Imported existing sources

This commit is contained in:
Daniel Brunner
2017-02-04 13:47:58 +01:00
parent 14a5be61cc
commit 7c97b9e539
86 changed files with 49665 additions and 0 deletions
+459
View File
@@ -0,0 +1,459 @@
/*
* GlassPanelForm - A transparent form that is placed over an ObjectListView
* to allow flicker-free overlay images during scrolling.
*
* Author: Phillip Piper
* Date: 14/04/2009 4:36 PM
*
* Change log:
* 2010-08-18 JPP - Added WS_EX_TOOLWINDOW style so that the form won't appear in Alt-Tab list.
* v2.4
* 2010-03-11 JPP - Work correctly in MDI applications -- more or less. Actually, less than more.
* They don't crash but they don't correctly handle overlapping MDI children.
* Overlays from one control are shown on top of other other windows.
* 2010-03-09 JPP - Correctly Unbind() when the related ObjectListView is disposed.
* 2009-10-28 JPP - Use FindForm() rather than TopMostControl, since the latter doesn't work
* as I expected when the OLV is part of an MDI child window. Thanks to
* wvd_vegt who tracked this down.
* v2.3
* 2009-08-19 JPP - Only hide the glass pane on resize, not on move
* - Each glass panel now only draws one overlays
* v2.2
* 2009-06-05 JPP - Handle when owning window is a topmost window
* 2009-04-14 JPP - Initial version
*
* To do:
*
* Copyright (C) 2009-2014 Phillip Piper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace BrightIdeasSoftware
{
/// <summary>
/// A GlassPanelForm sits transparently over an ObjectListView to show overlays.
/// </summary>
internal partial class GlassPanelForm : Form
{
public GlassPanelForm() {
this.Name = "GlassPanelForm";
this.Text = "GlassPanelForm";
ClientSize = new System.Drawing.Size(0, 0);
ControlBox = false;
FormBorderStyle = FormBorderStyle.None;
SizeGripStyle = SizeGripStyle.Hide;
StartPosition = FormStartPosition.Manual;
MaximizeBox = false;
MinimizeBox = false;
ShowIcon = false;
ShowInTaskbar = false;
FormBorderStyle = FormBorderStyle.None;
SetStyle(ControlStyles.Selectable, false);
this.Opacity = 0.5f;
this.BackColor = Color.FromArgb(255, 254, 254, 254);
this.TransparencyKey = this.BackColor;
this.HideGlass();
NativeMethods.ShowWithoutActivate(this);
}
protected override void Dispose(bool disposing) {
if (disposing)
this.Unbind();
base.Dispose(disposing);
}
#region Properties
/// <summary>
/// Get the low-level windows flag that will be given to CreateWindow.
/// </summary>
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20; // WS_EX_TRANSPARENT
cp.ExStyle |= 0x80; // WS_EX_TOOLWINDOW
return cp;
}
}
#endregion
#region Commands
/// <summary>
/// Attach this form to the given ObjectListView
/// </summary>
public void Bind(ObjectListView olv, IOverlay overlay) {
if (this.objectListView != null)
this.Unbind();
this.objectListView = olv;
this.Overlay = overlay;
this.mdiClient = null;
this.mdiOwner = null;
if (this.objectListView == null)
return;
// NOTE: If you listen to any events here, you *must* stop listening in Unbind()
this.objectListView.Disposed += new EventHandler(objectListView_Disposed);
this.objectListView.LocationChanged += new EventHandler(objectListView_LocationChanged);
this.objectListView.SizeChanged += new EventHandler(objectListView_SizeChanged);
this.objectListView.VisibleChanged += new EventHandler(objectListView_VisibleChanged);
this.objectListView.ParentChanged += new EventHandler(objectListView_ParentChanged);
// Collect our ancestors in the widget hierachy
if (this.ancestors == null)
this.ancestors = new List<Control>();
Control parent = this.objectListView.Parent;
while (parent != null) {
this.ancestors.Add(parent);
parent = parent.Parent;
}
// Listen for changes in the hierachy
foreach (Control ancestor in this.ancestors) {
ancestor.ParentChanged += new EventHandler(objectListView_ParentChanged);
TabControl tabControl = ancestor as TabControl;
if (tabControl != null) {
tabControl.Selected += new TabControlEventHandler(tabControl_Selected);
}
}
// Listen for changes in our owning form
this.Owner = this.objectListView.FindForm();
this.myOwner = this.Owner;
if (this.Owner != null) {
this.Owner.LocationChanged += new EventHandler(Owner_LocationChanged);
this.Owner.SizeChanged += new EventHandler(Owner_SizeChanged);
this.Owner.ResizeBegin += new EventHandler(Owner_ResizeBegin);
this.Owner.ResizeEnd += new EventHandler(Owner_ResizeEnd);
if (this.Owner.TopMost) {
// We can't do this.TopMost = true; since that will activate the panel,
// taking focus away from the owner of the listview
NativeMethods.MakeTopMost(this);
}
// We need special code to handle MDI
this.mdiOwner = this.Owner.MdiParent;
if (this.mdiOwner != null) {
this.mdiOwner.LocationChanged += new EventHandler(Owner_LocationChanged);
this.mdiOwner.SizeChanged += new EventHandler(Owner_SizeChanged);
this.mdiOwner.ResizeBegin += new EventHandler(Owner_ResizeBegin);
this.mdiOwner.ResizeEnd += new EventHandler(Owner_ResizeEnd);
// Find the MDIClient control, which houses all MDI children
foreach (Control c in this.mdiOwner.Controls) {
this.mdiClient = c as MdiClient;
if (this.mdiClient != null) {
break;
}
}
if (this.mdiClient != null) {
this.mdiClient.ClientSizeChanged += new EventHandler(myMdiClient_ClientSizeChanged);
}
}
}
this.UpdateTransparency();
}
void myMdiClient_ClientSizeChanged(object sender, EventArgs e) {
this.RecalculateBounds();
this.Invalidate();
}
/// <summary>
/// Made the overlay panel invisible
/// </summary>
public void HideGlass() {
if (!this.isGlassShown)
return;
this.isGlassShown = false;
this.Bounds = new Rectangle(-10000, -10000, 1, 1);
}
/// <summary>
/// Show the overlay panel in its correctly location
/// </summary>
/// <remarks>
/// If the panel is always shown, this method does nothing.
/// If the panel is being resized, this method also does nothing.
/// </remarks>
public void ShowGlass() {
if (this.isGlassShown || this.isDuringResizeSequence)
return;
this.isGlassShown = true;
this.RecalculateBounds();
}
/// <summary>
/// Detach this glass panel from its previous ObjectListView
/// </summary>
/// <remarks>
/// You should unbind the overlay panel before making any changes to the
/// widget hierarchy.
/// </remarks>
public void Unbind() {
if (this.objectListView != null) {
this.objectListView.Disposed -= new EventHandler(objectListView_Disposed);
this.objectListView.LocationChanged -= new EventHandler(objectListView_LocationChanged);
this.objectListView.SizeChanged -= new EventHandler(objectListView_SizeChanged);
this.objectListView.VisibleChanged -= new EventHandler(objectListView_VisibleChanged);
this.objectListView.ParentChanged -= new EventHandler(objectListView_ParentChanged);
this.objectListView = null;
}
if (this.ancestors != null) {
foreach (Control parent in this.ancestors) {
parent.ParentChanged -= new EventHandler(objectListView_ParentChanged);
TabControl tabControl = parent as TabControl;
if (tabControl != null) {
tabControl.Selected -= new TabControlEventHandler(tabControl_Selected);
}
}
this.ancestors = null;
}
if (this.myOwner != null) {
this.myOwner.LocationChanged -= new EventHandler(Owner_LocationChanged);
this.myOwner.SizeChanged -= new EventHandler(Owner_SizeChanged);
this.myOwner.ResizeBegin -= new EventHandler(Owner_ResizeBegin);
this.myOwner.ResizeEnd -= new EventHandler(Owner_ResizeEnd);
this.myOwner = null;
}
if (this.mdiOwner != null) {
this.mdiOwner.LocationChanged -= new EventHandler(Owner_LocationChanged);
this.mdiOwner.SizeChanged -= new EventHandler(Owner_SizeChanged);
this.mdiOwner.ResizeBegin -= new EventHandler(Owner_ResizeBegin);
this.mdiOwner.ResizeEnd -= new EventHandler(Owner_ResizeEnd);
this.mdiOwner = null;
}
if (this.mdiClient != null) {
this.mdiClient.ClientSizeChanged -= new EventHandler(myMdiClient_ClientSizeChanged);
this.mdiClient = null;
}
}
#endregion
#region Event Handlers
void objectListView_Disposed(object sender, EventArgs e) {
this.Unbind();
}
/// <summary>
/// Handle when the form that owns the ObjectListView begins to be resized
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Owner_ResizeBegin(object sender, EventArgs e) {
// When the top level window is being resized, we just want to hide
// the overlay window. When the resizing finishes, we want to show
// the overlay window, if it was shown before the resize started.
this.isDuringResizeSequence = true;
this.wasGlassShownBeforeResize = this.isGlassShown;
}
/// <summary>
/// Handle when the form that owns the ObjectListView finished to be resized
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Owner_ResizeEnd(object sender, EventArgs e) {
this.isDuringResizeSequence = false;
if (this.wasGlassShownBeforeResize)
this.ShowGlass();
}
/// <summary>
/// The owning form has moved. Move the overlay panel too.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Owner_LocationChanged(object sender, EventArgs e) {
if (this.mdiOwner != null)
this.HideGlass();
else
this.RecalculateBounds();
}
/// <summary>
/// The owning form is resizing. Hide our overlay panel until the resizing stops
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Owner_SizeChanged(object sender, EventArgs e) {
this.HideGlass();
}
/// <summary>
/// Handle when the bound OLV changes its location. The overlay panel must
/// be moved too, IFF it is currently visible.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void objectListView_LocationChanged(object sender, EventArgs e) {
if (this.isGlassShown) {
this.RecalculateBounds();
}
}
/// <summary>
/// Handle when the bound OLV changes size. The overlay panel must
/// resize too, IFF it is currently visible.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void objectListView_SizeChanged(object sender, EventArgs e) {
// This event is triggered in all sorts of places, and not always when the size changes.
//if (this.isGlassShown) {
// this.Size = this.objectListView.ClientSize;
//}
}
/// <summary>
/// Handle when the bound OLV is part of a TabControl and that
/// TabControl changes tabs. The overlay panel is hidden. The
/// first time the bound OLV is redrawn, the overlay panel will
/// be shown again.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void tabControl_Selected(object sender, TabControlEventArgs e) {
this.HideGlass();
}
/// <summary>
/// Somewhere the parent of the bound OLV has changed. Update
/// our events.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void objectListView_ParentChanged(object sender, EventArgs e) {
ObjectListView olv = this.objectListView;
IOverlay overlay = this.Overlay;
this.Unbind();
this.Bind(olv, overlay);
}
/// <summary>
/// Handle when the bound OLV changes its visibility.
/// The overlay panel should match the OLV's visibility.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void objectListView_VisibleChanged(object sender, EventArgs e) {
if (this.objectListView.Visible)
this.ShowGlass();
else
this.HideGlass();
}
#endregion
#region Implementation
protected override void OnPaint(PaintEventArgs e) {
if (this.objectListView == null || this.Overlay == null)
return;
Graphics g = e.Graphics;
g.TextRenderingHint = ObjectListView.TextRenderingHint;
g.SmoothingMode = ObjectListView.SmoothingMode;
//g.DrawRectangle(new Pen(Color.Green, 4.0f), this.ClientRectangle);
// If we are part of an MDI app, make sure we don't draw outside the bounds
if (this.mdiClient != null) {
Rectangle r = mdiClient.RectangleToScreen(mdiClient.ClientRectangle);
Rectangle r2 = this.objectListView.RectangleToClient(r);
g.SetClip(r2, System.Drawing.Drawing2D.CombineMode.Intersect);
}
this.Overlay.Draw(this.objectListView, g, this.objectListView.ClientRectangle);
}
protected void RecalculateBounds() {
if (!this.isGlassShown)
return;
Rectangle rect = this.objectListView.ClientRectangle;
rect.X = 0;
rect.Y = 0;
this.Bounds = this.objectListView.RectangleToScreen(rect);
}
internal void UpdateTransparency() {
ITransparentOverlay transparentOverlay = this.Overlay as ITransparentOverlay;
if (transparentOverlay == null)
this.Opacity = this.objectListView.OverlayTransparency / 255.0f;
else
this.Opacity = transparentOverlay.Transparency / 255.0f;
}
protected override void WndProc(ref Message m) {
const int WM_NCHITTEST = 132;
const int HTTRANSPARENT = -1;
switch (m.Msg) {
// Ignore all mouse interactions
case WM_NCHITTEST:
m.Result = (IntPtr)HTTRANSPARENT;
break;
}
base.WndProc(ref m);
}
#endregion
#region Implementation variables
internal IOverlay Overlay;
#endregion
#region Private variables
private ObjectListView objectListView;
private bool isDuringResizeSequence;
private bool isGlassShown;
private bool wasGlassShownBeforeResize;
// Cache these so we can unsubscribe from events even when the OLV has been disposed.
private Form myOwner;
private Form mdiOwner;
private List<Control> ancestors;
MdiClient mdiClient;
#endregion
}
}
File diff suppressed because it is too large Load Diff
+189
View File
@@ -0,0 +1,189 @@
/*
* ToolStripCheckedListBox - Puts a CheckedListBox into a tool strip menu item
*
* Author: Phillip Piper
* Date: 4-March-2011 11:59 pm
*
* Change log:
* 2011-03-04 JPP - First version
*
* Copyright (C) 2011-2014 Phillip Piper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace BrightIdeasSoftware {
/// <summary>
/// Instances of this class put a CheckedListBox into a tool strip menu item.
/// </summary>
public class ToolStripCheckedListBox : ToolStripControlHost {
/// <summary>
/// Create a ToolStripCheckedListBox
/// </summary>
public ToolStripCheckedListBox()
: base(new CheckedListBox()) {
this.CheckedListBoxControl.MaximumSize = new Size(400, 700);
this.CheckedListBoxControl.ThreeDCheckBoxes = true;
this.CheckedListBoxControl.CheckOnClick = true;
this.CheckedListBoxControl.SelectionMode = SelectionMode.One;
}
/// <summary>
/// Gets the control embedded in the menu
/// </summary>
public CheckedListBox CheckedListBoxControl {
get {
return Control as CheckedListBox;
}
}
/// <summary>
/// Gets the items shown in the checkedlistbox
/// </summary>
public CheckedListBox.ObjectCollection Items {
get {
return this.CheckedListBoxControl.Items;
}
}
/// <summary>
/// Gets or sets whether an item should be checked when it is clicked
/// </summary>
public bool CheckedOnClick {
get {
return this.CheckedListBoxControl.CheckOnClick;
}
set {
this.CheckedListBoxControl.CheckOnClick = value;
}
}
/// <summary>
/// Gets a collection of the checked items
/// </summary>
public CheckedListBox.CheckedItemCollection CheckedItems {
get {
return this.CheckedListBoxControl.CheckedItems;
}
}
/// <summary>
/// Add a possibly checked item to the control
/// </summary>
/// <param name="item"></param>
/// <param name="isChecked"></param>
public void AddItem(object item, bool isChecked) {
this.Items.Add(item);
if (isChecked)
this.CheckedListBoxControl.SetItemChecked(this.Items.Count - 1, true);
}
/// <summary>
/// Add an item with the given state to the control
/// </summary>
/// <param name="item"></param>
/// <param name="state"></param>
public void AddItem(object item, CheckState state) {
this.Items.Add(item);
this.CheckedListBoxControl.SetItemCheckState(this.Items.Count - 1, state);
}
/// <summary>
/// Gets the checkedness of the i'th item
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public CheckState GetItemCheckState(int i) {
return this.CheckedListBoxControl.GetItemCheckState(i);
}
/// <summary>
/// Set the checkedness of the i'th item
/// </summary>
/// <param name="i"></param>
/// <param name="checkState"></param>
public void SetItemState(int i, CheckState checkState) {
if (i >= 0 && i < this.Items.Count)
this.CheckedListBoxControl.SetItemCheckState(i, checkState);
}
/// <summary>
/// Check all the items in the control
/// </summary>
public void CheckAll() {
for (int i = 0; i < this.Items.Count; i++)
this.CheckedListBoxControl.SetItemChecked(i, true);
}
/// <summary>
/// Unchecked all the items in the control
/// </summary>
public void UncheckAll() {
for (int i = 0; i < this.Items.Count; i++)
this.CheckedListBoxControl.SetItemChecked(i, false);
}
#region Events
/// <summary>
/// Listen for events on the underlying control
/// </summary>
/// <param name="c"></param>
protected override void OnSubscribeControlEvents(Control c) {
base.OnSubscribeControlEvents(c);
CheckedListBox control = (CheckedListBox)c;
control.ItemCheck += new ItemCheckEventHandler(OnItemCheck);
}
/// <summary>
/// Stop listening for events on the underlying control
/// </summary>
/// <param name="c"></param>
protected override void OnUnsubscribeControlEvents(Control c) {
base.OnUnsubscribeControlEvents(c);
CheckedListBox control = (CheckedListBox)c;
control.ItemCheck -= new ItemCheckEventHandler(OnItemCheck);
}
/// <summary>
/// Tell the world that an item was checked
/// </summary>
public event ItemCheckEventHandler ItemCheck;
/// <summary>
/// Trigger the ItemCheck event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnItemCheck(object sender, ItemCheckEventArgs e) {
if (ItemCheck != null) {
ItemCheck(this, e);
}
}
#endregion
}
}
+699
View File
@@ -0,0 +1,699 @@
/*
* ToolTipControl - A limited wrapper around a Windows tooltip control
*
* For some reason, the ToolTip class in the .NET framework is implemented in a significantly
* different manner to other controls. For our purposes, the worst of these problems
* is that we cannot get the Handle, so we cannot send Windows level messages to the control.
*
* Author: Phillip Piper
* Date: 2009-05-17 7:22PM
*
* Change log:
* v2.3
* 2009-06-13 JPP - Moved ToolTipShowingEventArgs to Events.cs
* v2.2
* 2009-06-06 JPP - Fixed some Vista specific problems
* 2009-05-17 JPP - Initial version
*
* TO DO:
*
* Copyright (C) 2006-2014 Phillip Piper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
*/
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Security.Permissions;
namespace BrightIdeasSoftware
{
/// <summary>
/// A limited wrapper around a Windows tooltip window.
/// </summary>
public class ToolTipControl : NativeWindow
{
#region Constants
/// <summary>
/// These are the standard icons that a tooltip can display.
/// </summary>
public enum StandardIcons
{
/// <summary>
/// No icon
/// </summary>
None = 0,
/// <summary>
/// Info
/// </summary>
Info = 1,
/// <summary>
/// Warning
/// </summary>
Warning = 2,
/// <summary>
/// Error
/// </summary>
Error = 3,
/// <summary>
/// Large info (Vista and later only)
/// </summary>
InfoLarge = 4,
/// <summary>
/// Large warning (Vista and later only)
/// </summary>
WarningLarge = 5,
/// <summary>
/// Large error (Vista and later only)
/// </summary>
ErrorLarge = 6
}
const int GWL_STYLE = -16;
const int WM_GETFONT = 0x31;
const int WM_SETFONT = 0x30;
const int WS_BORDER = 0x800000;
const int WS_EX_TOPMOST = 8;
const int TTM_ADDTOOL = 0x432;
const int TTM_ADJUSTRECT = 0x400 + 31;
const int TTM_DELTOOL = 0x433;
const int TTM_GETBUBBLESIZE = 0x400 + 30;
const int TTM_GETCURRENTTOOL = 0x400 + 59;
const int TTM_GETTIPBKCOLOR = 0x400 + 22;
const int TTM_GETTIPTEXTCOLOR = 0x400 + 23;
const int TTM_GETDELAYTIME = 0x400 + 21;
const int TTM_NEWTOOLRECT = 0x400 + 52;
const int TTM_POP = 0x41c;
const int TTM_SETDELAYTIME = 0x400 + 3;
const int TTM_SETMAXTIPWIDTH = 0x400 + 24;
const int TTM_SETTIPBKCOLOR = 0x400 + 19;
const int TTM_SETTIPTEXTCOLOR = 0x400 + 20;
const int TTM_SETTITLE = 0x400 + 33;
const int TTM_SETTOOLINFO = 0x400 + 54;
const int TTF_IDISHWND = 1;
//const int TTF_ABSOLUTE = 0x80;
const int TTF_CENTERTIP = 2;
const int TTF_RTLREADING = 4;
const int TTF_SUBCLASS = 0x10;
//const int TTF_TRACK = 0x20;
//const int TTF_TRANSPARENT = 0x100;
const int TTF_PARSELINKS = 0x1000;
const int TTS_NOPREFIX = 2;
const int TTS_BALLOON = 0x40;
const int TTS_USEVISUALSTYLE = 0x100;
const int TTN_FIRST = -520;
/// <summary>
///
/// </summary>
public const int TTN_SHOW = (TTN_FIRST - 1);
/// <summary>
///
/// </summary>
public const int TTN_POP = (TTN_FIRST - 2);
/// <summary>
///
/// </summary>
public const int TTN_LINKCLICK = (TTN_FIRST - 3);
/// <summary>
///
/// </summary>
public const int TTN_GETDISPINFO = (TTN_FIRST - 10);
const int TTDT_AUTOMATIC = 0;
const int TTDT_RESHOW = 1;
const int TTDT_AUTOPOP = 2;
const int TTDT_INITIAL = 3;
#endregion
#region Properties
/// <summary>
/// Get or set if the style of the tooltip control
/// </summary>
internal int WindowStyle {
get {
return (int)NativeMethods.GetWindowLong(this.Handle, GWL_STYLE);
}
set {
NativeMethods.SetWindowLong(this.Handle, GWL_STYLE, value);
}
}
/// <summary>
/// Get or set if the tooltip should be shown as a ballon
/// </summary>
public bool IsBalloon {
get {
return (this.WindowStyle & TTS_BALLOON) == TTS_BALLOON;
}
set {
if (this.IsBalloon == value)
return;
int windowStyle = this.WindowStyle;
if (value) {
windowStyle |= (TTS_BALLOON | TTS_USEVISUALSTYLE);
// On XP, a border makes the ballon look wrong
if (!ObjectListView.IsVistaOrLater)
windowStyle &= ~WS_BORDER;
} else {
windowStyle &= ~(TTS_BALLOON | TTS_USEVISUALSTYLE);
if (!ObjectListView.IsVistaOrLater) {
if (this.hasBorder)
windowStyle |= WS_BORDER;
else
windowStyle &= ~WS_BORDER;
}
}
this.WindowStyle = windowStyle;
}
}
/// <summary>
/// Get or set if the tooltip should be shown as a ballon
/// </summary>
public bool HasBorder {
get {
return this.hasBorder;
}
set {
if (this.hasBorder == value)
return;
if (value) {
this.WindowStyle |= WS_BORDER;
} else {
this.WindowStyle &= ~WS_BORDER;
}
}
}
private bool hasBorder = true;
/// <summary>
/// Get or set the background color of the tooltip
/// </summary>
public Color BackColor {
get {
int color = (int)NativeMethods.SendMessage(this.Handle, TTM_GETTIPBKCOLOR, 0, 0);
return ColorTranslator.FromWin32(color);
}
set {
// For some reason, setting the color fails on Vista and messes up later ops.
// So we don't even try to set it.
if (!ObjectListView.IsVistaOrLater) {
int color = ColorTranslator.ToWin32(value);
NativeMethods.SendMessage(this.Handle, TTM_SETTIPBKCOLOR, color, 0);
//int x2 = Marshal.GetLastWin32Error();
}
}
}
/// <summary>
/// Get or set the color of the text and border on the tooltip.
/// </summary>
public Color ForeColor {
get {
int color = (int)NativeMethods.SendMessage(this.Handle, TTM_GETTIPTEXTCOLOR, 0, 0);
return ColorTranslator.FromWin32(color);
}
set {
// For some reason, setting the color fails on Vista and messes up later ops.
// So we don't even try to set it.
if (!ObjectListView.IsVistaOrLater) {
int color = ColorTranslator.ToWin32(value);
NativeMethods.SendMessage(this.Handle, TTM_SETTIPTEXTCOLOR, color, 0);
}
}
}
/// <summary>
/// Get or set the title that will be shown on the tooltip.
/// </summary>
public string Title {
get {
return this.title;
}
set {
if (String.IsNullOrEmpty(value))
this.title = String.Empty;
else
if (value.Length >= 100)
this.title = value.Substring(0, 99);
else
this.title = value;
NativeMethods.SendMessageString(this.Handle, TTM_SETTITLE, (int)this.standardIcon, this.title);
}
}
private string title;
/// <summary>
/// Get or set the icon that will be shown on the tooltip.
/// </summary>
public StandardIcons StandardIcon {
get {
return this.standardIcon;
}
set {
this.standardIcon = value;
NativeMethods.SendMessageString(this.Handle, TTM_SETTITLE, (int)this.standardIcon, this.title);
}
}
private StandardIcons standardIcon;
/// <summary>
/// Gets or sets the font that will be used to draw this control.
/// is still.
/// </summary>
/// <remarks>Setting this to null reverts to the default font.</remarks>
public Font Font {
get {
IntPtr hfont = NativeMethods.SendMessage(this.Handle, WM_GETFONT, 0, 0);
if (hfont == IntPtr.Zero)
return Control.DefaultFont;
else
return Font.FromHfont(hfont);
}
set {
Font newFont = value ?? Control.DefaultFont;
if (newFont == this.font)
return;
this.font = newFont;
IntPtr hfont = this.font.ToHfont(); // THINK: When should we delete this hfont?
NativeMethods.SendMessage(this.Handle, WM_SETFONT, hfont, 0);
}
}
private Font font;
/// <summary>
/// Gets or sets how many milliseconds the tooltip will remain visible while the mouse
/// is still.
/// </summary>
public int AutoPopDelay {
get { return this.GetDelayTime(TTDT_AUTOPOP); }
set { this.SetDelayTime(TTDT_AUTOPOP, value); }
}
/// <summary>
/// Gets or sets how many milliseconds the mouse must be still before the tooltip is shown.
/// </summary>
public int InitialDelay {
get { return this.GetDelayTime(TTDT_INITIAL); }
set { this.SetDelayTime(TTDT_INITIAL, value); }
}
/// <summary>
/// Gets or sets how many milliseconds the mouse must be still before the tooltip is shown again.
/// </summary>
public int ReshowDelay {
get { return this.GetDelayTime(TTDT_RESHOW); }
set { this.SetDelayTime(TTDT_RESHOW, value); }
}
private int GetDelayTime(int which) {
return (int)NativeMethods.SendMessage(this.Handle, TTM_GETDELAYTIME, which, 0);
}
private void SetDelayTime(int which, int value) {
NativeMethods.SendMessage(this.Handle, TTM_SETDELAYTIME, which, value);
}
#endregion
#region Commands
/// <summary>
/// Create the underlying control.
/// </summary>
/// <param name="parentHandle">The parent of the tooltip</param>
/// <remarks>This does nothing if the control has already been created</remarks>
public void Create(IntPtr parentHandle) {
if (this.Handle != IntPtr.Zero)
return;
CreateParams cp = new CreateParams();
cp.ClassName = "tooltips_class32";
cp.Style = TTS_NOPREFIX;
cp.ExStyle = WS_EX_TOPMOST;
cp.Parent = parentHandle;
this.CreateHandle(cp);
// Ensure that multiline tooltips work correctly
this.SetMaxWidth();
}
/// <summary>
/// Take a copy of the current settings and restore them when the
/// tooltip is poppped.
/// </summary>
/// <remarks>
/// This call cannot be nested. Subsequent calls to this method will be ignored
/// until PopSettings() is called.
/// </remarks>
public void PushSettings() {
// Ignore any nested calls
if (this.settings != null)
return;
this.settings = new Hashtable();
this.settings["IsBalloon"] = this.IsBalloon;
this.settings["HasBorder"] = this.HasBorder;
this.settings["BackColor"] = this.BackColor;
this.settings["ForeColor"] = this.ForeColor;
this.settings["Title"] = this.Title;
this.settings["StandardIcon"] = this.StandardIcon;
this.settings["AutoPopDelay"] = this.AutoPopDelay;
this.settings["InitialDelay"] = this.InitialDelay;
this.settings["ReshowDelay"] = this.ReshowDelay;
this.settings["Font"] = this.Font;
}
private Hashtable settings;
/// <summary>
/// Restore the settings of the tooltip as they were when PushSettings()
/// was last called.
/// </summary>
public void PopSettings() {
if (this.settings == null)
return;
this.IsBalloon = (bool)this.settings["IsBalloon"];
this.HasBorder = (bool)this.settings["HasBorder"];
this.BackColor = (Color)this.settings["BackColor"];
this.ForeColor = (Color)this.settings["ForeColor"];
this.Title = (string)this.settings["Title"];
this.StandardIcon = (StandardIcons)this.settings["StandardIcon"];
this.AutoPopDelay = (int)this.settings["AutoPopDelay"];
this.InitialDelay = (int)this.settings["InitialDelay"];
this.ReshowDelay = (int)this.settings["ReshowDelay"];
this.Font = (Font)this.settings["Font"];
this.settings = null;
}
/// <summary>
/// Add the given window to those for whom this tooltip will show tips
/// </summary>
/// <param name="window">The window</param>
public void AddTool(IWin32Window window) {
NativeMethods.TOOLINFO lParam = this.MakeToolInfoStruct(window);
NativeMethods.SendMessageTOOLINFO(this.Handle, TTM_ADDTOOL, 0, lParam);
}
/// <summary>
/// Hide any currently visible tooltip
/// </summary>
/// <param name="window"></param>
public void PopToolTip(IWin32Window window) {
NativeMethods.SendMessage(this.Handle, TTM_POP, 0, 0);
}
//public void Munge() {
// NativeMethods.TOOLINFO tool = new NativeMethods.TOOLINFO();
// IntPtr result = NativeMethods.SendMessageTOOLINFO(this.Handle, TTM_GETCURRENTTOOL, 0, tool);
// System.Diagnostics.Trace.WriteLine("-");
// System.Diagnostics.Trace.WriteLine(result);
// result = NativeMethods.SendMessageTOOLINFO(this.Handle, TTM_GETBUBBLESIZE, 0, tool);
// System.Diagnostics.Trace.WriteLine(String.Format("{0} {1}", result.ToInt32() >> 16, result.ToInt32() & 0xFFFF));
// NativeMethods.ChangeSize(this, result.ToInt32() & 0xFFFF, result.ToInt32() >> 16);
// //NativeMethods.RECT r = new NativeMethods.RECT();
// //r.right
// //IntPtr x = NativeMethods.SendMessageRECT(this.Handle, TTM_ADJUSTRECT, true, ref r);
// //System.Diagnostics.Trace.WriteLine(String.Format("{0} {1} {2} {3}", r.left, r.top, r.right, r.bottom));
//}
/// <summary>
/// Remove the given window from those managed by this tooltip
/// </summary>
/// <param name="window"></param>
public void RemoveToolTip(IWin32Window window) {
NativeMethods.TOOLINFO lParam = this.MakeToolInfoStruct(window);
NativeMethods.SendMessageTOOLINFO(this.Handle, TTM_DELTOOL, 0, lParam);
}
/// <summary>
/// Set the maximum width of a tooltip string.
/// </summary>
public void SetMaxWidth() {
this.SetMaxWidth(SystemInformation.MaxWindowTrackSize.Width);
}
/// <summary>
/// Set the maximum width of a tooltip string.
/// </summary>
/// <remarks>Setting this ensures that line breaks in the tooltip are honoured.</remarks>
public void SetMaxWidth(int maxWidth) {
NativeMethods.SendMessage(this.Handle, TTM_SETMAXTIPWIDTH, 0, maxWidth);
}
#endregion
#region Implementation
/// <summary>
/// Make a TOOLINFO structure for the given window
/// </summary>
/// <param name="window"></param>
/// <returns>A filled in TOOLINFO</returns>
private NativeMethods.TOOLINFO MakeToolInfoStruct(IWin32Window window) {
NativeMethods.TOOLINFO toolinfo_tooltip = new NativeMethods.TOOLINFO();
toolinfo_tooltip.hwnd = window.Handle;
toolinfo_tooltip.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolinfo_tooltip.uId = window.Handle;
toolinfo_tooltip.lpszText = (IntPtr)(-1); // LPSTR_TEXTCALLBACK
return toolinfo_tooltip;
}
/// <summary>
/// Handle a WmNotify message
/// </summary>
/// <param name="msg">The msg</param>
/// <returns>True if the message has been handled</returns>
protected virtual bool HandleNotify(ref Message msg) {
//THINK: What do we have to do here? Nothing it seems :)
//NativeMethods.NMHEADER nmheader = (NativeMethods.NMHEADER)msg.GetLParam(typeof(NativeMethods.NMHEADER));
//System.Diagnostics.Trace.WriteLine("HandleNotify");
//System.Diagnostics.Trace.WriteLine(nmheader.nhdr.code);
//switch (nmheader.nhdr.code) {
//}
return false;
}
/// <summary>
/// Handle a get display info message
/// </summary>
/// <param name="msg">The msg</param>
/// <returns>True if the message has been handled</returns>
public virtual bool HandleGetDispInfo(ref Message msg) {
//System.Diagnostics.Trace.WriteLine("HandleGetDispInfo");
this.SetMaxWidth();
ToolTipShowingEventArgs args = new ToolTipShowingEventArgs();
args.ToolTipControl = this;
this.OnShowing(args);
if (String.IsNullOrEmpty(args.Text))
return false;
this.ApplyEventFormatting(args);
NativeMethods.NMTTDISPINFO dispInfo = (NativeMethods.NMTTDISPINFO)msg.GetLParam(typeof(NativeMethods.NMTTDISPINFO));
dispInfo.lpszText = args.Text;
dispInfo.hinst = IntPtr.Zero;
if (args.RightToLeft == RightToLeft.Yes)
dispInfo.uFlags |= TTF_RTLREADING;
Marshal.StructureToPtr(dispInfo, msg.LParam, false);
return true;
}
private void ApplyEventFormatting(ToolTipShowingEventArgs args) {
if (!args.IsBalloon.HasValue &&
!args.BackColor.HasValue &&
!args.ForeColor.HasValue &&
args.Title == null &&
!args.StandardIcon.HasValue &&
!args.AutoPopDelay.HasValue &&
args.Font == null)
return;
this.PushSettings();
if (args.IsBalloon.HasValue)
this.IsBalloon = args.IsBalloon.Value;
if (args.BackColor.HasValue)
this.BackColor = args.BackColor.Value;
if (args.ForeColor.HasValue)
this.ForeColor = args.ForeColor.Value;
if (args.StandardIcon.HasValue)
this.StandardIcon = args.StandardIcon.Value;
if (args.AutoPopDelay.HasValue)
this.AutoPopDelay = args.AutoPopDelay.Value;
if (args.Font != null)
this.Font = args.Font;
if (args.Title != null)
this.Title = args.Title;
}
/// <summary>
/// Handle a TTN_LINKCLICK message
/// </summary>
/// <param name="msg">The msg</param>
/// <returns>True if the message has been handled</returns>
/// <remarks>This cannot call base.WndProc() since the msg may have come from another control.</remarks>
public virtual bool HandleLinkClick(ref Message msg) {
//System.Diagnostics.Trace.WriteLine("HandleLinkClick");
return false;
}
/// <summary>
/// Handle a TTN_POP message
/// </summary>
/// <param name="msg">The msg</param>
/// <returns>True if the message has been handled</returns>
/// <remarks>This cannot call base.WndProc() since the msg may have come from another control.</remarks>
public virtual bool HandlePop(ref Message msg) {
//System.Diagnostics.Trace.WriteLine("HandlePop");
this.PopSettings();
return true;
}
/// <summary>
/// Handle a TTN_SHOW message
/// </summary>
/// <param name="msg">The msg</param>
/// <returns>True if the message has been handled</returns>
/// <remarks>This cannot call base.WndProc() since the msg may have come from another control.</remarks>
public virtual bool HandleShow(ref Message msg) {
//System.Diagnostics.Trace.WriteLine("HandleShow");
return false;
}
/// <summary>
/// Handle a reflected notify message
/// </summary>
/// <param name="msg">The msg</param>
/// <returns>True if the message has been handled</returns>
protected virtual bool HandleReflectNotify(ref Message msg) {
NativeMethods.NMHEADER nmheader = (NativeMethods.NMHEADER)msg.GetLParam(typeof(NativeMethods.NMHEADER));
switch (nmheader.nhdr.code) {
case TTN_SHOW:
//System.Diagnostics.Trace.WriteLine("reflect TTN_SHOW");
if (this.HandleShow(ref msg))
return true;
break;
case TTN_POP:
//System.Diagnostics.Trace.WriteLine("reflect TTN_POP");
if (this.HandlePop(ref msg))
return true;
break;
case TTN_LINKCLICK:
//System.Diagnostics.Trace.WriteLine("reflect TTN_LINKCLICK");
if (this.HandleLinkClick(ref msg))
return true;
break;
case TTN_GETDISPINFO:
//System.Diagnostics.Trace.WriteLine("reflect TTN_GETDISPINFO");
if (this.HandleGetDispInfo(ref msg))
return true;
break;
}
return false;
}
/// <summary>
/// Mess with the basic message pump of the tooltip
/// </summary>
/// <param name="msg"></param>
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
override protected void WndProc(ref Message msg) {
//System.Diagnostics.Trace.WriteLine(String.Format("xx {0:x}", msg.Msg));
switch (msg.Msg) {
case 0x4E: // WM_NOTIFY
if (!this.HandleNotify(ref msg))
return;
break;
case 0x204E: // WM_REFLECT_NOTIFY
if (!this.HandleReflectNotify(ref msg))
return;
break;
}
base.WndProc(ref msg);
}
#endregion
#region Events
/// <summary>
/// Tell the world that a tooltip is about to show
/// </summary>
public event EventHandler<ToolTipShowingEventArgs> Showing;
/// <summary>
/// Tell the world that a tooltip is about to disappear
/// </summary>
public event EventHandler<EventArgs> Pop;
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected virtual void OnShowing(ToolTipShowingEventArgs e) {
if (this.Showing != null)
this.Showing(this, e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected virtual void OnPop(EventArgs e) {
if (this.Pop != null)
this.Pop(this, e);
}
#endregion
}
}