class ThumbnailScrollBar(QFrame): """ A widget that manages the display of the FigureThumbnails that are created when a figure is sent to the IPython console by the kernel and that controls what is displayed in the FigureViewer. """ redirect_stdio = Signal(bool) def __init__(self, figure_viewer, parent=None, background_color=None): super(ThumbnailScrollBar, self).__init__(parent) self._thumbnails = [] self.background_color = background_color self.current_thumbnail = None self.set_figureviewer(figure_viewer) self.setup_gui() def setup_gui(self): """Setup the main layout of the widget.""" scrollarea = self.setup_scrollarea() up_btn, down_btn = self.setup_arrow_buttons() self.setFixedWidth(150) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(up_btn) layout.addWidget(scrollarea) layout.addWidget(down_btn) def setup_scrollarea(self): """Setup the scrollarea that will contain the FigureThumbnails.""" self.view = QWidget() self.scene = QGridLayout(self.view) self.scene.setColumnStretch(0, 100) self.scene.setColumnStretch(2, 100) self.scrollarea = QScrollArea() self.scrollarea.setWidget(self.view) self.scrollarea.setWidgetResizable(True) self.scrollarea.setFrameStyle(0) self.scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scrollarea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scrollarea.setSizePolicy( QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)) # Set the vertical scrollbar explicitely : # This is required to avoid a "RuntimeError: no access to protected # functions or signals for objects not created from Python" in Linux. self.scrollarea.setVerticalScrollBar(QScrollBar()) return self.scrollarea def setup_arrow_buttons(self): """ Setup the up and down arrow buttons that are placed at the top and bottom of the scrollarea. """ # Get the size hint height of the horizontal scrollbar. height = self.scrollarea.horizontalScrollBar().sizeHint().height() # Setup the up and down arrow button. up_btn = up_btn = QPushButton(icon=ima.icon('last_edit_location')) up_btn.setFlat(True) up_btn.setFixedHeight(height) up_btn.clicked.connect(self.go_up) down_btn = QPushButton(icon=ima.icon('folding.arrow_down_on')) down_btn.setFlat(True) down_btn.setFixedHeight(height) down_btn.clicked.connect(self.go_down) return up_btn, down_btn def set_figureviewer(self, figure_viewer): """Set the bamespace for the FigureViewer.""" self.figure_viewer = figure_viewer # ---- Save Figure def save_all_figures_as(self): """Save all the figures to a file.""" self.redirect_stdio.emit(False) dirname = getexistingdirectory(self, caption='Save all figures', basedir=getcwd_or_home()) self.redirect_stdio.emit(True) if dirname: return self.save_all_figures_todir(dirname) def save_all_figures_todir(self, dirname): """Save all figure in dirname.""" fignames = [] for thumbnail in self._thumbnails: fig = thumbnail.canvas.fig fmt = thumbnail.canvas.fmt fext = { 'image/png': '.png', 'image/jpeg': '.jpg', 'image/svg+xml': '.svg' }[fmt] figname = get_unique_figname(dirname, 'Figure', fext) save_figure_tofile(fig, fmt, figname) fignames.append(figname) return fignames def save_current_figure_as(self): """Save the currently selected figure.""" if self.current_thumbnail is not None: self.save_figure_as(self.current_thumbnail.canvas.fig, self.current_thumbnail.canvas.fmt) def save_figure_as(self, fig, fmt): """Save the figure to a file.""" fext, ffilt = { 'image/png': ('.png', 'PNG (*.png)'), 'image/jpeg': ('.jpg', 'JPEG (*.jpg;*.jpeg;*.jpe;*.jfif)'), 'image/svg+xml': ('.svg', 'SVG (*.svg);;PNG (*.png)') }[fmt] figname = get_unique_figname(getcwd_or_home(), 'Figure', fext) self.redirect_stdio.emit(False) fname, fext = getsavefilename(parent=self.parent(), caption='Save Figure', basedir=figname, filters=ffilt, selectedfilter='', options=None) self.redirect_stdio.emit(True) if fname: save_figure_tofile(fig, fmt, fname) # ---- Thumbails Handlers def add_thumbnail(self, fig, fmt): thumbnail = FigureThumbnail(background_color=self.background_color) thumbnail.canvas.load_figure(fig, fmt) # Scale the thumbnail size, while respecting the figure # dimension ratio. fwidth = thumbnail.canvas.fwidth fheight = thumbnail.canvas.fheight max_length = 100 if fwidth / fheight > 1: canvas_width = max_length canvas_height = canvas_width / fwidth * fheight else: canvas_height = max_length canvas_width = canvas_height / fheight * fwidth thumbnail.canvas.setFixedSize(canvas_width, canvas_height) thumbnail.sig_canvas_clicked.connect(self.set_current_thumbnail) thumbnail.sig_remove_figure.connect(self.remove_thumbnail) thumbnail.sig_save_figure.connect(self.save_figure_as) self._thumbnails.append(thumbnail) self.scene.setRowStretch(self.scene.rowCount() - 1, 0) self.scene.addWidget(thumbnail, self.scene.rowCount() - 1, 1) self.scene.setRowStretch(self.scene.rowCount(), 100) self.set_current_thumbnail(thumbnail) def remove_current_thumbnail(self): """Remove the currently selected thumbnail.""" if self.current_thumbnail is not None: self.remove_thumbnail(self.current_thumbnail) def remove_all_thumbnails(self): """Remove all thumbnails.""" for thumbnail in self._thumbnails: self.layout().removeWidget(thumbnail) thumbnail.sig_canvas_clicked.disconnect() thumbnail.sig_remove_figure.disconnect() thumbnail.sig_save_figure.disconnect() thumbnail.deleteLater() self._thumbnails = [] self.current_thumbnail = None self.figure_viewer.figcanvas.clear_canvas() def remove_thumbnail(self, thumbnail): """Remove thumbnail.""" if thumbnail in self._thumbnails: index = self._thumbnails.index(thumbnail) self._thumbnails.remove(thumbnail) self.layout().removeWidget(thumbnail) thumbnail.deleteLater() thumbnail.sig_canvas_clicked.disconnect() thumbnail.sig_remove_figure.disconnect() thumbnail.sig_save_figure.disconnect() # Select a new thumbnail if any : if thumbnail == self.current_thumbnail: if len(self._thumbnails) > 0: self.set_current_index(min(index, len(self._thumbnails) - 1)) else: self.current_thumbnail = None self.figure_viewer.figcanvas.clear_canvas() def set_current_index(self, index): """Set the currently selected thumbnail by its index.""" self.set_current_thumbnail(self._thumbnails[index]) def get_current_index(self): """Return the index of the currently selected thumbnail.""" try: return self._thumbnails.index(self.current_thumbnail) except ValueError: return -1 def set_current_thumbnail(self, thumbnail): """Set the currently selected thumbnail.""" self.current_thumbnail = thumbnail self.figure_viewer.load_figure(thumbnail.canvas.fig, thumbnail.canvas.fmt) for thumbnail in self._thumbnails: thumbnail.highlight_canvas(thumbnail == self.current_thumbnail) def go_previous_thumbnail(self): """Select the thumbnail previous to the currently selected one.""" if self.current_thumbnail is not None: index = self._thumbnails.index(self.current_thumbnail) - 1 index = index if index >= 0 else len(self._thumbnails) - 1 self.set_current_index(index) self.scroll_to_item(index) def go_next_thumbnail(self): """Select thumbnail next to the currently selected one.""" if self.current_thumbnail is not None: index = self._thumbnails.index(self.current_thumbnail) + 1 index = 0 if index >= len(self._thumbnails) else index self.set_current_index(index) self.scroll_to_item(index) def scroll_to_item(self, index): """Scroll to the selected item of ThumbnailScrollBar.""" spacing_between_items = self.scene.verticalSpacing() height_view = self.scrollarea.viewport().height() height_item = self.scene.itemAt(index).sizeHint().height() height_view_excluding_item = max(0, height_view - height_item) height_of_top_items = spacing_between_items for i in range(index): item = self.scene.itemAt(i) height_of_top_items += item.sizeHint().height() height_of_top_items += spacing_between_items pos_scroll = height_of_top_items - height_view_excluding_item // 2 vsb = self.scrollarea.verticalScrollBar() vsb.setValue(pos_scroll) # ---- ScrollBar Handlers def go_up(self): """Scroll the scrollbar of the scrollarea up by a single step.""" vsb = self.scrollarea.verticalScrollBar() vsb.setValue(int(vsb.value() - vsb.singleStep())) def go_down(self): """Scroll the scrollbar of the scrollarea down by a single step.""" vsb = self.scrollarea.verticalScrollBar() vsb.setValue(int(vsb.value() + vsb.singleStep()))
class ThumbnailScrollBar(QFrame): """ A widget that manages the display of the FigureThumbnails that are created when a figure is sent to the IPython console by the kernel and that controls what is displayed in the FigureViewer. """ redirect_stdio = Signal(bool) _min_scrollbar_width = 100 def __init__(self, figure_viewer, parent=None, background_color=None): super(ThumbnailScrollBar, self).__init__(parent) self._thumbnails = [] self.background_color = background_color self.current_thumbnail = None self.set_figureviewer(figure_viewer) self.setup_gui() def setup_gui(self): """Setup the main layout of the widget.""" scrollarea = self.setup_scrollarea() up_btn, down_btn = self.setup_arrow_buttons() layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(up_btn) layout.addWidget(scrollarea) layout.addWidget(down_btn) def setup_scrollarea(self): """Setup the scrollarea that will contain the FigureThumbnails.""" self.view = QWidget() self.scene = QGridLayout(self.view) self.scene.setContentsMargins(0, 0, 0, 0) self.scrollarea = QScrollArea() self.scrollarea.setWidget(self.view) self.scrollarea.setWidgetResizable(True) self.scrollarea.setFrameStyle(0) self.scrollarea.setViewportMargins(2, 2, 2, 2) self.scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scrollarea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scrollarea.setMinimumWidth(self._min_scrollbar_width) # Set the vertical scrollbar explicitely. # This is required to avoid a "RuntimeError: no access to protected # functions or signals for objects not created from Python" in Linux. self.scrollarea.setVerticalScrollBar(QScrollBar()) # Install an event filter on the scrollbar. self.scrollarea.installEventFilter(self) return self.scrollarea def setup_arrow_buttons(self): """ Setup the up and down arrow buttons that are placed at the top and bottom of the scrollarea. """ # Get the size hint height of the horizontal scrollbar. height = self.scrollarea.horizontalScrollBar().sizeHint().height() # Setup the up and down arrow button. up_btn = up_btn = QPushButton(icon=ima.icon('last_edit_location')) up_btn.setFlat(True) up_btn.setFixedHeight(height) up_btn.clicked.connect(self.go_up) down_btn = QPushButton(icon=ima.icon('folding.arrow_down_on')) down_btn.setFlat(True) down_btn.setFixedHeight(height) down_btn.clicked.connect(self.go_down) return up_btn, down_btn def set_figureviewer(self, figure_viewer): """Set the bamespace for the FigureViewer.""" self.figure_viewer = figure_viewer def eventFilter(self, widget, event): """ An event filter to trigger an update of the thumbnails size so that their width fit that of the scrollarea. """ if event.type() == QEvent.Resize: self._update_thumbnail_size() return super(ThumbnailScrollBar, self).eventFilter(widget, event) # ---- Save Figure def save_all_figures_as(self): """Save all the figures to a file.""" self.redirect_stdio.emit(False) dirname = getexistingdirectory(self, caption='Save all figures', basedir=getcwd_or_home()) self.redirect_stdio.emit(True) if dirname: return self.save_all_figures_todir(dirname) def save_all_figures_todir(self, dirname): """Save all figure in dirname.""" fignames = [] for thumbnail in self._thumbnails: fig = thumbnail.canvas.fig fmt = thumbnail.canvas.fmt fext = { 'image/png': '.png', 'image/jpeg': '.jpg', 'image/svg+xml': '.svg' }[fmt] figname = get_unique_figname(dirname, 'Figure', fext) save_figure_tofile(fig, fmt, figname) fignames.append(figname) return fignames def save_current_figure_as(self): """Save the currently selected figure.""" if self.current_thumbnail is not None: self.save_figure_as(self.current_thumbnail.canvas.fig, self.current_thumbnail.canvas.fmt) def save_figure_as(self, fig, fmt): """Save the figure to a file.""" fext, ffilt = { 'image/png': ('.png', 'PNG (*.png)'), 'image/jpeg': ('.jpg', 'JPEG (*.jpg;*.jpeg;*.jpe;*.jfif)'), 'image/svg+xml': ('.svg', 'SVG (*.svg);;PNG (*.png)') }[fmt] figname = get_unique_figname(getcwd_or_home(), 'Figure', fext) self.redirect_stdio.emit(False) fname, fext = getsavefilename(parent=self.parent(), caption='Save Figure', basedir=figname, filters=ffilt, selectedfilter='', options=None) self.redirect_stdio.emit(True) if fname: save_figure_tofile(fig, fmt, fname) # ---- Thumbails Handlers def _calculate_figure_canvas_width(self, thumbnail): """ Calculate the witdh the thumbnail's figure canvas need to have for the thumbnail to fit the scrollarea. """ extra_padding = 10 if sys.platform == 'darwin' else 0 figure_canvas_width = (self.scrollarea.width() - 2 * self.lineWidth() - self.scrollarea.viewportMargins().left() - self.scrollarea.viewportMargins().right() - thumbnail.savefig_btn.width() - thumbnail.layout().spacing() - extra_padding) if is_dark_interface(): # This is required to take into account some hard-coded padding # and margin in qdarkstyle. figure_canvas_width = figure_canvas_width - 6 return figure_canvas_width def _setup_thumbnail_size(self, thumbnail): """ Scale the thumbnail's canvas size so that it fits the thumbnail scrollbar's width. """ max_canvas_size = self._calculate_figure_canvas_width(thumbnail) thumbnail.scale_canvas_size(max_canvas_size) def _update_thumbnail_size(self): """ Update the thumbnails size so that their width fit that of the scrollarea. """ # NOTE: We hide temporarily the thumbnails to prevent a repaint of # each thumbnail as soon as their size is updated in the loop, which # causes some flickering of the thumbnail scrollbar resizing animation. # Once the size of all the thumbnails has been updated, we show them # back so that they are repainted all at once instead of one after the # other. This is just a trick to make the resizing animation of the # thumbnail scrollbar look smoother. self.view.hide() for thumbnail in self._thumbnails: self._setup_thumbnail_size(thumbnail) self.view.show() def add_thumbnail(self, fig, fmt): """ Add a new thumbnail to that thumbnail scrollbar. """ thumbnail = FigureThumbnail(parent=self, background_color=self.background_color) thumbnail.canvas.load_figure(fig, fmt) thumbnail.sig_canvas_clicked.connect(self.set_current_thumbnail) thumbnail.sig_remove_figure.connect(self.remove_thumbnail) thumbnail.sig_save_figure.connect(self.save_figure_as) self._thumbnails.append(thumbnail) self.scene.setRowStretch(self.scene.rowCount() - 1, 0) self.scene.addWidget(thumbnail, self.scene.rowCount() - 1, 0) self.scene.setRowStretch(self.scene.rowCount(), 100) self.set_current_thumbnail(thumbnail) thumbnail.show() self._setup_thumbnail_size(thumbnail) def remove_current_thumbnail(self): """Remove the currently selected thumbnail.""" if self.current_thumbnail is not None: self.remove_thumbnail(self.current_thumbnail) def remove_all_thumbnails(self): """Remove all thumbnails.""" for thumbnail in self._thumbnails: self.layout().removeWidget(thumbnail) thumbnail.sig_canvas_clicked.disconnect() thumbnail.sig_remove_figure.disconnect() thumbnail.sig_save_figure.disconnect() self._thumbnails = [] self.current_thumbnail = None self.figure_viewer.figcanvas.clear_canvas() def remove_thumbnail(self, thumbnail): """Remove thumbnail.""" if thumbnail in self._thumbnails: index = self._thumbnails.index(thumbnail) self._thumbnails.remove(thumbnail) self.layout().removeWidget(thumbnail) thumbnail.sig_canvas_clicked.disconnect() thumbnail.sig_remove_figure.disconnect() thumbnail.sig_save_figure.disconnect() # Select a new thumbnail if any : if thumbnail == self.current_thumbnail: if len(self._thumbnails) > 0: self.set_current_index(min(index, len(self._thumbnails) - 1)) else: self.current_thumbnail = None self.figure_viewer.figcanvas.clear_canvas() def set_current_index(self, index): """Set the currently selected thumbnail by its index.""" self.set_current_thumbnail(self._thumbnails[index]) def get_current_index(self): """Return the index of the currently selected thumbnail.""" try: return self._thumbnails.index(self.current_thumbnail) except ValueError: return -1 def set_current_thumbnail(self, thumbnail): """Set the currently selected thumbnail.""" self.current_thumbnail = thumbnail self.figure_viewer.load_figure(thumbnail.canvas.fig, thumbnail.canvas.fmt) for thumbnail in self._thumbnails: thumbnail.highlight_canvas(thumbnail == self.current_thumbnail) def go_previous_thumbnail(self): """Select the thumbnail previous to the currently selected one.""" if self.current_thumbnail is not None: index = self._thumbnails.index(self.current_thumbnail) - 1 index = index if index >= 0 else len(self._thumbnails) - 1 self.set_current_index(index) self.scroll_to_item(index) def go_next_thumbnail(self): """Select thumbnail next to the currently selected one.""" if self.current_thumbnail is not None: index = self._thumbnails.index(self.current_thumbnail) + 1 index = 0 if index >= len(self._thumbnails) else index self.set_current_index(index) self.scroll_to_item(index) def scroll_to_item(self, index): """Scroll to the selected item of ThumbnailScrollBar.""" spacing_between_items = self.scene.verticalSpacing() height_view = self.scrollarea.viewport().height() height_item = self.scene.itemAt(index).sizeHint().height() height_view_excluding_item = max(0, height_view - height_item) height_of_top_items = spacing_between_items for i in range(index): item = self.scene.itemAt(i) height_of_top_items += item.sizeHint().height() height_of_top_items += spacing_between_items pos_scroll = height_of_top_items - height_view_excluding_item // 2 vsb = self.scrollarea.verticalScrollBar() vsb.setValue(pos_scroll) # ---- ScrollBar Handlers def go_up(self): """Scroll the scrollbar of the scrollarea up by a single step.""" vsb = self.scrollarea.verticalScrollBar() vsb.setValue(int(vsb.value() - vsb.singleStep())) def go_down(self): """Scroll the scrollbar of the scrollarea down by a single step.""" vsb = self.scrollarea.verticalScrollBar() vsb.setValue(int(vsb.value() + vsb.singleStep()))
class MainWindow(QMainWindow): FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = 0, 1, 2 def __init__(self, label_file=None): super(MainWindow, self).__init__() self.showMaximized() self.setWindowTitle("VTCC.Labelling") self.file_dirs = [] self.file_id = -1 self.labels = [] with open(label_file, 'r') as f: lines = f.read().splitlines() for label in lines: self.labels.append(label) # RIGHT DOCK self.label_dock = QDockWidget("Label List", self) self.label_list_widget = QListWidget(self) self.load_labels(label_file) self.label_dock.setWidget(self.label_list_widget) self.object_dock = QDockWidget("Object List", self) self.object_list_widget = QListWidget(self) self.object_list_widget.currentRowChanged.connect(self.change_object) self.object_dock.setWidget(self.object_list_widget) self.file_dock = QDockWidget("File List", self) self.file_list_widget = QListWidget(self) self.file_list_widget.currentRowChanged.connect(self.change_file) self.file_dock.setWidget(self.file_list_widget) self.addDockWidget(Qt.RightDockWidgetArea, self.label_dock) self.addDockWidget(Qt.RightDockWidgetArea, self.object_dock) self.addDockWidget(Qt.RightDockWidgetArea, self.file_dock) # MAIN CANVAS self.canvas = Canvas(self) self.canvas_area = QScrollArea() self.canvas_area.setWidget(self.canvas) self.canvas_area.setWidgetResizable(True) self.scrollBars = { Qt.Vertical: self.canvas_area.verticalScrollBar(), Qt.Horizontal: self.canvas_area.horizontalScrollBar(), } self.setCentralWidget(self.canvas_area) # LEFT DOCK self.open_action = QAction(QIcon('icons/open.png'), 'Open File', self) self.open_action.triggered.connect(self.open_file) self.open_action.setShortcut(QKeySequence("Ctrl+O")) self.open_dir_action = QAction(QIcon('icons/open.png'), 'Open Dir', self) self.open_dir_action.triggered.connect(self.open_dir) self.next_img_action = QAction(QIcon('icons/next.png'), 'Next Image', self) self.next_img_action.triggered.connect(self.next_img) self.next_img_action.setShortcut(QKeySequence("Right")) self.prev_img_action = QAction(QIcon('icons/prev.png'), 'Prev Image', self) self.prev_img_action.triggered.connect(self.prev_img) self.prev_img_action.setShortcut(QKeySequence("Left")) self.zoom_in_action = QAction(QIcon('icons/zoom-in.png'), 'Zoom In', self) self.zoom_in_action.triggered.connect(self.zoom_in) self.zoom_out_action = QAction(QIcon('icons/zoom-out.png'), 'Zoom Out', self) self.zoom_out_action.triggered.connect(self.zoom_out) self.zoom_org_action = QAction(QIcon('icons/fit-window.png'), 'Fit Window', self) self.zoom_org_action.triggered.connect(self.zoom_org) self.rectangle_action = QAction(QIcon('icons/objects.png'), 'New Rectangle', self) self.rectangle_action.triggered.connect(self.new_rectangle) self.auto_polygon_action = QAction(QIcon('icons/objects.png'), 'New Auto-Polygon', self) self.auto_polygon_action.triggered.connect(self.new_auto_polygon) self.polygon_action = QAction(QIcon('icons/objects.png'), 'New Polygon', self) self.polygon_action.triggered.connect(self.new_polygon) self.next_obj_action = QAction(QIcon('icons/next.png'), 'Next Object', self) self.next_obj_action.triggered.connect(self.canvas.next_obj) self.next_obj_action.setShortcut(QKeySequence("Down")) self.prev_obj_action = QAction(QIcon('icons/prev.png'), 'Prev Object', self) self.prev_obj_action.triggered.connect(self.canvas.prev_obj) self.prev_obj_action.setShortcut(QKeySequence("Up")) self.del_obj_action = QAction(QIcon('icons/delete.png'), 'Delete Object', self) self.del_obj_action.triggered.connect(self.canvas.del_obj) self.del_obj_action.setShortcut(QKeySequence("Del")) self.toolbar = QToolBar(self) self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.toolbar.addAction(self.open_action) self.toolbar.addAction(self.open_dir_action) self.toolbar.addAction(self.next_img_action) self.toolbar.addAction(self.prev_img_action) # self.toolbar.addAction(self.zoom_in_action) # self.toolbar.addAction(self.zoom_out_action) # self.toolbar.addAction(self.zoom_org_action) self.toolbar.addAction(self.rectangle_action) self.toolbar.addAction(self.auto_polygon_action) self.toolbar.addAction(self.polygon_action) self.toolbar.addAction(self.next_obj_action) self.toolbar.addAction(self.prev_obj_action) self.toolbar.addAction(self.del_obj_action) self.addToolBar(Qt.LeftToolBarArea, self.toolbar) self.scalers = { self.FIT_WINDOW: self.scaleFitWindow, self.FIT_WIDTH: self.scaleFitWidth, # Set to one to scale to 100% when loading files. self.MANUAL_ZOOM: lambda: 1, } def update_mode(self, mode_id): pass def change_object(self, row): if (row >= 0): self.canvas.cur_object = row self.canvas.repaint() def change_file(self, row): if (row >= 0): self.file_id = row self.canvas.load_file(self.file_dirs[self.file_id]) self.adjustScale(initial=True) def open_file(self): path = '.' if len(self.file_dirs) > 0: path = os.path.dirname(str(self.file_dirs[0])) formats = [ '*.{}'.format(fmt.data().decode()) for fmt in QImageReader.supportedImageFormats() ] filters = "Image files (%s)" % ' '.join(formats) file_dir = QFileDialog.getOpenFileName(self, \ "Choose Image file", path, filters)[0] self.file_dirs = [file_dir] self.import_files() def open_dir(self): targetDirPath = str( QFileDialog.getExistingDirectory( self, 'Open Directory', '.', QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)) self.file_dirs = [] for fmt in QImageReader.supportedImageFormats(): pattern = os.path.join(targetDirPath, "*." + fmt.data().decode()) self.file_dirs += glob.glob(pattern) self.import_files() def next_img(self): if (len(self.file_dirs) > 0): self.file_id = (self.file_id + 1) % len(self.file_dirs) self.canvas.load_file(self.file_dirs[self.file_id]) self.adjustScale(initial=True) self.file_list_widget.setCurrentRow(self.file_id) def prev_img(self): if (len(self.file_dirs) > 0): self.file_id = (self.file_id + len(self.file_dirs) - 1) % len( self.file_dirs) self.canvas.load_file(self.file_dirs[self.file_id]) self.adjustScale(initial=True) self.file_list_widget.setCurrentRow(self.file_id) def import_files(self): self.load_file_list() self.file_id = 0 self.canvas.load_file(self.file_dirs[0]) self.adjustScale(initial=True) self.file_list_widget.setCurrentRow(self.file_id) def load_labels(self, label_file): self.label_list_widget.clear() for label in self.labels: item = QListWidgetItem(label) self.label_list_widget.addItem(item) def load_object_list(self, objects): self.object_list_widget.clear() for obj in objects: item = QListWidgetItem(obj.label) self.object_list_widget.addItem(item) def load_file_list(self): self.file_list_widget.clear() for image_dir in self.file_dirs: if not QFile.exists(image_dir): continue item = QListWidgetItem(image_dir) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) label_dir = os.path.splitext(image_dir)[0] + '.json' if QFile.exists(label_dir): item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) self.file_list_widget.addItem(item) def scaleFitWindow(self): """Figure out the size of the pixmap to fit the main widget.""" e = 2.0 # So that no scrollbars are generated. w1 = self.centralWidget().width() - e h1 = self.centralWidget().height() - e a1 = w1 / h1 # Calculate a new scale value based on the pixmap's aspect ratio. w2 = self.canvas.pixmap.width() - 0.0 h2 = self.canvas.pixmap.height() - 0.0 a2 = w2 / h2 return w1 / w2 if a2 >= a1 else h1 / h2 def scaleFitWidth(self): # The epsilon does not seem to work too well here. w = self.centralWidget().width() - 2.0 return w / self.canvas.pixmap.width() def adjustScale(self, initial=False): value = self.scalers[self.FIT_WINDOW if initial else self.zoomMode]() self.canvas.rescale(value) def zoom_in(self): value = self.canvas.scale self.canvas.rescale(value * 1.1) def zoom_out(self): value = self.canvas.scale self.canvas.rescale(value * 0.9) def zoom_org(self): print(self.centralWidget().width(), self.centralWidget().height()) print(self.canvas.pixmap.width(), self.canvas.pixmap.height()) print(self.canvas.width(), self.canvas.height()) print(self.canvas_area.width(), self.canvas_area.height()) self.adjustScale(initial=True) def new_rectangle(self): self.canvas.points = [] self.canvas.mode = self.canvas.RECTANGLE def new_auto_polygon(self): self.canvas.points = [] self.canvas.mode = self.canvas.AUTO_POLYGON def new_polygon(self): self.canvas.points = [] self.canvas.mode = self.canvas.POLYGON