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.

623 lines
20 KiB

# Licensed under GPLv3
# Written by Sebastian Lohff (seba@someserver.de)
# http://seba-geek.de/projects/seopardy/
11 years ago
from PySide import QtGui, QtCore
import copy
from gamestate import QuestionAnswers
from music import MusicBox
from video import VideoPlayer
from player import Player, ButtonEvent, nobodyColor
11 years ago
class QuestionWindow(QtGui.QDialog):
buzzersOpen = QtCore.Signal(bool)
playerGotQuestion = QtCore.Signal(int)
def __init__(self, players, section, qnumber, question, answers=None, dj=None, parent=None):
11 years ago
super(QuestionWindow, self).__init__(parent)
self.players = players
11 years ago
self.section = section
self.qnumber = qnumber
11 years ago
self.question = question
self.dj = dj
self._windowSetup = False
self._videoPlayer = None
if answers is not None:
self.answers = answers
else:
self.answers = QuestionAnswers(self.section, self.qnumber)
11 years ago
if not self.answers.is_answered():
if not self._question_has_audio():
MusicBox.play_music("questionSong")
if self.dj:
self.answers.set_dj_points(self.dj[1])
playerNo = self.players.index(self.dj[0])+1
QtCore.QCoreApplication.postEvent(self, ButtonEvent(playerNo))
11 years ago
self._setupGui()
self.setWindowTitle("Seopardy - %s - %d" % (section, qnumber*100))
self._inWindow = False
11 years ago
if self.question["Type"] == "Music":
tag = "%s-%s" % (self.section, self.qnumber)
MusicBox.add_music(tag, self.question["Question"])
MusicBox.play_music(tag)
elif self.question["Type"] == "Video":
self._videoPlayer.play()
def get_answers(self):
return self.answers
11 years ago
def closeEvent(self, event):
if not self._inWindow:
self.buzzersOpen.emit(False)
MusicBox.stop_music()
if self._videoPlayer:
self._videoPlayer.stop()
event.accept()
else:
event.ignore()
def _mkQuestionLabel(self, text, monospaced=False):
11 years ago
question = QtGui.QLabel(text, alignment=QtCore.Qt.AlignCenter)
question.setWordWrap(True)
extra = ""
if monospaced:
extra += "font-family: monospace;"
question.setStyleSheet("QLabel { font-size: 40px; %s }" % (extra,))
11 years ago
return question
def _setupGui(self):
self.layout = QtGui.QVBoxLayout()
seclabel = QtGui.QLabel(self.section)
seclabel.setStyleSheet("QLabel { font-size: 30px; }")
self.layout.addWidget(seclabel, alignment=QtCore.Qt.AlignCenter)
self.layout.addStretch()
qlabel = None
stretch = 0
11 years ago
if self.question["Type"] == "Text":
qlabel = self._mkQuestionLabel(self.question["Question"])
11 years ago
elif self.question["Type"] == "Music":
qlabel = self._mkQuestionLabel("Listen...")
11 years ago
elif self.question["Type"] == "Image":
qlabel = QtGui.QLabel()
pixmap = QtGui.QPixmap()
pixmap.loadFromData(open(self.question["Question"]).read())
qlabel.setPixmap(pixmap)
qlabel.setAlignment(QtCore.Qt.AlignCenter)
elif self.question["Type"] == "Code":
# to have this a) aligned but b) centered we "cheat" a bit with the spaces...
code = self.question["Question"].split("\n")
code = map(lambda x: x.replace("\t", " "), code)
maxLineLen = max(map(len, code))
code = map(lambda x: x + ((maxLineLen-len(x))*" "), code)
qlabel = self._mkQuestionLabel("<pre>"+"\n".join(code)+"</pre>", monospaced=True)
elif self.question["Type"] == "Video":
self._videoPlayer = VideoPlayer(self.question["Question"], self.question["Audio"])
qlabel = self._videoPlayer.get_widget()
stretch = 1
11 years ago
else:
raise ValueError("%s is an unknown type for section %s question name %s" % (self.question["Type"], self.section, self.question["Name"]))
self.layout.addWidget(qlabel, stretch=stretch)
11 years ago
self.layout.addStretch()
self.setLayout(self.layout)
def event(self, e):
if e.type() == ButtonEvent.eventType:
if e.get_playerno() <= len(self.players) and not self._inWindow:
done = False
if self.question["Type"] == "Music":
MusicBox.stop_music()
elif self.question["Type"] == "Video":
self._videoPlayer.pause()
self._inWindow = True
player = self.players[e.get_playerno()-1]
qawin = QuestionAnswerWindow(player, self)
self.playerGotQuestion.emit(e.get_playerno())
res = qawin.exec_()
if res == QuestionAnswerWindow.CORRECT:
self.answers.add_try(player, correct=True)
self._inWindow = False
done = True
self.close()
elif res == QuestionAnswerWindow.WRONG:
self.answers.add_try(player, correct=False)
self._inWindow = False
if not done:
self.buzzersOpen.emit(True)
if self.question["Type"] == "Music":
# resume music if question was not answered
MusicBox.play_music("%s-%s" % (self.section, self.qnumber))
elif self.question["Type"] == "Video":
# resume video if question was not answered
self._videoPlayer.play()
elif e.get_playerno() > len(self.players) and not self._inWindow:
# unknown player! to not confuse certain devices we send a buttons open event
self.buzzersOpen.emit(True)
print("unknown player", e.get_playerno())
return True
else:
ret = super(QuestionWindow, self).event(e)
# we want to do this after the window has focus for the first time
if not self._windowSetup and e.type() == QtCore.QEvent.FocusIn:
if not self.answers.is_answered():
self.buzzersOpen.emit(True)
self._windowSetup = True
return ret
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape:
if not self.answers.is_answered():
self.answers.nobody_knew()
self.close()
elif not self.answers.is_answered() and e.key() >= ord('1') and e.key() <= ord(str(len(self.players))):
QtCore.QCoreApplication.postEvent(self, ButtonEvent(int(chr(e.key()))))
@QtCore.Slot(int)
def playerButtonPress(self, no):
QtCore.QCoreApplication.postEvent(self, ButtonEvent(int(no)))
def _question_has_audio(self):
return self.question["Type"] == "Music" or (self.question["Type"] == "Video" and self.question["Audio"])
class QuestionAnswerWindow(QtGui.QDialog):
CORRECT = 1
WRONG = 2
OOPS = 3
def __init__(self, player, parent=None):
super(QuestionAnswerWindow, self).__init__(parent)
self.player = player
self._setupGui()
9 years ago
self.setWindowTitle("Seopardy - Answer by Player %s" % (self.player.name,))
# move window to bottom right of screen
g = QtGui.QApplication.desktop().screenGeometry()
self.show()
cPos = self.rect()
self.move(g.width() - cPos.width(), g.height() - cPos.height())
def _setupGui(self):
self.layout = QtGui.QVBoxLayout()
self.plabel = QtGui.QLabel(self.player.name)
self.plabel.setStyleSheet("QLabel { font-size: 60px; }")
self.layout.addWidget(self.plabel, alignment=QtCore.Qt.AlignCenter)
btnbox = QtGui.QHBoxLayout()
right = QtGui.QPushButton("Correct")
right.clicked.connect(lambda: self.done(self.CORRECT))
btnbox.addWidget(right)
wrong = QtGui.QPushButton("Wrong")
wrong.clicked.connect(lambda: self.done(self.WRONG))
btnbox.addWidget(wrong)
btnbox.addStretch()
oops = QtGui.QPushButton("Oops")
oops.clicked.connect(lambda: self.done(self.OOPS))
btnbox.addWidget(oops)
self.layout.addLayout(btnbox)
self.setLayout(self.layout)
class EditAnswersWindow(QtGui.QDialog):
def __init__(self, players, answers, parent=None):
super(EditAnswersWindow, self).__init__(parent)
self._players = players
self._answers = answers
self._nobody = not answers.got_answered()
self._dj_points = answers.get_dj_points()
self._in_window = False
if self._answers:
self._tries = copy.copy(self._answers.get_tries())
else:
self._tries = []
self._setupGui()
9 years ago
self.setWindowTitle("Seopardy - Edit Answers")
self.installEventFilter(KeyGrabber((QtCore.Qt.Key.Key_Left, QtCore.Qt.Key.Key_Right), self))
def get_new_answers(self):
qa = QuestionAnswers(self._answers.section, self._answers.qnumber, dj_points=self._dj_points)
rightPlayer = None
for player, correct in self._tries:
if correct:
rightPlayer = player
else:
qa.add_try(player, correct)
if rightPlayer:
qa.add_try(rightPlayer, True)
elif self._nobody:
qa.nobody_knew()
return qa
def closeEvent(self, event):
if not self._in_window:
event.accept()
else:
event.ignore()
def _setupGui(self):
self.layout = QtGui.QVBoxLayout()
self.qlabel = QtGui.QLabel("Questions")
self.qlabel.setStyleSheet("QLabel { font-size: 30px; }")
self.layout.addWidget(self.qlabel, alignment=QtCore.Qt.AlignCenter)
self.answerlayout = QtGui.QVBoxLayout()
self._resetAllButtons()
self.layout.addLayout(self.answerlayout)
self.xlabel = QtGui.QLabel("+/- right/wrong, d delete, a add, arrows change player\ne edit double jeopardy")
self.xlabel.setStyleSheet("QLabel { font-size: 15px; }")
self.layout.addWidget(self.xlabel)
self.setLayout(self.layout)
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape:
self.close()
elif e.key() == QtCore.Qt.Key_E:
# edit double jeopardy
if self._dj_points is not None and len(self._tries) > 0 and not self._in_window:
self._in_window = True
dwin = DoubleJeopardyWindow(self._players, self._answers.qnumber*100, self._tries[0][0], current_points=self._dj_points, parent=self)
dwin.exec_()
self._dj_points = dwin.get_chosen_points()
self._tries[0] = (dwin.get_player(), self._tries[0][1])
self._in_window = False
else:
currFocus = self._getCurrFocus()
if currFocus is None and e.key() != QtCore.Qt.Key_A:
return
nothingDone = False
if e.key() == QtCore.Qt.Key_Plus:
self._nobody = False
for i, (player, correct) in enumerate(self._tries):
self._tries[i] = (player, i==currFocus)
if currFocus == len(self._tries):
self._nobody = True
elif e.key() == QtCore.Qt.Key_Minus:
if currFocus == len(self._tries):
if len(self._tries) == 0:
self._nobody = False
else:
if self._tries[currFocus][1]:
# give nobody the score for this one
self._nobody = True
self._tries[currFocus] = (self._tries[currFocus][0], False)
elif e.key() == QtCore.Qt.Key_A:
self._tries.append((self._players[0], False))
self._makeNobodyConsistent()
currFocus = len(self._tries) - 1
elif e.key() == QtCore.Qt.Key_D and currFocus < len(self._tries):
del self._tries[currFocus]
elif e.key() == QtCore.Qt.Key_Left and currFocus < len(self._players):
playlen = len(self._players)
prevPlayer = self._players[(self._players.index(self._tries[currFocus][0])-1+playlen)%playlen]
self._tries[currFocus] = (prevPlayer, self._tries[currFocus][1])
elif e.key() == QtCore.Qt.Key_Right and currFocus < len(self._tries):
playlen = len(self._players)
nextPlayer = self._players[(self._players.index(self._tries[currFocus][0])+1+playlen)%playlen]
self._tries[currFocus] = (nextPlayer, self._tries[currFocus][1])
else:
super(EditAnswersWindow, self).keyPressEvent(e)
nothingDone = True
if not nothingDone:
self._resetAllButtons()
self.updateGeometry()
# reset focus
11 years ago
#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())
self.answerlayout.itemAt(min(currFocus, self.answerlayout.count())).widget().setFocus(QtCore.Qt.FocusReason.NoFocusReason)
11 years ago
#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())
#print(self.focusWidget())
#if self.focusWidget():
# print("widget", self.focusWidget().text())
def _makeNobodyConsistent(self):
if len(self._tries) > 0:
someoneKnew = any([c for p, c in self._tries])
self._nobody = not someoneKnew
def _getCurrFocus(self):
if self.focusWidget() is not None:
for i in range(self.answerlayout.count()):
if self.answerlayout.itemAt(i).widget() == self.focusWidget():
return i
return None
def _resetAllButtons(self):
f = self.answerlayout.takeAt(0)
while f is not None:
f.widget().deleteLater()
f = self.answerlayout.takeAt(0)
# add buttons
first = True
for player, correct in self._tries:
self._addAnswerButton(player, correct, first)
first = False
# add the nobody button
self._addAnswerButton(Player("nobody", nobodyColor), self._nobody)
def _addAnswerButton(self, player, correct=False, first=False):
prefix = "+" if correct else "-"
dj = " (D)" if first and self._dj_points is not None else ""
btn = QtGui.QPushButton("\n%s%s%s\n" % (prefix, player.name, dj), self)
btn.setStyleSheet("QPushButton { background-color: %s; color: white; font-size: 20px; border: none; }" % (player.color.name(),))
btn.installEventFilter(KeyGrabber((QtCore.Qt.Key.Key_Left, QtCore.Qt.Key.Key_Right), self))
self.answerlayout.addWidget(btn)
class KeyGrabber(QtCore.QObject):
def __init__(self, keys, parent, *args, **kwargs):
super(KeyGrabber, self).__init__(parent, *args, **kwargs)
self._keys = keys
self._parent = parent
def eventFilter(self, obj, e):
if e.type() == QtCore.QEvent.KeyPress:
if e.key() in self._keys:
self._parent.keyPressEvent(e)
return True
return QtCore.QObject.eventFilter(self, obj, e)
class PlayerStartWindow(QtGui.QDialog):
buzzersOpen = QtCore.Signal(bool)
playerGotQuestion = QtCore.Signal(int)
def __init__(self, players, parent):
super(PlayerStartWindow, self).__init__(parent)
self._players = players
self._parent = parent
self._playerLineEdits = []
self._windowSetup = False
self._setupGui()
9 years ago
self.setWindowTitle("Seopardy - Start")
self.show()
MusicBox.play_music("startSong")
# center window
g = QtGui.QApplication.desktop().screenGeometry()
cPos = self.rect()
self.move(g.width()/2 - cPos.width()/2, g.height()/2 - cPos.height()/2)
def event(self, e):
if e.type() == ButtonEvent.eventType:
if e.get_playerno() <= len(self._players)+1:
if e.get_playerno() == len(self._players)+1:
# add a new player
self._parent.add_player(addToGui=True)
self._guiAddPlayer(self._players[-1])
layoutItem = self.playerGrid.itemAtPosition(e.get_playerno(), 1)
if layoutItem:
widget = layoutItem.widget()
widget.selectAll()
widget.setFocus()
self.playerGotQuestion.emit(e.get_playerno())
return True
else:
ret = super(PlayerStartWindow, self).event(e)
if not self._windowSetup and e.type() == QtCore.QEvent.WindowActivate:
self.buzzersOpen.emit(True)
self._windowSetup = True
return ret
def closeEvent(self, event):
MusicBox.stop_music()
self.buzzersOpen.emit(False)
event.accept()
def keyPressEvent(self, e):
# needed to circumvent dialogclosing when enter is pressed
if e.key() == QtCore.Qt.Key_Escape:
self.close()
elif e.key() == QtCore.Qt.Key_K:
# FIXME: Remove this
QtCore.QCoreApplication.postEvent(self, ButtonEvent(1))
def _setupGui(self):
self.layout = QtGui.QVBoxLayout()
self.playerGrid = QtGui.QGridLayout()
for player in self._players:
self._guiAddPlayer(player)
self.layout.addLayout(self.playerGrid)
startbtn = QtGui.QPushButton("\nStart\n", self)
startbtn.setStyleSheet("QPushButton { font-size: 40px; }")
startbtn.clicked.connect(self.close)
self.layout.addWidget(startbtn)
self.setLayout(self.layout)
def _guiAddPlayer(self, player):
row = self.playerGrid.rowCount()
label = QtGui.QLabel("Player %d" % (row,), self)
label.setStyleSheet("QLabel { font-size: 40px; background-color: %s; color: white; }" % (player.color.name(),))
self.playerGrid.addWidget(label, row, 0)
edit = QtGui.QLineEdit(player.name, self)
edit.setStyleSheet("QLineEdit { font-size: 40px; }")
edit.editingFinished.connect(lambda widget=edit, player=player: self._playerDoneEditing(widget, player))
self.playerGrid.addWidget(edit, row, 1)
def _playerDoneEditing(self, widget, player):
player.change_name(widget.text())
self.buzzersOpen.emit(True)
@QtCore.Slot(int)
def playerButtonPress(self, no):
QtCore.QCoreApplication.postEvent(self, ButtonEvent(int(no)))
class VictoryWindow(QtGui.QDialog):
def __init__(self, players, parent):
super(VictoryWindow, self).__init__(parent)
self._players = players
self._parent = parent
self._setupGui()
9 years ago
self.setWindowTitle("Seopardy - Victory")
MusicBox.play_music("closingSong")
def _setupGui(self):
self.layout = QtGui.QVBoxLayout()
self.playerGrid = QtGui.QGridLayout()
winPlayers = sorted(self._players, key=lambda p: p.points, reverse=True)
for i, player in enumerate(winPlayers):
label = QtGui.QLabel(player.name, self)
fsize = 60 if i == 0 else 25
label.setStyleSheet("QLabel { font-size: %dpx; background-color: %s; color: white; }" % (fsize, player.color.name(),))
self.playerGrid.addWidget(label, i, 0)
points = QtGui.QLabel(str(player.points), self)
points.setStyleSheet("QLabel { font-size: %dpx; }" % (fsize,))
self.playerGrid.addWidget(points, i, 1, alignment=QtCore.Qt.AlignRight)
self.layout.addLayout(self.playerGrid)
self.setLayout(self.layout)
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape:
self.close()
def closeEvent(self, event):
MusicBox.stop_music()
event.accept()
class DoubleJeopardyWindow(QtGui.QDialog):
def __init__(self, player, points, current_player=None, current_points=None, parent=None):
super(DoubleJeopardyWindow, self).__init__(parent)
self._player = player
self._currentPlayer = current_player
self._points = points
if current_points:
self._currentPoints = current_points
else:
self._currentPoints = points
self._setupGui()
9 years ago
self.setWindowTitle("Seopardy - Double Jeopardy")
# move window to bottom right of screen
g = QtGui.QApplication.desktop().screenGeometry()
self.show()
cPos = self.rect()
self.move(g.width() - cPos.width(), g.height() - cPos.height())
def get_chosen_points(self):
return self._currentPoints
def get_player(self):
return self._currentPlayer
def _setupGui(self):
self.layout = QtGui.QVBoxLayout()
header = QtGui.QLabel("Double Jeopardy", self)
header.setStyleSheet("QLabel { font-size: 50px; }")
self.layout.addWidget(header, alignment=QtCore.Qt.AlignCenter)
self.pbtn = QtGui.QPushButton("", self)
self._stylePlayerButton()
self.pbtn.installEventFilter(KeyGrabber((QtCore.Qt.Key.Key_Left, QtCore.Qt.Key.Key_Right), self))
self.layout.addWidget(self.pbtn)
self.pointsbtn = QtGui.QPushButton("% 5s" % self._currentPoints)
self.pointsbtn.setStyleSheet("QPushButton { font-size: 50px; border: none; }")
self.pointsbtn.installEventFilter(KeyGrabber((QtCore.Qt.Key.Key_Left, QtCore.Qt.Key.Key_Right), self))
self.layout.addWidget(self.pointsbtn, alignment=QtCore.Qt.AlignCenter)
self.pointsbtn.setFocus()
start = QtGui.QPushButton("Done", self)
start.clicked.connect(self.closeIfNotNobody)
self.layout.addWidget(start)
self.setLayout(self.layout)
def closeIfNotNobody(self):
if self.get_player() is not None:
self.close()
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape or e.key() == QtCore.Qt.Key_Enter:
self.closeIfNotNobody()
elif e.key() == QtCore.Qt.Key_Left or e.key() == QtCore.Qt.Key_Right:
if self.focusWidget() == self.pbtn:
if e.key() == QtCore.Qt.Key_Right:
if self._currentPlayer == None:
self._currentPlayer = self._player[0]
elif self._currentPlayer == self._player[-1]:
self._currentPlayer = None
else:
self._currentPlayer = self._player[self._player.index(self._currentPlayer)+1]
elif e.key() == QtCore.Qt.Key_Left:
if self._currentPlayer == None:
self._currentPlayer = self._player[-1]
elif self._currentPlayer == self._player[0]:
self._currentPlayer = None
else:
self._currentPlayer = self._player[self._player.index(self._currentPlayer)-1]
self._stylePlayerButton()
elif self.focusWidget() == self.pointsbtn:
if e.key() == QtCore.Qt.Key_Right and self._currentPoints < self._points*2:
self._currentPoints += 50
elif e.key() == QtCore.Qt.Key_Left and self._currentPoints > self._points/2:
self._currentPoints += -50
self.pointsbtn.setText("% 4s" % self._currentPoints)
def _stylePlayerButton(self):
player = None
color = None
if self._currentPlayer == None:
player = "nobody"
color = nobodyColor
else:
player = self._currentPlayer.name
color = self._currentPlayer.color
self.pbtn.setText(player)
self.pbtn.setStyleSheet("QPushButton { background-color: %s; color: white; font-size: 50px; border: none; }" % (color.name(),))