No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

windows.py 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. from PySide import QtGui, QtCore
  2. import copy
  3. from gamestate import QuestionAnswers
  4. from music import MusicBox
  5. from player import Player, ButtonEvent, nobodyColor
  6. class QuestionWindow(QtGui.QDialog):
  7. def __init__(self, players, section, qnumber, question, answers=None, dj=None, parent=None):
  8. super(QuestionWindow, self).__init__(parent)
  9. self.players = players
  10. self.section = section
  11. self.qnumber = qnumber
  12. self.question = question
  13. self.dj = dj
  14. if answers is not None:
  15. self.answers = answers
  16. else:
  17. self.answers = QuestionAnswers(self.section, self.qnumber)
  18. if not self.answers.is_answered():
  19. MusicBox.play_music("questionSong")
  20. if self.dj:
  21. self.answers.set_dj_points(self.dj[1])
  22. playerNo = self.players.index(self.dj[0])+1
  23. QtCore.QCoreApplication.postEvent(self, ButtonEvent(playerNo))
  24. self._setupGui()
  25. self.setWindowTitle("Seopardy - %s - %d" % (section, qnumber*100))
  26. self._inWindow = False
  27. def get_answers(self):
  28. return self.answers
  29. def closeEvent(self, event):
  30. if not self._inWindow:
  31. MusicBox.stop_music()
  32. event.accept()
  33. else:
  34. event.ignore()
  35. def _mkQuestionLabel(self, text):
  36. question = QtGui.QLabel(text, alignment=QtCore.Qt.AlignCenter)
  37. question.setWordWrap(True)
  38. question.setStyleSheet("QLabel { font-size: 40px; }")
  39. return question
  40. def _setupGui(self):
  41. self.layout = QtGui.QVBoxLayout()
  42. seclabel = QtGui.QLabel(self.section)
  43. seclabel.setStyleSheet("QLabel { font-size: 30px; }")
  44. self.layout.addWidget(seclabel, alignment=QtCore.Qt.AlignCenter)
  45. self.layout.addStretch()
  46. qlabel = None
  47. if self.question["Type"] == "Text":
  48. qlabel = self._mkQuestionLabel(self.question["Question"])
  49. elif self.question["Type"] == "Music":
  50. qlabel = self._mkQuestionLabel("Listen...")
  51. elif self.question["Type"] == "Image":
  52. qlabel = QtGui.QLabel()
  53. pixmap = QtGui.QPixmap()
  54. pixmap.loadFromData(open(self.question["Question"]).read())
  55. qlabel.setPixmap(pixmap)
  56. else:
  57. raise ValueError("%s is an unknown type for section %s question name %s" % (self.question["Type"], self.section, self.question["Name"]))
  58. self.layout.addWidget(qlabel)
  59. self.layout.addStretch()
  60. self.setLayout(self.layout)
  61. def event(self, e):
  62. if e.type() == ButtonEvent.eventType:
  63. if e.get_playerno() <= len(self.players) and not self._inWindow:
  64. self._inWindow = True
  65. player = self.players[e.get_playerno()-1]
  66. qawin = QuestionAnswerWindow(player, self)
  67. res = qawin.exec_()
  68. if res == QuestionAnswerWindow.CORRECT:
  69. self.answers.add_try(player, correct=True)
  70. self._inWindow = False
  71. self.close()
  72. elif res == QuestionAnswerWindow.WRONG:
  73. self.answers.add_try(player, correct=False)
  74. self._inWindow = False
  75. return True
  76. else:
  77. return super(QuestionWindow, self).event(e)
  78. def keyPressEvent(self, e):
  79. if e.key() == QtCore.Qt.Key_Escape:
  80. if not self.answers.is_answered():
  81. self.answers.nobody_knew()
  82. self.close()
  83. elif not self.answers.is_answered() and e.key() >= ord('1') and e.key() <= ord(str(len(self.players))):
  84. QtCore.QCoreApplication.postEvent(self, ButtonEvent(int(chr(e.key()))))
  85. class QuestionAnswerWindow(QtGui.QDialog):
  86. CORRECT = 1
  87. WRONG = 2
  88. OOPS = 3
  89. def __init__(self, player, parent=None):
  90. super(QuestionAnswerWindow, self).__init__(parent)
  91. self.player = player
  92. self._setupGui()
  93. # move window to bottom right of screen
  94. g = QtGui.QApplication.desktop().screenGeometry()
  95. self.show()
  96. cPos = self.rect()
  97. self.move(g.width() - cPos.width(), g.height() - cPos.height())
  98. def _setupGui(self):
  99. self.layout = QtGui.QVBoxLayout()
  100. self.plabel = QtGui.QLabel(self.player.name)
  101. self.plabel.setStyleSheet("QLabel { font-size: 60px; }")
  102. self.layout.addWidget(self.plabel, alignment=QtCore.Qt.AlignCenter)
  103. btnbox = QtGui.QHBoxLayout()
  104. right = QtGui.QPushButton("Correct")
  105. right.clicked.connect(lambda: self.done(self.CORRECT))
  106. btnbox.addWidget(right)
  107. wrong = QtGui.QPushButton("Wrong")
  108. wrong.clicked.connect(lambda: self.done(self.WRONG))
  109. btnbox.addWidget(wrong)
  110. btnbox.addStretch()
  111. oops = QtGui.QPushButton("Oops")
  112. oops.clicked.connect(lambda: self.done(self.OOPS))
  113. btnbox.addWidget(oops)
  114. self.layout.addLayout(btnbox)
  115. self.setLayout(self.layout)
  116. class EditAnswersWindow(QtGui.QDialog):
  117. def __init__(self, players, answers, parent=None):
  118. super(EditAnswersWindow, self).__init__(parent)
  119. self._players = players
  120. self._answers = answers
  121. self._nobody = not answers.got_answered()
  122. self._dj_points = answers.get_dj_points()
  123. self._in_window = False
  124. if self._answers:
  125. self._tries = copy.copy(self._answers.get_tries())
  126. else:
  127. self._tries = []
  128. self._setupGui()
  129. self.installEventFilter(KeyGrabber((QtCore.Qt.Key.Key_Left, QtCore.Qt.Key.Key_Right), self))
  130. def get_new_answers(self):
  131. qa = QuestionAnswers(self._answers.section, self._answers.qnumber, dj_points=self._dj_points)
  132. rightPlayer = None
  133. for player, correct in self._tries:
  134. if correct:
  135. rightPlayer = player
  136. else:
  137. qa.add_try(player, correct)
  138. if rightPlayer:
  139. qa.add_try(rightPlayer, True)
  140. elif self._nobody:
  141. qa.nobody_knew()
  142. return qa
  143. def _setupGui(self):
  144. self.layout = QtGui.QVBoxLayout()
  145. self.qlabel = QtGui.QLabel("Questions")
  146. self.qlabel.setStyleSheet("QLabel { font-size: 30px; }")
  147. self.layout.addWidget(self.qlabel, alignment=QtCore.Qt.AlignCenter)
  148. self.answerlayout = QtGui.QVBoxLayout()
  149. self._resetAllButtons()
  150. self.layout.addLayout(self.answerlayout)
  151. self.xlabel = QtGui.QLabel("+/- right/wrong, d delete, a add, arrows change player\ne edit double jeopardy")
  152. self.xlabel.setStyleSheet("QLabel { font-size: 15px; }")
  153. self.layout.addWidget(self.xlabel)
  154. self.setLayout(self.layout)
  155. def keyPressEvent(self, e):
  156. if e.key() == QtCore.Qt.Key_Escape:
  157. self.close()
  158. elif e.key() == QtCore.Qt.Key_E:
  159. # edit double jeopardy
  160. if self._dj_points is not None and len(self._tries) > 0 and not self._in_window:
  161. self._in_window = True
  162. dwin = DoubleJeopardyWindow(self._players, self._answers.qnumber*100, self._tries[0][0], current_points=self._dj_points, parent=self)
  163. dwin.exec_()
  164. self._dj_points = dwin.get_chosen_points()
  165. self._tries[0] = (dwin.get_player(), self._tries[0][1])
  166. self._in_window = False
  167. else:
  168. currFocus = self._getCurrFocus()
  169. if currFocus is None and e.key() != QtCore.Qt.Key_A:
  170. return
  171. nothingDone = False
  172. if e.key() == QtCore.Qt.Key_Plus:
  173. self._nobody = False
  174. for i, (player, correct) in enumerate(self._tries):
  175. self._tries[i] = (player, i==currFocus)
  176. if currFocus == len(self._tries):
  177. self._nobody = True
  178. elif e.key() == QtCore.Qt.Key_Minus:
  179. if currFocus == len(self._tries):
  180. if len(self._tries) == 0:
  181. self._nobody = False
  182. else:
  183. self._tries[currFocus] = (self._tries[currFocus][0], False)
  184. elif e.key() == QtCore.Qt.Key_A:
  185. self._tries.append((self._players[0], False))
  186. self._makeNobodyConsistent()
  187. currFocus = len(self._tries) - 1
  188. elif e.key() == QtCore.Qt.Key_D and currFocus < len(self._tries):
  189. del self._tries[currFocus]
  190. elif e.key() == QtCore.Qt.Key_Left and currFocus < len(self._players):
  191. playlen = len(self._players)
  192. prevPlayer = self._players[(self._players.index(self._tries[currFocus][0])-1+playlen)%playlen]
  193. self._tries[currFocus] = (prevPlayer, self._tries[currFocus][1])
  194. elif e.key() == QtCore.Qt.Key_Right and currFocus < len(self._tries):
  195. playlen = len(self._players)
  196. nextPlayer = self._players[(self._players.index(self._tries[currFocus][0])+1+playlen)%playlen]
  197. self._tries[currFocus] = (nextPlayer, self._tries[currFocus][1])
  198. else:
  199. super(EditAnswersWindow, self).keyPressEvent(e)
  200. nothingDone = True
  201. if not nothingDone:
  202. self._resetAllButtons()
  203. self.updateGeometry()
  204. # reset focus
  205. #print("setting focus to", min(currFocus, self.answerlayout.count()), self.answerlayout.itemAt(min(currFocus, self.answerlayout.count())).widget().text(), self.answerlayout.itemAt(min(currFocus, self.answerlayout.count())).widget().hasFocus())
  206. self.answerlayout.itemAt(min(currFocus, self.answerlayout.count())).widget().setFocus(QtCore.Qt.FocusReason.NoFocusReason)
  207. #print("setting focus to", min(currFocus, self.answerlayout.count()), self.answerlayout.itemAt(min(currFocus, self.answerlayout.count())).widget().text(), self.answerlayout.itemAt(min(currFocus, self.answerlayout.count())).widget().hasFocus())
  208. #print(self.focusWidget())
  209. #if self.focusWidget():
  210. # print("widget", self.focusWidget().text())
  211. def _makeNobodyConsistent(self):
  212. if len(self._tries) > 0:
  213. someoneKnew = any([c for p, c in self._tries])
  214. self._nobody = not someoneKnew
  215. def _getCurrFocus(self):
  216. if self.focusWidget() is not None:
  217. for i in range(self.answerlayout.count()):
  218. if self.answerlayout.itemAt(i).widget() == self.focusWidget():
  219. return i
  220. return None
  221. def _resetAllButtons(self):
  222. f = self.answerlayout.takeAt(0)
  223. while f is not None:
  224. f.widget().deleteLater()
  225. f = self.answerlayout.takeAt(0)
  226. # add buttons
  227. first = True
  228. for player, correct in self._tries:
  229. self._addAnswerButton(player, correct, first)
  230. first = False
  231. # add the nobody button
  232. self._addAnswerButton(Player("nobody", nobodyColor), self._nobody)
  233. def _addAnswerButton(self, player, correct=False, first=False):
  234. prefix = "+" if correct else "-"
  235. dj = " (D)" if first and self._dj_points is not None else ""
  236. btn = QtGui.QPushButton("\n%s%s%s\n" % (prefix, player.name, dj), self)
  237. btn.setStyleSheet("QPushButton { background-color: %s; color: white; font-size: 20px; border: none; }" % (player.color.name(),))
  238. btn.installEventFilter(KeyGrabber((QtCore.Qt.Key.Key_Left, QtCore.Qt.Key.Key_Right), self))
  239. self.answerlayout.addWidget(btn)
  240. class KeyGrabber(QtCore.QObject):
  241. def __init__(self, keys, parent, *args, **kwargs):
  242. super(KeyGrabber, self).__init__(parent, *args, **kwargs)
  243. self._keys = keys
  244. self._parent = parent
  245. def eventFilter(self, obj, e):
  246. if e.type() == QtCore.QEvent.KeyPress:
  247. if e.key() in self._keys:
  248. self._parent.keyPressEvent(e)
  249. return True
  250. return QtCore.QObject.eventFilter(self, obj, e)
  251. class PlayerStartWindow(QtGui.QDialog):
  252. def __init__(self, players, parent):
  253. super(PlayerStartWindow, self).__init__(parent)
  254. self._players = players
  255. self._parent = parent
  256. self._playerLineEdits = []
  257. #print(self.disconnect(self, QtCore.SIGNAL("accepted()"), self, QtCore.SLOT("accept()")))
  258. self._setupGui()
  259. self.show()
  260. # center window
  261. g = QtGui.QApplication.desktop().screenGeometry()
  262. cPos = self.rect()
  263. self.move(g.width()/2 - cPos.width()/2, g.height()/2 - cPos.height()/2)
  264. def event(self, e):
  265. if e.type() == ButtonEvent.eventType:
  266. if e.get_playerno() <= len(self.players)+1:
  267. if e.get_playerno() == len(self.players)+1:
  268. # add a new player
  269. self._parent.add_player()
  270. self._guiAddPlayer(self._players[-1])
  271. self.playergrid.itemAtPosition(e.get_playerno()-1, 1).selectAll()
  272. return True
  273. else:
  274. return super(PlayerStartWindow, self).event(e)
  275. def keyPressEvent(self, e):
  276. # needed to circumvent dialogclosing when enter is pressed
  277. if e.key() == QtCore.Qt.Key_Escape:
  278. self.close()
  279. elif e.key() == QtCore.Qt.Key_K:
  280. # FIXME: Remove this
  281. QtCore.QCoreApplication.postEvent(self, ButtonEvent(1))
  282. def _setupGui(self):
  283. self.layout = QtGui.QVBoxLayout()
  284. self.playerGrid = QtGui.QGridLayout()
  285. for player in self._players:
  286. self._guiAddPlayer(player)
  287. self.layout.addLayout(self.playerGrid)
  288. startbtn = QtGui.QPushButton("\nStart\n", self)
  289. startbtn.setStyleSheet("QPushButton { font-size: 40px; }")
  290. startbtn.clicked.connect(self.close)
  291. self.layout.addWidget(startbtn)
  292. self.setLayout(self.layout)
  293. def _guiAddPlayer(self, player):
  294. row = self.playerGrid.rowCount()
  295. label = QtGui.QLabel("Player %d" % (row,), self)
  296. label.setStyleSheet("QLabel { font-size: 40px; background-color: %s; color: white; }" % (player.color.name(),))
  297. self.playerGrid.addWidget(label, row, 0)
  298. edit = QtGui.QLineEdit(player.name, self)
  299. edit.setStyleSheet("QLineEdit { font-size: 40px; }")
  300. edit.editingFinished.connect(lambda widget=edit, player=player: player.change_name(edit.text()))
  301. self.playerGrid.addWidget(edit, row, 1)
  302. class VictoryWindow(QtGui.QDialog):
  303. def __init__(self, players, parent):
  304. super(VictoryWindow, self).__init__(parent)
  305. self._players = players
  306. self._parent = parent
  307. self._setupGui()
  308. def _setupGui(self):
  309. self.layout = QtGui.QVBoxLayout()
  310. self.playerGrid = QtGui.QGridLayout()
  311. winPlayers = sorted(self._players, key=lambda p: p.points, reverse=True)
  312. for i, player in enumerate(winPlayers):
  313. label = QtGui.QLabel(player.name, self)
  314. fsize = 60 if i == 0 else 25
  315. label.setStyleSheet("QLabel { font-size: %dpx; background-color: %s; color: white; }" % (fsize, player.color.name(),))
  316. self.playerGrid.addWidget(label, i, 0)
  317. points = QtGui.QLabel(str(player.points), self)
  318. points.setStyleSheet("QLabel { font-size: %dpx; }" % (fsize,))
  319. self.playerGrid.addWidget(points, i, 1, alignment=QtCore.Qt.AlignRight)
  320. self.layout.addLayout(self.playerGrid)
  321. self.setLayout(self.layout)
  322. class DoubleJeopardyWindow(QtGui.QDialog):
  323. def __init__(self, player, points, current_player=None, current_points=None, parent=None):
  324. super(DoubleJeopardyWindow, self).__init__(parent)
  325. self._player = player
  326. self._currentPlayer = current_player
  327. self._points = points
  328. if current_points:
  329. self._currentPoints = current_points
  330. else:
  331. self._currentPoints = points
  332. self._setupGui()
  333. # move window to bottom right of screen
  334. g = QtGui.QApplication.desktop().screenGeometry()
  335. self.show()
  336. cPos = self.rect()
  337. self.move(g.width() - cPos.width(), g.height() - cPos.height())
  338. def get_chosen_points(self):
  339. return self._currentPoints
  340. def get_player(self):
  341. return self._currentPlayer
  342. def _setupGui(self):
  343. self.layout = QtGui.QVBoxLayout()
  344. header = QtGui.QLabel("Double Jeopardy", self)
  345. header.setStyleSheet("QLabel { font-size: 50px; }")
  346. self.layout.addWidget(header, alignment=QtCore.Qt.AlignCenter)
  347. self.pbtn = QtGui.QPushButton("", self)
  348. self._stylePlayerButton()
  349. self.pbtn.installEventFilter(KeyGrabber((QtCore.Qt.Key.Key_Left, QtCore.Qt.Key.Key_Right), self))
  350. self.layout.addWidget(self.pbtn)
  351. self.pointsbtn = QtGui.QPushButton("% 5s" % self._currentPoints)
  352. self.pointsbtn.setStyleSheet("QPushButton { font-size: 50px; border: none; }")
  353. self.pointsbtn.installEventFilter(KeyGrabber((QtCore.Qt.Key.Key_Left, QtCore.Qt.Key.Key_Right), self))
  354. self.layout.addWidget(self.pointsbtn, alignment=QtCore.Qt.AlignCenter)
  355. self.pointsbtn.setFocus()
  356. start = QtGui.QPushButton("Done", self)
  357. start.clicked.connect(self.closeIfNotNobody)
  358. self.layout.addWidget(start)
  359. self.setLayout(self.layout)
  360. def closeIfNotNobody(self):
  361. if self.get_player() is not None:
  362. self.close()
  363. def keyPressEvent(self, e):
  364. if e.key() == QtCore.Qt.Key_Escape or e.key() == QtCore.Qt.Key_Enter:
  365. self.closeIfNotNobody()
  366. elif e.key() == QtCore.Qt.Key_Left or e.key() == QtCore.Qt.Key_Right:
  367. if self.focusWidget() == self.pbtn:
  368. if e.key() == QtCore.Qt.Key_Right:
  369. if self._currentPlayer == None:
  370. self._currentPlayer = self._player[0]
  371. elif self._currentPlayer == self._player[-1]:
  372. self._currentPlayer = None
  373. else:
  374. self._currentPlayer = self._player[self._player.index(self._currentPlayer)+1]
  375. elif e.key() == QtCore.Qt.Key_Left:
  376. if self._currentPlayer == None:
  377. self._currentPlayer = self._player[-1]
  378. elif self._currentPlayer == self._player[0]:
  379. self._currentPlayer = None
  380. else:
  381. self._currentPlayer = self._player[self._player.index(self._currentPlayer)-1]
  382. self._stylePlayerButton()
  383. elif self.focusWidget() == self.pointsbtn:
  384. if e.key() == QtCore.Qt.Key_Right and self._currentPoints < self._points*2:
  385. self._currentPoints += 50
  386. elif e.key() == QtCore.Qt.Key_Left and self._currentPoints > self._points/2:
  387. self._currentPoints += -50
  388. self.pointsbtn.setText("% 4s" % self._currentPoints)
  389. def _stylePlayerButton(self):
  390. player = None
  391. color = None
  392. if self._currentPlayer == None:
  393. player = "nobody"
  394. color = nobodyColor
  395. else:
  396. player = self._currentPlayer.name
  397. color = self._currentPlayer.color
  398. self.pbtn.setText(player)
  399. self.pbtn.setStyleSheet("QPushButton { background-color: %s; color: white; font-size: 50px; border: none; }" % (color.name(),))