Skip to content

Commit e8a5284

Browse files
committed
Track PopupList bounds for Description location.
IntelliSenseServer v 0.0.8
1 parent 1a9d808 commit e8a5284

File tree

6 files changed

+54
-110
lines changed

6 files changed

+54
-110
lines changed

Source/ExcelDna.IntelliSense/IntelliSenseDisplay.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class IntelliSenseDisplay : IDisposable
4242
IntPtr _formulaEditWindow;
4343
IntPtr _functionListWindow;
4444

45+
const int DescriptionLeftMargin = 3;
46+
4547
public IntelliSenseDisplay(SynchronizationContext syncContextMain, UIMonitor uiMonitor)
4648
{
4749
// We expect this to be running in a macro context on the main Excel thread (ManagedThreadId = 1).
@@ -150,15 +152,15 @@ void StateUpdate(object sender, UIStateUpdate update)
150152
// TODO: TEMP
151153
_functionListWindow = fls.FunctionListWindow;
152154
FunctionListShow();
153-
FunctionListSelectedItemChange(fls.SelectedItemText, fls.SelectedItemBounds, fls.HasScrollBar);
155+
FunctionListSelectedItemChange(fls.SelectedItemText, fls.SelectedItemBounds, fls.FunctionListBounds);
154156
break;
155157
case UIStateUpdate.UpdateType.FunctionListMove:
156158
var flm = (UIState.FunctionList)update.NewState;
157-
FunctionListMove(flm.SelectedItemBounds, flm.HasScrollBar);
159+
FunctionListMove(flm.SelectedItemBounds, flm.FunctionListBounds);
158160
break;
159161
case UIStateUpdate.UpdateType.FunctionListSelectedItemChange:
160162
var fl = (UIState.FunctionList)update.NewState;
161-
FunctionListSelectedItemChange(fl.SelectedItemText, fl.SelectedItemBounds, fl.HasScrollBar);
163+
FunctionListSelectedItemChange(fl.SelectedItemText, fl.SelectedItemBounds, fl.FunctionListBounds);
162164
break;
163165
case UIStateUpdate.UpdateType.FunctionListHide:
164166
FunctionListHide();
@@ -306,9 +308,9 @@ void FunctionListHide()
306308
}
307309

308310
// Runs on the main thread
309-
void FunctionListSelectedItemChange(string selectedItemText, Rect selectedItemBounds, bool hasScrollBar)
311+
void FunctionListSelectedItemChange(string selectedItemText, Rect selectedItemBounds, Rect listBounds)
310312
{
311-
Logger.Display.Verbose($"IntelliSenseDisplay - PopupListSelectedItemChanged - New text - {selectedItemText} ({(hasScrollBar ? "Scroll" : "NoScroll")})");
313+
Logger.Display.Verbose($"IntelliSenseDisplay - PopupListSelectedItemChanged - {selectedItemText} List/Item Bounds: {listBounds} / {selectedItemBounds}");
312314

313315
IntelliSenseFunctionInfo functionInfo;
314316
if (_functionInfoMap.TryGetValue(selectedItemText, out functionInfo))
@@ -317,11 +319,10 @@ void FunctionListSelectedItemChange(string selectedItemText, Rect selectedItemBo
317319
var descriptionLines = GetFunctionDescriptionOrNull(functionInfo);
318320
if (descriptionLines != null)
319321
{
320-
var leftMargin = hasScrollBar ? 21 : 4;
321322
_descriptionToolTip.ShowToolTip(
322323
text: new FormattedText { GetFunctionDescriptionOrNull(functionInfo) },
323-
left: (int)selectedItemBounds.Right + leftMargin,
324-
top: (int)selectedItemBounds.Top);
324+
left: (int)listBounds.Right + DescriptionLeftMargin,
325+
top: (int)selectedItemBounds.Bottom - 18);
325326
return;
326327
}
327328
}
@@ -330,10 +331,9 @@ void FunctionListSelectedItemChange(string selectedItemText, Rect selectedItemBo
330331
_descriptionToolTip.Hide();
331332
}
332333

333-
void FunctionListMove(Rect selectedItemBounds, bool hasScrollBar)
334+
void FunctionListMove(Rect selectedItemBounds, Rect listBounds)
334335
{
335-
var leftMargin = hasScrollBar ? 21 : 4;
336-
_descriptionToolTip.MoveToolTip((int)selectedItemBounds.Right + leftMargin, (int)selectedItemBounds.Top);
336+
_descriptionToolTip.MoveToolTip((int)listBounds.Right + DescriptionLeftMargin, (int)selectedItemBounds.Bottom - 18);
337337
}
338338

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

Source/ExcelDna.IntelliSense/IntelliSenseServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ namespace ExcelDna.IntelliSense
4747
// REMEMBER: COM events are not necessarily safe macro contexts.
4848
public static class IntelliSenseServer
4949
{
50-
const string ServerVersion = "0.0.7"; // TODO: Define and manage this somewhere else
50+
const string ServerVersion = "0.0.8"; // TODO: Define and manage this somewhere else
5151

5252
// NOTE: Do not change these constants in custom versions.
5353
// They are part of the co-operative safety mechanism allowing different add-ins providing IntelliSense to work together safely.

Source/ExcelDna.IntelliSense/ToolTipForm.cs

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Drawing;
55
using System.Drawing.Drawing2D;
66
using System.Linq;
7-
using System.Text;
87
using System.Windows.Forms;
98

109
namespace ExcelDna.IntelliSense
@@ -21,6 +20,7 @@ class ToolTipForm : Form
2120
int _top;
2221
Brush _textBrush;
2322
Pen _borderPen;
23+
Pen _borderLightPen;
2424
private ToolTip tipDna;
2525
Dictionary<FontStyle, Font> _fonts;
2626

@@ -40,7 +40,8 @@ public ToolTipForm(IntPtr hwndOwner)
4040

4141
};
4242
_textBrush = new SolidBrush(Color.FromArgb(68, 68, 68));
43-
_borderPen = new Pen(Color.FromArgb(205, 205, 205));
43+
_borderPen = new Pen(Color.FromArgb(195, 195, 195));
44+
_borderLightPen = new Pen(Color.FromArgb(225, 225, 225));
4445
//Win32Helper.SetParent(this.Handle, hwndOwner);
4546

4647
// _owner = new NativeWindow();
@@ -175,7 +176,7 @@ protected override void OnPaint(PaintEventArgs e)
175176
const int leftPadding = 6;
176177
const int linePadding = 2;
177178
const int widthPadding = 10;
178-
const int heightPadding = 3;
179+
const int heightPadding = 2;
179180

180181
base.OnPaint(e);
181182
List<int> lineWidths = new List<int>();
@@ -187,7 +188,7 @@ protected override void OnPaint(PaintEventArgs e)
187188
{
188189
int layoutLeft = ClientRectangle.Location.X + leftPadding;
189190
int layoutTop = ClientRectangle.Location.Y;
190-
Rectangle layoutRect = new Rectangle(layoutLeft, layoutTop, 1000, 500);
191+
Rectangle layoutRect = new Rectangle(layoutLeft, layoutTop - 1, 1000, 500);
191192

192193
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
193194
Size textSize;
@@ -214,26 +215,8 @@ protected override void OnPaint(PaintEventArgs e)
214215

215216
var width = lineWidths.Max() + widthPadding;
216217
var height = totalHeight + heightPadding;
217-
//if (Left != _left ||
218-
// Top != _top ||
219-
// Width != width ||
220-
// Height != height)
221-
//{
222-
//var pRegion = Win32Helper.CreateRoundRectRgn(0, 0, width - 1, height - 1, 2, 2);
223-
//try
224-
//{
225-
// Region = Region.FromHrgn(pRegion);
226-
//}
227-
//finally
228-
//{
229-
// Win32Helper.DeleteObject(pRegion);
230-
//}
231-
SetBounds(_left, _top, width, height);
232-
//}
233-
218+
SetBounds(_left, _top, width, height);
234219
DrawRoundedRectangle(e.Graphics, new RectangleF(0,0, Width - 1, Height - 1), 2, 2);
235-
236-
// Size = new Size(lineWidths.Max() + widthPadding, totalHeight + heightPadding);
237220
}
238221

239222
void DrawString(Graphics g, Brush brush, ref Rectangle rect, out Size used,
@@ -264,29 +247,14 @@ void DrawString(Graphics g, Brush brush, ref Rectangle rect, out Size used,
264247
public void DrawRoundedRectangle(Graphics g, RectangleF r, float radiusX, float radiusY)
265248
{
266249
var oldMode = g.SmoothingMode;
267-
g.SmoothingMode = SmoothingMode.AntiAlias;
250+
g.SmoothingMode = SmoothingMode.None;
268251

269-
// Draw the truncated rectangle in white.
270-
using (GraphicsPath path = new GraphicsPath())
271-
{
272-
path.StartFigure();
252+
g.DrawRectangle(_borderLightPen, new Rectangle((int)r.X, (int)r.Y, 1, 1));
253+
g.DrawRectangle(_borderLightPen, new Rectangle((int)(r.X + r.Width - 1), (int)r.Y, 1, 1));
254+
g.DrawRectangle(_borderLightPen, new Rectangle((int)(r.X + r.Width - 1), (int)(r.Y + r.Height - 1), 1, 1));
255+
g.DrawRectangle(_borderLightPen, new Rectangle((int)(r.X), (int)(r.Y + r.Height - 1), 1, 1));
256+
g.DrawRectangle(_borderPen, new Rectangle((int)r.X, (int)r.Y, (int)r.Width, (int)r.Height));
273257

274-
// if (radiusX <= 0.0F || radiusY <= 0.0F)
275-
{
276-
path.AddRectangle(r);
277-
}
278-
//else
279-
{
280-
//arcs work with diameters (radius * 2)
281-
PointF d = new PointF(Math.Min(radiusX * 2, r.Width), Math.Min(radiusY * 2, r.Height));
282-
path.AddArc(r.X, r.Y, d.X, d.Y, 180, 90);
283-
path.AddArc(r.Right - d.X, r.Y, d.X, d.Y, 270, 90);
284-
path.AddArc(r.Right - d.X, r.Bottom - d.Y, d.X, d.Y, 0, 90);
285-
path.AddArc(r.X, r.Bottom - d.Y, d.X, d.Y, 90, 90);
286-
}
287-
path.CloseFigure();
288-
g.DrawPath(_borderPen, path);
289-
}
290258
g.SmoothingMode = oldMode;
291259
}
292260

@@ -327,8 +295,6 @@ void InitializeComponent()
327295

328296
}
329297

330-
331-
332298
class Win32Window : IWin32Window
333299
{
334300
public IntPtr Handle

Source/ExcelDna.IntelliSense/UIMonitor/FormulaEditWatcher.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -274,25 +274,6 @@ void UninstallTextChangeMonitor(AutomationElement element)
274274
}
275275
}
276276

277-
// Breaks the PopupList SelectedItemChange event handler ... !?
278-
//// Expected on some automation event handler thread
279-
//void FocusChangedEventHandler(object sender, AutomationFocusChangedEventArgs e)
280-
//{
281-
// return;
282-
// Logger.WindowWatcher.Verbose($"++++> Focus Changed! ({_formulaEditFocus})");
283-
// if (_formulaEditFocus == FormulaEditFocus.None)
284-
// return;
285-
286-
// var formulaPrefix = XlCall.GetFormulaEditPrefix();
287-
// if (formulaPrefix == null)
288-
// {
289-
// // We need to update
290-
// _formulaEditFocus = FormulaEditFocus.None;
291-
// UpdateFormulaPolling();
292-
// UpdateEditState();
293-
// }
294-
//}
295-
296277
// Threading... ???
297278
void UpdateFormulaPolling()
298279
{

Source/ExcelDna.IntelliSense/UIMonitor/PopupListWatcher.cs

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class PopupListWatcher : IDisposable
2020
public bool IsVisible{ get; set; } = false;
2121
public string SelectedItemText { get; set; } = string.Empty;
2222
public Rect SelectedItemBounds { get; set; } = Rect.Empty;
23-
public bool HasVerticalScrollBar { get; set; } = false;
23+
public Rect ListBounds { get; set; } = Rect.Empty;
2424
public IntPtr PopupListHandle => _hwndPopupList;
2525

2626
SynchronizationContext _syncContextAuto;
@@ -86,7 +86,7 @@ void _windowWatcher_PopupListWindowChanged(object sender, WindowWatcher.WindowCh
8686
case WindowWatcher.WindowChangedEventArgs.ChangeType.Hide:
8787
Logger.WindowWatcher.Verbose($"PopupList window hide");
8888
IsVisible = false;
89-
UpdateSelectedItem(_selectedItem, false);
89+
UpdateSelectedItem(_selectedItem);
9090
break;
9191
case WindowWatcher.WindowChangedEventArgs.ChangeType.Focus:
9292
case WindowWatcher.WindowChangedEventArgs.ChangeType.Unfocus:
@@ -126,12 +126,11 @@ void _windowWatcher_PopupListWindowChanged(object sender, WindowWatcher.WindowCh
126126
// This runs on an automation event handler thread
127127
void PopupListBoundsChanged(object sender, AutomationPropertyChangedEventArgs e)
128128
{
129-
if (IsVisible && _selectedItem != null)
130-
{
131-
// Debug.Print($">>>> PopupListWatcher.LocationChanged on thread {Thread.CurrentThread.ManagedThreadId}");
132-
// We assume the scroll bar presence has not changed
133-
UpdateSelectedItem(_selectedItem, HasVerticalScrollBar);
134-
}
129+
Debug.Print($"##### PopupList BoundsChanged: {e.NewValue}");
130+
if (e.NewValue != null)
131+
ListBounds = (Rect)e.NewValue;
132+
133+
// We don't have to trigger the update
135134

136135
//_syncContextAuto.Post(delegate
137136
//{
@@ -168,11 +167,7 @@ void PopupListElementSelectedHandler(object sender, AutomationEventArgs e)
168167
{
169168
Logger.WindowWatcher.Verbose($"PopupList PopupListElementSelectedHandler on thread {Thread.CurrentThread.ManagedThreadId}");
170169
var selectedItem = (AutomationElement)sender;
171-
// CONSIDER: Maybe monitor changes to scrollbar as an event? (for performance)
172-
var walker = TreeWalker.ControlViewWalker;
173-
var list = walker.GetParent(walker.GetParent(selectedItem));
174-
var hasVerticalScrollBar = (bool)list.GetCurrentPropertyValue(AutomationElement.IsScrollPatternAvailableProperty);
175-
UpdateSelectedItem(selectedItem, hasVerticalScrollBar);
170+
UpdateSelectedItem(selectedItem);
176171
}
177172

178173
// Runs on our automation thread
@@ -184,8 +179,8 @@ void InstallEventHandlers()
184179
Automation.AddAutomationEventHandler(
185180
SelectionItemPattern.ElementSelectedEvent, _popupList, TreeScope.Descendants /* was .Children */, PopupListElementSelectedHandler);
186181
Logger.WindowWatcher.Verbose($"PopupList selection event handler added");
187-
Automation.AddAutomationPropertyChangedEventHandler(_popupList, TreeScope.Element, PopupListBoundsChanged, AutomationElement.BoundingRectangleProperty);
188-
Logger.WindowWatcher.Verbose($"PopupList bounds change event handler added");
182+
//Automation.AddAutomationPropertyChangedEventHandler(_popupList, TreeScope.Element, PopupListBoundsChanged, AutomationElement.BoundingRectangleProperty);
183+
//Logger.WindowWatcher.Verbose($"PopupList bounds change event handler added");
189184
}
190185
catch (Exception ex)
191186
{
@@ -209,14 +204,12 @@ void UpdateSelectedItem()
209204
if (listElement != null)
210205
{
211206
var selectionPattern = listElement.GetCurrentPattern(SelectionPattern.Pattern) as SelectionPattern;
212-
// CONSIDER: We might dig in a big more (e.g. is horizontal scrolling possible?)
213-
var hasVerticalScrollBar = (bool)listElement.GetCurrentPropertyValue(AutomationElement.IsScrollPatternAvailableProperty);
214207
var currentSelection = selectionPattern.Current.GetSelection();
215208
if (currentSelection.Length > 0)
216209
{
217210
try
218211
{
219-
UpdateSelectedItem(currentSelection[0], hasVerticalScrollBar);
212+
UpdateSelectedItem(currentSelection[0]);
220213
}
221214
catch (Exception ex)
222215
{
@@ -232,9 +225,9 @@ void UpdateSelectedItem()
232225

233226
// Can run on our automation thread or on any automation event thread (which is also allowed to read properties)
234227
// But might fail, if the newSelectedItem is already gone by the time we run...
235-
void UpdateSelectedItem(AutomationElement newSelectedItem, bool hasVerticalScrollBar)
228+
void UpdateSelectedItem(AutomationElement newSelectedItem)
236229
{
237-
// Debug.Print($"POPUPLISTWATCHER WINDOW CURRENT SELECTION {newSelectedItem}");
230+
Debug.Print($"POPUPLISTWATCHER WINDOW CURRENT SELECTION {newSelectedItem}");
238231

239232
// TODO: Sometimes the IsVisble is not updated, but we are visible and the first selection is set
240233

@@ -250,16 +243,20 @@ void UpdateSelectedItem(AutomationElement newSelectedItem, bool hasVerticalScrol
250243
_selectedItem = null;
251244
SelectedItemText = string.Empty;
252245
SelectedItemBounds = Rect.Empty;
246+
ListBounds = Rect.Empty;
253247
}
254248
else
255249
{
256250
string selectedItemText = string.Empty;
257251
Rect selectedItemBounds = Rect.Empty;
252+
Rect listBounds = Rect.Empty;
258253

259254
try
260255
{
261256
selectedItemText = (string)newSelectedItem.GetCurrentPropertyValue(AutomationElement.NameProperty);
262257
selectedItemBounds = (Rect)newSelectedItem.GetCurrentPropertyValue(AutomationElement.BoundingRectangleProperty);
258+
listBounds = (Rect)_popupList.GetCurrentPropertyValue(AutomationElement.BoundingRectangleProperty);
259+
Debug.Print($"#### PopupList Update - ListBounds: {listBounds} / SelectedItemBounds: {selectedItemBounds}");
263260
}
264261
catch (Exception ex)
265262
{
@@ -269,19 +266,19 @@ void UpdateSelectedItem(AutomationElement newSelectedItem, bool hasVerticalScrol
269266
}
270267

271268
_selectedItem = newSelectedItem;
269+
ListBounds = listBounds;
272270
SelectedItemText = selectedItemText;
273271
SelectedItemBounds = selectedItemBounds;
274272
// Debug.Print($"SelectedItemBounds: {SelectedItemBounds}");
275273
}
276-
HasVerticalScrollBar = hasVerticalScrollBar;
277274
OnSelectedItemChanged();
278275
}
279276

280277
// Raises the event on the automation thread (but the SyncContext.Post here is redundant)
281278
void OnSelectedItemChanged()
282279
{
283-
Logger.WindowWatcher.Verbose($"PopupList SelectedItemChanged {SelectedItemText} ({(HasVerticalScrollBar ? "Scroll" : "NoScroll")})");
284-
_syncContextAuto.Post(_ => SelectedItemChanged(this, EventArgs.Empty), null);
280+
Logger.WindowWatcher.Verbose($"PopupList SelectedItemChanged {SelectedItemText} ListBounds: {ListBounds}");
281+
_syncContextAuto.Post(_ => SelectedItemChanged?.Invoke(this, EventArgs.Empty), null);
285282
}
286283

287284
public void Dispose()

0 commit comments

Comments
 (0)