using FastReport.Design.PageDesigners.Dialog; using FastReport.Design.Toolbars; using FastReport.Utils; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Windows.Forms; namespace FastReport.Design.StandardDesigner { /// /// Represents the standard report designer. /// /// /// This control extends the control with /// standard menu, status bar, and toolbars. /// To choose toolbars and tool windows in design-time, click the "View" menu /// in this control and select what you want to see. Toolbars can be reordered using the mouse. /// To restore the designer layout at runtime, you need to call the /// RefreshLayout method in your /// form's Load event handler. /// [ToolboxItem(true), ToolboxBitmap(typeof(Report), "Resources.DesignerControl.bmp")] public partial class DesignerControl : Designer { #region Fields private DesignerMenu mainMenu; private DesignerStatusBar statusBar; private Panel toolStripPanel; private StandardToolbar standardToolbar; private TextToolbar textToolbar; private BorderToolbar borderToolbar; private LayoutToolbar layoutToolbar; private StyleToolbar styleToolbar; private PolygonToolbar polygonToolbar; private ContextMenuStrip mnuContext; private bool showMainMenu; private bool showStatusBar; #endregion #region Properties /// /// Gets the main menu. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public DesignerMenu MainMenu { get { return mainMenu; } } /// /// Gets or sets a value indicating whether the main menu should be displayed or not. /// [SRCategory("Toolbars")] [DefaultValue(true)] public bool ShowMainMenu { get { return showMainMenu; } set { showMainMenu = value; mainMenu.Visible = value; } } /// /// Gets or sets a value indicating whether the status bar should be displayed or not. /// [SRCategory("Toolbars")] [DefaultValue(true)] public bool ShowStatusBar { get { return showStatusBar; } set { showStatusBar = value; statusBar.Visible = value; } } #endregion #region Private Methods private void CreateToolbarMenu() { mnuContext = new ContextMenuStrip(); toolStripPanel.ContextMenuStrip = mnuContext; mnuContext.Opening += mnuContext_Opening; foreach (IDesignerPlugin plugin in Plugins) { if (plugin is DesignerToolbarBase) { var menuItem = new ToolStripMenuItem(); menuItem.Text = (plugin as DesignerToolbarBase).Text; menuItem.Tag = plugin; menuItem.Click += toolbar_Click; mnuContext.Items.Add(menuItem); } } } private void mnuContext_Opening(object sender, EventArgs e) { mnuContext.Renderer = UIStyleUtils.GetToolStripRenderer(UIStyle); foreach (ToolStripItem item in mnuContext.Items) { var menuItem = item as ToolStripMenuItem; var toolbar = item.Tag as DesignerToolbarBase; menuItem.Text = toolbar.Text; menuItem.Checked = toolbar.Visible; } } private void toolbar_Click(object sender, EventArgs e) { var toolbar = (sender as ToolStripItem).Tag as DesignerToolbarBase; toolbar.Visible = !toolbar.Visible; LayoutToolbars(); } private int LayoutToolbar(DesignerToolbarBase toolbar, int left, int top) { bool rtl = RightToLeft == RightToLeft.Yes; toolbar.Location = new Point(rtl ? Width - left - toolbar.Width : left, top); return left + toolbar.Width; } internal void LayoutToolbars() { var rowHeight = standardToolbar.Height; if (rowHeight == 0) return; // get list of visible toolbars var toolbars = toolStripPanel.Controls.OfType().Where(tb => tb.Visible).ToList(); List> rows = new List>(); int maxRows = Height / rowHeight; // find toolbars on each row for (int i = -1; i < maxRows; i++) { var row = new List(); rows.Add(row); int rowTop = i * rowHeight - rowHeight / 2; int rowBottom = rowTop + rowHeight; if (i == -1) { // handle special case when toolbar is dragged out of parent bounds (above the first row) rowTop = -1000; } // find toolbars on this row for (int j = 0; j < toolbars.Count; j++) { var tb = toolbars[j]; if (tb.Top >= rowTop && tb.Top <= rowBottom) { row.Add(tb); // remove from toolbars list to avoid having one toolbar on multiple rows (due to math errors) toolbars.RemoveAt(j); j--; } } if (toolbars.Count == 0) break; } // sort each row by Left (Right in opposite order in case of rtl) bool rtl = RightToLeft == RightToLeft.Yes; rows.ForEach(row => row.Sort((x, y) => rtl ? y.Right.CompareTo(x.Right) : x.Left.CompareTo(y.Left))); // remove empty rows rows.RemoveAll(row => row.Count == 0); // layout toolbars for (int i = 0; i < rows.Count; i++) { int x = 0; int y = i * rowHeight; rows[i].ForEach(tb => x = LayoutToolbar(tb, x, y)); } // set overall height toolStripPanel.Height = rows.Count * rowHeight; } private void toolStripPanel_Paint(object sender, PaintEventArgs e) { var ct = UIStyleUtils.GetColorTable(UIStyle); Rectangle rect = new Rectangle(0, 0, toolStripPanel.Width, toolStripPanel.Height); using (var brush = new LinearGradientBrush(rect, ct.ToolStripPanelGradientBegin, ct.ToolStripPanelGradientEnd, LinearGradientMode.Horizontal)) e.Graphics.FillRectangle(brush, rect); int _1 = this.LogicalToDevice(1); using (var brush = new SolidBrush(ct.ToolStripBorder)) e.Graphics.FillRectangle(brush, 0, rect.Height - _1, rect.Width, _1); } #endregion #region Protected Methods internal override void AfterRestoreState() { base.AfterRestoreState(); #if AVALONIA // this should be deferred to get correct toolbars size this.control.Loaded += (s,e) => #endif LayoutToolbars(); } /// protected override void OnResize(EventArgs e) { base.OnResize(e); if (RightToLeft == RightToLeft.Yes) LayoutToolbars(); } /// protected override void InitPlugins() { base.InitPlugins(); toolStripPanel = new Panel(); toolStripPanel.Dock = DockStyle.Top; toolStripPanel.Paint += toolStripPanel_Paint; Controls.Add(toolStripPanel); mainMenu = new DesignerMenu(this); statusBar = new DesignerStatusBar(this); // create toolbars and make default toolbar layout standardToolbar = new StandardToolbar(this) { Left = 0, Top = 0 }; layoutToolbar = new LayoutToolbar(this) { Left = standardToolbar.Right, Top = 0 }; textToolbar = new TextToolbar(this) { Left = 0, Top = standardToolbar.Bottom }; borderToolbar = new BorderToolbar(this) { Left = textToolbar.Right, Top = textToolbar.Top }; styleToolbar = new StyleToolbar(this) { Left = borderToolbar.Right, Top = textToolbar.Top }; polygonToolbar = new PolygonToolbar(this) { Left = styleToolbar.Right, Top = textToolbar.Top }; var toolbars = new Control[] { standardToolbar, layoutToolbar, textToolbar, borderToolbar, styleToolbar, polygonToolbar }; foreach (var toolbar in toolbars) { // WPF/Avalonia: occurs when toolbar is dragged to a new position. Not used in Mono toolbar.DragDrop += (s, e) => LayoutToolbars(); } toolStripPanel.Controls.AddRange(toolbars); Plugins.AddRange(new IDesignerPlugin[] { mainMenu, statusBar, standardToolbar, textToolbar, borderToolbar, layoutToolbar, styleToolbar, polygonToolbar }); CreateToolbarMenu(); } #endregion #region Public Methods /// public override void ShowStatus(string location, string size, string text, string locationRightBot) { statusBar.UpdateLocationAndSize(location, size, locationRightBot); statusBar.UpdateText(text); } /// public override void UpdateUIStyle() { base.UpdateUIStyle(); toolStripPanel.Refresh(); } /// public override void UpdateDpiDependencies(object sender) { base.UpdateDpiDependencies(sender); mnuContext.Font = this.Font; LayoutToolbars(); } internal void UpdateFirstDialogPage() { // WPF bug: designer workspace is not initialized if the dialog form is the first page in a report (reason: visible designer form is needed) if (ActiveReportTab != null && ActiveReportTab.ActivePageDesigner is DialogPageDesigner pd) pd.UpdateDpiDependencies(); } #endregion /// /// Initializes a new instance of the class with default settings. /// public DesignerControl() { ShowMainMenu = true; ShowStatusBar = true; } } }