TextAnnotation.cs 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207
  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: Text annotation class.
  6. //
  7. using System;
  8. using System.Windows.Forms;
  9. using System.ComponentModel;
  10. using System.Drawing;
  11. using System.Drawing.Design;
  12. using System.Drawing.Drawing2D;
  13. using System.Security;
  14. using FastReport.DataVisualization.Charting.Utilities;
  15. namespace FastReport.DataVisualization.Charting
  16. {
  17. using Point = System.Drawing.Point;
  18. using Size = System.Drawing.Size;
  19. /// <summary>
  20. /// <b>TextAnnotation</b> is a class that represents a text annotation.
  21. /// </summary>
  22. /// <remarks>
  23. /// Note that other annotations do display inner text (e.g. rectangle,
  24. /// ellipse annotations.).
  25. /// </remarks>
  26. [
  27. SRDescription("DescriptionAttributeTextAnnotation_TextAnnotation"),
  28. ]
  29. public class TextAnnotation : Annotation
  30. {
  31. // Annotation text
  32. private string _text = "";
  33. // Indicates multiline text
  34. private bool _isMultiline = false;
  35. // Current content size
  36. internal SizeF contentSize = SizeF.Empty;
  37. // Indicates that annotion is an ellipse
  38. internal bool isEllipse = false;
  39. // Control used to edit text
  40. private TextBox _editTextBox = null;
  41. #region Construction and Initialization
  42. /// <summary>
  43. /// Default public constructor.
  44. /// </summary>
  45. public TextAnnotation()
  46. : base()
  47. {
  48. }
  49. #endregion
  50. #region Properties
  51. #region Text Visual Attributes
  52. /// <summary>
  53. /// Annotation's text.
  54. /// </summary>
  55. [
  56. SRCategory("CategoryAttributeAppearance"),
  57. DefaultValue(""),
  58. SRDescription("DescriptionAttributeText"),
  59. ]
  60. virtual public string Text
  61. {
  62. get
  63. {
  64. return _text;
  65. }
  66. set
  67. {
  68. _text = value;
  69. Invalidate();
  70. // Reset content size to empty
  71. contentSize = SizeF.Empty;
  72. }
  73. }
  74. /// <summary>
  75. /// Indicates whether the annotation text is multiline.
  76. /// </summary>
  77. [
  78. SRCategory("CategoryAttributeAppearance"),
  79. DefaultValue(false),
  80. SRDescription("DescriptionAttributeMultiline"),
  81. ]
  82. virtual public bool IsMultiline
  83. {
  84. get
  85. {
  86. return _isMultiline;
  87. }
  88. set
  89. {
  90. _isMultiline = value;
  91. Invalidate();
  92. }
  93. }
  94. /// <summary>
  95. /// Gets or sets the font of an annotation's text.
  96. /// <seealso cref="Annotation.ForeColor"/>
  97. /// </summary>
  98. /// <value>
  99. /// A <see cref="Font"/> object used for an annotation's text.
  100. /// </value>
  101. [
  102. SRCategory("CategoryAttributeAppearance"),
  103. DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
  104. SRDescription("DescriptionAttributeTextFont4"),
  105. ]
  106. override public Font Font
  107. {
  108. get
  109. {
  110. return base.Font;
  111. }
  112. set
  113. {
  114. base.Font = value;
  115. // Reset content size to empty
  116. contentSize = SizeF.Empty;
  117. }
  118. }
  119. #endregion
  120. #region Non Applicable Annotation Appearance Attributes (set as Non-Browsable)
  121. /// <summary>
  122. /// Not applicable to this annotation type.
  123. /// </summary>
  124. [
  125. SRCategory("CategoryAttributeAppearance"),
  126. Browsable(false),
  127. DefaultValue(typeof(Color), "Black"),
  128. TypeConverter(typeof(ColorConverter)),
  129. #if DESIGNER
  130. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  131. #endif
  132. ]
  133. override public Color LineColor
  134. {
  135. get
  136. {
  137. return base.LineColor;
  138. }
  139. set
  140. {
  141. base.LineColor = value;
  142. }
  143. }
  144. /// <summary>
  145. /// Not applicable to this annotation type.
  146. /// </summary>
  147. [
  148. SRCategory("CategoryAttributeAppearance"),
  149. Browsable(false),
  150. DefaultValue(1),
  151. SRDescription("DescriptionAttributeLineWidth"),
  152. ]
  153. override public int LineWidth
  154. {
  155. get
  156. {
  157. return base.LineWidth;
  158. }
  159. set
  160. {
  161. base.LineWidth = value;
  162. }
  163. }
  164. /// <summary>
  165. /// Not applicable to this annotation type.
  166. /// </summary>
  167. [
  168. SRCategory("CategoryAttributeAppearance"),
  169. Browsable(false),
  170. DefaultValue(ChartDashStyle.Solid),
  171. ]
  172. override public ChartDashStyle LineDashStyle
  173. {
  174. get
  175. {
  176. return base.LineDashStyle;
  177. }
  178. set
  179. {
  180. base.LineDashStyle = value;
  181. }
  182. }
  183. /// <summary>
  184. /// Not applicable to this annotation type.
  185. /// </summary>
  186. [
  187. SRCategory("CategoryAttributeAppearance"),
  188. Browsable(false),
  189. DefaultValue(typeof(Color), ""),
  190. NotifyParentPropertyAttribute(true),
  191. TypeConverter(typeof(ColorConverter)),
  192. #if DESIGNER
  193. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  194. #endif
  195. ]
  196. override public Color BackColor
  197. {
  198. get
  199. {
  200. return base.BackColor;
  201. }
  202. set
  203. {
  204. base.BackColor = value;
  205. }
  206. }
  207. /// <summary>
  208. /// Not applicable to this annotation type.
  209. /// </summary>
  210. [
  211. SRCategory("CategoryAttributeAppearance"),
  212. Browsable(false),
  213. DefaultValue(ChartHatchStyle.None),
  214. NotifyParentPropertyAttribute(true),
  215. #if DESIGNER
  216. Editor(typeof(HatchStyleEditor), typeof(UITypeEditor))
  217. #endif
  218. ]
  219. override public ChartHatchStyle BackHatchStyle
  220. {
  221. get
  222. {
  223. return base.BackHatchStyle;
  224. }
  225. set
  226. {
  227. base.BackHatchStyle = value;
  228. }
  229. }
  230. /// <summary>
  231. /// Not applicable to this annotation type.
  232. /// </summary>
  233. [
  234. SRCategory("CategoryAttributeAppearance"),
  235. Browsable(false),
  236. DefaultValue(GradientStyle.None),
  237. NotifyParentPropertyAttribute(true),
  238. #if DESIGNER
  239. Editor(typeof(GradientEditor), typeof(UITypeEditor))
  240. #endif
  241. ]
  242. override public GradientStyle BackGradientStyle
  243. {
  244. get
  245. {
  246. return base.BackGradientStyle;
  247. }
  248. set
  249. {
  250. base.BackGradientStyle = value;
  251. }
  252. }
  253. /// <summary>
  254. /// Not applicable to this annotation type.
  255. /// </summary>
  256. [
  257. SRCategory("CategoryAttributeAppearance"),
  258. Browsable(false),
  259. DefaultValue(typeof(Color), ""),
  260. NotifyParentPropertyAttribute(true),
  261. TypeConverter(typeof(ColorConverter)),
  262. #if DESIGNER
  263. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  264. #endif
  265. ]
  266. override public Color BackSecondaryColor
  267. {
  268. get
  269. {
  270. return base.BackSecondaryColor;
  271. }
  272. set
  273. {
  274. base.BackSecondaryColor = value;
  275. }
  276. }
  277. #endregion
  278. #region Other
  279. /// <summary>
  280. /// Gets or sets an annotation's type name.
  281. /// </summary>
  282. /// <remarks>
  283. /// This property is used to get the name of each annotation type
  284. /// (e.g. Line, Rectangle, Ellipse).
  285. /// <para>
  286. /// This property is for internal use and is hidden at design and run time.
  287. /// </para>
  288. /// </remarks>
  289. [
  290. SRCategory("CategoryAttributeMisc"),
  291. Bindable(true),
  292. Browsable(false),
  293. EditorBrowsableAttribute(EditorBrowsableState.Never),
  294. DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
  295. SerializationVisibilityAttribute(SerializationVisibility.Hidden),
  296. SRDescription("DescriptionAttributeTextAnnotation_AnnotationType"),
  297. ]
  298. public override string AnnotationType
  299. {
  300. get
  301. {
  302. return "Text";
  303. }
  304. }
  305. /// <summary>
  306. /// Annotation selection points style.
  307. /// </summary>
  308. [
  309. SRCategory("CategoryAttributeAppearance"),
  310. DefaultValue(SelectionPointsStyle.Rectangle),
  311. ParenthesizePropertyNameAttribute(true),
  312. Browsable(false),
  313. EditorBrowsableAttribute(EditorBrowsableState.Never),
  314. DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
  315. SerializationVisibilityAttribute(SerializationVisibility.Hidden),
  316. SRDescription("DescriptionAttributeSelectionPointsStyle"),
  317. ]
  318. override internal SelectionPointsStyle SelectionPointsStyle
  319. {
  320. get
  321. {
  322. return SelectionPointsStyle.Rectangle;
  323. }
  324. }
  325. #endregion
  326. #endregion
  327. #region Methods
  328. #region Painting
  329. /// <summary>
  330. /// Paints an annotation object on the specified graphics.
  331. /// </summary>
  332. /// <param name="graphics">
  333. /// A <see cref="ChartGraphics"/> object, used to paint an annotation object.
  334. /// </param>
  335. /// <param name="chart">
  336. /// Reference to the <see cref="Chart"/> owner control.
  337. /// </param>
  338. override internal void Paint(Chart chart, ChartGraphics graphics)
  339. {
  340. // Get annotation position in relative coordinates
  341. PointF firstPoint = PointF.Empty;
  342. PointF anchorPoint = PointF.Empty;
  343. SizeF size = SizeF.Empty;
  344. GetRelativePosition(out firstPoint, out size, out anchorPoint);
  345. PointF secondPoint = new PointF(firstPoint.X + size.Width, firstPoint.Y + size.Height);
  346. // Create selection rectangle
  347. RectangleF selectionRect = new RectangleF(firstPoint, new SizeF(secondPoint.X - firstPoint.X, secondPoint.Y - firstPoint.Y));
  348. // Get text position
  349. RectangleF textPosition = new RectangleF(selectionRect.Location, selectionRect.Size);
  350. if(textPosition.Width < 0)
  351. {
  352. textPosition.X = textPosition.Right;
  353. textPosition.Width = -textPosition.Width;
  354. }
  355. if(textPosition.Height < 0)
  356. {
  357. textPosition.Y = textPosition.Bottom;
  358. textPosition.Height = -textPosition.Height;
  359. }
  360. // Check if text position is valid
  361. if( textPosition.IsEmpty ||
  362. float.IsNaN(textPosition.X) ||
  363. float.IsNaN(textPosition.Y) ||
  364. float.IsNaN(textPosition.Right) ||
  365. float.IsNaN(textPosition.Bottom) )
  366. {
  367. return;
  368. }
  369. if(this.Common.ProcessModePaint)
  370. {
  371. DrawText(graphics, textPosition, false, false);
  372. }
  373. if(this.Common.ProcessModeRegions)
  374. {
  375. // Add hot region
  376. if(isEllipse)
  377. {
  378. using (GraphicsPath ellipsePath = new GraphicsPath())
  379. {
  380. ellipsePath.AddEllipse(textPosition);
  381. this.Common.HotRegionsList.AddHotRegion(
  382. graphics,
  383. ellipsePath,
  384. true,
  385. ReplaceKeywords(this.ToolTip),
  386. String.Empty,
  387. String.Empty,
  388. String.Empty,
  389. this,
  390. ChartElementType.Annotation);
  391. }
  392. }
  393. else
  394. {
  395. this.Common.HotRegionsList.AddHotRegion(
  396. textPosition,
  397. ReplaceKeywords(this.ToolTip),
  398. String.Empty,
  399. String.Empty,
  400. String.Empty,
  401. this,
  402. ChartElementType.Annotation,
  403. String.Empty);
  404. }
  405. }
  406. // Paint selection handles
  407. PaintSelectionHandles(graphics, selectionRect, null);
  408. }
  409. /// <summary>
  410. /// Draws text in specified rectangle.
  411. /// </summary>
  412. /// <param name="graphics">Chart graphics.</param>
  413. /// <param name="textPosition">Text position.</param>
  414. /// <param name="noSpacingForCenteredText">True if text allowed to be outside of position when centered.</param>
  415. /// <param name="getTextPosition">True if position text must be returned by the method.</param>
  416. /// <returns>Text actual position if required.</returns>
  417. internal RectangleF DrawText(ChartGraphics graphics, RectangleF textPosition, bool noSpacingForCenteredText, bool getTextPosition)
  418. {
  419. RectangleF textActualPosition = RectangleF.Empty;
  420. //***************************************************************
  421. //** Adjust text position uing text spacing
  422. //***************************************************************
  423. bool annotationRelative = false;
  424. RectangleF textSpacing = GetTextSpacing(out annotationRelative);
  425. float spacingScaleX = 1f;
  426. float spacingScaleY = 1f;
  427. if(annotationRelative)
  428. {
  429. if(textPosition.Width > 25f)
  430. {
  431. spacingScaleX = textPosition.Width / 50f;
  432. spacingScaleX = Math.Max(1f, spacingScaleX);
  433. }
  434. if(textPosition.Height > 25f)
  435. {
  436. spacingScaleY = textPosition.Height / 50f;
  437. spacingScaleY = Math.Max(1f, spacingScaleY);
  438. }
  439. }
  440. RectangleF textPositionWithSpacing = new RectangleF(textPosition.Location, textPosition.Size);
  441. textPositionWithSpacing.Width -= (textSpacing.Width + textSpacing.X) * spacingScaleX;
  442. textPositionWithSpacing.X += textSpacing.X * spacingScaleX;
  443. textPositionWithSpacing.Height -= (textSpacing.Height + textSpacing.Y) * spacingScaleY;
  444. textPositionWithSpacing.Y += textSpacing.Y * spacingScaleY;
  445. //***************************************************************
  446. //** Replace new line characters
  447. //***************************************************************
  448. string titleText = this.ReplaceKeywords(this.Text.Replace("\\n", "\n"));
  449. //***************************************************************
  450. //** Check if centered text require spacing.
  451. //** Use only half of the spacing required.
  452. //** Apply only for 1 line of text.
  453. //***************************************************************
  454. if(noSpacingForCenteredText &&
  455. titleText.IndexOf('\n') == -1)
  456. {
  457. if(this.Alignment == ContentAlignment.MiddleCenter ||
  458. this.Alignment == ContentAlignment.MiddleLeft ||
  459. this.Alignment == ContentAlignment.MiddleRight)
  460. {
  461. textPositionWithSpacing.Y = textPosition.Y;
  462. textPositionWithSpacing.Height = textPosition.Height;
  463. textPositionWithSpacing.Height -= textSpacing.Height/2f + textSpacing.Y / 2f;
  464. textPositionWithSpacing.Y += textSpacing.Y / 2f;
  465. }
  466. if(this.Alignment == ContentAlignment.BottomCenter ||
  467. this.Alignment == ContentAlignment.MiddleCenter ||
  468. this.Alignment == ContentAlignment.TopCenter)
  469. {
  470. textPositionWithSpacing.X = textPosition.X;
  471. textPositionWithSpacing.Width = textPosition.Width;
  472. textPositionWithSpacing.Width -= textSpacing.Width/2f + textSpacing.X / 2f;
  473. textPositionWithSpacing.X += textSpacing.X / 2f;
  474. }
  475. }
  476. // Draw text
  477. using( Brush textBrush = new SolidBrush(this.ForeColor) )
  478. {
  479. using (StringFormat format = new StringFormat(StringFormat.GenericTypographic))
  480. {
  481. //***************************************************************
  482. //** Set text format
  483. //***************************************************************
  484. format.FormatFlags = format.FormatFlags ^ StringFormatFlags.LineLimit;
  485. format.Trimming = StringTrimming.EllipsisCharacter;
  486. if (this.Alignment == ContentAlignment.BottomRight ||
  487. this.Alignment == ContentAlignment.MiddleRight ||
  488. this.Alignment == ContentAlignment.TopRight)
  489. {
  490. format.Alignment = StringAlignment.Far;
  491. }
  492. if (this.Alignment == ContentAlignment.BottomCenter ||
  493. this.Alignment == ContentAlignment.MiddleCenter ||
  494. this.Alignment == ContentAlignment.TopCenter)
  495. {
  496. format.Alignment = StringAlignment.Center;
  497. }
  498. if (this.Alignment == ContentAlignment.BottomCenter ||
  499. this.Alignment == ContentAlignment.BottomLeft ||
  500. this.Alignment == ContentAlignment.BottomRight)
  501. {
  502. format.LineAlignment = StringAlignment.Far;
  503. }
  504. if (this.Alignment == ContentAlignment.MiddleCenter ||
  505. this.Alignment == ContentAlignment.MiddleLeft ||
  506. this.Alignment == ContentAlignment.MiddleRight)
  507. {
  508. format.LineAlignment = StringAlignment.Center;
  509. }
  510. //***************************************************************
  511. //** Set shadow color and offset
  512. //***************************************************************
  513. Color textShadowColor = ChartGraphics.GetGradientColor(this.ForeColor, Color.Black, 0.8);
  514. int textShadowOffset = 1;
  515. TextStyle textStyle = this.TextStyle;
  516. if (textStyle == TextStyle.Shadow &&
  517. ShadowOffset != 0)
  518. {
  519. // Draw shadowed text
  520. textShadowColor = ShadowColor;
  521. textShadowOffset = ShadowOffset;
  522. }
  523. if (textStyle == TextStyle.Shadow)
  524. {
  525. textShadowColor = (textShadowColor.A != 255) ? textShadowColor : Color.FromArgb(textShadowColor.A / 2, textShadowColor);
  526. }
  527. //***************************************************************
  528. //** Get text actual position
  529. //***************************************************************
  530. if (getTextPosition)
  531. {
  532. // Measure text size
  533. SizeF textSize = graphics.MeasureStringRel(
  534. this.ReplaceKeywords(_text.Replace("\\n", "\n")),
  535. this.Font,
  536. textPositionWithSpacing.Size,
  537. format);
  538. // Get text position
  539. textActualPosition = new RectangleF(textPositionWithSpacing.Location, textSize);
  540. if (this.Alignment == ContentAlignment.BottomRight ||
  541. this.Alignment == ContentAlignment.MiddleRight ||
  542. this.Alignment == ContentAlignment.TopRight)
  543. {
  544. textActualPosition.X += textPositionWithSpacing.Width - textSize.Width;
  545. }
  546. if (this.Alignment == ContentAlignment.BottomCenter ||
  547. this.Alignment == ContentAlignment.MiddleCenter ||
  548. this.Alignment == ContentAlignment.TopCenter)
  549. {
  550. textActualPosition.X += (textPositionWithSpacing.Width - textSize.Width) / 2f;
  551. }
  552. if (this.Alignment == ContentAlignment.BottomCenter ||
  553. this.Alignment == ContentAlignment.BottomLeft ||
  554. this.Alignment == ContentAlignment.BottomRight)
  555. {
  556. textActualPosition.Y += textPositionWithSpacing.Height - textSize.Height;
  557. }
  558. if (this.Alignment == ContentAlignment.MiddleCenter ||
  559. this.Alignment == ContentAlignment.MiddleLeft ||
  560. this.Alignment == ContentAlignment.MiddleRight)
  561. {
  562. textActualPosition.Y += (textPositionWithSpacing.Height - textSize.Height) / 2f;
  563. }
  564. // Do not allow text to go outside annotation position
  565. textActualPosition.Intersect(textPositionWithSpacing);
  566. }
  567. RectangleF absPosition = graphics.GetAbsoluteRectangle(textPositionWithSpacing);
  568. Title.DrawStringWithStyle(
  569. graphics,
  570. titleText,
  571. this.TextStyle,
  572. this.Font,
  573. absPosition,
  574. this.ForeColor,
  575. textShadowColor,
  576. textShadowOffset,
  577. format,
  578. TextOrientation.Auto
  579. );
  580. }
  581. }
  582. return textActualPosition;
  583. }
  584. #endregion // Painting
  585. #region Text Editing
  586. /// <summary>
  587. /// Stops editing of the annotation text.
  588. /// <seealso cref="BeginTextEditing"/>
  589. /// </summary>
  590. /// <remarks>
  591. /// Call this method to cancel text editing, which was started via a call to
  592. /// the <see cref="BeginTextEditing"/> method, or after the end-user double-clicks
  593. /// on the annotation.
  594. /// </remarks>
  595. public void StopTextEditing()
  596. {
  597. // Check if text is currently edited
  598. if(_editTextBox != null)
  599. {
  600. // Set annotation text
  601. this.Text = _editTextBox.Text;
  602. // Remove and dispose the text box
  603. try
  604. {
  605. _editTextBox.KeyDown -= new KeyEventHandler(OnTextBoxKeyDown);
  606. _editTextBox.LostFocus -= new EventHandler(OnTextBoxLostFocus);
  607. }
  608. catch(SecurityException)
  609. {
  610. // Ignore security issues
  611. }
  612. if(this.Chart.Controls.Contains(_editTextBox))
  613. {
  614. TextBox tempControl = null;
  615. try
  616. {
  617. // NOTE: Workaround .Net bug. Issue with appplication closing if
  618. // active control is removed.
  619. Form parentForm = this.Chart.FindForm();
  620. if(parentForm != null)
  621. {
  622. tempControl = new TextBox();
  623. tempControl.Visible = false;
  624. // Add temp. control as active
  625. parentForm.Controls.Add(tempControl);
  626. parentForm.ActiveControl = tempControl;
  627. }
  628. }
  629. catch(SecurityException)
  630. {
  631. // Ignore security issues
  632. }
  633. // Remove text editor
  634. this.Chart.Controls.Remove(_editTextBox);
  635. // Dispose temp. text box
  636. if(tempControl != null)
  637. {
  638. tempControl.Dispose();
  639. }
  640. }
  641. // Dispose edit box
  642. _editTextBox.Dispose();
  643. _editTextBox = null;
  644. // Raise notification event
  645. if(this.Chart != null)
  646. {
  647. this.Chart.OnAnnotationTextChanged(this);
  648. }
  649. // Update chart
  650. if(this.Chart != null)
  651. {
  652. this.Chart.Invalidate();
  653. this.Chart.Update();
  654. }
  655. }
  656. }
  657. /// <summary>
  658. /// Handles event when focus is lost by the text editing control.
  659. /// </summary>
  660. /// <param name="sender">Event sender.</param>
  661. /// <param name="e">Event arguments.</param>
  662. private void OnTextBoxLostFocus(object sender, EventArgs e)
  663. {
  664. StopTextEditing();
  665. }
  666. /// <summary>
  667. /// Handles event when key is pressed in the text editing control.
  668. /// </summary>
  669. /// <param name="sender">Event sender.</param>
  670. /// <param name="e">Event arguments.</param>
  671. private void OnTextBoxKeyDown(object sender, KeyEventArgs e)
  672. {
  673. if(e.KeyCode == Keys.Escape)
  674. {
  675. // Reset text and stop editing
  676. _editTextBox.Text = this.Text;
  677. StopTextEditing();
  678. }
  679. else if(e.KeyCode == Keys.Enter &&
  680. this.IsMultiline == false)
  681. {
  682. // Stop editing
  683. StopTextEditing();
  684. }
  685. }
  686. /// <summary>
  687. /// Begins editing the annotation's text by an end user.
  688. /// <seealso cref="StopTextEditing"/>
  689. /// </summary>
  690. /// <remarks>
  691. /// After calling this method, the annotation displays an editing box which allows
  692. /// for editing of the annotation's text.
  693. /// <para>
  694. /// Call the <see cref="StopTextEditing"/> method to cancel this mode programatically.
  695. /// Note that editing ends when the end-user hits the <c>Enter</c> key if multi-line
  696. /// is false, or when the end-user clicks outside of the editing box if multi-line is true.
  697. /// </para>
  698. /// </remarks>
  699. public void BeginTextEditing()
  700. {
  701. if(this.Chart != null && this.AllowTextEditing)
  702. {
  703. // Dispose previous text box
  704. if(_editTextBox != null)
  705. {
  706. if(this.Chart.Controls.Contains(_editTextBox))
  707. {
  708. this.Chart.Controls.Remove(_editTextBox);
  709. }
  710. _editTextBox.Dispose();
  711. _editTextBox = null;
  712. }
  713. // Create a text box inside the chart
  714. _editTextBox = new TextBox();
  715. _editTextBox.Text = this.Text;
  716. _editTextBox.Multiline = this.IsMultiline;
  717. _editTextBox.Font = this.Font;
  718. _editTextBox.BorderStyle = BorderStyle.FixedSingle;
  719. _editTextBox.BackColor = Color.FromArgb(255, (this.BackColor.IsEmpty) ? Color.White : this.BackColor);
  720. _editTextBox.ForeColor = Color.FromArgb(255, this.ForeColor);
  721. // Calculate text position in relative coordinates
  722. PointF firstPoint = PointF.Empty;
  723. PointF anchorPoint = PointF.Empty;
  724. SizeF size = SizeF.Empty;
  725. GetRelativePosition(out firstPoint, out size, out anchorPoint);
  726. PointF secondPoint = new PointF(firstPoint.X + size.Width, firstPoint.Y + size.Height);
  727. RectangleF textPosition = new RectangleF(firstPoint, new SizeF(secondPoint.X - firstPoint.X, secondPoint.Y - firstPoint.Y));
  728. if(textPosition.Width < 0)
  729. {
  730. textPosition.X = textPosition.Right;
  731. textPosition.Width = -textPosition.Width;
  732. }
  733. if(textPosition.Height < 0)
  734. {
  735. textPosition.Y = textPosition.Bottom;
  736. textPosition.Height = -textPosition.Height;
  737. }
  738. // Set text control position in pixels
  739. if(GetGraphics() != null)
  740. {
  741. // Convert point to relative coordinates
  742. textPosition = GetGraphics().GetAbsoluteRectangle(textPosition);
  743. }
  744. // Adjust Location and Size
  745. if(this.IsMultiline)
  746. {
  747. textPosition.X -= 1;
  748. textPosition.Y -= 1;
  749. textPosition.Width += 2;
  750. textPosition.Height += 2;
  751. }
  752. else
  753. {
  754. textPosition.Y += textPosition.Height / 2f - _editTextBox.Size.Height / 2f;
  755. }
  756. _editTextBox.Location = Point.Round(textPosition.Location);
  757. _editTextBox.Size = Size.Round(textPosition.Size);
  758. // Add control to the chart
  759. this.Chart.Controls.Add(_editTextBox);
  760. try
  761. {
  762. _editTextBox.SelectAll();
  763. _editTextBox.Focus();
  764. }
  765. catch(SecurityException)
  766. {
  767. // Ignore security issues
  768. }
  769. try
  770. {
  771. // Set text box event hanlers
  772. _editTextBox.KeyDown += new KeyEventHandler(OnTextBoxKeyDown);
  773. _editTextBox.LostFocus += new EventHandler(OnTextBoxLostFocus);
  774. }
  775. catch(SecurityException)
  776. {
  777. // Ignore security issues
  778. }
  779. }
  780. }
  781. #endregion // Text Editing
  782. #region Content Size
  783. /// <summary>
  784. /// Gets text annotation content size based on the text and font.
  785. /// </summary>
  786. /// <returns>Annotation content position.</returns>
  787. override internal RectangleF GetContentPosition()
  788. {
  789. // Return pre calculated value
  790. if(!contentSize.IsEmpty)
  791. {
  792. return new RectangleF(float.NaN, float.NaN, contentSize.Width, contentSize.Height);
  793. }
  794. // Create temporary bitmap based chart graphics if chart was not
  795. // rendered yet and the graphics was not created.
  796. // NOTE: Fix for issue #3978.
  797. IGraphics graphics = null;
  798. System.Drawing.Image graphicsImage = null;
  799. ChartGraphics tempChartGraph = null;
  800. if(GetGraphics() == null && this.Common != null)
  801. {
  802. graphicsImage = new System.Drawing.Bitmap(Common.ChartPicture.Width, Common.ChartPicture.Height);
  803. graphics = new FastReport.GdiGraphics( graphicsImage );
  804. tempChartGraph = new ChartGraphics( Common );
  805. tempChartGraph.Graphics = graphics;
  806. tempChartGraph.SetPictureSize( Common.ChartPicture.Width, Common.ChartPicture.Height );
  807. this.Common.graph = tempChartGraph;
  808. }
  809. // Calculate content size
  810. RectangleF result = RectangleF.Empty;
  811. if(GetGraphics() != null && this.Text.Trim().Length > 0)
  812. {
  813. // Measure text using current font and slightly increase it
  814. contentSize = GetGraphics().MeasureString(
  815. "W" + this.ReplaceKeywords(this.Text.Replace("\\n", "\n")),
  816. this.Font,
  817. new SizeF(2000, 2000),
  818. StringFormat.GenericTypographic);
  819. contentSize.Height *= 1.04f;
  820. // Convert to relative coordinates
  821. contentSize = GetGraphics().GetRelativeSize(contentSize);
  822. // Add spacing
  823. bool annotationRelative = false;
  824. RectangleF textSpacing = GetTextSpacing(out annotationRelative);
  825. float spacingScaleX = 1f;
  826. float spacingScaleY = 1f;
  827. if(annotationRelative)
  828. {
  829. if(contentSize.Width > 25f)
  830. {
  831. spacingScaleX = contentSize.Width / 25f;
  832. spacingScaleX = Math.Max(1f, spacingScaleX);
  833. }
  834. if(contentSize.Height > 25f)
  835. {
  836. spacingScaleY = contentSize.Height / 25f;
  837. spacingScaleY = Math.Max(1f, spacingScaleY);
  838. }
  839. }
  840. contentSize.Width += (textSpacing.X + textSpacing.Width) * spacingScaleX;
  841. contentSize.Height += (textSpacing.Y + textSpacing.Height) * spacingScaleY;
  842. result = new RectangleF(float.NaN, float.NaN, contentSize.Width, contentSize.Height);
  843. }
  844. // Dispose temporary chart graphics
  845. if(tempChartGraph != null)
  846. {
  847. tempChartGraph.Dispose();
  848. graphics.Dispose();
  849. graphicsImage.Dispose();
  850. this.Common.graph = null;
  851. }
  852. return result;
  853. }
  854. /// <summary>
  855. /// Gets text spacing on four different sides in relative coordinates.
  856. /// </summary>
  857. /// <param name="annotationRelative">Indicates that spacing is in annotation relative coordinates.</param>
  858. /// <returns>Rectangle with text spacing values.</returns>
  859. internal virtual RectangleF GetTextSpacing(out bool annotationRelative)
  860. {
  861. annotationRelative = false;
  862. RectangleF rect = new RectangleF(3f, 3f, 3f, 3f);
  863. if(GetGraphics() != null)
  864. {
  865. rect = GetGraphics().GetRelativeRectangle(rect);
  866. }
  867. return rect;
  868. }
  869. #endregion
  870. #region Placement Methods
  871. /// <summary>
  872. /// Ends user placement of an annotation.
  873. /// </summary>
  874. /// <remarks>
  875. /// Ends an annotation placement operation previously started by a
  876. /// <see cref="Annotation.BeginPlacement"/> method call.
  877. /// <para>
  878. /// Calling this method is not required, since placement will automatically
  879. /// end when an end user enters all required points. However, it is useful when an annotation
  880. /// placement operation needs to be aborted for some reason.
  881. /// </para>
  882. /// </remarks>
  883. override public void EndPlacement()
  884. {
  885. // Check if text editing is allowed
  886. // Maybe changed later in the EndPlacement method.
  887. bool allowTextEditing = this.AllowTextEditing;
  888. // Call base class
  889. base.EndPlacement();
  890. // Begin text editing
  891. if(this.Chart != null)
  892. {
  893. this.Chart.Annotations.lastClickedAnnotation = this;
  894. if(allowTextEditing)
  895. {
  896. BeginTextEditing();
  897. }
  898. }
  899. }
  900. #endregion // Placement Methods
  901. #endregion // Methods
  902. }
  903. /// <summary>
  904. /// The <b>AnnotationSmartLabelStyle</b> class is used to store an annotation's smart
  905. /// labels properties.
  906. /// <seealso cref="Annotation.SmartLabelStyle"/>
  907. /// </summary>
  908. /// <remarks>
  909. /// This class is derived from the <b>SmartLabelStyle</b> class
  910. /// used for <b>Series</b> objects.
  911. /// </remarks>
  912. [
  913. DefaultProperty("Enabled"),
  914. SRDescription("DescriptionAttributeAnnotationSmartLabelsStyle_AnnotationSmartLabelsStyle"),
  915. TypeConverter(typeof(NoNameExpandableObjectConverter)),
  916. ]
  917. public class AnnotationSmartLabelStyle : SmartLabelStyle
  918. {
  919. #region Constructors and initialization
  920. /// <summary>
  921. /// Default public constructor.
  922. /// </summary>
  923. public AnnotationSmartLabelStyle()
  924. {
  925. this.chartElement = null;
  926. }
  927. /// <summary>
  928. /// Constructor.
  929. /// </summary>
  930. /// <param name="chartElement">
  931. /// Chart element this style belongs to.
  932. /// </param>
  933. public AnnotationSmartLabelStyle(Object chartElement) : base(chartElement)
  934. {
  935. }
  936. #endregion
  937. #region Non Applicable Appearance Attributes (set as Non-Browsable)
  938. /// <summary>
  939. /// Callout style of the repositioned smart labels.
  940. /// </summary>
  941. /// <remarks>
  942. /// This method is for internal use and is hidden at design time and runtime.
  943. /// </remarks>
  944. [
  945. SRCategory("CategoryAttributeMisc"),
  946. Browsable(false),
  947. EditorBrowsableAttribute(EditorBrowsableState.Never),
  948. DefaultValue(LabelCalloutStyle.Underlined),
  949. SRDescription("DescriptionAttributeCalloutStyle3"),
  950. ]
  951. override public LabelCalloutStyle CalloutStyle
  952. {
  953. get
  954. {
  955. return base.CalloutStyle;
  956. }
  957. set
  958. {
  959. base.CalloutStyle = value;
  960. }
  961. }
  962. /// <summary>
  963. /// Label callout line color.
  964. /// </summary>
  965. /// <remarks>
  966. /// This method is for internal use and is hidden at design and run time.
  967. /// </remarks>
  968. [
  969. SRCategory("CategoryAttributeAppearance"),
  970. Browsable(false),
  971. EditorBrowsableAttribute(EditorBrowsableState.Never),
  972. DefaultValue(typeof(Color), "Black"),
  973. SRDescription("DescriptionAttributeCalloutLineColor"),
  974. TypeConverter(typeof(ColorConverter)),
  975. #if DESIGNER
  976. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  977. #endif
  978. ]
  979. override public Color CalloutLineColor
  980. {
  981. get
  982. {
  983. return base.CalloutLineColor;
  984. }
  985. set
  986. {
  987. base.CalloutLineColor = value;
  988. }
  989. }
  990. /// <summary>
  991. /// Label callout line style.
  992. /// </summary>
  993. /// <remarks>
  994. /// This method is for internal use and is hidden at design and run time.
  995. /// </remarks>
  996. [
  997. SRCategory("CategoryAttributeAppearance"),
  998. Browsable(false),
  999. EditorBrowsableAttribute(EditorBrowsableState.Never),
  1000. DefaultValue(ChartDashStyle.Solid),
  1001. SRDescription("DescriptionAttributeLineDashStyle"),
  1002. ]
  1003. override public ChartDashStyle CalloutLineDashStyle
  1004. {
  1005. get
  1006. {
  1007. return base.CalloutLineDashStyle;
  1008. }
  1009. set
  1010. {
  1011. base.CalloutLineDashStyle = value;
  1012. }
  1013. }
  1014. /// <summary>
  1015. /// Label callout back color. Applies to the Box style only.
  1016. /// </summary>
  1017. /// <remarks>
  1018. /// This method is for internal use and is hidden at design and run time.
  1019. /// </remarks>
  1020. [
  1021. SRCategory("CategoryAttributeAppearance"),
  1022. Browsable(false),
  1023. EditorBrowsableAttribute(EditorBrowsableState.Never),
  1024. DefaultValue(typeof(Color), "Transparent"),
  1025. SRDescription("DescriptionAttributeCalloutBackColor"),
  1026. TypeConverter(typeof(ColorConverter)),
  1027. #if DESIGNER
  1028. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  1029. #endif
  1030. ]
  1031. override public Color CalloutBackColor
  1032. {
  1033. get
  1034. {
  1035. return base.CalloutBackColor;
  1036. }
  1037. set
  1038. {
  1039. base.CalloutBackColor = value;
  1040. }
  1041. }
  1042. /// <summary>
  1043. /// Label callout line width.
  1044. /// </summary>
  1045. /// <remarks>
  1046. /// This method is for internal use and is hidden at design and run time.
  1047. /// </remarks>
  1048. [
  1049. SRCategory("CategoryAttributeAppearance"),
  1050. Browsable(false),
  1051. EditorBrowsableAttribute(EditorBrowsableState.Never),
  1052. DefaultValue(1),
  1053. SRDescription("DescriptionAttributeLineWidth"),
  1054. ]
  1055. override public int CalloutLineWidth
  1056. {
  1057. get
  1058. {
  1059. return base.CalloutLineWidth;
  1060. }
  1061. set
  1062. {
  1063. base.CalloutLineWidth = value;
  1064. }
  1065. }
  1066. /// <summary>
  1067. /// Label callout line anchor cap.
  1068. /// </summary>
  1069. /// <remarks>
  1070. /// This method is for internal use and is hidden at design and run time.
  1071. /// </remarks>
  1072. [
  1073. SRCategory("CategoryAttributeAppearance"),
  1074. Browsable(false),
  1075. EditorBrowsableAttribute(EditorBrowsableState.Never),
  1076. DefaultValue(LineAnchorCapStyle.Arrow),
  1077. SRDescription("DescriptionAttributeCalloutLineAnchorCapStyle"),
  1078. ]
  1079. override public LineAnchorCapStyle CalloutLineAnchorCapStyle
  1080. {
  1081. get
  1082. {
  1083. return base.CalloutLineAnchorCapStyle;
  1084. }
  1085. set
  1086. {
  1087. base.CalloutLineAnchorCapStyle = value;
  1088. }
  1089. }
  1090. #endregion
  1091. }
  1092. }