示例#1
0
class CPinUI(QWidget):
    def __init__(self, pinID, parent=None):
        super(CPinUI, self).__init__(parent)
        self.m_PinID = pinID
        self.m_NodeID = interface.GetNodeIDByPinID(pinID)
        self.m_GraphicID = interface.GetGraphicIDByNodeID(self.m_NodeID)
        self.m_Btn = None
        self.m_Label = None
        self.m_HLayout = None
        self.m_DefaultWidget = None  # 默认值控件
        self._InitUI()
        self.SetIcon()
        self.SetText()
        self.ShowDefaultWidget()
        GetUIMgr().AddPinUI(pinID, self)

    def __del__(self):
        GetUIMgr().DelPinUI(self.m_PinID)

    def _InitUI(self):
        hBox = QHBoxLayout(self)
        hBox.setContentsMargins(0, 0, 0, 0)
        hBox.setSpacing(6)
        self.m_Btn = CTypeButton(self.m_PinID, self)
        self.m_Label = QLabel(self)
        self.m_HLayout = QHBoxLayout()
        self.m_HLayout.setContentsMargins(0, 0, 0, 0)
        self.m_HLayout.setSpacing(6)
        hBox.addWidget(self.m_Btn)
        hBox.addWidget(self.m_Label)
        hBox.addLayout(self.m_HLayout)

    def contextMenuEvent(self, event):
        super(CPinUI, self).contextMenuEvent(event)
        lstLineID = interface.GetAllLineByPin(self.m_PinID)
        menu = QMenu()
        for lineID in lstLineID:
            oPinID = interface.GetLineOtherPin(lineID, self.m_PinID)
            sPinDisplayName = interface.GetPinAttr(oPinID, bddefine.PinAttrName.DISPLAYNAME)
            nodeID = interface.GetNodeIDByPinID(oPinID)
            sNodeDisplayName = interface.GetNodeAttr(nodeID, bddefine.NodeAttrName.DISPLAYNAME)
            sMsg = "删除与\"%s\"-\"%s\"的连线" % (sNodeDisplayName, sPinDisplayName)
            func = functor.Functor(interface.DelLine, lineID)
            menu.addAction(sMsg, func)
        menu.exec_(QCursor.pos())
        event.accept()

    def SetIcon(self, iDataType=None):
        if iDataType is None:
            iPinType = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.PIN_TYPE)
            if bddefine.PinIsFlow(iPinType):
                iDataType = -1
            else:
                iDataType = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.DATA_TYPE)
        icon = QIcon()
        pix = ":/icon/btn_%s.png" % iDataType
        icon.addPixmap(QPixmap(pix), QIcon.Normal, QIcon.Off)
        self.m_Btn.setIcon(icon)

    def SetText(self, sText=None):
        if sText is None:
            sText = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.DISPLAYNAME)
        self.m_Label.setText(sText)

    def ShowDefaultWidget(self):
        iPinType = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.PIN_TYPE)
        if iPinType != bddefine.PIN_INPUT_DATA_TYPE:
            return
        lstLine = interface.GetAllLineByPin(self.m_PinID)
        if lstLine:
            return
        oWidget = None
        iDataTye = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.DATA_TYPE)
        if iDataTye in (bddefine.Type.INT, bddefine.Type.FLOAT, bddefine.Type.STR):
            oWidget = subpinui.CValidatorLineEdit(self.m_PinID, iDataTye)
        elif iDataTye == bddefine.Type.BOOL:
            oWidget = subpinui.CCheckBox(self.m_PinID)
        elif iDataTye == bddefine.Type.ENUM:
            oWidget = subpinui.CEnum(self.m_PinID)
        elif iDataTye == bddefine.Type.VECTOR3:
            oWidget = subpinui.CVector3(self.m_PinID)
        elif iDataTye == bddefine.Type.CHECKBOX:
            oWidget = subpinui.CComCheckBox(self.m_PinID)
        if oWidget:
            self.m_HLayout.addWidget(oWidget)
            self.m_DefaultWidget = oWidget
            self.adjustSize()

    def HideDefaultWidget(self):
        if not self.m_DefaultWidget:
            return
        self.m_DefaultWidget.setParent(None)
        index = self.m_HLayout.indexOf(self.m_DefaultWidget)
        item = self.m_HLayout.itemAt(index)
        self.m_HLayout.removeWidget(self.m_DefaultWidget)
        self.m_HLayout.removeItem(item)
        self.m_DefaultWidget = None
        self.adjustSize()

    def enterEvent(self, event):
        super(CPinUI, self).enterEvent(event)
        GetSignal().UI_LINE_CONNECT.emit(self.m_GraphicID, self.m_PinID)
        event.accept()
示例#2
0
class GuiWindow(QMainWindow):
    def __init__(self, controller, base_img_fp: str):
        super(GuiWindow, self).__init__()
        # self.app = QApplication([])

        self.img_manager = ImageManager(base_img_fp)

        self._file_path = base_img_fp

        self._anim_thread = None
        self._anim_worker = None
        self.animation_widget = None

        self._current_chunk_size = 0

        self.setWindowTitle("Don't Feel Good Inc.")

        self.controller = controller
        self.create_content()
        self.show()

    def create_content(self):
        self.snap_sound = PyQt5.QtMultimedia.QSound("snap_ex.wav")

        # Build the components first

        # Build a textbox for the filepath.

        self.outer_widget = PyQt5.QtWidgets.QWidget(
            self)  # Dummy outer widget needed so that we can add others to it

        # This is the frame to hold the options.
        self.main_frame = PyQt5.QtWidgets.QGroupBox(
            self.outer_widget
        )  # Specifying parent=self locks it within the current window
        # self.main_frame.setTitle("Parameters")

        # The main layout for the param box and the image
        self.main_layout_wide = QHBoxLayout(self.main_frame)

        self.input_frame = QWidget(self.outer_widget)

        self.main_layout_wide.addWidget(self.input_frame)

        self.input_frame_layout = QVBoxLayout(self.input_frame)

        # Now, adding the parts back in...

        self.textbox = QLabel(self.input_frame)
        self.textbox.setText(self._file_path)

        self.load_file_button = PyQt5.QtWidgets.QPushButton(self.input_frame)
        self.load_file_button.setText("Browse for file")

        self.load_file_button.clicked.connect(self.on_load)

        self.gain_slider_label = PyQt5.QtWidgets.QLabel(self.input_frame)
        self.gain_slider_label.setText("Custom adjustment")

        self.gain_slider = PyQt5.QtWidgets.QSlider(Qt.Horizontal,
                                                   self.input_frame)
        self.gain_slider.valueChanged.connect(self.on_gain_slider_adjust)

        # size slider

        self.chunk_slider_label = PyQt5.QtWidgets.QLabel(self.input_frame)
        self.chunk_slider_label.setText("Chunk size")

        self.chunk_size_slider = PyQt5.QtWidgets.QSlider(
            Qt.Horizontal, self.input_frame)

        # Start this in the middle so we don't get a div/0

        self.chunk_size_slider.setSliderPosition(40)

        self.chunk_size_slider.valueChanged.connect(
            self.on_chunk_slider_adjust)

        # This needs to be controlled with a single button press as it'll involve reloading the object
        self.chunk_size_button = PyQt5.QtWidgets.QPushButton(
            "Apply chunk size", self.input_frame)

        self.chunk_size_button.clicked.connect(self.on_chunk_click)

        # self.go_button = PyQt5.QtWidgets.QPushButton("*snap*", self.input_frame)
        #
        # self.go_button.clicked.connect(self.on_snap)

        self.full_snap_button = PyQt5.QtWidgets.QPushButton(
            "*snap*", self.input_frame)

        self.full_snap_button.clicked.connect(self.display_animation)

        self.reset_button = PyQt5.QtWidgets.QPushButton(
            "Use the time stone (reset)", self.input_frame)

        self.reset_button.clicked.connect(self.on_reset)

        self.input_frame_layout.addWidget(self.textbox)
        self.input_frame_layout.addWidget(self.load_file_button)
        self.input_frame_layout.addWidget(self.chunk_slider_label)
        self.input_frame_layout.addWidget(self.chunk_size_slider)
        self.input_frame_layout.addWidget(self.chunk_size_button)
        self.input_frame_layout.addWidget(self.gain_slider_label)
        self.input_frame_layout.addWidget(self.gain_slider)
        # self.input_frame_layout.addWidget(self.go_button)
        self.input_frame_layout.addWidget(self.full_snap_button)
        self.input_frame_layout.addWidget(self.reset_button)

        # Trying something else out

        self.image_frame = QFrame(self)

        # Creating the second container

        self.image_widget = ImageWidget(self._file_path, self.outer_widget)

        self.main_layout_wide.addWidget(self.image_widget)

        # self.main_layout.addLayout(self.main_frame)

        self.setCentralWidget(self.outer_widget)

        self.setFixedSize(self.main_layout_wide.sizeHint())

        self.on_chunk_click()

        # Make sure we're ready to handle an animation if the need arises
        # AnimationReadyEmitter.trigger.connect(self.display_animation)

        # self.main_frame.show()

    def on_load(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.ExistingFile)
        new_path, _ = dlg.getOpenFileName(None, "Open file",
                                          "%userprofile%\\Pictures\\")
        if new_path == ("", ""):
            return
        if not os.path.exists(new_path):
            self.textbox.setStyleSheet("color: rgb(255, 0, 0);")
        else:
            self.textbox.setStyleSheet("color: rgb(0, 0, 0);")

            self._file_path = new_path
            self.textbox.setText(self._file_path)
            self.img_manager = ImageManager(new_path)
            q_pixmap = PyQt5.QtGui.QPixmap(self._file_path)

            self.image_widget.setPixmap(q_pixmap)
            self.image_widget.resize(q_pixmap.width(), q_pixmap.height())
            self.main_frame.resize(self.main_layout_wide.sizeHint())
            self.setFixedSize(self.main_layout_wide.sizeHint())

    def display_animation(self):
        self.snap_sound.play()
        self._anim_worker = AnimWorker(self.img_manager, True)
        self._anim_thread = QThread()
        self._anim_worker.moveToThread(self._anim_thread)

        self._anim_worker.anim_done.connect(self.on_animation_complete)

        self._anim_thread.started.connect(self._anim_worker.work)

        self.full_snap_button.setDisabled(True)

        self._anim_thread.start()

    @pyqtSlot(str)
    def on_animation_complete(self, file_path: str):
        """Replace the original image widget until the movie completes, and then change it back"""
        self.animation_widget = AnimationWidget(file_path, self.outer_widget)
        self.full_snap_button.setDisabled(False)

        # self.main_layout_wide.replaceWidget(self.image_widget, self.animation_widget)
        prev_image_ix = self.main_layout_wide.indexOf(self.image_widget)
        # self.main_layout_wide.removeWidget(self.image_widget)
        self.image_widget.hide()  # FIXME Yuck
        self.main_layout_wide.addWidget(self.animation_widget, Qt.Horizontal)
        self.animation_widget.movie.finished.connect(
            self.replace_original_img_widget)
        # self.animation_widget.movie.setScaledSize(QSize(900, 900))
        self.animation_widget.movie.start()
        self.animation_widget.show()

    @pyqtSlot()
    def replace_original_img_widget(self):
        self.animation_widget.movie.stop()  # This is needed to
        self.animation_widget.hide()
        self.image_widget.show()
        self.main_layout_wide.removeWidget(self.animation_widget)
        self.main_layout_wide.insertWidget(1, self.image_widget)
        self.main_layout_wide.replaceWidget(self.animation_widget,
                                            self.image_widget)

    def on_snap(self):
        self.snap_sound.play()
        self.reload_image()

    def on_full_snap(self):
        for i in reversed(range(1, 101)):
            self.gain_slider.setSliderPosition(i)
            self.reload_image()
            sleep(3 / i**2)
            # sleep(1)

    def reload_image(self):
        """
        Reload the image within the current frame, asking the underlying functions to recalculate
        based on its current values.
        """
        img = self.img_manager.update_image()

        q_image = PyQt5.QtGui.QImage.fromData(img.read())
        q_pixmap = PyQt5.QtGui.QPixmap.fromImage(q_image)

        self.image_widget.setPixmap(q_pixmap)

    def on_gain_slider_adjust(self):
        new_value = self.gain_slider.value()
        # TODO Scale this
        print(new_value)
        self.img_manager.gain = new_value
        if self.img_manager.chunk_size > 10:
            self.reload_image()

    def on_chunk_slider_adjust(self):
        if self.chunk_size_slider.value() != self._current_chunk_size:
            self.chunk_size_button.setDisabled(False)

    def on_chunk_click(self):
        new_value = self.chunk_size_slider.value(
        ) + 1  # Make sure it's never equal to 0
        self.img_manager.chunk_size = new_value
        self.chunk_size_button.setDisabled(True)

    def on_reset(self):
        self.img_manager.reset()
        self.gain_slider.setValue(0)
        q_pixmap = PyQt5.QtGui.QPixmap(self._file_path)

        self.image_widget.setPixmap(q_pixmap)
示例#3
0
class SpaceLineEdit(QWidget):
    SPLIT_CHARS = ' ,;'

    def __init__(self, parent=None, validator=None, flags=Qt.WindowFlags()):
        # type: (QWidget, QValidator, Qt.WindowFlags) -> None
        super(SpaceLineEdit, self).__init__(parent, flags)
        self.setFocusPolicy(Qt.StrongFocus)
        self._validator = validator
        self._layout = QHBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._prepareLineEdit(0)

    def setValidator(self, validator):  # type: (QValidator) -> None
        self._validator = validator

    def getValues(self):  # type: () -> List[str]
        values = []
        for index in range(self._layout.count()):
            text = self._layout.itemAt(index).widget().text()
            values.append(text)
        return values

    def setValues(self, values):  # type: (List[str]) -> None
        self._cleanAll()
        if not values:
            values = ['']
        for index, value in enumerate(values):
            self._prepareLineEdit(index, value)

    def _cleanAll(self):
        for index in reversed(range(self._layout.count())):
            widget = self._layout.takeAt(index).widget()  # type: QWidget
            widget.setParent(None)
            widget.deleteLater()

    def _prepareLineEdit(self, position, text=''):  # type: (int, str) -> None
        lineEdit = QLineEdit(str(text), self)
        lineEdit.setValidator(self._validator)
        lineEdit.textChanged.connect(partial(self.onTextChanged, lineEdit))
        lineEdit.installEventFilter(self)
        self._layout.insertWidget(position, lineEdit)

    def focusInEvent(self, event):
        item = self._layout.itemAt(0)
        if item:
            item.widget().setFocus()

    def onTextChanged(self, lineEdit, text):  # type: (QLineEdit, str) -> None
        if not text:
            self._removeLineEdit(lineEdit)

        text = self._convert(text)
        if self._isSplit(text):
            self._addLineEdit(lineEdit, text)

    def _removeLineEdit(self,
                        lineEdit,
                        changeFocus=True):  # type: (QLineEdit, bool) -> None
        if self._layout.count() <= 1:
            return

        if changeFocus:
            if not self._setFocus(lineEdit, offset=-1):
                self._setFocus(lineEdit, offset=1)

        self._layout.removeWidget(lineEdit)
        lineEdit.deleteLater()

    @staticmethod
    def _convert(text):  # type: (str) -> str
        for sch in SpaceLineEdit.SPLIT_CHARS[1:]:
            text = text.replace(sch, ' ')
        return text

    @staticmethod
    def _isSplit(text):  # type: (str) -> bool
        return ' ' in text

    def _addLineEdit(self, lineEdit, text):  # type: (QLineEdit, str) -> None
        texts = text.split()
        if not texts:
            lineEdit.setText('')
            return
        else:
            lineEdit.setText(texts[0])

        if len(texts) == 1:
            texts.append('')

        insertIndex = self._layout.indexOf(lineEdit) + 1
        for index, text in enumerate(texts[1:], insertIndex):
            self._prepareLineEdit(index, text)

        self._setFocus(lineEdit, offset=1)

    def eventFilter(self, watched, event):  # type: (QWidget, QEvent) -> bool
        if isinstance(watched, QLineEdit):
            lineEdit = watched  # type: QLineEdit

            if event.type() == QEvent.FocusOut and not lineEdit.text():
                self._removeLineEdit(lineEdit, changeFocus=False)

            elif event.type() == QEvent.KeyPress and isinstance(
                    event, QKeyEvent):
                if event.key() == Qt.Key_Backspace and not lineEdit.text():
                    self._removeLineEdit(lineEdit)

                if event.key() == Qt.Key_Down:
                    self._setFocus(lineEdit, offset=1)
                elif event.key() == Qt.Key_Up:
                    self._setFocus(lineEdit, offset=-1)

        return super(SpaceLineEdit, self).eventFilter(watched, event)

    def _setFocus(self, lineEdit, offset):  # type: (QLineEdit, int) -> bool
        index = self._layout.indexOf(lineEdit) + offset
        item = self._layout.itemAt(index)
        if item:
            item.widget().setFocus(Qt.OtherFocusReason)
            return True

        return False
示例#4
0
class View(QWidget):

    def __init__(self, W):
        self.W = int(W)
        super().__init__()
        self.sounds = Models(self)
        self.sounds.initSound()
        self.image_index = 0        # Keeps track of the first image in image list to be displayed in the thumbnail bar
        self.mode = 0         # Determines and Tracks current mode of view (1 - Full Screen, 0 - Thumbnail)
        self.selected_index = 0     # Keeps track of the current selected index in the thumbnail bar
        self.loadTags()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("Image Browser")
        self.setStyleSheet("background-color: #324d7a")
        self.H = (self.W/4)*3
        self.move(250, 250)
        self.setFixedSize(self.W, self.H)

        # Setting-up Layout for images
        self.layout = QHBoxLayout(self)     # Creates a Horizontal Layout
        self.layout.setContentsMargins(20, 0, 20, 0)    # Removes margins around stored object in the layout
        self.layout.setSpacing(0)           # Removes spaces between layout objects
        self.layout.setAlignment(Qt.AlignCenter)    # Pushes image to the top of the window

        # Setting-up text box for adding tags
        self.textBox = QLineEdit(self)
        self.textBox.setStyleSheet("QLineEdit{ background: #f8f8f8; selection-background-color: #f8f8f8; }")
        self.textBox.setPlaceholderText("Enter your tags here")
        self.textBox.resize(self.W/2,self.H/10)
        self.textBox.move(20, self.H*(5/6))

        # Setting-up add and save buttons for tags
        self.addButton = QPushButton('Add Tag', self)
        self.addButton.setStyleSheet("background-color: #F5F5F5")
        self.addButton.move(self.W/1.9,self.H*(5/6))
        self.addButton.resize(self.W/6, self.H/10)
        self.addButton.clicked.connect(self.addTag)

        self.saveButton = QPushButton('Save Tags', self)
        self.saveButton.setStyleSheet("background-color: #F5F5F5")
        self.saveButton.move(self.W/1.42,self.H*(5/6))
        self.saveButton.resize(self.W/6, self.H/10)
        self.saveButton.clicked.connect(self.saveTags)

        # Setting up layout for holding tags
        self.tagList = QVBoxLayout()
        self.tagList.setSpacing(10)
        self.tagList.setContentsMargins(40, 0, 5, 0)

        self.textBox.hide()
        self.addButton.hide()
        self.saveButton.hide()

        self.thumbnail_bar()
        self.select(0) # Selects first image-box in layou
        self.show()

    def thumbnail_bar(self):     # Creates a List of QLabels and places them in a horizontal Layout
        labels = []
        for i in range(0, 6):
            labels.insert(i, QLabel(self))
            if i != (5):
                labels[i].setPixmap(QPixmap("data/"+Models.images[i]).scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))      # Sets images to each label in layout
                labels[i].setFixedSize((self.W-40)/5, (self.W-40)/5)
            labels[i].setAlignment(Qt.AlignCenter)      # Align images to the center of the label
            labels[i].setStyleSheet('border: 10px solid red')
            self.layout.addWidget(labels[i])        # Add label into layout container
            clickable(self.getWidget(i)).connect(self.indexOfLabel)     # Connects the click even to the indexOfLabel function

        # Properties of full screen view label:
        self.getWidget(5).setStyleSheet('border: 20px solid red')
        self.getWidget(5).setFixedSize(self.W/1.33, self.H/1.28)
        self.getWidget(5).hide()

    def drawTags(self):
        image_key = str((self.image_index+self.selected_index)%len(Models.images))
        if image_key in self.tags:
            for i in range(0, len(self.getTags())):
                self.getTags().itemAt(0).widget().setParent(None)
            for tag in self.tags[image_key]:
                self.getTags().addWidget(QPushButton(tag, self))
                self.getTags().itemAt(len(self.getTags())-1).widget().setStyleSheet("background-color: #f5f5f5")
        else:
            for i in range(0, len(self.getTags())):
                item = self.getTags().itemAt(0).widget().setParent(None)


    def enlarge(self, index):    # Makes necessary changes to change to Full Screen (Window Fill) Mode
        self.sounds.expand_sound.play()
        self.layout.addLayout(self.tagList)     # Adding TagList layout to main layout
        self.mode = 1
        self.selected_index = index
        pixContainer = self.getWidget(index).pixmap()
        for i in range(0, 5):
            self.getWidget(i).hide()
        self.getWidget(5).show()    # Shows label that displays in full screen
        self.getWidget(5).setPixmap(pixContainer.scaled((self.W/1.33)-40, (self.H/1.28)-40, Qt.KeepAspectRatio))   # Sets image in selected label to full screen label
        self.layout.setContentsMargins(0, 0, 0, 0)    # Pushes image to the top of the window
        self.layout.setAlignment(Qt.AlignTop | Qt.AlignLeft)    # Pushes image to the top of the window
        self.getTags().setAlignment(Qt.AlignRight)
        self.textBox.show()
        self.addButton.show()
        self.saveButton.show()
        self.drawTags()


    def circularTraverse(self, steps, direction):    # Responsible for Circular Traversing the image list in the given direction
        if direction == "left":
            return (self.image_index-steps)%(len(Models.images))
        else:
            return (self.image_index+steps)%(len(Models.images))

    def select(self, selected_index):   # Selects new item
        self.getWidget(self.selected_index).setStyleSheet("border: 10px solid red")   # Changes old image box to not selected border
        self.getWidget(selected_index).setStyleSheet("border: 10px solid green")    # Changes new image box to selected border
        self.selected_index = selected_index      # Updates Current selection index

    def shiftLeft(self):            # Shifts the select box and scope of the Thumbnail Bar to the left
        if self.selected_index != 0:         # Shift select box till first image
            if self.mode == 1:
                pixContainer = self.getWidget(self.selected_index-1).pixmap()
                self.getWidget(5).setPixmap(pixContainer.scaled((self.W/1.33)-40, (self.H/1.28)-40, Qt.KeepAspectRatio))
            self.select(self.selected_index-1)

        else:
            if 5 == 5:       # If there are more than 5 images, shift scope of Thumbnail Bar to left
                for i in range(4, 0, -1):     # Shifts scope
                    self.getWidget(i).setPixmap(self.getWidget(i-1).pixmap().scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
                self.getWidget(0).setPixmap(QPixmap("data/"+Models.images[self.circularTraverse(1, "left")]).scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
                if self.mode == 1:     # If in full screen mode, load previous image
                    self.getWidget(5).setPixmap(self.getWidget(0).pixmap().scaled((self.W/1.33)-40, (self.H/1.28)-40, Qt.KeepAspectRatio))
                self.image_index = self.circularTraverse(1, "left")

    def shiftRight(self):       # Shifts the select box and scope of the Thumbnail Bar to the right
        if self.selected_index != 4:      # Shift select box till last image
            if self.mode == 1:
                pixContainer = self.getWidget(self.selected_index+1).pixmap()
                self.getWidget(5).setPixmap(pixContainer.scaled((self.W/1.33)-40, (self.H/1.28)-40, Qt.KeepAspectRatio))
            self.select(self.selected_index+1)
        else:
            if 5 == 5:      # If there are more than 5 images, shift scope of Thumbnail Bar to rght
                for i in range(0, 4):    # Shifts scope
                    self.getWidget(i).setPixmap(self.getWidget(i+1).pixmap().scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
                self.getWidget(4).setPixmap(QPixmap("data/"+Models.images[self.circularTraverse(5, "right")]).scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
                if self.mode == 1:    # If in full screen mode, load next image
                    self.getWidget(5).setPixmap(self.getWidget(4).pixmap().scaled((self.W/1.33)-40, (self.H/1.28)-40, Qt.KeepAspectRatio))
                self.image_index = self.circularTraverse(1, "right")

    def shrink(self, index):     # Makes necessary changes to change back to Thumbnail Mode
        self.sounds.expand_sound.play()
        self.mode = 0       # Upadates mode variable
        self.getWidget(5).hide()    # Hides full screen label
        for i in range(0,5):    # Un-hides thumbnail labels
            self.getWidget(i).show()
        self.layout.setContentsMargins(20, 0, 20, 0)
        self.layout.setAlignment(Qt.AlignVCenter)    # Pushes image to the top of the window
        self.textBox.hide()
        self.addButton.hide()
        self.saveButton.hide()
        for i in range(0, len(self.getTags())):
            self.getTags().itemAt(0).widget().setParent(None)
        self.layout.removeItem(self.tagList)




#=========================================== EVENT HANDLERS =========================================

    def loadTags(self):
        # If file exists, open and load tags. If does not exist, initialize empty tags dictionary
        try:
            f = open("tags.json","r")
            self.tags = json.load(f)
            f.close()
        except:
            self.tags = {}

    def addTag(self):
        # Add tag if not empty string or spaces
        if not (self.textBox.text().isspace() or self.textBox.text() == ""):
            image_key = str((self.image_index+self.selected_index)%len(Models.images)) # Generating image key for dictionary from unique combination of image_index and selected_index
            if image_key not in self.tags:      # If no tags exist, create a new list for tags
                self.tags[image_key] = []
            self.tags[image_key].append(self.textBox.text())    # Append to the tags lis of image
            self.textBox.setText("")
            self.setFocus()     # Return focus to main window
            self.drawTags()

    def saveTags(self):
        f = open("tags.json", "w+")        # Create file if does not exist
        json.dump(self.tags, f)     # save tags in file
        print("{} saved".format(self.tags))
        f.close()
        self.setFocus()     # Return focus back to window

    def getWidget(self, index):     # Gets stored widget from layout in the passed index
        return self.layout.itemAt(index).widget()

    def getTags(self):
        return self.layout.itemAt(6).layout()

    def indexOfLabel(self, label):      # Provides the index of the clicked label for further operations
        self.setFocus()
        if self.mode == 0:
            self.select(self.layout.indexOf(label))
            self.enlarge(self.layout.indexOf(label))

    def keyPressEvent(self, e):     # Handles all key press events
        if e.key() == Qt.Key_Right:
            self.sounds.select_sound.play()
            self.shiftRight()
            if self.mode == 1:
                self.drawTags()


        if e.key() == Qt.Key_Left:
            self.sounds.select_sound.play()
            self.shiftLeft()
            if self.mode == 1:
                self.drawTags()

        elif e.key() == Qt.Key_Period and self.mode == 0 and 5 == 5:    # Moves to the next 5 images only if there are enough images to overflow
            self.sounds.next_set_sound.play()
            self.image_index=self.circularTraverse(5, "right")
            for i in range(0,5):
                self.getWidget(i).setPixmap(QPixmap("data/"+Models.images[self.circularTraverse(i, "right")]).scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
            self.select(0)

        elif e.key() == Qt.Key_Comma and self.mode == 0 and 5 == 5:     # Moves to the previous 5 images only if there are enough images to overflow
            self.sounds.next_set_sound.play()
            self.image_index=self.circularTraverse(5, "left")
            for i in range(0,5):
                self.getWidget(i).setPixmap(QPixmap("data/"+Models.images[self.circularTraverse(i, "right")]).scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
            self.select(0)

        elif e.key() == Qt.Key_Up and self.mode == 0:
            self.enlarge(self.selected_index)

        elif e.key() == Qt.Key_Down and self.mode == 1:
            self.setFocus()
            self.shrink(self.selected_index)
            if 5 == 5:      # Checks if there are more than 5 images
                center_distance = self.selected_index - 2      # Calculates the distance of the seleted image from the center box
                if center_distance > 0:     # Checks if the selected image is right of center
                    # Shifts thumbnail bar accordingly to place selected image in middle on coming back to thumbnai bar mode:
                    for i in range(0, center_distance):
                        for j in range(0,4):
                            self.getWidget(j).setPixmap(self.getWidget(j+1).pixmap().scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
                        self.getWidget(4).setPixmap(QPixmap("data/"+Models.images[self.circularTraverse(5, "right")]).scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
                        self.image_index = self.circularTraverse(1, "right")
                elif center_distance < 0:      # Checks if selected image is left of center
                    # Shifts thumbnail bar accordingly to place selected image in middle on coming back to thumbnai bar mode:
                    for i in range(0, abs(center_distance)):
                        for j in range(4, 0, -1):
                            self.getWidget(j).setPixmap(self.getWidget(j-1).pixmap().scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
                        self.getWidget(0).setPixmap(QPixmap("data/"+Models.images[self.circularTraverse(1, "left")]).scaled(((self.W-40)/5)-20, ((self.W-40)/5)-20, Qt.KeepAspectRatio))
                        self.image_index = self.circularTraverse(1, "left")
                self.select(2)

        elif e.key() == Qt.Key_Escape:      # Returns focus back to main window
            self.setFocus()