#from __future__ import unicode_literals # -*- coding: utf-8 -*- from __future__ import division from PyQt4.QtCore import QPointF, Qt, QSize, QString from PyQt4.QtGui import QGraphicsScene, QColor, QGraphicsPolygonItem, \ QGraphicsItem, QPolygonF, QPen, QGraphicsPixmapItem, QApplication, \ QGraphicsSimpleTextItem, QFont from Pion import ImgPion, EtiquettePion class VueEditionForme(QGraphicsScene): """vue graphique permettant d'afficher et de modifier la forme des creatures/decors""" def __init__(self, vue, parent=None): super(VueEditionForme, self).__init__() self.vue = vue self._vefImage = VefImage(self) self._vefEtiquette = VefEtiquette(self) self._couleur = QColor(190,190,190,255) self._cases = {} self._formeCases = "H" self._autoriseModifForme = False self._l0 = 0 self._h0 = 0 self._rotation = 0 self.selection = None self.vue.setScene(self) self.vue.centerOn(self.vue.mapFromScene(QPointF(60,60))) #centre la vue sur la case 0,0 self.vue.scale(0.22, 0.22) def setCursor(self, curseur): self.vue.setCursor(curseur) #acces aux donnees def chargerFormeDef(self, formeDef): self._formeDef = formeDef self._majFormeGraphique() def formeDef(self): """renvoie la definition de forme (selon la forme des cases actuelle)""" retour = [] for coord in self._cases: if self._cases[coord].estSelectionnee() and coord != (0,0): retour.append(coord) return retour def chargerEtiquetteDef(self, etiquetteDef): self._vefEtiquette.charger(etiquetteDef) def etiquetteDef(self): return self._vefEtiquette.definition() def chargerImageDef(self, imgDef): self._vefImage.charger(imgDef) def nouvelleImageDef(self, rimage): imgDef = ImgPion() imgDef.rimage = rimage self._vefImage.charger(imgDef) def imageDef(self): return self._vefImage.definition() def majCouleur(self, couleur): """met a jour la couleur du pion""" self._couleur = couleur self._majCouleurGraphique() def couleur(self): return self._couleur def formeCases(self): return self._formeCases #creation, suppression, mises a jour... def creer(self, formeCases = "H"): self._formeCases = formeCases for x in range(-5,6): for y in range(-5,6): if not ((x%2)==1 and y == -5): c = VefCase(self) c.creer(x, y, self._couleur, self._formeCases) self._cases[(x,y)] = c def vider(self): for coord in self._cases: self.removeItem(self._cases[coord]) self._cases = {} def _majFormeGraphique(self): """met a jour la forme affichee sur le graphique""" if self._formeDef: for coord in self._formeDef: if coord in self._cases: self._cases[coord].selectionner(True) self._cases[coord].setBrush(self._couleur) def _majCouleurGraphique(self): for coord in self._cases: if self._cases[coord].estSelectionnee(): if coord == (0,0): c = self._couleur.darker(150) self._cases[coord].setBrush(c) else: self._cases[coord].setBrush(self._couleur) def majSelection(self, coord): """met a jour l'affichage des cases selectionnees pour l'affichage de la forme""" if self._autoriseModifForme: if self._cases[coord].estSelectionnee(): valide = True for coordVerif in self._cases: #on parcourt les autres cases selectionnees if coordVerif != (0,0) and coordVerif != coord and self._cases[coordVerif].estSelectionnee(): #on liste les cases connectees a cette case, de proche en proche connectees = [coordVerif] for coordVerif2 in connectees: for coordVoisin in self._cases[coordVerif2].voisins(): if coordVoisin in self._cases and not coordVoisin in connectees: if self._cases[coordVoisin].estSelectionnee(): connectees.append(coordVoisin) if not (0,0) in connectees: valide = False break if valide: self._cases[coord].selectionner(False) else: #on s'assure que la case est bien adjacente a une case selectionnee valide = False for coordVerif in self._cases[coord].voisins(): if coordVerif in self._cases: if self._cases[coordVerif].estSelectionnee(): valide = True break if valide: self._cases[coord].selectionner(True) self._majCouleurGraphique() def afficherMsg(self, msg): print msg def autoriserModifForme(self, actif): self._autoriseModifForme = actif class VefCase(QGraphicsPolygonItem): """case utilisee dans une VueEditionForme()""" def __init__(self, scene, parent=None): super(VefCase, self).__init__() self.scene = scene self._position = (0,0) self._estSelectionnee = False self._voisins = [] self._couleur = None #interactions graphiques self.setFlag(QGraphicsItem.ItemIsFocusable) self.setAcceptHoverEvents(True) def estSelectionnee(self): return self._estSelectionnee def selectionner(self, actif): if actif: self.setBrush(self._couleur) else: self.setBrush(QColor(255,255,255,50)) self._estSelectionnee = actif def voisins(self): return self._voisins def creer(self, x, y, couleur, formeCases="H"): """creation du polygone et enregistrement des donnees geometriques""" self._position = (x, y) polygone = QPolygonF() if formeCases == "H": my = 0 if (x % 2) == 1: my = -0.5 polygone << QPointF(((x*0.866)+0.2886)*120, (y+my)*120) \ << QPointF(((x*0.866)+0.866)*120, (y+my)*120) \ << QPointF(((x*0.866)+1.1547)*120, (y+my+0.5)*120) \ << QPointF(((x*0.866)+0.866)*120, (y+my+1)*120) \ << QPointF(((x*0.866)+0.2886)*120, (y+my+1)*120) \ << QPointF( (x*0.866)*120, (y+my+0.5)*120) else: polygone << QPointF(x*120, y*120) \ << QPointF((x+1)*120, y*120) \ << QPointF((x+1)*120, (y+1)*120) \ << QPointF(x*120, (y+1)*120) self.setPolygon(polygone) #enregistrement des cases voisines: if formeCases == "H": self._voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x, y+1), (x-1, y), (x-1, y-1)] else: self._voisins.append((x, y-1)) self._voisins.append((x, y+1)) self._voisins.append((x-1, y)) self._voisins.append((x+1, y)) #pour afficher les coordonnees des cases: ## text = QGraphicsSimpleTextItem("{} {}".format(x, y), parent=self) ## police = QFont() ## police.setPointSize(20) ## text.setFont(police) ## k = 0 ## if (x % 2) == 1: k = - 0.5 ## text.setPos(QPointF(((x*0.866)+0.5773)*120, (y+0.5+k)*120)) #couleur de fond par defaut if couleur.__class__.__name__ == "QColor": if couleur.isValid(): self._couleur = couleur else: self._couleur = QColor("grey") else: self._couleur = QColor("grey") if self._position == (0, 0): couleur = self._couleur.darker(150) self.setBrush(couleur) self._estSelectionnee = True else: self.selectionner(False) #creation de l'objet graphique sur le plateau pinceau = QPen() pinceau.setWidth(2) pinceau.setColor(QColor(150,150,150,150)) self.setPen(pinceau) self.scene.addItem(self) def mousePressEvent(self, event): """evenement lors du clic souris""" super(VefCase, self).mousePressEvent(event) if event.button() == 1: #sur clic gauche if self._position != (0, 0): self.scene.majSelection(self._position) class VefImage(QGraphicsPixmapItem): """etiquette utilisee dans une VueEditionForme()""" def __init__(self, scene, parent=None): super(VefImage, self).__init__() self.scene = scene self._def = ImgPion() self._pix = None self._l0 = 0 self._h0 = 0 self.setAcceptDrops(True) self.setAcceptHoverEvents(True) self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable) self.scene.addItem(self) self.setZValue(10) def charger(self, definition): self._pix = None self._l0 = 0 self._h0 = 0 self._def = definition self._maj() def definition(self): return self._def def _maj(self): if self._def.rimage.estValide(): if self._pix == None: self._pix = self._def.rimage.pix() if not self._pix.isNull(): if self._pix.height() >= self._pix.width(): self._pix = self._pix.scaledToHeight(120*0.9, Qt.SmoothTransformation) else: self._pix = self._pix.scaledToWidth(120*0.9, Qt.SmoothTransformation) self._l0 = self._pix.width() self._h0 = self._pix.height() else: self._pix = None else: self._pix = None if self._pix: taille = QSize((self._def.kx/10)*self._l0, (self._def.ky/10)*self._h0) self._pix = self._pix.scaled(taille, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) k = 1 if self.scene.formeCases() == "H": k = 1.1544 deltaX = self._def.dx + 0.5*(120*k - self._pix.width()) deltaY = self._def.dy + 0.5*(120 - self._pix.height()) self.setPixmap(self._pix) self.setPos(QPointF(deltaX, deltaY)) self.setRotation(self._def.rotation) def width(self): return self.boundingRect().width() def height(self): return self.boundingRect().height() def majPos(self, pos): k = 1 if self.scene.formeCases() == "H": k = 1.1544 self._def.dx = pos.x() - 0.5*(120*k - self._pix.width()) self._def.dy = pos.y() - 0.5*(120 - self._pix.height()) def mousePressEvent(self, event): self.prepareGeometryChange() self.scene.afficherMsg("Utilisez les touches Z, Q, S, D pour modifier la taille de l'image\n" \ "Utilisez les touches W et X pour faire pivoter l'image") def mouseReleaseEvent(self, event): self.scene.afficherMsg("") super(VefImage, self).mouseReleaseEvent(event) QApplication.processEvents() self.majPos(self.scenePos()) def keyPressEvent(self, event): if event.key() in [Qt.Key_Z, Qt.Key_Q, Qt.Key_S, Qt.Key_D, Qt.Key_W, Qt.Key_X]: if event.key() == Qt.Key_Z: self._def.ky += 2 elif event.key() == Qt.Key_Q: self._def.kx -= 2 elif event.key() == Qt.Key_S: self._def.ky -= 2 elif event.key() == Qt.Key_D: self._def.kx += 2 elif event.key() == Qt.Key_W: self._def.rotation -= 5 elif event.key() == Qt.Key_X: self._def.rotation += 5 self.majPos(self.scenePos()) self._maj() class VefEtiquette(QGraphicsSimpleTextItem): """etiquette utilisee dans une VueEditionForme()""" def __init__(self, scene, parent=None): super(VefEtiquette, self).__init__() self.scene = scene self._def = EtiquettePion() self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable) self.setAcceptDrops(True) self.setAcceptHoverEvents(True) self.scene.addItem(self) self.setZValue(10) def charger(self, definition): self._def = definition self._maj() def definition(self): return self._def def _maj(self): if len(self._def.txt) > 0: self.setText(QString.fromUtf8(self._def.txt)) self.setPos(QPointF(self._def.dx - 0.112*120, self._def.dy - 0.5*120)) police = QFont("Verdana", self._def.taille_police) police.setBold(self._def.gras) self.setFont(police) def majPos(self, pos): self._def.dx = pos.x() - 0.112*120 self._def.dy = pos.y() - 0.5*120 def mousePressEvent(self, event): self.prepareGeometryChange() self.scene.afficherMsg("Utilisez les touches HAUT et BAS pour modifier la taille de la police\n" \ "Utilisez la touche G pour activer/desactiver l'écriture en gras") def mouseReleaseEvent(self, event): self.scene.afficherMsg("") super(VefEtiquette, self).mouseReleaseEvent(event) QApplication.processEvents() self.majPos(self.scenePos()) def keyPressEvent(self, event): if event.key() == Qt.Key_Up: self._def.taille_police += 4 self.majPos(self.scenePos()) self._maj() elif event.key() == Qt.Key_Down: self._def.taille_police -= 4 self.majPos(self.scenePos()) self._maj() elif event.key() == Qt.Key_G: if not self._def.gras: self._def.gras = True else: self._def.gras = False self.majPos(self.scenePos()) self._maj()