comparison FBGUI/FBGUI.cs @ 88:c9da306e06c9

FBGUI: Improved FBGContainerControl thread safety
author Ivo Smits <Ivo@UCIS.nl>
date Tue, 11 Mar 2014 17:45:48 +0100
parents 4ca44dd25a6a
children 3347e1758e55
comparison
equal deleted inserted replaced
83:4ca44dd25a6a 88:c9da306e06c9
6 using System.Drawing.Imaging; 6 using System.Drawing.Imaging;
7 using System.IO; 7 using System.IO;
8 using System.Reflection; 8 using System.Reflection;
9 using System.Threading; 9 using System.Threading;
10 using System.Windows.Forms; 10 using System.Windows.Forms;
11 using UCIS.Util;
11 using UCIS.VNCServer; 12 using UCIS.VNCServer;
12 using ThreadingTimer = System.Threading.Timer; 13 using ThreadingTimer = System.Threading.Timer;
13 14
14 namespace UCIS.FBGUI { 15 namespace UCIS.FBGUI {
15 public abstract class FBGEvent { 16 public abstract class FBGEvent {
91 void HandleEvent(FBGEvent e); 92 void HandleEvent(FBGEvent e);
92 void Orphaned(); 93 void Orphaned();
93 } 94 }
94 public interface IFBGContainerControl { 95 public interface IFBGContainerControl {
95 void AddControl(IFBGControl control); 96 void AddControl(IFBGControl control);
96 void RemoveControl(IFBGControl control); 97 Boolean RemoveControl(IFBGControl control);
97 void HandleMessage(IFBGControl sender, FBGMessage e); 98 void HandleMessage(IFBGControl sender, FBGMessage e);
98 Size ClientSize { get; } 99 Size ClientSize { get; }
99 } 100 }
100 101
101 public class FBGControl : IFBGControl { 102 public class FBGControl : IFBGControl {
210 protected void RaiseEvent(PaintEventHandler eh, PaintEventArgs ea) { if (eh != null) eh(this, ea); } 211 protected void RaiseEvent(PaintEventHandler eh, PaintEventArgs ea) { if (eh != null) eh(this, ea); }
211 protected void RaiseEvent<T>(EventHandler<T> eh, T ea) where T : EventArgs { if (eh != null) eh(this, ea); } 212 protected void RaiseEvent<T>(EventHandler<T> eh, T ea) where T : EventArgs { if (eh != null) eh(this, ea); }
212 protected void RaiseEvent(EventHandler eh, EventArgs ea) { if (eh != null) eh(this, ea); } 213 protected void RaiseEvent(EventHandler eh, EventArgs ea) { if (eh != null) eh(this, ea); }
213 protected void RaiseEvent(EventHandler eh) { if (eh != null) eh(this, new EventArgs()); } 214 protected void RaiseEvent(EventHandler eh) { if (eh != null) eh(this, new EventArgs()); }
214 } 215 }
215 public class FBGContainerControl : FBGControl, IFBGContainerControl { 216 public class FBGContainerControl : FBGControl, IFBGContainerControl, IList<IFBGControl> {
216 protected List<IFBGControl> controls = new List<IFBGControl>(); 217 protected IFBGControl[] controls = new IFBGControl[0];
217 protected IFBGControl mouseCaptureControl = null; 218 protected IFBGControl mouseCaptureControl = null;
218 protected IFBGControl keyboardCaptureControl = null; 219 protected IFBGControl keyboardCaptureControl = null;
219 public virtual Rectangle ClientRectangle { get { return new Rectangle(Point.Empty, Bounds.Size); } } 220 public virtual Rectangle ClientRectangle { get { return new Rectangle(Point.Empty, Bounds.Size); } }
220 public virtual Size ClientSize { get { return ClientRectangle.Size; } set { Bounds = new Rectangle(Bounds.Location, Bounds.Size - ClientRectangle.Size + value); } } 221 public virtual Size ClientSize { get { return ClientRectangle.Size; } set { Bounds = new Rectangle(Bounds.Location, Bounds.Size - ClientRectangle.Size + value); } }
221 public FBGContainerControl(IFBGContainerControl parent) : base(parent) { } 222 public FBGContainerControl(IFBGContainerControl parent) : base(parent) { }
222 void IFBGContainerControl.AddControl(IFBGControl control) { AddControl(control); } 223 void IFBGContainerControl.AddControl(IFBGControl control) { AddControl(control); }
223 protected virtual void AddControl(IFBGControl control) { 224 protected virtual void AddControl(IFBGControl control) {
224 controls.Add(control); 225 ArrayUtil.Add(ref controls, control);
225 if (control.Visible) Invalidate(control); 226 if (control.Visible) Invalidate(control);
226 } 227 }
227 public virtual void RemoveControl(IFBGControl control) { 228 public virtual Boolean RemoveControl(IFBGControl control) {
228 if (controls.Remove(control)) { 229 if (!ArrayUtil.Remove(ref controls, control)) return false;
229 if (control.Visible) Invalidate(control); 230 if (control.Visible) Invalidate(control);
231 HandleMessage(control, new FBGPointingCaptureMessage(control, false));
232 HandleMessage(control, new FBGKeyboardCaptureMessage(control, false));
233 control.Orphaned();
234 return true;
235 }
236 public virtual void RemoveAllControls() {
237 IFBGControl[] c = Interlocked.Exchange(ref controls, new IFBGControl[0]);
238 foreach (IFBGControl control in c) {
230 HandleMessage(control, new FBGPointingCaptureMessage(control, false)); 239 HandleMessage(control, new FBGPointingCaptureMessage(control, false));
231 HandleMessage(control, new FBGKeyboardCaptureMessage(control, false)); 240 HandleMessage(control, new FBGKeyboardCaptureMessage(control, false));
232 control.Orphaned(); 241 control.Orphaned();
233 } 242 }
234 } 243 Invalidate();
235 public IList<IFBGControl> Controls { get { return controls.AsReadOnly(); } } 244 }
245 public IList<IFBGControl> Controls { get { return this; } }
236 public virtual Point PointToChild(IFBGControl child, Point point) { 246 public virtual Point PointToChild(IFBGControl child, Point point) {
237 return point - (Size)child.Bounds.Location - (Size)ClientRectangle.Location; 247 return point - (Size)child.Bounds.Location - (Size)ClientRectangle.Location;
238 } 248 }
239 public virtual Point PointFromChild(IFBGControl child, Point point) { 249 public virtual Point PointFromChild(IFBGControl child, Point point) {
240 return point + (Size)child.Bounds.Location + (Size)ClientRectangle.Location; 250 return point + (Size)child.Bounds.Location + (Size)ClientRectangle.Location;
241 } 251 }
242 public virtual void BringControlToFront(IFBGControl control) { 252 public virtual void BringControlToFront(IFBGControl control) {
243 if (controls.Count == 0) return; 253 if (controls.Length == 0) return;
244 if (ReferenceEquals(controls[controls.Count - 1], control)) return; 254 int oldindex = Array.IndexOf(controls, control);
245 if (!controls.Remove(control)) return; 255 if (oldindex == -1 || oldindex == controls.Length - 1) return;
246 controls.Add(control); 256 for (int i = oldindex; i < controls.Length - 1; i++) controls[i] = controls[i + 1];
257 controls[controls.Length - 1] = control;
247 if (control.Visible) Invalidate(control); 258 if (control.Visible) Invalidate(control);
248 } 259 }
249 public virtual void Invalidate(IFBGControl control) { 260 public virtual void Invalidate(IFBGControl control) {
250 Invalidate(new Rectangle(PointFromChild(control, Point.Empty), control.Bounds.Size)); 261 Invalidate(new Rectangle(PointFromChild(control, Point.Empty), control.Bounds.Size));
251 } 262 }
276 } 287 }
277 public IFBGControl FindControlAtPosition(Point p) { 288 public IFBGControl FindControlAtPosition(Point p) {
278 Rectangle childarea = ClientRectangle; 289 Rectangle childarea = ClientRectangle;
279 if (!childarea.Contains(p)) return null; 290 if (!childarea.Contains(p)) return null;
280 p.Offset(-childarea.X, -childarea.Y); 291 p.Offset(-childarea.X, -childarea.Y);
281 return ((List<IFBGControl>)controls).FindLast(delegate(IFBGControl control) { return control.Visible && control.Bounds.Contains(p); }); 292 return Array.FindLast(controls, delegate(IFBGControl control) { return control.Visible && control.Bounds.Contains(p); });
282 } 293 }
283 protected override void HandlePointingEvent(FBGPointingEvent e) { 294 protected override void HandlePointingEvent(FBGPointingEvent e) {
284 IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : FindControlAtPosition(e.Position); 295 IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : FindControlAtPosition(e.Position);
285 if (control == null) { 296 if (control == null) {
286 base.HandlePointingEvent(e); 297 base.HandlePointingEvent(e);
326 protected override void HandleKeyboardCaptureEvent(FBGKeyboardCaptureEvent e) { 337 protected override void HandleKeyboardCaptureEvent(FBGKeyboardCaptureEvent e) {
327 if (keyboardCaptureControl != null) keyboardCaptureControl.HandleEvent(new FBGKeyboardCaptureEvent(false)); 338 if (keyboardCaptureControl != null) keyboardCaptureControl.HandleEvent(new FBGKeyboardCaptureEvent(false));
328 base.HandleKeyboardCaptureEvent(e); 339 base.HandleKeyboardCaptureEvent(e);
329 } 340 }
330 protected override void Orphaned() { 341 protected override void Orphaned() {
331 base.Orphaned(); 342 IFBGControl[] c = Interlocked.Exchange(ref controls, new IFBGControl[0]);
332 IFBGControl[] c = controls.ToArray();
333 controls.Clear();
334 foreach (IFBGControl control in c) control.Orphaned(); 343 foreach (IFBGControl control in c) control.Orphaned();
335 mouseCaptureControl = null; 344 mouseCaptureControl = null;
336 keyboardCaptureControl = null; 345 keyboardCaptureControl = null;
337 } 346 base.Orphaned();
347 }
348
349 #region IList<IFBGControl> Members
350 int IList<IFBGControl>.IndexOf(IFBGControl item) { return Array.IndexOf(controls, item); }
351 void IList<IFBGControl>.Insert(int index, IFBGControl item) { throw new NotSupportedException(); }
352 void IList<IFBGControl>.RemoveAt(int index) { RemoveControl(controls[index]); }
353 IFBGControl IList<IFBGControl>.this[int index] {
354 get { return controls[index]; }
355 set { throw new NotSupportedException(); }
356 }
357 void ICollection<IFBGControl>.Add(IFBGControl item) { throw new NotSupportedException(); }
358 void ICollection<IFBGControl>.Clear() { RemoveAllControls(); }
359 bool ICollection<IFBGControl>.Contains(IFBGControl item) { return Array.IndexOf(controls, item) != -1; }
360 void ICollection<IFBGControl>.CopyTo(IFBGControl[] array, int arrayIndex) { controls.CopyTo(array, arrayIndex); }
361 int ICollection<IFBGControl>.Count { get { return controls.Length; } }
362 bool ICollection<IFBGControl>.IsReadOnly { get { return false; } }
363 bool ICollection<IFBGControl>.Remove(IFBGControl item) { return RemoveControl(item); }
364 IEnumerator<IFBGControl> IEnumerable<IFBGControl>.GetEnumerator() { return ((IEnumerable<IFBGControl>)controls).GetEnumerator(); }
365 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return controls.GetEnumerator(); }
366 #endregion
338 } 367 }
339 public class FBGDockContainer : FBGContainerControl { 368 public class FBGDockContainer : FBGContainerControl {
340 private Dictionary<IFBGControl, DockStyle> dockStyles = new Dictionary<IFBGControl, DockStyle>(); 369 private Dictionary<IFBGControl, DockStyle> dockStyles = new Dictionary<IFBGControl, DockStyle>();
341 private Dictionary<IFBGControl, AnchorStyles> anchorStyles = new Dictionary<IFBGControl, AnchorStyles>(); 370 private Dictionary<IFBGControl, AnchorStyles> anchorStyles = new Dictionary<IFBGControl, AnchorStyles>();
342 private Rectangle oldBounds; 371 private Rectangle oldBounds;
349 } 378 }
350 public override void BringControlToFront(IFBGControl control) { 379 public override void BringControlToFront(IFBGControl control) {
351 base.BringControlToFront(control); 380 base.BringControlToFront(control);
352 if (dockStyles.ContainsKey(control)) DoLayout(); 381 if (dockStyles.ContainsKey(control)) DoLayout();
353 } 382 }
354 public override void RemoveControl(IFBGControl control) { 383 public override Boolean RemoveControl(IFBGControl control) {
355 base.RemoveControl(control); 384 if (!base.RemoveControl(control)) return false;
356 if (dockStyles.Remove(control)) DoLayout(); 385 if (dockStyles.Remove(control)) DoLayout();
386 return true;
387 }
388 public override void RemoveAllControls() {
389 base.RemoveAllControls();
390 dockStyles.Clear();
357 } 391 }
358 public override Rectangle Bounds { 392 public override Rectangle Bounds {
359 get { return base.Bounds; } 393 get { return base.Bounds; }
360 set { 394 set {
361 base.Bounds = value; 395 base.Bounds = value;
382 return ds; 416 return ds;
383 } 417 }
384 public void SetDockStyle(IFBGControl control, DockStyle style) { 418 public void SetDockStyle(IFBGControl control, DockStyle style) {
385 if (style == DockStyle.None) { 419 if (style == DockStyle.None) {
386 if (dockStyles.Remove(control)) DoLayout(); 420 if (dockStyles.Remove(control)) DoLayout();
387 } else if (controls.Contains(control)) { 421 } else if (Array.IndexOf(controls, control) != -1) {
388 anchorStyles.Remove(control); 422 anchorStyles.Remove(control);
389 dockStyles[control] = style; 423 dockStyles[control] = style;
390 DoLayout(); 424 DoLayout();
391 } 425 }
392 } 426 }
396 return ds; 430 return ds;
397 } 431 }
398 public void SetAnchorStyle(IFBGControl control, AnchorStyles style) { 432 public void SetAnchorStyle(IFBGControl control, AnchorStyles style) {
399 if (style == (AnchorStyles.Left | AnchorStyles.Top)) { 433 if (style == (AnchorStyles.Left | AnchorStyles.Top)) {
400 anchorStyles.Remove(control); 434 anchorStyles.Remove(control);
401 } else if (controls.Contains(control)) { 435 } else if (Array.IndexOf(controls, control) != -1) {
402 dockStyles.Remove(control); 436 dockStyles.Remove(control);
403 anchorStyles[control] = style; 437 anchorStyles[control] = style;
404 } 438 }
405 } 439 }
406 public void SetAnchor(IFBGControl control, AnchorStyles style, int value) { 440 public void SetAnchor(IFBGControl control, AnchorStyles style, int value) {
407 if (controls.Contains(control)) { 441 if (Array.IndexOf(controls, control) != -1) {
408 AnchorStyles oldstyle; 442 AnchorStyles oldstyle;
409 if (!anchorStyles.TryGetValue(control, out oldstyle)) oldstyle = AnchorStyles.Left | AnchorStyles.Top; 443 if (!anchorStyles.TryGetValue(control, out oldstyle)) oldstyle = AnchorStyles.Left | AnchorStyles.Top;
410 Rectangle b = control.Bounds; 444 Rectangle b = control.Bounds;
411 switch (style) { 445 switch (style) {
412 case AnchorStyles.None: throw new ArgumentException("style", "Anchor style can not be None"); 446 case AnchorStyles.None: throw new ArgumentException("style", "Anchor style can not be None");
494 if (!ReferenceEquals(childControl, null)) throw new InvalidOperationException("This container can have only one child control"); 528 if (!ReferenceEquals(childControl, null)) throw new InvalidOperationException("This container can have only one child control");
495 childControl = control; 529 childControl = control;
496 control.Bounds = new Rectangle(Point.Empty, ClientSize); 530 control.Bounds = new Rectangle(Point.Empty, ClientSize);
497 Invalidate(control.Bounds); 531 Invalidate(control.Bounds);
498 } 532 }
499 void IFBGContainerControl.RemoveControl(IFBGControl control) { 533 Boolean IFBGContainerControl.RemoveControl(IFBGControl control) {
500 if (!ReferenceEquals(childControl, control)) return; 534 if (!ReferenceEquals(childControl, control)) return false;
501 childControl = null; 535 childControl = null;
502 Invalidate(control.Bounds); 536 Invalidate(control.Bounds);
503 if (mouseCaptureControl == control) mouseCaptureControl = null; 537 if (mouseCaptureControl == control) mouseCaptureControl = null;
504 if (keyboardCaptureControl == control) control = null; 538 if (keyboardCaptureControl == control) control = null;
505 control.Orphaned(); 539 control.Orphaned();
540 return true;
506 } 541 }
507 void IFBGContainerControl.HandleMessage(IFBGControl sender, FBGMessage e) { 542 void IFBGContainerControl.HandleMessage(IFBGControl sender, FBGMessage e) {
508 if (e is FBGInvalidateMessage) { 543 if (e is FBGInvalidateMessage) {
509 FBGInvalidateMessage p = (FBGInvalidateMessage)e; 544 FBGInvalidateMessage p = (FBGInvalidateMessage)e;
510 Invalidate(new Rectangle(PointFromChild(sender, p.Area.Location), p.Area.Size)); 545 Invalidate(new Rectangle(PointFromChild(sender, p.Area.Location), p.Area.Size));
1037 foreach (FBGWindowState wsa in windowstates.Values) if (!ReferenceEquals(ws, wsa)) wsa.MenuButton.BackColor = SystemColors.ButtonFace; 1072 foreach (FBGWindowState wsa in windowstates.Values) if (!ReferenceEquals(ws, wsa)) wsa.MenuButton.BackColor = SystemColors.ButtonFace;
1038 ws.MenuButton.BackColor = Color.DarkGray; 1073 ws.MenuButton.BackColor = Color.DarkGray;
1039 } 1074 }
1040 }; 1075 };
1041 } 1076 }
1042 public override void RemoveControl(IFBGControl control) { 1077 public override Boolean RemoveControl(IFBGControl control) {
1043 windowcontainer.RemoveControl(control); 1078 if (!windowcontainer.RemoveControl(control)) return false;
1079 FBGWindowState ws = windowstates[control];
1080 menucontainer.RemoveControl(ws.MenuButton);
1044 windowstates.Remove(control); 1081 windowstates.Remove(control);
1082 ScaleMenuButtons();
1083 return true;
1084 }
1085 public override void RemoveAllControls() {
1086 windowcontainer.RemoveAllControls();
1087 menucontainer.RemoveAllControls();
1088 windowstates.Clear();
1045 ScaleMenuButtons(); 1089 ScaleMenuButtons();
1046 } 1090 }
1047 private void ScaleMenuButtons() { 1091 private void ScaleMenuButtons() {
1048 int bcount = windowstates.Count; 1092 int bcount = windowstates.Count;
1049 int bwidth = 200; 1093 int bwidth = 200;