comparison FBGUI.cs @ 23:644a923bca98

Added FBGUI and VNCServer
author Ivo Smits <Ivo@UCIS.nl>
date Mon, 15 Apr 2013 02:04:36 +0200
parents
children 7f0b7a53a000
comparison
equal deleted inserted replaced
22:5b14fed54a89 23:644a923bca98
1 using System;
2 using System.Collections.Generic;
3 using System.Drawing;
4 using System.Drawing.Drawing2D;
5 using System.Drawing.Imaging;
6 using System.IO;
7 using System.Threading;
8 using System.Windows.Forms;
9 using UCIS.VNCServer;
10 using ThreadingTimer = System.Threading.Timer;
11
12 namespace UCIS.FBGUI {
13 public interface IFBGControl {
14 Rectangle Bounds { get; set; }
15 Boolean Visible { get; set; }
16 void Paint(Graphics g);
17 void MouseMove(Point position, MouseButtons buttons);
18 void MouseDown(Point position, MouseButtons buttons);
19 void MouseUp(Point position, MouseButtons buttons);
20 void KeyDown(Keys key);
21 void KeyPress(Char keyChar);
22 void KeyUp(Keys key);
23 void LostKeyboardCapture();
24 void Orphaned();
25 }
26 public interface IFBGContainerControl {
27 Size Size { get; } //Todo: really necessary? Probably not.
28 void Invalidate(IFBGControl control, Rectangle rect);
29 void AddControl(IFBGControl control);
30 void RemoveControl(IFBGControl control);
31 Boolean CaptureMouse(IFBGControl control, Boolean capture);
32 Boolean CaptureKeyboard(IFBGControl control, Boolean capture);
33 }
34 public class FBGControl : IFBGControl {
35 private Rectangle bounds = new Rectangle(0, 0, 100, 100);
36 private Color backColor = Color.Transparent;
37 private Boolean visible = true;
38 public virtual IFBGContainerControl Parent { get; private set; }
39 public event MouseEventHandler OnMouseDown;
40 public event MouseEventHandler OnMouseMove;
41 public event MouseEventHandler OnMouseUp;
42 public event PaintEventHandler OnPaint;
43 public event EventHandler OnResize;
44 public event EventHandler OnMove;
45 public FBGControl(IFBGContainerControl parent) {
46 this.Parent = parent;
47 if (Parent != null) Parent.AddControl(this);
48 }
49 public virtual Rectangle Bounds {
50 get { return bounds; }
51 set {
52 if (bounds == value) return;
53 Rectangle old = bounds;
54 bounds = value;
55 Parent.Invalidate(this, Rectangle.Union(new Rectangle(Point.Empty, value.Size), new Rectangle(old.X - value.X, old.Y - value.Y, old.Width, old.Height)));
56 if (value.Location != old.Location) RaiseEvent(OnMove);
57 if (value.Size != old.Size) RaiseEvent(OnResize);
58 }
59 }
60 public virtual Boolean Visible {
61 get { return visible; }
62 set {
63 visible = value;
64 Invalidate();
65 }
66 }
67 public Size Size { get { return Bounds.Size; } set { Rectangle r = Bounds; r.Size = value; Bounds = r; } }
68 public Point Location { get { return Bounds.Location; } set { Rectangle r = Bounds; r.Location = value; Bounds = r; } }
69 public int Left { get { return Bounds.Left; } set { Rectangle r = Bounds; r.X = value; Bounds = r; } }
70 public int Top { get { return Bounds.Top; } set { Rectangle r = Bounds; r.Y = value; Bounds = r; } }
71 public int Width { get { return Bounds.Width; } set { Rectangle r = Bounds; r.Width = value; Bounds = r; } }
72 public int Height { get { return Bounds.Height; } set { Rectangle r = Bounds; r.Height = value; Bounds = r; } }
73 public virtual Color BackColor { get { return backColor; } set { if (backColor == value) return; backColor = value; Invalidate(); } }
74 public virtual void Invalidate() {
75 Invalidate(new Rectangle(Point.Empty, Bounds.Size));
76 }
77 public virtual void Invalidate(Rectangle rect) {
78 Parent.Invalidate(this, rect);
79 }
80 void IFBGControl.Paint(Graphics g) { Paint(g); }
81 void IFBGControl.MouseMove(Point position, MouseButtons buttons) { MouseMove(position, buttons); }
82 void IFBGControl.MouseDown(Point position, MouseButtons buttons) { MouseDown(position, buttons); }
83 void IFBGControl.MouseUp(Point position, MouseButtons buttons) { MouseUp(position, buttons); }
84 void IFBGControl.KeyDown(Keys g) { KeyDown(g); }
85 void IFBGControl.KeyPress(Char g) { KeyPress(g); }
86 void IFBGControl.KeyUp(Keys g) { KeyUp(g); }
87 void IFBGControl.LostKeyboardCapture() { LostKeyboardCapture(); }
88 void IFBGControl.Orphaned() { Orphaned(); }
89 protected virtual void Paint(Graphics g) {
90 if (!visible) return;
91 if (backColor.A != 0) g.Clear(backColor);
92 RaiseEvent(OnPaint, new PaintEventArgs(g, Rectangle.Round(g.ClipBounds)));
93 }
94 protected virtual void MouseMove(Point position, MouseButtons buttons) { RaiseEvent(OnMouseMove, new MouseEventArgs(buttons, 0, position.X, position.Y, 0)); }
95 protected virtual void MouseDown(Point position, MouseButtons buttons) { RaiseEvent(OnMouseDown, new MouseEventArgs(buttons, 1, position.X, position.Y, 0)); }
96 protected virtual void MouseUp(Point position, MouseButtons buttons) { RaiseEvent(OnMouseUp, new MouseEventArgs(buttons, 1, position.X, position.Y, 0)); }
97 protected virtual Boolean CaptureMouse(Boolean capture) {
98 return Parent.CaptureMouse(this, capture);
99 }
100 protected virtual void KeyDown(Keys key) { }
101 protected virtual void KeyPress(Char keyChar) { }
102 protected virtual void KeyUp(Keys key) { }
103 protected virtual Boolean CaptureKeyboard(Boolean capture) {
104 return Parent.CaptureKeyboard(this, capture);
105 }
106 protected virtual void LostKeyboardCapture() { }
107 protected virtual void Orphaned() {
108 //IDisposable disp = this as IDisposable;
109 //if (!ReferenceEquals(disp, null)) disp.Dispose();
110 }
111 protected void RaiseEvent(KeyEventHandler eh, KeyEventArgs ea) { if (eh != null) eh(this, ea); }
112 protected void RaiseEvent(KeyPressEventHandler eh, KeyPressEventArgs ea) { if (eh != null) eh(this, ea); }
113 protected void RaiseEvent(MouseEventHandler eh, MouseEventArgs ea) { if (eh != null) eh(this, ea); }
114 protected void RaiseEvent(PaintEventHandler eh, PaintEventArgs ea) { if (eh != null) eh(this, ea); }
115 protected void RaiseEvent<T>(EventHandler<T> eh, T ea) where T : EventArgs { if (eh != null) eh(this, ea); }
116 protected void RaiseEvent(EventHandler eh, EventArgs ea) { if (eh != null) eh(this, ea); }
117 protected void RaiseEvent(EventHandler eh) { if (eh != null) eh(this, new EventArgs()); }
118 }
119 public class FBGContainerControl : FBGControl, IFBGContainerControl {
120 protected List<IFBGControl> controls = new List<IFBGControl>();
121 private IFBGControl mouseCaptureControl = null;
122 private IFBGControl keyboardCaptureControl = null;
123 private Rectangle childarea = Rectangle.Empty;
124 public Rectangle ClientRectangle { get { return childarea; } protected set { childarea = value; Invalidate(); } }
125 public FBGContainerControl(IFBGContainerControl parent) : base(parent) { }
126 Size IFBGContainerControl.Size { get { return childarea.IsEmpty ? Bounds.Size : childarea.Size; } }
127 void IFBGContainerControl.AddControl(IFBGControl control) { AddControl(control); }
128 protected virtual void AddControl(IFBGControl control) {
129 controls.Add(control);
130 if (control.Visible) Invalidate(control);
131 }
132 public virtual void RemoveControl(IFBGControl control) {
133 if (controls.Remove(control)) {
134 if (control.Visible) Invalidate(control);
135 CaptureMouse(control, false);
136 CaptureKeyboard(control, false);
137 control.Orphaned();
138 }
139 }
140 public virtual Point PointToChild(IFBGControl child, Point point) {
141 return point - (Size)child.Bounds.Location - (Size)ClientRectangle.Location;
142 }
143 public virtual Point PointFromChild(IFBGControl child, Point point) {
144 return point + (Size)child.Bounds.Location + (Size)ClientRectangle.Location;
145 }
146 public virtual void BringControlToFront(IFBGControl control) {
147 if (controls.Count == 0) return;
148 if (ReferenceEquals(controls[controls.Count - 1], control)) return;
149 if (!controls.Remove(control)) return;
150 controls.Add(control);
151 if (control.Visible) Invalidate(control);
152 }
153 public virtual void Invalidate(IFBGControl control) {
154 Invalidate(new Rectangle(PointFromChild(control, Point.Empty), control.Bounds.Size));
155 }
156 public virtual void Invalidate(IFBGControl control, Rectangle rect) {
157 Invalidate(new Rectangle(PointFromChild(control, rect.Location), rect.Size));
158 }
159 protected override void Paint(Graphics g) {
160 base.Paint(g);
161 if (controls == null) return;
162 GraphicsState state2 = null;
163 if (!childarea.IsEmpty) {
164 state2 = g.Save();
165 g.TranslateTransform(childarea.X, childarea.Y, MatrixOrder.Append);
166 g.IntersectClip(new Rectangle(Point.Empty, childarea.Size));
167 }
168 foreach (IFBGControl control in controls) {
169 if (!control.Visible) continue;
170 if (control.Bounds.Width <= 0 || control.Bounds.Height <= 0) continue;
171 if (!g.ClipBounds.IntersectsWith((RectangleF)control.Bounds)) continue;
172 GraphicsState state = g.Save();
173 g.TranslateTransform(control.Bounds.X, control.Bounds.Y, MatrixOrder.Append);
174 g.IntersectClip(new Rectangle(Point.Empty, control.Bounds.Size));
175 control.Paint(g);
176 g.Restore(state);
177 }
178 if (state2 != null) g.Restore(state2);
179 }
180 public IFBGControl FindControlAtPosition(Point p) {
181 if (!childarea.IsEmpty && !childarea.Contains(p)) return null;
182 p.Offset(-childarea.X, -childarea.Y);
183 return ((List<IFBGControl>)controls).FindLast(delegate(IFBGControl control) { return control.Visible && control.Bounds.Contains(p); });
184 }
185 protected override void MouseMove(Point position, MouseButtons buttons) {
186 IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : FindControlAtPosition(position);
187 if (control == null) {
188 base.MouseMove(position, buttons);
189 } else {
190 control.MouseMove(PointToChild(control, position), buttons);
191 }
192 }
193 protected override void MouseDown(Point position, MouseButtons buttons) {
194 IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : FindControlAtPosition(position);
195 if (control == null) {
196 base.MouseDown(position, buttons);
197 } else {
198 control.MouseDown(PointToChild(control, position), buttons);
199 }
200 }
201 protected override void MouseUp(Point position, MouseButtons buttons) {
202 IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : FindControlAtPosition(position);
203 if (control == null) {
204 base.MouseUp(position, buttons);
205 } else {
206 control.MouseUp(PointToChild(control, position), buttons);
207 }
208 }
209 Boolean IFBGContainerControl.CaptureMouse(IFBGControl control, Boolean capture) { return CaptureMouse(control, capture); }
210 protected Boolean CaptureMouse(IFBGControl control, Boolean capture) {
211 if (capture && !ReferenceEquals(mouseCaptureControl, null)) return false;
212 if (!capture && !ReferenceEquals(mouseCaptureControl, control)) return false;
213 if (!CaptureMouse(capture)) return false;
214 mouseCaptureControl = capture ? control : null;
215 return true;
216 }
217 protected override void KeyDown(Keys key) {
218 if (ReferenceEquals(keyboardCaptureControl, null)) base.KeyDown(key);
219 else keyboardCaptureControl.KeyDown(key);
220 }
221 protected override void KeyPress(Char keyChar) {
222 if (ReferenceEquals(keyboardCaptureControl, null)) base.KeyPress(keyChar);
223 else keyboardCaptureControl.KeyPress(keyChar);
224 }
225 protected override void KeyUp(Keys key) {
226 if (ReferenceEquals(keyboardCaptureControl, null)) base.KeyUp(key);
227 else keyboardCaptureControl.KeyUp(key);
228 }
229 Boolean IFBGContainerControl.CaptureKeyboard(IFBGControl control, Boolean capture) { return CaptureKeyboard(control, capture); }
230 protected Boolean CaptureKeyboard(IFBGControl control, Boolean capture) {
231 if (!capture && !ReferenceEquals(keyboardCaptureControl, control)) return false;
232 if (!CaptureKeyboard(capture)) return false;
233 IFBGControl prev = keyboardCaptureControl;
234 keyboardCaptureControl = capture ? control : null;
235 if (prev != null) LostKeyboardCapture();
236 return true;
237 }
238 protected override void LostKeyboardCapture() {
239 base.LostKeyboardCapture();
240 if (keyboardCaptureControl != null) keyboardCaptureControl.LostKeyboardCapture();
241 }
242 protected override void Orphaned() {
243 base.Orphaned();
244 IFBGControl[] c = controls.ToArray();
245 controls.Clear();
246 foreach (IFBGControl control in c) control.Orphaned();
247 mouseCaptureControl = null;
248 keyboardCaptureControl = null;
249 }
250 }
251 public class FBGDockContainer : FBGContainerControl {
252 private Dictionary<IFBGControl, DockStyle> dockStyles = new Dictionary<IFBGControl, DockStyle>();
253 private Dictionary<IFBGControl, AnchorStyles> anchorStyles = new Dictionary<IFBGControl, AnchorStyles>();
254 private Rectangle oldBounds;
255 public FBGDockContainer(IFBGContainerControl parent)
256 : base(parent) {
257 oldBounds = ClientRectangle.IsEmpty ? Bounds : new Rectangle(Bounds.Location + (Size)ClientRectangle.Location, ClientRectangle.Size);
258 }
259 protected override void AddControl(IFBGControl control) {
260 base.AddControl(control);
261 }
262 public override void BringControlToFront(IFBGControl control) {
263 base.BringControlToFront(control);
264 if (dockStyles.ContainsKey(control)) DoLayout();
265 }
266 public override void RemoveControl(IFBGControl control) {
267 base.RemoveControl(control);
268 if (dockStyles.Remove(control)) DoLayout();
269 }
270 public override Rectangle Bounds {
271 get { return base.Bounds; }
272 set {
273 base.Bounds = value;
274 DoLayout();
275 Rectangle newBounds = ClientRectangle.IsEmpty ? Bounds : new Rectangle(Bounds.Location + (Size)ClientRectangle.Location, ClientRectangle.Size);
276 foreach (KeyValuePair<IFBGControl, AnchorStyles> c in anchorStyles) {
277 Rectangle b = c.Key.Bounds;
278 if ((c.Value & AnchorStyles.Right) != 0) {
279 if ((c.Value & AnchorStyles.Left) == 0) b.X += newBounds.Width - oldBounds.Width;
280 else b.Width += newBounds.Width - oldBounds.Width;
281 } else if ((c.Value & AnchorStyles.Left) == 0) b.X += newBounds.X - oldBounds.X;
282 if ((c.Value & AnchorStyles.Bottom) != 0) {
283 if ((c.Value & AnchorStyles.Top) == 0) b.Y += newBounds.Height - oldBounds.Height;
284 else b.Height += newBounds.Height - oldBounds.Height;
285 } else if ((c.Value & AnchorStyles.Top) == 0) b.Y += newBounds.Y - oldBounds.Y;
286 c.Key.Bounds = b;
287 }
288 oldBounds = newBounds;
289 }
290 }
291 public DockStyle GetDockStyle(IFBGControl control) {
292 DockStyle ds;
293 if (!dockStyles.TryGetValue(control, out ds)) ds = DockStyle.None;
294 return ds;
295 }
296 public void SetDockStyle(IFBGControl control, DockStyle style) {
297 if (style == DockStyle.None) {
298 if (dockStyles.Remove(control)) DoLayout();
299 } else if (controls.Contains(control)) {
300 anchorStyles.Remove(control);
301 dockStyles[control] = style;
302 DoLayout();
303 }
304 }
305 public AnchorStyles GetAnchorStyle(IFBGControl control) {
306 AnchorStyles ds;
307 if (!anchorStyles.TryGetValue(control, out ds)) ds = AnchorStyles.Left | AnchorStyles.Top;
308 return ds;
309 }
310 public void SetAnchorStyle(IFBGControl control, AnchorStyles style) {
311 if (style == (AnchorStyles.Left | AnchorStyles.Top)) {
312 anchorStyles.Remove(control);
313 } else if (controls.Contains(control)) {
314 dockStyles.Remove(control);
315 anchorStyles[control] = style;
316 }
317 }
318 public void SetAnchor(IFBGControl control, AnchorStyles style, int value) {
319 if (controls.Contains(control)) {
320 AnchorStyles oldstyle;
321 if (!anchorStyles.TryGetValue(control, out oldstyle)) oldstyle = AnchorStyles.Left | AnchorStyles.Top;
322 Rectangle b = control.Bounds;
323 switch (style) {
324 case AnchorStyles.None: throw new ArgumentException("style", "Anchor style can not be None");
325 case AnchorStyles.Left: b.X = value; break;
326 case AnchorStyles.Top: b.Y = value; break;
327 case AnchorStyles.Right:
328 if ((oldstyle & AnchorStyles.Left) == 0) b.X = ClientRectangle.Width - b.Width - value;
329 else b.Width = ClientRectangle.Width - b.X - value;
330 break;
331 case AnchorStyles.Bottom:
332 if ((oldstyle & AnchorStyles.Top) == 0) b.Y = ClientRectangle.Height - b.Height - value;
333 else b.Height = ClientRectangle.Height - b.Y - value;
334 break;
335 default: throw new ArgumentOutOfRangeException("style", "The value vor the style argument is invalid");
336 }
337 control.Bounds = b;
338 dockStyles.Remove(control);
339 anchorStyles[control] = oldstyle | style;
340 }
341 }
342 private void DoLayout() {
343 Rectangle a = new Rectangle(Point.Empty, ClientRectangle.IsEmpty ? Bounds.Size : ClientRectangle.Size);
344 foreach (KeyValuePair<IFBGControl, DockStyle> c in dockStyles) {
345 Rectangle b = c.Key.Bounds;
346 if (c.Value == DockStyle.Left) {
347 b.Location = a.Location;
348 b.Height = a.Height;
349 a.X += b.Width;
350 a.Width -= b.Width;
351 } else if (c.Value == DockStyle.Top) {
352 b.Location = a.Location;
353 b.Width = a.Width;
354 a.Y += b.Height;
355 a.Height -= b.Height;
356 } else if (c.Value == DockStyle.Right) {
357 b.X = a.X + a.Width - b.Width;
358 b.Y = a.Y;
359 b.Height = a.Height;
360 a.Width -= b.Width;
361 } else if (c.Value == DockStyle.Bottom) {
362 b.X = a.X;
363 b.Y = a.Y + a.Height - b.Height;
364 b.Width = a.Width;
365 a.Height -= b.Height;
366 } else if (c.Value == DockStyle.Fill) {
367 b = a;
368 }
369 c.Key.Bounds = b;
370 if (a.Width < 0) a.Width = 0;
371 if (a.Height < 0) a.Height = 0;
372 }
373 }
374 }
375 public class FBGGroupBox : FBGDockContainer {
376 private String text = String.Empty;
377 public FBGGroupBox(IFBGContainerControl parent)
378 : base(parent) {
379 ClientRectangle = new Rectangle(1, 15, Bounds.Width - 2, Bounds.Height - 17);
380 }
381 public override Rectangle Bounds {
382 get { return base.Bounds; }
383 set {
384 ClientRectangle = new Rectangle(1, 15, value.Width - 2, value.Height - 17);
385 base.Bounds = value;
386 }
387 }
388 public String Text { get { return text; } set { if (text == value) return; text = value; Invalidate(new Rectangle(0, 0, Bounds.Width, 15)); } }
389 protected override void Paint(Graphics g) {
390 base.Paint(g);
391 g.DrawRectangle(Pens.Gray, 0, 6, Bounds.Width - 1, Bounds.Height - 7);
392 SizeF ss = g.MeasureString(Text, SystemFonts.DefaultFont, new Size(Bounds.Width - 10 - 9, 15));
393 g.FillRectangle(SystemBrushes.Control, 9, 0, ss.Width, ss.Height);
394 g.DrawString(Text, SystemFonts.DefaultFont, Brushes.DarkBlue, new Rectangle(9, 0, Bounds.Width - 10 - 9, 15));
395 }
396 }
397 public class WinFormsFBGHost : Control, IFBGContainerControl {
398 private IFBGControl childControl = null;
399 private IFBGControl mouseCaptureControl = null;
400 private IFBGControl keyboardCaptureControl = null;
401 public IFBGControl ChildControl { get { return childControl; } }
402
403 public WinFormsFBGHost() {
404 DoubleBuffered = true;
405 }
406
407 public virtual Point PointToChild(IFBGControl child, Point point) {
408 return point - (Size)child.Bounds.Location;
409 }
410 public virtual Point PointFromChild(IFBGControl child, Point point) {
411 return point + (Size)child.Bounds.Location;
412 }
413
414 Size IFBGContainerControl.Size { get { return ClientSize; } }
415 void IFBGContainerControl.Invalidate(IFBGControl control, Rectangle rect) {
416 Invalidate(new Rectangle(PointFromChild(control, rect.Location), rect.Size));
417 }
418 void IFBGContainerControl.AddControl(IFBGControl control) {
419 if (!ReferenceEquals(childControl, null)) throw new InvalidOperationException("This container can have only one child control");
420 childControl = control;
421 control.Bounds = new Rectangle(Point.Empty, ClientSize);
422 Invalidate(control.Bounds);
423 }
424 void IFBGContainerControl.RemoveControl(IFBGControl control) {
425 if (!ReferenceEquals(childControl, control)) return;
426 childControl = null;
427 Invalidate(control.Bounds);
428 if (mouseCaptureControl == control) mouseCaptureControl = null;
429 if (keyboardCaptureControl == control) control = null;
430 control.Orphaned();
431 }
432 Boolean IFBGContainerControl.CaptureMouse(IFBGControl control, Boolean capture) {
433 if (capture && !ReferenceEquals(mouseCaptureControl, null)) return false;
434 if (!capture && !ReferenceEquals(mouseCaptureControl, control)) return false;
435 mouseCaptureControl = capture ? control : null;
436 return true;
437 }
438 Boolean IFBGContainerControl.CaptureKeyboard(IFBGControl control, Boolean capture) {
439 if (!capture && !ReferenceEquals(keyboardCaptureControl, control)) return false;
440 keyboardCaptureControl = capture ? control : null;
441 return true;
442 }
443
444 protected override void OnPaint(PaintEventArgs e) {
445 base.OnPaint(e);
446 Graphics g = e.Graphics;
447 GraphicsState state = g.Save();
448 g.SetClip(e.ClipRectangle);
449 if (ReferenceEquals(childControl, null)) return;
450 if (childControl.Bounds.Width <= 0 || childControl.Bounds.Height <= 0) return;
451 if (!g.ClipBounds.IntersectsWith((RectangleF)childControl.Bounds)) return;
452 g.TranslateTransform(childControl.Bounds.X, childControl.Bounds.Y, MatrixOrder.Append);
453 g.IntersectClip(new Rectangle(Point.Empty, childControl.Bounds.Size));
454 childControl.Paint(g);
455 g.Restore(state);
456 }
457 protected override void OnResize(EventArgs e) {
458 if (!ReferenceEquals(childControl, null)) childControl.Bounds = new Rectangle(Point.Empty, ClientSize);
459 base.OnResize(e);
460 }
461 protected override void OnMouseDown(MouseEventArgs e) {
462 base.OnMouseDown(e);
463 IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : childControl;
464 if (control != null) control.MouseDown(PointToChild(control, e.Location), e.Button);
465 }
466 protected override void OnMouseUp(MouseEventArgs e) {
467 base.OnMouseUp(e);
468 IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : childControl;
469 if (control != null) control.MouseUp(PointToChild(control, e.Location), e.Button);
470 }
471 protected override void OnMouseMove(MouseEventArgs e) {
472 IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : childControl;
473 if (control != null) control.MouseMove(PointToChild(control, e.Location), e.Button);
474 }
475 protected override bool IsInputChar(char charCode) {
476 return true;
477 }
478 protected override bool IsInputKey(Keys keyData) {
479 return true;
480 }
481 protected override void OnKeyDown(KeyEventArgs e) {
482 //base.OnKeyDown(e);
483 if (!ReferenceEquals(keyboardCaptureControl, null)) keyboardCaptureControl.KeyDown(e.KeyData);
484 }
485 protected override void OnKeyPress(KeyPressEventArgs e) {
486 //base.OnKeyPress(e);
487 if (!ReferenceEquals(keyboardCaptureControl, null)) keyboardCaptureControl.KeyPress(e.KeyChar);
488 }
489 protected override void OnKeyUp(KeyEventArgs e) {
490 //base.OnKeyUp(e);
491 if (!ReferenceEquals(keyboardCaptureControl, null)) keyboardCaptureControl.KeyUp(e.KeyData);
492 }
493 protected override void OnHandleDestroyed(EventArgs e) {
494 if (!ReferenceEquals(childControl, null)) childControl.Orphaned();
495 base.OnHandleDestroyed(e);
496 }
497 }
498 public class FBGCursor {
499 public Image Image { get; private set; }
500 public Point Hotspot { get; private set; }
501 public Size Size { get; private set; }
502 public FBGCursor(Image image, Point hotspot) {
503 this.Image = image;
504 this.Hotspot = hotspot;
505 this.Size = image.Size;
506 }
507
508 private const String ArrowCursorImageData = "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAVCAYAAAByrA+0AAAAkUlEQVR42pWTORbEMAhDJb3cYNqUuf+JUk6bM2iKLM9DvGAqG/MFxpgAfKwbkTQBwOe7ewqwnYZ0L7KQyk0GUnSMINWcPUgtpRakXr01SKOuREiZ3pcQz329KeR7YpZaUCkQ50wjxWYGko8aSduGbZD8m2bF4NQsxeBj3XiX92rrzOfpvkMrizBpS+/wyuLynj9U+GDtLEEVuQAAAABJRU5ErkJggg==";
509 public static readonly FBGCursor ArrowCursor = new FBGCursor(Image.FromStream(new MemoryStream(Convert.FromBase64String(ArrowCursorImageData))), Point.Empty);
510 }
511 public class FBGRenderer : FBGContainerControl, IDisposable {
512 private FBGCursor cursor = null;
513 private Point cursorposition = Point.Empty;
514 public IFramebuffer Framebuffer { get; private set; }
515 private Bitmap Frontbuffer;
516 private Object RenderLock = new object();
517 public event EventHandler<InvalidateEventArgs> Painted;
518 private Size size;
519 private ThreadingTimer PaintTimer = null;
520 private Boolean PaintScheduled = false;
521 private int PaintDelay = 0;
522 public Boolean SuspendDrawing {
523 get { return suspenddrawing; }
524 set {
525 lock (RenderLock) {
526 suspenddrawing = value;
527 if (!value) {
528 Refresh(DirtyRectangle);
529 DirtyRectangle = Rectangle.Empty;
530 }
531 }
532 }
533 }
534 public int RedrawDelay {
535 get { return PaintDelay; }
536 set {
537 lock (RenderLock) {
538 if (value < 0) throw new ArgumentOutOfRangeException("value");
539 PaintDelay = value;
540 if (PaintDelay == 0) {
541 if (PaintTimer != null) PaintTimer.Dispose();
542 PaintTimer = null;
543 if (PaintScheduled) PaintTimerCallback(null);
544 } else {
545 PaintTimer = new ThreadingTimer(PaintTimerCallback);
546 }
547 }
548 }
549 }
550 private Boolean suspenddrawing = false;
551 private Rectangle DirtyRectangle;
552
553 public FBGCursor Cursor {
554 get { return cursor; }
555 set {
556 cursor = value;
557 Invalidate();
558 }
559 }
560 public Point CursorPosition {
561 get { return cursorposition; }
562 set {
563 if (cursorposition == value) return;
564 Point oldposition = cursorposition;
565 cursorposition = value;
566 if (cursor == null) return;
567 Size s = cursor.Size;
568 if (s.Width == 0 && s.Height == 0) s = new Size(32, 32);
569 Rectangle r = Rectangle.Union(new Rectangle(oldposition, s), new Rectangle(cursorposition, s));
570 r.Offset(-cursor.Hotspot.X, -cursor.Hotspot.Y);
571 if (Environment.OSVersion.Platform == PlatformID.Unix) {
572 r = Rectangle.Union(r, Rectangle.Union(new Rectangle(oldposition.X - 2, oldposition.Y - 2, 4, 4), new Rectangle(cursorposition.X - 2, cursorposition.Y - 2, 4, 4)));
573 }
574 Invalidate(r);
575 }
576 }
577 public override Rectangle Bounds {
578 get { return new Rectangle(Point.Empty, size); }
579 set { throw new NotSupportedException("Can not change the top control bounds"); }
580 }
581 public FBGRenderer(IFramebuffer fb) : this(fb.Width, fb.Height) {
582 Framebuffer = fb;
583 }
584 public FBGRenderer(Size fbsize) : this(fbsize.Width, fbsize.Height) { }
585 public FBGRenderer(int width, int height) : this(new Bitmap(width, height, PixelFormat.Format32bppRgb)) { }
586 public FBGRenderer(Bitmap bmp) : base(null) {
587 Frontbuffer = bmp;
588 BackColor = SystemColors.Control;
589 size = Frontbuffer.Size;
590 }
591 public override void Invalidate(Rectangle rect) {
592 if (rect.Width == 0 || rect.Height == 0) return;
593 lock (RenderLock) {
594 if (SuspendDrawing || PaintTimer != null) {
595 DirtyRectangle = DirtyRectangle.IsEmpty ? rect : Rectangle.Union(DirtyRectangle, rect);
596 if (!SuspendDrawing && !PaintScheduled) {
597 PaintScheduled = true;
598 PaintTimer.Change(PaintDelay, Timeout.Infinite);
599 }
600 } else {
601 Refresh(rect);
602 }
603 }
604 }
605 private void PaintTimerCallback(Object state) {
606 try {
607 lock (RenderLock) {
608 PaintScheduled = false;
609 Refresh(DirtyRectangle);
610 DirtyRectangle = Rectangle.Empty;
611 }
612 } catch { }
613 }
614 private void Refresh(Rectangle rect) {
615 lock (RenderLock) {
616 rect.Intersect(Bounds);
617 if (rect.Width == 0 || rect.Height == 0) return;
618 using (Graphics g = Graphics.FromImage(Frontbuffer)) {
619 g.SetClip(rect);
620 Paint(g);
621 }
622 if (Framebuffer != null) Framebuffer.DrawImage(Frontbuffer, rect, rect.Location);
623 RaiseEvent(Painted, new InvalidateEventArgs(rect));
624 }
625 }
626 protected override void Paint(Graphics g) {
627 base.Paint(g);
628 if (Cursor != null) {
629 Point r = CursorPosition;
630 r.Offset(-cursor.Hotspot.X, -cursor.Hotspot.Y);
631 g.DrawImageUnscaled(Cursor.Image, r);
632 }
633 }
634 protected override Boolean CaptureMouse(Boolean capture) {
635 return true;
636 }
637 protected override Boolean CaptureKeyboard(bool capture) {
638 return true;
639 }
640 public void Dispose() {
641 lock (RenderLock) {
642 if (PaintTimer != null) PaintTimer.Dispose();
643 PaintTimer = null;
644 }
645 Orphaned();
646 if (Frontbuffer != null) Frontbuffer.Dispose();
647 }
648 public Bitmap LockBitmapBuffer() {
649 Monitor.Enter(RenderLock);
650 return Frontbuffer;
651 }
652 public void UnlockBitmapBuffer() {
653 Monitor.Exit(RenderLock);
654 }
655 public new void MouseMove(Point position, MouseButtons buttons) { base.MouseMove(position, buttons); }
656 public new void MouseDown(Point position, MouseButtons buttons) { base.MouseDown(position, buttons); }
657 public new void MouseUp(Point position, MouseButtons buttons) { base.MouseUp(position, buttons); }
658 public new void KeyDown(Keys key) { base.KeyDown(key); }
659 public new void KeyPress(Char key) { base.KeyPress(key); }
660 public new void KeyUp(Keys key) { base.KeyUp(key); }
661 }
662 public class FBGForm : FBGDockContainer {
663 private Point prevPosition = Point.Empty;
664 private NonClientOps moveresize = 0;
665 private String text = String.Empty;
666 public event EventHandler TextChanged;
667 public Boolean Sizable { get; set; }
668 public Boolean Movable { get; set; }
669 public Boolean Closable { get; set; }
670 [Flags]
671 private enum NonClientOps : int {
672 None = 0,
673 Move = 1,
674 ResizeLeft = 2,
675 ResizeRight = 4,
676 ResizeTop = 8,
677 ResizeBottom = 16,
678 ButtonClose = 32,
679 MoveResize = ResizeLeft | ResizeRight | ResizeBottom | ResizeTop | Move,
680 }
681 public FBGForm(IFBGContainerControl parent) : base(parent) {
682 BackColor = SystemColors.Control;
683 ClientRectangle = new Rectangle(4, 22, Bounds.Width - 8, Bounds.Height - 26);
684 Sizable = true;
685 Movable = true;
686 Closable = false;
687 }
688 public override Rectangle Bounds {
689 get { return base.Bounds; }
690 set {
691 ClientRectangle = new Rectangle(4, 22, value.Width - 8, value.Height - 26);
692 base.Bounds = value;
693 }
694 }
695 public String Text { get { return text; } set { if (text == value) return; text = value; Invalidate(new Rectangle(0, 0, Bounds.Width, 20)); RaiseEvent(TextChanged); } }
696 protected override void MouseDown(Point p, MouseButtons buttons) {
697 NonClientOps mr = 0;
698 if ((buttons & MouseButtons.Left) != 0) {
699 if ((new Rectangle(Bounds.Width - 5 - 14, 4, 14, 14)).Contains(p)) {
700 mr = NonClientOps.ButtonClose;
701 } else {
702 if (Sizable) {
703 if (Movable) {
704 if (p.X < 4) mr |= NonClientOps.ResizeLeft;
705 if (p.Y < 4) mr |= NonClientOps.ResizeTop;
706 }
707 if (p.X >= Bounds.Width - 4) mr |= NonClientOps.ResizeRight;
708 if (p.Y >= Bounds.Height - 4) mr |= NonClientOps.ResizeBottom;
709 }
710 if (mr == 0 && Movable && p.Y < 20) mr = NonClientOps.Move;
711 }
712 }
713 if (mr != 0) {
714 moveresize = mr;
715 prevPosition = p;
716 CaptureMouse(true);
717 } else {
718 base.MouseDown(p, buttons);
719 }
720 }
721 protected override void MouseMove(Point position, MouseButtons buttons) {
722 if (moveresize == 0) {
723 base.MouseMove(position, buttons);
724 } else if ((moveresize & NonClientOps.MoveResize) != 0) {
725 Rectangle b = Bounds;
726 int dx = position.X - prevPosition.X;
727 int dy = position.Y - prevPosition.Y;
728 if (moveresize == NonClientOps.Move) b.Offset(dx, dy);
729 if ((moveresize & NonClientOps.ResizeLeft) != 0) {
730 b.X += dx;
731 b.Width -= dx;
732 } else if ((moveresize & NonClientOps.ResizeRight) != 0) {
733 b.Width += dx;
734 prevPosition.X = position.X;
735 }
736 if ((moveresize & NonClientOps.ResizeTop) != 0) {
737 b.Y += dy;
738 b.Height -= dy;
739 } else if ((moveresize & NonClientOps.ResizeBottom) != 0) {
740 b.Height += dy;
741 prevPosition.Y = position.Y;
742 }
743 if (b.Width < 55) b.Width = 55;
744 if (b.Height < 25) b.Height = 25;
745 Bounds = b;
746 }
747 }
748 protected override void MouseUp(Point position, MouseButtons buttons) {
749 if (moveresize == 0) {
750 base.MouseUp(position, buttons);
751 } else if ((buttons & MouseButtons.Left) != 0) {
752 MouseMove(position, buttons);
753 CaptureMouse(false);
754 if (moveresize == NonClientOps.ButtonClose && (new Rectangle(Bounds.Width - 5 - 14, 4, 14, 14)).Contains(position) && Closable) Close();
755 moveresize = 0;
756 }
757 }
758 protected override void Paint(Graphics g) {
759 base.Paint(g);
760 g.DrawRectangle(Pens.Gray, 0, 0, Bounds.Width - 1, Bounds.Height - 1);
761 g.DrawRectangle(Pens.LightGray, 1, 1, Bounds.Width - 3, Bounds.Height - 3);
762 g.DrawRectangle(Pens.DarkGray, 2, 20, Bounds.Width - 5, Bounds.Height - 23);
763 g.DrawRectangle(Pens.Gray, 3, 21, Bounds.Width - 7, Bounds.Height - 25);
764 using (Brush b = new LinearGradientBrush(new Rectangle(0, 1, 1, 18), Color.Gray, Color.LightGray, LinearGradientMode.Vertical))
765 g.FillRectangle(b, 2, 2, Bounds.Width - 4, 18);
766
767 g.DrawString(Text, SystemFonts.CaptionFont, Brushes.Black, 4, 1);
768
769 g.DrawRectangle(Pens.Gray, Bounds.Width - 5 - 14, 4, 14, 14);
770 g.DrawRectangle(Pens.Gray, Bounds.Width - 5 - 14 - 16, 4, 14, 14);
771 g.DrawRectangle(Pens.Gray, Bounds.Width - 5 - 14 - 32, 4, 14, 14);
772 using (Brush b = new LinearGradientBrush(new Rectangle(0, 5, 1, 13), Color.LightGray, Color.DarkGray, LinearGradientMode.Vertical)) {
773 g.FillRectangle(b, Bounds.Width - 5 - 14 + 1, 5, 13, 13);
774 g.FillRectangle(b, Bounds.Width - 5 - 14 + 1 - 16, 5, 13, 13);
775 g.FillRectangle(b, Bounds.Width - 5 - 14 + 1 - 32, 5, 13, 13);
776 }
777 if (Closable) {
778 g.DrawLine(Pens.Black, Bounds.Width - 5 - 14 + 3, 4 + 3, Bounds.Width - 5 - 14 + 14 - 3, 4 + 14 - 3);
779 g.DrawLine(Pens.Black, Bounds.Width - 5 - 14 + 3, 4 + 14 - 3, Bounds.Width - 5 - 14 + 14 - 3, 4 + 3);
780 }
781 }
782 public void Close() {
783 Parent.RemoveControl(this);
784 }
785 }
786 public class FBGDesktop : FBGContainerControl {
787 FBGContainerControl windowcontainer;
788 FBGContainerControl menucontainer;
789 Boolean startup = true;
790 class FBGWindowState {
791 public IFBGControl Control;
792 public FBGButton MenuButton;
793 public Boolean Visible;
794 public Rectangle OldBounds;
795 public FBGWindowState(IFBGControl cntrl, FBGButton btn) {
796 Control = cntrl;
797 MenuButton = btn;
798 Visible = true;
799 }
800 }
801 Dictionary<IFBGControl, FBGWindowState> windowstates = new Dictionary<IFBGControl, FBGWindowState>();
802 public FBGDesktop(IFBGContainerControl parent) : base(parent) {
803 menucontainer = new FBGContainerControl(this);
804 menucontainer.Bounds = new Rectangle(0, Bounds.Height - 25, Bounds.Width, 25);
805 windowcontainer = new FBGContainerControl(this);
806 windowcontainer.Bounds = new Rectangle(0, 0, Bounds.Width, Bounds.Height - 25);
807 startup = false;
808 }
809 public override Rectangle Bounds {
810 get { return base.Bounds; }
811 set {
812 if (Bounds == value) return;
813 base.Bounds = value;
814 if (startup) return;
815 menucontainer.Bounds = new Rectangle(0, value.Height - 25, value.Width, 25);
816 windowcontainer.Bounds = new Rectangle(0, 0, value.Width, value.Height - 25);
817 ScaleMenuButtons();
818 }
819 }
820 protected override void AddControl(IFBGControl control) {
821 if (startup) {
822 base.AddControl(control);
823 return;
824 }
825 ((IFBGContainerControl)windowcontainer).AddControl(control);
826 FBGButton btn = new FBGButton(menucontainer);
827 FBGForm formcontrol = control as FBGForm;
828 if (formcontrol == null) {
829 btn.Text = "Untitled";
830 } else {
831 formcontrol.TextChanged += delegate(Object sender, EventArgs e) {
832 btn.Text = formcontrol.Text;
833 };
834 btn.Text = formcontrol.Text;
835 }
836 FBGWindowState ws = new FBGWindowState(control, btn);
837 windowstates.Add(control, ws);
838 ScaleMenuButtons();
839 btn.Click += delegate(Object sender, EventArgs e) {
840 if (ws.Visible) {
841 if (ws.MenuButton.BackColor == Color.DarkGray) {
842 ws.OldBounds = ws.Control.Bounds;
843 ws.Visible = false;
844 ws.Control.Bounds = Rectangle.Empty;
845 } else {
846 windowcontainer.BringControlToFront(ws.Control);
847 foreach (FBGWindowState wsa in windowstates.Values) if (!ReferenceEquals(ws, wsa)) wsa.MenuButton.BackColor = SystemColors.ButtonFace;
848 ws.MenuButton.BackColor = Color.DarkGray;
849 }
850 } else {
851 ws.Control.Bounds = ws.OldBounds;
852 ws.Visible = true;
853 windowcontainer.BringControlToFront(ws.Control);
854 foreach (FBGWindowState wsa in windowstates.Values) if (!ReferenceEquals(ws, wsa)) wsa.MenuButton.BackColor = SystemColors.ButtonFace;
855 ws.MenuButton.BackColor = Color.DarkGray;
856 }
857 };
858 }
859 public override void RemoveControl(IFBGControl control) {
860 windowcontainer.RemoveControl(control);
861 windowstates.Remove(control);
862 ScaleMenuButtons();
863 }
864 private void ScaleMenuButtons() {
865 int bcount = windowstates.Count;
866 int bwidth = 200;
867 int twidth = bwidth * bcount;
868 if (twidth > Bounds.Width) bwidth = menucontainer.Bounds.Width / bcount;
869 int i = 0;
870 foreach (FBGWindowState ws in windowstates.Values) {
871 ws.MenuButton.Bounds = new Rectangle(i * bwidth, 0, bwidth, 25);
872 i++;
873 }
874 }
875 protected override void Paint(Graphics g) {
876 base.Paint(g);
877 g.DrawLine(Pens.Black, 0, Bounds.Height - 25, Bounds.Width, Bounds.Height - 25);
878 }
879 protected override void MouseDown(Point position, MouseButtons buttons) {
880 IFBGControl control = FindControlAtPosition(position);
881 if (ReferenceEquals(control, windowcontainer)) {
882 control = windowcontainer.FindControlAtPosition(PointToChild(windowcontainer, position));
883 if (!ReferenceEquals(control, null)) {
884 windowcontainer.BringControlToFront(control);
885 foreach (FBGWindowState ws in windowstates.Values)
886 ws.MenuButton.BackColor = ReferenceEquals(ws.Control, control) ? Color.DarkGray : SystemColors.ButtonFace;
887 }
888 }
889 base.MouseDown(position, buttons);
890 }
891 }
892
893 public class FBGLabel : FBGControl, IDisposable {
894 public FBGLabel(IFBGContainerControl parent) : base(parent) {
895 Size = new Size(200, 16);
896 }
897 private String text = String.Empty;
898 private Font font = SystemFonts.DefaultFont;
899 private Brush brush = SystemBrushes.ControlText;
900 private StringFormat stringformat = new StringFormat();
901 public String Text { get { return text; } set { text = value; Invalidate(); } }
902 public Font Font { get { return font; } set { font = value; Invalidate(); } }
903 public Brush Brush { get { return brush; } set { brush = value; Invalidate(); } }
904 public Color Color { set { Brush = new SolidBrush(value); } }
905 public StringAlignment Alignment { get { return stringformat.Alignment; } set { stringformat.Alignment = value; Invalidate(); } }
906 public StringFormatFlags FormatFlags { get { return stringformat.FormatFlags; } set { stringformat.FormatFlags = value; Invalidate(); } }
907 public StringAlignment LineAlignment { get { return stringformat.LineAlignment; } set { stringformat.LineAlignment = value; Invalidate(); } }
908 public StringTrimming Trimming { get { return stringformat.Trimming; } set { stringformat.Trimming = value; Invalidate(); } }
909 protected override void Paint(Graphics g) {
910 base.Paint(g);
911 g.DrawString(text, font, brush, new Rectangle(Point.Empty, Bounds.Size), stringformat);
912 }
913 public void Dispose() {
914 stringformat.Dispose();
915 }
916 protected override void Orphaned() {
917 base.Orphaned();
918 Dispose();
919 }
920 }
921 public class FBGTextBox : FBGControl {
922 public FBGTextBox(IFBGContainerControl parent) : base(parent) {
923 BackColor = Color.White;
924 Size = new Size(200, 20);
925 }
926 private String text = String.Empty;
927 private Char passwordChar = (Char)0;
928 private Font font = new Font(FontFamily.GenericMonospace, 10);
929 private Brush brush = SystemBrushes.ControlText;
930 private Boolean hasKeyboardFocus = false;
931 public String Text { get { return text; } set { text = value; if (CaretPosition > text.Length) CaretPosition = text.Length; Invalidate(); RaiseEvent(TextChanged); } }
932 public Font Font { get { return font; } set { font = value; Invalidate(); } }
933 public Brush Brush { get { return brush; } set { brush = value; Invalidate(); } }
934 public Color Color { set { Brush = new SolidBrush(value); } }
935 public Int32 CaretPosition { get; private set; }
936 public Char PasswordChar { get { return passwordChar; } set { passwordChar = value; Invalidate(); } }
937 public event EventHandler TextChanged;
938 public event KeyPressEventHandler OnKeyPress;
939 protected override void Paint(Graphics g) {
940 base.Paint(g);
941 g.DrawRectangle(Pens.Gray, 0, 0, Bounds.Width - 1, Bounds.Height - 1);
942 using (StringFormat sf_nonprinting = new StringFormat(StringFormat.GenericTypographic)) {
943 sf_nonprinting.Trimming = StringTrimming.None;
944 sf_nonprinting.FormatFlags = StringFormatFlags.DisplayFormatControl | StringFormatFlags.MeasureTrailingSpaces;
945 sf_nonprinting.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.None;
946
947 float x = 1;
948 float y = 1;
949 float w = Width - 2;
950 if (hasKeyboardFocus && CaretPosition == 0) {
951 g.DrawLine(Pens.Black, x + 2, 2, x + 2, Height - 4);
952 }
953 String c = passwordChar == 0 ? null : new String(passwordChar, 1);
954 for (int i = 0; i < text.Length; i++) {
955 if (passwordChar == 0) c = text.Substring(i, 1);
956 SizeF s = g.MeasureString(c, font, (int)Math.Ceiling(w), sf_nonprinting);
957 g.DrawString(c, font, brush, x, y);
958 x += (float)Math.Ceiling(s.Width);
959 w -= (float)Math.Ceiling(s.Width);
960
961 if (hasKeyboardFocus && i == CaretPosition - 1) {
962 g.DrawLine(Pens.Black, x + 2, 2, x + 2, Height - 4);
963 }
964 }
965 }
966 }
967 protected override void MouseDown(Point position, MouseButtons buttons) {
968 hasKeyboardFocus = CaptureKeyboard(true);
969 CaretPosition = text.Length;
970 float x = 1;
971 String c = passwordChar == 0 ? null : new String(passwordChar, 1);
972 for (int i = 0; i < text.Length; i++) {
973 if (passwordChar == 0) c = text.Substring(i, 1);
974 Size s;
975 try {
976 s = TextRenderer.MeasureText(c, font, Size.Empty, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix);
977 } catch (Exception) {
978 break;
979 }
980 x += s.Width;
981 if (position.X < x) {
982 CaretPosition = i;
983 break;
984 }
985 }
986 Invalidate();
987 }
988 protected override void KeyDown(Keys key) {
989 if ((key & Keys.KeyCode) == Keys.Left) {
990 CaretPosition--;
991 if (CaretPosition < 0) CaretPosition = 0;
992 Invalidate();
993 } else if ((key & Keys.KeyCode) == Keys.Right) {
994 CaretPosition++;
995 if (CaretPosition > text.Length) CaretPosition = text.Length;
996 Invalidate();
997 } else if ((key & Keys.KeyCode) == Keys.Home) {
998 CaretPosition = 0;
999 Invalidate();
1000 } else if ((key & Keys.KeyCode) == Keys.End) {
1001 CaretPosition = text.Length;
1002 Invalidate();
1003 } else if ((key & Keys.Control) != 0 && (key & Keys.KeyCode) == Keys.V) {
1004 String cbtext = Clipboard.GetText(TextDataFormat.UnicodeText);
1005 CaretPosition += cbtext.Length;
1006 Text = Text.Insert(CaretPosition - cbtext.Length, cbtext);
1007 }
1008 }
1009 protected override void KeyPress(char keyChar) {
1010 KeyPressEventArgs e = new KeyPressEventArgs(keyChar);
1011 RaiseEvent(OnKeyPress, e);
1012 if (e.Handled) return;
1013 hasKeyboardFocus = true;
1014 if (keyChar == 8) {
1015 if (CaretPosition > 0) {
1016 CaretPosition--;
1017 Text = Text.Remove(CaretPosition, 1);
1018 }
1019 } else if (keyChar == 127) {
1020 if (CaretPosition < Text.Length) {
1021 Text = Text.Remove(CaretPosition, 1);
1022 }
1023 } else if (keyChar < 32) {
1024 } else {
1025 CaretPosition++;
1026 Text = Text.Insert(CaretPosition - 1, new String(keyChar, 1));
1027 }
1028 }
1029 public void Focus() {
1030 hasKeyboardFocus = CaptureKeyboard(true);
1031 }
1032 protected override void LostKeyboardCapture() {
1033 base.LostKeyboardCapture();
1034 hasKeyboardFocus = false;
1035 Invalidate();
1036 }
1037 }
1038 public class FBGButton : FBGControl {
1039 public FBGButton(IFBGContainerControl parent) : base(parent) {
1040 BackColor = SystemColors.ButtonFace;
1041 }
1042 private String text = String.Empty;
1043 private Font font = SystemFonts.DefaultFont;
1044 private Color color = SystemColors.ControlText;
1045 private Boolean pressed = false;
1046 private Boolean enabled = true;
1047 public String Text { get { return text; } set { text = value; Invalidate(); } }
1048 public Font Font { get { return font; } set { font = value; Invalidate(); } }
1049 public Color Color { get { return color; } set { color = value; Invalidate(); } }
1050 public Boolean Enabled { get { return enabled; } set { enabled = value; Invalidate(); } }
1051 public event EventHandler Click;
1052 protected override void Paint(Graphics g) {
1053 base.Paint(g);
1054 if (Bounds.Width == 0 || Bounds.Height == 0) return;
1055 if (BackColor == SystemColors.ButtonFace) {
1056 ControlPaint.DrawButton(g, new Rectangle(0, 0, Bounds.Width, Bounds.Height), enabled ? (pressed ? ButtonState.Pushed : ButtonState.Normal) : ButtonState.Inactive);
1057 } else {
1058 //Hackish and not completely right...
1059 //Todo: borrowed from mono... possible licencing issues!?
1060 g.DrawLine(new Pen(ControlPaint.LightLight(BackColor)), 0, 0, Bounds.Width, 0);
1061 g.DrawLine(new Pen(ControlPaint.LightLight(BackColor)), 0, 0, 0, Bounds.Height);
1062 g.DrawLine(new Pen(ControlPaint.Dark(BackColor)), 1, Bounds.Height - 2, Bounds.Width - 1, Bounds.Height - 2);
1063 g.DrawLine(new Pen(ControlPaint.Dark(BackColor)), Bounds.Width - 2, 1, Bounds.Width - 2, Bounds.Height - 2);
1064 g.DrawLine(new Pen(ControlPaint.DarkDark(BackColor)), 0, Bounds.Height - 1, Bounds.Width, Bounds.Height - 1);
1065 g.DrawLine(new Pen(ControlPaint.DarkDark(BackColor)), Bounds.Width - 1, 1, Bounds.Width - 1, Bounds.Height - 1);
1066 Graphics dc = g;
1067 Rectangle rectangle = new Rectangle(0, 0, Bounds.Width - 1, Bounds.Height - 1);
1068 Color ColorControl = BackColor;
1069 Color ColorControlLight = ControlPaint.Light(ColorControl);
1070 ButtonState state = pressed ? ButtonState.Pushed : ButtonState.Normal;
1071 using (Pen NormalPen = new Pen(BackColor), LightPen = new Pen(ControlPaint.Light(BackColor)), DarkPen = new Pen(ControlPaint.Dark(BackColor))) {
1072 // sadly enough, the rectangle gets always filled with a hatchbrush
1073 using (HatchBrush hb = new HatchBrush(HatchStyle.Percent50, Color.FromArgb(Math.Min(255, ColorControl.R + 3), ColorControl.G, ColorControl.B), ColorControl)) {
1074 dc.FillRectangle(hb, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2);
1075 }
1076 if ((state & ButtonState.All) == ButtonState.All || ((state & ButtonState.Checked) == ButtonState.Checked && (state & ButtonState.Flat) == ButtonState.Flat)) {
1077 using (HatchBrush hb = new HatchBrush(HatchStyle.Percent50, ColorControlLight, ColorControl)) {
1078 dc.FillRectangle(hb, rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4);
1079 }
1080 dc.DrawRectangle(SystemPens.ControlDark, rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1);
1081 } else if ((state & ButtonState.Flat) == ButtonState.Flat) {
1082 dc.DrawRectangle(SystemPens.ControlDark, rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1);
1083 } else if ((state & ButtonState.Checked) == ButtonState.Checked) {
1084 using (HatchBrush hb = new HatchBrush(HatchStyle.Percent50, ColorControlLight, ColorControl)) {
1085 dc.FillRectangle(hb, rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4);
1086 }
1087 Pen pen = DarkPen;
1088 dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2);
1089 dc.DrawLine(pen, rectangle.X + 1, rectangle.Y, rectangle.Right - 2, rectangle.Y);
1090
1091 pen = NormalPen;
1092 dc.DrawLine(pen, rectangle.X + 1, rectangle.Y + 1, rectangle.X + 1, rectangle.Bottom - 3);
1093 dc.DrawLine(pen, rectangle.X + 2, rectangle.Y + 1, rectangle.Right - 3, rectangle.Y + 1);
1094
1095 pen = LightPen;
1096 dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 2, rectangle.Bottom - 1);
1097 dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 1);
1098 } else if (((state & ButtonState.Pushed) == ButtonState.Pushed) && ((state & ButtonState.Normal) == ButtonState.Normal)) {
1099 Pen pen = DarkPen;
1100 dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2);
1101 dc.DrawLine(pen, rectangle.X + 1, rectangle.Y, rectangle.Right - 2, rectangle.Y);
1102
1103 pen = NormalPen;
1104 dc.DrawLine(pen, rectangle.X + 1, rectangle.Y + 1, rectangle.X + 1, rectangle.Bottom - 3);
1105 dc.DrawLine(pen, rectangle.X + 2, rectangle.Y + 1, rectangle.Right - 3, rectangle.Y + 1);
1106
1107 pen = LightPen;
1108 dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 2, rectangle.Bottom - 1);
1109 dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 1);
1110 } else if (((state & ButtonState.Inactive) == ButtonState.Inactive) || ((state & ButtonState.Normal) == ButtonState.Normal)) {
1111 Pen pen = LightPen;
1112 dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.Right - 2, rectangle.Y);
1113 dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2);
1114
1115 pen = NormalPen;
1116 dc.DrawLine(pen, rectangle.X + 1, rectangle.Bottom - 2, rectangle.Right - 2, rectangle.Bottom - 2);
1117 dc.DrawLine(pen, rectangle.Right - 2, rectangle.Y + 1, rectangle.Right - 2, rectangle.Bottom - 3);
1118
1119 pen = DarkPen;
1120 dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 1, rectangle.Bottom - 1);
1121 dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 2);
1122 }
1123 }
1124 }
1125 Rectangle frect = new Rectangle(Point.Empty, Bounds.Size);
1126 SizeF textsize = g.MeasureString(Text, Font);
1127 using (Brush b = new SolidBrush(enabled ? Color : Color.DarkGray)) {
1128 g.DrawString(Text, Font, b, new PointF(Bounds.Width / 2.0f - textsize.Width / 2.0f, Bounds.Height / 2.0f - textsize.Height / 2.0f));
1129 }
1130 }
1131 protected override void MouseDown(Point position, MouseButtons buttons) {
1132 pressed = true;
1133 Invalidate();
1134 CaptureMouse(true);
1135 base.MouseDown(position, buttons);
1136 }
1137 protected override void MouseUp(Point position, MouseButtons buttons) {
1138 pressed = false;
1139 Invalidate();
1140 CaptureMouse(false);
1141 if (position.X >= 0 && position.X <= Bounds.Width && position.Y >= 0 && position.Y <= Bounds.Height && enabled) RaiseEvent(Click);
1142 base.MouseUp(position, buttons);
1143 }
1144 protected override void KeyDown(Keys key) {
1145 if (key == Keys.Return || key == Keys.Space) {
1146 pressed = true;
1147 Invalidate();
1148 }
1149 base.KeyDown(key);
1150 }
1151 protected override void KeyUp(Keys key) {
1152 if (key == Keys.Return || key == Keys.Space) {
1153 if (pressed) RaiseEvent(Click);
1154 pressed = false;
1155 Invalidate();
1156 }
1157 base.KeyUp(key);
1158 }
1159 public void Focus() {
1160 CaptureKeyboard(true);
1161 }
1162 }
1163 public class FBGCheckBox : FBGControl {
1164 public FBGCheckBox(IFBGContainerControl parent) : base(parent) { }
1165 private String text = String.Empty;
1166 private Font font = SystemFonts.DefaultFont;
1167 private Color color = SystemColors.ControlText;
1168 private Boolean _checked = false;
1169 public String Text { get { return text; } set { text = value; Invalidate(); } }
1170 public Font Font { get { return font; } set { font = value; Invalidate(); } }
1171 public Color Color { get { return color; } set { color = value; Invalidate(); } }
1172 public Boolean Checked { get { return _checked; } set { _checked = value; Invalidate(); } }
1173 public event EventHandler CheckedChanged;
1174 protected override void Paint(Graphics g) {
1175 base.Paint(g);
1176 ControlPaint.DrawCheckBox(g, 0, 0, 13, 13, _checked ? ButtonState.Checked : ButtonState.Normal);
1177 g.DrawString(Text, Font, new SolidBrush(Color), 15, 0);
1178 }
1179 protected override void MouseDown(Point position, MouseButtons buttons) {
1180 Checked = !Checked;
1181 RaiseEvent(CheckedChanged);
1182 base.MouseDown(position, buttons);
1183 }
1184 }
1185 public class FBGImageBox : FBGControl {
1186 Image image = null;
1187 PictureBoxSizeMode sizeMode = PictureBoxSizeMode.Normal;
1188 Rectangle imageRect;
1189 public Image Image { get { return image; } set { image = value; UpdateImageRect(false); } }
1190 public FBGImageBox(IFBGContainerControl parent) : base(parent) { }
1191 public PictureBoxSizeMode SizeMode { get { return sizeMode; } set { sizeMode = value; UpdateImageRect(false); } }
1192 public override Rectangle Bounds {
1193 get {
1194 return base.Bounds;
1195 }
1196 set {
1197 UpdateImageRect(true);
1198 base.Bounds = value;
1199 }
1200 }
1201 private void UpdateImageRect(Boolean boundsset) {
1202 if (image == null) return;
1203 if (!boundsset && sizeMode == PictureBoxSizeMode.AutoSize) {
1204 Size = Image.Size;
1205 return;
1206 }
1207 switch (sizeMode) {
1208 case PictureBoxSizeMode.AutoSize:
1209 case PictureBoxSizeMode.Normal:
1210 imageRect = new Rectangle(Point.Empty, image.Size);
1211 break;
1212 case PictureBoxSizeMode.CenterImage:
1213 imageRect = new Rectangle(Width / 2 - image.Width / 2, Height / 2 - Image.Height / 2, Width, Height);
1214 break;
1215 case PictureBoxSizeMode.StretchImage:
1216 imageRect = new Rectangle(Point.Empty, Size);
1217 break;
1218 case PictureBoxSizeMode.Zoom:
1219 float xrat = (float)Width / (float)image.Width;
1220 float yrat = (float)Height / (float)image.Height;
1221 float rat = Math.Min(xrat, yrat);
1222 SizeF dispsize = new SizeF(image.Width * rat, image.Height * rat);
1223 imageRect = Rectangle.Round(new RectangleF(Width / 2f - dispsize.Width / 2f, Height / 2f - dispsize.Height / 2f, dispsize.Width, dispsize.Height));
1224 break;
1225 }
1226 if (!boundsset) Invalidate();
1227 }
1228 protected override void Paint(Graphics g) {
1229 if (!Visible) return;
1230 base.Paint(g);
1231 if (image != null) g.DrawImage(image, imageRect);
1232 }
1233 }
1234 public class FBGListBox : FBGControl {
1235 private List<Object> items = new List<object>();
1236 private Object selected = null;
1237 private Object highlighted = null;
1238 private Boolean hasScrollBar = false;
1239 private Boolean hitScrollBar = false;
1240 private int offset = 0;
1241 private ButtonState buttonUpState = ButtonState.Normal;
1242 private ButtonState buttonDownState = ButtonState.Normal;
1243 private Converter<Object, String> itemFormatter = null;
1244 public Converter<Object, String> ItemFormatter { get { return itemFormatter; } set { itemFormatter = value; Invalidate(); } }
1245 public FBGListBox(IFBGContainerControl parent)
1246 : base(parent) {
1247 BackColor = Color.White;
1248 }
1249 public void AddItem(Object item) {
1250 items.Add(item);
1251 Invalidate();
1252 }
1253 protected override void Paint(Graphics g) {
1254 base.Paint(g);
1255 g.DrawRectangle(Pens.DarkBlue, 0, 0, Bounds.Width - 1, Bounds.Height - 1);
1256 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight());
1257 int th = lh * items.Count;
1258 int y = 2;
1259 using (Pen dottedpen = new Pen(Brushes.Black)) {
1260 dottedpen.DashStyle = DashStyle.Dot;
1261 using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap)) {
1262 for (int i = offset; i < items.Count; i++) {
1263 Object item = items[i];
1264 String text = itemFormatter == null ? (item == null ? String.Empty : item.ToString()) : itemFormatter(item);
1265 if (item == selected) g.FillRectangle(Brushes.DarkGray, 2, y, Bounds.Width - 4, lh);
1266 if (item == highlighted) g.DrawRectangle(dottedpen, 2, y, Bounds.Width - 5, lh - 1);
1267 g.DrawString(text, SystemFonts.DefaultFont, SystemBrushes.WindowText, new Rectangle(3, y, Bounds.Width - 6, lh), sf);
1268 y += lh;
1269 if (y + lh + 2 >= Bounds.Height) break;
1270 }
1271 }
1272 }
1273 if (y < th) hasScrollBar = true;
1274 if (hasScrollBar) {
1275 int xoff = Bounds.Width - 17;
1276 using (Brush b = new LinearGradientBrush(new Rectangle(xoff, 0, 17, 1), Color.LightGray, Color.White, LinearGradientMode.Horizontal))
1277 g.FillRectangle(b, xoff, 17, 16, Bounds.Height - 17 - 17);
1278 ControlPaint.DrawScrollButton(g, xoff, 1, 16, 16, ScrollButton.Up, buttonUpState);
1279 ControlPaint.DrawScrollButton(g, xoff, Bounds.Height - 17, 16, 16, ScrollButton.Down, buttonDownState);
1280 g.DrawRectangle(Pens.Black, new Rectangle(xoff, 17 + offset * (Bounds.Height - 17 - 17 - 20) / (items.Count - 1), 15, 20));
1281 }
1282 }
1283 protected override void MouseDown(Point position, MouseButtons buttons) {
1284 if ((buttons & MouseButtons.Left) != 0) {
1285 CaptureMouse(true);
1286 if (hasScrollBar && position.X > Bounds.Width - 17) {
1287 hitScrollBar = true;
1288 if (position.Y < 17) {
1289 offset--;
1290 buttonUpState = ButtonState.Pushed;
1291 } else if (position.Y > Bounds.Height - 17) {
1292 offset++;
1293 buttonDownState = ButtonState.Pushed;
1294 } else {
1295 offset = (int)Math.Round((position.Y - 17) * (items.Count - 1) / (double)(Bounds.Height - 17 - 17 - 10));
1296 }
1297 if (offset < 0) offset = 0;
1298 if (offset >= items.Count) offset = items.Count - 1;
1299 Invalidate();
1300 } else {
1301 MouseHandler(position, buttons);
1302 }
1303 }
1304 }
1305 protected override void MouseMove(Point position, MouseButtons buttons) {
1306 if (hitScrollBar) {
1307 if (position.Y < 17) {
1308 } else if (position.Y > Bounds.Height - 17) {
1309 } else {
1310 offset = (int)Math.Round((position.Y - 17) * (items.Count - 1) / (double)(Bounds.Height - 17 - 17 - 10));
1311 if (offset < 0) offset = 0;
1312 if (offset >= items.Count) offset = items.Count - 1;
1313 Invalidate();
1314 }
1315 return;
1316 }
1317 MouseHandler(position, buttons);
1318 }
1319 protected override void MouseUp(Point position, MouseButtons buttons) {
1320 if ((buttons & MouseButtons.Left) != 0) {
1321 CaptureMouse(false);
1322 buttonUpState = buttonDownState = ButtonState.Normal;
1323 Invalidate();
1324 if (hitScrollBar) {
1325 hitScrollBar = false;
1326 return;
1327 }
1328 }
1329 if (hitScrollBar) return;
1330 MouseHandler(position, buttons);
1331 }
1332 private void MouseHandler(Point position, MouseButtons buttons) {
1333 if ((buttons & MouseButtons.Left) != 0) {
1334 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight());
1335 int i = (position.Y - 2) / lh + offset;
1336 if (i < 0) i = 0;
1337 if (i >= items.Count) i = items.Count - 1;
1338 Boolean changed = false;
1339 Object current = items[i];
1340 if (!ReferenceEquals(highlighted, current)) changed = true;
1341 highlighted = current;
1342 if ((new Rectangle(Point.Empty, Bounds.Size)).Contains(position)) {
1343 if (!ReferenceEquals(selected, current)) changed = true;
1344 selected = current;
1345 }
1346 if (changed) Invalidate();
1347 }
1348 }
1349 }
1350 public class FBGDomainUpDown : FBGControl {
1351 private List<Object> items = new List<object>();
1352 private int selectedIndex = -1;
1353 private ButtonState buttonUpState = ButtonState.Normal;
1354 private ButtonState buttonDownState = ButtonState.Normal;
1355 private Converter<Object, String> itemFormatter = null;
1356 public Boolean AllowSelectEmpty { get; set; }
1357 public Converter<Object, String> ItemFormatter { get { return itemFormatter; } set { itemFormatter = value; Invalidate(); } }
1358 public event EventHandler SelectedIndexChanged;
1359 public FBGDomainUpDown(IFBGContainerControl parent)
1360 : base(parent) {
1361 BackColor = Color.White;
1362 }
1363 public void AddItem(Object item) {
1364 items.Add(item);
1365 Invalidate();
1366 }
1367 public void RemoveItem(Object item) {
1368 items.Remove(item);
1369 FixSelectedIndex(0);
1370 }
1371 public void RemoveItem(int index) {
1372 items.RemoveAt(index);
1373 FixSelectedIndex(0);
1374 }
1375 public int SelectedIndex {
1376 get { return selectedIndex; }
1377 set {
1378 if (value < -2 || value >= items.Count) throw new ArgumentOutOfRangeException("value", "Value must be between -1 and the number of items minus one");
1379 if (selectedIndex == value) return;
1380 selectedIndex = value;
1381 Invalidate();
1382 RaiseEvent(SelectedIndexChanged);
1383 }
1384 }
1385 public Object SelectedItem {
1386 get { return selectedIndex == -1 ? null : items[selectedIndex]; }
1387 set {
1388 if (value == null) {
1389 SelectedIndex = -1;
1390 } else {
1391 for (int i = 0; i < items.Count; i++) {
1392 if (items[i] == value) {
1393 SelectedIndex = i;
1394 break;
1395 }
1396 }
1397 }
1398 }
1399 }
1400 private void FixSelectedIndex(int change) {
1401 int value = selectedIndex;
1402 if (value == 0 && change == -1 && !AllowSelectEmpty) change = 0;
1403 value += change;
1404 if (value < -1) value = -1;
1405 if (value >= items.Count) value = items.Count - 1;
1406 SelectedIndex = value;
1407 }
1408 protected override void Paint(Graphics g) {
1409 base.Paint(g);
1410 g.DrawRectangle(Pens.DarkBlue, 0, 0, Bounds.Width - 1, Bounds.Height - 1);
1411 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight());
1412 if (selectedIndex == -1) {
1413 g.FillRectangle(Brushes.DarkGray, 2, 2, Bounds.Width - 4 - 16, Bounds.Height - 4);
1414 } else {
1415 using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap)) {
1416 sf.LineAlignment = StringAlignment.Center;
1417 Object item = items[selectedIndex];
1418 String text = itemFormatter == null ? (item == null ? String.Empty : item.ToString()) : itemFormatter(item);
1419 g.FillRectangle(Brushes.LightGray, 2, 2, Bounds.Width - 4 - 16, Bounds.Height - 4);
1420 g.DrawString(text, SystemFonts.DefaultFont, SystemBrushes.WindowText, new Rectangle(3, 2, Bounds.Width - 6 - 16, Bounds.Height - 4), sf);
1421 }
1422 }
1423 int xoff = Bounds.Width - 17;
1424 int he = (Bounds.Height - 2) / 2;
1425 ControlPaint.DrawScrollButton(g, xoff, 1, 16, he, ScrollButton.Up, buttonUpState);
1426 ControlPaint.DrawScrollButton(g, xoff, Bounds.Height - he - 1, 16, he, ScrollButton.Down, buttonDownState);
1427 }
1428 protected override void MouseDown(Point position, MouseButtons buttons) {
1429 CaptureKeyboard(true);
1430 if ((buttons & MouseButtons.Left) != 0) {
1431 CaptureMouse(true);
1432 if (position.X > Bounds.Width - 17) {
1433 if (position.Y < Bounds.Height / 2) {
1434 buttonUpState = ButtonState.Pushed;
1435 FixSelectedIndex(-1);
1436 } else {
1437 buttonDownState = ButtonState.Pushed;
1438 FixSelectedIndex(1);
1439 }
1440 Invalidate(new Rectangle(Bounds.Width - 16, 0, 16, Bounds.Height));
1441 }
1442 }
1443 }
1444 protected override void MouseUp(Point position, MouseButtons buttons) {
1445 if ((buttons & MouseButtons.Left) != 0) {
1446 CaptureMouse(false);
1447 buttonUpState = buttonDownState = ButtonState.Normal;
1448 Invalidate(new Rectangle(Bounds.Width - 16, 0, 16, Bounds.Height));
1449 }
1450 }
1451 protected override void KeyDown(Keys key) {
1452 base.KeyDown(key);
1453 if (key == Keys.Down) {
1454 FixSelectedIndex(1);
1455 } else if (key == Keys.Up) {
1456 FixSelectedIndex(-1);
1457 }
1458 }
1459 }
1460 public interface IFBGTreeParent {
1461 FBGTreeView TreeView { get; }
1462 int Depth { get; }
1463 void AddChild(FBGTreeNode node);
1464 void RemoveChild(FBGTreeNode node);
1465 }
1466 public class FBGTreeNode : IFBGTreeParent {
1467 private List<FBGTreeNode> children = new List<FBGTreeNode>();
1468 private Boolean expanded = true;
1469 private Boolean hasCheckBox = false;
1470 private Boolean isChecked = false;
1471 private Object item;
1472
1473 public FBGTreeView TreeView { get; private set; }
1474 public int Depth { get; private set; }
1475 public Object Tag { get; set; }
1476 public IFBGTreeParent Parent { get; private set; }
1477
1478 public IList<FBGTreeNode> Children { get { return children.AsReadOnly(); } }
1479
1480 public Object Item {
1481 get { return item; }
1482 set {
1483 item = value;
1484 Invalidate();
1485 }
1486 }
1487 public Boolean Expanded {
1488 get { return expanded; }
1489 set {
1490 if (expanded == value) return;
1491 expanded = value;
1492 UpdateTree();
1493 }
1494 }
1495 public Boolean HasCheckBox {
1496 get { return hasCheckBox; }
1497 set {
1498 if (hasCheckBox == value) return;
1499 hasCheckBox = value;
1500 Invalidate();
1501 }
1502 }
1503 public Boolean Checked {
1504 get { return isChecked; }
1505 set {
1506 if (isChecked == value) return;
1507 isChecked = value;
1508 Invalidate();
1509 if (TreeView != null) TreeView.RaiseNodeCheckedChanged(this);
1510 }
1511 }
1512
1513 public FBGTreeNode(IFBGTreeParent parent, Object item) {
1514 this.TreeView = parent.TreeView;
1515 this.Depth = parent.Depth + 1;
1516 this.Parent = parent;
1517 this.item = item;
1518 parent.AddChild(this);
1519 }
1520
1521 public void Remove() {
1522 Parent.RemoveChild(this);
1523 }
1524 void IFBGTreeParent.AddChild(FBGTreeNode node) {
1525 children.Add(node);
1526 if (Expanded) UpdateTree();
1527 else Invalidate();
1528 }
1529 void IFBGTreeParent.RemoveChild(FBGTreeNode node) {
1530 children.Remove(node);
1531 TreeView.ReleaseNodeFromTree(node);
1532 if (Expanded) UpdateTree();
1533 else Invalidate();
1534 }
1535 public void Invalidate() {
1536 if (TreeView != null) TreeView.Invalidate(this);
1537 }
1538 private void UpdateTree() {
1539 if (TreeView != null) TreeView.UpdateView();
1540 }
1541 public FBGTreeNode AddNode(Object item) {
1542 return new FBGTreeNode(this, item);
1543 }
1544 }
1545 public class FBGTreeView : FBGControl, IFBGTreeParent {
1546 private List<FBGTreeNode> items = new List<FBGTreeNode>();
1547 private List<FBGTreeNode> itemsView = new List<FBGTreeNode>();
1548 private FBGTreeNode selected = null;
1549 private FBGTreeNode highlighted = null;
1550 private Boolean hasScrollBar = false;
1551 private Boolean hitScrollBar = false;
1552 private int offset = 0;
1553 private ButtonState buttonUpState = ButtonState.Normal;
1554 private ButtonState buttonDownState = ButtonState.Normal;
1555 private Converter<Object, String> itemFormatter = null;
1556
1557 public Converter<Object, String> ItemFormatter { get { return itemFormatter; } set { itemFormatter = value; Invalidate(); } }
1558 public FBGTreeNode SelectedNode { get { return selected; } set { if (selected != value) { selected = value; Invalidate(); RaiseEvent(SelectedNodeChanged); } } }
1559 public IList<FBGTreeNode> Nodes { get { return items.AsReadOnly(); } }
1560
1561 public event EventHandler SelectedNodeChanged;
1562 public event EventHandler NodeCheckedChanged;
1563
1564 public FBGTreeView(IFBGContainerControl parent) : base(parent) {
1565 BackColor = Color.White;
1566 }
1567 FBGTreeView IFBGTreeParent.TreeView { get { return this; } }
1568 int IFBGTreeParent.Depth { get { return -1; } }
1569 void IFBGTreeParent.AddChild(FBGTreeNode node) {
1570 items.Add(node);
1571 UpdateView();
1572 }
1573 void IFBGTreeParent.RemoveChild(FBGTreeNode node) {
1574 items.Remove(node);
1575 ReleaseNodeFromTree(node);
1576 UpdateView();
1577 }
1578 public FBGTreeNode AddNode(Object item) { return new FBGTreeNode(this, item); }
1579 internal void ReleaseNodeFromTree(FBGTreeNode node) {
1580 if (highlighted == node) highlighted = null;
1581 if (selected == node) SelectedNode = null;
1582 }
1583 internal void RaiseNodeCheckedChanged(FBGTreeNode node) {
1584 RaiseEvent(NodeCheckedChanged);
1585 }
1586 internal void UpdateView() {
1587 List<FBGTreeNode> newView = new List<FBGTreeNode>();
1588 Stack<Queue<FBGTreeNode>> stack = new Stack<Queue<FBGTreeNode>>();
1589 stack.Push(new Queue<FBGTreeNode>(items));
1590 while (stack.Count > 0) {
1591 Queue<FBGTreeNode> list = stack.Peek();
1592 if (list.Count == 0) {
1593 stack.Pop();
1594 continue;
1595 }
1596 FBGTreeNode item = list.Dequeue();
1597 newView.Add(item);
1598 if (item.Expanded) stack.Push(new Queue<FBGTreeNode>(item.Children));
1599 }
1600 itemsView = newView;
1601 Invalidate();
1602 }
1603 internal void Invalidate(FBGTreeNode node) {
1604 int i = itemsView.IndexOf(node);
1605 if (i == -1) return;
1606 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight() / 2.0) * 2;
1607 Invalidate(new Rectangle(1, i * lh, Bounds.Width - 1, lh));
1608 }
1609 protected override void Paint(Graphics g) {
1610 base.Paint(g);
1611
1612 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight() / 2.0) * 2;
1613 int th = lh * itemsView.Count;
1614 hasScrollBar = offset > 0 || th + 2 > Bounds.Height;
1615 int y = 2;
1616 using (Pen dottedpen = new Pen(Brushes.Black)) {
1617 dottedpen.DashStyle = DashStyle.Dot;
1618 using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap)) {
1619 int lw = Bounds.Width - 2;
1620 if (hasScrollBar) lw -= 17;
1621 for (int i = offset; i < itemsView.Count; i++) {
1622 FBGTreeNode item = itemsView[i];
1623 if (y + 2 < Bounds.Height) {
1624 Object obj = item.Item;
1625 String text = itemFormatter == null ? (obj == null ? String.Empty : obj.ToString()) : itemFormatter(obj);
1626 if (item == selected) g.FillRectangle(Brushes.DarkGray, 2, y, lw - 2, lh);
1627 if (item == highlighted) g.DrawRectangle(dottedpen, 2, y, lw - 3, lh - 1);
1628 int x = 3 + 19 * item.Depth + 14;
1629 if (item.HasCheckBox) {
1630 x += 2;
1631 ControlPaint.DrawCheckBox(g, x, y, lh, lh, item.Checked ? ButtonState.Checked : ButtonState.Normal);
1632 x += lh + 1;
1633 }
1634 g.DrawString(text, SystemFonts.DefaultFont, SystemBrushes.WindowText, new Rectangle(x, y, lw - x, lh), sf);
1635 }
1636 int upto = y + 2 + 4 - 8;
1637 for (int j = i - 1; j >= 0; j--) {
1638 if (itemsView[j].Depth < item.Depth) {
1639 break;
1640 }
1641 if (itemsView[j].Depth == item.Depth) {
1642 if (itemsView[j].Children.Count > 0) {
1643 upto = 2 + lh * (j - offset) + 10;
1644 } else {
1645 upto = 2 + lh * (j - offset) + 6;
1646 }
1647 break;
1648 }
1649 if (j <= offset) {
1650 upto = 2 + 2 + 4 - 8;
1651 break;
1652 }
1653 }
1654 if (item.Children.Count > 0) {
1655 g.DrawRectangle(Pens.Black, 3 + 19 * item.Depth, y + 2, 8, 8);
1656 g.DrawLine(Pens.Black, 3 + 19 * item.Depth + 2, y + 2 + 4, 3 + 19 * item.Depth + 6, y + 2 + 4);
1657 if (!item.Expanded) g.DrawLine(Pens.Black, 3 + 19 * item.Depth + 4, y + 4, 3 + 19 * item.Depth + 4, y + 2 + 6);
1658
1659 g.DrawLine(dottedpen, 3 + 19 * item.Depth + 8, y + 2 + 4, 3 + 19 * item.Depth + 14, y + 2 + 4);
1660 g.DrawLine(dottedpen, 3 + 19 * item.Depth + 4, y + 2 + 4 - 6, 3 + 19 * item.Depth + 4, upto);
1661 } else {
1662 g.DrawLine(dottedpen, 3 + 19 * item.Depth + 4, y + 2 + 4, 3 + 19 * item.Depth + 14, y + 2 + 4);
1663 g.DrawLine(dottedpen, 3 + 19 * item.Depth + 4, y + 2 + 4 - 2, 3 + 19 * item.Depth + 4, upto);
1664 }
1665 y += lh;
1666 //if (y + lh + 2 >= Bounds.Height && item.Depth == 0) break;
1667 if (y + 2 >= Bounds.Height && item.Depth == 0) break;
1668 }
1669 }
1670 }
1671 //if (y < th) hasScrollBar = true;
1672 //hasScrollBar = true;
1673 if (hasScrollBar) {
1674 int xoff = Bounds.Width - 17;
1675 using (Brush b = new LinearGradientBrush(new Rectangle(xoff, 0, 17, 1), Color.LightGray, Color.White, LinearGradientMode.Horizontal))
1676 g.FillRectangle(b, xoff, 17, 16, Bounds.Height - 17 - 17);
1677 ControlPaint.DrawScrollButton(g, xoff, 1, 16, 16, ScrollButton.Up, buttonUpState);
1678 ControlPaint.DrawScrollButton(g, xoff, Bounds.Height - 17, 16, 16, ScrollButton.Down, buttonDownState);
1679 g.DrawRectangle(Pens.Black, new Rectangle(xoff, 17 + offset * (Bounds.Height - 17 - 17 - 20) / (itemsView.Count - 1), 15, 20));
1680 }
1681
1682 g.DrawRectangle(Pens.DarkBlue, 0, 0, Bounds.Width - 1, Bounds.Height - 1);
1683 }
1684 protected override void MouseDown(Point position, MouseButtons buttons) {
1685 CaptureKeyboard(true);
1686 if ((buttons & MouseButtons.Left) != 0) {
1687 CaptureMouse(true);
1688 if (hasScrollBar && position.X > Bounds.Width - 17) {
1689 hitScrollBar = true;
1690 if (position.Y < 17) {
1691 offset--;
1692 buttonUpState = ButtonState.Pushed;
1693 } else if (position.Y > Bounds.Height - 17) {
1694 offset++;
1695 buttonDownState = ButtonState.Pushed;
1696 } else {
1697 offset = (int)Math.Round((position.Y - 17) * (itemsView.Count - 1) / (double)(Bounds.Height - 17 - 17 - 10));
1698 }
1699 if (offset < 0) offset = 0;
1700 if (offset >= itemsView.Count) offset = itemsView.Count - 1;
1701 Invalidate();
1702 } else {
1703 MouseHandler(position, buttons, true);
1704 }
1705 }
1706 }
1707 protected override void MouseMove(Point position, MouseButtons buttons) {
1708 if (hitScrollBar) {
1709 if (position.Y < 17) {
1710 } else if (position.Y > Bounds.Height - 17) {
1711 } else {
1712 offset = (int)Math.Round((position.Y - 17) * (itemsView.Count - 1) / (double)(Bounds.Height - 17 - 17 - 10));
1713 if (offset < 0) offset = 0;
1714 if (offset >= itemsView.Count) offset = itemsView.Count - 1;
1715 Invalidate();
1716 }
1717 return;
1718 }
1719 MouseHandler(position, buttons, false);
1720 }
1721 protected override void MouseUp(Point position, MouseButtons buttons) {
1722 if ((buttons & MouseButtons.Left) != 0) {
1723 CaptureMouse(false);
1724 buttonUpState = buttonDownState = ButtonState.Normal;
1725 Invalidate();
1726 if (hitScrollBar) {
1727 hitScrollBar = false;
1728 return;
1729 }
1730 }
1731 if (hitScrollBar) return;
1732 MouseHandler(position, buttons, false);
1733 }
1734 private void MouseHandler(Point position, MouseButtons buttons, Boolean down) {
1735 if ((buttons & MouseButtons.Left) != 0 && itemsView.Count > 0) {
1736 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight() / 2.0) * 2;
1737 int i = (position.Y - 2) / lh + offset;
1738 if (i < 0) i = 0;
1739 if (i >= itemsView.Count) i = itemsView.Count - 1;
1740 Boolean changed = false;
1741 FBGTreeNode current = itemsView[i];
1742 if (!ReferenceEquals(highlighted, current)) changed = true;
1743 highlighted = current;
1744 if (current.Children.Count > 0 && (new Rectangle(3 + 19 * current.Depth, 2 + lh * (i - offset) + 2, 8, 8)).Contains(position)) {
1745 if (down) current.Expanded = !current.Expanded;
1746 } else if (current.HasCheckBox && (new Rectangle(3 + 19 * current.Depth + 14 + 2, 2 + lh * (i - offset), lh, lh)).Contains(position)) {
1747 if (down) current.Checked = !current.Checked;
1748 } else if ((new Rectangle(Point.Empty, Bounds.Size)).Contains(position)) {
1749 SelectedNode = current;
1750 changed = false;
1751 }
1752 if (changed) Invalidate();
1753 }
1754 }
1755 protected override void KeyDown(Keys key) {
1756 base.KeyDown(key);
1757 if (key == Keys.Up) {
1758 int i = itemsView.IndexOf(selected);
1759 i--;
1760 if (i >= 0) SelectAndScrollIntoView(itemsView[i]);
1761 } else if (key == Keys.Down) {
1762 int i = itemsView.IndexOf(selected);
1763 i++;
1764 if (i < itemsView.Count) SelectAndScrollIntoView(itemsView[i]);
1765 } else if (key == Keys.Left && selected != null) {
1766 if (selected.Expanded && selected.Children.Count > 0) {
1767 selected.Expanded = false;
1768 } else {
1769 FBGTreeNode tn = selected.Parent as FBGTreeNode;
1770 if (tn != null) SelectAndScrollIntoView(tn);
1771 }
1772 } else if (key == Keys.Right && selected != null) {
1773 if (!selected.Expanded && selected.Children.Count > 0) {
1774 selected.Expanded = true;
1775 } else if (selected.Children.Count > 0) {
1776 SelectAndScrollIntoView(selected.Children[0]);
1777 }
1778 } else if (key == Keys.Space && selected != null) {
1779 if (selected.HasCheckBox) selected.Checked = !selected.Checked;
1780 }
1781 }
1782 private void SelectAndScrollIntoView(FBGTreeNode tn) {
1783 int i = itemsView.IndexOf(tn);
1784 if (i == -1) {
1785 for (FBGTreeNode tp = tn.Parent as FBGTreeNode; tp != null; tp = tp.Parent as FBGTreeNode) if (!tp.Expanded) tp.Expanded = true;
1786 i = itemsView.IndexOf(tn);
1787 }
1788 if (i != -1) {
1789 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight() / 2.0) * 2;
1790 if (i < offset) offset = i;
1791 offset = Math.Max(offset, i - Bounds.Height / lh + 1);
1792 }
1793 highlighted = tn;
1794 SelectedNode = tn;
1795 }
1796 }
1797 }