Skip to content

Commit 196149a

Browse files
committed
Update ToolTip text painting to use GDI and fix layout
1 parent dceb6bb commit 196149a

File tree

1 file changed

+131
-5
lines changed

1 file changed

+131
-5
lines changed

Source/ExcelDna.IntelliSense/ToolTipForm.cs

Lines changed: 131 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class ToolTipForm : Form
3737
// Various graphics object cached
3838
Brush _textBrush;
3939
Brush _linkBrush;
40+
Color _textColor;
41+
Color _linkColor;
4042
Pen _borderPen;
4143
Pen _borderLightPen;
4244
Dictionary<FontStyle, Font> _fonts;
@@ -60,8 +62,10 @@ public ToolTipForm(IntPtr hwndOwner)
6062

6163
};
6264
//_textBrush = new SolidBrush(Color.FromArgb(68, 68, 68)); // Best matches Excel's built-in color, but I think a bit too light
63-
_textBrush = new SolidBrush(Color.FromArgb(52, 52, 52));
64-
_linkBrush = new SolidBrush(Color.Blue);
65+
_textColor = Color.FromArgb(60, 60, 60);
66+
_linkColor = Color.Blue;
67+
_textBrush = new SolidBrush(_textColor);
68+
_linkBrush = new SolidBrush(_linkColor);
6569
_borderPen = new Pen(Color.FromArgb(195, 195, 195));
6670
_borderLightPen = new Pen(Color.FromArgb(225, 225, 225));
6771
SetStyle(ControlStyles.UserMouse | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
@@ -311,7 +315,129 @@ Point GetMouseLocation(IntPtr lParam)
311315
#endregion
312316

313317
#region Painting
318+
319+
bool oldPaint = false;
320+
314321
protected override void OnPaint(PaintEventArgs e)
322+
{
323+
//if (oldPaint)
324+
//{
325+
// OnPaint_Plus(e);
326+
// return;
327+
//}
328+
if (oldPaint)
329+
{
330+
_textBrush = Brushes.Red;
331+
_linkBrush = Brushes.Pink;
332+
OnPaint_Plus(e);
333+
}
334+
335+
base.OnPaint(e);
336+
337+
List<int> lineWidths = new List<int>();
338+
const int maxWidth = 1000; // Should depend on screen width?
339+
const int maxHeight = 500;
340+
const int leftPadding = 6;
341+
const int linePadding = 0;
342+
const int widthPadding = 12;
343+
const int heightPadding = 2;
344+
const int minLineHeight = 16;
345+
346+
int layoutLeft = ClientRectangle.Location.X + leftPadding;
347+
int layoutTop = ClientRectangle.Location.Y;
348+
349+
var textFormatFlags = TextFormatFlags.Left |
350+
TextFormatFlags.Top |
351+
TextFormatFlags.NoPadding |
352+
TextFormatFlags.SingleLine |
353+
TextFormatFlags.ExternalLeading;
354+
355+
int currentHeight = 0; // Measured from layoutTop, going down
356+
foreach (var line in _text)
357+
{
358+
currentHeight += linePadding;
359+
int lineHeight = minLineHeight;
360+
int lineWidth = 0;
361+
foreach (var run in line)
362+
{
363+
// We support only a single link, for now
364+
Font font;
365+
Brush brush;
366+
Color color;
367+
if (run.IsLink && _linkActive)
368+
{
369+
font = _fonts[FontStyle.Underline];
370+
color = _linkColor;
371+
brush = _linkBrush;
372+
}
373+
else
374+
{
375+
font = _fonts[run.Style];
376+
color = _textColor;
377+
brush = _textBrush;
378+
}
379+
380+
foreach (var text in getRunParts(run.Text)) // Might split on space too?
381+
{
382+
if (text == "") continue;
383+
384+
// How wide is this part?
385+
var proposedSize = new Size(maxWidth - lineWidth, maxHeight - currentHeight);
386+
var textSize = TextRenderer.MeasureText(e.Graphics, text, font, proposedSize, textFormatFlags);
387+
if (textSize.Width <= proposedSize.Width)
388+
{
389+
// Draw it in this line
390+
TextRenderer.DrawText(e.Graphics, text, font, new Point(layoutLeft + lineWidth, layoutTop + currentHeight), color, textFormatFlags);
391+
}
392+
else
393+
{
394+
// Make a new line and definitely draw it there (maybe with ellipses?)
395+
lineWidths.Add(lineWidth);
396+
currentHeight += lineHeight;
397+
currentHeight += linePadding;
398+
399+
lineHeight = minLineHeight;
400+
lineWidth = 2; // Little bit of indent on these lines
401+
TextRenderer.DrawText(e.Graphics, text, font, new Rectangle(layoutLeft + lineWidth, layoutTop + currentHeight, maxWidth, maxHeight - currentHeight), color, textFormatFlags |= TextFormatFlags.EndEllipsis);
402+
}
403+
404+
if (run.IsLink)
405+
{
406+
_linkClientRect = new Rectangle(layoutLeft + lineWidth, layoutTop + currentHeight, textSize.Width, textSize.Height);
407+
_linkAddress = run.LinkAddress;
408+
}
409+
410+
lineWidth += textSize.Width; // + 1;
411+
lineHeight = Math.Max(lineHeight, textSize.Height);
412+
}
413+
}
414+
lineWidths.Add(lineWidth);
415+
currentHeight += lineHeight;
416+
}
417+
418+
var width = lineWidths.Max() + widthPadding;
419+
var height = currentHeight + heightPadding;
420+
421+
UpdateLocation(width, height);
422+
DrawRoundedRectangle(e.Graphics, new RectangleF(0, 0, Width - 1, Height - 1), 2, 2);
423+
}
424+
425+
IEnumerable<string> getRunParts(string runText)
426+
{
427+
int lastStart = 0;
428+
for (int i = 0; i < runText.Length; i++)
429+
{
430+
if (runText[i] == ',')
431+
{
432+
yield return runText.Substring(lastStart, i - lastStart + 1);
433+
lastStart = i + 1;
434+
}
435+
}
436+
yield return runText.Substring(lastStart);
437+
}
438+
439+
#region This is the original text painting, based on GDI+ calls
440+
protected void OnPaint_Plus(PaintEventArgs e)
315441
{
316442
const int leftPadding = 6;
317443
const int linePadding = 0;
@@ -357,7 +483,7 @@ protected override void OnPaint(PaintEventArgs e)
357483
// TODO: Empty strings are a problem....
358484
var text = run.Text == "" ? " " : run.Text;
359485

360-
DrawString(e.Graphics, brush, ref layoutRect, out textSize, format, text, font);
486+
DrawString_Plus(e.Graphics, brush, ref layoutRect, out textSize, format, text, font);
361487

362488
if (run.IsLink)
363489
{
@@ -385,7 +511,7 @@ protected override void OnPaint(PaintEventArgs e)
385511
DrawRoundedRectangle(e.Graphics, new RectangleF(0,0, Width - 1, Height - 1), 2, 2);
386512
}
387513

388-
void DrawString(Graphics g, Brush brush, ref Rectangle rect, out Size used,
514+
void DrawString_Plus(Graphics g, Brush brush, ref Rectangle rect, out Size used,
389515
StringFormat format, string text, Font font)
390516
{
391517
using (StringFormat copy = (StringFormat)format.Clone())
@@ -408,8 +534,8 @@ void DrawString(Graphics g, Brush brush, ref Rectangle rect, out Size used,
408534
rect.Width -= width;
409535
}
410536
}
537+
#endregion
411538

412-
413539
void DrawRoundedRectangle(Graphics g, RectangleF r, float radiusX, float radiusY)
414540
{
415541
var oldMode = g.SmoothingMode;

0 commit comments

Comments
 (0)