I. Gestion des événements

Image non disponible

Comme toujours, nous incluons les fichiers d'en-têtes, et nous utilisons l'espace de nommage d'Irrlicht. Nous stockons aussi un pointeur sur le moteur d'Irrlicht, un compteur pour changer la position d'une fenêtre à sa création, et un pointeur sur une liste déroulante.

 
Sélectionnez
#include <irrlicht.h>
#include "driverChoice.h"

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif

// Déclare une structure pour stocker le contexte du receveur d'événement
// dont il a besoin dans sa méthode OnEvent().
struct SAppContext
{
    IrrlichtDevice *device;
    s32             counter;
    IGUIListBox*    listbox;
};

// Défini quelques valeurs que nous utiliserons pour identifier les différents contrôles de l'interface utilisateur.
enum
{
    GUI_ID_QUIT_BUTTON = 101,
    GUI_ID_NEW_WINDOW_BUTTON,
    GUI_ID_FILE_OPEN_BUTTON,
    GUI_ID_TRANSPARENCY_SCROLL_BAR
};

Le receveur d'événement n'est pas seulement capable d'obtenir les événements d'entrée du clavier et de la souris, mais il peut aussi obtenir les événements de l'interface utilisateur graphique. Il y a des événements pour presque tout : les clics de boutons, le changement de sélection dans une liste déroulante, des événements qui disent qu'un élément a été survolé et bien plus. Pour être capable de réagir à ces événements, nous créons un receveur d'événement. Nous ne réagirons qu'aux événements de l'interface graphique, et si c'est le cas, nous obtenons l'identifiant de l'appelant (l'élément de l'interface à l'origine de l'événement) et nous obtenons un pointeur sur l'environnement de l'interface.

 
Sélectionnez
class MyEventReceiver : public IEventReceiver
{
public:
    MyEventReceiver(SAppContext & context) : Context(context) { }

    virtual bool OnEvent(const SEvent& event)
    {
        if (event.EventType == EET_GUI_EVENT)
        {
            s32 id = event.GUIEvent.Caller->getID();
            IGUIEnvironment* env = Context.device->getGUIEnvironment();

            switch(event.GUIEvent.EventType)
            {

I-A. Événement généré par la barre de défilement

Si une barre de défilement voit sa position changée, et si c'est la nôtre (celle avec l'identifiant GUI_ID_TRANSPARENCY_SCROLL_BAR), alors nous changeons la transparence de tous les éléments de l'interface. Ceci est très facile : il y a un objet « skin », dans lequel tous les paramètres des couleurs sont stockés. Nous parcourons simplement toutes les couleurs stockées dans le « skin » et nous changeons leur valeur alpha.

 
Sélectionnez
            case EGET_SCROLL_BAR_CHANGED:
                if (id == GUI_ID_TRANSPARENCY_SCROLL_BAR)
                {
                    s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                    
                    for (u32 i=0; i<EGDC_COUNT ; ++i)
                    {
                        SColor col = env->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
                        col.setAlpha(pos);
                        env->getSkin()->setColor((EGUI_DEFAULT_COLOR)i, col);
                    }
                    
                }
                break;

I-B. Événement généré par les boutons

Si un bouton a été cliqué, il pourrait bien être l'un de nos trois boutons. Si c'est le premier, nous arrêtons le moteur. Si c'est le second, nous créons une petite fenêtre avec du texte dedans. Nous ajoutons aussi une chaîne de caractères à la liste déroulante pour inscrire ce qu'il se passe. Et si c'est le troisième bouton, nous créons une pop-up d'ouverture de fichier et nous ajoutons le nom du fichier sélectionné comme une nouvelle entrée dans notre liste déroulante. C'est tout pour le receveur d'événement.

 
Sélectionnez
            case EGET_BUTTON_CLICKED:
                switch(id)
                {
                case GUI_ID_QUIT_BUTTON:
                    Context.device->closeDevice();
                    return true;

                case GUI_ID_NEW_WINDOW_BUTTON:
                    {
                    Context.listbox->addItem(L"Window created");
                    Context.counter += 30;
                    if (Context.counter > 200)
                        Context.counter = 0;

                    IGUIWindow* window = env->addWindow(
                        rect<s32>(100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter),
                        false, // modal?
                        L"Test window");

                    env->addStaticText(L"Please close me",
                        rect<s32>(35,35,140,50),
                        true, // bordure ?
                        false, // retours à la ligne ?
                        window);
                    }
                    return true;

                case GUI_ID_FILE_OPEN_BUTTON:
                    Context.listbox->addItem(L"File open");
                    // Il y a quelques options pour l'ouverture de fichier.
                    // Nous mettons le titre, indiquons qu'elle sera une fenêtre modale et nous assurons
                    // que le dossier de travail est restauré après que la fenêtre se soit fermée.
                    env->addFileOpenDialog(L"Please choose a file.", true, 0, -1, true);
                    return true;

                default:
                    return false;
                }
                break;

            case EGET_FILE_SELECTED:
                {
                    // Montre le nom du fichier sélectionné dans la fenêtre d'ouverture de fichier.
                    IGUIFileOpenDialog* dialog =
                        (IGUIFileOpenDialog*)event.GUIEvent.Caller;
                    Context.listbox->addItem(dialog->getFileName());
                }
                break;

            default:
                break;
            }
        }

        return false;
    }

private:
    SAppContext & Context;
};

II. Mise en place des éléments de l'interface utilisateur

Ok, maintenant la partie la plus intéressante. Premièrement, nous créons le moteur Irrlicht. Comme dans certains exemples précédents, nous demandons à l'utilisateur quel pilote il veut utiliser pour cet exemple :

 
Sélectionnez
int main()
{
    // demande à l'utilisateur un pilote à utiliser
    video::E_DRIVER_TYPE driverType=driverChoiceConsole();
    if (driverType==video::EDT_COUNT)
        return 1;

    // crée un moteur et quitte si la création a échouée

    IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(640, 480));

    if (device == 0)
        return 1; // on ne peut pas créer le pilote sélectionné

La création a réussie, maintenant nous installons le receveur d'événement et nous stockons le pilote dans l'environnement de l'interface utilisateur.

 
Sélectionnez
    device->setWindowCaption(L"Irrlicht Engine - User Interface Demo");
    device->setResizable(true);

    video::IVideoDriver* driver = device->getVideoDriver();
    IGUIEnvironment* env = device->getGUIEnvironment();

Pour rendre la police plus jolie, nous chargeons une police externe et nous la définissons comme nouvelle police par défaut du « skin ». Pour garder la police standard pour les info-bulles, nous la définissons comme police intégrée.

 
Sélectionnez
    IGUISkin* skin = env->getSkin();
    IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
    if (font)
        skin->setFont(font);

    skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP);

Nous ajoutons trois boutons. Le premier ferme le moteur. Le second crée une fenêtre et le troisième ouvre une pop-up d'ouverture de fichier. Le troisième paramètre est l'identifiant du bouton avec lequel nous pouvons facilement identifier le bouton dans le receveur d'événement.

 
Sélectionnez
    env->addButton(rect<s32>(10,240,110,240 + 32), 0, GUI_ID_QUIT_BUTTON,
            L"Quit", L"Exits Program");
    env->addButton(rect<s32>(10,280,110,280 + 32), 0, GUI_ID_NEW_WINDOW_BUTTON,
            L"New Window", L"Launches a new Window");
    env->addButton(rect<s32>(10,320,110,320 + 32), 0, GUI_ID_FILE_OPEN_BUTTON,
            L"File Open", L"Opens a file");

Maintenant nous ajoutons un texte statique et une barre de défilement, qui modifie la transparence de tous les éléments de l'interface utilisateur. Nous mettons la valeur maximale de la barre de défilement à 255 parce que c'est la valeur maximale pour une valeur de couleur. Après nous créons un autre texte statique et la liste déroulante.

 
Sélectionnez
    env->addStaticText(L"Transparent Control:", rect<s32>(150,20,350,40), true);
    IGUIScrollBar* scrollbar = env->addScrollBar(true,
            rect<s32>(150, 45, 350, 60), 0, GUI_ID_TRANSPARENCY_SCROLL_BAR);
    scrollbar->setMax(255);

    // met la position de la barre de défilement à la valeur alpha d'un élément choisi arbitrairement
    scrollbar->setPos(env->getSkin()->getColor(EGDC_WINDOW).getAlpha());

    env->addStaticText(L"Logging ListBox:", rect<s32>(50,110,250,130), true);
    IGUIListBox * listbox = env->addListBox(rect<s32>(50, 140, 250, 210));
    env->addEditBox(L"Editable Text", rect<s32>(350, 80, 550, 100));

    // Stocke les données appropriées dans la structure de contexte.
    SAppContext context;
    context.device = device;
    context.counter = 0;
    context.listbox = listbox;

    // Enfin, crée le receveur d'événement, on lui donne la structure de contexte.
    MyEventReceiver receiver(context);

    // Et nous disons au moteur d'utiliser notre receveur d'événement personnel.
    device->setEventReceiver(&receiver);

Et finalement, nous créons le joli logo du moteur Irrlicht.

 
Sélectionnez
    env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"),
            position2d<int>(10,10));

C'est tout, il nous reste plus qu'à tout dessiner.

 
Sélectionnez
   while(device->run() && driver)
    if (device->isWindowActive())
    {
        driver->beginScene(true, true, SColor(0,200,200,200));

        env->drawAll();
    
        driver->endScene();
    }

    device->drop();

    return 0;
}

III. Conclusion

Vous pouvez désormais construire votre propre interface utilisateur avec Irrlicht.

Dans le prochain tutoriel : Graphisme 2D, nous verrons comment afficher des images 2D avec le moteur Irrlicht, il vous permettra par exemple de dessiner une interface personnalisée.

IV. Remerciements

Merci à Nikolaus Gebhardt de nous permettre de traduire ce tutoriel.

Merci à LittleWhite pour sa relecture technique ainsi qu'à f-leb pour sa relecture orthographique.