Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions samples/ControlGallery/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public MainForm ()
tree.Items.Add ("FormShortcuts", ImageLoader.Get ("button.png"));
tree.Items.Add ("ImageList", ImageLoader.Get ("button.png"));
tree.Items.Add ("Label", ImageLoader.Get ("button.png"));
tree.Items.Add ("LinkLabel", ImageLoader.Get ("button.png"));
tree.Items.Add ("ListBox", ImageLoader.Get ("button.png"));
tree.Items.Add ("ListView", ImageLoader.Get ("button.png"));
tree.Items.Add ("Menu", ImageLoader.Get ("button.png"));
Expand Down Expand Up @@ -100,6 +101,8 @@ private void Tree_ItemSelected (object? sender, EventArgs<TreeViewItem> e)
return new ImageListPanel ();
case "Label":
return new LabelPanel ();
case "LinkLabel":
return new LinkLabelPanel ();
case "ListBox":
return new ListBoxPanel ();
case "ListView":
Expand Down
140 changes: 140 additions & 0 deletions samples/ControlGallery/Panels/LinkLabelPanel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using System.Drawing;
using Modern.Forms;
using SkiaSharp;

namespace ControlGallery.Panels
{
/// <summary>
/// Demonstrates the LinkLabel control with various configurations.
/// </summary>
public class LinkLabelPanel : Panel
{
private readonly Label output;

public LinkLabelPanel ()
{
Padding = new Padding (20);

output = new Label {
Text = "Output: ",
Location = new Point (20, 400),
Width = 500,
Height = 30
};

Controls.Add (output);

// === Simple single link ===
var simple = new LinkLabel {
Text = "Click here to open documentation",
Location = new Point (20, 20),
Width = 400,
Height = 30,
HoverLinkColor = SKColors.Red,
VisitedLinkColor = SKColors.Purple
};

simple.LinkClicked += (s, e) => {
output.Text = "Simple link clicked";
};

Controls.Add (simple);

// === Multiple links ===
var multi = new LinkLabel {
Text = "Visit docs or support page",
Location = new Point (20, 70),
Width = 400,
Height = 30
};

multi.Links.Clear ();
multi.Links.Add (0, 10, "docs");
multi.Links.Add (14, 7, "support");

multi.LinkClicked += (s, e) => {
output.Text = $"Clicked: {e.Link?.LinkData}";
};

Controls.Add (multi);

// === Visited links ===
var visited = new LinkLabel {
Text = "Visited link example",
Location = new Point (20, 120),
LinkVisited = true,
Width = 400,
Height = 30
};

visited.LinkClicked += (s, e) => {
output.Text = "Visited link clicked";
};

Controls.Add (visited);

// === Disabled link ===
var disabled = new LinkLabel {
Text = "Disabled link example",
Location = new Point (20, 170),
Width = 400,
Height = 30
};

disabled.Links[0].Enabled = false;

Controls.Add (disabled);

// === Hover underline only ===
var hover = new LinkLabel {
Text = "Hover underline example",
Location = new Point (20, 220),
Width = 400,
Height = 30,
LinkBehavior = LinkBehavior.HoverUnderline,
HoverLinkColor = SKColors.Red
};

hover.LinkClicked += (s, e) => {
output.Text = "Hover link clicked";
};

Controls.Add (hover);

// === Custom colors ===
var custom = new LinkLabel {
Text = "Custom color link",
Location = new Point (20, 270),
Width = 400,
Height = 30,
LinkColor = SKColors.Green,
ActiveLinkColor = SKColors.Red,
VisitedLinkColor = SKColors.Purple
};

custom.LinkClicked += (s, e) => {
output.Text = "Custom color link clicked";
};

Controls.Add (custom);

// === Keyboard navigation demo ===
var keyboard = new LinkLabel {
Text = "Use TAB / arrows to switch links",
Location = new Point (20, 320),
Width = 400,
Height = 30
};

keyboard.Links.Clear ();
keyboard.Links.Add (4, 3, "tab");
keyboard.Links.Add (10, 6, "arrows");

keyboard.LinkClicked += (s, e) => {
output.Text = $"Keyboard link: {e.Link?.LinkData}";
};

Controls.Add (keyboard);
}
}
}
56 changes: 56 additions & 0 deletions src/Modern.Forms/LinkArea.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
namespace Modern.Forms
{
/// <summary>
/// Represents a range of text treated as a link.
/// </summary>
public struct LinkArea : IEquatable<LinkArea>
{
/// <summary>
/// Initializes a new instance of the <see cref="LinkArea"/> struct.
/// </summary>
/// <param name="start">The zero-based starting character index.</param>
/// <param name="length">The length of the link range.</param>
public LinkArea (int start, int length)
{
Start = start;
Length = length;
}

/// <summary>
/// Gets or sets the zero-based starting character index of the link range.
/// </summary>
public int Start { get; set; }

/// <summary>
/// Gets or sets the length of the link range.
/// </summary>
public int Length { get; set; }

/// <summary>
/// Gets a value indicating whether this link area is empty.
/// </summary>
public bool IsEmpty => Start == 0 && Length == 0;

/// <inheritdoc/>
public override bool Equals (object? obj) => obj is LinkArea other && Equals (other);

/// <inheritdoc/>
public bool Equals (LinkArea other) => Start == other.Start && Length == other.Length;

/// <inheritdoc/>
public override int GetHashCode () => HashCode.Combine (Start, Length);

/// <summary>
/// Determines whether two <see cref="LinkArea"/> values are equal.
/// </summary>
public static bool operator == (LinkArea left, LinkArea right) => left.Equals (right);

/// <summary>
/// Determines whether two <see cref="LinkArea"/> values are not equal.
/// </summary>
public static bool operator != (LinkArea left, LinkArea right) => !left.Equals (right);

/// <inheritdoc/>
public override string ToString () => $"{{Start={Start}, Length={Length}}}";
}
}
32 changes: 32 additions & 0 deletions src/Modern.Forms/LinkBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace Modern.Forms
{
/// <summary>
/// Specifies how link text should be underlined in a <see cref="LinkLabel"/>.
/// </summary>
public enum LinkBehavior
{
/// <summary>
/// Uses the framework default behavior.
/// </summary>
/// <remarks>
/// In this implementation, <see cref="SystemDefault"/> behaves the same as
/// <see cref="AlwaysUnderline"/>.
/// </remarks>
SystemDefault,

/// <summary>
/// Link text is always underlined.
/// </summary>
AlwaysUnderline,

/// <summary>
/// Link text is underlined only while the pointer hovers over it.
/// </summary>
HoverUnderline,

/// <summary>
/// Link text is never underlined.
/// </summary>
NeverUnderline
}
}
Loading
Loading