/**
 *	Manialink library
 *	Contains different modules and functions for the manialink: animations, easing, tooltips, ...
 *	Documentation : http://maniaplanet.github.io/documentation/maniascript/libraries/library-manialink.html
 */

/**
 * Available easing:
 *	- Linear
 *	- Quad
 *	- Cubic
 *	- Quart
 *	- Quint
 *	- Sine
 *	- Exp
 *	- Circ
 *	- Back
 *	- Elastic
 *	- Bounce
 */

/**
 *	Not all properties can be animated, this is the list of the available ones.
 *
 *	CMlControl :
 *	- Position
 *	- Size
 *	- Scale
 *	- Rotation
 *	
 *	CMlQuad :
 *	- Opacity
 *	- Colorize
 *	- BgColor
 *	
 *	CMlLabel :
 *	- Opacity
 *	- TextColor
 *
 *	CMlGauge :
 *	- Ratio
 *	- Color
 */

/*
 *
 * TERMS OF USE - EASING EQUATIONS
 * 
 * Open source under the BSD License. 
 * 
 * Copyright © 2001 Robert Penner
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of 
 * conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice, this list 
 * of conditions and the following disclaimer in the documentation and/or other materials 
 * provided with the distribution.
 * 
 * Neither the name of the author nor the names of contributors may be used to endorse 
 * or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 * OF THE POSSIBILITY OF SUCH DAMAGE. 
 *
 */

#Const Version		"2014-03-17"
#Const ScriptName	"Manialink.Script.txt"

// ---------------------------------- //
// Contants
// ---------------------------------- //
#Const C_EaseDamping		1.70158
#Const C_DefaultDuration	500

// ---------------------------------- //
// Functions
// ---------------------------------- //
// ---------------------------------- //
// Private
// ---------------------------------- //

// ---------------------------------- //
/**	All easing functions:
 *	
 *	@param	_T	Current time
 *	@param	_B	Beginning value
 *	@param	_C	Change in value
 *	@param	_D	Duration
 *
 *	@return		The value for the current time
 */
Text Private_EaseLinear() {
	return """
Real LibManialink_EaseLinear(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	return (_C * X) + _B;
}
""";
}

Text Private_EaseInQuad() {
	return """
Real LibManialink_EaseInQuad(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	return _C * X * X + _B;
}
""";
}

Text Private_EaseOutQuad() {
	return """
Real LibManialink_EaseOutQuad(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	return -_C * X * (X-2.) + _B;
}
""";
}

Text Private_EaseInOutQuad() {
	return """
Real LibManialink_EaseInOutQuad(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D / 2.);
	declare Y = X - 1.;
	if (X < 1.) return _C / 2. * X * X + _B;
	return -_C / 2. * (Y * (Y - 2.) - 1.) + _B;
}
""";
}

Text Private_EaseInCubic() {
	return """
Real LibManialink_EaseInCubic(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	return _C * X * X * X + _B;
}
""";
}

Text Private_EaseOutCubic() {
	return """
Real LibManialink_EaseOutCubic(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.) - 1.;
	return _C * (X * X * X + 1.) + _B;
}
""";
}

Text Private_EaseInOutCubic() {
	return """
Real LibManialink_EaseInOutCubic(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D / 2.);
	declare Y = X - 2.;
	if (X < 1.) return _C / 2. * X * X * X + _B;
	return _C / 2. * (Y * Y * Y + 2.) + _B;
}
""";
}

Text Private_EaseInQuart() {
	return """
Real LibManialink_EaseInQuart(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	return _C * X * X * X * X + _B;
}
""";
}

Text Private_EaseOutQuart() {
	return """
Real LibManialink_EaseOutQuart(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.) - 1.;
	return -_C * (X * X * X * X - 1.) + _B;
}
""";
}

Text Private_EaseInOutQuart() {
	return """
Real LibManialink_EaseInOutQuart(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D / 2.);
	declare Y = X - 2.;
	if (X < 1.) return _C / 2. * X * X * X * X + _B;
	return -_C / 2. * (Y * Y * Y * Y - 2.) + _B;
}
""";
}

Text Private_EaseInQuint() {
	return """
Real LibManialink_EaseInQuint(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	return _C * X * X * X * X * X + _B;
}
""";
}

Text Private_EaseOutQuint() {
	return """
Real LibManialink_EaseOutQuint(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.) - 1.;
	return _C * (X * X * X * X * X + 1.) + _B;
}
""";
}

Text Private_EaseInOutQuint() {
	return """
Real LibManialink_EaseInOutQuint(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D / 2.);
	declare Y = X - 2.;
	if (X < 1.) return _C / 2. * X * X * X * X * X + _B;
	return _C / 2. * (Y * Y * Y * Y * Y + 2.) + _B;
}
""";
}

Text Private_EaseInSine() {
	return """
Real LibManialink_EaseInSine(Integer _T, Real _B, Real _C, Integer _D) {
	return -_C * ML::Cos(_T / (_D*1.) * (ML::PI() / 2.)) + _C + _B;
}
""";
}

Text Private_EaseOutSine() {
	return """
Real LibManialink_EaseOutSine(Integer _T, Real _B, Real _C, Integer _D) {
	return _C * ML::Sin(_T / (_D*1.) * (ML::PI() / 2.)) + _B;
}
""";
}

Text Private_EaseInOutSine() {
	return """
Real LibManialink_EaseInOutSine(Integer _T, Real _B, Real _C, Integer _D) {
	return -_C / 2. * (ML::Cos(ML::PI() * _T / (_D*1.)) - 1.) + _B;
}
""";
}

Text Private_EaseInExp() {
	return """
Real LibManialink_EaseInExp(Integer _T, Real _B, Real _C, Integer _D) {
	if (_T == 0) return _B;
	return _C * ML::Pow(2., 10. * (_T / (_D*1.) - 1.)) + _B;
}
""";
}

Text Private_EaseOutExp() {
	return """
Real LibManialink_EaseOutExp(Integer _T, Real _B, Real _C, Integer _D) {
	if (_T == _D) return _B + _C;
	return _C * (-ML::Pow(2., -10. * _T / (_D*1.)) + 1.) + _B;
}
""";
}

Text Private_EaseInOutExp() {
	return """
Real LibManialink_EaseInOutExp(Integer _T, Real _B, Real _C, Integer _D) {
	if (_T == 0) return _B;
	if (_T == _D) return _B + _C;
	declare X = _T / (_D / 2.);
	declare Y = X - 1.;
	if (X < 1.) return _C / 2. * ML::Pow(2., 10. * (X - 1.)) + _B;
	return _C / 2. * (-ML::Pow(2., -10. * Y) + 2.) + _B;
}
""";
}

Text Private_EaseInCirc() {
	return """
Real LibManialink_EaseInCirc(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	return -_C * (ML::Sqrt(1 - X * X) - 1.) + _B;
}
""";
}

Text Private_EaseOutCirc() {
	return """
Real LibManialink_EaseOutCirc(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.) - 1.;
	return _C * ML::Sqrt(1 - X * X) + _B;
}
""";
}

Text Private_EaseInOutCirc() {
	return """
Real LibManialink_EaseInOutCirc(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D / 2.);
	declare Y = X - 2.;
	if (X < 1.) return -_C / 2. * (ML::Sqrt(1 - X * X) - 1.) + _B;
	return _C / 2. * (ML::Sqrt(1 - Y * Y) + 1.) + _B;
}
""";
}

Text Private_EaseInBack() {
	return """
Real LibManialink_EaseInBack(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	return _C * X * X * (({{{C_EaseDamping}}} + 1.) * X - {{{C_EaseDamping}}}) + _B;
}
""";
}

Text Private_EaseOutBack() {
	return """
Real LibManialink_EaseOutBack(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.) - 1.;
	return _C * (X * X * (({{{C_EaseDamping}}} + 1.) * X + {{{C_EaseDamping}}}) + 1.) + _B;
}
""";
}

Text Private_EaseInOutBack() {
	return """
Real LibManialink_EaseInOutBack(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D / 2.);
	declare Y = {{{C_EaseDamping}}} * 1.525;
	declare Z = X - 2.;
	if (X < 1.) return _C / 2. * (X * X * ((Y + 1.) * X - Y)) + _B;
	return _C / 2. * (Z * Z * ((Y + 1.) * Z + Y) + 2.) + _B;
}
""";
}

Text Private_EaseInElastic() {
	return """
Real LibManialink_EaseInElastic(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	declare Y = _D * 0.3;
	declare Z = {{{C_EaseDamping}}};
	declare W = X - 1.;
	if (_T == 0) return _B;
	if (X == 1) return _B + _C;
	if (_C < ML::Abs(_C)) Z = Y / 4.;
	else Z = Y / (2 * ML::PI()) * ML::Asin(1.);
	return -(_C * ML::Pow(2., 10. * W) * ML::Sin((W * _D - Z)*(2.*ML::PI()) / Y)) + _B;
}
""";
}

Text Private_EaseOutElastic() {
	return """
Real LibManialink_EaseOutElastic(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	declare Y = _D * 0.3;
	declare Z = {{{C_EaseDamping}}};
	if (_T == 0) return _B;
	if (X == 1.) return _B + _C;
	if (_C < ML::Abs(_C)) Z = Y / 4.;
	else Z = Y / (2. * ML::PI()) * ML::Asin(1.);
	return _C * ML::Pow(2., -10. * X) * ML::Sin((X * _D - Z)*(2.*ML::PI()) / Y) + _C + _B;
}
""";
}

Text Private_EaseInOutElastic() {
	return """
Real LibManialink_EaseInOutElastic(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D / 2.);
	declare Y = _D * (0.3 * 1.5);
	declare Z = {{{C_EaseDamping}}};
	declare W = X - 1.;
	if (_T == 0) return _B;
	if (X == 2.) return _B + _C;
	if (_C < ML::Abs(_C)) Z = Y / 4.;
	else Z = Y / (2. * ML::PI()) * ML::Asin(1.);
	if (X < 1.) return -0.5 * (_C * ML::Pow(2., 10. * W) * ML::Sin((W * _D - Z)*(2.*ML::PI()) / Y)) + _B;
	return _C * ML::Pow(2., -10. * W) * ML::Sin((W * _D - Z)*(2.*ML::PI()) / Y) * 0.5 + _C + _B;
}
""";
}

Text Private_EaseInBounce() {
	return """
Real LibManialink_EaseInBounce(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = (_D - _T) / (_D*1.);
	
	if (X < (1 / 2.75)) {
		return _C - (_C * (7.5625 * X * X)) + _B;
	} else if (X < (2. / 2.75)) {
		declare Y = X - (1.5/2.75);
		return _C - (_C * (7.5625 * Y * Y + 0.75)) + _B;
	} else if (X < (2.5 / 2.75)) {
		declare Y = X - (2.25/2.75);
		return _C - (_C * (7.5625 * Y * Y + 0.9375)) + _B;
	}
	declare Y = X - (2.625/2.75);
	return _C - (_C * (7.5625 * Y * Y + 0.984375)) + _B;
}
""";
}

Text Private_EaseOutBounce() {
	return """
Real LibManialink_EaseOutBounce(Integer _T, Real _B, Real _C, Integer _D) {
	declare X = _T / (_D*1.);
	
	if (X < (1 / 2.75)) {
		return _C * (7.5625 * X * X) + _B;
	} else if (X < (2. / 2.75)) {
		declare Y = X - (1.5/2.75);
		return _C * (7.5625 * Y * Y + 0.75) + _B;
	} else if (X < (2.5 / 2.75)) {
		declare Y = X - (2.25/2.75);
		return _C * (7.5625 * Y * Y + 0.9375) + _B;
	}
	declare Y = X - (2.625/2.75);
	return _C * (7.5625 * Y * Y + 0.984375) + _B;
}
""";
}

Text Private_EaseInOutBounce() {
	return """
Real LibManialink_EaseInOutBounce(Integer _T, Real _B, Real _C, Integer _D) {
	if (_T < _D / 2.) {
		declare X = (_D - (_T * 2.)) / (_D*1.);
	
		if (X < (1. / 2.75)) {
			return (_C - (_C * (7.5625 * X * X))) * 0.5 + _B;
		} else if (X < (2. / 2.75)) {
			declare Y = X - (1.5/2.75);
			return (_C - (_C * (7.5625 * Y * Y + 0.75))) * 0.5 + _B;
		} else if (X < (2.5 / 2.75)) {
			declare Y = X - (2.25/2.75);
			return (_C - (_C * (7.5625 * Y * Y + 0.9375))) * 0.5 + _B;
		}
		declare Y = X - (2.625/2.75);
		return (_C - (_C * (7.5625 * Y * Y + 0.984375))) * 0.5 + _B;
	}
	
	declare X = (_T * 2. - _D) / (_D*1.);
	
	if (X < (1. / 2.75)) {
		return (_C * (7.5625 * X * X)) * 0.5 + _C * 0.5 + _B;
	} else if (X < (2. / 2.75)) {
		declare Y = X - (1.5/2.75);
		return (_C * (7.5625 * Y * Y + 0.75)) * 0.5 + _C * 0.5 + _B;
	} else if (X < (2.5 / 2.75)) {
		declare Y = X - (2.25/2.75);
		return (_C * (7.5625 * Y * Y + 0.9375)) * 0.5 + _C * 0.5 + _B;
	}
	declare Y = X - (2.625/2.75);
	return (_C * (7.5625 * Y * Y + 0.984375)) * 0.5 + _C * 0.5 + _B;
}
""";
}

Text Private_IsAnimated() {
	return """
Boolean LibManialink_IsAnimated(CMlControl _Control) {
	declare CMlControl[] LibManialink_Anims for Page;
	return LibManialink_Anims.exists(_Control);
}

Boolean LibManialink_IsAnimated(Text _ControlId) {
	declare Control <=> Page.GetFirstChild(_ControlId);
	if (Control == Null) return False;
	
	declare CMlControl[] LibManialink_Anims for Page;
	return LibManialink_Anims.exists(Control);
}
""";
}

// Todo -> reprend l'anime là où elle s'était arrêtée
Text Private_AnimPlay() {
	return """

""";
}

// Todo -> met l'anime en pause
Text Private_AnimPause() {
	return """

""";
}

// ---------------------------------- //
/** Animation repeat module
 *
 *	@return		The animation repeat module
 */
Text Private_AnimRepeat() {
	return """
Void LibManialink_AnimRepeatStart(Integer _RepeatTime, Integer _RepeatNb) {
	declare Boolean LibManialink_IsRepeating for Page;
	declare Integer LibManialink_RepeatTime for Page;
	declare Integer LibManialink_RepeatNb for Page;
	LibManialink_IsRepeating = True;
	LibManialink_RepeatTime = _RepeatTime;
	LibManialink_RepeatNb = _RepeatNb;
}

Void LibManialink_AnimRepeatStart(Integer _RepeatTime) {
	LibManialink_AnimRepeatStart(_RepeatTime, -1);
}

Void LibManialink_AnimRepeatEnd() {
	declare Boolean LibManialink_IsRepeating for Page;
	LibManialink_IsRepeating = False;
}
""";
}

// ---------------------------------- //
/** Animation module
 *
 *	@return		The animation module
 */
Text Private_Anim() {
	return """
Void LibManialink_AnimStop(CMlControl _Control, Integer _AnimId) {
	declare Integer[Integer] LibManialink_AnimQueue for _Control;
	
	declare Integer[Integer]	LibManialink_AnimStarTime		for _Control;
	declare Integer[Integer]	LibManialink_AnimDuration		for _Control;
	declare Integer[Integer]	LibManialink_AnimEndTime		for _Control;
	declare Text[Integer]		LibManialink_AnimEasing			for _Control;
	declare Text[Integer]		LibManialink_Visibility			for _Control;
	declare Boolean[Integer]	LibManialink_AnimRunning		for _Control;
	declare Integer[Integer]	LibManialink_AnimStyle			for _Control;
	declare Boolean[][Integer]	LibManialink_AnimActive			for _Control;
	declare Integer[Integer]	LibManialink_AnimReapeatTime	for _Control;
	declare Integer[Integer]	LibManialink_AnimReapeatNb		for _Control;
	
	declare Vec3[Integer]		LibManialink_AnimStart_Position	for _Control;
	declare Vec2[Integer]		LibManialink_AnimStart_Size		for _Control;
	declare Real[Integer]		LibManialink_AnimStart_Scale	for _Control;
	declare Real[Integer]		LibManialink_AnimStart_Rotation	for _Control;
	declare Real[Integer]		LibManialink_AnimStart_Opacity	for _Control;
	declare Vec3[Integer]		LibManialink_AnimStart_Colorize	for _Control;
	declare Vec3[Integer]		LibManialink_AnimStart_BgColor	for _Control;
	declare Vec3[Integer]		LibManialink_AnimStart_TextColor for _Control;
	declare Real[Integer]		LibManialink_AnimStart_Ratio	for _Control;
	declare Vec3[Integer]		LibManialink_AnimStart_GaugeColor for _Control;
	
	declare Vec3[Integer]		LibManialink_AnimEnd_Position	for _Control;
	declare Vec2[Integer]		LibManialink_AnimEnd_Size		for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Scale		for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Rotation	for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Opacity	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_Colorize	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_BgColor	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_TextColor	for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Ratio		for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_GaugeColor	for _Control;
	
	declare Vec3[Integer]		LibManialink_AnimDiff_Position	for _Control;
	declare Vec2[Integer]		LibManialink_AnimDiff_Size		for _Control;
	declare Real[Integer]		LibManialink_AnimDiff_Scale		for _Control;
	declare Real[Integer]		LibManialink_AnimDiff_Rotation	for _Control;
	declare Real[Integer]		LibManialink_AnimDiff_Opacity	for _Control;
	declare Vec3[Integer]		LibManialink_AnimDiff_Colorize	for _Control;
	declare Vec3[Integer]		LibManialink_AnimDiff_BgColor	for _Control;
	declare Vec3[Integer]		LibManialink_AnimDiff_TextColor	for _Control;
	declare Real[Integer]		LibManialink_AnimDiff_Ratio		for _Control;
	declare Vec3[Integer]		LibManialink_AnimDiff_GaugeColor for _Control;
	
	if (_AnimId < 0) {
		LibManialink_AnimQueue.clear();
		
		LibManialink_AnimStarTime.clear();
		LibManialink_AnimDuration.clear();
		LibManialink_AnimEndTime.clear();
		LibManialink_AnimEasing.clear();
		LibManialink_Visibility.clear();
		LibManialink_AnimRunning.clear();
		LibManialink_AnimStyle.clear();
		LibManialink_AnimActive.clear();
		LibManialink_AnimReapeatNb.clear();
		LibManialink_AnimReapeatTime.clear();
		
		LibManialink_AnimStart_Position.clear();
		LibManialink_AnimStart_Size.clear();
		LibManialink_AnimStart_Scale.clear();
		LibManialink_AnimStart_Rotation.clear();
		LibManialink_AnimStart_Opacity.clear();
		LibManialink_AnimStart_Colorize.clear();
		LibManialink_AnimStart_BgColor.clear();
		LibManialink_AnimStart_TextColor.clear();
		LibManialink_AnimStart_Ratio.clear();
		LibManialink_AnimStart_GaugeColor.clear();
		
		LibManialink_AnimEnd_Position.clear();
		LibManialink_AnimEnd_Size.clear();
		LibManialink_AnimEnd_Scale.clear();
		LibManialink_AnimEnd_Rotation.clear();
		LibManialink_AnimEnd_Opacity.clear();
		LibManialink_AnimEnd_Colorize.clear();
		LibManialink_AnimEnd_BgColor.clear();
		LibManialink_AnimEnd_TextColor.clear();
		LibManialink_AnimEnd_Ratio.clear();
		LibManialink_AnimEnd_GaugeColor.clear();
		
		LibManialink_AnimDiff_Position.clear();
		LibManialink_AnimDiff_Size.clear();
		LibManialink_AnimDiff_Scale.clear();
		LibManialink_AnimDiff_Rotation.clear();
		LibManialink_AnimDiff_Opacity.clear();
		LibManialink_AnimDiff_Colorize.clear();
		LibManialink_AnimDiff_BgColor.clear();
		LibManialink_AnimDiff_TextColor.clear();
		LibManialink_AnimDiff_Ratio.clear();
		LibManialink_AnimDiff_GaugeColor.clear();
	
		declare CMlControl[] LibManialink_Anims for Page;
		declare Removed = LibManialink_Anims.remove(_Control);
	} else {
		declare Removed = LibManialink_AnimQueue.removekey(_AnimId);
		
		Removed = LibManialink_AnimStarTime.removekey(_AnimId);
		Removed = LibManialink_AnimDuration.removekey(_AnimId);
		Removed = LibManialink_AnimEndTime.removekey(_AnimId);
		Removed = LibManialink_AnimEasing.removekey(_AnimId);
		Removed = LibManialink_Visibility.removekey(_AnimId);
		Removed = LibManialink_AnimRunning.removekey(_AnimId);
		Removed = LibManialink_AnimStyle.removekey(_AnimId);
		Removed = LibManialink_AnimActive.removekey(_AnimId);
		Removed = LibManialink_AnimReapeatNb.removekey(_AnimId);
		Removed = LibManialink_AnimReapeatTime.removekey(_AnimId);
		
		Removed = LibManialink_AnimStart_Position.removekey(_AnimId);
		Removed = LibManialink_AnimStart_Size.removekey(_AnimId);
		Removed = LibManialink_AnimStart_Scale.removekey(_AnimId);
		Removed = LibManialink_AnimStart_Rotation.removekey(_AnimId);
		Removed = LibManialink_AnimStart_Opacity.removekey(_AnimId);
		Removed = LibManialink_AnimStart_Colorize.removekey(_AnimId);
		Removed = LibManialink_AnimStart_BgColor.removekey(_AnimId);
		Removed = LibManialink_AnimStart_TextColor.removekey(_AnimId);
		Removed = LibManialink_AnimStart_Ratio.removekey(_AnimId);
		Removed = LibManialink_AnimStart_GaugeColor.removekey(_AnimId);
		
		Removed = LibManialink_AnimEnd_Position.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_Size.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_Scale.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_Rotation.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_Opacity.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_Colorize.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_BgColor.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_TextColor.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_Ratio.removekey(_AnimId);
		Removed = LibManialink_AnimEnd_GaugeColor.removekey(_AnimId);
		
		Removed = LibManialink_AnimDiff_Position.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_Size.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_Scale.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_Rotation.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_Opacity.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_Colorize.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_BgColor.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_TextColor.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_Ratio.removekey(_AnimId);
		Removed = LibManialink_AnimDiff_GaugeColor.removekey(_AnimId);
	}
}

Void LibManialink_AnimStop(CMlControl _Control) {
	LibManialink_AnimStop(_Control, -1);
}

Void LibManialink_AnimStop(Text _ControlId) {
	LibManialink_AnimStop(Page.GetFirstChild(_ControlId), -1);
}

Void LibManialink_Private_AnimComputeDiff(CMlControl _Control, Integer _AnimId) {
	declare Boolean[][Integer]	LibManialink_AnimActive			for _Control;
	
	declare Vec3[Integer]		LibManialink_AnimStart_Position	for _Control;
	declare Vec2[Integer]		LibManialink_AnimStart_Size		for _Control;
	declare Real[Integer]		LibManialink_AnimStart_Scale	for _Control;
	declare Real[Integer]		LibManialink_AnimStart_Rotation	for _Control;
	declare Real[Integer]		LibManialink_AnimStart_Opacity	for _Control;
	declare Vec3[Integer]		LibManialink_AnimStart_Colorize	for _Control;
	declare Vec3[Integer]		LibManialink_AnimStart_BgColor	for _Control;
	declare Vec3[Integer]		LibManialink_AnimStart_TextColor for _Control;
	declare Real[Integer]		LibManialink_AnimStart_Ratio	for _Control;
	declare Vec3[Integer]		LibManialink_AnimStart_GaugeColor for _Control;
	
	declare Vec3[Integer]		LibManialink_AnimEnd_Position	for _Control;
	declare Vec2[Integer]		LibManialink_AnimEnd_Size		for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Scale		for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Rotation	for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Opacity	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_Colorize	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_BgColor	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_TextColor	for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Ratio		for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_GaugeColor	for _Control;
	
	declare Vec3[Integer]		LibManialink_AnimDiff_Position	for _Control;
	declare Vec2[Integer]		LibManialink_AnimDiff_Size		for _Control;
	declare Real[Integer]		LibManialink_AnimDiff_Scale		for _Control;
	declare Real[Integer]		LibManialink_AnimDiff_Rotation	for _Control;
	declare Real[Integer]		LibManialink_AnimDiff_Opacity	for _Control;
	declare Vec3[Integer]		LibManialink_AnimDiff_Colorize	for _Control;
	declare Vec3[Integer]		LibManialink_AnimDiff_BgColor	for _Control;
	declare Vec3[Integer]		LibManialink_AnimDiff_TextColor	for _Control;
	declare Real[Integer]		LibManialink_AnimDiff_Ratio		for _Control;
	declare Vec3[Integer]		LibManialink_AnimDiff_GaugeColor for _Control;
	
	LibManialink_AnimStart_Position[_AnimId]	= _Control.RelativePosition;
	LibManialink_AnimStart_Size[_AnimId]		= _Control.Size;
	LibManialink_AnimStart_Scale[_AnimId]		= _Control.RelativeScale;
	LibManialink_AnimStart_Rotation[_AnimId]	= _Control.RelativeRotation;
	LibManialink_AnimStart_Opacity[_AnimId]		= 0.;
	LibManialink_AnimStart_Colorize[_AnimId]	= <0., 0., 0.>;
	LibManialink_AnimStart_BgColor[_AnimId]		= <0., 0., 0.>;
	LibManialink_AnimStart_TextColor[_AnimId]	= <0., 0., 0.>;
	LibManialink_AnimStart_Ratio[_AnimId]		= 0.;
	LibManialink_AnimStart_GaugeColor[_AnimId]	= <0., 0., 0.>;
	if (_Control is CMlQuad) {
		declare Quad <=> (_Control as CMlQuad);
		LibManialink_AnimStart_Opacity[_AnimId]		= Quad.Opacity;
		LibManialink_AnimStart_Colorize[_AnimId]	= Quad.Colorize;
		LibManialink_AnimStart_BgColor[_AnimId]		= Quad.BgColor;
	} else if (_Control is CMlLabel) {
		declare Label <=> (_Control as CMlLabel);
		LibManialink_AnimStart_Opacity[_AnimId]		= Label.Opacity;
		LibManialink_AnimStart_TextColor[_AnimId]	= Label.TextColor;
	} else if (_Control is CMlGauge) {
		declare Gauge <=> (_Control as CMlGauge);
		LibManialink_AnimStart_Ratio[_AnimId]		= Gauge.Ratio;
		LibManialink_AnimStart_GaugeColor[_AnimId]	= Gauge.Color;
	}
	
	LibManialink_AnimDiff_Position[_AnimId]		= <0., 0., 0.>;
	LibManialink_AnimDiff_Size[_AnimId]			= <0., 0.>;
	LibManialink_AnimDiff_Scale[_AnimId]		= 0.;
	LibManialink_AnimDiff_Rotation[_AnimId]		= 0.;
	LibManialink_AnimDiff_Opacity[_AnimId]		= 0.;
	LibManialink_AnimDiff_Colorize[_AnimId]		= <0., 0., 0.>;
	LibManialink_AnimDiff_BgColor[_AnimId]		= <0., 0., 0.>;
	LibManialink_AnimDiff_TextColor[_AnimId]	= <0., 0., 0.>;
	LibManialink_AnimDiff_Ratio[_AnimId]		= 0.;
	LibManialink_AnimDiff_GaugeColor[_AnimId]	= <0., 0., 0.>;
	
	if (LibManialink_AnimActive[_AnimId][0]) {
		LibManialink_AnimDiff_Position[_AnimId] = LibManialink_AnimEnd_Position[_AnimId] - LibManialink_AnimStart_Position[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][1]) {
		LibManialink_AnimDiff_Size[_AnimId] = LibManialink_AnimEnd_Size[_AnimId] - LibManialink_AnimStart_Size[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][2]) {
		LibManialink_AnimDiff_Scale[_AnimId]	= LibManialink_AnimEnd_Scale[_AnimId] - LibManialink_AnimStart_Scale[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][3]) {
		LibManialink_AnimDiff_Rotation[_AnimId]	= LibManialink_AnimEnd_Rotation[_AnimId] - LibManialink_AnimStart_Rotation[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][4]) {
		LibManialink_AnimDiff_Opacity[_AnimId] = LibManialink_AnimEnd_Opacity[_AnimId] - LibManialink_AnimStart_Opacity[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][5]) {
		LibManialink_AnimDiff_Colorize[_AnimId] = LibManialink_AnimEnd_Colorize[_AnimId] - LibManialink_AnimStart_Colorize[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][6]) {
		LibManialink_AnimDiff_BgColor[_AnimId] = LibManialink_AnimEnd_BgColor[_AnimId] - LibManialink_AnimStart_BgColor[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][7]) {
		LibManialink_AnimDiff_TextColor[_AnimId] = LibManialink_AnimEnd_TextColor[_AnimId] - LibManialink_AnimStart_TextColor[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][8]) {
		LibManialink_AnimDiff_Ratio[_AnimId] = LibManialink_AnimEnd_Ratio[_AnimId] - LibManialink_AnimStart_Ratio[_AnimId];
	}
	if (LibManialink_AnimActive[_AnimId][9]) {
		LibManialink_AnimDiff_GaugeColor[_AnimId] = LibManialink_AnimEnd_GaugeColor[_AnimId] - LibManialink_AnimStart_GaugeColor[_AnimId];
	}
}

Void LibManialink_Private_AnimTargetProperties(
	CMlControl _Control,
	Integer _AnimId,
	Vec3 _Position,
	Vec2 _Size,
	Real _Scale,
	Real _Rotation,
	Real _Opacity,
	Vec3 _Colorize,
	Vec3 _BgColor,
	Vec3 _TextColor,
	Real _Ratio,
	Vec3 _GaugeColor
) {
	declare Vec3[Integer]		LibManialink_AnimEnd_Position	for _Control;
	declare Vec2[Integer]		LibManialink_AnimEnd_Size		for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Scale		for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Rotation	for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Opacity	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_Colorize	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_BgColor	for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_TextColor	for _Control;
	declare Real[Integer]		LibManialink_AnimEnd_Ratio		for _Control;
	declare Vec3[Integer]		LibManialink_AnimEnd_GaugeColor	for _Control;
	
	LibManialink_AnimEnd_Position[_AnimId]	= _Position;
	LibManialink_AnimEnd_Size[_AnimId]		= _Size;
	LibManialink_AnimEnd_Scale[_AnimId]		= _Scale;
	LibManialink_AnimEnd_Rotation[_AnimId]	= _Rotation;
	LibManialink_AnimEnd_Opacity[_AnimId]	= _Opacity;
	LibManialink_AnimEnd_Colorize[_AnimId]	= _Colorize;
	LibManialink_AnimEnd_BgColor[_AnimId]	= _BgColor;
	LibManialink_AnimEnd_TextColor[_AnimId]	= _TextColor;
	LibManialink_AnimEnd_Ratio[_AnimId]		= _Ratio;
	LibManialink_AnimEnd_GaugeColor[_AnimId]= _GaugeColor;
}

Void LibManialink_Private_Anim(
	CMlControl _Control,
	Boolean[] _Active,
	Vec3 _Position,
	Vec2 _Size,
	Real _Scale,
	Real _Rotation,
	Real _Opacity,
	Vec3 _Colorize,
	Vec3 _BgColor,
	Vec3 _TextColor,
	Real _Ratio,
	Vec3 _GaugeColor,
	Integer _StartTime,
	Integer _Duration,
	Text _Easing,
	Text _Visibility,
	Integer _Style
) {	
	declare Integer[Integer] LibManialink_AnimQueue for _Control;
	
	declare Integer[Integer]	LibManialink_AnimStarTime		for _Control;
	declare Integer[Integer]	LibManialink_AnimDuration		for _Control;
	declare Integer[Integer]	LibManialink_AnimEndTime		for _Control;
	declare Text[Integer]		LibManialink_AnimEasing			for _Control;
	declare Text[Integer]		LibManialink_Visibility			for _Control;
	declare Boolean[Integer]	LibManialink_AnimRunning		for _Control;
	declare Integer[Integer]	LibManialink_AnimStyle			for _Control;
	declare Boolean[][Integer]	LibManialink_AnimActive			for _Control;
	declare Integer[Integer]	LibManialink_AnimReapeatNb		for _Control;
	declare Integer[Integer]	LibManialink_AnimReapeatTime	for _Control;
	
	declare AnimStartTime = 0;
	declare AnimId = 0;
	
	// Anim
	if (_Style < 0) {
		LibManialink_AnimStop(_Control);
		AnimStartTime = Now;
	} 
	// Anim chain
	else if (_Style == 0) {
		declare AnimEndTime = Now;
		foreach (Id => StartTime in LibManialink_AnimQueue) {
			AnimEndTime = LibManialink_AnimEndTime[Id];
			if (AnimEndTime > AnimStartTime) AnimStartTime = AnimEndTime;
		}
	} 
	// Anim Insert
	else {
		AnimStartTime = Now + _StartTime;
	}
	
	LibManialink_AnimQueue = LibManialink_AnimQueue.sortkey();
	foreach (Id => StartTime in LibManialink_AnimQueue) {
		if (AnimId != Id) break;
		AnimId += 1;
	}
	
	declare Boolean LibManialink_IsRepeating for Page;
	declare Integer LibManialink_RepeatTime for Page;
	declare Integer LibManialink_RepeatNb for Page;
	declare Repeat = 1;
	if (LibManialink_IsRepeating) Repeat = LibManialink_RepeatNb;
	
	LibManialink_AnimQueue[AnimId] = AnimStartTime;
	
	LibManialink_AnimStarTime[AnimId]	= AnimStartTime;
	LibManialink_AnimDuration[AnimId]	= _Duration;
	LibManialink_AnimEndTime[AnimId]	= LibManialink_AnimStarTime[AnimId] + LibManialink_AnimDuration[AnimId];
	LibManialink_AnimEasing[AnimId]		= _Easing;
	LibManialink_Visibility[AnimId]		= _Visibility;
	LibManialink_AnimRunning[AnimId]	= False;
	LibManialink_AnimStyle[AnimId]		= _Style;
	LibManialink_AnimActive[AnimId]		= _Active;
	LibManialink_AnimReapeatNb[AnimId]	= Repeat;
	LibManialink_AnimReapeatTime[AnimId]= LibManialink_RepeatTime;
	
	LibManialink_Private_AnimTargetProperties(
		_Control, AnimId, _Position, _Size, _Scale, _Rotation, _Opacity, _Colorize, _BgColor, _TextColor, _Ratio, _GaugeColor
	);
	LibManialink_Private_AnimComputeDiff(_Control, AnimId);
	
	declare CMlControl[] LibManialink_Anims for Page;
	declare CopyControl = _Control;
	if (!LibManialink_Anims.exists(_Control)) LibManialink_Anims.add(CopyControl);
}

Void LibManialink_Private_Anim(CMlControl _Control, Text _TargetXml, Integer _StartTime, Integer _Duration, Text _Easing, Integer _Style) {
	declare CMlControl Control;
	if (_Control != Null) {
		Control <=> _Control;
	}
	
	declare XmlDoc = Xml.Create(_TargetXml);
	if (XmlDoc == Null) {
		log(Now^"> Library Manialink > XML argument not valid");
		return;
	}
	
	if (Control == Null) {
		declare ControlId = XmlDoc.Root.GetAttributeText("id", "");
		if (ControlId == "") return;
		Control <=> Page.GetFirstChild(ControlId);
	}
	
	if (Control == Null) return;
	
	declare Active		= [False, False, False, False, False, False, False, False, False, False];
	declare Vec3 Position;
	declare Vec2 Size;
	declare Real Scale;
	declare Real Rotation;
	declare Real Opacity;
	declare Vec3 Colorize;
	declare Vec3 BgColor;
	declare Vec3 TextColor;
	declare Real Ratio;
	declare Vec3 GaugeColor;
	declare Text Visibility;
	
	declare XmlPosition = XmlDoc.Root.GetAttributeText("posn", "");
	if (XmlPosition != "") {
		declare PositionSplit = TL::Split(" ", XmlPosition);
		if (PositionSplit.existskey(0)) Position.X = TL::ToReal(PositionSplit[0]);
		if (PositionSplit.existskey(1)) Position.Y = TL::ToReal(PositionSplit[1]);
		if (PositionSplit.existskey(2)) Position.Z = TL::ToReal(PositionSplit[2]);
		Active[0] = True;
	}
	
	declare XmlSize = XmlDoc.Root.GetAttributeText("sizen", "");
	if (XmlSize != "") {
		declare SizeSplit = TL::Split(" ", XmlSize);
		if (SizeSplit.existskey(0)) Size.X = TL::ToReal(SizeSplit[0]);
		if (SizeSplit.existskey(1)) Size.Y = TL::ToReal(SizeSplit[1]);
		Active[1] = True;
	}
	
	declare XmlScale = XmlDoc.Root.GetAttributeText("scale", "");
	if (XmlScale != "") {
		Scale = TL::ToReal(XmlScale);
		Active[2] = True;
	}
	
	declare XmlRotation = XmlDoc.Root.GetAttributeText("rot", "");
	if (XmlRotation != "") {
		Rotation = TL::ToReal(XmlRotation);
		Active[3] = True;
	}
	
	declare XmlOpacity = XmlDoc.Root.GetAttributeText("opacity", "");
	if (XmlOpacity != "") {
		Opacity = TL::ToReal(XmlOpacity);
		Active[4] = True;
	}
	
	declare XmlColorize = XmlDoc.Root.GetAttributeText("colorize", "");
	if (XmlColorize != "") {
		Colorize = TL::ToColor(XmlColorize);
		Active[5] = True;
	}
	
	declare XmlBgColor = XmlDoc.Root.GetAttributeText("bgcolor", "");
	if (XmlBgColor != "") {
		BgColor = TL::ToColor(XmlBgColor);
		Active[6] = True;
	}
	
	declare XmlTextColor = XmlDoc.Root.GetAttributeText("textcolor", "");
	if (XmlTextColor != "") {
		TextColor = TL::ToColor(XmlTextColor);
		Active[7] = True;
	}
	
	declare XmlRatio = XmlDoc.Root.GetAttributeText("ratio", "");
	if (XmlRatio != "") {
		Ratio = TL::ToReal(XmlRatio);
		Active[8] = True;
	}
	
	declare XmlGaugeColor = XmlDoc.Root.GetAttributeText("color", "");
	if (XmlGaugeColor != "") {
		GaugeColor = TL::ToColor(XmlGaugeColor);
		Active[9] = True;
	}
	
	if (Visibility == "") {
		declare XmlVisibility = XmlDoc.Root.GetAttributeText("hidden", "");
		if (XmlVisibility != "") {
			if (XmlVisibility == "true" || XmlVisibility == "1") Visibility = "Hide";
			else Visibility = "Show";
		}
	}
	
	LibManialink_Private_Anim(Control, Active, Position, Size, Scale, Rotation, Opacity, Colorize, BgColor, TextColor, Ratio, GaugeColor, _StartTime, _Duration, _Easing, Visibility, _Style);
}

Void LibManialink_Anim(CMlControl _Control, Text _TargetXml, Integer _Duration, Text _Easing) {
	LibManialink_Private_Anim(_Control, _TargetXml, -1, _Duration, _Easing, -1);
}

Void LibManialink_AnimChain(CMlControl _Control, Text _TargetXml, Integer _Duration, Text _Easing) {
	LibManialink_Private_Anim(_Control, _TargetXml, -1, _Duration, _Easing, 0);
}

Void LibManialink_AnimInsert(CMlControl _Control, Text _TargetXml, Integer _StartTime, Integer _Duration, Text _Easing) {
	LibManialink_Private_Anim(_Control, _TargetXml, _StartTime, _Duration, _Easing, 1);
}

Void LibManialink_Anim(Text _TargetXml, Integer _Duration, Text _Easing) {
	LibManialink_Private_Anim(Null, _TargetXml, -1, _Duration, _Easing, -1);
}

Void LibManialink_AnimChain(Text _TargetXml, Integer _Duration, Text _Easing) {
	LibManialink_Private_Anim(Null, _TargetXml, -1, _Duration, _Easing, 0);
}

Void LibManialink_AnimInsert(Text _TargetXml, Integer _StartTime, Integer _Duration, Text _Easing) {
	LibManialink_Private_Anim(Null, _TargetXml, _StartTime, _Duration, _Easing, 1);
}
""";
}

// ---------------------------------- //
/** Tween module
 *
 *	@return		The tween module
 */
Text Private_Tween(Text [] _Easings) {
	declare Easings = "";
	declare Count = 0;
	foreach (Easing in _Easings) {
		if (Easing == "") continue;
		Easings ^= """
		case "{{{Easing}}}" : return LibManialink_{{{Easing}}}(_CurrentTime, _StartValue, _DiffValue, _Duration);""";
		Count += 1;
	}
	if (Count <= 0) Easings ^= """
		case "EaseNull": {}""";
	Easings ^= """
		default: return LibManialink_EaseLinear(_CurrentTime, _StartValue, _DiffValue, _Duration);""";

	return """
Real LibManialink_Tween(Integer _CurrentTime, Real _StartValue, Real _DiffValue, Integer _Duration, Text _Easing) {
	switch (_Easing) {
		{{{Easings}}}
	}
	return _StartValue;
}
""";
}

// ---------------------------------- //
/** The AnimLoop() function, update the running animations
 *
 *	@return		The AnimLoop() function
 */
Text Private_AnimLoop() {
	return """
Void LibManialink_AnimLoop() {
	declare CMlControl[] LibManialink_Anims for Page;
	declare CMlControl[] ControlsToRemove;
	
	foreach (Control in LibManialink_Anims) {
		declare Integer[Integer] LibManialink_AnimQueue for Control;
	
		declare Integer[Integer]	LibManialink_AnimStarTime	for Control;
		declare Integer[Integer]	LibManialink_AnimDuration	for Control;
		declare Integer[Integer]	LibManialink_AnimEndTime	for Control;
		declare Text[Integer]		LibManialink_AnimEasing		for Control;
		declare Text[Integer]		LibManialink_Visibility		for Control;
		declare Boolean[Integer]	LibManialink_AnimRunning	for Control;
		declare Integer[Integer]	LibManialink_AnimStyle		for Control;
		declare Integer[Integer]	LibManialink_AnimReapeatTime	for Control;
		declare Integer[Integer]	LibManialink_AnimReapeatNb		for Control;
		
		declare Vec3[Integer]	LibManialink_AnimStart_Position	for Control;
		declare Vec2[Integer]	LibManialink_AnimStart_Size		for Control;
		declare Real[Integer]	LibManialink_AnimStart_Scale	for Control;
		declare Real[Integer]	LibManialink_AnimStart_Rotation	for Control;
		declare Real[Integer]	LibManialink_AnimStart_Opacity	for Control;
		declare Vec3[Integer]	LibManialink_AnimStart_Colorize	for Control;
		declare Vec3[Integer]	LibManialink_AnimStart_BgColor	for Control;
		declare Vec3[Integer]	LibManialink_AnimStart_TextColor for Control;
		declare Real[Integer]	LibManialink_AnimStart_Ratio	for Control;
		declare Vec3[Integer]	LibManialink_AnimStart_GaugeColor for Control;
		
		declare Vec3[Integer]	LibManialink_AnimDiff_Position	for Control;
		declare Vec2[Integer]	LibManialink_AnimDiff_Size		for Control;
		declare Real[Integer]	LibManialink_AnimDiff_Scale		for Control;
		declare Real[Integer]	LibManialink_AnimDiff_Rotation	for Control;
		declare Real[Integer]	LibManialink_AnimDiff_Opacity	for Control;
		declare Vec3[Integer]	LibManialink_AnimDiff_Colorize	for Control;
		declare Vec3[Integer]	LibManialink_AnimDiff_BgColor	for Control;
		declare Vec3[Integer]	LibManialink_AnimDiff_TextColor	for Control;
		declare Real[Integer]	LibManialink_AnimDiff_Ratio		for Control;
		declare Vec3[Integer]	LibManialink_AnimDiff_GaugeColor for Control;
		
		declare Integer[] AnimsToRemove;
		declare Integer[] AnimsToRepeat;
		
		foreach (AnimId => AnimStartTime in LibManialink_AnimQueue) {
			if (AnimStartTime > Now) continue;
			
			if (!LibManialink_AnimRunning[AnimId]) {
				LibManialink_AnimRunning[AnimId] = True;
				if (LibManialink_Visibility[AnimId] == "Show") {
					Control.Visible = True;
				}
				
				// LibManialink_AnimStyle
				// -1	-> Start new anim
				// 0	-> Chain anim
				// 1	-> Insert anim
				if (LibManialink_AnimStyle[AnimId] != -1) {
					LibManialink_Private_AnimComputeDiff(Control, AnimId);
				}
			}
			
			if (!LibManialink_AnimQueue.existskey(AnimId)) continue;
			
			declare AnimationCurrentTime = Now - LibManialink_AnimStarTime[AnimId];
			if (AnimationCurrentTime > LibManialink_AnimDuration[AnimId]) AnimationCurrentTime = LibManialink_AnimDuration[AnimId];
			
			// Position
			if (LibManialink_AnimDiff_Position[AnimId].X != 0.) Control.RelativePosition.X = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Position[AnimId].X, LibManialink_AnimDiff_Position[AnimId].X, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
			if (LibManialink_AnimDiff_Position[AnimId].Y != 0.) Control.RelativePosition.Y = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Position[AnimId].Y, LibManialink_AnimDiff_Position[AnimId].Y, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
			if (LibManialink_AnimDiff_Position[AnimId].Z != 0.) Control.RelativePosition.Z = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Position[AnimId].Z, LibManialink_AnimDiff_Position[AnimId].Z, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
			
			// Size
			if (LibManialink_AnimDiff_Size[AnimId].X != 0.) Control.Size.X = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Size[AnimId].X, LibManialink_AnimDiff_Size[AnimId].X, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
			if (LibManialink_AnimDiff_Size[AnimId].Y != 0.) Control.Size.Y = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Size[AnimId].Y, LibManialink_AnimDiff_Size[AnimId].Y, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
			
			// Scale
			if (LibManialink_AnimDiff_Scale[AnimId] != 0.) Control.RelativeScale = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Scale[AnimId], LibManialink_AnimDiff_Scale[AnimId], LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
			
			// Rotation
			if (LibManialink_AnimDiff_Rotation[AnimId] != 0.) Control.RelativeRotation = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Rotation[AnimId], LibManialink_AnimDiff_Rotation[AnimId], LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
			
			if (Control is CMlQuad) {
				declare Quad <=> (Control as CMlQuad);
				
				// Opacity
				if (LibManialink_AnimDiff_Opacity[AnimId] != 0.) Quad.Opacity = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Opacity[AnimId], LibManialink_AnimDiff_Opacity[AnimId], LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
				
				// Colorize
				declare NewColorize = Quad.Colorize;
				declare UpdateColorize = False;
				if (LibManialink_AnimDiff_Colorize[AnimId].X != 0.) {
					NewColorize.X = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Colorize[AnimId].X, LibManialink_AnimDiff_Colorize[AnimId].X, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewColorize.X > 1.) NewColorize.X = 1.;
					else if (NewColorize.X < 0.) NewColorize.X = 0.;
					UpdateColorize = True;
				}
				if (LibManialink_AnimDiff_Colorize[AnimId].Y != 0.) {
					NewColorize.Y = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Colorize[AnimId].Y, LibManialink_AnimDiff_Colorize[AnimId].Y, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewColorize.Y > 1.) NewColorize.Y = 1.;
					else if (NewColorize.Y < 0.) NewColorize.Y = 0.;
					UpdateColorize = True;
				}
				if (LibManialink_AnimDiff_Colorize[AnimId].Z != 0.) {
					NewColorize.Z = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Colorize[AnimId].Z, LibManialink_AnimDiff_Colorize[AnimId].Z, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewColorize.Z > 1.) NewColorize.Z = 1.;
					else if (NewColorize.Z < 0.) NewColorize.Z = 0.;
					UpdateColorize = True;
				}
				if (UpdateColorize) Quad.Colorize = NewColorize;
				
				// BgColor
				declare NewBgColor = Quad.BgColor;
				declare UpdateColor = False;
				if (LibManialink_AnimDiff_BgColor[AnimId].X != 0.) {
					NewBgColor.X = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_BgColor[AnimId].X, LibManialink_AnimDiff_BgColor[AnimId].X, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewBgColor.X > 1.) NewBgColor.X = 1.;
					else if (NewBgColor.X < 0.) NewBgColor.X = 0.;
					UpdateColor = True;
				}
				if (LibManialink_AnimDiff_BgColor[AnimId].Y != 0.) {
					NewBgColor.Y = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_BgColor[AnimId].Y, LibManialink_AnimDiff_BgColor[AnimId].Y, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewBgColor.Y > 1.) NewBgColor.Y = 1.;
					else if (NewBgColor.Y < 0.) NewBgColor.Y = 0.;
					UpdateColor = True;
				}
				if (LibManialink_AnimDiff_BgColor[AnimId].Z != 0.) {
					NewBgColor.Z = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_BgColor[AnimId].Z, LibManialink_AnimDiff_BgColor[AnimId].Z, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewBgColor.Z > 1.) NewBgColor.Z = 1.;
					else if (NewBgColor.Z < 0.) NewBgColor.Z = 0.;
					UpdateColor = True;
				}
				if (UpdateColor) Quad.BgColor = NewBgColor;
			}
			
			if (Control is CMlLabel) {
				declare Label <=> (Control as CMlLabel);
				
				// Opacity
				if (LibManialink_AnimDiff_Opacity[AnimId] != 0.) Label.Opacity = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Opacity[AnimId], LibManialink_AnimDiff_Opacity[AnimId], LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
				
				// TextColor
				declare NewTextColor = Label.TextColor;
				declare UpdateTextColor = False;
				if (LibManialink_AnimDiff_TextColor[AnimId].X != 0.) {
					NewTextColor.X = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_TextColor[AnimId].X, LibManialink_AnimDiff_TextColor[AnimId].X, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewTextColor.X > 1.) NewTextColor.X = 1.;
					else if (NewTextColor.X < 0.) NewTextColor.X = 0.;
					UpdateTextColor = True;
				}
				if (LibManialink_AnimDiff_TextColor[AnimId].Y != 0.) {
					NewTextColor.Y = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_TextColor[AnimId].Y, LibManialink_AnimDiff_TextColor[AnimId].Y, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewTextColor.Y > 1.) NewTextColor.Y = 1.;
					else if (NewTextColor.Y < 0.) NewTextColor.Y = 0.;
					UpdateTextColor = True;
				}
				if (LibManialink_AnimDiff_TextColor[AnimId].Z != 0.) {
					NewTextColor.Z = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_TextColor[AnimId].Z, LibManialink_AnimDiff_TextColor[AnimId].Z, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewTextColor.Z > 1.) NewTextColor.Z = 1.;
					else if (NewTextColor.Z < 0.) NewTextColor.Z = 0.;
					UpdateTextColor = True;
				}
				if (UpdateTextColor) Label.TextColor = NewTextColor;
			}
			
			if (Control is CMlGauge) {
				declare Gauge <=> (Control as CMlGauge);
				
				// Ratio
				declare NewRatio = Gauge.Ratio;
				if (LibManialink_AnimDiff_Ratio[AnimId] != 0.) NewRatio = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_Ratio[AnimId], LibManialink_AnimDiff_Ratio[AnimId], LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
				if (NewRatio > 1.) NewRatio = 1.;
				else if (NewRatio < 0.) NewRatio = 0.;
				Gauge.Ratio = NewRatio;
				
				// GaugeColor
				declare NewGaugeColor = Gauge.Color;
				declare UpdateGaugeColor = False;
				if (LibManialink_AnimDiff_GaugeColor[AnimId].X != 0.) {
					NewGaugeColor.X = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_GaugeColor[AnimId].X, LibManialink_AnimDiff_GaugeColor[AnimId].X, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewGaugeColor.X > 1.) NewGaugeColor.X = 1.;
					else if (NewGaugeColor.X < 0.) NewGaugeColor.X = 0.;
					UpdateGaugeColor = True;
				}
				if (LibManialink_AnimDiff_GaugeColor[AnimId].Y != 0.) {
					NewGaugeColor.Y = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_GaugeColor[AnimId].Y, LibManialink_AnimDiff_GaugeColor[AnimId].Y, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewGaugeColor.Y > 1.) NewGaugeColor.Y = 1.;
					else if (NewGaugeColor.Y < 0.) NewGaugeColor.Y = 0.;
					UpdateGaugeColor = True;
				}
				if (LibManialink_AnimDiff_GaugeColor[AnimId].Z != 0.) {
					NewGaugeColor.Z = LibManialink_Tween(AnimationCurrentTime, LibManialink_AnimStart_GaugeColor[AnimId].Z, LibManialink_AnimDiff_GaugeColor[AnimId].Z, LibManialink_AnimDuration[AnimId], LibManialink_AnimEasing[AnimId]);
					if (NewGaugeColor.Z > 1.) NewGaugeColor.Z = 1.;
					else if (NewGaugeColor.Z < 0.) NewGaugeColor.Z = 0.;
					UpdateGaugeColor = True;
				}
				if (UpdateGaugeColor)Gauge.Color = NewGaugeColor;
			}
			
			if (Now >= LibManialink_AnimEndTime[AnimId]) {
				if (LibManialink_AnimReapeatNb[AnimId] > 1 || LibManialink_AnimReapeatNb[AnimId] < 0) {
					if (LibManialink_AnimReapeatNb[AnimId] > 0) LibManialink_AnimReapeatNb[AnimId] -= 1;
					AnimsToRepeat.add(AnimId);
				} else {
					AnimsToRemove.add(AnimId);
				}
				
				LibManialink_AnimRunning[AnimId] = False;
				if (LibManialink_Visibility[AnimId] == "Hide") {
					Control.Visible = False;
				}
			}
		}
		
		foreach (AnimId in AnimsToRemove) {
			LibManialink_AnimStop(Control, AnimId);
		}
		
		foreach (AnimId in AnimsToRepeat) {
			LibManialink_AnimStarTime[AnimId]	+= LibManialink_AnimReapeatTime[AnimId];
			LibManialink_AnimEndTime[AnimId]	= LibManialink_AnimStarTime[AnimId] + LibManialink_AnimDuration[AnimId];
			LibManialink_AnimStyle[AnimId]		= 0;
			LibManialink_AnimQueue[AnimId]		= LibManialink_AnimStarTime[AnimId];
		}
		
		if (LibManialink_AnimQueue.count <= 0) {
			ControlsToRemove.add(Control);
		}
	}
	
	foreach (Control in ControlsToRemove) {
		declare Removed = LibManialink_Anims.remove(Control);
	}
}
""";
}

// ---------------------------------- //
/** Tooltip module
 *
 *	@return		The tooltip module
 */
Text Private_Tooltip() {
	return """
// ---------------------------------- //
// Tooltip Start
// ---------------------------------- //
Void LibManialink_TooltipShow(Text _Id, CMlControl _Control, Text _Text) {
	Page.GetClassChildren("LibManialink_Tooltip", Page.MainFrame, True);
	foreach (Control in Page.GetClassChildren_Result) {
		if (Control.ControlId != _Id) continue;
		
		declare Frame_Tooltip	<=> (Control as CMlFrame);
		if (Frame_Tooltip == Null) return;
		declare Tooltip_Message		<=> (Frame_Tooltip.GetFirstChild("Tooltip_Message")		as CMlLabel);
		declare Tooltip_BoundingBox	<=> (Frame_Tooltip.GetFirstChild("Tooltip_BoundingBox")	as CMlQuad);
		
		declare Vec3 Pos;
		Pos.X = (_Control.AbsolutePosition.X - Frame_Tooltip.AbsolutePosition.X) + Frame_Tooltip.RelativePosition.X;
		Pos.Y = (_Control.AbsolutePosition.Y - Frame_Tooltip.AbsolutePosition.Y) + Frame_Tooltip.RelativePosition.Y;
		Pos.Z = (_Control.AbsolutePosition.Z - Frame_Tooltip.AbsolutePosition.Z) + Frame_Tooltip.RelativePosition.Z + 1.;
		
		if (_Control.HorizontalAlign == CMlControl::AlignHorizontal::HCenter) {
			Pos.X -= (_Control.Size.X / 2.);
		} else if (_Control.HorizontalAlign == CMlControl::AlignHorizontal::Right) {
			Pos.X -= (_Control.Size.X);
		}
		
		if (_Control.VerticalAlign == CMlControl::AlignVertical::Top) {
			Pos.Y -= _Control.Size.Y;
		} else if (_Control.VerticalAlign == CMlControl::AlignVertical::VCenter || _Control.VerticalAlign == CMlControl::AlignVertical::VCenter2) {
			Pos.Y -= _Control.Size.Y / 2.;
		}
		
		if (Tooltip_BoundingBox != Null) {
			if (Tooltip_BoundingBox.HorizontalAlign == CMlControl::AlignHorizontal::HCenter) {
				Pos.X += (Tooltip_BoundingBox.Size.X / 2.);
			} else if (Tooltip_BoundingBox.HorizontalAlign == CMlControl::AlignHorizontal::Right) {
				Pos.X += (Tooltip_BoundingBox.Size.X);
			}
			
			if (Tooltip_BoundingBox.VerticalAlign == CMlControl::AlignVertical::Bottom) {
				Pos.Y -= Tooltip_BoundingBox.Size.Y;
			} else if (Tooltip_BoundingBox.VerticalAlign == CMlControl::AlignVertical::VCenter) {
				Pos.Y -= Tooltip_BoundingBox.Size.Y / 2.;
			}
		}
		
		if (Tooltip_BoundingBox != Null) {
			declare PosMax = <160., 90.>;
			declare PosMin = <-160., -90.>;
			
			if (Tooltip_BoundingBox.HorizontalAlign == CMlControl::AlignHorizontal::HCenter) {
				PosMax.X = ((160. - Tooltip_BoundingBox.Size.X / 2.) - Frame_Tooltip.AbsolutePosition.X) + Frame_Tooltip.RelativePosition.X;
				PosMin.X = ((-160. + Tooltip_BoundingBox.Size.X / 2.) - Frame_Tooltip.AbsolutePosition.X) + Frame_Tooltip.RelativePosition.X;
			} else if (Tooltip_BoundingBox.HorizontalAlign == CMlControl::AlignHorizontal::Right) {
				PosMin.X = ((-160. + Tooltip_BoundingBox.Size.X) - Frame_Tooltip.AbsolutePosition.X) + Frame_Tooltip.RelativePosition.X;
			} else {
				PosMax.X = ((160. - Tooltip_BoundingBox.Size.X) - Frame_Tooltip.AbsolutePosition.X) + Frame_Tooltip.RelativePosition.X;
			}
			
			if (Tooltip_BoundingBox.VerticalAlign == CMlControl::AlignVertical::VCenter) {
				PosMax.Y = ((90. - Tooltip_BoundingBox.Size.Y / 2.) - Frame_Tooltip.AbsolutePosition.Y) + Frame_Tooltip.RelativePosition.Y;
				PosMin.Y = ((-90. + Tooltip_BoundingBox.Size.Y / 2.) - Frame_Tooltip.AbsolutePosition.Y) + Frame_Tooltip.RelativePosition.Y;
			} else if (Tooltip_BoundingBox.VerticalAlign == CMlControl::AlignVertical::Bottom) {
				PosMax.Y = ((90. - Tooltip_BoundingBox.Size.Y) - Frame_Tooltip.AbsolutePosition.Y) + Frame_Tooltip.RelativePosition.Y;
			} else {
				PosMin.Y = ((-90. + Tooltip_BoundingBox.Size.Y) - Frame_Tooltip.AbsolutePosition.Y) + Frame_Tooltip.RelativePosition.Y;
			}
			
			if (Pos.X > PosMax.X) Pos.X = PosMax.X;
			if (Pos.X < PosMin.X) Pos.X = PosMin.X;
			if (Pos.Y > PosMax.Y) Pos.Y = PosMax.Y;
			if (Pos.Y < PosMin.Y) Pos.Y = PosMin.Y;
		}
			
		Frame_Tooltip.RelativePosition = Pos;
		Frame_Tooltip.Visible = True;
		if (Tooltip_Message != Null) Tooltip_Message.Value = _Text;
	}
}

Void LibManialink_TooltipHide(Text _Id) {
	Page.GetClassChildren("LibManialink_Tooltip", Page.MainFrame, True);
	foreach (Control in Page.GetClassChildren_Result) {
		if (Control.ControlId != _Id) continue;
		Control.Visible = False;
	}
}

Void LibManialink_TooltipLoop() {
	foreach (Event in PendingEvents) {
		if (Event.Type == CMlEvent::Type::MouseOver) {
			if (Event.Control.HasClass("LibManialink_TooltipShow")) {
				declare Text LibManialink_TooltipMessage for Event.Control;
				LibManialink_TooltipShow(Event.ControlId, Event.Control, LibManialink_TooltipMessage);
			}
		} else if (Event.Type == CMlEvent::Type::MouseOut) {
			if (Event.Control.HasClass("LibManialink_TooltipShow")) {
				LibManialink_TooltipHide(Event.ControlId);
			}
		}
	}
}

Void LibManialink_SetTooltipMessage(Text _Id, Text _Message) {
	Page.GetClassChildren("LibManialink_TooltipShow", Page.MainFrame, True);
	foreach (Control in Page.GetClassChildren_Result) {
		if (Control.ControlId != _Id) continue;
		declare Text LibManialink_TooltipMessage for Control;
		LibManialink_TooltipMessage = _Message;
	}
}
// ---------------------------------- //
// Tooltip Stop
// ---------------------------------- //
""";
}

// ---------------------------------- //
/** Draggable module
 *
 *	@return		The draggable module
 */
Text Private_Draggable() {
	return """
// ---------------------------------- //
// Draggable Start
// ---------------------------------- //
Real[] LibManialink_PrivateDraggableGetOffset(CMlControl _Control) {
	declare Offset = [0., 0., 0., 0.];
	if (_Control == Null) return Offset;
					
	if (_Control.HorizontalAlign == CMlControl::AlignHorizontal::HCenter) {
		Offset[0] -= _Control.Size.X / 2.;
		Offset[1] += _Control.Size.X / 2.;
	} else if (_Control.HorizontalAlign == CMlControl::AlignHorizontal::Right) {
		Offset[0] -= _Control.Size.X;
	} else {
		Offset[1] += _Control.Size.X;
	}
	
	if (_Control.VerticalAlign == CMlControl::AlignVertical::VCenter) {
		Offset[2] -= _Control.Size.Y / 2.;
		Offset[3] += _Control.Size.Y / 2.;
	} else if (_Control.VerticalAlign == CMlControl::AlignVertical::Bottom) {
		Offset[3] += _Control.Size.Y;
	} else {
		Offset[2] -= _Control.Size.Y;
	}
	
	return Offset;
}

Void LibManialink_DraggableLoop() {
	declare Boolean LibManialink_DragMouseLeftButton for Page;
	declare Boolean LibManialink_IsDragging for Page;
	declare Text LibManialink_Draggable for Page;
	declare CMlControl[Integer] LibManialink_Dragging for Page;
	declare Real[] LibManialink_DragLimit for Page;
	declare CMlControl LibManialink_DragBoundingBox for Page;
	declare Real[] LibManialink_DragBoundingBoxOffset for Page;
	
	if (LibManialink_DragMouseLeftButton != MouseLeftButton) {
		LibManialink_DragMouseLeftButton = MouseLeftButton;
		
		if (MouseLeftButton && LibManialink_Draggable != "") {
			LibManialink_IsDragging = True;
			LibManialink_Dragging.clear();
			LibManialink_DragLimit = [-160., 160., -90., 90.];
			LibManialink_DragBoundingBox = Null;
			
			Page.GetClassChildren("LibManialink_Draggable", Page.MainFrame, True);
			foreach (Key => Control in Page.GetClassChildren_Result) {
				if (Control.ControlId == LibManialink_Draggable) {
					declare Vec2 LibManialink_DragOffset for Control;
					LibManialink_DragOffset = <Control.RelativePosition.X - MouseX, Control.RelativePosition.Y - MouseY>;
					LibManialink_Dragging[Key] = Control;
				}
			}
			
			Page.GetClassChildren("LibManialink_DraggableArea", Page.MainFrame, True);
			foreach (Control in Page.GetClassChildren_Result) {
				if (Control.ControlId == LibManialink_Draggable) {
					LibManialink_DragLimit = [Control.AbsolutePosition.X, Control.AbsolutePosition.X, Control.AbsolutePosition.Y, Control.AbsolutePosition.Y];
					declare Offset = LibManialink_PrivateDraggableGetOffset(Control);
					
					for (I, 0, 3) {
						LibManialink_DragLimit[I] += Offset[I];
					}
					
					break;
				}
			}
			
			Page.GetClassChildren("LibManialink_DraggableBoundingBox", Page.MainFrame, True);
			foreach (Control in Page.GetClassChildren_Result) {
				if (Control.ControlId == LibManialink_Draggable) {
					LibManialink_DragBoundingBox = Control;
					LibManialink_DragBoundingBoxOffset = LibManialink_PrivateDraggableGetOffset(Control);
					
					break;
				}
			}
		} else {
			LibManialink_IsDragging = False;
			LibManialink_Dragging.clear();
		}
	}
	
	foreach (Event in PendingEvents) {
		if (Event.Type == CMlEvent::Type::MouseOver) {
			if (Event.Control.HasClass("LibManialink_DraggableHandle")) {
				LibManialink_Draggable = Event.ControlId;
			} else {
				LibManialink_Draggable = "";
			}
		} else if (Event.Type == CMlEvent::Type::MouseOut) {
			LibManialink_Draggable = "";
		}
	}
	
	if (LibManialink_IsDragging && LibManialink_Dragging.count > 0) {
		foreach (Control in LibManialink_Dragging) {
			declare Vec2 LibManialink_DragOffset for Control;
			Control.RelativePosition.X = MouseX + LibManialink_DragOffset.X;
			Control.RelativePosition.Y = MouseY + LibManialink_DragOffset.Y;
		}
		
		if (LibManialink_DragBoundingBox != Null) {
			declare Box = [
				LibManialink_DragBoundingBox.AbsolutePosition.X + LibManialink_DragBoundingBoxOffset[0],
				LibManialink_DragBoundingBox.AbsolutePosition.X + LibManialink_DragBoundingBoxOffset[1],
				LibManialink_DragBoundingBox.AbsolutePosition.Y + LibManialink_DragBoundingBoxOffset[2],
				LibManialink_DragBoundingBox.AbsolutePosition.Y + LibManialink_DragBoundingBoxOffset[3]
			];
			declare Shift = <0., 0.>;
			if (Box[0] < LibManialink_DragLimit[0]) Shift.X += LibManialink_DragLimit[0] - Box[0];
			if (Box[1] > LibManialink_DragLimit[1]) Shift.X += LibManialink_DragLimit[1] - Box[1];
			if (Box[2] < LibManialink_DragLimit[2]) Shift.Y += LibManialink_DragLimit[2] - Box[2];
			if (Box[3] > LibManialink_DragLimit[3]) Shift.Y += LibManialink_DragLimit[3] - Box[3];
			
			foreach (Control in LibManialink_Dragging) {
				Control.RelativePosition.X += Shift.X;
				Control.RelativePosition.Y += Shift.Y;
			}
		}
	}
}
// ---------------------------------- //
// Draggable Stop
// ---------------------------------- //
""";
}

// ---------------------------------- //
// Public
// ---------------------------------- //

// ---------------------------------- //
/** Return the version number of the script
 *
 *	@return		The version number of the script
 */
Text GetScriptVersion() {
	return Version;
}

// ---------------------------------- //
/** Return the name of the script
 *
 *	@return		The name of the script
 */
Text GetScriptName() {
	return ScriptName;
}

// ---------------------------------- //
/** Insert the #Include statement at the beginning of your maniascript
 *
 *	@return		One include
 */
Text Include(Text _Path, Text _Namespace) {
	return """#Include "{{{_Path}}}" as {{{_Namespace}}}""";
}

// ---------------------------------- //
/** Insert the #Include statements at the beginning of your maniascript
 *
 *	@return		Several includes
 */
Text Includes(Text[Text] _Libs) {
	declare Includes = "";
	foreach (Path => Namespace in _Libs) {
		Includes ^= Include(Path, Namespace)^"""
""";
	}
	return Includes;
}

// ---------------------------------- //
/** Insert a function inside your maniascript
 *
 *	@return		The function
 */
Text Function(Text _FunctionName) {	
	switch (_FunctionName) {
		case "EaseLinear"		: return Private_EaseLinear();
		case "EaseInQuad"		: return Private_EaseInQuad();
		case "EaseOutQuad"		: return Private_EaseOutQuad();
		case "EaseInOutQuad"	: return Private_EaseInOutQuad();
		case "EaseInCubic"		: return Private_EaseInCubic();
		case "EaseOutCubic"		: return Private_EaseOutCubic();
		case "EaseInOutCubic"	: return Private_EaseInOutCubic();
		case "EaseInQuart"		: return Private_EaseInQuart();
		case "EaseOutQuart"		: return Private_EaseOutQuart();
		case "EaseInOutQuart"	: return Private_EaseInOutQuart();
		case "EaseInQuint"		: return Private_EaseInQuint();
		case "EaseOutQuint"		: return Private_EaseOutQuint();
		case "EaseInOutQuint"	: return Private_EaseInOutQuint();
		case "EaseInSine"		: return Private_EaseInSine();
		case "EaseOutSine"		: return Private_EaseOutSine();
		case "EaseInOutSine"	: return Private_EaseInOutSine();
		case "EaseInExp"		: return Private_EaseInExp();
		case "EaseOutExp"		: return Private_EaseOutExp();
		case "EaseInOutExp"		: return Private_EaseInOutExp();
		case "EaseInCirc"		: return Private_EaseInCirc();
		case "EaseOutCirc"		: return Private_EaseOutCirc();
		case "EaseInOutCirc"	: return Private_EaseInOutCirc();
		case "EaseInBack"		: return Private_EaseInBack();
		case "EaseOutBack"		: return Private_EaseOutBack();
		case "EaseInOutBack"	: return Private_EaseInOutBack();
		case "EaseInElastic"	: return Private_EaseInElastic();
		case "EaseOutElastic"	: return Private_EaseOutElastic();
		case "EaseInOutElastic"	: return Private_EaseInOutElastic();
		case "EaseInBounce"		: return Private_EaseInBounce();
		case "EaseOutBounce"	: return Private_EaseOutBounce();
		case "EaseInOutBounce"	: return Private_EaseInOutBounce();
		case "Anim"				: return Private_Anim();
		case "AnimPause"		: return Private_AnimPause();
		case "AnimPlay"			: return Private_AnimPlay();
		case "AnimRepeat"		: return Private_AnimRepeat();
		case "IsAnimated"		: return Private_IsAnimated();
		case "AnimLoop"			: return Private_AnimLoop();
		case "Tooltip"			: return Private_Tooltip();
		case "Draggable"		: return Private_Draggable();
	}
	
	return "";
}

// ---------------------------------- //
/** Insert several functions inside your maniascript
 *
 *	@return		The functions
 */
Text Functions(Text[] _FunctionsNames) {
	declare FunctionsContent = "";
	foreach (FunctionName in _FunctionsNames) {
		FunctionsContent ^= Function(FunctionName);
	}
	return FunctionsContent;
}

// ---------------------------------- //
/** Insert the tween module inside your maniascript
 *
 *	@param	_Easings		An array of easing functions to insert in the tween module
 *
 *	@return		The tween module with the given easing functions
 */
Text Tweens(Text[] _Easings) {
	declare Functions = _Easings;
	if (!Functions.exists("EaseLinear")) Functions.add("EaseLinear");
	return """
// ---------------------------------- //
// Easing and Tweens Start
// ---------------------------------- //
"""^Functions(Functions)^Private_Tween(_Easings)^"""
// ---------------------------------- //
// Easings and Tweens Stop
// ---------------------------------- //
""";
}

// ---------------------------------- //
/** Insert the animation module inside your maniascript
 *
 *	@param	_Easings		An array of easing functions to insert in the animation module
 *
 *	@return		The animation module with the given easing functions
 */
Text Animations(Text[] _Easings) {
	return """
// ---------------------------------- //
// Animations Start
// ---------------------------------- //
"""^Function("Anim")^Tweens(_Easings)^Function("AnimLoop")^"""
// ---------------------------------- //
// Animations Stop
// ---------------------------------- //
""";
}

// ---------------------------------- //
/** Insert the animation module inside your maniascript
 *
 *	@return		The animation module without any easing function
 */
Text Animations() {
	return Animations(Text[]);
}

// ---------------------------------- //
/** Inject a Text between """ """ in your manialink
 *
 *	@param	_In		The Text to inject
 *
 *	@return		The Text
 */
Text Inject(Text _In) {
	declare Out = "\"\"\"";
	Out ^= _In;
	Out ^= "\"\"\"";
	return Out;
}

// ---------------------------------- //
/** Create a tooltip frame
 *
 *	@param	_Id			The id of the tooltip
 *	@param	_Size		The size of the tooltip
 *	@param	_LinesNb	The number of text lines in the tooltip
 *
 *	@return		The tooltip manialink frame
 */
Text Tooltip(Text _Id, Vec2 _Size, Integer _LinesNb) {
	declare Autonewline = 0;
	return """
<frame hidden="1" class="LibManialink_Tooltip" id="{{{_Id}}}">
	<label posn="0 0 1" sizen="{{{_Size.X - 2.}}} {{{_Size.Y - 2.}}}" halign="center" valign="center2" autonewline="{{{Autonewline}}}" maxline="{{{_LinesNb}}}" textsize="1.5" textcolor="aaa" id="Tooltip_Message" />
	<quad sizen="{{{_Size.X}}} {{{_Size.Y}}}" halign="center" valign="center" bgcolor="000d" id="Tooltip_BoundingBox" />
</frame>
""";
}

// ---------------------------------- //
/** Create the default tooltip frame
 *
 *	@param	_Id			The id of the tooltip
 *
 *	@return		The tooltip manialink frame
 */
Text Tooltip(Text _Id) {
	return Tooltip(_Id, <50., 6.>, 1);
}

// ---------------------------------- //
/** Dump all the functions of the library
 *
 *	@return		The complete library
 */
Text DumpLib() {
	return Includes(["MathLib" => "ML", "TextLib" => "TL"])^Functions(["AnimPause", "AnimPlay", "AnimRepeat", "IsAnimated", "Tooltip", "Draggable"])^Animations(["EaseLinear", "EaseInQuad", "EaseOutQuad", "EaseInOutQuad", "EaseInCubic", "EaseOutCubic", "EaseInOutCubic", "EaseInQuart", "EaseOutQuart", "EaseInOutQuart", "EaseInQuint", "EaseOutQuint", "EaseInOutQuint", "EaseInSine", "EaseOutSine", "EaseInOutSine", "EaseInExp", "EaseOutExp", "EaseInOutExp", "EaseInCirc", "EaseOutCirc", "EaseInOutCirc", "EaseInBack", "EaseOutBack", "EaseInOutBack", "EaseInElastic", "EaseOutElastic", "EaseInOutElastic", "EaseInBounce", "EaseOutBounce", "EaseInOutBounce"]);
}