diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/editorui/paths.py | 112 | ||||
-rw-r--r-- | src/unlock.py | 138 |
2 files changed, 153 insertions, 97 deletions
diff --git a/src/editorui/paths.py b/src/editorui/paths.py index 4110188..a0e65d6 100644 --- a/src/editorui/paths.py +++ b/src/editorui/paths.py @@ -538,93 +538,6 @@ class KPEditorPath(QtGui.QGraphicsLineItem): self.setPalette(palette) - class UnlockButton(QtGui.QPushButton): - def __init__(self, pathRef): - QtGui.QPushButton.__init__(self) - - self.setFixedSize(48,48) - - self.iconList = [QtGui.QIcon("Resources/Key.png"), - QtGui.QIcon("Resources/SecretKey.png")] - - self.unlockIcon = QtGui.QIcon("Resources/Unlock.png") - self.arrowIcon = [QtGui.QIcon("Resources/KeyArrow.png"), - QtGui.QIcon("Resources/SecretKeyArrow.png")] - - - self._pathRef = pathRef - - self.secret = 0 - self.path = 0 - - if not hasattr(KPEditorPath.UnlockButton, 'PALETTE'): - KPEditorPath.UnlockButton.PALETTE = QtGui.QPalette(Qt.transparent) - - self.setPalette(self.PALETTE) - - self.released.connect(self.toggle) - - - def toggle(self): - - path = self._pathRef() - - if KP.app.keyboardModifiers() == Qt.ShiftModifier: - if self.secret == 1: - self.secret = 0 - else: - self.secret = 1 - - path.secret = self.secret - - else: - self.path += 1 - - if self.path > 2: - self.path = 0 - - path.unlocks = self.path - - - def paintEvent(self, event): - painter = QtGui.QPainter(self) - contentsRect = self.contentsRect() - smallRect = QtCore.QRect(12, 12, 24, 24) - painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform) - - if self.path > 0: - painter.save() - - displaceX, displaceY = contentsRect.width() / 2, contentsRect.height() / 2 - - pathItem = self._pathRef().qtItem.line() - - if self.path == 1: - angle = 90 - pathItem.angle() - else: - angle = 270 - pathItem.angle() - - painter.translate(displaceX, displaceY) - painter.rotate(angle) - painter.translate(-displaceX, -displaceY) - self.arrowIcon[self.secret].paint(painter, contentsRect, Qt.AlignCenter) - - painter.restore() - - if self.isDown(): - self.iconList[self.secret].paint(painter, smallRect, Qt.AlignCenter, QtGui.QIcon.Disabled) - else: - self.iconList[self.secret].paint(painter, smallRect, Qt.AlignCenter) - - else: - if self.isDown(): - self.unlockIcon.paint(painter, smallRect, Qt.AlignCenter, QtGui.QIcon.Disabled) - else: - self.unlockIcon.paint(painter, smallRect, Qt.AlignCenter) - - painter.end() - - class HiddenProxy(QtGui.QGraphicsProxyWidget): def __init__(self, button, parent, x, y): QtGui.QGraphicsProxyWidget.__init__(self, parent) @@ -663,12 +576,6 @@ class KPEditorPath(QtGui.QGraphicsLineItem): if not hasattr(KPEditorPath, 'SELECTION_PEN'): KPEditorPath.SELECTION_PEN = QtGui.QPen(Qt.blue, 1, Qt.DotLine) - self.unlock = self.UnlockButton(self._pathRef) - self.unlockProxy = self.HiddenProxy(self.unlock, self, -24, -24) - - self.unlock.secret = path.secret - self.unlock.path = path.unlocks - self.options = self.PathOptionsMenuButton(self._pathRef) self.optionsProxy = self.HiddenProxy(self.options, self, -54, +24) @@ -677,6 +584,20 @@ class KPEditorPath(QtGui.QGraphicsLineItem): self.updatePosition() + def mousePressEvent(self, event): + if event.button() != Qt.LeftButton: + return + if QtGui.QApplication.keyboardModifiers() != QtCore.Qt.ControlModifier: + return + + # modify the unlock settings + from unlock import KPUnlockSpecDialog + + # todo: set the existing thing there + result = KPUnlockSpecDialog.exec_() + if result == QtGui.QDialog.Accepted: + print "OK!" + def updatePosition(self): path = self._pathRef() @@ -720,12 +641,9 @@ class KPEditorPath(QtGui.QGraphicsLineItem): painter.setPen(self.SELECTION_PEN) painter.setBrush(QtGui.QColor(0,0,0,0)) painter.drawPath(self.shape()) - - self.unlockProxy.show() self.optionsProxy.show() else: - self.unlockProxy.hide() self.optionsProxy.hide() @@ -753,4 +671,4 @@ class KPEditorPath(QtGui.QGraphicsLineItem): self.scene().removeItem(self) -
\ No newline at end of file + diff --git a/src/unlock.py b/src/unlock.py new file mode 100644 index 0000000..0f954d6 --- /dev/null +++ b/src/unlock.py @@ -0,0 +1,138 @@ +import re + +LEVEL_RE = re.compile(r'^([0-9]{1,2})-([0-9]{1,2})( secret)?$') +COMBINER_RE = re.compile(r'[ ]*(and|or)[ ]*') + +class UnlockParseError(ValueError): + # todo: is this the proper way to make an Error? + pass + +def parseUnlockText(text): + return _parseUnlockBit(text) + +def _parseUnlockBit(text): + # blank criterion + if text == '': + return ('always',) + + # is this a simple one...? + m = LEVEL_RE.match(text) + if m: + one, two, secret = m.groups() + return ('level', int(one), int(two), (secret != None)) + + # OK, let's parse parentheses + pLevel = 0 + endAt = len(text) - 1 + + # this could be either AND or OR or nothing at all + # we won't know it until we finish parsing! + whatCombiner = None + + subTerms = [] + currentSubTermStart = None + + skip = 0 + + for index, char in enumerate(text): + if skip > 0: + skip -= 1 + continue + + if char == '(': + if pLevel == 0: + currentSubTermStart = index + pLevel += 1 + elif char == ')': + pLevel -= 1 + if pLevel < 0: + raise UnlockParseError('close parenthesis without a matching open') + elif pLevel == 0: + subTerms.append((currentSubTermStart, index, text[currentSubTermStart+1:index])) + # are we expecting to see something else? + if index == endAt: break + + m = COMBINER_RE.match(text, index + 1) + if not m: + raise UnlockParseError('something unexpected at %d' % (index+1)) + + # what is it? + nextCombiner = m.group(1) + if whatCombiner is not None and nextCombiner != whatCombiner: + raise UnlockParseError('mixed %s and %s in one term. use more parentheses!' % (whatCombiner,nextCombiner)) + whatCombiner = nextCombiner + + # go right past this, to the next subterm + skip = len(m.group(0)) + else: + if pLevel == 0: + raise UnlockParseError('something unexpected at %d' % index) + + # now that we're here, we must have parsed these subterms + # do we have a combiner? + if whatCombiner is None: + assert len(subTerms) == 1 + + return _parseUnlockBit(subTerms[0][2]) + else: + return (whatCombiner, map(lambda x: _parseUnlockBit(x[2]), subTerms)) + + + +if __name__ == '__main__': + print repr(parseUnlockText('((01-01 secret) and (01-02)) or (02-99 secret) or (01-01)')) + + from sys import exit + exit() + + + + + +from common import * + + + + +class KPUnlockSpecDialog(QtGui.QDialog): + def __init__(self, forWhat, unlockAdjective): + QtGui.QDialog.__init__(self) + + self.setWindowTitle('Set Unlock Criteria') + + text = """You may enter various criteria that must be fulfilled for this {0} to be {1}.<br> + <br> + Here are some examples of what you can use: + <ul> + <li>01-01 - <i>a single criterion</i></li> + <li>01-01 secret - <i>secret exits</i></li> + <li>(01-01 secret) and (01-02) - <i>combine two criteria</i></li> + <li>((01-01 secret) or (01-02)) and (01-04) - <i>nested criteria</i></li> + </ul> + Each criterion used on the sides of AND and OR must be surrounded by parentheses.<br> + <br> + To leave this {0} permanently unlocked, leave the box blank. + """.format(forWhat, unlockAdjective) + + self.label = QtGui.QLabel(text) + self.label.setWordWrap(True) + + self.textBox = QtGui.QLineEdit() + self.textBox.textChanged.connect(self.checkInputValidity) + + self.buttons = QtGui.QDialogButtonBox( + QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) + + self.buttons.accepted.connect(self.accept) + self.buttons.rejected.connect(self.reject) + + self.layout = QtGui.VBoxLayout() + self.layout.addWidget(self.label) + self.layout.addWidget(self.textBox) + self.layout.addWidget(self.buttons) + self.setLayout(self.layout) + + def checkInputValidity(self, text): + self.parsed = parseUnlockText(text) + self.buttons.button(QtGui.QDialogButtonBox.Ok).setEnabled(not (self.parsed is None)) + |