Skip to content

Commit e11a9ba

Browse files
committed
Improve ToolTip postion tracking
1 parent 88785fd commit e11a9ba

File tree

4 files changed

+62
-66
lines changed

4 files changed

+62
-66
lines changed

Source/ExcelDna.IntelliSense/IntelliSenseDisplay.cs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ void StateUpdate(object sender, UIStateUpdate update)
164164
var fetc = (UIState.FormulaEdit)update.NewState;
165165
FormulaEditTextChange(fetc.FormulaPrefix, fetc.EditWindowBounds, fetc.ExcelToolTipWindow);
166166
break;
167+
case UIStateUpdate.UpdateType.FormulaEditExcelToolTipChange:
168+
var fett = (UIState.FormulaEdit)update.NewState;
169+
FormulaEditExcelToolTipShow(fett.EditWindowBounds, fett.ExcelToolTipWindow);
170+
break;
167171
case UIStateUpdate.UpdateType.FunctionListShow:
168172
var fls = (UIState.FunctionList)update.NewState;
169173
// TODO: TEMP
@@ -185,10 +189,7 @@ void StateUpdate(object sender, UIStateUpdate update)
185189
case UIStateUpdate.UpdateType.FormulaEditEnd:
186190
FormulaEditEnd();
187191
break;
188-
case UIStateUpdate.UpdateType.FormulaEditExcelToolTipChange:
189-
//var fett = (UIState.FormulaEdit)update.NewState;
190-
//FormulaEditExcelToolTipShow(fett.ExcelToolTipWindow);
191-
break;
192+
192193
case UIStateUpdate.UpdateType.SelectDataSourceShow:
193194
case UIStateUpdate.UpdateType.SelectDataSourceWindowChange:
194195
case UIStateUpdate.UpdateType.SelectDataSourceHide:
@@ -277,7 +278,8 @@ void FormulaEditMove(Rect editWindowBounds, IntPtr excelToolTipWindow)
277278
Logger.Display.Warn("FormulaEditMode Unexpected null Arguments ToolTip!?");
278279
return;
279280
}
280-
_argumentsToolTip.MoveToolTip((int)editWindowBounds.Left, (int)editWindowBounds.Bottom + 5, null);
281+
int topOffset = GetTopOffset(excelToolTipWindow);
282+
_argumentsToolTip.MoveToolTip((int)editWindowBounds.Left, (int)editWindowBounds.Bottom + 5, topOffset);
281283
}
282284

283285
// Runs on the main thread
@@ -305,17 +307,9 @@ void FormulaEditTextChange(string formulaPrefix, Rect editWindowBounds, IntPtr e
305307
// Win32Helper.HideWindow(excelToolTipWindow);
306308
// }
307309
//}
308-
309-
// For now we try to keep out of its way...
310-
int moveDown = 0;
311-
if (excelToolTipWindow != IntPtr.Zero)
312-
{
313-
// TODO: Maybe get its height...?
314-
moveDown = 18;
315-
}
316-
310+
int topOffset = GetTopOffset(excelToolTipWindow);
317311
var infoText = GetFunctionIntelliSense(functionInfo, currentArgIndex);
318-
_argumentsToolTip.ShowToolTip(infoText, (int)editWindowBounds.Left, (int)editWindowBounds.Bottom + 5 + moveDown, null);
312+
_argumentsToolTip.ShowToolTip(infoText, (int)editWindowBounds.Left, (int)editWindowBounds.Bottom + 5, topOffset);
319313
}
320314
else
321315
{
@@ -335,15 +329,29 @@ void FormulaEditTextChange(string formulaPrefix, Rect editWindowBounds, IntPtr e
335329
}
336330
}
337331

338-
//void FormulaEditExcelToolTipShow(IntPtr excelToolTipWindow)
339-
//{
340-
// // Excel tool tip has just been shown
341-
// // If we're showing the arguments dialog, hide the Excel tool tip
342-
// if (_argumentsToolTip != null && _argumentsToolTip.Visible)
343-
// {
344-
// Win32Helper.HideWindow(excelToolTipWindow);
345-
// }
346-
//}
332+
333+
// This helper just keeps us out of the Excel tooltip's way.
334+
int GetTopOffset(IntPtr excelToolTipWindow)
335+
{
336+
// TODO: Maybe get its height...?
337+
return (excelToolTipWindow == IntPtr.Zero) ? 0 : 18;
338+
}
339+
340+
void FormulaEditExcelToolTipShow(Rect editWindowBounds, IntPtr excelToolTipWindow)
341+
{
342+
// // Excel tool tip has just been shown
343+
// // If we're showing the arguments dialog, hide the Excel tool tip
344+
// if (_argumentsToolTip != null && _argumentsToolTip.Visible)
345+
// {
346+
// Win32Helper.HideWindow(excelToolTipWindow);
347+
// }
348+
349+
if (_argumentsToolTip != null && _argumentsToolTip.Visible)
350+
{
351+
int topOffset = GetTopOffset(excelToolTipWindow);
352+
_argumentsToolTip.MoveToolTip((int)editWindowBounds.Left, (int)editWindowBounds.Bottom + 5, topOffset);
353+
}
354+
}
347355

348356
// Runs on the main thread
349357
void FunctionListShow()
@@ -378,6 +386,7 @@ void FunctionListSelectedItemChange(string selectedItemText, Rect selectedItemBo
378386
text: new FormattedText { GetFunctionDescriptionOrNull(functionInfo) },
379387
left: (int)listBounds.Right + DescriptionLeftMargin,
380388
top: (int)selectedItemBounds.Bottom - 18,
389+
topOffset: 0,
381390
listLeft: (int)selectedItemBounds.Left);
382391
return;
383392
}
@@ -389,7 +398,11 @@ void FunctionListSelectedItemChange(string selectedItemText, Rect selectedItemBo
389398

390399
void FunctionListMove(Rect selectedItemBounds, Rect listBounds)
391400
{
392-
_descriptionToolTip.MoveToolTip((int)listBounds.Right + DescriptionLeftMargin, (int)selectedItemBounds.Bottom - 18, (int)selectedItemBounds.Left);
401+
_descriptionToolTip.MoveToolTip(
402+
left: (int)listBounds.Right + DescriptionLeftMargin,
403+
top: (int)selectedItemBounds.Bottom - 18,
404+
topOffset: 0,
405+
listLeft: (int)selectedItemBounds.Left);
393406
}
394407

395408
// TODO: Performance / efficiency - cache these somehow

Source/ExcelDna.IntelliSense/ToolTipForm.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class ToolTipForm : Form
2929
int _currentTop;
3030
int _showLeft;
3131
int _showTop;
32+
int _topOffset; // Might be trying to move the tooltip out of the way of Excel's tip - we track this extra offset here
3233
int? _listLeft;
3334
// Various graphics object cached
3435
Brush _textBrush;
@@ -109,23 +110,25 @@ void ShowToolTip()
109110
}
110111
}
111112

112-
public void ShowToolTip(FormattedText text, int left, int top, int? listLeft)
113+
public void ShowToolTip(FormattedText text, int left, int top, int topOffset, int? listLeft = null)
113114
{
115+
Debug.Print($"@@@ ShowToolTip - Old TopOffset: {_topOffset}, New TopOffset: {topOffset}");
114116
_text = text;
115-
if (left != _showLeft || top != _showTop || listLeft != _listLeft)
117+
if (left != _showLeft || top != _showTop || topOffset != _topOffset || listLeft != _listLeft)
116118
{
117119
// Update the start position and the current position
118120
_currentLeft = left;
119121
_currentTop = top;
120122
_showLeft = left;
121123
_showTop = top;
124+
_topOffset = topOffset;
122125
_listLeft = listLeft;
123126
}
124127
if (!Visible)
125128
{
126129
Debug.Print($"ShowToolTip - Showing ToolTipForm: {_text.ToString()}");
127130
// Make sure we're in the right position before we're first shown
128-
SetBounds(_currentLeft, _currentTop, 0, 0);
131+
SetBounds(_currentLeft, _currentTop + _topOffset, 0, 0);
129132
ShowToolTip();
130133
}
131134
else
@@ -135,14 +138,15 @@ public void ShowToolTip(FormattedText text, int left, int top, int? listLeft)
135138
}
136139
}
137140

138-
139-
public void MoveToolTip(int left, int top, int? listLeft)
141+
public void MoveToolTip(int left, int top, int topOffset, int? listLeft = null)
140142
{
143+
Debug.Print($"@@@ MoveToolTip - Old TopOffset: {_topOffset}, New TopOffset: {topOffset}");
141144
// We might consider checking the new position against earlier mouse movements
142145
_currentLeft = left;
143146
_currentTop = top;
144147
_showLeft = left;
145148
_showTop = top;
149+
_topOffset = topOffset;
146150
_listLeft = listLeft;
147151
Invalidate();
148152
}
@@ -370,16 +374,16 @@ void DrawRoundedRectangle(Graphics g, RectangleF r, float radiusX, float radiusY
370374

371375
void UpdateLocation(int width, int height)
372376
{
373-
var workingArea = Screen.GetWorkingArea(new Point(_currentLeft, _currentTop));
374-
bool tipFits = workingArea.Contains(new Rectangle(_currentLeft, _currentTop, width, height));
377+
var workingArea = Screen.GetWorkingArea(new Point(_currentLeft, _currentTop + _topOffset));
378+
bool tipFits = workingArea.Contains(new Rectangle(_currentLeft, _currentTop + _topOffset, width, height));
375379
if (!tipFits && (_currentLeft == _showLeft && _currentTop == _showTop))
376380
{
377381
// It doesn't fit and it's still where we initially tried to show it
378382
// (so it probably hasn't been moved).
379383
if (_listLeft == null)
380384
{
381385
// Not in list selection mode - probably FormulaEdit
382-
_currentLeft = Math.Max(0, (_currentLeft + width) - workingArea.Right);
386+
_currentLeft -= Math.Max(0, (_currentLeft + width) - workingArea.Right);
383387
// CONSIDER: Move up too???
384388
}
385389
else
@@ -392,7 +396,7 @@ void UpdateLocation(int width, int height)
392396
}
393397
}
394398
}
395-
SetBounds(_currentLeft, _currentTop, width, height);
399+
SetBounds(_currentLeft, _currentTop + _topOffset, width, height);
396400
}
397401
#endregion
398402

Source/ExcelDna.IntelliSense/UIMonitor/WinEvents.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ public enum WinEvent : uint
7777
EVENT_SYSTEM_ARRANGMENTPREVIEW = 0x8016,
7878
EVENT_SYSTEM_MOVESIZESTART = 0x000A,
7979
EVENT_SYSTEM_MOVESIZEEND = 0x000B, // The movement or resizing of a window has finished. This event is sent by the system, never by servers.
80-
// There are slso events about minimize / restore
80+
EVENT_SYSTEM_MINIMIZESTART = 0x0016, // A window object is about to be minimized.
81+
EVENT_SYSTEM_MINIMIZEEND = 0x0017, // A window object is about to be restored.
82+
EVENT_SYSTEM_END = 0x00FF,
8183
EVENT_OBJECT_END = 0x80FF,
8284
EVENT_AIA_START = 0xA000,
8385
EVENT_AIA_END = 0xAFFF,

Source/ExcelDna.IntelliSense/UIMonitor/WindowLocationWatcher.cs

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,33 @@ public class WindowLocationWatcher : IDisposable
99
{
1010
IntPtr _hWnd;
1111
SynchronizationContext _syncContextAuto;
12-
WinEventHook _windowMoveSizeHook;
1312
WinEventHook _windowLocationChangeHook;
1413

1514
public event EventHandler LocationChanged;
1615

16+
// NOTE: An earlier attempt was to monitor LOCATIONCHANGE only between EVENT_SYSTEM_MOVESIZESTART and EVENT_SYSTEM_MOVESIZEEND
17+
// This nearly worked, and meant we were watching many fewer events ...
18+
// ...but we missed some of the resizing events for the window, leaving our tooltip stranded.
19+
// So until we can find a workaround for that (perhaps a timer would work fine for this), we watch all the LOCATIONCHANGE events.
1720
public WindowLocationWatcher(IntPtr hWnd, SynchronizationContext syncContextAuto)
1821
{
1922
_hWnd = hWnd;
2023
_syncContextAuto = syncContextAuto;
21-
_windowMoveSizeHook = new WinEventHook(WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZESTART, WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZEEND, _syncContextAuto, _hWnd);
22-
_windowMoveSizeHook.WinEventReceived += _windowMoveHook_WinEventReceived;
23-
}
24-
25-
void _windowMoveHook_WinEventReceived(object sender, WinEventHook.WinEventArgs winEventArgs)
26-
{
27-
#if DEBUG
28-
Logger.WinEvents.Verbose($"{winEventArgs.EventType} - Window {winEventArgs.WindowHandle:X} ({Win32Helper.GetClassName(winEventArgs.WindowHandle)} - Object/Child {winEventArgs.ObjectId} / {winEventArgs.ChildId} - Thread {winEventArgs.EventThreadId} at {winEventArgs.EventTimeMs}");
29-
#endif
30-
if (winEventArgs.EventType == WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZESTART)
31-
{
32-
if (_windowLocationChangeHook != null)
33-
{
34-
Debug.Fail("Unexpected move start without end");
35-
_windowLocationChangeHook.Dispose();
36-
}
37-
_windowLocationChangeHook = new WinEventHook(WinEventHook.WinEvent.EVENT_OBJECT_LOCATIONCHANGE, WinEventHook.WinEvent.EVENT_OBJECT_LOCATIONCHANGE, _syncContextAuto, _hWnd);
38-
_windowLocationChangeHook.WinEventReceived += _windowLocationChangeHook_WinEventReceived;
39-
}
40-
else if (winEventArgs.EventType == WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZEEND)
41-
{
42-
_windowLocationChangeHook.Dispose();
43-
_windowLocationChangeHook = null;
44-
}
24+
_windowLocationChangeHook = new WinEventHook(WinEventHook.WinEvent.EVENT_OBJECT_LOCATIONCHANGE, WinEventHook.WinEvent.EVENT_OBJECT_LOCATIONCHANGE, _syncContextAuto, _hWnd);
25+
_windowLocationChangeHook.WinEventReceived += _windowLocationChangeHook_WinEventReceived;
4526
}
4627

4728
void _windowLocationChangeHook_WinEventReceived(object sender, WinEventHook.WinEventArgs winEventArgs)
4829
{
4930
#if DEBUG
5031
Logger.WinEvents.Verbose($"{winEventArgs.EventType} - Window {winEventArgs.WindowHandle:X} ({Win32Helper.GetClassName(winEventArgs.WindowHandle)} - Object/Child {winEventArgs.ObjectId} / {winEventArgs.ChildId} - Thread {winEventArgs.EventThreadId} at {winEventArgs.EventTimeMs}");
5132
#endif
52-
LocationChanged?.Invoke(this, EventArgs.Empty);
33+
if (winEventArgs.WindowHandle == _hWnd)
34+
LocationChanged?.Invoke(this, EventArgs.Empty);
5335
}
5436

5537
public void Dispose()
5638
{
57-
if (_windowMoveSizeHook != null)
58-
{
59-
_windowMoveSizeHook.Dispose();
60-
_windowMoveSizeHook = null;
61-
}
6239
if (_windowLocationChangeHook != null)
6340
{
6441
_windowLocationChangeHook.Dispose();

0 commit comments

Comments
 (0)