Mercurial > hg > ucis.core
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; |