Mercurial > hg > ucis.core
annotate FBGUI.cs @ 26:7f0b7a53a000
FBGUI: Allow derived classes to access some internals
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 15 Apr 2013 20:29:02 +0200 |
parents | 644a923bca98 |
children | 5bfc6c68591e |
rev | line source |
---|---|
23 | 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>(); | |
26
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
121 protected IFBGControl mouseCaptureControl = null; |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
122 protected IFBGControl keyboardCaptureControl = null; |
23 | 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; } | |
26
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
515 private Bitmap Frontbuffer = null; |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
516 protected Object RenderLock = new object(); |
23 | 517 public event EventHandler<InvalidateEventArgs> Painted; |
26
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
518 protected Size size = Size.Empty; |
23 | 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 } | |
26
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
591 protected FBGRenderer() : base(null) { |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
592 BackColor = SystemColors.Control; |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
593 } |
23 | 594 public override void Invalidate(Rectangle rect) { |
595 if (rect.Width == 0 || rect.Height == 0) return; | |
596 lock (RenderLock) { | |
597 if (SuspendDrawing || PaintTimer != null) { | |
598 DirtyRectangle = DirtyRectangle.IsEmpty ? rect : Rectangle.Union(DirtyRectangle, rect); | |
599 if (!SuspendDrawing && !PaintScheduled) { | |
600 PaintScheduled = true; | |
601 PaintTimer.Change(PaintDelay, Timeout.Infinite); | |
602 } | |
603 } else { | |
604 Refresh(rect); | |
605 } | |
606 } | |
607 } | |
608 private void PaintTimerCallback(Object state) { | |
609 try { | |
610 lock (RenderLock) { | |
611 PaintScheduled = false; | |
612 Refresh(DirtyRectangle); | |
613 DirtyRectangle = Rectangle.Empty; | |
614 } | |
615 } catch { } | |
616 } | |
26
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
617 protected virtual void Refresh(Rectangle rect) { |
23 | 618 lock (RenderLock) { |
619 rect.Intersect(Bounds); | |
620 if (rect.Width == 0 || rect.Height == 0) return; | |
26
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
621 if (Frontbuffer != null) { |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
622 using (Graphics g = Graphics.FromImage(Frontbuffer)) { |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
623 g.SetClip(rect); |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
624 Paint(g); |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
625 } |
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
626 if (Framebuffer != null) Framebuffer.DrawImage(Frontbuffer, rect, rect.Location); |
23 | 627 } |
628 RaiseEvent(Painted, new InvalidateEventArgs(rect)); | |
629 } | |
630 } | |
631 protected override void Paint(Graphics g) { | |
632 base.Paint(g); | |
633 if (Cursor != null) { | |
634 Point r = CursorPosition; | |
635 r.Offset(-cursor.Hotspot.X, -cursor.Hotspot.Y); | |
636 g.DrawImageUnscaled(Cursor.Image, r); | |
637 } | |
638 } | |
639 protected override Boolean CaptureMouse(Boolean capture) { | |
640 return true; | |
641 } | |
642 protected override Boolean CaptureKeyboard(bool capture) { | |
643 return true; | |
644 } | |
26
7f0b7a53a000
FBGUI: Allow derived classes to access some internals
Ivo Smits <Ivo@UCIS.nl>
parents:
23
diff
changeset
|
645 public virtual void Dispose() { |
23 | 646 lock (RenderLock) { |
647 if (PaintTimer != null) PaintTimer.Dispose(); | |
648 PaintTimer = null; | |
649 } | |
650 Orphaned(); | |
651 if (Frontbuffer != null) Frontbuffer.Dispose(); | |
652 } | |
653 public Bitmap LockBitmapBuffer() { | |
654 Monitor.Enter(RenderLock); | |
655 return Frontbuffer; | |
656 } | |
657 public void UnlockBitmapBuffer() { | |
658 Monitor.Exit(RenderLock); | |
659 } | |
660 public new void MouseMove(Point position, MouseButtons buttons) { base.MouseMove(position, buttons); } | |
661 public new void MouseDown(Point position, MouseButtons buttons) { base.MouseDown(position, buttons); } | |
662 public new void MouseUp(Point position, MouseButtons buttons) { base.MouseUp(position, buttons); } | |
663 public new void KeyDown(Keys key) { base.KeyDown(key); } | |
664 public new void KeyPress(Char key) { base.KeyPress(key); } | |
665 public new void KeyUp(Keys key) { base.KeyUp(key); } | |
666 } | |
667 public class FBGForm : FBGDockContainer { | |
668 private Point prevPosition = Point.Empty; | |
669 private NonClientOps moveresize = 0; | |
670 private String text = String.Empty; | |
671 public event EventHandler TextChanged; | |
672 public Boolean Sizable { get; set; } | |
673 public Boolean Movable { get; set; } | |
674 public Boolean Closable { get; set; } | |
675 [Flags] | |
676 private enum NonClientOps : int { | |
677 None = 0, | |
678 Move = 1, | |
679 ResizeLeft = 2, | |
680 ResizeRight = 4, | |
681 ResizeTop = 8, | |
682 ResizeBottom = 16, | |
683 ButtonClose = 32, | |
684 MoveResize = ResizeLeft | ResizeRight | ResizeBottom | ResizeTop | Move, | |
685 } | |
686 public FBGForm(IFBGContainerControl parent) : base(parent) { | |
687 BackColor = SystemColors.Control; | |
688 ClientRectangle = new Rectangle(4, 22, Bounds.Width - 8, Bounds.Height - 26); | |
689 Sizable = true; | |
690 Movable = true; | |
691 Closable = false; | |
692 } | |
693 public override Rectangle Bounds { | |
694 get { return base.Bounds; } | |
695 set { | |
696 ClientRectangle = new Rectangle(4, 22, value.Width - 8, value.Height - 26); | |
697 base.Bounds = value; | |
698 } | |
699 } | |
700 public String Text { get { return text; } set { if (text == value) return; text = value; Invalidate(new Rectangle(0, 0, Bounds.Width, 20)); RaiseEvent(TextChanged); } } | |
701 protected override void MouseDown(Point p, MouseButtons buttons) { | |
702 NonClientOps mr = 0; | |
703 if ((buttons & MouseButtons.Left) != 0) { | |
704 if ((new Rectangle(Bounds.Width - 5 - 14, 4, 14, 14)).Contains(p)) { | |
705 mr = NonClientOps.ButtonClose; | |
706 } else { | |
707 if (Sizable) { | |
708 if (Movable) { | |
709 if (p.X < 4) mr |= NonClientOps.ResizeLeft; | |
710 if (p.Y < 4) mr |= NonClientOps.ResizeTop; | |
711 } | |
712 if (p.X >= Bounds.Width - 4) mr |= NonClientOps.ResizeRight; | |
713 if (p.Y >= Bounds.Height - 4) mr |= NonClientOps.ResizeBottom; | |
714 } | |
715 if (mr == 0 && Movable && p.Y < 20) mr = NonClientOps.Move; | |
716 } | |
717 } | |
718 if (mr != 0) { | |
719 moveresize = mr; | |
720 prevPosition = p; | |
721 CaptureMouse(true); | |
722 } else { | |
723 base.MouseDown(p, buttons); | |
724 } | |
725 } | |
726 protected override void MouseMove(Point position, MouseButtons buttons) { | |
727 if (moveresize == 0) { | |
728 base.MouseMove(position, buttons); | |
729 } else if ((moveresize & NonClientOps.MoveResize) != 0) { | |
730 Rectangle b = Bounds; | |
731 int dx = position.X - prevPosition.X; | |
732 int dy = position.Y - prevPosition.Y; | |
733 if (moveresize == NonClientOps.Move) b.Offset(dx, dy); | |
734 if ((moveresize & NonClientOps.ResizeLeft) != 0) { | |
735 b.X += dx; | |
736 b.Width -= dx; | |
737 } else if ((moveresize & NonClientOps.ResizeRight) != 0) { | |
738 b.Width += dx; | |
739 prevPosition.X = position.X; | |
740 } | |
741 if ((moveresize & NonClientOps.ResizeTop) != 0) { | |
742 b.Y += dy; | |
743 b.Height -= dy; | |
744 } else if ((moveresize & NonClientOps.ResizeBottom) != 0) { | |
745 b.Height += dy; | |
746 prevPosition.Y = position.Y; | |
747 } | |
748 if (b.Width < 55) b.Width = 55; | |
749 if (b.Height < 25) b.Height = 25; | |
750 Bounds = b; | |
751 } | |
752 } | |
753 protected override void MouseUp(Point position, MouseButtons buttons) { | |
754 if (moveresize == 0) { | |
755 base.MouseUp(position, buttons); | |
756 } else if ((buttons & MouseButtons.Left) != 0) { | |
757 MouseMove(position, buttons); | |
758 CaptureMouse(false); | |
759 if (moveresize == NonClientOps.ButtonClose && (new Rectangle(Bounds.Width - 5 - 14, 4, 14, 14)).Contains(position) && Closable) Close(); | |
760 moveresize = 0; | |
761 } | |
762 } | |
763 protected override void Paint(Graphics g) { | |
764 base.Paint(g); | |
765 g.DrawRectangle(Pens.Gray, 0, 0, Bounds.Width - 1, Bounds.Height - 1); | |
766 g.DrawRectangle(Pens.LightGray, 1, 1, Bounds.Width - 3, Bounds.Height - 3); | |
767 g.DrawRectangle(Pens.DarkGray, 2, 20, Bounds.Width - 5, Bounds.Height - 23); | |
768 g.DrawRectangle(Pens.Gray, 3, 21, Bounds.Width - 7, Bounds.Height - 25); | |
769 using (Brush b = new LinearGradientBrush(new Rectangle(0, 1, 1, 18), Color.Gray, Color.LightGray, LinearGradientMode.Vertical)) | |
770 g.FillRectangle(b, 2, 2, Bounds.Width - 4, 18); | |
771 | |
772 g.DrawString(Text, SystemFonts.CaptionFont, Brushes.Black, 4, 1); | |
773 | |
774 g.DrawRectangle(Pens.Gray, Bounds.Width - 5 - 14, 4, 14, 14); | |
775 g.DrawRectangle(Pens.Gray, Bounds.Width - 5 - 14 - 16, 4, 14, 14); | |
776 g.DrawRectangle(Pens.Gray, Bounds.Width - 5 - 14 - 32, 4, 14, 14); | |
777 using (Brush b = new LinearGradientBrush(new Rectangle(0, 5, 1, 13), Color.LightGray, Color.DarkGray, LinearGradientMode.Vertical)) { | |
778 g.FillRectangle(b, Bounds.Width - 5 - 14 + 1, 5, 13, 13); | |
779 g.FillRectangle(b, Bounds.Width - 5 - 14 + 1 - 16, 5, 13, 13); | |
780 g.FillRectangle(b, Bounds.Width - 5 - 14 + 1 - 32, 5, 13, 13); | |
781 } | |
782 if (Closable) { | |
783 g.DrawLine(Pens.Black, Bounds.Width - 5 - 14 + 3, 4 + 3, Bounds.Width - 5 - 14 + 14 - 3, 4 + 14 - 3); | |
784 g.DrawLine(Pens.Black, Bounds.Width - 5 - 14 + 3, 4 + 14 - 3, Bounds.Width - 5 - 14 + 14 - 3, 4 + 3); | |
785 } | |
786 } | |
787 public void Close() { | |
788 Parent.RemoveControl(this); | |
789 } | |
790 } | |
791 public class FBGDesktop : FBGContainerControl { | |
792 FBGContainerControl windowcontainer; | |
793 FBGContainerControl menucontainer; | |
794 Boolean startup = true; | |
795 class FBGWindowState { | |
796 public IFBGControl Control; | |
797 public FBGButton MenuButton; | |
798 public Boolean Visible; | |
799 public Rectangle OldBounds; | |
800 public FBGWindowState(IFBGControl cntrl, FBGButton btn) { | |
801 Control = cntrl; | |
802 MenuButton = btn; | |
803 Visible = true; | |
804 } | |
805 } | |
806 Dictionary<IFBGControl, FBGWindowState> windowstates = new Dictionary<IFBGControl, FBGWindowState>(); | |
807 public FBGDesktop(IFBGContainerControl parent) : base(parent) { | |
808 menucontainer = new FBGContainerControl(this); | |
809 menucontainer.Bounds = new Rectangle(0, Bounds.Height - 25, Bounds.Width, 25); | |
810 windowcontainer = new FBGContainerControl(this); | |
811 windowcontainer.Bounds = new Rectangle(0, 0, Bounds.Width, Bounds.Height - 25); | |
812 startup = false; | |
813 } | |
814 public override Rectangle Bounds { | |
815 get { return base.Bounds; } | |
816 set { | |
817 if (Bounds == value) return; | |
818 base.Bounds = value; | |
819 if (startup) return; | |
820 menucontainer.Bounds = new Rectangle(0, value.Height - 25, value.Width, 25); | |
821 windowcontainer.Bounds = new Rectangle(0, 0, value.Width, value.Height - 25); | |
822 ScaleMenuButtons(); | |
823 } | |
824 } | |
825 protected override void AddControl(IFBGControl control) { | |
826 if (startup) { | |
827 base.AddControl(control); | |
828 return; | |
829 } | |
830 ((IFBGContainerControl)windowcontainer).AddControl(control); | |
831 FBGButton btn = new FBGButton(menucontainer); | |
832 FBGForm formcontrol = control as FBGForm; | |
833 if (formcontrol == null) { | |
834 btn.Text = "Untitled"; | |
835 } else { | |
836 formcontrol.TextChanged += delegate(Object sender, EventArgs e) { | |
837 btn.Text = formcontrol.Text; | |
838 }; | |
839 btn.Text = formcontrol.Text; | |
840 } | |
841 FBGWindowState ws = new FBGWindowState(control, btn); | |
842 windowstates.Add(control, ws); | |
843 ScaleMenuButtons(); | |
844 btn.Click += delegate(Object sender, EventArgs e) { | |
845 if (ws.Visible) { | |
846 if (ws.MenuButton.BackColor == Color.DarkGray) { | |
847 ws.OldBounds = ws.Control.Bounds; | |
848 ws.Visible = false; | |
849 ws.Control.Bounds = Rectangle.Empty; | |
850 } else { | |
851 windowcontainer.BringControlToFront(ws.Control); | |
852 foreach (FBGWindowState wsa in windowstates.Values) if (!ReferenceEquals(ws, wsa)) wsa.MenuButton.BackColor = SystemColors.ButtonFace; | |
853 ws.MenuButton.BackColor = Color.DarkGray; | |
854 } | |
855 } else { | |
856 ws.Control.Bounds = ws.OldBounds; | |
857 ws.Visible = true; | |
858 windowcontainer.BringControlToFront(ws.Control); | |
859 foreach (FBGWindowState wsa in windowstates.Values) if (!ReferenceEquals(ws, wsa)) wsa.MenuButton.BackColor = SystemColors.ButtonFace; | |
860 ws.MenuButton.BackColor = Color.DarkGray; | |
861 } | |
862 }; | |
863 } | |
864 public override void RemoveControl(IFBGControl control) { | |
865 windowcontainer.RemoveControl(control); | |
866 windowstates.Remove(control); | |
867 ScaleMenuButtons(); | |
868 } | |
869 private void ScaleMenuButtons() { | |
870 int bcount = windowstates.Count; | |
871 int bwidth = 200; | |
872 int twidth = bwidth * bcount; | |
873 if (twidth > Bounds.Width) bwidth = menucontainer.Bounds.Width / bcount; | |
874 int i = 0; | |
875 foreach (FBGWindowState ws in windowstates.Values) { | |
876 ws.MenuButton.Bounds = new Rectangle(i * bwidth, 0, bwidth, 25); | |
877 i++; | |
878 } | |
879 } | |
880 protected override void Paint(Graphics g) { | |
881 base.Paint(g); | |
882 g.DrawLine(Pens.Black, 0, Bounds.Height - 25, Bounds.Width, Bounds.Height - 25); | |
883 } | |
884 protected override void MouseDown(Point position, MouseButtons buttons) { | |
885 IFBGControl control = FindControlAtPosition(position); | |
886 if (ReferenceEquals(control, windowcontainer)) { | |
887 control = windowcontainer.FindControlAtPosition(PointToChild(windowcontainer, position)); | |
888 if (!ReferenceEquals(control, null)) { | |
889 windowcontainer.BringControlToFront(control); | |
890 foreach (FBGWindowState ws in windowstates.Values) | |
891 ws.MenuButton.BackColor = ReferenceEquals(ws.Control, control) ? Color.DarkGray : SystemColors.ButtonFace; | |
892 } | |
893 } | |
894 base.MouseDown(position, buttons); | |
895 } | |
896 } | |
897 | |
898 public class FBGLabel : FBGControl, IDisposable { | |
899 public FBGLabel(IFBGContainerControl parent) : base(parent) { | |
900 Size = new Size(200, 16); | |
901 } | |
902 private String text = String.Empty; | |
903 private Font font = SystemFonts.DefaultFont; | |
904 private Brush brush = SystemBrushes.ControlText; | |
905 private StringFormat stringformat = new StringFormat(); | |
906 public String Text { get { return text; } set { text = value; Invalidate(); } } | |
907 public Font Font { get { return font; } set { font = value; Invalidate(); } } | |
908 public Brush Brush { get { return brush; } set { brush = value; Invalidate(); } } | |
909 public Color Color { set { Brush = new SolidBrush(value); } } | |
910 public StringAlignment Alignment { get { return stringformat.Alignment; } set { stringformat.Alignment = value; Invalidate(); } } | |
911 public StringFormatFlags FormatFlags { get { return stringformat.FormatFlags; } set { stringformat.FormatFlags = value; Invalidate(); } } | |
912 public StringAlignment LineAlignment { get { return stringformat.LineAlignment; } set { stringformat.LineAlignment = value; Invalidate(); } } | |
913 public StringTrimming Trimming { get { return stringformat.Trimming; } set { stringformat.Trimming = value; Invalidate(); } } | |
914 protected override void Paint(Graphics g) { | |
915 base.Paint(g); | |
916 g.DrawString(text, font, brush, new Rectangle(Point.Empty, Bounds.Size), stringformat); | |
917 } | |
918 public void Dispose() { | |
919 stringformat.Dispose(); | |
920 } | |
921 protected override void Orphaned() { | |
922 base.Orphaned(); | |
923 Dispose(); | |
924 } | |
925 } | |
926 public class FBGTextBox : FBGControl { | |
927 public FBGTextBox(IFBGContainerControl parent) : base(parent) { | |
928 BackColor = Color.White; | |
929 Size = new Size(200, 20); | |
930 } | |
931 private String text = String.Empty; | |
932 private Char passwordChar = (Char)0; | |
933 private Font font = new Font(FontFamily.GenericMonospace, 10); | |
934 private Brush brush = SystemBrushes.ControlText; | |
935 private Boolean hasKeyboardFocus = false; | |
936 public String Text { get { return text; } set { text = value; if (CaretPosition > text.Length) CaretPosition = text.Length; Invalidate(); RaiseEvent(TextChanged); } } | |
937 public Font Font { get { return font; } set { font = value; Invalidate(); } } | |
938 public Brush Brush { get { return brush; } set { brush = value; Invalidate(); } } | |
939 public Color Color { set { Brush = new SolidBrush(value); } } | |
940 public Int32 CaretPosition { get; private set; } | |
941 public Char PasswordChar { get { return passwordChar; } set { passwordChar = value; Invalidate(); } } | |
942 public event EventHandler TextChanged; | |
943 public event KeyPressEventHandler OnKeyPress; | |
944 protected override void Paint(Graphics g) { | |
945 base.Paint(g); | |
946 g.DrawRectangle(Pens.Gray, 0, 0, Bounds.Width - 1, Bounds.Height - 1); | |
947 using (StringFormat sf_nonprinting = new StringFormat(StringFormat.GenericTypographic)) { | |
948 sf_nonprinting.Trimming = StringTrimming.None; | |
949 sf_nonprinting.FormatFlags = StringFormatFlags.DisplayFormatControl | StringFormatFlags.MeasureTrailingSpaces; | |
950 sf_nonprinting.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.None; | |
951 | |
952 float x = 1; | |
953 float y = 1; | |
954 float w = Width - 2; | |
955 if (hasKeyboardFocus && CaretPosition == 0) { | |
956 g.DrawLine(Pens.Black, x + 2, 2, x + 2, Height - 4); | |
957 } | |
958 String c = passwordChar == 0 ? null : new String(passwordChar, 1); | |
959 for (int i = 0; i < text.Length; i++) { | |
960 if (passwordChar == 0) c = text.Substring(i, 1); | |
961 SizeF s = g.MeasureString(c, font, (int)Math.Ceiling(w), sf_nonprinting); | |
962 g.DrawString(c, font, brush, x, y); | |
963 x += (float)Math.Ceiling(s.Width); | |
964 w -= (float)Math.Ceiling(s.Width); | |
965 | |
966 if (hasKeyboardFocus && i == CaretPosition - 1) { | |
967 g.DrawLine(Pens.Black, x + 2, 2, x + 2, Height - 4); | |
968 } | |
969 } | |
970 } | |
971 } | |
972 protected override void MouseDown(Point position, MouseButtons buttons) { | |
973 hasKeyboardFocus = CaptureKeyboard(true); | |
974 CaretPosition = text.Length; | |
975 float x = 1; | |
976 String c = passwordChar == 0 ? null : new String(passwordChar, 1); | |
977 for (int i = 0; i < text.Length; i++) { | |
978 if (passwordChar == 0) c = text.Substring(i, 1); | |
979 Size s; | |
980 try { | |
981 s = TextRenderer.MeasureText(c, font, Size.Empty, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix); | |
982 } catch (Exception) { | |
983 break; | |
984 } | |
985 x += s.Width; | |
986 if (position.X < x) { | |
987 CaretPosition = i; | |
988 break; | |
989 } | |
990 } | |
991 Invalidate(); | |
992 } | |
993 protected override void KeyDown(Keys key) { | |
994 if ((key & Keys.KeyCode) == Keys.Left) { | |
995 CaretPosition--; | |
996 if (CaretPosition < 0) CaretPosition = 0; | |
997 Invalidate(); | |
998 } else if ((key & Keys.KeyCode) == Keys.Right) { | |
999 CaretPosition++; | |
1000 if (CaretPosition > text.Length) CaretPosition = text.Length; | |
1001 Invalidate(); | |
1002 } else if ((key & Keys.KeyCode) == Keys.Home) { | |
1003 CaretPosition = 0; | |
1004 Invalidate(); | |
1005 } else if ((key & Keys.KeyCode) == Keys.End) { | |
1006 CaretPosition = text.Length; | |
1007 Invalidate(); | |
1008 } else if ((key & Keys.Control) != 0 && (key & Keys.KeyCode) == Keys.V) { | |
1009 String cbtext = Clipboard.GetText(TextDataFormat.UnicodeText); | |
1010 CaretPosition += cbtext.Length; | |
1011 Text = Text.Insert(CaretPosition - cbtext.Length, cbtext); | |
1012 } | |
1013 } | |
1014 protected override void KeyPress(char keyChar) { | |
1015 KeyPressEventArgs e = new KeyPressEventArgs(keyChar); | |
1016 RaiseEvent(OnKeyPress, e); | |
1017 if (e.Handled) return; | |
1018 hasKeyboardFocus = true; | |
1019 if (keyChar == 8) { | |
1020 if (CaretPosition > 0) { | |
1021 CaretPosition--; | |
1022 Text = Text.Remove(CaretPosition, 1); | |
1023 } | |
1024 } else if (keyChar == 127) { | |
1025 if (CaretPosition < Text.Length) { | |
1026 Text = Text.Remove(CaretPosition, 1); | |
1027 } | |
1028 } else if (keyChar < 32) { | |
1029 } else { | |
1030 CaretPosition++; | |
1031 Text = Text.Insert(CaretPosition - 1, new String(keyChar, 1)); | |
1032 } | |
1033 } | |
1034 public void Focus() { | |
1035 hasKeyboardFocus = CaptureKeyboard(true); | |
1036 } | |
1037 protected override void LostKeyboardCapture() { | |
1038 base.LostKeyboardCapture(); | |
1039 hasKeyboardFocus = false; | |
1040 Invalidate(); | |
1041 } | |
1042 } | |
1043 public class FBGButton : FBGControl { | |
1044 public FBGButton(IFBGContainerControl parent) : base(parent) { | |
1045 BackColor = SystemColors.ButtonFace; | |
1046 } | |
1047 private String text = String.Empty; | |
1048 private Font font = SystemFonts.DefaultFont; | |
1049 private Color color = SystemColors.ControlText; | |
1050 private Boolean pressed = false; | |
1051 private Boolean enabled = true; | |
1052 public String Text { get { return text; } set { text = value; Invalidate(); } } | |
1053 public Font Font { get { return font; } set { font = value; Invalidate(); } } | |
1054 public Color Color { get { return color; } set { color = value; Invalidate(); } } | |
1055 public Boolean Enabled { get { return enabled; } set { enabled = value; Invalidate(); } } | |
1056 public event EventHandler Click; | |
1057 protected override void Paint(Graphics g) { | |
1058 base.Paint(g); | |
1059 if (Bounds.Width == 0 || Bounds.Height == 0) return; | |
1060 if (BackColor == SystemColors.ButtonFace) { | |
1061 ControlPaint.DrawButton(g, new Rectangle(0, 0, Bounds.Width, Bounds.Height), enabled ? (pressed ? ButtonState.Pushed : ButtonState.Normal) : ButtonState.Inactive); | |
1062 } else { | |
1063 //Hackish and not completely right... | |
1064 //Todo: borrowed from mono... possible licencing issues!? | |
1065 g.DrawLine(new Pen(ControlPaint.LightLight(BackColor)), 0, 0, Bounds.Width, 0); | |
1066 g.DrawLine(new Pen(ControlPaint.LightLight(BackColor)), 0, 0, 0, Bounds.Height); | |
1067 g.DrawLine(new Pen(ControlPaint.Dark(BackColor)), 1, Bounds.Height - 2, Bounds.Width - 1, Bounds.Height - 2); | |
1068 g.DrawLine(new Pen(ControlPaint.Dark(BackColor)), Bounds.Width - 2, 1, Bounds.Width - 2, Bounds.Height - 2); | |
1069 g.DrawLine(new Pen(ControlPaint.DarkDark(BackColor)), 0, Bounds.Height - 1, Bounds.Width, Bounds.Height - 1); | |
1070 g.DrawLine(new Pen(ControlPaint.DarkDark(BackColor)), Bounds.Width - 1, 1, Bounds.Width - 1, Bounds.Height - 1); | |
1071 Graphics dc = g; | |
1072 Rectangle rectangle = new Rectangle(0, 0, Bounds.Width - 1, Bounds.Height - 1); | |
1073 Color ColorControl = BackColor; | |
1074 Color ColorControlLight = ControlPaint.Light(ColorControl); | |
1075 ButtonState state = pressed ? ButtonState.Pushed : ButtonState.Normal; | |
1076 using (Pen NormalPen = new Pen(BackColor), LightPen = new Pen(ControlPaint.Light(BackColor)), DarkPen = new Pen(ControlPaint.Dark(BackColor))) { | |
1077 // sadly enough, the rectangle gets always filled with a hatchbrush | |
1078 using (HatchBrush hb = new HatchBrush(HatchStyle.Percent50, Color.FromArgb(Math.Min(255, ColorControl.R + 3), ColorControl.G, ColorControl.B), ColorControl)) { | |
1079 dc.FillRectangle(hb, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2); | |
1080 } | |
1081 if ((state & ButtonState.All) == ButtonState.All || ((state & ButtonState.Checked) == ButtonState.Checked && (state & ButtonState.Flat) == ButtonState.Flat)) { | |
1082 using (HatchBrush hb = new HatchBrush(HatchStyle.Percent50, ColorControlLight, ColorControl)) { | |
1083 dc.FillRectangle(hb, rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4); | |
1084 } | |
1085 dc.DrawRectangle(SystemPens.ControlDark, rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1); | |
1086 } else if ((state & ButtonState.Flat) == ButtonState.Flat) { | |
1087 dc.DrawRectangle(SystemPens.ControlDark, rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1); | |
1088 } else if ((state & ButtonState.Checked) == ButtonState.Checked) { | |
1089 using (HatchBrush hb = new HatchBrush(HatchStyle.Percent50, ColorControlLight, ColorControl)) { | |
1090 dc.FillRectangle(hb, rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4); | |
1091 } | |
1092 Pen pen = DarkPen; | |
1093 dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); | |
1094 dc.DrawLine(pen, rectangle.X + 1, rectangle.Y, rectangle.Right - 2, rectangle.Y); | |
1095 | |
1096 pen = NormalPen; | |
1097 dc.DrawLine(pen, rectangle.X + 1, rectangle.Y + 1, rectangle.X + 1, rectangle.Bottom - 3); | |
1098 dc.DrawLine(pen, rectangle.X + 2, rectangle.Y + 1, rectangle.Right - 3, rectangle.Y + 1); | |
1099 | |
1100 pen = LightPen; | |
1101 dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 2, rectangle.Bottom - 1); | |
1102 dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 1); | |
1103 } else if (((state & ButtonState.Pushed) == ButtonState.Pushed) && ((state & ButtonState.Normal) == ButtonState.Normal)) { | |
1104 Pen pen = DarkPen; | |
1105 dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); | |
1106 dc.DrawLine(pen, rectangle.X + 1, rectangle.Y, rectangle.Right - 2, rectangle.Y); | |
1107 | |
1108 pen = NormalPen; | |
1109 dc.DrawLine(pen, rectangle.X + 1, rectangle.Y + 1, rectangle.X + 1, rectangle.Bottom - 3); | |
1110 dc.DrawLine(pen, rectangle.X + 2, rectangle.Y + 1, rectangle.Right - 3, rectangle.Y + 1); | |
1111 | |
1112 pen = LightPen; | |
1113 dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 2, rectangle.Bottom - 1); | |
1114 dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 1); | |
1115 } else if (((state & ButtonState.Inactive) == ButtonState.Inactive) || ((state & ButtonState.Normal) == ButtonState.Normal)) { | |
1116 Pen pen = LightPen; | |
1117 dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.Right - 2, rectangle.Y); | |
1118 dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); | |
1119 | |
1120 pen = NormalPen; | |
1121 dc.DrawLine(pen, rectangle.X + 1, rectangle.Bottom - 2, rectangle.Right - 2, rectangle.Bottom - 2); | |
1122 dc.DrawLine(pen, rectangle.Right - 2, rectangle.Y + 1, rectangle.Right - 2, rectangle.Bottom - 3); | |
1123 | |
1124 pen = DarkPen; | |
1125 dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 1, rectangle.Bottom - 1); | |
1126 dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 2); | |
1127 } | |
1128 } | |
1129 } | |
1130 Rectangle frect = new Rectangle(Point.Empty, Bounds.Size); | |
1131 SizeF textsize = g.MeasureString(Text, Font); | |
1132 using (Brush b = new SolidBrush(enabled ? Color : Color.DarkGray)) { | |
1133 g.DrawString(Text, Font, b, new PointF(Bounds.Width / 2.0f - textsize.Width / 2.0f, Bounds.Height / 2.0f - textsize.Height / 2.0f)); | |
1134 } | |
1135 } | |
1136 protected override void MouseDown(Point position, MouseButtons buttons) { | |
1137 pressed = true; | |
1138 Invalidate(); | |
1139 CaptureMouse(true); | |
1140 base.MouseDown(position, buttons); | |
1141 } | |
1142 protected override void MouseUp(Point position, MouseButtons buttons) { | |
1143 pressed = false; | |
1144 Invalidate(); | |
1145 CaptureMouse(false); | |
1146 if (position.X >= 0 && position.X <= Bounds.Width && position.Y >= 0 && position.Y <= Bounds.Height && enabled) RaiseEvent(Click); | |
1147 base.MouseUp(position, buttons); | |
1148 } | |
1149 protected override void KeyDown(Keys key) { | |
1150 if (key == Keys.Return || key == Keys.Space) { | |
1151 pressed = true; | |
1152 Invalidate(); | |
1153 } | |
1154 base.KeyDown(key); | |
1155 } | |
1156 protected override void KeyUp(Keys key) { | |
1157 if (key == Keys.Return || key == Keys.Space) { | |
1158 if (pressed) RaiseEvent(Click); | |
1159 pressed = false; | |
1160 Invalidate(); | |
1161 } | |
1162 base.KeyUp(key); | |
1163 } | |
1164 public void Focus() { | |
1165 CaptureKeyboard(true); | |
1166 } | |
1167 } | |
1168 public class FBGCheckBox : FBGControl { | |
1169 public FBGCheckBox(IFBGContainerControl parent) : base(parent) { } | |
1170 private String text = String.Empty; | |
1171 private Font font = SystemFonts.DefaultFont; | |
1172 private Color color = SystemColors.ControlText; | |
1173 private Boolean _checked = false; | |
1174 public String Text { get { return text; } set { text = value; Invalidate(); } } | |
1175 public Font Font { get { return font; } set { font = value; Invalidate(); } } | |
1176 public Color Color { get { return color; } set { color = value; Invalidate(); } } | |
1177 public Boolean Checked { get { return _checked; } set { _checked = value; Invalidate(); } } | |
1178 public event EventHandler CheckedChanged; | |
1179 protected override void Paint(Graphics g) { | |
1180 base.Paint(g); | |
1181 ControlPaint.DrawCheckBox(g, 0, 0, 13, 13, _checked ? ButtonState.Checked : ButtonState.Normal); | |
1182 g.DrawString(Text, Font, new SolidBrush(Color), 15, 0); | |
1183 } | |
1184 protected override void MouseDown(Point position, MouseButtons buttons) { | |
1185 Checked = !Checked; | |
1186 RaiseEvent(CheckedChanged); | |
1187 base.MouseDown(position, buttons); | |
1188 } | |
1189 } | |
1190 public class FBGImageBox : FBGControl { | |
1191 Image image = null; | |
1192 PictureBoxSizeMode sizeMode = PictureBoxSizeMode.Normal; | |
1193 Rectangle imageRect; | |
1194 public Image Image { get { return image; } set { image = value; UpdateImageRect(false); } } | |
1195 public FBGImageBox(IFBGContainerControl parent) : base(parent) { } | |
1196 public PictureBoxSizeMode SizeMode { get { return sizeMode; } set { sizeMode = value; UpdateImageRect(false); } } | |
1197 public override Rectangle Bounds { | |
1198 get { | |
1199 return base.Bounds; | |
1200 } | |
1201 set { | |
1202 UpdateImageRect(true); | |
1203 base.Bounds = value; | |
1204 } | |
1205 } | |
1206 private void UpdateImageRect(Boolean boundsset) { | |
1207 if (image == null) return; | |
1208 if (!boundsset && sizeMode == PictureBoxSizeMode.AutoSize) { | |
1209 Size = Image.Size; | |
1210 return; | |
1211 } | |
1212 switch (sizeMode) { | |
1213 case PictureBoxSizeMode.AutoSize: | |
1214 case PictureBoxSizeMode.Normal: | |
1215 imageRect = new Rectangle(Point.Empty, image.Size); | |
1216 break; | |
1217 case PictureBoxSizeMode.CenterImage: | |
1218 imageRect = new Rectangle(Width / 2 - image.Width / 2, Height / 2 - Image.Height / 2, Width, Height); | |
1219 break; | |
1220 case PictureBoxSizeMode.StretchImage: | |
1221 imageRect = new Rectangle(Point.Empty, Size); | |
1222 break; | |
1223 case PictureBoxSizeMode.Zoom: | |
1224 float xrat = (float)Width / (float)image.Width; | |
1225 float yrat = (float)Height / (float)image.Height; | |
1226 float rat = Math.Min(xrat, yrat); | |
1227 SizeF dispsize = new SizeF(image.Width * rat, image.Height * rat); | |
1228 imageRect = Rectangle.Round(new RectangleF(Width / 2f - dispsize.Width / 2f, Height / 2f - dispsize.Height / 2f, dispsize.Width, dispsize.Height)); | |
1229 break; | |
1230 } | |
1231 if (!boundsset) Invalidate(); | |
1232 } | |
1233 protected override void Paint(Graphics g) { | |
1234 if (!Visible) return; | |
1235 base.Paint(g); | |
1236 if (image != null) g.DrawImage(image, imageRect); | |
1237 } | |
1238 } | |
1239 public class FBGListBox : FBGControl { | |
1240 private List<Object> items = new List<object>(); | |
1241 private Object selected = null; | |
1242 private Object highlighted = null; | |
1243 private Boolean hasScrollBar = false; | |
1244 private Boolean hitScrollBar = false; | |
1245 private int offset = 0; | |
1246 private ButtonState buttonUpState = ButtonState.Normal; | |
1247 private ButtonState buttonDownState = ButtonState.Normal; | |
1248 private Converter<Object, String> itemFormatter = null; | |
1249 public Converter<Object, String> ItemFormatter { get { return itemFormatter; } set { itemFormatter = value; Invalidate(); } } | |
1250 public FBGListBox(IFBGContainerControl parent) | |
1251 : base(parent) { | |
1252 BackColor = Color.White; | |
1253 } | |
1254 public void AddItem(Object item) { | |
1255 items.Add(item); | |
1256 Invalidate(); | |
1257 } | |
1258 protected override void Paint(Graphics g) { | |
1259 base.Paint(g); | |
1260 g.DrawRectangle(Pens.DarkBlue, 0, 0, Bounds.Width - 1, Bounds.Height - 1); | |
1261 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight()); | |
1262 int th = lh * items.Count; | |
1263 int y = 2; | |
1264 using (Pen dottedpen = new Pen(Brushes.Black)) { | |
1265 dottedpen.DashStyle = DashStyle.Dot; | |
1266 using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap)) { | |
1267 for (int i = offset; i < items.Count; i++) { | |
1268 Object item = items[i]; | |
1269 String text = itemFormatter == null ? (item == null ? String.Empty : item.ToString()) : itemFormatter(item); | |
1270 if (item == selected) g.FillRectangle(Brushes.DarkGray, 2, y, Bounds.Width - 4, lh); | |
1271 if (item == highlighted) g.DrawRectangle(dottedpen, 2, y, Bounds.Width - 5, lh - 1); | |
1272 g.DrawString(text, SystemFonts.DefaultFont, SystemBrushes.WindowText, new Rectangle(3, y, Bounds.Width - 6, lh), sf); | |
1273 y += lh; | |
1274 if (y + lh + 2 >= Bounds.Height) break; | |
1275 } | |
1276 } | |
1277 } | |
1278 if (y < th) hasScrollBar = true; | |
1279 if (hasScrollBar) { | |
1280 int xoff = Bounds.Width - 17; | |
1281 using (Brush b = new LinearGradientBrush(new Rectangle(xoff, 0, 17, 1), Color.LightGray, Color.White, LinearGradientMode.Horizontal)) | |
1282 g.FillRectangle(b, xoff, 17, 16, Bounds.Height - 17 - 17); | |
1283 ControlPaint.DrawScrollButton(g, xoff, 1, 16, 16, ScrollButton.Up, buttonUpState); | |
1284 ControlPaint.DrawScrollButton(g, xoff, Bounds.Height - 17, 16, 16, ScrollButton.Down, buttonDownState); | |
1285 g.DrawRectangle(Pens.Black, new Rectangle(xoff, 17 + offset * (Bounds.Height - 17 - 17 - 20) / (items.Count - 1), 15, 20)); | |
1286 } | |
1287 } | |
1288 protected override void MouseDown(Point position, MouseButtons buttons) { | |
1289 if ((buttons & MouseButtons.Left) != 0) { | |
1290 CaptureMouse(true); | |
1291 if (hasScrollBar && position.X > Bounds.Width - 17) { | |
1292 hitScrollBar = true; | |
1293 if (position.Y < 17) { | |
1294 offset--; | |
1295 buttonUpState = ButtonState.Pushed; | |
1296 } else if (position.Y > Bounds.Height - 17) { | |
1297 offset++; | |
1298 buttonDownState = ButtonState.Pushed; | |
1299 } else { | |
1300 offset = (int)Math.Round((position.Y - 17) * (items.Count - 1) / (double)(Bounds.Height - 17 - 17 - 10)); | |
1301 } | |
1302 if (offset < 0) offset = 0; | |
1303 if (offset >= items.Count) offset = items.Count - 1; | |
1304 Invalidate(); | |
1305 } else { | |
1306 MouseHandler(position, buttons); | |
1307 } | |
1308 } | |
1309 } | |
1310 protected override void MouseMove(Point position, MouseButtons buttons) { | |
1311 if (hitScrollBar) { | |
1312 if (position.Y < 17) { | |
1313 } else if (position.Y > Bounds.Height - 17) { | |
1314 } else { | |
1315 offset = (int)Math.Round((position.Y - 17) * (items.Count - 1) / (double)(Bounds.Height - 17 - 17 - 10)); | |
1316 if (offset < 0) offset = 0; | |
1317 if (offset >= items.Count) offset = items.Count - 1; | |
1318 Invalidate(); | |
1319 } | |
1320 return; | |
1321 } | |
1322 MouseHandler(position, buttons); | |
1323 } | |
1324 protected override void MouseUp(Point position, MouseButtons buttons) { | |
1325 if ((buttons & MouseButtons.Left) != 0) { | |
1326 CaptureMouse(false); | |
1327 buttonUpState = buttonDownState = ButtonState.Normal; | |
1328 Invalidate(); | |
1329 if (hitScrollBar) { | |
1330 hitScrollBar = false; | |
1331 return; | |
1332 } | |
1333 } | |
1334 if (hitScrollBar) return; | |
1335 MouseHandler(position, buttons); | |
1336 } | |
1337 private void MouseHandler(Point position, MouseButtons buttons) { | |
1338 if ((buttons & MouseButtons.Left) != 0) { | |
1339 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight()); | |
1340 int i = (position.Y - 2) / lh + offset; | |
1341 if (i < 0) i = 0; | |
1342 if (i >= items.Count) i = items.Count - 1; | |
1343 Boolean changed = false; | |
1344 Object current = items[i]; | |
1345 if (!ReferenceEquals(highlighted, current)) changed = true; | |
1346 highlighted = current; | |
1347 if ((new Rectangle(Point.Empty, Bounds.Size)).Contains(position)) { | |
1348 if (!ReferenceEquals(selected, current)) changed = true; | |
1349 selected = current; | |
1350 } | |
1351 if (changed) Invalidate(); | |
1352 } | |
1353 } | |
1354 } | |
1355 public class FBGDomainUpDown : FBGControl { | |
1356 private List<Object> items = new List<object>(); | |
1357 private int selectedIndex = -1; | |
1358 private ButtonState buttonUpState = ButtonState.Normal; | |
1359 private ButtonState buttonDownState = ButtonState.Normal; | |
1360 private Converter<Object, String> itemFormatter = null; | |
1361 public Boolean AllowSelectEmpty { get; set; } | |
1362 public Converter<Object, String> ItemFormatter { get { return itemFormatter; } set { itemFormatter = value; Invalidate(); } } | |
1363 public event EventHandler SelectedIndexChanged; | |
1364 public FBGDomainUpDown(IFBGContainerControl parent) | |
1365 : base(parent) { | |
1366 BackColor = Color.White; | |
1367 } | |
1368 public void AddItem(Object item) { | |
1369 items.Add(item); | |
1370 Invalidate(); | |
1371 } | |
1372 public void RemoveItem(Object item) { | |
1373 items.Remove(item); | |
1374 FixSelectedIndex(0); | |
1375 } | |
1376 public void RemoveItem(int index) { | |
1377 items.RemoveAt(index); | |
1378 FixSelectedIndex(0); | |
1379 } | |
1380 public int SelectedIndex { | |
1381 get { return selectedIndex; } | |
1382 set { | |
1383 if (value < -2 || value >= items.Count) throw new ArgumentOutOfRangeException("value", "Value must be between -1 and the number of items minus one"); | |
1384 if (selectedIndex == value) return; | |
1385 selectedIndex = value; | |
1386 Invalidate(); | |
1387 RaiseEvent(SelectedIndexChanged); | |
1388 } | |
1389 } | |
1390 public Object SelectedItem { | |
1391 get { return selectedIndex == -1 ? null : items[selectedIndex]; } | |
1392 set { | |
1393 if (value == null) { | |
1394 SelectedIndex = -1; | |
1395 } else { | |
1396 for (int i = 0; i < items.Count; i++) { | |
1397 if (items[i] == value) { | |
1398 SelectedIndex = i; | |
1399 break; | |
1400 } | |
1401 } | |
1402 } | |
1403 } | |
1404 } | |
1405 private void FixSelectedIndex(int change) { | |
1406 int value = selectedIndex; | |
1407 if (value == 0 && change == -1 && !AllowSelectEmpty) change = 0; | |
1408 value += change; | |
1409 if (value < -1) value = -1; | |
1410 if (value >= items.Count) value = items.Count - 1; | |
1411 SelectedIndex = value; | |
1412 } | |
1413 protected override void Paint(Graphics g) { | |
1414 base.Paint(g); | |
1415 g.DrawRectangle(Pens.DarkBlue, 0, 0, Bounds.Width - 1, Bounds.Height - 1); | |
1416 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight()); | |
1417 if (selectedIndex == -1) { | |
1418 g.FillRectangle(Brushes.DarkGray, 2, 2, Bounds.Width - 4 - 16, Bounds.Height - 4); | |
1419 } else { | |
1420 using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap)) { | |
1421 sf.LineAlignment = StringAlignment.Center; | |
1422 Object item = items[selectedIndex]; | |
1423 String text = itemFormatter == null ? (item == null ? String.Empty : item.ToString()) : itemFormatter(item); | |
1424 g.FillRectangle(Brushes.LightGray, 2, 2, Bounds.Width - 4 - 16, Bounds.Height - 4); | |
1425 g.DrawString(text, SystemFonts.DefaultFont, SystemBrushes.WindowText, new Rectangle(3, 2, Bounds.Width - 6 - 16, Bounds.Height - 4), sf); | |
1426 } | |
1427 } | |
1428 int xoff = Bounds.Width - 17; | |
1429 int he = (Bounds.Height - 2) / 2; | |
1430 ControlPaint.DrawScrollButton(g, xoff, 1, 16, he, ScrollButton.Up, buttonUpState); | |
1431 ControlPaint.DrawScrollButton(g, xoff, Bounds.Height - he - 1, 16, he, ScrollButton.Down, buttonDownState); | |
1432 } | |
1433 protected override void MouseDown(Point position, MouseButtons buttons) { | |
1434 CaptureKeyboard(true); | |
1435 if ((buttons & MouseButtons.Left) != 0) { | |
1436 CaptureMouse(true); | |
1437 if (position.X > Bounds.Width - 17) { | |
1438 if (position.Y < Bounds.Height / 2) { | |
1439 buttonUpState = ButtonState.Pushed; | |
1440 FixSelectedIndex(-1); | |
1441 } else { | |
1442 buttonDownState = ButtonState.Pushed; | |
1443 FixSelectedIndex(1); | |
1444 } | |
1445 Invalidate(new Rectangle(Bounds.Width - 16, 0, 16, Bounds.Height)); | |
1446 } | |
1447 } | |
1448 } | |
1449 protected override void MouseUp(Point position, MouseButtons buttons) { | |
1450 if ((buttons & MouseButtons.Left) != 0) { | |
1451 CaptureMouse(false); | |
1452 buttonUpState = buttonDownState = ButtonState.Normal; | |
1453 Invalidate(new Rectangle(Bounds.Width - 16, 0, 16, Bounds.Height)); | |
1454 } | |
1455 } | |
1456 protected override void KeyDown(Keys key) { | |
1457 base.KeyDown(key); | |
1458 if (key == Keys.Down) { | |
1459 FixSelectedIndex(1); | |
1460 } else if (key == Keys.Up) { | |
1461 FixSelectedIndex(-1); | |
1462 } | |
1463 } | |
1464 } | |
1465 public interface IFBGTreeParent { | |
1466 FBGTreeView TreeView { get; } | |
1467 int Depth { get; } | |
1468 void AddChild(FBGTreeNode node); | |
1469 void RemoveChild(FBGTreeNode node); | |
1470 } | |
1471 public class FBGTreeNode : IFBGTreeParent { | |
1472 private List<FBGTreeNode> children = new List<FBGTreeNode>(); | |
1473 private Boolean expanded = true; | |
1474 private Boolean hasCheckBox = false; | |
1475 private Boolean isChecked = false; | |
1476 private Object item; | |
1477 | |
1478 public FBGTreeView TreeView { get; private set; } | |
1479 public int Depth { get; private set; } | |
1480 public Object Tag { get; set; } | |
1481 public IFBGTreeParent Parent { get; private set; } | |
1482 | |
1483 public IList<FBGTreeNode> Children { get { return children.AsReadOnly(); } } | |
1484 | |
1485 public Object Item { | |
1486 get { return item; } | |
1487 set { | |
1488 item = value; | |
1489 Invalidate(); | |
1490 } | |
1491 } | |
1492 public Boolean Expanded { | |
1493 get { return expanded; } | |
1494 set { | |
1495 if (expanded == value) return; | |
1496 expanded = value; | |
1497 UpdateTree(); | |
1498 } | |
1499 } | |
1500 public Boolean HasCheckBox { | |
1501 get { return hasCheckBox; } | |
1502 set { | |
1503 if (hasCheckBox == value) return; | |
1504 hasCheckBox = value; | |
1505 Invalidate(); | |
1506 } | |
1507 } | |
1508 public Boolean Checked { | |
1509 get { return isChecked; } | |
1510 set { | |
1511 if (isChecked == value) return; | |
1512 isChecked = value; | |
1513 Invalidate(); | |
1514 if (TreeView != null) TreeView.RaiseNodeCheckedChanged(this); | |
1515 } | |
1516 } | |
1517 | |
1518 public FBGTreeNode(IFBGTreeParent parent, Object item) { | |
1519 this.TreeView = parent.TreeView; | |
1520 this.Depth = parent.Depth + 1; | |
1521 this.Parent = parent; | |
1522 this.item = item; | |
1523 parent.AddChild(this); | |
1524 } | |
1525 | |
1526 public void Remove() { | |
1527 Parent.RemoveChild(this); | |
1528 } | |
1529 void IFBGTreeParent.AddChild(FBGTreeNode node) { | |
1530 children.Add(node); | |
1531 if (Expanded) UpdateTree(); | |
1532 else Invalidate(); | |
1533 } | |
1534 void IFBGTreeParent.RemoveChild(FBGTreeNode node) { | |
1535 children.Remove(node); | |
1536 TreeView.ReleaseNodeFromTree(node); | |
1537 if (Expanded) UpdateTree(); | |
1538 else Invalidate(); | |
1539 } | |
1540 public void Invalidate() { | |
1541 if (TreeView != null) TreeView.Invalidate(this); | |
1542 } | |
1543 private void UpdateTree() { | |
1544 if (TreeView != null) TreeView.UpdateView(); | |
1545 } | |
1546 public FBGTreeNode AddNode(Object item) { | |
1547 return new FBGTreeNode(this, item); | |
1548 } | |
1549 } | |
1550 public class FBGTreeView : FBGControl, IFBGTreeParent { | |
1551 private List<FBGTreeNode> items = new List<FBGTreeNode>(); | |
1552 private List<FBGTreeNode> itemsView = new List<FBGTreeNode>(); | |
1553 private FBGTreeNode selected = null; | |
1554 private FBGTreeNode highlighted = null; | |
1555 private Boolean hasScrollBar = false; | |
1556 private Boolean hitScrollBar = false; | |
1557 private int offset = 0; | |
1558 private ButtonState buttonUpState = ButtonState.Normal; | |
1559 private ButtonState buttonDownState = ButtonState.Normal; | |
1560 private Converter<Object, String> itemFormatter = null; | |
1561 | |
1562 public Converter<Object, String> ItemFormatter { get { return itemFormatter; } set { itemFormatter = value; Invalidate(); } } | |
1563 public FBGTreeNode SelectedNode { get { return selected; } set { if (selected != value) { selected = value; Invalidate(); RaiseEvent(SelectedNodeChanged); } } } | |
1564 public IList<FBGTreeNode> Nodes { get { return items.AsReadOnly(); } } | |
1565 | |
1566 public event EventHandler SelectedNodeChanged; | |
1567 public event EventHandler NodeCheckedChanged; | |
1568 | |
1569 public FBGTreeView(IFBGContainerControl parent) : base(parent) { | |
1570 BackColor = Color.White; | |
1571 } | |
1572 FBGTreeView IFBGTreeParent.TreeView { get { return this; } } | |
1573 int IFBGTreeParent.Depth { get { return -1; } } | |
1574 void IFBGTreeParent.AddChild(FBGTreeNode node) { | |
1575 items.Add(node); | |
1576 UpdateView(); | |
1577 } | |
1578 void IFBGTreeParent.RemoveChild(FBGTreeNode node) { | |
1579 items.Remove(node); | |
1580 ReleaseNodeFromTree(node); | |
1581 UpdateView(); | |
1582 } | |
1583 public FBGTreeNode AddNode(Object item) { return new FBGTreeNode(this, item); } | |
1584 internal void ReleaseNodeFromTree(FBGTreeNode node) { | |
1585 if (highlighted == node) highlighted = null; | |
1586 if (selected == node) SelectedNode = null; | |
1587 } | |
1588 internal void RaiseNodeCheckedChanged(FBGTreeNode node) { | |
1589 RaiseEvent(NodeCheckedChanged); | |
1590 } | |
1591 internal void UpdateView() { | |
1592 List<FBGTreeNode> newView = new List<FBGTreeNode>(); | |
1593 Stack<Queue<FBGTreeNode>> stack = new Stack<Queue<FBGTreeNode>>(); | |
1594 stack.Push(new Queue<FBGTreeNode>(items)); | |
1595 while (stack.Count > 0) { | |
1596 Queue<FBGTreeNode> list = stack.Peek(); | |
1597 if (list.Count == 0) { | |
1598 stack.Pop(); | |
1599 continue; | |
1600 } | |
1601 FBGTreeNode item = list.Dequeue(); | |
1602 newView.Add(item); | |
1603 if (item.Expanded) stack.Push(new Queue<FBGTreeNode>(item.Children)); | |
1604 } | |
1605 itemsView = newView; | |
1606 Invalidate(); | |
1607 } | |
1608 internal void Invalidate(FBGTreeNode node) { | |
1609 int i = itemsView.IndexOf(node); | |
1610 if (i == -1) return; | |
1611 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight() / 2.0) * 2; | |
1612 Invalidate(new Rectangle(1, i * lh, Bounds.Width - 1, lh)); | |
1613 } | |
1614 protected override void Paint(Graphics g) { | |
1615 base.Paint(g); | |
1616 | |
1617 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight() / 2.0) * 2; | |
1618 int th = lh * itemsView.Count; | |
1619 hasScrollBar = offset > 0 || th + 2 > Bounds.Height; | |
1620 int y = 2; | |
1621 using (Pen dottedpen = new Pen(Brushes.Black)) { | |
1622 dottedpen.DashStyle = DashStyle.Dot; | |
1623 using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap)) { | |
1624 int lw = Bounds.Width - 2; | |
1625 if (hasScrollBar) lw -= 17; | |
1626 for (int i = offset; i < itemsView.Count; i++) { | |
1627 FBGTreeNode item = itemsView[i]; | |
1628 if (y + 2 < Bounds.Height) { | |
1629 Object obj = item.Item; | |
1630 String text = itemFormatter == null ? (obj == null ? String.Empty : obj.ToString()) : itemFormatter(obj); | |
1631 if (item == selected) g.FillRectangle(Brushes.DarkGray, 2, y, lw - 2, lh); | |
1632 if (item == highlighted) g.DrawRectangle(dottedpen, 2, y, lw - 3, lh - 1); | |
1633 int x = 3 + 19 * item.Depth + 14; | |
1634 if (item.HasCheckBox) { | |
1635 x += 2; | |
1636 ControlPaint.DrawCheckBox(g, x, y, lh, lh, item.Checked ? ButtonState.Checked : ButtonState.Normal); | |
1637 x += lh + 1; | |
1638 } | |
1639 g.DrawString(text, SystemFonts.DefaultFont, SystemBrushes.WindowText, new Rectangle(x, y, lw - x, lh), sf); | |
1640 } | |
1641 int upto = y + 2 + 4 - 8; | |
1642 for (int j = i - 1; j >= 0; j--) { | |
1643 if (itemsView[j].Depth < item.Depth) { | |
1644 break; | |
1645 } | |
1646 if (itemsView[j].Depth == item.Depth) { | |
1647 if (itemsView[j].Children.Count > 0) { | |
1648 upto = 2 + lh * (j - offset) + 10; | |
1649 } else { | |
1650 upto = 2 + lh * (j - offset) + 6; | |
1651 } | |
1652 break; | |
1653 } | |
1654 if (j <= offset) { | |
1655 upto = 2 + 2 + 4 - 8; | |
1656 break; | |
1657 } | |
1658 } | |
1659 if (item.Children.Count > 0) { | |
1660 g.DrawRectangle(Pens.Black, 3 + 19 * item.Depth, y + 2, 8, 8); | |
1661 g.DrawLine(Pens.Black, 3 + 19 * item.Depth + 2, y + 2 + 4, 3 + 19 * item.Depth + 6, y + 2 + 4); | |
1662 if (!item.Expanded) g.DrawLine(Pens.Black, 3 + 19 * item.Depth + 4, y + 4, 3 + 19 * item.Depth + 4, y + 2 + 6); | |
1663 | |
1664 g.DrawLine(dottedpen, 3 + 19 * item.Depth + 8, y + 2 + 4, 3 + 19 * item.Depth + 14, y + 2 + 4); | |
1665 g.DrawLine(dottedpen, 3 + 19 * item.Depth + 4, y + 2 + 4 - 6, 3 + 19 * item.Depth + 4, upto); | |
1666 } else { | |
1667 g.DrawLine(dottedpen, 3 + 19 * item.Depth + 4, y + 2 + 4, 3 + 19 * item.Depth + 14, y + 2 + 4); | |
1668 g.DrawLine(dottedpen, 3 + 19 * item.Depth + 4, y + 2 + 4 - 2, 3 + 19 * item.Depth + 4, upto); | |
1669 } | |
1670 y += lh; | |
1671 //if (y + lh + 2 >= Bounds.Height && item.Depth == 0) break; | |
1672 if (y + 2 >= Bounds.Height && item.Depth == 0) break; | |
1673 } | |
1674 } | |
1675 } | |
1676 //if (y < th) hasScrollBar = true; | |
1677 //hasScrollBar = true; | |
1678 if (hasScrollBar) { | |
1679 int xoff = Bounds.Width - 17; | |
1680 using (Brush b = new LinearGradientBrush(new Rectangle(xoff, 0, 17, 1), Color.LightGray, Color.White, LinearGradientMode.Horizontal)) | |
1681 g.FillRectangle(b, xoff, 17, 16, Bounds.Height - 17 - 17); | |
1682 ControlPaint.DrawScrollButton(g, xoff, 1, 16, 16, ScrollButton.Up, buttonUpState); | |
1683 ControlPaint.DrawScrollButton(g, xoff, Bounds.Height - 17, 16, 16, ScrollButton.Down, buttonDownState); | |
1684 g.DrawRectangle(Pens.Black, new Rectangle(xoff, 17 + offset * (Bounds.Height - 17 - 17 - 20) / (itemsView.Count - 1), 15, 20)); | |
1685 } | |
1686 | |
1687 g.DrawRectangle(Pens.DarkBlue, 0, 0, Bounds.Width - 1, Bounds.Height - 1); | |
1688 } | |
1689 protected override void MouseDown(Point position, MouseButtons buttons) { | |
1690 CaptureKeyboard(true); | |
1691 if ((buttons & MouseButtons.Left) != 0) { | |
1692 CaptureMouse(true); | |
1693 if (hasScrollBar && position.X > Bounds.Width - 17) { | |
1694 hitScrollBar = true; | |
1695 if (position.Y < 17) { | |
1696 offset--; | |
1697 buttonUpState = ButtonState.Pushed; | |
1698 } else if (position.Y > Bounds.Height - 17) { | |
1699 offset++; | |
1700 buttonDownState = ButtonState.Pushed; | |
1701 } else { | |
1702 offset = (int)Math.Round((position.Y - 17) * (itemsView.Count - 1) / (double)(Bounds.Height - 17 - 17 - 10)); | |
1703 } | |
1704 if (offset < 0) offset = 0; | |
1705 if (offset >= itemsView.Count) offset = itemsView.Count - 1; | |
1706 Invalidate(); | |
1707 } else { | |
1708 MouseHandler(position, buttons, true); | |
1709 } | |
1710 } | |
1711 } | |
1712 protected override void MouseMove(Point position, MouseButtons buttons) { | |
1713 if (hitScrollBar) { | |
1714 if (position.Y < 17) { | |
1715 } else if (position.Y > Bounds.Height - 17) { | |
1716 } else { | |
1717 offset = (int)Math.Round((position.Y - 17) * (itemsView.Count - 1) / (double)(Bounds.Height - 17 - 17 - 10)); | |
1718 if (offset < 0) offset = 0; | |
1719 if (offset >= itemsView.Count) offset = itemsView.Count - 1; | |
1720 Invalidate(); | |
1721 } | |
1722 return; | |
1723 } | |
1724 MouseHandler(position, buttons, false); | |
1725 } | |
1726 protected override void MouseUp(Point position, MouseButtons buttons) { | |
1727 if ((buttons & MouseButtons.Left) != 0) { | |
1728 CaptureMouse(false); | |
1729 buttonUpState = buttonDownState = ButtonState.Normal; | |
1730 Invalidate(); | |
1731 if (hitScrollBar) { | |
1732 hitScrollBar = false; | |
1733 return; | |
1734 } | |
1735 } | |
1736 if (hitScrollBar) return; | |
1737 MouseHandler(position, buttons, false); | |
1738 } | |
1739 private void MouseHandler(Point position, MouseButtons buttons, Boolean down) { | |
1740 if ((buttons & MouseButtons.Left) != 0 && itemsView.Count > 0) { | |
1741 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight() / 2.0) * 2; | |
1742 int i = (position.Y - 2) / lh + offset; | |
1743 if (i < 0) i = 0; | |
1744 if (i >= itemsView.Count) i = itemsView.Count - 1; | |
1745 Boolean changed = false; | |
1746 FBGTreeNode current = itemsView[i]; | |
1747 if (!ReferenceEquals(highlighted, current)) changed = true; | |
1748 highlighted = current; | |
1749 if (current.Children.Count > 0 && (new Rectangle(3 + 19 * current.Depth, 2 + lh * (i - offset) + 2, 8, 8)).Contains(position)) { | |
1750 if (down) current.Expanded = !current.Expanded; | |
1751 } else if (current.HasCheckBox && (new Rectangle(3 + 19 * current.Depth + 14 + 2, 2 + lh * (i - offset), lh, lh)).Contains(position)) { | |
1752 if (down) current.Checked = !current.Checked; | |
1753 } else if ((new Rectangle(Point.Empty, Bounds.Size)).Contains(position)) { | |
1754 SelectedNode = current; | |
1755 changed = false; | |
1756 } | |
1757 if (changed) Invalidate(); | |
1758 } | |
1759 } | |
1760 protected override void KeyDown(Keys key) { | |
1761 base.KeyDown(key); | |
1762 if (key == Keys.Up) { | |
1763 int i = itemsView.IndexOf(selected); | |
1764 i--; | |
1765 if (i >= 0) SelectAndScrollIntoView(itemsView[i]); | |
1766 } else if (key == Keys.Down) { | |
1767 int i = itemsView.IndexOf(selected); | |
1768 i++; | |
1769 if (i < itemsView.Count) SelectAndScrollIntoView(itemsView[i]); | |
1770 } else if (key == Keys.Left && selected != null) { | |
1771 if (selected.Expanded && selected.Children.Count > 0) { | |
1772 selected.Expanded = false; | |
1773 } else { | |
1774 FBGTreeNode tn = selected.Parent as FBGTreeNode; | |
1775 if (tn != null) SelectAndScrollIntoView(tn); | |
1776 } | |
1777 } else if (key == Keys.Right && selected != null) { | |
1778 if (!selected.Expanded && selected.Children.Count > 0) { | |
1779 selected.Expanded = true; | |
1780 } else if (selected.Children.Count > 0) { | |
1781 SelectAndScrollIntoView(selected.Children[0]); | |
1782 } | |
1783 } else if (key == Keys.Space && selected != null) { | |
1784 if (selected.HasCheckBox) selected.Checked = !selected.Checked; | |
1785 } | |
1786 } | |
1787 private void SelectAndScrollIntoView(FBGTreeNode tn) { | |
1788 int i = itemsView.IndexOf(tn); | |
1789 if (i == -1) { | |
1790 for (FBGTreeNode tp = tn.Parent as FBGTreeNode; tp != null; tp = tp.Parent as FBGTreeNode) if (!tp.Expanded) tp.Expanded = true; | |
1791 i = itemsView.IndexOf(tn); | |
1792 } | |
1793 if (i != -1) { | |
1794 int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight() / 2.0) * 2; | |
1795 if (i < offset) offset = i; | |
1796 offset = Math.Max(offset, i - Bounds.Height / lh + 1); | |
1797 } | |
1798 highlighted = tn; | |
1799 SelectedNode = tn; | |
1800 } | |
1801 } | |
1802 } |