I. Gestion des événements▲
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.
#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.
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.
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.
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 :
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.
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.
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.
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.
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.
env->
addImage(driver->
getTexture("../../media/irrlichtlogo2.png"
),
position2d<
int
>
(10
,10
));
C'est tout, il nous reste plus qu'à tout dessiner.
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.