QGraphicsView for image browsing

This commit is contained in:
BasioMeusPuga
2017-11-16 23:25:03 +05:30
parent b1b27cf3b9
commit d70d61a84e
3 changed files with 133 additions and 51 deletions

View File

@@ -34,6 +34,8 @@
✓ Keep fontsize and margins consistent - Let page increase in length ✓ Keep fontsize and margins consistent - Let page increase in length
✓ Fullscreening ✓ Fullscreening
✓ Remember open tabs ✓ Remember open tabs
Special Keyboard shortcuts and view modes for QGraphicsView
Selectable background color for QGraphicsView
Record progress Record progress
Pagination Pagination
Set context menu for definitions and the like Set context menu for definitions and the like
@@ -286,11 +288,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.tabWidget.removeTab(tab_index) self.tabWidget.removeTab(tab_index)
def set_toc_position(self, event=None): def set_toc_position(self, event=None):
chapter_name = self.bookToolBar.tocBox.currentText()
current_tab = self.tabWidget.widget(self.tabWidget.currentIndex()) current_tab = self.tabWidget.widget(self.tabWidget.currentIndex())
required_content = current_tab.metadata['content'][chapter_name]
# We're also updating the underlying model to have real-time # We're updating the underlying model to have real-time
# updates on the read status # updates on the read status
# Set a baseline model index in case the item gets deleted # Set a baseline model index in case the item gets deleted
@@ -314,14 +314,13 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.viewModel.setData( self.viewModel.setData(
model_index, current_tab.metadata['position'], QtCore.Qt.UserRole + 7) model_index, current_tab.metadata['position'], QtCore.Qt.UserRole + 7)
# current_tab.contentView.verticalScrollBar().setValue(0) current_tab.chapter_change()
current_tab.contentView.clear()
current_tab.contentView.setHtml(required_content)
def set_fullscreen(self): def set_fullscreen(self):
current_tab = self.tabWidget.currentIndex() current_tab = self.tabWidget.currentIndex()
current_tab_widget = self.tabWidget.widget(current_tab) current_tab_widget = self.tabWidget.widget(current_tab)
self.current_contentView = current_tab_widget.findChildren(QtWidgets.QTextBrowser)[0] self.current_contentView = current_tab_widget.findChildren(
(QtWidgets.QTextBrowser, QtWidgets.QGraphicsView))[0]
self.current_contentView.setWindowFlags(QtCore.Qt.Window) self.current_contentView.setWindowFlags(QtCore.Qt.Window)
self.current_contentView.setWindowState(QtCore.Qt.WindowFullScreen) self.current_contentView.setWindowState(QtCore.Qt.WindowFullScreen)
@@ -458,16 +457,8 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
return return
# Change contentView to match new settings # Change contentView to match new settings
current_tab = self.tabWidget.currentIndex() current_tab = self.tabWidget.widget(self.tabWidget.currentIndex())
current_tab_widget = self.tabWidget.widget(current_tab) current_tab.format_view(font, font_size, foreground, background, padding)
current_contentView = current_tab_widget.findChildren(QtWidgets.QTextBrowser)[0]
# This allows for the scrollbar to always be at the edge of the screen
current_contentView.setViewportMargins(padding, 0, padding, 0)
current_contentView.setStyleSheet(
"QTextEdit {{font-family: {0}; font-size: {1}px; color: {2}; background-color: {3}}}".format(
font, font_size, foreground, background))
def reset_profile(self): def reset_profile(self):
current_profile_index = self.bookToolBar.profileBox.currentIndex() current_profile_index = self.bookToolBar.profileBox.currentIndex()

View File

@@ -93,7 +93,7 @@ class ParseCBZ:
page_name = 'Page ' + str(count) page_name = 'Page ' + str(count)
image_path = os.path.join(extract_path, image_dir, i) image_path = os.path.join(extract_path, image_dir, i)
# contents[page_name] = image_path contents[page_name] = image_path
contents[page_name] = "<img src='%s' align='middle'/>" % image_path # contents[page_name] = "<img src='%s' align='middle'/>" % image_path
return contents, file_settings return contents, file_settings

View File

@@ -274,28 +274,14 @@ class Tab(QtWidgets.QWidget):
# Take hint from a position function argument to open the book # Take hint from a position function argument to open the book
# at a specific page # at a specific page
# The content display widget is currently a QTextBrowser
super(Tab, self).__init__(parent) super(Tab, self).__init__(parent)
self.parent = parent self.parent = parent
self.metadata = metadata # Save progress data into this dictionary self.metadata = metadata # Save progress data into this dictionary
self.gridLayout = QtWidgets.QGridLayout(self) self.gridLayout = QtWidgets.QGridLayout(self)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.contentView = PliantQTextBrowser(self.window())
self.contentView.setFrameShape(QtWidgets.QFrame.NoFrame)
self.contentView.setObjectName("contentView")
self.contentView.verticalScrollBar().setSingleStep(7)
self.contentView.setHorizontalScrollBarPolicy(
QtCore.Qt.ScrollBarAlwaysOff)
self.scroll_past_end_tries = 0
title = self.metadata['title']
position = self.metadata['position'] position = self.metadata['position']
relative_path_root = self.metadata['temp_dir']
relative_paths = []
for i in os.walk(relative_path_root):
relative_paths.append(os.path.join(relative_path_root, i[0]))
# TODO # TODO
# Chapter position and vertical scrollbar position # Chapter position and vertical scrollbar position
@@ -307,13 +293,42 @@ class Tab(QtWidgets.QWidget):
chapter_name = list(self.metadata['content'])[current_chapter - 1] chapter_name = list(self.metadata['content'])[current_chapter - 1]
chapter_content = self.metadata['content'][chapter_name] chapter_content = self.metadata['content'][chapter_name]
# The content display widget is, by default a QTextBrowser
# In case the incoming data is only images
# such as in the case of comic book files,
# we want a QGraphicsView widget doing all the heavy lifting
# instead of a QTextBrowser
self.are_we_doing_images_only = self.metadata['images_only']
if self.are_we_doing_images_only: # Boolean
self.contentView = PliantQGraphicsView(self.window())
self.contentView.loadImage(chapter_content)
self.setStyleSheet("background-color: black;")
else:
self.contentView = PliantQTextBrowser(self.window())
relative_path_root = self.metadata['temp_dir']
relative_paths = []
for i in os.walk(relative_path_root):
relative_paths.append(os.path.join(relative_path_root, i[0]))
self.contentView.setSearchPaths(relative_paths) self.contentView.setSearchPaths(relative_paths)
self.contentView.setOpenLinks(False) # Change this when HTML navigation works self.contentView.setOpenLinks(False) # Change this when HTML navigation works
self.contentView.setHtml(chapter_content) self.contentView.setHtml(chapter_content)
# The following are common to both the text browser and
# the graphics view
self.contentView.setFrameShape(QtWidgets.QFrame.NoFrame)
self.contentView.setObjectName("contentView")
self.contentView.verticalScrollBar().setSingleStep(7)
self.contentView.setHorizontalScrollBarPolicy(
QtCore.Qt.ScrollBarAlwaysOff)
self.generate_keyboard_shortcuts() self.generate_keyboard_shortcuts()
self.gridLayout.addWidget(self.contentView, 0, 0, 1, 1) self.gridLayout.addWidget(self.contentView, 0, 0, 1, 1)
title = self.metadata['title']
self.parent.addTab(self, title) self.parent.addTab(self, title)
def generate_position(self): def generate_position(self):
@@ -352,40 +367,116 @@ class Tab(QtWidgets.QWidget):
# self.exit_all.activated.connect(self.sneaky_exit) # self.exit_all.activated.connect(self.sneaky_exit)
def exit_fullscreen(self): def exit_fullscreen(self):
self.window().show()
self.contentView.setWindowFlags(QtCore.Qt.Widget) self.contentView.setWindowFlags(QtCore.Qt.Widget)
self.contentView.setWindowState(QtCore.Qt.WindowNoState) self.contentView.setWindowState(QtCore.Qt.WindowNoState)
self.contentView.show() self.contentView.show()
self.window().show()
def chapter_change(self):
chapter_name = self.window().bookToolBar.tocBox.currentText()
required_content = self.metadata['content'][chapter_name]
if self.are_we_doing_images_only:
self.contentView.loadImage(required_content)
else:
self.contentView.clear()
self.contentView.setHtml(required_content)
def format_view(self, font, font_size, foreground, background, padding):
self.contentView.setViewportMargins(padding, 0, padding, 0)
if self.are_we_doing_images_only:
self.contentView.setBackgroundBrush(
QtGui.QBrush(QtCore.Qt.black, QtCore.Qt.SolidPattern))
else:
self.contentView.setStyleSheet(
"QTextEdit {{font-family: {0}; font-size: {1}px; color: {2}; background-color: {3}}}".format(
font, font_size, foreground, background))
def sneaky_change(self): def sneaky_change(self):
direction = -1 direction = -1
if self.sender().objectName() == 'nextChapter': if self.sender().objectName() == 'nextChapter':
direction = 1 direction = 1
self.contentView.change_chapter(direction, True) self.contentView.common_functions.change_chapter(
direction, True)
def sneaky_exit(self): def sneaky_exit(self):
self.contentView.hide() self.contentView.hide()
self.window().closeEvent() self.window().closeEvent()
class PliantQGraphicsView(QtWidgets.QGraphicsView):
def __init__(self, main_window, parent=None):
super(PliantQGraphicsView, self).__init__(parent)
self.main_window = main_window
self.image_pixmap = None
self.ignore_wheel_event = False
self.ignore_wheel_event_number = 0
self.common_functions = PliantWidgetsCommonFunctions(self, self.main_window)
def loadImage(self, image_path):
self.image_pixmap = QtGui.QPixmap()
self.image_pixmap.load(image_path)
self.resizeEvent()
def resizeEvent(self, event=None):
if not self.image_pixmap:
return
profile_index = self.main_window.bookToolBar.profileBox.currentIndex()
current_profile = self.main_window.bookToolBar.profileBox.itemData(
profile_index, QtCore.Qt.UserRole)
padding = current_profile['padding']
available_width = self.viewport().width() - 2 * padding
if self.image_pixmap.width() > available_width:
image_pixmap = self.image_pixmap.scaledToWidth(
available_width, QtCore.Qt.SmoothTransformation)
else:
image_pixmap = self.image_pixmap
graphics_scene = QtWidgets.QGraphicsScene()
graphics_scene.addPixmap(image_pixmap)
self.setScene(graphics_scene)
self.show()
def wheelEvent(self, event):
self.common_functions.wheelEvent(event, True)
class PliantQTextBrowser(QtWidgets.QTextBrowser): class PliantQTextBrowser(QtWidgets.QTextBrowser):
def __init__(self, main_window, parent=None): def __init__(self, main_window, parent=None):
super(PliantQTextBrowser, self).__init__(parent) super(PliantQTextBrowser, self).__init__(parent)
self.main_window = main_window self.main_window = main_window
self.ignore_wheel_event = False self.ignore_wheel_event = False
self.ignore_wheel_event_number = 0 self.ignore_wheel_event_number = 0
self.common_functions = PliantWidgetsCommonFunctions(self, self.main_window)
def wheelEvent(self, event): def wheelEvent(self, event):
if self.ignore_wheel_event: self.common_functions.wheelEvent(event, False)
class PliantWidgetsCommonFunctions():
def __init__(self, parent_widget, main_window):
self.pw = parent_widget
self.main_window = main_window
def wheelEvent(self, event, are_we_doing_images_only):
if self.pw.ignore_wheel_event:
# Ignore first n wheel events after a chapter change # Ignore first n wheel events after a chapter change
self.ignore_wheel_event_number += 1 self.pw.ignore_wheel_event_number += 1
if self.ignore_wheel_event_number > 20: if self.pw.ignore_wheel_event_number > 20:
self.ignore_wheel_event = False self.pw.ignore_wheel_event = False
self.ignore_wheel_event_number = 0 self.pw.ignore_wheel_event_number = 0
return return
QtWidgets.QTextBrowser.wheelEvent(self, event) if are_we_doing_images_only:
QtWidgets.QGraphicsView.wheelEvent(self.pw, event)
else:
QtWidgets.QTextBrowser.wheelEvent(self.pw, event)
# Since this is a delta on a mouse move event, it cannot ever be 0 # Since this is a delta on a mouse move event, it cannot ever be 0
vertical_pdelta = event.pixelDelta().y() vertical_pdelta = event.pixelDelta().y()
@@ -396,19 +487,19 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
if abs(vertical_pdelta) > 100: # Adjust sensitivity here if abs(vertical_pdelta) > 100: # Adjust sensitivity here
# Implies that no scrollbar movement is possible # Implies that no scrollbar movement is possible
if self.verticalScrollBar().value() == self.verticalScrollBar().maximum() == 0: if self.pw.verticalScrollBar().value() == self.pw.verticalScrollBar().maximum() == 0:
if moving_up: if moving_up:
self.change_chapter(-1) self.change_chapter(-1)
else: else:
self.change_chapter(1) self.change_chapter(1)
# Implies that the scrollbar is at the bottom # Implies that the scrollbar is at the bottom
elif self.verticalScrollBar().value() == self.verticalScrollBar().maximum(): elif self.pw.verticalScrollBar().value() == self.pw.verticalScrollBar().maximum():
if not moving_up: if not moving_up:
self.change_chapter(1) self.change_chapter(1)
# Implies scrollbar is at the top # Implies scrollbar is at the top
elif self.verticalScrollBar().value() == 0: elif self.pw.verticalScrollBar().value() == 0:
if moving_up: if moving_up:
self.change_chapter(-1) self.change_chapter(-1)
@@ -422,12 +513,12 @@ class PliantQTextBrowser(QtWidgets.QTextBrowser):
# Set page position depending on if the chapter number is increasing or decreasing # Set page position depending on if the chapter number is increasing or decreasing
if direction == 1 or was_button_pressed: if direction == 1 or was_button_pressed:
self.verticalScrollBar().setValue(0) self.pw.verticalScrollBar().setValue(0)
else: else:
self.verticalScrollBar().setValue( self.pw.verticalScrollBar().setValue(
self.verticalScrollBar().maximum()) self.pw.verticalScrollBar().maximum())
self.ignore_wheel_event = True self.pw.ignore_wheel_event = True
class LibraryDelegate(QtWidgets.QStyledItemDelegate): class LibraryDelegate(QtWidgets.QStyledItemDelegate):