ElementPosition.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. //
  5. // Purpose: Class is used to store relative position of the chart
  6. // elements like Legend, Title and others. It uses
  7. // relative coordinate system where top left corner is
  8. // 0,0 and bottom right is 100,100.
  9. // :
  10. // If Auto property is set to true, all position properties
  11. // (X,Y,Width and Height) are ignored and they automatically
  12. // calculated during chart rendering.
  13. // :
  14. // Note that setting any of the position properties will
  15. // automatically set Auto property to false.
  16. //
  17. using System;
  18. using System.ComponentModel;
  19. using System.Diagnostics.CodeAnalysis;
  20. using System.Drawing;
  21. namespace FastReport.DataVisualization.Charting
  22. {
  23. /// <summary>
  24. /// ElementPosition is the base class for many chart visual
  25. /// elements like Legend, Title and ChartArea. It provides
  26. /// the position of the chart element in relative coordinates,
  27. /// from (0,0) to (100,100).
  28. /// </summary>
  29. [
  30. SRDescription("DescriptionAttributeElementPosition_ElementPosition"),
  31. DefaultProperty("Data"),
  32. ]
  33. public class ElementPosition : ChartElement
  34. {
  35. #region Fields
  36. // Private data members, which store properties values
  37. private float _x = 0;
  38. private float _y = 0;
  39. private float _width = 0;
  40. private float _height = 0;
  41. internal bool _auto = true;
  42. // Indicates the auto position of all areas must be reset
  43. internal bool resetAreaAutoPosition = false;
  44. #endregion
  45. #region Constructors
  46. /// <summary>
  47. /// ElementPosition default constructor
  48. /// </summary>
  49. public ElementPosition()
  50. {
  51. }
  52. /// <summary>
  53. /// ElementPosition default constructor
  54. /// </summary>
  55. internal ElementPosition(IChartElement parent)
  56. : base(parent)
  57. {
  58. }
  59. /// <summary>
  60. /// ElementPosition constructor.
  61. /// </summary>
  62. /// <param name="x">X position.</param>
  63. /// <param name="y">Y position.</param>
  64. /// <param name="width">Width.</param>
  65. /// <param name="height">Height.</param>
  66. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
  67. Justification = "X and Y are cartesian coordinates and well understood")]
  68. public ElementPosition(float x, float y, float width, float height)
  69. {
  70. this._auto = false;
  71. this._x = x;
  72. this._y = y;
  73. this._width = width;
  74. this._height = height;
  75. }
  76. #endregion
  77. #region Methods
  78. /// <summary>
  79. /// Asks the user at design-time if he wants to change the Auto position
  80. /// of all areas at the same time.
  81. /// </summary>
  82. /// <param name="autoValue">Value to be set for the Auto property.</param>
  83. private void ResetAllAreasAutoPosition(bool autoValue)
  84. {
  85. if(resetAreaAutoPosition)
  86. {
  87. // Proceed only if at design time
  88. if(Chart != null && Chart.IsDesignMode() && !Chart.serializing && Chart.Site != null)
  89. {
  90. // Check if there is more than one area and Auto position set to the same value
  91. if(Chart.ChartAreas.Count > 1)
  92. {
  93. bool firstAutoValue = Chart.ChartAreas[0].Position.Auto;
  94. bool sameAutoValue = true;
  95. foreach(ChartArea area in Chart.ChartAreas)
  96. {
  97. if(area.Position.Auto != firstAutoValue)
  98. {
  99. sameAutoValue = false;
  100. break;
  101. }
  102. }
  103. // Proceed only all Auto values are the same
  104. if(sameAutoValue)
  105. {
  106. string message = SR.MessageChangingChartAreaPositionProperty;
  107. if (autoValue)
  108. {
  109. message += SR.MessageChangingChartAreaPositionConfirmAutomatic;
  110. }
  111. else
  112. {
  113. message += SR.MessageChangingChartAreaPositionConfirmCustom;
  114. }
  115. IDesignerMessageBoxDialog confirm = Chart.Site.GetService(typeof(IDesignerMessageBoxDialog)) as IDesignerMessageBoxDialog;
  116. if (confirm != null && confirm.ShowQuestion(message))
  117. {
  118. foreach (ChartArea area in Chart.ChartAreas)
  119. {
  120. if (autoValue)
  121. {
  122. this.SetPositionNoAuto(0f, 0f, 0f, 0f);
  123. }
  124. area.Position._auto = autoValue;
  125. }
  126. }
  127. }
  128. }
  129. }
  130. }
  131. }
  132. /// <summary>
  133. /// Convert element position into RectangleF
  134. /// </summary>
  135. /// <returns>RectangleF structure.</returns>
  136. public RectangleF ToRectangleF()
  137. {
  138. return new RectangleF(_x, _y, _width, _height);
  139. }
  140. /// <summary>
  141. /// Initializes ElementPosition from RectangleF
  142. /// </summary>
  143. /// <param name="rect">RectangleF structure.</param>
  144. public void FromRectangleF(RectangleF rect)
  145. {
  146. if (rect == null)
  147. throw new ArgumentNullException("rect");
  148. this._x = rect.X;
  149. this._y = rect.Y;
  150. this._width = rect.Width;
  151. this._height = rect.Height;
  152. this._auto = false;
  153. }
  154. /// <summary>
  155. /// Gets the size of the ElementPosition object.
  156. /// </summary>
  157. /// <returns>The size of the ElementPosition object.</returns>
  158. [Browsable(false)]
  159. [Utilities.SerializationVisibility(Utilities.SerializationVisibility.Hidden)]
  160. public SizeF Size
  161. {
  162. get { return new SizeF(this._width, this._height); }
  163. }
  164. /// <summary>
  165. /// Gets the bottom position in relative coordinates.
  166. /// </summary>
  167. /// <returns>Bottom position.</returns>
  168. [Browsable(false)]
  169. [Utilities.SerializationVisibility(Utilities.SerializationVisibility.Hidden)]
  170. public float Bottom
  171. {
  172. get { return this._y + this._height; }
  173. }
  174. /// <summary>
  175. /// Gets the right position in relative coordinates.
  176. /// </summary>
  177. /// <returns>Right position.</returns>
  178. [Browsable(false)]
  179. [Utilities.SerializationVisibility(Utilities.SerializationVisibility.Hidden)]
  180. public float Right
  181. {
  182. get{ return this._x + this._width; }
  183. }
  184. /// <summary>
  185. /// Determines whether the specified Object is equal to the current Object.
  186. /// </summary>
  187. /// <param name="obj">The Object to compare with the current Object.</param>
  188. /// <returns>true if the specified Object is equal to the current Object; otherwise, false.</returns>
  189. internal override bool EqualsInternal(object obj)
  190. {
  191. ElementPosition pos = obj as ElementPosition;
  192. if(pos != null)
  193. {
  194. if(this._auto == true && this._auto == pos._auto)
  195. {
  196. return true;
  197. }
  198. else if(this._x == pos._x && this._y == pos._y &&
  199. this._width == pos._width && this._height == pos._height)
  200. {
  201. return true;
  202. }
  203. }
  204. return false;
  205. }
  206. /// <summary>
  207. /// Returns a string that represents the element position data.
  208. /// </summary>
  209. /// <returns>Element position data as a string.</returns>
  210. internal override string ToStringInternal()
  211. {
  212. string posString = Constants.AutoValue;
  213. if(!this._auto)
  214. {
  215. posString =
  216. this._x.ToString(System.Globalization.CultureInfo.CurrentCulture)+", "+
  217. this._y.ToString(System.Globalization.CultureInfo.CurrentCulture)+", "+
  218. this._width.ToString(System.Globalization.CultureInfo.CurrentCulture)+", "+
  219. this._height.ToString(System.Globalization.CultureInfo.CurrentCulture);
  220. }
  221. return posString;
  222. }
  223. /// <summary>
  224. /// Set the element position without modifying the "Auto" property
  225. /// </summary>
  226. /// <param name="x">X position.</param>
  227. /// <param name="y">Y position.</param>
  228. /// <param name="width">Width.</param>
  229. /// <param name="height">Height.</param>
  230. internal void SetPositionNoAuto(float x, float y, float width, float height)
  231. {
  232. bool oldValue = this._auto;
  233. this._x = x;
  234. this._y = y;
  235. this._width = width;
  236. this._height = height;
  237. this._auto = oldValue;
  238. }
  239. #endregion
  240. #region Element Position properties
  241. /// <summary>
  242. /// X position of element.
  243. /// </summary>
  244. [
  245. SRCategory("CategoryAttributeMisc"),
  246. Bindable(true),
  247. DefaultValue(0.0F),
  248. SRDescription("DescriptionAttributeElementPosition_X"),
  249. NotifyParentPropertyAttribute(true),
  250. RefreshPropertiesAttribute(RefreshProperties.All),
  251. SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "X")
  252. ]
  253. public float X
  254. {
  255. get
  256. {
  257. return _x;
  258. }
  259. set
  260. {
  261. if(value < 0.0 || value > 100.0)
  262. {
  263. throw(new ArgumentOutOfRangeException("value", SR.ExceptionElementPositionArgumentOutOfRange));
  264. }
  265. _x = value;
  266. Auto = false;
  267. // Adjust width
  268. if( (_x + Width) > 100)
  269. {
  270. Width = 100 - _x;
  271. }
  272. this.Invalidate();
  273. CallOnModifing();
  274. }
  275. }
  276. /// <summary>
  277. /// Y position of element.
  278. /// </summary>
  279. [
  280. SRCategory("CategoryAttributeMisc"),
  281. Bindable(true),
  282. DefaultValue(0.0F),
  283. SRDescription("DescriptionAttributeElementPosition_Y"),
  284. NotifyParentPropertyAttribute(true),
  285. RefreshPropertiesAttribute(RefreshProperties.All),
  286. SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Y")
  287. ]
  288. public float Y
  289. {
  290. get
  291. {
  292. return _y;
  293. }
  294. set
  295. {
  296. if(value < 0.0 || value > 100.0)
  297. {
  298. throw(new ArgumentOutOfRangeException("value", SR.ExceptionElementPositionArgumentOutOfRange));
  299. }
  300. _y = value;
  301. Auto = false;
  302. // Adjust heigth
  303. if( (_y + Height) > 100)
  304. {
  305. Height = 100 - _y;
  306. }
  307. this.Invalidate();
  308. CallOnModifing();
  309. }
  310. }
  311. /// <summary>
  312. /// Width of element.
  313. /// </summary>
  314. [
  315. SRCategory("CategoryAttributeMisc"),
  316. Bindable(true),
  317. DefaultValue(0.0F),
  318. SRDescription("DescriptionAttributeElementPosition_Width"),
  319. NotifyParentPropertyAttribute(true),
  320. RefreshPropertiesAttribute(RefreshProperties.All)
  321. ]
  322. public float Width
  323. {
  324. get
  325. {
  326. return _width;
  327. }
  328. set
  329. {
  330. if(value < 0.0 || value > 100.0)
  331. {
  332. throw(new ArgumentOutOfRangeException("value", SR.ExceptionElementPositionArgumentOutOfRange));
  333. }
  334. _width = value;
  335. Auto = false;
  336. // Adjust x
  337. if( (_x + Width) > 100)
  338. {
  339. _x = 100 - Width;
  340. }
  341. this.Invalidate();
  342. CallOnModifing();
  343. }
  344. }
  345. /// <summary>
  346. /// Height of element.
  347. /// </summary>
  348. [
  349. SRCategory("CategoryAttributeMisc"),
  350. Bindable(true),
  351. DefaultValue(0.0F),
  352. SRDescription("DescriptionAttributeElementPosition_Height"),
  353. NotifyParentPropertyAttribute(true),
  354. RefreshPropertiesAttribute(RefreshProperties.All)
  355. ]
  356. public float Height
  357. {
  358. get
  359. {
  360. return _height;
  361. }
  362. set
  363. {
  364. if(value < 0.0 || value > 100.0)
  365. {
  366. throw(new ArgumentOutOfRangeException("value", SR.ExceptionElementPositionArgumentOutOfRange));
  367. }
  368. _height = value;
  369. Auto = false;
  370. // Adjust y
  371. if( (_y + Height) > 100)
  372. {
  373. _y = 100 - Height;
  374. }
  375. this.Invalidate();
  376. CallOnModifing();
  377. }
  378. }
  379. /// <summary>
  380. /// Gets or sets a flag which indicates whether positioning is on.
  381. /// </summary>
  382. [
  383. SRCategory("CategoryAttributeMisc"),
  384. Bindable(true),
  385. DefaultValue(true),
  386. SRDescription("DescriptionAttributeElementPosition_Auto"),
  387. NotifyParentPropertyAttribute(true),
  388. RefreshPropertiesAttribute(RefreshProperties.All)
  389. ]
  390. public bool Auto
  391. {
  392. get
  393. {
  394. return _auto;
  395. }
  396. set
  397. {
  398. if(value != _auto)
  399. {
  400. ResetAllAreasAutoPosition(value);
  401. if(value)
  402. {
  403. this._x = 0;
  404. this._y = 0;
  405. this._width = 0;
  406. this._height = 0;
  407. }
  408. _auto = value;
  409. this.Invalidate();
  410. CallOnModifing();
  411. }
  412. }
  413. }
  414. #endregion
  415. }
  416. /// <summary>
  417. /// Used for invoking windows forms MesageBox dialog.
  418. /// </summary>
  419. internal interface IDesignerMessageBoxDialog
  420. {
  421. /// <summary>
  422. /// Shows Yes/No MessageBox.
  423. /// </summary>
  424. /// <param name="message">The message.</param>
  425. /// <returns>
  426. /// true if user confirms with Yes
  427. /// </returns>
  428. bool ShowQuestion(string message);
  429. }
  430. }