Browse Source

Corrections de bugs liés a la creation/suppression de pion

olinox14 10 năm trước cách đây
mục cha
commit
633009c635
21 tập tin đã thay đổi với 5586 bổ sung5648 xóa
  1. 17 6
      .settings/org.eclipse.core.resources.prefs
  2. 239 235
      DMonde.ppr
  3. 253 252
      DMonde.py
  4. 160 205
      lib/AEtoile.py
  5. 639 641
      lib/Actions.py
  6. 0 119
      lib/Cache - Copie.py
  7. 604 601
      lib/Case.py
  8. 76 86
      lib/Combattant.py
  9. 103 103
      lib/EcranChargerPlateau.py
  10. 720 632
      lib/Modes.py
  11. 326 325
      lib/Pion.py
  12. 1542 1528
      lib/Plateau.py
  13. 29 33
      lib/afficherSousMenu.py
  14. BIN
      lib/biblio/decor
  15. 199 200
      lib/br.py
  16. 111 114
      lib/outilsSvg.py
  17. 6 8
      lib/test.py
  18. 561 558
      lib/ui/dm.py
  19. BIN
      parties/Partie1/svg/1.p
  20. BIN
      parties/Partie1/svg/4.p
  21. 1 2
      parties/Partie1/svg/infos_sauvegarde

+ 17 - 6
.settings/org.eclipse.core.resources.prefs

@@ -1,6 +1,17 @@
-eclipse.preferences.version=1
-encoding//lib/Actions.py=utf-8
-encoding//lib/Case.py=utf-8
-encoding//lib/Combattant.py=utf-8
-encoding//lib/Plateau.py=utf-8
-encoding/DMonde.py=utf-8
+eclipse.preferences.version=1
+encoding//lib/AEtoile.py=utf-8
+encoding//lib/Actions.py=utf-8
+encoding//lib/Cache.py=utf-8
+encoding//lib/Case.py=utf-8
+encoding//lib/Combattant.py=utf-8
+encoding//lib/Decor.py=utf-8
+encoding//lib/EcranChargerPlateau.py=utf-8
+encoding//lib/EcranEditionCombattant.py=utf-8
+encoding//lib/EcranGestionCombat.py=utf-8
+encoding//lib/Modes.py=utf-8
+encoding//lib/Pion.py=utf-8
+encoding//lib/Plateau.py=utf-8
+encoding//lib/Terrain.py=utf-8
+encoding//lib/outilsSvg.py=latin1
+encoding//lib/ui/dm.py=utf-8
+encoding/DMonde.py=utf-8

+ 239 - 235
DMonde.ppr

@@ -1,235 +1,239 @@
-[Config]
-Compilator.SaveAll=0
-Compilator.Capture=0
-Compilator.HideOutput=0
-Compilator.ProgSaveAll=0
-Compilator.ProgRunSelection=0
-Compilator.LogType=0
-DefaultDir=F:\DMonde
-DefaultCPIndex=0
-LogtoEnd=1
-DontOpen=0
-AbsolutePath=0
-FileFormat=0
-ProjectFilesOnly=0
-Extensions=*.py
-[Project tree]
-DMonde
-	+DMonde
-		-.git
-			-hooks
-			-info
-			-logs
-				-refs
-					-heads
-					-remotes
-						-origin
-			-objects
-				-01
-				-02
-				-05
-				-06
-				-08
-				-0c
-				-14
-				-1c
-				-1e
-				-1f
-				-23
-				-24
-				-31
-				-33
-				-37
-				-39
-				-3c
-				-3f
-				-41
-				-48
-				-4b
-				-53
-				-57
-				-58
-				-59
-				-5b
-				-5d
-				-5e
-				-67
-				-68
-				-6f
-				-77
-				-79
-				-7a
-				-7e
-				-81
-				-83
-				-85
-				-87
-				-8b
-				-8d
-				-8f
-				-93
-				-a1
-				-a3
-				-a4
-				-a6
-				-aa
-				-b4
-				-bb
-				-bc
-				-c3
-				-c4
-				-c7
-				-c8
-				-cd
-				-d0
-				-d7
-				-d8
-				-d9
-				-e0
-				-e3
-				-e4
-				-e8
-				-ec
-				-ee
-				-ef
-				-f1
-				-f4
-				-f9
-				-fb
-				-fd
-				-ff
-				-info
-				-pack
-			-refs
-				-heads
-				-remotes
-					-origin
-				-tags
-		+lib
-			-biblio
-			+ui
-				-corbeille_ui
-					lib\ui\corbeille_ui\dmOngletsH.py
-					lib\ui\corbeille_ui\dmtableattaques - Copie.py
-					lib\ui\corbeille_ui\dmtableattaques_tableAttaques.py
-					lib\ui\corbeille_ui\ecran_panneauAttaques.py
-					lib\ui\corbeille_ui\EcranEditionAttaques.py
-					lib\ui\corbeille_ui\test_ui.py
-				-ressource
-				lib\ui\__init__.py
-				lib\ui\dm.py
-				lib\ui\dmOngletsH.py
-				lib\ui\ecran_affichageTexte.py
-				lib\ui\ecran_chargerPlateau.py
-				lib\ui\ecran_creationPlateau.py
-				lib\ui\ecran_creerPlateau.py
-				lib\ui\ecran_editionAttaques.py
-				lib\ui\ecran_editionCombattant.py
-				lib\ui\ecran_editionCreature.py
-				lib\ui\ecran_editionDecor.py
-				lib\ui\ecran_editionObjet.py
-				lib\ui\ecran_editionQuantiteObjet.py
-				lib\ui\ecran_editionTerrain.py
-				lib\ui\ecran_explorateur.py
-				lib\ui\ecran_gestionCombat.py
-				lib\ui\ecran_panneauAttaques.py
-				lib\ui\ecran_panneauPj.py
-				lib\ui\ecran_principal.py
-				lib\ui\ecran_selectionPj.py
-				lib\ui\panneauImage.py
-				lib\ui\ressource_rc.py
-				lib\dmK.py
-			lib\__init__.py
-			lib\Actions.py
-			lib\AEtoile.py
-			lib\afficherSousMenu.py
-			lib\Boucle.py
-			lib\br.py
-			lib\Cache - Copie.py
-			lib\Cache.py
-			lib\Case.py
-			lib\Combattant.py
-			lib\Creature.py
-			lib\Decor.py
-			lib\dmF.py
-			lib\EcranAffichageTexte.py
-			lib\EcranChargerPlateau.py
-			lib\EcranCreerPlateau.py
-			lib\EcranEditionCombattant.py
-			lib\EcranEditionDecor.py
-			lib\EcranEditionObjet.py
-			lib\EcranEditionTerrain.py
-			lib\EcranFondPlateau.py
-			lib\EcranGestionCombat.py
-			lib\EcranSelectionPj.py
-			lib\EcranVol.py
-			lib\EffetsCase.py
-			lib\EntreeSortie.py
-			lib\fonctionsCommunes.py
-			lib\Forme.py
-			lib\frameAttaque.py
-			lib\framePj.py
-			lib\Inventaire.py
-			lib\lancer.py
-			lib\Modes.py
-			lib\Objet.py
-			lib\ObjetAction.py
-			lib\outilsSvg.py
-			lib\Partie.py
-			lib\Pinceau.py
-			lib\Pion.py
-			lib\Plateau.py
-			lib\ProjectionDep.py
-			lib\regles.py
-			lib\rsc.py
-			lib\Terrain.py
-			lib\test.py
-			lib\VueEditionForme.py
-		-parties
-			-Partie1
-				-journal
-				-personnages
-				-ressources
-				-svg
-		-ressources
-			-commun
-			-dd35
-			-dm
-		__init__.py
-		DMonde.py
-[Open project files]
-0=DMonde.py
-1=lib\Plateau.py
-2=lib\Modes.py
-3=lib\br.py
-4=lib\Case.py
-5=lib\Actions.py
-6=lib\Pion.py
-7=lib\ui\dm.py
-[Selected Project Files]
-Main=
-Selected=lib\Actions.py
-[DMonde.py]
-TopLine=15
-Caret=15,26
-[lib\Plateau.py]
-TopLine=662
-Caret=34,676
-[lib\Modes.py]
-TopLine=604
-Caret=23,621
-[lib\br.py]
-TopLine=9
-Caret=1,22
-[lib\Case.py]
-TopLine=240
-Caret=22,231
-[lib\Actions.py]
-TopLine=548
-Caret=19,557
-[lib\Pion.py]
-TopLine=151
-Caret=35,158
-[lib\ui\dm.py]
-TopLine=535
-Caret=47,538
+[Config]
+Compilator.SaveAll=0
+Compilator.Capture=0
+Compilator.HideOutput=0
+Compilator.ProgSaveAll=0
+Compilator.ProgRunSelection=0
+Compilator.LogType=0
+DefaultDir=F:\DMonde
+DefaultCPIndex=0
+LogtoEnd=1
+DontOpen=0
+AbsolutePath=0
+FileFormat=0
+ProjectFilesOnly=0
+Extensions=*.py
+[Project tree]
+DMonde
+	+DMonde
+		-.git
+			-hooks
+			-info
+			-logs
+				-refs
+					-heads
+					-remotes
+						-origin
+			-objects
+				-01
+				-02
+				-05
+				-06
+				-08
+				-0c
+				-14
+				-1c
+				-1e
+				-1f
+				-23
+				-24
+				-31
+				-33
+				-37
+				-39
+				-3c
+				-3f
+				-41
+				-48
+				-4b
+				-53
+				-57
+				-58
+				-59
+				-5b
+				-5d
+				-5e
+				-67
+				-68
+				-6f
+				-77
+				-79
+				-7a
+				-7e
+				-81
+				-83
+				-85
+				-87
+				-8b
+				-8d
+				-8f
+				-93
+				-a1
+				-a3
+				-a4
+				-a6
+				-aa
+				-b4
+				-bb
+				-bc
+				-c3
+				-c4
+				-c7
+				-c8
+				-cd
+				-d0
+				-d7
+				-d8
+				-d9
+				-e0
+				-e3
+				-e4
+				-e8
+				-ec
+				-ee
+				-ef
+				-f1
+				-f4
+				-f9
+				-fb
+				-fd
+				-ff
+				-info
+				-pack
+			-refs
+				-heads
+				-remotes
+					-origin
+				-tags
+		+lib
+			-biblio
+			-ui
+				-corbeille_ui
+					lib\ui\corbeille_ui\dmOngletsH.py
+					lib\ui\corbeille_ui\dmtableattaques - Copie.py
+					lib\ui\corbeille_ui\dmtableattaques_tableAttaques.py
+					lib\ui\corbeille_ui\ecran_panneauAttaques.py
+					lib\ui\corbeille_ui\EcranEditionAttaques.py
+					lib\ui\corbeille_ui\test_ui.py
+				-ressource
+				lib\ui\__init__.py
+				lib\ui\dm.py
+				lib\ui\dmOngletsH.py
+				lib\ui\ecran_affichageTexte.py
+				lib\ui\ecran_chargerPlateau.py
+				lib\ui\ecran_creationPlateau.py
+				lib\ui\ecran_creerPlateau.py
+				lib\ui\ecran_editionAttaques.py
+				lib\ui\ecran_editionCombattant.py
+				lib\ui\ecran_editionCreature.py
+				lib\ui\ecran_editionDecor.py
+				lib\ui\ecran_editionObjet.py
+				lib\ui\ecran_editionQuantiteObjet.py
+				lib\ui\ecran_editionTerrain.py
+				lib\ui\ecran_explorateur.py
+				lib\ui\ecran_gestionCombat.py
+				lib\ui\ecran_panneauAttaques.py
+				lib\ui\ecran_panneauPj.py
+				lib\ui\ecran_principal.py
+				lib\ui\ecran_selectionPj.py
+				lib\ui\panneauImage.py
+				lib\ui\ressource_rc.py
+				lib\dmK.py
+			lib\__init__.py
+			lib\Actions.py
+			lib\AEtoile.py
+			lib\afficherSousMenu.py
+			lib\Boucle.py
+			lib\br.py
+			lib\Cache - Copie.py
+			lib\Cache.py
+			lib\Case.py
+			lib\Combattant.py
+			lib\Creature.py
+			lib\Decor.py
+			lib\dmF.py
+			lib\EcranAffichageTexte.py
+			lib\EcranChargerPlateau.py
+			lib\EcranCreerPlateau.py
+			lib\EcranEditionCombattant.py
+			lib\EcranEditionDecor.py
+			lib\EcranEditionObjet.py
+			lib\EcranEditionTerrain.py
+			lib\EcranFondPlateau.py
+			lib\EcranGestionCombat.py
+			lib\EcranSelectionPj.py
+			lib\EcranVol.py
+			lib\EffetsCase.py
+			lib\EntreeSortie.py
+			lib\fonctionsCommunes.py
+			lib\Forme.py
+			lib\frameAttaque.py
+			lib\framePj.py
+			lib\Inventaire.py
+			lib\lancer.py
+			lib\Modes.py
+			lib\Objet.py
+			lib\ObjetAction.py
+			lib\outilsSvg.py
+			lib\Partie.py
+			lib\Pinceau.py
+			lib\Pion.py
+			lib\Plateau.py
+			lib\ProjectionDep.py
+			lib\regles.py
+			lib\rsc.py
+			lib\Terrain.py
+			lib\test.py
+			lib\VueEditionForme.py
+		-parties
+			-Partie1
+				-journal
+				-personnages
+				-ressources
+				-svg
+		-ressources
+			-commun
+			-dd35
+			-dm
+		__init__.py
+		DMonde.py
+[Open project files]
+0=DMonde.py
+1=lib\Plateau.py
+2=lib\Modes.py
+3=lib\br.py
+4=lib\Case.py
+5=lib\Actions.py
+6=lib\Pion.py
+7=lib\ui\dm.py
+8=lib\EcranEditionCombattant.py
+[Selected Project Files]
+Main=
+Selected=lib\Plateau.py
+[DMonde.py]
+TopLine=1
+Caret=25,26
+[lib\Plateau.py]
+TopLine=990
+Caret=22,1002
+[lib\Modes.py]
+TopLine=537
+Caret=1,564
+[lib\br.py]
+TopLine=9
+Caret=1,22
+[lib\Case.py]
+TopLine=256
+Caret=18,269
+[lib\Actions.py]
+TopLine=397
+Caret=49,416
+[lib\Pion.py]
+TopLine=151
+Caret=35,158
+[lib\ui\dm.py]
+TopLine=535
+Caret=47,538
+[lib\EcranEditionCombattant.py]
+TopLine=1
+Caret=30,9

+ 253 - 252
DMonde.py

@@ -1,252 +1,253 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-"""Interface principale du programme DMonde
-"""
-from sys import exit, argv
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-
-from lib.ui.ecran_principal import Ui_principal
-from lib.EcranCreerPlateau import EcranCreerPlateau
-from lib.EcranChargerPlateau import EcranChargerPlateau
-from lib.EcranFondPlateau import EcranFondPlateau
-from lib.EcranEditionCombattant import EcranEditionCombattant
-from lib.framePj import FramePj
-
-from lib.Plateau import Plateau
-
-from lib.outilsSvg import *
-
-class DMonde(QMainWindow):
-    """interface comprenant: chat ecrit, fenetre d'infos, lancer de des, echange de fichiers, lancement du chat vocal"""
-    def __init__(self, parent=None):
-        """initialisation de la fenetre"""
-        super (DMonde, self).__init__()
-        self.plateau = None
-        self.partie = "partie1"
-        self.idPlateauEnCours = ""
-        self.plateauConnecte = False
-        self._compteurPj = 0
-        self.createWidgets()
-
-    def createWidgets(self):
-        """construction de l'interface"""
-        self.ui = Ui_principal()
-        self.ui.setupUi(self)
-        self.afficherPanneauxPlateau(False)
-        self.connect(self.ui.cbt_sauver, SIGNAL("clicked()"), self.sauverPlateau)   
-        self.connect(self.ui.cbt_fermer, SIGNAL("clicked()"), self.fermerPlateau)
-        self.ui.cbt_vue.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
-        self.ui.cp_ongletsListes.setStyleSheet("QTabBar::tab { width: 38px; }")
-        self.ui.pi_ongletsListes.setStyleSheet("QTabBar::tab { width: 38px; }")
-
-        self.majFichierInfosSvg()
-        self.creerEcranFondPlateau()
-        self.chargerListePj()
-        self.connect(self.ui.grp_nouveauPj, SIGNAL("clicked()"), self.nouveauPj)
-##        self.showMaximized()
-
-
-    ########## onglet plateau
-    def creerEcranFondPlateau(self):
-        ecranFondPlateau = EcranFondPlateau(self)
-        self.ui.cbt_vue.resetTransform()
-        self.ui.cbt_vue.setScene(ecranFondPlateau)
-
-    def afficherEcranCreerPlateau(self):
-        """ouvre la fenetre de creation de plateau"""
-        valide = True
-        if self.plateau != None:
-            if self.plateau.estCree() == True:
-                valide = False
-        if valide:
-            self.creationPlateau = EcranCreerPlateau(self)
-            self.creationPlateau.setWindowModality(Qt.ApplicationModal)
-            self.creationPlateau.show()
-            self.creationPlateau.raise_()
-
-    def creerPlateau(self, nom, chapitre, formeCases, largeur, hauteur, couleur):
-        """cree le plateau entre en parametre"""
-        nouvelId = str(len(afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie))))
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        self.plateau = Plateau(self)
-        self.plateau.creer(nouvelId, nom, chapitre, formeCases, largeur, hauteur, couleur)
-        QApplication.restoreOverrideCursor()
-        del self.creationPlateau
-
-    def afficherEcranChargerPlateau(self):
-        """ouvre la fenetre de chargement de plateau"""
-        valide = True
-        if self.plateau != None:
-            if self.plateau.estCree() == True:
-                valide = False
-        if valide:
-            self.chargementPlateau = EcranChargerPlateau(self)
-            self.chargementPlateau.setWindowModality(Qt.ApplicationModal)
-            self.chargementPlateau.show()
-            self.chargementPlateau.raise_()
-
-    def chargerPlateau(self, nomFichierSvg):
-        if self.plateau != None:
-            if self.plateau.estCree() == True:
-                self.fermerPlateau()
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        self.plateau = chargerUnique("parties\\{}\\svg\\{}.p".format(self.partie, nomFichierSvg))
-        if self.plateau:
-            self.plateau.recreer(self)
-        else:
-            self.plateau = Plateau(self)
-        QApplication.restoreOverrideCursor()    
-
-    def chargerDernierPlateau(self):
-        """charge le dernier plateau sauvegarde"""
-        infosSvg = afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie))
-        dernier = None
-        for id_svg in infosSvg:
-            if not dernier or infosSvg[id_svg]["dateSvg"] > infosSvg[dernier]["dateSvg"]:
-                dernier = id_svg
-        if dernier:
-            self.chargerPlateau(dernier)
-                                   
-    def sauverPlateau(self):
-        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
-        if self.plateau.id in afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie)):
-            idPlateau = self.plateau.id
-        else:   
-            idPlateau = str(len(afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie))))
-
-        enregistrerUnique(self.plateau, "parties\\{}\\svg\\{}.p".format(self.partie, idPlateau))
-        infos = {"nom": self.plateau.nom, "chapitre": self.plateau.chapitre, "dateCreation":self.plateau.dateCreation, "dateSvg":self.plateau.dateSvg, \
-                 "public": self.plateau.public, "enCours": self.plateau.enCours}
-        enregistrer(str(idPlateau), infos, "parties\\{}\\svg\\infos_sauvegarde".format(self.partie))
-        QApplication.restoreOverrideCursor()
-    
-    def fermerPlateau(self):
-        self.plateau.fermer()
-        self.plateau = None
-        self.creerEcranFondPlateau()
-        self.afficherPanneauxPlateau(False) 
-
-    def majFichierInfosSvg(self):
-        """construit/maj le fichier contenant la liste des
-           plateaux sauvegardes et leurs informations"""
-        #on parcourt les fichiers de sauvegarde
-        f = []
-        lstFichiersSvg = []
-        for (dirpath, dirnames, filenames) in os.walk("parties\\{}\\svg\\".format(self.partie)):
-            f.extend(filenames)
-            break
-        for fichier in f:
-            fileName, fileExtension = os.path.splitext(fichier)
-            if fileExtension == ".p":
-                lstFichiersSvg.append(fileName)
-      
-        #on verifie leur presence dans le fichier 'infos_sauvegarde'
-        infosSvg = afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie))
-        index = len(infosSvg)
-
-        #on ajoute les sauvegardes manquantes si besoin
-        for fichier in lstFichiersSvg:
-            if not fichier in infosSvg:
-                plateau = chargerUnique("parties\\{}\\svg\\{}.p".format(self.partie, fichier))
-                enregistrer(fichier, {"nom": plateau.nom, "chapitre": plateau.chapitre, "dateCreation":plateau.dateCreation, "dateSvg":plateau.dateSvg, \
-                                      "public": plateau.public, "enCours": plateau.enCours}, "svg\\infos_sauvegarde")
-                index += 1       
-        #on supprime ceux qui ne sont plus trouves
-        for fichier in infosSvg:
-            if not fichier in lstFichiersSvg:
-                supprSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie), fichier)
-
-
-    ########## apparence de l'onglet plateau
-    def afficherPanneauxPlateau(self, actif):
-        index = int(actif)   # 0 si faux, 1 si vrai
-        self.ui.cbt_panneauBas.setCurrentIndex(index)
-        self.ui.cbt_panneauHaut.setCurrentIndex(index)
-        self.ui.cbt_panneauDroite.setCurrentIndex(index)
-        self.ui.cbt_panneauGauche.setCurrentIndex(index)
-
-    def reinitialiserPanneauxPlateau(self):
-        """remet a neuf les commandes liees au plateau"""
-        for panneau in [self.ui.cbt_panneauHaut, \
-                         self.ui.cbt_panneauBas, \
-                         self.ui.cbt_panneauGauche, \
-                         self.ui.cbt_panneauDroite]:
-            #listes
-            for liste in panneau.findChildren(QTableWidget):
-                while liste.rowCount() > 0:
-                    liste.removeRow(0)
-            #textes
-            for texte in panneau.findChildren(QLineEdit):
-                texte.clear()         
-            for texte in panneau.findChildren(QTextEdit):
-                texte.clear()
-            #a cocher
-            for bouton in panneau.findChildren(QToolButton):
-                if bouton.isCheckable():
-                    bouton.setChecked(False)
-            #autre
-            for item in panneau.findChildren(QSlider):
-                item.setValue(1)
-            for item in panneau.findChildren(QDoubleSpinBox):
-                item.setValue(0)                
-
-
-    ########## onglet groupe
-    def chargerListePj(self):
-        listePj = chargerUnique("parties\\{}\\groupe".format(self.partie))
-        if not listePj: listePj = []
-        self.ui.grp_deroulement_layout.setAlignment(Qt.AlignTop)
-        for pj in listePj:
-            self.pjAjouterAListe(pj)
-
-    def pjAjouterAListe(self, pj = None):
-        self._compteurPj += 1
-        panneau = FramePj(self._compteurPj)
-        if pj:
-            panneau.chargerPj(pj)
-        panneau.setObjectName(QString("pj_panneau_{}".format(self._compteurPj)))
-        self.connect(panneau, SIGNAL("pjModifie(int)"), self.pjEnregistrer)
-        self.ui.grp_deroulement_layout.addWidget(panneau)    
-
-    def pjSupprimer(self, index):
-        panneau = self.findChild(QFrame, "pj_panneau_{}".format(index))
-        self.ui.grp_deroulement_layout.removeWidget(panneau)
-
-    def nouveauPj(self):
-        self.editionPj = EcranEditionCombattant()
-        self.editionPj.setAttribute(Qt.WA_DeleteOnClose)
-        self.editionPj.exec_()
-        pj = self.editionPj.combattant
-        self.pjAjouterAListe(pj)
-        self.pjEnregistrer(self._compteurPj)
-
-    def pjEnregistrer(self, idPj):
-        listePj = chargerUnique("parties\\{}\\groupe".format(self.partie))
-        if not listePj: listePj = []
-        panneau = self.findChild(QFrame, "pj_panneau_{}".format(idPj))
-        pj = panneau.pj()
-        listePj.append(pj)
-        enregistrerUnique(listePj, "parties\\{}\\groupe".format(self.partie))
-
-    def resizeEvent(self, event):
-        val = (self.ui.dm_panneauCentre.width() - 20) / 3
-        self.ui.dm_panneauCentre.setStyleSheet("QTabBar::tab { height: 25; width: "+str(val)+"px; }")
-        
-        
-if __name__ == "__main__":
-    app = QApplication(argv)
-    #settrace(trace_calls)
-    dm = DMonde()
-    dm.show()
-    r = app.exec_()
-    exit(r)
-   
-
-
-
-
-
-
-
-
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+"""Interface principale du programme DMonde
+"""
+import os
+from sys import exit, argv
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from lib.EcranChargerPlateau import EcranChargerPlateau
+from lib.EcranCreerPlateau import EcranCreerPlateau
+from lib.EcranEditionCombattant import EcranEditionCombattant
+from lib.EcranFondPlateau import EcranFondPlateau
+from lib.Plateau import Plateau
+from lib.framePj import FramePj
+from lib.outilsSvg import *
+from lib.ui.ecran_principal import Ui_principal
+
+
+class DMonde(QMainWindow):
+    """interface comprenant: chat ecrit, fenetre d'infos, lancer de des, echange de fichiers, lancement du chat vocal"""
+    def __init__(self, parent=None):
+        """initialisation de la fenetre"""
+        super (DMonde, self).__init__()
+        self.plateau = None
+        self.partie = "partie1"
+        self.idPlateauEnCours = ""
+        self.plateauConnecte = False
+        self._compteurPj = 0
+        self.createWidgets()
+
+    def createWidgets(self):
+        """construction de l'interface"""
+        self.ui = Ui_principal()
+        self.ui.setupUi(self)
+        self.afficherPanneauxPlateau(False)
+        self.connect(self.ui.cbt_sauver, SIGNAL("clicked()"), self.sauverPlateau)   
+        self.connect(self.ui.cbt_fermer, SIGNAL("clicked()"), self.fermerPlateau)
+        self.ui.cbt_vue.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
+        self.ui.cp_ongletsListes.setStyleSheet("QTabBar::tab { width: 38px; }")
+        self.ui.pi_ongletsListes.setStyleSheet("QTabBar::tab { width: 38px; }")
+
+        self.majFichierInfosSvg()
+        self.creerEcranFondPlateau()
+        self.chargerListePj()
+        self.connect(self.ui.grp_nouveauPj, SIGNAL("clicked()"), self.nouveauPj)
+##        self.showMaximized()
+
+
+    ########## onglet plateau
+    def creerEcranFondPlateau(self):
+        ecranFondPlateau = EcranFondPlateau(self)
+        self.ui.cbt_vue.resetTransform()
+        self.ui.cbt_vue.setScene(ecranFondPlateau)
+
+    def afficherEcranCreerPlateau(self):
+        """ouvre la fenetre de creation de plateau"""
+        valide = True
+        if self.plateau != None:
+            if self.plateau.estCree() == True:
+                valide = False
+        if valide:
+            self.creationPlateau = EcranCreerPlateau(self)
+            self.creationPlateau.setWindowModality(Qt.ApplicationModal)
+            self.creationPlateau.show()
+            self.creationPlateau.raise_()
+
+    def creerPlateau(self, nom, chapitre, formeCases, largeur, hauteur, couleur):
+        """cree le plateau entre en parametre"""
+        nouvelId = str(len(afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie))))
+        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
+        self.plateau = Plateau(self)
+        self.plateau.creer(nouvelId, nom, chapitre, formeCases, largeur, hauteur, couleur)
+        QApplication.restoreOverrideCursor()
+        del self.creationPlateau
+
+    def afficherEcranChargerPlateau(self):
+        """ouvre la fenetre de chargement de plateau"""
+        valide = True
+        if self.plateau != None:
+            if self.plateau.estCree() == True:
+                valide = False
+        if valide:
+            self.chargementPlateau = EcranChargerPlateau(self)
+            self.chargementPlateau.setWindowModality(Qt.ApplicationModal)
+            self.chargementPlateau.show()
+            self.chargementPlateau.raise_()
+
+    def chargerPlateau(self, nomFichierSvg):
+        if self.plateau != None:
+            if self.plateau.estCree() == True:
+                self.fermerPlateau()
+        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
+        self.plateau = chargerUnique("parties\\{}\\svg\\{}.p".format(self.partie, nomFichierSvg))
+        if self.plateau:
+            self.plateau.recreer(self)
+        else:
+            self.plateau = Plateau(self)
+        QApplication.restoreOverrideCursor()    
+
+    def chargerDernierPlateau(self):
+        """charge le dernier plateau sauvegarde"""
+        infosSvg = afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie))
+        dernier = None
+        for id_svg in infosSvg:
+            if not dernier or infosSvg[id_svg]["dateSvg"] > infosSvg[dernier]["dateSvg"]:
+                dernier = id_svg
+        if dernier:
+            self.chargerPlateau(dernier)
+                                   
+    def sauverPlateau(self):
+        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
+        if self.plateau.id in afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie)):
+            idPlateau = self.plateau.id
+        else:   
+            idPlateau = str(len(afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie))))
+
+        enregistrerUnique(self.plateau, "parties\\{}\\svg\\{}.p".format(self.partie, idPlateau))
+        infos = {"nom": self.plateau.nom, "chapitre": self.plateau.chapitre, "dateCreation":self.plateau.dateCreation, "dateSvg":self.plateau.dateSvg, \
+                 "public": self.plateau.public, "enCours": self.plateau.enCours}
+        enregistrer(str(idPlateau), infos, "parties\\{}\\svg\\infos_sauvegarde".format(self.partie))
+        QApplication.restoreOverrideCursor()
+    
+    def fermerPlateau(self):
+        self.plateau.fermer()
+        self.plateau = None
+        self.creerEcranFondPlateau()
+        self.afficherPanneauxPlateau(False) 
+
+    def majFichierInfosSvg(self):
+        """construit/maj le fichier contenant la liste des
+           plateaux sauvegardes et leurs informations"""
+        #on parcourt les fichiers de sauvegarde
+        f = []
+        lstFichiersSvg = []
+        for (dirpath, dirnames, filenames) in os.walk("parties\\{}\\svg\\".format(self.partie)):
+            f.extend(filenames)
+            break
+        for fichier in f:
+            fileName, fileExtension = os.path.splitext(fichier)
+            if fileExtension == ".p":
+                lstFichiersSvg.append(fileName)
+      
+        #on verifie leur presence dans le fichier 'infos_sauvegarde'
+        infosSvg = afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie))
+        index = len(infosSvg)
+
+        #on ajoute les sauvegardes manquantes si besoin
+        for fichier in lstFichiersSvg:
+            if not fichier in infosSvg:
+                plateau = chargerUnique("parties\\{}\\svg\\{}.p".format(self.partie, fichier))
+                enregistrer(fichier, {"nom": plateau.nom, "chapitre": plateau.chapitre, "dateCreation":plateau.dateCreation, "dateSvg":plateau.dateSvg, \
+                                      "public": plateau.public, "enCours": plateau.enCours}, "svg\\infos_sauvegarde")
+                index += 1       
+        #on supprime ceux qui ne sont plus trouves
+        for fichier in infosSvg:
+            if not fichier in lstFichiersSvg:
+                supprSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.partie), fichier)
+
+
+    ########## apparence de l'onglet plateau
+    def afficherPanneauxPlateau(self, actif):
+        index = int(actif)   # 0 si faux, 1 si vrai
+        self.ui.cbt_panneauBas.setCurrentIndex(index)
+        self.ui.cbt_panneauHaut.setCurrentIndex(index)
+        self.ui.cbt_panneauDroite.setCurrentIndex(index)
+        self.ui.cbt_panneauGauche.setCurrentIndex(index)
+
+    def reinitialiserPanneauxPlateau(self):
+        """remet a neuf les commandes liees au plateau"""
+        for panneau in [self.ui.cbt_panneauHaut, \
+                         self.ui.cbt_panneauBas, \
+                         self.ui.cbt_panneauGauche, \
+                         self.ui.cbt_panneauDroite]:
+            #listes
+            for liste in panneau.findChildren(QTableWidget):
+                while liste.rowCount() > 0:
+                    liste.removeRow(0)
+            #textes
+            for texte in panneau.findChildren(QLineEdit):
+                texte.clear()         
+            for texte in panneau.findChildren(QTextEdit):
+                texte.clear()
+            #a cocher
+            for bouton in panneau.findChildren(QToolButton):
+                if bouton.isCheckable():
+                    bouton.setChecked(False)
+            #autre
+            for item in panneau.findChildren(QSlider):
+                item.setValue(1)
+            for item in panneau.findChildren(QDoubleSpinBox):
+                item.setValue(0)                
+
+
+    ########## onglet groupe
+    def chargerListePj(self):
+        listePj = chargerUnique("parties\\{}\\groupe".format(self.partie))
+        if not listePj: listePj = []
+        self.ui.grp_deroulement_layout.setAlignment(Qt.AlignTop)
+        for pj in listePj:
+            self.pjAjouterAListe(pj)
+
+    def pjAjouterAListe(self, pj = None):
+        self._compteurPj += 1
+        panneau = FramePj(self._compteurPj)
+        if pj:
+            panneau.chargerPj(pj)
+        panneau.setObjectName(QString("pj_panneau_{}".format(self._compteurPj)))
+        self.connect(panneau, SIGNAL("pjModifie(int)"), self.pjEnregistrer)
+        self.ui.grp_deroulement_layout.addWidget(panneau)    
+
+    def pjSupprimer(self, index):
+        panneau = self.findChild(QFrame, "pj_panneau_{}".format(index))
+        self.ui.grp_deroulement_layout.removeWidget(panneau)
+
+    def nouveauPj(self):
+        self.editionPj = EcranEditionCombattant()
+        self.editionPj.setAttribute(Qt.WA_DeleteOnClose)
+        self.editionPj.exec_()
+        pj = self.editionPj.combattant
+        self.pjAjouterAListe(pj)
+        self.pjEnregistrer(self._compteurPj)
+
+    def pjEnregistrer(self, idPj):
+        listePj = chargerUnique("parties\\{}\\groupe".format(self.partie))
+        if not listePj: listePj = []
+        panneau = self.findChild(QFrame, "pj_panneau_{}".format(idPj))
+        pj = panneau.pj()
+        listePj.append(pj)
+        enregistrerUnique(listePj, "parties\\{}\\groupe".format(self.partie))
+
+    def resizeEvent(self, event):
+        val = (self.ui.dm_panneauCentre.width() - 20) / 3
+        self.ui.dm_panneauCentre.setStyleSheet("QTabBar::tab { height: 25; width: "+str(val)+"px; }")
+        
+        
+if __name__ == "__main__":
+    app = QApplication(argv)
+    #settrace(trace_calls)
+    dm = DMonde()
+    dm.show()
+    r = app.exec_()
+    exit(r)
+   
+
+
+
+
+
+
+
+

+ 160 - 205
lib/AEtoile.py

@@ -1,205 +1,160 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-"""algorithme de recherche du plus court chemin entre deux cases"""
-from math import *
-import time
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-#pour des performances correctes, ne pas utiliser pour de deplacements de plus de 100 cases
-
-        
-def distance(coord1, coord2):
-    return sqrt((coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2)
-
-def distanceCarree(coord1, coord2):
-    """bcp plus rapide a calculer que la distance reelle"""
-    return (coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2
-       
-class N():
-    """noeud du chemin"""
-    def __init__(self, coord):
-        self.parent = None    #coord du noeud qui a amene a ce noeud-ci
-        self.coord = coord
-        self.kDep = 1
-        self.coutG = 0
-        self.coutH = 0
-        self.cout = 0
-
-    def creer(self, parent, cible, kDep):
-        self.parent = parent
-        self.kDep = kDep
-        self.coutH = distanceCarree(self.coord, cible)
-        self.coutG = self.parent.coutG + self.kDep
-        self.cout =  self.coutG + self.coutH
-
-class Chemin():
-    def __init__(self, plateau, origine, cible, z1 = 0, z2 = 0):
-        self.plateau = plateau
-        self.origine = origine
-        self.cible = cible
-        self.echec = False
-        self.stop = False
-        self._z1 = z1
-        self._z2 = z2
-
-        ###active l'evolution sur le plateau
-        self.debug = False
-
-    def arreter(self):
-        self.stop = True
-
-    def liste(self):
-        """retourne la liste des coord a traverser pour atteindre l'objectif
-           se base sur la fonction estFranchissable() des cases"""
-        if self.debug:
-            for coord in self.plateau.cases:
-                self.plateau.cases[coord].majEstCibleCurseur(False)
-                self.plateau.cases[coord].majEstCibleAttaque(False)
-                QApplication.processEvents()
-
-        t0 = time.time()
-        nO = N(self.origine)
-        nO.parent = None
-        nO.coutG = 0
-        nO.cout = 0
-
-        filOuvert = []   #"liste ouverte": noeuds etudies et a etudier
-        filFerme = [nO]    #"liste fermee":  noeuds retenus
-        chemin = []
-        position = nO
-        echec = False
-        
-        #on continue jusqu'a tomber sur la case cible, ou jusqu'a un echec
-        it = 0
-        while position.coord != self.cible and not self.echec:
-            it += 1
-##            print "iteration: ", i
-            
-            #on etudie tous les voisins de la case en cours
-            for coord in self.plateau.cases[position.coord].voisins:
-                if self.stop: return []
-                #on elimine les cases deja retenues (celles qui sont dans le fil ferme)
-                trouve = False
-                for nTest in filFerme:
-                    if self.stop: return []
-                    if nTest.coord == coord:
-                        trouve = True
-                if not trouve:
-                    
-                    #on elimine les cases infranchissables
-                    if self.plateau.cases[coord].estFranchissable():
-                        noeud = N(coord)
-                        
-                        #on calcule le cout de la case
-                        if self.stop: return []
-                        noeud.creer(position, self.cible, self.plateau.cases[coord].coutDep())
-
-                        #si le noeud est trouve dans la liste ouverte, on le compare a celui-ci
-                        # si ce nouveau noeud a un cout moindre, on remplace
-                        # sinon on ajoute ce noeud a la liste ouverte
-                        trouve = False
-                        for nTest in filOuvert:
-                            if self.stop: return []
-                            if nTest.coord == noeud.coord:
-                                if noeud.cout < nTest.cout:
-                                    nTest.parent = noeud.parent
-                                    nTest.cout = noeud.cout
-                                    trouve = True
-                                    
-                        if not trouve:
-                            filOuvert.append(noeud)
-                            if self.debug:
-                                self.plateau.cases[noeud.coord].majEstCibleCurseur(True, True)
-                                time.sleep(0.05)
-                                QApplication.processEvents()
-
-            #on parcourt les noeuds de la liste ouverte
-            #et on cherche le meilleur noeud (le cout le plus faible)
-            #si trouve: on l'ajoute a la liste fermee, on le retire de la liste ouverte et on continue
-            #sinon, le chemin n'existe pas
-            meilleur = None                
-                            
-            for noeud in filOuvert:
-                if self.stop: return []
-                if meilleur == None:
-                    meilleur = noeud
-                else:
-                    if noeud.cout < meilleur.cout:
-                        meilleur = noeud
-                    
-            if meilleur:
-                filFerme.append(meilleur)
-                if self.debug:
-                    self.plateau.cases[meilleur.coord].majEstCibleCurseur(True, False)
-                    QApplication.processEvents()
-                    time.sleep(0.05)
-                filOuvert.remove(meilleur)
-                position = meilleur
-            else:
-                echec = True
-
-        #on revient de parent en parent jusqu'a l'arrivee
-        if not self.echec:
-            while position.coord != self.origine:
-                if self.stop: return []
-                chemin.insert(0, (position.coord, position.coutG))
-                if self.debug:
-                    self.plateau.cases[position.coord].majEstCibleCurseur(False)
-                    self.plateau.cases[position.coord].majEstCibleAttaque(True)
-                    QApplication.processEvents()
-                
-                position = position.parent
-        else:
-            chemin = []          
-        
-        return chemin   
-    
-### pour les tests
-
-##class Plateau():
-##    def __init__(self):
-##        self.cases = {}
-##
-##class Case():
-##    def __init__(self, coord):
-##        self.coord = coord
-##        self.voisins = []
-##        self.majVoisins()
-##        
-##    def majVoisins(self):
-##        voisins = []
-##        lst = [(x, y-1), (x+1, y-1), (x+1, y), (x+1, y+1), (x,   y+1), (x-1, y+1), (x-1, y), (x-1, y-1)]
-##        for coord in lst: 
-##            if (coord[0] > 0 and coord[1] > 0 and coord[0] <= 5 and coord[1] <= 5):
-##                self.voisins.append(coord)
-##                
-##    def estFranchissable(self):
-##        return not (self.coord[0]==2 and self.coord[1] in [3, 4])
-##
-##    def coutDep(self):
-##        cout = 1
-##        if self.coord in [(3,2), (3,3), (3, 4), (4,3), (4,4)]:
-##            cout = 2
-##        return cout
-##
-##    
-##plateau = Plateau()
-##
-##for x in range(1, 6):
-##    for y in range(1, 6):
-##        plateau.cases[(x, y)] = Case((x, y))
-##depart = (1, 2)
-##arrivee = (5, 5)
-##    
-##for essai in range(1,2):
-##    t0 = time.time()
-##    c = chemin(plateau, depart, arrivee)
-##    print (time.time() - t0)
-##    print c
-
-
-
-
-
-
-        
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+"""algorithme de recherche du plus court chemin entre deux cases"""
+from math import sqrt
+import time
+from PyQt4.QtGui import QApplication
+#pour des performances correctes, ne pas utiliser pour de deplacements de plus de 100 cases
+
+        
+def distance(coord1, coord2):
+    return sqrt((coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2)
+
+def distanceCarree(coord1, coord2):
+    """bcp plus rapide a calculer que la distance reelle"""
+    return (coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2
+       
+class N():
+    """noeud du chemin"""
+    def __init__(self, coord):
+        self.parent = None    #coord du noeud qui a amene a ce noeud-ci
+        self.coord = coord
+        self.kDep = 1
+        self.coutG = 0
+        self.coutH = 0
+        self.cout = 0
+
+    def creer(self, parent, cible, kDep):
+        self.parent = parent
+        self.kDep = kDep
+        self.coutH = distanceCarree(self.coord, cible)
+        self.coutG = self.parent.coutG + self.kDep
+        self.cout =  self.coutG + self.coutH
+
+class Chemin():
+    def __init__(self, plateau, origine, cible, z1 = 0, z2 = 0):
+        self.plateau = plateau
+        self.origine = origine
+        self.cible = cible
+        self.echec = False
+        self.stop = False
+        self._z1 = z1
+        self._z2 = z2
+
+        ###active l'evolution sur le plateau
+        self.debug = False
+
+    def arreter(self):
+        self.stop = True
+
+    def liste(self):
+        """retourne la liste des coord a traverser pour atteindre l'objectif
+           se base sur la fonction estFranchissable() des cases"""
+        if self.debug:
+            for coord in self.plateau.cases:
+                self.plateau.cases[coord].majEstCibleCurseur(False)
+                self.plateau.cases[coord].majEstCibleAttaque(False)
+                QApplication.processEvents()
+
+        nO = N(self.origine)
+        nO.parent = None
+        nO.coutG = 0
+        nO.cout = 0
+
+        filOuvert = []   #"liste ouverte": noeuds etudies et a etudier
+        filFerme = [nO]    #"liste fermee":  noeuds retenus
+        chemin = []
+        position = nO
+        self.echec = False
+        
+        #on continue jusqu'a tomber sur la case cible, ou jusqu'a un echec
+        it = 0
+        while position.coord != self.cible and not self.echec:
+            it += 1
+##            print "iteration: ", i
+            
+            #on etudie tous les voisins de la case en cours
+            for coord in self.plateau.cases[position.coord].voisins:
+                if self.stop: return []
+                #on elimine les cases deja retenues (celles qui sont dans le fil ferme)
+                trouve = False
+                for nTest in filFerme:
+                    if self.stop: return []
+                    if nTest.coord == coord:
+                        trouve = True
+                if not trouve:
+                    
+                    #on elimine les cases infranchissables
+                    if self.plateau.cases[coord].estFranchissable():
+                        noeud = N(coord)
+                        
+                        #on calcule le cout de la case
+                        if self.stop: return []
+                        noeud.creer(position, self.cible, self.plateau.cases[coord].coutDep())
+
+                        #si le noeud est trouve dans la liste ouverte, on le compare a celui-ci
+                        # si ce nouveau noeud a un cout moindre, on remplace
+                        # sinon on ajoute ce noeud a la liste ouverte
+                        trouve = False
+                        for nTest in filOuvert:
+                            if self.stop: return []
+                            if nTest.coord == noeud.coord:
+                                if noeud.cout < nTest.cout:
+                                    nTest.parent = noeud.parent
+                                    nTest.cout = noeud.cout
+                                    trouve = True
+                                    
+                        if not trouve:
+                            filOuvert.append(noeud)
+                            if self.debug:
+                                self.plateau.cases[noeud.coord].majEstCibleCurseur(True, True)
+                                time.sleep(0.05)
+                                QApplication.processEvents()
+
+            #on parcourt les noeuds de la liste ouverte
+            #et on cherche le meilleur noeud (le cout le plus faible)
+            #si trouve: on l'ajoute a la liste fermee, on le retire de la liste ouverte et on continue
+            #sinon, le chemin n'existe pas
+            meilleur = None                
+                            
+            for noeud in filOuvert:
+                if self.stop: return []
+                if meilleur == None:
+                    meilleur = noeud
+                else:
+                    if noeud.cout < meilleur.cout:
+                        meilleur = noeud
+                    
+            if meilleur:
+                filFerme.append(meilleur)
+                if self.debug:
+                    self.plateau.cases[meilleur.coord].majEstCibleCurseur(True, False)
+                    QApplication.processEvents()
+                    time.sleep(0.05)
+                filOuvert.remove(meilleur)
+                position = meilleur
+            else:
+                self.echec = True
+
+        #on revient de parent en parent jusqu'a l'arrivee
+        if not self.echec:
+            while position.coord != self.origine:
+                if self.stop: return []
+                chemin.insert(0, (position.coord, position.coutG))
+                if self.debug:
+                    self.plateau.cases[position.coord].majEstCibleCurseur(False)
+                    self.plateau.cases[position.coord].majEstCibleAttaque(True)
+                    QApplication.processEvents()
+                
+                position = position.parent
+        else:
+            chemin = []          
+        
+        return chemin   
+
+
+
+
+
+
+        

+ 639 - 641
lib/Actions.py

@@ -1,641 +1,639 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-import regles
-import AEtoile
-import time, threading
-import br
-from Pion import Pion
-from Combattant import Combattant
-from Decor import Decor
-
-class Action(object):
-    """action effectuee par un combattant sur le plateau de jeu"""
-    def __init__(self):
-        self._num = None         #no du pion actif
-        self._coordCible = None  #coord de la case ciblee par le curseur
-        self._cible = None       #cible (case ou pion)
-        self._sourceCurseur = ""
-        self._nomBouton = ""
-        self._enCours = False
-        self._desactivationDemandee = False
-
-    #decorateur
-    def autorise(f):
-        def _autorise(self, *args):
-            def fVide(*args):
-                pass
-            retour = fVide
-            if not self._desactivationDemandee:
-                retour = f
-            retour(self, *args)                            
-        return _autorise
-
-    def typeAtt(self):
-        return ""
-
-    def activer(self, plateau, numPion):
-        self.plateau = plateau
-        self._num = numPion
-        
-        self.enfoncerBouton(True)
-        self.activerCurseur()
-        self.creerItemsGraphiques()
-
-        self._enCours = True
-
-    def majCoordCible(self, coord):
-        """met a jour les coordonnees de la cible,
-            cad la case actuellement survolee par la souris"""
-        if self.plateau.coordonneesValides(coord):
-            self._coordCible = coord
-            self.maj()
-
-    def desactiver(self):
-        self._desactivationDemandee = True
-        self.afficherCibles(False)
-        self.detruireItemsGraphiques()
-        self.desactiverCurseur()
-        self.enfoncerBouton(False)
-        self._enCours = False
-
-    def enCours(self):
-        return self._enCours
-
-    def valider(self):
-        #envoyer signal
-        self.envoiSignal()
-        self.desactiver()
-
-    def estValide(self):
-        return True
-
-    def maj(self):
-        pass
-
-    def acteur(self):
-        return self.plateau.combattants[self._num]
-
-    def coordActeur(self):
-        return self.acteur().position
-
-    def activerCurseur(self):
-        if len(self._sourceCurseur) > 0:
-            curseurPix = QPixmap(self._sourceCurseur)
-            if not curseurPix.isNull():
-                curseur = QCursor(curseurPix, 0, curseurPix.height())
-                self.plateau.fenetre.ui.cbt_vue.setCursor(curseur)   
-
-    def desactiverCurseur(self):
-        self.plateau.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
-
-    def enfoncerBouton(self, actif):
-        for bouton in self.plateau.fenetre.ui.pi_actions.findChildren(QToolButton):
-            if bouton.objectName() == self._nomBouton:
-                bouton.setChecked(actif)
-
-    #manipulation des items graphiques
-    def creerItemsGraphiques(self):
-        pass
-
-    def majItemsGraphiques(self):
-        pass    
-
-    def detruireItemsGraphiques(self):
-        pass
-
-    #affichage des cibles
-    def afficherCibles(self, actif):
-        pass
-
-    #envoi du signal en cas de validation
-    def envoiSignal(self):
-        pass
-
-    def pivoter(self, modRotation):
-        pass
-
-         
-        
-class Deplacement(Action):
-    ### a completer avec des icones de deplacement,
-    #la prise en compte de la nage et de l'escalade
-    #et le calcul du cout de deplacement
-    def __init__(self):
-        super(Deplacement, self).__init__()
-        self._chemin = []  #liste des coord des cases a traverser
-        self._chercheurChemin = None
-        self._cout = 0     #cout en points de dep
-        self._zCible = 0
-        self.cible_aConfirmer = None
-        self._sourceCurseur = ""
-        self._nomBouton = "pi_deplacement" 
-
-    def typeAtt(self):
-        return "dep"
-    
-    def activer(self, plateau, numPion):
-        super(Deplacement, self).activer(plateau, numPion)
-        self.plateau.proj.creer(self.acteur())
-        
-    def desactiver(self):
-        self.plateau.proj.desactiver()
-        if self._chercheurChemin:
-            self._chercheurChemin.arreter()
-            self._chercheurChemin = None
-        super(Deplacement, self).desactiver()
-
-    def valider(self):
-        if not self.cible_aConfirmer or self.cible_aConfirmer != self._coordCible:             
-            self.cible_aConfirmer = self._coordCible
-            self.recupZCible()
-            self.creerChemin() 
-        else:
-            if self.estValide() and self.plateau.proj.projectionValide():
-                self.acteur().majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
-                self.acteur().majZ(self._zCible)
-                super(Deplacement, self).valider()
-
-    def estValide(self):
-        return len(self._chemin)>0
-
-    def majCoordCible(self, coord):
-        if coord != self.coordActeur():
-            super(Deplacement, self).majCoordCible(coord)
-
-    def maj(self):
-        self.plateau.proj.majCoord(self._coordCible)
-
-    def pivoter(self, modRotation):
-        self.plateau.proj.majRotation(modRotation)
-            
-    def creerChemin(self):
-        self.afficherCibles(False)
-        self._chemin = []
-        self._cout = 0
-        if self._chercheurChemin:
-            self._chercheurChemin.arreter()
-            self._chercheurChemin = None
-        self._chercheurChemin = AEtoile.Chemin(self.plateau, self.coordActeur(), self._coordCible, self.acteur().z, self._zCible)
-        self._chemin = self._chercheurChemin.liste()
-        self.afficherCibles(True)        
-
-    def afficherCibles(self, actif):
-        for coord, cout in self._chemin:
-            valide = True
-            if actif:
-                if cout > self.acteur().depMarche: valide = False
-            else:
-                cout = 0
-            self.plateau.cases[coord].majAffichageDeplacement(cout, valide)
-
-    def envoiSignal(self):
-        cout = self._chemin[-1][1]  #cout de deplacement retenu pour la derniere case
-        print "{} s'est deplacé et a utilisé {} points de mouvement".format(self.acteur().txtId(), cout)
-
-    def recupZCible(self):
-        self._zCible = self.acteur().z    
-
-
-class Vol(Deplacement):
-    """idem que Deplacement, mais affiche en plus la boite de dialogue Vol
-       (et n'utilise pas le meme algo de deplacement?)"""
-    def __init__(self):
-        super(Vol, self).__init__()
-        self._zCible = 0
-        self._nomBouton = "pi_vol" 
-
-    def typeAtt(self):
-        return "vol"
-        
-    def recupZCible(self):
-        nouveauZ = self.plateau.dialogueVol(self.acteur().z)
-        self._zCible = nouveauZ 
-
-class Attaque(Action):
-    """attaque pre-parametree affectee a un pion, un personnage ou une creature"""
-    def __init__(self):
-        super(Attaque, self).__init__()
-        self._nom = "Attaque"
-        self._icone = ""
-        self._portee = 1   #portee max en cases
-        self._rayon = 0
-        self._attributs = regles.listeAttributsAttaques()
-        self._notes = ""
-
-    def typeAtt(self):
-        return "att"
-
-    def nom(self):
-        return self._nom
-
-    def majNom(self, nom):
-        if len(str(nom)) > 0:
-            self._nom = nom
-
-    def portee(self):
-        return self._portee
-
-    def majPortee(self, portee):
-        try:
-            ent = int(portee)
-            if ent > 0:
-                if ent >= 1000: ent = 999
-                self._portee = ent
-        except:
-            pass
-
-    def rayon(self):
-        return self._rayon
-    
-    def majRayon(self, rayon):
-        try:
-            ent = int(rayon)
-            if ent > 0:
-                if ent >= 100: ent = 99
-                self._rayon = ent
-        except:
-            pass
-
-    def majAttribut(self, nom, nouvelleVal):
-        if nom in self._attributs:
-            if regles.attributAttaque(nom).controler(nouvelleVal):
-                self._attributs[nom] = nouvelleVal
-
-    def majAttributs(self, dicoAttributs):
-        self._attributs = dicoAttributs
-    
-    def attributs(self):
-        return self._attributs
-
-    def notes(self):
-        return self._notes
-
-    def majNotes(self, notes):
-        #on limite a 400 le nombre de caracteres
-        notes = str(notes)
-        self._notes = notes[0:400]
-
-    def icone(self):
-        return QIcon(self._icone)
- 
-class Cac(Attaque):
-    """attaque au corps a corps"""
-    def __init__(self):
-        super(Cac, self).__init__()
-        self._nom = "Attaque au corps-à-corps"
-        self._pionCible = None
-        self._sourceCurseur = ""
-        self._nomBouton = "pi_attaqueCac"
-        self._icone = "img\\curseurEpee.png"
-
-    def typeAtt(self):
-        return "cac"
-
-    def desactiver(self):
-        self.afficherCibles(False)
-        super(Cac, self).desactiver()
-
-    def valider(self):
-        if self.estValide() and self._pionCible:
-            super(Cac, self).valider()
-      
-    def maj(self):
-        self.afficherCibles(False)
-        pionCible = self.plateau.cases[self._coordCible].occupant()
-        if pionCible != None and pionCible != self.plateau.pionSelectionne():
-            self._pionCible = pionCible
-        else:
-            self._pionCible = None
-        self.afficherCibles(True)
-
-    def estValide(self):
-        return (self._coordCible in self.plateau.zone(self.plateau.pionSelectionne().position, self.portee, 0, False, True))
-
-    def afficherCibles(self, actif):
-        if self._pionCible:
-            self._pionCible.estCibleAttaque(actif, self.estValide())
-
-    def envoiSignal(self):
-        print "{} a attaqué {} au corps-à-corps".format(self.acteur().txtId(), self._pionCible.txtId())
-
-class Distance(Attaque):
-    """attaque a distance"""
-    def __init__(self):
-        super(Distance, self).__init__()
-        self._nom = "Attaque à distance"
-        self._itemLigne = None
-        self._pionCible = None
-        self._sourceCurseur = ""
-        self._nomBouton = "pi_attaqueDist"
-        self._icone = ":/interface/16/ressource/arc_16.png"
-
-    def typeAtt(self):
-        return "dist"
-
-    def majCoordCible(self, coord):
-        if self._pionCible:
-            self._pionCible.estCibleAttaque(False, self.estValide())
-        if self._coordCible in self.plateau.cases:    
-            self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
-        super(Distance, self).majCoordCible(coord)        
-
-    def valider(self):
-        if self.estValide() and self._pionCible != None:
-            super(Distance, self).valider()
-
-    def maj(self):
-        """met a jour la ligne de mire representant l'attaque a distance"""
-        self.afficherCibles(False)
-        pionCible = self.plateau.cases[self._coordCible].occupant()
-        self.majItemsGraphiques()
-        if pionCible != None and pionCible != self.plateau.pionSelectionne():
-            self._pionCible = pionCible
-        else:
-            self._pionCible = None
-        self.afficherCibles(True)
-
-    def estValide(self):
-        return self.plateau.estCibleAttaqueDistValide(self._coordCible)
-
-    def afficherCibles(self, actif):
-        valide = True
-        if actif: valide = self.estValide()
-        
-        if self._pionCible:
-            self._pionCible.estCibleAttaque(actif, valide)
-        else:
-            #si pas de pion vise, on affiche la case cible comme visee
-            self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, valide)            
-
-    def creerItemsGraphiques(self):
-        self._itemLigne = QGraphicsLineItem()
-        self._itemLigne.setZValue(100)
-        pinceau = QPen()
-        pinceau.setWidth(6)
-        self._itemLigne.setPen(pinceau)
-        self._itemLigne.prepareGeometryChange()
-        self.plateau.addItem(self._itemLigne)
-
-    def majItemsGraphiques(self):
-        self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
-                                       self.plateau.cases[self._coordCible].centreGraphique))
-
-    def detruireItemsGraphiques(self):
-        if self._itemLigne != None:
-            self._itemLigne.prepareGeometryChange()
-            self.plateau.removeItem(self._itemLigne)
-            self._itemLigne = None
-
-    def envoiSignal(self):
-        print "{} a attaqué {} a distance".format(self.acteur().txtId(), self._pionCible.txtId())
-
-
-class Zone(Attaque):
-    """attaque de zone de base"""
-    def __init__(self):
-        super(Zone, self).__init__()    
-        self._nom = "Attaque de zone"
-        self._itemLigne = None
-        self._itemCible = None
-        self._casesCibles = []
-        self._sourceCurseur = ""
-        self._nomBouton = "pi_attaqueZone"
-        self._icone = ":/interface/16/ressource/baguette_16.png"
-
-    def typeAtt(self):
-        return "zone"
-
-    def valider(self):
-        if self.estValide() and len(self._casesCibles) > 0:
-            super(Zone, self).valider() 
-
-#     def desactiver(self):
-#         self.detruireItemsGraphiques()
-#         super(Zone, self).desactiver() 
-
-    def maj(self):
-        """maj la forme de l'attaque de zone et les items cibles"""
-        self.afficherCibles(False)
-        self.majItemsGraphiques()
-        self.majCibles()
-        self.afficherCibles(True)      
-
-    def afficherCibles(self, actif):
-        for coord in self._casesCibles:
-            self.plateau.cases[(coord[0], coord[1])].majEstCibleCurseur(actif)
-            z = 0 if len(coord) == 2 else coord[2]
-            if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
-                pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
-                pion.estCibleAttaque(actif) 
-
-    def listePionsCibles(self):
-        retour = []
-        print self._casesCibles
-        for coord in self._casesCibles:
-            z = 0 if len(coord) == 2 else coord[2]
-            if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
-                pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
-                if not pion in retour:
-                    retour.append(pion)
-        return retour
-
-    def creerItemsGraphiques(self):
-        self._itemLigne = QGraphicsLineItem()
-        self._itemLigne.setPen(QPen(QColor("black")))
-        self._itemLigne.prepareGeometryChange()
-        self.plateau.addItem(self._itemLigne)
-
-        self._itemCible = QGraphicsEllipseItem()
-        self._itemCible.setPen(QPen(QColor("black")))
-        self._itemCible.prepareGeometryChange()
-        self.plateau.addItem(self._itemCible)
-
-    def detruireItemsGraphiques(self):
-        if self._itemCible != None:
-            self._itemCible.prepareGeometryChange()
-            self.plateau.removeItem(self._itemCible)
-            self._itemCible = None
-        
-        if self._itemLigne != None:
-            self._itemLigne.prepareGeometryChange()
-            self.plateau.removeItem(self._itemLigne)
-            self._itemLigne = None
-
-    def envoiSignal(self):
-        touches = ""
-        for pion in self.listePionsCibles():
-            touches += "{}, ".format(pion.txtId())
-        touches = touches[:-2]
-        print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches)
-
-
-class Ligne(Zone):
-    """attaque de zone de forme lineaire"""
-    def __init__(self):
-        super(Ligne, self).__init__()
-        self._nom = "Attaque de zone: ligne"
-
-    def typeAttZone(self):
-        return "ligne"
-
-    def majItemsGraphiques(self):
-        if not self._desactivationDemandee:
-            self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
-                                           self.plateau.cases[self._coordCible].centreGraphique))
-
-    def majCibles(self):
-        """met a jour la liste des cases cibles"""
-        if not self._desactivationDemandee:
-            self._casesCibles = []
-            x1, y1 = self.acteur().position
-            z1 = self.acteur().zAbs() + self.acteur().hauteur
-            x2, y2 = self._coordCible
-            if self.plateau.cases[(x2, y2)].estOccupee():
-                z2 = self.plateau.cases[(x2, y2)].occupant().zAbs()
-            else:
-                z2 = self.plateau.cases[(x2, y2)].altitude   
-             
-            for coord in br.ligne((x1, y1, z1), (x2, y2, z2)):
-                if coord != (x1, y1, z1):
-                    self._casesCibles.append(coord)  
-            
-            if not self.estValide(): self._casesCibles = []
-        
-    def estValide(self):
-        retour = True
-        for coord in self._casesCibles:
-            x, y, z = coord
-            if not self.plateau.cases[(x, y)].estFranchissable(z):
-                if not isinstance(self.plateau.cases[(x, y)].occupant(z), Combattant):
-                    retour = False
-                    break
-        return retour
-            
-class Disque(Zone):
-    """attaque de zone de forme circulaire"""
-    def __init__(self):
-        super(Disque, self).__init__()
-        self._nom = "Attaque de zone: disque"
-
-    #decorateur
-    def autorise(f):
-        def _autorise(self, *args):
-            def fVide(*args):
-                pass
-            retour = fVide
-            if not self._desactivationDemandee:
-                retour = f
-            retour(self, *args)                            
-        return _autorise
-
-    def typeAttZone(self):
-        return "disque"
-
-    def activer(self, plateau, numPion):
-        super(Disque, self).activer(plateau, numPion)
-        self._rayon = self.plateau.fenetre.ui.pi_rayonAttaqueZone.value()
-    
-    @autorise  
-    def majCoordCible(self, coord):
-        if self._coordCible in self.plateau.cases:    
-            self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
-        super(Disque, self).majCoordCible(coord)    
-
-    @autorise
-    def majCibles(self):
-        if self.plateau.cases[self._coordCible].estOccupee():
-            zCible = self.plateau.cases[self._coordCible].occupant().zAbs()
-        else:
-            zCible = self.plateau.cases[self._coordCible].altitude   
-        self._casesCibles = self.plateau.zone3d(self._coordCible, self._rayon, zCible)
-
-    def afficherCibles(self, actif):
-        if self.estValide():
-            super(Disque, self).afficherCibles(actif)
-        else:
-            super(Disque, self).afficherCibles(False)
-            self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, False)
-    
-    @autorise
-    def majRayon(self, val):
-        self._rayon = val
-        self.maj()
-
-    @autorise
-    def majItemsGraphiques(self):
-        self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
-                                       self.plateau.cases[self._coordCible].centreGraphique))
-        if self.estValide():
-            rect = self.rectEllipseCirculaire(self.plateau.cases[self._coordCible].centreGraphique, self._rayon)
-            if rect != None:
-                self._itemCible.setRect(rect)
-        self._itemCible.setVisible(self.estValide() and rect != None)
-
-    def estValide(self):
-        return self.plateau.estCibleAttaqueDistValide(self._coordCible)
-
-    @autorise
-    def rectEllipseCirculaire(self, centre, rayon):
-        """renvoie le QRectF definissant une ellipse ayant le QPointF pour centre et le rayon en cases entres en param
-           attention: l'ellipse n'est pas tout a fait circulaire, elle couvre horizontalement et
-           verticalement le nombre de cases demandees"""
-        rect = None
-        if rayon > 0:
-            p1 = QPointF((centre.x() - (rayon * self.plateau.hCase)), (centre.y() - (rayon * self.plateau.hCase)))
-            p2 = QPointF((centre.x() + (rayon * self.plateau.hCase)), (centre.y() + (rayon * self.plateau.hCase)))
-            if p1 != p2:
-                rect = QRectF()
-                rect.setTopLeft(p1)
-                rect.setBottomRight(p2)
-        return rect
-
-class Cone(Zone):
-    """attaque de zone de forme conique"""
-    def __init__(self):
-        super(Cone, self).__init__()
-        self._nom = "Attaque de zone: cône"
-
-    def typeAttZone(self):
-        return "cone"
-
-    def creerItemsGraphiques(self):
-        self._itemCible = QGraphicsPolygonItem()
-        self._itemCible.setPen(QPen(QColor("black")))
-        self._itemCible.prepareGeometryChange()
-        self.plateau.addItem(self._itemCible)
-
-    def majItemsGraphiques(self):        
-        self._itemCible.setPolygon(self.polygoneCone(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
-                                                     self.plateau.cases[self._coordCible].centreGraphique))
-
-
-    def polygoneCone(self, point1, point2):
-        """renvoie le polygone du cone defini par les deux points (origine, distance)"""
-        ligne1 = QLineF(point1, point2)
-        longueur = ligne1.length()
-        ligne1.setAngle(ligne1.angle() + 22.5)
-        ligne1.setLength(1.1547*longueur)
-        ligne2 = QLineF(point1, point2)    
-        ligne2.setAngle(ligne2.angle() - 22.5)
-        ligne2.setLength(1.1547*longueur)
-        polygone = QPolygonF()
-        polygone.append(point1)
-        polygone.append(ligne1.p2())
-        polygone.append(ligne2.p2())
-        return polygone
-
-
-
-
-
-
-
-
-
-
-
-
-        
-
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+import regles
+import AEtoile
+import br
+from Pion import Pion
+from Combattant import Combattant
+from Decor import Decor
+
+class Action(object):
+    """action effectuee par un combattant sur le plateau de jeu"""
+    def __init__(self):
+        self._num = None         #no du pion actif
+        self._coordCible = None  #coord de la case ciblee par le curseur
+        self._cible = None       #cible (case ou pion)
+        self._sourceCurseur = ""
+        self._nomBouton = ""
+        self._enCours = False
+        self._desactivationDemandee = False
+
+    #decorateur
+    def autorise(f):
+        def _autorise(self, *args):
+            def fVide(*args):
+                pass
+            retour = fVide
+            if not self._desactivationDemandee:
+                retour = f
+            retour(self, *args)                            
+        return _autorise
+
+    def typeAtt(self):
+        return ""
+
+    def activer(self, plateau, numPion):
+        self.plateau = plateau
+        self._num = numPion
+        
+        self.enfoncerBouton(True)
+        self.activerCurseur()
+        self.creerItemsGraphiques()
+
+        self._enCours = True
+
+    def majCoordCible(self, coord):
+        """met a jour les coordonnees de la cible,
+            cad la case actuellement survolee par la souris"""
+        if self.plateau.coordonneesValides(coord):
+            self._coordCible = coord
+            self.maj()
+
+    def desactiver(self):
+        self._desactivationDemandee = True
+        self.afficherCibles(False)
+        self.detruireItemsGraphiques()
+        self.desactiverCurseur()
+        self.enfoncerBouton(False)
+        self._enCours = False
+
+    def enCours(self):
+        return self._enCours
+
+    def valider(self):
+        #envoyer signal
+        self.envoiSignal()
+        self.desactiver()
+
+    def estValide(self):
+        return True
+
+    def maj(self):
+        pass
+
+    def acteur(self):
+        return self.plateau.combattants[self._num]
+
+    def coordActeur(self):
+        return self.acteur().position
+
+    def activerCurseur(self):
+        if len(self._sourceCurseur) > 0:
+            curseurPix = QPixmap(self._sourceCurseur)
+            if not curseurPix.isNull():
+                curseur = QCursor(curseurPix, 0, curseurPix.height())
+                self.plateau.fenetre.ui.cbt_vue.setCursor(curseur)   
+
+    def desactiverCurseur(self):
+        self.plateau.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
+
+    def enfoncerBouton(self, actif):
+        for bouton in self.plateau.fenetre.ui.pi_actions.findChildren(QToolButton):
+            if bouton.objectName() == self._nomBouton:
+                bouton.setChecked(actif)
+
+    #manipulation des items graphiques
+    def creerItemsGraphiques(self):
+        pass
+
+    def majItemsGraphiques(self):
+        pass    
+
+    def detruireItemsGraphiques(self):
+        pass
+
+    #affichage des cibles
+    def afficherCibles(self, actif):
+        pass
+
+    #envoi du signal en cas de validation
+    def envoiSignal(self):
+        pass
+
+    def pivoter(self, modRotation):
+        pass
+
+         
+        
+class Deplacement(Action):
+    ### a completer avec des icones de deplacement,
+    #la prise en compte de la nage et de l'escalade
+    #et le calcul du cout de deplacement
+    def __init__(self):
+        super(Deplacement, self).__init__()
+        self._chemin = []  #liste des coord des cases a traverser
+        self._chercheurChemin = None
+        self._cout = 0     #cout en points de dep
+        self._zCible = 0
+        self.cible_aConfirmer = None
+        self._sourceCurseur = ""
+        self._nomBouton = "pi_deplacement" 
+
+    def typeAtt(self):
+        return "dep"
+    
+    def activer(self, plateau, numPion):
+        super(Deplacement, self).activer(plateau, numPion)
+        self.plateau.proj.creer(self.acteur())
+        
+    def desactiver(self):
+        self.plateau.proj.desactiver()
+        if self._chercheurChemin:
+            self._chercheurChemin.arreter()
+            self._chercheurChemin = None
+        super(Deplacement, self).desactiver()
+
+    def valider(self):
+        if not self.cible_aConfirmer or self.cible_aConfirmer != self._coordCible:             
+            self.cible_aConfirmer = self._coordCible
+            self.recupZCible()
+            self.creerChemin() 
+        else:
+            if self.estValide() and self.plateau.proj.projectionValide():
+                self.acteur().majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
+                self.acteur().majZ(self._zCible)
+                super(Deplacement, self).valider()
+
+    def estValide(self):
+        return len(self._chemin)>0
+
+    def majCoordCible(self, coord):
+        if coord != self.coordActeur():
+            super(Deplacement, self).majCoordCible(coord)
+
+    def maj(self):
+        self.plateau.proj.majCoord(self._coordCible)
+
+    def pivoter(self, modRotation):
+        self.plateau.proj.majRotation(modRotation)
+            
+    def creerChemin(self):
+        self.afficherCibles(False)
+        self._chemin = []
+        self._cout = 0
+        if self._chercheurChemin:
+            self._chercheurChemin.arreter()
+            self._chercheurChemin = None
+        self._chercheurChemin = AEtoile.Chemin(self.plateau, self.coordActeur(), self._coordCible, self.acteur().z, self._zCible)
+        self._chemin = self._chercheurChemin.liste()
+        self.afficherCibles(True)        
+
+    def afficherCibles(self, actif):
+        for coord, cout in self._chemin:
+            valide = True
+            if actif:
+                if cout > self.acteur().depMarche: valide = False
+            else:
+                cout = 0
+            self.plateau.cases[coord].majAffichageDeplacement(cout, valide)
+
+    def envoiSignal(self):
+        cout = self._chemin[-1][1]  #cout de deplacement retenu pour la derniere case
+        print "{} s'est deplacé et a utilisé {} points de mouvement".format(self.acteur().txtId(), cout)
+
+    def recupZCible(self):
+        self._zCible = self.acteur().z    
+
+
+class Vol(Deplacement):
+    """idem que Deplacement, mais affiche en plus la boite de dialogue Vol
+       (et n'utilise pas le meme algo de deplacement?)"""
+    def __init__(self):
+        super(Vol, self).__init__()
+        self._zCible = 0
+        self._nomBouton = "pi_vol" 
+
+    def typeAtt(self):
+        return "vol"
+        
+    def recupZCible(self):
+        nouveauZ = self.plateau.dialogueVol(self.acteur().z)
+        self._zCible = nouveauZ 
+
+class Attaque(Action):
+    """attaque pre-parametree affectee a un pion, un personnage ou une creature"""
+    def __init__(self):
+        super(Attaque, self).__init__()
+        self._nom = "Attaque"
+        self._icone = ""
+        self._portee = 1   #portee max en cases
+        self._rayon = 0
+        self._attributs = regles.listeAttributsAttaques()
+        self._notes = ""
+
+    def typeAtt(self):
+        return "att"
+
+    def nom(self):
+        return self._nom
+
+    def majNom(self, nom):
+        if len(str(nom)) > 0:
+            self._nom = nom
+
+    def portee(self):
+        return self._portee
+
+    def majPortee(self, portee):
+        try:
+            ent = int(portee)
+            if ent > 0:
+                if ent >= 1000: ent = 999
+                self._portee = ent
+        except:
+            pass
+
+    def rayon(self):
+        return self._rayon
+    
+    def majRayon(self, rayon):
+        try:
+            ent = int(rayon)
+            if ent > 0:
+                if ent >= 100: ent = 99
+                self._rayon = ent
+        except:
+            pass
+
+    def majAttribut(self, nom, nouvelleVal):
+        if nom in self._attributs:
+            if regles.attributAttaque(nom).controler(nouvelleVal):
+                self._attributs[nom] = nouvelleVal
+
+    def majAttributs(self, dicoAttributs):
+        self._attributs = dicoAttributs
+    
+    def attributs(self):
+        return self._attributs
+
+    def notes(self):
+        return self._notes
+
+    def majNotes(self, notes):
+        #on limite a 400 le nombre de caracteres
+        notes = str(notes)
+        self._notes = notes[0:400]
+
+    def icone(self):
+        return QIcon(self._icone)
+ 
+class Cac(Attaque):
+    """attaque au corps a corps"""
+    def __init__(self):
+        super(Cac, self).__init__()
+        self._nom = "Attaque au corps-à-corps"
+        self._pionCible = None
+        self._sourceCurseur = ""
+        self._nomBouton = "pi_attaqueCac"
+        self._icone = "img\\curseurEpee.png"
+
+    def typeAtt(self):
+        return "cac"
+
+    def desactiver(self):
+        self.afficherCibles(False)
+        super(Cac, self).desactiver()
+
+    def valider(self):
+        if self.estValide() and self._pionCible:
+            super(Cac, self).valider()
+      
+    def maj(self):
+        self.afficherCibles(False)
+        pionCible = self.plateau.cases[self._coordCible].occupant()
+        if pionCible != None and pionCible != self.plateau.pionSelectionne():
+            self._pionCible = pionCible
+        else:
+            self._pionCible = None
+        self.afficherCibles(True)
+
+    def estValide(self):
+        return (self._coordCible in self.plateau.zone(self.plateau.pionSelectionne().position, self.portee, 0, False, True))
+
+    def afficherCibles(self, actif):
+        if self._pionCible:
+            self._pionCible.estCibleAttaque(actif, self.estValide())
+
+    def envoiSignal(self):
+        print "{} a attaqué {} au corps-à-corps".format(self.acteur().txtId(), self._pionCible.txtId())
+
+class Distance(Attaque):
+    """attaque a distance"""
+    def __init__(self):
+        super(Distance, self).__init__()
+        self._nom = "Attaque à distance"
+        self._itemLigne = None
+        self._pionCible = None
+        self._sourceCurseur = ""
+        self._nomBouton = "pi_attaqueDist"
+        self._icone = ":/interface/16/ressource/arc_16.png"
+
+    def typeAtt(self):
+        return "dist"
+
+    def majCoordCible(self, coord):
+        if self._pionCible:
+            self._pionCible.estCibleAttaque(False, self.estValide())
+        if self._coordCible in self.plateau.cases:    
+            self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
+        super(Distance, self).majCoordCible(coord)        
+
+    def valider(self):
+        if self.estValide() and self._pionCible != None:
+            super(Distance, self).valider()
+
+    def maj(self):
+        """met a jour la ligne de mire representant l'attaque a distance"""
+        self.afficherCibles(False)
+        pionCible = self.plateau.cases[self._coordCible].occupant()
+        self.majItemsGraphiques()
+        if pionCible != None and pionCible != self.plateau.pionSelectionne():
+            self._pionCible = pionCible
+        else:
+            self._pionCible = None
+        self.afficherCibles(True)
+
+    def estValide(self):
+        return self.plateau.estCibleAttaqueDistValide(self._coordCible)
+
+    def afficherCibles(self, actif):
+        valide = True
+        if actif: valide = self.estValide()
+        
+        if self._pionCible:
+            self._pionCible.estCibleAttaque(actif, valide)
+        else:
+            #si pas de pion vise, on affiche la case cible comme visee
+            self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, valide)            
+
+    def creerItemsGraphiques(self):
+        self._itemLigne = QGraphicsLineItem()
+        self._itemLigne.setZValue(100)
+        pinceau = QPen()
+        pinceau.setWidth(6)
+        self._itemLigne.setPen(pinceau)
+        self._itemLigne.prepareGeometryChange()
+        self.plateau.addItem(self._itemLigne)
+
+    def majItemsGraphiques(self):
+        self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
+                                       self.plateau.cases[self._coordCible].centreGraphique))
+
+    def detruireItemsGraphiques(self):
+        if self._itemLigne != None:
+            self._itemLigne.prepareGeometryChange()
+            self.plateau.removeItem(self._itemLigne)
+            self._itemLigne = None
+
+    def envoiSignal(self):
+        print "{} a attaqué {} a distance".format(self.acteur().txtId(), self._pionCible.txtId())
+
+
+class Zone(Attaque):
+    """attaque de zone de base"""
+    def __init__(self):
+        super(Zone, self).__init__()    
+        self._nom = "Attaque de zone"
+        self._itemLigne = None
+        self._itemCible = None
+        self._casesCibles = []
+        self._sourceCurseur = ""
+        self._nomBouton = "pi_attaqueZone"
+        self._icone = ":/interface/16/ressource/baguette_16.png"
+
+    def typeAtt(self):
+        return "zone"
+
+    def valider(self):
+        if self.estValide() and len(self._casesCibles) > 0:
+            super(Zone, self).valider() 
+
+#     def desactiver(self):
+#         self.detruireItemsGraphiques()
+#         super(Zone, self).desactiver() 
+
+    def maj(self):
+        """maj la forme de l'attaque de zone et les items cibles"""
+        self.afficherCibles(False)
+        self.majItemsGraphiques()
+        self.majCibles()
+        self.afficherCibles(True)      
+
+    def afficherCibles(self, actif):
+        for coord in self._casesCibles:
+            self.plateau.cases[(coord[0], coord[1])].majEstCibleCurseur(actif)
+            z = 0 if len(coord) == 2 else coord[2]
+            if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
+                pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
+                pion.estCibleAttaque(actif) 
+
+    def listePionsCibles(self):
+        retour = []
+        for coord in self._casesCibles:
+            z = 0 if len(coord) == 2 else coord[2]
+            if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
+                pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
+                if not pion in retour:
+                    retour.append(pion)
+        return retour
+
+    def creerItemsGraphiques(self):
+        self._itemLigne = QGraphicsLineItem()
+        self._itemLigne.setPen(QPen(QColor("black")))
+        self._itemLigne.prepareGeometryChange()
+        self.plateau.addItem(self._itemLigne)
+
+        self._itemCible = QGraphicsEllipseItem()
+        self._itemCible.setPen(QPen(QColor("black")))
+        self._itemCible.prepareGeometryChange()
+        self.plateau.addItem(self._itemCible)
+
+    def detruireItemsGraphiques(self):
+        if self._itemCible != None:
+            self._itemCible.prepareGeometryChange()
+            self.plateau.removeItem(self._itemCible)
+            self._itemCible = None
+        
+        if self._itemLigne != None:
+            self._itemLigne.prepareGeometryChange()
+            self.plateau.removeItem(self._itemLigne)
+            self._itemLigne = None
+
+    def envoiSignal(self):
+        touches = ""
+        for pion in self.listePionsCibles():
+            touches += "{}, ".format(pion.txtId())
+        touches = touches[:-2]
+        print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches)
+
+
+class Ligne(Zone):
+    """attaque de zone de forme lineaire"""
+    def __init__(self):
+        super(Ligne, self).__init__()
+        self._nom = "Attaque de zone: ligne"
+
+    def typeAttZone(self):
+        return "ligne"
+
+    def majItemsGraphiques(self):
+        if not self._desactivationDemandee:
+            self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
+                                           self.plateau.cases[self._coordCible].centreGraphique))
+
+    def majCibles(self):
+        """met a jour la liste des cases cibles"""
+        if not self._desactivationDemandee:
+            self._casesCibles = []
+            x1, y1 = self.acteur().position
+            z1 = self.acteur().zAbs() + self.acteur().hauteur
+            x2, y2 = self._coordCible
+            if self.plateau.cases[(x2, y2)].estOccupee():
+                z2 = self.plateau.cases[(x2, y2)].occupant().zAbs()
+            else:
+                z2 = self.plateau.cases[(x2, y2)].altitude   
+             
+            for coord in br.ligne((x1, y1, z1), (x2, y2, z2)):
+                if coord != (x1, y1, z1):
+                    self._casesCibles.append(coord)  
+            
+            if not self.estValide(): self._casesCibles = []
+        
+    def estValide(self):
+        retour = True
+        for coord in self._casesCibles:
+            x, y, z = coord
+            if not self.plateau.cases[(x, y)].estFranchissable(z):
+                if not isinstance(self.plateau.cases[(x, y)].occupant(z), Combattant):
+                    retour = False
+                    break
+        return retour
+            
+class Disque(Zone):
+    """attaque de zone de forme circulaire"""
+    def __init__(self):
+        super(Disque, self).__init__()
+        self._nom = "Attaque de zone: disque"
+
+    #decorateur
+    def autorise(f):
+        def _autorise(self, *args):
+            def fVide(*args):
+                pass
+            retour = fVide
+            if not self._desactivationDemandee:
+                retour = f
+            retour(self, *args)                            
+        return _autorise
+
+    def typeAttZone(self):
+        return "disque"
+
+    def activer(self, plateau, numPion):
+        super(Disque, self).activer(plateau, numPion)
+        self._rayon = self.plateau.fenetre.ui.pi_rayonAttaqueZone.value()
+    
+    @autorise  
+    def majCoordCible(self, coord):
+        if self._coordCible in self.plateau.cases:    
+            self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
+        super(Disque, self).majCoordCible(coord)    
+
+    @autorise
+    def majCibles(self):
+        if self.plateau.cases[self._coordCible].estOccupee():
+            zCible = self.plateau.cases[self._coordCible].occupant().zAbs()
+        else:
+            zCible = self.plateau.cases[self._coordCible].altitude   
+        self._casesCibles = self.plateau.zone3d(self._coordCible, self._rayon, zCible)
+
+    def afficherCibles(self, actif):
+        if self.estValide():
+            super(Disque, self).afficherCibles(actif)
+        else:
+            super(Disque, self).afficherCibles(False)
+            self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, False)
+    
+    @autorise
+    def majRayon(self, val):
+        self._rayon = val
+        self.maj()
+
+    @autorise
+    def majItemsGraphiques(self):
+        self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
+                                       self.plateau.cases[self._coordCible].centreGraphique))
+        if self.estValide():
+            rect = self.rectEllipseCirculaire(self.plateau.cases[self._coordCible].centreGraphique, self._rayon)
+            if rect != None:
+                self._itemCible.setRect(rect)
+        self._itemCible.setVisible(self.estValide() and rect != None)
+
+    def estValide(self):
+        return self.plateau.estCibleAttaqueDistValide(self._coordCible)
+
+    @autorise
+    def rectEllipseCirculaire(self, centre, rayon):
+        """renvoie le QRectF definissant une ellipse ayant le QPointF pour centre et le rayon en cases entres en param
+           attention: l'ellipse n'est pas tout a fait circulaire, elle couvre horizontalement et
+           verticalement le nombre de cases demandees"""
+        rect = None
+        if rayon > 0:
+            p1 = QPointF((centre.x() - (rayon * self.plateau.hCase)), (centre.y() - (rayon * self.plateau.hCase)))
+            p2 = QPointF((centre.x() + (rayon * self.plateau.hCase)), (centre.y() + (rayon * self.plateau.hCase)))
+            if p1 != p2:
+                rect = QRectF()
+                rect.setTopLeft(p1)
+                rect.setBottomRight(p2)
+        return rect
+
+class Cone(Zone):
+    """attaque de zone de forme conique"""
+    def __init__(self):
+        super(Cone, self).__init__()
+        self._nom = "Attaque de zone: cône"
+
+    def typeAttZone(self):
+        return "cone"
+
+    def creerItemsGraphiques(self):
+        self._itemCible = QGraphicsPolygonItem()
+        self._itemCible.setPen(QPen(QColor("black")))
+        self._itemCible.prepareGeometryChange()
+        self.plateau.addItem(self._itemCible)
+
+    def majItemsGraphiques(self):        
+        self._itemCible.setPolygon(self.polygoneCone(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
+                                                     self.plateau.cases[self._coordCible].centreGraphique))
+
+
+    def polygoneCone(self, point1, point2):
+        """renvoie le polygone du cone defini par les deux points (origine, distance)"""
+        ligne1 = QLineF(point1, point2)
+        longueur = ligne1.length()
+        ligne1.setAngle(ligne1.angle() + 22.5)
+        ligne1.setLength(1.1547*longueur)
+        ligne2 = QLineF(point1, point2)    
+        ligne2.setAngle(ligne2.angle() - 22.5)
+        ligne2.setLength(1.1547*longueur)
+        polygone = QPolygonF()
+        polygone.append(point1)
+        polygone.append(ligne1.p2())
+        polygone.append(ligne2.p2())
+        return polygone
+
+
+
+
+
+
+
+
+
+
+
+
+        
+

+ 0 - 119
lib/Cache - Copie.py

@@ -1,119 +0,0 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-from __future__ import division
-import Modes
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-
-class Cache(QGraphicsPolygonItem):
-    """cache place sur le plateau"""
-    def __init__(self, plateau, numero, parent=None):
-        """initialisation de la fenetre"""
-        super (Cache, self).__init__(parent)
-        self.plateau = plateau
-        self.numero = numero
-        self.nom = ""
-        self.listeCases = []
-        self._active = False
-        self._etiquette = None
-
-    def __getstate__(self):
-        """selectionne les attributs qui seront sauvegardes"""
-        self._active = False
-        state = {key:value for key, value in self.__dict__.items() if key in ["numero", "nom", "listeCases", "_active"]}
-        return (state)
-
-    def __setstate__(self, state):
-        """recupere les attributs sauvegardes"""
-        self.__dict__ = state
-
-    def recreer(self, plateau):
-        super (Cache, self).__init__()
-        self._etiquette = None        
-        self.plateau = plateau
-        self.creer()
-        
-    def creer(self):
-        """cree le cache sur la liste de cases en parametre"""
-        self.setFlag(QGraphicsItem.ItemIsFocusable)
-        self.setAcceptHoverEvents(True)
-        self.setBrush(QColor(0,0,0,255))
-        pinceau = QPen(QColor("black"))
-        pinceau.setWidth(10)
-        self.setPen(pinceau)
-        self._etiquette = QGraphicsTextItem(QString.fromUtf8("{}- {}".format(self.numero, self.nom)))
-        self._etiquette.setPos(self.mapFromScene(self.plateau.cases[self.coordCentre()].centreGraphique))
-        police = QFont("Arial",30)
-        police.setBold(True)
-        self._etiquette.setFont(police)
-        self._etiquette.setDefaultTextColor(QColor(50,50,50,180))     
-        self._etiquette.setParentItem(self)
-        self.setPolygon(self.plateau.polygoneAgglo(self.listeCases))
-        self.setZValue(100)
-        self.plateau.addItem(self)
-        self._active = True
-
-    def majPolygone(self, listeCases):
-        self.listeCases = listeCases
-        self.setPolygon(self.plateau.polygoneAgglo(self.listeCases))
-        self._etiquette.setPos(self.mapFromScene(self.plateau.cases[self.coordCentre()].centreGraphique))
-
-    def majEtiquette(self):
-        self._etiquette.setPlainText(QString().fromUtf8(self.nom))
-
-    def modeChange(self, mode):
-        if self._active:
-            if issubclass(mode, Modes.ModeBaseCp):
-                transparence = 130
-            else:
-                transparence = 255
-            self.setBrush(QColor(0,0,0, transparence))
-
-    def activer(self, actif):
-        self._active = actif
-        self.majAffichage()
-
-    def actif(self):
-        return self._active
-
-    def majAffichage(self):
-        self.setVisible(self._active)
-
-    def coordCentre(self):
-        """renvoie les coordonnees de la case la plus centrale de la liste"""
-        xtot = 0
-        ytot = 0
-        for coord in self.listeCases:
-            xtot += coord[0]
-            ytot += coord[1]
-
-        ecartMin = None
-        coordRetenues = None
-        for coord in self.listeCases:
-            ecartX = abs(xtot - (coord[0] * len(self.listeCases)))
-            ecartY = abs(ytot - (coord[1] * len(self.listeCases)))
-            if not ecartMin or (ecartX + ecartY) < ecartMin:
-                coordRetenues = coord
-                ecartMin = ecartX + ecartY
-        return coordRetenues
-
-    def sceneEvent(self, event):
-        """filtre les evenements souris et clavier
-            si vrai: l'evenement est bloque"""
-        retour = (not self.actif() or issubclass(self.plateau.modeActif.__class__, Modes.ModeBaseCp))
-        if not retour:
-            event.accept()
-        else:
-            event.ignore()
-        return retour         
-
-
-
-
-
-
-
-
-
-
-

+ 604 - 601
lib/Case.py

@@ -1,601 +1,604 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-from __future__ import division
-import os
-
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from outilsSvg import *
-from Terrain import Terrain
-import Modes
-from Pion import Pion
-from Combattant import Combattant
-from Decor import Decor
-
-class Case(QGraphicsPolygonItem):
-    """objet graphique representant une case du plateau"""
-    def __init__(self, plateau, parent=None):
-        super(Case, self).__init__(parent)
-        #plateau
-        self.plateau = plateau
-        
-        #attributs
-        self.x = 0
-        self.y = 0        
-        self.altitude = 0                   
-        self.terrain = Terrain()                       #terrain par defaut 
-        self.bordure = QColor(85, 85, 85, 85)          #couleur de la bordure par defaut
-        self.centreGraphique = None
-
-        self.occupation = {}    #z: num pion
-        self.cachesActifs = []       #liste des caches places par le MJ (cache le terrain, les decors, les pions aux joueurs...)
-        self.cachesInactifs = []
-
-        #effet sur la case 
-        self.effetActif = "" 
-
-        #polygones d'affichage
-        self.polygoneEffet = None
-        self.polygoneAffichageSpecial = None
-        self.etiquetteAltitude = None
-        self.polygoneCache = None
-        
-
-    def __getstate__(self):
-        """selectionne les attributs qui seront sauvegardes"""
-        state = {key:value for key, value in self.__dict__.items() if key in ["x", "y", "altitude","terrain","bordure","couleur", \
-                                                                              "ombre", "effetActif", "cachesActifs", "cachesInactifs"]}
-
-        return (state)
-
-    def __setstate__(self, state):
-        """recupere les attributs sauvegardes"""
-        self.__dict__ = state
-        
-    ######## fonctions de base : geometrie, aspect graphique      ######
-    def creer(self, x, y, couleur = QColor(0, 255, 0, 80)):
-        """creation du polygone et enregistrement des donnees geometriques"""
-        self.x = x
-        self.y = y
-        self.terrain.couleur = couleur
-        #creation de l'objet graphique sur le plateau
-        self.creerGraphique()
-        
-    def creerGraphique(self):
-        """cree les objets graphiques representant la case"""
-        #reinitialisation des variables 
-        self.couleurEffet = {"brule":QColor("orange"), "glace":QColor("white"), "poison":QColor("green"), "eau":QColor("blue")}
-        self.imgEffet = {"brule":"effFeu.jpg", "glace":"effGlace.jpg", "poison":"effPoison.png", "eau":"effEau.png"}
-
-        #enregistrement des cases voisines: 
-        self.voisins = self.lstVoisins(self.x, self.y)
-        self.occupation = {}
-   
-        #enregistrement du centre
-        if self.plateau.formeCases == "H":  #refPlateau
-            k = 0
-            if 1 == (self.x % 2): k = 0.5
-            self.centreGraphique = QPointF(((self.x*0.866)+0.5773)*self.plateau.hCase, (self.y+k+0.5)*self.plateau.hCase)
-        else:
-            self.centreGraphique = QPointF((self.x+0.5)*self.plateau.hCase, (self.y+0.5)*self.plateau.hCase)
-        
-        #cree le polygone de la case
-        self.setPolygon(self.polygone(self.x, self.y))
-        self.plateau.addItem(self)  #refPlateau
-        
-        #interactions graphiques:
-        self.setFlag(QGraphicsItem.ItemIsFocusable)
-        self.setAcceptHoverEvents(True)
-        self.setAcceptDrops(True)
-        self.setZValue(0)
-        self.setFiltersChildEvents(True)
-
-#        #pour afficher les coordonnees des cases:  
-        self.etiquette = None
-        self.afficherEtiquette("{}-{}".format(self.x,self.y))     
-
-        self.logoDep = LogoDep(self)
-        self.logoDep.creer()
-        
-        #apparence initiale de la case
-        self.majTerrain(self.terrain)            
-
-        #polygone utilise pour afficher la cible du curseur
-        self.polygoneCible = QGraphicsPolygonItem(self.polygone(self.x, self.y), parent=self)
-        self.polygoneCible.setVisible(False)
-        self.polygoneCible.setAcceptHoverEvents(False)
-        
-        #cache
-        self.polygoneCache = PolygoneCache(self)
-        self.polygoneCache.creer()
-        self.majCache()
-
-    def recreer(self, plateau):
-##        self.plateau = plateau  #refPlateau
-        self.plateau = plateau
-        super(Case, self).__init__()
-        #polygones d'affichage
-        self.polygoneEffet = None
-        self.polygoneAffichageSpecial = None
-        self.polygoneCache = None
-        self.etiquetteAltitude = None
-        
-        self.creerGraphique()
-        self.majTerrain(self.terrain)   
-        self.majAffichageSpecial("")
-        self.majEffet(self.effetActif)
-
-    def polygone(self, x, y):
-        """renvoie l'objet graphique hexagone de la case"""
-        polygone = QPolygonF()
-        if self.plateau.formeCases == "H":
-            #si x est impair sur un plateau a cases hexagonales, le y est augmente de 0.5
-            if 1 == (x % 2):
-                y += 0.5
-            polygone  << QPointF(((x*0.866)+0.2886)*self.plateau.hCase,  y*self.plateau.hCase) \
-                      << QPointF(((x*0.866)+0.866)*self.plateau.hCase,   y*self.plateau.hCase) \
-                      << QPointF(((x*0.866)+1.1547)*self.plateau.hCase, (y+0.5)*self.plateau.hCase) \
-                      << QPointF(((x*0.866)+0.866)*self.plateau.hCase,  (y+1)*self.plateau.hCase) \
-                      << QPointF(((x*0.866)+0.2886)*self.plateau.hCase, (y+1)*self.plateau.hCase)  \
-                      << QPointF( (x*0.866)*self.plateau.hCase,         (y+0.5)*self.plateau.hCase)
-        else:
-            polygone  << QPointF(x*self.plateau.hCase,      y*self.plateau.hCase) \
-                      << QPointF((x+1)*self.plateau.hCase,  y*self.plateau.hCase) \
-                      << QPointF((x+1)*self.plateau.hCase,  (y+1)*self.plateau.hCase) \
-                      << QPointF(x*self.plateau.hCase,      (y+1)*self.plateau.hCase)          
-        return polygone
-
-    def lstVoisins(self, x, y):
-        """renvoie la liste des cases voisines
-           seulement cases existantes sur le plateau / seulement cases adjacentes (cas des cases carrees)"""
-        voisins = []
-        if self.plateau.formeCases == "H":
-            if 1 == (x % 2):
-                lst = [(x, y-1), (x+1, y), (x+1, y+1), (x,  y+1), (x-1, y+1), (x-1, y)]
-            else:
-                lst = [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
-        else:
-            lst = [(x, y-1), (x+1, y-1), (x+1, y), (x+1, y+1), (x,   y+1), (x-1, y+1), (x-1, y), (x-1, y-1)]
-                  
-        for coord in lst: 
-            if (coord[0] >= 0 and coord[1] >= 0 and coord[0] < self.plateau.nbCasesX and coord[1] < self.plateau.nbCasesY):
-                voisins.append(coord)
-        return voisins                           
-    
-    def afficherEtiquette(self, txt):
-        """affiche l'etiquette avec le texte demande"""
-        if self.etiquette == None:
-            self.etiquette = QGraphicsSimpleTextItem(QString().fromUtf8(str(txt)), parent=self)
-            k = 0
-            if 1 == (self.x % 2): k = 0.5
-            if self.plateau.formeCases == "H":
-                self.etiquette.setPos(QPointF(((self.x*0.866)+0.2886)*self.plateau.hCase,  (self.y+k+0.5)*self.plateau.hCase))
-            else:
-                self.etiquette.setPos(QPointF(self.x*self.plateau.hCase,  self.y*self.plateau.hCase))
-        else:
-            self.etiquette.setText(QString().fromUtf8(str(txt)))
-      
-    
-     
-    ########################
-
-    ### deplacement
-    def coutDep(self):
-        #a implementer, en fonction des
-        #capacites de deplacement du pion actuellement selectionne
-        return 1
-
-    ### occupation
-    def occuper(self, numPion, z):
-        """un pion vient occuper la case a l'altitude z"""
-        self.occupation[z] = numPion
-
-    def liberer(self, z):
-        """aucun pion n'occupe plus la case a l'altitude z"""
-        if z in self.occupation:
-            del self.occupation[z]
-            
-    def estOccupee(self, z=None):
-        """renvoie vrai si la case correspondant a la hauteur z est occupee"""
-        if z:
-            retour = (z in self.occupation) 
-        else:
-            retour = len(self.occupation) > 0
-        return retour       
-
-    def occupant(self, z=None, classe = Pion):
-        """si la case correspondant a la hauteur z est occupee, renvoie l'objet en question
-           sinon renvoie None"""
-        num = None
-        if z:
-            if z in self.occupation:
-                num = self.occupation[z]   
-        else:
-            #si aucune altitude n'est donnee, renvoie le premier occupant
-            for z in self.occupation:
-                num = self.occupation[z]
-                break
-        retour = None
-        if num:
-            if num < 10000:
-                retour = self.plateau.combattants[num]
-            else:
-                retour = self.plateau.decors[num] 
-        if retour:
-            if not isinstance(retour, classe): retour = None        
-        return retour                          
-
-    def estFranchissable(self, zAbs = None):
-        """a l'altitude absolue demandee, 
-        la case est-elle franchissable pour une ligne de mire ou un deplacement"""
-        if not zAbs: zAbs = self.altitude
-        return (not self.estOccupee( (zAbs - self.altitude) ) and (zAbs >= self.altitude))
-
-    ########## fonctions de maj ###########
-    def majTerrain(self, terrain = Terrain()):
-        """met a jour le terrain de la case"""
-        self.terrain = terrain
-        if self.terrain.imgTexture.estValide():
-            self.setBrush(QBrush(QImage(self.terrain.imgTexture.chemin())))
-        else:
-            if self.terrain.couleur.isValid():
-                self.setBrush(QBrush(self.terrain.couleur))
-        pinceau = QPen()
-        pinceau.setColor(self.couleurBordure())
-        pinceau.setWidth(1)
-        self.setPen(pinceau)
-
-    def majAltitude(self, altitude):
-        """met a jour l'altitude de la case"""
-        self.altitude = altitude  
-#         self.afficherEtiquette(altitude)   
-
-    def majAffichageDeplacement(self, cout, valide = True):
-        """lorsque cette case est sur le chemin d'un pion,
-            un disque blanc ou rouge apparait indiquant le
-            cout du deplacement jusqua cette case
-            un cout de 0 fait disparaitre ce symbole"""
-        self.logoDep.afficher(cout, valide)
-
-    def majEstCibleCurseur(self, actif, valide=True):
-        """affiche la case comme etant la cible du curseur (lors d'une creation de pion, d'un deplacement...)"""
-        if actif:
-            pinceau = QPen()
-            pinceau.setWidth(5)
-            brush = QBrush()
-            brush.setStyle(13)
-            pinceau.setColor(self.couleurProj(valide))
-            brush.setColor(self.couleurProj(valide))
-            self.polygoneCible.setPen(pinceau)
-            self.polygoneCible.setBrush(brush)
-            self.setZValue(99)
-        else:
-            self.setZValue(0)
-        self.polygoneCible.setVisible(actif)    
-            
-    def majEffet(self, effet):
-        """met a jour l'effet actif sur la case"""       
-        if self.polygoneEffet == None:
-            #on cree le polygone utilise pour afficher les effets
-            self.polygoneEffet = QGraphicsPolygonItem(self.polygone(self.x, self.y), parent=self)
-            pinceau = QPen()
-            pinceau.setColor(self.bordure)
-            pinceau.setWidth(1)
-            self.polygoneEffet.setPen(pinceau)
-            self.polygoneEffet.setVisible(False)
-
-        if len(effet) > 0 and effet != "aucun":
-            #gradient de couleur
-            gradient = QRadialGradient(self.centreGraphique, 0.5*self.plateau.hCase)
-            couleur0 = QColor(0,0,0,0)
-            couleur20 = self.couleurEffet[effet]
-            couleur20.setAlpha(70)
-            couleur10 = self.couleurEffet[effet]
-            couleur10.setAlpha(255)
-
-            gradient.setColorAt(0, couleur0)
-            gradient.setColorAt(0.8, couleur0)
-            gradient.setColorAt(0.95, couleur10)
-            gradient.setColorAt(0.98, couleur20)
-            gradient.setColorAt(1, couleur10)
-            self.polygoneEffet.setBrush(gradient)
-   
-            self.polygoneEffet.setVisible(True)
-
-            self.effetActif = effet
-        else:
-            self.polygoneEffet.setVisible(False)              
-
-    def majAffichageSpecial(self, affichage=""):
-        """donne a la case l'aspect demande en rendant visible/invisible le polygone d'affichage special"""
-        #polygone d'affichage special (altitude, tactique...)
-        if self.polygoneAffichageSpecial == None:
-            self.polygoneAffichageSpecial = QGraphicsPolygonItem(self.polygone(self.x, self.y), parent=self)
-            pinceau = QPen()
-            pinceau.setColor(self.bordure)
-            pinceau.setWidth(1)
-            self.polygoneAffichageSpecial.setPen(pinceau)
-
-        if affichage != "altitude" and self.etiquetteAltitude:
-            self.etiquetteAltitude.setVisible(False)
-            
-        if affichage == "tactique":
-            if self.terrain.franchissable:
-                self.polygoneAffichageSpecial.setBrush(QColor(255,255,255))
-            else:
-                self.polygoneAffichageSpecial.setBrush(QColor(50,50,50))
-            self.polygoneAffichageSpecial.setVisible(True)
-            
-        elif affichage == "altitude":
-            if self.etiquetteAltitude == None:
-                self.etiquetteAltitude = QGraphicsSimpleTextItem("{}".format(self.altitude), parent=self)
-                police = QFont("Georgia", 18)
-                police.setItalic(True)
-                self.etiquetteAltitude.setFont(police)
-                self.etiquetteAltitude.setPos(QPointF(((self.x*0.866)+0.65)*self.plateau.hCase,  (self.y+0.7)*self.plateau.hCase))
-            if self.altitude >= 0:
-                couleur = QColor("red").lighter(200-(5*self.altitude))
-            else:
-                couleur = QColor("purple").lighter(200+(5*self.altitude))
-            self.polygoneAffichageSpecial.setBrush(couleur)
-            self.polygoneAffichageSpecial.setZValue(5)
-            self.polygoneAffichageSpecial.setVisible(True)
-            self.etiquetteAltitude.setText(QString.fromUtf8("{}".format(self.altitude)))
-            self.etiquetteAltitude.setVisible(True)
-            self.etiquetteAltitude.setZValue(6)
-        else:
-            self.polygoneAffichageSpecial.setVisible(False)
-
-
-    #caches
-    def ajouterCache(self, idCache, actif = True):
-        if actif:
-            if not idCache in self.cachesActifs:
-                self.cachesActifs.append(idCache)
-                self.majCache() 
-        else:
-            if not idCache in self.cachesInactifs:
-                self.cachesInactifs.append(idCache)
-        
-    def supprimerCache(self, idCache):
-        if idCache in self.cachesActifs:
-            self.cachesActifs.remove(idCache) 
-            self.majCache() 
-        elif idCache in self.cachesInactifs:
-            self.cachesInactifs.remove(idCache)     
-
-    def activerCache(self, idCache, actif = True):
-        if actif:
-            if idCache in self.cachesInactifs:
-                self.cachesInactifs.remove(idCache)
-                self.cachesActifs.append(idCache)
-                self.majCache()
-        else:
-            if idCache in self.cachesActifs:
-                self.cachesActifs.remove(idCache)
-                self.cachesInactifs.append(idCache)
-                self.majCache()
-                                    
-    def majCache(self):
-        self.polygoneCache.setVisible((len(self.cachesActifs) > 0))
-        if len(self.cachesActifs) > 0:
-            self.polygoneCache.majTransparence() 
-
-    def estCachee(self):
-        """une case cachee ne recoit plus aucun evenement souris ou clavier"""
-        retour = (len(self.cachesActifs) > 0 and \
-                not issubclass(self.plateau.modeActif.__class__, Modes.ModeBaseCp))
-        return retour
-
-    #fonctions secondaires
-    def couleurDep(self):
-        """renvoie une couleur secondaire utilisee pour les champs de deplacements"""
-        luminositeActuelle = self.couleurEffective().lightness()
-        if luminositeActuelle < 150:
-            retour = QColor(210,255,255,100)
-        else:
-            retour = QColor(210,255,255,100)
-        return retour
-
-    def couleurProj(self, valide):
-        """renvoie une couleur secondaire utilisee pour les projections de deplacement"""
-        luminositeActuelle = self.couleurEffective().lightness()
-        if valide:
-            retour = QColor("white")
-        else:
-            retour = QColor("red")
-        if luminositeActuelle > 220:
-            retour = retour.darker(120)
-            
-        return retour
-
-    def couleurBordure(self):
-        """renvoie la couleur utilisee pour les bordures de la case"""
-        luminositeActuelle = self.couleurEffective().lightness()
-        if luminositeActuelle > 150:
-            retour = QColor(85, 85, 85, 130)
-        elif luminositeActuelle > 100 and luminositeActuelle <= 150:
-            retour = QColor(10, 10, 10, 130)
-        else:
-            retour = QColor(255, 255, 255, 180)
-        return retour        
-
-    def couleurEffective(self):
-        """renvoie la couleur effective de la case (utile quand la texture est une image)"""
-        texture = self.brush()
-        if texture.textureImage().isNull():
-            couleurFond = texture.color()
-        else:
-            couleurFond = self.couleurDominante(texture.textureImage())
-        return couleurFond
-
-    def couleurDominante(self, img):
-        """retourne la couleur dominante d'une QImage"""
-        r = 0
-        v = 0
-        b = 0
-        for i in range(0, img.width()):
-            for j in range(0, img.height()):
-                pixel = img.pixel(i,j)
-                r += qRed(pixel)
-                v += qGreen(pixel)
-                b += qBlue(pixel)
-        nb_pix = img.width() * img.height()   
-        r_moy = int(r / nb_pix)
-        v_moy = int(v / nb_pix)
-        b_moy = int(b / nb_pix)
-        return QColor(r_moy, v_moy, b_moy)
-
-    ######### evenements souris et clavier    #################
-    def mousePressEvent(self, event):
-        """evenement lors du clic souris"""
-        super(Case, self).mousePressEvent(event)
-        if event.button() == 1: #sur clic gauche
-            accepte = self.plateau.caseCliquee(self.x, self.y)  #refPlateau
-            if accepte: event.accept()
-        else:
-            event.ignore()
-
-    def hoverEnterEvent(self, event):
-        """met a jour l'affichage de la case au survol de la souris, si un pion est selectionne"""
-        super(Case, self).hoverEnterEvent(event)
-        if not self.estCachee():
-            self.plateau.caseSurvol(self.x, self.y)
-
-    def hoverLeaveEvent(self, event):
-        """met a jour l'affichage de la case au survol de la souris, si un pion est selectionne"""
-        super(Case, self).hoverLeaveEvent(event)
-    
-    ########################
-
-class LogoDep(QGraphicsEllipseItem):
-    """logo utilise pour afficher le chemin que va suivre le pion lors d'un deplacement"""
-    def __init__(self, parent = None):
-        super(LogoDep, self).__init__()
-        self.parent = parent
-        self.couleur = None
-        self.txt = None
-
-    def creer(self):
-        
-        hC = self.parent.plateau.hCase
-        rect = QRectF()
-        rayon = 0.4*hC
-        rect.setTopLeft(QPointF(self.parent.centreGraphique.x() - rayon, self.parent.centreGraphique.y() - rayon))
-        rect.setBottomRight(QPointF(self.parent.centreGraphique.x() + rayon, self.parent.centreGraphique.y() + rayon))
-
-        self.setRect(rect)
-        
-
-        self.txt = QGraphicsTextItem(self)
-        police = QFont("Georgia", 24)
-        police.setBold(True)
-        self.txt.setFont(police)
-        self.txt.setParentItem(self)
-        self.txt.setPos(QPointF(self.parent.centreGraphique.x() - rayon, self.parent.centreGraphique.y() - 0.6*rayon))
-
-        self.txt.setTextWidth(2*rayon)
-        self.txt.setPlainText(QString.fromUtf8(""))
-        self.centrerTexte()
-
-        self.setVisible(False)
-        self.setAcceptHoverEvents(False)
-        
-        self.setParentItem(self.parent)
-
-
-    def afficher(self, valeur, valide):
-        """lorsque cette case est sur le chemin d'un pion,
-            un disque blanc ou rouge apparait indiquant le
-            mode de deplacement (icone: 'dep_simple', 'nage', 'escalade', 'vol')
-            un cout de 0 fait disparaitre ce symbole"""
-        if valeur > 0:
-            #couleur
-            if valide:
-                couleur = QColor(255, 255, 220, 200)
-            else:
-                couleur = QColor(240, 60, 20, 200)
-
-            self.setBrush(couleur)
-            self.setPen(QPen(couleur))
-
-            #txt
-            self.txt.setPlainText(QString.fromUtf8(str(valeur)))
-            self.centrerTexte()
-
-            self.setVisible(True)
-        else:
-            self.setVisible(False)
-
-    def centrerTexte(self):
-        f = QTextBlockFormat()
-        f.setAlignment(Qt.AlignCenter)
-        cursor = self.txt.textCursor()
-        cursor.select(QTextCursor.Document)
-        cursor.mergeBlockFormat(f)
-        cursor.clearSelection()
-        self.txt.setTextCursor(cursor)
-   
-
-class PolygoneCache(QGraphicsPolygonItem):
-    def __init__(self, case, parent=None):
-        """initialisation de la fenetre"""
-        super(PolygoneCache, self).__init__(parent)
-        self.case = case
-        self.case.plateau.fenetre.connect(self.case.plateau.fenetre.ui.cbt_vue, SIGNAL("zoomChange(int)"), self.zoomChange)
-        
-    def creer(self):
-        polygone = self.case.polygone(self.case.x, self.case.y)
-        self.setPolygon(polygone)
-        self.majTransparence()
-        self.setTransformOriginPoint(self.case.centreGraphique)
-        self.setZValue(100)
-        self.setVisible(False)
-        self.setScale(1.05)
-#         self.setAcceptHoverEvents(True)
-#         self.setAcceptDrops(True)
-        self.case.plateau.addItem(self)
-    
-    def afficher(self, actif = True):
-        self.setVisible(actif)    
-
-    def majTransparence(self):
-        self.setBrush(QColor(0,0,0,self.transparence()))
-        pinceau = QPen()
-        pinceau.setBrush(QColor(0,0,0,self.transparence()))
-        pinceau.setWidth(1)
-        self.setPen(pinceau)        
-
-    def transparence(self):
-        if issubclass(self.case.plateau.modeActif.__class__, Modes.ModeBaseCp):
-            retour = 100
-        else:
-            retour = 255
-        return retour
-
-    def activerSurbrillance(self, actif):
-        if actif:
-            couleur = QColor(150,150,150,100)
-        else:
-            couleur = QColor(0,0,0,100)
-        self.setBrush(couleur)
-        
-    def zoomChange(self, nbZoom):
-        """le zoom sur la dmGraphicsView a change, on met a jour le scale de l'objet,
-           on cherche a eviter un phenomene qui fait que lorsque le zoom est lointain, 
-           on devine les couleurs entre les polygones du cache, le rendant a moitie inutile"""
-        s = (1 + 0.01*(10-nbZoom))
-        self.setScale(s)
-        
-    def sceneEvent(self, event):
-        """filtre les evenements souris et clavier
-            si faux: l'evenement est bloque"""
-        autorise = not self.case.estCachee()
-        if not autorise:
-            event.accept()
-        else:
-            event.ignore()
-        return autorise
-
-
-        
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+from __future__ import division
+
+from PyQt4.QtCore import Qt, SIGNAL, QPointF, QString, QRectF
+from PyQt4.QtGui import QGraphicsPolygonItem, QColor, QGraphicsItem, QPolygonF, \
+    QGraphicsSimpleTextItem, QBrush, QImage, QPen, QRadialGradient, QFont, qRed, \
+    qGreen, qBlue, QGraphicsEllipseItem, QGraphicsTextItem, QTextBlockFormat, \
+    QTextCursor
+
+import Modes
+from Pion import Pion
+from Terrain import Terrain
+
+
+# from Combattant import Combattant
+# from Decor import Decor
+class Case(QGraphicsPolygonItem):
+    """objet graphique representant une case du plateau"""
+    def __init__(self, plateau, parent=None):
+        super(Case, self).__init__(parent)
+        #plateau
+        self.plateau = plateau
+        
+        #attributs
+        self.x = 0
+        self.y = 0        
+        self.altitude = 0                   
+        self.terrain = Terrain()                       #terrain par defaut 
+        self.bordure = QColor(85, 85, 85, 85)          #couleur de la bordure par defaut
+        self.centreGraphique = None
+
+        self.occupation = {}    #z: num pion
+        self.cachesActifs = []       #liste des caches places par le MJ (cache le terrain, les decors, les pions aux joueurs...)
+        self.cachesInactifs = []
+
+        #effet sur la case 
+        self.effetActif = "" 
+
+        #polygones d'affichage
+        self.polygoneEffet = None
+        self.polygoneAffichageSpecial = None
+        self.etiquetteAltitude = None
+        self.polygoneCache = None
+        
+
+    def __getstate__(self):
+        """selectionne les attributs qui seront sauvegardes"""
+        state = {key:value for key, value in self.__dict__.items() if key in ["x", "y", "altitude","terrain","bordure","couleur", \
+                                                                              "ombre", "effetActif", "cachesActifs", "cachesInactifs"]}
+
+        return (state)
+
+    def __setstate__(self, state):
+        """recupere les attributs sauvegardes"""
+        self.__dict__ = state
+        
+    ######## fonctions de base : geometrie, aspect graphique      ######
+    def creer(self, x, y, couleur = QColor(0, 255, 0, 80)):
+        """creation du polygone et enregistrement des donnees geometriques"""
+        self.x = x
+        self.y = y
+        self.terrain.couleur = couleur
+        #creation de l'objet graphique sur le plateau
+        self.creerGraphique()
+        
+    def creerGraphique(self):
+        """cree les objets graphiques representant la case"""
+        #reinitialisation des variables 
+        self.couleurEffet = {"brule":QColor("orange"), "glace":QColor("white"), "poison":QColor("green"), "eau":QColor("blue")}
+        self.imgEffet = {"brule":"effFeu.jpg", "glace":"effGlace.jpg", "poison":"effPoison.png", "eau":"effEau.png"}
+
+        #enregistrement des cases voisines: 
+        self.voisins = self.lstVoisins(self.x, self.y)
+        self.occupation = {}
+   
+        #enregistrement du centre
+        if self.plateau.formeCases == "H":  #refPlateau
+            k = 0
+            if 1 == (self.x % 2): k = 0.5
+            self.centreGraphique = QPointF(((self.x*0.866)+0.5773)*self.plateau.hCase, (self.y+k+0.5)*self.plateau.hCase)
+        else:
+            self.centreGraphique = QPointF((self.x+0.5)*self.plateau.hCase, (self.y+0.5)*self.plateau.hCase)
+        
+        #cree le polygone de la case
+        self.setPolygon(self.polygone(self.x, self.y))
+        self.plateau.addItem(self)  #refPlateau
+        
+        #interactions graphiques:
+        self.setFlag(QGraphicsItem.ItemIsFocusable)
+        self.setAcceptHoverEvents(True)
+        self.setAcceptDrops(True)
+        self.setZValue(0)
+        self.setFiltersChildEvents(True)
+
+#        #pour afficher les coordonnees des cases:  
+        self.etiquette = None
+#         self.afficherEtiquette("{}-{}".format(self.x,self.y))     
+
+        self.logoDep = LogoDep(self)
+        self.logoDep.creer()
+        
+        #apparence initiale de la case
+        self.majTerrain(self.terrain)            
+
+        #polygone utilise pour afficher la cible du curseur
+        self.polygoneCible = QGraphicsPolygonItem(self.polygone(self.x, self.y), parent=self)
+        self.polygoneCible.setVisible(False)
+        self.polygoneCible.setAcceptHoverEvents(False)
+        
+        #cache
+        self.polygoneCache = PolygoneCache(self)
+        self.polygoneCache.creer()
+        self.majCache()
+
+    def recreer(self, plateau):
+##        self.plateau = plateau  #refPlateau
+        self.plateau = plateau
+        super(Case, self).__init__()
+        #polygones d'affichage
+        self.polygoneEffet = None
+        self.polygoneAffichageSpecial = None
+        self.polygoneCache = None
+        self.etiquetteAltitude = None
+        
+        self.creerGraphique()
+        self.majTerrain(self.terrain)   
+        self.majAffichageSpecial("")
+        self.majEffet(self.effetActif)
+
+    def polygone(self, x, y):
+        """renvoie l'objet graphique hexagone de la case"""
+        polygone = QPolygonF()
+        if self.plateau.formeCases == "H":
+            #si x est impair sur un plateau a cases hexagonales, le y est augmente de 0.5
+            if 1 == (x % 2):
+                y += 0.5
+            polygone  << QPointF(((x*0.866)+0.2886)*self.plateau.hCase,  y*self.plateau.hCase) \
+                      << QPointF(((x*0.866)+0.866)*self.plateau.hCase,   y*self.plateau.hCase) \
+                      << QPointF(((x*0.866)+1.1547)*self.plateau.hCase, (y+0.5)*self.plateau.hCase) \
+                      << QPointF(((x*0.866)+0.866)*self.plateau.hCase,  (y+1)*self.plateau.hCase) \
+                      << QPointF(((x*0.866)+0.2886)*self.plateau.hCase, (y+1)*self.plateau.hCase)  \
+                      << QPointF( (x*0.866)*self.plateau.hCase,         (y+0.5)*self.plateau.hCase)
+        else:
+            polygone  << QPointF(x*self.plateau.hCase,      y*self.plateau.hCase) \
+                      << QPointF((x+1)*self.plateau.hCase,  y*self.plateau.hCase) \
+                      << QPointF((x+1)*self.plateau.hCase,  (y+1)*self.plateau.hCase) \
+                      << QPointF(x*self.plateau.hCase,      (y+1)*self.plateau.hCase)          
+        return polygone
+
+    def lstVoisins(self, x, y):
+        """renvoie la liste des cases voisines
+           seulement cases existantes sur le plateau / seulement cases adjacentes (cas des cases carrees)"""
+        voisins = []
+        if self.plateau.formeCases == "H":
+            if 1 == (x % 2):
+                lst = [(x, y-1), (x+1, y), (x+1, y+1), (x,  y+1), (x-1, y+1), (x-1, y)]
+            else:
+                lst = [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
+        else:
+            lst = [(x, y-1), (x+1, y-1), (x+1, y), (x+1, y+1), (x,   y+1), (x-1, y+1), (x-1, y), (x-1, y-1)]
+                  
+        for coord in lst: 
+            if (coord[0] >= 0 and coord[1] >= 0 and coord[0] < self.plateau.nbCasesX and coord[1] < self.plateau.nbCasesY):
+                voisins.append(coord)
+        return voisins                           
+    
+    def afficherEtiquette(self, txt):
+        """affiche l'etiquette avec le texte demande"""
+        if self.etiquette == None:
+            self.etiquette = QGraphicsSimpleTextItem(QString().fromUtf8(str(txt)), parent=self)
+            k = 0
+            if 1 == (self.x % 2): k = 0.5
+            if self.plateau.formeCases == "H":
+                self.etiquette.setPos(QPointF(((self.x*0.866)+0.2886)*self.plateau.hCase,  (self.y+k+0.5)*self.plateau.hCase))
+            else:
+                self.etiquette.setPos(QPointF(self.x*self.plateau.hCase,  self.y*self.plateau.hCase))
+        else:
+            self.etiquette.setText(QString().fromUtf8(str(txt)))
+      
+    
+     
+    ########################
+
+    ### deplacement
+    def coutDep(self):
+        #a implementer, en fonction des
+        #capacites de deplacement du pion actuellement selectionne
+        return 1
+
+    ### occupation
+    def occuper(self, numPion, z = 0):
+        """un pion vient occuper la case a l'altitude z"""
+        self.occupation[z] = numPion
+
+    def liberer(self, z):
+        """aucun pion n'occupe plus la case a l'altitude z"""
+        if z in self.occupation:
+            del self.occupation[z]
+            
+    def estOccupee(self, z=None):
+        """renvoie vrai si la case correspondant a la hauteur z est occupee"""
+        if z:
+            retour = (z in self.occupation) 
+        else:
+            retour = len(self.occupation) > 0
+        return retour       
+
+    def occupant(self, z=None, classe = Pion):
+        """si la case correspondant a la hauteur z est occupee, renvoie l'objet en question
+           sinon renvoie None"""
+        num = None
+        if z:
+            if z in self.occupation:
+                num = self.occupation[z]   
+        else:
+            #si aucune altitude n'est donnee, renvoie le premier occupant
+            for z in self.occupation:
+                num = self.occupation[z]
+                break
+        retour = None
+        if num:
+            if num < 10000:
+                retour = self.plateau.combattants[num]
+            else:
+                retour = self.plateau.decors[num] 
+        if retour:
+            if not isinstance(retour, classe): retour = None        
+        return retour                          
+
+    def estFranchissable(self, zAbs = None):
+        """a l'altitude absolue demandee, 
+        la case est-elle franchissable pour une ligne de mire ou un deplacement"""
+        if not zAbs: zAbs = self.altitude
+        return (not self.estOccupee( (zAbs - self.altitude) ) and (zAbs >= self.altitude))
+
+    ########## fonctions de maj ###########
+    def majTerrain(self, terrain = Terrain()):
+        """met a jour le terrain de la case"""
+        self.terrain = terrain
+        if self.terrain.imgTexture.estValide():
+            self.setBrush(QBrush(QImage(self.terrain.imgTexture.chemin())))
+        else:
+            if self.terrain.couleur.isValid():
+                self.setBrush(QBrush(self.terrain.couleur))
+        pinceau = QPen()
+        pinceau.setColor(self.couleurBordure())
+        pinceau.setWidth(1)
+        self.setPen(pinceau)
+
+    def majAltitude(self, altitude):
+        """met a jour l'altitude de la case"""
+        self.altitude = altitude  
+#         self.afficherEtiquette(altitude)   
+
+    def majAffichageDeplacement(self, cout, valide = True):
+        """lorsque cette case est sur le chemin d'un pion,
+            un disque blanc ou rouge apparait indiquant le
+            cout du deplacement jusqua cette case
+            un cout de 0 fait disparaitre ce symbole"""
+        self.logoDep.afficher(cout, valide)
+
+    def majEstCibleCurseur(self, actif, valide=True):
+        """affiche la case comme etant la cible du curseur (lors d'une creation de pion, d'un deplacement...)"""
+        if actif:
+            pinceau = QPen()
+            pinceau.setWidth(5)
+            brush = QBrush()
+            brush.setStyle(13)
+            pinceau.setColor(self.couleurProj(valide))
+            brush.setColor(self.couleurProj(valide))
+            self.polygoneCible.setPen(pinceau)
+            self.polygoneCible.setBrush(brush)
+            self.setZValue(99)
+        else:
+            self.setZValue(0)
+        self.polygoneCible.setVisible(actif)    
+            
+    def majEffet(self, effet):
+        """met a jour l'effet actif sur la case"""       
+        if self.polygoneEffet == None:
+            #on cree le polygone utilise pour afficher les effets
+            self.polygoneEffet = QGraphicsPolygonItem(self.polygone(self.x, self.y), parent=self)
+            pinceau = QPen()
+            pinceau.setColor(self.bordure)
+            pinceau.setWidth(1)
+            self.polygoneEffet.setPen(pinceau)
+            self.polygoneEffet.setVisible(False)
+
+        if len(effet) > 0 and effet != "aucun":
+            #gradient de couleur
+            gradient = QRadialGradient(self.centreGraphique, 0.5*self.plateau.hCase)
+            couleur0 = QColor(0,0,0,0)
+            couleur20 = self.couleurEffet[effet]
+            couleur20.setAlpha(70)
+            couleur10 = self.couleurEffet[effet]
+            couleur10.setAlpha(255)
+
+            gradient.setColorAt(0, couleur0)
+            gradient.setColorAt(0.8, couleur0)
+            gradient.setColorAt(0.95, couleur10)
+            gradient.setColorAt(0.98, couleur20)
+            gradient.setColorAt(1, couleur10)
+            self.polygoneEffet.setBrush(gradient)
+   
+            self.polygoneEffet.setVisible(True)
+
+            self.effetActif = effet
+        else:
+            self.polygoneEffet.setVisible(False)              
+
+    def majAffichageSpecial(self, affichage=""):
+        """donne a la case l'aspect demande en rendant visible/invisible le polygone d'affichage special"""
+        #polygone d'affichage special (altitude, tactique...)
+        if self.polygoneAffichageSpecial == None:
+            self.polygoneAffichageSpecial = QGraphicsPolygonItem(self.polygone(self.x, self.y), parent=self)
+            pinceau = QPen()
+            pinceau.setColor(self.bordure)
+            pinceau.setWidth(1)
+            self.polygoneAffichageSpecial.setPen(pinceau)
+
+        if affichage != "altitude" and self.etiquetteAltitude:
+            self.etiquetteAltitude.setVisible(False)
+            
+        if affichage == "tactique":
+            if self.terrain.franchissable:
+                self.polygoneAffichageSpecial.setBrush(QColor(255,255,255))
+            else:
+                self.polygoneAffichageSpecial.setBrush(QColor(50,50,50))
+            self.polygoneAffichageSpecial.setVisible(True)
+            
+        elif affichage == "altitude":
+            if self.etiquetteAltitude == None:
+                self.etiquetteAltitude = QGraphicsSimpleTextItem("{}".format(self.altitude), parent=self)
+                police = QFont("Georgia", 18)
+                police.setItalic(True)
+                self.etiquetteAltitude.setFont(police)
+                self.etiquetteAltitude.setPos(QPointF(((self.x*0.866)+0.65)*self.plateau.hCase,  (self.y+0.7)*self.plateau.hCase))
+            if self.altitude >= 0:
+                couleur = QColor("red").lighter(200-(5*self.altitude))
+            else:
+                couleur = QColor("purple").lighter(200+(5*self.altitude))
+            self.polygoneAffichageSpecial.setBrush(couleur)
+            self.polygoneAffichageSpecial.setZValue(5)
+            self.polygoneAffichageSpecial.setVisible(True)
+            self.etiquetteAltitude.setText(QString.fromUtf8("{}".format(self.altitude)))
+            self.etiquetteAltitude.setVisible(True)
+            self.etiquetteAltitude.setZValue(6)
+        else:
+            self.polygoneAffichageSpecial.setVisible(False)
+
+
+    #caches
+    def ajouterCache(self, idCache, actif = True):
+        if actif:
+            if not idCache in self.cachesActifs:
+                self.cachesActifs.append(idCache)
+                self.majCache() 
+        else:
+            if not idCache in self.cachesInactifs:
+                self.cachesInactifs.append(idCache)
+        
+    def supprimerCache(self, idCache):
+        if idCache in self.cachesActifs:
+            self.cachesActifs.remove(idCache) 
+            self.majCache() 
+        elif idCache in self.cachesInactifs:
+            self.cachesInactifs.remove(idCache)     
+
+    def activerCache(self, idCache, actif = True):
+        if actif:
+            if idCache in self.cachesInactifs:
+                self.cachesInactifs.remove(idCache)
+                self.cachesActifs.append(idCache)
+                self.majCache()
+        else:
+            if idCache in self.cachesActifs:
+                self.cachesActifs.remove(idCache)
+                self.cachesInactifs.append(idCache)
+                self.majCache()
+                                    
+    def majCache(self):
+        self.polygoneCache.setVisible((len(self.cachesActifs) > 0))
+        if len(self.cachesActifs) > 0:
+            self.polygoneCache.majTransparence() 
+
+    def estCachee(self):
+        """une case cachee ne recoit plus aucun evenement souris ou clavier"""
+        retour = (len(self.cachesActifs) > 0 and \
+                not issubclass(self.plateau.modeActif.__class__, Modes.ModeBaseCp))
+        return retour
+
+    #fonctions secondaires
+    def couleurDep(self):
+        """renvoie une couleur secondaire utilisee pour les champs de deplacements"""
+        luminositeActuelle = self.couleurEffective().lightness()
+        if luminositeActuelle < 150:
+            retour = QColor(210,255,255,100)
+        else:
+            retour = QColor(210,255,255,100)
+        return retour
+
+    def couleurProj(self, valide):
+        """renvoie une couleur secondaire utilisee pour les projections de deplacement"""
+        luminositeActuelle = self.couleurEffective().lightness()
+        if valide:
+            retour = QColor("white")
+        else:
+            retour = QColor("red")
+        if luminositeActuelle > 220:
+            retour = retour.darker(120)
+            
+        return retour
+
+    def couleurBordure(self):
+        """renvoie la couleur utilisee pour les bordures de la case"""
+        luminositeActuelle = self.couleurEffective().lightness()
+        if luminositeActuelle > 150:
+            retour = QColor(85, 85, 85, 130)
+        elif luminositeActuelle > 100 and luminositeActuelle <= 150:
+            retour = QColor(10, 10, 10, 130)
+        else:
+            retour = QColor(255, 255, 255, 180)
+        return retour        
+
+    def couleurEffective(self):
+        """renvoie la couleur effective de la case (utile quand la texture est une image)"""
+        texture = self.brush()
+        if texture.textureImage().isNull():
+            couleurFond = texture.color()
+        else:
+            couleurFond = self.couleurDominante(texture.textureImage())
+        return couleurFond
+
+    def couleurDominante(self, img):
+        """retourne la couleur dominante d'une QImage"""
+        r = 0
+        v = 0
+        b = 0
+        for i in range(0, img.width()):
+            for j in range(0, img.height()):
+                pixel = img.pixel(i,j)
+                r += qRed(pixel)
+                v += qGreen(pixel)
+                b += qBlue(pixel)
+        nb_pix = img.width() * img.height()   
+        r_moy = int(r / nb_pix)
+        v_moy = int(v / nb_pix)
+        b_moy = int(b / nb_pix)
+        return QColor(r_moy, v_moy, b_moy)
+
+    ######### evenements souris et clavier    #################
+    def mousePressEvent(self, event):
+        """evenement lors du clic souris"""
+        super(Case, self).mousePressEvent(event)
+        if event.button() == 1: #sur clic gauche
+            accepte = self.plateau.caseCliquee(self.x, self.y)  #refPlateau
+            if accepte: event.accept()
+        else:
+            event.ignore()
+
+    def hoverEnterEvent(self, event):
+        """met a jour l'affichage de la case au survol de la souris, si un pion est selectionne"""
+        super(Case, self).hoverEnterEvent(event)
+        if not self.estCachee():
+            self.plateau.caseSurvol(self.x, self.y)
+
+    def hoverLeaveEvent(self, event):
+        """met a jour l'affichage de la case au survol de la souris, si un pion est selectionne"""
+        super(Case, self).hoverLeaveEvent(event)
+    
+    ########################
+
+class LogoDep(QGraphicsEllipseItem):
+    """logo utilise pour afficher le chemin que va suivre le pion lors d'un deplacement"""
+    def __init__(self, parent = None):
+        super(LogoDep, self).__init__()
+        self.parent = parent
+        self.couleur = None
+        self.txt = None
+
+    def creer(self):
+        
+        hC = self.parent.plateau.hCase
+        rect = QRectF()
+        rayon = 0.4*hC
+        rect.setTopLeft(QPointF(self.parent.centreGraphique.x() - rayon, self.parent.centreGraphique.y() - rayon))
+        rect.setBottomRight(QPointF(self.parent.centreGraphique.x() + rayon, self.parent.centreGraphique.y() + rayon))
+
+        self.setRect(rect)
+        
+
+        self.txt = QGraphicsTextItem(self)
+        police = QFont("Georgia", 24)
+        police.setBold(True)
+        self.txt.setFont(police)
+        self.txt.setParentItem(self)
+        self.txt.setPos(QPointF(self.parent.centreGraphique.x() - rayon, self.parent.centreGraphique.y() - 0.6*rayon))
+
+        self.txt.setTextWidth(2*rayon)
+        self.txt.setPlainText(QString.fromUtf8(""))
+        self.centrerTexte()
+
+        self.setVisible(False)
+        self.setAcceptHoverEvents(False)
+        
+        self.setParentItem(self.parent)
+
+
+    def afficher(self, valeur, valide):
+        """lorsque cette case est sur le chemin d'un pion,
+            un disque blanc ou rouge apparait indiquant le
+            mode de deplacement (icone: 'dep_simple', 'nage', 'escalade', 'vol')
+            un cout de 0 fait disparaitre ce symbole"""
+        if valeur > 0:
+            #couleur
+            if valide:
+                couleur = QColor(255, 255, 220, 200)
+            else:
+                couleur = QColor(240, 60, 20, 200)
+
+            self.setBrush(couleur)
+            self.setPen(QPen(couleur))
+
+            #txt
+            self.txt.setPlainText(QString.fromUtf8(str(valeur)))
+            self.centrerTexte()
+
+            self.setVisible(True)
+        else:
+            self.setVisible(False)
+
+    def centrerTexte(self):
+        f = QTextBlockFormat()
+        f.setAlignment(Qt.AlignCenter)
+        cursor = self.txt.textCursor()
+        cursor.select(QTextCursor.Document)
+        cursor.mergeBlockFormat(f)
+        cursor.clearSelection()
+        self.txt.setTextCursor(cursor)
+   
+
+class PolygoneCache(QGraphicsPolygonItem):
+    def __init__(self, case, parent=None):
+        """initialisation de la fenetre"""
+        super(PolygoneCache, self).__init__(parent)
+        self.case = case
+        self.case.plateau.fenetre.connect(self.case.plateau.fenetre.ui.cbt_vue, SIGNAL("zoomChange(int)"), self.zoomChange)
+        
+    def creer(self):
+        polygone = self.case.polygone(self.case.x, self.case.y)
+        self.setPolygon(polygone)
+        self.majTransparence()
+        self.setTransformOriginPoint(self.case.centreGraphique)
+        self.setZValue(100)
+        self.setVisible(False)
+        self.setScale(1.05)
+#         self.setAcceptHoverEvents(True)
+#         self.setAcceptDrops(True)
+        self.case.plateau.addItem(self)
+    
+    def afficher(self, actif = True):
+        self.setVisible(actif)    
+
+    def majTransparence(self):
+        self.setBrush(QColor(0,0,0,self.transparence()))
+        pinceau = QPen()
+        pinceau.setBrush(QColor(0,0,0,self.transparence()))
+        pinceau.setWidth(1)
+        self.setPen(pinceau)        
+
+    def transparence(self):
+        if issubclass(self.case.plateau.modeActif.__class__, Modes.ModeBaseCp):
+            retour = 100
+        else:
+            retour = 255
+        return retour
+
+    def activerSurbrillance(self, actif):
+        if actif:
+            couleur = QColor(150,150,150,100)
+        else:
+            couleur = QColor(0,0,0,100)
+        self.setBrush(couleur)
+        
+    def zoomChange(self, nbZoom):
+        """le zoom sur la dmGraphicsView a change, on met a jour le scale de l'objet,
+           on cherche a eviter un phenomene qui fait que lorsque le zoom est lointain, 
+           on devine les couleurs entre les polygones du cache, le rendant a moitie inutile"""
+        s = (1 + 0.01*(10-nbZoom))
+        self.setScale(s)
+        
+    def sceneEvent(self, event):
+        """filtre les evenements souris et clavier
+            si faux: l'evenement est bloque"""
+        autorise = not self.case.estCachee()
+        if not autorise:
+            event.accept()
+        else:
+            event.ignore()
+        return autorise
+
+
+        

+ 76 - 86
lib/Combattant.py

@@ -1,86 +1,76 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-from __future__ import division
-import os
-
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-
-from Pion import Pion
-from Forme import Forme
-from outilsSvg import *
-import regles
-
-class Combattant(Pion):
-    """combattant sur un plateau de combat"""
-    def __init__(self, parent=None):
-        super(Combattant, self).__init__()
-        #caracs
-        self.id = None
-
-        self.taille = 2
-        self.depMarche = regles.valeurDefaut("depMarche")
-        self.depNage = regles.valeurDefaut("depNage")
-        self.depEscalade = regles.valeurDefaut("depEscalade")
-        self.depVol = regles.valeurDefaut("depVol")
-        self.saut = regles.valeurDefaut("saut")
-        
-        self.attaques = []   #liste des attaques pre-parametrees du pion
-        self.listeAttributs = regles.listeAttributs()
-        self.inventaire = []
-        self.details = {}
-        self.notes = ""        
-
-        #caracs liees au combat:
-        self.etat = ""
-        self.deplacementRestant = 0        
-
-##    def listeAttributs(self):
-##        return self.listeAttributs
-
-    def listeAttaques(self):
-        return self.attaques
-    
-    def ajouterAuPlateau(self, plateau):
-        self.plateau = plateau
-        super(Combattant, self).ajouterAuPlateau(self.plateau)
-        self.majEtiquette()
-        
-    def hoverEnterEvent(self, event):
-        """evenement lors du survol de la souris (en entree)"""
-        self.plateau.combattantSurvol(self.numero)
-        event.ignore()
-
-    def hoverLeaveEvent(self, event):
-        """evenement lors du survol de la souris (en entree)"""
-        self.plateau.combattantFinSurvol(self.numero)
-
-    def mousePressEvent(self, event):
-        """evenement lors du clic souris"""
-        super(Pion, self).mousePressEvent(event)
-        if event.button() == 1: #sur clic gauche
-           accepte = self.plateau.pionClique(self.numero)
-           if accepte: event.accept()
-        else:
-           event.ignore()
-
-    def mouseDoubleClickEvent(self, event):
-        """evenement lors du clic souris"""
-        super(Pion, self).mouseDoubleClickEvent(event)
-        if event.button() == 1: #sur clic gauche
-           accepte = self.plateau.pionDoubleClic(self.numero)
-           if accepte: event.accept()
-        else:
-           event.ignore()
-
-
-
-
-
-
-
-
-
-
-
-           
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+from Pion import Pion
+import regles
+
+
+class Combattant(Pion):
+    """combattant sur un plateau de combat"""
+    def __init__(self, parent=None):
+        super(Combattant, self).__init__()
+        #caracs
+        self.id = None
+
+        self.taille = 2
+        self.depMarche = regles.valeurDefaut("depMarche")
+        self.depNage = regles.valeurDefaut("depNage")
+        self.depEscalade = regles.valeurDefaut("depEscalade")
+        self.depVol = regles.valeurDefaut("depVol")
+        self.saut = regles.valeurDefaut("saut")
+        
+        self.attaques = []   #liste des attaques pre-parametrees du pion
+        self.listeAttributs = regles.listeAttributs()
+        self.inventaire = []
+        self.details = {}
+        self.notes = ""        
+
+        #caracs liees au combat:
+        self.etat = ""
+        self.deplacementRestant = 0        
+
+    def listeAttaques(self):
+        return self.attaques
+    
+    def ajouterAuPlateau(self, plateau):
+        self.plateau = plateau
+        super(Combattant, self).ajouterAuPlateau(self.plateau)
+        self.majEtiquette()
+        
+    def hoverEnterEvent(self, event):
+        """evenement lors du survol de la souris (en entree)"""
+        self.plateau.combattantSurvol(self.numero)
+        event.ignore()
+
+    def hoverLeaveEvent(self, event):
+        """evenement lors du survol de la souris (en entree)"""
+        self.plateau.combattantFinSurvol(self.numero)
+
+    def mousePressEvent(self, event):
+        """evenement lors du clic souris"""
+        super(Pion, self).mousePressEvent(event)
+        if event.button() == 1: #sur clic gauche
+            accepte = self.plateau.pionClique(self.numero)
+            if accepte: event.accept()
+        else:
+            event.ignore()
+
+    def mouseDoubleClickEvent(self, event):
+        """evenement lors du clic souris"""
+        super(Pion, self).mouseDoubleClickEvent(event)
+        if event.button() == 1: #sur clic gauche
+            accepte = self.plateau.pionDoubleClic(self.numero)
+            if accepte: event.accept()
+        else:
+            event.ignore()
+
+
+
+
+
+
+
+
+
+
+
+           

+ 103 - 103
lib/EcranChargerPlateau.py

@@ -1,103 +1,103 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-from __future__ import division
-from time import time, sleep, strftime, localtime
-
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-
-from ui.ecran_chargerPlateau import Ui_chp_fenetre
-
-from outilsSvg import *
-
-class EcranChargerPlateau(QDialog):
-    """interface de creation/chargement de plateau"""
-    def __init__(self, fenetrePrincipale, terrain=None, parent=None):
-        """initialisation de la fenetre"""
-        super (EcranChargerPlateau, self).__init__()
-        self.fenetre = fenetrePrincipale
-        self.createWidgets()
-        self.majAffichage()
-        
-    def createWidgets(self):
-        """construction de l'interface"""
-        #construction de l'interface
-        self.ui = Ui_chp_fenetre()
-        self.ui.setupUi(self)
-        self.majListeChargement()
-        self.connect(self.ui.chp_supprimer, SIGNAL("clicked()"), self.supprimerPlateau)
-        self.connect(self.ui.chp_ok, SIGNAL("clicked()"), self.charger)
-        self.connect(self.ui.chp_chapitre, SIGNAL("valueChanged(int)"), self.majListeChargement)
-        self.connect(self.ui.chp_toutAfficher, SIGNAL("stateChanged(int)"), self.majListeChargement)
-        
-        self.connect(self.ui.chp_liste, SIGNAL("cellClicked(int,int)"), self.focusBoutonCharger)
-        self.connect(self.ui.chp_liste, SIGNAL("cellClicked(int,int)"), self.majAffichage)
-        self.connect(self.ui.chp_liste, SIGNAL("cellDoubleClicked(int,int)"), self.charger)
-
-    def charger(self):
-        """charge le plateau selectionne"""
-        index = self.ui.chp_liste.texte(self.ui.chp_liste.currentRow(), 0)
-        self.fenetre.chargerPlateau(index)
-        self.done(1)
-            
-    def supprimerPlateau(self):
-        """supprime le plateau selectionne"""
-        reponse = QMessageBox.question(self, 'Avertissement',
-                                           QString().fromUtf8("Etes-vous sûr de vouloir supprimer ce plateau?"), QMessageBox.Yes | 
-                                           QMessageBox.No, QMessageBox.No)
-        if reponse == QMessageBox.Yes:       
-            index = self.ui.chp_liste.texte(self.ui.chp_liste.currentRow(), 0)
-            os.remove("parties\\{}\\svg\\{}.p".format(self.fenetre.partie, index))
-            supprSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.fenetre.partie), index)
-            self.majListeChargement()
-
-    def majAffichage(self):
-        self.ui.chp_ok.setEnabled(self.ui.chp_liste.currentRow()>=0)
-        self.ui.chp_supprimer.setEnabled(self.ui.chp_liste.currentRow()>=0)
-
-    def focusBoutonCharger(self):
-        self.ui.chp_ok.setFocus()
-
-    def majListeChargement(self):
-        """remplit ou maj la liste des plateaux sauvegardes"""
-        #on met a jour la largeur des colonnes
-        largeurs = [0, 30, 30, 310, 100, 0]
-        for col in self.ui.chp_liste.colonnes():
-            self.ui.chp_liste.setColumnWidth(col, largeurs[col]);
-
-        self.ui.chp_liste.setSortingEnabled(False)
-
-        self.ui.chp_liste.vider()
-        
-        infosSvg = afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.fenetre.partie))
-        
-        for id_svg in infosSvg:
-            if infosSvg[id_svg]["chapitre"] == str(self.ui.chp_chapitre.value()) or bool(self.ui.chp_toutAfficher.checkState()) == True:
-                ligne = self.ui.chp_liste.nouvelleLigneFin()
-                self.ui.chp_liste.majTexte(ligne, 0, str(id_svg))
-                if infosSvg[id_svg]["public"] == True:
-                    icone = QIcon(":/interface/32/ressource/oeil_32.png")
-                else:
-                    icone = QIcon(":/interface/32/ressource/oeilBarre2_32.png")
-                item = QTableWidgetItem(icone, QString(""))
-                
-                self.ui.chp_liste.setItem(ligne, 1, item)
-                self.ui.chp_liste.majTexte(ligne, 2, (str(infosSvg[id_svg]["chapitre"])))
-                self.ui.chp_liste.majTexte(ligne, 3, infosSvg[id_svg]["nom"])
-                self.ui.chp_liste.majTexte(ligne, 4, strftime('%d/%m/%y %H:%M',localtime(infosSvg[id_svg]["dateSvg"])))
-                self.ui.chp_liste.majData(ligne, 5, infosSvg[id_svg]["dateSvg"])
-                
-        for col in self.ui.chp_liste.colonnes():
-            self.ui.chp_liste.sizeHintForColumn(col)
-            
-        #on trie par date
-        self.ui.chp_liste.setSortingEnabled(True)
-        self.ui.chp_liste.sortItems(5, 1)
-        self.majAffichage()
-        
-
-
-
-
-
-        
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+from __future__ import division
+from time import strftime, localtime
+import os
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from ui.ecran_chargerPlateau import Ui_chp_fenetre
+
+from outilsSvg import *
+
+class EcranChargerPlateau(QDialog):
+    """interface de creation/chargement de plateau"""
+    def __init__(self, fenetrePrincipale, terrain=None, parent=None):
+        """initialisation de la fenetre"""
+        super (EcranChargerPlateau, self).__init__()
+        self.fenetre = fenetrePrincipale
+        self.createWidgets()
+        self.majAffichage()
+        
+    def createWidgets(self):
+        """construction de l'interface"""
+        #construction de l'interface
+        self.ui = Ui_chp_fenetre()
+        self.ui.setupUi(self)
+        self.majListeChargement()
+        self.connect(self.ui.chp_supprimer, SIGNAL("clicked()"), self.supprimerPlateau)
+        self.connect(self.ui.chp_ok, SIGNAL("clicked()"), self.charger)
+        self.connect(self.ui.chp_chapitre, SIGNAL("valueChanged(int)"), self.majListeChargement)
+        self.connect(self.ui.chp_toutAfficher, SIGNAL("stateChanged(int)"), self.majListeChargement)
+        
+        self.connect(self.ui.chp_liste, SIGNAL("cellClicked(int,int)"), self.focusBoutonCharger)
+        self.connect(self.ui.chp_liste, SIGNAL("cellClicked(int,int)"), self.majAffichage)
+        self.connect(self.ui.chp_liste, SIGNAL("cellDoubleClicked(int,int)"), self.charger)
+
+    def charger(self):
+        """charge le plateau selectionne"""
+        index = self.ui.chp_liste.texte(self.ui.chp_liste.currentRow(), 0)
+        self.fenetre.chargerPlateau(index)
+        self.done(1)
+            
+    def supprimerPlateau(self):
+        """supprime le plateau selectionne"""
+        reponse = QMessageBox.question(self, 'Avertissement',
+                                           QString().fromUtf8("Etes-vous sûr de vouloir supprimer ce plateau?"), QMessageBox.Yes | 
+                                           QMessageBox.No, QMessageBox.No)
+        if reponse == QMessageBox.Yes:       
+            index = self.ui.chp_liste.texte(self.ui.chp_liste.currentRow(), 0)
+            os.remove("parties\\{}\\svg\\{}.p".format(self.fenetre.partie, index))
+            supprSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.fenetre.partie), index)
+            self.majListeChargement()
+
+    def majAffichage(self):
+        self.ui.chp_ok.setEnabled(self.ui.chp_liste.currentRow()>=0)
+        self.ui.chp_supprimer.setEnabled(self.ui.chp_liste.currentRow()>=0)
+
+    def focusBoutonCharger(self):
+        self.ui.chp_ok.setFocus()
+
+    def majListeChargement(self):
+        """remplit ou maj la liste des plateaux sauvegardes"""
+        #on met a jour la largeur des colonnes
+        largeurs = [0, 30, 30, 310, 100, 0]
+        for col in self.ui.chp_liste.colonnes():
+            self.ui.chp_liste.setColumnWidth(col, largeurs[col]);
+
+        self.ui.chp_liste.setSortingEnabled(False)
+
+        self.ui.chp_liste.vider()
+        
+        infosSvg = afficheSvg("parties\\{}\\svg\\infos_sauvegarde".format(self.fenetre.partie))
+        
+        for id_svg in infosSvg:
+            if infosSvg[id_svg]["chapitre"] == str(self.ui.chp_chapitre.value()) or bool(self.ui.chp_toutAfficher.checkState()) == True:
+                ligne = self.ui.chp_liste.nouvelleLigneFin()
+                self.ui.chp_liste.majTexte(ligne, 0, str(id_svg))
+                if infosSvg[id_svg]["public"] == True:
+                    icone = QIcon(":/interface/32/ressource/oeil_32.png")
+                else:
+                    icone = QIcon(":/interface/32/ressource/oeilBarre2_32.png")
+                item = QTableWidgetItem(icone, QString(""))
+                
+                self.ui.chp_liste.setItem(ligne, 1, item)
+                self.ui.chp_liste.majTexte(ligne, 2, (str(infosSvg[id_svg]["chapitre"])))
+                self.ui.chp_liste.majTexte(ligne, 3, infosSvg[id_svg]["nom"])
+                self.ui.chp_liste.majTexte(ligne, 4, strftime('%d/%m/%y %H:%M',localtime(infosSvg[id_svg]["dateSvg"])))
+                self.ui.chp_liste.majData(ligne, 5, infosSvg[id_svg]["dateSvg"])
+                
+        for col in self.ui.chp_liste.colonnes():
+            self.ui.chp_liste.sizeHintForColumn(col)
+            
+        #on trie par date
+        self.ui.chp_liste.setSortingEnabled(True)
+        self.ui.chp_liste.sortItems(5, 1)
+        self.majAffichage()
+        
+
+
+
+
+
+        

+ 720 - 632
lib/Modes.py

@@ -1,632 +1,720 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-"""les modes d'interaction permettent l'interaction
-entre l'interface (l'utilisateur) et le plateau de combat.
-Un seul mode ne peut etre actif a la fois
-Cette classe doit permettre de recevoir les commandes de l'utilisateur
-de maniere a produire un resultat unique (cases peintes, pion deplace...)"""
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from EntreeSortie import EntreeSortie
-import Actions
-import regles
-from Pion import Pion
-from Combattant import Combattant
-from Decor import Decor
-import dmK
-
-class ModeBase(object):
-    """mode de base: tous les modes heritent de cette classe"""
-    def __init__(self, plateau):
-        self.plateau = plateau
-        #le mode est il active
-        self._actif = False
-        #le dragmode est il active sur la QGraphicsView
-        self._activerDragMode = 0
-        #curseur de la QGraphicsView
-        self._sourceCurseur = ""
-        #met le focus sur la QGraphicsView a l'activation
-        self._focus = False 
-
-    def nom(self):
-        return self.__class__.__name__
-
-    def activer(self, param = None):
-        """active le mode"""
-        self.activerCurseur()
-        if self._focus:
-            self.plateau.fenetre.ui.cbt_vue.setFocus()
-        self._actif = True    
-
-    def desactiver(self):
-        """desactive le mode"""
-        self.desactiverCurseur()
-        self.plateau.fenetre.ui.cbt_vue.setDragMode(1)
-        self._actif = False
-
-    def reinit(self):
-        """remet les variables a 0 et reactive le mode"""
-        pass
-
-    def activerCurseur(self):
-        self.plateau.fenetre.ui.cbt_vue.setDragMode(self._activerDragMode)
-        curseurPix = QPixmap(self._sourceCurseur)
-        if not curseurPix.isNull():
-            curseur = QCursor(curseurPix, 0, curseurPix.height())
-            self.plateau.fenetre.ui.cbt_vue.setCursor(curseur)   
-
-    def desactiverCurseur(self):
-        self.plateau.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
-
-    ### gestion des evenements souris
-    # clic gauche
-    def clic_combattant(self, num):
-        pass
-
-    def clic_decor(self, num):
-        pass
-
-    def clic_case(self, coord):
-        pass
-
-    def clic_es(self, es):
-        #clic sur une entree/sortie
-        pass
-        
-    #double clic gauche
-    def doubleClic_combattant(self, num):
-        pass
-
-    def doubleClic_decor(self, num):
-        pass
-
-    def doubleClic_case(self, coord):
-        pass
-
-    #survol de la souris (entree)   
-    def survol_combattant(self, num):
-        pass
-
-    def survol_decor(self, num):
-        pass
-
-    def survol_case(self, coord):
-        pass
-
-    #survol de la souris (sortie)  
-    def finSurvol_combattant(self, num):
-        pass
-
-    def finSurvol_decor(self, num):
-        pass
-
-    def finSurvol_case(self, coord):
-        pass
-
-    #survol de la souris avec clic gauche enfonce (entree)   
-    def survolClic_combattant(self, event):
-        pass
-
-    def survolClic_decor(self, event):
-        pass
-
-    def survolClic_case(self, coord):
-        pass
-
-    #autre
-    def clicGauche(self, event):
-        pass
-
-    def finClicGauche(self, event):
-        pass
-    
-    def mouvementSouris(self, event):
-        pass
-    
-    def toucheClavier(self, event):
-        pass
-
-    def clicDroit(self, event):
-        pass
-
-
-class ModeBaseCp(ModeBase):
-    """mode servant de base a tous les modes lies a la creation de plateau"""
-    def __init__(self, plateau):
-        super(ModeBaseCp, self).__init__(plateau)
-        self.type = "cp"
-
-    def activer(self, param = None):
-        self.plateau.fenetre.ui.cbt_modeCreation.setChecked(True)
-        super(ModeBaseCp, self).activer(param)
-        
-    def desactiver(self):
-        self.plateau.fenetre.ui.cbt_modeCreation.setChecked(False)
-        super(ModeBaseCp, self).desactiver()
-        
-    def clicDroit(self, event):
-        self.plateau.activerMode(StandardCp)
-
-class ModeBasePi(ModeBase):
-    """mode servant de base a tous les modes lies aux actions des combattants"""
-    def __init__(self, plateau):
-        super(ModeBasePi, self).__init__(plateau)
-        self.type = "pi"
-
-    def activer(self, param = None):
-        self.plateau.fenetre.ui.cbt_modeCombat.setChecked(True)
-        super(ModeBasePi, self).activer(param)
-        
-    def desactiver(self):
-        self.plateau.fenetre.ui.cbt_modeCombat.setChecked(False)
-        super(ModeBasePi, self).desactiver()
-
-    def clicDroit(self, event):
-        self.plateau.activerMode(StandardPi)
-
-### --------------------------------------- ####
-
-
-class StandardCp(ModeBaseCp):
-    """mode standard en creation de plateau"""
-    def __init__(self, plateau):
-        super(StandardCp, self).__init__(plateau)
-        self._sourceCurseur = ""
-        self._focus = False
-        self._activerDragMode = True
-
-    def activer(self, param):
-        """active le mode"""
-        self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(1)
-        if len(self.plateau.caches) > 0:
-            for coord in self.plateau.cases:
-                self.plateau.cases[coord].majCache()
-        super(StandardCp, self).activer()
-
-    def clic_combattant(self, num):
-        self.plateau.activerMode(DeplacementPion, num)
-        
-    def clic_decor(self, num):
-        self.plateau.activerMode(DeplacementPion, num)
-
-    def clic_es(self, es):
-        self.plateau.activerMode(EditionEntreeSortie, es)
- 
-class MajCases(ModeBaseCp):
-    """mode de mise a jour des cases (terrain, couleur, effet special)"""
-    def __init__(self, plateau):
-        super(MajCases, self).__init__(plateau)
-        self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
-        self._focus = True
-        self._param = None   #parametre avec lequel on mettra a jour la case
-        self._caseSurvolee = None
-
-    def activer(self, param):
-        """active le mode"""
-        self.majParam(param)
-        super(MajCases, self).activer()
-
-    def desactiver(self):
-        """desactive le mode"""
-        self.plateau.pinceau.reinit()
-        super(MajCases, self).desactiver()
-
-    def majParam(self, param):
-        self._param = param
-        
-    def param(self):
-        return self._param
-
-    def clic_case(self, coord):
-        #demarre une operation de peinture des cases
-        self.plateau.pinceau.demarrer(coord)
-
-    def survolClic_case(self, coord):
-        if coord != self._caseSurvolee:
-            self.plateau.pinceau.maj(coord)
-
-    def finClicGauche(self, event):
-        if self.plateau.pinceau.estActif():
-            for coord in self.plateau.pinceau.selection():
-                self.plateau.cases[coord].majTerrain(self._param)
-                self.plateau.cases[coord].majAltitude(self.plateau.fenetre.ui.cp_valeurAltitude.value())
-                self.plateau.pinceau.reinit()
-            self.reinit()
-
-    def toucheClavier(self, event):
-        if event.key() == Qt.Key_Up:
-            self.plateau.fenetre.ui.epaisseurPinceau.setValue(self.plateau.fenetre.ui.epaisseurPinceau.value()+1)
-        elif event.key() == Qt.Key_Down:
-            self.plateau.fenetre.ui.epaisseurPinceau.setValue(self.plateau.fenetre.ui.epaisseurPinceau.value()-1)
-
-class MajCasesEffet(MajCases):
-    """mode de mise a jour des cases (effets speciaux)"""
-    def __init__(self, plateau):
-        super(MajCasesEffet, self).__init__(plateau)
-        self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
-
-    def finClicGauche(self, event):
-        if self.plateau.pinceau.estActif():
-            for coord in self.plateau.pinceau.selection():
-                self.plateau.cases[coord].majEffet(self._param)
-                self.plateau.pinceau.reinit()
-            self.reinit()
-
-class Pipette(ModeBaseCp):
-    """mode pipette: on preleve la couleur ou le terrain d'une case"""
-    def __init__(self, plateau):
-        super(Pipette, self).__init__(plateau)
-        self._sourceCurseur = ":/interface/16/ressource/seringue_16.png"
-
-    def activerCurseur(self):
-        super(Pipette, self).activerCurseur()
-        
-    def clic_case(self, coord):
-        self.plateau.activerMode(MajCases, self.plateau.cases[coord].terrain)
-
-class ZonePlacement(ModeBaseCp):
-    """mode de definition de la/les zones de placement des joueurs"""
-    def __init__(self, plateau):
-        super(ZonePlacement, self).__init__(plateau)
-        self._sourceCurseur = ":/interface/16/ressource/pinceau.png"
-        self._focus = True
-
-    def activerCurseur(self):
-        super(ZonePlacement, self).activerCurseur()
-
-    def activer(self, param = None):
-        self.plateau.pinceau.majForme("rectP")
-        self.plateau.pinceau.verrouillerForme(True)
-        super(ZonePlacement, self).activer()
-
-    def desactiver(self):
-        self.plateau.pinceau.reinit()
-        super(ZonePlacement, self).desactiver()
-
-    def clic_case(self, coord):
-        #demarre une operation de peinture des cases
-        self.plateau.pinceau.demarrer(coord)
-        
-    def survolClic_case(self, coord):
-        self.plateau.pinceau.maj(coord)
-    
-    def finClicGauche(self, coord):
-        if self.plateau.pinceau.estActif():
-            if len(self.plateau.pinceau.selection()) > 0:
-                self.plateau.majZonePlacement(self.plateau.pinceau.selection())
-
-class EditerCaches(ModeBaseCp):
-    """mode de creation/ edition des caches"""
-    def __init__(self, plateau):
-        super(EditerCaches, self).__init__(plateau)
-        self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
-        self._focus = True
-        self._numCache = None
-
-    def activer(self, param = None):
-        self._numCache = param
-        self.plateau.pinceau.majForme("rectP")
-        super(EditerCaches, self).activer()
-
-    def desactiver(self):
-        self.plateau.pinceau.reinit()
-        super(EditerCaches, self).desactiver()        
-
-    def clic_case(self, coord):
-        self.plateau.pinceau.demarrer(coord)
-        
-    def survolClic_case(self, coord):
-        self.plateau.pinceau.maj(coord)
-    
-    def finClicGauche(self, coord):
-        if self.plateau.pinceau.estActif():
-            if len(self.plateau.pinceau.selection()) > 0:
-                if self._numCache != None:
-                    self.plateau.editerFormeCache(self._numCache, self.plateau.pinceau.selection())
-                else:
-                    self.plateau.nouveauCache(self.plateau.pinceau.selection())
-                self.plateau.activerMode(StandardCp)
-
-class EntreeSortieBase(ModeBaseCp):
-    """mode de base de la gestion des entrees et sorties du plateau"""
-    def __init__(self, plateau):
-        super(EntreeSortieBase, self).__init__(plateau)
-        self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
-        self._focus = True
-
-    def activerCurseur(self):
-        super(EntreeSortieBase, self).activerCurseur()
-
-    def activer(self, param):
-        self.es = param
-        self.es.saisir()
-        super(EntreeSortieBase, self).activer()
-
-    def desactiver(self):
-        if not self.es.estPositionne:
-            self.es.prepareGeometryChange()
-            self.es.plateau = None
-            self.plateau.removeItem(self.es)
-            if self.es in self.plateau.entreesSorties:
-                self.plateau.entreesSorties.remove(self.es) 
-        super(EntreeSortieBase, self).desactiver()
-        
-    def mouvementSouris(self, event):
-        if event.buttons() != Qt.LeftButton:
-            if not self.es.estPositionne:
-                self.es.majProjection(event.scenePos())
-
-    def toucheClavier(self, event):
-        if event.key() == Qt.Key_Delete:
-            self.es.supprimer()
-            if self.es in self.plateau.entreesSorties:
-                self.plateau.entreesSorties.remove(self.es)            
-            self.plateau.activerMode(StandardCp)
-        elif event.key() == Qt.Key_Right:
-            self.es.nbRotations += 1
-            self.es.majProjection()   
-        elif event.key() == Qt.Key_Left:
-            self.es.nbRotations -= 1
-            self.es.majProjection()    
-
-class CreationEntreeSortie(EntreeSortieBase):
-    """mode de creation des entrees / sorties"""
-    def __init__(self, plateau):
-        super(CreationEntreeSortie, self).__init__(plateau)    
-
-    def activer(self, typeES):
-        self.plateau.fenetre.ui.cbt_vue.fitInView(self.plateau.sceneRect(), Qt.KeepAspectRatio)
-        param = EntreeSortie(self.plateau, typeES)
-        param.creerForme()
-        super(CreationEntreeSortie, self).activer(param)
-
-    def clicGauche(self, event):
-        self.es.positionner()
-        self.plateau.entreesSorties.append(self.es)
-        self.plateau.activerMode(StandardCp)
-
-class EditionEntreeSortie(EntreeSortieBase):
-    """mode d'edition des entrees / sorties"""
-    def __init__(self, plateau):
-        super(EditionEntreeSortie, self).__init__(plateau)
-
-    def clicGauche(self, event):
-        if not event.isAccepted():
-            self.es.positionner()
-            self.plateau.activerMode(StandardCp)
-
-class CreationPion(ModeBaseCp):
-    """mode de creation de pions (combattant ou decor)"""
-    def __init__(self, plateau):
-        super(CreationPion, self).__init__(plateau)
-        self._focus = True
-        self._pion = None
-
-    def activer(self, pion):
-        self._pion = pion
-        self.plateau.proj.creer(self._pion)
-        super(CreationPion, self).activer()
-        
-    def desactiver(self):
-        self.plateau.proj.desactiver()
-        self._pion = None
-        super(CreationPion, self).desactiver()
-
-    def survol_case(self, coord):
-        if self._pion:
-            self.plateau.proj.majCoord(coord)
-
-    def clic_case(self, coord):
-        if self._pion:
-            if not self.plateau.cases[coord].estOccupee():
-                if isinstance(self._pion, Combattant) and dmK.touchesEnfoncees() == ["maj"]:
-                    nouveauZ = self.plateau.dialogueVol(self._pion.z)
-                    self._pion.majZ(nouveauZ)
-                self.plateau.creerPion(self._pion)
-
-    def toucheClavier(self, event):
-        if self._pion:
-            if event.key() == Qt.Key_Right:
-                self.plateau.proj.majRotation(1)
-            elif event.key() == Qt.Key_Left:
-                self.plateau.proj.majRotation(-1)
-
-
-class SuppressionPion(ModeBaseCp):
-    """mode de suppression de pions (combattant ou decor)"""
-    def __init__(self, plateau):
-        super(SuppressionPion, self).__init__(plateau)
-        self._sourceCurseur = ":/interface/16/ressource/gomme_16.png"
-        self._enSurbrillance = []
-        self._focus = True
-        self._cible = ""
-
-    def activer(self, cible = Pion):
-        #cible est le nom de la classe des objets a supprimer
-        self._cible = cible
-        super(SuppressionPion, self).activer()
-
-    def desactiver(self):
-        for num in self._enSurbrillance:
-            if num >= 10000:
-                if num in self.plateau.decors:
-                    self.plateau.decors[num].surbrillance(False)
-            else:
-                if num in self.plateau.combattants:
-                    self.plateau.combattants[num].surbrillance(False)
-        super(SuppressionPion, self).desactiver()
-
-    def clicGauche(self, event):
-        """supprime le pion sous le clic. S'il y en a plusieurs,
-            supprime le premier de la pile"""
-        num = None
-        item = self.plateau.itemAt(event.scenePos())
-        if isinstance(item.parentItem(), self._cible):
-            num = item.parentItem().numero
-        elif isinstance(item.parentItem().parentItem(), self._cible):
-            num = item.parentItem().parentItem().numero
-        if num:
-            self.plateau.pionSupprimer(num)
-
-    def survol_combattant(self, num):
-        if self._cible == Combattant:
-            self.plateau.combattants[num].surbrillance(True, 0.4)
-            self._enSurbrillance.append(num)
-
-    def finSurvol_combattant(self, num):
-        if self._cible == Combattant:
-            self.plateau.combattants[num].surbrillance(False)   
-
-    def survol_decor(self, num):
-        if self._cible == Decor:
-            self.plateau.decors[num].surbrillance(True, 0.4)
-            self._enSurbrillance.append(num)
-
-    def finSurvol_decor(self, num):
-        if self._cible == Decor:
-            self.plateau.decors[num].surbrillance(False)  
-
-class DeplacementPion(ModeBaseCp):
-    """mode de deplacement de pions (combattant ou decor) en mode creation
-        attention: different des actions de type deplacement qu'effectuent les pions en mode Combat"""
-    def __init__(self, plateau):
-        super(DeplacementPion, self).__init__(plateau)
-        self._num = 0
-        
-    def activer(self, num):
-        self._num = num
-        if self._num < 10000:
-            pion = self.plateau.combattants[self._num]
-        else:
-            pion = self.plateau.decors[self._num]
-        self.plateau.proj.creer(pion)
-        self.deplace = False
-        super(DeplacementPion, self).activer()
-
-    def desactiver(self):
-        self.plateau.proj.desactiver()
-        self._num = 0
-        super(DeplacementPion, self).desactiver()
-
-    def survol_case(self, coord):
-        if self._num > 0:
-            self.plateau.proj.majCoord(coord)
-            self.deplace = True
-
-    def clic_case(self, coord):
-        if self._num > 0:
-            if self.deplace:
-                if self._num < 10000:
-                    pion = self.plateau.combattants[self._num]
-                    if dmK.touchesEnfoncees() == ["maj"]:
-                        nouveauZ = self.plateau.dialogueVol(pion.z)
-                        pion.majZ(nouveauZ)
-                else:
-                    pion = self.plateau.decors[self._num]
-                pion.majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
-
-    def toucheClavier(self, event):
-        if self._num > 0:
-            if event.key() == Qt.Key_Right:
-                self.plateau.proj.majRotation(1)
-                self.deplace = True
-            elif event.key() == Qt.Key_Left:
-                self.plateau.proj.majRotation(-1)
-                self.deplace = True
-        
-#-----------------------------------------------
-#-----------------------------------------------
-
-class StandardPi(ModeBasePi):
-    """mode standard de la manipulation de pion en combat"""
-    def __init__(self, plateau):
-        super(StandardPi, self).__init__(plateau)
-        self._focus = False
-        self._activerDragMode = True
-
-    def activer(self, num):
-        self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(3)
-        if len(self.plateau.caches) > 0:
-            for coord in self.plateau.cases:
-                self.plateau.cases[coord].majCache()
-        super(StandardPi, self).activer()
-
-    def clic_combattant(self, num):
-        self.plateau.activerMode(PionSelectionne, num)
-
-    def clic_decor(self, num):
-        self.plateau.activerMode(PionSelectionne, num)
-
-    def nouvelleAction(self, action):
-        pass
-        
-    
-class PionSelectionne(ModeBasePi):
-    """mode active a la selection d'un pion combattant"""
-    def __init__(self, plateau):
-        super(PionSelectionne, self).__init__(plateau)
-        self._focus = True
-        self._num = None
-        self._action = None
-
-    def pion(self):
-        """retourne la ref du pion actuellement selectionne"""
-        retour = None
-        if self._num in self.plateau.combattants:
-            retour = self.plateau.combattants[self._num]
-        elif self._num in self.plateau.decors:
-            retour = self.plateau.decors[self._num]
-        return retour
-
-    def activer(self, num):
-        self._num = num
-        self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(2)
-        self.pion().afficheOmbreSelection(True)
-        self.plateau.majPanneauPi()
-        super(PionSelectionne, self).activer()
-
-    def desactiver(self):
-        if self._action:
-            self._action.desactiver()
-            self._action = None
-        self.pion().afficheOmbreSelection(False)
-        self._num = None
-        self.plateau.majPanneauPi()
-        super(PionSelectionne, self).desactiver()
-
-    def nouvelleAction(self, action):
-        if self._action:
-            self._action.desactiver()
-            self._action = None            
-        self._action = action()
-        self._action.activer(self.plateau, self._num)
-    
-    def action(self):
-        return self._action
-        
-    def survol_case(self, coord):
-        if self._action:
-            self._action.majCoordCible(coord)
-
-    def clic_case(self, coord):
-        if self._action:
-            terminee = self._action.valider()
-            if not self._action.enCours(): self._action = None
-           
-    def clicDroit(self, event):
-        if self._action != None:
-            self._action.desactiver()
-            self._action = None
-        else:
-            super(PionSelectionne, self).clicDroit(event)
-
-    def toucheClavier(self, event):
-        if self._num > 0:
-            if event.key() == Qt.Key_Right:
-                self._action.pivoter(1)
-            elif event.key() == Qt.Key_Left:
-                self._action.pivoter(-1)
-
-
-
-        
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+"""les modes d'interaction permettent l'interaction
+entre l'interface (l'utilisateur) et le plateau de combat.
+Un seul mode ne peut etre actif a la fois
+Cette classe doit permettre de recevoir les commandes de l'utilisateur
+de maniere a produire un resultat unique (cases peintes, pion deplace...)"""
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+from EntreeSortie import EntreeSortie
+import Actions
+import regles
+from Pion import Pion
+from Combattant import Combattant
+from Decor import Decor
+import dmK
+
+class ModeBase(object):
+    """mode de base: tous les modes heritent de cette classe"""
+    def __init__(self, plateau):
+        self.plateau = plateau
+        #le mode est il active
+        self._actif = False
+        #le dragmode est il active sur la QGraphicsView
+        self._activerDragMode = 0
+        #curseur de la QGraphicsView
+        self._sourceCurseur = ""
+        #met le focus sur la QGraphicsView a l'activation
+        self._focus = False 
+
+    def nom(self):
+        return self.__class__.__name__
+
+    def activer(self, param = None):
+        """active le mode"""
+        self.activerCurseur()
+        if self._focus:
+            self.plateau.fenetre.ui.cbt_vue.setFocus()
+        self._actif = True    
+
+    def desactiver(self):
+        """desactive le mode"""
+        self.desactiverCurseur()
+        self.plateau.fenetre.ui.cbt_vue.setDragMode(1)
+        self._actif = False
+
+    def reinit(self):
+        """remet les variables a 0 et reactive le mode"""
+        pass
+
+    def activerCurseur(self):
+        self.plateau.fenetre.ui.cbt_vue.setDragMode(self._activerDragMode)
+        curseurPix = QPixmap(self._sourceCurseur)
+        if not curseurPix.isNull():
+            curseur = QCursor(curseurPix, 0, curseurPix.height())
+            self.plateau.fenetre.ui.cbt_vue.setCursor(curseur)   
+
+    def desactiverCurseur(self):
+        self.plateau.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
+
+    ### gestion des evenements souris
+    # clic gauche
+    def clic_combattant(self, num):
+        return False
+
+    def clic_decor(self, num):
+        return False
+
+    def clic_case(self, coord):
+        return False
+
+    def clic_es(self, es):
+        #clic sur une entree/sortie
+        return False
+        
+    #double clic gauche
+    def doubleClic_combattant(self, num):
+        return False
+
+    def doubleClic_decor(self, num):
+        return False
+
+    def doubleClic_case(self, coord):
+        return False
+
+    #survol de la souris (entree)   
+    def survol_combattant(self, num):
+        return False
+
+    def survol_decor(self, num):
+        return False
+
+    def survol_case(self, coord):
+        return False
+
+    #survol de la souris (sortie)  
+    def finSurvol_combattant(self, num):
+        return False
+
+    def finSurvol_decor(self, num):
+        return False
+
+    def finSurvol_case(self, coord):
+        return False
+
+    #survol de la souris avec clic gauche enfonce (entree)   
+    def survolClic_combattant(self, event):
+        return False
+
+    def survolClic_decor(self, event):
+        return False
+
+    def survolClic_case(self, coord):
+        return False
+
+    #autre
+    def clicGauche(self, event):
+        return False
+
+    def finClicGauche(self, event):
+        return False
+    
+    def mouvementSouris(self, event):
+        return False
+    
+    def toucheClavier(self, event):
+        return False
+
+    def clicDroit(self, event):
+        return False
+
+
+class ModeBaseCp(ModeBase):
+    """mode servant de base a tous les modes lies a la creation de plateau"""
+    def __init__(self, plateau):
+        super(ModeBaseCp, self).__init__(plateau)
+        self.type = "cp"
+
+    def activer(self, param = None):
+        self.plateau.fenetre.ui.cbt_modeCreation.setChecked(True)
+        super(ModeBaseCp, self).activer(param)
+        
+    def desactiver(self):
+        self.plateau.fenetre.ui.cbt_modeCreation.setChecked(False)
+        super(ModeBaseCp, self).desactiver()
+        
+    def clicDroit(self, event):
+        self.plateau.activerMode(StandardCp)
+        return True
+
+class ModeBasePi(ModeBase):
+    """mode servant de base a tous les modes lies aux actions des combattants"""
+    def __init__(self, plateau):
+        super(ModeBasePi, self).__init__(plateau)
+        self.type = "pi"
+
+    def activer(self, param = None):
+        self.plateau.fenetre.ui.cbt_modeCombat.setChecked(True)
+        super(ModeBasePi, self).activer(param)
+        
+    def desactiver(self):
+        self.plateau.fenetre.ui.cbt_modeCombat.setChecked(False)
+        super(ModeBasePi, self).desactiver()
+
+    def clicDroit(self, event):
+        self.plateau.activerMode(StandardPi)
+        return True
+
+### --------------------------------------- ####
+
+
+class StandardCp(ModeBaseCp):
+    """mode standard en creation de plateau"""
+    def __init__(self, plateau):
+        super(StandardCp, self).__init__(plateau)
+        self._sourceCurseur = ""
+        self._focus = False
+        self._activerDragMode = True
+
+    def activer(self, param):
+        """active le mode"""
+        self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(1)
+        if len(self.plateau.caches) > 0:
+            for coord in self.plateau.cases:
+                self.plateau.cases[coord].majCache()
+        super(StandardCp, self).activer()
+
+    def clic_combattant(self, num):
+        self.plateau.activerMode(DeplacementPion, num)
+        return True
+        
+    def clic_decor(self, num):
+        self.plateau.activerMode(DeplacementPion, num)
+        return True
+
+    def clic_es(self, es):
+        self.plateau.activerMode(EditionEntreeSortie, es)
+        return True
+ 
+class MajCases(ModeBaseCp):
+    """mode de mise a jour des cases (terrain, couleur, effet special)"""
+    def __init__(self, plateau):
+        super(MajCases, self).__init__(plateau)
+        self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
+        self._focus = True
+        self._param = None   #parametre avec lequel on mettra a jour la case
+        self._caseSurvolee = None
+
+    def activer(self, param):
+        """active le mode"""
+        self.majParam(param)
+        super(MajCases, self).activer()
+
+    def desactiver(self):
+        """desactive le mode"""
+        self.plateau.pinceau.reinit()
+        super(MajCases, self).desactiver()
+
+    def majParam(self, param):
+        self._param = param
+        
+    def param(self):
+        return self._param
+
+    def clic_case(self, coord):
+        #demarre une operation de peinture des cases
+        self.plateau.pinceau.demarrer(coord)
+        return True
+
+    def survolClic_case(self, coord):
+        accepte = False
+        if coord != self._caseSurvolee:
+            self.plateau.pinceau.maj(coord)
+            accepte = True
+        return accepte
+
+    def finClicGauche(self, event):
+        accepte = False
+        if self.plateau.pinceau.estActif():
+            for coord in self.plateau.pinceau.selection():
+                self.plateau.cases[coord].majTerrain(self._param)
+                self.plateau.cases[coord].majAltitude(self.plateau.fenetre.ui.cp_valeurAltitude.value())
+                self.plateau.pinceau.reinit()
+            self.reinit()
+            accepte = True
+        return accepte
+    
+    def toucheClavier(self, event):
+        accepte = False
+        if event.key() == Qt.Key_Up:
+            self.plateau.fenetre.ui.epaisseurPinceau.setValue(self.plateau.fenetre.ui.epaisseurPinceau.value()+1)
+            accepte = True
+        elif event.key() == Qt.Key_Down:
+            self.plateau.fenetre.ui.epaisseurPinceau.setValue(self.plateau.fenetre.ui.epaisseurPinceau.value()-1)
+            accepte = True
+        return accepte
+    
+class MajCasesEffet(MajCases):
+    """mode de mise a jour des cases (effets speciaux)"""
+    def __init__(self, plateau):
+        super(MajCasesEffet, self).__init__(plateau)
+        self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
+
+    def finClicGauche(self, event):
+        accepte = False
+        if self.plateau.pinceau.estActif():
+            for coord in self.plateau.pinceau.selection():
+                self.plateau.cases[coord].majEffet(self._param)
+                self.plateau.pinceau.reinit()
+            self.reinit()
+            accepte = True
+        return accepte
+
+class Pipette(ModeBaseCp):
+    """mode pipette: on preleve la couleur ou le terrain d'une case"""
+    def __init__(self, plateau):
+        super(Pipette, self).__init__(plateau)
+        self._sourceCurseur = ":/interface/16/ressource/seringue_16.png"
+
+    def activerCurseur(self):
+        super(Pipette, self).activerCurseur()
+        
+    def clic_case(self, coord):
+        self.plateau.activerMode(MajCases, self.plateau.cases[coord].terrain)
+        return True
+
+class ZonePlacement(ModeBaseCp):
+    """mode de definition de la/les zones de placement des joueurs"""
+    def __init__(self, plateau):
+        super(ZonePlacement, self).__init__(plateau)
+        self._sourceCurseur = ":/interface/16/ressource/pinceau.png"
+        self._focus = True
+
+    def activerCurseur(self):
+        super(ZonePlacement, self).activerCurseur()
+
+    def activer(self, param = None):
+        self.plateau.pinceau.majForme("rectP")
+        self.plateau.pinceau.verrouillerForme(True)
+        super(ZonePlacement, self).activer()
+
+    def desactiver(self):
+        self.plateau.pinceau.reinit()
+        super(ZonePlacement, self).desactiver()
+
+    def clic_case(self, coord):
+        #demarre une operation de peinture des cases
+        self.plateau.pinceau.demarrer(coord)
+        return True
+        
+    def survolClic_case(self, coord):
+        self.plateau.pinceau.maj(coord)
+        return True
+    
+    def finClicGauche(self, coord):
+        if self.plateau.pinceau.estActif():
+            if len(self.plateau.pinceau.selection()) > 0:
+                self.plateau.majZonePlacement(self.plateau.pinceau.selection())
+        return True        
+
+class EditerCaches(ModeBaseCp):
+    """mode de creation/ edition des caches"""
+    def __init__(self, plateau):
+        super(EditerCaches, self).__init__(plateau)
+        self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
+        self._focus = True
+        self._numCache = None
+
+    def activer(self, param = None):
+        self._numCache = param
+        self.plateau.pinceau.majForme("rectP")
+        super(EditerCaches, self).activer()
+
+    def desactiver(self):
+        self.plateau.pinceau.reinit()
+        super(EditerCaches, self).desactiver()        
+
+    def clic_case(self, coord):
+        self.plateau.pinceau.demarrer(coord)
+        return True
+        
+    def survolClic_case(self, coord):
+        self.plateau.pinceau.maj(coord)
+        return True
+    
+    def finClicGauche(self, coord):
+        accepte = False
+        if self.plateau.pinceau.estActif():
+            if len(self.plateau.pinceau.selection()) > 0:
+                if self._numCache != None:
+                    self.plateau.editerFormeCache(self._numCache, self.plateau.pinceau.selection())
+                else:
+                    self.plateau.nouveauCache(self.plateau.pinceau.selection())
+                self.plateau.activerMode(StandardCp)
+            accepte = True
+        return accepte
+    
+class EntreeSortieBase(ModeBaseCp):
+    """mode de base de la gestion des entrees et sorties du plateau"""
+    def __init__(self, plateau):
+        super(EntreeSortieBase, self).__init__(plateau)
+        self._sourceCurseur = ":/interface/16/ressource/pinceau_16.png"
+        self._focus = True
+
+    def activerCurseur(self):
+        super(EntreeSortieBase, self).activerCurseur()
+
+    def activer(self, param):
+        self.es = param
+        self.es.saisir()
+        super(EntreeSortieBase, self).activer()
+
+    def desactiver(self):
+        if not self.es.estPositionne:
+            self.es.prepareGeometryChange()
+            self.es.plateau = None
+            self.plateau.removeItem(self.es)
+            if self.es in self.plateau.entreesSorties:
+                self.plateau.entreesSorties.remove(self.es) 
+        super(EntreeSortieBase, self).desactiver()
+        
+    def mouvementSouris(self, event):
+        accepte = False
+        if event.buttons() != Qt.LeftButton:
+            if not self.es.estPositionne:
+                self.es.majProjection(event.scenePos())
+                accepte = True
+        return accepte
+    
+    def toucheClavier(self, event):
+        accepte = False
+        if event.key() == Qt.Key_Delete:
+            self.es.supprimer()
+            if self.es in self.plateau.entreesSorties:
+                self.plateau.entreesSorties.remove(self.es)            
+            self.plateau.activerMode(StandardCp)
+            accepte = True
+        elif event.key() == Qt.Key_Right:
+            self.es.nbRotations += 1
+            self.es.majProjection()  
+            accepte = True 
+        elif event.key() == Qt.Key_Left:
+            self.es.nbRotations -= 1
+            self.es.majProjection()  
+            accepte = True  
+        return accepte
+    
+class CreationEntreeSortie(EntreeSortieBase):
+    """mode de creation des entrees / sorties"""
+    def __init__(self, plateau):
+        super(CreationEntreeSortie, self).__init__(plateau)    
+
+    def activer(self, typeES):
+        self.plateau.fenetre.ui.cbt_vue.fitInView(self.plateau.sceneRect(), Qt.KeepAspectRatio)
+        param = EntreeSortie(self.plateau, typeES)
+        param.creerForme()
+        super(CreationEntreeSortie, self).activer(param)
+
+    def clicGauche(self, event):
+        self.es.positionner()
+        self.plateau.entreesSorties.append(self.es)
+        self.plateau.activerMode(StandardCp)
+        return True
+
+class EditionEntreeSortie(EntreeSortieBase):
+    """mode d'edition des entrees / sorties"""
+    def __init__(self, plateau):
+        super(EditionEntreeSortie, self).__init__(plateau)
+
+    def clicGauche(self, event):
+        accepte = False
+        if not event.isAccepted():
+            self.es.positionner()
+            self.plateau.activerMode(StandardCp)
+            accepte = True
+        return accepte
+
+class CreationPion(ModeBaseCp):
+    """mode de creation de pions (combattant ou decor)"""
+    def __init__(self, plateau):
+        super(CreationPion, self).__init__(plateau)
+        self._focus = True
+        self._pion = None
+
+    def activer(self, pion):
+        self._pion = pion
+        self.plateau.proj.creer(self._pion)
+        super(CreationPion, self).activer()
+        
+    def desactiver(self):
+        self.plateau.proj.desactiver()
+        self._pion = None
+        super(CreationPion, self).desactiver()
+
+    def survol_case(self, coord):
+        accepte = False
+        if self._pion:
+            self.plateau.proj.majCoord(coord)
+            accepte = True
+        return accepte
+
+    def clic_case(self, coord):
+        accepte = False
+        if self._pion:
+            if not self.plateau.cases[coord].estOccupee():
+                if isinstance(self._pion, Combattant) and dmK.touchesEnfoncees() == ["maj"]:
+                    nouveauZ = self.plateau.dialogueVol(self._pion.z)
+                    self._pion.majZ(nouveauZ)
+                self.plateau.creerPion(self._pion)
+                accepte = True
+        return accepte
+    
+    def toucheClavier(self, event):
+        accepte = False
+        if self._pion:
+            if event.key() == Qt.Key_Right:
+                self.plateau.proj.majRotation(1)
+                accepte = True
+            elif event.key() == Qt.Key_Left:
+                self.plateau.proj.majRotation(-1)
+                accepte = True
+        return accepte
+
+class SuppressionPion(ModeBaseCp):
+    """mode de suppression de pions (combattant ou decor)"""
+    def __init__(self, plateau):
+        super(SuppressionPion, self).__init__(plateau)
+        self._sourceCurseur = ":/interface/16/ressource/gomme_16.png"
+        self._enSurbrillance = []
+        self._focus = True
+        self._cible = ""
+
+    def activer(self, cible = Pion):
+        #cible est le nom de la classe des objets a supprimer
+        self._cible = cible
+        super(SuppressionPion, self).activer()
+
+    def desactiver(self):
+        for num in self._enSurbrillance:
+            if num >= 10000:
+                if num in self.plateau.decors:
+                    self.plateau.decors[num].surbrillance(False)
+            else:
+                if num in self.plateau.combattants:
+                    self.plateau.combattants[num].surbrillance(False)
+        super(SuppressionPion, self).desactiver()
+
+    def clicGauche(self, event):
+        """supprime le pion sous le clic. S'il y en a plusieurs,
+            supprime le premier de la pile"""
+        accepte = False
+        num = None
+        item = self.plateau.itemAt(event.scenePos())
+        if isinstance(item.parentItem(), self._cible):
+            num = item.parentItem().numero
+        elif isinstance(item.parentItem().parentItem(), self._cible):
+            num = item.parentItem().parentItem().numero
+        if num:
+            self.plateau.pionSupprimer(num)
+            accepte = True
+        return accepte
+    
+    def survol_combattant(self, num):
+        accepte = False
+        if self._cible == Combattant:
+            self.plateau.combattants[num].surbrillance(True, 0.4)
+            self._enSurbrillance.append(num)
+            accepte = True
+        return accepte
+    
+    def finSurvol_combattant(self, num):
+        accepte = False
+        if self._cible == Combattant:
+            self.plateau.combattants[num].surbrillance(False)  
+            accepte = True 
+        return accepte
+    
+    def survol_decor(self, num):
+        accepte = False
+        if self._cible == Decor:
+            self.plateau.decors[num].surbrillance(True, 0.4)
+            self._enSurbrillance.append(num)
+            accepte = True
+        return accepte
+    
+    def finSurvol_decor(self, num):
+        accepte = False
+        if self._cible == Decor:
+            self.plateau.decors[num].surbrillance(False)  
+            accepte = True
+        return accepte
+    
+class DeplacementPion(ModeBaseCp):
+    """mode de deplacement de pions (combattant ou decor) en mode creation
+        attention: different des actions de type deplacement qu'effectuent les pions en mode Combat"""
+    def __init__(self, plateau):
+        super(DeplacementPion, self).__init__(plateau)
+        self._num = 0
+        
+    def activer(self, num):
+        self._num = num
+        if self._num < 10000:
+            pion = self.plateau.combattants[self._num]
+        else:
+            pion = self.plateau.decors[self._num]
+        self.plateau.proj.creer(pion)
+        self.deplace = False
+        super(DeplacementPion, self).activer()
+
+    def desactiver(self):
+        self.plateau.proj.desactiver()
+        self._num = 0
+        super(DeplacementPion, self).desactiver()
+
+    def survol_case(self, coord):
+        accepte = False
+        if self._num > 0:
+            self.plateau.proj.majCoord(coord)
+            self.deplace = True
+            accepte = True
+        return accepte
+    
+    def clic_case(self, coord):
+        accepte = False
+        if self._num > 0:
+            if self.deplace:
+                if self._num < 10000:
+                    pion = self.plateau.combattants[self._num]
+                    if dmK.touchesEnfoncees() == ["maj"]:
+                        nouveauZ = self.plateau.dialogueVol(pion.z)
+                        pion.majZ(nouveauZ)
+                else:
+                    pion = self.plateau.decors[self._num]
+                pion.majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
+                accepte = True
+        return accepte
+    
+    def toucheClavier(self, event):
+        accepte = False
+        if self._num > 0:
+            if event.key() == Qt.Key_Right:
+                self.plateau.proj.majRotation(1)
+                self.deplace = True
+                accepte = True
+            elif event.key() == Qt.Key_Left:
+                self.plateau.proj.majRotation(-1)
+                self.deplace = True
+                accepte = True
+        return accepte
+            
+#-----------------------------------------------
+#-----------------------------------------------
+
+class StandardPi(ModeBasePi):
+    """mode standard de la manipulation de pion en combat"""
+    def __init__(self, plateau):
+        super(StandardPi, self).__init__(plateau)
+        self._focus = False
+        self._activerDragMode = True
+
+    def activer(self, num):
+        self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(3)
+        if len(self.plateau.caches) > 0:
+            for coord in self.plateau.cases:
+                self.plateau.cases[coord].majCache()
+        super(StandardPi, self).activer()
+
+    def clic_combattant(self, num):
+        self.plateau.activerMode(PionSelectionne, num)
+        return True
+
+    def clic_decor(self, num):
+        self.plateau.activerMode(PionSelectionne, num)
+        return True
+
+    def nouvelleAction(self, action):
+        pass
+        
+    
+class PionSelectionne(ModeBasePi):
+    """mode active a la selection d'un pion combattant"""
+    def __init__(self, plateau):
+        super(PionSelectionne, self).__init__(plateau)
+        self._focus = True
+        self._num = None
+        self._action = None
+
+    def pion(self):
+        """retourne la ref du pion actuellement selectionne"""
+        retour = None
+        if self._num in self.plateau.combattants:
+            retour = self.plateau.combattants[self._num]
+        elif self._num in self.plateau.decors:
+            retour = self.plateau.decors[self._num]
+        return retour
+
+    def activer(self, num):
+        self._num = num
+        self.plateau.fenetre.ui.cbt_panneauDroite.setCurrentIndex(2)
+        self.pion().afficheOmbreSelection(True)
+        self.plateau.majPanneauPi()
+        super(PionSelectionne, self).activer()
+
+    def desactiver(self):
+        if self._action:
+            self._action.desactiver()
+            self._action = None
+        self.pion().afficheOmbreSelection(False)
+        self._num = None
+        self.plateau.majPanneauPi()
+        super(PionSelectionne, self).desactiver()
+
+    def nouvelleAction(self, action):
+        if self._action:
+            self._action.desactiver()
+            self._action = None            
+        self._action = action()
+        self._action.activer(self.plateau, self._num)
+    
+    def action(self):
+        return self._action
+        
+    def survol_case(self, coord):
+        accepte = False
+        if self._action:
+            self._action.majCoordCible(coord)
+            accepte = True
+        return accepte
+    
+    def clic_case(self, coord):
+        accepte = False
+        if self._action:
+            self._action.valider()
+            if not self._action.enCours(): self._action = None
+            accepte = True
+        return accepte
+               
+    def clicDroit(self, event):
+        accepte = False
+        if self._action != None:
+            self._action.desactiver()
+            self._action = None
+            accepte = True
+        else:
+            accepte = super(PionSelectionne, self).clicDroit(event)
+        return accepte
+
+    def toucheClavier(self, event):
+        accepte = False
+        if self._num > 0:
+            if event.key() == Qt.Key_Right:
+                self._action.pivoter(1)
+                accepte = True
+            elif event.key() == Qt.Key_Left:
+                self._action.pivoter(-1)
+                accepte = True
+        return accepte
+
+
+        

+ 326 - 325
lib/Pion.py

@@ -1,325 +1,326 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-from __future__ import division
-import os
-
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-
-from Forme import Forme
-from outilsSvg import *
-from rsc import *
-import dmK
-
-class Pion(QGraphicsItem):
-    """pion du plateau de combat"""
-    def __init__(self, parent=None):
-        super(Pion, self).__init__()
-        #caracteristiques du pion
-        self.numero = 0
-        self.nom = ""
-        self.couleur = QColor()
-        self.logo = ""
-        self.img = ImgPion()
-        self.etiquette = EtiquettePion()
-
-        #infos liees au plateau (forme et position)
-        self.plateau = None
-        self.numComplementaire = ""    #numero complementaire si necessaire
-                                        #(si plusieurs pions portent le meme nom)
-        self.position = (-1, -1)
-        self.z = 0
-        self.hauteur = 1
-        self.forme = None
-        self.formeDef = {"H":[], "C":[]}
-
-        #objets et parametres graphiques
-        self.pixGraphique = None
-        self.etiquetteGraphique = None
-        self._l0 = 0
-        self._h0 = 0
-        self.polygoneGraphique = None
-        self.nbRotations = 0
-
-        
-    def __getstate__(self):
-        nePasSvg = ["plateau", "brillance", "shadow", "creature", "polygonesForme", "pixGraphique", "etiquetteGraphique"]
-        state = {key:value for key, value in self.__dict__.items() if not key in nePasSvg}
-        return (state)
-    
-    def __setstate__(self, state):
-        self.__dict__ = state
-        self.pixGraphique = None
-        self.etiquetteGraphique = None
-        super(Pion, self).__init__()
-
-    def paint(self, painter, option, widget = None):
-        """reimplemente de QGraphicsItem: on ne peint pas cet item, seulement ses items enfants"""
-        pass
-
-    def txtId(self):
-        """renvoie le nom et le numero complementaire du pion"""
-        return "{} {}".format(self.nom, self.numComplementaire)
-
-    def icone(self):
-        """renvoie l'image a afficher dans les listes"""
-        return self.logo
-
-    def yReel(self):
-        """renvoie le y reel (pour les contructions graphiques"""
-        if 1 == (self.position[0] % 2):
-             y = self.position[1] + 0.5
-        else:
-             y = self.position[1]
-        return y
-    
-    ###attributs du pion
-    def position(self):
-        """retourne la position actuelle du pion"""
-        return self.position
-
-    def casesOccupees(self):
-        """retourne la liste des cases occupees sur le plateau par le pion (x,y,z)"""
-        retour = []
-        if self.plateau:
-            for x, y in self.forme.listeCases(self.position, self.nbRotations):
-                for z in range(1, self.hauteur):
-                    retour.append((x, y, (self.plateau.cases[(x, y)].altitude + self.z + z)))
-        return retour
-
-    def majZ(self, valeur):
-        """met a jour l'altitude Z du pion"""
-        if valeur != self.z:
-            self.z = valeur    
-
-    def zAbs(self):
-        """retourne la coord z absolue du pion"""
-        return (self.plateau.cases[self.position].altitude + self.z)
-
-    ########### fonctions graphiques et geometriques   ##############
-    def ajouterAuPlateau(self, plateau):
-        """cerre l'objet graphique representant le pion et le place sur le plateau"""
-        self.plateau = plateau
-
-        #definition de la forme (interpretation de formeDef)
-        self.forme = Forme(self.plateau.formeCases)
-        if len(self.formeDef[self.plateau.formeCases]) > 0:
-            self.forme.definirForme(self.formeDef[self.plateau.formeCases])        
-
-        #creation du polygone
-        polygone = self.plateau.polygoneAgglo(self.forme.listeCases((0,0)))
-        self.polygoneGraphique = QGraphicsPolygonItem()
-        self.polygoneGraphique.setPolygon(polygone)
-        self.polygoneGraphique.setAcceptHoverEvents(True)
-        self.polygoneGraphique.setFlag(QGraphicsItem.ItemIsFocusable)   #l'item peut recevoir des commandes souris/clavier
-        self.polygoneGraphique.setParentItem(self)
-        self.polygoneGraphique.setPos(QPointF(0,0))
-        if self.plateau.formeCases == "H":
-            self.polygoneGraphique.setTransformOriginPoint(QPointF(2*0.2886*self.plateau.hCase, 0.5*self.plateau.hCase))
-        else:
-            self.polygoneGraphique.setTransformOriginPoint(QPointF(0.5*self.plateau.hCase,0.5*self.plateau.hCase))
-
-        #parametres de l'objet graphique
-        self.setZValue(10)
-        self.setFlag(QGraphicsItem.ItemHasNoContents)
-        self.setHandlesChildEvents(True)
-         
-        pinceau = QPen()
-        pinceau.setColor(self.couleur.darker(130))
-        pinceau.setWidth(10)
-        self.polygoneGraphique.setPen(pinceau)
-
-        if self.couleur.isValid():
-             self.polygoneGraphique.setBrush(self.couleur)
-        else:
-             self.polygoneGraphique.setBrush(QColor(255, 0, 0, 150))
-
-        self.shadow = QGraphicsDropShadowEffect()
-        self.shadow.setColor(QColor(50, 50, 50)) 
-        self.shadow.setXOffset(1) 
-        self.shadow.setYOffset(2) 
-        self.shadow.setBlurRadius(3)  
-        self.shadow.setEnabled(True)
-        self.polygoneGraphique.setGraphicsEffect(self.shadow)
-        
-        self.polygoneBrillance = QGraphicsPolygonItem()
-        self.polygoneBrillance.setPolygon(self.polygoneGraphique.polygon())
-        self.polygoneBrillance.setVisible(False)
-        self.polygoneGraphique.setFlag(QGraphicsItem.ItemIsFocusable)
-        self.setAcceptHoverEvents(True)   #accepte les evenements survol souris
-        self.polygoneBrillance.setParentItem(self.polygoneGraphique)
-
-        #on ajoute l'objet au plateau
-        self.plateau.addItem(self)
-        self.majPosition(self.position, self.nbRotations)
-
-    def majPosition(self, nouvellePosition, nbRotations = 0):
-        """met a jour la position de l'objet graphique et de sa forme en fonction de sa position enregistree"""
-        if self.plateau:
-            #on met a jour l'occupation des cases
-            if self.position != (-1,-1):
-                for coord in self.forme.listeCases(self.position, self.nbRotations):
-                    for z in range(self.z, (self.z + self.hauteur)):
-                        self.plateau.cases[coord].liberer(z)
-
-            #on met a jour la position du pion        
-            self.position = nouvellePosition
-            self.majNbRotation(nbRotations)
-
-            #on replace
-            if self.plateau.formeCases == "H":
-                angleRotation = 60
-                positionGraphique = QPointF(self.position[0] * 0.866 * self.plateau.hCase, self.yReel() * self.plateau.hCase)
-            else:
-                angleRotation = 90
-                positionGraphique = QPointF(self.position[0] * self.plateau.hCase, self.position[1] * self.plateau.hCase)
-            self.prepareGeometryChange()
-            self.setPos(positionGraphique)
-            self.polygoneGraphique.setRotation(self.nbRotations*angleRotation)
-            
-            #maj de l'image
-            self.majImage()
-            
-            #on met a jour l'occupation des cases
-            for coord in self.forme.listeCases(self.position, self.nbRotations):
-                for z in range(self.z, (self.z + self.hauteur)):
-                    self.plateau.cases[coord].occuper(self.numero, z)
-                 
-    def majImage(self):
-        """met a jour la taille, la position et l'orientation de l'image"""
-        if self.img.rimage.estValide():
-            pix = self.img.rimage.pix()
-            if not pix.isNull():
-                if not self.pixGraphique:
-                    self.pixGraphique = QGraphicsPixmapItem()
-                    self.pixGraphique.setZValue(10) 
-                    if pix.height() >= pix.width():
-                        pix = pix.scaledToHeight(self.plateau.hCase*0.9, Qt.SmoothTransformation)
-                    else:
-                        pix = pix.scaledToWidth(self.plateau.hCase*0.9, Qt.SmoothTransformation)
-                    self._l0 = pix.width()
-                    self._h0 = pix.height()
-                    pix = pix.scaled((self.img.kx/10)*pix.width(), \
-                                     (self.img.ky/10)*pix.height(), \
-                                      Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
-                    self.pixGraphique.setPixmap(pix)
-
-##                deltaX = self.img.dx + 0.5*(self.plateau.hCase*1.1544 - self._l0)
-##                deltaY = self.img.dy + 0.5*(self.plateau.hCase - self._h0)
-                deltaX = self.img.dx + 0.5*(self.plateau.hCase*1.1544 - self.pixGraphique.pixmap().width())
-                deltaY = self.img.dy + 0.5*(self.plateau.hCase - self.pixGraphique.pixmap().height())
-                    
-                if self.img.rimage.nom() == self.logo.nom():
-                    #si l'image est le logo, elle ne doit pas pivoter
-                    self.pixGraphique.setParentItem(self)
-                else:
-                    self.pixGraphique.setParentItem(self.polygoneGraphique)
-                self.pixGraphique.setRotation(self.img.rotation)
-                self.pixGraphique.setPos(QPointF(deltaX, deltaY))
-
-    def majEtiquette(self):
-        """met a jour la taille, le format et l'orientation de l'etiquette"""
-        self.etiquetteGraphique = QGraphicsSimpleTextItem("{}".format(self.txtId()))
-        self.etiquetteGraphique.setPos(QPointF(self.etiquette.dx - 0.112*self.plateau.hCase, \
-                                                self.etiquette.dy - 0.5*self.plateau.hCase))
-        police = QFont("Verdana", self.etiquette.taille_police)
-        police.setBold(self.etiquette.gras)
-        self.etiquetteGraphique.setFont(police)
-        self.etiquetteGraphique.setParentItem(self)        
-                
-    def majNbRotation(self, nbRotations):
-        """ajoute/retranche le nombre au nombre total de rotations du pion"""
-        self.nbRotations = nbRotations
-        if self.plateau.formeCases == "H":
-            rotationsTour = 6
-        else:
-            rotationsTour = 4
-            
-        if self.nbRotations >= 0:
-            self.nbRotations = self.nbRotations % rotationsTour
-        else:
-            self.nbRotations = self.nbRotations % (-rotationsTour)
-
-    def retirerDuPlateau(self):
-        """'deconnecte' les items enfants avant de supprimer du pion du plateau"""
-        for coord in self.forme.listeCases(self.position, self.nbRotations):
-            for z in range(self.z, (self.z + self.hauteur)):
-                self.plateau.cases[coord].liberer(z)
-
-        self.polygoneBrillance.prepareGeometryChange()
-        self.polygoneBrillance.setParentItem(None)
-        if self.pixGraphique != None:
-            self.pixGraphique.prepareGeometryChange()
-            self.pixGraphique.setParentItem(None)
-        self.polygoneGraphique.prepareGeometryChange()
-        self.polygoneGraphique.setParentItem(None)
-        if self.etiquetteGraphique:
-            self.etiquetteGraphique.prepareGeometryChange()
-            self.etiquetteGraphique.setParentItem(None)
-        self.plateau.removeItem(self)
-        self.plateau = None
-
-    ###effets graphiques 
-    def afficheOmbreSelection(self, actif = False):
-        """modifie l'ombre du pion en fonction de si celui-ci est selectionne ou non"""
-        if actif:
-            self.shadow.setXOffset(3) 
-            self.shadow.setYOffset(3)
-        else:
-            self.shadow.setXOffset(1) 
-            self.shadow.setYOffset(2)
-            
-    def surbrillance(self, active, opacite = 0.7, couleur = "white"):
-        """active/desactive la surbrillance"""
-        if active:
-            self.polygoneBrillance.setOpacity(opacite)
-            couleur = self.couleurSurbrillance(couleur)
-            pinceau = self.polygoneGraphique.pen()
-            self.polygoneBrillance.setBrush(couleur)
-            self.polygoneBrillance.setPen(pinceau)
-        self.polygoneBrillance.setVisible(active)
-        
-    def estCibleAttaque(self, estCible, possible = True):
-        """le pion s'affiche comme etant cible d'une attaque"""
-        if not possible:
-            couleur = "red"
-        else:
-            couleur = "white"
-        self.surbrillance(estCible, 0.8, couleur)
-        
-    def couleurSurbrillance(self, couleur = "white"):
-        """renvoie une QColor visible pour la surbrillance, selon la couleur du pion"""
-        retour = QColor(couleur)
-        if self.polygoneGraphique.brush().color().lightness() > 220:
-            retour = retour.darker(140)
-        elif self.polygoneGraphique.brush().color().lightness() < 80:
-            retour = retour.lighter(140)
-        return retour
-
-    ##################
-
-    ###############   evenements clavier et souris    ##############
-    def boundingRect(self):
-        return QRectF()
-        
-     #######################
-
-class ImgPion():
-    def __init__(self):
-        self.rimage = RImage("")        #ressource: image
-        self.kx = 10                 #coeff d'agrandissement horizontal
-        self.ky = 10                 #coeff d'agrandissement vertical
-        self.dx = 0                 #decalage horizontal
-        self.dy = 0                 #decalage vertical
-        self.rotation = 0           #rotation(en degres)
-        self.pivote = False         #l'image pivote avec le pion?
-        self.masqueAuto = False     #creer un masque automatiquement
-        
-class EtiquettePion():
-    def __init__(self):
-        self.txt = ""
-        self.taille_police = 28     #taille de la police
-        self.gras = False           #en gras
-        self.dx = 0                 #decalage horizontal
-        self.dy = 0                 #decalage vertical
-
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+from __future__ import division
+import os
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from Forme import Forme
+from outilsSvg import *
+from rsc import *
+import dmK
+
+class Pion(QGraphicsItem):
+    """pion du plateau de combat"""
+    def __init__(self, parent=None):
+        super(Pion, self).__init__()
+        #caracteristiques du pion
+        self.numero = 0
+        self.nom = ""
+        self.couleur = QColor()
+        self.logo = ""
+        self.img = ImgPion()
+        self.etiquette = EtiquettePion()
+
+        #infos liees au plateau (forme et position)
+        self.plateau = None
+        self.numComplementaire = ""    #numero complementaire si necessaire
+                                        #(si plusieurs pions portent le meme nom)
+        self.position = (-1, -1)
+        self.z = 0
+        self.hauteur = 1
+        self.forme = None
+        self.formeDef = {"H":[], "C":[]}
+
+        #objets et parametres graphiques
+        self.pixGraphique = None
+        self.etiquetteGraphique = None
+        self._l0 = 0
+        self._h0 = 0
+        self.polygoneGraphique = None
+        self.nbRotations = 0
+
+        
+    def __getstate__(self):
+        nePasSvg = ["plateau", "brillance", "shadow", "creature", "polygonesForme", "pixGraphique", "etiquetteGraphique"]
+        state = {key:value for key, value in self.__dict__.items() if not key in nePasSvg}
+        return (state)
+    
+    def __setstate__(self, state):
+        self.__dict__ = state
+        self.pixGraphique = None
+        self.etiquetteGraphique = None
+        super(Pion, self).__init__()
+
+    def paint(self, painter, option, widget = None):
+        """reimplemente de QGraphicsItem: on ne peint pas cet item, seulement ses items enfants"""
+        pass
+
+    def txtId(self):
+        """renvoie le nom et le numero complementaire du pion"""
+        return "{} {}".format(self.nom, self.numComplementaire)
+
+    def icone(self):
+        """renvoie l'image a afficher dans les listes"""
+        return self.logo
+
+    def yReel(self):
+        """renvoie le y reel (pour les contructions graphiques"""
+        if 1 == (self.position[0] % 2):
+             y = self.position[1] + 0.5
+        else:
+             y = self.position[1]
+        return y
+    
+    ###attributs du pion
+    def position(self):
+        """retourne la position actuelle du pion"""
+        return self.position
+
+    def casesOccupees(self):
+        """retourne la liste des cases occupees sur le plateau par le pion (x,y,z)"""
+        retour = []
+        if self.plateau:
+            for x, y in self.forme.listeCases(self.position, self.nbRotations):
+                for z in range(1, self.hauteur):
+                    retour.append((x, y, (self.plateau.cases[(x, y)].altitude + self.z + z)))
+        return retour
+
+    def majZ(self, valeur):
+        """met a jour l'altitude Z du pion"""
+        if valeur != self.z:
+            self.z = valeur    
+
+    def zAbs(self):
+        """retourne la coord z absolue du pion"""
+        return (self.plateau.cases[self.position].altitude + self.z)
+
+    ########### fonctions graphiques et geometriques   ##############
+    def ajouterAuPlateau(self, plateau):
+        """cerre l'objet graphique representant le pion et le place sur le plateau"""
+        self.plateau = plateau
+
+        #definition de la forme (interpretation de formeDef)
+        self.forme = Forme(self.plateau.formeCases)
+        if len(self.formeDef[self.plateau.formeCases]) > 0:
+            self.forme.definirForme(self.formeDef[self.plateau.formeCases])        
+
+        #creation du polygone
+        polygone = self.plateau.polygoneAgglo(self.forme.listeCases((0,0)))
+        self.polygoneGraphique = QGraphicsPolygonItem()
+        self.polygoneGraphique.setPolygon(polygone)
+        self.polygoneGraphique.setAcceptHoverEvents(True)
+        self.polygoneGraphique.setFlag(QGraphicsItem.ItemIsFocusable)   #l'item peut recevoir des commandes souris/clavier
+        self.polygoneGraphique.setParentItem(self)
+        self.polygoneGraphique.setPos(QPointF(0,0))
+        if self.plateau.formeCases == "H":
+            self.polygoneGraphique.setTransformOriginPoint(QPointF(2*0.2886*self.plateau.hCase, 0.5*self.plateau.hCase))
+        else:
+            self.polygoneGraphique.setTransformOriginPoint(QPointF(0.5*self.plateau.hCase,0.5*self.plateau.hCase))
+
+        #parametres de l'objet graphique
+        self.setZValue(10)
+        self.setFlag(QGraphicsItem.ItemHasNoContents)
+        self.setHandlesChildEvents(True)
+         
+        pinceau = QPen()
+        pinceau.setColor(self.couleur.darker(130))
+        pinceau.setWidth(10)
+        self.polygoneGraphique.setPen(pinceau)
+
+        if self.couleur.isValid():
+            self.polygoneGraphique.setBrush(self.couleur)
+        else:
+            self.polygoneGraphique.setBrush(QColor(255, 0, 0, 150))
+
+        self.shadow = QGraphicsDropShadowEffect()
+        self.shadow.setColor(QColor(50, 50, 50)) 
+        self.shadow.setXOffset(1) 
+        self.shadow.setYOffset(2) 
+        self.shadow.setBlurRadius(3)  
+        self.shadow.setEnabled(True)
+        self.polygoneGraphique.setGraphicsEffect(self.shadow)
+        
+        self.polygoneBrillance = QGraphicsPolygonItem()
+        self.polygoneBrillance.setPolygon(self.polygoneGraphique.polygon())
+        self.polygoneBrillance.setVisible(False)
+        self.polygoneGraphique.setFlag(QGraphicsItem.ItemIsFocusable)
+        self.setAcceptHoverEvents(True)   #accepte les evenements survol souris
+        self.polygoneBrillance.setParentItem(self.polygoneGraphique)
+
+        #on ajoute l'objet au plateau
+        self.plateau.addItem(self)
+        self.majPosition(self.position, self.nbRotations)
+
+    def majPosition(self, nouvellePosition, nbRotations = 0):
+        """met a jour la position de l'objet graphique et de sa forme en fonction de sa position enregistree"""
+        if self.plateau:
+            #on met a jour l'occupation des cases
+            if self.position != (-1,-1):
+                for coord in self.forme.listeCases(self.position, self.nbRotations):
+                    for z in range(self.z, (self.z + self.hauteur)):
+                        self.plateau.cases[coord].liberer(z)
+
+            #on met a jour la position du pion        
+            self.position = nouvellePosition
+            self.majNbRotation(nbRotations)
+
+            #on replace
+            if self.plateau.formeCases == "H":
+                angleRotation = 60
+                positionGraphique = QPointF(self.position[0] * 0.866 * self.plateau.hCase, self.yReel() * self.plateau.hCase)
+            else:
+                angleRotation = 90
+                positionGraphique = QPointF(self.position[0] * self.plateau.hCase, self.position[1] * self.plateau.hCase)
+            self.prepareGeometryChange()
+            self.setPos(positionGraphique)
+            self.polygoneGraphique.setRotation(self.nbRotations*angleRotation)
+            
+            #maj de l'image
+            self.majImage()
+            
+            #on met a jour l'occupation des cases
+            for coord in self.forme.listeCases(self.position, self.nbRotations):
+                for z in range(self.z, (self.z + self.hauteur)):
+                    self.plateau.cases[coord].occuper(self.numero, z)
+                    
+                 
+    def majImage(self):
+        """met a jour la taille, la position et l'orientation de l'image"""
+        if self.img.rimage.estValide():
+            pix = self.img.rimage.pix()
+            if not pix.isNull():
+                if not self.pixGraphique:
+                    self.pixGraphique = QGraphicsPixmapItem()
+                    self.pixGraphique.setZValue(10) 
+                    if pix.height() >= pix.width():
+                        pix = pix.scaledToHeight(self.plateau.hCase*0.9, Qt.SmoothTransformation)
+                    else:
+                        pix = pix.scaledToWidth(self.plateau.hCase*0.9, Qt.SmoothTransformation)
+                    self._l0 = pix.width()
+                    self._h0 = pix.height()
+                    pix = pix.scaled((self.img.kx/10)*pix.width(), \
+                                     (self.img.ky/10)*pix.height(), \
+                                      Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
+                    self.pixGraphique.setPixmap(pix)
+
+##                deltaX = self.img.dx + 0.5*(self.plateau.hCase*1.1544 - self._l0)
+##                deltaY = self.img.dy + 0.5*(self.plateau.hCase - self._h0)
+                deltaX = self.img.dx + 0.5*(self.plateau.hCase*1.1544 - self.pixGraphique.pixmap().width())
+                deltaY = self.img.dy + 0.5*(self.plateau.hCase - self.pixGraphique.pixmap().height())
+                    
+                if self.img.rimage.nom() == self.logo.nom():
+                    #si l'image est le logo, elle ne doit pas pivoter
+                    self.pixGraphique.setParentItem(self)
+                else:
+                    self.pixGraphique.setParentItem(self.polygoneGraphique)
+                self.pixGraphique.setRotation(self.img.rotation)
+                self.pixGraphique.setPos(QPointF(deltaX, deltaY))
+
+    def majEtiquette(self):
+        """met a jour la taille, le format et l'orientation de l'etiquette"""
+        self.etiquetteGraphique = QGraphicsSimpleTextItem("{}".format(self.txtId()))
+        self.etiquetteGraphique.setPos(QPointF(self.etiquette.dx - 0.112*self.plateau.hCase, \
+                                                self.etiquette.dy - 0.5*self.plateau.hCase))
+        police = QFont("Verdana", self.etiquette.taille_police)
+        police.setBold(self.etiquette.gras)
+        self.etiquetteGraphique.setFont(police)
+        self.etiquetteGraphique.setParentItem(self)        
+                
+    def majNbRotation(self, nbRotations):
+        """ajoute/retranche le nombre au nombre total de rotations du pion"""
+        self.nbRotations = nbRotations
+        if self.plateau.formeCases == "H":
+            rotationsTour = 6
+        else:
+            rotationsTour = 4
+            
+        if self.nbRotations >= 0:
+            self.nbRotations = self.nbRotations % rotationsTour
+        else:
+            self.nbRotations = self.nbRotations % (-rotationsTour)
+
+    def retirerDuPlateau(self):
+        """'deconnecte' les items enfants avant de supprimer du pion du plateau"""
+        for coord in self.forme.listeCases(self.position, self.nbRotations):
+            for z in range(self.z, (self.z + self.hauteur)):
+                self.plateau.cases[coord].liberer(z)
+
+        self.polygoneBrillance.prepareGeometryChange()
+        self.polygoneBrillance.setParentItem(None)
+        if self.pixGraphique != None:
+            self.pixGraphique.prepareGeometryChange()
+            self.pixGraphique.setParentItem(None)
+        self.polygoneGraphique.prepareGeometryChange()
+        self.polygoneGraphique.setParentItem(None)
+        if self.etiquetteGraphique:
+            self.etiquetteGraphique.prepareGeometryChange()
+            self.etiquetteGraphique.setParentItem(None)
+        self.plateau.removeItem(self)
+        self.plateau = None
+
+    ###effets graphiques 
+    def afficheOmbreSelection(self, actif = False):
+        """modifie l'ombre du pion en fonction de si celui-ci est selectionne ou non"""
+        if actif:
+            self.shadow.setXOffset(3) 
+            self.shadow.setYOffset(3)
+        else:
+            self.shadow.setXOffset(1) 
+            self.shadow.setYOffset(2)
+            
+    def surbrillance(self, active, opacite = 0.7, couleur = "white"):
+        """active/desactive la surbrillance"""
+        if active:
+            self.polygoneBrillance.setOpacity(opacite)
+            couleur = self.couleurSurbrillance(couleur)
+            pinceau = self.polygoneGraphique.pen()
+            self.polygoneBrillance.setBrush(couleur)
+            self.polygoneBrillance.setPen(pinceau)
+        self.polygoneBrillance.setVisible(active)
+        
+    def estCibleAttaque(self, estCible, possible = True):
+        """le pion s'affiche comme etant cible d'une attaque"""
+        if not possible:
+            couleur = "red"
+        else:
+            couleur = "white"
+        self.surbrillance(estCible, 0.8, couleur)
+        
+    def couleurSurbrillance(self, couleur = "white"):
+        """renvoie une QColor visible pour la surbrillance, selon la couleur du pion"""
+        retour = QColor(couleur)
+        if self.polygoneGraphique.brush().color().lightness() > 220:
+            retour = retour.darker(140)
+        elif self.polygoneGraphique.brush().color().lightness() < 80:
+            retour = retour.lighter(140)
+        return retour
+
+    ##################
+
+    ###############   evenements clavier et souris    ##############
+    def boundingRect(self):
+        return QRectF()
+        
+     #######################
+
+class ImgPion():
+    def __init__(self):
+        self.rimage = RImage("")        #ressource: image
+        self.kx = 10                 #coeff d'agrandissement horizontal
+        self.ky = 10                 #coeff d'agrandissement vertical
+        self.dx = 0                 #decalage horizontal
+        self.dy = 0                 #decalage vertical
+        self.rotation = 0           #rotation(en degres)
+        self.pivote = False         #l'image pivote avec le pion?
+        self.masqueAuto = False     #creer un masque automatiquement
+        
+class EtiquettePion():
+    def __init__(self):
+        self.txt = ""
+        self.taille_police = 28     #taille de la police
+        self.gras = False           #en gras
+        self.dx = 0                 #decalage horizontal
+        self.dy = 0                 #decalage vertical
+

+ 1542 - 1528
lib/Plateau.py

@@ -1,1528 +1,1542 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-from __future__ import division
-
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-
-##from ui.ecran_editionAttaques import Ui_editionAttaques
-
-import Modes
-import Actions
-from Case import Case
-from Combattant import Combattant
-from Decor import Decor
-from Pinceau import Pinceau
-from ProjectionDep import ProjectionDep
-from Cache import Cache
-from Terrain import Terrain
-
-from EcranEditionCombattant import EcranEditionCombattant
-from EcranEditionDecor import EcranEditionDecor
-from EcranEditionTerrain import EcranEditionTerrain
-from EcranAffichageTexte import EcranAffichageTexte
-from EcranGestionCombat import EcranGestionCombat
-from EcranSelectionPj import EcranSelectionPj
-from EcranVol import EcranVol
-
-import regles as regles
-from outilsSvg import *
-import br
-
-from math import sqrt
-
-m_couleursRapides = [(255,255,255), (200,200,200), (130,130,130), (90,90,90), (15,15,15), \
-                   (0,85,0), (170,255,0), (170,255,127), (85,85,0), (85,0,0), (170,85,0), (100,50,0), \
-                   (255,255,127), (240,80,0), (85,170,255), (85,85,255), (85,0,255), (0,255,255)]
-        
-class Plateau(QGraphicsScene):
-    """plateau de jeu contenant les cases, decors et pions"""
-    def __init__(self, fenetre, parent=None):
-        super(Plateau, self).__init__()
-        #parametres et variables
-
-        self.fenetre = fenetre
-
-        ##partie et infos plateau
-        self.id = ""
-        self.nom = ""
-        self.chapitre = 0
-        self.tour = 1
-        
-        self.enCours = False
-        self.public = False
-        self.dateCreation = ""
-        self.dateSvg = ""
-        self.notes = ""
-        
-        #carac 
-        self.nbCasesX = 0
-        self.nbCasesY = 0
-        self.hCase = 0
-
-        #objets
-        self.pinceau = Pinceau(self)
-        self.cases = {}   #dict des cases du plateau   (coordonnées: case)
-        self.combattants = {}   #liste de combattants positionnes sur le plateau
-        self.decors = {}  #liste des decors places sur le plateau
-        self.caches = {}
-        self.listeCasesZonePlacement = []
-        self.polygoneZonePlacement = None
-        self.entreesSorties = []
-
-        #infos combat
-        self.numCombattantEnCours = 0
-        self.ordreJeu = {}  #numero du pion: ordre de jeu
-            
-        #note: la hauteur Z (qui gere l'empilement des objets graphiques est distribuee de cette maniere:
-        #cases : 0 a 9
-        #pions : 10 et +
-        
-    def __getstate__(self):
-        self.dateSvg = time()
-        state = {key:value for key, value in self.__dict__.items() if not key in ["fenetre", "modeActif", \
-                                                                                  "editionTerrain", "editionCreature", "editionDecor", \
-                                                                                  "polygoneZonePlacement", "gestionCombat", \
-                                                                                  "editionAttaques", "pinceau"]}
-        return (state)
-
-    def __setstate__(self, state):
-        self.__dict__ = state
-
-    def vue(self):
-        return self.fenetre.ui.cbt_vue
-
-    def creer(self, idPlateau, nom, chapitre, formeCases, nbCasesX, nbCasesY, couleur = QColor(0, 255, 0, 80)):
-        """cree le plateau"""
-        self.id = idPlateau
-        self.nom = nom
-        self.chapitre = chapitre
-        self.dateCreation = time()
-        self.hCase = 120  #hauteur d'une case
-        self.nbCasesX = nbCasesX   #nb cases en x
-        self.nbCasesY = nbCasesY   #nb cases en y
-        self.formeCases = formeCases
-        self.modeActif = Modes.ModeBase(self)
-        self.gestionCombat = None
-        self.initialisationGraphique()
-        self.connexions()
-        
-        #cree les cases hexagonales
-        for x in range(nbCasesX):
-            for y in range(nbCasesY):
-                c = Case(self)
-                c.creer(x, y, couleur)
-                self.cases[(x,y)] = c
-
-        self.plateauModeCreation()
-
-    def recreer(self, fenetre):
-        self.fenetre = fenetre
-        self.gestionCombat = None
-        super(Plateau, self).__init__()
-        self.modeActif = Modes.ModeBase(self)
-        self.connexions()
-        self.initialisationGraphique() 
-
-        #recreation des cases 
-        for coord in self.cases:
-            self.cases[coord].recreer(self)
-
-        #recreation des caches
-        self.initListeCaches()
-
-        #recreation des pions
-        for numCombattant in self.combattants:
-            self.combattants[numCombattant].ajouterAuPlateau(self)
-        self.majOrdreJeu()    
-
-        #recreation des decors
-        for num in self.decors:
-            self.decors[num].ajouterAuPlateau(self)
-
-        #recreation des marqueurs entree/sortie
-        for entreeSortie in self.entreesSorties:
-            entreeSortie.recreer(self)
-
-        #recreation de la zone de placement: 
-        if len(self.listeCasesZonePlacement) > 0:
-            self.polygoneZonePlacement = None
-            self.majZonePlacement(self.listeCasesZonePlacement)
-
-        self.plateauModeCombat()
-
-    def fermer(self):
-        """ferme le plateau 'proprement'"""
-        self.miniature()
-        self.pinceau = None
-        for item in self.items():
-            item.prepareGeometryChange()
-            self.removeItem(item)
-        if self.gestionCombat != None:    
-            del self.gestionCombat           
-        self.fenetre.reinitialiserPanneauxPlateau()
-
-    def miniature(self):
-        """renvoie une miniature du plateau (QPixMap compresse) qui sera enregistree avec les infos de la sauvegarde"""
-##        img = QImage(128, 128, QImage.Format_ARGB32_Premultiplied)
-        img = QPixmap(1024, 768)
-        img.fill(QColor("white"))
-        peintre = QPainter(img)
-        self.render(peintre)
-        peintre.end()
-        img.scaledToHeight(128, Qt.FastTransformation)
-        
-    def connexions(self):
-        """connecte le plateau aux differents widgets de la fenetre principale"""
-        #modes d'interaction
-        self.fenetre.connect(self.fenetre.ui.cbt_modeCreation, SIGNAL("clicked()"), self.plateauModeCreation, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cbt_modeCombat, SIGNAL("clicked()"), self.plateauModeCombat, Qt.UniqueConnection)
-##        self.fenetre.connect(self.fenetre.ui.modeAffichagePlateau, SIGNAL("currentIndexChanged(int)"), self.majModeAffichage, Qt.UniqueConnection)
-
-
-        #affichage de fenetres
-        self.fenetre.connect(self.fenetre.ui.cbt_afficherGestion, SIGNAL("clicked()"), self.afficheEcranGestionCombat, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cbt_ajouterPj, SIGNAL("clicked()"), self.ajouterPj, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee, Qt.UniqueConnection)
-
-        self.fenetre.connect(self.fenetre.ui.cp_dialogueCouleurs, SIGNAL("clicked()"), self.modePeintureCase, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_pipetteCouleur, SIGNAL("clicked()"), self.modeCopieTerrain, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_afficherNotes, SIGNAL("clicked()"), self.agrandirNotesMjPlateau, Qt.UniqueConnection)
-        
-
-        #listes
-        self.fenetre.connect(self.fenetre.ui.inf_listeOrdreJeu, SIGNAL("cellClicked(int,int)"), self.clicListOrdreJeu, Qt.UniqueConnection)
-        
-        self.fenetre.connect(self.fenetre.ui.cp_listeTerrains, SIGNAL("cellClicked(int,int)"), self.modeMajTerrainCase, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_listeCreatures, SIGNAL("cellClicked(int,int)"), self.modeCreationCombattant, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_listeDecors, SIGNAL("cellClicked(int,int)"), self.modeCreationDecor, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_listeCaches, SIGNAL("cellClicked(int,int)"), self.mettreCacheEnEvidence, Qt.UniqueConnection)
-#         self.fenetre.connect(self.fenetre.ui.cp_listeCaches, SIGNAL("cellChanged(int,int)"), self.majNomCache, Qt.UniqueConnection)
-        
-        self.fenetre.connect(self.fenetre.ui.cp_editerTerrain, SIGNAL("clicked()"), self.terrainEdit, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_nouveauTerrain, SIGNAL("clicked()"), self.terrainNouveau, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_editerCombattant, SIGNAL("clicked()"), self.creatureEdit, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_nouveauCombattant, SIGNAL("clicked()"), self.creatureNouveau, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_gommeCombattant, SIGNAL("clicked()"), self.majModeSupprimerCombattant, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_editerDecor, SIGNAL("clicked()"), self.decorEdit, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_nouveauDecor, SIGNAL("clicked()"), self.decorNouveau, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_gommeDecor, SIGNAL("clicked()"), self.majModeSupprimerDecor, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_editerCache, SIGNAL("clicked()"), self.activerModeEditionCache, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_nouveauCache, SIGNAL("clicked()"), self.activerModeCreationCache, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_supprimerCache, SIGNAL("clicked()"), self.supprimerCache, Qt.UniqueConnection)
-
-        #creation
-        self.fenetre.connect(self.fenetre.ui.cp_epaisseurPinceau, SIGNAL("valueChanged(int)"), self.majEpaisseurPinceau, Qt.UniqueConnection)
-##        self.fenetre.connect(self.fenetre.ui.altitudeCase, SIGNAL("valueChanged(double)"), self.modeMajAltitudeCase, Qt.UniqueConnection)
-
-        #autres:
-        #ajouter effet
-        self.fenetre.connect(self.fenetre.ui.cp_placerEntree, SIGNAL("clicked()"), self.majModeDefinirEntree, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_placerSortie, SIGNAL("clicked()"), self.majModeDefinirSortie, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_defPlacement, SIGNAL("clicked()"), self.majModeZonePlacement, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.pi_notes, SIGNAL("textChanged()"), self.majNotesCombattant, Qt.UniqueConnection)
-
-        #formes (dessin)
-        self.fenetre.connect(self.fenetre.ui.cp_formeSimple, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_formeLigne, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_formeLigneOrientee, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_formePot, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_formeRectVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.cp_formeRectPlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
-
-        self.fenetre.connect(self.fenetre.ui.pi_deplacement, SIGNAL("clicked()"), self.majModeCombatDeplacement, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.pi_vol, SIGNAL("clicked()"), self.majModeCombatVol, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.pi_attaqueCac, SIGNAL("clicked()"), self.majModeCombatAttaqueCaC, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.pi_attaqueDist, SIGNAL("clicked()"), self.majModeCombatAttaqueDist, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.pi_attaqueZone, SIGNAL("clicked()"), self.majModeCombatZone, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.pi_formeAttaqueZone, SIGNAL("activated (int)"), self.majModeCombatZone, Qt.UniqueConnection)
-        self.fenetre.connect(self.fenetre.ui.pi_rayonAttaqueZone, SIGNAL("valueChanged(int)"), self.majRayonZone, Qt.UniqueConnection)
-
-        
-        self.fenetre.connect(self.fenetre.ui.pi_finTour, SIGNAL("clicked()"), self.pionSuivant, Qt.UniqueConnection)
-        
-    def initialisationGraphique(self):
-        """cree la scene graphique et les parametres necessaires a son fonctionnement, et met a jour l'interface""" 
-        #on cree la scene graphique
-        kx = 1
-        if self.formeCases == "H":
-            kx = 0.866
-        marge = 240    
-        self.setSceneRect(0 - marge, 0 - marge, (kx*self.hCase*(self.nbCasesX+2)) + marge, (self.hCase*(self.nbCasesY+2)) + marge)
-        self.vue().setScene(self)
-        self.vue().scale(0.25, 0.25)
-        self.vue().centerOn(QPointF(0,0))
-        self.vue().setDragMode(1)
-        self.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
-        
-        self.polygoneZonePlacement = None
-
-        #gestion du mode d'interaction avec le plateau
-        
-        self.pinceau = Pinceau(self)
-        self.proj = ProjectionDep(self)
-  
-        #mise a jour de l'interface de creation
-        self.fenetre.afficherPanneauxPlateau(True)
-        self.fenetre.ui.cbt_nom.majTexte(self.nom)
-        self.majBoutonsCouleursPerso()
-        self.fenetre.ui.cp_listeTerrains.defFichier("lib\\biblio\\terrain")
-        self.fenetre.ui.cp_listeTerrains.initAffichage()
-        self.fenetre.ui.cp_listeCreatures.defFichier("lib\\biblio\\combattant")
-        self.fenetre.ui.cp_listeCreatures.initAffichage()
-        self.fenetre.ui.cp_listeDecors.defFichier("lib\\biblio\\decor")
-        self.fenetre.ui.cp_listeDecors.initAffichage()
-        self.majListeTerrains()
-        self.majListeCreatures()
-        self.majListeDecors()
-        self.initListeCaches()
-        
-        self.initListeOrdreJeu()
-        self.initListeAttaques()
-
-        self.fenetre.ui.pi_deplacement.setCheckable(True)
-        self.fenetre.ui.pi_attaqueCac.setCheckable(True)
-        self.fenetre.ui.pi_attaqueDist.setCheckable(True)
-        self.fenetre.ui.pi_attaqueZone.setCheckable(True)
-
-        #mise a jour de l'interface d'informations
-        self.majInfosCombattant(None)
-        self.majInfosDecor(None)
-
-    def estCree(self):
-        """renvoie vrai si des cases ont ete creees"""
-        return (len(self.cases) > 0)
-
-    def majBoutonsCouleursPerso(self):
-        """met a jour l'affichage des couleurs customisees dans la boite de dialogue de selection de couleur"""
-        for i in range(0,18):
-            couleur = QColor()
-            r, g, b = m_couleursRapides[i]
-            couleur.setRgb(r, g, b)
-            bouton = self.fenetre.ui.cp_boiteCouleurs.findChild(QToolButton, "cp_couleur{}".format(i+1))
-            if couleur.isValid():
-                bouton.setStyleSheet("QToolButton {backGround:%s}"%(couleur.name()))
-                self.fenetre.connect(bouton, SIGNAL("clicked()"), self.modePeintureCase_perso)
-
-    def chercherCouleur(self):
-        """ouvre la boite de dialogue de selection de couleur"""
-        couleur = QColorDialog(self.vue()).getColor(QColor("white"), self.vue())
-        return couleur
-
-    def majListesPions(self, numCombattant = None):
-        """met a jour les listes contenant des donnees liees aux pions"""
-##        self.majListeOrdreJeu()
-##        
-##        if numCombattant == None or numCombattant == self.pionSelectionne().numero:
-##            self.majListeAttributs()
-##        QApplication.processEvents()
-        pass
-
-    def ajouterPj(self):
-        """affiche la fenetre de selection des pj, et recupere l'eventuel pj selectionne"""
-        self.ecranSelPj = EcranSelectionPj(self.fenetre)
-        self.ecranSelPj.setAttribute(Qt.WA_DeleteOnClose)
-        listePj = chargerUnique("parties\\{}\\groupe".format(self.fenetre.partie))
-        self.ecranSelPj.charger(listePj)
-        r = self.ecranSelPj.exec_()
-        if r == 1:
-            idPj = int(self.ecranSelPj.selection())
-            if idPj != None:
-                pj = listePj[idPj]
-                self.activerMode(Modes.CreationPion, pj)
-        self.ecranSelPj = None
-
-    def agrandirNotesMjPlateau(self):
-        """affiche les notes du plateau dans une QDialog, puis recupere les donnees qui y sont saisies"""
-        affichageTexte = EcranAffichageTexte(self.notes)
-        affichageTexte.setAttribute(Qt.WA_DeleteOnClose)
-        affichageTexte.exec_()
-        self.notes = affichageTexte.recupererTexte()
-        
-    ##### affichage de la liste des terrains enregistres, et fonctions d'acces aux donnees""""     
-    def afficheEcranEditionTerrains(self, terrain = None):
-        """affiche l'ecran d'edition/creation de terrains"""
-        self.editionTerrain = EcranEditionTerrain(terrain)     
-        self.editionTerrain.setAttribute(Qt.WA_DeleteOnClose)
-        r = self.editionTerrain.exec_()
-        if r == 1:
-            self.majListeTerrains()
-            self.activerMode(Modes.StandardCp)
- 
-    def majListeTerrains(self):
-        """mise a jour de la liste des terrains depuis la sauvegarde"""
-        self.fenetre.ui.cp_listeTerrains.maj()
-
-    def terrainEdit(self):
-        """ouvre la fenetre 'terrains' en mode edition"""
-        index = self.fenetre.ui.cp_listeTerrains.item(self.fenetre.ui.cp_listeTerrains.currentRow(), 0)
-        if index > 0:
-            terrain = charger("lib\\biblio\\terrain", str(index.text().toUtf8()))
-            self.afficheEcranEditionTerrains(terrain)
-            self.activerMode(Modes.StandardCp)
-        
-    def terrainNouveau(self):
-        """ouvre la fenetre 'terrains' en mode edition"""
-        self.afficheEcranEditionTerrains()
-        self.activerMode(Modes.StandardCp)
-    ###############
-
-    ##### affichage de la liste des creatures enregistrees, et fonctions d'acces aux donnees""""     
-    def afficheEcranEditionCombattants(self, creature = None):
-        """affiche l'ecran d'edition/creation de creatures"""
-        self.editionCreature = EcranEditionCombattant(creature, 0, self.formeCases)
-        self.editionCreature.setAttribute(Qt.WA_DeleteOnClose)
-        r = self.editionCreature.exec_()
-        if r == 1:
-            combattant = self.editionCreature.combattant
-            enregistrer(combattant.id, combattant, "lib\\biblio\\combattant")
-            self.majListeCreatures()
-            self.activerMode(Modes.StandardCp)
-        self.editionCreature = None
-        
-    def majListeCreatures(self):
-        """mise a jour de la liste des creatures depuis la sauvegarde"""
-        self.fenetre.ui.cp_listeCreatures.maj()
-
-    def creatureEdit(self):
-        """ouvre la fenetre 'creatures' en mode edition"""
-        index = self.fenetre.ui.cp_listeCreatures.item(self.fenetre.ui.cp_listeCreatures.currentRow(), 0)
-        if index > 0:
-            creature = charger("lib\\biblio\\combattant", str(index.text().toUtf8()))
-            self.afficheEcranEditionCombattants(creature)
-            self.activerMode(Modes.StandardCp)
-        
-    def creatureNouveau(self):
-        """ouvre la fenetre 'creatures' en mode edition"""
-        self.afficheEcranEditionCombattants()
-        self.activerMode(Modes.StandardCp)
-        
-    ###############
-
-    ##### affichage de la liste des decors enregistrees, et fonctions d'acces aux donnees""""     
-    def afficheEcranEditionDecors(self, decor = None):
-        """affiche l'ecran d'edition/creation de decors"""
-        self.editionDecor = EcranEditionDecor(decor, 0, self.formeCases)
-        self.editionDecor.setAttribute(Qt.WA_DeleteOnClose)
-        r = self.editionDecor.exec_()
-        if r == 1:
-            decor = self.editionDecor.decor
-            enregistrer(decor.id, decor, "lib\\biblio\\decor")
-            self.majListeDecors()
-            self.activerMode(Modes.StandardCp)
-            
-    def majListeDecors(self):
-        """mise a jour de la liste des decors depuis la sauvegarde"""
-        self.fenetre.ui.cp_listeDecors.maj()
-
-    def decorEdit(self):
-        """ouvre la fenetre 'decors' en mode edition"""
-        self.afficheEcranEditionDecors(self.fenetre.ui.cp_listeDecors.actuel())
-        self.activerMode(Modes.StandardCp)
-        
-    def decorNouveau(self):
-        """ouvre la fenetre 'decors' en mode edition"""
-        self.afficheEcranEditionDecors()
-        self.activerMode(Modes.StandardCp)
-        
-    ###############
-
-    ############### maj des infos du panneau Pi a la selection/deselection d'un pion
-        #voir a balancer tout ca dans une classe a part
-
-    def majPanneauPi(self):
-        
-        if self.pionSelectionne():
-            estCombattant = (self.pionSelectionne().numero < 10000)
-            #affichage
-            self.fenetre.ui.pi_actions.setEnabled(estCombattant)
-            self.fenetre.ui.pi_finTour.setEnabled(estCombattant)
-            self.fenetre.ui.pi_ongletsListes.setTabEnabled(0, estCombattant)
-            self.fenetre.ui.pi_ongletsListes.setTabEnabled(1, estCombattant)
-            
-            ### maj la selection dans la liste d'ordre de jeu
-            if estCombattant:
-                for i in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()):
-                    if str(self.fenetre.ui.inf_listeOrdreJeu.item(i, 0).text().toUtf8()) == str(self.pionSelectionne().numero):
-                        self.fenetre.ui.inf_listeOrdreJeu.setCurrentCell(i,0)
-
-            ### maj des infos dans le panneau pi
-            self.fenetre.ui.pi_nom.majTexte(self.pionSelectionne().txtId())
-            self.fenetre.ui.pi_img.chargerImage(self.pionSelectionne().img.rimage)
-
-            ### maj de la liste des attributs
-            if estCombattant:
-                self.fenetre.ui.pi_listeAttributs.setColumnWidth(0, 50)
-                self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
-            
-                #on vide la liste
-                while self.fenetre.ui.pi_listeAttributs.rowCount() > 0:
-                    self.fenetre.ui.pi_listeAttributs.removeRow(0)
-
-                #creation des lignes de base    
-                lignesBase = ["Nom","Etat","Alt."]   #attention: modifier aussi dans listeAttributCelluleModifiee
-                for i in range(0, 10):    #10 premieres colonnes reservees pour les infos de base
-                    self.fenetre.ui.pi_listeAttributs.insertRow(i)
-                    item = QTableWidgetItem()
-                    if i < len(lignesBase):
-                        item.setText(QString.fromUtf8(lignesBase[i]))
-                    item.setFlags(Qt.NoItemFlags)    
-                    self.fenetre.ui.pi_listeAttributs.setItem(i, 0, item)
-                    self.fenetre.ui.pi_listeAttributs.setRowHidden(i, (i >= len(lignesBase)))
-
-                #maj des donnees de base    
-                self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Nom"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().nom))))
-                self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Etat"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().etat))))
-                self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Alt."), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().z))))
-                
-                #attributs issus des regles utilisees    
-                ordre = regles.ordreAttributs()
-                for elt in ordre:
-                    ligne = 10 + ordre.index(elt)
-                    self.fenetre.ui.pi_listeAttributs.insertRow(ligne)
-                    item = QTableWidgetItem(QString.fromUtf8(elt))
-                    item.setFlags(Qt.NoItemFlags)
-                    self.fenetre.ui.pi_listeAttributs.setItem(ligne, 0, item)
-                    self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[elt]))))
-                    
-                self.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
-            
-            ###affiche les notes du combattant
-            self.fenetre.ui.pi_notes.majTexte(self.pionSelectionne().notes)
-
-            ###maj la liste des attaques du pion
-            if estCombattant:
-                #on vide la liste
-                while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
-                    self.fenetre.ui.pi_listeAttaques.removeRow(0)
-                    
-                i = 0
-                for attaque in self.pionSelectionne().attaques:
-                    self.fenetre.ui.pi_listeAttaques.insertRow(i)
-                    self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque)))))
-                    icone = None
-                    if attaque.typ == "cac":
-                        icone = QIcon(":/interface/16/ressource/epee_16.png")
-                    if attaque.typ == "dist":
-                        icone = QIcon(":/interface/16/ressource/arc_16.png")
-                    if attaque.typ == "zone":
-                        icone = QIcon(":/interface/16/ressource/baguette_16.png")
-                    if icone != None:
-                        self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8("")))
-                    self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom)))  
-
-        else:
-            #maj des infos dans le panneau pi
-            self.fenetre.ui.pi_img.clear()  
-            self.fenetre.ui.pi_nom.majTexte("Pas de pion\nselectionné")
-
-            #vide la liste des attributs
-            self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
-            while self.fenetre.ui.pi_listeAttributs.rowCount() > 0:
-                self.fenetre.ui.pi_listeAttributs.removeRow(0)        
-
-            #vide la liste des attaques du pion
-            while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
-                self.fenetre.ui.pi_listeAttaques.removeRow(0)
-                
-        self.majInfosAttaqueEC()
-
-    ##### activation des differents modes d'interaction avec le plateau et mises a jour des principaux parametres  #######
-    def plateauModeCreation(self):
-        self.activerMode(Modes.StandardCp)
-
-    def plateauModeCombat(self):
-        self.activerMode(Modes.StandardPi)
-
-    def activerMode(self, mode, param = None):
-        """desactive le mode actif et active le nouveau a la place"""
-        self.modeActif.desactiver()
-        self.modeActif = mode(self)
-        self.modeActif.activer(param)
-        
-##    def majModeAffichage(self, index):
-##        """met a jour le mode d'affichage"""
-##        nouveauMode = ""
-##        if index == 0:
-##            #passe a l'affichage standard
-##            pass
-##        elif index == 1:
-##            #passe en mode affichage de l'altitude
-##            nouveauMode = "altitude"    
-##        elif index == 2:
-##            #affichage des terrains slt
-##            nouveauMode = "terrain"
-##        elif index == 3:
-##            #affichage tactique
-##            nouveauMode = "tactique"
-##            
-##        for coord in self.cases:
-##            self.cases[coord].majAffichageSpecial(nouveauMode)
-
-    def modePeintureCase(self):
-        """enclenche le mode peinture de case a partir de la couleur selectionnee"""
-        couleur = self.chercherCouleur()
-        if couleur.isValid():
-            terrain = Terrain()
-            terrain.couleur = couleur
-            self.activerMode(Modes.MajCases, terrain)
-        else:
-            self.activerMode(Modes.StandardCp)
-
-    def modePeintureCase_perso(self):
-        origine = self.sender().objectName()
-        index = int(origine.replace("cp_couleur",""))-1
-        couleur = QColor()
-        r, g, b = m_couleursRapides[index]
-        couleur.setRgb(r, g, b)
-        if couleur.isValid():
-            terrain = Terrain()
-            terrain.couleur = couleur
-            self.activerMode(Modes.MajCases, terrain)
-        else:
-            self.activerMode(Modes.StandardCp)            
-
-    def modeCopieTerrain(self):
-        """enclenche le mode copie de case"""
-        self.activerMode(Modes.Pipette)
-
-    def modeCaseEffet(self, index):
-        """enclenche le mode de mise a jour de l'effet actif des cases"""
-        effets = ["brule", "eau", "glace", "poison", "aucun"]
-        self.activerMode(Modes.MajCasesEffet, effets[index])
-
-    def modeCreationPion(self):
-        """enclenche le mode de creation de pions simples"""
-        self.majMode("pionCreation")
-
-    def majModeSupprimerDecor(self):
-        """enclenche le mode suppression de pions sur clic gauche (creatures ou decors)"""
-        self.activerMode(Modes.SuppressionPion, Decor)
-
-    def majModeSupprimerCombattant(self):
-        """enclenche le mode suppression de pions sur clic gauche (creatures ou decors)"""
-        self.activerMode(Modes.SuppressionPion, Combattant)
-    
-    def modeCreationDecor(self, ligne, col):
-        """enclenche le mode de creation de decors depuis la liste des decors"""
-        index = self.fenetre.ui.cp_listeDecors.item(ligne, 0)
-        decor = charger("lib\\biblio\\decor", str(index.text().toUtf8()))
-        self.activerMode(Modes.CreationPion, decor)
-        
-    def modeCreationCombattant(self, ligne, col):
-        """enclenche le mode de creation de pions depuis la liste des creatures"""
-        index = self.fenetre.ui.cp_listeCreatures.item(ligne, 0)
-        creature = charger("lib\\biblio\\combattant", str(index.text().toUtf8()))
-        self.activerMode(Modes.CreationPion, creature)
-
-    def modeMajTerrainCase(self, ligne, col):
-        """enclenche le mode permettant la mise a jour du terrain des cases"""
-        index = self.fenetre.ui.cp_listeTerrains.item(ligne, 0)
-        terrain = charger("lib\\biblio\\terrain", str(index.text().toUtf8()))
-        if terrain:
-            self.activerMode(Modes.MajCases, terrain)
-        else:
-            print "terrain invalide"
-
-    def majEpaisseurPinceau(self, epaisseur):
-        """met a jour l'epaisseur du pinceau (en cases)"""
-        self.fenetre.ui.cp_valeurEpaisseurPinceau.majTexte(str(epaisseur))
-        self.pinceau.majEpaisseur(int(epaisseur))
-
-    def modeMajAltitudeCase(self):
-        self.majMode("caseMajAltitude")
-
-    def majModeForme(self):
-        """met a jour la forme utilisee pour la peinture"""
-        formes = {"cp_formeSimple": "simple", \
-                  "cp_formeLigne": "ligne", \
-                  "cp_formeLigneOrientee": "frontiere", \
-                  "cp_formePot": "pot", \
-                  "cp_formeEllipseVide": "ellipseV", \
-                  "cp_formeEllipsePlein": "ellipseP", \
-                  "cp_formeRectVide": "rectV", \
-                  "cp_formeRectPlein": "rectP"}
-        self.pinceau.majForme(formes[str(self.sender().objectName())])
-
-    def majModeCombatDeplacement(self):
-        """active le mode de combat 'deplacement' (mode standard)"""
-        self.modeActif.nouvelleAction(Actions.Deplacement)
-
-    def majModeCombatVol(self):
-        """active le mode de combat 'vol'"""
-        self.modeActif.nouvelleAction(Actions.Vol)
-
-    def majModeCombatAttaqueCaC(self):
-        """active le mode de combat 'corps-a-corps'"""
-        self.modeActif.nouvelleAction(Actions.Cac)
-
-    def majModeCombatAttaqueDist(self):
-        """active le mode de combat 'attaque a distance'"""
-        self.modeActif.nouvelleAction(Actions.Distance)
-
-    def majModeCombatZone(self):
-        if self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 0:
-            action = Actions.Ligne
-        elif self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 1:
-            action = Actions.Disque
-        elif self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 2:
-            action = Actions.Cone
-        if action:    
-            self.modeActif.nouvelleAction(action)      
-
-    def majRayonZone(self, val):
-        action = self.modeActif.action()
-        if action:
-            action.majRayon(val) 
-
-    def majModeDefinirEntree(self):
-        self.activerMode(Modes.CreationEntreeSortie, "E")
-
-    def majModeDefinirSortie(self):
-        self.activerMode(Modes.CreationEntreeSortie, "S")
-
-    def majModeZonePlacement(self):
-        self.activerMode(Modes.ZonePlacement)
-    
-
-    ###############
-
-    ########## Gestion du combat ##############
-    def majAffichageTour(self):
-        """met a jour l'affichage du tour en cours"""
-        self.fenetre.ui.cbt_tour.majTexte("Tour: {}".format(self.tour))
-
-    def initListeOrdreJeu(self):
-        """cree les colonnes et met en forme la table ordre jeu"""
-        self.fenetre.ui.inf_listeOrdreJeu.setColumnWidth(2, 30)
-        self.fenetre.ui.inf_listeOrdreJeu.hideColumn(0)
-        self.fenetre.ui.inf_listeOrdreJeu.hideColumn(2)      
-        self.fenetre.ui.inf_listeOrdreJeu.setIconSize(QSize(30,20))   
-            
-    def majListeOrdreJeu(self):
-        """met a jour la liste des pions infoOrdreJeu"""
-        while self.fenetre.ui.inf_listeOrdreJeu.rowCount() > 0:
-            self.fenetre.ui.inf_listeOrdreJeu.removeRow(0)
-        index = 0
-        for num in self.ordreJeu:
-            self.fenetre.ui.inf_listeOrdreJeu.insertRow(int(index))
-            self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 0, QTableWidgetItem(QString.fromUtf8(str(num))))
-            icon = QIcon(self.combattants[num].logo.chemin())
-            item = QTableWidgetItem(icon, QString.fromUtf8(self.combattants[num].txtId()))
-            self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 1, item)
-            self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 2, QTableWidgetItem(QString.fromUtf8(str(self.ordreJeu[num]))))
-            index += 1
-
-        self.fenetre.ui.inf_listeOrdreJeu.sizeHintForColumn(1)
-##        trierTable(self.fenetre.ui.infoOrdreJeu, 2, 0)
-
-    def clicListOrdreJeu(self, ligne, col):
-        """on a clique dans la liste d'ordre de jeu, le pion correspondant est selectionne et centre sur la carte"""
-        numCombattant = int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8())  
-        self.vue().centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique)
-        self.modeActif.clic_combattant(numCombattant)
-
-    def pionSuivant(self):
-        """selection du pion suivant dans la liste d'ordre de jeu"""
-        if self.numPionEnCours in self.combattants:
-            suivant = self.ordreJeu[self.numPionEnCours] + 1
-        else:
-            suivant = 1
-        if suivant > len(self.ordreJeu):
-            self.tour += 1
-            self.majAffichageTour()
-            suivant = 1
-        for num in self.ordreJeu:
-            if self.ordreJeu[num] == suivant:
-                numCombattant = num
-                break
-
-        for ligne in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()):
-            item = self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0)
-            item.setSelected(int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8()) == numCombattant)
-            if int(item.text().toUtf8()) == numCombattant:
-                self.fenetre.ui.inf_listeOrdreJeu.scrollToItem(item)
-
-        self.vue().centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique)
-        self.pionSaisir(numCombattant)        
- 
-    def afficheEcranGestionCombat(self):
-        """affiche l'ecran de gestion du combat"""
-        self.gestionCombat = EcranGestionCombat(self)
-        self.gestionCombat.show()
-        self.connect(self.fenetre, SIGNAL("majListesPions"), self.majListesPions)
-        self.connect(self.gestionCombat, SIGNAL("majListesPions"), self.majListesPions)
-        QApplication.processEvents()
-##        r = self.gestionCombat.exec_()
-
-    def majOrdreJeu(self):
-        """met a jour l'ordre de jeu des pions en fonction de l'attribut prevu par les regles s'il existe,
-           ou en fonction de l'ordre de jeu parametre sinon"""
-        attribut = regles.attributOrdreJeu()
-        if attribut != None:
-            dico = {}
-            for numCombattant in self.combattants:
-                dico[numCombattant] = int(self.combattants[numCombattant].listeAttributs[attribut])
-            ordre = sorted(dico, key = dico.get, reverse=(regles.sensTriOrdreJeu() == 1)) 
-            self.ordreJeu = {}    
-            for numCombattant in self.combattants:
-                self.ordreJeu[numCombattant] = ordre.index(numCombattant) + 1
-        self.majListeOrdreJeu()  
-
-    def pionDeplacerDansOrdreJeu(self, numCombattant, nouvellePosition):
-        """deplace un pion dans le dictionnaire gerant l'ordre de jeu de maniere a assurer sa coherence
-           nouvellePosition = 0 supprime le pion de la liste"""
-        if numCombattant in self.ordreJeu:
-            if nouvellePosition == 0:
-                del self.ordreJeu[numCombattant]
-        if len(self.ordreJeu) > 0:        
-            i = 0    
-            tmp = sorted(self.ordreJeu, key=self.ordreJeu.get)
-            if numCombattant in tmp:
-                tmp.remove(numCombattant)
-            for num in tmp:
-                i += 1
-                if i == nouvellePosition:
-                    self.ordreJeu[numCombattant] = i
-                    i += 1
-                self.ordreJeu[num] = i
-            if i < nouvellePosition:
-                self.ordreJeu[numCombattant] = i + 1 
-        elif nouvellePosition > 0:
-            self.ordreJeu[numCombattant] = 1
-        self.majOrdreJeu()
-        
-
-    def listeAttributCelluleModifiee(self, ligne, colonne):
-        """une cellule de la liste des attributs a ete modifiee"""
-        if colonne != 1:
-            print("valeur non modifiable")
-        else:
-            #on verifie la validite de la donnee entree
-            lignesBase = ["Nom","Etat","Alt."]   #attention: modifier aussi dans majListeAttribut
-            if ligne < len(lignesBase):
-                pass
-            elif ligne >= 10:
-                attribut = regles.ordreAttributs()[(ligne - 10)]
-                nouvelleVal = str(self.fenetre.ui.pi_listeAttributs.item(ligne, 1).text().toUtf8())
-                valVerifiee = regles.listeControle()[attribut].controler(nouvelleVal)
-                if valVerifiee != None:
-                    self.pionSelectionne().listeAttributs[attribut] = valVerifiee
-                    if attribut == regles.attributOrdreJeu():
-                        print("maj ordre (a implementer)")
-                else:    
-                    self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[attribut]))))
-
-    def initListeAttaques(self):
-        """met en forme et connecte la liste des attaques du pion"""
-        self.fenetre.ui.pi_listeAttaques.setColumnWidth(0, 0) 
-        self.fenetre.ui.pi_listeAttaques.setColumnWidth(1, (0.3*self.fenetre.ui.pi_listeAttaques.width()))
-        self.fenetre.ui.pi_listeAttaques.setColumnWidth(2, (0.7*self.fenetre.ui.pi_listeAttaques.width()))
-        self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("itemSelectionChanged()"), self.majInfosAttaqueEC)
-        self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("cellClicked(int, int)"), self.listeAttaquesCelluleCliquee)
-        self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
-        self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(0, (0.49*self.fenetre.ui.pi_listeAttributsAttaqueEC.width())) 
-        self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(1, (0.5*self.fenetre.ui.pi_listeAttributsAttaqueEC.width()))
-        
-    def majListeAttaques(self):
-        """met a jour la liste des attaques du pion dans le panneau de combat"""
-        #on vide la liste
-        while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
-            self.fenetre.ui.pi_listeAttaques.removeRow(0)
-            
-        self.fenetre.ui.pi_listeAttaques.setVisible((self.pionSelectionne() != None))
-##        self.fenetre.ui.editerAttaques.setVisible((self.pionSelectionne() != None))
-        self.fenetre.ui.pi_panneauAttaqueEC.setVisible((self.pionSelectionne() != None))
-
-        i = 0
-        if self.pionSelectionne() != None:        
-            for attaque in self.pionSelectionne().attaques:
-                self.fenetre.ui.pi_listeAttaques.insertRow(i)
-                self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque)))))
-                icone = None
-                if attaque.typ == "cac":
-                    icone = QIcon(":/interface/16/ressource/epee_16.png")
-                if attaque.typ == "dist":
-                    icone = QIcon(":/interface/16/ressource/arc_16.png")
-                if attaque.typ == "zone":
-                    icone = QIcon(":/interface/16/ressource/baguette_16.png")
-                if icone != None:
-                    self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8("")))
-                self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom)))
-        self.majInfosAttaqueEC()                                                 
-
-    def listeAttaquesCelluleCliquee(self, ligne, colonne):
-        """on a clique sur une cellule de la liste des attaques"""
-        numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
-        if numAttaque >= 0:
-            self.utiliserAttaque(numAttaque)  
-
-    def utiliserAttaque(self, numAttaque):
-        """le pion selectionne utilise son attaque n"""
-        if self.pionSelectionne() != None:
-            if numAttaque < len(self.pionSelectionne().attaques):
-                attaque = self.pionSelectionne().attaques[numAttaque]
-                if attaque.typ == "cac":
-                    self.majModeCombat("combatAttaqueCaC")
-                if attaque.typ == "dist":
-                    self.majModeCombat("combatAttaqueDist")                
-                if attaque.typ == "zone":
-                    self.modeParam["typeAttaqueZone"] = attaque.formeZone
-                    self.fenetre.ui.pi_rayonAttaqueZone.setValue(attaque.rayon)
-                    self.majModeCombat("combatAttaqueZone")
-
-    def majInfosAttaqueEC(self):
-        """met a jour les infos de l'attaque en cours (selectionnee)"""
-        selection = self.fenetre.ui.pi_listeAttaques.selectedItems()
-        self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0)
-        
-        if self.pionSelectionne() != None and len(selection) > 0:
-            ligne = selection[0].row()
-            numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
-            self.disconnect(self.fenetre.ui.pi_panneauAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee)
-            #on vide la liste
-            while self.fenetre.ui.pi_listeAttributsAttaqueEC.rowCount() > 0:
-                self.fenetre.ui.pi_listeAttributsAttaqueEC.removeRow(0)
-                
-            self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(0)
-            self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 0, QTableWidgetItem(QString.fromUtf8("numAtt")))
-            self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 1, QTableWidgetItem(QString.fromUtf8(str(numAttaque))))
-            self.fenetre.ui.pi_listeAttributsAttaqueEC.setRowHidden(0, True)
-            
-            #attributs issus des regles utilisees    
-            ordre = regles.ordreAttributsAttaques()
-            for elt in ordre:
-                ligne = 1 + ordre.index(elt)
-                self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(ligne)
-                item = QTableWidgetItem(QString.fromUtf8(elt))
-                item.setFlags(Qt.NoItemFlags)
-                self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 0, item)
-                self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques[numAttaque].attributs[elt]))))
-                
-            self.connect(self.fenetre.ui.pi_listeAttributsAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee)
-            #maj des notes
-            self.disconnect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
-            self.fenetre.ui.pi_notesAttaqueEC.majTexte(self.pionSelectionne().attaques[numAttaque].notes)
-            self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
-            
-    def attaqueECCelluleModifiee(self, ligne, colonne):
-        """une cellule de la liste d'attributs de l'attaque en cours a ete modifiee"""
-        pass
-
-    def majNotesAttaqueEC(self):
-        """met a jour les notes de l'attaque en cours (selectionnee)"""
-        selection = self.fenetre.ui.pi_listeAttaques.selectedItems()
-        self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0)
-        if self.pionSelectionne() != None and len(selection) > 0:
-            ligne = selection[0].row()
-            numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))        
-            self.pionSelectionne().attaques[numAttaque].notes = str(self.fenetre.ui.pi_notesAttaqueEC.toPlainText().toUtf8())
-
-    def majNotesCombattant(self):
-        """les notes du pion ont ete mises a jour"""
-        if self.pionSelectionne() != None:
-            self.pionSelectionne().notes = str(self.fenetre.ui.pi_notes.toPlainText().toUtf8())
-        else:
-            pass
-            
-    ###############
-
-    ### panneau d'info
-    def majInfosCombattant(self, combattant=None):
-        self.fenetre.ui.inf_boitePion.maj(combattant)
-
-    def majInfosDecor(self, decor=None):
-        self.fenetre.ui.inf_boiteDecor.maj(decor)
-
-    def majInfosCase(self, case=None):
-        self.fenetre.ui.inf_boiteCase.maj(case)        
-
-    ############### fonctions de calcul ################ 
-    def coordonneesValides(self, coord):
-        """les coordonnees entrees en parametre sont elles celles d'une case du plateau"""
-        return (coord[0] >= 0 and coord[1] >= 0 and coord[0] < self.nbCasesX and coord[1] < self.nbCasesY)
-
-    def lstCoordAdjacentes(self, x, y):
-        """renvoie la liste des coordonnees adjacentes, !!!! sans condition d'existence sur le plateau !!!!
-           attention: l'ordre est important"""
-        if self.formeCases == "H":
-            if 1 == (x % 2):
-                voisins = [(x, y-1), (x+1, y), (x+1, y+1), (x,  y+1), (x-1, y+1), (x-1, y)]
-            else:
-                voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
-        else:
-            voisins = [(x, y-1), (x+1, y), (x,   y+1), (x-1, y)]
-        return voisins      
-
-    def zone(self, origine, rayon, z=0, conditionFranchissable = False, conditionVisible = False):
-        """renvoie un dictionnaire representant la liste des coordonnees des cases comprises dans la zone
-           la zone en question est la liste des cases situees a une distance d des coordonnees d'origine
-           z = 0 -> hauteur z de l'origine par rapport a l'altitude de la case
-           conditionFranchissable = Vrai -> les cases infranchissables ne sont pas prises en compte
-           conditionVisible = Vrai -> les cases bloquant la visibilite ne sont pas prises en compte"""
-        aVerifier = []
-        aVerifier2 = []
-        resultat = {}
-        k = 0        
-        #on part de la premiere case, puis on itere a partir de chaque nouveau depart sur les voisins
-        if origine in self.cases:
-            aVerifier.append(origine)
-            while k <= rayon:
-                for depart in aVerifier:
-                    for coord in self.cases[depart].voisins:
-                        if not coord in aVerifier and not coord in aVerifier2 and not coord in resultat:
-                            if conditionFranchissable and not conditionVisible:
-                                if self.cases[coord].estFranchissable(z):
-                                    aVerifier2.append(coord)
-                                elif not conditionFranchissable and conditionVisible:          
-                                    if self.cases[coord].terrain.visibilite:
-                                        aVerifier2.append(coord)
-                            elif conditionFranchissable and conditionVisible:          
-                                if self.cases[coord].estFranchissable(z) and self.cases[coord].terrain.visibilite:
-                                    aVerifier2.append(coord)
-                            else:
-                                aVerifier2.append(coord)      
-                for elt in aVerifier:
-                    resultat[elt] = k
-                aVerifier = aVerifier2
-                aVerifier2 = []
-                k += 1
-         
-        return resultat
-
-    def zone3d(self, origine, rayon, zCible=0):
-        """renvoie les cases de la zone au format (x, y, z)"""
-        retour = []
-        zone = self.zone(origine, rayon)
-        for coord in zone:
-            x, y = coord
-            dz = rayon - zone[coord]
-            for z in range(-dz, dz + 1):
-                retour.append( (x, y, (zCible+z) ) )
-        return retour            
-
-    def polygoneAgglo(self, listeCases):
-        """renvoie un polygone contruit par agglomeration des polygones des cases de la liste
-           les cases doivent etre adjacentes (cases hexagonales ou carrees)"""
-        pointsPolygone = []
-        segments = []
-        case = Case(self)
-        
-        #on verifie que toutes les cases sont adjacentes les unes aux autres
-        valide = True
-        if len(listeCases) > 1:
-            for coord in listeCases:
-                if not len(set(listeCases).intersection(self.lstCoordAdjacentes(coord[0], coord[1]))) > 0: valide = False
-        if not len(listeCases) > 0:
-            valide = False
-        
-        if valide:
-            #on parcourt les faces des polygones des cases, et on ne garde que ceux qui n'ont pas de case 'en face'
-            for coord in listeCases:
-                polygone = case.polygone(coord[0], coord[1])
-                voisins = self.lstCoordAdjacentes(coord[0], coord[1])
-                
-                for i in range(0, len(voisins)):
-                    if not voisins[i] in listeCases:
-                        j = i+1
-                        if j > len(voisins) - 1:
-                            j = 0
-                        segments.append(QLineF(polygone[i], polygone[j]))
-
-            #on 'accroche' les segments les uns aux autres, dans l'ordre
-            segments2 = [segments[0]]
-            for segment2 in segments2:
-                for segment in segments:
-                    if not QLineF(segment.p1(), segment.p2()) in segments2 and not QLineF(segment.p2(), segment.p1()) in segments2:
-                        if sqrt((segment.p1().x()-segment2.p2().x())**2+(segment.p1().y()-segment2.p2().y())**2) < 1:
-                            segments2.append(QLineF(segment.p1(), segment.p2()))
-                        elif sqrt((segment.p2().x()-segment2.p2().x())**2+(segment.p2().y()-segment2.p2().y())**2) < 1:   
-                            segments2.append(QLineF(segment.p2(), segment.p1()))
-
-            pointsPolygone = []
-            premierPoint = segments2[0].p1()
-            pointsPolygone.append(premierPoint)
-            for segment in segments2:
-                pointSuivant = segment.p2()
-                if pointSuivant != premierPoint:
-                    pointsPolygone.append(pointSuivant)
-
-            #creation du polygone
-            polygone = QPolygonF()
-            for point in pointsPolygone:   
-                polygone.append(point)   
-        else:
-            polygone = None
-
-        return polygone  
-
-    def coordCentreListeCases(self, listeCases):
-        """renvoie les coordonnees centrales d'une liste de cases"""
-        retour = None
-        if len(listeCases) > 0:
-            listeTriee = sorted(listeCases)
-            posMilieu = int(len(listeCases)/2)
-            retour = listeTriee[posMilieu]
-        return retour    
-
-    def coordonneesAuPoint(self, point):
-        """renvoie les coordonnees de la case situee au QPointF entre en parametre"""
-        coord = None
-        if point != None:
-            lstObjets = self.vue().scene().items(point)
-            for objet in lstObjets:
-                if objet:
-                    if objet.__class__.__name__ == "Case":
-                        coord = (objet.x, objet.y)
-                        break       
-        return coord            
-
-    def casesSousForme(self, forme, plein = True, epaisseur = 0):
-        """renvoie la liste des cases en collision avec un QGraphicsItem en parametre
-            plein = False: pas le contenu de la forme
-            epaisseur = renvoie aussi les cases voisines jusqu'a la distance demandee"""
-        tmp = []
-        listeCases = []
-        point1 = None
-        point2 = None
-        #point 1 et 2
-        if forme.__class__.__name__ == "QGraphicsLineItem":
-            point1 = forme.line().p1()
-            point2 = forme.line().p2()
-        elif forme.__class__.__name__ == "QGraphicsRectItem" or forme.__class__.__name__ == "QGraphicsEllipseItem":
-            point1 = forme.rect().topLeft()
-            point2 = forme.rect().bottomRight()
-        else:
-            point1 = forme.boundingRect().topLeft()
-            point2 = forme.boundingRect().bottomRight()            
- 
-        #preselection des cases (meilleures perf)    
-        if point1 != None and point2 != None and point1 != point2:
-            preSelection = self.preSelectionCollision(point1, point2)
-        else:
-            preSelection = []
-            for coord in self.cases:
-                preSelection.append(coord)
-       
-        #on liste les cases en collision avec la forme 
-        for coord in preSelection:
-            if self.cases[coord].collidesWithItem(forme, Qt.IntersectsItemShape):
-                if plein:
-                    tmp.append(coord) 
-                else:
-                    contenu = True
-                    for i in range(0,len(self.cases[coord].polygon())):
-                        if not forme.contains(self.cases[coord].polygon().at(i)):
-                            contenu = False
-                            break
-                    if contenu == False:
-                        tmp.append(coord)    
-        #on applique l'epaisseur du pinceau (lignes ou formes vides seulement) si necessaire
-        if not plein and epaisseur > 0:
-            for coord in tmp:
-                zone = self.zone(coord, epaisseur)
-                for coord2 in zone:
-                    if not coord2 in listeCases:
-                        listeCases.append(coord2)
-        else:
-            listeCases = tmp
-        #si la liste est vide, on ajoute l'origine de la forme
-        if len(listeCases) == 0:
-            listeCases = [self.coordonneesAuPoint(point1)]    
-        return listeCases                
-
-    def preSelectionCollision(self, point1, point2):
-        """renvoie une liste des cases qui peuvent etre concernees par une collision avec
-           un graphicsItem (pour des raisons de performance)"""
-        preSelection = []
-        coord1 = self.coordonneesAuPoint(point1)  
-        coord2 = self.coordonneesAuPoint(point2)
-        if coord1 != None and coord2 != None:
-            minX = min(coord1[0], coord2[0]) - 1
-            maxX = max(coord1[0], coord2[0]) + 1
-            minY = min(coord1[1], coord2[1]) - 1
-            maxY = max(coord1[1], coord2[1]) + 1
-            for coord in self.cases:
-                if coord[0] >= minX and coord[0] <= maxX and coord[1] >= minY and coord[1] <= maxY :
-                    preSelection.append(coord)
-        else:
-            preSelection = self.cases
-        return preSelection
-    
-    def listeZCible(self, coord):
-        """retourne l'altitude absolue a prendre en compte en fonction de la case ciblee
-            c'est l'altitude la case si aucun pion n'occupe la case
-            c'est la liste des cases occupees en hauteur par le pion sinon
-            'coord' est de la forme (x, y)"""
-        if self.cases[coord].estOccupee():
-            retour = range(self.cases[coord].occupant().zAbs(), \
-                            self.cases[coord].occupant().zAbs() + self.cases[coord].occupant().hauteur)
-        else:
-            retour = [self.cases[coord].altitude]             
-        return retour
-
-    def estCibleAttaqueDistValide(self, coordCible):
-        """la case cible est elle valide pour une attaque a distance depuis la position et hauteur
-            du pion selectionne
-            les coord sont de la forme (x, y)"""
-        valide = False
-        x1, y1 = self.pionSelectionne().position
-        coordOrigine = (x1, y1, (self.pionSelectionne().zAbs() + self.pionSelectionne().hauteur))
-        
-        x2, y2 = coordCible
-        cible = self.cases[coordCible].occupant()
-        listeZ2 = self.listeZCible(coordCible)      
-        if coordOrigine[0] != coordCible[0] or coordOrigine[1] != coordCible[1]:
-            for z2 in listeZ2:
-                zValide = True
-                casesLigneMire = br.ligne(coordOrigine, (x2, y2, z2), self.formeCases)
-                casesLigneMire.remove(coordOrigine)
-                casesLigneMire.remove((x2, y2, z2))
-                for coord in casesLigneMire:
-                    if zValide:
-                        x, y, z = coord
-                        if self.cases[(x,y)].estOccupee(z): 
-                            if self.cases[(x,y)].occupant(z) not in [self.pionSelectionne(), cible]:
-                                zValide = False
-                if zValide: 
-                    valide = True #si au moins un des z cibles est valide, la ligne de mire est valide
-                    break
-                
-        return valide       
-                      
-    def pionSurCase(self, coord):
-        """renvoie le pion present sur la case, none sinon"""
-        retour = None
-        for num in self.combattants:
-            if self.combattants[num].position == coord:
-                retour = num
-        return retour        
-
-    def pionsSurListeCase(self, listeCases):
-        """renvoie la liste des num des pions presents sur la liste de cases"""
-        retour = []
-        for coord in listeCases:
-            pion = self.cases[coord].occupant()
-            if pion != None and not pion.numero in retour:
-                retour.append(pion.numero)
-        return retour   
-
-    def majZonePlacement(self, listeCases):
-        """met a jour la forme et l'affichage de la zone de placement initale des joueurs"""
-        if len(listeCases) > 0:
-            if self.polygoneZonePlacement == None:
-                self.polygoneZonePlacement = QGraphicsPolygonItem(scene=self)
-                self.polygoneZonePlacement.setZValue(0)
-                qCouleurFond = QColor("white")
-                qCouleurFond.setAlpha(50)
-                self.polygoneZonePlacement.setBrush(qCouleurFond)
-                pinceau = QPen(QColor("orange"))
-                pinceau.setWidth(20)
-                self.polygoneZonePlacement.setPen(pinceau)
-                self.polygoneZonePlacement.setAcceptedMouseButtons(Qt.NoButton)
-                self.polygoneZonePlacement.setAcceptHoverEvents(False)
-                self.addItem(self.polygoneZonePlacement)
-            listeCases2 = []    
-            for coord in listeCases:
-                if self.cases[coord].estFranchissable():
-                    listeCases2.append(coord)
-            self.polygoneZonePlacement.setPolygon(self.polygoneAgglo(listeCases2))
-            self.listeCasesZonePlacement = listeCases
-
-    def materialiserPions(self,actif):
-        """avtive/desactive la reception par les pions (autres que le pion selectionne) des hover events"""
-        for numCombattant in self.combattants:
-            if numCombattant != self.modeParam["numPionSelectionne"]:
-                self.combattants[numCombattant].setAcceptsHoverEvents(actif)
-                self.combattants[numCombattant].polygoneGraphique.setAcceptsHoverEvents(actif)
-        for numCombattant in self.decors:
-            self.decors[numCombattant].setAcceptsHoverEvents(actif)
-            self.decors[numCombattant].polygoneGraphique.setAcceptsHoverEvents(actif)
-                
-    #######################
-
-    ######## interaction avec les cases, decors et pions  #############
-    def pionSelectionne(self):
-        """renvoie le pion actuellement selectionne"""
-        retour = None
-        if self.modeActif.__class__.__name__ == "PionSelectionne":
-            retour = self.modeActif.pion()
-        return retour    
-
-    def caseCliquee(self, x, y):
-        """on a clique sur la case (clic gauche)"""
-        coord = (x, y)
-        self.modeActif.clic_case(coord)     
-
-    def caseSurvolClicEnfonce(self, coord):
-        """une case est survolee par le curseur (le clic gauche est enfonce)"""
-        self.modeActif.survolClic_case(coord)
-
-    def caseSurvol(self, x, y):
-        """une case est survole par le curseur, on affiche ses informations dans la zone prevue"""
-        self.majInfosCase(self.cases[(x,y)]) 
-        self.modeActif.survol_case((x,y))
-                         
-    def afficherListeCases(self, listeCases, actif):
-        """met ou non en evidence les cases selectionnees"""
-        for coord in listeCases:
-            self.cases[coord].majEstCibleCurseur(actif)
-
-    def pionClique(self, num):
-        """on a clique sur ce pion"""
-        if num < 10000:
-            self.modeActif.clic_combattant(num)
-        else:
-            self.modeActif.clic_decor(num)
-
-    def combattantSurvol(self, num):
-        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
-        self.modeActif.survol_combattant(num)
-        pion = self.combattants[num]
-        self.majInfosCombattant(pion)
-        self.caseSurvol(pion.position[0], pion.position[1])
-
-    def combattantFinSurvol(self, num):
-        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
-        self.modeActif.finSurvol_combattant(num)
-        self.majInfosCombattant(None)
-
-    def decorSurvol(self, num):
-        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
-        self.modeActif.survol_decor(num)
-        pion = self.decors[num]
-        self.majInfosDecor(pion)
-        self.caseSurvol(pion.position[0], pion.position[1])
-
-    def decorFinSurvol(self, num):
-        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
-        self.modeActif.finSurvol_decor(num)
-        self.majInfosDecor(None)
-            
-    def pionDoubleClic(self, numCombattant):
-        """on a double-clique sur le pion"""
-        self.modeActif.doubleClic_combattant(numCombattant)       
-
-    def creerPion(self, pionModele):
-        """creer un pion (combattant ou decor) aux coordonnees indiquees"""
-        cree = False
-        if self.proj.projectionValide():
-
-            if pionModele.__class__.__name__ == "Combattant":
-                pion = Combattant()
-            elif pionModele.__class__.__name__ == "Decor":
-                pion = Decor()
-
-            for elt in pionModele.__dict__:
-                pion.__dict__[elt] = pionModele.__dict__[elt]
-            
-            if pionModele.__class__.__name__ == "Combattant":
-                numero = 1
-                if len(self.combattants) > 0:
-                    numero = max(self.combattants) + 1
-                pion.numero = numero    
-                pion.numComplementaire = self.numeroterNom(pion.nom)    
-                self.combattants[numero] = pion
-                self.pionDeplacerDansOrdreJeu(numero, len(self.ordreJeu) + 2)
-                
-            elif pionModele.__class__.__name__ == "Decor":
-                numero = 10001
-                if len(self.decors) > 0:
-                    numero = max(self.decors) + 10001
-                pion.numero = numero
-                self.decors[numero] = pion
-
-            pion.position = self.proj.coord()
-            pion.nbRotations = self.proj.nbRotations()
-            pion.ajouterAuPlateau(self)
-
-            cree = True
-        return cree            
-
-    def numeroterNom(self, nom):
-        """renvoie le nom du pion avec un numero complementaire si necessaire """
-        i = 1
-        for numCombattant in self.combattants:
-            if self.combattants[numCombattant].nom == nom:
-                i += 1     
-        if i == 1:
-            retour = ""
-        else:
-            retour = str(i)
-        return retour
-        
-    def pionDeposer(self, coordCase):
-        """on depose le pion sur la case voulue"""
-        if self.pionSelectionne() != None:
-            pion = self.pionSelectionne()
-        
-        if pion != None:
-            if self.proj.projectionValide():        
-                pion.majPosition(self.proj.coord(), self.proj.nbRotations())
-
-    def majZPion(self, valeur):
-        """met a jour l'altitude du pion selectionne"""
-        if self.pionSelectionne() != None:
-            self.pionSelectionne().majZ(valeur)
-
-    def dialogueVol(self, actuelle):
-        ecran = EcranVol(actuelle)
-        ecran.exec_() 
-        nouvelle = ecran.resultat()
-        del ecran
-        return nouvelle   
-            
-    def pionSupprimer(self, num):
-        """supprime le pion entre en parametre"""
-        #settrace(trace_calls)
-        if num in self.combattants:    
-            self.pionDeplacerDansOrdreJeu(num, 0)
-            pionSuppr = self.combattants.pop(num)
-        elif num in self.decors:    
-            pionSuppr = self.decors.pop(num)
-            
-        pionSuppr.retirerDuPlateau()
-            
-    ###############
-
-    ######### caches ###############
-    def activerModeCreationCache(self):
-        self.activerMode(Modes.EditerCaches)
-
-    def activerModeEditionCache(self):
-        idCache = int(self.fenetre.ui.cp_listeCaches.texte(self.fenetre.ui.cp_listeCaches.currentRow(), 0))
-        self.activerMode(Modes.EditerCaches, idCache)
-
-    def initListeCaches(self):
-        """charge la liste des caches avec les donnees en memoire"""
-        self.fenetre.ui.cp_listeCaches.setColumnWidth(0, 10)
-        self.fenetre.ui.cp_listeCaches.setColumnWidth(1, 100)
-        self.fenetre.ui.cp_listeCaches.setColumnWidth(2, 18)
-        for idCache in self.caches:
-            self.ajouterCacheATable(self.caches[idCache])
-
-    def nouveauCache(self, listeCases):
-        nouvelId = 0
-        if len(self.caches) > 0:
-            nouvelId = max(self.caches) + 1
-        cache = Cache(nouvelId)
-        cache.activer(True)
-        cache.nom = "Cache {}".format(nouvelId + 1)
-        self.caches[nouvelId] = cache
-        self.ajouterCacheATable(cache)
-        for coord in listeCases:
-            self.cases[coord].ajouterCache(nouvelId)        
-
-    def editerFormeCache(self, idCache, listeCases):
-        """edite le cache avec la liste des cases en param"""
-        actif = self.caches[idCache].actif()
-        for coord in self.cases:
-            if coord in listeCases:
-                self.cases[coord].ajouterCache(idCache, actif)
-            else:
-                self.cases[coord].supprimerCache(idCache)
-        
-    def majEtatCache(self, actif):
-        emetteur = self.sender().objectName()
-        idCache = int(emetteur.replace("afficherCache_", ""))
-        self.caches[idCache].activer(actif)
-        if actif:
-            nomImg = "oeilBarre2_32.png"
-        else:
-            nomImg = "oeil_32.png"
-        self.fenetre.ui.cp_listeCaches.item(idCache, 1).setIcon(QIcon(":/interface/32/ressource/{}".format(nomImg)))
-        for coord in self.cases:
-            self.cases[coord].activerCache(idCache, actif)
-
-    def majNomCache(self, ligne, colonne):
-        idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0))
-        nouveauNom = self.fenetre.ui.cp_listeCaches.texte(ligne, 1)
-        if nouveauNom != self.caches[idCache].nom:
-            self.caches[idCache].nom = nouveauNom
-
-    def supprimerCache(self):
-        ligne = self.fenetre.ui.cp_listeCaches.currentRow()
-        idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0)) 
-        for coord in self.cases:
-            self.cases[coord].supprimerCache(idCache)
-        self.fenetre.ui.cp_listeCaches.removeRow(idCache)
-        del self.caches[idCache]
-
-    def mettreCacheEnEvidence(self, ligne, colonne):
-        idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0))
-        for coord in self.cases:
-            if len(self.cases[coord].cachesActifs) > 0:
-                self.cases[coord].polygoneCache.activerSurbrillance((idCache in self.cases[coord].cachesActifs))        
-
-    def ajouterCacheATable(self, cache):
-        """ajoute le cache a la table des caches"""
-        self.fenetre.disconnect(self.fenetre.ui.cp_listeCaches, SIGNAL("cellChanged(int,int)"), self.majNomCache)
-        ligne = self.fenetre.ui.cp_listeCaches.nouvelleLigneFin()
-        if cache.actif():
-            nomImg = "oeilBarre2_32.png"
-        else:
-            nomImg = "oeil_32.png"
-        self.fenetre.ui.cp_listeCaches.majTexte(ligne, 0, str(cache.numero))  
-          
-        item = QTableWidgetItem(QIcon(":/interface/32/ressource/{}".format(nomImg)), cache.nom)
-        item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable)
-        self.fenetre.ui.cp_listeCaches.setItem(ligne, 1, item)
-        
-        widget = QCheckBox(QString(""))
-        widget.setChecked(cache.actif())
-        widget.setObjectName(QString("afficherCache_{}".format(ligne)))
-        self.connect(widget, SIGNAL("toggled(bool)"), self.majEtatCache)
-        self.fenetre.ui.cp_listeCaches.setCellWidget(ligne, 2, widget)
-        
-        self.fenetre.connect(self.fenetre.ui.cp_listeCaches, SIGNAL("cellChanged(int,int)"), self.majNomCache, Qt.UniqueConnection)
-    ###############"
-        
-    ######### gestion des evenements souris et clavier ###############
-    def mouseMoveEvent(self, event):
-        super(Plateau, self).mouseMoveEvent(event)
-        if event.buttons() == Qt.LeftButton and self.vue().dragMode() != QGraphicsView.ScrollHandDrag:
-            coord = self.coordonneesAuPoint(event.scenePos())
-            if coord != None:
-                self.caseSurvolClicEnfonce(coord)  
-        else:
-            self.modeActif.mouvementSouris(event)
-            event.ignore() 
-
-    def mousePressEvent(self, event):
-        super(Plateau, self).mousePressEvent(event)
-        if event.button() == 1:
-            self.modeActif.clicGauche(event)
-        elif event.button() == 2:
-            self.modeActif.clicDroit(event)
-            event.accept()
-
-    def mouseReleaseEvent(self, event):
-        super(Plateau, self).mouseReleaseEvent(event)
-        self.modeActif.finClicGauche(event)
-
-    def keyPressEvent(self, event):
-        """gestion des evenements clavier"""
-        self.modeActif.toucheClavier(event)
-
-    ################   
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-        
-  
-
-
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+from __future__ import division
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+##from ui.ecran_editionAttaques import Ui_editionAttaques
+
+import Modes
+import Actions
+from Case import Case
+from Combattant import Combattant
+from Decor import Decor
+from Pinceau import Pinceau
+from ProjectionDep import ProjectionDep
+from Cache import Cache
+from Terrain import Terrain
+
+from EcranEditionCombattant import EcranEditionCombattant
+from EcranEditionDecor import EcranEditionDecor
+from EcranEditionTerrain import EcranEditionTerrain
+from EcranAffichageTexte import EcranAffichageTexte
+from EcranGestionCombat import EcranGestionCombat
+from EcranSelectionPj import EcranSelectionPj
+from EcranVol import EcranVol
+
+import regles as regles
+from outilsSvg import enregistrer, charger, chargerUnique
+from time import time
+import br
+
+from math import sqrt
+
+m_couleursRapides = [(255,255,255), (200,200,200), (130,130,130), (90,90,90), (15,15,15), \
+                   (0,85,0), (170,255,0), (170,255,127), (85,85,0), (85,0,0), (170,85,0), (100,50,0), \
+                   (255,255,127), (240,80,0), (85,170,255), (85,85,255), (85,0,255), (0,255,255)]
+        
+class Plateau(QGraphicsScene):
+    """plateau de jeu contenant les cases, decors et pions"""
+    def __init__(self, fenetre, parent=None):
+        super(Plateau, self).__init__()
+        #parametres et variables
+
+        self.fenetre = fenetre
+
+        self.id = ""
+        ##partie et infos plateau
+        self.nom = ""
+        self.chapitre = 0
+        self.tour = 1
+        
+        self.enCours = False
+        self.public = False
+        self.dateCreation = ""
+        self.dateSvg = ""
+        self.notes = ""
+        
+        #carac 
+        self.nbCasesX = 0
+        self.nbCasesY = 0
+        self.hCase = 0
+
+        #objets
+        self.pinceau = Pinceau(self)
+        self.cases = {}   #dict des cases du plateau   (coordonnées: case)
+        self.combattants = {}   #liste de combattants positionnes sur le plateau
+        self.decors = {}  #liste des decors places sur le plateau
+        self.caches = {}
+        self.listeCasesZonePlacement = []
+        self.polygoneZonePlacement = None
+        self.entreesSorties = []
+
+        #infos combat
+        self.numCombattantEnCours = 0
+        self.ordreJeu = {}  #numero du pion: ordre de jeu
+            
+        #note: la hauteur Z (qui gere l'empilement des objets graphiques est distribuee de cette maniere:
+        #cases : 0 a 9
+        #pions : 10 et +
+        
+    def __getstate__(self):
+        self.dateSvg = time()
+        state = {key:value for key, value in self.__dict__.items() if not key in ["fenetre", "modeActif", \
+                                                                                  "editionTerrain", "editionCreature", "editionDecor", \
+                                                                                  "polygoneZonePlacement", "gestionCombat", \
+                                                                                  "editionAttaques", "pinceau"]}
+        return (state)
+
+    def __setstate__(self, state):
+        self.__dict__ = state
+
+    def vue(self):
+        return self.fenetre.ui.cbt_vue
+
+    def creer(self, idPlateau, nom, chapitre, formeCases, nbCasesX, nbCasesY, couleur = QColor(0, 255, 0, 80)):
+        """cree le plateau"""
+        self.id = idPlateau
+        self.nom = nom
+        self.chapitre = chapitre
+        self.dateCreation = time()
+        self.hCase = 120  #hauteur d'une case
+        self.nbCasesX = nbCasesX   #nb cases en x
+        self.nbCasesY = nbCasesY   #nb cases en y
+        self.formeCases = formeCases
+        self.modeActif = Modes.ModeBase(self)
+        self.gestionCombat = None
+        self.initialisationGraphique()
+        self.connexions()
+        
+        #cree les cases hexagonales
+        for x in range(nbCasesX):
+            for y in range(nbCasesY):
+                c = Case(self)
+                c.creer(x, y, couleur)
+                self.cases[(x,y)] = c
+
+        self.plateauModeCreation()
+
+    def recreer(self, fenetre):
+        self.fenetre = fenetre
+        self.gestionCombat = None
+        super(Plateau, self).__init__()
+        self.modeActif = Modes.ModeBase(self)
+        self.connexions()
+        self.initialisationGraphique() 
+
+        #recreation des cases 
+        for coord in self.cases:
+            self.cases[coord].recreer(self)
+
+        #recreation des caches
+        self.initListeCaches()
+
+        #recreation des pions
+        for numCombattant in self.combattants:
+            self.combattants[numCombattant].ajouterAuPlateau(self)
+        self.majOrdreJeu()    
+
+        #recreation des decors
+        for num in self.decors:
+            self.decors[num].ajouterAuPlateau(self)
+
+        #recreation des marqueurs entree/sortie
+        for entreeSortie in self.entreesSorties:
+            entreeSortie.recreer(self)
+
+        #recreation de la zone de placement: 
+        if len(self.listeCasesZonePlacement) > 0:
+            self.polygoneZonePlacement = None
+            self.majZonePlacement(self.listeCasesZonePlacement)
+
+        self.plateauModeCombat()
+
+    def fermer(self):
+        """ferme le plateau 'proprement'"""
+        self.miniature()
+        self.pinceau = None
+        for item in self.items():
+            item.prepareGeometryChange()
+            self.removeItem(item)
+        if self.gestionCombat != None:    
+            del self.gestionCombat           
+        self.fenetre.reinitialiserPanneauxPlateau()
+
+    def miniature(self):
+        """renvoie une miniature du plateau (QPixMap compresse) qui sera enregistree avec les infos de la sauvegarde"""
+##        img = QImage(128, 128, QImage.Format_ARGB32_Premultiplied)
+        img = QPixmap(1024, 768)
+        img.fill(QColor("white"))
+        peintre = QPainter(img)
+        self.render(peintre)
+        peintre.end()
+        img.scaledToHeight(128, Qt.FastTransformation)
+        
+    def connexions(self):
+        """connecte le plateau aux differents widgets de la fenetre principale"""
+        #modes d'interaction
+        self.fenetre.connect(self.fenetre.ui.cbt_modeCreation, SIGNAL("clicked()"), self.plateauModeCreation, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cbt_modeCombat, SIGNAL("clicked()"), self.plateauModeCombat, Qt.UniqueConnection)
+##        self.fenetre.connect(self.fenetre.ui.modeAffichagePlateau, SIGNAL("currentIndexChanged(int)"), self.majModeAffichage, Qt.UniqueConnection)
+
+
+        #affichage de fenetres
+        self.fenetre.connect(self.fenetre.ui.cbt_afficherGestion, SIGNAL("clicked()"), self.afficheEcranGestionCombat, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cbt_ajouterPj, SIGNAL("clicked()"), self.ajouterPj, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee, Qt.UniqueConnection)
+
+        self.fenetre.connect(self.fenetre.ui.cp_dialogueCouleurs, SIGNAL("clicked()"), self.modePeintureCase, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_pipetteCouleur, SIGNAL("clicked()"), self.modeCopieTerrain, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_afficherNotes, SIGNAL("clicked()"), self.agrandirNotesMjPlateau, Qt.UniqueConnection)
+        
+
+        #listes
+        self.fenetre.connect(self.fenetre.ui.inf_listeOrdreJeu, SIGNAL("cellClicked(int,int)"), self.clicListOrdreJeu, Qt.UniqueConnection)
+        
+        self.fenetre.connect(self.fenetre.ui.cp_listeTerrains, SIGNAL("cellClicked(int,int)"), self.modeMajTerrainCase, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_listeCreatures, SIGNAL("cellClicked(int,int)"), self.modeCreationCombattant, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_listeDecors, SIGNAL("cellClicked(int,int)"), self.modeCreationDecor, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_listeCaches, SIGNAL("cellClicked(int,int)"), self.mettreCacheEnEvidence, Qt.UniqueConnection)
+#         self.fenetre.connect(self.fenetre.ui.cp_listeCaches, SIGNAL("cellChanged(int,int)"), self.majNomCache, Qt.UniqueConnection)
+        
+        self.fenetre.connect(self.fenetre.ui.cp_editerTerrain, SIGNAL("clicked()"), self.terrainEdit, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_nouveauTerrain, SIGNAL("clicked()"), self.terrainNouveau, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_editerCombattant, SIGNAL("clicked()"), self.creatureEdit, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_nouveauCombattant, SIGNAL("clicked()"), self.creatureNouveau, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_gommeCombattant, SIGNAL("clicked()"), self.majModeSupprimerCombattant, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_editerDecor, SIGNAL("clicked()"), self.decorEdit, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_nouveauDecor, SIGNAL("clicked()"), self.decorNouveau, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_gommeDecor, SIGNAL("clicked()"), self.majModeSupprimerDecor, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_editerCache, SIGNAL("clicked()"), self.activerModeEditionCache, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_nouveauCache, SIGNAL("clicked()"), self.activerModeCreationCache, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_supprimerCache, SIGNAL("clicked()"), self.supprimerCache, Qt.UniqueConnection)
+
+        #creation
+        self.fenetre.connect(self.fenetre.ui.cp_epaisseurPinceau, SIGNAL("valueChanged(int)"), self.majEpaisseurPinceau, Qt.UniqueConnection)
+##        self.fenetre.connect(self.fenetre.ui.altitudeCase, SIGNAL("valueChanged(double)"), self.modeMajAltitudeCase, Qt.UniqueConnection)
+
+        #autres:
+        #ajouter effet
+        self.fenetre.connect(self.fenetre.ui.cp_placerEntree, SIGNAL("clicked()"), self.majModeDefinirEntree, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_placerSortie, SIGNAL("clicked()"), self.majModeDefinirSortie, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_defPlacement, SIGNAL("clicked()"), self.majModeZonePlacement, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_notes, SIGNAL("textChanged()"), self.majNotesCombattant, Qt.UniqueConnection)
+
+        #formes (dessin)
+        self.fenetre.connect(self.fenetre.ui.cp_formeSimple, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_formeLigne, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_formeLigneOrientee, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_formePot, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_formeRectVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.cp_formeRectPlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
+
+        self.fenetre.connect(self.fenetre.ui.pi_deplacement, SIGNAL("clicked()"), self.majModeCombatDeplacement, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_vol, SIGNAL("clicked()"), self.majModeCombatVol, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_attaqueCac, SIGNAL("clicked()"), self.majModeCombatAttaqueCaC, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_attaqueDist, SIGNAL("clicked()"), self.majModeCombatAttaqueDist, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_attaqueZone, SIGNAL("clicked()"), self.majModeCombatZone, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_formeAttaqueZone, SIGNAL("activated (int)"), self.majModeCombatZone, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_rayonAttaqueZone, SIGNAL("valueChanged(int)"), self.majRayonZone, Qt.UniqueConnection)
+
+        
+        self.fenetre.connect(self.fenetre.ui.pi_finTour, SIGNAL("clicked()"), self.pionSuivant, Qt.UniqueConnection)
+        
+    def initialisationGraphique(self):
+        """cree la scene graphique et les parametres necessaires a son fonctionnement, et met a jour l'interface""" 
+        #on cree la scene graphique
+        kx = 1
+        if self.formeCases == "H":
+            kx = 0.866
+        marge = 240    
+        self.setSceneRect(0 - marge, 0 - marge, (kx*self.hCase*(self.nbCasesX+2)) + marge, (self.hCase*(self.nbCasesY+2)) + marge)
+        self.vue().setScene(self)
+        self.vue().scale(0.25, 0.25)
+        self.vue().centerOn(QPointF(0,0))
+        self.vue().setDragMode(1)
+        self.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
+        
+        self.polygoneZonePlacement = None
+
+        #gestion du mode d'interaction avec le plateau
+        
+        self.pinceau = Pinceau(self)
+        self.proj = ProjectionDep(self)
+  
+        #mise a jour de l'interface de creation
+        self.fenetre.afficherPanneauxPlateau(True)
+        self.fenetre.ui.cbt_nom.majTexte(self.nom)
+        self.majBoutonsCouleursPerso()
+        self.fenetre.ui.cp_listeTerrains.defFichier("lib\\biblio\\terrain")
+        self.fenetre.ui.cp_listeTerrains.initAffichage()
+        self.fenetre.ui.cp_listeCreatures.defFichier("lib\\biblio\\combattant")
+        self.fenetre.ui.cp_listeCreatures.initAffichage()
+        self.fenetre.ui.cp_listeDecors.defFichier("lib\\biblio\\decor")
+        self.fenetre.ui.cp_listeDecors.initAffichage()
+        self.majListeTerrains()
+        self.majListeCreatures()
+        self.majListeDecors()
+        self.initListeCaches()
+        
+        self.initListeOrdreJeu()
+        self.initListeAttaques()
+
+        self.fenetre.ui.pi_deplacement.setCheckable(True)
+        self.fenetre.ui.pi_attaqueCac.setCheckable(True)
+        self.fenetre.ui.pi_attaqueDist.setCheckable(True)
+        self.fenetre.ui.pi_attaqueZone.setCheckable(True)
+
+        #mise a jour de l'interface d'informations
+        self.majInfosCombattant(None)
+        self.majInfosDecor(None)
+
+    def estCree(self):
+        """renvoie vrai si des cases ont ete creees"""
+        return (len(self.cases) > 0)
+
+    def majBoutonsCouleursPerso(self):
+        """met a jour l'affichage des couleurs customisees dans la boite de dialogue de selection de couleur"""
+        for i in range(0,18):
+            couleur = QColor()
+            r, g, b = m_couleursRapides[i]
+            couleur.setRgb(r, g, b)
+            bouton = self.fenetre.ui.cp_boiteCouleurs.findChild(QToolButton, "cp_couleur{}".format(i+1))
+            if couleur.isValid():
+                bouton.setStyleSheet("QToolButton {backGround:%s}"%(couleur.name()))
+                self.fenetre.connect(bouton, SIGNAL("clicked()"), self.modePeintureCase_perso)
+
+    def chercherCouleur(self):
+        """ouvre la boite de dialogue de selection de couleur"""
+        couleur = QColorDialog(self.vue()).getColor(QColor("white"), self.vue())
+        return couleur
+
+    def majListesPions(self, numCombattant = None):
+        """met a jour les listes contenant des donnees liees aux pions"""
+##        self.majListeOrdreJeu()
+##        
+##        if numCombattant == None or numCombattant == self.pionSelectionne().numero:
+##            self.majListeAttributs()
+##        QApplication.processEvents()
+        pass
+
+    def ajouterPj(self):
+        """affiche la fenetre de selection des pj, et recupere l'eventuel pj selectionne"""
+        self.ecranSelPj = EcranSelectionPj(self.fenetre)
+        self.ecranSelPj.setAttribute(Qt.WA_DeleteOnClose)
+        listePj = chargerUnique("parties\\{}\\groupe".format(self.fenetre.partie))
+        self.ecranSelPj.charger(listePj)
+        r = self.ecranSelPj.exec_()
+        if r == 1:
+            idPj = int(self.ecranSelPj.selection())
+            if idPj != None:
+                pj = listePj[idPj]
+                self.activerMode(Modes.CreationPion, pj)
+        self.ecranSelPj = None
+
+    def agrandirNotesMjPlateau(self):
+        """affiche les notes du plateau dans une QDialog, puis recupere les donnees qui y sont saisies"""
+        affichageTexte = EcranAffichageTexte(self.notes)
+        affichageTexte.setAttribute(Qt.WA_DeleteOnClose)
+        affichageTexte.exec_()
+        self.notes = affichageTexte.recupererTexte()
+        
+    ##### affichage de la liste des terrains enregistres, et fonctions d'acces aux donnees""""     
+    def afficheEcranEditionTerrains(self, terrain = None):
+        """affiche l'ecran d'edition/creation de terrains"""
+        self.editionTerrain = EcranEditionTerrain(terrain)     
+        self.editionTerrain.setAttribute(Qt.WA_DeleteOnClose)
+        r = self.editionTerrain.exec_()
+        if r == 1:
+            self.majListeTerrains()
+            self.activerMode(Modes.StandardCp)
+ 
+    def majListeTerrains(self):
+        """mise a jour de la liste des terrains depuis la sauvegarde"""
+        self.fenetre.ui.cp_listeTerrains.maj()
+
+    def terrainEdit(self):
+        """ouvre la fenetre 'terrains' en mode edition"""
+        index = self.fenetre.ui.cp_listeTerrains.item(self.fenetre.ui.cp_listeTerrains.currentRow(), 0)
+        if index > 0:
+            terrain = charger("lib\\biblio\\terrain", str(index.text().toUtf8()))
+            self.afficheEcranEditionTerrains(terrain)
+            self.activerMode(Modes.StandardCp)
+        
+    def terrainNouveau(self):
+        """ouvre la fenetre 'terrains' en mode edition"""
+        self.afficheEcranEditionTerrains()
+        self.activerMode(Modes.StandardCp)
+    ###############
+
+    ##### affichage de la liste des creatures enregistrees, et fonctions d'acces aux donnees""""     
+    def afficheEcranEditionCombattants(self, creature = None):
+        """affiche l'ecran d'edition/creation de creatures"""
+        self.editionCreature = EcranEditionCombattant(creature, 0, self.formeCases)
+        self.editionCreature.setAttribute(Qt.WA_DeleteOnClose)
+        r = self.editionCreature.exec_()
+        if r == 1:
+            combattant = self.editionCreature.combattant
+            enregistrer(combattant.id, combattant, "lib\\biblio\\combattant")
+            self.majListeCreatures()
+            self.activerMode(Modes.StandardCp)
+        self.editionCreature = None
+        
+    def majListeCreatures(self):
+        """mise a jour de la liste des creatures depuis la sauvegarde"""
+        self.fenetre.ui.cp_listeCreatures.maj()
+
+    def creatureEdit(self):
+        """ouvre la fenetre 'creatures' en mode edition"""
+        index = self.fenetre.ui.cp_listeCreatures.item(self.fenetre.ui.cp_listeCreatures.currentRow(), 0)
+        if index > 0:
+            creature = charger("lib\\biblio\\combattant", str(index.text().toUtf8()))
+            self.afficheEcranEditionCombattants(creature)
+            self.activerMode(Modes.StandardCp)
+        
+    def creatureNouveau(self):
+        """ouvre la fenetre 'creatures' en mode edition"""
+        self.afficheEcranEditionCombattants()
+        self.activerMode(Modes.StandardCp)
+        
+    ###############
+
+    ##### affichage de la liste des decors enregistrees, et fonctions d'acces aux donnees""""     
+    def afficheEcranEditionDecors(self, decor = None):
+        """affiche l'ecran d'edition/creation de decors"""
+        self.editionDecor = EcranEditionDecor(decor, 0, self.formeCases)
+        self.editionDecor.setAttribute(Qt.WA_DeleteOnClose)
+        r = self.editionDecor.exec_()
+        if r == 1:
+            decor = self.editionDecor.decor
+            enregistrer(decor.id, decor, "lib\\biblio\\decor")
+            self.majListeDecors()
+            self.activerMode(Modes.StandardCp)
+            
+    def majListeDecors(self):
+        """mise a jour de la liste des decors depuis la sauvegarde"""
+        self.fenetre.ui.cp_listeDecors.maj()
+
+    def decorEdit(self):
+        """ouvre la fenetre 'decors' en mode edition"""
+        self.afficheEcranEditionDecors(self.fenetre.ui.cp_listeDecors.actuel())
+        self.activerMode(Modes.StandardCp)
+        
+    def decorNouveau(self):
+        """ouvre la fenetre 'decors' en mode edition"""
+        self.afficheEcranEditionDecors()
+        self.activerMode(Modes.StandardCp)
+        
+    ###############
+
+    ############### maj des infos du panneau Pi a la selection/deselection d'un pion
+        #voir a balancer tout ca dans une classe a part
+
+    def majPanneauPi(self):
+        
+        if self.pionSelectionne():
+            estCombattant = (self.pionSelectionne().numero < 10000)
+            #affichage
+            self.fenetre.ui.pi_actions.setEnabled(estCombattant)
+            self.fenetre.ui.pi_finTour.setEnabled(estCombattant)
+            self.fenetre.ui.pi_ongletsListes.setTabEnabled(0, estCombattant)
+            self.fenetre.ui.pi_ongletsListes.setTabEnabled(1, estCombattant)
+            
+            ### maj la selection dans la liste d'ordre de jeu
+            if estCombattant:
+                for i in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()):
+                    if str(self.fenetre.ui.inf_listeOrdreJeu.item(i, 0).text().toUtf8()) == str(self.pionSelectionne().numero):
+                        self.fenetre.ui.inf_listeOrdreJeu.setCurrentCell(i,0)
+
+            ### maj des infos dans le panneau pi
+            self.fenetre.ui.pi_nom.majTexte(self.pionSelectionne().txtId())
+            self.fenetre.ui.pi_img.chargerImage(self.pionSelectionne().img.rimage)
+
+            ### maj de la liste des attributs
+            if estCombattant:
+                self.fenetre.ui.pi_listeAttributs.setColumnWidth(0, 50)
+                self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
+            
+                #on vide la liste
+                while self.fenetre.ui.pi_listeAttributs.rowCount() > 0:
+                    self.fenetre.ui.pi_listeAttributs.removeRow(0)
+
+                #creation des lignes de base    
+                lignesBase = ["Nom","Etat","Alt."]   #attention: modifier aussi dans listeAttributCelluleModifiee
+                for i in range(0, 10):    #10 premieres colonnes reservees pour les infos de base
+                    self.fenetre.ui.pi_listeAttributs.insertRow(i)
+                    item = QTableWidgetItem()
+                    if i < len(lignesBase):
+                        item.setText(QString.fromUtf8(lignesBase[i]))
+                    item.setFlags(Qt.NoItemFlags)    
+                    self.fenetre.ui.pi_listeAttributs.setItem(i, 0, item)
+                    self.fenetre.ui.pi_listeAttributs.setRowHidden(i, (i >= len(lignesBase)))
+
+                #maj des donnees de base    
+                self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Nom"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().nom))))
+                self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Etat"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().etat))))
+                self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Alt."), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().z))))
+                
+                #attributs issus des regles utilisees    
+                ordre = regles.ordreAttributs()
+                for elt in ordre:
+                    ligne = 10 + ordre.index(elt)
+                    self.fenetre.ui.pi_listeAttributs.insertRow(ligne)
+                    item = QTableWidgetItem(QString.fromUtf8(elt))
+                    item.setFlags(Qt.NoItemFlags)
+                    self.fenetre.ui.pi_listeAttributs.setItem(ligne, 0, item)
+                    self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[elt]))))
+                    
+                self.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
+            
+            ###affiche les notes du combattant
+            self.fenetre.ui.pi_notes.majTexte(self.pionSelectionne().notes)
+
+            ###maj la liste des attaques du pion
+            if estCombattant:
+                #on vide la liste
+                while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
+                    self.fenetre.ui.pi_listeAttaques.removeRow(0)
+                    
+                i = 0
+                for attaque in self.pionSelectionne().attaques:
+                    self.fenetre.ui.pi_listeAttaques.insertRow(i)
+                    self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque)))))
+                    icone = None
+                    if attaque.typ == "cac":
+                        icone = QIcon(":/interface/16/ressource/epee_16.png")
+                    if attaque.typ == "dist":
+                        icone = QIcon(":/interface/16/ressource/arc_16.png")
+                    if attaque.typ == "zone":
+                        icone = QIcon(":/interface/16/ressource/baguette_16.png")
+                    if icone != None:
+                        self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8("")))
+                    self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom)))  
+
+        else:
+            #maj des infos dans le panneau pi
+            self.fenetre.ui.pi_img.clear()  
+            self.fenetre.ui.pi_nom.majTexte("Pas de pion\nselectionné")
+
+            #vide la liste des attributs
+            self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
+            while self.fenetre.ui.pi_listeAttributs.rowCount() > 0:
+                self.fenetre.ui.pi_listeAttributs.removeRow(0)        
+
+            #vide la liste des attaques du pion
+            while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
+                self.fenetre.ui.pi_listeAttaques.removeRow(0)
+                
+        self.majInfosAttaqueEC()
+
+    ##### activation des differents modes d'interaction avec le plateau et mises a jour des principaux parametres  #######
+    def plateauModeCreation(self):
+        self.activerMode(Modes.StandardCp)
+
+    def plateauModeCombat(self):
+        self.activerMode(Modes.StandardPi)
+
+    def activerMode(self, mode, param = None):
+        """desactive le mode actif et active le nouveau a la place"""
+        self.modeActif.desactiver()
+        self.modeActif = mode(self)
+        self.modeActif.activer(param)
+        
+##    def majModeAffichage(self, index):
+##        """met a jour le mode d'affichage"""
+##        nouveauMode = ""
+##        if index == 0:
+##            #passe a l'affichage standard
+##            pass
+##        elif index == 1:
+##            #passe en mode affichage de l'altitude
+##            nouveauMode = "altitude"    
+##        elif index == 2:
+##            #affichage des terrains slt
+##            nouveauMode = "terrain"
+##        elif index == 3:
+##            #affichage tactique
+##            nouveauMode = "tactique"
+##            
+##        for coord in self.cases:
+##            self.cases[coord].majAffichageSpecial(nouveauMode)
+
+    def modePeintureCase(self):
+        """enclenche le mode peinture de case a partir de la couleur selectionnee"""
+        couleur = self.chercherCouleur()
+        if couleur.isValid():
+            terrain = Terrain()
+            terrain.couleur = couleur
+            self.activerMode(Modes.MajCases, terrain)
+        else:
+            self.activerMode(Modes.StandardCp)
+
+    def modePeintureCase_perso(self):
+        origine = self.sender().objectName()
+        index = int(origine.replace("cp_couleur",""))-1
+        couleur = QColor()
+        r, g, b = m_couleursRapides[index]
+        couleur.setRgb(r, g, b)
+        if couleur.isValid():
+            terrain = Terrain()
+            terrain.couleur = couleur
+            self.activerMode(Modes.MajCases, terrain)
+        else:
+            self.activerMode(Modes.StandardCp)            
+
+    def modeCopieTerrain(self):
+        """enclenche le mode copie de case"""
+        self.activerMode(Modes.Pipette)
+
+    def modeCaseEffet(self, index):
+        """enclenche le mode de mise a jour de l'effet actif des cases"""
+        effets = ["brule", "eau", "glace", "poison", "aucun"]
+        self.activerMode(Modes.MajCasesEffet, effets[index])
+
+    def modeCreationPion(self):
+        """enclenche le mode de creation de pions simples"""
+        self.majMode("pionCreation")
+
+    def majModeSupprimerDecor(self):
+        """enclenche le mode suppression de pions sur clic gauche (creatures ou decors)"""
+        self.activerMode(Modes.SuppressionPion, Decor)
+
+    def majModeSupprimerCombattant(self):
+        """enclenche le mode suppression de pions sur clic gauche (creatures ou decors)"""
+        self.activerMode(Modes.SuppressionPion, Combattant)
+    
+    def modeCreationDecor(self, ligne, col):
+        """enclenche le mode de creation de decors depuis la liste des decors"""
+        index = self.fenetre.ui.cp_listeDecors.item(ligne, 0)
+        decor = charger("lib\\biblio\\decor", str(index.text().toUtf8()))
+        self.activerMode(Modes.CreationPion, decor)
+        
+    def modeCreationCombattant(self, ligne, col):
+        """enclenche le mode de creation de pions depuis la liste des creatures"""
+        index = self.fenetre.ui.cp_listeCreatures.item(ligne, 0)
+        creature = charger("lib\\biblio\\combattant", str(index.text().toUtf8()))
+        self.activerMode(Modes.CreationPion, creature)
+
+    def modeMajTerrainCase(self, ligne, col):
+        """enclenche le mode permettant la mise a jour du terrain des cases"""
+        index = self.fenetre.ui.cp_listeTerrains.item(ligne, 0)
+        terrain = charger("lib\\biblio\\terrain", str(index.text().toUtf8()))
+        if terrain:
+            self.activerMode(Modes.MajCases, terrain)
+        else:
+            print "terrain invalide"
+
+    def majEpaisseurPinceau(self, epaisseur):
+        """met a jour l'epaisseur du pinceau (en cases)"""
+        self.fenetre.ui.cp_valeurEpaisseurPinceau.majTexte(str(epaisseur))
+        self.pinceau.majEpaisseur(int(epaisseur))
+
+    def modeMajAltitudeCase(self):
+        self.majMode("caseMajAltitude")
+
+    def majModeForme(self):
+        """met a jour la forme utilisee pour la peinture"""
+        formes = {"cp_formeSimple": "simple", \
+                  "cp_formeLigne": "ligne", \
+                  "cp_formeLigneOrientee": "frontiere", \
+                  "cp_formePot": "pot", \
+                  "cp_formeEllipseVide": "ellipseV", \
+                  "cp_formeEllipsePlein": "ellipseP", \
+                  "cp_formeRectVide": "rectV", \
+                  "cp_formeRectPlein": "rectP"}
+        self.pinceau.majForme(formes[str(self.sender().objectName())])
+
+    def majModeCombatDeplacement(self):
+        """active le mode de combat 'deplacement' (mode standard)"""
+        self.modeActif.nouvelleAction(Actions.Deplacement)
+
+    def majModeCombatVol(self):
+        """active le mode de combat 'vol'"""
+        self.modeActif.nouvelleAction(Actions.Vol)
+
+    def majModeCombatAttaqueCaC(self):
+        """active le mode de combat 'corps-a-corps'"""
+        self.modeActif.nouvelleAction(Actions.Cac)
+
+    def majModeCombatAttaqueDist(self):
+        """active le mode de combat 'attaque a distance'"""
+        self.modeActif.nouvelleAction(Actions.Distance)
+
+    def majModeCombatZone(self):
+        if self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 0:
+            action = Actions.Ligne
+        elif self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 1:
+            action = Actions.Disque
+        elif self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 2:
+            action = Actions.Cone
+        if action:    
+            self.modeActif.nouvelleAction(action)      
+
+    def majRayonZone(self, val):
+        action = self.modeActif.action()
+        if action:
+            action.majRayon(val) 
+
+    def majModeDefinirEntree(self):
+        self.activerMode(Modes.CreationEntreeSortie, "E")
+
+    def majModeDefinirSortie(self):
+        self.activerMode(Modes.CreationEntreeSortie, "S")
+
+    def majModeZonePlacement(self):
+        self.activerMode(Modes.ZonePlacement)
+    
+    ###############
+
+    ########## Gestion du combat ##############
+    def majAffichageTour(self):
+        """met a jour l'affichage du tour en cours"""
+        self.fenetre.ui.cbt_tour.majTexte("Tour: {}".format(self.tour))
+
+    def initListeOrdreJeu(self):
+        """cree les colonnes et met en forme la table ordre jeu"""
+        self.fenetre.ui.inf_listeOrdreJeu.setColumnWidth(2, 30)
+        self.fenetre.ui.inf_listeOrdreJeu.hideColumn(0)
+        self.fenetre.ui.inf_listeOrdreJeu.hideColumn(2)      
+        self.fenetre.ui.inf_listeOrdreJeu.setIconSize(QSize(30,20))   
+            
+    def majListeOrdreJeu(self):
+        """met a jour la liste des pions infoOrdreJeu"""
+        while self.fenetre.ui.inf_listeOrdreJeu.rowCount() > 0:
+            self.fenetre.ui.inf_listeOrdreJeu.removeRow(0)
+        index = 0
+        for num in self.ordreJeu:
+            self.fenetre.ui.inf_listeOrdreJeu.insertRow(int(index))
+            self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 0, QTableWidgetItem(QString.fromUtf8(str(num))))
+            icon = QIcon(self.combattants[num].logo.chemin())
+            item = QTableWidgetItem(icon, QString.fromUtf8(self.combattants[num].txtId()))
+            self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 1, item)
+            self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 2, QTableWidgetItem(QString.fromUtf8(str(self.ordreJeu[num]))))
+            index += 1
+
+        self.fenetre.ui.inf_listeOrdreJeu.sizeHintForColumn(1)
+##        trierTable(self.fenetre.ui.infoOrdreJeu, 2, 0)
+
+    def clicListOrdreJeu(self, ligne, col):
+        """on a clique dans la liste d'ordre de jeu, le pion correspondant est selectionne et centre sur la carte"""
+        numCombattant = int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8())  
+        self.vue().centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique)
+        self.modeActif.clic_combattant(numCombattant)
+
+    def pionSuivant(self):
+        """selection du pion suivant dans la liste d'ordre de jeu"""
+        if self.numPionEnCours in self.combattants:
+            suivant = self.ordreJeu[self.numPionEnCours] + 1
+        else:
+            suivant = 1
+        if suivant > len(self.ordreJeu):
+            self.tour += 1
+            self.majAffichageTour()
+            suivant = 1
+        for num in self.ordreJeu:
+            if self.ordreJeu[num] == suivant:
+                numCombattant = num
+                break
+
+        for ligne in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()):
+            item = self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0)
+            item.setSelected(int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8()) == numCombattant)
+            if int(item.text().toUtf8()) == numCombattant:
+                self.fenetre.ui.inf_listeOrdreJeu.scrollToItem(item)
+
+        self.vue().centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique)
+        self.pionSaisir(numCombattant)        
+ 
+    def afficheEcranGestionCombat(self):
+        """affiche l'ecran de gestion du combat"""
+        self.gestionCombat = EcranGestionCombat(self)
+        self.gestionCombat.show()
+        self.connect(self.fenetre, SIGNAL("majListesPions"), self.majListesPions)
+        self.connect(self.gestionCombat, SIGNAL("majListesPions"), self.majListesPions)
+        QApplication.processEvents()
+##        r = self.gestionCombat.exec_()
+
+    def majOrdreJeu(self):
+        """met a jour l'ordre de jeu des pions en fonction de l'attribut prevu par les regles s'il existe,
+           ou en fonction de l'ordre de jeu parametre sinon"""
+        if len(self.ordreJeu) > 0:
+            attribut = regles.attributOrdreJeu()
+            if attribut != None:
+                dico = {}
+                for numCombattant in self.combattants:
+                    dico[numCombattant] = int(self.combattants[numCombattant].listeAttributs[attribut])
+                ordre = sorted(dico, key = dico.get, reverse=(regles.sensTriOrdreJeu() == 1)) 
+                self.ordreJeu = {}    
+                for numCombattant in self.combattants:
+                    self.ordreJeu[numCombattant] = ordre.index(numCombattant) + 1
+        self.majListeOrdreJeu()  
+
+    def pionDeplacerDansOrdreJeu(self, numCombattant, nouvellePosition):
+        """deplace un pion dans le dictionnaire gerant l'ordre de jeu de maniere a assurer sa coherence
+           nouvellePosition = 0 supprime le pion de la liste"""
+        if numCombattant in self.ordreJeu:
+            if nouvellePosition == 0:
+                del self.ordreJeu[numCombattant]
+        if len(self.ordreJeu) > 0:        
+            i = 0    
+            tmp = sorted(self.ordreJeu, key=self.ordreJeu.get)
+            if numCombattant in tmp:
+                tmp.remove(numCombattant)
+            for num in tmp:
+                i += 1
+                if i == nouvellePosition:
+                    self.ordreJeu[numCombattant] = i
+                    i += 1
+                self.ordreJeu[num] = i
+            if i < nouvellePosition:
+                self.ordreJeu[numCombattant] = i + 1 
+        elif nouvellePosition > 0:
+            self.ordreJeu[numCombattant] = 1
+        self.majOrdreJeu()
+
+    def listeAttributCelluleModifiee(self, ligne, colonne):
+        """une cellule de la liste des attributs a ete modifiee"""
+        if colonne != 1:
+            print("valeur non modifiable")
+        else:
+            #on verifie la validite de la donnee entree
+            lignesBase = ["Nom","Etat","Alt."]   #attention: modifier aussi dans majListeAttribut
+            if ligne < len(lignesBase):
+                pass
+            elif ligne >= 10:
+                attribut = regles.ordreAttributs()[(ligne - 10)]
+                nouvelleVal = str(self.fenetre.ui.pi_listeAttributs.item(ligne, 1).text().toUtf8())
+                valVerifiee = regles.listeControle()[attribut].controler(nouvelleVal)
+                if valVerifiee != None:
+                    self.pionSelectionne().listeAttributs[attribut] = valVerifiee
+                    if attribut == regles.attributOrdreJeu():
+                        print("maj ordre (a implementer)")
+                else:    
+                    self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[attribut]))))
+
+    def initListeAttaques(self):
+        """met en forme et connecte la liste des attaques du pion"""
+        self.fenetre.ui.pi_listeAttaques.setColumnWidth(0, 0) 
+        self.fenetre.ui.pi_listeAttaques.setColumnWidth(1, (0.3*self.fenetre.ui.pi_listeAttaques.width()))
+        self.fenetre.ui.pi_listeAttaques.setColumnWidth(2, (0.7*self.fenetre.ui.pi_listeAttaques.width()))
+        self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("itemSelectionChanged()"), self.majInfosAttaqueEC)
+        self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("cellClicked(int, int)"), self.listeAttaquesCelluleCliquee)
+        self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
+        self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(0, (0.49*self.fenetre.ui.pi_listeAttributsAttaqueEC.width())) 
+        self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(1, (0.5*self.fenetre.ui.pi_listeAttributsAttaqueEC.width()))
+        
+    def majListeAttaques(self):
+        """met a jour la liste des attaques du pion dans le panneau de combat"""
+        #on vide la liste
+        while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
+            self.fenetre.ui.pi_listeAttaques.removeRow(0)
+            
+        self.fenetre.ui.pi_listeAttaques.setVisible((self.pionSelectionne() != None))
+##        self.fenetre.ui.editerAttaques.setVisible((self.pionSelectionne() != None))
+        self.fenetre.ui.pi_panneauAttaqueEC.setVisible((self.pionSelectionne() != None))
+
+        i = 0
+        if self.pionSelectionne() != None:        
+            for attaque in self.pionSelectionne().attaques:
+                self.fenetre.ui.pi_listeAttaques.insertRow(i)
+                self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque)))))
+                icone = None
+                if attaque.typ == "cac":
+                    icone = QIcon(":/interface/16/ressource/epee_16.png")
+                if attaque.typ == "dist":
+                    icone = QIcon(":/interface/16/ressource/arc_16.png")
+                if attaque.typ == "zone":
+                    icone = QIcon(":/interface/16/ressource/baguette_16.png")
+                if icone != None:
+                    self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8("")))
+                self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom)))
+        self.majInfosAttaqueEC()                                                 
+
+    def listeAttaquesCelluleCliquee(self, ligne, colonne):
+        """on a clique sur une cellule de la liste des attaques"""
+        numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
+        if numAttaque >= 0:
+            self.utiliserAttaque(numAttaque)  
+
+    def utiliserAttaque(self, numAttaque):
+        """le pion selectionne utilise son attaque n"""
+        if self.pionSelectionne() != None:
+            if numAttaque < len(self.pionSelectionne().attaques):
+                attaque = self.pionSelectionne().attaques[numAttaque]
+                if attaque.typ == "cac":
+                    self.majModeCombat("combatAttaqueCaC")
+                if attaque.typ == "dist":
+                    self.majModeCombat("combatAttaqueDist")                
+                if attaque.typ == "zone":
+                    self.modeParam["typeAttaqueZone"] = attaque.formeZone
+                    self.fenetre.ui.pi_rayonAttaqueZone.setValue(attaque.rayon)
+                    self.majModeCombat("combatAttaqueZone")
+
+    def majInfosAttaqueEC(self):
+        """met a jour les infos de l'attaque en cours (selectionnee)"""
+        selection = self.fenetre.ui.pi_listeAttaques.selectedItems()
+        self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0)
+        
+        if self.pionSelectionne() != None and len(selection) > 0:
+            ligne = selection[0].row()
+            numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
+            self.disconnect(self.fenetre.ui.pi_panneauAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee)
+            #on vide la liste
+            while self.fenetre.ui.pi_listeAttributsAttaqueEC.rowCount() > 0:
+                self.fenetre.ui.pi_listeAttributsAttaqueEC.removeRow(0)
+                
+            self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(0)
+            self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 0, QTableWidgetItem(QString.fromUtf8("numAtt")))
+            self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 1, QTableWidgetItem(QString.fromUtf8(str(numAttaque))))
+            self.fenetre.ui.pi_listeAttributsAttaqueEC.setRowHidden(0, True)
+            
+            #attributs issus des regles utilisees    
+            ordre = regles.ordreAttributsAttaques()
+            for elt in ordre:
+                ligne = 1 + ordre.index(elt)
+                self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(ligne)
+                item = QTableWidgetItem(QString.fromUtf8(elt))
+                item.setFlags(Qt.NoItemFlags)
+                self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 0, item)
+                self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques[numAttaque].attributs[elt]))))
+                
+            self.connect(self.fenetre.ui.pi_listeAttributsAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee)
+            #maj des notes
+            self.disconnect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
+            self.fenetre.ui.pi_notesAttaqueEC.majTexte(self.pionSelectionne().attaques[numAttaque].notes)
+            self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
+            
+    def attaqueECCelluleModifiee(self, ligne, colonne):
+        """une cellule de la liste d'attributs de l'attaque en cours a ete modifiee"""
+        pass
+
+    def majNotesAttaqueEC(self):
+        """met a jour les notes de l'attaque en cours (selectionnee)"""
+        selection = self.fenetre.ui.pi_listeAttaques.selectedItems()
+        self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0)
+        if self.pionSelectionne() != None and len(selection) > 0:
+            ligne = selection[0].row()
+            numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))        
+            self.pionSelectionne().attaques[numAttaque].notes = str(self.fenetre.ui.pi_notesAttaqueEC.toPlainText().toUtf8())
+
+    def majNotesCombattant(self):
+        """les notes du pion ont ete mises a jour"""
+        if self.pionSelectionne() != None:
+            self.pionSelectionne().notes = str(self.fenetre.ui.pi_notes.toPlainText().toUtf8())
+        else:
+            pass
+            
+    ###############
+
+    ### panneau d'info
+    def majInfosCombattant(self, combattant=None):
+        self.fenetre.ui.inf_boitePion.maj(combattant)
+
+    def majInfosDecor(self, decor=None):
+        self.fenetre.ui.inf_boiteDecor.maj(decor)
+
+    def majInfosCase(self, case=None):
+        self.fenetre.ui.inf_boiteCase.maj(case)        
+
+    ############### fonctions de calcul ################ 
+    def coordonneesValides(self, coord):
+        """les coordonnees entrees en parametre sont elles celles d'une case du plateau"""
+        return (coord[0] >= 0 and coord[1] >= 0 and coord[0] < self.nbCasesX and coord[1] < self.nbCasesY)
+
+    def lstCoordAdjacentes(self, x, y):
+        """renvoie la liste des coordonnees adjacentes, !!!! sans condition d'existence sur le plateau !!!!
+           attention: l'ordre est important"""
+        if self.formeCases == "H":
+            if 1 == (x % 2):
+                voisins = [(x, y-1), (x+1, y), (x+1, y+1), (x,  y+1), (x-1, y+1), (x-1, y)]
+            else:
+                voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
+        else:
+            voisins = [(x, y-1), (x+1, y), (x,   y+1), (x-1, y)]
+        return voisins      
+
+    def zone(self, origine, rayon, z=0, conditionFranchissable = False, conditionVisible = False):
+        """renvoie un dictionnaire representant la liste des coordonnees des cases comprises dans la zone
+           la zone en question est la liste des cases situees a une distance d des coordonnees d'origine
+           z = 0 -> hauteur z de l'origine par rapport a l'altitude de la case
+           conditionFranchissable = Vrai -> les cases infranchissables ne sont pas prises en compte
+           conditionVisible = Vrai -> les cases bloquant la visibilite ne sont pas prises en compte"""
+        aVerifier = []
+        aVerifier2 = []
+        resultat = {}
+        k = 0        
+        #on part de la premiere case, puis on itere a partir de chaque nouveau depart sur les voisins
+        if origine in self.cases:
+            aVerifier.append(origine)
+            while k <= rayon:
+                for depart in aVerifier:
+                    for coord in self.cases[depart].voisins:
+                        if not coord in aVerifier and not coord in aVerifier2 and not coord in resultat:
+                            if conditionFranchissable and not conditionVisible:
+                                if self.cases[coord].estFranchissable(z):
+                                    aVerifier2.append(coord)
+                                elif not conditionFranchissable and conditionVisible:          
+                                    if self.cases[coord].terrain.visibilite:
+                                        aVerifier2.append(coord)
+                            elif conditionFranchissable and conditionVisible:          
+                                if self.cases[coord].estFranchissable(z) and self.cases[coord].terrain.visibilite:
+                                    aVerifier2.append(coord)
+                            else:
+                                aVerifier2.append(coord)      
+                for elt in aVerifier:
+                    resultat[elt] = k
+                aVerifier = aVerifier2
+                aVerifier2 = []
+                k += 1
+        return resultat
+
+    def zone3d(self, origine, rayon, zCible=0):
+        """renvoie les cases de la zone au format (x, y, z)"""
+        retour = []
+        zone = self.zone(origine, rayon)
+        for coord in zone:
+            x, y = coord
+            dz = rayon - zone[coord]
+            for z in range(-dz, dz + 1):
+                retour.append( (x, y, (zCible+z) ) )
+        return retour            
+
+    def cone(self, coord1, coord2):
+        """renvoie les coord des cases composant le cone (en 2d)"""
+        pass
+
+    def polygoneAgglo(self, listeCases):
+        """renvoie un polygone contruit par agglomeration des polygones des cases de la liste
+           les cases doivent etre adjacentes (cases hexagonales ou carrees)"""
+        pointsPolygone = []
+        segments = []
+        case = Case(self)
+        
+        #on verifie que toutes les cases sont adjacentes les unes aux autres
+        valide = True
+        if len(listeCases) > 1:
+            for coord in listeCases:
+                if not len(set(listeCases).intersection(self.lstCoordAdjacentes(coord[0], coord[1]))) > 0: valide = False
+        if not len(listeCases) > 0:
+            valide = False
+        
+        if valide:
+            #on parcourt les faces des polygones des cases, et on ne garde que ceux qui n'ont pas de case 'en face'
+            for coord in listeCases:
+                polygone = case.polygone(coord[0], coord[1])
+                voisins = self.lstCoordAdjacentes(coord[0], coord[1])
+                
+                for i in range(0, len(voisins)):
+                    if not voisins[i] in listeCases:
+                        j = i+1
+                        if j > len(voisins) - 1:
+                            j = 0
+                        segments.append(QLineF(polygone[i], polygone[j]))
+
+            #on 'accroche' les segments les uns aux autres, dans l'ordre
+            segments2 = [segments[0]]
+            for segment2 in segments2:
+                for segment in segments:
+                    if not QLineF(segment.p1(), segment.p2()) in segments2 and not QLineF(segment.p2(), segment.p1()) in segments2:
+                        if sqrt((segment.p1().x()-segment2.p2().x())**2+(segment.p1().y()-segment2.p2().y())**2) < 1:
+                            segments2.append(QLineF(segment.p1(), segment.p2()))
+                        elif sqrt((segment.p2().x()-segment2.p2().x())**2+(segment.p2().y()-segment2.p2().y())**2) < 1:   
+                            segments2.append(QLineF(segment.p2(), segment.p1()))
+
+            pointsPolygone = []
+            premierPoint = segments2[0].p1()
+            pointsPolygone.append(premierPoint)
+            for segment in segments2:
+                pointSuivant = segment.p2()
+                if pointSuivant != premierPoint:
+                    pointsPolygone.append(pointSuivant)
+
+            #creation du polygone
+            polygone = QPolygonF()
+            for point in pointsPolygone:   
+                polygone.append(point)   
+        else:
+            polygone = None
+
+        return polygone  
+
+    def coordCentreListeCases(self, listeCases):
+        """renvoie les coordonnees centrales d'une liste de cases"""
+        retour = None
+        if len(listeCases) > 0:
+            listeTriee = sorted(listeCases)
+            posMilieu = int(len(listeCases)/2)
+            retour = listeTriee[posMilieu]
+        return retour    
+
+    def coordonneesAuPoint(self, point):
+        """renvoie les coordonnees de la case situee au QPointF entre en parametre"""
+        coord = None
+        if point != None:
+            lstObjets = self.vue().scene().items(point)
+            for objet in lstObjets:
+                if objet:
+                    if objet.__class__.__name__ == "Case":
+                        coord = (objet.x, objet.y)
+                        break       
+        return coord            
+
+    def casesSousForme(self, forme, plein = True, epaisseur = 0):
+        """renvoie la liste des cases en collision avec un QGraphicsItem en parametre
+            plein = False: pas le contenu de la forme
+            epaisseur = renvoie aussi les cases voisines jusqu'a la distance demandee"""
+        tmp = []
+        listeCases = []
+        point1 = None
+        point2 = None
+        #point 1 et 2
+        if forme.__class__.__name__ == "QGraphicsLineItem":
+            point1 = forme.line().p1()
+            point2 = forme.line().p2()
+        elif forme.__class__.__name__ == "QGraphicsRectItem" or forme.__class__.__name__ == "QGraphicsEllipseItem":
+            point1 = forme.rect().topLeft()
+            point2 = forme.rect().bottomRight()
+        else:
+            point1 = forme.boundingRect().topLeft()
+            point2 = forme.boundingRect().bottomRight()            
+ 
+        #preselection des cases (meilleures perf)    
+        if point1 != None and point2 != None and point1 != point2:
+            preSelection = self.preSelectionCollision(point1, point2)
+        else:
+            preSelection = []
+            for coord in self.cases:
+                preSelection.append(coord)
+       
+        #on liste les cases en collision avec la forme 
+        for coord in preSelection:
+            if self.cases[coord].collidesWithItem(forme, Qt.IntersectsItemShape):
+                if plein:
+                    tmp.append(coord) 
+                else:
+                    contenu = True
+                    for i in range(0,len(self.cases[coord].polygon())):
+                        if not forme.contains(self.cases[coord].polygon().at(i)):
+                            contenu = False
+                            break
+                    if contenu == False:
+                        tmp.append(coord)    
+        #on applique l'epaisseur du pinceau (lignes ou formes vides seulement) si necessaire
+        if not plein and epaisseur > 0:
+            for coord in tmp:
+                zone = self.zone(coord, epaisseur)
+                for coord2 in zone:
+                    if not coord2 in listeCases:
+                        listeCases.append(coord2)
+        else:
+            listeCases = tmp
+        #si la liste est vide, on ajoute l'origine de la forme
+        if len(listeCases) == 0:
+            listeCases = [self.coordonneesAuPoint(point1)]    
+        return listeCases                
+
+    def preSelectionCollision(self, point1, point2):
+        """renvoie une liste des cases qui peuvent etre concernees par une collision avec
+           un graphicsItem (pour des raisons de performance)"""
+        preSelection = []
+        coord1 = self.coordonneesAuPoint(point1)  
+        coord2 = self.coordonneesAuPoint(point2)
+        if coord1 != None and coord2 != None:
+            minX = min(coord1[0], coord2[0]) - 1
+            maxX = max(coord1[0], coord2[0]) + 1
+            minY = min(coord1[1], coord2[1]) - 1
+            maxY = max(coord1[1], coord2[1]) + 1
+            for coord in self.cases:
+                if coord[0] >= minX and coord[0] <= maxX and coord[1] >= minY and coord[1] <= maxY :
+                    preSelection.append(coord)
+        else:
+            preSelection = self.cases
+        return preSelection
+    
+    def listeZCible(self, coord):
+        """retourne l'altitude absolue a prendre en compte en fonction de la case ciblee
+            c'est l'altitude la case si aucun pion n'occupe la case
+            c'est la liste des cases occupees en hauteur par le pion sinon
+            'coord' est de la forme (x, y)"""
+        if self.cases[coord].estOccupee():
+            retour = range(self.cases[coord].occupant().zAbs(), \
+                            self.cases[coord].occupant().zAbs() + self.cases[coord].occupant().hauteur)
+        else:
+            retour = [self.cases[coord].altitude]             
+        return retour
+
+    def estCibleAttaqueDistValide(self, coordCible):
+        """la case cible est elle valide pour une attaque a distance depuis la position et hauteur
+            du pion selectionne
+            les coord sont de la forme (x, y)"""
+        valide = False
+        x1, y1 = self.pionSelectionne().position
+        coordOrigine = (x1, y1, (self.pionSelectionne().zAbs() + self.pionSelectionne().hauteur))
+        
+        x2, y2 = coordCible
+        cible = self.cases[coordCible].occupant()
+        listeZ2 = self.listeZCible(coordCible)      
+        if coordOrigine[0] != coordCible[0] or coordOrigine[1] != coordCible[1]:
+            for z2 in listeZ2:
+                zValide = True
+                casesLigneMire = br.ligne(coordOrigine, (x2, y2, z2), self.formeCases)
+                casesLigneMire.remove(coordOrigine)
+                casesLigneMire.remove((x2, y2, z2))
+                for coord in casesLigneMire:
+                    if zValide:
+                        x, y, z = coord
+                        if self.cases[(x,y)].estOccupee(z): 
+                            if self.cases[(x,y)].occupant(z) not in [self.pionSelectionne(), cible]:
+                                zValide = False
+                if zValide: 
+                    valide = True #si au moins un des z cibles est valide, la ligne de mire est valide
+                    break
+                
+        return valide       
+                      
+    def pionSurCase(self, coord):
+        """renvoie le pion present sur la case, none sinon"""
+        retour = None
+        for num in self.combattants:
+            if self.combattants[num].position == coord:
+                retour = num
+        return retour        
+
+    def pionsSurListeCase(self, listeCases):
+        """renvoie la liste des num des pions presents sur la liste de cases"""
+        retour = []
+        for coord in listeCases:
+            pion = self.cases[coord].occupant()
+            if pion != None and not pion.numero in retour:
+                retour.append(pion.numero)
+        return retour   
+
+    def majZonePlacement(self, listeCases):
+        """met a jour la forme et l'affichage de la zone de placement initale des joueurs"""
+        if len(listeCases) > 0:
+            if self.polygoneZonePlacement == None:
+                self.polygoneZonePlacement = QGraphicsPolygonItem(scene=self)
+                self.polygoneZonePlacement.setZValue(0)
+                qCouleurFond = QColor("white")
+                qCouleurFond.setAlpha(50)
+                self.polygoneZonePlacement.setBrush(qCouleurFond)
+                pinceau = QPen(QColor("orange"))
+                pinceau.setWidth(20)
+                self.polygoneZonePlacement.setPen(pinceau)
+                self.polygoneZonePlacement.setAcceptedMouseButtons(Qt.NoButton)
+                self.polygoneZonePlacement.setAcceptHoverEvents(False)
+                self.addItem(self.polygoneZonePlacement)
+            listeCases2 = []    
+            for coord in listeCases:
+                if self.cases[coord].estFranchissable():
+                    listeCases2.append(coord)
+            self.polygoneZonePlacement.setPolygon(self.polygoneAgglo(listeCases2))
+            self.listeCasesZonePlacement = listeCases
+
+    def materialiserPions(self,actif):
+        """avtive/desactive la reception par les pions (autres que le pion selectionne) des hover events"""
+        for numCombattant in self.combattants:
+            if numCombattant != self.modeParam["numPionSelectionne"]:
+                self.combattants[numCombattant].setAcceptsHoverEvents(actif)
+                self.combattants[numCombattant].polygoneGraphique.setAcceptsHoverEvents(actif)
+        for numCombattant in self.decors:
+            self.decors[numCombattant].setAcceptsHoverEvents(actif)
+            self.decors[numCombattant].polygoneGraphique.setAcceptsHoverEvents(actif)
+                
+    #######################
+
+    ######## interaction avec les cases, decors et pions  #############
+    def pionSelectionne(self):
+        """renvoie le pion actuellement selectionne"""
+        retour = None
+        if self.modeActif.__class__.__name__ == "PionSelectionne":
+            retour = self.modeActif.pion()
+        return retour    
+
+    def caseCliquee(self, x, y):
+        """on a clique sur la case (clic gauche)"""
+        coord = (x, y)
+        accepte = self.modeActif.clic_case(coord)   
+        return accepte  
+
+    def caseSurvolClicEnfonce(self, coord):
+        """une case est survolee par le curseur (le clic gauche est enfonce)"""
+        accepte = self.modeActif.survolClic_case(coord)
+        return accepte
+    
+    def caseSurvol(self, x, y):
+        """une case est survole par le curseur, on affiche ses informations dans la zone prevue"""
+        self.majInfosCase(self.cases[(x,y)]) 
+        accepte = self.modeActif.survol_case((x,y))
+        return accepte
+                             
+    def afficherListeCases(self, listeCases, actif):
+        """met ou non en evidence les cases selectionnees"""
+        for coord in listeCases:
+            self.cases[coord].majEstCibleCurseur(actif)
+
+    def pionClique(self, num):
+        """on a clique sur ce pion"""
+        if num < 10000:
+            accepte = self.modeActif.clic_combattant(num)
+        else:
+            accepte = self.modeActif.clic_decor(num)
+        return accepte
+    
+    def combattantSurvol(self, num):
+        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
+        accepte = self.modeActif.survol_combattant(num)
+        pion = self.combattants[num]
+        self.majInfosCombattant(pion)
+        if not accepte: 
+            accepte = self.caseSurvol(pion.position[0], pion.position[1])
+        return accepte        
+
+    def combattantFinSurvol(self, num):
+        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
+        accepte = self.modeActif.finSurvol_combattant(num)
+        self.majInfosCombattant(None)
+        return accepte 
+
+    def decorSurvol(self, num):
+        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
+        accepte = self.modeActif.survol_decor(num)
+        pion = self.decors[num]
+        self.majInfosDecor(pion)
+        if not accepte: 
+            accepte = self.caseSurvol(pion.position[0], pion.position[1])
+        return accepte
+    
+    def decorFinSurvol(self, num):
+        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
+        accepte = self.modeActif.finSurvol_decor(num)
+        self.majInfosDecor(None)
+        return accepte
+                
+    def pionDoubleClic(self, numCombattant):
+        """on a double-clique sur le pion"""
+        accepte = self.modeActif.doubleClic_combattant(numCombattant)       
+        return accepte
+    
+    def creerPion(self, pionModele):
+        """creer un pion (combattant ou decor) aux coordonnees indiquees"""
+        cree = False
+        if self.proj.projectionValide():
+
+            if pionModele.__class__.__name__ == "Combattant":
+                pion = Combattant()
+            elif pionModele.__class__.__name__ == "Decor":
+                pion = Decor()
+
+            for elt in pionModele.__dict__:
+                pion.__dict__[elt] = pionModele.__dict__[elt]
+            
+            if pionModele.__class__.__name__ == "Combattant":
+                numero = 1
+                if len(self.combattants) > 0:
+                    numero = max(self.combattants) + 1
+                pion.numero = numero    
+                pion.numComplementaire = self.numeroterNom(pion.nom)    
+                self.combattants[numero] = pion
+                self.pionDeplacerDansOrdreJeu(numero, len(self.ordreJeu) + 2)
+                
+            elif pionModele.__class__.__name__ == "Decor":
+                numero = 10001
+                if len(self.decors) > 0:
+                    numero = max(self.decors) + 10001
+                pion.numero = numero
+                self.decors[numero] = pion
+
+            pion.position = self.proj.coord()
+            pion.nbRotations = self.proj.nbRotations()
+            pion.ajouterAuPlateau(self)
+
+            cree = True
+        return cree            
+
+    def numeroterNom(self, nom):
+        """renvoie le nom du pion avec un numero complementaire si necessaire """
+        i = 1
+        for numCombattant in self.combattants:
+            if self.combattants[numCombattant].nom == nom:
+                i += 1     
+        if i == 1:
+            retour = ""
+        else:
+            retour = str(i)
+        return retour
+        
+    def pionDeposer(self, coordCase):
+        """on depose le pion sur la case voulue"""
+        if self.pionSelectionne() != None:
+            pion = self.pionSelectionne()
+        
+        if pion != None:
+            if self.proj.projectionValide():        
+                pion.majPosition(self.proj.coord(), self.proj.nbRotations())
+
+    def majZPion(self, valeur):
+        """met a jour l'altitude du pion selectionne"""
+        if self.pionSelectionne() != None:
+            self.pionSelectionne().majZ(valeur)
+
+    def dialogueVol(self, actuelle):
+        ecran = EcranVol(actuelle)
+        ecran.exec_() 
+        nouvelle = ecran.resultat()
+        del ecran
+        return nouvelle   
+            
+    def pionSupprimer(self, num):
+        """supprime le pion entre en parametre"""
+        #settrace(trace_calls)
+        if num in self.combattants:    
+            self.pionDeplacerDansOrdreJeu(num, 0)
+            pionSuppr = self.combattants.pop(num)
+        elif num in self.decors:    
+            pionSuppr = self.decors.pop(num)
+            
+        pionSuppr.retirerDuPlateau()
+            
+    ###############
+
+    ######### caches ###############
+    def activerModeCreationCache(self):
+        self.activerMode(Modes.EditerCaches)
+
+    def activerModeEditionCache(self):
+        idCache = int(self.fenetre.ui.cp_listeCaches.texte(self.fenetre.ui.cp_listeCaches.currentRow(), 0))
+        self.activerMode(Modes.EditerCaches, idCache)
+
+    def initListeCaches(self):
+        """charge la liste des caches avec les donnees en memoire"""
+        self.fenetre.ui.cp_listeCaches.setColumnWidth(0, 10)
+        self.fenetre.ui.cp_listeCaches.setColumnWidth(1, 100)
+        self.fenetre.ui.cp_listeCaches.setColumnWidth(2, 18)
+        for idCache in self.caches:
+            self.ajouterCacheATable(self.caches[idCache])
+
+    def nouveauCache(self, listeCases):
+        nouvelId = 0
+        if len(self.caches) > 0:
+            nouvelId = max(self.caches) + 1
+        cache = Cache(nouvelId)
+        cache.activer(True)
+        cache.nom = "Cache {}".format(nouvelId + 1)
+        self.caches[nouvelId] = cache
+        self.ajouterCacheATable(cache)
+        for coord in listeCases:
+            self.cases[coord].ajouterCache(nouvelId)        
+
+    def editerFormeCache(self, idCache, listeCases):
+        """edite le cache avec la liste des cases en param"""
+        actif = self.caches[idCache].actif()
+        for coord in self.cases:
+            if coord in listeCases:
+                self.cases[coord].ajouterCache(idCache, actif)
+            else:
+                self.cases[coord].supprimerCache(idCache)
+        
+    def majEtatCache(self, actif):
+        emetteur = self.sender().objectName()
+        idCache = int(emetteur.replace("afficherCache_", ""))
+        self.caches[idCache].activer(actif)
+        if actif:
+            nomImg = "oeilBarre2_32.png"
+        else:
+            nomImg = "oeil_32.png"
+        self.fenetre.ui.cp_listeCaches.item(idCache, 1).setIcon(QIcon(":/interface/32/ressource/{}".format(nomImg)))
+        for coord in self.cases:
+            self.cases[coord].activerCache(idCache, actif)
+
+    def majNomCache(self, ligne, colonne):
+        idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0))
+        nouveauNom = self.fenetre.ui.cp_listeCaches.texte(ligne, 1)
+        if nouveauNom != self.caches[idCache].nom:
+            self.caches[idCache].nom = nouveauNom
+
+    def supprimerCache(self):
+        ligne = self.fenetre.ui.cp_listeCaches.currentRow()
+        idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0)) 
+        for coord in self.cases:
+            self.cases[coord].supprimerCache(idCache)
+        self.fenetre.ui.cp_listeCaches.removeRow(idCache)
+        del self.caches[idCache]
+
+    def mettreCacheEnEvidence(self, ligne, colonne):
+        idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0))
+        for coord in self.cases:
+            if len(self.cases[coord].cachesActifs) > 0:
+                self.cases[coord].polygoneCache.activerSurbrillance((idCache in self.cases[coord].cachesActifs))        
+
+    def ajouterCacheATable(self, cache):
+        """ajoute le cache a la table des caches"""
+        self.fenetre.disconnect(self.fenetre.ui.cp_listeCaches, SIGNAL("cellChanged(int,int)"), self.majNomCache)
+        ligne = self.fenetre.ui.cp_listeCaches.nouvelleLigneFin()
+        if cache.actif():
+            nomImg = "oeilBarre2_32.png"
+        else:
+            nomImg = "oeil_32.png"
+        self.fenetre.ui.cp_listeCaches.majTexte(ligne, 0, str(cache.numero))  
+          
+        item = QTableWidgetItem(QIcon(":/interface/32/ressource/{}".format(nomImg)), cache.nom)
+        item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable)
+        self.fenetre.ui.cp_listeCaches.setItem(ligne, 1, item)
+        
+        widget = QCheckBox(QString(""))
+        widget.setChecked(cache.actif())
+        widget.setObjectName(QString("afficherCache_{}".format(ligne)))
+        self.connect(widget, SIGNAL("toggled(bool)"), self.majEtatCache)
+        self.fenetre.ui.cp_listeCaches.setCellWidget(ligne, 2, widget)
+        
+        self.fenetre.connect(self.fenetre.ui.cp_listeCaches, SIGNAL("cellChanged(int,int)"), self.majNomCache, Qt.UniqueConnection)
+    ###############"
+        
+    ######### gestion des evenements souris et clavier ###############
+    def mouseMoveEvent(self, event):
+        super(Plateau, self).mouseMoveEvent(event)
+        if event.buttons() == Qt.LeftButton and self.vue().dragMode() != QGraphicsView.ScrollHandDrag:
+            coord = self.coordonneesAuPoint(event.scenePos())
+            if coord != None:
+                self.caseSurvolClicEnfonce(coord)  
+        else:
+            self.modeActif.mouvementSouris(event)
+            event.ignore() 
+
+    def mousePressEvent(self, event):
+        super(Plateau, self).mousePressEvent(event)
+        if event.button() == 1:
+            self.modeActif.clicGauche(event)
+        elif event.button() == 2:
+            self.modeActif.clicDroit(event)
+            event.accept()
+
+    def mouseReleaseEvent(self, event):
+        super(Plateau, self).mouseReleaseEvent(event)
+        self.modeActif.finClicGauche(event)
+
+    def keyPressEvent(self, event):
+        """gestion des evenements clavier"""
+        self.modeActif.toucheClavier(event)
+
+    ################   
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        
+  
+
+

+ 29 - 33
lib/afficherSousMenu.py

@@ -1,33 +1,29 @@
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from PyQt4 import uic
-import os
-from sys import argv
-
-UiSousMenu, _ = uic.loadUiType(os.path.join(
-    os.path.dirname(__file__), 'ui/sousMenu.ui'))
-
-class SousMenu(QDialog, UiSousMenu):
-    """affiche une fenetre pourvue d'onglets horizontaux""" 
-    def __init__(self, parent=None):
-        """Construction de la fenetre"""
-        super(SousMenu, self).__init__(parent)
-        self.setupUi(self)
-        self.connect(self.listeMenus, SIGNAL("cellClicked(int,int)"), self.menuChange, Qt.UniqueConnection)
-        self.listeMenus.setCurrentCell(0,0)
-        self.menus.setCurrentIndex(0)
-        
-    def menuChange(self, ligne, col):
-        """le menu a ete change dans la QTableWidget"""
-        self.menus.setCurrentIndex(ligne)
-
-
-
-
-if __name__ == "__main__":
-   app = QApplication(argv)
-   #settrace(trace_calls)
-   sm = SousMenu()
-   sm.show()
-   r = app.exec_()
-   exit(r)      
+from PyQt4.QtCore import Qt, SIGNAL
+from PyQt4.QtGui import QDialog, QApplication 
+from PyQt4 import uic
+import os
+from sys import argv
+
+UiSousMenu, _ = uic.loadUiType(os.path.join(
+    os.path.dirname(__file__), 'ui/sousMenu.ui'))
+
+class SousMenu(QDialog, UiSousMenu):
+    """affiche une fenetre pourvue d'onglets horizontaux""" 
+    def __init__(self, parent=None):
+        """Construction de la fenetre"""
+        super(SousMenu, self).__init__(parent)
+        self.setupUi(self)
+        self.connect(self.listeMenus, SIGNAL("cellClicked(int,int)"), self.menuChange, Qt.UniqueConnection)
+        self.listeMenus.setCurrentCell(0,0)
+        self.menus.setCurrentIndex(0)
+        
+    def menuChange(self, ligne, col):
+        """le menu a ete change dans la QTableWidget"""
+        self.menus.setCurrentIndex(ligne)
+
+if __name__ == "__main__":
+    app = QApplication(argv)
+    sm = SousMenu()
+    sm.show()
+    r = app.exec_()
+    exit(r)      

BIN
lib/biblio/decor


+ 199 - 200
lib/br.py

@@ -1,200 +1,199 @@
-"""Algorithme de Bresenham"""
-from __future__ import division
-from math import *
-from dmF import *
-
-def ligne(coord1, coord2, formeCases = "H"):
-    if coord1[0] != coord2[0] or coord1[1] != coord2[1]:
-        if len(coord1) == 2 and len(coord2) == 2:
-            retour = _ligne2d(coord1, coord2, formeCases)
-        elif len(coord1) == 3 and len(coord2) == 3:
-            retour = _ligne3d(coord1, coord2, formeCases)
-        elif len(coord1) == 2 and len(coord2) == 3: 
-            x1, y1 = coord1
-            retour = _ligne3d((x1, y1, 0), coord2, formeCases)
-        elif len(coord1) == 2 and len(coord2) == 3: 
-            x2, y2 = coord2
-            retour = _ligne3d(coord1, (x2, y2, 0), formeCases)
-        else:
-            retour = [coord1]   
-    else:            
-        retour = [coord1]
-         
-    return retour    
-                
-def _ligne2d(coord1, coord2, formeCases = "H"):
-    """renvoie la liste des cases traversees par la ligne entre les cases 1 et 2
-        prend en parametre des coord de la forme (x,y)"""
-    x1, y1 = coord1
-    x2, y2 = coord2
-
-    # on inverse les coord si necessaire (si on va de gauche a droite)
-    inversee = False
-    if x1 > x2:
-        x1, x2 = x2, x1
-        y1, y2 = y2, y1
-        inversee = True
-
-    if formeCases == "H":
-        retour = _brH(x1, y1, x2, y2)
-    else:
-        retour = _brC(x1, y1, x2, y2)
-        
-    # retourne la liste si les coordonnees ont ete interverties
-    if inversee:
-        retour.reverse()
-    return retour
-
-
-def _ligne3d(coord1, coord2, formeCases = "H"):
-    """renvoie la liste des cases traversees par la ligne entre les cases 1 et 2
-        prend en parametre des coord de la forme (x,y, z)"""
-    x1, y1, z1 = coord1
-    x2, y2, z2 = coord2
-    ligne = _ligne2d((x1, y1), (x2, y2), formeCases)
-    ligneZ = _brC(0, z1, (len(ligne)-1), z2)
-    
-    retour = []
-    for coordZ in ligneZ:
-        dist, z = coordZ
-        x, y = ligne[dist]
-        retour.append((x, y, z))
-        
-    return retour
-
-def _brC(x1, y1, x2, y2):
-    """Algorithme ligne de Bresenham (pour cases carrees)"""
-
-    # on verifie si la ligne est plus verticale qu'horizontale
-    estVerticale = abs(y2 - y1) > abs(x2 - x1)
-    if estVerticale:
-        x1, y1 = y1, x1
-        x2, y2 = y2, x2  
-
-    # Calcul des ecarts
-    dx = x2 - x1
-    dy = y2 - y1
- 
-    # Calcul de l'erreur  (l'ecart qui doit s'accumuler au fur et a mesure qu'on avance)
-    #2dx est l'unite, de maniere a travailler avec des entiers
-    error = 0.0
-    pasY = 1 if y1 < y2 else -1
- 
-    # on itere sur les coordonnees de la boite qui contient les coordonnees 1 et 2
-    y = y1
-    retour = []
-    for x in range(x1, x2 + 1):
-        coord = (y, x) if estVerticale else (x, y)
-        retour.append(coord)
-        error += (abs(dy) / dx)
-        if error > 0.5:
-            y += pasY
-            error -= 1.0
-
-    return retour
-
-def _brH(x1, y1, x2, y2):
-    """Algorithme ligne de Bresenham (pour cases hexagonales)"""
-    #calcul selon secteur
-    if abs(x2 - x1) < (2*abs((y2-y1)) + abs(x2 % 2) - abs(x1 % 1)):
-        retour = _brH_v(x1, y1, x2, y2)
-    else:
-        retour = _brH_h(x1, y1, x2, y2)   
-    return retour
-        
-def _brH_h(x1, y1, x2, y2):
-    """Algorithme ligne de Bresenham (pour cases hexagonales - secteur horizontal)"""  
-    # Calcul des ecarts
-    dx = x2 - x1
-    dy = y2 - y1 
-    if (x1 + x2) % 2 == 1: 
-        if x1 % 2 == 0:
-            dy += 0.5
-        else:
-            dy -= 0.5
-                
-    # Calcul de l'erreur  (l'ecart qui doit s'accumuler au fur et a mesure qu'on avance)
-    k = dy / dx
-    pas = 1
-    
-    # on itere sur les coordonnees de la boite qui contient les coordonnees 1 et 2
-    retour = []
-    d = 0.0
-    pos = (x1, y1)
-    retour.append(pos)
-    
-    while pos != (x2, y2):
-        d += k*pas
-        if d > 0:
-            #on se deplace vers la case en dessous a droite 
-            x, y = pos
-            if x %2 == 0:
-                pos = x + 1, y 
-            else:
-                pos = x + 1, y + 1 
-            retour.append(pos)
-            d -= 0.5
-        else:
-            #on se deplace vers la case au dessus a droite
-            x, y = pos
-            if x %2 == 0:
-                pos = x + 1, y - 1   
-            else:
-                pos = x + 1, y         
-            retour.append(pos)
-            d += 0.5
-        
-        if pos[0] > x2:
-            retour = []
-            break
-                      
-    return retour
-    
-def _brH_v(x1, y1, x2, y2):
-    """Algorithme ligne de Bresenham (pour cases hexagonales - secteur vertical)"""
-    #on prend comme unite la demi largeur: u = 0.5773
-    #la demi hauteur d'un hexa vaut donc 0.8860u, ou sqrt(3)/2
-    #[a revoir] une fois cela pose, on muliplie tout par 4dy afin d'eviter nombres flottants et divisions
-    sens = 1 if y2 > y1 else -1
-
-    # Calcul des ecarts
-    dx = 1.5 * (x2 - x1)      #en x, on a 1.5u de centre a centre
-    dy = sens * (y2 - y1)     #en y, on compte en demi hauteurs
-    if (x1 + x2) % 2 == 1: 
-        if x1 % 2 == 0:
-            dy += sens*0.5
-        else:
-            dy -= sens*0.5
-
-    k = dx/(dy*sqrt(3)) #k est la tangente de l'angle par rapport a la verticale
-    pas = 0.5*sqrt(3)   #on avance par demi hauteurs
-
-    retour = []
-    d = 0.0     #decalage
-    pos = (x1, y1)
-    retour.append(pos)
-    
-    while pos != (x2, y2):
-        d += (k*pas)
-        if d <= 0.5:
-            #on se deplace vers la case en dessous (ou au dessus)
-            x, y = pos
-            pos = x, y + sens
-            retour.append(pos)
-            d += (k*pas)
-        else:
-            #on se deplace vers la case en dessous (ou au dessus) a droite
-            x, y = pos
-            if (x %2 == 0 and sens == 1) or (x % 2 == 1 and sens == -1):
-                pos = x + 1, y
-            else:
-                pos = x + 1, y + sens            
-            retour.append(pos)
-            d -= 1.5
-        
-        if sens*pos[1] > sens*y2:
-            retour = []
-            break
-
-    return retour 
-
+"""Algorithme de Bresenham"""
+from __future__ import division
+from math import sqrt
+
+def ligne(coord1, coord2, formeCases = "H"):
+    if coord1[0] != coord2[0] or coord1[1] != coord2[1]:
+        if len(coord1) == 2 and len(coord2) == 2:
+            retour = _ligne2d(coord1, coord2, formeCases)
+        elif len(coord1) == 3 and len(coord2) == 3:
+            retour = _ligne3d(coord1, coord2, formeCases)
+        elif len(coord1) == 2 and len(coord2) == 3: 
+            x1, y1 = coord1
+            retour = _ligne3d((x1, y1, 0), coord2, formeCases)
+        elif len(coord1) == 2 and len(coord2) == 3: 
+            x2, y2 = coord2
+            retour = _ligne3d(coord1, (x2, y2, 0), formeCases)
+        else:
+            retour = [coord1]   
+    else:            
+        retour = [coord1]
+         
+    return retour    
+                
+def _ligne2d(coord1, coord2, formeCases = "H"):
+    """renvoie la liste des cases traversees par la ligne entre les cases 1 et 2
+        prend en parametre des coord de la forme (x,y)"""
+    x1, y1 = coord1
+    x2, y2 = coord2
+
+    # on inverse les coord si necessaire (si on va de gauche a droite)
+    inversee = False
+    if x1 > x2:
+        x1, x2 = x2, x1
+        y1, y2 = y2, y1
+        inversee = True
+
+    if formeCases == "H":
+        retour = _brH(x1, y1, x2, y2)
+    else:
+        retour = _brC(x1, y1, x2, y2)
+        
+    # retourne la liste si les coordonnees ont ete interverties
+    if inversee:
+        retour.reverse()
+    return retour
+
+
+def _ligne3d(coord1, coord2, formeCases = "H"):
+    """renvoie la liste des cases traversees par la ligne entre les cases 1 et 2
+        prend en parametre des coord de la forme (x,y, z)"""
+    x1, y1, z1 = coord1
+    x2, y2, z2 = coord2
+    ligne = _ligne2d((x1, y1), (x2, y2), formeCases)
+    ligneZ = _brC(0, z1, (len(ligne)-1), z2)
+    
+    retour = []
+    for coordZ in ligneZ:
+        dist, z = coordZ
+        x, y = ligne[dist]
+        retour.append((x, y, z))
+        
+    return retour
+
+def _brC(x1, y1, x2, y2):
+    """Algorithme ligne de Bresenham (pour cases carrees)"""
+
+    # on verifie si la ligne est plus verticale qu'horizontale
+    estVerticale = abs(y2 - y1) > abs(x2 - x1)
+    if estVerticale:
+        x1, y1 = y1, x1
+        x2, y2 = y2, x2  
+
+    # Calcul des ecarts
+    dx = x2 - x1
+    dy = y2 - y1
+ 
+    # Calcul de l'erreur  (l'ecart qui doit s'accumuler au fur et a mesure qu'on avance)
+    #2dx est l'unite, de maniere a travailler avec des entiers
+    error = 0.0
+    pasY = 1 if y1 < y2 else -1
+ 
+    # on itere sur les coordonnees de la boite qui contient les coordonnees 1 et 2
+    y = y1
+    retour = []
+    for x in range(x1, x2 + 1):
+        coord = (y, x) if estVerticale else (x, y)
+        retour.append(coord)
+        error += (abs(dy) / dx)
+        if error > 0.5:
+            y += pasY
+            error -= 1.0
+
+    return retour
+
+def _brH(x1, y1, x2, y2):
+    """Algorithme ligne de Bresenham (pour cases hexagonales)"""
+    #calcul selon secteur
+    if abs(x2 - x1) < (2*abs((y2-y1)) + abs(x2 % 2) - abs(x1 % 1)):
+        retour = _brH_v(x1, y1, x2, y2)
+    else:
+        retour = _brH_h(x1, y1, x2, y2)   
+    return retour
+        
+def _brH_h(x1, y1, x2, y2):
+    """Algorithme ligne de Bresenham (pour cases hexagonales - secteur horizontal)"""  
+    # Calcul des ecarts
+    dx = x2 - x1
+    dy = y2 - y1 
+    if (x1 + x2) % 2 == 1: 
+        if x1 % 2 == 0:
+            dy += 0.5
+        else:
+            dy -= 0.5
+                
+    # Calcul de l'erreur  (l'ecart qui doit s'accumuler au fur et a mesure qu'on avance)
+    k = dy / dx
+    pas = 1
+    
+    # on itere sur les coordonnees de la boite qui contient les coordonnees 1 et 2
+    retour = []
+    d = 0.0
+    pos = (x1, y1)
+    retour.append(pos)
+    
+    while pos != (x2, y2):
+        d += k*pas
+        if d > 0:
+            #on se deplace vers la case en dessous a droite 
+            x, y = pos
+            if x %2 == 0:
+                pos = x + 1, y 
+            else:
+                pos = x + 1, y + 1 
+            retour.append(pos)
+            d -= 0.5
+        else:
+            #on se deplace vers la case au dessus a droite
+            x, y = pos
+            if x %2 == 0:
+                pos = x + 1, y - 1   
+            else:
+                pos = x + 1, y         
+            retour.append(pos)
+            d += 0.5
+        
+        if pos[0] > x2:
+            retour = []
+            break
+                      
+    return retour
+    
+def _brH_v(x1, y1, x2, y2):
+    """Algorithme ligne de Bresenham (pour cases hexagonales - secteur vertical)"""
+    #on prend comme unite la demi largeur: u = 0.5773
+    #la demi hauteur d'un hexa vaut donc 0.8860u, ou sqrt(3)/2
+    #[a revoir] une fois cela pose, on muliplie tout par 4dy afin d'eviter nombres flottants et divisions
+    sens = 1 if y2 > y1 else -1
+
+    # Calcul des ecarts
+    dx = 1.5 * (x2 - x1)      #en x, on a 1.5u de centre a centre
+    dy = sens * (y2 - y1)     #en y, on compte en demi hauteurs
+    if (x1 + x2) % 2 == 1: 
+        if x1 % 2 == 0:
+            dy += sens*0.5
+        else:
+            dy -= sens*0.5
+
+    k = dx/(dy*sqrt(3)) #k est la tangente de l'angle par rapport a la verticale
+    pas = 0.5*sqrt(3)   #on avance par demi hauteurs
+
+    retour = []
+    d = 0.0     #decalage
+    pos = (x1, y1)
+    retour.append(pos)
+    
+    while pos != (x2, y2):
+        d += (k*pas)
+        if d <= 0.5:
+            #on se deplace vers la case en dessous (ou au dessus)
+            x, y = pos
+            pos = x, y + sens
+            retour.append(pos)
+            d += (k*pas)
+        else:
+            #on se deplace vers la case en dessous (ou au dessus) a droite
+            x, y = pos
+            if (x %2 == 0 and sens == 1) or (x % 2 == 1 and sens == -1):
+                pos = x + 1, y
+            else:
+                pos = x + 1, y + sens            
+            retour.append(pos)
+            d -= 1.5
+        
+        if sens*pos[1] > sens*y2:
+            retour = []
+            break
+
+    return retour 
+

+ 111 - 114
lib/outilsSvg.py

@@ -1,114 +1,111 @@
-# -*-coding:Latin-1 -*
-"""enregistre et recupere les objets crees depuis une classe dans un dictionnaire"""
-import cPickle as pickle #lecture/ecriture d'objets dans un fichier
-                         #(cpickle remplace pickle, en + rapide)
-from time import time
-import os
-#import pickle
-
-
-def enregistrer(nomObj, obj, fichier = "", remplacer = True):
-     """enregistre un objet. le nom du fichier est le nom de la classe de l'objet"""
-     #on récupère le dictionnaire s'il existe, sinon on le cree
-     #t0 = time()
-     if len(fichier) == 0 :
-          fichier = "{}".format(obj.__class__.__name__)
-          
-     try:
-         with open(fichier, 'rb') as input:
-             dico = pickle.load(input) 
-         input.close() 
-     except IOError:
-         dico = {}
-        
-     #on ajoute notre nouvel objet (si remplacer est faux, en le renommant s'il existe déja)
-     if dico.has_key(nomObj) and not remplacer:
-        k = 1 
-        while dico.has_key("{}{}".format(nomObj, k)):
-            k += 1 
-        dico["{}{}".format(nomObj,k)]=obj  
-     else:
-        dico[nomObj]=obj   
-          
-     #on remet le dictionnaire dans le fichier
-     with open(fichier, 'wb') as output:
-         pickle.dump(dico, output, protocol=pickle.HIGHEST_PROTOCOL)
-     output.close()
-     chaine = "{} sauvegarde.".format(nomObj)
-     return chaine
-
-def enregistrerUnique(obj, fichier = "", remplacer = True):
-     """comme enregistrer, mais stocke l'objet dans un fichier a part (ex: plateau)"""
-     if len(fichier) == 0 :
-          fichier = "{}".format(obj.__class__.__name__)
-     with open(fichier, 'wb') as output:
-         pickle.dump(obj, output, protocol=pickle.HIGHEST_PROTOCOL)
-     output.close()  
-
-def charger(fichier, nomObj):
-    """recupere un objet enregistre"""
-    fichier = "{}".format(fichier)
-    #on recupere le dictionnaire
-    retour = None
-    try:
-        with open(fichier, 'rb') as input:
-            dico = pickle.load(input)
-        retour = dico[nomObj]
-        input.close()
-    except IOError:
-        retour = None
-    return retour
-
-def chargerUnique(fichier):
-    """comme charger, mais charge un objet stocke dans un fichier a part (ex: plateau)"""
-    fichier = "{}".format(fichier) 
-    #on recupere l'objet
-    try:
-        with open(fichier, 'rb') as input:
-            objet = pickle.load(input)
-        input.close()
-    except IOError:
-        objet = None
-    return objet
-
-def afficheSvg(fichier):
-    """renvoie le contenu enregistre dans un fichier"""
-    #on récupère le dictionnaire s'il existe
-    try: 
-        with open(fichier, 'rb') as input:
-           dico = pickle.load(input)
-        input.close()  
-        #on met en forme le retour:
-        #chaine = ""   
-        #for clef in dico.keys():
-        #    chaine = chaine + "\n '{}': {}".format(clef,dico[clef])
-    except IOError:
-        #chaine = "Erreur pour afficher la sauvegarde du fichier {}".format(fichier)
-        dico = {}
-    return dico
-
-def supprSvg(fichier, nomObj):
-    """supprime un objet enregistré dans le fichier"""
-    fichier = "{}".format(fichier)
-    try:
-        #on recupere le dictionnaire
-        with open(fichier, 'rb') as input:
-            dico = pickle.load(input)
-        input.close()    
-        #on supprime l'enregistrement    
-        del dico[nomObj]
-        #on remet le dictionnaire dans le fichier
-        with open(fichier, 'wb') as output:
-            pickle.dump(dico, output, -1)
-        output.close()    
-        chaine = "{} supprimé.".format(nomObj)
-    except IOError:
-        chaine = "Erreur: {} non trouve dans le fichier {}.".format(nomObj, fichier)
-        pass
-    return chaine
-
-
-
-
-
-    
+# -*-coding:Latin-1 -*
+"""enregistre et recupere les objets crees depuis une classe dans un dictionnaire"""
+import cPickle as pickle #lecture/ecriture d'objets dans un fichier (cpickle remplace pickle, en + rapide)
+#import pickle
+
+
+def enregistrer(nomObj, obj, fichier = "", remplacer = True):
+    """enregistre un objet. le nom du fichier est le nom de la classe de l'objet"""
+    #on récupère le dictionnaire s'il existe, sinon on le cree
+    #t0 = time()
+    if len(fichier) == 0 :
+        fichier = "{}".format(obj.__class__.__name__)
+          
+    try:
+        with open(fichier, 'rb') as f:
+            dico = pickle.load(f) 
+        f.close() 
+    except IOError:
+        dico = {}
+        
+    #on ajoute notre nouvel objet (si remplacer est faux, en le renommant s'il existe déja)
+    if dico.has_key(nomObj) and not remplacer:
+        k = 1 
+        while dico.has_key("{}{}".format(nomObj, k)):
+            k += 1 
+        dico["{}{}".format(nomObj,k)]=obj  
+    else:
+        dico[nomObj]=obj   
+          
+    #on remet le dictionnaire dans le fichier
+    with open(fichier, 'wb') as f:
+        pickle.dump(dico, f, protocol=pickle.HIGHEST_PROTOCOL)
+    f.close()
+    chaine = "{} sauvegarde.".format(nomObj)
+    return chaine
+
+def enregistrerUnique(obj, fichier = "", remplacer = True):
+    """comme enregistrer, mais stocke l'objet dans un fichier a part (ex: plateau)"""
+    if len(fichier) == 0 :
+        fichier = "{}".format(obj.__class__.__name__)
+    with open(fichier, 'wb') as f:
+        pickle.dump(obj, f, protocol=pickle.HIGHEST_PROTOCOL)
+    f.close()  
+
+def charger(fichier, nomObj):
+    """recupere un objet enregistre"""
+    fichier = "{}".format(fichier)
+    #on recupere le dictionnaire
+    retour = None
+    try:
+        with open(fichier, 'rb') as f:
+            dico = pickle.load(f)
+        retour = dico[nomObj]
+        f.close()
+    except IOError:
+        retour = None
+    return retour
+
+def chargerUnique(fichier):
+    """comme charger, mais charge un objet stocke dans un fichier a part (ex: plateau)"""
+    fichier = "{}".format(fichier) 
+    #on recupere l'objet
+    try:
+        with open(fichier, 'rb') as f:
+            objet = pickle.load(f)
+        f.close()
+    except IOError:
+        objet = None
+    return objet
+
+def afficheSvg(fichier):
+    """renvoie le contenu enregistre dans un fichier"""
+    #on récupère le dictionnaire s'il existe
+    try: 
+        with open(fichier, 'rb') as f:
+            dico = pickle.load(f)
+        f.close()  
+        #on met en forme le retour:
+        #chaine = ""   
+        #for clef in dico.keys():
+        #    chaine = chaine + "\n '{}': {}".format(clef,dico[clef])
+    except IOError:
+        #chaine = "Erreur pour afficher la sauvegarde du fichier {}".format(fichier)
+        dico = {}
+    return dico
+
+def supprSvg(fichier, nomObj):
+    """supprime un objet enregistré dans le fichier"""
+    fichier = "{}".format(fichier)
+    try:
+        #on recupere le dictionnaire
+        with open(fichier, 'rb') as f:
+            dico = pickle.load(f)
+        f.close()    
+        #on supprime l'enregistrement    
+        del dico[nomObj]
+        #on remet le dictionnaire dans le fichier
+        with open(fichier, 'wb') as f:
+            pickle.dump(dico, f, -1)
+        f.close()    
+        chaine = "{} supprimé.".format(nomObj)
+    except IOError:
+        chaine = "Erreur: {} non trouve dans le fichier {}.".format(nomObj, fichier)
+        pass
+    return chaine
+
+
+
+
+
+    

+ 6 - 8
lib/test.py

@@ -1,8 +1,6 @@
-import time
-
-t0 = time.time()
-
-for i in range(0,100000):
-    test = 0 < 1 < 10
-
-print time.time() - t0
+
+
+def add(a,b):
+    return a+b
+
+print add(1,2)

+ 561 - 558
lib/ui/dm.py

@@ -1,558 +1,561 @@
-#from __future__ import unicode_literals
-# -*- coding: utf-8 -*-
-"""ensemble des widgets surchargés"""
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-try:
-    from lib.outilsSvg import *
-except:
-    try:
-        from outilsSvg import *
-    except:
-        print "dm: impossible de charger outilsSvg"
-try:        
-    import lib.regles as regles
-except:
-    try:
-        import regles as regles
-    except:
-        print "dm: impossible de charger regles"
-
-class Biblio():
-    """cette classe fournit une liste spreciale"""
-    def __init__(self):
-        self.dico = {}
-        self.ordre = []
-
-    def trierPar(self, param):
-        """trie en fonction du parametre des objets"""
-        ordre = []
-        return ordre
-
-    def elt(self, index):
-        return self.dict[index]
-
-        
-class DmLabel(QLabel):
-    """surcharge de QLabel"""
-    def __init__(self, parent = None):
-        super(DmLabel, self).__init__(parent)
-        self._image = None
-
-    def majTexte(self, txt):
-        self.clear()
-        self.setText(QString.fromUtf8(txt))
-
-    def chargerImage(self, img = None):
-        """prend une RImage en parametre"""
-        self.clear()
-        if img:
-            self._image = img
-            pix = img.pix(self.width(), self.height())
-        else:
-            pix = QPixmap()
-        self.setPixmap(pix)         
-
-    def texte(self):
-        return str(self.text().toUtf8())
-
-    def image(self):
-        return self._image
-
-    def mousePressEvent(self, event):
-        if event.button() == 1:
-            self.emit(SIGNAL("clicked()"))
-
-    def mouseDoubleClickEvent(self, event):
-        if event.button() == 1:
-            self.emit(SIGNAL("doubleClicked()"))
-
-class DmTextEdit(QTextEdit):
-    def __init__(self, parent = None):
-        super(DmTextEdit, self).__init__(parent)    
-
-    def majTexte(self, txt):
-        self.clear()
-        self.setText(QString.fromUtf8(str(txt)))    
-
-    def texte(self):
-        return str(self.toPlainText().toUtf8())
-
-class DmLineEdit(QLineEdit):
-    def __init__(self, parent = None):
-        super(DmLineEdit, self).__init__(parent)    
-
-    def majTexte(self, txt):
-        self.clear()
-        self.setText(QString.fromUtf8(str(txt)))    
-
-    def texte(self):
-        return str(self.text().toUtf8())
-
-class DmGraphicsView(QGraphicsView):
-    """surcharge de QGraphicsView"""
-    def __init__(self, parent = None):
-        super(DmGraphicsView, self).__init__(parent)
-        self.nbZoomActuel = 0
-
-    def resizeEvent(self, event):
-        super(DmGraphicsView, self).resizeEvent(event)
-        self.emit(SIGNAL("resizeEvent()"))
-
-    def wheelEvent(self, event):
-        """zoom/dezoom avec la molette de la souris"""
-        #on zoom/dezoom et on recentre sur la position du curseur
-        zoom = 1.00
-        if event.delta() > 0:
-            if self.nbZoomActuel <= 10:
-                self.nbZoomActuel += 1
-                zoom = 1.25
-        elif event.delta() < 0:
-            if self.nbZoomActuel >= -10:
-                zoom = 0.8
-                self.nbZoomActuel -= 1 
-        if zoom != 0.00:
-           self.scale(zoom, zoom)
-           self.centerOn(self.mapToScene(event.pos()))
-           self.emit(SIGNAL("zoomChange(int)"), self.nbZoomActuel)
-        event.accept() #pour considerer l'evenement comme resolu, sans ca les barres de defilement reagissent aussi      
-
-
-class DmComboBox(QComboBox):
-    """surcharge de QComboBox"""
-    def __init__(self, parent = None):
-        super(DmComboBox, self).__init__(parent)
-
-    def allerA(self, donnee):
-        """cherche la donnee demandee et affiche la ligne"""
-        index = self.findData(QVariant(donnee))
-        self.setCurrentIndex(index)
-
-    def valeurActuelle(self):
-        """renvoie sous forme de QVariant la valeur en cours"""
-        return self.itemData(self.currentIndex())
-
-class DmSpinBox(QSpinBox):
-    """surcharge de QSpinBox"""
-    def __init__(self, parent = None):
-        super(DmSpinBox, self).__init__(parent)
-    
-    def focusInEvent(self, event):
-        super(DmSpinBox, self).focusInEvent(event)
-        self.selectAll()
-
-
-class DmTabInventaire(QTabWidget):
-    """surcharge de QTabWidget stylisee et
-        utilisee pour filtrer les types d'objets affiches"""
-    def __init__(self, parent = None):
-        super(DmTabInventaire, self).__init__(parent)
-        self.setStyleSheet(QString.fromUtf8("""
-                                             QTabWidget::pane { border-top: 2px solid #C2C7CB; }
-                                             QTabWidget::tab-bar { alignment: right; }
-                                             QTabBar::tab {
-                                                 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-                                                                             stop: 0 #E1E1E1, stop: 0.4 #DDDDDD,
-                                                                             stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3);
-                                                 border: 2px solid #C4C4C3;
-                                                 border-bottom-color: #C2C7CB;                                                  border-top-left-radius: 4px;
-                                                 border-top-right-radius: 8px;
-                                                 border-top-left-radius: 8px;
-                                                 padding-left: 15px; }
-                                             QTabBar::tab:selected, QTabBar::tab:hover {
-                                                 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
-                                                                             stop: 0 #fafafa, stop: 0.4 #f4f4f4,
-                                                                             stop: 0.5 #e7e7e7, stop: 1.0 #fafafa); }
-                                             QTabBar::tab:selected { border-color: #9B9B9B;
-                                                                     border-bottom-color: #C2C7CB; }
-                                               """))
-
-class DmTableWidget(QTableWidget):
-    """surcharge de QTableWidget"""
-    def __init__(self, parent = None):
-        super(DmTableWidget, self).__init__(parent)
-        self.majEnCours = False
-
-    def vider(self):
-        """supprime toutes les lignes"""
-        self.majEnCours = True
-        while self.rowCount() > 0:
-            self.removeRow(0)
-        self.majEnCours = False    
-
-    def nouvelleLigneFin(self):
-        """ajoute une ligne en derniere position"""
-        pos = self.rowCount()
-        self.insertRow(pos)
-        return pos
-
-    def lignes(self):
-        """retourne la liste des index de lignes de la table"""
-        return range(0, self.rowCount())
-
-    def colonnes(self):
-        """retourne la liste des index de lignes de la table"""
-        return range(0, self.columnCount())
-
-    def masquerColonneId(self):
-        """masque la colonne en position 0 qui contient les identifiants"""
-        self.setColumnWidth(0, 0)
-
-    def majData(self, ligne, colonne, var):
-        """met a jour la cellule avec une donnee de type QVariant"""
-        var = QVariant(var)
-        if not self.item(ligne, colonne):
-            item = QTableWidgetItem()
-            item.setData(0, var)
-            self.setItem(ligne, colonne, item)
-        else:
-            self.item(ligne, colonne).setData(0, var)
-        return True
-    
-    def majTexte(self, ligne, colonne, texte):
-        """met a jour la cellule avec du texte"""
-        if not self.item(ligne, colonne):
-            self.setItem(ligne, colonne, QTableWidgetItem(QString.fromUtf8(str(texte))))
-        else:
-            self.item(ligne, colonne).setText(QString.fromUtf8(str(texte)))
-        return True
-
-    def majEnt(self, ligne, colonne, valeur):
-        """met a jour la cellule avec une valeur numerique entiere
-           si valeur ne peut etre converti en numerique, on retourne Faux"""
-        retour = False
-        try:
-            entier = QVariant(long(valeur))
-            self.item(ligne, colonne).setData(0, entier)
-            retour = True
-        except:
-            pass
-        return retour
-                
-    def chercherLigne(self, colonne, valeur):
-        """cherche la valeur dans la colonne demandee
-           renvoie la ligne correspondante """
-        ligne = None
-        for i in range(0, self.rowCount()):
-            if str(self.item(i, colonne).text().toUtf8()) == str(valeur):
-                ligne = i
-                break           
-        return ligne
-
-    def majLigne(self, ligne, dico, flags = []):
-        """rempli la ligne avec les donnees trouvees dans le dictionnaire"""
-        for colonne in range(0, self.columnCount()):
-            nomChamp = ""
-            item = self.horizontalHeaderItem(colonne)
-            if item:
-                nomChamp = str(item.text())
-            if nomChamp in dico:
-                item = QTableWidgetItem()
-                for f in flags:
-                    item.setFlag(f)
-                var = QVariant(dico[nomChamp])
-                item.setData(0, var)
-                self.setItem(ligne, colonne, item)
-
-    def texte(self, ligne, colonne):
-        return str(self.item(ligne, colonne).text().toUtf8())
-
-    def data(self, ligne, colonne):
-        retour = None
-        item = self.item(ligne, colonne)
-        if item:
-            retour = item.data(0)
-        return retour
-
-    def ligneSelectionnee(self):
-        """renvoie la ligne selectionnee (la premiere si plusieurs le sont)"""
-        return self.currentRow()
-
-    def selectionner(self, ligne, colonne):
-        self.setCurrentCell(ligne, colonne, QItemSelectionModel.Select)
-
-
-class DmTableBiblio(DmTableWidget):
-    """table utilisee pour afficher les bibliotheques d'objets:
-        terrains, decors, creatures"""
-    def __init__(self, parent = None):
-        super(DmTableBiblio, self).__init__(parent)
-        self.fichier = ""
-        self.masquerColonneId()
-
-    def defFichier(self, fichier):
-        """definit le fichier de sauvegarde qui la source des donnees de la table"""
-        self.fichier = fichier
-
-    def initAffichage(self):
-        """fait les differents reglages relatifs a l'apparence"""
-        self.setColumnWidth(0, 0)
-        self.setIconSize(QSize(30,20))   
-        self.horizontalHeader().setStretchLastSection(True)
-        
-    def remplir(self):
-        """remplit la table avec les donnees contenues dans le dictionnaire de la savuvegarde"""
-        dico = afficheSvg(self.fichier)
-        self.majEnCours = True
-        self.setSortingEnabled(False)
-        index = 0
-        for elt in dico:
-            objet = dico[elt]
-            self.insertRow(int(index))
-            
-            #code de l'objet
-            self.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt)))
-            #icone et nom
-            icon = QIcon(objet.icone().chemin())
-            item = QTableWidgetItem(icon, QString.fromUtf8(objet.nom))
-            self.setItem(int(index),1,item)
-            
-            index += 1        
-        self.sizeHintForColumn(1)
-        self.setSortingEnabled(True)
-        self.sortItems(1)
-        self.majEnCours = False
-
-    def maj(self):
-        self.vider()
-        self.remplir()
-
-    def actuel(self):
-        """renvoie l'objet actuellement selectionne"""
-        objet = None
-        index = self.item(self.currentRow(), 0)
-        if index > 0:
-            objet = charger(self.fichier, str(index.text().toUtf8()))
-        return objet
-    
-
-class DmTableAttributsPi(DmTableWidget):
-    """table utilisee pour afficher les attributs d'un pion dans le panneau Pi"""
-    def __init__(self, parent = None):
-        super(DmTableBiblio, self).__init__(parent)
-        self.fichier = ""
-        self.masquerColonneId()
-
-    def defFichier(self, fichier):
-        """definit le fichier de sauvegarde qui la source des donnees de la table"""
-        self.fichier = fichier
-
-    def initAffichage(self):
-        """fait les differents reglages relatifs a l'apparence"""
-        self.setColumnWidth(0, 0)
-        self.setIconSize(QSize(30,20))   
-        self.horizontalHeader().setStretchLastSection(True)
-        
-    def remplir(self):
-        """remplit la table avec les donnees contenues dans le dictionnaire de la savuvegarde"""
-        dico = afficheSvg(self.fichier)
-        self.majEnCours = True
-        self.setSortingEnabled(False)
-        index = 0
-        for elt in dico:
-            objet = dico[elt]
-            self.insertRow(int(index))
-            
-            #code de l'objet
-            self.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt)))
-            #icone et nom
-            icon = QIcon("img\\"+objet.icone())
-            item = QTableWidgetItem(icon,QString.fromUtf8(objet.nom))
-            self.setItem(int(index),1,item)
-            
-            index += 1        
-        self.sizeHintForColumn(1)
-        self.setSortingEnabled(True)
-        self.sortItems(1)
-        self.majEnCours = False
-
-    def maj(self):
-        self.vider()
-        self.remplir()
-
-    def actuel(self):
-        """renvoie l'objet actuellement selectionne"""
-        objet = None
-        index = self.item(self.currentRow(), 0)
-        if index > 0:
-            objet = charger(self.fichier, str(index.text().toUtf8()))
-        return objet
-
-
-class DmTableInventaire(DmTableWidget):
-    """table utilisee pour afficher l'inventaire d'un combattant"""
-    itemExited = pyqtSignal(QTableWidgetItem)
-    def __init__(self, parent = None):
-        super(DmTableInventaire, self).__init__(parent)
-        self._inventaire = []
-        
-        #pour la gestion des survols
-        self.setMouseTracking(True)
-        self._last_index = QPersistentModelIndex()
-        self.viewport().installEventFilter(self)
-        
-        self.connect(self, SIGNAL("itemEntered(QTableWidgetItem*)"), self.itemSurvole)
-        self.connect(self, SIGNAL("itemExited(QTableWidgetItem*)"), self.itemSurvoleFin)
-        self.connect(self, SIGNAL("itemClicked(QTableWidgetItem*)"), self.itemClique)
-
-    def construire(self):
-        self.setColumnWidth(0, 20);self.setColumnWidth(1, 70)
-        self.setColumnWidth(2, 241);self.setColumnWidth(4, 60)
-        self.setColumnWidth(6, 20)
-
-    def ajouterObjet(self, objet):
-        ligne = self.rowCount() - 1   #avant la ligne 'ajouter'
-        self.insertRow(ligne)
-        self.remplirLigne(ligne, objet)
-        self._inventaire.append(objet)
-
-    def charger(self, inventaire):
-        """charge l'inventaire en parametre"""
-        for objet in inventaire:
-            self.ajouterObjet(objet)
-
-    def majObjet(self, ancien, nouveau):
-        """maj la ligne correspondant a l'objet"""
-        index = self._inventaire.index(ancien)
-        self._inventaire[index] = nouveau
-        self.remplirLigne(index, nouveau)
-        
-    def supprimerObjet(self, objet):
-        """ajoute la ligne correspondant a l'objet"""
-        index = self._inventaire.index(objet)  
-        self._inventaire.remove(objet)
-        self.removeRow(index)
-
-    def remplirLigne(self, ligne, objet):
-        """remplit les cellules de la ligne avec les donnees de l'objet"""
-        imgType = ["pieces.png", "btn_ModeCombat.png", "chimie.png", "diamant.png", "boite_outils.png"]
-        self.creerItem(ligne, 0, "", imgType[objet.typeObjet])
-        self.creerItem(ligne, 1, objet.quantite)
-        self.creerItem(ligne, 2, objet.nom)
-        self.creerItem(ligne, 3, objet.poidsTotal())
-        self.creerItem(ligne, 4, "")
-                       
-    def inventaire(self):
-        """cree un inventaire a partir des donnees de la table"""
-        return self._inventaire
-
-    def itemSurvole(self, item):
-        ligne = item.row()
-        self.majCouleurLigne(ligne, QColor(150, 50, 50, 150))
-
-    def itemSurvoleFin(self, item):
-        ligne = item.row()
-        self.majCouleurLigne(ligne, QColor(248, 248, 248, 150))
-
-    def itemClique(self, item):
-        ligne = item.row()
-        self.emit(SIGNAL("objetClique(int)"), ligne)
-
-    def majCouleurLigne(self, ligne, couleur):
-        """modifie la couleur de fond des items de la lignes"""
-        for col in self.colonnes():
-            item = self.item(ligne, col)
-            if item:
-                item.setBackground(QBrush(couleur))
-
-    def creerItem(self, ligne, colonne, txt, img = None):
-        item = QTableWidgetItem()
-        item.setFlags(Qt.NoItemFlags)
-        item.setText(QString().fromUtf8(" {}".format(txt)))
-        if img:
-            pix = QPixmap("img\\{}".format(img))
-            item.setIcon(QIcon(pix))
-        self.setItem(ligne, colonne, item)
-
-    def filtrer(self, typeObjet):
-        """filtre l'affichage des lignes par type d'objet"""
-        for ligne in range(0, self.rowCount() - 1):
-            self.setRowHidden(ligne, typeObjet >= 0 and typeObjet != self._inventaire[ligne].typeObjet )
-
-    def eventFilter(self, widget, event):
-        if widget is self.viewport():
-            index = self._last_index
-            if event.type() == QEvent.MouseMove:
-                index = self.indexAt(event.pos())
-            elif event.type() == QEvent.Leave:
-                index = QModelIndex()
-            if index != self._last_index:
-                row = self._last_index.row()
-                column = self._last_index.column()
-                item = self.item(row, column)
-                if item is not None:
-                    self.itemExited.emit(item)
-                self._last_index = QPersistentModelIndex(index)
-        return QTableWidget.eventFilter(self, widget, event)
-
-
-class DmTableInventaireCombat(DmTableInventaire):
-    """inventaire affiche dans le panneau de combat"""
-    def __init__(self, parent = None):
-        super(DmTableInventaireCombat, self).__init__(parent)    
-
-class DmTableMenu(QTableWidget):
-    """table utilisee comme barre d'onglets verticale"""
-    def __init__(self, parent = None):
-        super(DmTableMenu, self).__init__(parent)
-      
-    def setItem(self, ligne, colonne, item):
-        super(DmTableMenu, self).setItem(ligne, colonne, item)
-        if ligne == 0:
-            self.setItemSelected(item, True)
-
-class DmFrameInf_Combattant(QGroupBox):
-    """frame d'information (combattant)"""
-    def __init__(self, parent = None):
-        super(DmFrameInf_Combattant, self).__init__(parent)
-
-    def maj(self, combattant):
-        self.setVisible((combattant != None))
-        if combattant:
-            self.findChild(DmLabel, "inf_pionNom").majTexte(combattant.nom)
-            self.findChild(DmLabel, "inf_pionImage").chargerImage(combattant.img.rimage)
-            self.findChild(DmLabel, "inf_pionEffet").setVisible(False)
-            
-
-class DmFrameInf_Decor(QGroupBox):
-    """frame d'information (decor)"""
-    def __init__(self, parent = None):
-        super(DmFrameInf_Decor, self).__init__(parent)
-
-    def maj(self, decor):
-        self.setVisible((decor != None))
-        if decor:
-            self.findChild(DmLabel, "inf_decorNom").majTexte(decor.nom)
-            self.findChild(DmLabel, "inf_decorImage").chargerImage(decor.img.rimage)
-
-class DmFrameInf_Case(QGroupBox):
-    """frame d'information (case)"""
-    def __init__(self, parent = None):
-        super(DmFrameInf_Case, self).__init__(parent)
-
-    def maj(self, case):
-        self.setVisible((case != None))
-        if len(case.terrain.nom) > 0:
-            self.findChild(DmLabel, "inf_caseTerrain").majTexte(case.terrain.nom)
-        else:
-            self.findChild(DmLabel, "inf_caseTerrain").majTexte("Case")
-            
-        self.findChild(DmLabel, "inf_caseCoord").majTexte("X: {}  Y: {}".format(case.x, case.y))
-        self.findChild(DmLabel, "inf_caseAltitude").majTexte("Alt.: {}".format(case.altitude))
-        
-        if case.effetActif != "":
-            self.findChild(DmLabel, "inf_caseEffet").chargerImage("img\\"+case.imgEffet[case.effetActif])          
-        else:
-            self.findChild(DmLabel, "inf_caseEffet").clear()      
-
-class DmFrame(QFrame):
-    """surcharge de QFrame"""
-    def __init__(self, parent = None):
-        super(DmFrame, self).__init__(parent)
-
-        
-
-
-
-    
-
+#from __future__ import unicode_literals
+# -*- coding: utf-8 -*-
+"""ensemble des widgets surchargés"""
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+try:
+    from lib.outilsSvg import *
+except:
+    try:
+        from outilsSvg import *
+    except:
+        print "dm: impossible de charger outilsSvg"
+try:        
+    import lib.regles as regles
+except:
+    try:
+        import regles as regles
+    except:
+        print "dm: impossible de charger regles"
+
+class Biblio():
+    """cette classe fournit une liste spreciale"""
+    def __init__(self):
+        self.dico = {}
+        self.ordre = []
+
+    def trierPar(self, param):
+        """trie en fonction du parametre des objets"""
+        ordre = []
+        return ordre
+
+    def elt(self, index):
+        return self.dict[index]
+
+        
+class DmLabel(QLabel):
+    """surcharge de QLabel"""
+    def __init__(self, parent = None):
+        super(DmLabel, self).__init__(parent)
+        self._image = None
+
+    def majTexte(self, txt):
+        self.clear()
+        self.setText(QString.fromUtf8(txt))
+
+    def chargerImage(self, img = None):
+        """prend une RImage en parametre"""
+        self.clear()
+        if img:
+            self._image = img
+            pix = img.pix(self.width(), self.height())
+        else:
+            pix = QPixmap()
+        self.setPixmap(pix)         
+
+    def texte(self):
+        return str(self.text().toUtf8())
+
+    def image(self):
+        return self._image
+
+    def mousePressEvent(self, event):
+        if event.button() == 1:
+            self.emit(SIGNAL("clicked()"))
+
+    def mouseDoubleClickEvent(self, event):
+        if event.button() == 1:
+            self.emit(SIGNAL("doubleClicked()"))
+
+class DmTextEdit(QTextEdit):
+    def __init__(self, parent = None):
+        super(DmTextEdit, self).__init__(parent)    
+
+    def majTexte(self, txt):
+        self.clear()
+        self.setText(QString.fromUtf8(str(txt)))    
+
+    def texte(self):
+        return str(self.toPlainText().toUtf8())
+
+class DmLineEdit(QLineEdit):
+    def __init__(self, parent = None):
+        super(DmLineEdit, self).__init__(parent)    
+
+    def majTexte(self, txt):
+        self.clear()
+        self.setText(QString.fromUtf8(str(txt)))    
+
+    def texte(self):
+        return str(self.text().toUtf8())
+
+class DmGraphicsView(QGraphicsView):
+    """surcharge de QGraphicsView"""
+    def __init__(self, parent = None):
+        super(DmGraphicsView, self).__init__(parent)
+        self.nbZoomActuel = 0
+
+    def resizeEvent(self, event):
+        super(DmGraphicsView, self).resizeEvent(event)
+        self.emit(SIGNAL("resizeEvent()"))
+
+    def wheelEvent(self, event):
+        """zoom/dezoom avec la molette de la souris"""
+        #on zoom/dezoom et on recentre sur la position du curseur
+        zoom = 1.00
+        if event.delta() > 0:
+            if self.nbZoomActuel <= 10:
+                self.nbZoomActuel += 1
+                zoom = 1.25
+        elif event.delta() < 0:
+            if self.nbZoomActuel >= -10:
+                zoom = 0.8
+                self.nbZoomActuel -= 1 
+        if zoom != 0.00:
+           self.scale(zoom, zoom)
+           self.centerOn(self.mapToScene(event.pos()))
+           self.emit(SIGNAL("zoomChange(int)"), self.nbZoomActuel)
+        event.accept() #pour considerer l'evenement comme resolu, sans ca les barres de defilement reagissent aussi      
+
+
+class DmComboBox(QComboBox):
+    """surcharge de QComboBox"""
+    def __init__(self, parent = None):
+        super(DmComboBox, self).__init__(parent)
+
+    def allerA(self, donnee):
+        """cherche la donnee demandee et affiche la ligne"""
+        index = self.findData(QVariant(donnee))
+        self.setCurrentIndex(index)
+
+    def valeurActuelle(self):
+        """renvoie sous forme de QVariant la valeur en cours"""
+        return self.itemData(self.currentIndex())
+
+class DmSpinBox(QSpinBox):
+    """surcharge de QSpinBox"""
+    def __init__(self, parent = None):
+        super(DmSpinBox, self).__init__(parent)
+    
+    def focusInEvent(self, event):
+        super(DmSpinBox, self).focusInEvent(event)
+        self.selectAll()
+
+
+class DmTabInventaire(QTabWidget):
+    """surcharge de QTabWidget stylisee et
+        utilisee pour filtrer les types d'objets affiches"""
+    def __init__(self, parent = None):
+        super(DmTabInventaire, self).__init__(parent)
+        self.setStyleSheet(QString.fromUtf8("""
+                                             QTabWidget::pane { border-top: 2px solid #C2C7CB; }
+                                             QTabWidget::tab-bar { alignment: right; }
+                                             QTabBar::tab {
+                                                 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+                                                                             stop: 0 #E1E1E1, stop: 0.4 #DDDDDD,
+                                                                             stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3);
+                                                 border: 2px solid #C4C4C3;
+                                                 border-bottom-color: #C2C7CB;                                                  border-top-left-radius: 4px;
+                                                 border-top-right-radius: 8px;
+                                                 border-top-left-radius: 8px;
+                                                 padding-left: 15px; }
+                                             QTabBar::tab:selected, QTabBar::tab:hover {
+                                                 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+                                                                             stop: 0 #fafafa, stop: 0.4 #f4f4f4,
+                                                                             stop: 0.5 #e7e7e7, stop: 1.0 #fafafa); }
+                                             QTabBar::tab:selected { border-color: #9B9B9B;
+                                                                     border-bottom-color: #C2C7CB; }
+                                               """))
+
+class DmTableWidget(QTableWidget):
+    """surcharge de QTableWidget"""
+    def __init__(self, parent = None):
+        super(DmTableWidget, self).__init__(parent)
+        self.majEnCours = False
+
+    def vider(self):
+        """supprime toutes les lignes"""
+        self.majEnCours = True
+        while self.rowCount() > 0:
+            self.removeRow(0)
+        self.majEnCours = False    
+
+    def nouvelleLigneFin(self):
+        """ajoute une ligne en derniere position"""
+        pos = self.rowCount()
+        self.insertRow(pos)
+        return pos
+
+    def lignes(self):
+        """retourne la liste des index de lignes de la table"""
+        return range(0, self.rowCount())
+
+    def colonnes(self):
+        """retourne la liste des index de lignes de la table"""
+        return range(0, self.columnCount())
+
+    def masquerColonneId(self):
+        """masque la colonne en position 0 qui contient les identifiants"""
+        self.setColumnWidth(0, 0)
+
+    def majData(self, ligne, colonne, var):
+        """met a jour la cellule avec une donnee de type QVariant"""
+        var = QVariant(var)
+        if not self.item(ligne, colonne):
+            item = QTableWidgetItem()
+            item.setData(0, var)
+            self.setItem(ligne, colonne, item)
+        else:
+            self.item(ligne, colonne).setData(0, var)
+        return True
+    
+    def majTexte(self, ligne, colonne, texte):
+        """met a jour la cellule avec du texte"""
+        if not self.item(ligne, colonne):
+            self.setItem(ligne, colonne, QTableWidgetItem(QString.fromUtf8(str(texte))))
+        else:
+            self.item(ligne, colonne).setText(QString.fromUtf8(str(texte)))
+        return True
+
+    def majEnt(self, ligne, colonne, valeur):
+        """met a jour la cellule avec une valeur numerique entiere
+           si valeur ne peut etre converti en numerique, on retourne Faux"""
+        retour = False
+        try:
+            entier = QVariant(long(valeur))
+            self.item(ligne, colonne).setData(0, entier)
+            retour = True
+        except:
+            pass
+        return retour
+                
+    def chercherLigne(self, colonne, valeur):
+        """cherche la valeur dans la colonne demandee
+           renvoie la ligne correspondante """
+        ligne = None
+        for i in range(0, self.rowCount()):
+            if str(self.item(i, colonne).text().toUtf8()) == str(valeur):
+                ligne = i
+                break           
+        return ligne
+
+    def majLigne(self, ligne, dico, flags = []):
+        """rempli la ligne avec les donnees trouvees dans le dictionnaire"""
+        for colonne in range(0, self.columnCount()):
+            nomChamp = ""
+            item = self.horizontalHeaderItem(colonne)
+            if item:
+                nomChamp = str(item.text())
+            if nomChamp in dico:
+                item = QTableWidgetItem()
+                for f in flags:
+                    item.setFlag(f)
+                var = QVariant(dico[nomChamp])
+                item.setData(0, var)
+                self.setItem(ligne, colonne, item)
+
+    def texte(self, ligne, colonne):
+        return str(self.item(ligne, colonne).text().toUtf8())
+
+    def data(self, ligne, colonne):
+        retour = None
+        item = self.item(ligne, colonne)
+        if item:
+            retour = item.data(0)
+        return retour
+
+    def ligneSelectionnee(self):
+        """renvoie la ligne selectionnee (la premiere si plusieurs le sont)"""
+        return self.currentRow()
+
+    def selectionner(self, ligne, colonne):
+        self.setCurrentCell(ligne, colonne, QItemSelectionModel.Select)
+
+
+class DmTableBiblio(DmTableWidget):
+    """table utilisee pour afficher les bibliotheques d'objets:
+        terrains, decors, creatures"""
+    def __init__(self, parent = None):
+        super(DmTableBiblio, self).__init__(parent)
+        self.fichier = ""
+        self.masquerColonneId()
+
+    def defFichier(self, fichier):
+        """definit le fichier de sauvegarde qui la source des donnees de la table"""
+        self.fichier = fichier
+
+    def initAffichage(self):
+        """fait les differents reglages relatifs a l'apparence"""
+        self.setColumnWidth(0, 0)
+        self.setIconSize(QSize(30,20))   
+        self.horizontalHeader().setStretchLastSection(True)
+        
+    def remplir(self):
+        """remplit la table avec les donnees contenues dans le dictionnaire de la savuvegarde"""
+        dico = afficheSvg(self.fichier)
+        self.majEnCours = True
+        self.setSortingEnabled(False)
+        index = 0
+        for elt in dico:
+            objet = dico[elt]
+            self.insertRow(int(index))
+            
+            #code de l'objet
+            self.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt)))
+            #icone et nom
+            if objet.icone():
+                icon = QIcon(objet.icone().chemin())
+            else:
+                icon = QIcon()
+            item = QTableWidgetItem(icon, QString.fromUtf8(objet.nom))
+            self.setItem(int(index),1,item)
+            
+            index += 1        
+        self.sizeHintForColumn(1)
+        self.setSortingEnabled(True)
+        self.sortItems(1)
+        self.majEnCours = False
+
+    def maj(self):
+        self.vider()
+        self.remplir()
+
+    def actuel(self):
+        """renvoie l'objet actuellement selectionne"""
+        objet = None
+        index = self.item(self.currentRow(), 0)
+        if index > 0:
+            objet = charger(self.fichier, str(index.text().toUtf8()))
+        return objet
+    
+
+class DmTableAttributsPi(DmTableWidget):
+    """table utilisee pour afficher les attributs d'un pion dans le panneau Pi"""
+    def __init__(self, parent = None):
+        super(DmTableBiblio, self).__init__(parent)
+        self.fichier = ""
+        self.masquerColonneId()
+
+    def defFichier(self, fichier):
+        """definit le fichier de sauvegarde qui la source des donnees de la table"""
+        self.fichier = fichier
+
+    def initAffichage(self):
+        """fait les differents reglages relatifs a l'apparence"""
+        self.setColumnWidth(0, 0)
+        self.setIconSize(QSize(30,20))   
+        self.horizontalHeader().setStretchLastSection(True)
+        
+    def remplir(self):
+        """remplit la table avec les donnees contenues dans le dictionnaire de la savuvegarde"""
+        dico = afficheSvg(self.fichier)
+        self.majEnCours = True
+        self.setSortingEnabled(False)
+        index = 0
+        for elt in dico:
+            objet = dico[elt]
+            self.insertRow(int(index))
+            
+            #code de l'objet
+            self.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt)))
+            #icone et nom
+            icon = QIcon("img\\"+objet.icone())
+            item = QTableWidgetItem(icon,QString.fromUtf8(objet.nom))
+            self.setItem(int(index),1,item)
+            
+            index += 1        
+        self.sizeHintForColumn(1)
+        self.setSortingEnabled(True)
+        self.sortItems(1)
+        self.majEnCours = False
+
+    def maj(self):
+        self.vider()
+        self.remplir()
+
+    def actuel(self):
+        """renvoie l'objet actuellement selectionne"""
+        objet = None
+        index = self.item(self.currentRow(), 0)
+        if index > 0:
+            objet = charger(self.fichier, str(index.text().toUtf8()))
+        return objet
+
+
+class DmTableInventaire(DmTableWidget):
+    """table utilisee pour afficher l'inventaire d'un combattant"""
+    itemExited = pyqtSignal(QTableWidgetItem)
+    def __init__(self, parent = None):
+        super(DmTableInventaire, self).__init__(parent)
+        self._inventaire = []
+        
+        #pour la gestion des survols
+        self.setMouseTracking(True)
+        self._last_index = QPersistentModelIndex()
+        self.viewport().installEventFilter(self)
+        
+        self.connect(self, SIGNAL("itemEntered(QTableWidgetItem*)"), self.itemSurvole)
+        self.connect(self, SIGNAL("itemExited(QTableWidgetItem*)"), self.itemSurvoleFin)
+        self.connect(self, SIGNAL("itemClicked(QTableWidgetItem*)"), self.itemClique)
+
+    def construire(self):
+        self.setColumnWidth(0, 20);self.setColumnWidth(1, 70)
+        self.setColumnWidth(2, 241);self.setColumnWidth(4, 60)
+        self.setColumnWidth(6, 20)
+
+    def ajouterObjet(self, objet):
+        ligne = self.rowCount() - 1   #avant la ligne 'ajouter'
+        self.insertRow(ligne)
+        self.remplirLigne(ligne, objet)
+        self._inventaire.append(objet)
+
+    def charger(self, inventaire):
+        """charge l'inventaire en parametre"""
+        for objet in inventaire:
+            self.ajouterObjet(objet)
+
+    def majObjet(self, ancien, nouveau):
+        """maj la ligne correspondant a l'objet"""
+        index = self._inventaire.index(ancien)
+        self._inventaire[index] = nouveau
+        self.remplirLigne(index, nouveau)
+        
+    def supprimerObjet(self, objet):
+        """ajoute la ligne correspondant a l'objet"""
+        index = self._inventaire.index(objet)  
+        self._inventaire.remove(objet)
+        self.removeRow(index)
+
+    def remplirLigne(self, ligne, objet):
+        """remplit les cellules de la ligne avec les donnees de l'objet"""
+        imgType = ["pieces.png", "btn_ModeCombat.png", "chimie.png", "diamant.png", "boite_outils.png"]
+        self.creerItem(ligne, 0, "", imgType[objet.typeObjet])
+        self.creerItem(ligne, 1, objet.quantite)
+        self.creerItem(ligne, 2, objet.nom)
+        self.creerItem(ligne, 3, objet.poidsTotal())
+        self.creerItem(ligne, 4, "")
+                       
+    def inventaire(self):
+        """cree un inventaire a partir des donnees de la table"""
+        return self._inventaire
+
+    def itemSurvole(self, item):
+        ligne = item.row()
+        self.majCouleurLigne(ligne, QColor(150, 50, 50, 150))
+
+    def itemSurvoleFin(self, item):
+        ligne = item.row()
+        self.majCouleurLigne(ligne, QColor(248, 248, 248, 150))
+
+    def itemClique(self, item):
+        ligne = item.row()
+        self.emit(SIGNAL("objetClique(int)"), ligne)
+
+    def majCouleurLigne(self, ligne, couleur):
+        """modifie la couleur de fond des items de la lignes"""
+        for col in self.colonnes():
+            item = self.item(ligne, col)
+            if item:
+                item.setBackground(QBrush(couleur))
+
+    def creerItem(self, ligne, colonne, txt, img = None):
+        item = QTableWidgetItem()
+        item.setFlags(Qt.NoItemFlags)
+        item.setText(QString().fromUtf8(" {}".format(txt)))
+        if img:
+            pix = QPixmap("img\\{}".format(img))
+            item.setIcon(QIcon(pix))
+        self.setItem(ligne, colonne, item)
+
+    def filtrer(self, typeObjet):
+        """filtre l'affichage des lignes par type d'objet"""
+        for ligne in range(0, self.rowCount() - 1):
+            self.setRowHidden(ligne, typeObjet >= 0 and typeObjet != self._inventaire[ligne].typeObjet )
+
+    def eventFilter(self, widget, event):
+        if widget is self.viewport():
+            index = self._last_index
+            if event.type() == QEvent.MouseMove:
+                index = self.indexAt(event.pos())
+            elif event.type() == QEvent.Leave:
+                index = QModelIndex()
+            if index != self._last_index:
+                row = self._last_index.row()
+                column = self._last_index.column()
+                item = self.item(row, column)
+                if item is not None:
+                    self.itemExited.emit(item)
+                self._last_index = QPersistentModelIndex(index)
+        return QTableWidget.eventFilter(self, widget, event)
+
+
+class DmTableInventaireCombat(DmTableInventaire):
+    """inventaire affiche dans le panneau de combat"""
+    def __init__(self, parent = None):
+        super(DmTableInventaireCombat, self).__init__(parent)    
+
+class DmTableMenu(QTableWidget):
+    """table utilisee comme barre d'onglets verticale"""
+    def __init__(self, parent = None):
+        super(DmTableMenu, self).__init__(parent)
+      
+    def setItem(self, ligne, colonne, item):
+        super(DmTableMenu, self).setItem(ligne, colonne, item)
+        if ligne == 0:
+            self.setItemSelected(item, True)
+
+class DmFrameInf_Combattant(QGroupBox):
+    """frame d'information (combattant)"""
+    def __init__(self, parent = None):
+        super(DmFrameInf_Combattant, self).__init__(parent)
+
+    def maj(self, combattant):
+        self.setVisible((combattant != None))
+        if combattant:
+            self.findChild(DmLabel, "inf_pionNom").majTexte(combattant.nom)
+            self.findChild(DmLabel, "inf_pionImage").chargerImage(combattant.img.rimage)
+            self.findChild(DmLabel, "inf_pionEffet").setVisible(False)
+            
+
+class DmFrameInf_Decor(QGroupBox):
+    """frame d'information (decor)"""
+    def __init__(self, parent = None):
+        super(DmFrameInf_Decor, self).__init__(parent)
+
+    def maj(self, decor):
+        self.setVisible((decor != None))
+        if decor:
+            self.findChild(DmLabel, "inf_decorNom").majTexte(decor.nom)
+            self.findChild(DmLabel, "inf_decorImage").chargerImage(decor.img.rimage)
+
+class DmFrameInf_Case(QGroupBox):
+    """frame d'information (case)"""
+    def __init__(self, parent = None):
+        super(DmFrameInf_Case, self).__init__(parent)
+
+    def maj(self, case):
+        self.setVisible((case != None))
+        if len(case.terrain.nom) > 0:
+            self.findChild(DmLabel, "inf_caseTerrain").majTexte(case.terrain.nom)
+        else:
+            self.findChild(DmLabel, "inf_caseTerrain").majTexte("Case")
+            
+        self.findChild(DmLabel, "inf_caseCoord").majTexte("X: {}  Y: {}".format(case.x, case.y))
+        self.findChild(DmLabel, "inf_caseAltitude").majTexte("Alt.: {}".format(case.altitude))
+        
+        if case.effetActif != "":
+            self.findChild(DmLabel, "inf_caseEffet").chargerImage("img\\"+case.imgEffet[case.effetActif])          
+        else:
+            self.findChild(DmLabel, "inf_caseEffet").clear()      
+
+class DmFrame(QFrame):
+    """surcharge de QFrame"""
+    def __init__(self, parent = None):
+        super(DmFrame, self).__init__(parent)
+
+        
+
+
+
+    
+

BIN
parties/Partie1/svg/1.p


BIN
parties/Partie1/svg/4.p


+ 1 - 2
parties/Partie1/svg/infos_sauvegarde

@@ -1,2 +1 @@
-€}q(U1}q(UnomqUtestqUdateCreationqGAÕgíƒUdateSvgqGAÕgöÕ“uUchapitreqU1UenCoursq‰Upublicq	‰uU4}q
-(UnomUdfgUdateCreationGAÕgìï�©üUdateSvgGAÕgìù!%UchapitreU1UenCours‰Upublic‰uu.
+€}qU0}q(UnomqUForêtqUdateCreationqGAÕiÜb«"ÑUdateSvgqGAÕiÜÊiXUchapitreqU1UenCoursq‰Upublicq	‰us.