// Runs on the main Excel thread in a macro context. void InitializeOptions() { Logger.Display.Verbose("InitializeOptions"); string listSeparator = ","; string standardFontName = "Calibri"; double standardFontSize = 11.0; object result; if (XlCallInt.TryExcel(XlCallInt.xlfGetWorkspace, out result, 37) == XlCallInt.XlReturn.XlReturnSuccess) { object[,] options = result as object[, ]; if (options != null) { listSeparator = (string)options[0, 4]; Logger.Initialization.Verbose($"InitializeOptions - Set ListSeparator to {listSeparator}"); } } FormulaParser.ListSeparator = listSeparator[0]; _argumentSeparator = listSeparator + " "; if (XlCallInt.TryExcel(XlCallInt.xlfGetWorkspace, out result, 56) == XlCallInt.XlReturn.XlReturnSuccess) { // Standard Font Name standardFontName = (string)result; Logger.Initialization.Verbose($"InitializeOptions - Set StandardFontName to {standardFontName}"); } if (XlCallInt.TryExcel(XlCallInt.xlfGetWorkspace, out result, 57) == XlCallInt.XlReturn.XlReturnSuccess) { // Standard Font Size standardFontSize = (double)result; Logger.Initialization.Verbose($"InitializeOptions - Set StandardFontSize to {standardFontSize}"); } ToolTipForm.SetStandardFont(standardFontName, standardFontSize); }
// Runs on the main thread void UpdateFormulaEditWindow(IntPtr formulaEditWindow) { if (_formulaEditWindow != formulaEditWindow) { _formulaEditWindow = formulaEditWindow; if (_argumentsToolTip != null) { // Rather ChangeParent...? _argumentsToolTip.Dispose(); _argumentsToolTip = null; _selectBox.Dispose(); _selectBox = null; } if (_formulaEditWindow != IntPtr.Zero) { _argumentsToolTip = new ToolTipForm(_formulaEditWindow); _selectBox = new SelectBoxForm(_formulaEditWindow); //_argumentsToolTip.OwnerHandle = _formulaEditWindow; } else { // Debug.Fail("Unexpected null FormulaEditWindow..."); } } }
void MainWindowChanged() { // TODO: This is to guard against shutdown, but we should not have a race here // - shutdown should be on the main thread, as is this event handler. if (_windowWatcher == null) { return; } // TODO: !!! Reset / re-parent ToolTipWindows Debug.Print("MainWindow Change - " + _windowWatcher.MainWindow.ToString("X")); Debug.Print("### Thread calling MainWindowChanged method: " + Thread.CurrentThread.ManagedThreadId); // _descriptionToolTip.SetOwner(e.Handle); // Not Parent, of course! if (_descriptionToolTip != null) { if (_descriptionToolTip.OwnerHandle != _windowWatcher.MainWindow) { _descriptionToolTip.Dispose(); _descriptionToolTip = null; } } if (_argumentsToolTip != null) { if (_argumentsToolTip.OwnerHandle != _windowWatcher.MainWindow) { _argumentsToolTip.Dispose(); _argumentsToolTip = null; } } // _descriptionToolTip = new ToolTipWindow("", _windowWatcher.MainWindow); }
void PopupListSelectedItemChanged() { if (_popupListWatcher == null) { return; } string functionName = _popupListWatcher.SelectedItemText; IntelliSenseFunctionInfo functionInfo; if (_functionInfoMap.TryGetValue(functionName, out functionInfo)) { if (_descriptionToolTip == null) { _descriptionToolTip = new ToolTipForm(_windowWatcher.MainWindow); _argumentsToolTip = new ToolTipForm(_windowWatcher.MainWindow); } // It's ours! _descriptionToolTip.ShowToolTip( new FormattedText { GetFunctionDescription(functionInfo) }, (int)_popupListWatcher.SelectedItemBounds.Right + 25, (int)_popupListWatcher.SelectedItemBounds.Top); } else { if (_descriptionToolTip != null) { _descriptionToolTip.Hide(); } } }
// Runs on the main thread void FunctionListShow() { Debug.Print($"IntelliSenseDisplay - FunctionListShow"); if (_descriptionToolTip == null) { _descriptionToolTip = new ToolTipForm(_functionListWindow); } }
// Runs on the main thread void FormulaEditTextChange(string formulaPrefix, Rect editWindowBounds, IntPtr excelToolTipWindow) { Debug.Print($"^^^ FormulaEditStateChanged. CurrentPrefix: {formulaPrefix}, Thread {Thread.CurrentThread.ManagedThreadId}"); var couldGet = FormulaParser.TryGetFormulaInfo(formulaPrefix, out string functionName, out int currentArgIndex); IntelliSenseEvents.Instance.OnEditingFunction(functionName); if (!couldGet) { IntelliSenseEvents.Instance.OnEditingArgument(null, null); } else { FunctionInfo functionInfo; if (_functionInfoMap.TryGetValue(functionName, out functionInfo)) { var lineBeforeFunctionName = FormulaParser.GetLineBeforeFunctionName(formulaPrefix, functionName); // We have a function name and we want to show info if (_argumentsToolTip != null) { // NOTE: Hiding or moving just once doesn't help - the tooltip pops up in its original place again // TODO: Try to move it off-screen, behind or make invisible //if (!_argumentsToolTip.Visible) //{ // // Fiddle a bit with the ExcelToolTip if it is already visible when we first show our FunctionEdit ToolTip // // At other times, the explicit UI update should catch and hide as appropriate // if (excelToolTipWindow != IntPtr.Zero) // { // Win32Helper.HideWindow(excelToolTipWindow); // } //} int topOffset = GetTopOffset(excelToolTipWindow); FormattedText infoText = GetFunctionIntelliSense(functionInfo, currentArgIndex); try { _argumentsToolTip.ShowToolTip(infoText, lineBeforeFunctionName, (int)editWindowBounds.Left, (int)editWindowBounds.Bottom + 5, topOffset); } catch (Exception ex) { Logger.Display.Warn($"IntelliSenseDisplay - FormulaEditTextChange Error - {ex}"); _argumentsToolTip.Dispose(); _argumentsToolTip = null; } } else { Logger.Display.Info("FormulaEditTextChange with no arguments tooltip !?"); } return; } } // All other paths, we hide the box _argumentsToolTip?.Hide(); }
// Runs on the main thread void FormulaEditEnd() { Debug.Print($"IntelliSenseDisplay - FormulaEditEnd"); // TODO: When can it be null if (_argumentsToolTip != null) { //_argumentsToolTip.Hide(); _argumentsToolTip.Dispose(); _argumentsToolTip = null; } }
// TODO: Need better formula parsing story here // Here are some ideas: http://fastexcel.wordpress.com/2013/10/27/parsing-functions-from-excel-formulas-using-vba-is-mid-or-a-byte-array-the-best-method/ void FormulaEditStateChanged(StateChangeTypeEnum stateChangeType) { // Check for watcher already disposed // CONSIDER: How to manage threading with disposal...? if (_formulaEditWatcher == null) { return; } if (stateChangeType == StateChangeTypeEnum.Move && _argumentsToolTip != null) { _argumentsToolTip.MoveToolTip( (int)_formulaEditWatcher.EditWindowBounds.Left, (int)_formulaEditWatcher.EditWindowBounds.Bottom + 5); return; } Debug.Print("^^^ FormulaEditStateChanged. CurrentPrefix: " + _formulaEditWatcher.CurrentPrefix); if (_formulaEditWatcher.IsEditingFormula && _formulaEditWatcher.CurrentPrefix != null) { string prefix = _formulaEditWatcher.CurrentPrefix; var match = Regex.Match(prefix, @"^=(?<functionName>\w*)\("); if (match.Success) { string functionName = match.Groups["functionName"].Value; IntelliSenseFunctionInfo functionInfo; if (_functionInfoMap.TryGetValue(functionName, out functionInfo)) { // It's ours! if (_argumentsToolTip == null) { _argumentsToolTip = new ToolTipForm(_windowWatcher.MainWindow); } // TODO: Fix this: Need to consider subformulae int currentArgIndex = _formulaEditWatcher.CurrentPrefix.Count(c => c == ','); _argumentsToolTip.ShowToolTip( GetFunctionIntelliSense(functionInfo, currentArgIndex), (int)_formulaEditWatcher.EditWindowBounds.Left, (int)_formulaEditWatcher.EditWindowBounds.Bottom + 5); return; } } } // All other paths, we just clear the box if (_argumentsToolTip != null) { _argumentsToolTip.Hide(); } }
//void UpdateFunctionListWindow(IntPtr functionListWindow) //{ // if (_functionListWindow != functionListWindow) // { // _functionListWindow = functionListWindow; // if (_descriptionToolTip != null) // { // _descriptionToolTip.Dispose(); // _descriptionToolTip = null; // } // if (_functionListWindow != IntPtr.Zero) // { // _descriptionToolTip = new ToolTipForm(_functionListWindow); // //_descriptionToolTip.OwnerHandle = _functionListWindow; // } // } //} // Runs on the main thread void FormulaEditStart(string formulaPrefix, Rect editWindowBounds, IntPtr excelToolTipWindow) { Debug.Print($"IntelliSenseDisplay - FormulaEditStart - FormulaEditWindow: {_formulaEditWindow}, ArgumentsToolTip: {_argumentsToolTip}"); if (_formulaEditWindow != IntPtr.Zero && _argumentsToolTip == null) { _argumentsToolTip = new ToolTipForm(_formulaEditWindow); } // Normally we would have no formula at this point. // One exception is after mouse-click on the formula list, we then need to process it. if (!string.IsNullOrEmpty(formulaPrefix)) { FormulaEditTextChange(formulaPrefix, editWindowBounds, excelToolTipWindow); } }
void UpdateFunctionListWindow(IntPtr functionListWindow) { if (_functionListWindow != functionListWindow) { _functionListWindow = functionListWindow; if (_descriptionToolTip != null) { _descriptionToolTip.Dispose(); _descriptionToolTip = null; } if (_functionListWindow != IntPtr.Zero) { _descriptionToolTip = new ToolTipForm(_functionListWindow); //_descriptionToolTip.OwnerHandle = _functionListWindow; } } }
void FunctionListMove(Rect selectedItemBounds, Rect listBounds) { try { _descriptionToolTip?.MoveToolTip( left: (int)listBounds.Right + DescriptionLeftMargin, top: (int)selectedItemBounds.Bottom - 18, topOffset: 0, listLeft: (int)selectedItemBounds.Left); } catch (Exception ex) { Logger.Display.Warn($"IntelliSenseDisplay - FunctionListMove Error - {ex}"); // Recycle the _DescriptionToolTip - won't show now, but should for the next function _descriptionToolTip?.Dispose(); _descriptionToolTip = null; } }
public void Dispose() { _current._syncContextAuto.Send(delegate { if (_windowWatcher != null) { _windowWatcher.MainWindowChanged -= OnMainWindowChanged; _windowWatcher.Dispose(); _windowWatcher = null; } if (_formulaEditWatcher != null) { _formulaEditWatcher.StateChanged -= OnStateChanged; _formulaEditWatcher.Dispose(); _formulaEditWatcher = null; } if (_popupListWatcher != null) { _popupListWatcher.SelectedItemChanged -= OnSelectedItemChanged; _popupListWatcher.Dispose(); _popupListWatcher = null; } }, null); _syncContextMain.Send(delegate { if (_descriptionToolTip != null) { _descriptionToolTip.Dispose(); _descriptionToolTip = null; } if (_argumentsToolTip != null) { _argumentsToolTip.Dispose(); _argumentsToolTip = null; } }, null); // NOTE: Add for separate UI Automation Thread _threadAuto.Abort(); _threadAuto = null; _syncContextAuto = null; _syncContextMain = null; }
// Runs on the main thread void FormulaEditEnd() { Debug.Print($"IntelliSenseDisplay - FormulaEditEnd"); // TODO: When can it be null if (!_selectBox?.ContainsFocus ?? true) { if (_argumentsToolTip != null) { //_argumentsToolTip.Hide(); _argumentsToolTip.Dispose(); _argumentsToolTip = null; } if (_selectBox != null) { _selectBox.Dispose(); _selectBox = null; } } }
// Runs on the main thread void FunctionListSelectedItemChange(string selectedItemText, Rect selectedItemBounds, Rect listBounds) { Logger.Display.Verbose($"IntelliSenseDisplay - PopupListSelectedItemChanged - {selectedItemText} List/Item Bounds: {listBounds} / {selectedItemBounds}"); FunctionInfo functionInfo; if (!string.IsNullOrEmpty(selectedItemText) && _functionInfoMap.TryGetValue(selectedItemText, out functionInfo)) { // It's ours! var descriptionLines = GetFunctionDescriptionOrNull(functionInfo); if (descriptionLines != null) { try { _descriptionToolTip?.ShowToolTip( text: new FormattedText { GetFunctionDescriptionOrNull(functionInfo) }, linePrefix: null, left: (int)listBounds.Right + DescriptionLeftMargin, top: (int)selectedItemBounds.Bottom - 18, topOffset: 0, listLeft: (int)selectedItemBounds.Left); return; } catch (Exception ex) { Logger.Display.Warn($"IntelliSenseDisplay - PopupListSelectedItemChanged Error - {ex}"); // Recycle the _DescriptionToolTip - won't show now, but should for the next function _descriptionToolTip.Dispose(); _descriptionToolTip = null; return; } } } // Not ours or no description _descriptionToolTip?.Hide(); }
// Runs on the main thread void FormulaEditMove(Rect editWindowBounds, IntPtr excelToolTipWindow) { Debug.Print($"IntelliSenseDisplay - FormulaEditMove"); if (_argumentsToolTip == null) { Logger.Display.Warn("FormulaEditMode Unexpected null Arguments ToolTip!?"); return; } int topOffset = GetTopOffset(excelToolTipWindow); try { _argumentsToolTip.MoveToolTip((int)editWindowBounds.Left, (int)editWindowBounds.Bottom + 5, topOffset); } catch (Exception ex) { Logger.Display.Warn($"IntelliSenseDisplay - FormulaEditMove Error - {ex}"); // Recycle the Arguments ToolTip - won't show now, but should for the next function _argumentsToolTip.Dispose(); _argumentsToolTip = null; } }
void FormulaEditExcelToolTipShow(Rect editWindowBounds, IntPtr excelToolTipWindow) { // // Excel tool tip has just been shown // // If we're showing the arguments dialog, hide the Excel tool tip // if (_argumentsToolTip != null && _argumentsToolTip.Visible) // { // Win32Helper.HideWindow(excelToolTipWindow); // } if (_argumentsToolTip != null && _argumentsToolTip.Visible) { int topOffset = GetTopOffset(excelToolTipWindow); try { _argumentsToolTip.MoveToolTip((int)editWindowBounds.Left, (int)editWindowBounds.Bottom + 5, topOffset); } catch (Exception ex) { Logger.Display.Warn($"IntelliSenseDisplay - FormulaEditExcelToolTipShow Error - {ex}"); _argumentsToolTip.Dispose(); _argumentsToolTip = null; } } }
// Runs on the main thread void FunctionListShow() { Debug.Print($"IntelliSenseDisplay - FunctionListShow"); if (_descriptionToolTip == null) _descriptionToolTip = new ToolTipForm(_functionListWindow); }
void PopupListSelectedItemChanged() { if (_popupListWatcher == null) return; string functionName = _popupListWatcher.SelectedItemText; IntelliSenseFunctionInfo functionInfo; if ( _functionInfoMap.TryGetValue(functionName, out functionInfo)) { if (_descriptionToolTip == null) { _descriptionToolTip = new ToolTipForm(_windowWatcher.MainWindow); _argumentsToolTip = new ToolTipForm(_windowWatcher.MainWindow); } // It's ours! _descriptionToolTip.ShowToolTip( new FormattedText { GetFunctionDescription(functionInfo) }, (int)_popupListWatcher.SelectedItemBounds.Right + 25, (int)_popupListWatcher.SelectedItemBounds.Top); } else { if (_descriptionToolTip != null) { _descriptionToolTip.Hide(); } } }
// Runs on the main thread void FormulaEditStart(string formulaPrefix, Rect editWindowBounds, IntPtr excelToolTipWindow) { Debug.Print($"IntelliSenseDisplay - FormulaEditStart - FormulaEditWindow: {_formulaEditWindow}, ArgumentsToolTip: {_argumentsToolTip}"); if (_formulaEditWindow != IntPtr.Zero && _argumentsToolTip == null) _argumentsToolTip = new ToolTipForm(_formulaEditWindow); // Normally we would have no formula at this point. // One exception is after mouse-click on the formula list, we then need to process it. if (!string.IsNullOrEmpty(formulaPrefix)) FormulaEditTextChange(formulaPrefix, editWindowBounds, excelToolTipWindow); }
void MainWindowChanged() { // TODO: This is to guard against shutdown, but we should not have a race here // - shutdown should be on the main thread, as is this event handler. if (_windowWatcher == null) return; // TODO: !!! Reset / re-parent ToolTipWindows Debug.Print("MainWindow Change - " + _windowWatcher.MainWindow.ToString("X")); Debug.Print("### Thread calling MainWindowChanged method: " + Thread.CurrentThread.ManagedThreadId); // _descriptionToolTip.SetOwner(e.Handle); // Not Parent, of course! if (_descriptionToolTip != null) { if (_descriptionToolTip.OwnerHandle != _windowWatcher.MainWindow) { _descriptionToolTip.Dispose(); _descriptionToolTip = null; } } if (_argumentsToolTip != null) { if (_argumentsToolTip.OwnerHandle != _windowWatcher.MainWindow) { _argumentsToolTip.Dispose(); _argumentsToolTip = null; } } // _descriptionToolTip = new ToolTipWindow("", _windowWatcher.MainWindow); }
// Runs on the main thread void UpdateFormulaEditWindow(IntPtr formulaEditWindow) { if (_formulaEditWindow != formulaEditWindow) { _formulaEditWindow = formulaEditWindow; if (_argumentsToolTip != null) { // Rather ChangeParent...? _argumentsToolTip.Dispose(); _argumentsToolTip = null; } if (_formulaEditWindow != IntPtr.Zero) { _argumentsToolTip = new ToolTipForm(_formulaEditWindow); //_argumentsToolTip.OwnerHandle = _formulaEditWindow; } else { // Debug.Fail("Unexpected null FormulaEditWindow..."); } } }
// TODO: Need better formula parsing story here // Here are some ideas: http://fastexcel.wordpress.com/2013/10/27/parsing-functions-from-excel-formulas-using-vba-is-mid-or-a-byte-array-the-best-method/ void FormulaEditStateChanged(StateChangeTypeEnum stateChangeType) { // Check for watcher already disposed // CONSIDER: How to manage threading with disposal...? if (_formulaEditWatcher == null) return; if (stateChangeType == StateChangeTypeEnum.Move && _argumentsToolTip != null) { _argumentsToolTip.MoveToolTip( (int)_formulaEditWatcher.EditWindowBounds.Left, (int)_formulaEditWatcher.EditWindowBounds.Bottom + 5); return; } Debug.Print("^^^ FormulaEditStateChanged. CurrentPrefix: " + _formulaEditWatcher.CurrentPrefix); if (_formulaEditWatcher.IsEditingFormula && _formulaEditWatcher.CurrentPrefix != null) { string prefix = _formulaEditWatcher.CurrentPrefix; var match = Regex.Match(prefix, @"^=(?<functionName>\w*)\("); if (match.Success) { string functionName = match.Groups["functionName"].Value; IntelliSenseFunctionInfo functionInfo; if (_functionInfoMap.TryGetValue(functionName, out functionInfo)) { // It's ours! if (_argumentsToolTip == null) { _argumentsToolTip = new ToolTipForm(_windowWatcher.MainWindow); } // TODO: Fix this: Need to consider subformulae int currentArgIndex = _formulaEditWatcher.CurrentPrefix.Count(c => c == ','); _argumentsToolTip.ShowToolTip( GetFunctionIntelliSense(functionInfo, currentArgIndex), (int)_formulaEditWatcher.EditWindowBounds.Left, (int)_formulaEditWatcher.EditWindowBounds.Bottom + 5); return; } } } // All other paths, we just clear the box if (_argumentsToolTip != null) _argumentsToolTip.Hide(); }