Voilà j'ai codé ça cet après-midi donc je partage.
C'est un nouveau GUIElement qui se presente sous forme de boite avec une barre de titre et qui a la particularité de pouvoir se rétracter et prendre une forme compacte (seule la barre de titre reste visible). Elle possède aussi le nécessaire pour chainer plusieurs boites les une aux autres afin que lorsque qu'une boite se rétracte elle tire la boite qui lui est associée qui elle-même tire la boite qui lui est associée...
Pour les avantages, inconvénients et l'utilisation, j'ai mis ce qu'il faut dans le .h. Si quelqu'un a des idées pour améliorer, ou si quelqu'un l'améliore de son côté qu'il poste ça, on pourrait avoir quelque chose de sympa.
Voici des screenshots :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #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 BoxRetractable* BoxEssai = new BoxRetractable(recti(10,10,290,110), L"Box retractable", mGUI, "../include/GUI_BoxRetractable/", element_parent); BoxRetractable* BoxEssaiSuivant = new BoxRetractable(recti(10,115,290,265), L"Box retractable Suivante", mGUI, "../include/GUI_BoxRetractable/", element_parent); /// insertion d'une box fixe BoxRetractable* BoxEssaiTailleFixe = new BoxRetractable(recti(10,270,290,320), L"Box non retractable", mGUI, "../include/GUI_BoxRetractable/", element_parent, NULL, false); BoxRetractable* BoxEssaiSuivant2 = new BoxRetractable(recti(10,325,290,525), L"Box retractable Suivante2", mGUI, "../include/GUI_BoxRetractable/", element_parent); /// liaison des boxs (chainage) BoxEssai->setSuivant(BoxEssaiSuivant); BoxEssaiSuivant->setSuivant(BoxEssaiTailleFixe); BoxEssaiTailleFixe->setSuivant(BoxEssaiSuivant2); /// destruction BoxEssai->remove(); BoxEssaiSuivant->remove(); BoxEssaiTailleFixe->remove(); BoxEssaiSuivant2->remove(); **/ class BoxRetractable : public IGUIElement { public : BoxRetractable(rect<s32> rectangle, stringw titre, IGUIEnvironment* environment, stringw pathImage="../include/GUI_BoxRetractable/", IGUIElement* parent=0, BoxRetractable* suivant=NULL, bool retractable=true, s32 id=-1); ~BoxRetractable(); bool OnEvent(const SEvent& event); void moveRequest(s32 decalageY); void setSuivant(BoxRetractable* suivant); protected : IGUIEnvironment* mGUI; /// BoxRetractable* Suivant; // pointeur vers la BoxRetractable suivante void setExtend(bool extend); void moveSuivant(s32 decalage); s32 mDecalage; /// 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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | #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, BoxRetractable* suivant, bool retractable, s32 id) : IGUIElement(EGUIET_ELEMENT, gui, (parent!=0)?parent:gui->getRootGUIElement(), id, rectangle), mGUI(gui), Suivant(suivant), mRetractable(retractable) { #ifdef _DEBUG setDebugName("../include/GUI_BoxRetractable/"); #endif /// si c'est la première instance on charge les textures if(compteurInstance < 1) { TCaption = mGUI->getVideoDriver()->getTexture(pathImage+"BoxRetractable"); TBordure = mGUI->getVideoDriver()->getTexture(pathImage+"BoxRetractable_caption.jpg"); } /// incrémente le compteur d'instance compteurInstance++; #ifdef _DEBUG printf("BoxRetractable_bord.jpg", 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\n", 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(); if(compteurInstance < 1) { if(TCaption) { mGUI->getVideoDriver()->removeTexture(TCaption); TCaption = NULL; } if(TBordure) { mGUI->getVideoDriver()->removeTexture(TBordure); TBordure = NULL; } } } 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); moveSuivant(mDecalage); } else { setExtend(false); moveSuivant(-mDecalage); } } } } } /// si aucun événement n'a été traité par BoxRetractable return IGUIElement::OnEvent(event); } void BoxRetractable::setSuivant(BoxRetractable* suivant) { Suivant = suivant; } void BoxRetractable::setExtend(bool 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); } void BoxRetractable::moveSuivant(s32 decalage) { if(Suivant != NULL) Suivant->moveRequest(decalage); } void BoxRetractable::moveRequest(s32 decalage) { move(position2di(0,decalage)); moveSuivant(decalage); } |
Les 2 fichiers images qui servent de shin à la box : (ces fichiers sont nécessaires et il faut donner le chemin d'accès à la création de la box)
Pour les enregistrer "clic droit" sur le lien, "enregistrer la cible sous" car les fichiers sont tout petits.
BoxRetractable_bord.jpg
BoxRetractable_caption.jpg
Voilà!
Màj 1 : chargement unique des textures et destruction automatique grace à un compteur d'instance.
Prochaines fonctionnalités à implémenter :
- ajout et chainage avec des positions relatives entre les maillons; FAIT dans la v2
Dernière modification par johnplayer (05-07-2012 13:44:48)
Hors ligne
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | #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\n", 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\n", 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); } |
Hors ligne
Une nouvelle fonctionnalité! Il me manquait les bouton radio donc je me suis dit que je pouvais utilisé mes BoxRetractables comme GroupBox.
Le principe est simple :
- on créé une BoxRetractable;
- on créé le BoutonRadioControl;
- on ajoute des checkBox qui serviront de bouton radio.
Il y a 2 fonctionnements possible : normal ou atypique.
Normal :
Seul un bouton est actif. L'activation d'un autre bouton désactive tous les autres.
Il y a TOUJOURS un bouton actif.
Atypique :
Seul un bouton peut être actif. L'activation d'un autre bouton désactive tous les autres.
On peut désactivé TOUS les boutons.
Comme d'habitude, toutes les explications sont données dans les *.h avant la déclaration de la classe.
Je ne remets pas les images, elles sont dans le premier post.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | #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; class BoutonRadioControl; /** 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(); /// création du BoutonRadioControl (1 exemplaire par BoxRetractable) BoxSuivante2->createBoutonRadioControl(false); /// ajout de checkbox à la BoxRetractable (et au BoutonRadioControl) BoxSuivante2->addCheckBoxToBoutonRadioControl(recti(5,25,25,45)); BoxSuivante2->addCheckBoxToBoutonRadioControl(recti(30,25,50,45)); BoxSuivante2->addCheckBoxToBoutonRadioControl(recti(55,25,75,45)); BoxSuivante2->addCheckBoxToBoutonRadioControl(recti(80,25,100,45)); **/ 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); //! créé un BoutonRadioControl associée à la BoxRetractable void createBoutonRadioControl(bool atypique=false); //! ajoute une checkbox à la BoxRetractable, l'assigne au BoutonRadioControl et renvoie un pointeur //! index renvoie la position de la nouvelle checkbox dans la liste s32 addCheckBoxToBoutonRadioControl(recti rectangle, IGUICheckBox* checkbox=NULL, const wchar_t *text=0); //! renvoie un pointeur sur la CheckBox active IGUICheckBox* getCheckBoxActive(); //! renvoie la position dans la liste de la CheckBox active s32 getCheckBoxActiveIndex(); 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; /// utilisation GroupBox BoutonRadioControl *GroupBox; private : static int compteurInstance; static ITexture *TCaption; static ITexture *TBordure; }; #endif // GUI_BOXRETRACTABLE_H_INCLUDED |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | #include "GUI_BoxRetractable.h" #include "GUI_BoutonRadioControl.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), GroupBox(NULL) { #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\n", 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\n", 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(); if(GroupBox) { GroupBox->removeAllBox(); GroupBox->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) { if (isEnabled()) { /// é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); return true; } } } } if(mExtend) { if(GroupBox != NULL) if(GroupBox->OnEvent(event)) return true; } } /// 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::createBoutonRadioControl(bool atypique) { if(GroupBox == NULL) GroupBox = new BoutonRadioControl(atypique); } s32 BoxRetractable::addCheckBoxToBoutonRadioControl(recti rectangle, IGUICheckBox* checkbox, const wchar_t *text) { IGUICheckBox *tmp = mGUI->addCheckBox(false, rectangle, this, -1, text); checkbox = tmp; return GroupBox->addCheckBox(tmp); } IGUICheckBox* BoxRetractable::getCheckBoxActive() { return GroupBox->getCheckedBox(); } s32 BoxRetractable::getCheckBoxActiveIndex() { return GroupBox->getChecked(); } 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); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | #ifndef GUI_BOUTONRADIOCONTROL_H_INCLUDED #define GUI_BOUTONRADIOCONTROL_H_INCLUDED #include "IGUICheckBox.h" using namespace irr; using namespace gui; using namespace core; /** Cette classe permet de servir des checkBox comme des boutons radio. Seul un bouton peut être actif.L'activation d'un autre bouton désactive tous les autres. Elle n'affiche rien elle gère juste les events des checkbox qui lui sont associées. Si mAtypique=true, BoutonRadioControl autorise la désactivation de toutes les checkboxs. **/ class BoutonRadioControl { public: BoutonRadioControl(bool atypique=false) : mAtypique(atypique) { /// initilisation des membres mActive = 0; } ~BoutonRadioControl() { mListe.clear(); } //! détruit le BoutonRadioControl void remove() { delete this; } //! détruit toutes les checkBox void removeAllBox() { for(u32 a=0; a < mListe.size(); a++) mListe[a]->remove(); } //! ajoute une checkbox a la liste s32 addCheckBox(IGUICheckBox* newCB) { /// teste si c'est la première insérée if(!mListe.empty()) { /// vérifie qu'elle n'est pas déjà inséré for(u32 a=0; a < mListe.size(); a++) if(mListe[a] == newCB) return -1; /// elle n'est pas déjà inséré donc on la met dans la liste mListe.push_back(newCB); /// s'assure que la box n'est pas checké newCB->setChecked(false); } else { /// on la met dans la liste mListe.push_back(newCB); /// on l'active puisque c'est la première newCB->setChecked(true); mActive = 1; } /// renvoie la position return mListe.size() - 1; } //! supprime une checkbox de la liste void deleteCheckBox(IGUICheckBox* oldCB) { /// s'il y a une checkbox dans la liste if(!mListe.empty()) { /// cherche la checkbox dans la liste for(u32 a=0; a < mListe.size(); a++) { if(mListe[a] == oldCB) { bool changementActif=false; /// si c'est la checkbox active if(a == (mActive-1) ) changementActif=true; /// efface la checkbox de la liste mListe.erase(a); /// si il y a besoin d'un changement de checkbox active if(changementActif) setChecked(1); /// on sort return; } } } } //! gère les checkbox bool OnEvent(const SEvent& event) { /// événements de la gui if (event.EventType == EET_GUI_EVENT) { if(event.GUIEvent.EventType == EGET_CHECKBOX_CHANGED) { for(u32 a=0; a < mListe.size(); a++) if(event.GUIEvent.Caller == mListe[a]) { if(mListe[a]->isChecked()) setChecked(a); else { if(mAtypique) { mListe[a]->setChecked(false); mActive = 0; } else mListe[a]->setChecked(true); } return true; } } } /// aucun événement n'a été traité return false; } //! renvoie l'id de la checkbox active et -1 si aucune ne l'est s32 getChecked() { return (mActive - 1); } //! renvoie un pointeur sur la checkbox active et NULL si aucune ne l'est IGUICheckBox* getCheckedBox() { if(mActive < 1) return NULL; return mListe[mActive - 1]; } //! check une checkbox et "décheck" toutes les autres void setChecked(u32 IDcheck) { if(mListe.empty()) mActive = 0; else /// si la checkbox existe et qu'elle n'est pas déjà active if( (IDcheck < mListe.size()) && ((mActive-1) != IDcheck) ) { /// "décheck" l'ancienne checkbox active if(mActive > 0) mListe[mActive-1]->setChecked(false); /// on met à jour l'index de la checkbox active mActive = IDcheck+1; } } //! renvoie le nombre de checkbox assignées au control u32 getCheckBoxCount() { return mListe.size(); } protected: /// MEMBRES /// array<IGUICheckBox*> mListe; u32 mActive; // attention : elle vaut (index_de_la_box + 1) car le 0 est utilisé pour le cas où aucune checkbox n'est checkée bool mAtypique; }; #endif // GUI_BOUTONRADIOCONTROL_H_INCLUDED |
Voilà, j'aurais certainement d'autres bouts de code à poster suivant ce que je dois coder pour ma gui.
Hors ligne
ah, bien super johnplayer
petit code qui en arangerons plus d'un,
sympas pour le partage, j'était passer a coter, merci
par contre pourquoi ne pas utiliser l'array présent dans IGUIElement qui contient les childs pour géré le bouton radio ?
avec un bête if(child[i]->getType() == EGT_CHECKBOX) ?
ou plutot je n'aurais pas fait un groupbox, mais j'aurais surment relier les buttonbox par le parent et donc dériver le buttonbox de la checkbox
parent->child[i]->... comme dit présédament, sa évite un obj a instancier après tout ?
bonne soiré
Hors ligne
Parce que comme je fais actuellement, je peux limiter les fonctionnalités. Tu remarqueras que j'ai codé le retrait d'une checkbox dans le BoutonRadioControl mais que je n'en permet pas l'utilisation car inutile pour le moment.
De plus, tu remarqueras que BoutonRadioControl n'est pas un GUIElement parce que je lui réserve d'autres utilisations, je voulais que ce control soit indépendant ce qui n'aurai évidemment pas été le cas si je l'avais intégré directement à BoxRetractable. Cela dit rien n'empêche à quiconque de coder une version intégrée et de le poster, plus il y a de version, plus y a de chance de trouver exactement ce que l'on recherche.
Sinon je vais certainement codé un (ou plusieurs versions de) GUI_ButtonRadio par la suite.
Merci pour la critique, si quelqu'un souhaite avoir le BoutonRadioControl intégré à BoxRetractable, tu lui auras donné une piste. Et puis, ça se trouve, je le ferais^^.
Hors ligne