In this case, the quickest way I see is to look into the example project with the warp-to-0 autopilot bot. This bot uses the squares representing the solar systems in the autopilot route and also the context menu entries.
TL DR
Before diving into the details, a quick summary to copy and paste into your app code:
Function to get the first square icon from the info panel:
infoPanelRouteFirstMarkerFromParsedUserInterface : EveOnline.MemoryReading.ParsedUserInterface -> Maybe InfoPanelRouteRouteElementMarker
infoPanelRouteFirstMarkerFromParsedUserInterface =
.infoPanelRoute
>> maybeNothingFromCanNotSeeIt
>> Maybe.map .routeElementMarker
>> Maybe.map (List.sortBy (\routeMarker -> routeMarker.uiNode.totalDisplayRegion.x + routeMarker.uiNode.totalDisplayRegion.y))
>> Maybe.andThen List.head
Function to get the context menu entry:
menuEntryToJumpFromParsedUserInterface : EveOnline.MemoryReading.ParsedUserInterface -> Maybe EveOnline.MemoryReading.ContextMenuEntry
menuEntryToJumpFromParsedUserInterface =
.contextMenus
>> List.head
>> Maybe.andThen (.entries >> List.filter (.text >> String.toLower >> String.contains "jump") >> List.head)
The Long Version
Wondering how I found these functions? Then read on:
To find the paths to the UI elements in the program code, I start at the location where the mouse click effects are computed and then trace back to the EveOnline.MemoryReading.ParsedUserInterface
that we receive from the EVE Online bot framework with the MemoryReadingCompleted
event.
The command to open the context menu on the square is computed here:
Following the propagation of infoPanelRouteFirstMarker
back its source, we arrive at this function:
infoPanelRouteFirstMarkerFromParsedUserInterface : ParsedUserInterface -> Maybe InfoPanelRouteRouteElementMarker
infoPanelRouteFirstMarkerFromParsedUserInterface =
.infoPanelRoute
>> maybeNothingFromCanNotSeeIt
>> Maybe.map .routeElementMarker
>> Maybe.map (List.sortBy (\routeMarker -> routeMarker.uiNode.totalDisplayRegion.x + routeMarker.uiNode.totalDisplayRegion.y))
>> Maybe.andThen List.head
What is most important about this function is that you can reuse it by just copy and paste it into your bot: In the functions type annotation at the top, we see it takes only an EveOnline.MemoryReading.ParsedUserInterface
as input.
The returned InfoPanelRouteRouteElementMarker
is wrapped in a Maybe
, because you can have no squares at all, and in this case, it returns the Nothing
value.
Since there can be multiple squares in the autopilot info panel, the function sorts them by their location on the screen. In this functions, we also find also the field names we need to navigate from the root type down to the square icon: infoPanelRoute
and routeElementMarker
. Since even the route info panel itself can be hidden, there is some unpacking included for these cases.
When the right context menu is open, the bot clicks on the menu entry with this implementation:
Also here following the dataflow backward, we land here:
maybeMenuEntryToClick =
firstMenu.entries
|> List.filter
(\menuEntry ->
let
textLowercase =
menuEntry.text |> String.toLower
in
(textLowercase |> String.contains "dock")
|| (textLowercase |> String.contains "jump")
)
|> List.head
The function the bot uses is a bit more complicated than what you are looking for because it not only clicks on the entry to jump but also to dock. You can use this simplified version:
maybeMenuEntryToClick =
firstMenu.entries
|> List.filter (.text >> String.toLower >> String.contains "jump")
|> List.head
For the context menu entry, we use an instance of the Maybe
type again because not always is there a matching menu entry, for example, when no context menu is open at all.
You can integrate this into one function that you can use directly on the memory reading value that you get from the bot framework:
menuEntryToJumpFromParsedUserInterface : EveOnline.MemoryReading.ParsedUserInterface -> Maybe EveOnline.MemoryReading.ContextMenuEntry
menuEntryToJumpFromParsedUserInterface =
.contextMenus
>> List.head
>> Maybe.andThen (.entries >> List.filter (.text >> String.toLower >> String.contains "jump") >> List.head)