This thread will cover the new design for Exilebuddy's GUI API. The GUI API provides the means to interact with Path of Exile's in-game GUI.
The original design was first introduction around August 2014, along with the 1.3 update. That design modeled each client GUI as its own system, and had very little code reuse. At that time, the GUI system the client was using wasn't understood well, so a lot of things were hacked together and patched as they broke as time went along. This design worked for a while, but due to constant client changes over time, it grew to an unmanageable state. With the compiler changes that accompanied the Ascendancy expansion, a better solution was pursued.
The new design models common controls first, then each client GUI system, reusing them where possible. As more time was spent understanding the GUI system the current client is using, a lot of similarities were discovered that helped lead to the creation of a system that would significantly reduce how much underlying code there was while at the same time add missing functionality, reduce the overhead of that functionality, and provide an easier means of future maintenance.
New GUI Manager
There's a new GUI manager class that will hold all relevant GUI functionality. In the old design, most GUI stuff was simply thrown into the global LokiPoe namespace, so things were pretty unorganized.
The new GUI manager class provides a better means to work with the GUI as well. In the past, certain issues arose from the implementations used for trying to interact with more complex GUIs. For example, when resizing the client, the tab list control on the Stash/Guild GUI would mess up due to scaling, and the functions for choosing a tab from the list would break.
A new addition is the identification of some common controls used in the game. In the old design, an inefficient method was used to try and identify some controls, which resulted in a lot of maintenance when the client changed. This system has been greatly simplified, and should now allow a much easier means of common control identification moving forward.
Common Controls
The common controls implement shared behavior that other GUI systems can reuse. In the old design, this functionality would be duplicated across each GUI system, and some systems didn't even implement them. More common controls are being worked on, but for now these are the ones that currently exist.
DockedWindowControlWrapper
The DockedWindowControlWrapper is for docked GUIs that are displayed on the left or right sides of the screen. These all have a title bar, a close button, then the fancy logo and side borders.
This control exposes:
Title - The title of the window
Close() - A function to close the window, by clicking on the X. This helps avoid the current issue of having to close all windows.
WindowControlWrapper
The WindowControlWrapper is for "floating" windows that are not docked on the left or right sides of the screen. These all have a title bar, a close button, then the fancy logo and side borders.
This control exposes:
Title - The title of the window
Close() - A function to close the window, by clicking on the X. This helps avoid the current issue of having to close all windows.
VerticalScrollBarControlWrapper
The VerticalScrollBarControlWrapper is an internal class used to interop with vertical scroll bars. This is helpful for managing any type of GUI that has a variable amount of content that must be scrolled though. One of the newest additions to this control is the ability to "fast scroll", which will be very noticeable on large stash tab lists.
TabControlWrapper
The TabControlWrapper models a simple tab control used in the game. Tab controls are used in a number of places, and this helps simplify a lot of logic. For example, the Trade GUI is a tab control that holds a Trade control on each tab. The World GUI is a tab container that nests another tab container which then holds the map for the current act/difficulty.
This control exposes:
CurrentTabName - The current tab name.
TabNames - A list of tab names.
IsOnFirstTab - A bool if the current tab is the first tab.
IsOnLastTab - A bool if the current tab is the last tab.
PreviousTabKeyboard() - A function to change to the previous tab using the keyboard. This is for stash tabs mostly as the other tab controls don't support input actions.
NextTabKeyboard() - A function to change to the next tab using the keyboard. This is for stash tabs mostly as the other tab controls don't support input actions.
SwitchToTabKeyboard() - A function to switch to a tab either by tab index or tab name using the keyboard.
SwitchToTabMouse() - A function to switch to a tab either by tab index or tab name using the mouse. This function supports "tab lists" with help of the VerticalScrollBarControlWrapper for fast tab switching.
ComboBoxWrapper
The ComboBoxWrapper is an internal class used to model a combobox control. It will be used for accurate selection of the league at the character selection screen, as there have been reported issues regarding that in the past.
InventoryControlWrapper
The InventoryControlWrapper is the best example of why the massive internal GUI changes were done. This control models an inventory control. Inventory controls are used in many GUIs, and are typically a grid shaped display (sell, main inventory, rewards) although single item inventories also exist (equipped items, Divination trader, Cadiro, etc...)
In the old design, each GUI system implemented its own limited set of functions for interacting with the inventory. This created a massive amount of code that had to be maintained and updated when anything changed that affected all of them. In the new design, all GUIs that have an inventory now implement an InventoryControlWrapper to expose shared functionality. This means one set of code is now used for all inventory related operations. This alone has reduced internal GUI code by over 5000 lines of code as a result!
One of the biggest changes to the API design is the use of local item ids now. These were previously not exposed, due to a lot of implementation limitations but they are now fully supported. Users refer to items by id now, and can lookup an item by id to know if it exists or not to figure out if an operation has completed. The previous method of checking for an item with the specific BaseAddress still works, but is less efficient.
This control exposes:
Inventory - The Inventory object of the GUI. The Inventory class holds items and offers other features such as figuring out if an item can fit.
IsItemTransparent() - A function to know if an item has been moved into a trade inventory and is now a shadow copy.
GetItemCost() - A function to get the cost of an item in a sell inventory.
ViewItemsInInventory() - A function to selectively mouse over all items in an inventory to build their display tooltips. This is for sell inventories so GetItemCost can work.
Pickup() - A function to pickup an item to the cursor from an inventory.
FastMove() - A function to perform a fast move operation, control click, on an item in the inventory. This can be used for selecting rewards, buying items, or stashing/trading.
MergeStack() - A function to merge the cursor with another item in the inventory.
SplitStack() - A function to split an item in the inventory into a stack on the cursor.
UseItem() - A function to right click an item to use it. This mechanic has changed in that it no longer applies the item, as another function does that.
BeginApplyCursor() - A function to being applying an item on the cursor to other items in the inventory. Shift use is now supported.
EndApplyCursor() - A function to end applying an item, by clearing key states.
ApplyCursorAt() - A function to apply the cursor to an item at a specific location. This is because an item's id will change after it is modified.
ApplyCursorTo() - A function to apply the cursor to an item with a specific id.
PlaceCursorInto() - A function to place the item in the cursor into a specific position in the inventory. The mechanic for placing the item has been updated to be nearly instant now and not drag anymore.
UnequipSkillGem() - A function to unequip a skillgem from an item in the inventory. This means you can now unequip skillgems from non-equipped items!
EquipSkillGem() - A function to equip a skillgem to an item in the inventory. This means you can now equip skillgems to unequipped items!
TradeControlWrapper
The TradeControlWrapper models a trade control. The trade control is used on the NPC Sell GUI as well as inside a tab in the player Trade GUI. Once again, because of this reuse, internal code is greatly simplified now.
This control exposes:
AcceptButtonText - The text of the accept button.
IsConfirmLabelVisible - A bool if the confirm label is visible.
ConfirmLabelText - The text of the confirm label.
InventoryControl_OtherOffer - An InventoryControlWrapper for working with the items in the other offer inventory.
InventoryControl_YourOffer - An InventoryControlWrapper for working with the items in your offer inventory.
Accept() - A function to accept the trade.
Cancel() - A function to cancel the trade.
Because of the new common controls, the functionality to mouse over all player traded items is exposed though the ViewItemsInInventory function in the InventoryControlWrapper!
The original design was first introduction around August 2014, along with the 1.3 update. That design modeled each client GUI as its own system, and had very little code reuse. At that time, the GUI system the client was using wasn't understood well, so a lot of things were hacked together and patched as they broke as time went along. This design worked for a while, but due to constant client changes over time, it grew to an unmanageable state. With the compiler changes that accompanied the Ascendancy expansion, a better solution was pursued.
The new design models common controls first, then each client GUI system, reusing them where possible. As more time was spent understanding the GUI system the current client is using, a lot of similarities were discovered that helped lead to the creation of a system that would significantly reduce how much underlying code there was while at the same time add missing functionality, reduce the overhead of that functionality, and provide an easier means of future maintenance.
New GUI Manager
There's a new GUI manager class that will hold all relevant GUI functionality. In the old design, most GUI stuff was simply thrown into the global LokiPoe namespace, so things were pretty unorganized.
The new GUI manager class provides a better means to work with the GUI as well. In the past, certain issues arose from the implementations used for trying to interact with more complex GUIs. For example, when resizing the client, the tab list control on the Stash/Guild GUI would mess up due to scaling, and the functions for choosing a tab from the list would break.
A new addition is the identification of some common controls used in the game. In the old design, an inefficient method was used to try and identify some controls, which resulted in a lot of maintenance when the client changed. This system has been greatly simplified, and should now allow a much easier means of common control identification moving forward.
Common Controls
The common controls implement shared behavior that other GUI systems can reuse. In the old design, this functionality would be duplicated across each GUI system, and some systems didn't even implement them. More common controls are being worked on, but for now these are the ones that currently exist.
DockedWindowControlWrapper
The DockedWindowControlWrapper is for docked GUIs that are displayed on the left or right sides of the screen. These all have a title bar, a close button, then the fancy logo and side borders.
This control exposes:
Title - The title of the window
Close() - A function to close the window, by clicking on the X. This helps avoid the current issue of having to close all windows.
WindowControlWrapper
The WindowControlWrapper is for "floating" windows that are not docked on the left or right sides of the screen. These all have a title bar, a close button, then the fancy logo and side borders.
This control exposes:
Title - The title of the window
Close() - A function to close the window, by clicking on the X. This helps avoid the current issue of having to close all windows.
VerticalScrollBarControlWrapper
The VerticalScrollBarControlWrapper is an internal class used to interop with vertical scroll bars. This is helpful for managing any type of GUI that has a variable amount of content that must be scrolled though. One of the newest additions to this control is the ability to "fast scroll", which will be very noticeable on large stash tab lists.
TabControlWrapper
The TabControlWrapper models a simple tab control used in the game. Tab controls are used in a number of places, and this helps simplify a lot of logic. For example, the Trade GUI is a tab control that holds a Trade control on each tab. The World GUI is a tab container that nests another tab container which then holds the map for the current act/difficulty.
This control exposes:
CurrentTabName - The current tab name.
TabNames - A list of tab names.
IsOnFirstTab - A bool if the current tab is the first tab.
IsOnLastTab - A bool if the current tab is the last tab.
PreviousTabKeyboard() - A function to change to the previous tab using the keyboard. This is for stash tabs mostly as the other tab controls don't support input actions.
NextTabKeyboard() - A function to change to the next tab using the keyboard. This is for stash tabs mostly as the other tab controls don't support input actions.
SwitchToTabKeyboard() - A function to switch to a tab either by tab index or tab name using the keyboard.
SwitchToTabMouse() - A function to switch to a tab either by tab index or tab name using the mouse. This function supports "tab lists" with help of the VerticalScrollBarControlWrapper for fast tab switching.
ComboBoxWrapper
The ComboBoxWrapper is an internal class used to model a combobox control. It will be used for accurate selection of the league at the character selection screen, as there have been reported issues regarding that in the past.
InventoryControlWrapper
The InventoryControlWrapper is the best example of why the massive internal GUI changes were done. This control models an inventory control. Inventory controls are used in many GUIs, and are typically a grid shaped display (sell, main inventory, rewards) although single item inventories also exist (equipped items, Divination trader, Cadiro, etc...)
In the old design, each GUI system implemented its own limited set of functions for interacting with the inventory. This created a massive amount of code that had to be maintained and updated when anything changed that affected all of them. In the new design, all GUIs that have an inventory now implement an InventoryControlWrapper to expose shared functionality. This means one set of code is now used for all inventory related operations. This alone has reduced internal GUI code by over 5000 lines of code as a result!
One of the biggest changes to the API design is the use of local item ids now. These were previously not exposed, due to a lot of implementation limitations but they are now fully supported. Users refer to items by id now, and can lookup an item by id to know if it exists or not to figure out if an operation has completed. The previous method of checking for an item with the specific BaseAddress still works, but is less efficient.
This control exposes:
Inventory - The Inventory object of the GUI. The Inventory class holds items and offers other features such as figuring out if an item can fit.
IsItemTransparent() - A function to know if an item has been moved into a trade inventory and is now a shadow copy.
GetItemCost() - A function to get the cost of an item in a sell inventory.
ViewItemsInInventory() - A function to selectively mouse over all items in an inventory to build their display tooltips. This is for sell inventories so GetItemCost can work.
Pickup() - A function to pickup an item to the cursor from an inventory.
FastMove() - A function to perform a fast move operation, control click, on an item in the inventory. This can be used for selecting rewards, buying items, or stashing/trading.
MergeStack() - A function to merge the cursor with another item in the inventory.
SplitStack() - A function to split an item in the inventory into a stack on the cursor.
UseItem() - A function to right click an item to use it. This mechanic has changed in that it no longer applies the item, as another function does that.
BeginApplyCursor() - A function to being applying an item on the cursor to other items in the inventory. Shift use is now supported.
EndApplyCursor() - A function to end applying an item, by clearing key states.
ApplyCursorAt() - A function to apply the cursor to an item at a specific location. This is because an item's id will change after it is modified.
ApplyCursorTo() - A function to apply the cursor to an item with a specific id.
PlaceCursorInto() - A function to place the item in the cursor into a specific position in the inventory. The mechanic for placing the item has been updated to be nearly instant now and not drag anymore.
UnequipSkillGem() - A function to unequip a skillgem from an item in the inventory. This means you can now unequip skillgems from non-equipped items!
EquipSkillGem() - A function to equip a skillgem to an item in the inventory. This means you can now equip skillgems to unequipped items!
TradeControlWrapper
The TradeControlWrapper models a trade control. The trade control is used on the NPC Sell GUI as well as inside a tab in the player Trade GUI. Once again, because of this reuse, internal code is greatly simplified now.
This control exposes:
AcceptButtonText - The text of the accept button.
IsConfirmLabelVisible - A bool if the confirm label is visible.
ConfirmLabelText - The text of the confirm label.
InventoryControl_OtherOffer - An InventoryControlWrapper for working with the items in the other offer inventory.
InventoryControl_YourOffer - An InventoryControlWrapper for working with the items in your offer inventory.
Accept() - A function to accept the trade.
Cancel() - A function to cancel the trade.
Because of the new common controls, the functionality to mouse over all player traded items is exposed though the ViewItemsInInventory function in the InventoryControlWrapper!
Last edited by a moderator:






