dynamictreerow.cs

来自「SharpDevelop2.0.0 c#开发免费工具」· CS 代码 · 共 448 行

CS
448
字号
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
//     <version>$Revision: 1351 $</version>
// </file>

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace ICSharpCode.SharpDevelop.Gui.TreeGrid
{
	public class DynamicTreeRow : DynamicListRow
	{
		CollectionWithEvents<DynamicListColumn> childColumns = new CollectionWithEvents<DynamicListColumn>();
		CollectionWithEvents<DynamicListRow> childRows = new CollectionWithEvents<DynamicListRow>();
		
		DynamicListItem plus;
		
		public DynamicTreeRow()
		{
			plus = this[0];
			ShowPlus = true;
		}
		
		#region Plus painting
		bool showPlus;
		
		public bool ShowPlus {
			get {
				return showPlus;
			}
			set {
				if (showPlus == value)
					return;
				showPlus = value;
				plus.HighlightBrush = showPlus ? Brushes.AliceBlue : null;
				plus.Cursor = showPlus ? Cursors.Hand : null;
				if (showPlus) {
					plus.Click += OnPlusClick;
					plus.Paint += OnPlusPaint;
				} else {
					plus.Click -= OnPlusClick;
					plus.Paint -= OnPlusPaint;
				}
				OnShowPlusChanged(EventArgs.Empty);
			}
		}
		
		static readonly Color PlusBorder = Color.FromArgb(120, 152, 181);
		static readonly Color LightPlusBorder = Color.FromArgb(176, 194, 221);
		public static readonly Color DefaultExpandedRowColor = Color.FromArgb(235, 229, 209);
		
		public static void DrawPlusSign(Graphics graphics, Rectangle r, bool drawMinus)
		{
			using (Brush b = new LinearGradientBrush(r, Color.White, DynamicListColumn.DefaultRowHighlightBackColor, 66f)) {
				graphics.FillRectangle(b, r);
			}
			using (Pen p = new Pen(PlusBorder)) {
				graphics.DrawRectangle(p, r);
			}
			using (Brush b = new SolidBrush(LightPlusBorder)) {
				graphics.FillRectangle(b, new Rectangle(r.X, r.Y, 1, 1));
				graphics.FillRectangle(b, new Rectangle(r.Right, r.Y, 1, 1));
				graphics.FillRectangle(b, new Rectangle(r.X, r.Bottom, 1, 1));
				graphics.FillRectangle(b, new Rectangle(r.Right, r.Bottom, 1, 1));
			}
			graphics.DrawLine(Pens.Black, r.Left + 2, r.Top + r.Height / 2, r.Right - 2, r.Top + r.Height / 2);
			if (!drawMinus) {
				graphics.DrawLine(Pens.Black, r.Left + r.Width / 2, r.Top + 2, r.Left + r.Width / 2, r.Bottom - 2);
			}
		}
		
		protected virtual void OnPlusPaint(object sender, ItemPaintEventArgs e)
		{
			Rectangle r = e.ClipRectangle;
			r.Inflate(-4, -4);
			DrawPlusSign(e.Graphics, r, expandedIn != null && expandedIn.Contains(e.List));
		}
		
		protected override DynamicListItem CreateItem()
		{
			DynamicListItem item = base.CreateItem();
			item.Paint += delegate(object sender, ItemPaintEventArgs e) {
				if (e.Item != plus && expandedIn != null && !expandedRowColor.IsEmpty && expandedIn.Contains(e.List)) {
					using (Brush b = new SolidBrush(expandedRowColor)) {
						e.Graphics.FillRectangle(b, e.FillRectangle);
					}
				}
			};
			return item;
		}
		
		List<DynamicList> expandedIn;
		Color expandedRowColor = DefaultExpandedRowColor;
		
		public bool ShowMinusWhileExpanded {
			get {
				return expandedIn != null;
			}
			set {
				if (this.ShowMinusWhileExpanded == value)
					return;
				expandedIn = value ? new List<DynamicList>() : null;
			}
		}
		
		/// <summary>
		/// Gets/Sets the row color used when the row is expanded. Only works together with ShowMinusWhileExpanded.
		/// </summary>
		public Color ExpandedRowColor {
			get {
				return expandedRowColor;
			}
			set {
				expandedRowColor = value;
			}
		}
		#endregion
		
		#region Events
		public event EventHandler<DynamicListEventArgs> Expanding;
		public event EventHandler<DynamicListEventArgs> Expanded;
		public event EventHandler<DynamicListEventArgs> Collapsed;
		public event EventHandler ShowPlusChanged;
		
		protected virtual void OnExpanding(DynamicListEventArgs e)
		{
			if (Expanding != null) {
				Expanding(this, e);
			}
		}
		protected virtual void OnExpanded(DynamicListEventArgs e)
		{
			if (Expanded != null) {
				Expanded(this, e);
			}
		}
		protected virtual void OnCollapsed(DynamicListEventArgs e)
		{
			if (Collapsed != null) {
				Collapsed(this, e);
			}
		}
		public virtual void OnShowPlusChanged(EventArgs e)
		{
			if (ShowPlusChanged != null) {
				ShowPlusChanged(this, e);
			}
		}
		#endregion
		
		#region Properties
		public CollectionWithEvents<DynamicListColumn> ChildColumns {
			get {
				return childColumns;
			}
			set {
				if (value == null)
					throw new ArgumentNullException("value");
				childColumns = value;
			}
		}
		
		public CollectionWithEvents<DynamicListRow> ChildRows {
			get {
				return childRows;
			}
			set {
				if (value == null)
					throw new ArgumentNullException("value");
				childRows = value;
			}
		}
		
		public static readonly Color DefaultBorderColor = Color.FromArgb(195, 192, 175);
		
		Color childBorderColor = DefaultBorderColor;
		
		public Color ChildBorderColor {
			get {
				return childBorderColor;
			}
			set {
				childBorderColor = value;
			}
		}
		#endregion
		
		#region Child form
		static bool isOpeningChild;
		
		/// <summary>
		/// Block the next click event - used to ensure that a click on the "-" sign
		/// does not cause the submenu to open again when the "-" sign becomes a "+" sign
		/// before the click event is handled.
		/// </summary>
		bool blockClickEvent;
		
		protected virtual void OnPlusClick(object sender, DynamicListEventArgs e)
		{
			if (blockClickEvent) { blockClickEvent = false; return; }
			OnExpanding(e);
			ChildForm frm = new ChildForm();
			frm.Closed += delegate {
				blockClickEvent = true;
				if (expandedIn != null)
					expandedIn.Remove(e.List);
				OnCollapsed(e);
				plus.RaiseItemChanged();
				Timer timer = new Timer();
				timer.Interval = 85;
				timer.Tick += delegate(object sender2, EventArgs e2) { 
					((Timer)sender2).Stop();
					((Timer)sender2).Dispose();
					blockClickEvent = false;
				};
				timer.Start();
			};
			Point p = e.List.PointToScreen(e.List.GetPositionFromRow(this));
			p.Offset(e.List.Columns[0].Width, Height);
			frm.StartPosition = FormStartPosition.Manual;
			frm.BackColor = childBorderColor;
			frm.Location = p;
			frm.ShowInTaskbar = false;
			frm.Owner = e.List.FindForm();
			
			VerticalScrollContainer scrollContainer = new VerticalScrollContainer();
			scrollContainer.Dock = DockStyle.Fill;
			
			DynamicList childList = new DynamicList(childColumns, childRows);
			childList.Dock = DockStyle.Fill;
			childList.KeyDown += delegate(object sender2, KeyEventArgs e2) {
				if (e2.KeyData == Keys.Escape) {
					frm.Close();
					// workaround focus problem: sometimes the mainform gets focus after this
					e.List.FindForm().Focus();
				}
			};
			scrollContainer.Controls.Add(childList);
			
			frm.Controls.Add(scrollContainer);
			
			int screenHeight = Screen.FromPoint(p).WorkingArea.Bottom - p.Y;
			screenHeight -= frm.Size.Height - frm.ClientSize.Height;
			int requiredHeight = childList.TotalRowHeight + 4;
			int formHeight = Math.Min(requiredHeight, screenHeight);
			if (formHeight < requiredHeight) {
				int missingHeight = Math.Min(100, requiredHeight - formHeight);
				formHeight += missingHeight;
				frm.Top -= missingHeight;
			}
			// Autosize child window
			int formWidth;
			using (Graphics g = childList.CreateGraphics()) {
				formWidth = 8 + childList.GetRequiredWidth(g);
			}
			int screenWidth = Screen.FromPoint(p).WorkingArea.Right - p.X;
			if (formWidth > screenWidth) {
				int missingWidth = Math.Min(100, formWidth - screenWidth);
				formWidth = screenWidth + missingWidth;
				frm.Left -= missingWidth;
			}
			frm.ClientSize = new Size(formWidth, formHeight);
			frm.MinimumSize = new Size(100, Math.Min(50, formHeight));
			isOpeningChild = true;
			frm.Show();
			isOpeningChild = false;
			childList.Focus();
			if (expandedIn != null)
				expandedIn.Add(e.List);
			OnExpanded(e);
			plus.RaiseItemChanged();
		}
		
		public class ChildForm : Form, IActivatable
		{
			bool isActivated = true;
			
			public bool IsActivated {
				get {
					return isActivated;
				}
			}
			
			bool allowResizing = true;
			
			public bool AllowResizing {
				get {
					return allowResizing;
				}
				set {
					if (allowResizing == value)
						return;
					allowResizing = value;
					this.DockPadding.All = value ? 2 : 1;
				}
			}
			
			public ChildForm()
			{
				this.FormBorderStyle = FormBorderStyle.None;
				this.DockPadding.All = 2;
				this.BackColor = DefaultBorderColor;
			}
			
			bool showWindowWithoutActivation;
			
			/// <summary>
			/// Gets/Sets whether the window will receive focus when it is shown.
			/// </summary>
			public bool ShowWindowWithoutActivation {
				get {
					return showWindowWithoutActivation;
				}
				set {
					showWindowWithoutActivation = value;
				}
			}
			
			protected override bool ShowWithoutActivation {
				get {
					return showWindowWithoutActivation;
				}
			}
			
			protected override CreateParams CreateParams {
				get {
					CreateParams p = base.CreateParams;
					ICSharpCode.TextEditor.Gui.CompletionWindow.AbstractCompletionWindow.AddShadowToWindow(p);
					return p;
				}
			}
			
			#region Resizing the form
			private enum MousePositionCodes
			{
				HTERROR             = (-2),
				HTTRANSPARENT       = (-1),
				HTNOWHERE           = 0,
				HTCLIENT            = 1,
				HTCAPTION           = 2,
				HTSYSMENU           = 3,
				HTGROWBOX           = 4,
				HTSIZE              = HTGROWBOX,
				HTMENU              = 5,
				HTHSCROLL           = 6,
				HTVSCROLL           = 7,
				HTMINBUTTON         = 8,
				HTMAXBUTTON         = 9,
				HTLEFT              = 10,
				HTRIGHT             = 11,
				HTTOP               = 12,
				HTTOPLEFT           = 13,
				HTTOPRIGHT          = 14,
				HTBOTTOM            = 15,
				HTBOTTOMLEFT        = 16,
				HTBOTTOMRIGHT       = 17,
				HTBORDER            = 18,
				HTREDUCE            = HTMINBUTTON,
				HTZOOM              = HTMAXBUTTON,
				HTSIZEFIRST         = HTLEFT,
				HTSIZELAST          = HTBOTTOMRIGHT,
				HTOBJECT            = 19,
				HTCLOSE             = 20,
				HTHELP              = 21
			}
			
			protected override void WndProc(ref Message m)
			{
				base.WndProc(ref m);
				if (m.Msg == 0x0084) // WM_NCHITTEST
					HitTest(ref m);
			}
			
			void HitTest(ref Message m)
			{
				if (!allowResizing)
					return;
				int mousePos = m.LParam.ToInt32();
				int mouseX = mousePos & 0xffff;
				int mouseY = mousePos >> 16;
				//System.Diagnostics.Debug.WriteLine(mouseX + " / " + mouseY);
				Rectangle bounds = Bounds;
				bool isLeft = mouseX == bounds.Left || mouseX + 1 == bounds.Left;
				bool isTop = mouseY == bounds.Top || mouseY + 1 == bounds.Top;
				bool isRight = mouseX == bounds.Right - 1 || mouseX == bounds.Right - 2;
				bool isBottom = mouseY == bounds.Bottom - 1 || mouseY == bounds.Bottom - 2;
				if (isLeft) {
					if (isTop)
						m.Result = new IntPtr((int)MousePositionCodes.HTTOPLEFT);
					else if (isBottom)
						m.Result = new IntPtr((int)MousePositionCodes.HTBOTTOMLEFT);
					else
						m.Result = new IntPtr((int)MousePositionCodes.HTLEFT);
				} else if (isRight) {
					if (isTop)
						m.Result = new IntPtr((int)MousePositionCodes.HTTOPRIGHT);
					else if (isBottom)
						m.Result = new IntPtr((int)MousePositionCodes.HTBOTTOMRIGHT);
					else
						m.Result = new IntPtr((int)MousePositionCodes.HTRIGHT);
				} else if (isTop) {
					m.Result = new IntPtr((int)MousePositionCodes.HTTOP);
				} else if (isBottom) {
					m.Result = new IntPtr((int)MousePositionCodes.HTBOTTOM);
				}
			}
			#endregion
			
			protected override void OnActivated(EventArgs e)
			{
				isActivated = true;
				base.OnActivated(e);
				Refresh();
			}
			
			protected override void OnDeactivate(EventArgs e)
			{
				isActivated = false;
				base.OnDeactivate(e);
				if (isOpeningChild) {
					Refresh();
					return;
				}
				BeginInvoke(new MethodInvoker(CloseOnDeactivate));
			}
			
			void CloseOnDeactivate()
			{
				ChildForm owner = Owner as ChildForm;
				if (owner != null) {
					if (owner.isActivated)
						Close();
					else
						owner.CloseOnDeactivate();
				} else {
					Close();
				}
			}
		}
		#endregion
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?