VueEditionForme.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #from __future__ import unicode_literals
  2. # -*- coding: utf-8 -*-
  3. from __future__ import division
  4. import os
  5. from PyQt4.QtCore import *
  6. from PyQt4.QtGui import *
  7. from Pion import ImgPion, EtiquettePion
  8. class VueEditionForme(QGraphicsScene):
  9. """vue graphique permettant d'afficher et de modifier la forme des creatures/decors"""
  10. def __init__(self, fenetre, parent=None):
  11. super(VueEditionForme, self).__init__()
  12. self.fenetre = fenetre
  13. self._vefImage = VefImage(self)
  14. self._vefEtiquette = VefEtiquette(self)
  15. self._couleur = QColor("grey")
  16. self._cases = {}
  17. self._formeCases = "H"
  18. self._l0 = 0
  19. self._h0 = 0
  20. self._rotation = 0
  21. self.fenetre.ui.edc_vueForme.setScene(self)
  22. self.fenetre.ui.edc_vueForme.centerOn(self.fenetre.ui.edc_vueForme.mapFromScene(QPointF(60,60))) #centre la vue sur la case 0,0
  23. self.fenetre.ui.edc_vueForme.scale(0.25, 0.25)
  24. #acces aux donnees
  25. def chargerFormeDef(self, formeDef):
  26. self._formeDef = formeDef
  27. self._majFormeGraphique()
  28. def formeDef(self):
  29. """renvoie la definition de forme (selon la forme des cases actuelle)"""
  30. retour = []
  31. for coord in self._cases:
  32. if self._cases[coord].estSelectionnee() and coord != (0,0):
  33. retour.append(coord)
  34. return retour
  35. def chargerEtiquetteDef(self, etiquetteDef):
  36. self._vefEtiquette.charger(etiquetteDef)
  37. def etiquetteDef(self):
  38. return self._vefEtiquette.definition()
  39. def chargerImageDef(self, imgDef):
  40. self._vefImage.charger(imgDef)
  41. def nouvelleImageDef(self, cheminFichier):
  42. imgDef = ImgPion()
  43. imgDef.nomFichier = cheminFichier
  44. self._vefImage.charger(imgDef)
  45. def imageDef(self):
  46. return self._vefImage.definition()
  47. def majCouleur(self, couleur):
  48. """met a jour la couleur du pion"""
  49. self._couleur = couleur
  50. self._majCouleurGraphique()
  51. def couleur(self):
  52. return self._couleur
  53. def formeCases(self):
  54. return self._formeCases
  55. #creation, suppression, mises a jour...
  56. def creer(self, formeCases = "H"):
  57. self._formeCases = formeCases
  58. for x in range(-5,6):
  59. for y in range(-5,5):
  60. if self._formeCases == "H":
  61. if 1 == (x % 2):
  62. y += 0.5
  63. c = VefCase(self)
  64. c.creer(x, y, self._couleur, self._formeCases)
  65. self._cases[(x,y)] = c
  66. def vider(self):
  67. for coord in self._cases:
  68. self.removeItem(self._cases[coord])
  69. self._cases = {}
  70. def _majFormeGraphique(self):
  71. """met a jour la forme affichee sur le graphique"""
  72. if self._formeDef:
  73. for coord in self._formeDef:
  74. if coord in self._cases:
  75. self._cases[coord].selectionner(True)
  76. self._cases[coord].setBrush(self._couleur)
  77. def majSelection(self, coord):
  78. """met a jour l'affichage des cases selectionnees pour l'affichage de la forme"""
  79. if self._cases[coord].estSelectionnee():
  80. #on deselectionne la case
  81. ## self._cases[coord].selectionner(False)
  82. valide = True
  83. for coordVerif in self._cases:
  84. #on parcourt les autres cases selectionnees
  85. if coordVerif != (0,0) and coordVerif != coord and self._cases[coordVerif].estSelectionnee():
  86. #on liste les cases connectees a cette case, de proche en proche
  87. connectees = [coordVerif]
  88. for coordVerif2 in connectees:
  89. for coordVoisin in self._cases[coordVerif2].voisins():
  90. if coordVoisin in self._cases and not coordVoisin in connectees:
  91. if self._cases[coordVoisin].estSelectionnee():
  92. connectees.append(coordVoisin)
  93. if not (0,0) in connectees:
  94. valide = False
  95. break
  96. if valide:
  97. self._cases[coord].selectionner(False)
  98. else:
  99. #on s'assure que la case est bien adjacente a une case selectionnee
  100. valide = False
  101. for coordVerif in self._cases[coord].voisins():
  102. if coordVerif in self._cases:
  103. if self._cases[coordVerif].estSelectionnee():
  104. valide = True
  105. break
  106. if valide:
  107. self._cases[coord].selectionner(True)
  108. def afficherMsg(self, msg):
  109. print msg
  110. class VefCase(QGraphicsPolygonItem):
  111. """case utilisee dans une VueEditionForme()"""
  112. def __init__(self, scene, parent=None):
  113. super(VefCase, self).__init__()
  114. self.scene = scene
  115. self._position = (0,0)
  116. self._estSelectionnee = False
  117. self._voisins = []
  118. self._couleur = None
  119. #interactions graphiques
  120. self.setFlag(QGraphicsItem.ItemIsFocusable)
  121. self.setAcceptHoverEvents(True)
  122. def estSelectionnee(self):
  123. return self._estSelectionnee
  124. def selectionner(self, actif):
  125. if actif:
  126. self.setBrush(self._couleur)
  127. else:
  128. self.setBrush(QColor(255,255,255,50))
  129. self._estSelectionnee = actif
  130. def voisins(self):
  131. return self._voisins
  132. def creer(self, x, y, couleur, formeCases="H"):
  133. """creation du polygone et enregistrement des donnees geometriques"""
  134. self._position = (x, y)
  135. polygone = QPolygonF()
  136. if formeCases == "H":
  137. polygone << QPointF(((x*0.866)+0.2886)*120, y*120) \
  138. << QPointF(((x*0.866)+0.866)*120, y*120) \
  139. << QPointF(((x*0.866)+1.1547)*120, (y+0.5)*120) \
  140. << QPointF(((x*0.866)+0.866)*120, (y+1)*120) \
  141. << QPointF(((x*0.866)+0.2886)*120, (y+1)*120) \
  142. << QPointF( (x*0.866)*120, (y+0.5)*120)
  143. else:
  144. polygone << QPointF(x*120, y*120) \
  145. << QPointF((x+1)*120, y*120) \
  146. << QPointF((x+1)*120, (y+1)*120) \
  147. << QPointF(x*120, (y+1)*120)
  148. self.setPolygon(polygone)
  149. #enregistrement des cases voisines:
  150. if formeCases == "H":
  151. self._voisins.append((x, y+1))
  152. self._voisins.append((x, y-1))
  153. self._voisins.append((x-1, y+0.5))
  154. self._voisins.append((x-1, y-0.5))
  155. self._voisins.append((x+1, y+0.5))
  156. self._voisins.append((x+1, y-0.5))
  157. else:
  158. self._voisins.append((x, y-1))
  159. self._voisins.append((x, y+1))
  160. self._voisins.append((x-1, y))
  161. self._voisins.append((x+1, y))
  162. #pour afficher les coordonnees des cases:
  163. #text = QGraphicsSimpleTextItem("{}-{}".format(x,y), parent=self)
  164. #police = QFont()
  165. #police.setPointSize(20)
  166. #text.setFont(police)
  167. #text.setPos(QPointF(((x*0.866)+0.2886)*120, y*120))
  168. #couleur de fond par defaut
  169. if couleur.__class__.__name__ == "QColor":
  170. if couleur.isValid():
  171. self._couleur = couleur
  172. else:
  173. self._couleur = QColor("grey")
  174. else:
  175. self._couleur = QColor("grey")
  176. if self._position == (0, 0):
  177. couleur = self._couleur.darker(150)
  178. self.setBrush(couleur)
  179. self._estSelectionnee = True
  180. else:
  181. self.selectionner(False)
  182. #creation de l'objet graphique sur le plateau
  183. pinceau = QPen()
  184. pinceau.setWidth(2)
  185. pinceau.setColor(QColor(150,150,150,150))
  186. self.setPen(pinceau)
  187. self.scene.addItem(self)
  188. def mousePressEvent(self, event):
  189. """evenement lors du clic souris"""
  190. super(VefCase, self).mousePressEvent(event)
  191. if event.button() == 1: #sur clic gauche
  192. if self._position != (0, 0):
  193. self.scene.majSelection(self._position)
  194. class VefImage(QGraphicsPixmapItem):
  195. """etiquette utilisee dans une VueEditionForme()"""
  196. def __init__(self, scene, parent=None):
  197. super(VefImage, self).__init__()
  198. self.scene = scene
  199. self._def = ImgPion()
  200. self._pix = None
  201. self._l0 = 0
  202. self._h0 = 0
  203. self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | \
  204. QGraphicsItem.ItemSendsGeometryChanges | QGraphicsItem.ItemIsFocusable)
  205. self.scene.addItem(self)
  206. self.setZValue(10)
  207. def charger(self, definition):
  208. self._pix = None
  209. self._l0 = 0
  210. self._h0 = 0
  211. self._def = definition
  212. self._maj()
  213. def definition(self):
  214. return self._def
  215. def _maj(self):
  216. if len(self._def.nomFichier) > 0:
  217. if self._pix == None:
  218. self._pix = QPixmap(QString.fromUtf8(self._def.nomFichier))
  219. if not self._pix.isNull():
  220. if self._pix.height() >= self._pix.width():
  221. self._pix = self._pix.scaledToHeight(120*0.9, Qt.SmoothTransformation)
  222. else:
  223. self._pix = self._pix.scaledToWidth(120*0.9, Qt.SmoothTransformation)
  224. self.l0 = self._pix.width()
  225. self.h0 = self._pix.height()
  226. else:
  227. self._pix = None
  228. else:
  229. self_pix = None
  230. if self._pix:
  231. self._pix.scaled((self._def.kx/10)*self._l0, (self._def.ky/10)*self._h0, \
  232. Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
  233. k = 1
  234. if self.scene.formeCases() == "H": k = 1.1544
  235. deltaX = self._def.dx + 0.5*(120*k - self._pix.width())
  236. deltaY = self._def.dy + 0.5*(120 - self._pix.height())
  237. self.setPixmap(self._pix)
  238. self.setPos(QPointF(deltaX, deltaY))
  239. self.setRotation(self._def.rotation)
  240. def mousePressEvent(self, event):
  241. self.prepareGeometryChange()
  242. self.scene.afficherMsg("Utilisez les touches HAUT et BAS pour modifier la taille de l'image\n" \
  243. "Utilisez les touches GAUCHE et DROITE pour faire pivoter l'image\n" \
  244. "Utilisez la touche G pour activer/desactiver l'écriture en gras")
  245. def mouseReleaseEvent(self, event):
  246. self.scene.afficherMsg("")
  247. nouvellePos = self.scenePos()
  248. self._def.dx = nouvellePos.x()# - 0.5*(120*k - self._pix.width())
  249. self._def.dy = nouvellePos.y()# - 0.5*(120 - self._pix.height())
  250. def keyPressEvent(self, event):
  251. pass
  252. ## if event.key() == Qt.Key_Up:
  253. ## self._def.taille_police += 4
  254. ## self._maj()
  255. ## elif event.key() == Qt.Key_Down:
  256. ## self._def.taille_police -= 4
  257. ## self._maj()
  258. ## elif event.key() == Qt.Key_G:
  259. ## if not self._def.gras:
  260. ## self._def.gras = True
  261. ## else:
  262. ## self._def.gras = False
  263. ## self._maj()
  264. class VefEtiquette(QGraphicsSimpleTextItem):
  265. """etiquette utilisee dans une VueEditionForme()"""
  266. def __init__(self, scene, parent=None):
  267. super(VefEtiquette, self).__init__()
  268. self.scene = scene
  269. self._def = EtiquettePion()
  270. self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable)
  271. ## self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | \
  272. ## QGraphicsItem.ItemSendsGeometryChanges | QGraphicsItem.ItemIsFocusable)
  273. ## self.setFlags(QGraphicsItem.ItemIsSelectable | \
  274. ## QGraphicsItem.ItemSendsGeometryChanges | QGraphicsItem.ItemIsFocusable)
  275. self.setAcceptDrops(True)
  276. self.scene.addItem(self)
  277. self.setZValue(10)
  278. def charger(self, definition):
  279. self._def = definition
  280. self._maj()
  281. def definition(self):
  282. return self._def
  283. def _maj(self):
  284. if len(self._def.txt) > 0:
  285. self.setText(QString.fromUtf8(self._def.txt))
  286. self.setPos(QPointF(self._def.dx - 0.112*120, self._def.dy - 0.5*120))
  287. police = QFont("Verdana", self._def.taille_police)
  288. police.setBold(self._def.gras)
  289. self.setFont(police)
  290. ## def itemChange(self, changement, nouvelleValeur):
  291. ## """reimplementation de la fonction de QGraphicsItem"""
  292. ## if changement == QGraphicsItem.ItemPositionChange:
  293. ## nouvellePos = nouvelleValeur.toPointF()
  294. ## #maj de dx et dy (par rapport a la position initiale
  295. ## self._def.dx = nouvellePos.x() - 0.112*120
  296. ## self._def.dy = nouvellePos.y() - 0.5*120
  297. ## return super(VefEtiquette, self).itemChange(changement, nouvelleValeur)
  298. def mousePressEvent(self, event):
  299. self.prepareGeometryChange()
  300. self.scene.afficherMsg("Utilisez les touches HAUT et BAS pour modifier la taille de la police\n" \
  301. "Utilisez la touche G pour activer/desactiver l'écriture en gras")
  302. def mouseReleaseEvent(self, event):
  303. self.scene.afficherMsg("")
  304. nouvellePos = self.scenePos()
  305. self._def.dx = nouvellePos.x() - 0.112*120
  306. self._def.dy = nouvellePos.y() - 0.5*120
  307. def keyPressEvent(self, event):
  308. if event.key() == Qt.Key_Up:
  309. self._def.taille_police += 4
  310. self._maj()
  311. elif event.key() == Qt.Key_Down:
  312. self._def.taille_police -= 4
  313. self._maj()
  314. elif event.key() == Qt.Key_G:
  315. if not self._def.gras:
  316. self._def.gras = True
  317. else:
  318. self._def.gras = False
  319. self._maj()