PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/SurfaceAcademy2009Toolkit/SurfaceCardsGameKit/Dispositions/FanDisposition.cs

#
C# | 399 lines | 297 code | 86 blank | 16 comment | 35 complexity | c63ad8aacd34b87cb32cdaa550c4d8fa MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using SurfaceCardsBoardLibrary.Interfaces;
  6. using System.Windows;
  7. using SurfaceCardsGameKit.Tools;
  8. using Microsoft.Surface.Presentation.Controls;
  9. using System.Windows.Media.Animation;
  10. using System.Windows.Media;
  11. using SurfaceCardsBoardLibrary;
  12. namespace SurfaceCardsGameKit.Dispositions
  13. {
  14. class FanDisposition : IDisposition
  15. {
  16. private List<DispositionOffset> _offsets;
  17. #region IDisposition Members
  18. public void Render(IDeck deck, Size cardSize, Rect destinationRect, Point center,
  19. double deckOrientation, bool useTransitions, bool sizeChanged, DeckOrientation deckupDownOrientation, double durationRatio)
  20. {
  21. if (!sizeChanged && _offsets != null)
  22. {
  23. int i = 0;
  24. foreach (var card in deck)
  25. {
  26. if (card.ScatterViewItem.Visibility == Visibility.Collapsed)
  27. continue;
  28. ActuallyMoveChilds(useTransitions, deck, card, _offsets[i], durationRatio);
  29. i++;
  30. }
  31. }
  32. else
  33. {
  34. // put in line
  35. if (cardSize.Width * deck.Count <= destinationRect.Width)
  36. {
  37. MoveChilds(deck, cardSize, destinationRect, 1, double.NaN, true, deckupDownOrientation, durationRatio);
  38. return;
  39. }
  40. var ratio = cardSize.Width / (destinationRect.Width * deck.Count);
  41. double angleDegree = ratio * 50;
  42. double radius = Math.Pow(destinationRect.Width, 3) * deck.Count / Math.Pow(cardSize.Width, 3);
  43. MoveChilds(deck, cardSize, destinationRect, angleDegree, radius, useTransitions, deckupDownOrientation, durationRatio);
  44. }
  45. }
  46. void MoveChilds(IDeck deck, Size cardSize, Rect destinationRect, double angleDegree, double circleRadius, bool useTransitions,
  47. DeckOrientation deckupDownOrientation, double durationRatio)
  48. {
  49. _offsets = new List<DispositionOffset>();
  50. bool isEven = deck.Count % 2 == 0;
  51. double i;
  52. if (isEven)
  53. i = (deck.Count - 1) / -2.0;
  54. else
  55. i = -Math.Floor(deck.Count / 2.0);
  56. DispositionOffset[] offsets = new DispositionOffset[deck.Count];
  57. // first pass : calculate positions
  58. var j = 0;
  59. foreach (var card in deck)
  60. {
  61. var svi = card.ScatterViewItem;
  62. Point offsetPoint = new Point(0, 0);
  63. if (card.IsSelected)
  64. {
  65. switch (deckupDownOrientation)
  66. {
  67. case DeckOrientation.Up:
  68. offsetPoint.Y = -20;
  69. break;
  70. case DeckOrientation.Down:
  71. offsetPoint.Y = 20;
  72. break;
  73. }
  74. }
  75. offsets[j] = CalcOffset(angleDegree * i, circleRadius, cardSize, destinationRect, offsetPoint, deckupDownOrientation);
  76. i++;
  77. j++;
  78. }
  79. double offsetX = offsets.Max(o => o.Max.X) - offsets.Min(o => o.Min.X);
  80. //offsetX = (offsets[offsets.Length - 1].Center.X + cardSize.Width) - (offsets[0].Center.X - cardSize.Width / 2);
  81. double offsetY = offsets.Max(o => o.Max.Y) - offsets.Min(o => o.Min.Y);
  82. // ratio can be equal to 0 when cards are in line
  83. double ratioX = offsetX == 0 ? 1 : (destinationRect.Width / offsetX);
  84. double ratioY = offsetY == 0 ? 1 : (destinationRect.Height / offsetY);
  85. var middle = new Point(destinationRect.X + destinationRect.Width / 2, destinationRect.Y + destinationRect.Height / 2);
  86. j = 0;
  87. foreach (var card in deck)
  88. {
  89. if (card.ScatterViewItem.Visibility == Visibility.Collapsed)
  90. continue;
  91. var svi = card.ScatterViewItem;
  92. var offset = offsets[j];
  93. offset.Center = new Point(
  94. middle.X + offset.Center.X * ratioX,
  95. middle.Y + offset.Center.Y * ratioY
  96. );
  97. _offsets.Add(offset);
  98. ActuallyMoveChilds(useTransitions, deck, card, offset, durationRatio);
  99. j++;
  100. }
  101. }
  102. private static void ActuallyMoveChilds(bool useTransitions, IDeck deck, ICard card, DispositionOffset offset, double durationRatio)
  103. {
  104. // translate Center to Deck position
  105. var center = deck.ScatterViewItem.TranslatePoint(offset.Center, deck.ScatterView);
  106. // calc real orientation
  107. var orientation = DispositionHelper.CalcOrientationForCards(
  108. card.ScatterViewItem.ActualOrientation, offset.Orientation + deck.ScatterViewItem.ActualOrientation);
  109. var svi = card.ScatterViewItem;
  110. bool centerChanged = svi.Center != offset.Center;
  111. bool orientationChanged = svi.Orientation != offset.Orientation;
  112. if (useTransitions)
  113. {
  114. var duration = DispositionHelper.ComputeAnimationDuration(svi.ActualCenter, center, svi.ActualOrientation, orientation, durationRatio);
  115. // center animation
  116. if (centerChanged)
  117. DispositionHelper.BeginCenterAnimation(svi, center, duration);
  118. // orientation animation
  119. if (orientationChanged)
  120. DispositionHelper.BeginOrientationAnimation(svi, orientation, duration);
  121. }
  122. else
  123. {
  124. if (centerChanged)
  125. card.Center = center;
  126. if (orientationChanged)
  127. card.Orientation = orientation;
  128. }
  129. }
  130. public bool CanApplyDisposition(Size cardSize, Rect destinationRect, int cardsCount)
  131. {
  132. return true;
  133. //return destinationRect.Width > cardsCount * (cardSize.Width / 4);
  134. }
  135. private DispositionOffset CalcOffset(double angleDegree, double circleRadius, Size cardSize, Rect destinationRect, Point offsetPoint, DeckOrientation deckupDownOrientation)
  136. {
  137. DispositionOffset off = new DispositionOffset();
  138. if (double.IsNaN(circleRadius))
  139. {
  140. // put in line
  141. off.Center =
  142. new Point(
  143. cardSize.Width * angleDegree,
  144. 0);
  145. }
  146. else
  147. {
  148. var middle = new Point(destinationRect.Width / 2.0, destinationRect.Height / 2.0);
  149. Matrix m = new Matrix()
  150. {
  151. OffsetX = offsetPoint.X,
  152. OffsetY = offsetPoint.Y,
  153. };
  154. var midCardWidth = cardSize.Width / 2.0;
  155. var midCardHeight = cardSize.Height / 2.0;
  156. Point[] points = new Point[4];
  157. Point p1, p2, p3, p4;
  158. TranslateRotateCopyMatrix(-midCardWidth, -midCardHeight, angleDegree, 0.0, circleRadius, out p1);
  159. // top right
  160. TranslateRotateCopyMatrix(midCardWidth, -midCardHeight, angleDegree, 0.0, circleRadius, out p2);
  161. // bottom right
  162. TranslateRotateCopyMatrix(midCardWidth, midCardHeight, angleDegree, 0.0, circleRadius, out p3);
  163. // bottom left
  164. TranslateRotateCopyMatrix(-midCardWidth, midCardHeight, angleDegree, 0.0, circleRadius, out p4);
  165. points[0] = p1;
  166. points[1] = p2;
  167. points[2] = p3;
  168. points[3] = p4;
  169. off.Min = new Point(points.Min(p => p.X), points.Min(p => p.Y));
  170. off.Max = new Point(points.Max(p => p.X), points.Max(p => p.Y));
  171. switch (deckupDownOrientation)
  172. {
  173. case DeckOrientation.Up:
  174. m.RotateAt(angleDegree, 0, circleRadius);
  175. break;
  176. case DeckOrientation.Down:
  177. m.RotateAt(-angleDegree, 0, -circleRadius);
  178. break;
  179. }
  180. off.Center = new Point(m.OffsetX, m.OffsetY);
  181. switch (deckupDownOrientation)
  182. {
  183. case DeckOrientation.Up:
  184. off.Orientation = angleDegree;
  185. break;
  186. case DeckOrientation.Down:
  187. off.Orientation = -angleDegree;
  188. break;
  189. }
  190. }
  191. return off;
  192. }
  193. private void TranslateRotateCopyMatrix(double x, double y, double angle, double rotationX, double rotationY, out Point p)
  194. {
  195. var m = new Matrix() { OffsetX = x, OffsetY = y };
  196. m.RotateAt(angle, rotationX, rotationY);
  197. p = new Point(m.OffsetX, m.OffsetY);
  198. }
  199. #endregion
  200. public void Cut(Card card)
  201. {
  202. var cardIndex = card.Deck.IndexOf(card);
  203. var cardsLeft = card.Deck.Where(c => card.Deck.IndexOf(c) < cardIndex).OfType<Card>();
  204. var cardsRight = card.Deck.Where(c => card.Deck.IndexOf(c) >= cardIndex).OfType<Card>();
  205. if (!cardsLeft.Any() || !cardsRight.Any())
  206. return;
  207. var leftoffset = CalcPositions(cardsLeft, true);
  208. var rightOffset = CalcPositions(cardsRight, false);
  209. // set the same animation duration for both
  210. var dispositionRect = card.Deck.GetCardsDestinationRect();
  211. var duration = DispositionHelper.ComputeAnimationDuration(dispositionRect.TopLeft, dispositionRect.TopRight, 0, 0, 1);
  212. leftoffset.Duration = rightOffset.Duration = duration;
  213. GatherCards(cardsLeft, true, leftoffset, rightOffset, null);
  214. GatherCards(cardsRight, false, rightOffset, leftoffset,
  215. (s, e) =>
  216. {
  217. using (card.Deck.DeferUpdateDisposition(true, true, 2))
  218. {
  219. var cards = cardsLeft.ToList();
  220. var deck = card.Deck;
  221. foreach (var c in cards)
  222. {
  223. deck.Remove(c);
  224. deck.Insert(deck.Count, c);
  225. }
  226. }
  227. }
  228. );
  229. }
  230. private DispositionOffset CalcPositions(IEnumerable<Card> allCards, bool left)
  231. {
  232. if (!allCards.Any())
  233. throw new Exception("Should have som cards");
  234. Card gatheredCard;
  235. if (left)
  236. gatheredCard = allCards.First();
  237. else
  238. gatheredCard = allCards.Last();
  239. Point dest = gatheredCard.ScatterViewItem.ActualCenter;
  240. DispositionOffset offset = new DispositionOffset
  241. {
  242. Center = dest,
  243. Orientation = gatheredCard.Deck.ScatterViewItem.ActualOrientation,
  244. };
  245. return offset;
  246. }
  247. private void GatherCards(IEnumerable<Card> allCards, bool isLeft, DispositionOffset beginOffset, DispositionOffset endOffset,
  248. EventHandler animsCompleted)
  249. {
  250. int i = 0;
  251. foreach (var card in allCards)
  252. {
  253. Point acutalDest = new Point(beginOffset.Center.X + i, beginOffset.Center.Y + i / 2);
  254. double actualOrientation = DispositionHelper.CalcOrientationForCards(card.ScatterViewItem.ActualOrientation, beginOffset.Orientation);
  255. var ca = DispositionHelper.BeginCenterAnimation(card.ScatterViewItem, acutalDest, beginOffset.Duration);
  256. DispositionHelper.BeginOrientationAnimation(card.ScatterViewItem, actualOrientation, beginOffset.Duration);
  257. if (card == allCards.Last())
  258. {
  259. ca.Completed += (s, e) =>
  260. {
  261. // when first anim completed, begin second one
  262. AnimateStacks(allCards, isLeft, beginOffset, endOffset, animsCompleted);
  263. };
  264. }
  265. i++;
  266. }
  267. }
  268. private void AnimateStacks(IEnumerable<Card> cards, bool isLeft, DispositionOffset beginOffset, DispositionOffset endOffset,
  269. EventHandler animsCompleted)
  270. {
  271. int i = 0;
  272. foreach (var card in cards)
  273. {
  274. // stop current animations if there is any
  275. DispositionHelper.StopCenterAnimation(card.ScatterViewItem);
  276. DispositionHelper.StopOrientationAnimation(card.ScatterViewItem);
  277. Point actualbeginCenter = card.ScatterViewItem.ActualCenter;
  278. Point actualDestCenter = new Point(endOffset.Center.X + i, endOffset.Center.Y + i / 2);
  279. Point actualMiddleCenter;
  280. if (isLeft)
  281. actualMiddleCenter = new Point(
  282. (card.ScatterViewItem.ActualCenter.X + actualDestCenter.X) / 2,
  283. card.ScatterViewItem.ActualCenter.Y + 200);
  284. else
  285. actualMiddleCenter = new Point(
  286. (card.ScatterViewItem.ActualCenter.X + actualDestCenter.X) / 2,
  287. card.ScatterViewItem.ActualCenter.Y - 200);
  288. BezierSegment bs = new BezierSegment(
  289. actualbeginCenter,
  290. actualMiddleCenter,
  291. actualDestCenter,
  292. true);
  293. PathGeometry path = new PathGeometry();
  294. PathFigure figure = new PathFigure();
  295. figure.StartPoint = actualbeginCenter;
  296. figure.Segments.Add(bs);
  297. figure.IsClosed = false;
  298. path.Figures.Add(figure);
  299. PointAnimationUsingPath anim =
  300. new PointAnimationUsingPath();
  301. anim.PathGeometry = path;
  302. anim.Duration = beginOffset.Duration + beginOffset.Duration;
  303. if (card == cards.Last())
  304. {
  305. if (animsCompleted != null)
  306. anim.Completed += animsCompleted;
  307. }
  308. card.ScatterViewItem.BeginAnimation(ScatterViewItem.CenterProperty, anim);
  309. i++;
  310. }
  311. }
  312. }
  313. }