SnapManager.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Globalization;
  6. using System.Windows.Forms;
  7. namespace PaintDotNet
  8. {
  9. public sealed class SnapManager
  10. {
  11. private Dictionary<SnapObstacle, SnapDescription> obstacles =
  12. new Dictionary<SnapObstacle, SnapDescription>();
  13. private const string isSnappedValueName = "IsSnapped";
  14. private const string leftValueName = "Left";
  15. private const string topValueName = "Top";
  16. private const string widthValueName = "Width";
  17. private const string heightValueName = "Height";
  18. private const string nullName = "";
  19. private const string snappedToValueName = "SnappedTo";
  20. private const string horizontalEdgeValueName = "HorizontalEdge";
  21. private const string verticalEdgeValueName = "VerticalEdge";
  22. private const string xOffsetValueName = "XOffset";
  23. private const string yOffsetValueName = "YOffset";
  24. public void SaveSnapObstacleData(ISimpleCollection<string, string> saveTo, SnapObstacle so)
  25. {
  26. string prefix = so.Name + ".";
  27. SnapDescription sd = this.obstacles[so];
  28. bool isSnappedValue = (sd != null);
  29. saveTo.Set(prefix + isSnappedValueName, isSnappedValue.ToString(CultureInfo.InvariantCulture));
  30. if (isSnappedValue)
  31. {
  32. saveTo.Set(prefix + snappedToValueName, sd.SnappedTo.Name);
  33. saveTo.Set(prefix + horizontalEdgeValueName, sd.HorizontalEdge.ToString());
  34. saveTo.Set(prefix + verticalEdgeValueName, sd.VerticalEdge.ToString());
  35. saveTo.Set(prefix + xOffsetValueName, sd.XOffset.ToString(CultureInfo.InvariantCulture));
  36. saveTo.Set(prefix + yOffsetValueName, sd.YOffset.ToString(CultureInfo.InvariantCulture));
  37. }
  38. saveTo.Set(prefix + leftValueName, so.Bounds.Left.ToString(CultureInfo.InvariantCulture));
  39. saveTo.Set(prefix + topValueName, so.Bounds.Top.ToString(CultureInfo.InvariantCulture));
  40. saveTo.Set(prefix + widthValueName, so.Bounds.Width.ToString(CultureInfo.InvariantCulture));
  41. saveTo.Set(prefix + heightValueName, so.Bounds.Height.ToString(CultureInfo.InvariantCulture));
  42. }
  43. public void LoadSnapObstacleData(ISimpleCollection<string, string> loadFrom, SnapObstacle so)
  44. {
  45. string prefix = so.Name + ".";
  46. SnapDescription sd;
  47. string isSnappedString = loadFrom.Get(prefix + isSnappedValueName);
  48. bool isSnapped = bool.Parse(isSnappedString);
  49. if (isSnapped)
  50. {
  51. string snappedToString = loadFrom.Get(prefix + snappedToValueName);
  52. SnapObstacle snappedTo = FindObstacle(snappedToString);
  53. string horizontalEdgeString = loadFrom.Get(prefix + horizontalEdgeValueName);
  54. HorizontalSnapEdge horizontalEdge = (HorizontalSnapEdge)Enum.Parse(typeof(HorizontalSnapEdge), horizontalEdgeString, true);
  55. string verticalEdgeString = loadFrom.Get(prefix + verticalEdgeValueName);
  56. VerticalSnapEdge verticalEdge = (VerticalSnapEdge)Enum.Parse(typeof(VerticalSnapEdge), verticalEdgeString, true);
  57. string xOffsetString = loadFrom.Get(prefix + xOffsetValueName);
  58. int xOffset = int.Parse(xOffsetString, CultureInfo.InvariantCulture);
  59. string yOffsetString = loadFrom.Get(prefix + yOffsetValueName);
  60. int yOffset = int.Parse(yOffsetString, CultureInfo.InvariantCulture);
  61. sd = new SnapDescription(snappedTo, horizontalEdge, verticalEdge, xOffset, yOffset);
  62. }
  63. else
  64. {
  65. sd = null;
  66. }
  67. this.obstacles[so] = sd;
  68. string leftString = loadFrom.Get(prefix + leftValueName);
  69. int left = int.Parse(leftString, CultureInfo.InvariantCulture);
  70. string topString = loadFrom.Get(prefix + topValueName);
  71. int top = int.Parse(topString, CultureInfo.InvariantCulture);
  72. string widthString = loadFrom.Get(prefix + widthValueName);
  73. int width = int.Parse(widthString, CultureInfo.InvariantCulture);
  74. string heightString = loadFrom.Get(prefix + heightValueName);
  75. int height = int.Parse(heightString, CultureInfo.InvariantCulture);
  76. Rectangle newBounds = new Rectangle(left, top, width, height);
  77. so.RequestBoundsChange(newBounds);
  78. if (sd != null)
  79. {
  80. ParkObstacle(so, sd);
  81. }
  82. }
  83. // Requires that all SnapObstacles are already placed in this.obstacles
  84. public void Save(ISimpleCollection<string, string> saveTo)
  85. {
  86. foreach (SnapObstacle obstacle in this.obstacles.Keys)
  87. {
  88. if (obstacle.EnableSave)
  89. {
  90. SaveSnapObstacleData(saveTo, obstacle);
  91. }
  92. }
  93. }
  94. public void Load(ISimpleCollection<string, string> loadFrom)
  95. {
  96. SnapObstacle[] newObstacles = new SnapObstacle[this.obstacles.Count];
  97. this.obstacles.Keys.CopyTo(newObstacles, 0);
  98. foreach (SnapObstacle obstacle in newObstacles)
  99. {
  100. if (obstacle.EnableSave)
  101. {
  102. LoadSnapObstacleData(loadFrom, obstacle);
  103. }
  104. }
  105. }
  106. public void ParkObstacle(ISnapObstacleHost obstacle, ISnapObstacleHost snappedTo, HorizontalSnapEdge hEdge, VerticalSnapEdge vEdge)
  107. {
  108. ParkObstacle(obstacle.SnapObstacle, snappedTo.SnapObstacle, hEdge, vEdge);
  109. }
  110. public void ParkObstacle(SnapObstacle obstacle, SnapObstacle snappedTo, HorizontalSnapEdge hEdge, VerticalSnapEdge vEdge)
  111. {
  112. SnapDescription sd = new SnapDescription(snappedTo, hEdge, vEdge, obstacle.SnapDistance, obstacle.SnapDistance);
  113. this.obstacles[obstacle] = sd;
  114. ParkObstacle(obstacle, sd);
  115. }
  116. public void ReparkObstacle(ISnapObstacleHost obstacle)
  117. {
  118. ReparkObstacle(obstacle.SnapObstacle);
  119. }
  120. public void ReparkObstacle(SnapObstacle obstacle)
  121. {
  122. if (this.obstacles.ContainsKey(obstacle))
  123. {
  124. SnapDescription sd = this.obstacles[obstacle];
  125. if (sd != null)
  126. {
  127. ParkObstacle(obstacle, sd);
  128. }
  129. }
  130. }
  131. public void AddSnapObstacle(ISnapObstacleHost snapObstacleHost)
  132. {
  133. AddSnapObstacle(snapObstacleHost.SnapObstacle);
  134. }
  135. public void AddSnapObstacle(SnapObstacle snapObstacle)
  136. {
  137. if (!this.obstacles.ContainsKey(snapObstacle))
  138. {
  139. this.obstacles.Add(snapObstacle, null);
  140. if (snapObstacle.StickyEdges)
  141. {
  142. snapObstacle.BoundsChanging += SnapObstacle_BoundsChanging;
  143. snapObstacle.BoundsChanged += SnapObstacle_BoundsChanged;
  144. }
  145. }
  146. }
  147. private void SnapObstacle_BoundsChanging(object sender, EventArgs<Rectangle> e)
  148. {
  149. }
  150. private void SnapObstacle_BoundsChanged(object sender, EventArgs<Rectangle> e)
  151. {
  152. SnapObstacle senderSO = (SnapObstacle)sender;
  153. Rectangle fromRect = e.Data;
  154. Rectangle toRect = senderSO.Bounds;
  155. UpdateDependentObstacles(senderSO, fromRect, toRect);
  156. }
  157. private void UpdateDependentObstacles(SnapObstacle senderSO, Rectangle fromRect, Rectangle toRect)
  158. {
  159. int leftDelta = toRect.Left - fromRect.Left;
  160. int topDelta = toRect.Top - fromRect.Top;
  161. int rightDelta = toRect.Right - fromRect.Right;
  162. int bottomDelta = toRect.Bottom - fromRect.Bottom;
  163. foreach (SnapObstacle obstacle in this.obstacles.Keys)
  164. {
  165. if (!object.ReferenceEquals(senderSO, obstacle))
  166. {
  167. SnapDescription sd = this.obstacles[obstacle];
  168. if (sd != null && object.ReferenceEquals(sd.SnappedTo, senderSO))
  169. {
  170. int deltaX;
  171. if (sd.VerticalEdge == VerticalSnapEdge.Right)
  172. {
  173. deltaX = rightDelta;
  174. }
  175. else
  176. {
  177. deltaX = leftDelta;
  178. }
  179. int deltaY;
  180. if (sd.HorizontalEdge == HorizontalSnapEdge.Bottom)
  181. {
  182. deltaY = bottomDelta;
  183. }
  184. else
  185. {
  186. deltaY = topDelta;
  187. }
  188. Rectangle oldBounds = obstacle.Bounds;
  189. Point newLocation1 = new Point(oldBounds.Left + deltaX, oldBounds.Top + deltaY);
  190. Point newLocation2 = AdjustNewLocation(obstacle, newLocation1, sd);
  191. Rectangle newBounds = new Rectangle(newLocation2, oldBounds.Size);
  192. obstacle.RequestBoundsChange(newBounds);
  193. // Recursively update anything snapped to this obstacle
  194. UpdateDependentObstacles(obstacle, oldBounds, newBounds);
  195. }
  196. }
  197. }
  198. }
  199. public void RemoveSnapObstacle(ISnapObstacleHost snapObstacleHost)
  200. {
  201. RemoveSnapObstacle(snapObstacleHost.SnapObstacle);
  202. }
  203. public void RemoveSnapObstacle(SnapObstacle snapObstacle)
  204. {
  205. if (this.obstacles.ContainsKey(snapObstacle))
  206. {
  207. this.obstacles.Remove(snapObstacle);
  208. if (snapObstacle.StickyEdges)
  209. {
  210. snapObstacle.BoundsChanging -= SnapObstacle_BoundsChanging;
  211. snapObstacle.BoundsChanged -= SnapObstacle_BoundsChanged;
  212. }
  213. }
  214. }
  215. public bool ContainsSnapObstacle(ISnapObstacleHost snapObstacleHost)
  216. {
  217. return ContainsSnapObstacle(snapObstacleHost.SnapObstacle);
  218. }
  219. public bool ContainsSnapObstacle(SnapObstacle snapObstacle)
  220. {
  221. return this.obstacles.ContainsKey(snapObstacle);
  222. }
  223. private static bool AreEdgesClose(int l1, int r1, int l2, int r2)
  224. {
  225. if (r1 < l2)
  226. {
  227. return false;
  228. }
  229. else if (r2 < l1)
  230. {
  231. return false;
  232. }
  233. else if (l1 <= l2 && l2 <= r1 && r1 <= r2)
  234. {
  235. return true;
  236. }
  237. else if (l2 <= l1 && l1 <= r2 && r2 <= r1)
  238. {
  239. return true;
  240. }
  241. else if (l1 <= l2 && r2 <= r1)
  242. {
  243. return true;
  244. }
  245. else if (l2 <= l1 && l1 <= r2)
  246. {
  247. return true;
  248. }
  249. throw new InvalidOperationException();
  250. }
  251. private SnapDescription DetermineNewSnapDescription(
  252. SnapObstacle avoider,
  253. Point newLocation,
  254. SnapObstacle avoidee,
  255. SnapDescription currentSnapDescription)
  256. {
  257. int ourSnapProximity;
  258. if (currentSnapDescription != null &&
  259. (currentSnapDescription.HorizontalEdge != HorizontalSnapEdge.Neither ||
  260. currentSnapDescription.VerticalEdge != VerticalSnapEdge.Neither))
  261. {
  262. // the avoider is already snapped to the avoidee -- make it more difficult to un-snap
  263. ourSnapProximity = avoidee.SnapProximity * 2;
  264. }
  265. else
  266. {
  267. ourSnapProximity = avoidee.SnapProximity;
  268. }
  269. Rectangle avoiderRect = avoider.Bounds;
  270. avoiderRect.Location = newLocation;
  271. Rectangle avoideeRect = avoidee.Bounds;
  272. // Are the vertical edges close enough for snapping?
  273. bool vertProximity = AreEdgesClose(avoiderRect.Top, avoiderRect.Bottom, avoideeRect.Top, avoideeRect.Bottom);
  274. // Are the horizontal edges close enough for snapping?
  275. bool horizProximity = AreEdgesClose(avoiderRect.Left, avoiderRect.Right, avoideeRect.Left, avoideeRect.Right);
  276. // Compute distances from pertinent edges
  277. // (e.g. if SnapRegion.Interior, figure out distance from avoider's right edge to avoidee's right edge,
  278. // if SnapRegion.Exterior, figure out distance from avoider's right edge to avoidee's left edge)
  279. int leftDistance;
  280. int rightDistance;
  281. int topDistance;
  282. int bottomDistance;
  283. switch (avoidee.SnapRegion)
  284. {
  285. case SnapRegion.Interior:
  286. leftDistance = Math.Abs(avoiderRect.Left - avoideeRect.Left);
  287. rightDistance = Math.Abs(avoiderRect.Right - avoideeRect.Right);
  288. topDistance = Math.Abs(avoiderRect.Top - avoideeRect.Top);
  289. bottomDistance = Math.Abs(avoiderRect.Bottom - avoideeRect.Bottom);
  290. break;
  291. case SnapRegion.Exterior:
  292. leftDistance = Math.Abs(avoiderRect.Left - avoideeRect.Right);
  293. rightDistance = Math.Abs(avoiderRect.Right - avoideeRect.Left);
  294. topDistance = Math.Abs(avoiderRect.Top - avoideeRect.Bottom);
  295. bottomDistance = Math.Abs(avoiderRect.Bottom - avoideeRect.Top);
  296. break;
  297. default:
  298. throw new InvalidEnumArgumentException("avoidee.SnapRegion");
  299. }
  300. bool leftClose = (leftDistance < ourSnapProximity);
  301. bool rightClose = (rightDistance < ourSnapProximity);
  302. bool topClose = (topDistance < ourSnapProximity);
  303. bool bottomClose = (bottomDistance < ourSnapProximity);
  304. VerticalSnapEdge vEdge = VerticalSnapEdge.Neither;
  305. if (vertProximity)
  306. {
  307. if ((leftClose && avoidee.SnapRegion == SnapRegion.Exterior) ||
  308. (rightClose && avoidee.SnapRegion == SnapRegion.Interior))
  309. {
  310. vEdge = VerticalSnapEdge.Right;
  311. }
  312. else if ((rightClose && avoidee.SnapRegion == SnapRegion.Exterior) ||
  313. (leftClose && avoidee.SnapRegion == SnapRegion.Interior))
  314. {
  315. vEdge = VerticalSnapEdge.Left;
  316. }
  317. }
  318. HorizontalSnapEdge hEdge = HorizontalSnapEdge.Neither;
  319. if (horizProximity)
  320. {
  321. if ((topClose && avoidee.SnapRegion == SnapRegion.Exterior) ||
  322. (bottomClose && avoidee.SnapRegion == SnapRegion.Interior))
  323. {
  324. hEdge = HorizontalSnapEdge.Bottom;
  325. }
  326. else if ((bottomClose && avoidee.SnapRegion == SnapRegion.Exterior) ||
  327. (topClose && avoidee.SnapRegion == SnapRegion.Interior))
  328. {
  329. hEdge = HorizontalSnapEdge.Top;
  330. }
  331. }
  332. SnapDescription sd;
  333. if (hEdge != HorizontalSnapEdge.Neither || vEdge != VerticalSnapEdge.Neither)
  334. {
  335. int xOffset = avoider.SnapDistance;
  336. int yOffset = avoider.SnapDistance;
  337. if (hEdge == HorizontalSnapEdge.Neither)
  338. {
  339. if (avoidee.SnapRegion == SnapRegion.Interior)
  340. {
  341. yOffset = avoiderRect.Top - avoideeRect.Top;
  342. hEdge = HorizontalSnapEdge.Top;
  343. }
  344. }
  345. if (vEdge == VerticalSnapEdge.Neither)
  346. {
  347. if (avoidee.SnapRegion == SnapRegion.Interior)
  348. {
  349. xOffset = avoiderRect.Left - avoideeRect.Left;
  350. vEdge = VerticalSnapEdge.Left;
  351. }
  352. }
  353. sd = new SnapDescription(avoidee, hEdge, vEdge, xOffset, yOffset);
  354. }
  355. else
  356. {
  357. sd = null;
  358. }
  359. return sd;
  360. }
  361. private static void ParkObstacle(SnapObstacle avoider, SnapDescription snapDescription)
  362. {
  363. Point newLocation = avoider.Bounds.Location;
  364. Point adjustedLocation = AdjustNewLocation(avoider, newLocation, snapDescription);
  365. Rectangle newBounds = new Rectangle(adjustedLocation, avoider.Bounds.Size);
  366. avoider.RequestBoundsChange(newBounds);
  367. }
  368. private static Point AdjustNewLocation(SnapObstacle obstacle, Point newLocation, SnapDescription snapDescription)
  369. {
  370. if (snapDescription == null ||
  371. (snapDescription.HorizontalEdge == HorizontalSnapEdge.Neither &&
  372. snapDescription.VerticalEdge == VerticalSnapEdge.Neither))
  373. {
  374. return obstacle.Bounds.Location;
  375. }
  376. Rectangle obstacleRect = new Rectangle(newLocation, obstacle.Bounds.Size);
  377. Rectangle snappedToRect = snapDescription.SnappedTo.Bounds;
  378. HorizontalSnapEdge hEdge = snapDescription.HorizontalEdge;
  379. VerticalSnapEdge vEdge = snapDescription.VerticalEdge;
  380. SnapRegion region = snapDescription.SnappedTo.SnapRegion;
  381. int deltaY = 0;
  382. if (hEdge == HorizontalSnapEdge.Top && region == SnapRegion.Exterior)
  383. {
  384. int newBottomEdge = snappedToRect.Top - snapDescription.YOffset;
  385. deltaY = obstacleRect.Bottom - newBottomEdge;
  386. }
  387. else if (hEdge == HorizontalSnapEdge.Bottom && region == SnapRegion.Exterior)
  388. {
  389. int newTopEdge = snappedToRect.Bottom + snapDescription.YOffset;
  390. deltaY = obstacleRect.Top - newTopEdge;
  391. }
  392. else if (hEdge == HorizontalSnapEdge.Top && region == SnapRegion.Interior)
  393. {
  394. int newTopEdge = Math.Min(snappedToRect.Bottom, snappedToRect.Top + snapDescription.YOffset);
  395. deltaY = obstacleRect.Top - newTopEdge;
  396. }
  397. else if (hEdge == HorizontalSnapEdge.Bottom && region == SnapRegion.Interior)
  398. {
  399. int newBottomEdge = Math.Max(snappedToRect.Top, snappedToRect.Bottom - snapDescription.YOffset);
  400. deltaY = obstacleRect.Bottom - newBottomEdge;
  401. }
  402. int deltaX = 0;
  403. if (vEdge == VerticalSnapEdge.Left && region == SnapRegion.Exterior)
  404. {
  405. int newRightEdge = snappedToRect.Left - snapDescription.XOffset;
  406. deltaX = obstacleRect.Right - newRightEdge;
  407. }
  408. else if (vEdge == VerticalSnapEdge.Right && region == SnapRegion.Exterior)
  409. {
  410. int newLeftEdge = snappedToRect.Right + snapDescription.XOffset;
  411. deltaX = obstacleRect.Left - newLeftEdge;
  412. }
  413. else if (vEdge == VerticalSnapEdge.Left && region == SnapRegion.Interior)
  414. {
  415. int newLeftEdge = Math.Min(snappedToRect.Right, snappedToRect.Left + snapDescription.XOffset);
  416. deltaX = obstacleRect.Left - newLeftEdge;
  417. }
  418. else if (vEdge == VerticalSnapEdge.Right && region == SnapRegion.Interior)
  419. {
  420. int newRightEdge = Math.Max(snappedToRect.Left, snappedToRect.Right - snapDescription.XOffset);
  421. deltaX = obstacleRect.Right - newRightEdge;
  422. }
  423. Point adjustedLocation = new Point(obstacleRect.Left - deltaX, obstacleRect.Top - deltaY);
  424. return adjustedLocation;
  425. }
  426. /// <summary>
  427. /// Given an obstacle and its attempted destination, determines the correct landing
  428. /// spot for an obstacle.
  429. /// </summary>
  430. /// <param name="movingObstacle">The obstacle that is moving.</param>
  431. /// <param name="newLocation">The upper-left coordinate of the obstacle's original intended destination.</param>
  432. /// <returns>
  433. /// A Point that determines where the obstacle should be placed instead. If there are no adjustments
  434. /// required to the obstacle's desintation, then the return value will be equal to newLocation.
  435. /// </returns>
  436. /// <remarks>
  437. /// movingObstacle's SnapDescription will also be updated. The caller of this method is required
  438. /// to update the SnapObstacle with the new, adjusted location.
  439. /// </remarks>
  440. public Point AdjustObstacleDestination(SnapObstacle movingObstacle, Point newLocation)
  441. {
  442. Point adjusted1 = AdjustObstacleDestination(movingObstacle, newLocation, false);
  443. Point adjusted2 = AdjustObstacleDestination(movingObstacle, adjusted1, true);
  444. return adjusted2;
  445. }
  446. public Point AdjustObstacleDestination(SnapObstacle movingObstacle, Point newLocation, bool considerStickies)
  447. {
  448. Point adjustedLocation = newLocation;
  449. SnapDescription sd = this.obstacles[movingObstacle];
  450. SnapDescription newSD = null;
  451. foreach (SnapObstacle avoidee in this.obstacles.Keys)
  452. {
  453. if (avoidee.StickyEdges != considerStickies)
  454. {
  455. continue;
  456. }
  457. if (avoidee.Enabled && !object.ReferenceEquals(avoidee, movingObstacle))
  458. {
  459. SnapDescription newSD2 = DetermineNewSnapDescription(movingObstacle, adjustedLocation, avoidee, newSD);
  460. if (newSD2 != null)
  461. {
  462. Point adjustedLocation2 = AdjustNewLocation(movingObstacle, adjustedLocation, newSD2);
  463. newSD = newSD2;
  464. adjustedLocation = adjustedLocation2;
  465. Rectangle newBounds = new Rectangle(adjustedLocation, movingObstacle.Bounds.Size);
  466. }
  467. }
  468. }
  469. if (sd == null || !sd.SnappedTo.StickyEdges || newSD == null || newSD.SnappedTo.StickyEdges)
  470. {
  471. this.obstacles[movingObstacle] = newSD;
  472. }
  473. return adjustedLocation;
  474. }
  475. public SnapObstacle FindObstacle(string name)
  476. {
  477. foreach (SnapObstacle so in this.obstacles.Keys)
  478. {
  479. if (string.Compare(so.Name, name, true) == 0)
  480. {
  481. return so;
  482. }
  483. }
  484. return null;
  485. }
  486. public static SnapManager FindMySnapManager(Control me)
  487. {
  488. if (!(me is ISnapObstacleHost))
  489. {
  490. throw new ArgumentException("must be called with a Control that implements ISnapObstacleHost");
  491. }
  492. ISnapManagerHost ismh;
  493. ismh = me as ISnapManagerHost;
  494. if (ismh == null)
  495. {
  496. ismh = me.FindForm() as ISnapManagerHost;
  497. }
  498. SnapManager sm;
  499. if (ismh != null)
  500. {
  501. sm = ismh.SnapManager;
  502. }
  503. else
  504. {
  505. sm = null;
  506. }
  507. return sm;
  508. }
  509. public SnapManager()
  510. {
  511. }
  512. }
  513. }