Exemple #1
0
class CollapsibleBox(QWidget):
    def __init__(self, title="", parent=None):
        super(CollapsibleBox, self).__init__(parent)

        self.toggle_button = QToolButton(text=title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

        self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.content_area.setFrameShape(QFrame.NoFrame)

        lay = QVBoxLayout(self)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.toggle_button)
        lay.addWidget(self.content_area)

        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area, b"maximumHeight"))

    @pyqtSlot()
    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def setContentLayout(self, layout):
        lay = self.content_area.layout()
        del lay
        self.content_area.setLayout(layout)
        collapsed_height = self.sizeHint().height(
        ) - self.content_area.maximumHeight()
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(500)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(500)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
Exemple #2
0
    def step_ani(self, is_back=False):
        title_move_ani, title_fade_ani = self.fade_to_left_ani(self.title)
        content1_move_ani, content1_fade_ani = self.fade_to_left_ani(
            self.content1)
        content2_move_ani, content2_fade_ani = self.fade_to_left_ani(
            self.content2)
        form_move_ani, form_fade_ani = self.fade_to_left_ani(self.form)

        # 动画队列
        ani_group = QParallelAnimationGroup(self)
        ani_group.addAnimation(title_move_ani)
        ani_group.addAnimation(title_fade_ani)
        ani_group.addAnimation(content1_move_ani)
        ani_group.addAnimation(content1_fade_ani)
        ani_group.addAnimation(content2_move_ani)
        ani_group.addAnimation(content2_fade_ani)
        ani_group.addAnimation(form_move_ani)
        ani_group.addAnimation(form_fade_ani)

        if is_back:
            ani_group.setDirection(ani_group.Backward)

        ani_group.start()

        return ani_group
Exemple #3
0
    def step_ani(self, is_back=False):
        img_ani = QPropertyAnimation(self.img, b'geometry', self)
        img_ani.setStartValue(QRect(0, 0, self.img_width, self.img_height))
        img_ani.setEndValue(
            QRect(0, -self.img_height * 2, self.img_width * 2,
                  self.img_height * 2))
        img_ani.setDuration(200)
        img_ani.setEasingCurve(QEasingCurve.OutCurve)

        title_ani = QPropertyAnimation(self.title, b'pos', self)
        title_ani.setStartValue(QPoint(self.title_x, self.title_y))
        title_ani.setEndValue(QPoint(244, 78))
        title_ani.setDuration(200)
        title_ani.setEasingCurve(QEasingCurve.OutCurve)

        content1_ani = QPropertyAnimation(self.content1, b'pos', self)
        content1_ani.setStartValue(QPoint(self.content1_x, self.content1_y))
        content1_ani.setEndValue(QPoint(244, 112))
        content1_ani.setDuration(200)
        content1_ani.setEasingCurve(QEasingCurve.OutCurve)

        content2_ani = QPropertyAnimation(self.content2, b'pos', self)
        content2_ani.setStartValue(QPoint(self.content2_x, self.content2_y))
        content2_ani.setEndValue(QPoint(244, 134))
        content2_ani.setDuration(200)
        content2_ani.setEasingCurve(QEasingCurve.OutCurve)

        # 动画队列
        ani_group = QParallelAnimationGroup(self)
        ani_group.addAnimation(img_ani)
        ani_group.addAnimation(title_ani)
        ani_group.addAnimation(content1_ani)
        ani_group.addAnimation(content2_ani)

        if is_back:
            ani_group.setDirection(ani_group.Backward)

        ani_group.start()

        return ani_group
Exemple #4
0
class Spoiler(QWidget):
    def __init__(self, title="", animationDuration=300, parent=None):
        QWidget.__init__(self, parent)

        self.mainLayout = QGridLayout()
        self.toggleButton = QToolButton()
        self.toggleAnimation = QParallelAnimationGroup()
        self.contentArea = QScrollArea()
        self.headerLine = QFrame()
        self.animationDuration = animationDuration

        self.toggleButton.setStyleSheet("QToolButton { border: none; }")
        self.toggleButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggleButton.setArrowType(Qt.ArrowType.RightArrow)
        self.toggleButton.setText(title)
        self.toggleButton.setCheckable(True)
        self.toggleButton.setChecked(False)

        self.headerLine.setFrameShape(QFrame.HLine)
        self.headerLine.setFrameShadow(QFrame.Sunken)
        self.headerLine.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Maximum)

        self.contentArea.setStyleSheet(
            "QScrollArea { background-color: white; border: none; }")
        self.contentArea.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Fixed)

        self.contentArea.setMaximumHeight(0)
        self.contentArea.setMinimumHeight(0)
        # let the entire widget grow and shrink with its content
        self.toggleAnimation.addAnimation(QPropertyAnimation())
        self.toggleAnimation.addAnimation(QPropertyAnimation(self))
        self.toggleAnimation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggleAnimation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggleAnimation.addAnimation(
            QPropertyAnimation(self.contentArea, b"maximumHeight"))

        # don't waste space
        self.mainLayout.setVerticalSpacing(0)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        row = 0
        self.mainLayout.addWidget(self.toggleButton, 0, 0, 1, 1, Qt.AlignLeft)
        self.mainLayout.addWidget(self.headerLine, 0, 2, 1, 1)
        self.mainLayout.addWidget(self.contentArea, 1, 0, 1, 3)
        self.setLayout(self.mainLayout)

        self.toggleButton.clicked[bool].connect(self.expandShrinkContent)

    def expandShrinkContent(self, checked):
        if checked:
            self.toggleButton.setArrowType(Qt.ArrowType.DownArrow)
            self.toggleAnimation.setDirection(QAbstractAnimation.Forward)

        else:
            self.toggleButton.setArrowType(Qt.ArrowType.RightArrow)
            self.toggleAnimation.setDirection(QAbstractAnimation.Backward)

        self.toggleAnimation.start()

    def setContentLayout(self, contentLayout):

        self.contentArea.setLayout(contentLayout)
        collapsedHeight = self.sizeHint().height(
        ) - self.contentArea.maximumHeight()
        contentHeight = contentLayout.sizeHint().height()
        i = 0
        while i < self.toggleAnimation.animationCount():
            i += 1
            spoilerAnimation = self.toggleAnimation.animationAt(i)
            if spoilerAnimation is not None:
                spoilerAnimation.setDuration(self.animationDuration)
                spoilerAnimation.setStartValue(collapsedHeight)
                spoilerAnimation.setEndValue(collapsedHeight + contentHeight)

        contentAnimation = self.toggleAnimation.animationAt(
            self.toggleAnimation.animationCount() - 1)
        contentAnimation.setDuration(self.animationDuration)
        contentAnimation.setStartValue(0)
        contentAnimation.setEndValue(contentHeight)
Exemple #5
0
class Spoiler(QWidget):
    class Orientation(Enum):
        HORIZONTAL = 1
        VERTICAL = 2

    def __init__(self,
                 orientation=Orientation.HORIZONTAL,
                 animationDuration=120,
                 parent=None):
        QWidget.__init__(self, parent)

        self.opened = False
        self.orientation = orientation
        self.animationDuration = animationDuration
        self.mainLayout = None
        self.animator = QParallelAnimationGroup()

        if orientation is self.Orientation.HORIZONTAL:
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

            self.setMaximumWidth(0)
            self.setMinimumWidth(0)
            # let the entire widget grow and shrink with its content
            self.animator.addAnimation(QPropertyAnimation(self))
            self.animator.addAnimation(
                QPropertyAnimation(self, b"minimumWidth"))
            self.animator.addAnimation(
                QPropertyAnimation(self, b"maximumWidth"))

        elif orientation is self.Orientation.VERTICAL:
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

            self.setMaximumHeight(0)
            self.setMinimumHeight(0)
            # let the entire widget grow and shrink with its content
            self.animator.addAnimation(QPropertyAnimation(self))
            self.animator.addAnimation(
                QPropertyAnimation(self, b"minimumHeight"))
            self.animator.addAnimation(
                QPropertyAnimation(self, b"maximumHeight"))

    def open(self):
        self.animator.setDirection(QAbstractAnimation.Forward)
        self.animator.start()
        self.opened = True

    def close(self):
        self.animator.setDirection(QAbstractAnimation.Backward)
        self.animator.start()
        self.opened = False

    def isOpened(self):
        return self.opened

    def setContentLayout(self, contentLayout):
        self.setLayout(contentLayout)

        if self.orientation is self.Orientation.HORIZONTAL:
            collapsedSize = self.maximumWidth()
            contentSize = contentLayout.sizeHint().width()
        elif self.orientation is self.Orientation.VERTICAL:
            collapsedSize = self.maximumHeight()
            contentSize = contentLayout.sizeHint().height()

        i = 0
        while i < self.animator.animationCount():
            animation = self.animator.animationAt(i)
            animation.setDuration(self.animationDuration)
            animation.setStartValue(collapsedSize)
            animation.setEndValue(collapsedSize + contentSize)
            i += 1
Exemple #6
0
class CollapsibleWidget(QWidget):
    def __init__(self, title="", parent=None, animation_duration=300):
        """
        References:
            # Adapted from c++ version
            http://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt
        """
        super(CollapsibleWidget, self).__init__(parent)
        self.title = title
        self.toggle_button = QToolButton()
        self.toggle_animation = QParallelAnimationGroup(self)
        self.content_area = QScrollArea()
        self.animation_duration = animation_duration
        self._init_base_ui()

    def _init_base_ui(self):
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)
        self.toggle_button.setText(str(self.title))
        self.toggle_button.setCheckable(True)
        self.toggle_button.setChecked(False)

        self.content_area.setMaximumHeight(0)
        self.content_area.setMinimumHeight(0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.content_area.setFrameShape(QFrame.NoFrame)

        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area, b"maximumHeight"))

        layout = QVBoxLayout(self)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.toggle_button)
        layout.addWidget(self.content_area)

    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def set_content_layout(self, layout):
        initial_layout = self.content_area.layout()
        del initial_layout
        self.content_area.setLayout(layout)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(self.animation_duration)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(self.animation_duration)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)

    def set_content_widget(self, widget):
        initial_layout = self.content_area.layout()
        del initial_layout
        self.content_area.setWidget(widget)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = widget.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(self.animation_duration)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(self.animation_duration)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
Exemple #7
0
class ContentEditor(AnimateableEditor):
    contentChanged = pyqtSignal(object)
    preview = pyqtSignal(object)

    def __init__(self, win, site, content):
        AnimateableEditor.__init__(self)

        self.win = win
        self.site = site
        self.content = content
        self.is_new = False
        self.editor = None
        self.undoStack = QUndoStack()
        self.changed = False
        self.setAutoFillBackground(True)

        self.previewLink = HyperLink("")
        self.vbox = QVBoxLayout()
        self.layout = QGridLayout()
        self.titleLabel = QLabel()

        fnt = self.titleLabel.font()
        fnt.setPointSize(20)
        fnt.setBold(True)
        self.titleLabel.setFont(fnt)
        self.script = QPushButton("Page Script")
        self.title = QLineEdit()
        self.source = QLineEdit()
        self.source.setPlaceholderText("*.qml")
        self.excerpt = QLineEdit()
        self.date = QLineEdit()
        self.labelPermalink = QLabel("Permalink")
        self.labelTitle = QLabel("Title")
        self.labelAuthor = QLabel("Author")
        self.labelKeyword = QLabel("Keywords")
        self.labelLayout = QLabel("Layout")
        self.labelMenu = QLabel("Menu")
        self.author = QLineEdit()
        self.keywords = QLineEdit()
        self.menus = QComboBox()
        self.layouts = QComboBox()
        self.layouts.setMaximumWidth(100)

        for menu in self.site.menus.menus:
            self.menus.addItem(menu.name)

        for root, dirs, files in os.walk(
                os.path.join(self.site.source_path, "layouts")):
            for file in files:
                self.layouts.addItem(Path(file).stem)

        for root, dirs, files in os.walk(
                os.path.join(Generator.themesPath(), self.site.theme,
                             "layouts")):
            for file in files:
                self.layouts.addItem(Path(file).stem)

        self.close = FlatButton(":/images/close_normal.png",
                                ":/images/close_hover.png")
        self.close.setToolTip("Close Content Editor")
        self.undo = FlatButton(":/images/undo_normal.png",
                               ":/images/undo_hover.png", "",
                               ":/images/undo_disabled.png")
        self.redo = FlatButton(":/images/redo_normal.png",
                               ":/images/redo_hover.png", "",
                               ":/images/redo_disabled.png")
        self.undo.setToolTip("Undo")
        self.redo.setToolTip("Redo")
        self.undo.setEnabled(False)
        self.redo.setEnabled(False)
        hbox = QHBoxLayout()
        hbox.addWidget(self.undo)
        hbox.addWidget(self.redo)
        hbox.addWidget(self.close)

        self.scroll = QScrollArea()
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scroll.setWidgetResizable(True)
        self.scroll.installEventFilter(self)
        self.layout.addWidget(self.titleLabel, 0, 0)
        self.layout.addWidget(self.previewLink, 0, 1)
        self.layout.addLayout(hbox, 0, 3)
        self.layout.addWidget(self.labelTitle, 1, 0)
        self.layout.addWidget(self.title, 2, 0)
        self.layout.addWidget(self.labelPermalink, 1, 1)
        self.layout.addWidget(self.source, 2, 1)
        self.layout.addWidget(self.labelAuthor, 3, 0)
        self.layout.addWidget(self.author, 4, 0)
        self.layout.addWidget(self.labelKeyword, 3, 1)
        self.layout.addWidget(self.keywords, 4, 1)
        self.layout.addWidget(self.labelMenu, 3, 2)
        self.layout.addWidget(self.menus, 4, 2)
        self.layout.addWidget(self.labelLayout, 3, 3)
        self.layout.addWidget(self.layouts, 4, 3)
        self.layout.addWidget(self.scroll, 7, 0, 1, 4)
        self.layout.addWidget(self.script, 8, 0, 1, 4)
        self.vbox.addLayout(self.layout)
        self.setLayout(self.vbox)

        if self.content.content_type == ContentType.POST:
            self.previewLink.setText("view post")
            self.excerptLabel = QLabel("Excerpt")
            self.layout.addWidget(self.excerptLabel, 5, 0)
            self.layout.addWidget(self.excerpt, 6, 0, 1, 2)
            self.datelabel = QLabel("Date")
            self.layout.addWidget(self.datelabel, 5, 2)
            self.layout.addWidget(self.date, 6, 2, 1, 2)
            self.filename = self.site.source_path + "/posts/" + content.source
        else:
            self.previewLink.setText("view page")
            self.filename = self.site.source_path + "/pages/" + content.source

        self.load()

        self.close.clicked.connect(self.closeEditor)
        self.title.editingFinished.connect(self.titleFinished)
        self.title.textChanged.connect(self.titleChanged)
        self.source.editingFinished.connect(self.sourceChanged)
        self.excerpt.editingFinished.connect(self.excerptChanged)
        self.date.editingFinished.connect(self.dateChanged)
        self.author.editingFinished.connect(self.authorChanged)
        self.keywords.editingFinished.connect(self.keywordsChanged)
        self.menus.currentTextChanged.connect(self.menuChanged)
        self.layouts.currentTextChanged.connect(self.layoutChanged)
        self.undoStack.canUndoChanged.connect(self.canUndoChanged)
        self.undoStack.canRedoChanged.connect(self.canRedoChanged)
        self.undoStack.undoTextChanged.connect(self.undoTextChanged)
        self.undoStack.redoTextChanged.connect(self.redoTextChanged)
        self.undo.clicked.connect(self.undoAction)
        self.redo.clicked.connect(self.redoAction)
        self.previewLink.clicked.connect(self.previewPage)
        self.script.clicked.connect(self.scriptClicked)

    def scriptClicked(self):
        self.editor = Plugins.element_plugins["TextEditor"]
        self.editor.setContent(None)
        self.editor.setText(self.content.script)
        self.editor.setCaption("Page Script")
        self.editor.close.connect(self.scriptEditorClose)
        self.animate(self.scroll.widget().placeholder)

    def scriptEditorClose(self):
        if self.editor and self.editor.changed:
            self.content.script = self.editor.getText()
            self.editChanged("Update Script")
            self.editor.close.disconnect()
        self.editorClosed()

    def previewPage(self):
        self.preview.emit(self.content)

    def rowEdit(self, re):
        from widgets.rowpropertyeditor import RowPropertyEditor

        self.row_editor = re
        self.editor = RowPropertyEditor()
        self.editor.setRow(re.row)
        self.editor.close.connect(self.rowEditorClose)
        self.animate(re)

    def rowEditorClose(self):
        if self.editor and self.editor.changed:
            self.row_editor.load(self.editor.row)
            self.editChanged("Update Row")
            self.editor.close.disconnect()
        self.editorClosed()

    def canUndoChanged(self, can):
        self.undo.setEnabled(can)

    def canRedoChanged(self, can):
        self.redo.setEnabled(can)

    def undoTextChanged(self, text):
        self.undo.setToolTip("Undo " + text)

    def redoTextChanged(self, text):
        self.redo.setToolTip("Redo " + text)

    def undoAction(self):
        self.undoStack.undo()

    def redoAction(self):
        self.undoStack.redo()

    def menuChanged(self, menu):
        if menu != self.content.menu:
            self.content.menu = menu
            self.contentChanged.emit(self.content)
            self.editChanged("Menu Changed")

    def layoutChanged(self, layout):
        if layout != self.content.layout:
            self.content.layout = layout
            self.contentChanged.emit(self.content)
            self.editChanged("Layout Changed")

    def keywordsChanged(self):
        if self.keywords.text() != self.content.keywords:
            self.content.keywords = self.keywords.text()
            self.contentChanged.emit(self.content)
            self.editChanged("Keywords Changed")

    def authorChanged(self):
        if self.author.text() != self.content.author:
            self.content.author = self.author.text()
            self.contentChanged.emit(self.content)
            self.editChanged("Author Changed")

    def excerptChanged(self):
        if self.excerpt.text() != self.content.excerpt:
            self.content.excerpt = self.excerpt.text()
            self.contentChanged.emit(self.content)
            self.editChanged("Excerpt Changed")

    def dateChanged(self):
        if self.date.text() != self.content.date.toString("dd.MM.yyyy"):
            self.content.date = QDate.fromString(self.date.text(),
                                                 "dd.MM.yyyy")
            self.contentChanged.emit(self.content)
            self.editChanged("Date Changed")

    def sourceChanged(self):
        if self.source.text() != self.content.source:
            oldname = self.filename
            self.content.source = self.source.text()
            if self.content.content_type == ContentType.PAGE:
                self.filename = self.site.source_path + "/pages/" + self.content.source
            else:
                self.filename = self.site.source_path + "/posts/" + self.content.source

            self.contentChanged.emit(self.content)

            renameCommand = RenameContentCommand(self, oldname, self.filename,
                                                 "content file renamed")
            self.undoStack.push(renameCommand)

    def titleChanged(self, title):
        if self.is_new:
            source = title.lower().replace(" ", "_") + ".qml"
            self.source.setText(source)

    def titleFinished(self):
        if self.title.text() != self.content.title:
            if self.is_new:
                self.sourceChanged()
            self.content.title = self.title.text()
            self.contentChanged.emit(self.content)
            self.editChanged("Titel Changed")

    def sectionEdit(self, se):
        self.section_editor = se

        self.editor = SectionPropertyEditor()
        self.editor.setSection(se.section)
        self.editor.close.connect(self.sectionEditorClose)
        self.animate(se)

    def sectionEditorClose(self):
        if self.editor.changed:
            self.section_editor.setSection(self.editor.section)
            self.editChanged("Update Section")
            self.editor.close.disconnect()
        self.editorClosed()

    def load(self):
        from widgets.sectioneditor import SectionEditor
        self.content = self.site.loadContent(self.content.source,
                                             self.content.content_type)
        self.is_new = not self.content.title
        self.title.setText(self.content.title)
        self.source.setText(self.content.source)
        self.author.setText(self.content.author)
        self.keywords.setText(self.content.keywords)
        self.menus.setCurrentText(self.content.menu)
        self.layouts.setCurrentText(self.content.layout)
        if self.content.content_type == ContentType.POST:
            self.excerpt.setText(self.content.excerpt)
            self.date.setText(self.content.date.toString("dd.MM.yyyy"))

        pe = PageEditor()
        self.scroll.setWidget(pe)
        for item in self.content.items:
            if isinstance(item, Section):
                se = SectionEditor(item.fullwidth)
                se.load(item)
                pe.addSection(se)
            # todo other types

    def siteLoaded(self, site):
        self.site = site
        if self.content.contentType == ContentType.PAGE:
            for c in self.site.pages:
                if c.source == self.content.source:
                    self.title.setText(c.title)
        else:
            for c in self.site.posts:
                if c.source == self.content.source:
                    self.excerpt.setText(c.excerpt)
                    self.title.setText(c.title)

    def closeEditor(self):
        if self.editor:
            self.editor.closeEditor()
        self.closes.emit()

    def elementEdit(self, ee):
        self.element_editor = ee
        plugin_name = ""
        if ee.type:
            plugin_name = Plugins.getElementPluginByTagname(ee.type)
        if plugin_name:
            self.editor = Plugins.element_plugins[plugin_name]
        else:
            self.editor = Plugins.element_plugins["TextEditor"]
            self.editor.setCaption("Text Module")
        self.editor.site = self.site
        self.editor.setContent(ee.getContent())
        self.editor.close.connect(self.editorClose)
        self.animate(ee)

    def animate(self, widget):
        self.sourcewidget = widget
        pos = widget.mapTo(self.scroll, QPoint(0, 0))

        self.editor.setParent(self.scroll)
        self.editor.move(pos)
        self.editor.resize(widget.size())
        self.editor.show()

        self.animationgroup = QParallelAnimationGroup()
        self.animx = QPropertyAnimation()
        self.animx.setDuration(300)
        self.animx.setStartValue(pos.x())
        self.animx.setEndValue(0)
        self.animx.setTargetObject(self.editor)
        self.animx.setPropertyName("x".encode("utf-8"))
        self.animationgroup.addAnimation(self.animx)
        self.animy = QPropertyAnimation()
        self.animy.setDuration(300)
        self.animy.setStartValue(pos.y())
        self.animy.setEndValue(0)
        self.animy.setTargetObject(self.editor)
        self.animy.setPropertyName("y".encode("utf-8"))
        self.animationgroup.addAnimation(self.animy)
        self.animw = QPropertyAnimation()
        self.animw.setDuration(300)
        self.animw.setStartValue(widget.size().width())
        self.animw.setEndValue(self.scroll.size().width())
        self.animw.setTargetObject(self.editor)
        self.animw.setPropertyName("width".encode("utf-8"))
        self.animationgroup.addAnimation(self.animw)
        self.animh = QPropertyAnimation()
        self.animh.setDuration(300)
        self.animh.setStartValue(widget.size().height())
        self.animh.setEndValue(self.scroll.size().height())
        self.animh.setTargetObject(self.editor)
        self.animh.setPropertyName("height".encode("utf-8"))
        self.animationgroup.addAnimation(self.animh)
        self.animationgroup.finished.connect(self.animationFineshedZoomIn)
        self.animationgroup.start()

    def animationFineshedZoomIn(self):
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.title.setEnabled(False)
        self.author.setEnabled(False)
        self.keywords.setEnabled(False)
        self.menus.setEnabled(False)
        self.layouts.setEnabled(False)
        self.labelAuthor.setEnabled(False)
        self.labelKeyword.setEnabled(False)
        self.labelMenu.setEnabled(False)
        self.labelLayout.setEnabled(False)
        self.labelTitle.setEnabled(False)
        self.labelPermalink.setEnabled(False)
        self.previewLink.hide()
        self.undo.hide()
        self.redo.hide()
        self.close.hide()
        self.source.setEnabled(False)
        if self.content.content_type == ContentType.POST:
            self.excerpt.setEnabled(False)
            self.excerptLabel.setEnabled(False)
        self.animationgroup.finished.disconnect(self.animationFineshedZoomIn)

    def editorClose(self):
        if self.editor.changed:
            self.element_editor.setContent(self.editor.getContent())
            self.editChanged("Update Element")
        self.editor.close.disconnect()
        self.editorClosed()

    def editorClosed(self):
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        pos = self.sourcewidget.mapTo(self.scroll, QPoint(0, 0))
        # correct end values in case of resizing the window
        self.animx.setStartValue(pos.x())
        self.animy.setStartValue(pos.y())
        self.animw.setStartValue(self.sourcewidget.size().width())
        self.animh.setStartValue(self.sourcewidget.size().height())
        self.animationgroup.setDirection(QAbstractAnimation.Backward)
        self.animationgroup.finished.connect(self.animationFineshedZoomOut)
        self.animationgroup.start()

    def animationFineshedZoomOut(self):
        from widgets.rowpropertyeditor import RowPropertyEditor
        from widgets.sectionpropertyeditor import SectionPropertyEditor

        self.title.setEnabled(True)
        self.source.setEnabled(True)
        self.author.setEnabled(True)
        self.keywords.setEnabled(True)
        self.menus.setEnabled(True)
        self.layouts.setEnabled(True)
        self.labelAuthor.setEnabled(True)
        self.labelKeyword.setEnabled(True)
        self.labelMenu.setEnabled(True)
        self.labelLayout.setEnabled(True)
        self.labelTitle.setEnabled(True)
        self.labelPermalink.setEnabled(True)
        self.previewLink.show()
        self.undo.show()
        self.redo.show()
        self.close.show()
        if self.content.content_type == ContentType.POST:
            self.excerpt.setEnabled(True)
            self.excerptLabel.setEnabled(True)
        del self.animationgroup
        self.editor.hide()
        # parent has to be set to NULL, otherwise the plugin will be dropped by parent
        self.editor.setParent(None)
        # only delete Row- and SectionPropertyEditor the other editors are plugins
        if isinstance(self.editor, RowPropertyEditor):
            del self.editor
        elif isinstance(self.editor, SectionPropertyEditor):
            self.editor.close.disconnect(self.sectionEditorClose)
            del self.editor
        self.editor = None

    def editChanged(self, text):
        changeCommand = ChangeContentCommand(self.win, self, text)
        self.undoStack.push(changeCommand)

    def save(self):
        self.content.save(self.filename)

    def contentRenamed(self, name):
        self.filename = name
        base = os.path.basename(name)
        self.source.setText(base)
        self.content.source = base
Exemple #8
0
class GroupWidget(QWidget):
    def __init__(self, parent=None, title='', animation_duration=300):
        """
        References:
            # Adapted from c++ version
            http://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt
        """
        super(GroupWidget, self).__init__(parent=parent)

        self.animation_duration = animation_duration
        self.toggle_animation = QParallelAnimationGroup()
        self.content_area = QScrollArea()
        self.header_line = QFrame()
        self.toggle_button = QToolButton()
        self.main_layout = QGridLayout()

        toggle_button = self.toggle_button
        toggle_button.setStyleSheet("QToolButton { border: none; }")
        toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        toggle_button.setArrowType(Qt.RightArrow)
        toggle_button.setText(str(title))
        toggle_button.setCheckable(True)
        toggle_button.setChecked(False)

        header_line = self.header_line
        header_line.setFrameShape(QFrame.HLine)
        header_line.setFrameShadow(QFrame.Sunken)
        header_line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)

        self.content_area.setStyleSheet(
            "QScrollArea { background-color: white; border: none; }")
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        # start out collapsed
        self.content_area.setMaximumHeight(0)
        self.content_area.setMinimumHeight(0)
        # let the entire widget grow and shrink with its content
        toggle_animation = self.toggle_animation
        toggle_animation.addAnimation(
            QPropertyAnimation(self, bytes("minimumHeight", "utf-8")))
        toggle_animation.addAnimation(
            QPropertyAnimation(self, bytes("maximumHeight", "utf-8")))
        toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area,
                               bytes("maximumHeight", "utf-8")))
        # don't waste space
        main_layout = self.main_layout
        main_layout.setVerticalSpacing(0)
        main_layout.setContentsMargins(0, 0, 0, 0)
        row = 0
        main_layout.addWidget(self.toggle_button, row, 0, 1, 1, Qt.AlignLeft)
        main_layout.addWidget(self.header_line, row, 2, 1, 1)
        row += 1
        main_layout.addWidget(self.content_area, row, 0, 1, 3)
        self.setLayout(self.main_layout)

        def start_animation(checked):
            arrow_type = Qt.DownArrow if checked else Qt.RightArrow
            direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward
            toggle_button.setArrowType(arrow_type)
            self.toggle_animation.setDirection(direction)
            self.toggle_animation.start()

        self.toggle_button.clicked.connect(start_animation)

    def set_content_layout(self, content_layout):
        # Not sure if this is equivalent to self.contentArea.destroy()
        self.content_area.destroy()
        self.content_area.setLayout(content_layout)
        collapsed_height = self.sizeHint().height(
        ) - self.content_area.maximumHeight()
        content_height = content_layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount() - 1):
            spoiler_animation = self.toggle_animation.animationAt(i)
            spoiler_animation.setDuration(self.animation_duration)
            spoiler_animation.setStartValue(collapsed_height)
            spoiler_animation.setEndValue(collapsed_height + content_height)
        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(self.animation_duration)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
class CollapsibleBox(QWidget):
    def __init__(self, title="", parent=None):
        super(CollapsibleBox, self).__init__(parent)
        self.toggle_button = QToolButton(text=title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton {border: none;\
                border: 1px solid #FF17365D;\
                border-top-left-radius: 15px;\
                border-top-right-radius: 15px;\
                background-color: #FF17365D;\
                padding: 5px 0px;\
                color: rgb(255, 255, 255);\
                max-height: 30px;\
                font-size: 14px;\
            }\
            QToolButton:hover {\
                background-color: lightgreen;\
                color: black;\
            }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

        self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)

        lay = QVBoxLayout(self)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.toggle_button)
        lay.addWidget(self.content_area)

        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area, b"maximumHeight"))

    @QtCore.pyqtSlot()
    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def clear_layout(self, layout):
        try:
            for i in reversed(range(layout.count())):
                widgetToRemove = layout.itemAt(i).widget()
                layout.removeWidget(widgetToRemove)
                widgetToRemove.setPArent(None)
        except AttributeError:
            pass

    def setContentLayout(self, layout):
        lay = self.content_area.layout()
        self.clear_layout(lay)
        self.content_area.setLayout(layout)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(500)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(500)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
Exemple #10
0
class PopupPost(QMainWindow, Ui_PopupPost):
    def __init__(self, read_the_weibo):
        super().__init__(
            None, Qt.ToolTip
            | Qt.FramelessWindowHint
            | Qt.WindowStaysOnTopHint)
        self.setupUi(self)

        self._close_timer = QTimer(self)
        self._close_timer.setSingleShot(True)
        self._close_timer.timeout.connect(self.close)

        self._read_the_weibo = read_the_weibo

    def setupUi(self, popup_post):
        super().setupUi(popup_post)
        self.setAttribute(Qt.WA_TranslucentBackground)

        desktop = QApplication.desktop()
        self.move(desktop.width() - 50 - self.width(),
                  desktop.height() - 300 - self.height())

        # 因为带浏览器的透明窗口不能渲染,浏览器放在独立窗口
        self.content_view = WeiboWebView(self)
        self.content_view.setWindowOpacity(0)

        # 淡出淡入动画
        self._window_fade_anim = QPropertyAnimation(self, b'windowOpacity',
                                                    self)
        self._window_fade_anim.setDuration(300)
        self._window_fade_anim.setStartValue(0)
        self._window_fade_anim.setEndValue(0.5)
        self._content_fade_anim = QPropertyAnimation(self.content_view,
                                                     b'windowOpacity', self)
        self._content_fade_anim.setDuration(300)
        self._content_fade_anim.setStartValue(0)
        self._content_fade_anim.setEndValue(0.7)
        self._fade_anim_group = QParallelAnimationGroup(self)
        self._fade_anim_group.addAnimation(self._window_fade_anim)
        self._fade_anim_group.addAnimation(self._content_fade_anim)
        self._fade_anim_group.finished.connect(self._on_anim_finish)

    def moveEvent(self, event):
        logger.debug('moveEvent')
        # 如果在这里更新,content_widget位置和尺寸不对
        QTimer.singleShot(0, self._update_content_view_geometry)

    def resizeEvent(self, event):
        logger.debug('resizeEvent')
        # 如果在这里更新,content_widget位置和尺寸不对
        QTimer.singleShot(0, self._update_content_view_geometry)

    def _update_content_view_geometry(self):
        pos = self.mapToGlobal(self.content_widget.pos())
        size = self.content_widget.size()
        logger.debug('content_widget: (%d, %d) %d x %d', pos.x(), pos.y(),
                     size.width(), size.height())
        self.content_view.setGeometry(pos.x(), pos.y(), size.width(),
                                      size.height())

    def show_post(self, post):
        """
        显示一条微博
        :param post: 微博
        """

        self.show()
        self.content_view.show_post(post)

        # 淡入
        self._fade_anim_group.setDirection(QPropertyAnimation.Forward)
        self._fade_anim_group.start()

        # 如果只弹窗不发声则过一段时间自动关闭
        if not self._read_the_weibo.speak_post:
            content_len = len(post.content)
            if post.is_repost:
                content_len += len(post.original_post.content)
            self._close_timer.start(int((3 + content_len * 0.1) * 1000))

    def closeEvent(self, event):
        """
        取消关闭事件,改成淡出、隐藏窗口
        """

        logger.debug('closeEvent')
        event.ignore()
        self._close_timer.stop()

        if (self._fade_anim_group.state() != QPropertyAnimation.Running
                or self._fade_anim_group.direction() !=
                QPropertyAnimation.Backward):
            self._read_the_weibo.on_popup_post_close()

            # 淡出
            self._fade_anim_group.setDirection(QPropertyAnimation.Backward)
            self._fade_anim_group.start()

    def _on_anim_finish(self):
        if self._fade_anim_group.direction() == QPropertyAnimation.Backward:
            logger.debug('_on_anim_finish, direction = Backward')
            self.content_view.hide()
            self.hide()
            self._read_the_weibo.on_popup_post_hide()
        else:
            logger.debug('_on_anim_finish, direction = Forward')
class RevolutionSliderEditor(ElementEditorInterface):
    def __init__(self):
        ElementEditorInterface.__init__(self)
        self.class_name = "RevolutionSliderEditor"
        self.display_name = "RevolutionSlider"
        self.tag_name = "RevolutionSlider"
        self.version = "1.0"
        self.icon = QImage(":/revolution.png")
        self.changed = False
        self.setAutoFillBackground(True)

        grid = QGridLayout()
        self.id = QLineEdit()
        self.id.setMaximumWidth(200)
        self.adminlabel = QLineEdit()
        self.adminlabel.setMaximumWidth(200)
        titleLabel = QLabel("Slider Module")
        fnt = titleLabel.font()
        fnt.setPointSize(16)
        fnt.setBold(True)
        titleLabel.setFont(fnt)

        close = FlatButton(":/images/close_normal.png",
                           ":/images/close_hover.png")
        close.setToolTip("Close Editor")

        addSlide = QPushButton("Add Slide")
        addSlide.setMaximumWidth(120)

        self.list = QTableWidget(0, 2, self)
        self.list.verticalHeader().hide()
        self.list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.list.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.list.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)
        self.list.setToolTip("Double click to edit item")
        labels = ["", "Name"]
        self.list.setHorizontalHeaderLabels(labels)

        grid.addWidget(titleLabel, 0, 0)
        grid.addWidget(close, 0, 2, 1, 1, Qt.AlignRight)
        grid.addWidget(addSlide, 1, 0)
        grid.addWidget(self.list, 2, 0, 1, 3)
        grid.addWidget(QLabel("Id"), 4, 0)
        grid.addWidget(self.id, 5, 0)
        grid.addWidget(QLabel("Admin Label"), 6, 0)
        grid.addWidget(self.adminlabel, 7, 0)

        self.setLayout(grid)

        addSlide.clicked.connect(self.addSlide)
        self.adminlabel.textChanged.connect(self.contentChanged)
        self.id.textChanged.connect(self.contentChanged)
        close.clicked.connect(self.closeEditor)
        self.list.cellDoubleClicked.connect(self.tableDoubleClicked)

        self.installEventFilter(self)

    def closeEditor(self):
        if self.changed:
            if self.content:
                self.content.removeSlides()
                self.content.adminlabel = self.adminlabel.text()
                #self.content.text = html.escape(self.html.toPlainText())
                for i in range(self.list.rowCount()):
                    item = self.list.item(i, 1)
                    slide = item.data(Qt.UserRole)
                    self.content.addSlide(slide)
        self.close.emit()

    def registerContenType(self):
        qmlRegisterType(RevolutionSlider, 'RevolutionSlider', 1, 0,
                        'RevolutionSlider')
        qmlRegisterType(Slide, 'RevolutionSlider', 1, 0, 'Slide')

    def getImportString(self):
        return "import RevolutionSlider 1.0\n"

    def pluginStyles(self):
        return "<link href=\"assets/plugins/revolution-slider/css/settings.css\" rel=\"stylesheet\" type=\"text/css\"/>\n"

    def pluginScripts(self):
        script = "<script type=\"text/javascript\" src=\"assets/plugins/revolution-slider/js/jquery.themepunch.plugins.min.js\"></script>\n"
        script += "<script type=\"text/javascript\" src=\"assets/plugins/revolution-slider/js/jquery.themepunch.revolution.min.js\"></script>\n"
        script += "<script type=\"text/javascript\" src=\"assets/js/slider_revolution.js\"></script>\n"
        return script

    def installAssets(self, assets_path):
        assets = QDir(assets_path)
        assets.mkdir("plugins")
        assets.cd("plugins")
        assets.mkdir("revolution-slider")
        assets.cd("revolution-slider")
        assets.mkdir("css")
        assets.mkdir("js")
        assets.mkdir("assets")
        QFile.copy(":/css", assets_path + "/plugins/revolution-slider/css")
        QFile.copy(":/js", assets_path + "/js")
        QFile.copy(":/js/plugins",
                   assets_path + "/plugins/revolution-slider/js")
        QFile.copy(":/assets",
                   assets_path + "/plugins/revolution-slider/assets")

    def getDefaultContent(self):
        return RevolutionSlider()

    def setContent(self, content):
        self.content = content
        if content:
            #self.adminlabel.setText(content.adminlabel)
            self.changed = False

        self.list.setRowCount(0)

        for slide in content._items:
            self.addListItem(slide)
        self.changed = False

    def getContent(self):
        return self.content

    def addSlide(self):
        slide = Slide()
        self.addListItem(slide)
        self.contentChanged()
        self.tableDoubleClicked(self.list.rowCount() - 1)

    def addListItem(self, slide):
        rows = self.list.rowCount()
        self.list.setRowCount(rows + 1)
        tcb = TableCellButtons()
        tcb.setItem(slide)
        tcb.deleteItem.connect(self.deleteSlide)
        tcb.editItem.connect(self.editSlide)
        self.list.setCellWidget(rows, 0, tcb)
        self.list.setRowHeight(rows, tcb.sizeHint().height())
        titleItem = QTableWidgetItem(slide.title)
        titleItem.setFlags(titleItem.flags() ^ Qt.ItemIsEditable)
        titleItem.setData(Qt.UserRole, slide)
        self.list.setItem(rows, 1, titleItem)

    def tableDoubleClicked(self, row):
        item = self.list.item(row, 1)
        slide = item.data(Qt.UserRole)

        self.editor = SlideEditor()
        self.editor.setSite(self.site)
        self.editor.setSlide(slide)
        self.editor.closes.connect(self.editorClosed)
        self.animate(item)

    def animate(self, item):
        self.row = item.row()

        # create a cell widget to get the right position in the table
        self.sourcewidget = QWidget()
        self.list.setCellWidget(self.row, 1, self.sourcewidget)
        pos = self.sourcewidget.mapTo(self, QPoint(0, 0))

        self.editor.setParent(self)
        self.editor.move(pos)
        self.editor.resize(self.sourcewidget.size())
        self.editor.show()

        self.animationgroup = QParallelAnimationGroup()
        self.animx = QPropertyAnimation()
        self.animx.setDuration(300)
        self.animx.setStartValue(pos.x())
        self.animx.setEndValue(0)
        self.animx.setTargetObject(self.editor)
        self.animx.setPropertyName("x".encode("utf-8"))
        self.animationgroup.addAnimation(self.animx)
        self.animy = QPropertyAnimation()
        self.animy.setDuration(300)
        self.animy.setStartValue(pos.y())
        self.animy.setEndValue(0)
        self.animy.setTargetObject(self.editor)
        self.animy.setPropertyName("y".encode("utf-8"))
        self.animationgroup.addAnimation(self.animy)
        self.animw = QPropertyAnimation()
        self.animw.setDuration(300)
        self.animw.setStartValue(self.sourcewidget.size().width())
        self.animw.setEndValue(self.size().width())
        self.animw.setTargetObject(self.editor)
        self.animw.setPropertyName("width".encode("utf-8"))
        self.animationgroup.addAnimation(self.animw)
        self.animh = QPropertyAnimation()
        self.animh.setDuration(300)
        self.animh.setStartValue(self.sourcewidget.size().height())
        self.animh.setEndValue(self.size().height())
        self.animh.setTargetObject(self.editor)
        self.animh.setPropertyName("height".encode("utf-8"))
        self.animationgroup.addAnimation(self.animh)
        self.animationgroup.finished.connect(self.animationFineshedZoomIn)
        self.animationgroup.start()

    def animationFineshedZoomIn(self):
        pass

    def editorClosed(self):
        pos = self.sourcewidget.mapTo(self, QPoint(0, 0))
        # correct end values in case of resizing the window
        self.animx.setStartValue(pos.x())
        self.animy.setStartValue(pos.y())
        self.animw.setStartValue(self.sourcewidget.size().width())
        self.animh.setStartValue(self.sourcewidget.size().height())
        self.animationgroup.setDirection(QAbstractAnimation.Backward)
        #self.animationgroup.finished()), this, SLOT(animationFineshedZoomIn()))
        #connect(m_animationgroup, SIGNAL(finished()), this, SLOT(animationFineshedZoomOut()))
        self.animationgroup.start()

        item = self.list.item(self.row, 1)
        item.setData(Qt.UserRole, self.editor.slide)
        item.setText(self.editor.slide.title)
        if self.editor.changed:
            self.contentChanged()

    def animationFineshedZoomOut(self):
        #delete m_animationgroup
        #delete m_editor
        #self.editor = None
        pass

    def deleteSlide(self, slide):
        for row in range(self.list.rowCount()):
            item = self.list.item(row, 1)
            m = item.data(Qt.UserRole)
            if m == slide:
                self.list.removeRow(row)
                self.contentChanged()
                break

    def editSlide(self, slide):
        for row in range(self.list.rowCount()):
            item = self.list.item(row, 1)
            m = item.data(Qt.UserRole)
            if m == slide:
                self.list.selectRow(row)
                self.tableDoubleClicked(row)
                break
Exemple #12
0
class CarouselEditor(ElementEditorInterface):
    def __init__(self):
        ElementEditorInterface.__init__(self)
        self.class_name = "CarouselEditor"
        self.display_name = QCoreApplication.translate("CarouselEditor", "Carousel")
        self.tag_name = "Carousel"
        self.version = "1.0"
        self.icon = QImage(":/carousel.png")

        self.changed = False
        #self.editor = 0
        self.setAutoFillBackground(True)

        grid = QGridLayout()
        self.id = QLineEdit()
        self.id.setMaximumWidth(200)
        self.adminlabel = QLineEdit()
        self.adminlabel.setMaximumWidth(200)
        titleLabel = QLabel(QCoreApplication.translate("CarouselEditor", "Carousel Module"))
        fnt = titleLabel.font()
        fnt.setPointSize(16)
        fnt.setBold(True)
        titleLabel.setFont(fnt)

        close = FlatButton(":/images/close_normal.png", ":/images/close_hover.png")
        close.setToolTip(QCoreApplication.translate("general", "Close Editor"))

        addSlide = QPushButton(QCoreApplication.translate("CarouselEditor", "Add Slide"))
        addSlide.setMaximumWidth(120)

        self.list = QTableWidget(0, 2, self)
        self.list.verticalHeader().hide()
        self.list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.list.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.list.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch )
        self.list.setToolTip(QCoreApplication.translate("CarouselEditor", "Double click to edit item"))
        labels = ["", "Name"]
        self.list.setHorizontalHeaderLabels(labels)

        grid.addWidget(titleLabel, 0, 0)
        grid.addWidget(close, 0, 2, 1, 1, Qt.AlignRight)
        grid.addWidget(addSlide, 1, 0)
        grid.addWidget(self.list, 2, 0, 1, 3)
        grid.addWidget(QLabel("Id"), 4, 0)
        grid.addWidget(self.id, 5, 0)
        grid.addWidget(QLabel(QCoreApplication.translate("CarouselEditor", "Admin Label")), 6, 0)
        grid.addWidget(self.adminlabel, 7, 0)

        self.setLayout(grid)

        addSlide.clicked.connect(self.addSlide)
        self.adminlabel.textChanged.connect(self.contentChanged)
        self.id.textChanged.connect(self.contentChanged)
        close.clicked.connect(self.closeEditor)
        self.list.cellDoubleClicked.connect(self.tableDoubleClicked)

        self.installEventFilter(self)

    def closeEditor(self):
        if self.changed:
            if self.content:
                self.content.id = self.id.text()
                self.content.adminlabel = self.adminlabel.text()
        self.close.emit()

    def setContent(self, content):
        self.content = content
        if content:
            self.id.setText(content.id)
            self.adminlabel.setText(content.adminlabel)
            self.changed = False

    def getContent(self):
        return self.content

    def registerContenType(self):
        qmlRegisterType(Carousel, 'Carousel', 1, 0, 'Carousel')
        qmlRegisterType(Slide, 'Carousel', 1, 0, 'Slide')

    def getImportString(self):
        return "import Carousel 1.0\n"

    def getDefaultContent(self):
        return Carousel()

    def addSlide(self):
        slide = Slide()
        self.addListItem(slide)
        self.contentChanged()
        self.tableDoubleClicked(self.list.rowCount() - 1)

    def addListItem(self, slide):
        rows = self.list.rowCount()
        self.list.setRowCount(rows + 1)
        tcb = TableCellButtons()
        tcb.setItem(slide)
        tcb.deleteItem.connect(self.deleteSlide)
        tcb.editItem.connect(self.editSlide)
        self.list.setCellWidget(rows, 0, tcb)
        self.list.setRowHeight(rows, tcb.sizeHint().height())
        titleItem = QTableWidgetItem(slide.title)
        titleItem.setFlags(titleItem.flags() ^ Qt.ItemIsEditable)
        titleItem.setData(Qt.UserRole, slide)
        self.list.setItem(rows, 1, titleItem)

    def tableDoubleClicked(self, row):
        item = self.list.item(row, 1)
        slide = item.data(Qt.UserRole)

        self.editor = SlideEditor()
        #self.editor.setSite(self.site)
        self.editor.setSlide(slide)
        self.editor.closes.connect(self.editorClosed)
        self.animate(item)

    def animate(self, item):
        self.row = item.row()

        # create a cell widget to get the right position in the table
        self.sourcewidget = QWidget()
        self.list.setCellWidget(self.row, 1, self.sourcewidget)
        pos = self.sourcewidget.mapTo(self, QPoint(0,0))

        self.editor.setParent(self)
        self.editor.move(pos)
        self.editor.resize(self.sourcewidget.size())
        self.editor.show()

        self.animationgroup = QParallelAnimationGroup()
        self.animx = QPropertyAnimation()
        self.animx.setDuration(300)
        self.animx.setStartValue(pos.x())
        self.animx.setEndValue(0)
        self.animx.setTargetObject(self.editor)
        self.animx.setPropertyName("x".encode("utf-8"))
        self.animationgroup.addAnimation(self.animx)
        self.animy = QPropertyAnimation()
        self.animy.setDuration(300)
        self.animy.setStartValue(pos.y())
        self.animy.setEndValue(0)
        self.animy.setTargetObject(self.editor)
        self.animy.setPropertyName("y".encode("utf-8"))
        self.animationgroup.addAnimation(self.animy)
        self.animw = QPropertyAnimation()
        self.animw.setDuration(300)
        self.animw.setStartValue(self.sourcewidget.size().width())
        self.animw.setEndValue(self.size().width())
        self.animw.setTargetObject(self.editor)
        self.animw.setPropertyName("width".encode("utf-8"))
        self.animationgroup.addAnimation(self.animw)
        self.animh = QPropertyAnimation()
        self.animh.setDuration(300)
        self.animh.setStartValue(self.sourcewidget.size().height())
        self.animh.setEndValue(self.size().height())
        self.animh.setTargetObject(self.editor)
        self.animh.setPropertyName("height".encode("utf-8"))
        self.animationgroup.addAnimation(self.animh)
        self.animationgroup.finished.connect(self.animationFineshedZoomIn)
        self.animationgroup.start()

    def animationFineshedZoomIn(self):
        pass

    def editorClosed(self):
        pos = self.sourcewidget.mapTo(self, QPoint(0,0))
        # correct end values in case of resizing the window
        self.animx.setStartValue(pos.x())
        self.animy.setStartValue(pos.y())
        self.animw.setStartValue(self.sourcewidget.size().width())
        self.animh.setStartValue(self.sourcewidget.size().height())
        self.animationgroup.setDirection(QAbstractAnimation.Backward)
        #self.animationgroup.finished()), this, SLOT(animationFineshedZoomIn()));
        #connect(m_animationgroup, SIGNAL(finished()), this, SLOT(animationFineshedZoomOut()));
        self.animationgroup.start()

        item = self.list.item(self.row, 1)
        item.setData(Qt.UserRole, self.editor.slide)
        item.setText(self.editor.slide.title)
        if self.editor.changed:
            self.contentChanged()

    def animationFineshedZoomOut(self):
        #delete m_animationgroup
        #delete m_editor
        #self.editor = None
        pass

    def deleteSlide(self, slide):
        for row in range(self.list.rowCount()):
            item = self.list.item(row, 1)
            m = item.data(Qt.UserRole)
            if m == slide:
                self.list.removeRow(row)
                self.contentChanged()
                break

    def editSlide(self, slide):
        for row in range(self.list.rowCount()):
            item = self.list.item(row, 1)
            m = item.data(Qt.UserRole)
            if m == slide:
                self.list.selectRow(row)
                self.tableDoubleClicked(row)
                break
Exemple #13
0
class CollapsibleMessageBox(QWidget):
    ''' docstring: 消息显示类,按钮触发折叠 '''
    def __init__(self,
                 Title="",
                 parent=None,
                 defaultLayout=False,
                 Message=None):
        super().__init__(parent)

        self.toggle_button = QToolButton(text=Title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

        self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.content_area.setFrameShape(QFrame.NoFrame)

        lay = QVBoxLayout(self)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.toggle_button)
        lay.addWidget(self.content_area)

        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area, b"maximumHeight"))

        if defaultLayout:
            lay = QVBoxLayout()
            self.text = QLabel()
            pa = QPalette()
            pa.setColor(pa.Background, Qt.white)
            pa.setColor(pa.Foreground, Qt.black)
            self.text.setAutoFillBackground(True)
            self.text.setPalette(pa)
            self.text.setTextInteractionFlags(Qt.TextSelectableByMouse)
            self.text.setTextFormat(Qt.MarkdownText)
            self.text.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
            self.text.setWordWrap(True)
            if not Message:
                Message = '空'
            self.text.setText(Message.replace('\n', '\n\n') + '\n')
            lay.addWidget(self.text)
            self.setContentLayout(lay)

    @pyqtSlot()
    def on_pressed(self):
        ''' docstring: 按钮函数,设置动画参数并触发 '''
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def setContentLayout(self, layout):
        ''' docstring: 重新设置布局,并计算按钮动画参数 '''
        lay = self.content_area.layout()
        del lay
        self.content_area.setLayout(layout)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(500)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)
        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(500)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
Exemple #14
0
class SidebarItem(QWidget):
    on_pressed = pyqtSignal(bool)

    def __init__(self, text, pixmap=None, parent=None):
        super().__init__(parent)

        rgb_value = 255 if options.theme == 'dark' else 0
        self.theme = options.theme

        # You are supposed to set size policy like this, and not to override sizePolicy()
        # If vertical policy was preferred, then you would have to implement minimumSizeHint and
        # maximumSize to limit how much the item can shrink and grow.
        self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
        self.text = text
        self.pixmap = pixmap
        self._prepare_pixmap(QColor(rgb_value, rgb_value, rgb_value, 200))
        self.spacing = 12
        self.font = QApplication.font()
        self.font.setBold(True)
        self.fm = QFontMetrics(self.font)
        self.mouse_over = False
        self.checked = False
        self.active = False
        self.setMouseTracking(True)

        self.background_color = QColor(rgb_value, rgb_value, rgb_value, 0)
        self.background_animation = QPropertyAnimation(self, b'opacity')
        self.background_animation.setStartValue(0)
        self.background_animation.setEndValue(40)
        self.background_animation.setDuration(300)

        self.indicator_pos = 5
        self.indicator_position_anim = QPropertyAnimation(
            self, b'indicator_position')
        self.indicator_position_anim.setStartValue(5)
        self.indicator_position_anim.setEndValue(-5)
        self.indicator_position_anim.setDuration(300)

        self.indicator_background = QColor(rgb_value, rgb_value, rgb_value, 0)
        self.indicator_opacity_anim = QPropertyAnimation(
            self, b'indicator_opacity')
        self.indicator_opacity_anim.setStartValue(0)
        self.indicator_opacity_anim.setEndValue(140)
        self.indicator_opacity_anim.setDuration(300)

        self.all_animations = QParallelAnimationGroup()
        self.all_animations.addAnimation(self.background_animation)
        self.all_animations.addAnimation(self.indicator_position_anim)
        self.all_animations.addAnimation(self.indicator_opacity_anim)

        OptionEventChannel.subscribe('theme', self.handle_theme_change)

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        self.on_pressed.emit(True)

    def set_checked(self, checked):
        self.checked = checked
        self.check_active()

    def check_active(self):
        old_active = self.active
        if self.checked:
            self.active = True
        else:
            self.active = self.mouse_over

        if old_active == self.active:
            return

        if self.active is True:
            self.all_animations.setDirection(QParallelAnimationGroup.Forward)
            self.all_animations.start()
        else:
            self.all_animations.setDirection(QParallelAnimationGroup.Backward)
            self.all_animations.start()

        # Calling update 10 times will result in only one update.
        # So it's fine to do this even after starting the animations.
        self.update()

    def enterEvent(self, event):
        self.mouse_over = True
        self.check_active()

    def leaveEvent(self, event):
        self.mouse_over = False
        self.check_active()

    def sizeHint(self):
        # sizeHint is used by layouts to get the recommended size of the widget.
        return QSize(100, 40)

    # def minimumSizeHint(self):
    #     # minimumSizeHint is used by layouts to get the minimum size of the widget.
    #     # It's ignored if minimumSize is also implemented
    #     return self.sizeHint()

    def paintEvent(self, paint_event):
        super().paintEvent(paint_event)
        widget_rect = self.rect()
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.fillRect(widget_rect, self.background_color)

        if self.mouse_over:
            indicator_rect = QRect(
                widget_rect.width() + self.indicator_pos - 6,
                (widget_rect.height() - 6) // 2, 6, 9)
            triangle_path = QPainterPath(indicator_rect.topRight())
            triangle_path.lineTo(indicator_rect.bottomRight())
            mid_left = indicator_rect.bottomLeft()
            mid_left.setY(mid_left.y() - indicator_rect.height() // 2)
            triangle_path.lineTo(mid_left)
            triangle_path.lineTo(indicator_rect.topRight())

            painter.fillPath(triangle_path, self.indicator_background)

        if self.pixmap:
            pixmap_rect = QRect(self.spacing, (widget_rect.height() - 20) // 2,
                                20, 20)
            painter.drawPixmap(pixmap_rect, self.pixmap, self.pixmap.rect())
            # painter.drawRect(pixmap_rect)
        else:
            pixmap_rect = QRect(0, 0, 0, 0)

        text_rect = QRect(pixmap_rect.right() + self.spacing, 0, 0,
                          widget_rect.height())
        text_rect.setWidth(widget_rect.width() - text_rect.left())
        # painter.drawRect(text_rect)

        text = self.fm.elidedText(self.text, Qt.ElideRight, text_rect.width())
        painter.setFont(self.font)
        painter.drawText(text_rect, Qt.AlignVCenter | Qt.AlignLeft, text)

    def _prepare_pixmap(self, qcolor):
        if self.pixmap is None:
            return
        painter = QPainter(self.pixmap)
        painter.setCompositionMode(QPainter.CompositionMode_SourceAtop)
        painter.fillRect(self.pixmap.rect(), qcolor)
        painter.end()

    def _get_opacity(self):
        return self.background_color.alpha()

    def _set_opacity(self, new_value):
        self.background_color.setAlpha(new_value)
        self.update()

    opacity = pyqtProperty('int', _get_opacity, _set_opacity)

    def _get_indicator_position(self):
        return self.indicator_pos

    def _set_indicator_position(self, new_value):
        self.indicator_pos = new_value
        self.update()

    indicator_position = pyqtProperty('int', _get_indicator_position,
                                      _set_indicator_position)

    def _get_indicator_opacity(self):
        return self.indicator_background.alpha()

    def _set_indicator_opacity(self, new_value):
        self.indicator_background.setAlpha(new_value)
        self.update()

    indicator_opacity = pyqtProperty('int', _get_indicator_opacity,
                                     _set_indicator_opacity)

    def handle_theme_change(self, theme):
        if theme == self.theme:
            return

        self.theme = theme
        if theme == 'dark':
            rgb_value = 255
        else:
            rgb_value = 0

        self.background_color.setRgb(rgb_value, rgb_value, rgb_value,
                                     self.background_color.alpha())
        self.indicator_background.setRgb(rgb_value, rgb_value, rgb_value,
                                         self.indicator_background.alpha())
        self._prepare_pixmap(QColor(rgb_value, rgb_value, rgb_value, 200))
        self.update()