eric6/QScintilla/EditorButtonsWidget.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7229
53054eb5b15a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/QScintilla/EditorButtonsWidget.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,363 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a widget containing various buttons for accessing
+editor actions.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import pyqtSlot, Qt
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QToolButton, QFrame, QMenu, \
+    QSizePolicy, QScrollArea
+
+import UI.PixmapCache
+import Preferences
+
+from . import MarkupProviders
+
+
+class EditorButtonsWidget(QWidget):
+    """
+    Class implementing a widget containing various buttons for accessing
+    editor actions.
+    """
+    def __init__(self, editor, parent=None):
+        """
+        Constructor
+        
+        @param editor reference to the editor
+        @type Editor
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super(EditorButtonsWidget, self).__init__(parent)
+        
+        margin = 2
+        spacing = 3
+        
+        self.__buttonsWidget = QWidget(self)
+        
+        self.__layout = QVBoxLayout(self.__buttonsWidget)
+        self.__layout.setContentsMargins(0, 0, 0, 0)
+        self.__layout.setSpacing(spacing)
+        
+        self.__provider = None
+        
+        self.__editor = editor
+        self.__editor.languageChanged.connect(self.__updateButtonStates)
+        self.__editor.editorSaved.connect(self.__updateButtonStates)
+        self.__editor.editorRenamed.connect(self.__updateButtonStates)
+        self.__editor.selectionChanged.connect(self.__editorSelectionChanged)
+        self.__editor.settingsRead.connect(self.__editorSettingsRead)
+        
+        self.__createButtons()
+        
+        self.__layout.addStretch()
+        
+        self.__outerLayout = QVBoxLayout(self)
+        self.__outerLayout.setContentsMargins(margin, margin, margin, margin)
+        self.__outerLayout.setSpacing(spacing)
+        self.__outerLayout.setAlignment(Qt.AlignHCenter)
+        
+        self.__upButton = QToolButton(self)
+        self.__upButton.setArrowType(Qt.UpArrow)
+        self.__upButton.setSizePolicy(
+            QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
+        self.__upButton.setAutoRepeat(True)
+        
+        self.__scroller = QScrollArea(self)
+        self.__scroller.setWidget(self.__buttonsWidget)
+        self.__scroller.setSizePolicy(
+            QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.__scroller.setFrameShape(QFrame.NoFrame)
+        self.__scroller.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+        self.__scroller.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+        self.__scroller.setWidgetResizable(False)
+        
+        self.__downButton = QToolButton(self)
+        self.__downButton.setArrowType(Qt.DownArrow)
+        self.__downButton.setSizePolicy(
+            QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
+        self.__downButton.setAutoRepeat(True)
+        
+        self.__outerLayout.addWidget(self.__upButton)
+        self.__outerLayout.addWidget(self.__scroller)
+        self.__outerLayout.addWidget(self.__downButton)
+        
+        self.__upButton.clicked.connect(self.__slideUp)
+        self.__downButton.clicked.connect(self.__slideDown)
+        
+        self.setMaximumWidth(
+            self.__buttons["bold"].sizeHint().width() + 2 * margin)
+        
+        self.__updateButtonStates()
+
+    #######################################################################
+    ## Methods below implement some event handlers
+    #######################################################################
+    
+    def show(self):
+        """
+        Public slot to show the widget.
+        """
+        super(EditorButtonsWidget, self).show()
+        self.__enableScrollerButtons()
+    
+    def resizeEvent(self, evt):
+        """
+        Protected method to handle resize events.
+        
+        @param evt reference to the resize event (QResizeEvent)
+        """
+        self.__enableScrollerButtons()
+        super(EditorButtonsWidget, self).resizeEvent(evt)
+    
+    #######################################################################
+    ## Methods below implement scroller related functions
+    #######################################################################
+    
+    def __enableScrollerButtons(self):
+        """
+        Private method to set the enabled state of the scroll buttons.
+        """
+        scrollBar = self.__scroller.verticalScrollBar()
+        self.__upButton.setEnabled(scrollBar.value() > 0)
+        self.__downButton.setEnabled(scrollBar.value() < scrollBar.maximum())
+    
+    def __slideUp(self):
+        """
+        Private slot to move the widget upwards, i.e. show contents to the
+        bottom.
+        """
+        self.__slide(True)
+    
+    def __slideDown(self):
+        """
+        Private slot to move the widget downwards, i.e. show contents to
+        the top.
+        """
+        self.__slide(False)
+    
+    def __slide(self, up):
+        """
+        Private method to move the sliding widget.
+        
+        @param up flag indicating to move upwards (boolean)
+        """
+        scrollBar = self.__scroller.verticalScrollBar()
+        stepSize = scrollBar.singleStep()
+        if up:
+            stepSize = -stepSize
+        newValue = scrollBar.value() + stepSize
+        if newValue < 0:
+            newValue = 0
+        elif newValue > scrollBar.maximum():
+            newValue = scrollBar.maximum()
+        scrollBar.setValue(newValue)
+        self.__enableScrollerButtons()
+    
+    #######################################################################
+    ## Methods below implement the format button functions
+    #######################################################################
+    
+    def __createButtons(self):
+        """
+        Private slot to create the various tool buttons.
+        """
+        self.__buttons = {}
+        self.__separators = []
+        self.__headerMenu = QMenu()
+        
+        self.__addButton("bold", "formatTextBold.png",
+                         self.tr("Bold"))
+        self.__addButton("italic", "formatTextItalic.png",
+                         self.tr("Italic"))
+        self.__addButton("strikethrough", "formatTextStrikethrough.png",
+                         self.tr("Strike Through"))
+        self.__addSeparator()
+        self.__addButton("header1", "formatTextHeader1.png",
+                         self.tr("Header 1"))
+        self.__addButton("header2", "formatTextHeader2.png",
+                         self.tr("Header 2"))
+        self.__addButton("header3", "formatTextHeader3.png",
+                         self.tr("Header 3"))
+        button = self.__addButton("header", "formatTextHeader.png",
+                                  self.tr("Header"))
+        button.setPopupMode(QToolButton.InstantPopup)
+        button.setMenu(self.__headerMenu)
+        self.__addSeparator()
+        self.__addButton("code", "formatTextInlineCode.png",
+                         self.tr("Inline Code"))
+        self.__addButton("codeBlock", "formatTextCodeBlock.png",
+                         self.tr("Code Block"))
+        self.__addButton("quote", "formatTextQuote.png",
+                         self.tr("Quote"))
+        self.__addSeparator()
+        self.__addButton("hyperlink", "formatTextHyperlink.png",
+                         self.tr("Add Hyperlink"))
+        self.__addButton("line", "formatTextHorizontalLine.png",
+                         self.tr("Add Horizontal Line"))
+        self.__addButton("image", "formatTextImage.png",
+                         self.tr("Add Image"))
+        self.__addSeparator()
+        self.__addButton("bulletedList", "formatTextBulletedList.png",
+                         self.tr("Add Bulleted List"))
+        self.__addButton("numberedList", "formatTextNumberedList.png",
+                         self.tr("Add Numbered List"))
+        
+        self.__headerMenu.triggered.connect(self.__headerMenuTriggered)
+    
+    def __addButton(self, formatName, iconName, toolTip):
+        """
+        Private method to add a format button.
+        
+        @param formatName unique name of the format
+        @type str
+        @param iconName name of the icon for the button
+        @type str
+        @param toolTip text for the tool tip
+        @type str
+        @return generated button
+        @rtype QToolButton
+        """
+        button = QToolButton(self.__buttonsWidget)
+        button.setIcon(UI.PixmapCache.getIcon(iconName))
+        button.setToolTip(toolTip)
+        button.clicked.connect(lambda: self.__formatClicked(formatName))
+        self.__layout.addWidget(button)
+        self.__buttons[formatName] = button
+        
+        return button
+    
+    def __addSeparator(self):
+        """
+        Private method to add a separator line.
+        """
+        line = QFrame(self.__buttonsWidget)
+        line.setLineWidth(2)
+        if isinstance(self.__layout, QVBoxLayout):
+            line.setFrameShape(QFrame.HLine)
+        else:
+            line.setFrameShape(QFrame.VLine)
+        line.setFrameShadow(QFrame.Sunken)
+        
+        self.__layout.addWidget(line)
+        self.__separators.append(line)
+    
+    @pyqtSlot()
+    def __updateButtonStates(self):
+        """
+        Private slot to change the button states.
+        """
+        provider = MarkupProviders.getMarkupProvider(self.__editor)
+        if self.__provider is None or \
+                provider.kind() != self.__provider.kind():
+            self.__provider = provider
+            
+            self.__buttons["bold"].setEnabled(self.__provider.hasBold())
+            self.__buttons["italic"].setEnabled(self.__provider.hasItalic())
+            self.__buttons["strikethrough"].setEnabled(
+                self.__provider.hasStrikethrough())
+            
+            headerLevels = self.__provider.headerLevels()
+            self.__buttons["header1"].setEnabled(headerLevels >= 1)
+            self.__buttons["header2"].setEnabled(headerLevels >= 2)
+            self.__buttons["header3"].setEnabled(headerLevels >= 3)
+            self.__buttons["header"].setEnabled(headerLevels > 3)
+            self.__headerMenu.clear()
+            for level in range(1, headerLevels + 1):
+                act = self.__headerMenu.addAction(
+                    self.tr("Level {0}").format(level))
+                act.setData("header{0}".format(level))
+            
+            self.__buttons["code"].setEnabled(self.__provider.hasCode())
+            self.__buttons["codeBlock"].setEnabled(
+                self.__provider.hasCodeBlock())
+            
+            self.__buttons["bulletedList"].setEnabled(
+                self.__provider.hasBulletedList())
+            self.__buttons["numberedList"].setEnabled(
+                self.__provider.hasNumberedList())
+            
+            self.__editorSelectionChanged()
+            
+            if Preferences.getEditor("HideFormatButtons"):
+                self.setVisible(self.__provider.kind() != "none")
+    
+    def __formatClicked(self, formatName):
+        """
+        Private slot to handle a format button being clicked.
+        
+        @param formatName format type of the button
+        @type str
+        """
+        if formatName == "bold":
+            self.__provider.bold(self.__editor)
+        elif formatName == "italic":
+            self.__provider.italic(self.__editor)
+        elif formatName == "strikethrough":
+            self.__provider.strikethrough(self.__editor)
+        elif formatName.startswith("header"):
+            try:
+                level = int(formatName[-1])
+                self.__provider.header(self.__editor, level)
+            except ValueError:
+                pass
+        elif formatName == "code":
+            self.__provider.code(self.__editor)
+        elif formatName == "codeBlock":
+            self.__provider.codeBlock(self.__editor)
+        elif formatName == "quote":
+            self.__provider.quote(self.__editor)
+        elif formatName == "hyperlink":
+            self.__provider.hyperlink(self.__editor)
+        elif formatName == "line":
+            self.__provider.line(self.__editor)
+        elif formatName == "image":
+            self.__provider.image(self.__editor)
+        elif formatName == "bulletedList":
+            self.__provider.bulletedList(self.__editor)
+        elif formatName == "numberedList":
+            self.__provider.numberedList(self.__editor)
+    
+    def __headerMenuTriggered(self, act):
+        """
+        Private method handling the selection of a header menu entry.
+        
+        @param act action of the headers menu that was triggered
+        @type QAction
+        """
+        formatName = act.data()
+        self.__formatClicked(formatName)
+    
+    def __editorSelectionChanged(self):
+        """
+        Private slot to handle a change of the editor's selection.
+        """
+        hasSelection = self.__editor.hasSelectedText()
+        if self.__provider:
+            self.__buttons["quote"].setEnabled(
+                self.__provider.hasQuote() and (
+                    self.__provider.kind() == "html" or hasSelection
+                )
+            )
+            self.__buttons["hyperlink"].setEnabled(
+                self.__provider.hasHyperlink() and not hasSelection)
+            self.__buttons["line"].setEnabled(
+                self.__provider.hasLine() and not hasSelection)
+            self.__buttons["image"].setEnabled(
+                self.__provider.hasImage() and not hasSelection)
+    
+    def __editorSettingsRead(self):
+        """
+        Private slot to handle a change of the editor related settings.
+        """
+        if Preferences.getEditor("HideFormatButtons"):
+            if self.__provider is not None:
+                self.setVisible(self.__provider.kind() != "none")
+        else:
+            self.setVisible(True)

eric ide

mercurial