Пример #1
0
class PaletteView(QObject):
    """A toolvide to display palette of the current document"""
    colors = []
    toolView = None
    colorCellsWidget = None

    def __init__(self, parent):
        super(PaletteView, self).__init__(parent)
        self.toolView = kate.mainInterfaceWindow().createToolView(
            "color_tools_pate_plugin", kate.Kate.MainWindow.Bottom,
            kate.gui.loadIcon('color'), i18n("Palette"))
        self.toolView.installEventFilter(self)
        # By default, the toolview has box layout, which is not easy to delete.
        # For now, just add an extra widget.
        top = QWidget(self.toolView)
        # Set up the user interface from Designer.
        interior = uic.loadUi(
            os.path.join(os.path.dirname(__file__), 'color_tools_toolview.ui'),
            top)
        interior.update.clicked.connect(self.update)
        self.colorCellsWidget = KColorCells(interior, 1, 1)
        # TODO Don't know how to deal w/ drag-n-drops :(
        # It seems there is no signal to realize that some item has changed :(
        self.colorCellsWidget.setAcceptDrags(False)
        interior.verticalLayout.addWidget(self.colorCellsWidget)
        self.colorCellsWidget.colorSelected.connect(self.colorSelected)
        self.colorCellsWidget.colorDoubleClicked.connect(
            self.colorDoubleClicked)

    def __del__(self):
        """Plugins that use a toolview need to delete it for reloading to work."""
        if self.toolView:
            self.toolView.deleteLater()
            self.toolView = None

    def eventFilter(self, obj, event):
        """Hide the Palette tool view on ESCAPE key"""
        if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Escape:
            kate.mainInterfaceWindow().hideToolView(self.toolView)
            return True
        return self.toolView.eventFilter(obj, event)

    def updateColors(self, view=None):
        """Scan a document for #colors"""
        self.colors = list()  # Clear previous colors
        if view:
            document = view.document()
        else:
            try:
                document = kate.activeDocument()
            except kate.NoActiveView:
                return  # Do nothing if we can't get a current document
        # Iterate over document's lines trying to find #colors
        for l in range(0, document.lines()):
            line = document.line(l)  # Get the current line
            start = 0  # Set initial position to 0 (line start)
            while start < len(line):  # Repeat 'till the line end
                start = line.find(
                    '#',
                    start)  # Try to find a '#' character (start of #color)
                if start == -1:  # Did we found smth?
                    break  # No! Nothing to do...
                # Try to get a word right after the '#' char
                end = start + 1
                for c in line[end:]:
                    if not (c in string.hexdigits
                            or c in string.ascii_letters):
                        break
                    end += 1
                color_range = KTextEditor.Range(l, start, l, end)
                color_str = document.text(color_range)
                color = QColor(color_str)
                if color.isValid():
                    self.colors.append(ColorRangePair(color, color_range))
                    print('PALETTE VIEW: Found %s' % color_str)
                start = end

    def updateColorCells(self):
        """Calculate rows*columns and fill the cells w/ #colors"""
        if len(self.colors):
            # Recalculate rows/columns
            columns = int(math.sqrt(len(self.colors)))
            rows = int(len(self.colors) / columns) + int(
                bool(len(self.colors) % columns))
        else:
            columns = 1
            rows = 1
            self.colors.append(ColorRangePair(QColor(), KTextEditor.Range()))
        self.colorCellsWidget.setColumnCount(columns)
        self.colorCellsWidget.setRowCount(rows)
        self.colorCellsWidget.resizeColumnsToContents()
        self.colorCellsWidget.resizeRowsToContents()
        # Fill color cells
        for i, crp in enumerate(self.colors):
            self.colorCellsWidget.setColor(i, crp.color)

    @pyqtSlot()
    def update(self, view=None):
        self.updateColors(view)
        self.updateColorCells()

    @pyqtSlot(int, QColor)
    def colorSelected(self, idx, color):
        """Move cursor to the position of the selected #color and select the range"""
        view = kate.activeView()
        view.setCursorPosition(self.colors[idx].color_range.start())
        view.setSelection(self.colors[idx].color_range)

    @pyqtSlot(int, QColor)
    def colorDoubleClicked(self, idx, color):
        """Edit selected color on double click"""
        insertColor()
        self.update()
Пример #2
0
class PaletteView(QObject):
    '''A toolview to display palette of the current document'''
    colors = []
    toolView = None
    colorCellsWidget = None

    def __init__(self, parent):
        super(PaletteView, self).__init__(parent)
        self.toolView = kate.mainInterfaceWindow().createToolView(
            'color_tools_pate_plugin'
          , kate.Kate.MainWindow.Bottom
          , KIcon('color').pixmap(32, 32)
          , i18nc('@title:tab', 'Palette')
          )
        self.toolView.installEventFilter(self)
        # By default, the toolview has box layout, which is not easy to delete.
        # For now, just add an extra widget.
        top = QWidget(self.toolView)
        # Set up the user interface from Designer.
        interior = uic.loadUi(os.path.join(os.path.dirname(__file__), 'color_tools_toolview.ui'), top)
        interior.update.clicked.connect(self.update)
        self.colorCellsWidget = KColorCells(interior, 1, 1)
        # TODO Don't know how to deal w/ drag-n-drops :(
        # It seems there is no signal to realize that some item has changed :(
        # (at lieast I didn't find it)
        self.colorCellsWidget.setAcceptDrags(False)
        self.colorCellsWidget.setEditTriggers(self.colorCellsWidget.NoEditTriggers)
        interior.verticalLayout.addWidget(self.colorCellsWidget)
        self.colorCellsWidget.colorSelected.connect(self.colorSelected)
        self.colorCellsWidget.colorDoubleClicked.connect(self.colorDoubleClicked)

    #def __del__(self):
        #'''Plugins that use a toolview need to delete it for reloading to work.'''
        #if self.toolView:
            #self.toolView.deleteLater()
            #self.toolView = None

    def eventFilter(self, obj, event):
        '''Hide the Palette tool view on ESCAPE key'''
        if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Escape:
            kate.mainInterfaceWindow().hideToolView(self.toolView)
            return True
        return self.toolView.eventFilter(obj, event)

    def updateColors(self, view=None):
        '''Scan a document for #colors

            Returns a list of tuples: QColor and range in a document
            TODO Some refactoring needed to reduce code duplication
            (@sa _get_color_range_under_cursor())
        '''
        self.colors = []                                    # Clear previous colors
        if view:
            document = view.document()
        else:
            try:
                document = kate.activeDocument()
            except kate.NoActiveView:
                return                                      # Do nothing if we can't get a current document
        # Iterate over document's lines trying to find #colors
        for l in range(0, document.lines()):
            line = document.line(l)                         # Get the current line
            start = 0                                       # Set initial position to 0 (line start)
            while start < len(line):                        # Repeat 'till the line end
                start = line.find('#', start)               # Try to find a '#' character (start of #color)
                if start == -1:                             # Did we found smth?
                    break                                   # No! Nothing to do...
                # Try to get a word right after the '#' char
                end = start + 1
                for c in line[end:]:
                    if not (c in string.hexdigits):
                        break
                    end += 1
                color_range = KTextEditor.Range(l, start, l, end)
                color_str = document.text(color_range)
                color = QColor(color_str)
                if color.isValid():
                    self.colors.append(ColorRangePair(color, color_range))
                    kate.kDebug('ColorUtilsToolView: scan for #colors found {}'.format(color_str))
                start = end

    def updateColorCells(self):
        '''Calculate rows*columns and fill the cells w/ #colors'''
        if len(self.colors):
            # Recalculate rows/columns
            columns = int(self.colorCellsWidget.width() / 30)
            visible_rows = int(self.colorCellsWidget.height() / 25)
            if len(self.colors) < (columns * visible_rows):
                rows = visible_rows
            else:
                visible_cells = columns * visible_rows
                rest = len(self.colors) - visible_cells
                rows = visible_rows + int(rest / columns) + int(bool(rest % columns))
        else:
            columns = 1
            rows = 1
            self.colors.append(ColorRangePair(QColor(), KTextEditor.Range()))
        self.colorCellsWidget.setColumnCount(columns)
        self.colorCellsWidget.setRowCount(rows)
        self.colorCellsWidget.resizeColumnsToContents()
        self.colorCellsWidget.resizeRowsToContents()
        # Fill color cells
        for i, crp in enumerate(self.colors):
            self.colorCellsWidget.setColor(i, crp.color)
        for i in range(len(self.colors), columns * rows):
            self.colorCellsWidget.setColor(i, QColor())
        _set_tooltips(rows, columns, self.colorCellsWidget)


    @pyqtSlot()
    def update(self, view=None):
        self.updateColors(view)
        self.updateColorCells()


    @pyqtSlot(int, QColor)
    def colorSelected(self, idx, color):
        '''Move cursor to the position of the selected #color and select the range'''
        view = kate.activeView()
        view.setCursorPosition(self.colors[idx].color_range.start())
        view.setSelection(self.colors[idx].color_range)


    @pyqtSlot(int, QColor)
    def colorDoubleClicked(self, idx, color):
        '''Edit selected color on double click'''
        insertColor()
        self.update()
Пример #3
0
class ColorChooser(QFrame):
    '''
        Completion-like widget to quick select hexadecimal colors used in a document

        TODO Make cell/widget size configurable?
    '''
    colorSelected = pyqtSignal(QColor)

    def __init__(self, parent):
        super(ColorChooser, self).__init__(parent)
        self.colors = KColorCells(self, 1, 1)
        self.colors.setAcceptDrags(False)
        self.colors.setEditTriggers(self.colors.NoEditTriggers)
        self.otherBtn = KPushButton(self)
        self.otherBtn.setText(i18nc('@action:button', '&Other...'))
        layout = QVBoxLayout(self)
        layout.addWidget(self.colors)
        layout.addWidget(self.otherBtn)
        self.setFocusPolicy(Qt.StrongFocus)
        self.setFrameShape(QFrame.Panel)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Popup);

        # Subscribe to observe widget events
        # - open KColorDialog on 'Other...' button click
        self.otherBtn.clicked.connect(self.show_color_dialog)
        # - select color by RMB click or ENTER on keyboard
        self.colors.cellActivated.connect(self.color_selected)

        self.installEventFilter(self)


    def setColors(self, colors):
        if len(colors):
            rows, columns = _calc_dimensions_for_items_count(len(colors))
        else:
            self.hide()
            self.show_color_dialog(True)
            return
        self.colors.setColumnCount(columns)
        self.colors.setRowCount(rows)
        self.colors.setMinimumSize(20 * columns, 25 * rows)
        self.updateGeometry()
        self.adjustSize()
        self.colors.resizeColumnsToContents()
        self.colors.resizeRowsToContents()
        # Fill color cells
        for i, color in enumerate(colors):
            self.colors.setColor(i, color)
        _set_tooltips(rows, columns, self.colors)           # Set tooltips for all valid color cells
        self.colors.setFocus()                              # Give a focus to widget
        self.show()                                         # Show it!


    @pyqtSlot(bool)
    def show_color_dialog(self, f):
        '''Get color using KColorDialog'''
        # Preselect last used color
        color = QColor(kate.sessionConfiguration[_INSERT_COLOR_LCC])
        result = KColorDialog.getColor(color)
        if result == KColorDialog.Accepted:                  # Did user press OK?
            self.emitSelectedColorHideSelf(color)


    @pyqtSlot(int, int)
    def color_selected(self, row, column):
        '''Smth has selected in KColorCells'''
        color = self.colors.item(row, column).data(Qt.BackgroundRole)
        #kate.kDebug('ColorUtils: activated row={}, column={}, color={}'.format(row, column, color))
        self.emitSelectedColorHideSelf(color)


    def emitSelectedColorHideSelf(self, color):
        # Remember last selected color for future preselect
        kate.sessionConfiguration[_INSERT_COLOR_LCC] = color.name()
        self.colorSelected.emit(color)
        self.hide()


    def eventFilter(self, obj, event):
        '''Hide self on Esc key'''
        if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Escape:
            self.hide()
            return True
        return super(ColorChooser, self).eventFilter(obj, event)


    def moveAround(self, position):
        '''Smart positioning self around cursor'''
        self.colors.resizeColumnsToContents()
        self.colors.resizeRowsToContents()
        mwg = kate.mainWindow().geometry()
        wc = mwg.center()
        pos = mwg.topLeft() + position
        pos.setY(pos.y() + 40)
        if wc.y() < pos.y():
            pos.setY(pos.y() - self.height())
        if wc.x() < pos.x():
            pos.setX(pos.x() - self.width())

        self.move(pos)
Пример #4
0
class ColorChooser(QFrame):
    '''
        Completion-like widget to quick select hexadecimal colors used in a document

        TODO Make cell/widget size configurable?
    '''

    _INSERT_COLOR_LCC = 'insertColor:lastUsedColor'

    colorSelected = pyqtSignal(QColor)

    def __init__(self):
        super(ColorChooser, self).__init__(None)
        self.colors = KColorCells(self, 1, 1)
        self.colors.setAcceptDrags(False)
        self.colors.setEditTriggers(self.colors.NoEditTriggers)
        self.otherBtn = KPushButton(self)
        self.otherBtn.setText(i18nc('@action:button', '&Other...'))
        layout = QVBoxLayout(self)
        layout.addWidget(self.colors)
        layout.addWidget(self.otherBtn)
        self.setFocusPolicy(Qt.StrongFocus)
        self.setFrameShape(QFrame.Panel)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Popup)

        # Set default value for last used #color if not configured yet
        if ColorChooser._INSERT_COLOR_LCC not in kate.sessionConfiguration:
            kate.sessionConfiguration[ColorChooser._INSERT_COLOR_LCC] = '#ffffff'

        # Subscribe to observe widget events
        # - open KColorDialog on 'Other...' button click
        self.otherBtn.clicked.connect(self._show_color_dialog)
        # - select color by RMB click or ENTER on keyboard
        self.colors.cellActivated.connect(self._color_selected)
        # -
        self.colorSelected.connect(self._insert_color_into_active_document)

        self.installEventFilter(self)


    def __del__(self):
        mw = kate.mainInterfaceWindow()
        if mw:
            self.blockSignals(True)
            self.removeEventFilter(self)


    def updateColors(self, document):
        '''Scan a given document and collect unique colors

            Returns a list of QColor objects.
        '''
        result = []
        # Iterate over document's lines trying to find #colors
        for l in range(0, document.lines()):
            line = document.line(l)                         # Get the current line
            start = 0                                       # Set initial position to 0 (line start)
            while start < len(line):                        # Repeat 'till the line end
                start = line.find('#', start)               # Try to find a '#' character (start of #color)
                if start == -1:                             # Did we found smth?
                    break                                   # No! Nothing to do...
                # Try to get a word right after the '#' char
                end = start + 1
                for c in line[end:]:
                    if not (c in string.hexdigits or c in string.ascii_letters):
                        break
                    end += 1
                color_range = KTextEditor.Range(l, start, l, end)
                color_str = document.text(color_range)
                color = QColor(color_str)
                if color.isValid() and color not in result:
                    result.append(color)
                    kate.kDebug('ColorUtils: scan for #colors found {}'.format(color_str))
                start = end
        self._set_colors(result)


    def moveAround(self, position):
        '''Smart positioning self around cursor'''
        self.colors.resizeColumnsToContents()
        self.colors.resizeRowsToContents()
        mwg = kate.mainWindow().geometry()
        wc = mwg.center()
        pos = mwg.topLeft() + position
        pos.setY(pos.y() + 40)
        if wc.y() < pos.y():
            pos.setY(pos.y() - self.height())
        if wc.x() < pos.x():
            pos.setX(pos.x() - self.width())

        self.move(pos)


    def emitSelectedColorHideSelf(self, color):
        # Remember last selected color for future preselect
        kate.sessionConfiguration[ColorChooser._INSERT_COLOR_LCC] = color.name()
        self.colorSelected.emit(color)
        self.hide()


    def eventFilter(self, obj, event):
        '''Hide self on Esc key'''
        if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Escape:
            self.hide()
            return True
        return super(ColorChooser, self).eventFilter(obj, event)


    def _set_colors(self, colors):
        if len(colors):
            rows, columns = ColorChooser._calc_dimensions_for_items_count(len(colors))
        else:
            self.hide()
            self._show_color_dialog(True)
            return
        self.colors.setColumnCount(columns)
        self.colors.setRowCount(rows)
        self.colors.setMinimumSize(20 * columns, 25 * rows)
        self.updateGeometry()
        self.adjustSize()
        self.colors.resizeColumnsToContents()
        self.colors.resizeRowsToContents()
        # Fill color cells
        for i, color in enumerate(colors):
            self.colors.setColor(i, color)
        setTooltips(rows, columns, self.colors)             # Set tooltips for all valid color cells
        self.colors.setFocus()                              # Give a focus to widget
        self.show()                                         # Show it!


    @pyqtSlot(bool)
    def _show_color_dialog(self, f):
        '''Get color using KColorDialog'''
        # Preselect last used color
        color = QColor(kate.sessionConfiguration[ColorChooser._INSERT_COLOR_LCC])
        result = KColorDialog.getColor(color)
        if result == KColorDialog.Accepted:                 # Did user press OK?
            self.emitSelectedColorHideSelf(color)


    @pyqtSlot(int, int)
    def _color_selected(self, row, column):
        '''Smth has selected in KColorCells'''
        color = self.colors.item(row, column).data(Qt.BackgroundRole)
        #kate.kDebug('ColorUtils: activated row={}, column={}, color={}'.format(row, column, color))
        self.emitSelectedColorHideSelf(color)


    @pyqtSlot(QColor)
    def _insert_color_into_active_document(self, color):
        color_str = color.name()                            # Get it as color string
        #kate.kDebug('ColorUtils: selected color: {}'.format(color_str))
        document = kate.activeDocument()
        view = kate.activeView()
        has_selection = view.selection()                    # Remember current selection state
        color_range = ColorChooser._get_color_range_under_cursor(view)
        document.startEditing()
        document.replaceText(color_range, color_str)        # Replace selected/found range w/ a new text
        document.endEditing()
        # Select just entered #color, if something was selected before
        if has_selection:
            start_pos = color_range.start()
            view.setSelection(KTextEditor.Range(start_pos, len(color_str)))


    @staticmethod
    def _calc_dimensions_for_items_count(count):
        '''Recalculate rows/columns of table view for given items count'''
        rows = int(math.sqrt(count))
        columns = int(count / rows) + int(bool(count % rows))
        return (rows, columns)


    @staticmethod
    def _get_color_range_under_cursor(view):
        assert(view is not None)
        if view.selection():                                # Some text selected, just use it as input...
            color_range = view.selectionRange()
        else:                                               # If no selection, try to get a #color under cursor
            color_range = common.getBoundTextRangeSL(
                common.IDENTIFIER_BOUNDARIES - {'#'}
              , common.IDENTIFIER_BOUNDARIES
              , view.cursorPosition()
              , view.document()
              )
            # Check if a word under cursor is a valid #color
            color = QColor(view.document().text(color_range))
            if not color.isValid():
                color_range = KTextEditor.Range(view.cursorPosition(), view.cursorPosition())
        return color_range