|
using System;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace SilverlightProject1.Controls
{
internal enum ActionType { Selecting, Moving, RotatingScaling };
/// <summary>
/// Provides a Microsoft Surface like Canvas, where <see cref="Photo">Photos</see>
/// may be resized and dragged/rotated/and removed
/// </summary>
public class ImageCanvas : Canvas
{
#region Instance fields
private Photo _activePhoto;
private Photo _pendingPhoto;
private ActionType _actionType;
private Point _photoCenter;
private Point _lastPosition;
private SilverlightProject1.FlickrService.PhotoInfo[] _Photos;
public static bool RemoveArtWorkOnPhotoAdd=false;
private ArtyCanvas _ac;
#endregion
#region Ctor
public ImageCanvas()
{
this.SetValue(Canvas.BackgroundProperty, Color.FromRgb(210, 223, 232));
this.SetValue(Canvas.WidthProperty, 1000);
this.SetValue(Canvas.HeightProperty, 800);
// Hook up event handlers
BrowserHost.Resize += new EventHandler(BrowserHost_Resize);
MouseLeftButtonUp += new MouseEventHandler(OnMouseLeftButtonUpOrLeave);
MouseLeave += new EventHandler(OnMouseLeftButtonUpOrLeave);
MouseMove += new MouseEventHandler(OnMouseMove);
CreateArtyCanvas();
}
#endregion
#region Public properties/methods
public void AddPhoto(SilverlightProject1.FlickrService.PhotoInfo file)
{
if (ImageCanvas.RemoveArtWorkOnPhotoAdd)
this.Children.Remove(_ac);
new Photo(this, file);
_ac.Opacity = 0.3;
}
public double Left
{
get
{
return (double)GetValue(Canvas.LeftProperty);
}
set
{
SetValue(Canvas.LeftProperty, value);
}
}
public double Top
{
get
{
return (double)GetValue(Canvas.TopProperty);
}
set
{
SetValue(Canvas.TopProperty, value);
}
}
#endregion
#region Private/Internal properties/methods
private void BrowserHost_Resize(object sender, EventArgs e)
{
// Set size to host size
Width = BrowserHost.ActualWidth;
Height = (BrowserHost.ActualHeight - Constants.TOP_CANVAS_TOP_POS);
}
private void OnMouseLeftButtonUpOrLeave(object sender, EventArgs e)
{
if (null != _activePhoto)
{
// Tell the previously active photo to hide its controls (in case the mouse already left it)
Photo previouslyActivePhoto = _activePhoto;
_activePhoto = null;
previouslyActivePhoto.HideControls();
}
if (null != _pendingPhoto)
{
// Tell the pending photo (if any) to show its controls
_pendingPhoto.ShowControls();
_pendingPhoto = null;
}
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (null != _activePhoto)
{
// Perform the appropriate transform on the active photo
var position = e.GetPosition(null);
switch (_actionType)
{
case ActionType.Moving:
// Move it by the amount of the mouse move
_activePhoto.Translate(position.X - _lastPosition.X, position.Y - _lastPosition.Y);
break;
case ActionType.RotatingScaling:
// Rotate it according to the angle the mouse moved around the photo's center
var radiansToDegrees = 360 / (2 * Math.PI);
var lastAngle = Math.Atan2(_lastPosition.Y - _photoCenter.Y, _lastPosition.X - _photoCenter.X) * radiansToDegrees;
var currentAngle = Math.Atan2(position.Y - _photoCenter.Y, position.X - _photoCenter.X) * radiansToDegrees;
_activePhoto.Rotate(currentAngle - lastAngle);
// Scale it according to the distance the mouse moved relative to the photo's center
var lastLength = Math.Sqrt(Math.Pow(_lastPosition.Y - _photoCenter.Y, 2) + Math.Pow(_lastPosition.X - _photoCenter.X, 2));
var currentLength = Math.Sqrt(Math.Pow(position.Y - _photoCenter.Y, 2) + Math.Pow(position.X - _photoCenter.X, 2));
_activePhoto.Scale(currentLength / lastLength);
break;
}
_lastPosition = position;
}
}
private void CreateArtyCanvas()
{
_ac = new ArtyCanvas();
_ac.Left = 0;
_ac.Top = 0;
_ac.Opacity = 1.0;
this.Children.Add(_ac);
}
internal void SetActivePhoto(Photo photo, ActionType actionType, Point photoCenter, Point lastPosition)
{
if (null == _activePhoto)
{
// Set the active photo and note the relevant details
_activePhoto = photo;
_actionType = actionType;
_photoCenter = photoCenter;
_lastPosition = lastPosition;
// Bring the active photo to the top
Children.Remove(_activePhoto);
Children.Add(photo);
}
}
internal void RemovePhoto(Photo photo)
{
this.Children.Remove(photo);
if (ImageCanvas.RemoveArtWorkOnPhotoAdd)
{
if (this.Children.Count == 0 )
CreateArtyCanvas();
}
else if (this.Children.Contains(_ac) && this.Children.Count == 1)
_ac.Opacity = 1.0;
}
internal Photo GetActivePhoto()
{
return _activePhoto;
}
internal void SetPendingPhoto(Photo photo)
{
_pendingPhoto = photo;
}
#endregion
}
/// <summary>
/// Provides a resizable/draggable/rotatable Photo that may be placed on
/// a <see cref="ImageCanvas">ImageCanvas</see>. This classes uses the
/// <see cref="DisplayImage.ashx">DisplayImage.ashx</see> handler to fetch
/// the remote (not localost) image. In this case from Flickr
/// </summary>
internal class Photo : Control
{
#region Instance fields
private static Random _random = new Random();
private ImageCanvas _parent;
private FrameworkElement _root;
private Image _image;
private Image _imgClose;
private Canvas _allControls;
private RotateTransform _rotateTransform;
private ScaleTransform _scaleTransform;
private TranslateTransform _translateTransform;
private bool _mouseOver;
private string _imageUrl;
private Downloader _Downloader;
private SilverlightProject1.FlickrService.PhotoInfo _file;
#endregion
#region Ctor
public Photo(ImageCanvas parent, SilverlightProject1.FlickrService.PhotoInfo file)
{
// Load the control's XAML from the embedded resource
System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("SilverlightProject1.Controls.Photo.xaml");
_root = this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());
// Initialize
_parent = parent;
_file = file;
_Downloader = new Downloader();
_Downloader.Completed += new EventHandler(Downloader_Completed);
// Fetch elements from the loaded XAML
_image = _root.FindName("image") as Image;
_imgClose = _root.FindName("imgClose") as Image;
_imgClose.MouseLeftButtonUp += new MouseEventHandler(ImgClose_MouseLeftButtonUp);
TextBlock tb = _root.FindName("imgText") as TextBlock;
tb.Text = _file.Title.Length > 20 ? _file.Title.Substring(0, 20) + "..." : _file.Title;
_rotateTransform = _root.FindName("rotateTransform") as RotateTransform;
_scaleTransform = _root.FindName("scaleTransform") as ScaleTransform;
_translateTransform = _root.FindName("translateTransform") as TranslateTransform;
_allControls = _root.FindName("allControls") as Canvas;
Canvas translateControls = _root.FindName("translateControls") as Canvas;
Canvas rotateScaleControls = _root.FindName("rotateScaleControls") as Canvas;
_allControls.Opacity = 0;
_root.Visibility = Visibility.Collapsed;
// Hook up event handlers
_root.MouseLeftButtonDown += new MouseEventHandler(Root_MouseLeftButtonDown);
_allControls.MouseEnter += new MouseEventHandler(AllControls_MouseEnter);
_allControls.MouseLeave += new EventHandler(AllControls_MouseLeave);
translateControls.MouseLeftButtonDown += new MouseEventHandler(TranslateControls_MouseLeftButtonDown);
rotateScaleControls.MouseLeftButtonDown += new MouseEventHandler(RotateScaleControls_MouseLeftButtonDown);
// Position and rotate the photo randomly
Translate(_random.Next((int)(BrowserHost.ActualWidth - _root.Width)), _random.Next((int)((BrowserHost.ActualHeight - Constants.TOP_CANVAS_TOP_POS) - _root.Height)));
Rotate(_random.Next(-30, 30));
// Add the photo to the parent and play the display animation
_parent.Children.Add(this);
(_root.FindName("display") as Storyboard).Begin();
this.ImageUrl = GetPhotoUrl(_file);
}
#endregion
#region Public properties/methods
public string ImageUrl
{
get { return _imageUrl; }
set
{
_imageUrl = value;
if (!String.IsNullOrEmpty(_imageUrl) && _imageUrl.IndexOf("http") >= 0)
{
try
{
string url = value;
string fullImageUrl = "http://localhost:49505/WebSite1/DisplayImage.ashx?URL=" + url + "&Width=250";
Uri uri = new Uri(fullImageUrl, UriKind.Absolute);
_Downloader.Open("GET", uri);
_Downloader.Send();
}
catch (Exception ee)
{
string str = ee.ToString();
}
}
}
}
public void Translate(double deltaX, double deltaY)
{
_translateTransform.X += deltaX;
_translateTransform.Y += deltaY;
}
public void Rotate(double deltaAngle)
{
_rotateTransform.Angle += deltaAngle;
}
public void Scale(double deltaScale)
{
_scaleTransform.ScaleX *= deltaScale;
_scaleTransform.ScaleY *= deltaScale;
}
public void ShowControls()
{
if (_mouseOver)
{
// If the mouse is (still) over the photo
if (null == _parent.GetActivePhoto())
{
// No active photo, so this photo can show its controls
_allControls.Opacity = 0.4;
}
else
{
// Let the parent know this photo is ready to show its controls
_parent.SetPendingPhoto(this);
}
}
}
public void HideControls()
{
if (!_mouseOver && (this != _parent.GetActivePhoto()))
{
// If the mouse is not over the photo and it's not the active photo, hide its controls
_allControls.Opacity = 0;
}
}
#endregion
#region Private properties/methods
private string GetPhotoUrl(SilverlightProject1.FlickrService.PhotoInfo file)
{
return "http://farm" + file.Farm + ".static.flickr.com/" +
file.Server + "/" + file.Id + "_" +
file.Secret + "_m.jpg";
}
private void ImgClose_MouseLeftButtonUp(object sender, MouseEventArgs e)
{
_parent.RemovePhoto(this);
}
private void Downloader_Completed(object sender, EventArgs e)
{
_image.SetSource(_Downloader, null);
_root.Visibility = Visibility.Visible;
}
private void AllControls_MouseEnter(object sender, MouseEventArgs e)
{
_mouseOver = true;
ShowControls();
}
private void AllControls_MouseLeave(object sender, EventArgs e)
{
_mouseOver = false;
HideControls();
}
private void Root_MouseLeftButtonDown(object sender, MouseEventArgs e)
{
HandleMouseLeftButtonDown(ActionType.Selecting, e);
}
private void TranslateControls_MouseLeftButtonDown(object sender, MouseEventArgs e)
{
HandleMouseLeftButtonDown(ActionType.Moving, e);
}
private void RotateScaleControls_MouseLeftButtonDown(object sender, MouseEventArgs e)
{
HandleMouseLeftButtonDown(ActionType.RotatingScaling, e);
}
private void HandleMouseLeftButtonDown(ActionType actionType, MouseEventArgs e)
{
// Give the parent information about the new active photo
_parent.SetActivePhoto(this, actionType, new Point(_translateTransform.X + _rotateTransform.CenterX, _translateTransform.Y + _rotateTransform.CenterY), e.GetPosition(null));
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)
- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence
Both of these at Sussex University UK.
Award(s)
I am lucky enough to have won a few awards for Zany Crazy code articles over the years
- Microsoft C# MVP 2016
- Codeproject MVP 2016
- Microsoft C# MVP 2015
- Codeproject MVP 2015
- Microsoft C# MVP 2014
- Codeproject MVP 2014
- Microsoft C# MVP 2013
- Codeproject MVP 2013
- Microsoft C# MVP 2012
- Codeproject MVP 2012
- Microsoft C# MVP 2011
- Codeproject MVP 2011
- Microsoft C# MVP 2010
- Codeproject MVP 2010
- Microsoft C# MVP 2009
- Codeproject MVP 2009
- Microsoft C# MVP 2008
- Codeproject MVP 2008
- And numerous codeproject awards which you can see over at my blog