SelectedComponents.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Windows.Forms;
  5. using FastReport.Design;
  6. using System.Drawing;
  7. using System.Collections;
  8. using FastReport.Utils;
  9. namespace FastReport
  10. {
  11. /// <summary>
  12. /// Holds the list of <see cref="ComponentBase"/> objects currently selected in the designer.
  13. /// </summary>
  14. /// <remarks>
  15. /// This class is used by the "Alignment" toolbar. Use methods of this class to perform some
  16. /// operations on the selected objects.
  17. /// <para/>Note: after calling any method in this class, call the
  18. /// <see cref="Designer.SetModified()">Designer.SetModified</see> method to reflect changes.
  19. /// <para/>Note: this list contains only objects of <see cref="ComponentBase"/> type. If you want to access all
  20. /// selected objects, use the <see cref="Designer.SelectedObjects"/> property.
  21. /// </remarks>
  22. public class SelectedComponents
  23. {
  24. private List<ComponentBase> list;
  25. private Designer designer;
  26. /// <summary>
  27. /// Gets the first selected object.
  28. /// </summary>
  29. public ComponentBase First
  30. {
  31. get { return list.Count > 0 ? list[0] : null; }
  32. }
  33. /// <summary>
  34. /// Gets the number of selected objects.
  35. /// </summary>
  36. public int Count
  37. {
  38. get { return list.Count; }
  39. }
  40. private List<ComponentBase> MoveList
  41. {
  42. get { return list.FindAll(CanMove); }
  43. }
  44. private List<ComponentBase> ResizeList
  45. {
  46. get { return list.FindAll(CanResize); }
  47. }
  48. private bool CanMove(ComponentBase c)
  49. {
  50. return c.HasFlag(Flags.CanMove) && !c.HasRestriction(Restrictions.DontMove);
  51. }
  52. private bool CanResize(ComponentBase c)
  53. {
  54. return c.HasFlag(Flags.CanResize) && !c.HasRestriction(Restrictions.DontResize);
  55. }
  56. internal void Update()
  57. {
  58. list.Clear();
  59. if (designer.SelectedObjects != null)
  60. {
  61. foreach (Base c in designer.SelectedObjects)
  62. {
  63. if (c is ComponentBase)
  64. list.Add(c as ComponentBase);
  65. }
  66. }
  67. }
  68. /// <summary>
  69. /// Aligns left edges of the selected objects.
  70. /// </summary>
  71. public void AlignLeft(object sender = null, EventArgs e = null)
  72. {
  73. foreach (ComponentBase c in MoveList)
  74. {
  75. c.Left = First.Left;
  76. }
  77. designer.SetModified();
  78. }
  79. /// <summary>
  80. /// Aligns right edges of the selected objects.
  81. /// </summary>
  82. public void AlignRight(object sender = null, EventArgs e = null)
  83. {
  84. foreach (ComponentBase c in MoveList)
  85. {
  86. c.Left = First.Right - c.Width;
  87. }
  88. designer.SetModified();
  89. }
  90. /// <summary>
  91. /// Aligns centers of the selected objects.
  92. /// </summary>
  93. public void AlignCenter(object sender = null, EventArgs e = null)
  94. {
  95. foreach (ComponentBase c in MoveList)
  96. {
  97. c.Left = First.Left + (First.Width - c.Width) / 2;
  98. }
  99. designer.SetModified();
  100. }
  101. /// <summary>
  102. /// Aligns top edges of the selected objects.
  103. /// </summary>
  104. public void AlignTop(object sender = null, EventArgs e = null)
  105. {
  106. foreach (ComponentBase c in MoveList)
  107. {
  108. c.Top = First.Top;
  109. }
  110. designer.SetModified();
  111. }
  112. /// <summary>
  113. /// Aligns bottom edges of the selected objects.
  114. /// </summary>
  115. public void AlignBottom(object sender = null, EventArgs e = null)
  116. {
  117. foreach (ComponentBase c in MoveList)
  118. {
  119. c.Top = First.Bottom - c.Height;
  120. }
  121. designer.SetModified();
  122. }
  123. /// <summary>
  124. /// Aligns middles of the selected objects.
  125. /// </summary>
  126. public void AlignMiddle(object sender = null, EventArgs e = null)
  127. {
  128. foreach (ComponentBase c in MoveList)
  129. {
  130. c.Top = First.Top + (First.Height - c.Height) / 2;
  131. }
  132. designer.SetModified();
  133. }
  134. /// <summary>
  135. /// Makes the selected objects the same width as the first object.
  136. /// </summary>
  137. public void SameWidth(object sender = null, EventArgs e = null)
  138. {
  139. foreach (ComponentBase c in ResizeList)
  140. {
  141. c.Width = First.Width;
  142. }
  143. designer.SetModified();
  144. }
  145. /// <summary>
  146. /// Makes the selected objects the same height as the first object.
  147. /// </summary>
  148. public void SameHeight(object sender = null, EventArgs e = null)
  149. {
  150. foreach (ComponentBase c in ResizeList)
  151. {
  152. c.Height = First.Height;
  153. }
  154. designer.SetModified();
  155. }
  156. /// <summary>
  157. /// Makes the selected objects the same size as the first object.
  158. /// </summary>
  159. public void SameSize(object sender = null, EventArgs e = null)
  160. {
  161. foreach (ComponentBase c in ResizeList)
  162. {
  163. c.Width = First.Width;
  164. c.Height = First.Height;
  165. }
  166. designer.SetModified();
  167. }
  168. /// <summary>
  169. /// Centers the selected objects horizontally.
  170. /// </summary>
  171. public void CenterHorizontally(object sender = null, EventArgs e = null)
  172. {
  173. if (!(First.Parent is ComponentBase))
  174. return;
  175. float min = 100000;
  176. float max = -100000;
  177. foreach (ComponentBase c in MoveList)
  178. {
  179. if (c.Left < min)
  180. min = c.Left;
  181. if (c.Right > max)
  182. max = c.Right;
  183. }
  184. float parentWidth = (First.Parent as ComponentBase).ClientSize.Width;
  185. float dx = (parentWidth - (max - min)) / 2;
  186. foreach (ComponentBase c in MoveList)
  187. {
  188. c.Left += dx - min;
  189. }
  190. designer.SetModified();
  191. }
  192. /// <summary>
  193. /// Centers the selected objects vertically.
  194. /// </summary>
  195. public void CenterVertically(object sender = null, EventArgs e = null)
  196. {
  197. if (!(First.Parent is ComponentBase))
  198. return;
  199. float min = 100000;
  200. float max = -100000;
  201. foreach (ComponentBase c in MoveList)
  202. {
  203. if (c.Top < min)
  204. min = c.Top;
  205. if (c.Bottom > max)
  206. max = c.Bottom;
  207. }
  208. float parentHeight = (First.Parent as ComponentBase).ClientSize.Height;
  209. float dy = (parentHeight - (max - min)) / 2;
  210. foreach (ComponentBase c in MoveList)
  211. {
  212. c.Top += dy - min;
  213. }
  214. designer.SetModified();
  215. }
  216. /// <summary>
  217. /// Aligns the selected objects to the grid.
  218. /// </summary>
  219. public void AlignToGrid(object sender = null, EventArgs e = null)
  220. {
  221. SizeF snapSize = First.Page.SnapSize;
  222. foreach (ComponentBase c in MoveList)
  223. {
  224. c.Left = (int)Math.Round(c.Left / snapSize.Width) * snapSize.Width;
  225. c.Top = (int)Math.Round(c.Top / snapSize.Height) * snapSize.Height;
  226. }
  227. designer.SetModified();
  228. }
  229. /// <summary>
  230. /// Adjusts the size of selected objects to the grid.
  231. /// </summary>
  232. public void SizeToGrid(object sender = null, EventArgs e = null)
  233. {
  234. SizeF snapSize = First.Page.SnapSize;
  235. foreach (ComponentBase c in list)
  236. {
  237. if (c.HasFlag(Flags.CanMove) && !c.HasRestriction(Restrictions.DontMove))
  238. {
  239. c.Left = (int)Math.Round(c.Left / snapSize.Width) * snapSize.Width;
  240. c.Top = (int)Math.Round(c.Top / snapSize.Height) * snapSize.Height;
  241. }
  242. if (c.HasFlag(Flags.CanResize) && !c.HasRestriction(Restrictions.DontResize))
  243. {
  244. c.Width = (int)Math.Round(c.Width / snapSize.Width) * snapSize.Width;
  245. c.Height = (int)Math.Round(c.Height / snapSize.Height) * snapSize.Height;
  246. }
  247. }
  248. designer.SetModified();
  249. }
  250. /// <summary>
  251. /// Spaces the selected objects horizontally.
  252. /// </summary>
  253. public void SpaceHorizontally(object sender = null, EventArgs e = null)
  254. {
  255. List<ObjItem> list = new List<ObjItem>();
  256. foreach (ComponentBase c in MoveList)
  257. {
  258. list.Add(new ObjItem(c.Left, c));
  259. }
  260. list.Sort();
  261. if (list.Count < 3)
  262. return;
  263. float dx = list[list.Count - 1].obj.Left - list[0].obj.Right;
  264. float actualSize = 0;
  265. for (int i = 1; i < list.Count - 1; i++)
  266. {
  267. actualSize += list[i].obj.Width;
  268. }
  269. float sizeBetweenObj = actualSize < dx ? (dx - actualSize) / (list.Count - 1) : 0;
  270. float count = sizeBetweenObj > 0 ? list.Count - 1 : list.Count;
  271. for (int i = 1; i < count; i++)
  272. {
  273. list[i].obj.Left = list[i - 1].obj.Right + sizeBetweenObj;
  274. }
  275. designer.SetModified();
  276. }
  277. /// <summary>
  278. /// Increases horizontal spacing between the selected objects.
  279. /// </summary>
  280. public void IncreaseHorizontalSpacing(object sender = null, EventArgs e = null)
  281. {
  282. List<ObjItem> list = new List<ObjItem>();
  283. foreach (ComponentBase c in MoveList)
  284. {
  285. list.Add(new ObjItem(c.Left, c));
  286. }
  287. list.Sort();
  288. SizeF snapSize = First.Page.SnapSize;
  289. for (int i = 1; i < list.Count; i++)
  290. {
  291. list[i].obj.Left += snapSize.Width * i;
  292. }
  293. designer.SetModified();
  294. }
  295. /// <summary>
  296. /// Decreases horizontal spacing between the selected objects.
  297. /// </summary>
  298. public void DecreaseHorizontalSpacing(object sender = null, EventArgs e = null)
  299. {
  300. List<ObjItem> list = new List<ObjItem>();
  301. foreach (ComponentBase c in MoveList)
  302. {
  303. list.Add(new ObjItem(c.Left, c));
  304. }
  305. list.Sort();
  306. SizeF snapSize = First.Page.SnapSize;
  307. for (int i = 1; i < list.Count; i++)
  308. {
  309. list[i].obj.Left -= snapSize.Width * i;
  310. }
  311. designer.SetModified();
  312. }
  313. /// <summary>
  314. /// Removes horizontal spacing between the selected objects.
  315. /// </summary>
  316. public void RemoveHorizontalSpacing(object sender = null, EventArgs e = null)
  317. {
  318. List<ObjItem> list = new List<ObjItem>();
  319. foreach (ComponentBase c in MoveList)
  320. {
  321. list.Add(new ObjItem(c.Left, c));
  322. }
  323. list.Sort();
  324. for (int i = 1; i < list.Count; i++)
  325. {
  326. list[i].obj.Left = list[i - 1].obj.Right;
  327. }
  328. designer.SetModified();
  329. }
  330. /// <summary>
  331. /// Spaces the selected objects vertically.
  332. /// </summary>
  333. public void SpaceVertically(object sender = null, EventArgs e = null)
  334. {
  335. List<ObjItem> list = new List<ObjItem>();
  336. foreach (ComponentBase c in MoveList)
  337. {
  338. list.Add(new ObjItem(c.Top, c));
  339. }
  340. list.Sort();
  341. if (list.Count < 3)
  342. return;
  343. float dy = list[list.Count - 1].obj.Top - list[0].obj.Bottom;
  344. float actualSize = 0;
  345. for (int i = 1; i < list.Count - 1; i++)
  346. {
  347. actualSize += list[i].obj.Height;
  348. }
  349. float sizeBetweenObj = actualSize < dy ? (dy - actualSize) / (list.Count - 1) : 0;
  350. float count = sizeBetweenObj > 0 ? list.Count - 1 : list.Count;
  351. for (int i = 1; i < count; i++)
  352. {
  353. list[i].obj.Top = list[i - 1].obj.Bottom + sizeBetweenObj;
  354. }
  355. designer.SetModified();
  356. }
  357. /// <summary>
  358. /// Increases vertical spacing between the selected objects.
  359. /// </summary>
  360. public void IncreaseVerticalSpacing(object sender = null, EventArgs e = null)
  361. {
  362. List<ObjItem> list = new List<ObjItem>();
  363. foreach (ComponentBase c in MoveList)
  364. {
  365. list.Add(new ObjItem(c.Top, c));
  366. }
  367. list.Sort();
  368. SizeF snapSize = First.Page.SnapSize;
  369. for (int i = 1; i < list.Count; i++)
  370. {
  371. list[i].obj.Top += snapSize.Height * i;
  372. }
  373. designer.SetModified();
  374. }
  375. /// <summary>
  376. /// Decreases vertical spacing between the selected objects.
  377. /// </summary>
  378. public void DecreaseVerticalSpacing(object sender = null, EventArgs e = null)
  379. {
  380. List<ObjItem> list = new List<ObjItem>();
  381. foreach (ComponentBase c in MoveList)
  382. {
  383. list.Add(new ObjItem(c.Top, c));
  384. }
  385. list.Sort();
  386. SizeF snapSize = First.Page.SnapSize;
  387. for (int i = 1; i < list.Count; i++)
  388. {
  389. list[i].obj.Top -= snapSize.Height * i;
  390. }
  391. designer.SetModified();
  392. }
  393. /// <summary>
  394. /// Removes vertical spacing between the selected objects.
  395. /// </summary>
  396. public void RemoveVerticalSpacing(object sender = null, EventArgs e = null)
  397. {
  398. List<ObjItem> list = new List<ObjItem>();
  399. foreach (ComponentBase c in MoveList)
  400. {
  401. list.Add(new ObjItem(c.Left, c));
  402. }
  403. list.Sort();
  404. for (int i = 1; i < list.Count; i++)
  405. {
  406. list[i].obj.Top = list[i - 1].obj.Bottom;
  407. }
  408. designer.SetModified();
  409. }
  410. internal SelectedComponents(Designer designer)
  411. {
  412. this.designer = designer;
  413. list = new List<ComponentBase>();
  414. }
  415. private class ObjItem : IComparable
  416. {
  417. public float coord;
  418. public ComponentBase obj;
  419. public int CompareTo(object obj)
  420. {
  421. if (coord < (obj as ObjItem).coord)
  422. return -1;
  423. if (coord > (obj as ObjItem).coord)
  424. return 1;
  425. return 0;
  426. }
  427. public ObjItem(float coord, ComponentBase obj)
  428. {
  429. this.coord = coord;
  430. this.obj = obj;
  431. }
  432. }
  433. }
  434. }