Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/class/Managed.Windows.Forms/System.Windows.Forms/LinkLabel.cs')
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms/LinkLabel.cs895
1 files changed, 895 insertions, 0 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/LinkLabel.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/LinkLabel.cs
new file mode 100644
index 00000000000..33ae9a1001a
--- /dev/null
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/LinkLabel.cs
@@ -0,0 +1,895 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2004-2005 Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez, jordi@ximian.com
+//
+// Based on work by:
+// Daniel Carrera, dcarrera@math.toronto.edu (stubbed out)
+// Jaak Simm (jaaksimm@firm.ee) (stubbed out)
+//
+
+// COMPLETE
+
+
+using System.ComponentModel;
+using System.Collections;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace System.Windows.Forms
+{
+ [DefaultEvent("LinkClicked")]
+ public class LinkLabel : Label, IButtonControl
+ {
+ /* Encapsulates a piece of text (regular or link)*/
+ internal class Piece
+ {
+ public string text;
+ public int start;
+ public int end;
+ public LinkLabel.Link link; // Empty link indicates regular text
+ public Rectangle rect;
+ public bool clicked;
+ public bool focused;
+
+ public Piece ()
+ {
+ start = end = 0;
+ link = null;
+ clicked = false;
+ focused = false;
+ }
+ }
+
+ private Color active_link;
+ private Color disabled_link;
+ private Color link_color;
+ private Color visited_color;
+ private LinkArea link_area;
+ private LinkBehavior link_behavior;
+ private LinkCollection link_collection;
+ private bool link_visited;
+ private bool link_click;
+ internal Piece[] pieces;
+ internal int num_pieces;
+ internal Font link_font;
+ private Cursor override_cursor;
+ private DialogResult dialog_result;
+
+ #region Events
+ public event LinkLabelLinkClickedEventHandler LinkClicked;
+ #endregion // Events
+
+ public LinkLabel ()
+ {
+ LinkArea = new LinkArea (0, -1);
+ link_behavior = LinkBehavior.SystemDefault;
+ link_visited = false;
+ link_click = false;
+ pieces = null;
+ num_pieces = 0;
+ link_font = null;
+
+ ActiveLinkColor = Color.Red;
+ DisabledLinkColor = ThemeEngine.Current.ColorGrayText;
+ LinkColor = Color.FromArgb (255, 0, 0, 255);
+ VisitedLinkColor = Color.FromArgb (255, 128, 0, 128);
+ SetStyle (ControlStyles.Selectable, false);
+ SetStyle (ControlStyles.Opaque, true);
+ }
+
+ #region Public Properties
+
+ public Color ActiveLinkColor {
+ get { return active_link;}
+ set {
+ if (active_link == value)
+ return;
+
+ active_link = value;
+ Refresh ();
+ }
+ }
+
+ public Color DisabledLinkColor {
+
+ get { return disabled_link;}
+ set {
+ if (disabled_link == value)
+ return;
+
+ disabled_link = value;
+ Refresh ();
+ }
+ }
+
+ public Color LinkColor {
+ get { return link_color;}
+ set {
+ if (link_color == value)
+ return;
+
+ link_color = value;
+ Refresh ();
+ }
+ }
+
+ public Color VisitedLinkColor {
+ get { return visited_color;}
+ set {
+ if (visited_color == value)
+ return;
+
+ visited_color = value;
+ Refresh ();
+ }
+ }
+
+ [Localizable (true)]
+ [Editor ("System.Windows.Forms.Design.LinkAreaEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
+ public LinkArea LinkArea {
+ get { return link_area;}
+ set {
+
+ if (value.Start <0 || value.Length < -1)
+ throw new ArgumentException ();
+
+ if (!value.IsEmpty)
+ Links.Add (value.Start, value.Length);
+
+ link_area = value;
+ Refresh ();
+ }
+ }
+
+ [DefaultValue (LinkBehavior.SystemDefault)]
+ public LinkBehavior LinkBehavior {
+
+ get { return link_behavior;}
+ set {
+ if (link_behavior == value)
+ return;
+
+ link_behavior = value;
+ Refresh ();
+ }
+ }
+
+ [Browsable (false)]
+ [EditorBrowsable (EditorBrowsableState.Advanced)]
+ [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ public LinkLabel.LinkCollection Links {
+ get {
+ if (link_collection == null)
+ link_collection = new LinkCollection (this);
+
+ return link_collection;
+ }
+ }
+
+ [DefaultValue (false)]
+ public bool LinkVisited {
+ get { return link_visited;}
+ set {
+ if (link_visited == value)
+ return;
+
+ link_visited = value;
+ Refresh ();
+ }
+ }
+
+ protected Cursor OverrideCursor {
+ get { return override_cursor;}
+ set { override_cursor = value;}
+ }
+
+ [RefreshProperties(RefreshProperties.Repaint)]
+ public override string Text {
+ get { return base.Text; }
+ set {
+ if (base.Text == value)
+ return;
+
+ base.Text = value;
+ CreateLinkPieces ();
+ }
+ }
+
+ #endregion // Public Properties
+
+ DialogResult IButtonControl.DialogResult {
+ get { return dialog_result; }
+ set { dialog_result = value; }
+ }
+
+
+ void IButtonControl.NotifyDefault (bool value)
+ {
+
+ }
+
+ void IButtonControl.PerformClick ()
+ {
+
+ }
+
+ #region Public Methods
+ protected override AccessibleObject CreateAccessibilityInstance ()
+ {
+ return base.CreateAccessibilityInstance();
+ }
+
+ protected override void CreateHandle ()
+ {
+ base.CreateHandle ();
+ CreateLinkFont ();
+ CreateLinkPieces ();
+ }
+
+ protected override void OnEnabledChanged (EventArgs e)
+ {
+ base.OnEnabledChanged (e);
+ Refresh ();
+ }
+
+ protected override void OnFontChanged (EventArgs e)
+ {
+ base.OnFontChanged (e);
+ CreateLinkFont ();
+ CreateLinkPieces ();
+ }
+
+ protected override void OnGotFocus (EventArgs e)
+ {
+ base.OnGotFocus (e);
+
+ // Set focus to the first enabled link piece
+ for (int i = 0; i < num_pieces; i++) {
+ if (pieces[i].link != null && pieces[i].link.Enabled) {
+ pieces[i].focused = true;
+ Invalidate (pieces[i].rect);
+ break;
+ }
+ }
+ }
+
+ protected override void OnKeyDown (KeyEventArgs e)
+ {
+ base.OnKeyDown(e);
+
+ // Set focus to the next link piece
+ if (e.KeyCode == Keys.Tab || e.KeyCode == Keys.Right) {
+ for (int i = 0; i < num_pieces; i++) {
+ if (pieces[i].focused) {
+ pieces[i].focused = false;
+ Invalidate (pieces[i].rect);
+
+ for (int n = i + 1; n < num_pieces; n++) {
+ if (pieces[n].link != null && pieces[n].link.Enabled) {
+ pieces[n].focused = true;
+ e.Handled = true;
+ Invalidate (pieces[n].rect);
+ return;
+ }
+ }
+ }
+ }
+ } else if (e.KeyCode == Keys.Return) {
+ for (int i = 0; i < num_pieces; i++) {
+ if (pieces[i].focused && pieces[i].link != null) {
+ OnLinkClicked (new LinkLabelLinkClickedEventArgs (pieces[i].link));
+ break;
+ }
+ }
+ }
+ }
+
+ protected virtual void OnLinkClicked (LinkLabelLinkClickedEventArgs e)
+ {
+ if (LinkClicked != null)
+ LinkClicked (this, e);
+ }
+
+ protected override void OnLostFocus (EventArgs e)
+ {
+ base.OnLostFocus (e);
+
+ // Clean focus in link pieces
+ for (int i = 0; i < num_pieces; i++) {
+ if (pieces[i].focused) {
+ pieces[i].focused = false;
+ }
+ }
+
+ Refresh ();
+ }
+
+ protected override void OnMouseDown (MouseEventArgs e)
+ {
+ if (!Enabled) return;
+
+ base.OnMouseDown (e);
+ this.Capture = true;
+
+ for (int i = 0; i < num_pieces; i++) {
+ if (pieces[i].rect.Contains (e.X, e.Y)) {
+ if (pieces[i].link!= null) {
+ pieces[i].clicked = true;
+ Invalidate (pieces[i].rect);
+ }
+ break;
+ }
+ }
+ }
+
+ protected override void OnMouseLeave(EventArgs e)
+ {
+ if (!Enabled) return;
+ base.OnMouseLeave (e);
+ UpdateHover(null);
+ }
+
+ private bool UpdateHover(Link link) {
+ bool changed;
+
+ changed = false;
+ if (link == null) {
+ Cursor = Cursors.Default;
+
+ if (link_behavior == LinkBehavior.HoverUnderline) {
+ for (int i = 0; i < Links.Count; i++) {
+ if (Links[i].Hoovered == true) {
+ changed = true;
+ Links[i].Hoovered = false;
+ }
+ }
+ }
+ } else {
+ if (link_behavior == LinkBehavior.HoverUnderline) {
+ Cursor = Cursors.Hand;
+
+ if (link.Hoovered != true) {
+ link.Hoovered = true;
+ changed = true;
+ }
+ }
+ }
+
+ if (changed == true) {
+ Refresh ();
+ }
+
+
+ return changed;
+ }
+
+ protected override void OnMouseMove (MouseEventArgs e)
+ {
+ base.OnMouseMove (e);
+ UpdateHover(PointInLink (e.X, e.Y));
+ }
+
+ protected override void OnMouseUp (MouseEventArgs e)
+ {
+ if (!Enabled) return;
+
+ base.OnMouseUp (e);
+ this.Capture = false;
+
+ for (int i = 0; i < num_pieces; i++) {
+ if (pieces[i].link!= null && pieces[i].clicked == true) {
+ OnLinkClicked (new LinkLabelLinkClickedEventArgs (pieces[i].link));
+ pieces[i].clicked = false;
+ Invalidate (pieces[i].rect);
+ break;
+ }
+ }
+ }
+
+ protected override void OnPaint (PaintEventArgs pevent)
+ {
+ ThemeEngine.Current.DrawLinkLabel (pevent.Graphics, pevent.ClipRectangle, this);
+ DrawImage (pevent.Graphics, Image, ClientRectangle, image_align);
+ // Do not call base.OnPaint since it's the Label class
+ }
+
+ protected override void OnPaintBackground (PaintEventArgs e)
+ {
+ base.OnPaintBackground (e);
+ }
+
+ protected override void OnTextAlignChanged (EventArgs e)
+ {
+ base.OnTextAlignChanged (e);
+ CreateLinkPieces ();
+ }
+
+ protected override void OnTextChanged (EventArgs e)
+ {
+ base.OnTextChanged (e);
+ }
+
+ protected Link PointInLink (int x, int y)
+ {
+ for (int i = 0; i < num_pieces; i++) {
+ if (pieces[i].rect.Contains (x,y) && pieces[i].link != null)
+ return pieces[i].link;
+ }
+
+ return null;
+ }
+
+ protected override bool ProcessDialogKey (Keys keyData)
+ {
+ return base.ProcessDialogKey (keyData);
+ }
+
+ protected override void Select (bool directed, bool forward)
+ {
+ base.Select (directed, forward);
+ }
+
+ protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
+ {
+ base.SetBoundsCore (x, y, width, height, specified);
+ }
+
+ protected override void WndProc (ref Message m)
+ {
+ base.WndProc (ref m);
+ }
+
+ #endregion //Public Methods
+
+ #region Private Methods
+
+ internal void CreateLinkPieces ()
+ {
+ if (Links.Count == 0 || IsHandleCreated == false || Text.Length == 0)
+ return;
+
+ int cur_piece = 0;
+ num_pieces = 0;
+
+ if (Links.Count == 1 && Links[0].Start == 0 && Links[0].Length == -1) {
+ Links[0].Length = Text.Length;
+ }
+
+ pieces = new Piece [(Links.Count * 2) + 1];
+ pieces[cur_piece] = new Piece();
+ pieces[cur_piece].start = 0;
+
+ for (int i = 0; i < Text.Length; i++) { /* Every char on the text*/
+ for (int l = 0; l < Links.Count; l++) { /* Every link that we know of*/
+ if (Links[l].Start == i) {
+ if (i > 0) {
+ /*Push prev. regular text*/
+ pieces[cur_piece].end = i;
+ pieces[cur_piece].text = Text.Substring (pieces[cur_piece].start,
+ pieces[cur_piece].end - pieces[cur_piece].start);
+
+ cur_piece++;
+
+ /* New link*/
+ pieces[cur_piece] = new Piece ();
+ }
+
+ int end;
+
+ if (Links[l].Start + Links[l].Length > Text.Length) {
+ end = Text.Length - Links[l].Start;
+ }
+ else {
+ end = Links[l].Length;
+ }
+
+ pieces[cur_piece].start = Links[l].Start;
+ pieces[cur_piece].end = Links[l].Start + end;
+ pieces[cur_piece].link = Links[l];
+
+ pieces[cur_piece].text = Text.Substring (pieces[cur_piece].start, end);
+
+ cur_piece++; /* Push link*/
+ pieces[cur_piece] = new Piece();
+ i+= Links[l].Length;
+ pieces[cur_piece].start = i;
+ }
+ }
+ }
+
+ if (pieces[cur_piece].end == 0 && pieces[cur_piece].start < Text.Length) {
+ pieces[cur_piece].end = Text.Length;
+ pieces[cur_piece].text = Text.Substring (pieces[cur_piece].start, pieces[cur_piece].end - pieces[cur_piece].start);
+ cur_piece++;
+ }
+
+ num_pieces = cur_piece;
+
+ CharacterRange[] charRanges = new CharacterRange [num_pieces];
+
+ for (int i = 0; i < num_pieces; i++)
+ charRanges[i] = new CharacterRange (pieces[i].start, pieces[i].end - pieces[i].start);
+
+ Region[] charRegions = new Region [num_pieces];
+ string_format.SetMeasurableCharacterRanges (charRanges);
+
+ // BUG: This sizes do not match the ones used later when drawing
+ charRegions = DeviceContext.MeasureCharacterRanges (Text, link_font, ClientRectangle, string_format);
+
+ RectangleF rect;
+ for (int i = 0; i < num_pieces; i++) {
+ rect = charRegions[i].GetBounds (DeviceContext);
+ pieces[i].rect = Rectangle.Ceiling (rect);
+ charRegions[i].Dispose ();
+ }
+
+ if (Visible && IsHandleCreated)
+ Refresh ();
+
+ }
+
+ /* Check if the links overlap */
+ internal void CheckLinks ()
+ {
+ for (int i = 0; i < Links.Count; i++) {
+ for (int l = 0; l < Links.Count; l++) {
+ if (i==l) continue;
+
+ if (((Links[i].Start + Links[i].Length) >= Links[l].Start &&
+ Links[i].Start + Links[i].Length <= Links[l].Start + Links[l].Length) ||
+ (Links[i].Start >= Links[l].Start &&
+ Links[i].Start <= Links[l].Start + Links[l].Length))
+ throw new InvalidOperationException ("Overlapping link regions.");
+ }
+ }
+ }
+
+ internal Font GetPieceFont (Piece piece)
+ {
+ switch (link_behavior) {
+ case LinkBehavior.AlwaysUnderline:
+ case LinkBehavior.SystemDefault: // Depends on IE configuration
+ {
+ if (piece.link == null) {
+ return Font;
+ } else {
+ return link_font;
+ }
+ }
+ case LinkBehavior.HoverUnderline:
+ {
+ if (piece.link != null && piece.link.Hoovered) {
+ return link_font;
+ } else {
+ return Font;
+ }
+ }
+
+ case LinkBehavior.NeverUnderline:
+ default:
+ return Font;
+ }
+
+ }
+
+
+ internal Color GetLinkColor (Piece piece, int i)
+ {
+ Color color;
+
+ if (Enabled == false ||
+ (piece.link != null && piece.link.Enabled == false))
+ color = DisabledLinkColor;
+ else
+ if (piece.clicked == true)
+ color = ActiveLinkColor;
+ else
+ if ((LinkVisited == true && i == 0) ||
+ (piece.link != null && piece.link.Visited == true))
+ color = VisitedLinkColor;
+ else
+ color = LinkColor;
+
+ return color;
+ }
+
+ private void CreateLinkFont ()
+ {
+ if (link_font != null)
+ link_font.Dispose ();
+
+ link_font = new Font (Font.FontFamily, Font.Size, Font.Style | FontStyle.Underline,
+ Font.Unit);
+ }
+
+ #endregion // Private Methods
+
+ //
+ // System.Windows.Forms.LinkLabel.Link
+ //
+ public class Link
+ {
+ private bool enabled;
+ internal int length;
+ private object linkData;
+ private int start;
+ private bool visited;
+ private LinkLabel owner;
+ private bool hoovered;
+
+ internal Link ()
+ {
+ enabled = true;
+ visited = false;
+ length = start = 0;
+ linkData = null;
+ owner = null;
+ }
+
+ internal Link (LinkLabel owner)
+ {
+ enabled = true;
+ visited = false;
+ length = start = 0;
+ linkData = null;
+ this.owner = owner;
+ }
+
+ public bool Enabled {
+ get { return enabled; }
+ set {
+ if (enabled == value)
+ return;
+
+ enabled = value;
+
+ if (owner != null)
+ owner.Refresh ();
+ }
+ }
+
+ public int Length {
+ get {
+ if (length == -1) {
+ return owner.Text.Length;
+ }
+
+ return length;
+ }
+ set {
+ if (length == value)
+ return;
+
+ length = value;
+
+ if (owner != null)
+ owner.CreateLinkPieces ();
+ }
+ }
+
+ public object LinkData {
+ get { return linkData; }
+ set { linkData = value; }
+ }
+
+ public int Start {
+ get { return start; }
+ set {
+ if (start == value)
+ return;
+
+ start = value;
+
+ if (owner != null)
+ owner.CreateLinkPieces ();
+ }
+ }
+
+ public bool Visited {
+ get { return visited; }
+ set {
+ if (visited == value)
+ return;
+
+ visited = value;
+
+ if (owner != null)
+ owner.Refresh ();
+ }
+ }
+
+ internal bool Hoovered {
+ get { return hoovered; }
+ set { hoovered = value; }
+ }
+ }
+
+ //
+ // System.Windows.Forms.LinkLabel.Link
+ //
+ public class LinkCollection : IList, ICollection, IEnumerable
+ {
+ private LinkLabel owner;
+ private ArrayList collection = new ArrayList();
+
+ public LinkCollection (LinkLabel owner)
+ {
+ if (owner==null)
+ throw new ArgumentNullException ();
+
+ this.owner = owner;
+ }
+
+ [Browsable (false)]
+ public int Count {
+ get { return collection.Count; }
+ }
+
+ public bool IsReadOnly {
+ get { return false; }
+ }
+
+ public virtual LinkLabel.Link this[int index] {
+ get {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException();
+
+ return (LinkLabel.Link) collection[index];
+ }
+ set {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException();
+
+ collection[index] = value;
+ }
+ }
+
+ public Link Add (int start, int length)
+ {
+ return Add (start, length, null);
+ }
+
+
+ public Link Add (int start, int length, object o)
+ {
+ Link link = new Link (owner);
+ int idx;
+
+ if (Count == 1 && this[0].Start == 0
+ && this[0].length == -1) {
+ Clear ();
+ }
+
+ link.Length = length;
+ link.Start = start;
+ link.LinkData = o;
+ idx = collection.Add (link);
+
+ owner.CheckLinks ();
+ owner.CreateLinkPieces ();
+ return (Link) collection[idx];
+ }
+
+ public virtual void Clear ()
+ {
+ collection.Clear();
+ owner.CreateLinkPieces ();
+ }
+
+ public bool Contains (LinkLabel.Link link)
+ {
+ return collection.Contains (link);
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return collection.GetEnumerator ();
+ }
+
+ public int IndexOf (LinkLabel.Link link)
+ {
+ return collection.IndexOf (link);
+ }
+
+ public void Remove (LinkLabel.Link value)
+ {
+ collection.Remove (value);
+ owner.CreateLinkPieces ();
+ }
+
+ public void RemoveAt (int index)
+ {
+ if (index >= Count)
+ throw new ArgumentOutOfRangeException ("Invalid value for array index");
+
+ collection.Remove (collection[index]);
+ owner.CreateLinkPieces ();
+ }
+
+ bool IList.IsFixedSize {
+ get {return false;}
+ }
+
+ object IList.this[int index] {
+ get { return collection[index]; }
+ set { collection[index] = value; }
+ }
+
+ object ICollection.SyncRoot {
+ get {return this;}
+ }
+
+ bool ICollection.IsSynchronized {
+ get {return false;}
+ }
+
+ void ICollection.CopyTo (Array dest, int index)
+ {
+ collection.CopyTo (dest, index);
+ }
+
+ int IList.Add (object control)
+ {
+ int idx = collection.Add (control);
+ owner.CheckLinks ();
+ owner.CreateLinkPieces ();
+ return idx;
+ }
+
+ bool IList.Contains (object control)
+ {
+ return collection.Contains (control);
+ }
+
+ int IList.IndexOf (object control)
+ {
+ return collection.IndexOf (control);
+ }
+
+ void IList.Insert (int index, object value)
+ {
+ collection.Insert (index, value);
+ owner.CheckLinks ();
+ owner.CreateLinkPieces ();
+ }
+
+ void IList.Remove (object control)
+ {
+ collection.Remove (control);
+ owner.CreateLinkPieces ();
+ }
+ }
+#if NET_2_0
+
+ public bool UseCompatibleTextRendering {
+ get {
+ return use_compatible_text_rendering;
+ }
+
+ set {
+ use_compatible_text_rendering = value;
+ }
+ }
+#endif
+ }
+}