Search code examples
.netwinformscursordrawingtooltip

Paint a tooltip placed in the Cursor.Current bottom-left point


I'm trying to paint a tooltip in the cursor bottom left. I'm using the following code to calculate de Cursor bottom point:

    private void PaintTooltip()
    {
       ...
       Point target = this.PointToClient(GetCursorPoint()));
       ...
       // paint the tooltip at point target
    }

    private Point GetCursorPoint()
    {
        return new Point(
            Cursor.Position.X,
            Cursor.Position.Y + Cursor.Current.Size.Height - Cursor.Current.HotSpot.Y);
    }

Tip: Cursor.Current.Hostpot usually has 0 value.

Using this code, I'm getting the tooptip some pixels down:

enter image description here

Why am I getting this point?


Solution

  • Because the standard size of a Cursor is 32x32 pixels, but most of the pixels are transparent so you'd have to figure out the "actual" height by inspecting the cursor itself.

    For example, I drew the default cursor to a bitmap like this:

            Bitmap bmp = new Bitmap(Cursor.Current.Size.Width, Cursor.Current.Size.Height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.Clear(Color.Red);
                Cursor.Current.Draw(g, new Rectangle(new Point(0, 0), bmp.Size));
            }
            pictureBox1.Image = bmp;
    

    So you can clearly see how big the cursor is in relation to its actual size:

    enter image description here

    EDIT: Here's an example that draws a rectangle below the current cursor position based on the "actual" size of the cursor:

        private void button1_Click(object sender, EventArgs e)
        {
            Rectangle bounds = CursorBounds();
            Point pt = new Point(Cursor.Position.X + bounds.Left, Cursor.Position.Y + bounds.Bottom);
            ControlPaint.DrawReversibleFrame(new Rectangle(pt, new Size(100, 30)), this.BackColor, FrameStyle.Dashed);
        }
    
        private Rectangle CursorBounds()
        {
            using (Bitmap bmp = new Bitmap(Cursor.Current.Size.Width, Cursor.Current.Size.Height))
            {
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.Clear(Color.Transparent);
                    Cursor.Current.Draw(g, new Rectangle(new Point(0, 0), bmp.Size));
    
                    int xMin = bmp.Width;
                    int xMax = -1;
                    int yMin = bmp.Height;
                    int yMax = -1;
    
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        for (int y = 0; y < bmp.Height; y++)
                        {
                            if (bmp.GetPixel(x, y).A > 0)
                            {
                                xMin = Math.Min(xMin, x);
                                xMax = Math.Max(xMax, x);
                                yMin = Math.Min(yMin, y);
                                yMax = Math.Max(yMax, y);
                            }
                        }
                    }
                    return new Rectangle(new Point(xMin, yMin), new Size((xMax - xMin) + 1, (yMax - yMin) + 1));
                }
            }
        }
    

    I'm really not sure if there's a better way to do this... =\