1 using System;
2 using System.Collections.Generic;
3 using System.Drawing;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7 using System.Windows.Forms;
8 
9 namespace Mesen.GUI.Controls
10 {
11 	class ctrlSplitContainer : SplitContainer
12 	{
13 		public event EventHandler PanelCollapsed;
14 		public event EventHandler PanelExpanded;
15 		private int _originalDistance = 0;
16 		private int _originalMinSize = 0;
17 		private bool _collapsed = false;
18 		private bool _preventExpand = false;
19 		private bool _hidePanel2 = false;
20 
ctrlSplitContainer()21 		public ctrlSplitContainer()
22 		{
23 			this.DoubleBuffered = true;
24 			this.SplitterMoving += ctrlSplitContainer_SplitterMoving;
25 		}
26 
27 		public bool HidePanel2
28 		{
29 			get { return _hidePanel2; }
30 			set { _hidePanel2 = value; this.Invalidate(); }
31 		}
32 
ctrlSplitContainer_SplitterMoving(object sender, SplitterCancelEventArgs e)33 		private void ctrlSplitContainer_SplitterMoving(object sender, SplitterCancelEventArgs e)
34 		{
35 			if(_originalMinSize > 0) {
36 				e.Cancel = true;
37 				this.BeginInvoke((MethodInvoker)(() => {
38 					this.ExpandPanel();
39 				}));
40 			}
41 		}
42 
OnPaint(PaintEventArgs e)43 		protected override void OnPaint(PaintEventArgs e)
44 		{
45 			base.OnPaint(e);
46 
47 			if(_hidePanel2) {
48 				return;
49 			}
50 
51 			if(this.Orientation == Orientation.Horizontal) {
52 				int top = this.SplitterDistance + 1;
53 				int center = this.Width / 2;
54 				e.Graphics.DrawLine(Pens.DarkGray, center - 100, top, center + 100, top);
55 				top+=2;
56 				e.Graphics.DrawLine(Pens.DarkGray, center - 100, top, center + 100, top);
57 			} else {
58 				int center = this.Height / 2;
59 				int left = this.SplitterDistance + 1;
60 				e.Graphics.DrawLine(Pens.DarkGray, left, center - 100, left, center + 100);
61 				left+=2;
62 				e.Graphics.DrawLine(Pens.DarkGray, left, center - 100, left, center + 100);
63 			}
64 		}
65 
OnDoubleClick(EventArgs e)66 		protected override void OnDoubleClick(EventArgs e)
67 		{
68 			base.OnDoubleClick(e);
69 
70 			if(_hidePanel2) {
71 				return;
72 			}
73 
74 			if(_originalMinSize == 0) {
75 				this.CollapsePanel();
76 				_preventExpand = true;
77 			} else {
78 				this.ExpandPanel();
79 			}
80 		}
81 
ExpandPanel()82 		public void ExpandPanel()
83 		{
84 			if(_hidePanel2 || !_collapsed) {
85 				return;
86 			}
87 
88 			if(this.FixedPanel == FixedPanel.Panel1) {
89 				throw new Exception("Not implemented");
90 			} else if(this.FixedPanel == FixedPanel.Panel2) {
91 				if(_originalMinSize > 0) {
92 					this.Panel2MinSize = _originalMinSize;
93 					this.SplitterDistance = _originalDistance;
94 					_originalMinSize = 0;
95 				}
96 				this.PanelExpanded?.Invoke(this, EventArgs.Empty);
97 				_collapsed = false;
98 			}
99 		}
100 
CollapsePanel()101 		public void CollapsePanel()
102 		{
103 			if(_collapsed) {
104 				return;
105 			}
106 
107 			if(this.FixedPanel == FixedPanel.Panel1) {
108 				throw new Exception("Not implemented");
109 			} else if(this.FixedPanel == FixedPanel.Panel2) {
110 				_collapsed = true;
111 				_originalDistance = this.SplitterDistance;
112 				_originalMinSize = this.Panel2MinSize;
113 				this.Panel2MinSize = 2;
114 				this.SplitterDistance = this.Orientation == Orientation.Horizontal ? this.Height : this.Width;
115 
116 				this.PanelCollapsed?.Invoke(this, EventArgs.Empty);
117 			}
118 		}
119 
GetSplitterDistance()120 		public int GetSplitterDistance()
121 		{
122 			return _originalMinSize > 0 ? _originalDistance : this.SplitterDistance;
123 		}
124 
125 		DateTime _lastResize = DateTime.MinValue;
OnResize(EventArgs e)126 		protected override void OnResize(EventArgs e)
127 		{
128 			base.OnResize(e);
129 
130 			if(_hidePanel2) {
131 				return;
132 			}
133 
134 			//Horrible patch to fix what looks like a resize bug in SplitContainers
135 			//Resizing the window sometimes doesn't resize the inner panels properly
136 			//causing their content to go partially offscreen.
137 			//This code alters SplitterDistance approx 100ms after the last resize event
138 			//to fix the display bug
139 			if(this.IsHandleCreated) {
140 				bool firstResize;
141 				lock(this) {
142 					 firstResize = _lastResize == DateTime.MinValue;
143 					_lastResize = DateTime.Now;
144 				}
145 				if(firstResize) {
146 					Task.Run(() => {
147 						while((DateTime.Now - _lastResize).Milliseconds < 100) {
148 							System.Threading.Thread.Sleep(100);
149 						}
150 
151 						this.BeginInvoke((MethodInvoker)(() => {
152 							if(_originalMinSize == 0) {
153 								this.SuspendLayout();
154 								this.Panel1.SuspendLayout();
155 								this.Panel2.SuspendLayout();
156 								try {
157 									if(this.Width > 0 && this.Height > 0) {
158 										this.SplitterDistance++;
159 										this.SplitterDistance--;
160 									}
161 								} catch {
162 								} finally {
163 									this.ResumeLayout();
164 									this.Panel1.ResumeLayout();
165 									this.Panel2.ResumeLayout();
166 								}
167 							}
168 							this.Invalidate();
169 							lock(this) {
170 								_lastResize = DateTime.MinValue;
171 							}
172 						}));
173 					});
174 				}
175 			}
176 		}
177 
OnMouseUp(MouseEventArgs e)178 		protected override void OnMouseUp(MouseEventArgs e)
179 		{
180 			base.OnMouseUp(e);
181 			this.Panel1.Focus();
182 
183 			if(_hidePanel2) {
184 				return;
185 			}
186 
187 			if(!_preventExpand && _originalMinSize > 0) {
188 				this.ExpandPanel();
189 			}
190 
191 			_preventExpand = false;
192 		}
193 	}
194 }
195