﻿// Slide.Show, version 1.0
// Copyright © Vertigo Software, Inc.
// This source is subject to the Microsoft Public License (Ms-PL).
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx.
// All other rights reserved.

/// <reference path="SlideShow.js" />

/*******************************************
 * class: SlideShow.Button
 *******************************************/
SlideShow.Button = function(control, parent, xaml)
{
	/// <summary>Provides a base class for button controls.</summary>
	/// <param name="control">The Slide.Show control.</param>
	/// <param name="parent">The parent control.</param>
	/// <param name="xaml">The XAML for the button.</param>
	
	SlideShow.Button.base.constructor.call(this, control, parent, xaml);
	
	SlideShow.merge(this.options,
	{
		width: 22,
		height: 20,
		cursor: "Hand"
	});
	
	this.state = "Default";
	
	this.root.addEventListener("MouseEnter", SlideShow.createDelegate(this, this.onMouseEnter));
	this.root.addEventListener("MouseLeave", SlideShow.createDelegate(this, this.onMouseLeave));
	this.root.addEventListener("MouseLeftButtonDown", SlideShow.createDelegate(this, this.onMouseDown));
	this.root.addEventListener("MouseLeftButtonUp", SlideShow.createDelegate(this, this.onMouseUp));	
};

SlideShow.extend(SlideShow.UserControl, SlideShow.Button,
{
	render: function()
	{
		/// <summary>Renders the button using the current options.</summary>
		
		SlideShow.Button.base.render.call(this);
		
		this.root.cursor = this.options.cursor;
	},
	
	setState: function(state)
	{
		/// <summary>Sets the state of the button.</summary>
		/// <param name="state">The new state.</param>
		
		this.state = state;
		
		switch (state)
		{
			case "Disabled":
				this.root.cursor = "Default";
				break;	
			
			default:	
				this.root.cursor = this.options.cursor;
				break;
		}
	},
	
	enable: function()
	{
		/// <summary>Enables the button.</summary>
		
		if (this.state == "Disabled")
			this.setState("Default");
	},
	
	disable: function()
	{
		/// <summary>Disables the button.</summary>
		
		if (this.state != "Disabled")
			this.setState("Disabled");
	},
	
	onMouseEnter: function(sender, e)
	{
		/// <summary>Handles the event fired when the mouse enters the button.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		if (this.state != "Disabled")
			this.setState((this.state.indexOf("Active") > -1) ? "ActiveHover" : "Hover");
	},
	
	onMouseLeave: function(sender, e)
	{
		/// <summary>Handles the event fired when the mouse leaves the button.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		if (this.state != "Disabled")
			this.setState((this.state.indexOf("Active") > -1) ? "ActiveUnhover" : "Unhover");
	},
	
	onMouseDown: function(sender, e)
	{
		/// <summary>Handles the event fired when the mouse button is pressed.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		if (this.state != "Disabled")
		{
			this.setState((this.state.indexOf("Hover") > -1) ? "ActiveHover" : "Default");
			sender.captureMouse();
		}
	},
	
	onMouseUp: function(sender, e)
	{
		/// <summary>Handles the event fired when the mouse button is released.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		if (this.state != "Disabled")
		{
			var isClick = (this.state == "ActiveHover");
			this.setState((this.state.indexOf("Hover") > -1) ? "InactiveHover" : "Default");
			sender.releaseMouseCapture();
			
			if (isClick)
				this.onClick(e);
		}
	},
	
	onClick: function(e)
	{
		/// <summary>Handles the event fired when the button is clicked.</summary>
		/// <param name="e">The event arguments.</param>
		
		if (this.state != "Disabled")
			this.fireEvent("click", e);
	}
});

/*******************************************
 * class: SlideShow.PathButton
 *******************************************/
SlideShow.PathButton = function(control, parent, options)
{
	/// <summary>A path button control.</summary>
	/// <param name="control">The Slide.Show control.</param>
	/// <param name="parent">The parent control.</param>
	/// <param name="options">The options for the button.</param>
	
	var xaml =
		'<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="PathButton" Visibility="Collapsed">' +
		'	<Canvas.Resources>' +
		'		<Storyboard x:Name="HoverStoryboard">' +
		'			<ColorAnimationUsingKeyFrames Storyboard.TargetName="Path" Storyboard.TargetProperty="(Fill).(Color)">' +
		'				<LinearColorKeyFrame x:Name="HoverKeyFrame" />' +	
		'			</ColorAnimationUsingKeyFrames>' +
		'		</Storyboard>' +
		'	</Canvas.Resources>' +
		'	<Canvas.Clip>' +
		'		<RectangleGeometry x:Name="Clip" />' +
		'	</Canvas.Clip>' +
		'	<Rectangle x:Name="Background">' +
		'		<Rectangle.Fill>' +
		'			<LinearGradientBrush StartPoint="0.477254,1.16548" EndPoint="0.477254,0.0426189">' +
		'				<LinearGradientBrush.GradientStops>' +
		'					<GradientStop x:Name="BackgroundColor1" Offset="0.232877" />' +
		'					<GradientStop x:Name="BackgroundColor2" Offset="0.987288" />' +
		'				</LinearGradientBrush.GradientStops>' +
		'			</LinearGradientBrush>' +
		'		</Rectangle.Fill>' +
		'	</Rectangle>' +
		'	<Path x:Name="Path" />' +
		'</Canvas>';
	
	SlideShow.PathButton.base.constructor.call(this, control, parent, xaml);
	
	SlideShow.merge(this.options,
	{
		radius: 2,
		stroke: "#7F808BBC",
		strokeThickness: 1,
		backgroundColor1: "#273B5B",
		backgroundColor2: "#6A75A2",
		pathData: null,
		pathWidth: 10,
		pathHeight: 10,
		pathStretch: "Uniform",
		pathFill: "#BDC3DF",
		pathFillHover: "White",
		pathFillDisabled: "#6A75A2",
		hoverAnimationDuration: 0.2
	});
	
	this.setOptions(options);
	
	this.hoverStoryboard = this.root.findName("HoverStoryboard");
	this.hoverKeyFrame = this.root.findName("HoverKeyFrame");
	this.clip = this.root.findName("Clip");
	this.background = this.root.findName("Background");
	this.backgroundColor1 = this.root.findName("BackgroundColor1");
	this.backgroundColor2 = this.root.findName("BackgroundColor2");
	this.path = this.root.findName("Path");	
};

SlideShow.extend(SlideShow.Button, SlideShow.PathButton,
{
	render: function()
	{
		/// <summary>Renders the button using the current options.</summary>
		
		SlideShow.PathButton.base.render.call(this);
		
		// hover
		this.hoverKeyFrame.keyTime = SlideShow.formatString("0:0:{0}", this.options.hoverAnimationDuration);
		
		// clip
		this.clip.rect = SlideShow.formatString("0,0,{0},{1}", this.options.width, this.options.height);
		this.clip.radiusX = this.options.radius;
		this.clip.radiusY = this.options.radius;
		
		// background
		this.background.width = this.options.width;
		this.background.height = this.options.height;
		this.background.radiusX = this.options.radius;
		this.background.radiusY = this.options.radius;
		this.background.stroke = this.options.stroke;
		this.background.strokeThickness = this.options.strokeThickness;
		this.backgroundColor1.color = this.options.backgroundColor1;
		this.backgroundColor2.color = this.options.backgroundColor2;
		
		// path
		this.path.data = this.options.pathData;
		this.path.width = this.options.pathWidth;
		this.path.height = this.options.pathHeight;
		this.path.stretch = this.options.pathStretch;
		this.path.fill = this.options.pathFillDisabled;
		this.path["Canvas.Top"] = this.options.height / 2 - this.options.pathHeight / 2;
		this.path["Canvas.Left"] = this.options.width / 2 - this.options.pathWidth / 2;
		
		// disable by default
		this.disable();
	},
	
	setState: function(state)
	{
		/// <summary>Sets the button state.</summary>
		/// <param name="state">The new state.</param>
		
		SlideShow.PathButton.base.setState.call(this, state);
		
		switch (state)
		{
			case "Hover":
			case "ActiveHover":
			case "InactiveHover":
				this.hoverKeyFrame.value = this.options.pathFillHover;
				this.hoverStoryboard.begin();
				break;
				
			case "Disabled":
				this.hoverKeyFrame.value = this.options.pathFillDisabled;
				this.hoverStoryboard.begin();
				break;
			
			default:
				this.hoverKeyFrame.value = this.options.pathFill;
				this.hoverStoryboard.begin();
				break;
		}
	},
	
	setPath: function(data, width, height)
	{
		/// <summary>Sets the button path dynamically.</summary>
		/// <param name="data">The path data.</param>
		/// <param name="width">The width of the path.</param>
		/// <param name="height">The height of the path.</param>
		
		this.path.data = data;
		this.path.width = width || this.options.pathWidth;
		this.path.height = height || this.options.pathHeight;
		this.path["Canvas.Top"] = this.root.height / 2 - this.path.height / 2;
		this.path["Canvas.Left"] = this.root.width / 2 - this.path.width / 2;
	}
});

/*******************************************
 * class: SlideShow.AlbumButton
 *******************************************/
SlideShow.AlbumButton = function(control, parent, album, options)
{
	/// <summary>An album button control.</summary>
	/// <param name="control">The Slide.Show control.</param>
	/// <param name="parent">The parent control.</param>
	/// <param name="options">The options for the button.</param>
	/// <param name="album">The target album.</param>
	
	var xaml =
		'<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="AlbumButton" Visibility="Collapsed">' +
		'	<Canvas.Resources>' +
		'		<Storyboard x:Name="HoverStoryboard">' +
		'			<ColorAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="(Fill).(Color)">' +
		'				<LinearColorKeyFrame x:Name="HoverKeyFrame" />' +	
		'			</ColorAnimationUsingKeyFrames>' +
		'		</Storyboard>' +
		'		<Storyboard x:Name="LoadStoryboard" Storyboard.TargetName="Image" Storyboard.TargetProperty="Opacity">' +
		'			<DoubleAnimation x:Name="LoadAnimation" To="1" />' +
		'		</Storyboard>' +		
		'	</Canvas.Resources>' +
		'	<Canvas.Clip>' +
		'		<RectangleGeometry x:Name="Clip" />' +
		'	</Canvas.Clip>' +
		'	<Rectangle x:Name="Background" />' +
		'	<Rectangle x:Name="ImageBackground" />' +
		'	<Rectangle x:Name="Image" Opacity="0">' +
		'		<Rectangle.Fill>' +
		'			<ImageBrush x:Name="ImageBrush" />' +
		'		</Rectangle.Fill>' +
		'	</Rectangle>' +
		'	<TextBlock x:Name="TitleTextBlock" TextWrapping="Wrap" />' +
		'	<TextBlock x:Name="DescriptionTextBlock" TextWrapping="Wrap" />' +
		'</Canvas>';
	
	SlideShow.AlbumButton.base.constructor.call(this, control, parent, xaml);
	
	SlideShow.merge(this.options,
	{
		background: "#222",
		backgroundHover: "#333",
		hoverAnimationDuration: 0.2,
		loadAnimationDuration: 0.5,
		radius: 4,
		stroke: "#333",
		strokeThickness: 1,
		imageWidth: 75,
		imageHeight: 60,
		imagePaddingTop: 6,
		imagePaddingLeft: 6,
		imageBackground: "#777",
		imageSource: null,
		imageStretch: "UniformToFill",
		imageRadius: 0,
		imageStroke: "#333",
		imageStrokeThickness: 1,
		titleWidth: 126,
		titleHeight: 20,
		titlePaddingTop: 4,
		titlePaddingLeft: 6,
		titleFontFamily: "Portable User Interface",
		titleFontSize: 12,
		titleFontStretch: "Normal",
		titleFontStyle: "Normal",
		titleFontWeight: "Bold",
		titleForeground: "White",
		descriptionWidth: 126,
		descriptionHeight: 52,
		descriptionPaddingTop: 0,
		descriptionPaddingLeft: 6,
		descriptionFontFamily: "Portable User Interface",
		descriptionFontSize: 10,
		descriptionFontStretch: "Normal",
		descriptionFontStyle: "Normal",
		descriptionFontWeight: "Normal",
		descriptionForeground: "#777"
	});
	
	this.setOptions(options);
	
	this.album = album;
	this.hoverStoryboard = this.root.findName("HoverStoryboard");
	this.hoverKeyFrame = this.root.findName("HoverKeyFrame");
	this.loadStoryboard = this.root.findName("LoadStoryboard");
	this.loadAnimation = this.root.findName("LoadAnimation");		
	this.clip = this.root.findName("Clip");
	this.background = this.root.findName("Background");
	this.imageBackground = this.root.findName("ImageBackground");
	this.image = this.root.findName("Image");
	this.imageBrush = this.root.findName("ImageBrush");
	this.titleTextBlock = this.root.findName("TitleTextBlock");
	this.descriptionTextBlock = this.root.findName("DescriptionTextBlock");
};

SlideShow.extend(SlideShow.Button, SlideShow.AlbumButton,
{
	render: function()
	{
		/// <summary>Renders the button using the current options.</summary>
				
		SlideShow.AlbumButton.base.render.call(this);
		
		// image source
		if (!this.album)
			throw new Error("Album missing");
		else if (this.album.image)
			this.options.imageSource = this.album.image;
		else if (this.album.slide && this.album.slide.length)
			this.options.imageSource = this.album.slide[0].image;
		
		// clip
		this.clip.rect = SlideShow.formatString("0,0,{0},{1}", this.options.width, this.options.height);
		this.clip.radiusX = this.options.radius;
		this.clip.radiusY = this.options.radius;
		
		// background
		this.background.width = this.options.width;
		this.background.height = this.options.height;
		this.background.radiusX = this.options.radius;
		this.background.radiusY = this.options.radius;
		this.background.fill = this.options.background;
		this.background.stroke = this.options.stroke;
		this.background.strokeThickness = this.options.strokeThickness;
		
		// image background
		this.imageBackground.width = this.options.imageWidth;
		this.imageBackground.height = this.options.imageHeight;
		this.imageBackground["Canvas.Top"] = this.options.imagePaddingTop;
		this.imageBackground["Canvas.Left"] = this.options.imagePaddingLeft;
		this.imageBackground.radiusX = this.options.imageRadius;
		this.imageBackground.radiusY = this.options.imageRadius;
		this.imageBackground.fill = this.options.imageBackground;
		this.imageBackground.stroke = this.options.imageStroke;
		this.imageBackground.strokeThickness = this.options.imageStrokeThickness;
		
		// image
		this.image.width = this.options.imageWidth;
		this.image.height = this.options.imageHeight;
		this.image["Canvas.Top"] = this.options.imagePaddingTop;
		this.image["Canvas.Left"] = this.options.imagePaddingLeft;
		this.image.radiusX = this.options.imageRadius;
		this.image.radiusY = this.options.imageRadius;
		this.image.stroke = this.options.imageStroke;
		this.image.strokeThickness = this.options.imageStrokeThickness;
		this.imageBrush.stretch = this.options.imageStretch;
		this.imageBrush.imageSource = this.options.imageSource;
		
		// load animation
		if (this.imageBrush.downloadProgress == 1)
		{
			this.image.opacity = 1;
		}
		else
		{
			this.loadAnimation.duration = "0:0:" + this.options.loadAnimationDuration;
			this.imageBrush.addEventListener("DownloadProgressChanged", SlideShow.createDelegate(this, this.onImageDownloadProgressChanged));
			this.imageBrush.addEventListener("ImageFailed", SlideShow.createDelegate(this, this.onImageDownloadFailed));
		}
		
		// title
		this.titleTextBlock.width = this.options.titleWidth;
		this.titleTextBlock.height = this.options.titleHeight;
		this.titleTextBlock["Canvas.Top"] = this.options.titlePaddingTop;
		this.titleTextBlock["Canvas.Left"] = (this.options.imageWidth > 0) ? this.options.imagePaddingLeft + this.options.imageWidth + this.options.titlePaddingLeft : this.options.titlePaddingLeft;
		this.titleTextBlock.fontFamily = this.options.titleFontFamily;
		this.titleTextBlock.fontSize = this.options.titleFontSize;
		this.titleTextBlock.fontStretch = this.options.titleFontStretch;
		this.titleTextBlock.fontStyle = this.options.titleFontStyle;
		this.titleTextBlock.fontWeight = this.options.titleFontWeight;
		this.titleTextBlock.foreground = this.options.titleForeground;
		SlideShow.addTextToBlock(this.titleTextBlock, this.album.title);
		
		// description
		this.descriptionTextBlock.width = this.options.descriptionWidth;
		this.descriptionTextBlock.height = this.options.descriptionHeight;
		this.descriptionTextBlock["Canvas.Top"] = (this.options.titleHeight > 0) ? this.options.titlePaddingTop + this.options.titleHeight + this.options.descriptionPaddingTop : this.options.descriptionPaddingTop;
		this.descriptionTextBlock["Canvas.Left"] = (this.options.imageWidth > 0) ? this.options.imagePaddingLeft + this.options.imageWidth + this.options.descriptionPaddingLeft : this.options.descriptionPaddingLeft;
		this.descriptionTextBlock.fontFamily = this.options.descriptionFontFamily;
		this.descriptionTextBlock.fontSize = this.options.descriptionFontSize;
		this.descriptionTextBlock.fontStretch = this.options.descriptionFontStretch;
		this.descriptionTextBlock.fontStyle = this.options.descriptionFontStyle;
		this.descriptionTextBlock.fontWeight = this.options.descriptionFontWeight;
		this.descriptionTextBlock.foreground = this.options.descriptionForeground;
		SlideShow.addTextToBlock(this.descriptionTextBlock, this.album.description);
		
		// hover animation
		this.hoverKeyFrame.keyTime = SlideShow.formatString("0:0:{0}", this.options.hoverAnimationDuration);
	},
	
	setState: function(state)
	{
		/// <summary>Sets the button state.</summary>
		/// <param name="state">The new state.</param>
		
		SlideShow.AlbumButton.base.setState.call(this, state);
		
		switch (state)
		{
			case "Hover":
			case "ActiveHover":
			case "InactiveHover":
				this.hoverKeyFrame.value = this.options.backgroundHover;
				this.hoverStoryboard.begin();
				break;
			
			default:
				this.hoverKeyFrame.value = this.options.background;
				this.hoverStoryboard.begin();
				break;
		}
	},
	
	onImageDownloadProgressChanged: function(sender, e)
	{
		/// <summary>Handles the event fired while the image is downloading.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		if (sender.downloadProgress == 1)
			this.loadStoryboard.begin();
	},
	
	onImageDownloadFailed: function(sender, e)
	{
		/// <summary>Handles the event fired when the image failed to download.</summary>
		/// <param name="sender">The event soure.</param>
		/// <param name="e">The event arguments.</param>
		
		throw new Error("Image download failed: " + this.imageBrush.imageSource);
	},
	
	onClick: function(e)
	{
		/// <summary>Handles the event fired when the button is clicked.</summary>
		/// <param name="e">The event arguments.</param>
		
		SlideShow.AlbumButton.base.onClick.call(this, this.album);
	}
});

/*******************************************
 * class: SlideShow.ThumbnailButton
 *******************************************/
SlideShow.ThumbnailButton = function(control, parent, slide, options)
{
	/// <summary>A thumbnail button control.</summary>
	/// <param name="control">The Slide.Show control.</param>
	/// <param name="parent">The parent control.</param>
	/// <param name="slide">The target slide.</param>
	/// <param name="options">The options for the button.</param>
	
	var xaml =
		'<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="ThumbnailButton" Visibility="Collapsed">' +
		'	<Canvas.Resources>' +
		'		<Storyboard x:Name="LoadStoryboard" Storyboard.TargetName="Image" Storyboard.TargetProperty="Opacity">' +
		'			<DoubleAnimation x:Name="LoadAnimation" To="1" />' +
		'		</Storyboard>' +
		'	</Canvas.Resources>' +
		'	<Canvas.Clip>' +
		'		<RectangleGeometry x:Name="Clip" />' +
		'	</Canvas.Clip>' +
		'	<Rectangle x:Name="Background" />' +
		'	<Rectangle x:Name="Image" Opacity="0">' +
		'		<Rectangle.Fill>' +
		'			<ImageBrush x:Name="ImageBrush" />' +
		'		</Rectangle.Fill>' +
		'	</Rectangle>' +
		'</Canvas>';
	
	SlideShow.ThumbnailButton.base.constructor.call(this, control, parent, xaml);
	
	SlideShow.merge(this.options,
	{
		radius: 0,
		stroke: "Black",
		selectedStroke: "White",
		strokeThickness: 1,
		imageStretch: "UniformToFill",
		imageBackground: "#333",
		loadAnimationDuration: 0.5
	});
	
	this.setOptions(options);
	
	this.slide = slide;
	this.isSelected = false;
	this.loadStoryboard = this.root.findName("LoadStoryboard");
	this.loadAnimation = this.root.findName("LoadAnimation");
	this.clip = this.root.findName("Clip");
	this.background = this.root.findName("Background");
	this.image = this.root.findName("Image");
	this.imageBrush = this.root.findName("ImageBrush");
};

SlideShow.extend(SlideShow.Button, SlideShow.ThumbnailButton,
{
	render: function()
	{
		/// <summary>Renders the button using the current options.</summary>
		
		SlideShow.ThumbnailButton.base.render.call(this);
		
		// clip
		this.clip.rect = SlideShow.formatString("0,0,{0},{1}", this.options.width, this.options.height);
		this.clip.radiusX = this.options.radius;
		this.clip.radiusY = this.options.radius;
		
		// background
		this.background.width = this.options.width;
		this.background.height = this.options.height;
		this.background.radiusX = this.options.radius;
		this.background.radiusY = this.options.radius;
		this.background.fill = this.options.imageBackground;
		this.background.stroke = this.isSelected ? this.options.selectedStroke : this.options.stroke;
		this.background.strokeThickness = this.options.strokeThickness;
		
		// image
		this.image.width = this.options.width;
		this.image.height = this.options.height;
		this.image.radiusX = this.options.radius;
		this.image.radiusY = this.options.radius;
		this.image.stroke = this.isSelected ? this.options.selectedStroke : this.options.stroke;
		this.image.strokeThickness = this.options.strokeThickness;
		this.imageBrush.stretch = this.options.imageStretch;
		this.imageBrush.imageSource = this.getThumbnailImageSource();
		
		// load animation
		if (this.imageBrush.downloadProgress == 1)
		{
			this.image.opacity = 1;
		}
		else
		{
			this.loadAnimation.duration = "0:0:" + this.options.loadAnimationDuration;
			this.imageBrush.addEventListener("DownloadProgressChanged", SlideShow.createDelegate(this, this.onImageDownloadProgressChanged));
			this.imageBrush.addEventListener("ImageFailed", SlideShow.createDelegate(this, this.onImageDownloadFailed));
		}
	},
	
	getThumbnailImageSource: function()
	{
		/// <summary>Retrieves the appropriate thumbnail image for the button.</summary>
		/// <returns>The thumbnail image source.</returns>
		
		return this.slide.thumbnail || this.slide.image;
	},

	onSlideLoading: function(sender, e)
	{
		/// <summary>Handles the event fired when a new slide begins downloading.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		this.isSelected = e == this.slide;
		this.background.stroke = this.isSelected ? this.options.selectedStroke : this.options.stroke;
		this.image.stroke = this.isSelected ? this.options.selectedStroke : this.options.stroke;
	},
	
	onMouseEnter: function(sender, e)
	{
		/// <summary>Handles the event fired when the mouse enters the button.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		SlideShow.ThumbnailButton.base.onMouseEnter.call(this, sender, e);
		this.fireEvent("mouseEnter", this.isSelected);
	},
	
	onMouseLeave: function(sender, e)
	{
		/// <summary>Handles the event fired when the mouse leaves the button.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		SlideShow.ThumbnailButton.base.onMouseLeave.call(this, sender, e);
		this.fireEvent("mouseLeave", this.isSelected);
	},
	
	onImageDownloadProgressChanged: function(sender, e)
	{
		/// <summary>Handles the event fired while the image is downloading.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		if (sender.downloadProgress == 1)
			this.loadStoryboard.begin();
	},
	
	onImageDownloadFailed: function(sender, e)
	{
		/// <summary>Handles the event fired when the image failed to download.</summary>
		/// <param name="sender">The event soure.</param>
		/// <param name="e">The event arguments.</param>
		
		throw new Error("Image download failed: " + this.imageBrush.imageSource);
	},
	
	onClick: function(e)
	{
		/// <summary>Handles the event fired when the button is clicked.</summary>
		/// <param name="e">The event arguments.</param>
		
		SlideShow.ThumbnailButton.base.onClick.call(this, this.slide);
	}
});
