UI Management and Manipulation - morcSkyrim/SkyrimSE GitHub Wiki

Ryan's Skywind repository provides a substantial amount of coding manipulating UI's. Includes adding custom events, opening and closing menus.

The UI Class

The UI class provides a useful interface for determining what is going on in the program at a given time. It contains information on the menus currently in use, in addition to providing several member variables which contain information on the state of the menus.

The class has two primary members used for assessing the menus in use. The first (menuStack) is a stack, which contains the menus currently in use. The second (menuMap) is a map containing the name of the menu, in addition to its associated IMenu.

The menus on the stack and map are objects which inherit from the IMenu virtual class, providing a common interface.

Using the UI class

I only know how to use some of the basic functionality of the UI class, fortunately the member functions provided by CommonLib are extremely self explanatory. Instead, I think most of the classes functionality lies in using it to learn about the state of the various game menus. The menuMap can be used to print the names of the presently used menus at any instance in time.

Example

Say we want to close the inventory on some button press, we need to know what menus are open at a given time. To do this we iterate through the menuMap calling OnStack(), telling us whether the menu is in use or not. In the event that it is on the stack, we print the associated key of the menu.

  void MenusOnStack() {
      auto ui = RE::UI::GetSingleton();
  	auto iterator = ui->menuMap.cbegin();
  	for (uint32_t i = 0; i < ui->menuMap.size(); i++) {
  		auto menu = iterator->second.menu.get();
  		if (menu != NULL) {
  			auto onStack = menu->OnStack();
  			if (onStack) {
  				spdlog::info(iterator->first);
  			}
  		}
  		++iterator;
  	}
  }

Calling this function while the inventory is open yields, cursorMenu, tweenMenu, hudMenu, and inventoryMenu. Given that I would like to close the inventory, I then need to know which of these is used under normal circumstances. We then just call this function when the inventory is closed, where we find that hudMenu is the only menu open.

So to close the inventory we just need to close the cursor, tween, and inventory menus using the UIMessageQueue class. If you are using mods which modify user interfaces, the inventories on the stack may be completely different at any given time, so this may need to be performed on a case by case basis.

UIMessageQueue

Basically provides a game native method of manipulating menus.

    AddMessage(const BSFixedString& a_menuName, UI_MESSAGE_TYPE a_type, IUIMessageData* a_data)

allows for the manipulation of menu states. The UI_MESSAGE_TYPE, specifies what operation to perform on the menu, with options

enum class UI_MESSAGE_TYPE
{
    kUpdate = 0,
    kShow = 1,
    kReshow = 2,
    kHide = 3,
    kForceHide = 4,

    kScaleformEvent = 6,   // BSUIScaleformData
    kUserEvent = 7,		   // BSUIMessageData
    kInventoryUpdate = 8,  // InventoryUpdateData
    kUserProfileChange = 9,
    kMUStatusChange = 10,
    kResumeCaching = 11,
    kUpdateController = 12,
    kChatterEvent = 13
};

so specifying kHide will close the associated menu. I'm still quite unsure of the purpose of a_data.

Example

From the prior example, assume we would like to close the inventory, tween, and cursor menus,

auto uiQueue = RE::UIMessageQueue::GetSingleton();
auto intfcStr = RE::InterfaceStrings::GetSingleton();
uiQueue->AddMessage(intfcStr->inventoryMenu, RE::UI_MESSAGE_TYPE::kHide, 0);
uiQueue->AddMessage(intfcStr->cursorMenu, RE::UI_MESSAGE_TYPE::kHide, 0);
uiQueue->AddMessage(intfcStr->tweenMenu, RE::UI_MESSAGE_TYPE::kHide, 0);
⚠️ **GitHub.com Fallback** ⚠️