#if SYSLINKGETSWORKING
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.ComCtl32;
using static Vanara.PInvoke.User32;
namespace Vanara.PInvoke.Controls;
/// Represents a Windows SysLink control that displays one or more hyperlinks.
///
public class SysLink : Control
{
private static readonly bool IsPlatformSupported = Environment.OSVersion.Version.Major > 5;
private static Lazy init = new(() => InitCommonControlsEx(CommonControlClass.ICC_LINK_CLASS));
/// Initializes a new instance of the class.
public SysLink()
{
if (!IsPlatformSupported) throw new InvalidOperationException("A SysLink control is only supported after Vista.");
if (!init.Value) throw new InvalidOperationException("Failed to initialize common controls.");
Items = new(this);
}
/// Gets the list of hyperlinks.
/// The hyperlinks.
public SysLinkItemList Items { get; }
///
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ClassName = WC_LINK;
cp.Caption = "Click here";
return cp;
}
}
///
protected override Size DefaultSize => new(200, AutoSize ? PreferredSize.Height : 58);
///
public override Size GetPreferredSize(Size proposedSize)
{
SIZE sz = proposedSize;
if (IsHandleCreated)
{
using PinnedObject psz = new(sz);
var h = SendMessage(Handle, SysLinkMessage.LM_GETIDEALSIZE, proposedSize.Width, psz).ToInt32();
}
return sz;
}
}
/// Exposes the list of hyperlinks in a control. This class cannot be inherited.
public sealed class SysLinkItemList : IReadOnlyList
{
private readonly SysLink parent;
internal SysLinkItemList(SysLink parent) => this.parent = parent;
///
public int Count
{
get
{
int count = 0;
for (IEnumerator e = GetEnumerator(); e.MoveNext(); count++) ;
return Count;
}
}
///
public SysLinkItem this[int index] => new((HWND)parent.Handle, ValidateIndex(index));
///
public IEnumerator GetEnumerator()
{
LITEM li = new(0, LIF.LIF_STATE);
using var pli = new PinnedObject(li);
if (parent.IsHandleCreated)
for (; li.iLink < ushort.MaxValue && IntPtr.Zero != SendMessage(parent.Handle, SysLinkMessage.LM_GETITEM, default, pli); li.iLink++)
yield return new((HWND)parent.Handle, li.iLink);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
private int ValidateIndex(int index)
{
LITEM li = new(index, LIF.LIF_STATE);
using var pli = new PinnedObject(li);
return IntPtr.Zero == SendMessage(parent.Handle, SysLinkMessage.LM_GETITEM, default, pli)
? throw new ArgumentOutOfRangeException(nameof(index))
: index;
}
}
/// Information about a hyperlink exposed by a control. This class cannot be inherited.
public sealed class SysLinkItem
{
private readonly int index;
private readonly HWND parent;
internal SysLinkItem(HWND handle, int index) { parent = handle; this.index = index; }
/// Gets or sets a value indicating whether this is enabled.
/// if enabled; otherwise, .
public bool Enabled { get => GetState(LIS.LIS_ENABLED); set => SetState(LIS.LIS_ENABLED, value); }
/// Gets or sets a value indicating whether this is focused.
/// if focused; otherwise, .
public bool Focused { get => GetState(LIS.LIS_FOCUSED); set => SetState(LIS.LIS_FOCUSED, value); }
/// Gets or sets a value indicating whether this is hover.
/// if hover; otherwise, .
public bool Hover { get => GetState(LIS.LIS_HOTTRACK); set => SetState(LIS.LIS_HOTTRACK, value); }
/// Gets or sets the key.
/// The key.
public string Key { get => GetInfo(LIF.LIF_ITEMID).szID ?? index.ToString(); set => SetInfo(new(index, LIF.LIF_ITEMID) { szID = value }); }
/// Gets or sets the URL.
/// The URL.
public Uri Url { get => new(GetInfo(LIF.LIF_URL).szUrl); set => SetInfo(new(index, LIF.LIF_URL) { szUrl = value.AbsoluteUri }); }
/// Gets or sets a value indicating whether this is visited.
/// if visited; otherwise, .
public bool Visited { get => GetState(LIS.LIS_VISITED); set => SetState(LIS.LIS_VISITED, value); }
private LITEM GetInfo(LIF mask)
{
LITEM li = new(index, mask);
using PinnedObject pli = new(li);
if (mask.IsFlagSet(LIF.LIF_STATE))
li.stateMask = (LIS)0x1f;
SendMessage(parent, SysLinkMessage.LM_GETITEM, default, pli);
return li;
}
private bool GetState(LIS mask) => GetInfo(LIF.LIF_STATE).state.IsFlagSet(mask);
private void SetInfo(in LITEM item)
{
using PinnedObject pli = new(item);
if (0 != SendMessage(parent, SysLinkMessage.LM_SETITEM, default, pli).ToInt32())
Win32Error.ThrowLastError();
}
private void SetState(LIS lIS, bool value) => SetInfo(new(index, LIF.LIF_STATE) { stateMask = lIS, state = value ? lIS : 0 });
}
#endif