using FastReport.Utils; using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace FastReport.Controls { internal class FRTabControl : UserControl { private FRTabStrip tabStrip; private PageControl pageControl; private Panel captionPanel; private bool showTabs; private bool closeButtons; private ToolWindowColors style = new ToolWindowColors(); public event EventHandler SelectedTabChanged; public event EventHandler TabClosed; public event TabMovedEventHandler TabMoved; public TabOrientation TabOrientation { get { return tabStrip.TabOrientation; } set { tabStrip.TabOrientation = value; if (value == TabOrientation.Top) { tabStrip.Dock = DockStyle.Top; } else if (value == TabOrientation.Bottom) { tabStrip.Dock = DockStyle.Bottom; } } } public ControlCollection Tabs { get { return pageControl == null ? null : pageControl.Pages; } } public bool ShowCaption { get { return captionPanel.Visible; } set { captionPanel.Visible = value && TabOrientation == TabOrientation.Bottom; } } public bool ShowTabs { get { return showTabs; } set { showTabs = value; UpdateTabStripVisible(); } } public bool CloseButtons { get { return closeButtons; } set { closeButtons = value; } } public ToolWindowColors Style { get => style; set { style = value; tabStrip.Style = value.TabStrip; captionPanel.Refresh(); } } public ContextMenuStrip Menu { get; set; } public PageControlPage SelectedTab { get { return pageControl.ActivePage as PageControlPage; } set { SelectedTabIndex = GetTabIndex(value); } } public int SelectedTabIndex { get { return tabStrip.SelectedTabIndex; } set { tabStrip.SelectedTabIndex = value; } } private int GetTabIndex(PageControlPage page) { for (int i = 0; i < tabStrip.Tabs.Count; i++) { if (tabStrip.Tabs[i].Tag == page) return i; } return -1; } private void UpdateTabStripVisible() { if (tabStrip != null) tabStrip.Visible = showTabs && tabStrip.Tabs.Count > 1; } private void pageControl_ControlAdded(object sender, ControlEventArgs e) { PageControlPage page = e.Control as PageControlPage; Tab tab = new Tab(page.Text, page.Image); tab.Tag = page; tab.CloseButton = closeButtons; tabStrip.Tabs.Add(tab); UpdateTabStripVisible(); } private void pageControl_ControlRemoved(object sender, ControlEventArgs e) { PageControlPage page = e.Control as PageControlPage; int tabIndex = GetTabIndex(page); if (tabIndex != -1) { tabStrip.Tabs.RemoveAt(tabIndex); SelectedTabIndex = SelectedTabIndex; UpdateTabStripVisible(); } } private void tabStrip_TabChanged(object sender, EventArgs e) { int idx = tabStrip.SelectedTabIndex; if (idx >= 0) { pageControl.ActivePage = tabStrip.SelectedTab.Tag as PageControlPage; // update the title captionPanel.Refresh(); } if (SelectedTabChanged != null) SelectedTabChanged(this, e); } private void tabStrip_TabClosed(object sender, EventArgs e) { if (TabClosed != null) TabClosed((sender as Tab).Tag as PageControlPage, e); } private void tabStrip_TabMoved(object sender, TabMovedEventArgs e) { if (TabMoved != null) TabMoved(this, e); } public void UpdateDpiDependencies() { captionPanel.Height = this.LogicalToDevice(24); tabStrip.Height = this.LogicalToDevice(25); foreach (Tab tab in tabStrip.Tabs) { if (tab.Tag is PageControlPage pg) tab.Image = pg.Image; } } public void UpdateText() { foreach (Tab tab in tabStrip.Tabs) { if (tab.Tag is PageControlPage pg) tab.Text = pg.Text; } tabStrip.Refresh(); captionPanel.Refresh(); } public FRTabControl() { captionPanel = new CaptionPanel(this); captionPanel.Dock = DockStyle.Top; captionPanel.BackColor = Color.FromArgb(204, 199, 186); tabStrip = new FRTabStrip(); tabStrip.Dock = DockStyle.Bottom; tabStrip.TabOrientation = TabOrientation.Bottom; tabStrip.AllowTabReorder = false; tabStrip.Visible = false; tabStrip.SelectedTabChanged += tabStrip_TabChanged; tabStrip.TabClosed += tabStrip_TabClosed; tabStrip.TabMoved += tabStrip_TabMoved; pageControl = new PageControl(); pageControl.Dock = DockStyle.Fill; pageControl.ControlAdded += pageControl_ControlAdded; pageControl.ControlRemoved += pageControl_ControlRemoved; Controls.Add(pageControl); Controls.Add(tabStrip); Controls.Add(captionPanel); TabOrientation = TabOrientation.Bottom; ShowCaption = true; ShowTabs = true; CloseButtons = true; UpdateDpiDependencies(); } private class CaptionPanel : Panel { private FRTabControl owner; private bool hlMenuButton; protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); var rtl = RightToLeft == RightToLeft.Yes; var g = e.Graphics; var rect = new Rectangle(0, 0, Width, Height); using (var brush = new LinearGradientBrush(rect, owner.Style.Caption.GradientBegin, owner.Style.Caption.GradientEnd, LinearGradientMode.Vertical)) { g.FillRectangle(brush, rect); } rect.Inflate(this.LogicalToDevice(-4), 0); if (owner.ShowCaption && owner.tabStrip != null && owner.tabStrip.SelectedTab != null) TextRenderer.DrawText(g, owner.tabStrip.SelectedTab.Text, Font, rect, owner.Style.Caption.ForeColor, TextFormatFlags.VerticalCenter | (rtl ? TextFormatFlags.Right : TextFormatFlags.Left)); if (owner.Menu != null) { int _2 = this.LogicalToDevice(2); int _16 = this.LogicalToDevice(16); int _19 = this.LogicalToDevice(19); rect = new Rectangle(rtl ? _2 : Width - _19, (Height - _16) / 2, _16, _16); if (hlMenuButton) { using (var brush = new SolidBrush(owner.Style.Caption.HighlightButton)) { g.FillRectangle(brush, rect); } } // ownerdrawn down arrow: may be useful for contrast themes /*using (var pen = new Pen(owner.Style.Caption.ForeColor, this.LogicalToDevice(1f))) { int _4 = this.LogicalToDevice(4); int _8 = this.LogicalToDevice(8); int x = rect.Left + _4; int y = rect.Top + rect.Height / 2 - _2; g.SmoothingMode = SmoothingMode.HighQuality; g.DrawLines(pen, new Point[] { new Point(x, y), new Point(x + _4, y + _4), new Point(x + _8, y) }); }*/ g.DrawImage(this.GetImage(182), rect); } } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); var rtl = RightToLeft == RightToLeft.Yes; hlMenuButton = rtl ? e.X < Height : e.X > Width - Height; if (owner.Menu != null) Refresh(); } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if (e.Button == MouseButtons.Left && hlMenuButton && owner.Menu != null) { var rtl = RightToLeft == RightToLeft.Yes; int _19 = this.LogicalToDevice(19); hlMenuButton = false; Refresh(); owner.Menu.Show(this, rtl ? _19 : Width - _19, Height); } } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); hlMenuButton = false; if (owner.Menu != null) Refresh(); } public CaptionPanel(FRTabControl owner) { this.owner = owner; SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); } } } }