Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Core.Views/3.3/BreadcrumbViewHost.cs @ 13699

Last change on this file since 13699 was 13014, checked in by jkarder, 9 years ago

#2116: added new breadcrumb navigation prototype

File size: 7.2 KB
RevLine 
[13014]1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Common;
29using HeuristicLab.MainForm.WindowsForms;
30using View = HeuristicLab.MainForm.WindowsForms.View;
31
32namespace HeuristicLab.Core.Views {
33  public partial class BreadcrumbViewHost : ViewHost {
34    private const string Separator = ">>";
35    private const string Ellipsis = "...";
36
37    private readonly Font font = new Font("Microsoft Sans Serif", 7f);
38    private readonly List<Label> labels = new List<Label>();
39    private readonly LinkedList<Tuple<string, IContent>> breadcrumbs = new LinkedList<Tuple<string, IContent>>();
40
41    private Size requiredSize;
42    private Point requiredLocation;
43    private bool enableBreadcrumbs;
44    private bool showSingle;
45
46    [DefaultValue(false)]
47    public bool EnableBreadcrumbs {
48      get { return enableBreadcrumbs; }
49      set {
50        if (enableBreadcrumbs == value) return;
51        enableBreadcrumbs = value;
52        ConfigureViewLayout(ActiveView as ContentView);
53      }
54    }
55
56    [DefaultValue(false)]
57    public bool ShowSingle {
58      get { return showSingle; }
59      set {
60        if (showSingle == value) return;
61        showSingle = value;
62
63        if (enableBreadcrumbs && !breadcrumbs.Any())
64          AddBreadcrumbs(Content);
65
66        ConfigureViewLayout(ActiveView as ContentView);
67      }
68    }
69
70    public IEnumerable<IContent> Breadcrumbs { get { return breadcrumbs.Select(x => x.Item2); } }
71
72    public BreadcrumbViewHost() {
73      InitializeComponent();
74    }
75
76    #region Overrides
77    protected override void OnContentChanged() {
78      base.OnContentChanged();
79      if (Content == null) {
80        breadcrumbs.Clear();
81      } else {
82        if (enableBreadcrumbs && showSingle)
83          if (!breadcrumbs.Any())
84            AddBreadcrumbs(Content);
85          else if (breadcrumbs.Count == 1) {
86            breadcrumbs.Clear();
87            AddBreadcrumbs(Content);
88          }
89      }
90
91      UpdateBreadcrumbTrail();
92      ConfigureViewLayout(ActiveView as ContentView);
93    }
94
95    protected override void OnSizeChanged(EventArgs e) {
96      UpdateBreadcrumbTrail();
97      base.OnSizeChanged(e);
98    }
99
100    protected override void ConfigureViewLayout(View view) {
101      if (view == null) return;
102
103      base.ConfigureViewLayout(view);
104
105      requiredSize = view.Size;
106      requiredLocation = Point.Empty;
107
108      if (enableBreadcrumbs && (breadcrumbs.Count > 1 || breadcrumbs.Count == 1 && showSingle)) {
109        requiredSize.Height -= font.Height + 6;
110        requiredLocation.Y += font.Height + 8;
111
112        if (view.Dock == DockStyle.Fill)
113          view.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
114      }
115
116      view.Size = requiredSize;
117      view.Location = requiredLocation;
118    }
119    #endregion
120
121    public void AddBreadcrumbs(params IContent[] crumbs) {
122      foreach (var c in crumbs) {
123        var item = c as INamedItem;
124        string text = item != null ? item.Name : c != null ? c.ToString() : "null";
125        AddBreadcrumb(text, c);
126      }
127    }
128
129    public void AddBreadcrumb(string text, IContent content) {
130      if (breadcrumbs.Any(x => x.Item2 == content)) return;
131      breadcrumbs.AddLast(Tuple.Create(text, content));
132    }
133
134    #region Event Handlers
135    private void label_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
136      var label = (LinkLabel)sender;
137      var tuple = (Tuple<string, IContent>)label.Tag;
138
139      while (breadcrumbs.Any() && breadcrumbs.Last.Value != tuple)
140        breadcrumbs.RemoveLast();
141      if (breadcrumbs.Count == 1 && !showSingle)
142        breadcrumbs.RemoveLast();
143
144      Content = tuple.Item2;
145    }
146    #endregion
147
148    #region Helpers
149    private void UpdateBreadcrumbTrail() {
150      foreach (var l in labels)
151        Controls.Remove(l);
152      labels.Clear();
153
154      ConfigureViewLayout(ActiveView as ContentView);
155
156      if (!enableBreadcrumbs || !breadcrumbs.Any() || breadcrumbs.Count == 1 && !showSingle) return;
157
158      if (!AddLabelsLeftToRight())
159        AddLabelsRightToLeft();
160    }
161
162    private bool AddLabelsLeftToRight() {
163      var curLoc = new Point(3, 0);
164      int idx = 0;
165
166      foreach (var bc in breadcrumbs) {
167        Label label;
168
169        if (bc == breadcrumbs.Last.Value) {
170          label = new Label { Location = curLoc, AutoSize = true, Font = font, Text = bc.Item1 };
171        } else {
172          label = new LinkLabel { Location = curLoc, AutoSize = true, Font = font, Text = bc.Item1, Tag = bc };
173          ((LinkLabel)label).LinkClicked += label_LinkClicked;
174        }
175
176        labels.Add(label);
177        label.Size = label.GetPreferredSize(Size.Empty);
178        curLoc.X += label.Size.Width;
179
180        if (++idx < breadcrumbs.Count) {
181          var separator = new Label { Location = curLoc, AutoSize = true, Font = font, Text = Separator };
182          labels.Add(separator);
183          separator.Size = separator.GetPreferredSize(Size.Empty);
184          curLoc.X += separator.Size.Width;
185        }
186      }
187
188      double width = Width;
189      if (ViewsLabelVisible)
190        width -= viewsLabel.Width + viewsLabel.Margin.Left + viewsLabel.Margin.Right;
191      bool success = curLoc.X <= width;
192
193      if (success)
194        Controls.AddRange(labels.ToArray());
195
196      return success;
197    }
198
199    private void AddLabelsRightToLeft() {
200      if (!labels.Any()) return;
201
202      var curLoc = new Point(3, 0);
203
204      var ellipsis = new LinkLabel { Location = curLoc, AutoSize = true, Font = font, Text = Ellipsis };
205      labels.Insert(0, ellipsis);
206      Controls.Add(ellipsis);
207      curLoc.X += ellipsis.Size.Width;
208
209      double x = Width;
210      if (ViewsLabelVisible)
211        x -= viewsLabel.Width + viewsLabel.Margin.Left + viewsLabel.Margin.Right;
212
213      int i = labels.Count - 1;
214
215      while (i >= 1) {
216        x -= labels[i].Size.Width;
217        x -= labels[i - 1].Size.Width;
218        if (x < curLoc.X) break;
219        i -= 2;
220      }
221
222      ellipsis.Tag = breadcrumbs.ElementAt(i / 2);
223      ellipsis.LinkClicked += label_LinkClicked;
224
225      while (++i < labels.Count) {
226        var l = labels[i];
227        l.Location = curLoc;
228        Controls.Add(l);
229        curLoc.X += l.Size.Width;
230      }
231    }
232    #endregion
233  }
234}
Note: See TracBrowser for help on using the repository browser.