from __future__ import unicode_literals
# -*- coding: utf-8 -*-
from __future__ import division
import os
from sys import exit, argv, getsizeof
from time import time, sleep
from threading import Thread

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtOpenGL

from ecran_principal import Ui_principal
from ecran_editionTerrain import Ui_editionTerrain
from ecran_editionCreature import Ui_editionCreature
from ecran_editionDecor import Ui_editionDecor
from ecran_creationPlateau import Ui_creationPlateau

from outilsSvg import *

from operator import itemgetter, attrgetter
from math import *


class EcranPrincipal(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 (EcranPrincipal, self).__init__()
        self.plateau = Plateau(self)
        self.createWidgets()
        
    def createWidgets(self):
        """construction de l'interface"""
        #construction de l'interface
        self.ui = Ui_principal()
        self.ui.setupUi(self)        
        self.connect(self.ui.nouveauPlateau, SIGNAL("clicked()"), self.creerPlateau)
        self.connect(self.ui.sauverPlateau, SIGNAL("clicked()"), self.sauverPlateau)
        self.connect(self.ui.chargerPlateau, SIGNAL("clicked()"), self.chargerPlateau)        
        self.connect(self.ui.fermerPlateau, SIGNAL("clicked()"), self.fermerPlateau)
        self.creerEcranFondPlateau()
        self.ui.listEvenement.addItem( QString.fromUtf8("<- et -> pour pivoter en deplacement"))

    def creerEcranFondPlateau(self):
        ecranFondPlateau = EcranFondPlateau(self)
        self.ui.vuePlateau.resetTransform()
        self.ui.vuePlateau.setScene(ecranFondPlateau)
        
        
    def creerPlateau(self):
        """ouvre la fenetre de creation de plateau"""
        if self.plateau != None:
            if self.plateau.estCree() == True:
                print("un plateau est deja cree")
            else:
        #        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        #        self.plateau.creer("test", 80, 40)   #ne pas depasser 250*250, hauteur fixee a 120
        #        self.connexionPlateau()
         #       QApplication.restoreOverrideCursor()
                self.creationPlateau = EcranCreationPlateau(self)
                self.creationPlateau.show()
                self.creationPlateau.raise_()
                QApplication.processEvents()
                

    def sauverPlateau(self):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        #print(getsizeof(self.plateau))
        enregistrer(1, self.plateau, "plateau")
        QApplication.restoreOverrideCursor()

    def chargerPlateau(self):
        if self.plateau != None:
            if self.plateau.estCree() == True:
                print("un plateau est deja cree")
            else:
                QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
                self.plateau = charger("plateau", 1)
                self.plateau.recreer(self)
                self.connexionPlateau()
                QApplication.restoreOverrideCursor()

    def fermerPlateau(self):
        #if self.plateau != None:
        #    if self.plateau.estCree() == True:
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        for item in self.plateau.items():
            self.plateau.removeItem(item)
        self.plateau = Plateau(self)
        self.creerEcranFondPlateau()
        QApplication.restoreOverrideCursor()

    def connexionPlateau(self):
        self.connect(self.ui.affichageNormal, SIGNAL("clicked()"), self.plateau.affichageNormal)
        self.connect(self.ui.affichageAltitude, SIGNAL("clicked()"), self.plateau.affichageAltitude)
        self.connect(self.ui.affichageTactique, SIGNAL("clicked()"), self.plateau.affichageTactique)
        self.connect(self.ui.affichageBrouillard, SIGNAL("stateChanged(int)"), self.plateau.affichageBrouillard)
        
        self.connect(self.ui.terrainCouleur, SIGNAL("clicked()"), self.plateau.modePeintureCase)
        self.connect(self.ui.pionCouleur, SIGNAL("clicked()"), self.plateau.majCouleurPion)
        self.connect(self.ui.terrainEdit, SIGNAL("clicked()"), self.plateau.terrainEdit)
        self.connect(self.ui.terrainNouveau, SIGNAL("clicked()"), self.plateau.terrainNouveau)
        self.connect(self.ui.creatureEdit, SIGNAL("clicked()"), self.plateau.creatureEdit)
        self.connect(self.ui.creatureNouveau, SIGNAL("clicked()"), self.plateau.creatureNouveau)
        self.connect(self.ui.pionSimpleCreer, SIGNAL("clicked()"), self.plateau.modeCreationPion)
        self.connect(self.ui.decorEdit, SIGNAL("clicked()"), self.plateau.decorEdit)
        self.connect(self.ui.decorNouveau, SIGNAL("clicked()"), self.plateau.decorNouveau)
        self.connect(self.ui.majCaseAltitude, SIGNAL("clicked()"), self.plateau.modeMajAltitudeCase)
        
        self.connect(self.ui.listTerrains, SIGNAL("cellClicked(int,int)"), self.plateau.modeMajTerrainCase)
        self.connect(self.ui.listCreatures, SIGNAL("cellClicked(int,int)"), self.plateau.modeCreationCreaturePion)
        self.connect(self.ui.listDecors, SIGNAL("cellClicked(int,int)"), self.plateau.modeCreationDecor)
        self.connect(self.ui.listEffets, SIGNAL("cellClicked(int,int)"), self.plateau.modeCaseEffet)
        self.connect(self.ui.epaisseurPinceau, SIGNAL("valueChanged(double)"), self.plateau.majEpaisseurPinceau)    
        
        

class EcranFondPlateau(QGraphicsScene):
    """ecran de fond lorsqu'aucun plateau n'est cree"""
    def __init__(self, fenetre, parent=None):
        super(EcranFondPlateau, self).__init__()
        self.fenetre = fenetre
        self.setBackgroundBrush(QBrush(QPixmap("img\\parchemin.jpg")))
        police = QFont("GothicI", 16)
        self.addText(QString("Cliquer pour creer\nun nouveau plateau"),police)
        #self.ecranFondPlateau.addText(QString("Charger un plateau"),police)
        

    def mousePressEvent(self, event):
        """cree un plateau sur clic gauche"""
        if event.button() == 1:
            self.fenetre.creerPlateau()
            
        
class Plateau(QGraphicsScene):
    """plateau de jeu contenant les cases, decors et pions"""
    def __init__(self, fenetre, parent=None):
        super(Plateau, self).__init__()
        self.nom = ""
        self.fenetre = fenetre
        self.nbCasesX = 0
        self.nbCasesY = 0
        self.hCase = 0
        self.cases = {}   #dict des cases du plateau   (coordonnées: case)
        self.pions = []   #liste de pions positionnes sur le plateau
        self.decors = []  #liste des decors places sur le plateau
        self.modeActif = ""
        self.nbZoomActuel = 0
        self.epaisseurpinceau = 0
        
        #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):
        state = {key:value for key, value in self.__dict__.items() if not key in ["fenetre", "modeActif", "listMode", \
                                                                                  "modeParam", "nbZoomActuel", "epaisseurPinceau"]}
        return (state)

    def __setstate__(self, state):
        self.__dict__ = state

    def creer(self, nom, nbCasesX, nbCasesY, couleur = QColor(0, 255, 0, 80)):
        """cree le plateau"""
        self.nom = nom
        self.hCase = 120  #hauteur d'une case
        self.nbCasesX = nbCasesX   #nb cases en x
        self.nbCasesY = nbCasesY   #nb cases en y
        self.initialisationGraphique()
        
        #cree les cases hexagonales
        for x in range(nbCasesX):
            for y in range(nbCasesY):
                if 1 == (x % 2):
                     y += 0.5
                c = Case(self)
                c.creer(x, y, couleur)
                self.cases[(x,y)] = c

    def recreer(self, fenetre):
        self.fenetre = fenetre
        super(Plateau, self).__init__()

        self.initialisationGraphique() 

        #recreation des cases 
        for coord in self.cases:
            self.cases[coord].recreer(self)

        #recreation des pions
        for pion in self.pions:
            pion.recreer(self)

        #recreation des decors
        for pionDecor in self.decors:
            pionDecor.recreer(self)

    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
        self.setSceneRect(0, 0, 0.866*self.hCase*(self.nbCasesX+1), self.hCase*(self.nbCasesY+1))
        self.fenetre.ui.vuePlateau.setScene(self)
        self.fenetre.ui.vuePlateau.scale(0.25, 0.25)
        self.fenetre.ui.vuePlateau.centerOn(QPointF(0,0))
        self.fenetre.ui.vuePlateau.setDragMode(1)
        self.nbZoomActuel = 0
        self.epaisseurPinceau = 1

        #gestion du mode d'interaction avec le plateau
        self.modeActif = "standard"
        self.listMode = ["standard", "caseMajCouleur", "caseMajTerrain", "pionCreation", "pionMajCouleur", \
                         "pionSelectionne", "pionDecorCreation", "caseMajEffet", "caseMajAltitude"]
        self.modeParam = {"couleur": QColor("grey"), "terrain": None, "pionSelectionne": None, "pionNouveau": None, \
                          "creature": None, "coordProjectionPosition": (0,0), "formeProjectionPosition": None, \
                          "decor": None, "effet":""}
        
        #mise a jour de 'linterface de creation
        self.fenetre.ui.nomPlateau.setText(QString(self.nom))
        self.majListTerrains()
        self.majListCreatures()
        self.majListDecors()
        self.majListEffets()
        if self.modeParam["couleur"].isValid(): 
            self.fenetre.ui.pionCouleur.setStyleSheet("QPushButton {backGround:%s}" %(self.modeParam["couleur"].name()))
            
    def estCree(self):
        """renvoie vrai si des cases ont ete creees"""
        if len(self.cases) > 0:
            retour = True
        else:
            retour = False
        return retour

    ##### 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.show()
        self.editionTerrain.raise_()
        QApplication.processEvents()        
        self.connect(self.fenetre, SIGNAL("majListTerrains()"), self.majListTerrains)
        self.connect(self.editionTerrain, SIGNAL("majListTerrains()"), self.majListTerrains)
        
    def majListTerrains(self):
        """mise a jour de la liste des terrains depuis la sauvegarde"""
        dico = afficheSvg("terrain")
        while self.fenetre.ui.listTerrains.rowCount() > 0:
            self.fenetre.ui.listTerrains.removeRow(0)
        index = 0    
        #self.fenetre.ui.listTerrains.setColumnWidth(0,0)
        self.fenetre.ui.listTerrains.hideColumn(0)
        self.fenetre.ui.listTerrains.sizeHintForColumn(1)
        for elt in dico:
            terrain = dico[elt]
            self.fenetre.ui.listTerrains.insertRow(int(index))
            self.fenetre.ui.listTerrains.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt)))
            icon = QIcon("img\\"+terrain.imgTexture)
            item = QTableWidgetItem(icon,QString.fromUtf8(terrain.nom))
            self.fenetre.ui.listTerrains.setItem(int(index),1,item)
            index += 1
        self.fenetre.ui.listTerrains.setIconSize(QSize(30,20))   
        self.fenetre.ui.listTerrains.sizeHintForColumn(1)
        self.fenetre.ui.listTerrains.sortItems(0)

    def terrainEdit(self):
        """ouvre la fenetre 'terrains' en mode edition"""
        index = self.fenetre.ui.listTerrains.item(self.fenetre.ui.listTerrains.currentRow(), 0)
        if index > 0:
            terrain = charger("terrain", str(index.text()))
            self.afficheEcranEditionTerrains(terrain)
        
    def terrainNouveau(self):
        """ouvre la fenetre 'terrains' en mode edition"""
        self.afficheEcranEditionTerrains()

    def majListEffets(self):
        """met a jour la liste des effets a appliquer aux cases"""
        self.imgEffet = {"aucun":"","brule":"effFeu.jpg", "glace":"effGlace.jpg", "poison":"effPoison.jpg"}
        index = 0 
        self.fenetre.ui.listEffets.hideColumn(0)
        self.fenetre.ui.listEffets.sizeHintForColumn(1)
        for effet in self.imgEffet:
            self.fenetre.ui.listEffets.insertRow(int(index))
            self.fenetre.ui.listEffets.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(effet)))
            icon = QIcon("img\\"+self.imgEffet[effet])
            item = QTableWidgetItem(icon,QString.fromUtf8(effet))
            self.fenetre.ui.listEffets.setItem(int(index),1,item)
            index += 1
        self.fenetre.ui.listEffets.setIconSize(QSize(30,20))   
        self.fenetre.ui.listEffets.sizeHintForColumn(1)
        self.fenetre.ui.listEffets.sortItems(0)
        
    ###############

    ##### affichage de la liste des creatures enregistrees, et fonctions d'acces aux donnees""""     
    def afficheEcranEditionCreatures(self, creature = None):
        """affiche l'ecran d'edition/creation de creatures"""
        self.editionCreature = EcranEditionCreature(creature)
        self.editionCreature.show()
        self.editionCreature.raise_()
        QApplication.processEvents()        
        self.connect(self.fenetre, SIGNAL("majListCreatures()"), self.majListCreatures)
        self.connect(self.editionCreature, SIGNAL("majListCreatures()"), self.majListCreatures)
        
    def majListCreatures(self):
        """mise a jour de la liste des creatures depuis la sauvegarde"""
        dico = afficheSvg("creature")
        while self.fenetre.ui.listCreatures.rowCount() > 0:
            self.fenetre.ui.listCreatures.removeRow(0)
        index = 0    
        #self.fenetre.ui.listTerrains.setColumnWidth(0,0)
        self.fenetre.ui.listCreatures.hideColumn(0)
        self.fenetre.ui.listCreatures.sizeHintForColumn(1)
        for elt in dico:
            creature = dico[elt]
            self.fenetre.ui.listCreatures.insertRow(int(index))
            self.fenetre.ui.listCreatures.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt)))
            icon = QIcon("img\\"+creature.imgTexture)
            item = QTableWidgetItem(icon,QString.fromUtf8(creature.nom))
            self.fenetre.ui.listCreatures.setItem(int(index),1,item)
            index += 1
        self.fenetre.ui.listCreatures.setIconSize(QSize(30,20))   
        self.fenetre.ui.listCreatures.sizeHintForColumn(1)
        self.fenetre.ui.listCreatures.sortItems(0)

    def creatureEdit(self):
        """ouvre la fenetre 'creatures' en mode edition"""
        index = self.fenetre.ui.listCreatures.item(self.fenetre.ui.listCreatures.currentRow(), 0)
        if index > 0:
            creature = charger("creature", str(index.text()))
            self.afficheEcranEditionCreatures(creature)
        
    def creatureNouveau(self):
        """ouvre la fenetre 'creatures' en mode edition"""
        self.afficheEcranEditionCreatures()
    ###############

    ##### 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 = EcranEditionDecors(decor)
        self.editionDecor.show()
        self.editionDecor.raise_()
        QApplication.processEvents()        
        self.connect(self.fenetre, SIGNAL("majListDecors()"), self.majListDecors)
        self.connect(self.editionDecor, SIGNAL("majListDecors()"), self.majListDecors)
        
    def majListDecors(self):
        """mise a jour de la liste des decors depuis la sauvegarde"""
        dico = afficheSvg("decor")
        while self.fenetre.ui.listDecors.rowCount() > 0:
            self.fenetre.ui.listDecors.removeRow(0)
        index = 0    
        #self.fenetre.ui.listTerrains.setColumnWidth(0,0)
        self.fenetre.ui.listDecors.hideColumn(0)
        self.fenetre.ui.listDecors.sizeHintForColumn(1)
        for elt in dico:
            decor = dico[elt]
            self.fenetre.ui.listDecors.insertRow(int(index))
            self.fenetre.ui.listDecors.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt)))
            icon = QIcon(decor.img)
            item = QTableWidgetItem(icon,QString.fromUtf8(decor.nom))
            self.fenetre.ui.listDecors.setItem(int(index),1,item)
            index += 1
        self.fenetre.ui.listDecors.setIconSize(QSize(30,20))   
        self.fenetre.ui.listDecors.sizeHintForColumn(1)
        self.fenetre.ui.listDecors.sortItems(0)

    def decorEdit(self):
        """ouvre la fenetre 'decors' en mode edition"""
        index = self.fenetre.ui.listDecors.item(self.fenetre.ui.listDecors.currentRow(), 0)
        if index > 0:
            decor = charger("decor", str(index.text()))
            self.afficheEcranEditionDecors(decor)
        
    def decorNouveau(self):
        """ouvre la fenetre 'decors' en mode edition"""
        self.afficheEcranEditionDecors()
    ###############

    ########### affichage des curseurs personnalises ########
    def curseurSelection(self):
        self.fenetre.ui.vuePlateau.setDragMode(0)
        curseurPix = QPixmap("img\\pointe.png")#.scaledToHeight(55, Qt.FastTransformation)
        curseurPix.setMask(curseurPix.createHeuristicMask())
        curseurPointe = QCursor(curseurPix, 0, 0)
        self.fenetre.ui.vuePlateau.setCursor(curseurPointe)

    def curseurPinceau(self):
        self.fenetre.ui.vuePlateau.setDragMode(0)
        curseurPix = QPixmap("img\\pinceau.png")#.scaledToHeight(55, Qt.FastTransformation)
        curseurPix.setMask(curseurPix.createHeuristicMask())
        curseurPinceau = QCursor(curseurPix, 0, 0)
        self.fenetre.ui.vuePlateau.setCursor(curseurPinceau)
    ############

    ##### mise a jour du mode d'affichage  ####################
    def affichageNormal(self):
        """passe a l'affichage standard"""
        for coord in self.cases:
            self.cases[coord].majAffichageSpecial("")
            
    def affichageAltitude(self):
        """passe en mode affichage de l'altitude"""
        for coord in self.cases:
            self.cases[coord].majAffichageSpecial("altitude")            

    def affichageTactique(self):
        """passe en affichage tactique"""
        for coord in self.cases:
            self.cases[coord].majAffichageSpecial("tactique")

    def affichageBrouillard(self, nouvelEtat):
        """affiche ou pas le brouillard de guerre"""
        if nouvelEtat == 0:
            afficher = False
        else:
            afficher = True
        #for coord in self.cases:
            #self.cases[coord].afficherBrouillard(afficher)
        self.majBrouillard(afficher)

    ##### activation des differents modes d'interaction avec le plateau et mises a jour des principaux parametres  #######
    def modePeintureCase(self):
        """enclenche le mode peinture de case a partir de la couleur selectionnee"""
        couleur = QColorDialog(self.fenetre.ui.vuePlateau).getColor(QColor("white"), self.fenetre.ui.vuePlateau)
        if couleur.isValid():
            self.majMode("caseMajCouleur", couleur)
        else:
            self.majMode("standard")

    def modeCaseEffet(self, ligne, col):
        """enclenche le mode de mise a jour de l'ffet actif des cases"""
        effet = self.fenetre.ui.listEffets.item(ligne, 0).text()
        self.majMode("caseMajEffet", str(effet))
        self.fenetre.ui.vuePlateau.setFocus()

    def modeCreationPion(self):
        """enclenche le mode de creation de pions simples"""
        self.majMode("pionCreation")

    def modeCreationDecor(self, ligne, col):
        """enclenche le mode de creation de decors depuis la liste des decors"""
        index = self.fenetre.ui.listDecors.item(ligne, 0)
        decor = charger("decor", str(index.text()))
        self.majMode("pionDecorCreation", decor)
        self.fenetre.ui.vuePlateau.setFocus()
        
    def modeCreationCreaturePion(self, ligne, col):
        """enclenche le mode de creation de pions depuis la liste des creatures"""
        index = self.fenetre.ui.listCreatures.item(ligne, 0)
        creature = charger("creature", str(index.text()))
        self.majMode("pionCreation", creature)
        self.fenetre.ui.vuePlateau.setFocus()

    def modeMajTerrainCase(self, ligne, col):
        """enclenche le mode permettant la mise a jour du terrain des cases"""
        index = self.fenetre.ui.listTerrains.item(ligne, 0)
        terrain = charger("terrain", str(index.text()))
        self.majMode("caseMajTerrain", terrain)
        self.fenetre.ui.vuePlateau.setFocus()

    def majCouleurPion(self):
        """enclenche le mode peinture de pion a partir de la couleur selectionnee"""
        self.majMode("standard")
        couleur = QColorDialog(self.fenetre.ui.vuePlateau).getColor(QColor("white"), self.fenetre.ui.vuePlateau)
        if couleur.isValid():
            self.majMode("pionMajCouleur", couleur)
            self.fenetre.ui.pionCouleur.setStyleSheet("QPushButton {backGround:%s}" %(self.modeParam["couleur"].name()))
            
    def majEpaisseurPinceau(self, epaisseur):
        """met a jour l'epaisseur du pinceau (en cases)"""
        self.epaisseurPinceau = int(epaisseur)

    def modeMajAltitudeCase(self):
        self.majMode("caseMajAltitude")

    def majMode(self, mode = "standard", param = None):
        """modifie ou reinitialise le type d'interaction avec le plateau"""
        reinit = True    #doit-on reinitialiser a la fin de l'operation
        if mode in self.listMode and mode != "standard":
            self.modeActif = mode                    
            if mode == "caseMajCouleur":
                #curseur pinceau, on peint les cases de couleurs simples
                if param.isValid():
                    self.modeActif = mode
                    self.curseurPinceau()
                    self.fenetre.ui.vuePlateau.setDragMode(0)
                    self.modeParam["couleur"] = param
                    reinit = False
                    
            elif mode == "caseMajTerrain":
                #curseur pinceau, on ajoute des terrains au cases
                if param != None:
                    if param.__class__.__name__ == "Terrain":
                        self.modeActif = mode
                        self.curseurPinceau()
                        self.fenetre.ui.vuePlateau.setDragMode(0)
                        self.modeParam["terrain"] = param                
                        reinit = False

            elif mode == "caseMajEffet":
                #on met a jour l'effet actif sur les cases
                if param != None:
                    self.modeActif = mode
                    self.curseurPinceau()
                    self.fenetre.ui.vuePlateau.setDragMode(0)
                    self.modeParam["effet"] = param                
                    reinit = False

            elif mode == "caseMajAltitude":
                self.modeActif = mode
                self.curseurPinceau()
                self.fenetre.ui.vuePlateau.setDragMode(0)               
                reinit = False                
                
            elif mode == "pionDecorCreation":
                #curseur 'plus', on cree de nouveaux decors
                self.modeParam["decor"] = None
                self.fenetre.ui.vuePlateau.setDragMode(0)
                self.modeParam["formeProjectionPosition"] = Forme()
                if param != None:
                    if param.__class__.__name__ == "Decor":
                         self.modeParam["decor"] = param
                         self.modeParam["formeProjectionPosition"].definirForme(self.modeParam["decor"].formeDef)
                self.modeActif = mode
                reinit = False
            
            elif mode == "pionMajCouleur":
                #curseur pinceau, on peint les pions de couleurs simples
                if param.isValid():
                    #self.modeActif = mode
                    #self.curseurPinceau()
                    #self.fenetre.ui.vuePlateau.setDragMode(0)
                    self.modeParam["couleur"] = param
                    reinit = False
            
            elif mode == "pionCreation":
                #curseur 'plus', on cree de nouveaux pions
                self.modeParam["creature"] = None
                self.fenetre.ui.vuePlateau.setDragMode(0)
                self.modeParam["formeProjectionPosition"] = Forme()
                if param != None:
                    if param.__class__.__name__ == "Creature":
                         self.modeParam["creature"] = param
                         self.modeParam["formeProjectionPosition"].definirForme(self.modeParam["creature"].formeDef)
                self.modeActif = mode
                reinit = False

            elif mode == "pionSelectionne":
                #un pion est selectionne, on affiche les deplacements possibles
                if param != None:
                    self.modeParam["pionSelectionne"] = param
                    
                    #maj du curseur
                    self.fenetre.ui.vuePlateau.setDragMode(0)
                    self.fenetre.ui.vuePlateau.setCursor(QCursor(Qt.ClosedHandCursor))
                    #surbrillance du pion
                    self.modeParam["pionSelectionne"].surbrillance(True)
                    self.modeParam["formeProjectionPosition"] = Forme()
                    self.modeParam["formeProjectionPosition"].definirForme(self.modeParam["pionSelectionne"].forme.formeDef)
                        
                    self.modeParam["pionSelectionne"].champDeplacement = self.zone(self.modeParam["pionSelectionne"].position, \
                                                                          self.modeParam["pionSelectionne"].deplacementRestant, \
                                                                                   True)
                    
                    for coord in self.modeParam["pionSelectionne"].champDeplacement:
                         self.cases[coord].majEstDansChampDeplacement(True)
                    reinit = False     
                else:
                    #le pion a ete depose, on le deselectionne et on desactive l'affichage du champ de deplacement
                    self.modeParam["pionSelectionne"].surbrillance(False)
                    for coord in self.modeParam["pionSelectionne"].champDeplacement:
                       self.cases[coord].majEstDansChampDeplacement(False) 
                    self.modeParam["pionSelectionne"].champDeplacement = {}   
                    self.modeParam["pionSelectionne"] = None

        elif not mode in self.listMode:
            print("mode non reconnu")
                    
        if reinit:
            #mode standard : pas d'interaction avec les cases, on deplace le plateau en le saisissant ou les pions en cliquant dessus
            self.modeActif = "standard"
            self.majProjectionPosition(False)
            self.majInfosPion()
            self.modeParam["formeProjectionPosition"] = None
            self.modeParam["coordProjectionPosition"] = None
            self.fenetre.ui.vuePlateau.setCursor(QCursor(Qt.ArrowCursor))
            self.fenetre.ui.vuePlateau.setDragMode(1)
                             
    ###############

    ############### fonctions de calcul ################ 
    def zone(self, origine, distance, 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
           [cf methode A* (A-star)]"""
        aVerifier = []
        aVerifier2 = []
        resultat = {}
        k = 0           
        #on part de la premiere case, puis on itere a partir de chaque nouveau depart
        if origine in self.cases:
            aVerifier.append(origine)
            while k <= distance:
                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 champVision(self, origine, hauteur=0):
        """renvoie la liste des cases visibles depuis la case et la hauteur donnees"""
        #essai 4: on travaille par angle
        #lorsque l'angle entre les coordonnees d'une case et celles de l'origine est inferieure au demi rayon de l'obstacle a cette distance(tolerance, a revoir),
        #elle est consideree comme invisible
        #si elle est comprise entre le demi rayon et le rayon, elle presente un couvert partiel 

        obstacles = []
        visibilite = {}
        aVerifier = []
        #on enregistre les coord des obstacles (a ne faire qu'une fois avant de faire le champ de vision de tous les pions)
        for coord in self.cases:
            if coord != origine:
                aVerifier.append(coord)
                visibilite[coord] = 1
                if self.cases[coord].estObstacleVision(hauteur):
                   obstacles.append(coord)
        
        for coordObs in obstacles:
            tolerance = 0.5*atan(1/(sqrt((coordObs[0]-origine[0])**2+(coordObs[1]-origine[1])**2)))
            #quart sud-est
            if coordObs[0] > origine[0] and coordObs[1] >= origine[1]:
                for coord in aVerifier:
                    if visibilite[coord] > 0 and coord != coordObs and coord[0] >= coordObs[0] and coord[1] >= coordObs[1]:
                        deltaAngle = abs(atan((coord[1]-origine[1])/(coord[0]-origine[0]))-atan((coordObs[1]-origine[1])/(coordObs[0]-origine[0])))
                        if deltaAngle/(2*tolerance) < 1:
                            visibilite[coord] = visibilite[coord]*deltaAngle/(2*tolerance)     
            #quart nord-est                
            if coordObs[0] > origine[0] and coordObs[1] <= origine[1]:
                for coord in aVerifier:
                    if visibilite[coord] > 0 and coord != coordObs and coord[0] >= coordObs[0] and coord[1] <= coordObs[1]:
                        deltaAngle = abs(atan((coord[1]-origine[1])/(coord[0]-origine[0]))-atan((coordObs[1]-origine[1])/(coordObs[0]-origine[0])))
                        if deltaAngle/(2*tolerance) < 1:
                            visibilite[coord] = visibilite[coord]*deltaAngle/(2*tolerance)     
            #quart sud-ouest                
            if coordObs[0] < origine[0] and coordObs[1] >= origine[1]:
                #print tolerance
                for coord in aVerifier:
                    if visibilite[coord] > 0 and coord != coordObs and coord[0] <= coordObs[0] and coord[1] >= coordObs[1]:
                        deltaAngle = abs(atan((coord[1]-origine[1])/(coord[0]-origine[0]))-atan((coordObs[1]-origine[1])/(coordObs[0]-origine[0])))
                        if deltaAngle/(2*tolerance) < 1:
                            visibilite[coord] = visibilite[coord]*deltaAngle/(2*tolerance)     
            #quart nord-ouest                
            if coordObs[0] < origine[0] and coordObs[1] <= origine[1]:
                for coord in aVerifier:
                    if visibilite[coord] > 0 and coord != coordObs and coord[0] <= coordObs[0] and coord[1] <= coordObs[1]:
                        deltaAngle = abs(atan((coord[1]-origine[1])/(coord[0]-origine[0]))-atan((coordObs[1]-origine[1])/(coordObs[0]-origine[0])))
                        if deltaAngle/(2*tolerance) < 1:
                            visibilite[coord] = visibilite[coord]*deltaAngle/(2*tolerance)     
            #x = x obstacle
            if coordObs[0] == origine[0] and coordObs[1] != origine[1]:
                for coord in aVerifier:
                    if visibilite[coord] > 0 and coord != coordObs and copysign(coord[1], (coordObs[1]-origine[1])) > copysign(coordObs[1], (coordObs[1]-origine[1])):
                        deltaAngle = abs(atan((coord[0]-origine[0])/(coord[1]-origine[1]))-atan((coordObs[0]-origine[0])/(coordObs[1]-origine[1])))
                        if deltaAngle/(2*tolerance) < 1:
                            visibilite[coord] = visibilite[coord]*deltaAngle/(2*tolerance)                                      

        #for coord in visibilite:
        #    if visibilite[coord] <= 0.50:
        #        self.cases[coord].setBrush(QColor("grey"))
        #    elif visibilite[coord] <= 0.75:
        #        self.cases[coord].setBrush(QColor("grey").lighter(150))
        #    self.etiquetteVisibilite(coord, int(100*visibilite[coord]))
        return visibilite

    def etiquetteVisibilite(self, coord, taux):
        if taux > 100: taux = 100
        if taux < 0 : taux = 0
        self.cases[coord].etiquette = QGraphicsSimpleTextItem("{}".format(taux), parent=self.cases[coord])
        police = QFont("Georgia", 16)
        self.cases[coord].etiquette.setFont(police)
        self.cases[coord].etiquette.setPos(QPointF(((self.cases[coord].x*0.866)+0.55)*self.hCase,  (self.cases[coord].y+0.7)*self.hCase))
        
    #######################

    ######## interaction avec les cases, decors et pions  ##############         
    def caseMaj(self, coordCase):
        """met a jour la case selon le mode actif (et les cases adjacentes selon l'epaisseur du pinceau)"""
        zoneAPeindre = self.zone(coordCase, self.epaisseurPinceau-1)
        if self.modeActif == "caseMajTerrain":
            if self.modeParam["terrain"] != None:
                for coord in zoneAPeindre:
                    self.cases[coord].majTerrain(self.modeParam["terrain"])

        elif self.modeActif == "caseMajCouleur":
            if self.modeParam["couleur"].isValid():
                for coord in zoneAPeindre:
                    self.cases[coord].setBrush(self.modeParam["couleur"])
        elif self.modeActif == "caseMajEffet":
            for coord in zoneAPeindre:
                self.cases[coord].majEffet(self.modeParam["effet"])
        elif self.modeActif == "caseMajAltitude":
            for coord in zoneAPeindre:
                self.cases[coord].majAltitude(int(self.fenetre.ui.altitudeCase.value()))

    def caseSurvol(self, case):
        """une case est survole par le curseur, on affiche ses informations dans la zone prevue"""
        self.majInfosCase(case)
        
    def majInfosCase(self, case=None):
        """met a jour les informations d'un pion dans la zone prevue"""
        if case != None:
            if len(case.terrain.nom) > 0:
                self.fenetre.ui.infoCaseEnCours_terrain.setText(QString(case.terrain.nom))
            else:
                self.fenetre.ui.infoCaseEnCours_terrain.setText(QString("Case"))
            self.fenetre.ui.infoCaseEnCours_coord.setText(QString("X: {}  Y: {}".format(case.x, case.y)))
            self.fenetre.ui.infoCaseEnCours_altitude.setText(QString("Alt.: {}".format(case.altitude)))
            if case.effetActif != "":
                pix = QPixmap(QString.fromUtf8("img\\"+case.imgEffet[case.effetActif]))
                pix = pix.scaled(21, 21, Qt.KeepAspectRatio, Qt.SmoothTransformation)
                self.fenetre.ui.infoCaseEnCours_effetImg.setPixmap(pix)                
                self.fenetre.ui.infoCaseEnCours_effetNom.setText(QString(case.effetActif))
            else:
                self.fenetre.ui.infoCaseEnCours_effetImg.clear()
                self.fenetre.ui.infoCaseEnCours_effetNom.clear()

    def majBrouillard(self, actif=True):
        """active et met a jour le brouillard de guerre ou le desactive"""
        t0 = time()
        if actif:
            for pion in self.pions:
                visibilite = self.champVision(pion.position, (self.cases[pion.position].altitude+pion.hauteur))
                for coord in visibilite:
                    if visibilite[coord] > 0.5:
                        self.cases[coord].afficherBrouillard(False)
                    else:
                        self.cases[coord].afficherBrouillard(True)
        else:
            for coord in self.cases:
                self.cases[coord].afficherBrouillard(False)

    def pionCreer(self, coordCase):
        """creer un jeton aux coordonnees indiquees"""
        valide = True
        for coord in self.modeParam["formeProjectionPosition"].listeCases(coordCase):
            if not self.cases[coord].estFranchissable():
                 valide = False
        if valide:  
            numero = len(self.pions) + 1
            pion = Pion(self, numero)
            pion.creer(coordCase[0], coordCase[1], self.modeParam["creature"], self.modeParam["couleur"], self.modeParam["formeProjectionPosition"])
            self.pions.append(pion)
            

    def pionSaisir(self, pion):
        """on saisit un pion"""
        #on met a jour le mode d'interaction
        self.majMode("pionSelectionne", pion)
        
    def pionDeposer(self, coordCase):
        """on depose le pion sur la case voulue"""
        if self.modeParam["pionSelectionne"] != None:
            if coordCase in self.modeParam["pionSelectionne"].champDeplacement:
                valide = True
                for coord in self.modeParam["formeProjectionPosition"].listeCases(coordCase):
                    if not self.cases[coord].estFranchissable(self.modeParam["pionSelectionne"].z):
                        if not self.cases[coord].estOccupeePar(self.modeParam["pionSelectionne"].z) == self.modeParam["pionSelectionne"]:
                         #si la case est occupee par le pion qu'on depose, elle est donc valide pour un deplacement  
                            valide = False
                if valide:        
                    positionPrecedente = self.modeParam["pionSelectionne"].position 
                    #mise a jour de la position du pion
                    self.modeParam["pionSelectionne"].majPosition(coordCase, self.modeParam["formeProjectionPosition"])
                    print("le pion a ete deplace de {} vers {} \n    -> soit une distance de {} cases"\
                          "".format(positionPrecedente, coordCase, self.modeParam["pionSelectionne"].champDeplacement[coordCase]))
                    self.majMode("pionSelectionne", None)
                    self.majInfosPion()
                else:
                    print("deplacement impossible")
            else:
                print("pas dans le champ de deplacement")

    def pionSurvol(self, pion):
        """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
        self.majInfosPion(pion)     

    def majInfosPion(self, pionSurvole=None):
        """met a jour les informations d'un pion dans la zone prevue"""
        if pionSurvole != None:
            pion = pionSurvole
        elif self.modeParam["pionSelectionne"] != None:
            pion = self.modeParam["pionSelectionne"]
        else:
            pion = None

        if pion != None:  
            self.fenetre.ui.infoPionEnCours_nom.setText(QString(pion.nom))
            self.fenetre.ui.infoPionEnCours_depRestant.setText(QString("Dep.: {}".format(pion.deplacementRestant)))
            if len(pion.creature.imgTexture) > 0:
                pix = QPixmap(QString.fromUtf8("img\\"+pion.creature.imgTexture))
                pix = pix.scaled(61, 51, Qt.KeepAspectRatio, Qt.SmoothTransformation)
                self.fenetre.ui.infoPionEnCours_image.setPixmap(pix)
            else:
                if pion.creature.couleur.isValid():
                    self.fenetre.ui.infoPionEnCours_image.setStyleSheet("QLabel {backGround:%s}" %(pion.creature.couleur))
        else:
            self.fenetre.ui.infoPionEnCours_nom.clear()
            self.fenetre.ui.infoPionEnCours_depRestant.setText(QString("Dep.:"))
            self.fenetre.ui.infoPionEnCours_image.clear()

    def majProjectionPosition(self, activer, z=0):
        """maj l'affichage de la projection de la position d'un objet avant creation ou deplacement (pion, decor...)"""
        valide = True
        possible = True
        afficherProjection = True
        if activer and (self.modeActif == "pionCreation" or self.modeActif == "pionSelectionne" or self.modeActif == "pionDecorCreation"):
            if self.modeParam["formeProjectionPosition"] != None and self.modeParam["coordProjectionPosition"] != None:
                 proj = self.modeParam["formeProjectionPosition"].listeCases(self.modeParam["coordProjectionPosition"])
                 for coord in proj:
                     if coord[0] < 0 or coord[0] > self.nbCasesX or coord[1] < 0 or coord[1] > self.nbCasesY:
                          valide = False
                     else:     
                          if not self.cases[coord].estFranchissable(z):
                              if self.modeActif == "pionSelectionne" and self.cases[coord].estOccupeePar(z) == self.modeParam["pionSelectionne"]:
                                  #la case est occupee par le pion qui se deplace, elle est donc valide pour un deplacement
                                  possible = True
                              else:    
                                  possible = False
                 if valide == True:
                     for coord in proj:
                         if possible:
                             self.cases[coord].majEstCibleCurseur(True, True)
                             if self.modeActif == "pionSelectionne":
                                  if coord in self.modeParam["pionSelectionne"].champDeplacement:
                                      QToolTip.showText(QCursor.pos(), \
                                                        "Distance {}".format(self.modeParam["pionSelectionne"].champDeplacement[coord]), \
                                                        self.fenetre.ui.vuePlateau)
                         else:
                              self.cases[coord].majEstCibleCurseur(True, False)
        else:
            if self.modeParam["formeProjectionPosition"] != None and self.modeParam["coordProjectionPosition"] != None:
                 proj = self.modeParam["formeProjectionPosition"].listeCases(self.modeParam["coordProjectionPosition"])
                 for coord in proj:
                     if coord[0] < 0 or coord[0] > self.nbCasesX or coord[1] < 0 or coord[1] > self.nbCasesY:
                          valide = False        
                 if valide == True:
                     for coord in proj:
                         self.cases[coord].majEstCibleCurseur(False)

    def pionDecorCreer(self, coordCase):
        """creer un jeton aux coordonnees indiquees"""
        valide = True
        for coord in self.modeParam["formeProjectionPosition"].listeCases(coordCase):
            if not self.cases[coord].estFranchissable():
                 valide = False
        if valide:  
            pionDecor = PionDecor(self)
            pionDecor.creer(coordCase[0], coordCase[1], self.modeParam["decor"])
            self.decors.append(pionDecor)
                
    ###############
        
    ######### gestion des evenements souris et clavier ###############
    def wheelEvent(self, event):
        """zoom/dezoom avec la molette de la souris"""
        #on zoom/dezoom et on recentre sur la position du curseur
        #super (Plateau, self).wheelEvent(event)
        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.fenetre.ui.vuePlateau.scale(zoom, zoom)
           self.fenetre.ui.vuePlateau.centerOn(event.scenePos())
        event.accept() #pour considerer l'evenement comme resolu, sans ca les barres de defilement reagissent aussi  

    def mouseMoveEvent(self, event):
        super(Plateau, self).mouseMoveEvent(event)
        if event.buttons() == Qt.LeftButton:
            if self.modeActif == "caseMajCouleur" or self.modeActif == "caseMajTerrain" or self.modeActif == "caseMajEffet" or self.modeActif == "caseMajAltitude":
                 lstObjets = self.fenetre.ui.vuePlateau.scene().items(event.scenePos())
                 for objet in lstObjets:
                 #case = self.fenetre.ui.vuePlateau.scene().itemAt(event.scenePos())
                    if objet:
                        if objet.__class__.__name__ == "Case":
                             self.caseMaj((objet.x, objet.y))
                             break
        else:
           event.ignore() 

    def mousePressEvent(self, event):
        super(Plateau, self).mousePressEvent(event)
        if event.button() == 1:
             if self.modeActif == "caseMajCouleur" or self.modeActif == "caseMajTerrain" or self.modeActif == "caseMajEffet" or self.modeActif == "caseMajAltitude":
                  lstObjets = self.fenetre.ui.vuePlateau.scene().items(event.scenePos())
                  for objet in lstObjets:
                     if objet:
                        if objet.__class__.__name__ == "Case":
                           self.caseMaj((objet.x, objet.y))
                           event.accept()
                           break                          
        elif event.button() == 2:
            if self.modeParam["pionSelectionne"] != None:
                self.majMode("pionSelectionne", None)
            else:    
                self.majMode("standard")
            event.accept()
        #event.ignore()

    def keyPressEvent(self, event):
        """gestion des evenements clavier"""
        toucheClavier = event.key()
        #gestion des pivots de la projection du deplacement
        if self.modeActif == "pionCreation" or self.modeActif == "pionSelectionne" or self.modeActif == "pionDecorCreation":
            if toucheClavier == Qt.Key_Right:
                self.majProjectionPosition(False)
                self.modeParam["formeProjectionPosition"].pivoter("+")
                self.majProjectionPosition(True)
                event.accept()
            elif toucheClavier == Qt.Key_Left:
                self.majProjectionPosition(False)
                self.modeParam["formeProjectionPosition"].pivoter("-")
                self.majProjectionPosition(True)
                event.accept()
            
    ################           


class Case(QGraphicsPolygonItem):
    """objet graphique representant une case du plateau"""
    def __init__(self, plateau, parent=None):
        super(Case, self).__init__()
        #plateau
        self.plateau = plateau
        
        #attributs
        self.altitude = 0                   
        self.terrain = Terrain()                       #terrain par defaut 
        self.couleur = None                            #couleur du fond par defaut
        self.bordure = QColor(85, 85, 85, 85)          #couleur de la bordure par defaut
        self.estDansChampDeplacement = False           #la case est dans le champ de deplacement du pion selectionne
        self.centreGraphique = None

        self.occupeePar = {}    #objet: altitudes occupees (sous forme de tuple, ex: (0,1,2) pour une creature occupant les cases d'altitude 0, 1 et 2)
        self.brouillard = False   #brouillard (cache le terrain, les decors, les pions...)
        self.ombre = True         #ombre (cache les pions uniquement)  

        #effet sur la case 
        self.effetActif = "" 

        #polygones d'affichage
        self.polygoneEffet = None
        self.polygoneAffichageSpecial = None
        self.etiquetteAltitude = None
        

    def __getstate__(self):
        state = {key:value for key, value in self.__dict__.items() if not key in ["plateau", "polygoneBrouillard", "polygoneEffet", \
                                                                                  "polygoneCible", "polygoneChampDep", \
                                                                                  "polygoneAffichageSpecial", "etiquetteAltitude"\
                                                                                  "couleurEffet", "imgEffet", "voisins", "centreGraphique"]}
        return (state)

    def __setstate__(self, state):
        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.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"), "neige":QColor("white"), "glace":QColor("blue"), "poison":QColor("green")}
        self.imgEffet = {"brule":"effFeu.jpg", "glace":"effGlace.jpg", "poison":"effPoison.jpg"}

        #enregistrement des cases voisines:
        self.voisins = []    
        if self.y < (self.plateau.nbCasesY-1):                                        self.voisins.append((self.x,   self.y+1))
        if self.y > 0.5:                                                              self.voisins.append((self.x,   self.y-1))
        if self.x > 0 and self.y < (self.plateau.nbCasesY-1) :                        self.voisins.append((self.x-1, self.y+0.5))
        if self.x > 0 and self.y > 0:                                                 self.voisins.append((self.x-1, self.y-0.5))
        if self.x < (self.plateau.nbCasesX-1) and self.y < (self.plateau.nbCasesY-1): self.voisins.append((self.x+1, self.y+0.5))
        if self.x < (self.plateau.nbCasesX-1) and self.y > 0 :                        self.voisins.append((self.x+1, self.y-0.5))

        #enregistrement du centre
        self.centreGraphique = QPointF(((self.x*0.866)+0.5773)*self.plateau.hCase, (self.y+0.5)*self.plateau.hCase)
        
        #cree le polygone de la case
        self.setPolygon(self.polygone())
        self.plateau.addItem(self)
        
        #interactions graphiques:
        self.setFlag(QGraphicsItem.ItemIsFocusable)
        self.setAcceptHoverEvents(True)
        self.setAcceptDrops(True)
        self.setZValue(0)
        self.setFiltersChildEvents(True)

        #apparence initiale de la case
        pinceau = QPen()
        pinceau.setColor(self.bordure)
        pinceau.setWidth(1)
        self.setPen(pinceau)
        self.setBrush(self.couleur)

        #pour afficher les coordonnees des cases:        
        #text = QGraphicsSimpleTextItem("{}-{}".format(self.x,self.y), parent=self)
        #text.setPos(QPointF(((self.x*0.866)+0.2886)*self.plateau.hCase,  self.y*self.plateau.hCase))
        
        #polygone utilise pour afficher la cible du curseur
        self.polygoneCible = QGraphicsPolygonItem(self.polygone(), parent=self)
        self.polygoneCible.setVisible(False)

        #polygone utilise lorsque dans champ de deplacement
        self.polygoneChampDep = QGraphicsPolygonItem(self.polygone(), parent=self)
        self.polygoneChampDep.setPen(pinceau)
        self.polygoneChampDep.setBrush(self.couleur.lighter(200))
        self.polygoneChampDep.setVisible(False)

        #polygone (independant) utilise pour le brouillard de guerre
        self.polygoneBrouillard = QGraphicsPolygonItem(self.polygone())
        self.polygoneBrouillard.setBrush(QColor(120,120,120))
        self.plateau.addItem(self.polygoneBrouillard)
        self.polygoneBrouillard.setVisible(False)

    def majGraphique(self):
        """met a jour l'aspect graphique de la acse en fonction de son etat"""
        if self.terrain:
            if len(self.terrain.nom) > 0 : 
                self.majTerrain(self.terrain)
        self.afficherBrouillard(self.brouillard)        
        self.majAffichageSpecial("")
        self.majEffet(self.effetActif)

    def recreer(self, plateau):
        self.plateau = plateau
        super(Case, self).__init__()
        #polygones d'affichage
        self.polygoneEffet = None
        self.polygoneAffichageSpecial = None
        self.etiquetteAltitude = None
        
        self.creerGraphique()
        self.majGraphique()

    def polygone(self):
        """renvoie l'objet graphique hexagone de la case"""
        polygone = QPolygonF()
        polygone  << QPointF( (self.x*0.866)*self.plateau.hCase,         (self.y+0.5)*self.plateau.hCase) \
                  << QPointF(((self.x*0.866)+0.2886)*self.plateau.hCase,  self.y*self.plateau.hCase) \
                  << QPointF(((self.x*0.866)+0.866)*self.plateau.hCase,   self.y*self.plateau.hCase) \
                  << QPointF(((self.x*0.866)+1.1547)*self.plateau.hCase, (self.y+0.5)*self.plateau.hCase) \
                  << QPointF(((self.x*0.866)+0.866)*self.plateau.hCase,  (self.y+1)*self.plateau.hCase) \
                  << QPointF(((self.x*0.866)+0.2886)*self.plateau.hCase, (self.y+1)*self.plateau.hCase)
        return polygone
        
    ########################

    ########## fonctions liees a l'etat de la case ###########
    def majTerrain(self, terrain):
        if terrain: 
            self.terrain = terrain
            if len(self.terrain.imgTexture) > 0:
                self.setBrush(QBrush(QImage("img\\"+self.terrain.imgTexture)))
            else:
                if self.terrain.couleur.isValid():
                     self.setBrush(QBrush(self.terrain.couleur))

    def majOccupation(self, objet, nouveauZ=0):
        """met a jour l'occupation de la case par les pions, decors..."""
        if objet != None:
            if not objet in self.occupeePar or nouveauZ != 0:
                #on ajoute l'objet a la liste des objets occupant la case ou on met a jour son altitude
                casesOccupees = []
                for i in range(0, objet.hauteur):
                    casesOccupees.append(self.altitude + nouveauZ + i)
                self.occupeePar[objet] = casesOccupees
                
            elif objet in self.occupeePar and nouveauZ == 0:
                #on supprime l'objet de la liste des objets occupant la case
                del self.occupeePar[objet]
            else:
                pass
            #print self.occupeePar
            
    def estOccupee(self, z=0):
        """renvoie vrai si la case correspondant a la hauteur z est occupee"""
        retour = False
        for objet in self.occupeePar:
            if objet.hauteur > 0 and z in self.occupeePar[objet]:
                retour = True
        return retour        

    def estOccupeePar(self, z=0):
        """si la case correspondant a la hauteur z est occupee, renvoie l'objet en question
           sinon renvoie None"""
        retour = None
        for objet in self.occupeePar:
            if objet.hauteur > 0 and z in self.occupeePar[objet]:
                retour = objet
        return retour  

    def estFranchissable(self, z=0):
        """la case est-elle franchissable?"""
        retour = True
        if self.terrain.franchissable == False:
            retour = False
        else:
            if self.estOccupee(z) == True:
                retour = False
        return retour

    def estObstacleVision(self, hauteurObs):
        """renvoie vrai si la case et l'eventuel decor qui l'occupe bloquent le champ de
           vision d'un observateur situe a la hauteur precisee"""
        retour = False
        if self.altitude > hauteurObs:
            retour = True
        else:
            hauteurObstacle = 0
            for objet in self.occupeePar:
                if objet.hauteur > hauteurObstacle:
                    hauteurObstacle = objet.hauteur
            if (self.altitude + hauteurObstacle) > hauteurObs:
                retour = True
        return retour                

    def majEstDansChampDeplacement(self, actif):
        """la case apparait ou pas comme etant dans le champ de deplacement d'un pion"""
        self.polygoneChampDep.setVisible(actif)

    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(10)
            pinceau.setColor(QColor("white"))
            if valide:
                pinceau.setColor(QColor("white"))
            else:
                pinceau.setColor(QColor("red"))
            self.polygoneCible.setPen(pinceau)
            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(), 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 majAltitude(self, altitude):
        """met a jour l'altitude de la case"""
        self.altitude = altitude
        #self.majAffichageSpecial("altitude")

    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(), 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("{}".format(self.altitude)))
            self.etiquetteAltitude.setVisible(True)
            self.etiquetteAltitude.setZValue(6)
        else:
            self.polygoneAffichageSpecial.setVisible(False)

    def afficherBrouillard(self, actif):
        """affiche/cache le brouillard sur cette case"""
        self.polygoneBrouillard.setZValue(100)
        self.polygoneBrouillard.setAcceptHoverEvents(actif)
        self.polygoneBrouillard.setVisible(actif)
        self.polygoneBrouillard.setEnabled(actif)
        

    ######### evebements souris et clavier    #################    
    def mousePressEvent(self, event):
        """evenement lors du clic souris"""
        super(Case, self).mousePressEvent(event)
        if event.button() == 1: #sur clic gauche       
            if self.plateau.modeActif == "pionSelectionne":
                #un pion est selectionne, il est deplace
                if self.plateau.modeParam["pionSelectionne"] != None:
                    #on depose le pion
                    #self.majBordure(1)
                    self.plateau.pionDeposer((self.x, self.y))
                    event.accept()
            elif self.plateau.modeActif == "pionCreation":
                #le mode creation de pion est actif, on cree un pion a cette position
                self.plateau.pionCreer((self.x, self.y))
                event.accept()
            elif self.plateau.modeActif == "pionDecorCreation":
                #le mode creation de pion de decor est actif, on cree un pion decor a cette position
                self.plateau.pionDecorCreer((self.x, self.y))
                event.accept()
            else:
                event.ignore()
        else:
            #sur clic droit, on annule le mode en cours
            if self.plateau.modeActif == "pionSelectionne":
                self.plateau.majMode("pionSelectionne", None)
            else:    
                self.plateau.majMode("standard")

    def hoverEnterEvent(self, event):
        """met a jour l'affichage de la case au survol de la souris, si un pion est selectionne"""
        self.plateau.caseSurvol(self)
        if self.plateau.modeActif == "pionSelectionne" or self.plateau.modeActif == "pionCreation" or self.plateau.modeActif == "pionDecorCreation":
            self.plateau.majProjectionPosition(False)
            self.plateau.modeParam["coordProjectionPosition"] = (self.x, self.y)
            self.plateau.majProjectionPosition(True)
            event.accept()
    
    ########################


class Pion(QGraphicsEllipseItem):
    """pion du plateau de combat"""
    def __init__(self, plateau, numero, parent=None):
        super(Pion, self).__init__(parent)
        #plateau
        self.plateau = plateau

        #attributs
        self.numero = numero
        self.creature = Creature()
        self.nom = "pion"
        self.position = (-1, -1)
        self.forme = Forme()
        self.polygonesForme = []     #liste des polygones crees pour representer la forme de la creature
        self.champDeplacement = {}   #dictionnaire des cases jusqu'auquelles le pion peut se deplacer (coordonnees : distance)
        self.deplacementRestant = 0
        self.z = 0         #hauteur z par rapport a l'altitude de la case occupee
        self.hauteur = 1   #nombre de cases occupees en hauteur
        


    def __getstate__(self):
        state = {key:value for key, value in self.__dict__.items() if not key in ["plateau", "brillance", "shadow", \
                                                                                  "polygonesForme", "pixGraphique"]}
        return (state)

    def __setstate__(self, state):
        self.__dict__ = state

    ########### fonctions graphiques et geometriques   ##############
    def creer(self, posX, posY, creature = None, couleur = None, forme = None, nom = ""):
        """place le pion sur le plateau"""        
        #definition de la forme
        if creature != None:
            self.creature = creature
            if forme != None:
                self.forme.definirForme(forme.formeDef)
            else:    
                if len(self.creature.formeDef) > 0:
                    self.forme.definirForme(self.creature.formeDef)
        else:
            if couleur != None:
                if couleur.isValid():
                    self.creature.couleur = couleur

        self.deplacementRestant = self.creature.deplacement
        
        #creation de l'etiquette
        if len(nom) == 0:
            if creature != None:
                self.nom = self.creature.nom
            elif len(self.plateau.fenetre.ui.pionSimple_nom.text()) > 0:
                self.nom = self.plateau.fenetre.ui.pionSimple_nom.text()            
        else:
            self.nom = nom

        #aspect graphique
        self.majAspectGraphique()

        #ajout de l'objet graphique et placement
        self.plateau.addItem(self)

        #enregistrement et maj de la position 
        self.majPosition((posX, posY))

    def recreer(self, plateau):
        """recree le pion (apres un chargement du plateau par ex)"""
        self.plateau = plateau  
        super(Pion, self).__init__()
        self.majAspectGraphique()
        self.plateau.addItem(self)
        self.polygonesForme = []
        self.majPosition(self.position)
              

    def majPosition(self, nouvellePosition, nouvelleForme = None):
        """met a jour la position de l'objet graphique et de sa forme en fonction de sa position enregistree"""
        valide = True  
        if nouvellePosition in self.champDeplacement:
            distanceParcourue = self.champDeplacement[nouvellePosition]
            if distanceParcourue <= self.deplacementRestant:
                self.deplacementRestant -= distanceParcourue
            else:
                print ("pas assez de points de deplacement")
                valide = False

        if valide:
            #on efface la forme actuelle
            if len(self.polygonesForme) > 0:
                for polygone in self.polygonesForme:
                    self.plateau.removeItem(polygone)

            #on met a jour l'occupation des cases
            if self.position != (-1,-1):
                for coord in self.forme.listeCases((self.position[0],self.position[1])):
                    #self.plateau.cases[coord].estOccupee = False
                    self.plateau.cases[coord].majOccupation(self, self.z)
            if nouvelleForme != None:
                self.forme = nouvelleForme

            #on met a jour la position du pion        
            self.position = nouvellePosition
            self.setPos(QPointF((self.position[0]*0.866+0.075+0.05) * self.plateau.hCase, (self.position[1]+0.05) * self.plateau.hCase))
        
            #on recree la forme
            for coord in self.forme.listeCases((self.position[0],self.position[1])):
                 polygone = self.plateau.cases[coord].polygone()
                 polygoneGraphique = QGraphicsPolygonItem()            
                 polygoneGraphique.setPolygon(polygone)
             
                 couleur = QColor(self.creature.couleur)
                 if coord != nouvellePosition: 
                     couleur.setAlpha(180)
                 brosse = QBrush(couleur)
                 polygoneGraphique.setBrush(brosse)
             
                 pinceau = QPen()
                 pinceau.setColor(QColor(200, 200, 200, 100))
                 pinceau.setWidth(2)
                 polygoneGraphique.setPen(pinceau)
             
                 polygoneGraphique.setZValue(9)
             
                 self.polygonesForme.append(polygoneGraphique)
                 self.plateau.addItem(polygoneGraphique)
                 #self.plateau.cases[coord].estOccupee = True
                 self.plateau.cases[coord].majOccupation(self, self.z)
                
             
    def majAspectGraphique(self):
        """met a jour l'aspect graphique du pion"""
        #creation de la forme
        self.setRect(0, 0, self.plateau.hCase*0.9, self.plateau.hCase*0.9)
        self.setZValue(10)

        #interactions graphiques
        self.setFlag(QGraphicsItem.ItemIsFocusable)
        self.setAcceptHoverEvents(True)   #accepte les evenements survol souris

        #classes graphiques
        self.brillance = QGraphicsColorizeEffect()
        self.shadow = QGraphicsDropShadowEffect()
        
        #etiquette
        text = QGraphicsSimpleTextItem("{}. {}".format(self.numero, self.nom), parent=self)
        text.setPos(QPointF(0, -35))
        police = QFont("Georgia", 21)
        text.setFont(police)
        #text.setBrush(QBrush(QColor("black")))

        #bordure
        pinceau = QPen()
        pinceau.setColor(self.creature.couleur.darker(130))
        pinceau.setWidth(10)
        self.setPen(pinceau)

        #fond 
        if len(self.creature.imgTexture) > 0:
            pix = QPixmap(QString.fromUtf8("img\\"+self.creature.imgTexture))
            dx = 0
            dy = 0
            if pix.height() >= pix.width():
                pix = pix.scaledToHeight(self.plateau.hCase*0.9, Qt.SmoothTransformation)
                dx = 0.5*((self.plateau.hCase)-pix.width())
            else:
                pix = pix.scaledToWidth(self.plateau.hCase*0.9, Qt.SmoothTransformation)
                dy = 0.5*(self.plateau.hCase-pix.height())    
            self.pixGraphique = QGraphicsPixmapItem(pix)    
            self.pixGraphique.setPos(QPointF(dx, dy))
            self.pixGraphique.setZValue(10)
            self.plateau.addItem(self.pixGraphique)
            self.pixGraphique.setParentItem(self)
            
        else:
            if self.creature.couleur.isValid():
                self.setBrush(self.creature.couleur)
            else:
                self.setBrush(QColor(255, 0, 0, 150))
        
        #ombre
        self.shadow.setColor(QColor(50, 50, 50, 200)) 
        self.shadow.setXOffset(1) 
        self.shadow.setYOffset(1) 
        self.shadow.setBlurRadius(3) 
        self.setGraphicsEffect(self.shadow)
        self.shadow.setEnabled(True)

        #brillance (desactive par defaut)
        self.brillance.setColor(QColor(0, 0, 138)) 
        self.brillance.setStrength = 0.5
        self.setGraphicsEffect(self.brillance)
        self.brillance.setEnabled(False)

        #curseur:
        #curseurPix = QPixmap('pointe.png')#.scaledToHeight(55, Qt.FastTransformation)
        #curseurPix.setMask(curseurPix.createHeuristicMask())
        #curseurPointe = QCursor(curseurPix, 0, 0)
        #self.setCursor(curseurPointe)
            
    def surbrillance(self, active):
        """active/desactive la surbrillance"""
        self.brillance.setEnabled(active)
        for polygone in self.polygonesForme:
            brillance = QGraphicsColorizeEffect()
            brillance.setColor(QColor(0, 0, 138))
            brillance.setEnabled(active)
            brillance.setStrength = 0.5
            polygone.setGraphicsEffect(brillance)
    ##################

    ###############   evenements clavier et souris    ##############         
    def hoverEnterEvent(self, event):
        """evenement lors du survol de la souris (en entree)"""
        self.plateau.caseSurvol(self.plateau.cases[self.position])
        self.plateau.pionSurvol(self) 
        event.accept()

    def hoverLeaveEvent(self, event):
        """evenement lors du survol de la souris (en entree)"""
        self.plateau.pionSurvol(None)
        event.accept()

    def mousePressEvent(self, event):
        """evenement lors du clic souris"""
        if event.button() == 1: #sur clic gauche
            if self.plateau.modeParam["pionSelectionne"] == None:
                #aucun pion n'est selectionne
                #on saisit le pion:
                self.plateau.pionSaisir(self)
                event.accept()
                
            elif self.plateau.modeParam["pionSelectionne"] == self:
                #on annule le deplacement
                #self.surbrillance(False)
                self.plateau.majMode("pionSelectionne", None)
                event.accept()
            else:
                #un pion est deja selectionne
                pass
        else:
            event.ignore()
     #######################

class PionDecor(QGraphicsRectItem):
    """pion du plateau de combat representant un decor"""
    def __init__(self, plateau, parent=None):
        super(PionDecor, self).__init__(parent)
        #plateau
        self.plateau = plateau    

        #attributs
        self.nom = "decor"
        self.decor = Decor()
        self.position = (-1, -1)
        self.forme = Forme()
        self.polygonesForme = []     #liste des polygones crees pour representer la forme de la creature
        self.z = 0
        self.hauteur = 1   #hauteur de l'objet en cases

    def __getstate__(self):
        state = {key:value for key, value in self.__dict__.items() if not key in ["plateau", "polygonesForme", "pixGraphique"]}
        return (state)

    def __setstate__(self, state):
        self.__dict__ = state

    ########### fonctions graphiques et geometriques   ##############
    def creer(self, posX, posY, decor):
        """place le pion decor sur le plateau"""        
        self.decor = decor 
        if len(self.decor.formeDef) > 0:
            self.forme.definirForme(self.decor.formeDef)
        self.hauteur = self.decor.hauteur
        
        self.position = (posX, posY)

        #aspect graphique
        self.majAspectGraphique()

        #ajout de l'objet graphique et placement
        self.plateau.addItem(self)           

    def recreer(self, plateau):
        """recree l'objet graphique apres un chargement"""
        self.plateau = plateau
        super(PionDecor, self).__init__()
        self.polygonesForme = []
        #aspect graphique
        self.majAspectGraphique()
        #ajout de l'objet graphique et placement
        self.plateau.addItem(self)            
        
             
    def majAspectGraphique(self):
        """met a jour l'aspect graphique du pion"""
        #creation de la forme
        self.setRect(0, 0, self.plateau.hCase*0.7, self.plateau.hCase*0.7)
        self.setPos(QPointF((self.position[0]*0.866+0.075+0.15) * self.plateau.hCase, (self.position[1]+0.15) * self.plateau.hCase))
        self.setZValue(10)    #place au dessus des cases
        
        #interactions
        self.setFlag(QGraphicsItem.ItemIsFocusable)
        self.setAcceptHoverEvents(True)   #accepte les evenements survol souris

        #etiquette
        text = QGraphicsSimpleTextItem("{}".format(self.decor.nom), parent=self)
        text.setPos(QPointF(0, -35))
        police = QFont("Georgia", 21)
        text.setFont(police)
        #text.setBrush(QBrush(QColor("black")))

        #bordure
        pinceau = QPen()
        pinceau.setColor(self.decor.couleur.darker(130))
        pinceau.setWidth(10)
        self.setPen(pinceau)

        #fond 
        if len(self.decor.img) > 0:
            pix = QPixmap(QString.fromUtf8("img\\"+self.decor.img))
            dx = 0
            dy = 0
            if pix.height() >= pix.width():
                pix = pix.scaledToHeight(self.plateau.hCase*0.7, Qt.SmoothTransformation)
                dx = 0.5*((0.7*self.plateau.hCase)-pix.width())
            else:
                pix = pix.scaledToWidth(self.plateau.hCase*0.7, Qt.SmoothTransformation)
                dy = 0.5*((0.7*self.plateau.hCase)-pix.height())    
            self.pixGraphique = QGraphicsPixmapItem(pix)    
            self.pixGraphique.setPos(QPointF(dx, dy))
            self.pixGraphique.setZValue(10)
            self.plateau.addItem(self.pixGraphique)
            self.pixGraphique.setParentItem(self)
        else:
            if self.decor.couleur.isValid():
                self.setBrush(self.decor.couleur)
            else:
                self.setBrush(QColor(255, 0, 0, 150))

        #creation de la forme
        for coord in self.forme.listeCases((self.position[0],self.position[1])):
            polygone = self.plateau.cases[coord].polygone()
            polygoneGraphique = QGraphicsPolygonItem()            
            polygoneGraphique.setPolygon(polygone)
             
            couleur = QColor(self.decor.couleur)
            if coord == self.position:
                couleur.setAlpha(180)
            brosse = QBrush(couleur)
            polygoneGraphique.setBrush(brosse)
             
            pinceau = QPen()
            pinceau.setColor(QColor(200, 200, 200, 100))
            pinceau.setWidth(2)
            polygoneGraphique.setPen(pinceau)
             
            polygoneGraphique.setZValue(9)
             
            self.polygonesForme.append(polygoneGraphique)
            self.plateau.addItem(polygoneGraphique)
            #self.plateau.cases[coord].estOccupee = True
            self.plateau.cases[coord].majOccupation(self, self.z)
            

    ##################

    ###############   evenements clavier et souris    ##############         

    #######################
class EcranCreationPlateau(QFrame):
    """interface de creation/chargement de plateau"""
    def __init__(self, fenetrePrincipale, terrain=None, parent=None):
        """initialisation de la fenetre"""
        super (EcranCreationPlateau, self).__init__()
        self.fenetre = fenetrePrincipale
        self.couleur = QColor(0, 255, 0, 80)
        
        self.createWidgets()
        self.majAffichage()
        
        
    def createWidgets(self):
        """construction de l'interface"""
        #construction de l'interface
        self.ui = Ui_creationPlateau()
        self.ui.setupUi(self)
        
        self.ui.couleurCasesPlateau.setStyleSheet("QLabel {backGround:%s}" %(self.couleur))
        
        self.connect(self.ui.creerPlateau, SIGNAL("clicked()"), self.creerPlateau)
        self.connect(self.ui.nomPlateau, SIGNAL("textEdited(QString)"), self.majAffichage)
        self.connect(self.ui.selectionCouleur, SIGNAL("clicked()"), self.selectionCouleur) 

    def creerPlateau(self):
        nom = self.ui.nomPlateau.text()
        largeur = self.ui.largeurPlateau.value()
        hauteur = self.ui.hauteurPlateau.value()
        ok = True
        if (largeur * hauteur) > 10000:
            reponse = QMessageBox.question(self, 'Message',
                                           "Attention ! \nLe nombre élevé de cases peut entrainer des ralentissements " \
                                           "importants...\nVoulez vous continuer?", QMessageBox.Yes | 
                                           QMessageBox.No, QMessageBox.No)
            if reponse == QMessageBox.No:
                ok = False
        if ok == True:        
            self.fenetre.plateau.creer(nom, largeur, hauteur, self.couleur)
            self.close()
        
    def chargerPlateau(self):
        pass

    def majAffichage(self):
        self.ui.creerPlateau.setEnabled(len(self.ui.nomPlateau.text()) > 0)
        
    def selectionCouleur(self):
        """selectionne la couleur dans la boite de dialogue dediee"""
        couleur = QColorDialog(self).getColor(QColor("white"), self)
        if couleur.isValid():
            nomCouleur = couleur.name()
            self.ui.couleurCasesPlateau.setStyleSheet("QLabel {backGround:%s}" %(nomCouleur))
            self.couleur = couleur    

        
class Terrain():
    """terrain a affecter a une case"""
    def __init__(self, parent=None):
        self.id = "00"
        self.nom = ""                #libelle a afficher dans la liste 
        self.couleur = QColor("")    #couleur si pas de texture
        self.imgTexture = ""         #image source de la texture
        self.franchissable = True    #peut on franchir cette case
        self.visibilite = True       #peut on voir au travers 
        self.modDeplacement = 1.00   #modificateur a appliquer au deplacement

class EcranEditionTerrain(QFrame):
    """interface de creation/edition de terrains"""
    def __init__(self, terrain=None, parent=None):
        """initialisation de la fenetre"""
        super (EcranEditionTerrain, self).__init__()
        self.createWidgets()
        self.terrain = terrain
        if terrain == None:
            self.accesCreation()
        else:
            self.accesEdition()
        self.majAffichage("")    
        
    def createWidgets(self):
        """construction de l'interface"""
        #construction de l'interface
        self.ui = Ui_editionTerrain()
        self.ui.setupUi(self)
        self.connect(self.ui.enregistrerTerrain, SIGNAL("clicked()"), self.enregistrer)
        self.connect(self.ui.annulerTerrain, SIGNAL("clicked()"), self.annuler)
        self.connect(self.ui.supprimerTerrain, SIGNAL("clicked()"), self.supprimer)
        self.connect(self.ui.idTerrain, SIGNAL("textEdited(QString)"), self.majAffichage)
        self.connect(self.ui.nomTerrain, SIGNAL("textEdited(QString)"), self.majAffichage)
        self.connect(self.ui.couleurTerrain, SIGNAL("clicked()"), self.selectionCouleur)
        
    def accesEdition(self):
        """ouverture en mode edition"""
        self.ui.idTerrain.setEnabled(True)
       
        self.ui.idTerrain.setText(self.terrain.id)
        self.ui.nomTerrain.setText(self.terrain.nom)        
        if self.terrain.couleur.isValid():
            self.ui.affichageCouleurTerrain.setStyleSheet("QLabel {backGround:%s}" %(self.terrain.couleur.name()))
        self.ui.imgTextureTerrain.setText(self.terrain.imgTexture)      
        self.ui.modDeplacementTerrain.setValue(self.terrain.modDeplacement)
        if self.terrain.visibilite:
            self.ui.visibiliteTerrain.setCheckState(2)
        else:
            self.ui.visibiliteTerrain.setCheckState(0)
        if self.terrain.franchissable:    
            self.ui.franchissableTerrain.setCheckState(2)
        else:
            self.ui.franchissableTerrain.setCheckState(0)
        self.ui.supprimerTerrain.setEnabled(True)
        self.ui.idTerrain.setEnabled(False)

    def accesCreation(self):
        """ouverture en mode creation"""
        self.terrain = Terrain()
        self.ui.idTerrain.setEnabled(True)
        self.ui.idTerrain.setText(self.nouvelIdTerrain())
        self.ui.idTerrain.setEnabled(False)

    def majAffichage(self, txt):
        """verifie la validite des saisies"""
        self.ui.enregistrerTerrain.setEnabled(len(self.ui.idTerrain.text()) > 0 and len(self.ui.nomTerrain.text()) > 0)

    def nouvelIdTerrain(self):
        """renvoie un identifiant pour un nouveau terrain"""
        dicoSvg = afficheSvg("terrain")
        nouvelId = 1
        while str(nouvelId) in dicoSvg.keys():
            nouvelId += 1
        return str(nouvelId)

    def selectionCouleur(self):
        """selectionne la couleur dans la boite de dialogue dediee"""
        couleur = QColorDialog(self).getColor(QColor("white"), self)
        if couleur.isValid():
            nomCouleur = couleur.name()
            self.ui.affichageCouleurTerrain.setStyleSheet("QLabel {backGround:%s}" %(nomCouleur))
            self.terrain.couleur = couleur    
            
    def enregistrer(self):
        """enregistre le terrain cree/edite"""
        self.terrain.id = str(self.ui.idTerrain.text())
        self.terrain.nom = str(self.ui.nomTerrain.text())
        self.terrain.imgTexture = str(self.ui.imgTextureTerrain.text())
        self.terrain.modDeplacement = float(self.ui.modDeplacementTerrain.value())
        self.terrain.visibilite = bool(self.ui.visibiliteTerrain.checkState())
        self.terrain.franchissable = bool(self.ui.franchissableTerrain.checkState())
        enregistrer(self.terrain.id, self.terrain, "terrain")
        self.terrain = None
        self.close()
        self.emit(SIGNAL("majListTerrains()"))

    def supprimer(self):
        """supprimer l'enregistrement de ce terrain"""
        supprSvg("terrain", self.terrain.id)
        self.close()
        self.emit(SIGNAL("majListTerrains()"))

    def annuler(self):
        """annule la creation/edition"""
        self.terrain = None
        self.close()

class Creature():
    """creature a affecter a un pion"""
    def __init__(self, parent=None):
        self.id = "00"
        self.nom = ""                #libelle a afficher dans la liste 
        self.couleur = QColor("")    #couleur si pas de texture
        self.imgTexture = ""         #image source de la texture
        self.porteeDistance = 0      #portee de l'attaque a distance (0 si aucune)
        self.deplacement = 9         #capacite de deplacement (par tour)
        self.vol = False             #peut voler
        self.formeDef = []           #definition de la forme de la creature (cf. classe Forme())
        self.hauteur = 1             #?nombre de cases occupees verticalement par la creature

class EcranEditionCreature(QFrame):
    """interface de creation/edition de terrains"""
    def __init__(self, creature=None, parent=None):
        """initialisation de la fenetre"""
        super (EcranEditionCreature, self).__init__()
        self.createWidgets()
        self.creature = creature
        if creature == None:
            self.accesCreation()
        else:
            self.accesEdition()
        self.majAffichage("")    
        
    def createWidgets(self):
        """construction de l'interface"""
        #construction de l'interface
        self.ui = Ui_editionCreature()
        self.ui.setupUi(self)
        self.connect(self.ui.enregistrerCreature, SIGNAL("clicked()"), self.enregistrer)
        self.connect(self.ui.annulerCreature, SIGNAL("clicked()"), self.annuler)
        self.connect(self.ui.supprimerCreature, SIGNAL("clicked()"), self.supprimer)
        self.connect(self.ui.idCreature, SIGNAL("textEdited(QString)"), self.majAffichage)
        self.connect(self.ui.nomCreature, SIGNAL("textEdited(QString)"), self.majAffichage)
        self.connect(self.ui.couleurCreature, SIGNAL("clicked()"), self.selectionCouleur)

        self.vueForme = VueEditionForme(self)
        self.vueForme.creer()
        
    def accesEdition(self):
        """ouverture en mode edition"""
        self.ui.idCreature.setEnabled(True)
       
        self.ui.idCreature.setText(self.creature.id)
        self.ui.nomCreature.setText(self.creature.nom)        
        if self.creature.couleur.isValid():
            self.ui.affichageCouleurCreature.setStyleSheet("QLabel {backGround:%s}" %(self.creature.couleur.name()))
        self.ui.imgTextureCreature.setText(self.creature.imgTexture)      
        self.ui.deplacementCreature.setValue(self.creature.deplacement)
        self.ui.allongeCreature.setValue(self.creature.allonge)
        self.ui.porteeDistanceCreature.setValue(self.creature.porteeDistance)
        self.ui.hauteurCreature.setValue(self.creature.hauteur)
        if self.creature.vol:
            self.ui.volCreature.setCheckState(2)
        else:
            self.ui.volCreature.setCheckState(0)
            
        self.vueForme.majForme(self.creature.formeDef)    
        self.ui.supprimerCreature.setEnabled(True)
        self.ui.idCreature.setEnabled(False)

    def accesCreation(self):
        """ouverture en mode creation"""
        self.creature = Creature()
        self.ui.idCreature.setEnabled(True)
        self.ui.idCreature.setText(self.nouvelIdCreature())
        self.ui.idCreature.setEnabled(False)

    def majAffichage(self, txt):
        """verifie la validite des saisies"""
        self.ui.enregistrerCreature.setEnabled(len(self.ui.idCreature.text()) > 0 and len(self.ui.nomCreature.text()) > 0)

    def nouvelIdCreature(self):
        """renvoie un identifiant pour un nouveau terrain"""
        dicoSvg = afficheSvg("creature")
        nouvelId = 1
        while str(nouvelId) in dicoSvg.keys():
            nouvelId += 1
        return str(nouvelId)

    def selectionCouleur(self):
        """selectionne la couleur dans la boite de dialogue dediee"""
        couleur = QColorDialog(self).getColor(QColor("white"), self)
        if couleur.isValid():
            nomCouleur = couleur.name()
            self.ui.affichageCouleurCreature.setStyleSheet("QLabel {backGround:%s}" %(nomCouleur))
            self.creature.couleur = couleur    
            
    def enregistrer(self):
        """enregistre le terrain cree/edite"""
        self.creature.id = str(self.ui.idCreature.text())
        self.creature.nom = str(self.ui.nomCreature.text())
        self.creature.imgTexture = str(self.ui.imgTextureCreature.text())
        self.creature.deplacement = int(self.ui.deplacementCreature.value())
        self.creature.allonge = int(self.ui.allongeCreature.value())
        self.creature.porteeDistance = int(self.ui.porteeDistanceCreature.value())
        self.creature.hauteur = int(self.ui.hauteurCreature.value())
        self.creature.vol = bool(self.ui.volCreature.checkState())
        self.creature.formeDef = self.vueForme.formeDef()
        
        enregistrer(self.creature.id, self.creature, "creature")
        self.creature = None
        self.close()
        self.emit(SIGNAL("majListCreatures()"))

    def supprimer(self):
        """supprimer l'enregistrement de ce terrain"""
        supprSvg("creature", self.creature.id)
        self.close()
        self.emit(SIGNAL("majListCreatures()"))

    def annuler(self):
        """annule la creation/edition"""
        self.creature = None
        self.close()

class Decor():
    """decor a placer sur le plateau"""
    def __init__(self, parent=None):
        self.id = "00"
        self.nom = ""                   #libelle a afficher dans la liste 
        self.couleur = QColor("")       #couleur si pas de texture
        self.img = ""                   #image source a afficher
        self.escalade = False           #peut etre escalade
        self.franchissablePied = False  #peut etre franchi a pied
        self.franchissableVol = False   #peut etre franchi en volant
        self.brule = False              #peut prendre feu
        self.hauteur = 0                #hauteur (en cases)
        self.formeDef = []              #definition de la forme du decor (cf. classe Forme())


class EcranEditionDecors(QFrame):
    """interface de creation/edition de decors"""
    def __init__(self, decor=None, parent=None):
        """initialisation de la fenetre"""
        super (EcranEditionDecors, self).__init__()
        self.createWidgets()
        self.decor = decor
        if decor == None:
            self.accesCreation()
        else:
            self.accesEdition()
        self.majAffichage("")    
        
    def createWidgets(self):
        """construction de l'interface"""
        #construction de l'interface
        self.ui = Ui_editionDecor()
        self.ui.setupUi(self)
        self.connect(self.ui.enregistrerDecor, SIGNAL("clicked()"), self.enregistrer)
        self.connect(self.ui.annulerDecor, SIGNAL("clicked()"), self.annuler)
        self.connect(self.ui.supprimerDecor, SIGNAL("clicked()"), self.supprimer)
        self.connect(self.ui.idDecor, SIGNAL("textEdited(QString)"), self.majAffichage)
        self.connect(self.ui.nomDecor, SIGNAL("textEdited(QString)"), self.majAffichage)
        self.connect(self.ui.couleurDecor, SIGNAL("clicked()"), self.selectionCouleur)

        self.vueForme = VueEditionForme(self)
        self.vueForme.creer()
        
    def accesEdition(self):
        """ouverture en mode edition"""
        self.ui.idDecor.setEnabled(True)
       
        self.ui.idDecor.setText(self.decor.id)
        self.ui.nomDecor.setText(self.decor.nom)        
        if self.decor.couleur.isValid():
            self.ui.affichageCouleurDecor.setStyleSheet("QLabel {backGround:%s}" %(self.decor.couleur.name()))
        self.ui.imgDecor.setText(self.decor.img)      
        self.ui.hauteurDecor.setValue(self.decor.hauteur)    
        if self.decor.couvert:
            self.ui.couvertDecor.setCheckState(2)
        else:
            self.ui.couvertDecor.setCheckState(0)
        if self.decor.escalade:
            self.ui.escaladeDecor.setCheckState(2)
        else:
            self.ui.escaladeDecor.setCheckState(0)
        if self.decor.franchissablePied:
            self.ui.franchissablePiedDecor.setCheckState(2)
        else:
            self.ui.franchissablePiedDecor.setCheckState(0)
        if self.decor.franchissableVol:
            self.ui.franchissableVolDecor.setCheckState(2)
        else:
            self.ui.franchissableVolDecor.setCheckState(0)
        if self.decor.brule:
            self.ui.bruleDecor.setCheckState(2)
        else:
            self.ui.bruleDecor.setCheckState(0)
            
        self.vueForme.majForme(self.decor.formeDef)    
        self.ui.supprimerDecor.setEnabled(True)
        self.ui.idDecor.setEnabled(False)

    def accesCreation(self):
        """ouverture en mode creation"""
        self.decor = Decor()
        self.ui.idDecor.setEnabled(True)
        self.ui.idDecor.setText(self.nouvelIdCreature())
        self.ui.idDecor.setEnabled(False)

    def majAffichage(self, txt):
        """verifie la validite des saisies"""
        self.ui.enregistrerDecor.setEnabled(len(self.ui.idDecor.text()) > 0 and len(self.ui.nomDecor.text()) > 0)

    def nouvelIdCreature(self):
        """renvoie un identifiant pour un nouveau decor"""
        dicoSvg = afficheSvg("decor")
        nouvelId = 1
        while str(nouvelId) in dicoSvg.keys():
            nouvelId += 1
        return str(nouvelId)

    def selectionCouleur(self):
        """selectionne la couleur dans la boite de dialogue dediee"""
        couleur = QColorDialog(self).getColor(QColor("white"), self)
        if couleur.isValid():
            nomCouleur = couleur.name()
            self.ui.affichageCouleurDecor.setStyleSheet("QLabel {backGround:%s}" %(nomCouleur))
            self.decor.couleur = couleur    
            
    def enregistrer(self):
        """enregistre le terrain cree/edite"""
        self.decor.id = str(self.ui.idDecor.text())
        self.decor.nom = str(self.ui.nomDecor.text())
        self.decor.img = str(self.ui.imgDecor.text())
        self.decor.hauteur = int(self.ui.hauteurDecor.value())        
        self.decor.couvert = bool(self.ui.couvertDecor.checkState())
        self.decor.brule = bool(self.ui.bruleDecor.checkState())
        self.decor.franchissablePied = bool(self.ui.franchissablePiedDecor.checkState())
        self.decor.franchissableVol = bool(self.ui.franchissableVolDecor.checkState())
        self.decor.escalade = bool(self.ui.escaladeDecor.checkState())
        
        self.decor.formeDef = self.vueForme.formeDef()
        
        enregistrer(self.decor.id, self.decor, "decor")
        self.decor = None
        self.close()
        self.emit(SIGNAL("majListDecors()"))

    def supprimer(self):
        """supprimer l'enregistrement de ce terrain"""
        supprSvg("decor", self.decor.id)
        self.close()
        self.emit(SIGNAL("majListCreatures()"))

    def annuler(self):
        """annule la creation/edition"""
        self.decor = None
        self.close()

class VueEditionForme(QGraphicsScene):
    """vue graphique permettant d'afficher et de modifier la forme des creatures/decors"""
    def __init__(self, fenetre, parent=None):   
        super(VueEditionForme, self).__init__()
        self.fenetre = fenetre
        self.cases = {}

    def creer(self):
        self.setSceneRect(-0.866*30*4, -30*5, 0.866*30*10, 30*11)
 
        #cree les cases hexagonales
        for x in range(-5,6):
            for y in range(-5,5):
                if 1 == (x % 2):
                     y += 0.5
                c = CaseEditionForme(self)
                c.creer(x, y)
                self.cases[(x,y)] = c
        
        self.fenetre.ui.vueForme.setScene(self)    
        self.fenetre.ui.vueForme.centerOn(QPointF(0,0))   #centre la vue sur la case 0,0

    def formeDef(self):
        """liste definissant la forme"""
        retour = []
        for coord in self.cases:
            if self.cases[coord].estSelectionnee and coord != (0,0):
                retour.append(coord)      
        return retour        

    def majForme(self, formeDef):
        """met a jour la forme sur le graphique"""
        if formeDef:
            for coord in formeDef:
                if coord in self.cases:
                    self.cases[coord].estSelectionnee = True
                    self.cases[coord].setBrush(QColor("red"))
                

class CaseEditionForme(QGraphicsPolygonItem):
    """case utilisee dans une VueEditionForme()"""
    def __init__(self, vueForme, parent=None):
        super(CaseEditionForme, self).__init__()
        self.vue = vueForme
        self.position = (0,0)
        self.estSelectionnee = False
        self.voisins = []
        
        #interactions graphiques
        self.setFlag(QGraphicsItem.ItemIsFocusable)
        self.setAcceptHoverEvents(True)
        #self.setAcceptDrops(True)

    def creer(self, x, y):
        """creation du polygone et enregistrement des donnees geometriques"""
        self.position = (x, y)
    
        polygon = QPolygonF()
        polygon  << QPointF( (x*0.866)*30,         (y+0.5)*30) \
                 << QPointF(((x*0.866)+0.2886)*30,  y*30) \
                 << QPointF(((x*0.866)+0.866)*30,   y*30) \
                 << QPointF(((x*0.866)+1.1547)*30, (y+0.5)*30) \
                 << QPointF(((x*0.866)+0.866)*30,  (y+1)*30) \
                 << QPointF(((x*0.866)+0.2886)*30, (y+1)*30)
        self.setPolygon(polygon)

        #enregistrement des cases voisines:       
        self.voisins.append((x, y+1))
        self.voisins.append((x, y-1))
        self.voisins.append((x-1, y+0.5))
        self.voisins.append((x-1, y-0.5))
        self.voisins.append((x+1, y+0.5))
        self.voisins.append((x+1, y-0.5))

        #pour afficher les coordonnees des cases:        
        #text = QGraphicsSimpleTextItem("{}-{}".format(x,y), parent=self)
        #text.setPos(QPointF(((x*0.866)+0.2886)*30,  y*30))

        #couleur de fond par defaut
        if self.position == (0, 0):
            self.setBrush(QColor("purple"))
            self.estSelectionnee = True
        else:    
            self.setBrush(QColor("white"))
        #creation de l'objet graphique sur le plateau
        self.vue.addItem(self)

    def mousePressEvent(self, event):
        """evenement lors du clic souris"""
        super(CaseEditionForme, self).mousePressEvent(event)
        if event.button() == 1: #sur clic gauche
            if not self.estSelectionnee:
                #on verifie qu'au moins une des cases voisines est selectionnee
                valide = False
                for coord in self.voisins:
                    if coord in self.vue.cases:
                        if self.vue.cases[coord].estSelectionnee:
                            valide = True
                if valide:
                    self.setBrush(QColor("red"))
                    self.estSelectionnee = True
            else:
                self.setBrush(QColor("white"))
                self.estSelectionnee = False
        else:
            print(self.position)
                

class Forme():
    """forme a affecter a une creature, decor ou autre..."""
    def __init__(self, parent=None):
        
        self.formeDef = []           #coord relatives par rapport a la case (0,0) definissant la forme (vide si forme 1*1)
        
        #les anneaux sont utilises pour les rotations (coordonnees relatives a la case centrale)
        #attention: il est important que les cases soient enregistrees dans le sens de la rotation (sens des aiguilles d'une montre)
        self.anneau = {}
        self.anneau[1] = [(0,-1),(1,-0.5),(1,0.5), \
                          (0,1),(-1,0.5),(-1,-0.5)]
        self.anneau[2] = [(0,-2),(1,-1.5),(2,-1),(2,0),(2,1),(1,1.5), \
                          (0,2),(-1,1.5),(-2,1),(-2,0),(-2,-1),(-1,-1.5)]
        self.anneau[3] = [(0,-3),(1,-2.5),(2,-2),(3,-1.5),(3,-0.5),(3,0.5),(3,1.5),(2,2),(1,2.5), \
                        (0,3),(-1,2.5),(-2,2),(-3,1.5),(-3,0.5),(-3,-0.5),(-3,-1.5),(-2,-2),(-1,-2.5)]
        self.anneau[4] = [(0,-4),(1,-3.5),(2,-3),(3,-2.5),(4,-2),(4,-1),(4,0),(4,1),(4,2),(3,2.5),(2,3),(1,3.5), \
                        (0,4),(-1,3.5),(-2,3),(-3,2.5),(-4,2),(-4,1),(-4,0),(-4,-1),(-4,-2),(-3,-2.5),(-2,-3),(-1,-3.5)]
        self.anneau[5] = [(0,-5),(1,-4.5),(2,-4),(3,-3.5),(4,-3),(5,-2.5),(5,-1.5),(5,-0.5),(5,0.5),(5,1.5),(5,2.5),(4,3),(3,3.5),(2,4),(1,4.5), \
                        (0,5),(-1,4.5),(-2,4),(-3,3.5),(-4,3),(-5,2.5),(-5,1.5),(-5,0.5),(-5,-0.5),(-5,-1.5),(-5,-2.5),(-4,-3),(-3,-3.5),(-2,-4),(-1,-4.5)]

    def __repr__(self):
        """renvoie la liste des cases occupees par la forme"""
        retour = str(self.listeCases((0,0)))
        return retour
    
    def ajouterCase(self, coordRelatives):
        """ajoute une case a la liste des cases occupees de la forme"""
        ajoutee = False
        if not coordRelatives in self.formeDef:
            for distance in self.anneau:
                if coordRelatives in self.anneau[distance]:
                     self.formeDef.append(coordRelatives)
                     ajoutee = True
        if not ajoutee:
            print("case non prise en charge (trop eloignee du centre)")
            
    def definirForme(self, formeDef):
        """utilise une forme pre-definie"""
        self.formeDef = []
        if formeDef:
            if len(formeDef)>0:
                for coordRelatives in formeDef:
                    self.ajouterCase(coordRelatives)
        
    def retirerCase(self, coordRelatives):
        """retire une case a la liste des cases occupees de la forme"""
        if coordRelatives in self.formeDef:
            self.formeDef.remove(coordRelatives)    

    def pivoter(self, sens="+"):
        """pivote si possible la forme dans le sens '+' ou '-' et renvoie la liste des cases qui seront occupees"""
        if len(self.formeDef) > 0:
            nouvelleFormeDef = []
            for coord in self.formeDef:
                #on trouve dans quel anneau se situe cette case
                distance = 0
                i = 0
                while distance == 0 and i < 6:
                    i += 1
                    if coord in self.anneau[i]:
                        distance = i
                #si on a trouve la case, on la deplace selon les conditions de la rotation        
                if distance > 0:
                    #position actuelle dans la liste des cases de l'anneau
                    position = self.anneau[distance].index(coord) 

                    #le pivot entraine un deplacement dans la liste des cases de l'anneau egal a sa distance au centre
                    if sens == "+":
                        nouvellePosition = position + distance    
                    elif sens == "-":
                        nouvellePosition = position - distance

                    #retour au debut/a la fin de l'anneau si on atteint la fin/ le debut
                    if nouvellePosition >= len(self.anneau[distance]):   
                        nouvellePosition -= len(self.anneau[distance])
                    elif nouvellePosition < 0:
                        nouvellePosition += len(self.anneau[distance])
                        
                    #on retrouve les nouvelles coordonnees relatives a partir de la position dans l'anneau  
                    nouvellesCoord = self.anneau[distance][nouvellePosition]
                    #on ajoute cette position a la nouvelle definition de forme
                    nouvelleFormeDef.append((nouvellesCoord[0], nouvellesCoord[1]))
                else:
                    print("{} non trouvee dans les anneaux".format(coord))
                
            self.formeDef = nouvelleFormeDef                   

    def listeCases(self, coordCibles):
        """renvoie la liste des cases occupees par la forme en cours"""
        retour = [coordCibles]
        if len(self.formeDef) > 0:
            for coordRelatives in self.formeDef:
                retour.append((coordCibles[0]+coordRelatives[0], coordCibles[1]+coordRelatives[1]))       
        return retour

    
if __name__ == "__main__":

   app = QApplication(argv)
   ecranPrincipal = EcranPrincipal()
   ecranPrincipal.show()
   r = app.exec_()
   exit(r)        


