Voilà la v2, elle permet un chaînage contrôlé et mais plus de fonctions à disposition. On créé une box , cette box sera la box maîtresse. Puis on peut ajouter des box enfants, en insérer, en retirer, cacher une partie ou la totalité de la chaîne... Pour détruire la chaîne, il suffit de faire un remove() sur la box maîtresse.
#ifndef GUI_BOXRETRACTABLE_H_INCLUDED
#define GUI_BOXRETRACTABLE_H_INCLUDED
#include "IGUIElement.h"
#include "IGUICheckBox.h"
#include "IGUIImage.h"
#include "IGUIStaticText.h"
#include "ITexture.h"
using namespace irr;
using namespace gui;
using namespace core;
using namespace video;
/**
Avantages :
- Ces boxs peuvent être une alternative au scrollbars.
- Il est possible de les chainées, ainsi une box rétractée attire les box suivantes vers elle.
- Il est possible d'insérer les boxs à taille fixe (dans la chaine ou séparement).
Inconvénients :
- La taille ne doit pas être changé après la création.
Utilisation :
#include "GUI_BoxRetractable.h"
/// création d'une chaîne de box
BoxEssai = new BoxRetractable(recti(10,10,290,110), L"Box retractable 1", mGUI, "../MEDIAS/Systeme/GUI/", mTab1);
BoxRetractable *BoxSuivante1 = BoxEssai->addBoxSuivante(50, L"Box retractable 2", 10, true);
BoxRetractable *BoxSuivante2 = BoxSuivante1->addBoxSuivante(100, L"Box taille fixe 1", 10, false);
BoxRetractable *BoxSuivante3 = BoxSuivante2->addBoxSuivante(200, L"Box retractable 3", 10, true);
/// insertion d'une box au millieu de la chaîne (note : on pourrait aussi utiliser BoxSuivante2->addBoxSuivante(...); )
BoxRetractable *BoxSuivante2bis = BoxSuivante2->insertBox(40, L"Box retractable 2 bis", 20, true);
/// destruction : ne detruire que la première box d'une chaîne
BoxEssai->remove();
**/
class BoxRetractable : public IGUIElement
{
public :
BoxRetractable(rect<s32> rectangle, stringw titre, IGUIEnvironment* environment, stringw pathImage, IGUIElement* parent=0, bool retractable=true, s32 id=-1);
~BoxRetractable();
bool OnEvent(const SEvent& event);
//! ajoute une box "enfant" (chaînage)
//! A noter que s'il existe déjà une box "enfant", la nouvelle box sera insérée avant "l'enfant" déjà présent.
BoxRetractable* addBoxSuivante(u32 hauteurBox, stringw titre, u32 espace=5, bool retractable=true);
//! renvoie le pointeur sur la box "enfant"
BoxRetractable* getBoxSuivante();
//! retire la box suivante de la chaîne sans la brisée
void deleteSuivant();
//! retire toutes les boxs suivantes de la chaîne
void deleteAllSuivant();
//! insère une box dans la chaîne, elle sera "l'enfant" de la box qui sert à l'insertion
BoxRetractable* insertBox(u32 hauteurBox, stringw titre, u32 espace=5, bool retractable=true);
//! renvoie true si la boite est dépliée et false si la boite est en mode compact
bool isExtend();
//! se détache de son parent et se détruit
void remove();
//! affiche ou cache la chaîne
void setVisible(bool visible);
protected :
//! bascule l'élément en mode compact ou complet suivant la demande
void setExtend(bool extend);
//! decale "l'enfant" de cette box suivant Y
void moveSuivant(s32 decalage);
//! decale cette box suivant Y (qui elle, décale son "enfant")
void moveRequest(s32 decalage);
/// MEMBRES ///
IGUIEnvironment* mGUI;
/// Suivant
BoxRetractable* Suivant; // pointeur vers la BoxRetractable suivante
s32 mDecalage;
s32 mTrou;
/// Instances
bool mExtend;
bool mRetractable;
recti mExtendSize;
recti mRetractSize;
position2di ExtendSize, RetractSize;
IGUICheckBox* CBExtend; IGUIStaticText* STExtend;
IGUIImage* ICaption;
IGUIImage *IDroite, *IGauche, *IBasse;
private :
static int compteurInstance;
static ITexture *TCaption;
static ITexture *TBordure;
};
#endif // GUI_BOXRETRACTABLE_H_INCLUDED
#include "GUI_BoxRetractable.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUISkin.h"
/// initilisation des membres statiques
int BoxRetractable::compteurInstance=0;
ITexture* BoxRetractable::TCaption=NULL;
ITexture* BoxRetractable::TBordure=NULL;
/**
rectangle : position et taille maximale de l'objet
title : texte affiché dans la barre de titre de la box
suivant : permet de faire une chaine de boxretractable, lorsque qu'une boite est rétractée les boites en dessous sont relevées
retractable : si dans une chaine une boite doit ne pas être rétractable
**/
BoxRetractable::BoxRetractable(rect<s32> rectangle, stringw title, IGUIEnvironment* GUI, stringw pathImage, IGUIElement* parent, bool retractable, s32 id)
: IGUIElement(EGUIET_ELEMENT, GUI, (parent!=0)?parent:GUI->getRootGUIElement(), id, rectangle), mGUI(GUI), Suivant(NULL), mTrou(0), mExtend(true), mRetractable(retractable)
{
#ifdef _DEBUG
setDebugName("BoxRetractable");
#endif
/// si c'est la première instance on charge les textures
if(compteurInstance < 1)
{
TCaption = mGUI->getVideoDriver()->getTexture(pathImage+"BoxRetractable_caption.jpg");
TBordure = mGUI->getVideoDriver()->getTexture(pathImage+"BoxRetractable_bord.jpg");
}
/// incrémente le compteur d'instance
compteurInstance++;
#ifdef _DEBUG
printf("Nb d'instances : %i\
", compteurInstance);
#endif
/// récupère le skin
IGUISkin* skin = mGUI->getSkin();
/// les tailles etendue et rétractée
mExtendSize = rectangle;
mRetractSize = mExtendSize;
mRetractSize.LowerRightCorner.Y = rectangle.UpperLeftCorner.Y + skin->getSize(EGDS_CHECK_BOX_WIDTH) + 2;
/// dimension relatives
ExtendSize = position2di(rectangle.LowerRightCorner.X-rectangle.UpperLeftCorner.X,rectangle.LowerRightCorner.Y-rectangle.UpperLeftCorner.Y);
RetractSize = position2di(ExtendSize.X,skin->getSize(EGDS_CHECK_BOX_WIDTH) + 2);
/// image de fond du titre
recti CaptionSize(position2di(0,0),RetractSize);
ICaption = mGUI->addImage(CaptionSize, this);
ICaption->setImage(TCaption);
ICaption->setScaleImage(true);
/// choix entre retractable ou non
if(retractable)
{
STExtend = NULL;
/// bouton "extend" pour le pliage et le dépliage et titre de l'élément
CBExtend = mGUI->addCheckBox(true, recti(position2di(1,1), CaptionSize.LowerRightCorner), this, -1, title.c_str());
}
else
{
CBExtend = NULL;
/// affiche le titre mais pas la box
STExtend = mGUI->addStaticText(title.c_str(), recti(position2di(skin->getSize(EGDS_CHECK_BOX_WIDTH)+6, 1), CaptionSize.LowerRightCorner), false, false, this);
STExtend->setTextAlignment(EGUIA_UPPERLEFT, EGUIA_CENTER);
}
/// cadre entourant la box
// bordure gauche
recti bordure_gauche(0,CaptionSize.LowerRightCorner.Y,1,ExtendSize.Y);
IGauche = mGUI->addImage(bordure_gauche, this);
IGauche->setImage(TBordure);
IGauche->setScaleImage(true);
// bordure droite
recti bordure_droite(ExtendSize.X-1,CaptionSize.LowerRightCorner.Y,ExtendSize.X,ExtendSize.Y);
IDroite = mGUI->addImage(bordure_droite, this);
IDroite->setImage(TBordure);
IDroite->setScaleImage(true);
// bordure basse
recti bordure_basse(0,ExtendSize.Y-1,ExtendSize.X,ExtendSize.Y);
IBasse = mGUI->addImage(bordure_basse, this);
IBasse->setImage(TBordure);
IBasse->setScaleImage(true);
/// calcule le décalage
mDecalage = mExtendSize.LowerRightCorner.Y - mRetractSize.LowerRightCorner.Y;
}
BoxRetractable::~BoxRetractable()
{
/// décrémente le compteur d'instance
compteurInstance--;
#ifdef _DEBUG
printf("Nb d'instances : %i\
", compteurInstance);
#endif
/// libération des ressources
if(STExtend) STExtend->remove();
if(ICaption) ICaption->remove();
if(IGauche) IGauche->remove();
if(IDroite) IDroite->remove();
if(IBasse) IBasse->remove();
/// retire les textures si on en a plus besoin
if(compteurInstance < 1)
{
if(TCaption) { mGUI->getVideoDriver()->removeTexture(TCaption); TCaption = NULL; }
if(TBordure) { mGUI->getVideoDriver()->removeTexture(TBordure); TBordure = NULL; }
}
/// détruit son enfant (qui lui-même va détruire le sien...)
if(Suivant) Suivant->remove();
}
bool BoxRetractable::OnEvent(const SEvent& event)
{
/// événements de la GUI
if (event.EventType == EET_GUI_EVENT)
{
if (event.GUIEvent.EventType == EGET_CHECKBOX_CHANGED)
{
if(mRetractable)
{
if(event.GUIEvent.Caller == CBExtend)
{
if(CBExtend->isChecked()) setExtend(true);
else setExtend(false);
}
}
}
}
/// si aucun événement n'a été traité par BoxRetractable
return IGUIElement::OnEvent(event);
}
BoxRetractable* BoxRetractable::addBoxSuivante(u32 hauteurBox, stringw titre, u32 espace, bool retractable)
{
/// s'il y a déjà une box suivante on l'insert dans la chaîne
if(Suivant != NULL) return insertBox(hauteurBox, titre, espace, retractable);
/// détermine le rectangle occupé par la box
recti base = getRelativePosition();
recti rectangle(position2di(base.UpperLeftCorner.X,base.LowerRightCorner.Y+espace),position2di(base.LowerRightCorner.X,base.LowerRightCorner.Y+espace+hauteurBox));
/// créé la box suivante
Suivant = new BoxRetractable(rectangle, titre.c_str(), mGUI, "", Parent, retractable);
/// calcul la taille du trou
Suivant->mTrou = hauteurBox + espace;
/// retourne la box créée
return Suivant;
}
BoxRetractable* BoxRetractable::getBoxSuivante()
{
return Suivant;
}
void BoxRetractable::deleteSuivant()
{
if(Suivant != NULL)
{
/// enregistre le "Suivant" de la box à détruire
BoxRetractable *tmp = Suivant->getBoxSuivante();
/// on récupère la taille du trou que va créer l'enlèvement de la box
s32 tailletrou = Suivant->mTrou;
/// delete la box
Suivant->remove();
/// attache le "Suivant" de la box à détruire à elle-même
Suivant = tmp;
/// on décale le nouveau "Suivant"
if(Suivant != NULL) moveSuivant(-tailletrou);
}
}
void BoxRetractable::deleteAllSuivant()
{
/// s'il y a encore un suivant, on le détruit
if(Suivant != NULL)
{
Suivant->deleteAllSuivant();
Suivant->remove();
}
}
BoxRetractable* BoxRetractable::insertBox(u32 hauteurBox, stringw titre, u32 espace, bool retractable)
{
/// on sauvegarde le suivant actuel
BoxRetractable* tmp = Suivant;
Suivant = NULL;
/// on créé la nouvelle box
Suivant = addBoxSuivante(hauteurBox, titre, espace, retractable);
/// s'il y a des suivants
if(tmp != NULL)
{
/// on y accroche la chaîne
Suivant->Suivant = tmp;
/// on décale toute les autres box de la chaîne
tmp->moveRequest(Suivant->mTrou);
}
/// on renvoie un pointeur sur la nouvelle box
return Suivant;
}
bool BoxRetractable::isExtend()
{
return mExtend;
}
void BoxRetractable::remove()
{
if(Parent) Parent->removeChild(this);
delete this;
}
void BoxRetractable::setVisible(bool visible)
{
setVisible(visible);
Suivant->setVisible(visible);
}
void BoxRetractable::setExtend(bool extend)
{
if(mExtend == !extend)
{
/// récupère la position
recti newPos = getRelativePosition();
/// modifie la taille de l'élément
if(extend) newPos.LowerRightCorner = newPos.UpperLeftCorner + ExtendSize;
else newPos.LowerRightCorner = newPos.UpperLeftCorner + RetractSize;
/// applique la nouvelle taille
setRelativePosition(newPos);
/// décale son enfant
if(extend) moveSuivant(mDecalage);
else moveSuivant(-mDecalage);
/// change l'état extend de la box
mExtend = extend;
}
}
void BoxRetractable::moveSuivant(s32 decalage)
{
if(Suivant != NULL) Suivant->moveRequest(decalage);
}
void BoxRetractable::moveRequest(s32 decalage)
{
move(position2di(0,decalage));
moveSuivant(decalage);
}