Thanks both. This highlighted a missing piece in the ListBox API, so I’ve added:
ListBox.CellAtPoint(x As Double, y As Double) As ListBoxCellHit
The coordinates can be passed directly from MouseMove, MouseDown, MouseUp or MouseDrag. The returned snapshot contains the displayed Row, Column, cell-relative X and Y, and the rendered cell Width and Height. It returns Nothing when the pointer is not over a visible data cell.
The geometry uses the actual rendered cell, so it accounts for percentage/fill widths, resized columns, scrolling and frozen columns. It also uses the same coordinate space as the Graphics object supplied to the cell-painting events.
For two icons drawn in column 3:
Function IconAt(hit As ListBoxCellHit) As Integer
If hit = Nothing Then Return -1
If hit.Column <> 3 Then Return -1
If hit.Y < 4 Or hit.Y >= 24 Then Return -1
If hit.X >= 10 And hit.X < 30 Then Return 0
If hit.X >= 40 And hit.X < 60 Then Return 1
Return -1
End Function
Sub List_MouseMove(x As Double, y As Double)
Var icon As Integer = IconAt(Me.CellAtPoint(x, y))
If icon >= 0 Then
Me.MouseCursor = MouseCursor.Hand
Else
Me.MouseCursor = MouseCursor.Default
End If
End Sub
Sub List_MouseUp(x As Double, y As Double, button As MouseButton)
If button <> MouseButton.Left Then Return
Var hit As ListBoxCellHit = Me.CellAtPoint(x, y)
Var icon As Integer = IconAt(hit)
If icon >= 0 Then
Print("Pressed icon " + icon.ToString() +
" in row " + hit.Row.ToString())
End If
End Sub
This will be included in the next release: Hit-test ListBox cells at a point.