def __init__(self): super().__init__() # Título da janela. self.setWindowTitle('QWidget.') # Ícone da janela principal icon = QIcon() icon.addPixmap(QPixmap('../../../images/icons/icon.png')) self.setWindowIcon(icon) # Tamanho inicial da janela. screen_size = app.desktop().geometry() # screen_size = app.primaryScreen().geometry() width = screen_size.width() height = screen_size.height() self.resize(width / 2, height / 2) # Tamanho mínimo da janela. self.setMinimumSize(width / 2, height / 2) # Tamanho maximo da janela. self.setMaximumSize(width - 200, height - 200) # Widgets hbox = QHBoxLayout() self.setLayout(hbox) list_widget = QListWidget() list_widget.setAcceptDrops(True) list_widget.setDragEnabled(True) hbox.addWidget(list_widget) list_widget_icon_mode = QListWidget() list_widget_icon_mode.setViewMode(QListWidget.IconMode) list_widget_icon_mode.setAcceptDrops(True) list_widget_icon_mode.setDragEnabled(True) hbox.addWidget(list_widget_icon_mode) for index, icon in enumerate(self.icons): widget_item = QListWidgetItem( QIcon.fromTheme(icon), f'Ícone {index}', ) list_widget.insertItem(index, widget_item)
class MyWidget(QWidget): def __init__(self): QWidget.__init__(self) self.myListWidget1 = QListWidget() self.myListWidget2 = QListWidget() self.myListWidget2.setViewMode(QListWidget.IconMode) self.myListWidget1.setAcceptDrops(True) self.myListWidget1.setDragEnabled(True) self.myListWidget2.setAcceptDrops(True) self.myListWidget2.setDragEnabled(True) self.setGeometry(300, 350, 500, 150) self.myLayout = QHBoxLayout() self.myLayout.addWidget(self.myListWidget1) self.myLayout.addWidget(self.myListWidget2) self.l1 = QListWidgetItem(QIcon('doc_saved.png'), "Angry Bird Blue") self.l2 = QListWidgetItem(QIcon('doc_saved.png'), "Angry Bird Red") self.l3 = QListWidgetItem(QIcon('doc_saved.png'), "Angry Bird Green") self.l4 = QListWidgetItem(QIcon('doc_saved.png'), "Angry Bird Black") self.l5 = QListWidgetItem(QIcon('doc_saved.png'), "Angry Bird White") self.myListWidget1.insertItem(1, self.l1) self.myListWidget1.insertItem(2, self.l2) self.myListWidget1.insertItem(3, self.l3) self.myListWidget1.insertItem(4, self.l4) self.myListWidget1.insertItem(5, self.l5) QListWidgetItem(QIcon('doc_write.png'), "Grey Pig", self.myListWidget2) QListWidgetItem(QIcon('doc_write.png'), "Brown Pig", self.myListWidget2) QListWidgetItem(QIcon('doc_write.png'), "Green Pig", self.myListWidget2) self.setWindowTitle('Drag and Drop Example') self.setLayout(self.myLayout)
class stackedExample(QWidget): def __init__(self): super(stackedExample, self).__init__() self.leftList = QListWidget() self.leftList.insertItem(0, 'Contact') self.leftList.insertItem(1, 'Personal') self.leftList.insertItem(2, 'Educational') self.stack_1 = QWidget() self.stack_2 = QWidget() self.stack_3 = QWidget() self.stack_1_UI() self.stack_2_UI() self.stack_3_UI() self.stack = QStackedWidget() self.stack.addWidget(self.stack_1) self.stack.addWidget(self.stack_2) self.stack.addWidget(self.stack_3) hbox = QHBoxLayout() hbox.addWidget(self.leftList) hbox.addWidget(self.stack) self.setLayout(hbox) self.leftList.currentRowChanged.connect(self.display) self.setGeometry(300, 50, 10, 10) self.setWindowTitle("Stack Widget Demo") self.show() def stack_1_UI(self): layout = QFormLayout() layout.addRow("Name", QLineEdit()) layout.addRow("Address", QLineEdit()) #self.setTabText(0,"Contact Details") self.stack_1.setLayout(layout) def stack_2_UI(self): layout = QFormLayout() sex = QHBoxLayout() sex.addWidget(QRadioButton("Male")) sex.addWidget(QRadioButton("Female")) layout.addRow(QLabel("Sex"), sex) layout.addRow("Date of Birth", QLineEdit()) self.stack_2.setLayout(layout) def stack_3_UI(self): layout = QHBoxLayout() layout.addWidget(QLabel("subjects")) layout.addWidget(QCheckBox("Physics")) layout.addWidget(QCheckBox("Maths")) self.stack_3.setLayout(layout) def display(self, i): self.stack.setCurrentIndex(i)
class Window(QMainWindow): def __init__(self): super(Window, self).__init__() self.lastProjectDirectory = None self.view = None self.items = dict() self.loadSettings() self.setWindowTitle("2D Tagger") self.createActions() self.createMenus() self.createFileList() self.createContainer() self.createStatusBar() def loadSettings(self): try: with io.open(Path(__file__).parent / 'app.json', 'r') as f: data = json.load(f) if 'lastProjectDirectory' in data: self.lastProjectDirectory = data['lastProjectDirectory'] except: pass def saveSettings(self): data = dict() data['lastProjectDirectory'] = self.lastProjectDirectory with io.open(Path(__file__).parent / 'app.json', 'w') as f: json.dump(data, f, indent=' ') def createActions(self): # root = QFileInfo(__file__).absolutePath() self.openAct = QAction( # QIcon(root + '/icons/open.png'), "&Open", self, shortcut=QKeySequence.Open, statusTip="Open project", triggered=self.openProject) self.closeAct = QAction( # QIcon(root + '/icons/close.png'), "&Close", self, shortcut=QKeySequence.Close, statusTip="Close project", triggered=self.closeProject, enabled=False) self.exitAct = QAction( # QIcon(root + '/icons/quit.png'), "&Quit", self, shortcut=QKeySequence.Quit, statusTip="Close the application", triggered=self.close) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) def createMenus(self): fileMenu = self.menuBar().addMenu("&File") fileMenu.addAction(self.openAct) fileMenu.addAction(self.closeAct) fileMenu.addSeparator() fileMenu.addAction(self.exitAct) self.menuBar().addSeparator() helpMenu = self.menuBar().addMenu("&Help") helpMenu.addAction(self.aboutAct) def createFileList(self): self.files = QListWidget() self.files.setSelectionMode(QAbstractItemView.SingleSelection) self.files.setSortingEnabled(False) self.files.itemSelectionChanged.connect(self.onSelect) self.files.itemDoubleClicked.connect(self.onToggle) self.files.setEnabled(False) dock = QDockWidget("Images", self) dock.setAllowedAreas(Qt.LeftDockWidgetArea) dock.setFixedWidth(320) dock.setFeatures(QDockWidget.NoDockWidgetFeatures) dock.setWidget(self.files) self.addDockWidget(Qt.LeftDockWidgetArea, dock) def createContainer(self): self.container = QWidget(self) self.container.setStyleSheet("View { background: black; }") self.container.setLayout(QVBoxLayout()) self.setCentralWidget(self.container) def createStatusBar(self): self.statusBar().showMessage("Initialized") def enableProjectActions(self, enabled): actions = [self.closeAct, self.files] for action in actions: action.setEnabled(enabled) def closeEvent(self, event): event.accept() def openProject(self, path=None): if not path: path = QFileDialog.getExistingDirectory( self, "Choose image directory", dir=self.lastProjectDirectory) if path: self.closeProject() self.view = View(self) self.view.previous.connect(self.onPrevious) self.view.next.connect(self.onNext) self.container.layout().addWidget(self.view) filename = Path(path) / "items.json" if filename.exists(): with io.open(filename, 'r') as f: self.items = json.load(f) else: self.items = dict() for filename in find_images(Path(path)): if filename in self.items: continue self.items[filename] = dict({"active": True}) self.refreshItems() self.files.setItemSelected(self.files.item(0), True) self.enableProjectActions(True) self.lastProjectDirectory = path self.saveProject() self.saveSettings() def saveProject(self): if not self.view: return with io.open(Path(self.lastProjectDirectory) / "items.json", 'w') as f: json.dump(self.items, f, indent=' ') def closeProject(self): self.enableProjectActions(False) if self.view: self.container.layout().removeWidget(self.view) self.view.close() self.view = None self.items = dict() self.refreshItems() def selection(self): selection = self.files.selectedItems() if len(selection) > 0: return selection[0].text() return None def refreshItems(self): filenames = sorted(self.items.keys()) for i in range(len(filenames)): filename = filenames[i] item = self.items[filename] file = self.files.item(i) if not file: file = QListWidgetItem(filenames[i]) self.files.insertItem(i, file) if item['active']: file.setTextColor(QColor.fromRgbF(0.0, 0.5, 0.0)) else: file.setTextColor(QColor.fromRgbF(0.5, 0.0, 0.0)) while self.files.count() > len(filenames): self.files.takeItem(len(filenames)) @Slot() def onToggle(self, item): self.items[ item.text()]['active'] = not self.items[item.text()]['active'] self.refreshItems() self.saveProject() @Slot() def onSelect(self): selection = self.selection() if self.view: self.view.save() if selection: self.view.load(Path(self.lastProjectDirectory) / selection) @Slot() def onPrevious(self): if self.files.count() == 0: return index = 0 selection = self.selection() if selection: for i in range(self.files.count()): item = self.files.item(i) if item.text() == selection: index = i - 1 break if index < 0: index = self.files.count() - 1 self.files.setItemSelected(self.files.item(index), True) @Slot() def onNext(self): if self.files.count() == 0: return index = 0 selection = self.selection() if selection: for i in range(self.files.count()): item = self.files.item(i) if item.text() == selection: index = i + 1 break if index >= self.files.count(): index = 0 self.files.setItemSelected(self.files.item(index), True) @Slot(str) def showMessage(self, message): self.statusBar().showMessage(message) def about(self): QMessageBox.about( self, "About Application", "The <b>2D Tagger</b> can load images, manually tag/label images and export result." )
class _ViewSwitcherWidget(QWidget): """Object that handles displaying of Enigma model wikis and images""" def __init__(self, master, regen_plug): """ :param master: Qt parent object :param regen_plug: {callable} Regenerates settings view to new contents """ super().__init__(master) layout = QHBoxLayout() self.setLayout(layout) # LIST OF AVAILABLE MODELS ============================================= self.model_list = QListWidget() self.model_list.setMaximumWidth(150) self.model_list.setMinimumWidth(150) self.model_list.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.model_list.currentRowChanged.connect(self.select_model) self.regen_plug = regen_plug # STACKED MODEL VIEWS ================================================== self.stacked_wikis = QStackedWidget() for i, model in enumerate(VIEW_DATA): self.model_list.insertItem(i, model) description = VIEW_DATA[model]["description"] self.stacked_wikis.addWidget( _EnigmaViewWidget(self, model, description)) self.total_models = len(VIEW_DATA) layout.addWidget(self.model_list) layout.addWidget(self.stacked_wikis) # Sets initially viewed self.currently_selected = None def select_model(self, i): """Called when the "Use this model" button is pressed :param i: {str} Newly selected model index """ logging.info('Changing settings view to model "%s"' % list(VIEW_DATA.keys())[i]) model = list(VIEW_DATA.keys())[i] self.regen_plug(model) self.stacked_wikis.setCurrentIndex(i) self.model_list.blockSignals(True) self.model_list.setCurrentRow(i) self.model_list.blockSignals(False) self.currently_selected = model def highlight(self, i): """Highlights an option with Blue color, indicating that it is currently selected in EnigmaAPI :param i: {int} Index from list options """ for index in range(self.total_models): item = self.model_list.item(index) item.setForeground(Qt.black) item.setToolTip(None) selected = self.model_list.item(i) selected.setBackground(Qt.gray) # .setForeground(Qt.blue) selected.setToolTip("Currently used Enigma model")
class ImageToPdfWidget(QWidget): def __init__(self, status_link): super(ImageToPdfWidget, self).__init__() LABEL_WIDTH = 80 self.last_selected_items = [] self.options_mode = 0 self.update_status_combobox = False layout = QHBoxLayout() self.status_bar = status_link self.list_view = QListWidget() self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_view.setAlternatingRowColors(True) self.list_view.itemClicked.connect(self.click_item_signal) self.list_view.itemEntered.connect(self.click_item_signal) self.list_view.itemSelectionChanged.connect( self.change_selection_signal) controls_layout = QVBoxLayout() controls_layout.setAlignment(Qt.AlignTop) select_zone = SelectWidget(self.click_move_up, self.click_move_down, self.click_invert, self.click_delete) # options zone ------------------------------------- options_zone = QGroupBox("Options") self.options_zone_layout = QVBoxLayout() self.options_mode_combobox = QComboBox() self._add_items_to_mode_combobox(self.options_mode_combobox) options_mode_label = QLabel("Mode") options_mode_label.setMaximumWidth(LABEL_WIDTH) options_mode_layout = QHBoxLayout() options_mode_layout.addWidget(options_mode_label) options_mode_layout.addWidget(self.options_mode_combobox) self.options_zone_layout.addLayout(options_mode_layout) self.option_source_widget = OptionsFromSourceWidget( label_width=LABEL_WIDTH, status_bar=self.status_bar) self.options_a_widget = OptionsAWidget(label_width=LABEL_WIDTH, status_bar=self.status_bar) self.options_mode_combobox.currentIndexChanged.connect( self.change_options_mode_signal) self.change_options_mode_signal(self.options_mode) options_zone.setLayout(self.options_zone_layout) # Add files button and final structures --------------------------- add_file_button = QPushButton("Add Files") add_file_button.clicked.connect(self.click_add_files) controls_layout.addWidget(select_zone) controls_layout.addWidget(options_zone) controls_layout.addWidget(add_file_button) # image preview --------------------------------------------------- image_prev_layout = QVBoxLayout() image_prev_layout.setContentsMargins(0, 0, 4, 0) self.IMG_PREVIEW_WIDTH = 256 self.img_label = QLabel() self.img_label.setAlignment(Qt.AlignCenter) self.select_text = "Click item to preview" self.last_created_pix_path = "" self.img_label.setText(self.select_text) image_prev_layout.addWidget(self.img_label) # slider for the preview scale self.img_scale_slider = QSlider() self.img_scale_slider.setMinimum(6) self.img_scale_slider.setMaximum(2048) self.img_scale_slider.setValue(self.IMG_PREVIEW_WIDTH) self.img_scale_slider.setOrientation(Qt.Horizontal) self.img_scale_slider.valueChanged.connect( self.change_scale_slider_signal) image_prev_layout.addWidget(self.img_scale_slider) self._update_preview() layout.addLayout(image_prev_layout) layout.addWidget(self.list_view) layout.addLayout(controls_layout) self.setLayout(layout) self.update_status_combobox = True def _pillow_to_pixmap(self, img): if img.mode == "RGB": r, g, b = img.split() img = Image.merge("RGB", (b, g, r)) elif img.mode == "RGBA": r, g, b, a = img.split() img = Image.merge("RGBA", (b, g, r, a)) elif img.mode == "L": img = img.convert("RGBA") img2 = img.convert("RGBA") data = img2.tobytes("raw", "RGBA") qim = QImage(data, img.size[0], img.size[1], QImage.Format_ARGB32) pixmap = QPixmap.fromImage(qim) return pixmap def _update_preview(self): self.img_label.setMinimumWidth(self.IMG_PREVIEW_WIDTH) self.img_label.setMaximumWidth( max(self.IMG_PREVIEW_WIDTH, self.img_scale_slider.width())) if len(self.last_created_pix_path) > 0: img = Image.open(self.last_created_pix_path) img_pix = self._pillow_to_pixmap(img) img_pix = img_pix.scaled( QSize(self.IMG_PREVIEW_WIDTH, self.IMG_PREVIEW_WIDTH), Qt.KeepAspectRatio) self.img_label.setPixmap(img_pix) def _set_preview(self, img_path): if img_path is None: self.last_created_pix_path = "" self.img_label.setText(self.select_text) else: if img_path != self.last_created_pix_path: self.last_created_pix_path = img_path self._update_preview() def _add_items_to_mode_combobox(self, combobox): combobox.addItem("From Source") combobox.addItem("A4") # combobox.addItem("A5") # combobox.addItem("A6") # combobox.addItem("Letter") def _get_filtered_string(self, string): to_return_array = [] for s in string: if s.isdigit(): to_return_array.append(s) return "".join(to_return_array) def get_images_to_save(self): path_array = [] for i in range(self.list_view.count()): path_array.append(self.list_view.item(i).get_data()) return path_array def get_image_parameters(self): # return as dictionary if self.options_mode == 0: return { "mode": 0, "pixels": self.option_source_widget.get_pixel_value(), "margin": self.option_source_widget.get_margin_value(), "background": self.option_source_widget.get_background_value() } else: return { "mode": self.options_mode, "align": self.options_a_widget.get_align_value(), "margin": self.options_a_widget.get_margin_value(), "background": self.options_a_widget.get_background_value() } def add_items(self, array): added_names = [] for a in array: new_name = os.path.basename(a) new_item = ImageListItem(new_name, a) added_names.append(new_name) self.list_view.addItem(new_item) self.status_bar.showMessage("Add items: " + ", ".join(added_names)) def change_scale_slider_signal(self, value): self.IMG_PREVIEW_WIDTH = value self._update_preview() self.status_bar.showMessage("Set preview scale to " + str(value)) def click_item_signal(self, item): pass # self._set_preview(item.get_data()) # self.status_bar.showMessage("Select " + str(item.text())) def _get_first_new_index(self, current, last): for v in current: if v not in last: return v return current[0] def change_selection_signal(self): if len(self.list_view.selectedItems()) == 0: self._set_preview(None) # nothing selected else: selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in self.list_view.selectedItems() ] item = self.list_view.item( self._get_first_new_index(selected_indexes, self.last_selected_items)) self._set_preview(item.get_data()) self.status_bar.showMessage("Select " + str(item.text())) self.last_selected_items = selected_indexes def change_options_mode_signal(self, index): self.options_mode = index if self.options_mode == 0: self.options_zone_layout.removeWidget(self.options_a_widget) self.options_a_widget.setParent(None) self.options_zone_layout.addWidget(self.option_source_widget) else: self.options_zone_layout.removeWidget(self.option_source_widget) self.option_source_widget.setParent(None) self.options_zone_layout.addWidget(self.options_a_widget) if self.update_status_combobox: self.status_bar.showMessage( "Set combine mode to \"" + self.options_mode_combobox.itemText(index) + "\"") def resizeEvent(self, size): # self._update_preview() pass def click_move_up(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() if len(selected_indexes) > 0 and selected_indexes[0] > 0: for index in selected_indexes: prev_item = self.list_view.takeItem(index - 1) self.list_view.insertItem(index, prev_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_move_down(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() sel_count = len(selected_indexes) if len(selected_indexes) > 0 and selected_indexes[ sel_count - 1] < self.list_view.count() - 1: for i_index in range(sel_count): next_item = self.list_view.takeItem( selected_indexes[sel_count - i_index - 1] + 1) self.list_view.insertItem( selected_indexes[sel_count - i_index - 1], next_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_invert(self): selected = self.list_view.selectedItems() selected_indexes = [] for sel in selected: selected_indexes.append(self.list_view.indexFromItem(sel).row()) total_indexes = [i for i in range(self.list_view.count())] new_indexes = [] for i in total_indexes: if i not in selected_indexes: new_indexes.append(i) self.list_view.clearSelection() for i in new_indexes: self.list_view.item(i).setSelected(True) self.status_bar.showMessage("Invert selection: " + str(new_indexes)) def click_delete(self): selected = self.list_view.selectedItems() delete_names = [] for s in selected: s_index = self.list_view.indexFromItem(s).row() del_item = self.list_view.takeItem(s_index) delete_names.append(del_item.text()) if len(delete_names) == 0: self.status_bar.showMessage("Nothing to delete") else: self.status_bar.showMessage("Delete items: " + ", ".join(delete_names)) def click_add_files(self): files_dialog = QFileDialog() files_dialog.setNameFilter("Images (*.jpg *.jpeg *.bmp *.png *.tiff)") files_dialog.setFileMode(QFileDialog.ExistingFiles) if files_dialog.exec_(): files = files_dialog.selectedFiles() self.add_items(files)
class CreateSequenceWindow(QDialog): """ Window for creating a new sequence """ def __init__(self, motors={}, listOfSequenceHandler=None, sequence=None, modifySequence=False): """ Initializtion of the window for creating a new sequence :param motors: The dictionary of all the motors :param listOfSequenceHandler: The handler of the list of sequence """ QDialog.__init__(self) # Set the window icon appIcon = QIcon(icon) self.setWindowIcon(appIcon) ## Flag if the sequence is a modified one or a new one self.__modifySequence = modifySequence ## The handler of the list of sequence self.__listOfSequenceHandler = listOfSequenceHandler ## The dictionary of all the motors self.__motors = motors ## The new sequence self.__sequence = sequence ## A dictionary of the positions of the new sequence self.__wantedPositions = {} ## The layout of the create sequence window self.__layout = QVBoxLayout(self) ## The widget for the name of the sequenc self.nameEntry = QLineEdit() self.nameEntry.setText(self.__sequence.getName()) ## The label for the widget in which the name of the sequence is written self.__nameLabel = QLabel("Sequence Name") ## The list of the different moves that forms the sequence self.__listOfMoveLabels = QListWidget() moveNumber = 1 for move in self.__sequence.getMoves(): # Set text for the move label labelText = "move " + str(moveNumber) + ": " moveNumber += 1 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " + \ str(move.getMotorPosition(self.__motors[motor].getName())) + ", " label = moveLabel(move, labelText, self.__motors) # insert label to the head of the list self.__listOfMoveLabels.insertItem(0, label) # Put the sliders of the create sequence window in a list ## List of sliders in the create sequence window self.listOfSliders = [] dictOfSlider = dict() for motor in self.__motors: dictOfSlider[motor] = QSlider(Qt.Horizontal) dictOfSlider[motor].setMaximum(4095) dictOfSlider[motor].setValue( self.__motors[motor].getCurrentPosition()) dictOfSlider[motor].sliderMoved.connect( self.__motors[motor].setGoalPosition) self.listOfSliders.append(dictOfSlider[motor]) ## Message to make the user put a name to the sequence self.__noNameMessage = QMessageBox() self.__noNameMessage.setIcon(QMessageBox.Warning) self.__noNameMessage.setWindowIcon(appIcon) self.__noNameMessage.setText( "Please name your sequence before saving it") self.__noNameMessage.setStandardButtons(QMessageBox.Ok) # Renable the create sequence window and closes the message self.__noNameMessage.accepted.connect(self.enableWindow) ## Warning message to make sure the user doen't want to save the sequence self.__warningMessage = QMessageBox() self.__warningMessage.setIcon(QMessageBox.Warning) self.__warningMessage.setWindowIcon(appIcon) self.__warningMessage.setText( "Are you sure you want to close this window? Your sequence will not be saved" ) self.__warningMessage.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) # Close the create sequence window and the message self.__warningMessage.accepted.connect(self.reject) # Renable the create sequence window and closes the message self.__warningMessage.rejected.connect(self.enableWindow) # Set the text for the labels ## Labels for the motors in the UI self.__motorLabels = [] for motorNumber in range(0, len(motors)): self.__motorLabels.append( QLabel("Motor " + str(motorNumber + 1) + " position")) ## Button to add a move to the sequence and procede to the next move self.nextMoveButton = QPushButton("Save Move") ## Buttons to accept or cancel the creation of a sequence self.buttonBox = QDialogButtonBox() self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) # If ok pressed add the sequence to the list self.buttonBox.accepted.connect( lambda: self.addSequenceToList(self.__modifySequence)) # If cancel pressed close the create sequence window self.buttonBox.rejected.connect(self.__warningMessage.exec) # Renable the main window when the create sequence closes self.rejected.connect(self.__listOfSequenceHandler.enableUi) self.accepted.connect(self.__listOfSequenceHandler.enableUi) self.nextMoveButton.clicked.connect(self.addMovetoSequence) self.__listOfMoveLabels.itemDoubleClicked.connect( self.moveDoubleClicked) # Build the vertical layout with the different widgets self.__layout.addWidget(self.__nameLabel) self.__layout.addWidget(self.nameEntry) self.__layout.addWidget(self.__listOfMoveLabels) for motorNumber in range(len(self.__motors)): self.__layout.addWidget(self.__motorLabels[motorNumber]) self.__layout.addWidget(self.listOfSliders[motorNumber]) self.__layout.addWidget(self.nextMoveButton) self.__layout.addWidget(self.buttonBox) # Connect the qwidgetlist to the custom right click menu self.__listOfMoveLabels.setContextMenuPolicy(Qt.CustomContextMenu) self.__listOfMoveLabels.customContextMenuRequested.connect( self.rightClickMenu) def setName(self, name): """ Sets the name of the sequence with the user input :param name: The name of the sequence :return: No return """ self.__sequence.setName(name) def getSequence(self): """ Accessor of the sequence (for tests) :return: the sequence """ return self.__sequence def getListofMoveLabels(self): """ Accessor of the list of move labels (for tests) :return: the list of move labels """ return self.__listOfMoveLabels def addSequenceToList(self, modifySequence=False): """ Add the sequence to the list of sequence :param modifySequence: bool, if true there's a selected sequence that needs to be modified if false it's a new sequence :return: No return """ # TODO: look to move this method to the list of sequence handler # TODO: don't let the user enter a sequence that has the same name as an old one self.setName(self.nameEntry.text()) if self.__sequence.getName() != "": # Load previously saved sequences try: with open('SaveSequence.json') as save: savedListOfSequences = json.load(save) except FileNotFoundError: savedListOfSequences = [] if modifySequence: # Get the item that needs to be modified # selectedSequence = self.__listOfSequenceHandler.getSelectedItems() # Find the selected sequence in the list of saved ones for sequence in savedListOfSequences: if self.__sequence.getName() in sequence: indexOfTheSequence = savedListOfSequences.index( sequence) # remove the unmodified sequence to insert the modified sequence savedListOfSequences.remove(sequence) self.__listOfSequenceHandler.addItem(self.__sequence) # Make the sequence json seriable newSequence = dict() newSequence[self.__sequence.getName()] = [] for moveNumber in range(len( self.__sequence.getMoves())): newSequence[self.__sequence.getName()].append( self.__sequence.getMoves() [moveNumber].getMovePositions()) # Append new sequence to the old ones savedListOfSequences.insert(indexOfTheSequence, newSequence) # Write the sequences to the file with open('SaveSequence.json', 'w') as outfile: json.dump(savedListOfSequences, outfile) self.accept() else: self.__listOfSequenceHandler.addItem(self.__sequence) # Make the sequence json seriable newSequence = dict() newSequence[self.__sequence.getName()] = [] for moveNumber in range(len(self.__sequence.getMoves())): newSequence[self.__sequence.getName()].append( self.__sequence.getMoves() [moveNumber].getMovePositions()) # Append new sequence to the old ones savedListOfSequences.append(newSequence) # Write the sequences to the file with open('SaveSequence.json', 'w') as outfile: json.dump(savedListOfSequences, outfile) self.accept() else: self.setEnabled(False) self.__noNameMessage.exec_() def addMovetoSequence(self): """ Add the last move to the sequence :return: No return """ move = None labelToModify = None # Check if there's a move in modifying state for row in range(self.__listOfMoveLabels.count()): if not self.__listOfMoveLabels.item(row).getMove().isNew: move = self.__listOfMoveLabels.item(row).getMove() labelToModify = self.__listOfMoveLabels.item(row) break # verify if the move is a new one if move is None: # Create the new move and set his positions move = Move(self.__motors) i = 0 for motorName in self.__motors: move.setMotorPosition(motorName, self.listOfSliders[i].value()) i += 1 self.__sequence.addMove(move) # Set text for the move label labelText = "move " + str( self.__sequence.getNumberofMoves()) + ": " i = 0 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " +\ str(self.listOfSliders[i].value()) + ", " i += 1 label = moveLabel(move, labelText, self.__motors) # insert label to the head of the list self.__listOfMoveLabels.insertItem(0, label) else: # modify the move i = 0 for motorName in self.__motors: move.setMotorPosition(motorName, self.listOfSliders[i].value()) i += 1 # modify the label of the move textToEdit = labelToModify.text() listOfTextToEdit = textToEdit.split(' ') labelText = listOfTextToEdit[0] + " " + listOfTextToEdit[1] + " " i = 0 for motor in self.__motors: labelText += self.__motors[motor].getName() + " " + \ str(self.listOfSliders[i].value()) + ", " i += 1 labelToModify.setText(labelText) labelToModify.setSelected(False) labelToModify.setBackground(Qt.white) # reset the state of the move move.isNew = True # Access the move positions when double clicked on def moveDoubleClicked(self, moveItem): """ Called when a move in the sequence is double clicked :param moveItem: the move that was double clicked :return: No return """ moveItem.goToMoveOfTheLabel() self.updateSlidersPositions() def updateSlidersPositions(self): counterMotors = 0 for motor in self.__motors: self.listOfSliders[counterMotors].setValue( self.__motors[motor].getGoalPosition()) counterMotors += 1 def enableWindow(self): """ Enable the create sequence window :return: """ self.setEnabled(True) def rightClickMenu(self, event): """ The right click menu of the move list :param event: The event (here right click) that makes the menu come up :return: No return """ menu = QMenu() # Add a button in the menu that when clicked, it puts a move in modifying state menu.addAction( "Modify Move", lambda: self.modifyMove(self.__listOfMoveLabels. selectedItems()[0])) # Add a button in the menu that when clicked, it deletes a move in the list menu.addAction( "Delete Move", lambda: self.deleteMove(self.__listOfMoveLabels. selectedItems()[0])) menu.exec_(self.__listOfMoveLabels.mapToGlobal(event)) def deleteMove(self, label): """ Delete a move and its label of the sequence :param label: label of the move :return: No return """ # remove the label from the list self.__listOfMoveLabels.takeItem(self.__listOfMoveLabels.row(label)) # remove the move from the sequence self.__sequence.deleteMove(label.getMove()) # rename the labels in the list of moves for index in range(self.__sequence.getNumberofMoves() - 1, -1, -1): labelToModify = self.__listOfMoveLabels.item(index) textToEdit = labelToModify.text() listOfTextToEdit = textToEdit.split(' ') listOfTextToEdit[1] = str(self.__sequence.getNumberofMoves() - index) + ':' textToEdit = ' '.join(listOfTextToEdit) self.__listOfMoveLabels.item(index).setText(textToEdit) def modifyMove(self, label): """ Put a move to a modified state :param label: label of the move :return: No return """ # Check if there's a move in modifying state for row in range(self.__listOfMoveLabels.count()): if not self.__listOfMoveLabels.item(row).getMove().isNew: self.__listOfMoveLabels.item(row).getMove().isNew = True self.__listOfMoveLabels.item(row).setBackground( QBrush(Qt.white)) moveToModify = label.getMove() moveToModify.isNew = False label.setBackground(QBrush(Qt.darkCyan)) label.goToMoveOfTheLabel() self.updateSlidersPositions()
class Form(QWidget): """""" def __init__( self, parent: QApplication = None, *, title: str = "wooo", width: int = 400, height: int = 600, ) -> None: """Constructor""" super().__init__(parent) mixer.init() # initializethe pygame mixer self.assets_path: str = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'assets') if parent is not None: self.parent = parent """ self.parent.iconbitmap() """ horiz_pos = 100 # from left of screen vertic_pos = 200 # from top of screen self.height = height self.width = width self.title = title self.setGeometry(horiz_pos, vertic_pos, self.width, self.height) # QtCore.QRect(x, y, w, h) self.setWindowTitle(self.title) self.setWindowIcon(QtGui.QIcon(self.assets_path + '/icons/melody.ico')) self.init_vol: int = 70 self.paused: bool = False self.muted: bool = False self.playing: bool = False self.current_song: Opt[str] = None self.selected_song_num: Opt[int] = None self.playlist: List[str] = [] self._init_ui() self.show() def _init_ui(self) -> None: self.layout = QVBoxLayout() self._menubar() self._create_rightframe() self._create_middleframe() self._create_leftframe() self._create_bottomframe() self.edit = QLineEdit("Write my name here") self.layout.addWidget(self.edit) self.greet_button = QPushButton("Show Greetings") self.greet_button.clicked.connect(self.greetings) self.layout.addWidget(self.greet_button) self._statusbar() self.setLayout(self.layout) def _menubar(self) -> None: menubar = QMenuBar() self.layout.addWidget(menubar) fileMenu = menubar.addMenu('File') fileMenu.addAction('Open', self.browse_file) fileMenu.addSeparator() fileMenu.addAction('Exit', self.close) helpMenu = menubar.addMenu('Help') helpMenu.addSeparator() helpMenu.addAction('About Us', self.about_us) # toolbar = self.addToolBar('Exit') # toolbar.addAction(self.play_music) def _statusbar(self) -> None: self.statusbar = QStatusBar() self.layout.addWidget(self.statusbar) self.statusbar.showMessage('Welcome', timeout=10_000) # status_bar = statusbar_parent.addPermanentWidget(statusbar_parent, stretch=True) def _create_rightframe(self) -> None: self.rightframe = QVBoxLayout() self.layout.addLayout(self.rightframe) self.filelabel = QLabel(text='Lets make some noise!') self.rightframe.addWidget(self.filelabel) self.lengthlabel = QLabel(text='Total Length : --:--') self.rightframe.addWidget(self.lengthlabel) self.currenttimelabel = QLabel(text='Current Time : --:--') self.rightframe.addWidget(self.currenttimelabel) def _create_leftframe(self) -> None: self.leftframe = QVBoxLayout() self.layout.addLayout(self.leftframe) self.playlistbox = QListWidget(self) self.playlistbox.setToolTip('''PlayListBox: Select song from list to play. Use browse or delete buttons to change playlist''' ) self.leftframe.addWidget(self.playlistbox) self.browse_button = QPushButton("Browse") self.browse_button.clicked.connect(self.browse_file) self.leftframe.addWidget(self.browse_button) self.delete_button = QPushButton("Delete") self.delete_button.clicked.connect(self.del_song) self.leftframe.addWidget(self.delete_button) def _create_middleframe(self) -> None: self.middleframe = QVBoxLayout() self.layout.addLayout(self.middleframe) self.play_button = QPushButton("Play") self.play_button.clicked.connect(self.play_music) play_icon = QtGui.QIcon( QtGui.QPixmap(self.assets_path + '/icons/play.png')) # play_icon.addPixmap(QtGui.QPixmap(self.assets_path + '/icons/play.png')) self.play_button.setIcon(play_icon) # self.play_button.setIconSize(QtCore.QSize(100, 100)) self.middleframe.addWidget(self.play_button) self.stop_button = QPushButton("Stop") self.stop_button.clicked.connect(self.stop_music) stop_icon = QtGui.QIcon( QtGui.QPixmap(self.assets_path + '/icons/stop.png')) self.stop_button.setIcon(stop_icon) # self.stop_button.setIconSize(QtCore.QSize(100, 100)) self.middleframe.addWidget(self.stop_button) self.pause_button = QPushButton("Pause") self.pause_button.clicked.connect(self.pause_music) pause_icon = QtGui.QIcon( QtGui.QPixmap(self.assets_path + '/icons/pause.png')) self.pause_button.setIcon(pause_icon) # self.pause_button.setIconSize(QtCore.QSize(100, 100)) self.middleframe.addWidget(self.pause_button) def _create_bottomframe(self) -> None: self.bottomframe = QVBoxLayout() self.layout.addLayout(self.bottomframe) self.volume_button = QPushButton("Mute") self.mute_icon = QtGui.QIcon( QtGui.QPixmap(self.assets_path + '/icons/mute.png')) self.volume_icon = QtGui.QIcon( QtGui.QPixmap(self.assets_path + '/icons/volume.png')) self.volume_button.setIcon(self.volume_icon) # self.volume_button.setIconSize(QtCore.QSize(100, 100)) self.volume_button.clicked.connect(self.mute_music) self.bottomframe.addWidget(self.volume_button) self.rewind_button = QPushButton("Rewind") rewind_icon = QtGui.QIcon( QtGui.QPixmap(self.assets_path + '/icons/rewind.png')) self.rewind_button.setIcon(rewind_icon) # self.volume_button.setIconSize(QtCore.QSize(100, 100)) self.play_button.clicked.connect(self.rewind_music) self.bottomframe.addWidget(self.rewind_button) self.vol_scale = QSlider(QtCore.Qt.Horizontal) self.vol_scale.setMinimum(0) self.vol_scale.setMaximum(100) # self.vol_scale.setTickPosition(QSlider.TicksBelow) # self.vol_scale.setTickInterval(5) self.vol_scale.setValue(self.init_vol) self.vol_scale.valueChanged.connect(self.set_vol) self.bottomframe.addWidget(self.vol_scale) mixer.music.set_volume(self.vol_scale.value()) # exitAction = QtGui.QAction('Exit', self) # exitAction.setShortcut('Ctrl+Q') # exitAction.setStatusTip('Exit application') # exitAction.triggered.connect(self.close) def set_vol(self) -> None: self.vol_from_slider: int = self.vol_scale.value() volume_percent: float = self.vol_from_slider / 100 mixer.music.set_volume(volume_percent) # from 0 to 1 def mute_music(self) -> None: if self.muted: # Unmute the music mixer.music.set_volume(self.vol_pre_mute / 100) self.volume_button.setIcon(self.volume_icon) self.vol_scale.setValue( self.vol_pre_mute) # (self.vol_from_slider) self.muted = False else: # mute the music self.vol_pre_mute: int = self.vol_scale.value() mixer.music.set_volume(0) self.volume_button.setIcon(self.mute_icon) self.vol_scale.setValue(0) self.muted = True def greetings(self) -> None: text = self.edit.text() print('Contents of QLineEdit widget: {}'.format(text)) self.statusbar.showMessage(text, timeout=2_000) def about_us(self) -> None: text = self.edit.text() print('Contents of QLineEdit widget: {}'.format(text)) def browse_file(self) -> None: get_filename_path: Tuple[str, str] = QFileDialog.getOpenFileName( self, # if cancelled, returns ("", "") "Open Sound File", self.assets_path, "Sound Files (*.wav *.mp3 *.ogg)") print(get_filename_path) filename_path = get_filename_path[0] if filename_path: self.add_to_playlist(filename_path) mixer.music.queue(filename_path) def add_to_playlist(self, filepath: str) -> None: filename = os.path.basename(filepath) index = 0 # print(self.playlist) # QListWidgetItem(self.playlistbox).setText(filename) # last_added = self.playlistbox.insertItem(index, filename) # .addItems([filenames]) self.playlist.insert(index, filepath) index += 1 def del_song(self) -> None: self.get_selected_song_num() # update self.selected_song_num if self.selected_song_num is not None: # if a song is selected print(self.selected_song_num) if self.playlist[ self. selected_song_num] == self.current_song: # if song is currently playing self.stop_music() # stop it self.playlistbox.takeItem( self.selected_song_num ) # remove the song from the box, note returns the song object self.playlist.pop(self.selected_song_num) # and playlist # self.selected_song_num remains same, so will play/del next song? self.reset_song() self.statusbar.showMessage("Song removed from playlist", timeout=1_000) self.selected_song_num = None # reset self.selected_song_num""" def get_selected_song_num(self) -> None: if self.playlistbox.count() > 0: selected_song_from_box = self.playlistbox.currentItem( ) # get current item if selected_song_from_box: self.selected_song: str = selected_song_from_box.text( ) # get items text self.selected_song_num = self.playlistbox.currentRow() else: self.statusbar.showMessage("Choose a file from the playlist", timeout=2_000) else: self.statusbar.showMessage("No files loaded to playlist", timeout=2_000) def stop_music(self) -> None: if self.playing: self.playing = False self.current_song = None mixer.music.stop() self.statusbar.showMessage("Music Stopped", timeout=5_000) def pause_music(self) -> None: if self.playing: self.paused = True mixer.music.pause() self.statusbar.showMessage("Music paused", timeout=0) def rewind_music(self) -> None: if self.playing: self.stop_music() time.sleep(0.5) self.play_music() self.statusbar.showMessage("Music Rewound to start", timeout=1_000) def reset_song(self) -> None: self.current_song = None self.filelabel.setText("") self.lengthlabel.setText('Total Length : --:00') self.currenttimelabel.setText("Current Time : --:--") # self.statusbar.showMessage("", timeout=0) def show_details(self, play_song: str) -> None: self.filelabel.setText("Playing" + ' - ' + os.path.basename(play_song)) file_data = os.path.splitext(play_song) if file_data[1] == '.mp3': audio = MP3(play_song) total_length = audio.info.length elif file_data[1] == '.wav': a = mixer.Sound(play_song) total_length = a.get_length() else: try: a = mixer.Sound(play_song) total_length = a.get_length() except Exception as e: print(e) self.current_song_lenth = total_length mins, secs = divmod(total_length, 60) # returns (time//60, remainder) mins = round(mins) secs = round(secs) timeformat = '{:02d}:{:02d}'.format(mins, secs) self.lengthlabel.setText("Total Length" + ' - ' + timeformat) self.t1 = threading.Thread(target=self.start_count, args=(total_length, )) self.t1.start() def start_count(self, total_time: int) -> None: """""" current_time = 0 while current_time <= total_time and mixer.music.get_busy( ): # music.get_busy() -> Returns False when stopped if self.paused: continue # if paused, infinite loop (don't count) else: mins, secs = divmod(current_time, 60) mins = round(mins) secs = round(secs) timeformat = '{:02d}:{:02d}'.format(mins, secs) self.currenttimelabel.setText("Current Time" + ' - ' + timeformat) time.sleep(1) current_time += 1 def play_music(self) -> None: '''if not playing: play, if playing and paused, unpause''' self.get_selected_song_num() # update self.selected_song_num if self.selected_song_num is not None and self.playlist: play_it: Opt[str] = self.playlist[self.selected_song_num] else: play_it = None if not self.playing and play_it: # if not yet playing, play selected song try: self.stop_music() time.sleep(0.5) mixer.music.load(play_it) mixer.music.play() except Exception as e: # messagebox.showerror('File not found, or unknown file type. Please check again.') if DEBUG: print(e) else: self.playing = True self.current_song = play_it self.show_details(play_it) self.statusbar.showMessage("Playing music" + ' - ' + os.path.basename(play_it)) elif self.playing and self.paused: # if paused, resume mixer.music.unpause() # self.statusbar.showMessage("Playing music" + ' - ' + os.path.basename(play_it)) self.statusbar.showMessage("Music Resumed", timeout=1_000) self.paused = False elif self.playing and not self.paused: if play_it == self.current_song and play_it is not None: # if already playing song, do nothing self.statusbar.showMessage( "Playing music" + ' - ' + os.path.basename(play_it), timeout=0) # TODO timout current song len else: # if different song selected, retry self.playing = False self.play_music() def close(self) -> None: try: self.stop_music() QApplication.closeAllWindows() except Exception as e: sys.exit(1) if DEBUG: print(e) else: print('App closed')
class SynthPdfWidget(QWidget): def __init__(self, status_bar): super(SynthPdfWidget, self).__init__() self.status_bar = status_bar layout = QHBoxLayout() self.list_view = QListWidget() self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_view.setAlternatingRowColors(True) self.list_view.itemClicked.connect(self.click_item_signal) self.list_view.itemEntered.connect(self.click_item_signal) self.list_view.itemSelectionChanged.connect( self.change_selection_signal) controls_layout = QVBoxLayout() controls_layout.setAlignment(Qt.AlignTop) select_zone = SelectWidget(self.click_move_up, self.click_move_down, self.click_invert, self.click_delete) select_zone.setMinimumWidth(250) add_pages_button = QPushButton("Add Pages From PDF") add_pages_button.clicked.connect(self.add_pdf) controls_layout.addWidget(select_zone) controls_layout.addWidget(add_pages_button) layout.addWidget(self.list_view) layout.addLayout(controls_layout) self.setLayout(layout) def _add_pages_from_pdf(self, pdf_path): with open(pdf_path, "rb") as file: reader = PdfFileReader(file) file_name = os.path.basename(pdf_path) pages_count = reader.getNumPages() for i in range(pages_count): new_item = ImageListItem( "page " + str(i + 1) + " (" + file_name + ")", (pdf_path, i)) self.list_view.addItem(new_item) self.status_bar.showMessage("Add " + str(pages_count) + " pages") # ----------external methods from create command def extern_get_files_and_pages( self ): # return selected pages in the form {file1: [p1, p2, ...], file2: [p1, p2, ...], ...} to_return = {} if len(self.list_view.selectedItems() ) == 0: # nothing selected, add all pages items_count = self.list_view.count() for item_index in range(items_count): item = self.list_view.item(item_index) item_data = item.get_data() file_name = item_data[0] page_index = item_data[1] if file_name in to_return: to_return[file_name].append(page_index) else: to_return[file_name] = [page_index] else: for s in self.list_view.selectedItems(): s_data = s.get_data() file_name = s_data[0] page_index = s_data[1] if file_name in to_return: to_return[file_name].append(page_index) else: to_return[file_name] = [page_index] return to_return # ----------add button----------------------- def add_pdf(self): files_dialog = QFileDialog() files_dialog.setNameFilter("PDF (*.pdf)") files_dialog.setFileMode(QFileDialog.ExistingFiles) if files_dialog.exec_(): files = files_dialog.selectedFiles() for f_path in files: self._add_pages_from_pdf(f_path) # ----------List_view signals---------------- def click_item_signal(self, item): self.status_bar.showMessage("Select " + str(item.text())) def change_selection_signal(self): if len(self.list_view.selectedItems()) == 0: # self._set_preview(None) # nothing selected pass # ----------list_view commands--------------- def click_move_up(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() if len(selected_indexes) > 0 and selected_indexes[0] > 0: for index in selected_indexes: prev_item = self.list_view.takeItem(index - 1) self.list_view.insertItem(index, prev_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_move_down(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() sel_count = len(selected_indexes) if len(selected_indexes) > 0 and selected_indexes[ sel_count - 1] < self.list_view.count() - 1: for i_index in range(sel_count): next_item = self.list_view.takeItem( selected_indexes[sel_count - i_index - 1] + 1) self.list_view.insertItem( selected_indexes[sel_count - i_index - 1], next_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_invert(self): selected = self.list_view.selectedItems() selected_indexes = [] for sel in selected: selected_indexes.append(self.list_view.indexFromItem(sel).row()) total_indexes = [i for i in range(self.list_view.count())] new_indexes = [] for i in total_indexes: if i not in selected_indexes: new_indexes.append(i) self.list_view.clearSelection() for i in new_indexes: self.list_view.item(i).setSelected(True) self.status_bar.showMessage("Invert selection: " + str(new_indexes)) def click_delete(self): selected = self.list_view.selectedItems() delete_names = [] for s in selected: s_index = self.list_view.indexFromItem(s).row() del_item = self.list_view.takeItem(s_index) delete_names.append(del_item.text()) if len(delete_names) == 0: self.status_bar.showMessage("Nothing to delete") else: self.status_bar.showMessage("Delete items: " + ", ".join(delete_names))
class MainWidget(QWidget): # CONSTANTS EMPTY_STRING = "" # TOGGLE BUTTON CONSTANTS BUTTON_CLOSED_ICON_PATH = 'resources/menu_closed_button_icon.png' BUTTON_OPENED_ICON_PATH = 'resources/menu_opened_button_icon.png' TOOGLE_BUTTON_CSS_PROPERTY = "QPushButton {background-color: rgb(1,150,250); border: none ; qproperty-iconSize: 80px}" CURRENT_PATH_LINE_EDIT_PROPERTY = "QLineEdit {background-color: rgba(240, 240, 240, 1);}" TOOGLE_CLOSED_COLOR = "background-color: rgb(1,150,250);" TOOGLE_OPENED_COLOR = "background-color: rgba(44, 53, 57, 0.2);" WHITE = "background-color: rgb(255, 255, 255);" FRAME_BUTTON_STYLE = "background-color: rgb(0, 191, 255); color: rgb(255, 255, 255);" FRAME_LINE_EDIT_STYLE = "background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);" FRAME_LABEL_STYLE = "QLabel { background-color : rgba(44, 53, 57, 0); }" SEARCH_ICON_STYLE = "QPushButton {background-color: rgb(1,150,250);}" BACK_ICON_STYLE = "QPushButton {background-color: rgb(1,150,250);} QPushButton:pressed {background-color: rgb(40,170,250);}" WIDTH = 1440 HEIGHT = 900 # Size of the operations widget buttons OPERATION_BUTTON_WIDTH = 40 OPERATION_BUTTON_HEIGHT = 40 FILES_LIST_VIEW_WIDTH = 820 FILES_LIST_VIEW_HEIGHT = 680 TOGGLE_BUTTON_ANIMATION_DURATION = 200 RIGHT_MENU_ANIMATION_DURATION = 250 # ICONS PATHS # Actions icons ADD_FILE_ICON_PATH = "resources/add_file_icon.png" ADD_DIRECTORY_ICON_PATH = "resources/add_directory_icon.png" COPY_ELEMENT_ICON_PATH = "resources/copy_element_icon.png" MOVE_ELEMENT_ICON_PATH = "resources/move_element_icon.png" DELETE_ELEMENT_ICON_PATH = "resources/delete_element_icon.png" SEARCH_ICON_PATH = "resources/search_icon_white.png" CREATE_ARCHIVE_ICON_PATH = "resources/create_archive_icon.png" UNARCHIVE_FILE_ICON_PATH = "resources/unarchive_file_icon.png" RENAME_ELEMENT_ICON_PATH = "resources/rename_icon_white.png" BACK_ICON_PATH = "resources/back_icon.png" # Elements icons FILE_ICON_PATH = "resources/file_icon.png" FOLDER_ICON_PATH = "resources/folder_icon.png" ZIP_ICON_PATH = "resources/zip_icon.png" # Tooltips COPY_TOOLTIP = "Copy files / folders" MOVE_TOOLTIP = "Move files / folders" DELETE_TOOLTIP = "Delete files / folders" ARCHIVE_TOOLTIP = "Archive files / folders" UNARCHIVE_TOOLTIP = "Unarchive files / folders" CREATE_FILE_TOOLTIP = "Create a new text file" CREATE_DIRECTORY_TOOLTIP = "Create a new folder" RENAME_TOOLTIP = "Rename a file / folder" BACK_TOOLTIP = "Move up one directory" # Buttons name COPY = "Copy" MOVE = "Move" DELETE = "Delete" ARCHIVE = "Archive" UNARCHIVE = "Unarchive" RENAME = "Rename" CREATE_FILE = "Create file" CREATE_FOLDER = "Create folder" # Labels SELECTED_ITEMS_TEXT = "Selected items:" ARCHIVE_NAME_TEXT = "Archive name:" CREATE_FILE_NAME_TEXT = "File name:" CREATE_FOLDER_NAME_TEXT = "Folder name:" RENAME_ELEMENT_TEXT = "New name:" def __init__(self, parent, model, controller): super(MainWidget, self).__init__(parent) self._model = model self._controller = controller # FILES LIST VIEW self.filesListView = FilesListView(self.FILES_LIST_VIEW_WIDTH, self.FILES_LIST_VIEW_HEIGHT, self._model, self._controller, self) self.filesListView.move(230, 120) # TREE VIEW FOR SYSTEM DIRECTORY HIERARCHY self.treeView = TreeView(self._model, self._controller, self) self.treeView.setFixedSize(200, 820) self.treeView.move(0, 60) # DISC SELECTION COMBO BOX self.discSelectionComboBox = QComboBox(self) self.discSelectionComboBox.setFixedSize(100, 30) self.discSelectionComboBox.move(230, 60) self.discSelectionComboBox.addItems(self._model.combo_box_list) # CONNECT WIDGETS TO CONTROLLER self.discSelectionComboBox.currentTextChanged.connect( self._controller.change_combo_box_selection) # LISTEN FOR MODEL EVENT SIGNALS self._model.combo_box_selection_changed.connect( self.on_combo_box_selection_changed) self.frameRightMenu = QWidget(self) self.frameRightMenu.setFixedSize(360, self.HEIGHT) self.frameRightMenu.move(1450, 15) self.frameRightMenu.setStyleSheet(self.TOOGLE_CLOSED_COLOR) # BUTTON WHICH TOOGLE ON/OFF THE TREE VIEW CONTAINING THE SELECTED ITEMS TREE VIEW self.toggleButton = QPushButton(QIcon(self.BUTTON_CLOSED_ICON_PATH), self.EMPTY_STRING, self) self.toggleButton.setFixedSize(100, 70) self.toggleButton.move(1300, 0) self.toggleButton.setStyleSheet(self.TOOGLE_BUTTON_CSS_PROPERTY) self._enable = True self.toggleButton.clicked.connect( lambda: Animations.toggleMenu(self, self._enable)) # Label that shows "Selected items:" self.selectedItemsLabel = QLabel(self.SELECTED_ITEMS_TEXT, self.frameRightMenu) self.selectedItemsLabel.move(100, 20) self.selectedItemsLabel.setStyleSheet(self.FRAME_LABEL_STYLE) # The list with selected elements from FilesListView self.selectedFilesListWidget = QListWidget(self.frameRightMenu) self.selectedFilesListWidget.setFixedSize(320, 500) self.selectedFilesListWidget.move(23, 60) self.selectedFilesListWidget.setStyleSheet(self.WHITE) # ACTIONS BUTTONS # Copy button self.copyElementButton = OperationsWidgetButton( QIcon(self.COPY_ELEMENT_ICON_PATH), self.EMPTY_STRING, self) self.copyElementButton.clicked.connect(self.doCopy) self.copyElementButton.move(230, 0) self.copyElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.copyElementButton.setToolTip(self.COPY_TOOLTIP) # Move button self.moveElementButton = OperationsWidgetButton( QIcon(self.MOVE_ELEMENT_ICON_PATH), self.EMPTY_STRING, self) self.moveElementButton.clicked.connect(self.doMove) self.moveElementButton.move(290, 0) self.moveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.moveElementButton.setToolTip(self.MOVE_TOOLTIP) # Delete button self.deleteElementButton = OperationsWidgetButton( QIcon(self.DELETE_ELEMENT_ICON_PATH), self.EMPTY_STRING, self) self.deleteElementButton.clicked.connect(self.doDelete) self.deleteElementButton.move(350, 0) self.deleteElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.deleteElementButton.setToolTip(self.DELETE_TOOLTIP) # Archive button self.archiveElementButton = OperationsWidgetButton( QIcon(self.CREATE_ARCHIVE_ICON_PATH), self.EMPTY_STRING, self) self.archiveElementButton.clicked.connect(self.doArchive) self.archiveElementButton.move(410, 0) self.archiveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.archiveElementButton.setToolTip(self.ARCHIVE_TOOLTIP) # Unarchive button self.unarchiveElementButton = OperationsWidgetButton( QIcon(self.UNARCHIVE_FILE_ICON_PATH), self.EMPTY_STRING, self) self.unarchiveElementButton.clicked.connect(self.doUnarchive) self.unarchiveElementButton.move(470, 0) self.unarchiveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.unarchiveElementButton.setToolTip(self.UNARCHIVE_TOOLTIP) # Add file button self.addFileButton = OperationsWidgetButton( QIcon(self.ADD_FILE_ICON_PATH), self.EMPTY_STRING, self) self.addFileButton.clicked.connect(self.doCreateFile) self.addFileButton.move(530, 0) self.addFileButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.addFileButton.setToolTip(self.CREATE_FILE_TOOLTIP) # Add directory button self.addDirectoryButton = OperationsWidgetButton( QIcon(self.ADD_DIRECTORY_ICON_PATH), self.EMPTY_STRING, self) self.addDirectoryButton.clicked.connect(self.doCreateFolder) self.addDirectoryButton.move(590, 0) self.addDirectoryButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.addDirectoryButton.setToolTip(self.CREATE_DIRECTORY_TOOLTIP) # Move button self.renameElementButton = OperationsWidgetButton( QIcon(self.RENAME_ELEMENT_ICON_PATH), self.EMPTY_STRING, self) self.renameElementButton.clicked.connect(self.doRename) self.renameElementButton.move(650, 0) self.renameElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH, self.OPERATION_BUTTON_HEIGHT) self.renameElementButton.setToolTip(self.RENAME_TOOLTIP) # Text field needed for displaying the current path self.currentPathLineEdit = QLineEdit(self.EMPTY_STRING, self) self.currentPathLineEdit.move(350, 80) self.currentPathLineEdit.setFixedSize(400, 27) self.currentPathLineEdit.setStyleSheet( self.CURRENT_PATH_LINE_EDIT_PROPERTY) self.currentPathLineEdit.setReadOnly(True) self.currentPathLineEdit.setText(self._model.current_path) self.currentPathLineEdit.textChanged.connect( self._controller.change_current_path_text) self._model.current_path_changed.connect(self.on_current_path_changed) # Text field needed for searching file / folder by the name self.searchLineEdit = QLineEdit(self.EMPTY_STRING, self) self.searchLineEdit.move(810, 80) self.searchLineEdit.setFixedSize(200, 27) self.searchLineEdit.textChanged.connect( self._controller.change_search_text) self._model.current_search_changed.connect( self.on_current_search_changed) self.searchIconButton = OperationsWidgetButton( QIcon(self.SEARCH_ICON_PATH), self.EMPTY_STRING, self) self.searchIconButton.move(1015, 78) self.searchIconButton.setFixedSize(30, 30) self.searchIconButton.setStyleSheet(self.SEARCH_ICON_STYLE) self.searchIconButton.setEnabled(False) self.backButton = OperationsWidgetButton(QIcon(self.BACK_ICON_PATH), self.EMPTY_STRING, self) self.backButton.clicked.connect(self.doBack) self.backButton.move(765, 80) self.backButton.setFixedSize(25, 25) self.backButton.setStyleSheet(self.BACK_ICON_STYLE) self.backButton.setToolTip(self.BACK_TOOLTIP) self.backButton.setEnabled(True) # ACTIONS LABELS self.archiveLabel = QLabel(self.ARCHIVE_NAME_TEXT, self.frameRightMenu) self.createFolderLabel = QLabel(self.CREATE_FOLDER_NAME_TEXT, self.frameRightMenu) self.createFileLabel = QLabel(self.CREATE_FILE_NAME_TEXT, self.frameRightMenu) self.renameElementLabel = QLabel(self.RENAME_ELEMENT_TEXT, self.frameRightMenu) # ACTIONS LINE EDITS self.archiveNameEditLine = QLineEdit(self.EMPTY_STRING, self.frameRightMenu) self.createFileEditLine = QLineEdit(self.EMPTY_STRING, self.frameRightMenu) self.createFolderEditLine = QLineEdit(self.EMPTY_STRING, self.frameRightMenu) self.renameElementEditLine = QLineEdit(self.EMPTY_STRING, self.frameRightMenu) # ACTIONS BUTTONS self.copyButton = ToggleMenuButton(self.COPY, self.frameRightMenu) self.moveButton = ToggleMenuButton(self.MOVE, self.frameRightMenu) self.deleteButton = ToggleMenuButton(self.DELETE, self.frameRightMenu) self.archiveButton = ToggleMenuButton(self.ARCHIVE, self.frameRightMenu) self.unarchiveButton = ToggleMenuButton(self.UNARCHIVE, self.frameRightMenu) self.createFileButton = ToggleMenuButton(self.CREATE_FILE, self.frameRightMenu) self.createFolderButton = ToggleMenuButton(self.CREATE_FOLDER, self.frameRightMenu) self.renameElementButton = ToggleMenuButton(self.RENAME, self.frameRightMenu) self.__createFrameLayoutElements() @Slot(str) def on_current_path_changed(self, path): self._model.elements_list.clear() self._model.selected_items.clear() self.selectedFilesListWidget.clear() self._model.elements_list = Directory.get_all_subelements(path) self.filesListView.model().populateList() @Slot(str) def on_current_search_changed(self, name): print(name) def removeFromSelectedItems(self, item): Animations.toggleMenu(self, True) count = self.selectedFilesListWidget.count() index = 0 for i in range(count): if item.text() == self.selectedFilesListWidget.item(i).text(): index = i break self.selectedFilesListWidget.takeItem(index) def appendToSelectedItems(self, item): Animations.toggleMenu(self, True) listItem = ListWidgetItem(item) self.selectedFilesListWidget.insertItem(0, listItem) def setCurrentPath(self, path): self.currentPathLineEdit.setText(path) @Slot(str) def on_combo_box_selection_changed(self, value): index = self.discSelectionComboBox.findText(value) self.discSelectionComboBox.setCurrentIndex(index) Slot() def doBack(self): path = self.currentPathLineEdit.text() parentPath = os.path.dirname(path) self.setCurrentPath(parentPath) @Slot() def doCopy(self): self.__setCopyLayout(True) Animations.toggleMenu(self, True) @Slot() def doMove(self): self.__setMoveLayout(True) Animations.toggleMenu(self, True) @Slot() def doDelete(self): self.__setDeleteLayout(True) Animations.toggleMenu(self, True) @Slot() def doArchive(self): self.__setArchiveLayout(True) Animations.toggleMenu(self, True) @Slot() def doUnarchive(self): self.__setUnarchiveLayout(True) Animations.toggleMenu(self, True) @Slot() def doCreateFile(self): self.__setCreateFileLayout(True) Animations.toggleMenu(self, True) @Slot() def doCreateFolder(self): self.__setCreateFolderLayout(True) Animations.toggleMenu(self, True) @Slot() def doRename(self): self.__setRenameLayout(True) Animations.toggleMenu(self, True) # Method that creates all layout object from the frame layout def __createFrameLayoutElements(self): # ================= COPY ACTION ======================= # Copy button on right frame self.copyButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.copyButton.move(120, 600) self.copyButton.setFixedSize(120, 32) self.copyButton.setVisible(False) # ================= MOVE ACTION ======================= # Move button on right frame self.moveButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.moveButton.move(120, 600) self.moveButton.setFixedSize(120, 32) self.moveButton.setVisible(False) # ================= DELETE ACTION ======================= # Delete button on right frame self.deleteButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.deleteButton.move(120, 600) self.deleteButton.setFixedSize(120, 32) self.deleteButton.setVisible(False) # ================= UNARCHIVE ACTION ======================= # Unarchive button on right frame self.unarchiveButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.unarchiveButton.move(120, 600) self.unarchiveButton.setFixedSize(120, 32) self.unarchiveButton.setVisible(False) # ================= ARCHIVE ACTION ======================= self.archiveLabel.move(100, 590) self.archiveLabel.setStyleSheet(self.FRAME_LABEL_STYLE) self.archiveLabel.setVisible(False) self.archiveNameEditLine.move(55, 620) self.archiveNameEditLine.setFixedSize(250, 30) self.archiveNameEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE) self.archiveNameEditLine.setVisible(False) self.archiveButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.archiveButton.move(120, 700) self.archiveButton.setFixedSize(120, 32) self.archiveButton.setVisible(False) # ================= CREATE NEW FILE ACTION ======================= self.createFileLabel.move(120, 590) self.createFileLabel.setStyleSheet(self.FRAME_LABEL_STYLE) self.createFileLabel.setVisible(False) self.createFileEditLine.move(55, 620) self.createFileEditLine.setFixedSize(250, 30) self.createFileEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE) self.createFileEditLine.setVisible(False) self.createFileButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.createFileButton.move(120, 700) self.createFileButton.setFixedSize(120, 32) self.createFileButton.setVisible(False) # ================= CREATE NEW FOLDER ACTION ======================= self.createFolderLabel.move(120, 590) self.createFolderLabel.setStyleSheet(self.FRAME_LABEL_STYLE) self.createFolderLabel.setVisible(False) self.createFolderEditLine.move(55, 620) self.createFolderEditLine.setFixedSize(250, 30) self.createFolderEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE) self.createFolderEditLine.setVisible(False) self.createFolderButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.createFolderButton.move(120, 700) self.createFolderButton.setFixedSize(120, 32) self.createFolderButton.setVisible(False) # ================= RENAME ELEMENT ACTION ======================= self.renameElementLabel.move(120, 590) self.renameElementLabel.setStyleSheet(self.FRAME_LABEL_STYLE) self.renameElementLabel.setVisible(False) self.renameElementEditLine.move(55, 620) self.renameElementEditLine.setFixedSize(250, 30) self.renameElementEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE) self.renameElementEditLine.setVisible(False) self.renameElementButton.setStyleSheet(self.FRAME_BUTTON_STYLE) self.renameElementButton.move(120, 700) self.renameElementButton.setFixedSize(120, 32) self.renameElementButton.setVisible(False) # Method that sets the frame layout for rename operation def __setRenameLayout(self, shown): if shown == True: self.renameElementLabel.setVisible(True) self.renameElementEditLine.setVisible(True) self.renameElementButton.setVisible(True) self.__setCopyLayout(False) self.__setDeleteLayout(False) self.__setMoveLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.renameElementLabel.setVisible(False) self.renameElementEditLine.setVisible(False) self.renameElementButton.setVisible(False) # Method that sets the frame layout for archive operation def __setCreateFileLayout(self, shown): if shown == True: self.createFileLabel.setVisible(True) self.createFileEditLine.setVisible(True) self.createFileButton.setVisible(True) self.__setCopyLayout(False) self.__setDeleteLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.createFileLabel.setVisible(False) self.createFileEditLine.setVisible(False) self.createFileButton.setVisible(False) # Method that sets the frame layout for archive operation def __setCreateFolderLayout(self, shown): if shown == True: self.createFolderLabel.setVisible(True) self.createFolderEditLine.setVisible(True) self.createFolderButton.setVisible(True) self.__setCopyLayout(False) self.__setDeleteLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.createFolderLabel.setVisible(False) self.createFolderEditLine.setVisible(False) self.createFolderButton.setVisible(False) # Method that sets the frame layout for archive operation def __setArchiveLayout(self, shown): if shown == True: self.archiveLabel.setVisible(True) self.archiveNameEditLine.setVisible(True) self.archiveButton.setVisible(True) self.__setCopyLayout(False) self.__setDeleteLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setUnarchiveLayout(False) else: self.archiveLabel.setVisible(False) self.archiveNameEditLine.setVisible(False) self.archiveButton.setVisible(False) # Method that sets the frame layout for copy operation def __setCopyLayout(self, shown): if shown == True: self.copyButton.setVisible(True) self.__setMoveLayout(False) self.__setDeleteLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.copyButton.setVisible(False) # Method that sets the frame layout for move operation def __setMoveLayout(self, shown): if shown == True: self.moveButton.setVisible(True) self.__setDeleteLayout(False) self.__setCopyLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.moveButton.setVisible(False) # Method that sets the frame layout for delete operation def __setDeleteLayout(self, shown): if shown == True: self.deleteButton.setVisible(True) self.__setCopyLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setUnarchiveLayout(False) else: self.deleteButton.setVisible(False) # Method that sets the frame layout for unarchive operation def __setUnarchiveLayout(self, shown): if shown == True: self.unarchiveButton.setVisible(True) self.__setCopyLayout(False) self.__setMoveLayout(False) self.__setRenameLayout(False) self.__setCreateFileLayout(False) self.__setCreateFolderLayout(False) self.__setArchiveLayout(False) self.__setDeleteLayout(False) else: self.unarchiveButton.setVisible(False)