using
System;
using
System.Collections;
using
System.ComponentModel;
using
System.Drawing;
using
System.Windows.Forms;
using
System.Runtime.InteropServices;
namespace
WellFormed
{
///
<summary>
/// this
extender-provider component also implements the custom interface
/// IWndProcProvider
so that it can interact with the ExtNativeWindow class.
///
</summary>
[
ProvideProperty("TipText","System.Windows.Forms.Control"),
ProvideProperty("TipColor","System.Windows.Forms.Control"),
ProvideProperty("TipTextColor","System.Windows.Forms.Control"),
ProvideProperty("TipFont","System.Windows.Forms.Control"),
ProvideProperty("TipBorderColor","System.Windows.Forms.Control")
]
public class
NWTip : Component, IExtenderProvider, IWndProcProvider
{
#region
Interop
[DllImport("User32.dll")]
public
extern static
int ShowWindow( System.IntPtr hWnd,
short cmdShow);
[DllImport("User32.dll")]
public
extern static
int ValidateRect( System.IntPtr hWnd,
System.IntPtr rect);
#endregion
#region
Fields
//The
NativeWindow member
ExtNativeWindow _nw;
//hash
table that associates controls with tool tip data
Hashtable
_items=new Hashtable();
//a
reference to the current control. this is the control in which the cursor is
hovering
Control
_currentControl;
//timer,
used to remove the tool tip after a short interval.
Timer
_killTimer;
//A
rectangle calculated from the size of the text.
Rectangle
_tipRect;
#endregion
#region
tooltip data container
///
<summary>
///
This class maintains all the properties associated with each control.
///
The hash table associates this class with the control using a reference as a
key.
///
</summary>
protected
class tipData
{
string
_text;
public
string Text
{
get{return
_text;}
set{_text=value;}
}
Color
_tipColor=Color.Yellow;
public
Color TipColor
{
get{return
_tipColor;}
set{_tipColor=value;}
}
Color _textColor=Color.Black;
public
Color TextColor
{
get{return
_textColor;}
set{_textColor=value;}
}
Font
_font=SystemInformation.MenuFont;
public
Font Font
{
get{return
_font;}
set{_font=value;}
}
Color _borderColor=Color.Black;
public
Color BorderColor
{
get{return
_borderColor;}
set{_borderColor=value;}
}
}
#endregion
#region
Construction - disposal
//when
constructed, the class creates a new ExtNativeWindow
public
NWTip()
{
_nw=new
ExtNativeWindow(this);
}
//The
dispose method has to ensure that all the event handlers are removed from
//the
components that were extended.
protected
override void
Dispose(bool disposing)
{
if(disposing)
{
foreach(Control
c in _items.Keys)
{
c.MouseHover-=new EventHandler(this.c_MouseHover);
c.MouseLeave-=new EventHandler(this.c_MouseLeave);
}
this._items.Clear();
}
base.Dispose
(disposing);
}
#endregion
#region
IExtenderProvider Members
//This
component can extend control.
public
bool CanExtend(object
extendee)
{
return
extendee is Control;
}
//A
utility routing to extract tipData from the hash table using the
//Control
reference as a key.
protected
tipData GetItem(Control c)
{
if(this._items.Contains(c))
return
(tipData)_items[c];
tipData
td=new tipData();
_items[c]=td;
c.MouseHover+=new
EventHandler(c_MouseHover);
c.MouseLeave+=new
EventHandler(c_MouseLeave);
return
td;
}
/*
* The following ten methods implement the set and get methods for each of
the extended
* properties that we provide to control based classes.
*
*/
public
void SetTipText(Control c,
string value)
{
tipData
td=GetItem(c);
td.Text=value;
}
public
void SetTipColor(Control c, Color
value)
{
tipData
td=GetItem(c);
td.TipColor=value;
}
public
void SetTipTextColor(Control c, Color
value)
{
tipData
td=GetItem(c);
td.TextColor=value;
}
public
void SetTipFont(Control c, Font
value)
{
tipData
td=GetItem(c);
td.Font=value;
}
public
void SetTipBorderColor(Control c, Color
value)
{
tipData
td=GetItem(c);
td.BorderColor=value;
}
public
string GetTipText(Control c)
{
tipData
td=GetItem(c);
return
td.Text;
}
public
Color GetTipColor(Control c)
{
tipData
td=GetItem(c);
return
td.TipColor;
}
public
Color GetTipTextColor(Control c)
{
tipData
td=GetItem(c);
return
td.TextColor;
}
public
Font GetTipFont(Control c)
{
tipData
td=GetItem(c);
return
td.Font;
}
public
Color GetTipBorderColor(Control c)
{
tipData
td=GetItem(c);
return
td.BorderColor;
}
#endregion
#region
IWndProcProvider Members
//Implements
the IWndProcProvider interface which enables any class to host an
ExtNativeWindow
//Note.
It is important to call the default WndProc for any messages not processed by
this method.
void
WellFormed.IWndProcProvider.WndProc(ref Message
m, ExtNativeWindow defWndProcProvider)
{
switch(m.Msg)
{
case
(int)WmDefs.WM_PAINT:
PaintTooltip(ref m);
break;
default:
defWndProcProvider.DefWndProc(ref m);
break;
}
}
#endregion
#region
Extended control mouse handlers
//Handles
the MouseHover event from the control been extended.
//this
enables the extender-provider to know when the mouse cursor is in a control.
private
void c_MouseHover(object
sender, EventArgs e)
{
_currentControl=(Control)sender;
if(_killTimer!=null)
{
_killTimer.Enabled=false;
_killTimer.Dispose();
_killTimer=null;
_nw.DestroyHandle();
}
ShowTip();
}
//Handles
the MouseLeave event from the control be extended.
//This
enables the extender-provider to know when the mouse cursor has left the
//control
and hence, when to destroy the tool tip window.
private
void c_MouseLeave(object
sender, EventArgs e)
{
if(sender
== _currentControl)
{
_killTimer=new Timer();
_killTimer.Interval=100;
_killTimer.Tick+=new
EventHandler(_killTimer_Tick);
_killTimer.Enabled=true;
}
}
#endregion
#region
Painting
//A
simple paint routine. This fills the window with the background color,
//paints
the border, the text and finally validates the rectangle of the window.
protected
void PaintTooltip(ref
Message m)
{
tipData
td=this.GetItem(this._currentControl);
Graphics g=Graphics.FromHwnd(_nw.Handle);
g.Clear(td.TipColor);
Pen p=new
Pen(td.BorderColor,_tipRect.Height/100);
g.DrawRectangle(p,0,0,_tipRect.Width-1,_tipRect.Height-1);
p.Dispose();
SolidBrush sb=new SolidBrush(td.TextColor);
g.DrawString(td.Text,td.Font,sb,_tipRect.Width/20,_tipRect.Height/20,StringFormat.GenericTypographic);
sb.Dispose();
g.Dispose();
m.Result=IntPtr.Zero;
ValidateRect(m.HWnd,IntPtr.Zero);
}
#endregion
#region
low-level window management
//The
windows creation parameters.
protected
CreateParams CreateParams
{
get
{
System.Windows.Forms.CreateParams cp=new
System.Windows.Forms.CreateParams();
unchecked
{
cp.Style = (int)WindowStyles.WS_POPUP;
}
cp.ClassStyle=(int)ClassStyles.CS_OWNDC |
(int)ClassStyles.CS_HREDRAW | (int)ClassStyles.CS_VREDRAW;
cp.ExStyle=(int)WindowStyles.WS_EX_TOPMOST;
cp.ClassName="tooltips_class32";
cp.X=0;
cp.Y=0;
cp.Height=0;
cp.Width=0;
cp.Parent=System.IntPtr.Zero;
cp.Caption=null;
return
cp;
}
}
//This
handles the time out from the timer which is set whenever the cursor leaves a
control.
//It
destroys the tool tip window.
private
void _killTimer_Tick(object
sender, EventArgs e)
{
((Timer)sender).Enabled=false;
_nw.DestroyHandle();
}
//Called
by the mouse hover Handler to display the tool tip window.
private
void ShowTip()
{
CreateParams cp=this.CreateParams;
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
tipData
td = (tipData)_items[this._currentControl];
SizeF
sf=g.MeasureString(td.Text,td.Font,1024,StringFormat.GenericTypographic);
Point
position =Control.MousePosition;
Rectangle rc=new Rectangle(position.X,(int)(position.Y+SystemInformation.CursorSize.Height),(int)sf.Width,(int)sf.Height);
rc.Inflate(rc.Width/10,rc.Height/10);
_tipRect=rc;
if(rc.Right>SystemInformation.VirtualScreen.Right)
rc.Offset(-(rc.Right-SystemInformation.VirtualScreen.Right),0);
if(rc.Bottom>SystemInformation.VirtualScreen.Bottom)
rc.Offset(0,-((rc.Bottom-SystemInformation.VirtualScreen.Bottom)+rc.Height+SystemInformation.CursorSize.Height));
if(rc.Left<10)
rc.X=10;
cp.X=rc.X;
cp.Y=rc.Y;
cp.Width=rc.Width;
cp.Height=rc.Height;
_nw.CreateHandle(cp);
ShowWindow(_nw.Handle,(short)WellFormed.ShowWindow.SW_SHOWNOACTIVATE);
}
#endregion
}
}
Imports
System
Imports
System.Collections
Imports
System.ComponentModel
Imports
System.Drawing
Imports
System.Windows.Forms
Imports
System.Runtime.InteropServices
Class
resfinder
End
Class
Namespace
WellFormed
'' <summary>
'' me extender-provider component also implements the
custom interface
'' IWndProcProvider so that it can interact with the
ExtNativeWindow class.
'' </summary>
< _
ProvideProperty("TipText", "System.Windows.Forms.Control"), _
ProvideProperty("TipColor", "System.Windows.Forms.Control"), _
ProvideProperty("TipTextColor", "System.Windows.Forms.Control"), _
ProvideProperty("TipFont", "System.Windows.Forms.Control"), _
ProvideProperty("TipBorderColor", "System.Windows.Forms.Control"), _
ToolboxBitmap(GetType(resfinder),
"NWTip.NWTip.bmp") _
> _
Public
Class NWTip
Inherits
Component
Implements
IExtenderProvider, IWndProcProvider
#Region
"Interop"
<DllImport("User32.dll")> _
Public
Shared Function
ShowWindow(ByVal hWnd
As System.IntPtr, ByVal cmdShow
As Short)
As Integer
End
Function
<DllImport("User32.dll")> _
Public
Shared Function
ValidateRect(ByVal hWnd
As System.IntPtr, ByVal rect
As System.IntPtr) As
Integer
End
Function
#End
Region
#Region
"Fields"
'The
NativeWindow member
Private
nw As ExtNativeWindow
'hash
table that associates controls with tool tip data
Private
items As New
Hashtable
'a
reference to the current control. me is the control in which the cursor is
hovering
Private
currentControl As Control
'timer,
used to remove the tool tip after a short interval.
Private
killTimer As Timer
'A
rectangle calculated from the size of the text.
Private
tipRect As Rectangle
#End
Region
#Region
"tooltip data container"
''
<summary>
''
This class maintains all the properties associated with each control.
''
The hash table associates me class with the control imports a reference as a
key.
''
</summary>
Protected
Class tipData
Private
_text As String
Public
Property Text() As
String
Get
Return
_text
End
Get
Set(ByVal
Value As String)
_text = Value
End
Set
End
Property
Private
_tipColor As Color = Color.Yellow
Public
Property TipColor() As
Color
Get
Return
_tipColor
End
Get
Set(ByVal
Value As Color)
_tipColor = Value
End
Set
End
Property
Private
_textColor As Color = Color.Black
Public
Property TextColor() As
Color
Get
Return
_textColor
End
Get
Set(ByVal
Value As Color)
_textColor = Value
End
Set
End
Property
Private
_font As Font = SystemInformation.MenuFont
Public
Property Font() As
Font
Get
Return
_font
End
Get
Set(ByVal
Value As Font)
_font = Value
End
Set
End
Property
Private
_borderColor As Color = Color.Black
Public
Property BorderColor()
As Color
Get
Return
_borderColor
End
Get
Set(ByVal
Value As Color)
_borderColor = Value
End
Set
End
Property
End
Class
#End
Region
#Region
"Construction - disposal"
'when
constructed, the class creates a new ExtNativeWindow
Public
Sub New()
nw =
New ExtNativeWindow(Me)
End
Sub
'The
dispose method has to ensure that all the event handlers are removed from
'the
components that were extended.
Protected
Overloads Overrides
Sub Dispose(ByVal
disposing As Boolean)
If
(disposing) Then
Dim
c As Control
For
Each c In
items.Keys
RemoveHandler
c.MouseHover, AddressOf
Me.cMouseHover
RemoveHandler
c.MouseLeave, AddressOf
Me.cMouseLeave
Next
Me.items.Clear()
End
If
MyBase.Dispose(disposing)
End
Sub
#End
Region
#Region
"IExtenderProvider Members"
'This
component can extend control.
Public
Function CanExtend(ByVal
extendee As [Object])
As Boolean
Implements IExtenderProvider.CanExtend
If
TypeOf extendee Is
Control Then
Return
True
Else
Return
False
End
If
End
Function
'A
utility routing to extract tipData from the hash table imports the
'Control
reference as a key.
Protected
Function GetItem(ByVal
c As Control) As
tipData
If
(Me.items.Contains(c))
Then
Return
CType(items(c), tipData)
End
If
Dim
td As New
tipData
items(c) = td
AddHandler
c.MouseHover, AddressOf cMouseHover
AddHandler
c.MouseLeave, AddressOf cMouseLeave
Return
td
End
Function
'*
'*
The following ten methods implement the set and get methods for each of the
extended
'*
properties that we provide to control based classes.
'*
'*
Public
Sub SetTipText(ByVal
c As Control, ByVal
value As String)
Dim
td As tipData = GetItem(c)
td.Text
= value
End
Sub
Public
Sub SetTipColor(ByVal
c As Control, ByVal
value As Color)
Dim
td As tipData = GetItem(c)
td.TipColor = value
End
Sub
Public
Sub SetTipTextColor(ByVal
c As Control, ByVal value
As Color)
Dim
td As tipData = GetItem(c)
td.TextColor = value
End
Sub
Public Sub
SetTipFont(ByVal c As
Control, ByVal value As
Font)
Dim
td As tipData = GetItem(c)
td.Font
= value
End
Sub
Public
Sub SetTipBorderColor(ByVal
c As Control, ByVal
value As Color)
Dim
td As tipData = GetItem(c)
td.BorderColor = value
End
Sub
Public
Function GetTipText(ByVal
c As Control) As
String
Dim
td As tipData = GetItem(c)
Return
td.Text
End
Function
Public
Function GetTipColor(ByVal
c As Control) As
Color
Dim
td As tipData = GetItem(c)
Return
td.TipColor
End
Function
Public
Function GetTipTextColor(ByVal
c As Control) As Color
Dim
td As tipData = GetItem(c)
Return
td.TextColor
End
Function
Public
Function GetTipFont(ByVal
c As Control) As
Font
Dim
td As tipData = GetItem(c)
Return
td.Font
End
Function
Public
Function GetTipBorderColor(ByVal
c As Control) As
Color
Dim
td As tipData = GetItem(c)
Return
td.BorderColor
End
Function
#End
Region
#Region
"IWndProcProvider Members"
'Implements
the IWndProcProvider interface which enables any class to host an
ExtNativeWindow
'Note.
It is important to call the default WndProc for any messages not processed by me
method.
Public
Sub WndProc(ByRef
m As Message, ByVal
defWndProcProvider As ExtNativeWindow)
Implements IWndProcProvider.WndProc
Select
Case m.Msg
Case
WmDefs.WM_PAINT
PaintTooltip(m)
Case
Else
defWndProcProvider.DefWndProc(m)
End
Select
End
Sub
#End
Region
#Region
"Extended control mouse handlers"
'Handles
the MouseHover event from the control been extended.
'me
enables the extender-provider to know when the mouse cursor is in a control.
Private
Sub cMouseHover(ByVal
sender As Object,
ByVal e As
EventArgs)
currentControl = CType(sender, Control)
If
(Not killTimer Is
Nothing) Then
killTimer.Enabled = False
killTimer.Dispose()
killTimer = Nothing
nw.DestroyHandle()
End
If
ShowTip()
End
Sub
'Handles
the MouseLeave event from the control be extended.
'This
enables the extender-provider to know when the mouse cursor has left the
'control
and hence, when to destroy the tool tip window.
Private
Sub cMouseLeave(ByVal
sender As Object,
ByVal e As
EventArgs)
If
(sender Is currentControl)
Then
killTimer = New Timer
killTimer.Interval = 100
AddHandler
killTimer.Tick, AddressOf killTimerTick
killTimer.Enabled = True
End
If
End
Sub
#End
Region
#Region
"Painting"
'A
simple paint routine. This fills the window with the background color,
'paints
the border, the _text and finally validates the rectangle of the window.
Protected
Sub PaintTooltip(ByRef
m As Message)
Dim
td As tipData = Me.GetItem(Me.currentControl)
Dim
g As Graphics = Graphics.FromHwnd(nw.Handle)
g.Clear(td.TipColor)
Dim
p As New
Pen(td.BorderColor, tipRect.Height / 100)
g.DrawRectangle(p, 0, 0, tipRect.Width - 1, tipRect.Height - 1)
p.Dispose()
Dim
sb As New
SolidBrush(td.TextColor)
g.DrawString(td.Text, td.Font, sb, tipRect.Width / 10, tipRect.Height / 20,
StringFormat.GenericTypographic)
sb.Dispose()
g.Dispose()
m.Result = IntPtr.Zero
ValidateRect(m.HWnd, IntPtr.Zero)
End
Sub
#End
Region
#Region
"low-level window management"
'The
windows creation parameters.
Protected
ReadOnly Property
CreateParams() As CreateParams
Get
Dim
cp As New
System.Windows.Forms.CreateParams
cp.Style = CInt(WindowStyles.WS_POPUP)
cp.ClassStyle = CInt(ClassStyles.CS_OWNDC
Or ClassStyles.CS_HREDRAW
Or ClassStyles.CS_VREDRAW)
cp.ExStyle = CInt(WindowStyles.WS_EX_TOPMOST)
cp.ClassName = "tooltips_class32"
cp.X
= 0
cp.Y
= 0
cp.Height = 0
cp.Width = 0
cp.Parent = System.IntPtr.Zero
cp.Caption = Nothing
Return
cp
End
Get
End
Property
'This
handles the time out from the timer which is set whenever the cursor leaves a
control.
'It
destroys the tool tip window.
Private
Sub killTimerTick(ByVal
sender As Object,
ByVal e As
EventArgs)
CType(sender,
Timer).Enabled = False
nw.DestroyHandle()
End
Sub
'Called
by the mouse hover Handler to display the tool tip window.
Private
Sub ShowTip()
Dim
cp As CreateParams = Me.CreateParams
Dim
g As Graphics = Graphics.FromHwnd(IntPtr.Zero)
Dim
td As tipData = CType(items(Me.currentControl),
tipData)
Dim
sf As SizeF = g.MeasureString(td.Text, td.Font,
1024, StringFormat.GenericTypographic)
Dim
position As Point = Control.MousePosition
Dim
rc As New
Rectangle(position.X, CInt((position.Y +
SystemInformation.CursorSize.Height)), CInt(sf.Width),
CInt(sf.Height))
rc.Inflate(rc.Width / 10, rc.Height / 10)
tipRect
= rc
If
(rc.Right > SystemInformation.VirtualScreen.Right) Then
rc.Offset(-(rc.Right
- SystemInformation.VirtualScreen.Right), 0)
End
If
If
(rc.Bottom > SystemInformation.VirtualScreen.Bottom)
Then
rc.Offset(0, -((rc.Bottom - SystemInformation.VirtualScreen.Bottom) +
rc.Height + SystemInformation.CursorSize.Height))
End
If
If
(rc.Left < 10) Then
rc.X
= 10
End
If
cp.X =
rc.X
cp.Y =
rc.Y
cp.Width
= rc.Width
cp.Height
= rc.Height
nw.CreateHandle(cp)
ShowWindow(nw.Handle,
CType(WellFormed.ShowWindow.SW_SHOWNOACTIVATE,
Short))
End
Sub
#End
Region
End Class
End
Namespace