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;
}
}
}