Option Explicit
Private Type POINTAPI
x As Long
y As Long
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
#If VBA7 Then
Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
#Else
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function GetActiveWindow Lib "user32" () As Long
#End If
Private WithEvents cmndbars As CommandBars
Private Sub Class_Initialize()
Set cmndbars = Application.CommandBars
Call cmndbars_OnUpdate
End Sub
Private Sub cmndbars_OnUpdate()
Static oPrevRange As Range
Dim tCurPos As POINTAPI, oRange As Range, oComment As Comment
On Error Resume Next
If GetActiveWindow <> Application.Hwnd Then Exit Sub
Call GetCursorPos(tCurPos)
Set oRange = ActiveWindow.RangeFromPoint(tCurPos.x, tCurPos.y)
If oRange.Address <> oPrevRange.Address Then
With oPrevRange.Comment
.Visible = False
.Shape.Top = .Parent.Top - 10
.Shape.Left = .Parent.Offset(0, 1).Left + 15
End With
Set oComment = oRange.Comment
If Not oComment Is Nothing Then
If oComment.Parent.Row = ActiveWindow.VisibleRange.Row Then
oComment.Visible = True
oComment.Shape.Top = oComment.Parent.Offset(1).Top
End If
If IsOffScreenX(oComment) Then
oComment.Shape.Left = oComment.Parent.Left - oComment.Shape.Width
End If
If IsOffScreenY(oComment) Then
oComment.Shape.Top = oComment.Parent.Top - oComment.Shape.Height
End If
End If
End If
Set oPrevRange = oRange
With Application.CommandBars.FindControl(ID:=2020): .Enabled = Not .Enabled: End With
End Sub
Private Function IsOffScreenX(ByVal Comment As Comment) As Boolean
Dim tCommentRect As RECT
Comment.Visible = True
tCommentRect = GetRangeRect(Comment.Shape)
If ActiveWindow.RangeFromPoint(tCommentRect.Right, tCommentRect.Top) Is Nothing Then
IsOffScreenX = True
End If
End Function
Private Function IsOffScreenY(ByVal Comment As Comment) As Boolean
Dim tCommentRect As RECT
Comment.Visible = True
tCommentRect = GetRangeRect(Comment.Shape)
If ActiveWindow.RangeFromPoint(tCommentRect.Right, tCommentRect.Bottom) Is Nothing Then
IsOffScreenY = True
End If
End Function
Private Function GetRangeRect(ByVal Obj As Object) As RECT
Dim oPane As Pane
Set oPane = ActiveWindow.ActivePane
With GetRangeRect
.Left = oPane.PointsToScreenPixelsX(Obj.Left)
.Top = oPane.PointsToScreenPixelsY(Obj.Top)
.Right = oPane.PointsToScreenPixelsX(Obj.Left + Obj.Width)
.Bottom = oPane.PointsToScreenPixelsY(Obj.Top + Obj.Height)
End With
End Function