def __init__(self): super().__init__(None, Qt.WindowFlags()) self.window().setWindowTitle(APP_NAME) self.setMinimumWidth(APP_MIN_WIDTH) self.setMinimumHeight(APP_MIN_HEIGHT) self.thread_pool = QThreadPool() self._initial_point = None self._drown_points = None self._canvas = Canvas( initial_point_handler=self._initial_point_handler) self._btn_draw = QPushButton(self.tr('Draw'), 90, 30, self._draw_points) self._btn_draw.setEnabled(False) self._btn_reset = QPushButton(self.tr('Reset'), 90, 30, self._reset_canvas) self._btn_reset.setEnabled(False) self._btn_save = QPushButton(self.tr('Save'), 90, 30, self._save_canvas) self._btn_save.setEnabled(False) self._points_count_line_edit = QLineEdit() self._segment_div_line_edit = QLineEdit() main_widget = self.init_main_widget() self.setCentralWidget(main_widget) # self.setup_navigation_menu() self.setFont(QFont('SansSerif', APP_FONT))
def test_set_color(canvas: Canvas): assert canvas.color == (255, 255, 255) canvas.set_brush(CircleShapeBrush()) canvas.set_color((100, 200, 100)) assert canvas.color == (100, 200, 100) assert canvas.brush.color == (100, 200, 100)
def canvas(qtbot) -> Canvas: controller = ControllerMockup() gui = MainWindow(controller) gui.show() qtbot.addWidget(gui) canvas = Canvas(controller) assert canvas.hasMouseTracking() is True return canvas
def __init__(self, controller): super().__init__() self._controller = controller # Initializing the whole UI self._ui = Ui_MainWindow() self._ui.setupUi(self) self.set_status() self.canvas = Canvas(controller) # Menu buttons self._ui.actionNew.triggered.connect(lambda: self._handle_action_new()) self._ui.actionSave.triggered.connect(lambda: self.save_dialog()) self._ui.actionLoad.triggered.connect(lambda: self.load_dialog()) self._ui.actionUndo.triggered.connect(lambda: self._controller.undo()) self._ui.actionRedo.triggered.connect(lambda: self._controller.redo()) self._ui.actionQuit.triggered.connect( lambda: self._handle_action_quit()) self.disable_undo() self.disable_redo() # Setting specific brush for canvas after clicking on one of the tool buttons self._ui.dotButton.clicked.connect( lambda: self._toggle_brush(DotShapeBrush())) self._ui.lineButton.clicked.connect( lambda: self._toggle_brush(LineShapeBrush())) self._ui.polylineButton.clicked.connect( lambda: self._toggle_brush(PolylineShapeBrush())) self._ui.rectagleButton.clicked.connect( lambda: self._toggle_brush(RectShapeBrush())) self._ui.circleButton.clicked.connect( lambda: self._toggle_brush(CircleShapeBrush())) self._ui.removeButton.clicked.connect( lambda: self._toggle_brush(RemoveShapeBrush())) self._ui.colorButton.clicked.connect(lambda: self._handle_color_pick()) self.brush_buttons = { DotShapeBrush(): self._ui.dotButton, LineShapeBrush(): self._ui.lineButton, PolylineShapeBrush(): self._ui.polylineButton, RectShapeBrush(): self._ui.rectagleButton, CircleShapeBrush(): self._ui.circleButton, RemoveShapeBrush(): self._ui.removeButton } self._ui.manualInput.returnPressed.connect( lambda: self._handle_user_input()) self._ui.canvasHolder.setWidget(self.canvas) self._ui.canvasHolder.setStyleSheet('background-color: white')
def test_mouse_move_event(canvas: Canvas): assert canvas.brush == MoveShapeBrush() assert canvas.cursor() == Qt.ArrowCursor canvas.mouseMoveEvent(EventMockup) assert (canvas._controller.command is None) canvas.set_brush(DotShapeBrush()) canvas.mouseMoveEvent(EventMockup) assert (canvas._controller.command == PrintDotCommand( canvas._controller, EventMockup.x(), EventMockup.y(), (255, 255, 255))) assert canvas.cursor() == Qt.CrossCursor
def test_mouse_press_event(canvas: Canvas): assert canvas.brush == MoveShapeBrush() assert canvas.cursor() == Qt.ArrowCursor canvas.mousePressEvent(EventMockup) assert canvas._controller.command is None canvas.set_brush(RectShapeBrush()) canvas.mousePressEvent(EventMockup) canvas.mousePressEvent(EventMockup) assert (canvas._controller.command == PrintRectCommand( receiver=canvas._controller, start_x=EventMockup.x(), start_y=EventMockup.y(), color=(255, 255, 255), rect_factory=PointsRectFactory, end_x=EventMockup.x(), end_y=EventMockup.y()))
class MainWindow(QMainWindow): def __init__(self): super().__init__(None, Qt.WindowFlags()) self.window().setWindowTitle(APP_NAME) self.setMinimumWidth(APP_MIN_WIDTH) self.setMinimumHeight(APP_MIN_HEIGHT) self.thread_pool = QThreadPool() self._initial_point = None self._drown_points = None self._canvas = Canvas( initial_point_handler=self._initial_point_handler) self._btn_draw = QPushButton(self.tr('Draw'), 90, 30, self._draw_points) self._btn_draw.setEnabled(False) self._btn_reset = QPushButton(self.tr('Reset'), 90, 30, self._reset_canvas) self._btn_reset.setEnabled(False) self._btn_save = QPushButton(self.tr('Save'), 90, 30, self._save_canvas) self._btn_save.setEnabled(False) self._points_count_line_edit = QLineEdit() self._segment_div_line_edit = QLineEdit() main_widget = self.init_main_widget() self.setCentralWidget(main_widget) # self.setup_navigation_menu() self.setFont(QFont('SansSerif', APP_FONT)) def _reset_canvas(self): self._initial_point = None self._drown_points = None self._canvas.clean() self._btn_draw.setEnabled(False) self._btn_reset.setEnabled(False) self._btn_save.setEnabled(False) def _save_canvas(self): # TODO: print('Canvas is saved') def _draw_points(self): worker = Worker(self._draw_points_fn) worker.signals.error.connect(self._popup_err) worker.signals.param_success.connect(self._draw_points_finished) self.thread_pool.start(worker) def _draw_points_finished(self, points): self._drown_points = points self._canvas.set_points(points) self._btn_save.setEnabled(True) def _draw_points_fn(self): triangle = Triangle(self._canvas.width(), self._canvas.height(), int(self._segment_div_line_edit.text())) return triangle.calc_points( (self._initial_point.x(), self._initial_point.y()), int(self._points_count_line_edit.text())) def _initial_point_handler(self, point): if self._initial_point is None: self._initial_point = point self._btn_draw.setEnabled(True) self._btn_reset.setEnabled(True) return point return None def _add_input_field(self, parent, title, default=None, regex=None): widget = QWidget(self, flags=self.windowFlags()) layout = QVBoxLayout(widget) layout.addWidget(QLabel(title), 0, Qt.AlignLeft) line_edit = QLineEdit() if default is not None: line_edit.setText(str(default)) line_edit.setAlignment(Qt.AlignHCenter) if regex is not None: line_edit.setValidator(QRegExpValidator(QRegExp(regex), line_edit)) line_edit.textChanged.connect(self._inputs_changed) layout.addWidget(line_edit, 0, Qt.AlignLeft) parent.addWidget(widget, 0, Qt.AlignHCenter) return line_edit def init_main_widget(self): layout = QVBoxLayout() # noinspection PyArgumentList layout.addWidget(self._canvas) container = QWidget(self, flags=self.windowFlags()) container.setStyleSheet('background-color: lightgray;') container.setFixedHeight(100) tools = QHBoxLayout(container) self._points_count_line_edit = self._add_input_field( tools, 'Points count:', 100000, '[1-9]+[0-9]*') self._segment_div_line_edit = self._add_input_field( tools, 'Segment divisor:', 2, '[1-9]+[0-9]*') tools.addWidget(self._btn_draw, 0, Qt.AlignHCenter) tools.addWidget(self._btn_reset, 0, Qt.AlignHCenter) tools.addWidget(self._btn_save, 0, Qt.AlignHCenter) # noinspection PyArgumentList layout.addWidget(container) widget = QWidget(flags=self.windowFlags()) widget.setLayout(layout) return widget @staticmethod def _empty(inp): return len(inp.text()) == 0 def _inputs_changed(self): if self._empty(self._segment_div_line_edit) or self._empty( self._points_count_line_edit) or self._initial_point is None: self._btn_draw.setEnabled(False) else: self._btn_draw.setEnabled(True) def _popup_err(self, err): err_msg = 'Input data error\nCheck inputs' if err is not None: err_msg = err[1] msg_box = QMessageBox() msg_box.warning(self, 'Input data error', err_msg, QMessageBox.Ok) self._btn_draw.setEnabled(True)
class MainWindow(QtWidgets.QMainWindow): def __init__(self, controller): super().__init__() self._controller = controller # Initializing the whole UI self._ui = Ui_MainWindow() self._ui.setupUi(self) self.set_status() self.canvas = Canvas(controller) # Menu buttons self._ui.actionNew.triggered.connect(lambda: self._handle_action_new()) self._ui.actionSave.triggered.connect(lambda: self.save_dialog()) self._ui.actionLoad.triggered.connect(lambda: self.load_dialog()) self._ui.actionUndo.triggered.connect(lambda: self._controller.undo()) self._ui.actionRedo.triggered.connect(lambda: self._controller.redo()) self._ui.actionQuit.triggered.connect( lambda: self._handle_action_quit()) self.disable_undo() self.disable_redo() # Setting specific brush for canvas after clicking on one of the tool buttons self._ui.dotButton.clicked.connect( lambda: self._toggle_brush(DotShapeBrush())) self._ui.lineButton.clicked.connect( lambda: self._toggle_brush(LineShapeBrush())) self._ui.polylineButton.clicked.connect( lambda: self._toggle_brush(PolylineShapeBrush())) self._ui.rectagleButton.clicked.connect( lambda: self._toggle_brush(RectShapeBrush())) self._ui.circleButton.clicked.connect( lambda: self._toggle_brush(CircleShapeBrush())) self._ui.removeButton.clicked.connect( lambda: self._toggle_brush(RemoveShapeBrush())) self._ui.colorButton.clicked.connect(lambda: self._handle_color_pick()) self.brush_buttons = { DotShapeBrush(): self._ui.dotButton, LineShapeBrush(): self._ui.lineButton, PolylineShapeBrush(): self._ui.polylineButton, RectShapeBrush(): self._ui.rectagleButton, CircleShapeBrush(): self._ui.circleButton, RemoveShapeBrush(): self._ui.removeButton } self._ui.manualInput.returnPressed.connect( lambda: self._handle_user_input()) self._ui.canvasHolder.setWidget(self.canvas) self._ui.canvasHolder.setStyleSheet('background-color: white') # ------------------------------------------------ Handlers ------------------------------------------------------- def _handle_action_new(self): command = ClearCommand(self._controller) self._controller.execute_command(command) def _handle_save_file(self): command = SaveCommand(self._controller) self._controller.execute_command(command) def _handle_load_file(self): command = LoadCommand(self._controller) self._controller.execute_command(command) def _toggle_brush(self, brush: Brush): if self.canvas.brush != MoveShapeBrush(): # Un-checking the previous brush button previous_brush_button = self.brush_buttons[self.canvas.brush] previous_brush_button.setChecked(False) if self.canvas.brush != brush: self.canvas.set_brush(brush) self.set_status(str(brush)) else: self.canvas.set_brush() self.set_status() def _handle_color_pick(self): # Color picker will popup and returns chosen color color = QColorDialog().getColor(QColor(*self.canvas.color)) if color.isValid(): self._ui.colorButton.setStyleSheet( f'background-color: {color.name()}') r, g, b, alpha = color.getRgb() self.canvas.set_color((r, g, b)) def _handle_user_input(self): command_text = self._ui.manualInput.text() self._ui.manualInput.setText('') if command_text != '' and not command_text.isspace(): self._controller.parse_command(command_text) def _handle_action_quit(self): command = QuitCommand(self._controller) self._controller.execute_command(command) # --------------------------------------------- Main window methods ----------------------------------------------- @staticmethod def clear_dialog() -> bool: res = ClearDialog() return res.accepted def set_status(self, message: str = str(MoveShapeBrush())): self.statusBar().showMessage(message) def save_dialog(self, path_to_file: str = None): # Save file dialog will open and returns tuple (name of the saved file, type) user = getpass.getuser() path = path_to_file or f'/home/{user}/untitled.txt' name, _ = QFileDialog().getSaveFileName(self, 'Save File', path) if name: self._controller.save(name) def load_dialog(self, path_to_file: str = None): # Load file dialog will open and returns tuple (name of the loaded file, type) user = getpass.getuser() path = path_to_file or f'/home/{user}/untitled.txt' name, _ = QFileDialog().getOpenFileName(self, 'Load File', path) if name: self._controller.load(name) def enable_undo(self): self._ui.actionUndo.setEnabled(True) def disable_undo(self): self._ui.actionUndo.setEnabled(False) def enable_redo(self): self._ui.actionRedo.setEnabled(True) def disable_redo(self): self._ui.actionRedo.setEnabled(False) def print_lines_to_history(self, lines: str): self._ui.history.append(lines) def delete_from_history(self, number_of_lines: int = 1): history = self._ui.history.toPlainText() history = history.split('\n') if number_of_lines > len(history): raise ValueError history = history[:(-number_of_lines)] history = '\n'.join(history) self._ui.history.setText(history) self._ui.history.moveCursor(QTextCursor.End) self._ui.history.ensureCursorVisible() def clear_history(self): self._ui.history.setText('')
def test_pain_event(canvas: Canvas): canvas.paintEvent(EventMockup) assert canvas._controller.all_shapes == 'printed all shapes'
def test_set_brush(canvas: Canvas): assert canvas.brush == MoveShapeBrush() assert canvas.cursor() == Qt.ArrowCursor canvas.set_brush(LineShapeBrush()) assert canvas.brush.color == (255, 255, 255) assert canvas.brush == LineShapeBrush() assert canvas.cursor() == Qt.CrossCursor canvas.set_color((10, 20, 30)) canvas.set_brush(RectShapeBrush()) assert canvas.brush.color == (10, 20, 30) assert canvas.brush == RectShapeBrush() assert canvas.cursor() == Qt.CrossCursor canvas.set_brush() assert canvas.brush == MoveShapeBrush() assert canvas.cursor() == Qt.ArrowCursor