Skip to content

Extra Menu Documents Functionality and .rml

brodenini edited this page Feb 7, 2013 · 7 revisions

WIP


Here follows a brief summary of some custom rules that has been implemented to extend functionality in rml-files.

LibRocketEventManagerSystem

A system that processes specific event commands implemented to give a nice menu flow. It also allows other systems (deriving from EventHandler) to process additional commands that isn't processed by the LibRocketEventManagerSystem (more about that below).

Clearing the stack

The system above uses an internal stack to keep track of the documents that are opened (not to be confused with being visible). Clearing the stack removes all documents and hides them if they are visible. This is done by calling this method:

void LibRocketEventManagerSystem::clearDocumentStack()

Event commands

modal

Specifies that the document should stay focused with the modal option. A modal document is a document that doesn't lose its focus until it has been hidden.

Example from main_menu.rml:

<body id="main_menu" template="window" onshow="modal">
    [...]
</body>

The first/root document that is displayed on screen should always have the modal option set. The root document should also be loaded in the LibRocketEventManagerSystem in order to be processed. Currently, all existing documents are loaded in the MenuSystem. The first menu is also loaded in the LibRocketEventManagerSystem.

rocketEventManager->loadWindow("main_menu");

goto #document_id#

Hides the current document and shows the document with the specified id and pushes it onto the open documents stack. The id is the id defined in the body (see "main_menu" as example above). In the source code, there's a method

int LibRocketBackendSystem::loadDocumentByName(const char* p_windowName)
int LibRocketBackendSystem::loadDocument( const char* p_filePath, const char* p_windowName=NULL)
This windowName will _OVERRIDE_ the id specified in the body, so if either of these methods are used when loading a
document (it is recommended that they are used), specifying the body id in the rml file is not required. The latter method will extract the windowName basing it on the filePath, if it's not specified.
To retrieve a document later, use
int LibRocketBackendSystem::getDocumentByName(const char* p_id)

goto previous

Hides the current document and pops it from the open documents stack. Shows the previous document (that is now at to top of the stack).

exit

Hides and clears all documents from the stack. Requests that the world should shutdown.

open #document_id#

Opens a document without hiding the parent document. If the opened document is modal, focus of the parent document will be lost. To regain focus, use goto previous.


Note that there is NO command open previous. Would we want support for recursive opening of a previously opened document:P?


There can be written multiple commands in a single attribute string. In order to do so, use ; as delimiter

Example:

<form onsubmit="apply_settings; goto previous">
	[Some more content here]
</form>

Event Handlers

There's also support to add arbitrary amount of commands that isn't handled by the LibRocketEventManagerSystem. For these, a class derived from EventHandler (and recommended, also from EntitySystem so that other systems can be utilized) implementing the

void EventHandler::processEvent( Rocket::Core::Event& p_event, const Rocket::Core::String& p_value )

For instance, GameOptionsSystem is currently interested in parsing the commands apply_settings and restore_settings.

void GameOptionsSystem::processEvent( Rocket::Core::Event& p_event, const Rocket::Core::String& p_value )
{
    // The value here should match the onsubmit attribute in the options-rml-file.
    // For instance, if it says <form onsubmit="apply_settings; goto main_menu"> then it means that
    // the value we are interested in is "apply_settings".
    // However, there could also be other interesting values, such as "restore_settings".
    if (value == "apply_settings")
    {
        DEBUGPRINT(("GameOptionsSystem::processEvent(event, value=apply_settings) was called."));
    }
    else if (value == "restore_settings")
    {
        DEBUGPRINT(("GameOptionsSystem::processEvent(event, value=restore_settings) was called."));
    }
}

Another example would be the ClientConnectToServerSystem, which is interested in the join_server command.

void ClientConnectToServerSystem::processEvent( Rocket::Core::Event& p_event, const Rocket::Core::String& p_value )
{
    // Sent from the 'onsubmit' of the play screen, we set the network ip and port here,
    // and enable the system.
    if (p_value == "join_server")
    {
        // "server_host" is the name attribute specified in the input element in the rml file.
        // "localhost" simply is provided as a default value, if the host isn't set. This could be left as "" as well.
        string server_host = p_event.GetParameter<Rocket::Core::String>("server_host", "localhost").CString();
        string server_port = p_event.GetParameter<Rocket::Core::String>("server_port", "1337").CString();

        if( !m_tcpClient->hasActiveConnection() &&  !m_isLookingForConnection)
            connectToNetworkAddress(server_host, server_port);
    }
}

EventHandler registration

In order to be able to process commands like the ones in the examples above, the instance of the derived EventHandler must be registered. To sum everything up, this is the current code snippet inside MenuSystem that initializes menu documents:

rocketEventManager->registerEventHandler(connectToServerSys);
rocketEventManager->registerEventHandler(gameOptionsSys);

rocketBackend->loadDocumentByName("main_menu");
rocketBackend->loadDocumentByName("play");
rocketBackend->loadDocumentByName("join");
rocketBackend->loadDocumentByName("host");
rocketBackend->loadDocumentByName("options");
rocketBackend->loadDocumentByName("credits");

rocketEventManager->loadWindow("main_menu");
Clone this wiki locally