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