Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.Netron/3.0.2672.12446/Netron.Diagramming.Core-3.0.2672.12446/Diagram elements/Materials/FolderMaterial.cs @ 4068

Last change on this file since 4068 was 4068, checked in by swagner, 14 years ago

Sorted usings and removed unused usings in entire solution (#1094)

File size: 20.5 KB
Line 
1using System;
2using System.ComponentModel;
3using System.Drawing;
4using System.Drawing.Design;
5using System.Drawing.Drawing2D;
6using System.Windows.Forms;
7namespace Netron.Diagramming.Core {
8  /// <summary>
9  /// This material holds other shape material entries which can be
10  /// collapsed or expanded like a tree-node or folder.
11  /// </summary>
12  public partial class FolderMaterial :
13      ShapeMaterialBase,
14      IMouseListener,
15      IHoverListener {
16    #region Constants
17    /// <summary>
18    /// the height of the entries
19    /// </summary>
20    public const int ItemHeight = 16;
21    /// <summary>
22    /// the height of the folder header
23    /// </summary>
24    public const int HeaderHeight = 16;
25    /// <summary>
26    /// the vertical spacing between entries
27    /// </summary>
28    public const int ItemSpacing = 1;
29    /// <summary>
30    /// the horizontal shift between the plusminus icon and the header
31    /// </summary>
32    public const int HeaderSpacing = 4;
33    #endregion
34
35    #region Events
36    /// <summary>
37    /// Occurs when the state of this folder has changed; on collasping or expanding the entries this folder contains.
38    /// </summary>
39    public event EventHandler<RectangleEventArgs> OnFolderChanged;
40    #endregion
41
42    #region Fields
43
44    // ------------------------------------------------------------------
45    /// <summary>
46    /// Implementation of IVersion - the current version of
47    /// FolderMaterial.
48    /// </summary>
49    // ------------------------------------------------------------------
50    protected double folderMaterialVersion = 1.0;
51
52    /// <summary>
53    /// the Text field
54    /// </summary>
55    protected string mText;
56
57    /// <summary>
58    /// volatile pointer to a hovered material
59    /// </summary>
60    protected IHoverListener currentHoveredMaterial = null;
61
62    /// <summary>
63    /// the width of the individual items
64    /// </summary>
65    protected int itemWidth = 100;
66
67    /// <summary>
68    /// the collection of material entries
69    /// </summary>
70    protected CollectionBase<IShapeMaterial> mEntries;
71
72    /// <summary>
73    /// the plus/minus icon to collapse expand the items
74    /// </summary>
75    protected SwitchIconMaterial plusminus;
76
77    /// <summary>
78    /// the header of the folder
79    /// </summary>
80    protected ClickableLabelMaterial header;
81
82    /// <summary>
83    /// whether the folder is collapsed
84    /// </summary>
85    protected bool mCollapsed = true;
86
87    /// <summary>
88    /// the ShowLines field
89    /// </summary>
90    protected bool mShowLines = true;
91
92    #endregion
93
94    #region Properties
95
96    // ------------------------------------------------------------------
97    /// <summary>
98    /// Gets the current version.
99    /// </summary>
100    // ------------------------------------------------------------------
101    public override double Version {
102      get {
103        return folderMaterialVersion;
104      }
105    }
106
107    /// <summary>
108    /// Gets or sets the text style for all nodes.
109    /// </summary>
110    public override ITextStyle TextStyle {
111      get {
112        return base.TextStyle;
113      }
114      set {
115        base.TextStyle = value;
116        header.TextStyle = myTextStyle;
117        myTextStyle.TextStyleChanged +=
118            new TextStyleChangedEventHandler(
119            HandleTextStyleChanged);
120
121        foreach (IShapeMaterial matl in Entries) {
122          matl.TextStyle = value;
123        }
124      }
125    }
126
127    /// <summary>
128    /// Gets or sets whether the connecting line between nodes is desplayed.
129    /// </summary>
130    public bool ShowLines {
131      get { return mShowLines; }
132      set { mShowLines = value; }
133    }
134    /// <summary>
135    /// Gets or sets the Shape
136    /// </summary>
137    /// <value></value>
138    public override IShape Shape {
139      get {
140        return base.Shape;
141      }
142      set {
143        base.Shape = value;
144        plusminus.Shape = value;
145        header.Shape = value;
146        //have to go one level deeper than the normal material here
147        foreach (IShapeMaterial material in mEntries) {
148          material.Shape = value;
149        }
150      }
151    }
152    /// <summary>
153    /// Gets or sets the text or name of the folder
154    /// </summary>
155    public string Text {
156      get { return header.Text; }
157      set { header.Text = value; }
158    }
159    /// <summary>
160    /// Gets the entries.
161    /// </summary>
162    /// <value>The entries.</value>
163    [Editor(typeof(ShapeMaterialCollectionEditor<IconLabelMaterial>), typeof(UITypeEditor))]
164    public CollectionBase<IShapeMaterial> Entries {
165      get {
166        return mEntries;
167      }
168      internal set { mEntries = value; }
169    }
170
171    /// <summary>
172    /// Gets if the root node is collapsed.
173    /// </summary>
174    public bool IsCollapsed {
175      get {
176        return mCollapsed;
177      }
178      set {
179        mCollapsed = value;
180        plusminus.Collapsed = value;
181      }
182    }
183    #endregion
184
185    #region Constructor
186    ///<summary>
187    ///Default constructor
188    ///</summary>
189    public FolderMaterial(string title)
190      : base() {
191      myTextStyle = new TextStyle(
192          Color.Black,
193          new Font("Arial", 10),
194          StringAlignment.Near,
195          StringAlignment.Near);
196      mEntries = new CollectionBase<IShapeMaterial>();
197      mEntries.OnItemAdded +=
198          new EventHandler<CollectionEventArgs<IShapeMaterial>>(
199          mEntries_OnItemAdded);
200
201      Gliding = false;
202      Resizable = true;
203
204      plusminus = new SwitchIconMaterial(SwitchIconType.PlusMinus);
205      plusminus.TextStyle = myTextStyle;
206      plusminus.Transform(new Rectangle(0, 0, 16, 16));
207      plusminus.Visible = true;
208      plusminus.Gliding = false;
209      plusminus.OnExpand += new EventHandler(plusminus_OnExpand);
210      plusminus.OnCollapse += new EventHandler(plusminus_OnCollapse);
211
212
213      header = new ClickableLabelMaterial();
214      header.TextStyle = myTextStyle;
215      header.Transform(new Rectangle(0, 0, 100, HeaderHeight));
216      header.Text = title;
217      header.Gliding = false;
218      header.Visible = true;
219      header.Resizable = true;
220    }
221
222    /// <summary>
223    /// Initializes a new instance of the <see cref="T:FolderMaterial"/> class.
224    /// </summary>
225    /// <param name="title">The title.</param>
226    /// <param name="entries">The entries.</param>
227    public FolderMaterial(string title, string[] entries)
228      : this(title) {
229      myTextStyle = new TextStyle(
230          Color.Black,
231          new Font("Arial", 10),
232          StringAlignment.Near,
233          StringAlignment.Near);
234      IconLabelMaterial label;
235      for (int k = 0; k < entries.Length; k++) {
236        label = new IconLabelMaterial("Resources.Text.png", entries[k]);
237
238        // We attach our ITextStyle to items when they're added to the
239        // collection.
240        mEntries.Add(label);
241      }
242      Collapse();
243    }
244
245    /// <summary>
246    /// Initializes a new instance of the <see cref="T:FolderMaterial"/> class.
247    /// </summary>
248    /// <param name="title">The title.</param>
249    /// <param name="entries">The entries.</param>
250    /// <param name="defaultIconLocation">The default icon location.</param>
251    public FolderMaterial(
252        string title,
253        string[] entries,
254        string defaultIconLocation)
255      : this(title) {
256      IconLabelMaterial label;
257      myTextStyle = new TextStyle(
258           Color.Black,
259           new Font("Arial", 10),
260           StringAlignment.Near,
261           StringAlignment.Near);
262
263      for (int k = 0; k < entries.Length; k++) {
264        label = new IconLabelMaterial(entries[k], defaultIconLocation);
265        mEntries.Add(label);
266      }
267      Collapse();
268
269      myTextStyle.TextStyleChanged +=
270          new TextStyleChangedEventHandler(HandleTextStyleChanged);
271    }
272
273    // ------------------------------------------------------------------
274    /// <summary>
275    /// Called when our TextStyle has changed, each item in our mEntries
276    /// is updated.
277    /// </summary>
278    /// <param name="sender">object</param>
279    /// <param name="e">TextStyleChangedEventArgs</param>
280    // ------------------------------------------------------------------
281    protected virtual void HandleTextStyleChanged(
282        object sender,
283        TextStyleChangedEventArgs e) {
284      header.TextStyle = myTextStyle;
285      foreach (IShapeMaterial item in mEntries) {
286        item.TextStyle = myTextStyle;
287      }
288    }
289
290
291    #endregion
292
293    #region Methods
294    /// <summary>
295    /// Recalculates and initializes things when an entry has been added.
296    /// </summary>
297    /// <param name="sender">The sender.</param>
298    /// <param name="e">The e.</param>
299    protected virtual void mEntries_OnItemAdded(
300        object sender,
301        CollectionEventArgs<IShapeMaterial> e) {
302      e.Item.Shape = this.Shape;
303      e.Item.TextStyle = myTextStyle;
304      Transform(this.Rectangle);//simply recalculate with the same base rectangle
305      //notify the hierarchy
306      RaiseOnFolderChanged(new RectangleEventArgs(Rectangle));
307      e.Item.Visible = !mCollapsed;
308
309    }
310
311    // ------------------------------------------------------------------
312    /// <summary>
313    /// Calculates the size needed to fit all items for the specified
314    /// GDI+ drawing surface.
315    /// </summary>
316    /// <param name="g"></param>
317    /// <returns></returns>
318    // ------------------------------------------------------------------
319    public override Size CalculateMinSize(Graphics g) {
320      // When collapsed, the only thing drawn is the header (root node).
321      Size minSizeNeeded = header.CalculateMinSize(g);
322      Size plusMinusSize;
323      Size materialSize;
324      int linesLength = 0;  // The lenght of the lines that are drawn
325      // connecting the folders.
326
327      int padding = 20;  // Accounts for the spacing around materials.
328
329      if (mShowLines) {
330        // 7 for the lines themselves, another 7 for the space between
331        // the line and the material.
332        linesLength = 14;
333      }
334
335      if (minSizeNeeded == Size.Empty) {
336        minSizeNeeded = new Size(1, 1);
337      } else {
338        // Account for the padding around the header.
339        minSizeNeeded.Height += (padding / 2);
340        minSizeNeeded.Width += padding;
341      }
342
343      // The plus-minus icon is placed to the left of the header text,
344      // so it's width gets added to the current min size.
345      if (plusminus != null) {
346        plusMinusSize = plusminus.CalculateMinSize(g);
347
348        if (plusMinusSize != Size.Empty) {
349          plusMinusSize.Width += linesLength;
350          plusMinusSize.Width += padding;
351
352          minSizeNeeded.Width += plusMinusSize.Width;
353
354          if (plusMinusSize.Height > minSizeNeeded.Height) {
355            minSizeNeeded.Height = plusMinusSize.Height;
356          }
357        }
358      }
359
360      foreach (IShapeMaterial matl in Entries) {
361        if (matl.Visible) {
362          materialSize = matl.CalculateMinSize(g);
363          if (materialSize != Size.Empty) {
364            materialSize.Width += linesLength;
365            materialSize.Width += padding;
366            if (materialSize.Width > minSizeNeeded.Width) {
367              minSizeNeeded.Width = materialSize.Width;
368            }
369            minSizeNeeded.Height += materialSize.Height + 3;
370          }
371        }
372      }
373
374      return minSizeNeeded;
375    }
376
377    /// <summary>
378    /// Handles the OnExpand event of the plusminus control.
379    /// </summary>
380    /// <param name="sender">The source of the event.</param>
381    /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
382    protected virtual void plusminus_OnExpand(
383        object sender,
384        EventArgs e) {
385      Expand();
386    }
387    /// <summary>
388    /// Handles the OnCollapse event of the plusminus control.
389    /// </summary>
390    /// <param name="sender">The source of the event.</param>
391    /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
392    protected virtual void plusminus_OnCollapse(
393        object sender,
394        EventArgs e) {
395      Collapse();
396    }
397    /// <summary>
398    /// Gets the service object of the specified type.
399    /// </summary>
400    /// <param name="serviceType">An object that specifies the type of service object to get.</param>
401    /// <returns>
402    /// A service object of type serviceType.-or- null if there is no service object of type serviceType.
403    /// </returns>
404    public override object GetService(Type serviceType) {
405      if (serviceType.Equals(typeof(IMouseListener)))
406        return this;
407      else if (serviceType.Equals(typeof(IHoverListener)))
408        return this;
409      else
410        return null;
411    }
412    /// <summary>
413    /// Expands the items.
414    /// </summary>
415    public virtual void Expand() {
416      mCollapsed = false;
417      foreach (IShapeMaterial material in mEntries) {
418        material.Visible = true;
419      }
420
421      Transform(Rectangle);
422      RaiseOnFolderChanged(new RectangleEventArgs(Rectangle));
423    }
424    /// <summary>
425    /// Collapses the items.
426    /// </summary>
427    public virtual void Collapse() {
428      mCollapsed = true;
429
430      foreach (IShapeMaterial material in mEntries) {
431        material.Visible = false;
432      }
433
434      Transform(Rectangle);
435
436      RaiseOnFolderChanged(new RectangleEventArgs(Rectangle));
437    }
438    /// <summary>
439    /// Transforms the specified rectangle.
440    /// </summary>
441    /// <param name="rectangle">The rectangle of the COLLAPSED FOLDER!
442    /// </param>
443    public override void Transform(Rectangle rectangle) {
444      //IMPORTANT: the rectangle given as the transformation parameter
445      // is supposed to be the rectangle of the collapsed folder!
446
447      itemWidth = rectangle.Width - plusminus.Rectangle.Width - HeaderSpacing;
448      //shift the plusminus icon
449      plusminus.Transform(new Rectangle(rectangle.Location, plusminus.Rectangle.Size));
450      //header
451      header.Transform(new Rectangle(rectangle.Location.X + plusminus.Rectangle.Width + 10, rectangle.Location.Y, itemWidth, header.Rectangle.Height));
452      //transform the entries
453      int k = 0;
454      foreach (IShapeMaterial material in mEntries) {
455        material.Transform(new Rectangle(rectangle.X + plusminus.Rectangle.Width + 10, rectangle.Y + HeaderHeight + 7 + k * (ItemHeight + ItemSpacing), itemWidth, ItemHeight));
456        k++;
457      }
458
459      if (mCollapsed)
460        base.Transform(new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, HeaderHeight));
461      else
462        base.Transform(new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, HeaderHeight + ItemSpacing + mEntries.Count * (ItemSpacing + ItemHeight)));
463    }
464    /// <summary>
465    /// Raises the OnFolderChanged event.
466    /// </summary>
467    /// <param name="e">The <see cref="T:Netron.Diagramming.Core.RectangleEventArgs"/> instance containing the event data.</param>
468    protected virtual void RaiseOnFolderChanged(RectangleEventArgs e) {
469      EventHandler<RectangleEventArgs> handler = OnFolderChanged;
470      if (handler != null) {
471        handler(this, e);
472      }
473    }
474    /// <summary>
475    /// Paints the entity using the given graphics object
476    /// </summary>
477    /// <param name="g"></param>
478    public override void Paint(System.Drawing.Graphics g) {
479      if (!Visible) return;
480
481      //g.DrawRectangle(Pens.OrangeRed, Rectangle);
482      GraphicsContainer cto = g.BeginContainer();
483      g.SetClip(Shape.Rectangle);
484      plusminus.Paint(g);
485      header.Paint(g);
486      if (!mCollapsed && mShowLines) {
487        g.DrawLine(
488            ArtPalette.FolderLinesPen,
489            Rectangle.X + 7,
490            plusminus.Rectangle.Bottom,
491            Rectangle.X + 7,
492            plusminus.Rectangle.Bottom + mEntries.Count * (ItemHeight + ItemSpacing));
493      }
494      int k = 1;
495      foreach (IShapeMaterial material in mEntries) {
496        material.Paint(g);
497        if (!mCollapsed && mShowLines) {
498          g.DrawLine(
499              ArtPalette.FolderLinesPen,
500              Rectangle.X + 7,
501              plusminus.Rectangle.Bottom + k * (ItemHeight + ItemSpacing),
502              Rectangle.X + 16,
503              plusminus.Rectangle.Bottom + k * (ItemHeight + ItemSpacing));
504          k++;
505        }
506      }
507      g.EndContainer(cto);
508    }
509    /// <summary>
510    /// Handles the mouse-down event
511    /// </summary>
512    /// <param name="e">The <see cref="T:MouseEventArgs"/> instance containing the event data.</param>
513    public virtual bool MouseDown(MouseEventArgs e) {
514
515      if (header.Rectangle.Contains(e.Location)) {
516        header.MouseDown(e);
517        return true;
518      }
519      if (plusminus.Rectangle.Contains(e.Location)) {
520        plusminus.MouseDown(e);
521        return true;
522      }
523
524      if (mCollapsed) return false;
525      IMouseListener listener;
526      foreach (IShapeMaterial material in Entries) {
527        if (material.Rectangle.Contains(e.Location)) {
528          listener = material.GetService(typeof(IMouseListener)) as IMouseListener;
529          if (listener != null)
530            if (listener.MouseDown(e))
531              return true;
532        }
533
534      }
535      return false;
536    }
537    /// <summary>
538    /// Handles the mouse-move event
539    /// </summary>
540    /// <param name="e">The <see cref="T:MouseEventArgs"/> instance containing the event data.</param>
541    public virtual void MouseMove(MouseEventArgs e) {
542      //System.Diagnostics.Trace.WriteLine(e.Location.ToString());
543    }
544    /// <summary>
545    /// Handles the mouse-up event
546    /// </summary>
547    /// <param name="e">The <see cref="T:MouseEventArgs"/> instance containing the event data.</param>
548    public virtual void MouseUp(MouseEventArgs e) {
549
550    }
551    #region IHoverListener Members
552    /// <summary>
553    /// <see cref="IHoverListener"/> implementation
554    /// </summary>
555    /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
556    public virtual void MouseHover(MouseEventArgs e) {
557      if (header.Rectangle.Contains(e.Location)) {
558        HoverEntity(e, header);
559        return;
560      }
561      if (plusminus.Rectangle.Contains(e.Location)) {
562        HoverEntity(e, plusminus);
563        return;
564      }
565
566      if (!mCollapsed) //no need to check the rest if the folder is collapsed!
567            {
568        IHoverListener listener;
569
570        foreach (IShapeMaterial material in this.Entries) {
571          if (material.Rectangle.Contains(e.Location)) //we caught an material
572                    {
573            listener = HoverEntity(e, material);
574            return; //only one material at a time
575          }
576
577        }
578      }
579      if (currentHoveredMaterial != null) {
580        currentHoveredMaterial.MouseLeave(e);
581        currentHoveredMaterial = null;
582      }
583
584    }
585    protected virtual IHoverListener HoverEntity(
586        MouseEventArgs e,
587        IShapeMaterial material) {
588      IHoverListener listener;
589      listener = material.GetService(typeof(IHoverListener)) as IHoverListener;
590      if (listener != null) //the caught material does listen
591            {
592        if (currentHoveredMaterial == listener) //it's the same as the previous time
593          listener.MouseHover(e);
594        else //we moved from one material to another listening material
595                {
596          if (currentHoveredMaterial != null) //tell the previous material we are leaving
597            currentHoveredMaterial.MouseLeave(e);
598          listener.MouseEnter(e); //tell the current one we enter
599          currentHoveredMaterial = listener;
600        }
601      } else //the caught material does not listen
602            {
603        if (currentHoveredMaterial != null) {
604          currentHoveredMaterial.MouseLeave(e);
605          currentHoveredMaterial = null;
606        }
607      }
608      return listener;
609    }
610
611    /// <summary>
612    /// <see cref="IHoverListener"/> implementation
613    /// </summary>
614    /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
615    public virtual void MouseEnter(MouseEventArgs e) {
616
617    }
618    /// <summary>
619    /// <see cref="IHoverListener"/> implementation
620    /// </summary>
621    /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
622    public virtual void MouseLeave(MouseEventArgs e) {
623      currentHoveredMaterial = null;
624      this.Shape.Model.RaiseOnCursorChange(Cursors.Default);//HACK: should be the cursor before entering into another one
625    }
626
627    #endregion
628    #endregion
629
630  }
631
632
633}
Note: See TracBrowser for help on using the repository browser.