예제 #1
0
    def _create_permanent_segments(self, el_pix):
        perms = []

        # PROG
        el = Lamp(self, el_pix, 66, 0, 64, 19, True)
        el.move(393, 37)
        perms.append(el)

        # VERB
        el = Lamp(self, el_pix, 66, 41, 64, 20, True)
        el.move(286, 106)
        perms.append(el)

        # NOUN
        el = Lamp(self, el_pix, 66, 20, 64, 20, True)
        el.move(393, 106)
        perms.append(el)

        for i in range(3):
            el = Lamp(self, el_pix, 0, 63, 142, 5, True)
            el.move(305, 170 + i * 55)
            perms.append(el)
예제 #2
0
class DSKY(QMainWindow):
    def __init__(self, parent):
        super().__init__(parent)
        self.setWindowTitle('mDSKY')

        try:
            self._el_serial = serial.Serial('/dev/dsky_el', 57600)
            self._el_serial.write(b'R\nR\n')
        except:
            self._el_serial = None

        try:
            self._il_serial = serial.Serial('/dev/dsky_il', 57600)
        except:
            self._il_serial = None

        self._setup_ui()

        self._packet = [0, 0, 0, 0]
        self._packet_idx = 0

        self._socket = QTcpSocket(self)
        self._socket.readyRead.connect(self._read_data)
        self._socket.disconnected.connect(self._connect_to_magc)
        self._connect_to_magc()

        self._last_el_cmd = b''
        self._last_il_cmd = b''
        self._timer = QTimer()
        self._timer.timeout.connect(self._update_display)
        self._timer.start(10)

    def _connect_to_magc(self):
        self._socket.connectToHost('localhost', 19681)
        connected = self._socket.waitForConnected(RECONNECT_MS)
        if not connected:
            QTimer.singleShot(RECONNECT_MS, self._connect_to_magc)

    def _read_data(self):
        data = self._socket.read(STATE_SIZE * 10)
        while data:
            (out0, vnflash, restart, oper_err, key_rel, temp, upl_act,
             comp_act, stby) = struct.unpack_from(STATE_FMT, data, 0)
            data = data[STATE_SIZE:]
            self._update_segments(out0)

            self._verb[0].set_on(not vnflash)
            self._verb[1].set_on(not vnflash)
            self._noun[0].set_on(not vnflash)
            self._noun[1].set_on(not vnflash)

            self._key_rel.set_on(key_rel)
            self._opr_err.set_on(oper_err)
            self._upl_act.set_on(upl_act)
            self._com_act.set_on(comp_act)
            self._restart.set_on(restart)
            self._temp.set_on(temp)
            self._stby.set_on(stby)

    def _update_segments(self, out0):
        relay = (out0 >> 11) & 0x0F
        relay_value = out0 & 0o3777

        if relay == 1:
            self._sign3.set_minus_bit((relay_value >> 10) & 0o1)
            self._reg3[3].set_relay_bits((relay_value >> 5) & 0o37)
            self._reg3[4].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 2:
            self._sign3.set_plus_bit((relay_value >> 10) & 0o1)
            self._reg3[1].set_relay_bits((relay_value >> 5) & 0o37)
            self._reg3[2].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 3:
            self._reg2[4].set_relay_bits((relay_value >> 5) & 0o37)
            self._reg3[0].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 4:
            self._sign2.set_minus_bit((relay_value >> 10) & 0o1)
            self._reg2[2].set_relay_bits((relay_value >> 5) & 0o37)
            self._reg2[3].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 5:
            self._sign2.set_plus_bit((relay_value >> 10) & 0o1)
            self._reg2[0].set_relay_bits((relay_value >> 5) & 0o37)
            self._reg2[1].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 6:
            self._sign1.set_minus_bit((relay_value >> 10) & 0o1)
            self._reg1[3].set_relay_bits((relay_value >> 5) & 0o37)
            self._reg1[4].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 7:
            self._sign1.set_plus_bit((relay_value >> 10) & 0o1)
            self._reg1[1].set_relay_bits((relay_value >> 5) & 0o37)
            self._reg1[2].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 8:
            self._reg1[0].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 9:
            self._noun[0].set_relay_bits((relay_value >> 5) & 0o37)
            self._noun[1].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 10:
            self._verb[0].set_relay_bits((relay_value >> 5) & 0o37)
            self._verb[1].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 11:
            self._prog[0].set_relay_bits((relay_value >> 5) & 0o37)
            self._prog[1].set_relay_bits((relay_value >> 0) & 0o37)
        elif relay == 12:
            self._prio_disp.set_on((relay_value >> 0) & 0o1)
            self._no_dap.set_on((relay_value >> 1) & 0o1)
            self._vel.set_on((relay_value >> 2) & 0o1)
            self._no_att.set_on((relay_value >> 3) & 0o1)
            self._alt.set_on((relay_value >> 4) & 0o1)
            self._gimbal_lock.set_on((relay_value >> 5) & 0o1)
            self._tracker.set_on((relay_value >> 7) & 0o1)
            self._prog_alarm.set_on((relay_value >> 8) & 0o1)

    def _setup_ui(self):
        self.setObjectName('#DSKY')
        self.setWindowFlags(Qt.Window)
        self.setFixedSize(500, 580)
        self.setStyleSheet(
            'DSKY{background-image: url(:/resources/dsky.png);}')
        self.setWindowTitle('mDSKY')

        el_pix = QPixmap(':/resources/el.png')
        lamp_pix = QPixmap(':/resources/lamps.png')

        self._com_act = Lamp(self, el_pix, 0, 1, 65, 61, False)
        self._com_act.move(285, 36)
        self._perms = self._create_permanent_segments(el_pix)
        self._prog = self._create_mode(el_pix, 394, 60)
        self._verb = self._create_mode(el_pix, 287, 129)
        self._noun = self._create_mode(el_pix, 394, 129)
        self._sign1, self._reg1 = self._create_reg(el_pix, 287, 184)
        self._sign2, self._reg2 = self._create_reg(el_pix, 287, 239)
        self._sign3, self._reg3 = self._create_reg(el_pix, 287, 294)

        self._but_verb = self._create_button(8, 404, 0b10001)  # VERB
        self._but_noun = self._create_button(8, 474, 0b11111)  # NOUN
        self._but_plus = self._create_button(78, 369, 0b11010)  # +
        self._but_minus = self._create_button(78, 439, 0b11011)  # -
        self._but_0 = self._create_button(78, 509, 0b10000)  # 0
        self._but_7 = self._create_button(148, 369, 0b00111)  # 7
        self._but_4 = self._create_button(148, 439, 0b00100)  # 4
        self._but_1 = self._create_button(148, 509, 0b00001)  # 1
        self._but_8 = self._create_button(218, 369, 0b01000)  # 8
        self._but_5 = self._create_button(218, 439, 0b00101)  # 5
        self._but_2 = self._create_button(218, 509, 0b00010)  # 2
        self._but_9 = self._create_button(288, 369, 0b01001)  # 9
        self._but_6 = self._create_button(288, 439, 0b00110)  # 6
        self._but_3 = self._create_button(288, 509, 0b00011)  # 3
        self._but_clr = self._create_button(359, 369, 0b11110)  # CLR
        self._but_pro = self._create_button(359, 439, 0b100000)  # PRO
        self._but_key_rel = self._create_button(359, 509, 0b11001)  # KEY REL
        self._but_enter = self._create_button(429, 404, 0b11100)  # ENTER
        self._but_reset = self._create_button(429, 474, 0b10010)  # RESET

        self._upl_act = Lamp(self, lamp_pix, 0, 0, 78, 37, False)
        self._upl_act.move(45, 34)
        self._no_att = Lamp(self, lamp_pix, 0, 38, 78, 37, False)
        self._no_att.move(45, 77)
        self._stby = Lamp(self, lamp_pix, 0, 76, 78, 37, False)
        self._stby.move(45, 120)
        self._key_rel = Lamp(self, lamp_pix, 0, 114, 78, 37, False)
        self._key_rel.move(45, 163)
        self._opr_err = Lamp(self, lamp_pix, 0, 152, 78, 37, False)
        self._opr_err.move(45, 206)
        self._prio_disp = Lamp(self, lamp_pix, 0, 190, 78, 37, False)
        self._prio_disp.move(45, 249)
        self._no_dap = Lamp(self, lamp_pix, 0, 228, 78, 37, False)
        self._no_dap.move(45, 292)

        self._temp = Lamp(self, lamp_pix, 79, 0, 78, 37, False)
        self._temp.move(134, 34)
        self._gimbal_lock = Lamp(self, lamp_pix, 79, 38, 78, 37, False)
        self._gimbal_lock.move(134, 77)
        self._prog_alarm = Lamp(self, lamp_pix, 79, 76, 78, 37, False)
        self._prog_alarm.move(134, 120)
        self._restart = Lamp(self, lamp_pix, 79, 114, 78, 37, False)
        self._restart.move(134, 163)
        self._tracker = Lamp(self, lamp_pix, 79, 152, 78, 37, False)
        self._tracker.move(134, 206)
        self._alt = Lamp(self, lamp_pix, 79, 190, 78, 37, False)
        self._alt.move(134, 249)
        self._vel = Lamp(self, lamp_pix, 79, 228, 78, 37, False)
        self._vel.move(134, 292)

        self._il_lamps = [
            self._upl_act, self._no_att, self._stby, self._key_rel,
            self._opr_err, self._prio_disp, self._no_dap, self._temp,
            self._gimbal_lock, self._prog_alarm, self._restart, self._tracker,
            self._alt, self._vel
        ]

        self.show()

    def _create_reg(self, el_pix, col, row):
        digits = []

        sign = Sign(self, el_pix)
        sign.move(col, row + 6)

        for i in range(5):
            ss = SevenSegment(self, el_pix)
            ss.move(col + 18 + 30 * i, row)
            digits.append(ss)

        return sign, digits

    def _create_mode(self, el_pix, col, row):
        digits = []
        for i in range(2):
            ss = SevenSegment(self, el_pix)
            ss.move(col + 30 * i, row)
            digits.append(ss)

        return digits

    def _create_permanent_segments(self, el_pix):
        perms = []

        # PROG
        el = Lamp(self, el_pix, 66, 0, 64, 19, True)
        el.move(393, 37)
        perms.append(el)

        # VERB
        el = Lamp(self, el_pix, 66, 41, 64, 20, True)
        el.move(286, 106)
        perms.append(el)

        # NOUN
        el = Lamp(self, el_pix, 66, 20, 64, 20, True)
        el.move(393, 106)
        perms.append(el)

        for i in range(3):
            el = Lamp(self, el_pix, 0, 63, 142, 5, True)
            el.move(305, 170 + i * 55)
            perms.append(el)

    def _create_button(self, x, y, keycode):
        b = Button(self)
        b.setFixedSize(63, 63)
        b.move(x, y)
        b.setStyleSheet('QPushButton{background-color: rgba(0,0,0,0);}')
        b.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        b.setAutoRepeat(False)
        if keycode == 0b100000:
            key_on = keycode | 0b1
            key_off = keycode
        else:
            key_on = keycode
            key_off = 0
        b.pressed.connect(lambda: self._send_key(key_on))
        b.released.connect(lambda: self._send_key(key_off))
        return b

    def _send_key(self, k):
        self._socket.write(QByteArray(struct.pack('<B', k)))

    def _update_display(self):
        reg1 = b''.join([ss.value for ss in self._reg1])
        reg2 = b''.join([ss.value for ss in self._reg2])
        reg3 = b''.join([ss.value for ss in self._reg3])
        verb = b''.join([ss.value for ss in self._verb])
        noun = b''.join([ss.value for ss in self._noun])
        prog = b''.join([ss.value for ss in self._prog])
        el_cmd = b'DA%s%s%s%s%s%s%s%s%s%s\n' % (
            self._sign1.value, reg1, self._sign2.value, reg2,
            self._sign3.value, reg3, verb, noun, self._com_act.value, prog)
        if el_cmd != self._last_el_cmd:
            if self._el_serial is not None:
                self._el_serial.write(el_cmd)
                self._el_serial.readline()
            self._last_el_cmd = el_cmd

        il_values = 0
        for i in range(len(self._il_lamps)):
            if self._il_lamps[i].value == b'1':
                il_values |= 1 << i

        il_cmd = b'M%04X\n' % il_values
        if il_cmd != self._last_il_cmd:
            if self._il_serial is not None:
                self._il_serial.write(il_cmd)
                self._il_serial.readline()
            self._last_il_cmd = il_cmd

    def paintEvent(self, event):
        opt = QStyleOption()
        opt.init(self)
        p = QPainter(self)
        self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)

    def keyPressEvent(self, event):
        if event.isAutoRepeat():
            return
        key = event.key()
        self._set_key_down(key, True)

    def keyReleaseEvent(self, event):
        if event.isAutoRepeat():
            return
        key = event.key()
        self._set_key_down(key, False)

    def _set_key_down(self, key, down):
        but = None

        if key == Qt.Key.Key_V:
            but = self._but_verb
        elif key == Qt.Key.Key_N:
            but = self._but_noun
        elif key == Qt.Key.Key_V:
            but = self._but_verb
        elif key == Qt.Key.Key_Plus or key == Qt.Key.Key_Equal:
            but = self._but_plus
        elif key == Qt.Key.Key_Minus:
            but = self._but_minus
        elif key == Qt.Key.Key_0:
            but = self._but_0
        elif key == Qt.Key.Key_1:
            but = self._but_1
        elif key == Qt.Key.Key_2:
            but = self._but_2
        elif key == Qt.Key.Key_3:
            but = self._but_3
        elif key == Qt.Key.Key_4:
            but = self._but_4
        elif key == Qt.Key.Key_5:
            but = self._but_5
        elif key == Qt.Key.Key_6:
            but = self._but_6
        elif key == Qt.Key.Key_7:
            but = self._but_7
        elif key == Qt.Key.Key_8:
            but = self._but_8
        elif key == Qt.Key.Key_9:
            but = self._but_9
        elif key == Qt.Key.Key_C:
            but = self._but_clr
        elif key == Qt.Key.Key_P:
            but = self._but_pro
        elif key == Qt.Key.Key_K:
            but = self._but_key_rel
        elif key == Qt.Key.Key_E:
            but = self._but_enter
        elif key == Qt.Key.Key_R:
            but = self._but_reset

        if but is None:
            return

        if down:
            but.press()
        else:
            but.release()
예제 #3
0
class DSKY(QWidget):
    def __init__(self, parent, usbif):
        super().__init__(parent)

        self._usbif = usbif

        self._setup_ui()

        self._vnflash = False
        self._flash_on = True
        QTimer.singleShot(FLASH_ON_MS, self._update_flash)

        usbif.poll("dsky", um.DSKYProg())
        usbif.poll("dsky", um.DSKYVerb())
        usbif.poll("dsky", um.DSKYNoun())
        usbif.poll("dsky", um.DSKYReg1L())
        usbif.poll("dsky", um.DSKYReg1H())
        usbif.poll("dsky", um.DSKYReg2L())
        usbif.poll("dsky", um.DSKYReg2H())
        usbif.poll("dsky", um.DSKYReg3L())
        usbif.poll("dsky", um.DSKYReg3H())
        usbif.poll("dsky", um.DSKYStatus())

        usbif.listen(self)

    def handle_msg(self, msg):
        if isinstance(msg, um.DSKYProg):
            self._prog[0].set_relay_bits(msg.digit2)
            self._prog[1].set_relay_bits(msg.digit1)
        elif isinstance(msg, um.DSKYVerb):
            self._verb[0].set_relay_bits(msg.digit2)
            self._verb[1].set_relay_bits(msg.digit1)
        elif isinstance(msg, um.DSKYNoun):
            self._noun[0].set_relay_bits(msg.digit2)
            self._noun[1].set_relay_bits(msg.digit1)
        elif isinstance(msg, um.DSKYReg1L):
            self._reg1[2].set_relay_bits(msg.digit3)
            self._reg1[3].set_relay_bits(msg.digit2)
            self._reg1[4].set_relay_bits(msg.digit1)
        elif isinstance(msg, um.DSKYReg1H):
            self._sign1.set_relay_bits(msg.sign)
            self._reg1[0].set_relay_bits(msg.digit5)
            self._reg1[1].set_relay_bits(msg.digit4)
        elif isinstance(msg, um.DSKYReg2L):
            self._reg2[2].set_relay_bits(msg.digit3)
            self._reg2[3].set_relay_bits(msg.digit2)
            self._reg2[4].set_relay_bits(msg.digit1)
        elif isinstance(msg, um.DSKYReg2H):
            self._sign2.set_relay_bits(msg.sign)
            self._reg2[0].set_relay_bits(msg.digit5)
            self._reg2[1].set_relay_bits(msg.digit4)
        elif isinstance(msg, um.DSKYReg3L):
            self._reg3[2].set_relay_bits(msg.digit3)
            self._reg3[3].set_relay_bits(msg.digit2)
            self._reg3[4].set_relay_bits(msg.digit1)
        elif isinstance(msg, um.DSKYReg3H):
            self._sign3.set_relay_bits(msg.sign)
            self._reg3[0].set_relay_bits(msg.digit5)
            self._reg3[1].set_relay_bits(msg.digit4)
        elif isinstance(msg, um.DSKYStatus):
            self._vnflash = msg.vnflash

            self._com_act.set_on(msg.comp_acty)
            self._upl_act.set_on(msg.uplink_acty)
            self._no_att.set_on(msg.no_att)
            self._stby.set_on(msg.stby)
            self._key_rel.set_on(msg.key_rel)
            self._opr_err.set_on(msg.opr_err)
            self._prio_disp.set_on(msg.prio_disp)
            self._no_dap.set_on(msg.no_dap)
            self._temp.set_on(msg.temp)
            self._gimbal_lock.set_on(msg.gimbal_lock)
            self._prog_alarm.set_on(msg.prog)
            self._restart.set_on(msg.restart)
            self._tracker.set_on(msg.tracker)
            self._alt.set_on(msg.alt)
            self._vel.set_on(msg.vel)

    def _setup_ui(self):
        self.setObjectName('#DSKY')
        self.setWindowFlags(Qt.Window)
        self.setFixedSize(500, 580)
        self.setStyleSheet('DSKY{background-image: url(:/dsky.png);}')
        self.setWindowTitle('Monitor DSKY')

        el_pix = QPixmap(':/el.png')
        lamp_pix = QPixmap(':/lamps.png')

        self._com_act = Lamp(self, el_pix, 0, 1, 65, 61, False)
        self._com_act.move(285, 36)
        self._perms = self._create_permanent_segments(el_pix)
        self._prog = self._create_mode(el_pix, 394, 60)
        self._verb = self._create_mode(el_pix, 287, 129)
        self._noun = self._create_mode(el_pix, 394, 129)
        self._sign1, self._reg1 = self._create_reg(el_pix, 287, 184)
        self._sign2, self._reg2 = self._create_reg(el_pix, 287, 239)
        self._sign3, self._reg3 = self._create_reg(el_pix, 287, 294)

        self._but_verb = self._create_button(8, 404, 0b10001)  # VERB
        self._but_noun = self._create_button(8, 474, 0b11111)  # NOUN
        self._but_plus = self._create_button(78, 369, 0b11010)  # +
        self._but_minus = self._create_button(78, 439, 0b11011)  # -
        self._but_0 = self._create_button(78, 509, 0b10000)  # 0
        self._but_7 = self._create_button(148, 369, 0b00111)  # 7
        self._but_4 = self._create_button(148, 439, 0b00100)  # 4
        self._but_1 = self._create_button(148, 509, 0b00001)  # 1
        self._but_8 = self._create_button(218, 369, 0b01000)  # 8
        self._but_5 = self._create_button(218, 439, 0b00101)  # 5
        self._but_2 = self._create_button(218, 509, 0b00010)  # 2
        self._but_9 = self._create_button(288, 369, 0b01001)  # 9
        self._but_6 = self._create_button(288, 439, 0b00110)  # 6
        self._but_3 = self._create_button(288, 509, 0b00011)  # 3
        self._but_clr = self._create_button(359, 369, 0b11110)  # CLR
        self._but_pro = self._create_button(359, 439, None)  # PRO
        self._but_key_rel = self._create_button(359, 509, 0b11001)  # KEY REL
        self._but_enter = self._create_button(429, 404, 0b11100)  # ENTER
        self._but_reset = self._create_button(429, 474, 0b10010)  # RESET

        self._upl_act = Lamp(self, lamp_pix, 0, 0, 78, 37, False)
        self._upl_act.move(45, 34)
        self._no_att = Lamp(self, lamp_pix, 0, 38, 78, 37, False)
        self._no_att.move(45, 77)
        self._stby = Lamp(self, lamp_pix, 0, 76, 78, 37, False)
        self._stby.move(45, 120)
        self._key_rel = Lamp(self, lamp_pix, 0, 114, 78, 37, False)
        self._key_rel.move(45, 163)
        self._opr_err = Lamp(self, lamp_pix, 0, 152, 78, 37, False)
        self._opr_err.move(45, 206)
        self._prio_disp = Lamp(self, lamp_pix, 0, 190, 78, 37, False)
        self._prio_disp.move(45, 249)
        self._no_dap = Lamp(self, lamp_pix, 0, 228, 78, 37, False)
        self._no_dap.move(45, 292)

        self._temp = Lamp(self, lamp_pix, 79, 0, 78, 37, False)
        self._temp.move(134, 34)
        self._gimbal_lock = Lamp(self, lamp_pix, 79, 38, 78, 37, False)
        self._gimbal_lock.move(134, 77)
        self._prog_alarm = Lamp(self, lamp_pix, 79, 76, 78, 37, False)
        self._prog_alarm.move(134, 120)
        self._restart = Lamp(self, lamp_pix, 79, 114, 78, 37, False)
        self._restart.move(134, 163)
        self._tracker = Lamp(self, lamp_pix, 79, 152, 78, 37, False)
        self._tracker.move(134, 206)
        self._alt = Lamp(self, lamp_pix, 79, 190, 78, 37, False)
        self._alt.move(134, 249)
        self._vel = Lamp(self, lamp_pix, 79, 228, 78, 37, False)
        self._vel.move(134, 292)

        self.show()

    def _create_button(self, x, y, keycode):
        b = DSKYButton(self)
        b.setFixedSize(63, 63)
        b.move(x, y)

        b.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        b.setAutoRepeat(False)
        if keycode is None:
            b.pressed.connect(lambda: self._usbif.send(um.DSKYProceed(1)))
            b.released.connect(lambda: self._usbif.send(um.DSKYKeyRelease(1)))
            #b.released.connect(lambda: print("PRO released"))
            #b.pressed.connect(lambda: print("PRO pressed"))
        else:
            b.pressed.connect(lambda k=keycode: self._usbif.send(
                um.DSKYMainButton(keycode=k)))
            b.released.connect(lambda: self._usbif.send(um.DSKYKeyRelease(1)))
            #b.pressed.connect(lambda k=keycode: print(keycode, "pressed"))
            #b.released.connect(lambda k=keycode: print(keycode, "released"))
            if keycode == 0b10010:
                b.pressed.connect(lambda: self._usbif.send(um.DSKYReset(1)))

        return b

    def _create_reg(self, el_pix, col, row):
        digits = []

        sign = Sign(self, el_pix)
        sign.move(col, row + 6)

        for i in range(5):
            ss = SevenSegment(self, el_pix)
            ss.move(col + 18 + 30 * i, row)
            digits.append(ss)

        return sign, digits

    def _create_mode(self, el_pix, col, row):
        digits = []
        for i in range(2):
            ss = SevenSegment(self, el_pix)
            ss.move(col + 30 * i, row)
            digits.append(ss)

        return digits

    def _create_permanent_segments(self, el_pix):
        perms = []

        # PROG
        el = Lamp(self, el_pix, 66, 0, 64, 19, True)
        el.move(393, 37)
        perms.append(el)

        # VERB
        el = Lamp(self, el_pix, 66, 41, 64, 20, True)
        el.move(286, 106)
        perms.append(el)

        # NOUN
        el = Lamp(self, el_pix, 66, 20, 64, 20, True)
        el.move(393, 106)
        perms.append(el)

        for i in range(3):
            el = Lamp(self, el_pix, 0, 63, 142, 5, True)
            el.move(305, 170 + i * 55)
            perms.append(el)
        return perms

    def _update_flash(self):
        self._flash_on = not self._flash_on
        QTimer.singleShot(FLASH_ON_MS if self._flash_on else FLASH_OFF_MS,
                          self._update_flash)
        vn = (not self._flash_on) if self._vnflash else True
        self._verb[0].set_on(vn)
        self._verb[1].set_on(vn)
        self._noun[0].set_on(vn)
        self._noun[1].set_on(vn)

        self._key_rel.set_flash(self._flash_on)
        self._opr_err.set_flash(self._flash_on)

    def paintEvent(self, event):
        opt = QStyleOption()
        opt.init(self)
        p = QPainter(self)
        self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)

    def keyPressEvent(self, event):
        key = event.key()
        self._set_key_down(key, True)

    def keyReleaseEvent(self, event):
        key = event.key()
        self._set_key_down(key, False)

    def _set_key_down(self, key, down):
        but = None

        if key == Qt.Key.Key_V:
            but = self._but_verb
        elif key == Qt.Key.Key_N:
            but = self._but_noun
        elif key == Qt.Key.Key_V:
            but = self._but_verb
        elif key == Qt.Key.Key_Plus or key == Qt.Key.Key_Equal:
            but = self._but_plus
        elif key == Qt.Key.Key_Minus:
            but = self._but_minus
        elif key == Qt.Key.Key_0:
            but = self._but_0
        elif key == Qt.Key.Key_1:
            but = self._but_1
        elif key == Qt.Key.Key_2:
            but = self._but_2
        elif key == Qt.Key.Key_3:
            but = self._but_3
        elif key == Qt.Key.Key_4:
            but = self._but_4
        elif key == Qt.Key.Key_5:
            but = self._but_5
        elif key == Qt.Key.Key_6:
            but = self._but_6
        elif key == Qt.Key.Key_7:
            but = self._but_7
        elif key == Qt.Key.Key_8:
            but = self._but_8
        elif key == Qt.Key.Key_9:
            but = self._but_9
        elif key == Qt.Key.Key_C:
            but = self._but_clr
        elif key == Qt.Key.Key_P:
            but = self._but_pro
        elif key == Qt.Key.Key_K:
            but = self._but_key_rel
        elif key == Qt.Key.Key_E:
            but = self._but_enter
        elif key == Qt.Key.Key_R:
            but = self._but_reset

        if but is None:
            return

        if down:
            but.click()
        but.setDown(down)