DesignerControl.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. using FastReport.Design.PageDesigners.Dialog;
  2. using FastReport.Design.Toolbars;
  3. using FastReport.Utils;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel;
  7. using System.Drawing;
  8. using System.Drawing.Drawing2D;
  9. using System.Linq;
  10. using System.Windows.Forms;
  11. namespace FastReport.Design.StandardDesigner
  12. {
  13. /// <summary>
  14. /// Represents the standard report designer.
  15. /// </summary>
  16. /// <remarks>
  17. /// This control extends the <see cref="FastReport.Design.Designer"/> control with
  18. /// standard menu, status bar, and toolbars.
  19. /// <para/>To choose toolbars and tool windows in design-time, click the "View" menu
  20. /// in this control and select what you want to see. Toolbars can be reordered using the mouse.
  21. /// <para/>To restore the designer layout at runtime, you need to call the
  22. /// <see cref="FastReport.Design.Designer.RefreshLayout">RefreshLayout</see> method in your
  23. /// form's <b>Load</b> event handler.
  24. /// </remarks>
  25. [ToolboxItem(true), ToolboxBitmap(typeof(Report), "Resources.DesignerControl.bmp")]
  26. public partial class DesignerControl : Designer
  27. {
  28. #region Fields
  29. private DesignerMenu mainMenu;
  30. private DesignerStatusBar statusBar;
  31. private Panel toolStripPanel;
  32. private StandardToolbar standardToolbar;
  33. private TextToolbar textToolbar;
  34. private BorderToolbar borderToolbar;
  35. private LayoutToolbar layoutToolbar;
  36. private StyleToolbar styleToolbar;
  37. private PolygonToolbar polygonToolbar;
  38. private ContextMenuStrip mnuContext;
  39. private bool showMainMenu;
  40. private bool showStatusBar;
  41. #endregion
  42. #region Properties
  43. /// <summary>
  44. /// Gets the main menu.
  45. /// </summary>
  46. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  47. public DesignerMenu MainMenu
  48. {
  49. get { return mainMenu; }
  50. }
  51. /// <summary>
  52. /// Gets or sets a value indicating whether the main menu should be displayed or not.
  53. /// </summary>
  54. [SRCategory("Toolbars")]
  55. [DefaultValue(true)]
  56. public bool ShowMainMenu
  57. {
  58. get { return showMainMenu; }
  59. set
  60. {
  61. showMainMenu = value;
  62. mainMenu.Visible = value;
  63. }
  64. }
  65. /// <summary>
  66. /// Gets or sets a value indicating whether the status bar should be displayed or not.
  67. /// </summary>
  68. [SRCategory("Toolbars")]
  69. [DefaultValue(true)]
  70. public bool ShowStatusBar
  71. {
  72. get { return showStatusBar; }
  73. set
  74. {
  75. showStatusBar = value;
  76. statusBar.Visible = value;
  77. }
  78. }
  79. #endregion
  80. #region Private Methods
  81. private void CreateToolbarMenu()
  82. {
  83. mnuContext = new ContextMenuStrip();
  84. toolStripPanel.ContextMenuStrip = mnuContext;
  85. mnuContext.Opening += mnuContext_Opening;
  86. foreach (IDesignerPlugin plugin in Plugins)
  87. {
  88. if (plugin is DesignerToolbarBase)
  89. {
  90. var menuItem = new ToolStripMenuItem();
  91. menuItem.Text = (plugin as DesignerToolbarBase).Text;
  92. menuItem.Tag = plugin;
  93. menuItem.Click += toolbar_Click;
  94. mnuContext.Items.Add(menuItem);
  95. }
  96. }
  97. }
  98. private void mnuContext_Opening(object sender, EventArgs e)
  99. {
  100. mnuContext.Renderer = UIStyleUtils.GetToolStripRenderer(UIStyle);
  101. foreach (ToolStripItem item in mnuContext.Items)
  102. {
  103. var menuItem = item as ToolStripMenuItem;
  104. var toolbar = item.Tag as DesignerToolbarBase;
  105. menuItem.Text = toolbar.Text;
  106. menuItem.Checked = toolbar.Visible;
  107. }
  108. }
  109. private void toolbar_Click(object sender, EventArgs e)
  110. {
  111. var toolbar = (sender as ToolStripItem).Tag as DesignerToolbarBase;
  112. toolbar.Visible = !toolbar.Visible;
  113. LayoutToolbars();
  114. }
  115. private int LayoutToolbar(DesignerToolbarBase toolbar, int left, int top)
  116. {
  117. bool rtl = RightToLeft == RightToLeft.Yes;
  118. toolbar.Location = new Point(rtl ? Width - left - toolbar.Width : left, top);
  119. return left + toolbar.Width;
  120. }
  121. internal void LayoutToolbars()
  122. {
  123. var rowHeight = standardToolbar.Height;
  124. if (rowHeight == 0)
  125. return;
  126. // get list of visible toolbars
  127. var toolbars = toolStripPanel.Controls.OfType<DesignerToolbarBase>().Where(tb => tb.Visible).ToList();
  128. List<List<DesignerToolbarBase>> rows = new List<List<DesignerToolbarBase>>();
  129. int maxRows = Height / rowHeight;
  130. // find toolbars on each row
  131. for (int i = -1; i < maxRows; i++)
  132. {
  133. var row = new List<DesignerToolbarBase>();
  134. rows.Add(row);
  135. int rowTop = i * rowHeight - rowHeight / 2;
  136. int rowBottom = rowTop + rowHeight;
  137. if (i == -1)
  138. {
  139. // handle special case when toolbar is dragged out of parent bounds (above the first row)
  140. rowTop = -1000;
  141. }
  142. // find toolbars on this row
  143. for (int j = 0; j < toolbars.Count; j++)
  144. {
  145. var tb = toolbars[j];
  146. if (tb.Top >= rowTop && tb.Top <= rowBottom)
  147. {
  148. row.Add(tb);
  149. // remove from toolbars list to avoid having one toolbar on multiple rows (due to math errors)
  150. toolbars.RemoveAt(j);
  151. j--;
  152. }
  153. }
  154. if (toolbars.Count == 0)
  155. break;
  156. }
  157. // sort each row by Left (Right in opposite order in case of rtl)
  158. bool rtl = RightToLeft == RightToLeft.Yes;
  159. rows.ForEach(row => row.Sort((x, y) => rtl ? y.Right.CompareTo(x.Right) : x.Left.CompareTo(y.Left)));
  160. // remove empty rows
  161. rows.RemoveAll(row => row.Count == 0);
  162. // layout toolbars
  163. for (int i = 0; i < rows.Count; i++)
  164. {
  165. int x = 0;
  166. int y = i * rowHeight;
  167. rows[i].ForEach(tb => x = LayoutToolbar(tb, x, y));
  168. }
  169. // set overall height
  170. toolStripPanel.Height = rows.Count * rowHeight;
  171. }
  172. private void toolStripPanel_Paint(object sender, PaintEventArgs e)
  173. {
  174. var ct = UIStyleUtils.GetColorTable(UIStyle);
  175. Rectangle rect = new Rectangle(0, 0, toolStripPanel.Width, toolStripPanel.Height);
  176. using (var brush = new LinearGradientBrush(rect, ct.ToolStripPanelGradientBegin, ct.ToolStripPanelGradientEnd, LinearGradientMode.Horizontal))
  177. e.Graphics.FillRectangle(brush, rect);
  178. int _1 = this.LogicalToDevice(1);
  179. using (var brush = new SolidBrush(ct.ToolStripBorder))
  180. e.Graphics.FillRectangle(brush, 0, rect.Height - _1, rect.Width, _1);
  181. }
  182. #endregion
  183. #region Protected Methods
  184. internal override void AfterRestoreState()
  185. {
  186. base.AfterRestoreState();
  187. #if AVALONIA
  188. // this should be deferred to get correct toolbars size
  189. this.control.Loaded += (s,e) =>
  190. #endif
  191. LayoutToolbars();
  192. }
  193. /// <inheritdoc/>
  194. protected override void OnResize(EventArgs e)
  195. {
  196. base.OnResize(e);
  197. if (RightToLeft == RightToLeft.Yes)
  198. LayoutToolbars();
  199. }
  200. /// <inheritdoc/>
  201. protected override void InitPlugins()
  202. {
  203. base.InitPlugins();
  204. toolStripPanel = new Panel();
  205. toolStripPanel.Dock = DockStyle.Top;
  206. toolStripPanel.Paint += toolStripPanel_Paint;
  207. Controls.Add(toolStripPanel);
  208. mainMenu = new DesignerMenu(this);
  209. statusBar = new DesignerStatusBar(this);
  210. // create toolbars and make default toolbar layout
  211. standardToolbar = new StandardToolbar(this) { Left = 0, Top = 0 };
  212. layoutToolbar = new LayoutToolbar(this) { Left = standardToolbar.Right, Top = 0 };
  213. textToolbar = new TextToolbar(this) { Left = 0, Top = standardToolbar.Bottom };
  214. borderToolbar = new BorderToolbar(this) { Left = textToolbar.Right, Top = textToolbar.Top };
  215. styleToolbar = new StyleToolbar(this) { Left = borderToolbar.Right, Top = textToolbar.Top };
  216. polygonToolbar = new PolygonToolbar(this) { Left = styleToolbar.Right, Top = textToolbar.Top };
  217. var toolbars = new Control[] { standardToolbar, layoutToolbar, textToolbar, borderToolbar, styleToolbar, polygonToolbar };
  218. foreach (var toolbar in toolbars)
  219. {
  220. // WPF/Avalonia: occurs when toolbar is dragged to a new position. Not used in Mono
  221. toolbar.DragDrop += (s, e) => LayoutToolbars();
  222. }
  223. toolStripPanel.Controls.AddRange(toolbars);
  224. Plugins.AddRange(new IDesignerPlugin[] {
  225. mainMenu, statusBar, standardToolbar, textToolbar, borderToolbar,
  226. layoutToolbar, styleToolbar, polygonToolbar });
  227. CreateToolbarMenu();
  228. }
  229. #endregion
  230. #region Public Methods
  231. /// <inheritdoc/>
  232. public override void ShowStatus(string location, string size, string text, string locationRightBot)
  233. {
  234. statusBar.UpdateLocationAndSize(location, size, locationRightBot);
  235. statusBar.UpdateText(text);
  236. }
  237. /// <inheritdoc/>
  238. public override void UpdateUIStyle()
  239. {
  240. base.UpdateUIStyle();
  241. toolStripPanel.Refresh();
  242. }
  243. /// <inheritdoc/>
  244. public override void UpdateDpiDependencies(object sender)
  245. {
  246. base.UpdateDpiDependencies(sender);
  247. mnuContext.Font = this.Font;
  248. LayoutToolbars();
  249. }
  250. internal void UpdateFirstDialogPage()
  251. {
  252. // WPF bug: designer workspace is not initialized if the dialog form is the first page in a report (reason: visible designer form is needed)
  253. if (ActiveReportTab != null && ActiveReportTab.ActivePageDesigner is DialogPageDesigner pd)
  254. pd.UpdateDpiDependencies();
  255. }
  256. #endregion
  257. /// <summary>
  258. /// Initializes a new instance of the <see cref="DesignerControl"/> class with default settings.
  259. /// </summary>
  260. public DesignerControl()
  261. {
  262. ShowMainMenu = true;
  263. ShowStatusBar = true;
  264. }
  265. }
  266. }