def __init__(self, image: str = None, parent=None) -> None: super().__init__(parent) self._path = image self.image = None if image is not None: self.image = os.path.basename(image) lyt = QtGui.QGridLayout() self.setLayout(lyt) self.close_btn = IconButton( QtGui.QPixmap(res("cancel_red.png", "icon")), -1) self.close_btn.hide() self.close_btn.setToolTip("Remove the Image") self.close_btn.clicked.connect(self.hideImage) self.add_btn = IconButton(QtGui.QPixmap(res("plus_green.png", "icon")), -1) self.add_btn.clicked.connect(self.choose_image) self.add_btn.setToolTip("Add an Image") self.lbl = QtGui.QLabel( "<font size=10 color=grey><i>Insert an Image<i></font>") lyt.addWidget(self.close_btn, 1, 1) lyt.addWidget(self.add_btn, 1, 1) lyt.addWidget(self.lbl, 0, 0, 2, 2, alignment=QtCore.Qt.AlignCenter) lyt.setRowStretch(0, 1) lyt.setColumnStretch(0, 1) if image is not None: self.setImage(image)
def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("إختر امتحانًا") self.setWindowIcon(QtGui.QIcon(res("test.ico", "icon"))) self.resize(600, 300) lyt = QtGui.QVBoxLayout() wrap = QtGui.QWidget() wrap.setLayout(lyt) scroll = QtGui.QScrollArea() scroll.setWidget(wrap) topmost = QtGui.QVBoxLayout() scroll.setWidgetResizable(True) topmost.addWidget(scroll) self.setLayout(topmost) lyt.setMargin(8) a = len(TESTS) if a == 0: lyt.addWidget( QtGui.QLabel("لا يوجد أية إمتحان، اضف واحدًا لتكمل."), alignment=QtCore.Qt.AlignCenter) return for i, test in enumerate(TESTS): lyt.addWidget(TestCard(test, i, self, chose=self.chose)) if a > 1: lyt.addWidget(QtGui.QLabel("<hr>")) lyt.addWidget(QtGui.QLabel("النهاية"), alignment=QtCore.Qt.AlignCenter) login_link = QtGui.QLabel("<a href='#open'>Open tests editor</a>") login_link.setOpenExternalLinks(False) def f(_): auth = Auth(parent=self) center_widget(auth) auth.parent_window = self auth.show() CURRENT_ACTIVE[0] = auth self.hide() login_link.linkActivated.connect(f) topmost.addWidget(QtGui.QLabel("<hr>")) dwn = QtGui.QHBoxLayout() dwn.addWidget(QtGui.QLabel()) dwn.addWidget(QtGui.QLabel("{} Test{}".format(a, 's' if a > 1 else '')), alignment=QtCore.Qt.AlignCenter) dwn.addWidget(login_link, alignment=QtCore.Qt.AlignRight) topmost.addLayout(dwn)
def f1(e: QtGui.QContextMenuEvent): selected_item = self.tests_list.itemAt(e.pos()) if selected_item is None: return menu = QtGui.QMenu() delete = menu.addAction("Delete") delete.setIcon(QtGui.QIcon(res("halt.png", "icon"))) action = menu.exec_(QtGui.QCursor.pos()) if action == delete: self.delete_test(index=self.tests_list.row(selected_item))
def contextMenuEvent(self, event: QtGui.QContextMenuEvent): row = self.rowAt(event.pos().y()) if row == -1: return menu = QtGui.QMenu() delete = menu.addAction("Delete") delete.setIcon(QtGui.QIcon(res("halt.png", "icon"))) action = menu.exec_(QtGui.QCursor.pos()) if action == delete: self.delete_row(row)
def main(): _init() app = QtGui.QApplication(sys.argv) app.setApplicationName("Examer") app.setApplicationVersion("0.1") app.setWindowIcon(QtGui.QIcon(res("test.ico", "icon"))) main_widget = TestChooser() center_widget(main_widget) main_widget.show() app.exec_() del main_widget del app _defer()
def __init__(self, answer: Answer, index: int, last=False, parent: QtGui.QWidget = None, **kwargs) -> None: QtGui.QWidget.__init__(self, parent, **kwargs) self._last = last self.index = index self.mod = None # type: IconButton self.deleted = False lyt = QtGui.QHBoxLayout() self.add_pixmap = QtGui.QPixmap(res("plus_green.png", "icon")) self.remove_pixmap = QtGui.QPixmap(res("cancel_red.png", "icon")) self.setLayout(lyt) self.chk = chk = QtGui.QCheckBox() chk.stateChanged.connect(lambda x: self.validityChanged.emit( x == QtCore.Qt.Checked, self.index)) if answer.valid: chk.toggle() lyt.addWidget(chk) self.edt = edt = EditableLabel("") # to get the signal emitted edt.textChanged.connect(self.observe_text) edt.setText(answer.string) edt.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Maximum) edt.setAlignment(QtCore.Qt.AlignAbsolute) lyt.addWidget(edt) self.last = last lyt.setDirection(QtGui.QBoxLayout.LeftToRight)
def __init__(self, test: Test, item: QtGui.QListWidgetItem, parent: QtGui.QWidget = None) -> None: super().__init__(parent) self._item = item self.s_test = test self.setTabBar(TabBar()) self.setTabsClosable(True) self.setUpdatesEnabled(True) self.setMovable(True) btn = QtGui.QToolButton() btn.setIcon(QtGui.QIcon(res("add.png", "icon"))) btn.clicked.connect(self.add_question) self.setCornerWidget(btn) self.details = details = TestDetails(test, parent=self) details.wantFocusChanged.connect( lambda r: self.updateErrors.emit(self.errors)) details.nameChanged.connect( lambda s: self.nameChanged.emit(self.index, s)) self.addTab(details, "Details") self.tabBar().tabButton(0, QtGui.QTabBar.RightSide).resize( 0, 0) # makes it not closable self.degrees_widget = degrees_widget = DegreesWidget( copy.deepcopy(test), parent=self) def f(r): self.tabBar().setEnabled( r is DegreesTable.PreserveFocusReason.NONE) self.cornerWidget().setEnabled( r is DegreesTable.PreserveFocusReason.NONE) self.updateErrors.emit(self.errors) degrees_widget.wantFocusChanged.connect(f) self.addTab(degrees_widget, "Degrees") self.tabBar().tabButton(1, QtGui.QTabBar.RightSide).resize( 0, 0) # makes it not closable self.tabBar().tabMoved.connect(self.tab_moved) for question in test.questions: self.add_question(question=question, setfocus=False) self.tabCloseRequested.connect(self.delete_question)
def save(self) -> bool: errors = self.tests_widget.currentWidget().errors if errors: QtGui.QMessageBox.warning(self, "Invalid Operation", "Cannot save while there's an error.") return False else: self.sts_bar_lbl.setText("Saved Tests.") QtCore.QTimer.singleShot(3000, self.update_status_bar) new_tests = self.tests for widget, test in zip(self.widgets, new_tests): widget.s_test = test self.old_tests = TESTS[:] TESTS.clear() TESTS.extend(new_tests) dump_tests(new_tests, res("data.enc", "state"), encrypt=True) return True
def __init__(self, test: Test, index: int, parent=None, **kwargs) -> None: super().__init__(parent, **kwargs) self.index = index self.setFrameShadow(QtGui.QFrame.Sunken) self.setFrameShape(QtGui.QFrame.StyledPanel) lyt = QtGui.QGridLayout() lyt.addWidget(QtGui.QLabel("<b><font size=5>%s</font></b>" % test.name), 0, 0, alignment=QtCore.Qt.AlignLeft) lyt.addWidget(QtGui.QLabel("<hr>"), 1, 0, 1, 2) lyt.addWidget(QtGui.QLabel("<font size=3 color=grey>%s</font>" % (test.description or "<i>" "لا يوجد وصف" "</i>")), 1, 0, 2, 2, alignment=QtCore.Qt.AlignLeft) btn = QtGui.QPushButton("افتح", self) btn.setIcon(QtGui.QIcon(res("arrow.png", "icon"))) btn.clicked.connect(self.open) lyt.addWidget(QtGui.QLabel(), 2, 0) text = re.sub( r'\b(\d+)\b', r'<b>\1</b>', "%s | %d درجة | %d سؤال" % (format_secs(test.time), int(test.degree), len(test.questions))) lyt.addWidget(QtGui.QLabel("<font size=3 color=grey>%s</font>" % text), 3, 0, 1, 2, alignment=QtCore.Qt.AlignLeft) lyt.addWidget(btn, 4, 1, alignment=QtCore.Qt.AlignRight) self.setLayout(lyt)
def __init__(self, id_: int, question: Question, parent=None): super().__init__(parent) self.id = id_ self.degree = -1 random.shuffle(question.answers) self.question = question self.valid = [ question.answers.index(a) for a in self.question.answers if a.valid ] self.is_radio = len(self.valid) == 1 self.pic = QtGui.QLabel() my_layout = QtGui.QVBoxLayout() self.question = QtGui.QLabel("<font size=2 color=red><b>" + question.string + "</b></font>") self.question.setBackgroundRole(QtGui.QPalette.Background) self.question.setFont(QtGui.QFont("Times", weight=QtGui.QFont.Bold)) self.question.setWordWrap(True) my_layout.addWidget(self.question) self.setTitle("سؤال رقم " + str(self.id)) my_layout.addWidget(QtGui.QLabel("<hr>")) answers_images_lyt = QtGui.QHBoxLayout() answers_lyt = QtGui.QVBoxLayout() if self.is_radio: self.answers = QtGui.QButtonGroup() for a in question.answers: btn = QtGui.QRadioButton(a.string) btn.clicked.connect(self.answering) self.answers.addButton(btn) answers_lyt.addWidget(btn) else: self.answers = [] for a in question.answers: btn = QtGui.QCheckBox(a.string) btn.stateChanged.connect(self.answering) answers_lyt.addWidget(btn) self.answers.append(btn) self.checkbox_clicked = 0 answers_images_lyt.addLayout(answers_lyt, 3) answers_images_lyt.addStretch(1) answers_images_lyt.addWidget(self.pic, 2, alignment=QtCore.Qt.AlignRight) my_layout.addLayout(answers_images_lyt) if question.pic: self.pic.setPixmap(QtGui.QPixmap(res(question.pic))) self.lcdScreen = QtGui.QLCDNumber() self.lcdScreen.setSegmentStyle(QtGui.QLCDNumber.Flat) my_layout.addItem( QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)) my_layout.addWidget(QtGui.QLabel("<hr>")) child_layout = QtGui.QHBoxLayout() self.number_label = QtGui.QLabel() child_layout.addWidget(self.number_label, alignment=QtCore.Qt.AlignRight) vline = QtGui.QFrame() vline.setFrameShape(QtGui.QFrame.VLine) vline.setFrameShadow(QtGui.QFrame.Sunken) child_layout.addWidget(vline) child_layout.addWidget(self.lcdScreen, alignment=QtCore.Qt.AlignLeft) my_layout.addLayout(child_layout) self.setLayout(my_layout)
def initializePage(self): degrees = self.wizard().degrees test = self.wizard().test name = self.field("name").title() school = self.field("school") grade = GRADES[int(self.field("grade")) - 1] number = self.field("number") sum_of_degrees = float(sum(i for i in degrees if i != -1)) if not number.startswith("+2"): number = "+2" + number self.nameL.setText(name) self.schoolL.setText(school) self.gradeL.setText(grade) self.numberL.setText(number) failed_at = [] left = [] for i, v in enumerate(degrees): if v == 0: failed_at.append(i) elif v == -1: left.append(i) student = dict( zip(headers, [ name, school, grade, number, sum_of_degrees, test.degree, left, failed_at, test.name, ])) questions_n = len(test.questions) left_n = len(left) failed_at_n = len(failed_at) self.grey.description.setText(self.grey.description.text().format( left_n / questions_n * 100)) self.red.description.setText(self.red.description.text().format( failed_at_n / questions_n * 100)) self.green.description.setText(self.green.description.text().format( (questions_n - (left_n + failed_at_n)) / questions_n * 100)) pieces = (left_n * test.degree / questions_n, failed_at_n * test.degree / questions_n, sum_of_degrees) set_angle = 0 total = sum(pieces) colors = [ QtGui.QColor(128, 128, 128), QtGui.QColor(255, 0, 0), QtGui.QColor(0, 128, 0) ] scene = QtGui.QGraphicsScene() for i, piece in enumerate(pieces): angle = round(float(piece * 5760) / total) ellipse = QtGui.QGraphicsEllipseItem(0, 0, 400, 400) ellipse.setPos(0, 0) ellipse.setStartAngle(set_angle) ellipse.setSpanAngle(angle) ellipse.setBrush(colors[i]) set_angle += angle scene.addItem(ellipse) view = QtGui.QGraphicsView(scene) view.setStyleSheet("background-color: transparent") self.lyt.insertWidget(0, view) test.student_degrees.append(StudentDegree(**student)) dump_tests(TESTS, res("data.enc", "state"), encrypt=True)
def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Tests Editor") self.just_deleted_a_test = False # used in navigation (not to test that there were errors in the deleted test) self.old_tests = None # type: Optional[List[Test]] open_action = QtGui.QAction("&Open", self) open_action.setShortcut("Ctrl+O") save_action = QtGui.QAction("&Save", self) save_action.setShortcut("Ctrl+S") quit_action = QtGui.QAction("&Quit", self) quit_action.setShortcut("Ctrl+Q") open_action.triggered.connect(self.open) save_action.triggered.connect(self.save) quit_action.triggered.connect(self.close) menu_bar = self.menuBar() file_menu = menu_bar.addMenu("&File") file_menu.addAction(open_action) file_menu.addAction(save_action) file_menu.addSeparator() file_menu.addAction(quit_action) sts_bar = QtGui.QStatusBar() sts_bar.setStyleSheet( "QStatusBar { background-color: #ccc; border-top: 1.5px solid grey } " ) self.sts_bar_lbl = QtGui.QLabel("Ready.") self.sts_bar_lbl.setOpenExternalLinks(False) self.sts_bar_lbl.linkActivated.connect( lambda index: self.tests_widget.currentWidget().setCurrentIndex( int(index))) sts_bar.addWidget(self.sts_bar_lbl) self.setStatusBar(sts_bar) self.resize(1000, 600) self.parent_window = None self._current_row = 0 frm = QtGui.QFrame() self.lyt = lyt = QtGui.QGridLayout() frm.setLayout(lyt) self.setCentralWidget(frm) lyt.setMargin(10) self.save_btn = save_btn = QtGui.QPushButton( QtGui.QIcon(res("save.png", "icon")), "Save") save_btn.clicked.connect(self.save) save_btn.setToolTip("Save Tests") filter_edit = QtGui.QLineEdit() filter_edit.setPlaceholderText("Search tests...") filter_edit.textChanged.connect(self.update_tests_list) self.tests_list = QtGui.QListWidget() def f1(e: QtGui.QContextMenuEvent): selected_item = self.tests_list.itemAt(e.pos()) if selected_item is None: return menu = QtGui.QMenu() delete = menu.addAction("Delete") delete.setIcon(QtGui.QIcon(res("halt.png", "icon"))) action = menu.exec_(QtGui.QCursor.pos()) if action == delete: self.delete_test(index=self.tests_list.row(selected_item)) def f2(e: QtGui.QKeyEvent): if e.key() == QtCore.Qt.Key_Delete: self.delete_test() self.tests_list.contextMenuEvent = f1 self.tests_list.keyPressEvent = f2 self.tests_list.setSelectionMode( QtGui.QAbstractItemView.SingleSelection) self.tests_list.currentItemChanged.connect(self.item_changed) left_side = QtGui.QVBoxLayout() left_side.addWidget(filter_edit) left_side.addWidget(self.tests_list) self.btn_add_test = btn_add_test = QtGui.QPushButton() btn_add_test.setToolTip("Add a new test") btn_add_test.setIcon(QtGui.QIcon(res("add.png", "icon"))) btn_add_test.clicked.connect(self.open_test_dialog) self.btn_remove_test = btn_remove_test = QtGui.QPushButton() btn_remove_test.setToolTip("Remove selected test") btn_remove_test.setIcon(QtGui.QIcon(res("minus.png", "icon"))) btn_remove_test.clicked.connect(self.delete_test) buttons = QtGui.QHBoxLayout() buttons.addWidget(btn_add_test, alignment=QtCore.Qt.AlignLeft) buttons.addStretch(1) buttons.addWidget(btn_remove_test, alignment=QtCore.Qt.AlignRight) left_side.addLayout(buttons) lyt.addLayout(left_side, 0, 0, 3, 1) lyt.addItem(QtGui.QSpacerItem(10, 1), 0, 2) self.tests_widget = QtGui.QStackedWidget() for test in TESTS: self.add_test(test) if TESTS: self.tests_list.setCurrentItem(self.tests_list.item(0)) lyt.addWidget(self.tests_widget, 0, 3, 2, 3) lyt.addWidget(save_btn, 2, 5) lyt.setColumnStretch(3, 1) lyt.setRowStretch(1, 1)
def __init__(self, question: Question = None, index: int = -1, parent: QtGui.QWidget = None) -> None: super().__init__(parent) self.want_focus_reasons = QuestionTab.PreserveFocusReason.NONE self.answers_lyt = QtGui.QVBoxLayout() self.s_question = question or Question("", None, [Answer("", False)]) self.answers = [] # type: List[AnswerWidget] self.deleted = False self.image = QuestionImage(self.s_question.pic and res(self.s_question.pic)) self.disabled_because = set() # type: Set[int] self.questionT = QtGui.QTextEdit() self.questionT.textChanged.connect(self.observe_name) self.answers_num = 0 self.valid_num = 0 self.index = index if not self.s_question.string: self.questionT.setPlainText("Enter question") self.questionT.selectAll() else: self.questionT.setPlainText(self.s_question.string) lyt = QtGui.QVBoxLayout() self.setLayout(lyt) wrap = QtGui.QWidget() wrap.setObjectName("wrap") wrap.setStyleSheet("wrap { background-color: transparent; }") wrap.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Maximum) wrap.setLayout(self.answers_lyt) self.scroll = answers_scroll = QtGui.QScrollArea() answers_scroll.setWidget(wrap) answers_scroll.setWidgetResizable(True) answers_scroll.setStyleSheet( "QScrollArea { border: none; background-color: transparent; }") image_and_answers = QtGui.QHBoxLayout() image_and_answers.addWidget(answers_scroll, 3) image_lyt = QtGui.QVBoxLayout() image_lyt.addWidget(self.image, 3) image_lyt.addWidget(QtGui.QLabel(), 2) image_and_answers.addLayout(image_lyt, 2) lyt.addWidget(self.questionT, 1) lyt.addWidget(QtGui.QLabel("<hr>")) lyt.addLayout(image_and_answers, 2) self.status = QtGui.QLabel() lyt.addWidget(self.status) self.add_answers(self.s_question.answers) self._check_reason(QuestionTab.PreserveFocusReason.EMPTY_QUESTION, not self.s_question.string) self._check_reason(QuestionTab.PreserveFocusReason.NUMBER_OF_ANSWERS, len(self.s_question.answers) < 2) self._check_reason( QuestionTab.PreserveFocusReason.NO_CORRECT_ANSWER, not any(ans.valid for ans in self.s_question.answers)) self._check_reason(QuestionTab.PreserveFocusReason.ALL_ANSWERS_CORRECT, all(ans.valid for ans in self.s_question.answers)) self._check_reason( QuestionTab.PreserveFocusReason.EMPTY_ANSWER, any(not ans.string for ans in self.s_question.answers))
from utils.helpers import res, _init from utils.parsers import parse_tests _init() TESTS = parse_tests(res("data.enc", "state"), encrypted=True)