Exemple #1
0
def read_settings_API_1(stream, settings):
    """ Write all settings such as fonts for labels and legend.
    
    NOTE: This function doesn't return anything and changes
    the settings directly."""

    labelFont     = QFont()
    legendFont    = QFont()

    stream >> labelFont

    labelInterval = stream.readInt32()
    labelState = get_row_label_identifier(labelInterval)

    stream >> legendFont
    gridCellWidth = stream.readInt32()
    gridCellHeight = stream.readInt32()

    # make sure we parsed something sensible before 
    # touching the settings
    if labelFont.family():
        settings.labelFont.value = labelFont

    if labelState:
        settings.rowLabelMode.value = labelState

    if legendFont.family():
        settings.legendFont.value = legendFont

    if gridCellWidth != 0:
        settings.gridCellWidth.value = gridCellWidth

    if gridCellHeight != 0:
        settings.gridCellHeight.value = gridCellHeight
Exemple #2
0
def read_settings_API_1(stream, settings):
    """ Write all settings such as fonts for labels and legend.
    
    NOTE: This function doesn't return anything and changes
    the settings directly."""

    labelFont = QFont()
    legendFont = QFont()

    stream >> labelFont

    labelInterval = stream.readInt32()
    labelState = get_row_label_identifier(labelInterval)

    stream >> legendFont
    gridCellWidth = stream.readInt32()
    gridCellHeight = stream.readInt32()

    # make sure we parsed something sensible before
    # touching the settings
    if labelFont.family():
        settings.labelFont.value = labelFont

    if labelState:
        settings.rowLabelMode.value = labelState

    if legendFont.family():
        settings.legendFont.value = legendFont

    if gridCellWidth != 0:
        settings.gridCellWidth.value = gridCellWidth

    if gridCellHeight != 0:
        settings.gridCellHeight.value = gridCellHeight
Exemple #3
0
    def applySettings(self):
        """Apply editor and lexer settings
        """
        if self.qscilexer is None:
            return

        # Apply fonts and colors
        config = core.config()["Editor"]
        defaultFont = QFont(config["DefaultFont"], config["DefaultFontSize"])
        self.qscilexer.setDefaultFont(defaultFont)
        for i in range(128):
            if self.qscilexer.description(i):
                font = self.qscilexer.font(i)
                font.setFamily(defaultFont.family())
                font.setPointSize(defaultFont.pointSize())
                self.qscilexer.setFont(font, i)
                # lexer->setColor(lexer->defaultColor(i), i);  # TODO configure lexer colors
                # lexer->setEolFill(lexer->defaultEolFill(i), i);
                # lexer->setPaper(lexer->defaultPaper(i), i);
                if config["DefaultDocumentColours"]:
                    self.qscilexer.setPaper(QColor(config["DefaultDocumentPaper"]), i)
                    self.qscilexer.setEolFill(True, i)
                else:
                    self.qscilexer.setPaper(self.qscilexer.defaultPaper(i), i)
                    self.qscilexer.setEolFill(self.qscilexer.defaultEolFill(i), i)

        if config["DefaultDocumentColours"]:
            self.qscilexer.setColor(QColor(config["DefaultDocumentPen"]), 0)
        else:
            self.qscilexer.setColor(self.qscilexer.defaultColor(0), 0)
Exemple #4
0
def getMonoFont(fontsize=12, msg=False):
    monofont = QFont()
    monofont.setStyleStrategy(QFont.PreferAntialias+QFont.PreferMatch)
    monofont.setStyleHint(QFont.Courier)
    monofont.setFamily(IMC.fontFamily)
    monofont.setFixedPitch(True) # probably unnecessary
    monofont.setPointSize(fontsize)
    if msg and (monofont.family() != IMC.fontFamily):
        infoMsg("Font {0} not available, using {1}".format(
            IMC.fontFamily, monoinf.family()) )
    return monofont
Exemple #5
0
    def test_1(self):
        font = QFont("Arial", 88)

        def continueFunc(dialog):
            page = dialog._pageForItem["Editor/Font"]

            page.lFont.setFont(font)

            QTest.keyClick(dialog, Qt.Key_Enter)

        self.openSettings(continueFunc)

        self.assertEqual(core.config()['Qutepart']['Font']['Family'],
                         font.family())
        self.assertEqual(core.config()['Qutepart']['Font']['Size'],
                         font.pointSize())

        self.assertEqual(
            core.workspace().currentDocument().qutepart.font().family(),
            font.family())
        self.assertEqual(
            core.workspace().currentDocument().qutepart.font().pointSize(),
            font.pointSize())
Exemple #6
0
    def loadHistoryData(self):      
        tabledata = self.history.toList()   
        self.tablemodel = BeeralyzerTableModel(tabledata)
        self.historyTableView.setModel(self.tablemodel)
        self.historyTableView.setShowGrid(True)

        font = QFont(self.historTableFontFamily, self.historTableFontSize)
        self.displayHistoryTableFont(font.family(), font.pointSize())
        self.historyTableView.setFont(font)
        vh = self.historyTableView.verticalHeader()
        vh.setVisible(True)
        hh = self.historyTableView.horizontalHeader()
        hh.setStretchLastSection(True)
        self.historyTableView.setSortingEnabled(True)   
        self.historyTableView.resizeColumnsToContents()
Exemple #7
0
def getFontFromSetting(setting_data, default_font=None):
    import hex.utils as utils

    font = default_font or QFont()
    if isinstance(setting_data, str):
        stored_font = QFont()
        ok = stored_font.fromString(setting_data)
        return stored_font if ok else font
    elif isinstance(setting_data, (tuple, list)):
        for font_data in setting_data:
            if isinstance(font_data, str):
                stored_font = QFont()
                ok = stored_font.fromString(font_data)
                if ok and utils.isFontInstalled(stored_font.family()):
                    return stored_font
    return font
Exemple #8
0
 def test_1(self):
     font = QFont("Arial", 88)
     
     def continueFunc(dialog):
         page = dialog._pageForItem["Editor/Font"]
         
         page.lFont.setFont(font)
         
         QTest.keyClick(dialog, Qt.Key_Enter)
     
     self.openSettings(continueFunc)
     
     self.assertEqual(core.config()['Qutepart']['Font']['Family'], font.family())
     self.assertEqual(core.config()['Qutepart']['Font']['Size'], font.pointSize())
     
     self.assertEqual(core.workspace().currentDocument().qutepart.font(), font)
Exemple #9
0
class CharMap(QWidget):
    """A widget displaying a table of characters."""
    characterSelected = pyqtSignal(str)
    characterClicked = pyqtSignal(str)

    def __init__(self, parent=None):
        super(CharMap, self).__init__(parent)
        self._showToolTips = True
        self._showWhatsThis = True
        self._selected = -1
        self._column_count = 32
        self._square = 24
        self._range = (0, 0)
        self._font = QFont()

    def setRange(self, first, last):
        self._range = (first, last)
        self._selected = -1
        self.adjustSize()
        self.update()

    def range(self):
        return self._range

    def square(self):
        """Returns the width of one item (determined by font size)."""
        return self._square

    def select(self, charcode):
        """Selects the specified character (int or str)."""
        if not isinstance(charcode, int):
            charcode = ord(charcode)
        if not self._range[0] <= charcode <= self._range[1]:
            charcode = -1
        if self._selected != charcode:
            self._selected = charcode
            self.characterSelected.emit(chr(charcode))
            self.update()

    def character(self):
        """Returns the currently selected character, if any."""
        if self._selected != -1:
            return chr(self._selected)

    def setDisplayFont(self, font):
        self._font.setFamily(font.family())
        self.update()

    def displayFont(self):
        return QFont(self._font)

    def setDisplayFontSize(self, size):
        self._font.setPointSize(size)
        self._square = max(24, QFontMetrics(self._font).xHeight() * 3)
        self.adjustSize()
        self.update()

    def displayFontSize(self):
        return self._font.pointSize()

    def setDisplayFontSizeF(self, size):
        self._font.setPointSizeF(size)
        self._square = max(24, QFontMetrics(self._font).xHeight() * 3)
        self.adjustSize()
        self.update()

    def displayFontSizeF(self):
        return self._font.pointSizeF()

    def setColumnCount(self, count):
        """Sets how many columns should be used."""
        count = max(1, count)
        self._column_count = count
        self.adjustSize()
        self.update()

    def columnCount(self):
        return self._column_count

    def sizeHint(self):
        return self.sizeForColumnCount(self._column_count)

    def paintEvent(self, ev):
        rect = ev.rect()
        s = self._square
        rows = range(rect.top() // s, rect.bottom() // s + 1)
        cols = range(rect.left() // s, rect.right() // s + 1)

        painter = QPainter(self)
        painter.setPen(QPen(self.palette().color(QPalette.Window)))
        painter.setFont(self._font)
        metrics = QFontMetrics(self._font)

        # draw characters on white tiles
        tile = self.palette().color(QPalette.Base)
        selected_tile = self.palette().color(QPalette.Highlight)
        selected_tile.setAlpha(96)
        selected_box = self.palette().color(QPalette.Highlight)

        text_pen = QPen(self.palette().text())
        disabled_pen = QPen(self.palette().color(QPalette.Disabled,
                                                 QPalette.Text))
        selection_pen = QPen(selected_box)
        for row in rows:
            for col in cols:
                char = row * self._column_count + col + self._range[0]
                if char > self._range[1]:
                    break
                printable = self.isprint(char)
                painter.setClipRect(col * s, row * s, s, s)
                if char == self._selected:
                    painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2,
                                     selected_tile)
                    painter.setPen(selection_pen)
                    painter.drawRect(col * s, row * s, s - 1, s - 1)
                elif printable:
                    painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2,
                                     tile)
                painter.setPen(text_pen if printable else disabled_pen)
                t = chr(char)
                x = col * s + s // 2 - metrics.width(t) // 2
                y = row * s + 4 + metrics.ascent()
                painter.drawText(x, y, t)
            else:
                continue
            break

    def sizeForColumnCount(self, count):
        """Returns the size the widget would have in a certain column count.
        
        This can be used in e.g. a resizable scroll area.
        
        """
        first, last = self._range
        rows = ((last - first) // count) + 1
        return QSize(count, rows) * self._square

    def columnCountForWidth(self, width):
        """Returns the number of columns that would fit into the given width."""
        return width // self._square

    def mousePressEvent(self, ev):
        charcode = self.charcodeAt(ev.pos())
        if charcode != -1 and self.isprint(charcode):
            self.select(charcode)
            if ev.button() != Qt.RightButton:
                self.characterClicked.emit(chr(charcode))

    def charcodeRect(self, charcode):
        """Returns the rectangular box around the given charcode, if any."""
        if self._range[0] <= charcode <= self._range[1]:
            row, col = divmod(charcode - self._range[0], self._column_count)
            s = self._square
            return QRect(col * s, row * s, s, s)

    def charcodeAt(self, position):
        row = position.y() // self._square
        col = position.x() // self._square
        if col <= self._column_count:
            charcode = self._range[0] + row * self._column_count + col
            if charcode <= self._range[1]:
                return charcode
        return -1

    def event(self, ev):
        if ev.type() == QEvent.ToolTip:
            if self._showToolTips:
                c = self.charcodeAt(ev.pos())
                if c:
                    text = self.getToolTipText(c)
                    if text:
                        rect = self.charcodeRect(c)
                        QToolTip.showText(ev.globalPos(), text, self, rect)
                        ev.accept()
                        return True
        elif ev.type() == QEvent.QueryWhatsThis:
            if self._showWhatsThis:
                ev.accept()
                return True
        elif ev.type() == QEvent.WhatsThis:
            ev.accept()
            if self._showWhatsThis:
                c = self.charcodeAt(ev.pos())
                text = self.getWhatsThisText(c) if c else None
                if text:
                    QWhatsThis.showText(ev.globalPos(), text, self)
                else:
                    QWhatsThis.leaveWhatsThisMode()
            return True
        return super(CharMap, self).event(ev)

    def getToolTipText(self, charcode):
        try:
            return unicodedata.name(chr(charcode))
        except ValueError:
            pass

    def getWhatsThisText(self, charcode):
        try:
            name = unicodedata.name(chr(charcode))
        except ValueError:
            return
        return whatsthis_html.format(self._font.family(), chr(charcode), name,
                                     charcode)

    def setShowToolTips(self, enabled):
        self._showToolTips = bool(enabled)

    def showToolTips(self):
        return self._showToolTips

    def setShowWhatsThis(self, enabled):
        self._showWhatsThis = bool(enabled)

    def showWhatsThis(self):
        return self._showWhatsThis

    def isprint(self, charcode):
        """Returns True if the given charcode is printable."""
        return isprint(charcode)
Exemple #10
0
class TextEditBaseWidget(QPlainTextEdit, BaseEditMixin):
    """Text edit base widget"""
    BRACE_MATCHING_SCOPE = ('sof', 'eof')
    CELL_SEPARATORS = ('#%%', '# %%', '# <codecell>')

    def __init__(self, parent=None):
        QPlainTextEdit.__init__(self, parent)
        BaseEditMixin.__init__(self)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.extra_selections_dict = {}

        self.connect(self, SIGNAL('textChanged()'), self.changed)
        self.connect(self, SIGNAL('cursorPositionChanged()'),
                     self.cursor_position_changed)

        self.indent_chars = " " * 4

        # Code completion / calltips
        if parent is not None:
            mainwin = parent
            while not isinstance(mainwin, QMainWindow):
                mainwin = mainwin.parent()
                if mainwin is None:
                    break
            if mainwin is not None:
                parent = mainwin
        self.completion_widget = CompletionWidget(self, parent)
        self.codecompletion_auto = False
        self.codecompletion_case = True
        self.codecompletion_single = False
        self.codecompletion_enter = False
        self.calltips = True
        self.calltip_position = None
        self.calltip_size = 600
        self.calltip_font = QFont()
        self.completion_text = ""

        # Highlight current line color
        self.currentline_color = QColor(Qt.red).lighter(190)

        # Brace matching
        self.bracepos = None
        self.matched_p_color = QColor(Qt.green)
        self.unmatched_p_color = QColor(Qt.red)

    def setup_calltips(self, size=None, font=None):
        self.calltip_size = size
        self.calltip_font = font

    def setup_completion(self, size=None, font=None):
        self.completion_widget.setup_appearance(size, font)

    def set_indent_chars(self, indent_chars):
        self.indent_chars = indent_chars

    def set_palette(self, background, foreground):
        """
        Set text editor palette colors:
        background color and caret (text cursor) color
        """
        palette = QPalette()
        palette.setColor(QPalette.Base, background)
        palette.setColor(QPalette.Text, foreground)
        self.setPalette(palette)

    #------Line number area
    def get_linenumberarea_width(self):
        """Return line number area width"""
        # Implemented in CodeEditor, but needed here for completion widget
        return 0

    #------Extra selections
    def get_extra_selections(self, key):
        return self.extra_selections_dict.get(key, [])

    def set_extra_selections(self, key, extra_selections):
        self.extra_selections_dict[key] = extra_selections

    def update_extra_selections(self):
        extra_selections = []
        for key, extra in list(self.extra_selections_dict.items()):
            if key == 'current_line':
                # Python 3 compatibility (weird): current line has to be
                # highlighted first
                extra_selections = extra + extra_selections
            else:
                extra_selections += extra
        self.setExtraSelections(extra_selections)

    def clear_extra_selections(self, key):
        self.extra_selections_dict[key] = []
        self.update_extra_selections()

    def changed(self):
        """Emit changed signal"""
        self.emit(SIGNAL('modificationChanged(bool)'),
                  self.document().isModified())

    #------Highlight current line
    def highlight_current_line(self):
        """Highlight current line"""
        selection = QTextEdit.ExtraSelection()
        #        selection.format.setProperty(QTextFormat.FullWidthSelection,
        #                                     QVariant(True))
        selection.format.setBackground(self.currentline_color)
        selection.cursor = self.textCursor()
        selection.cursor.clearSelection()
        self.set_extra_selections('current_line', [selection])
        self.update_extra_selections()

    def unhighlight_current_line(self):
        """Unhighlight current line"""
        self.clear_extra_selections('current_line')

    #------Brace matching
    def find_brace_match(self, position, brace, forward):
        start_pos, end_pos = self.BRACE_MATCHING_SCOPE
        if forward:
            bracemap = {'(': ')', '[': ']', '{': '}'}
            text = self.get_text(position, end_pos)
            i_start_open = 1
            i_start_close = 1
        else:
            bracemap = {')': '(', ']': '[', '}': '{'}
            text = self.get_text(start_pos, position)
            i_start_open = len(text) - 1
            i_start_close = len(text) - 1

        while True:
            if forward:
                i_close = text.find(bracemap[brace], i_start_close)
            else:
                i_close = text.rfind(bracemap[brace], 0, i_start_close + 1)
            if i_close > -1:
                if forward:
                    i_start_close = i_close + 1
                    i_open = text.find(brace, i_start_open, i_close)
                else:
                    i_start_close = i_close - 1
                    i_open = text.rfind(brace, i_close, i_start_open + 1)
                if i_open > -1:
                    if forward:
                        i_start_open = i_open + 1
                    else:
                        i_start_open = i_open - 1
                else:
                    # found matching brace
                    if forward:
                        return position + i_close
                    else:
                        return position - (len(text) - i_close)
            else:
                # no matching brace
                return

    def __highlight(self, positions, color=None, cancel=False):
        if cancel:
            self.clear_extra_selections('brace_matching')
            return
        extra_selections = []
        for position in positions:
            if position > self.get_position('eof'):
                return
            selection = QTextEdit.ExtraSelection()
            selection.format.setBackground(color)
            selection.cursor = self.textCursor()
            selection.cursor.clearSelection()
            selection.cursor.setPosition(position)
            selection.cursor.movePosition(QTextCursor.NextCharacter,
                                          QTextCursor.KeepAnchor)
            extra_selections.append(selection)
        self.set_extra_selections('brace_matching', extra_selections)
        self.update_extra_selections()

    def cursor_position_changed(self):
        """Brace matching"""
        if self.bracepos is not None:
            self.__highlight(self.bracepos, cancel=True)
            self.bracepos = None
        cursor = self.textCursor()
        if cursor.position() == 0:
            return
        cursor.movePosition(QTextCursor.PreviousCharacter,
                            QTextCursor.KeepAnchor)
        text = to_text_string(cursor.selectedText())
        pos1 = cursor.position()
        if text in (')', ']', '}'):
            pos2 = self.find_brace_match(pos1, text, forward=False)
        elif text in ('(', '[', '{'):
            pos2 = self.find_brace_match(pos1, text, forward=True)
        else:
            return
        if pos2 is not None:
            self.bracepos = (pos1, pos2)
            self.__highlight(self.bracepos, color=self.matched_p_color)
        else:
            self.bracepos = (pos1, )
            self.__highlight(self.bracepos, color=self.unmatched_p_color)

    #-----Widget setup and options
    def set_codecompletion_auto(self, state):
        """Set code completion state"""
        self.codecompletion_auto = state

    def set_codecompletion_case(self, state):
        """Case sensitive completion"""
        self.codecompletion_case = state
        self.completion_widget.case_sensitive = state

    def set_codecompletion_single(self, state):
        """Show single completion"""
        self.codecompletion_single = state
        self.completion_widget.show_single = state

    def set_codecompletion_enter(self, state):
        """Enable Enter key to select completion"""
        self.codecompletion_enter = state
        self.completion_widget.enter_select = state

    def set_calltips(self, state):
        """Set calltips state"""
        self.calltips = state

    def set_wrap_mode(self, mode=None):
        """
        Set wrap mode
        Valid *mode* values: None, 'word', 'character'
        """
        if mode == 'word':
            wrap_mode = QTextOption.WrapAtWordBoundaryOrAnywhere
        elif mode == 'character':
            wrap_mode = QTextOption.WrapAnywhere
        else:
            wrap_mode = QTextOption.NoWrap
        self.setWordWrapMode(wrap_mode)

    #------Reimplementing Qt methods
    def copy(self):
        """
        Reimplement Qt method
        Copy text to clipboard with correct EOL chars
        """
        QApplication.clipboard().setText(self.get_selected_text())

    #------Text: get, set, ...
    def get_selection_as_executable_code(self):
        """Return selected text as a processed text,
        to be executable in a Python/IPython interpreter"""
        ls = self.get_line_separator()

        _indent = lambda line: len(line) - len(line.lstrip())

        line_from, line_to = self.get_selection_bounds()
        text = self.get_selected_text()
        if not text:
            return

        lines = text.split(ls)
        if len(lines) > 1:
            # Multiline selection -> eventually fixing indentation
            original_indent = _indent(self.get_text_line(line_from))
            text = (" " * (original_indent - _indent(lines[0]))) + text

        # If there is a common indent to all lines, find it.
        # Moving from bottom line to top line ensures that blank
        # lines inherit the indent of the line *below* it,
        # which is the desired behavior.
        min_indent = 999
        current_indent = 0
        lines = text.split(ls)
        for i in range(len(lines) - 1, -1, -1):
            line = lines[i]
            if line.strip():
                current_indent = _indent(line)
                min_indent = min(current_indent, min_indent)
            else:
                lines[i] = ' ' * current_indent
        if min_indent:
            lines = [line[min_indent:] for line in lines]

        # Remove any leading whitespace or comment lines
        # since they confuse the reserved word detector that follows below
        first_line = lines[0].lstrip()
        while first_line == '' or first_line[0] == '#':
            lines.pop(0)
            first_line = lines[0].lstrip()

        # Add an EOL character after indentation blocks that start with some
        # Python reserved words, so that it gets evaluated automatically
        # by the console
        varname = re.compile('[a-zA-Z0-9_]*')  # matches valid variable names
        maybe = False
        nextexcept = ()
        for n, line in enumerate(lines):
            if not _indent(line):
                word = varname.match(line).group()
                if maybe and word not in nextexcept:
                    lines[n - 1] += ls
                    maybe = False
                if word:
                    if word in ('def', 'for', 'while', 'with', 'class'):
                        maybe = True
                        nextexcept = ()
                    elif word == 'if':
                        maybe = True
                        nextexcept = ('elif', 'else')
                    elif word == 'try':
                        maybe = True
                        nextexcept = ('except', 'finally')
        if maybe:
            if lines[-1].strip() == '':
                lines[-1] += ls
            else:
                lines.append(ls)

        return ls.join(lines)

    def get_cell_as_executable_code(self):
        """Return cell contents as executable code"""
        start_pos, end_pos = self.__save_selection()
        self.select_current_cell()
        text = self.get_selection_as_executable_code()
        self.__restore_selection(start_pos, end_pos)
        return text

    def is_cell_separator(self, cursor=None, block=None):
        """Return True if cursor (or text block) is on a block separator"""
        assert cursor is not None or block is not None
        if cursor is not None:
            cursor0 = QTextCursor(cursor)
            cursor0.select(QTextCursor.BlockUnderCursor)
            text = to_text_string(cursor0.selectedText())
        else:
            text = to_text_string(block.text())
        return text.lstrip().startswith(self.CELL_SEPARATORS)

    def select_current_cell(self):
        """Select cell under cursor
        cell = group of lines separated by CELL_SEPARATORS"""
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.StartOfBlock)
        cur_pos = prev_pos = cursor.position()
        # Moving to the next line that is not a separator, if we are
        # exactly at one of them
        while self.is_cell_separator(cursor):
            cursor.movePosition(QTextCursor.NextBlock)
            prev_pos = cur_pos
            cur_pos = cursor.position()
            if cur_pos == prev_pos:
                return
        # If not, move backwards to find the previous separator
        while not self.is_cell_separator(cursor):
            cursor.movePosition(QTextCursor.PreviousBlock)
            prev_pos = cur_pos
            cur_pos = cursor.position()
            if cur_pos == prev_pos:
                if self.is_cell_separator(cursor):
                    return
                else:
                    break
        cursor.setPosition(prev_pos)
        cell_at_file_start = cursor.atStart()
        # Once we find it (or reach the beginning of the file)
        # move to the next separator (or the end of the file)
        # so we can grab the cell contents
        while not self.is_cell_separator(cursor):
            cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor)
            cur_pos = cursor.position()
            if cur_pos == prev_pos:
                cursor.movePosition(QTextCursor.EndOfBlock,
                                    QTextCursor.KeepAnchor)
                break
            prev_pos = cur_pos
        # Do nothing if we moved from beginning to end without
        # finding a separator
        if cell_at_file_start and cursor.atEnd():
            return
        self.setTextCursor(cursor)

    def go_to_next_cell(self):
        """Go to the next cell of lines"""
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.NextBlock)
        cur_pos = prev_pos = cursor.position()
        while not self.is_cell_separator(cursor):
            # Moving to the next code cell
            cursor.movePosition(QTextCursor.NextBlock)
            prev_pos = cur_pos
            cur_pos = cursor.position()
            if cur_pos == prev_pos:
                return
        self.setTextCursor(cursor)

    def get_line_count(self):
        """Return document total line number"""
        return self.blockCount()

    def __save_selection(self):
        """Save current cursor selection and return position bounds"""
        cursor = self.textCursor()
        return cursor.selectionStart(), cursor.selectionEnd()

    def __restore_selection(self, start_pos, end_pos):
        """Restore cursor selection from position bounds"""
        cursor = self.textCursor()
        cursor.setPosition(start_pos)
        cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
        self.setTextCursor(cursor)

    def __duplicate_line_or_selection(self, after_current_line=True):
        """Duplicate current line or selected text"""
        cursor = self.textCursor()
        cursor.beginEditBlock()
        start_pos, end_pos = self.__save_selection()
        if to_text_string(cursor.selectedText()):
            cursor.setPosition(end_pos)
            # Check if end_pos is at the start of a block: if so, starting
            # changes from the previous block
            cursor.movePosition(QTextCursor.StartOfBlock,
                                QTextCursor.KeepAnchor)
            if not to_text_string(cursor.selectedText()):
                cursor.movePosition(QTextCursor.PreviousBlock)
                end_pos = cursor.position()

        cursor.setPosition(start_pos)
        cursor.movePosition(QTextCursor.StartOfBlock)
        while cursor.position() <= end_pos:
            cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
            if cursor.atEnd():
                cursor_temp = QTextCursor(cursor)
                cursor_temp.clearSelection()
                cursor_temp.insertText(self.get_line_separator())
                break
            cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor)
        text = cursor.selectedText()
        cursor.clearSelection()

        if not after_current_line:
            # Moving cursor before current line/selected text
            cursor.setPosition(start_pos)
            cursor.movePosition(QTextCursor.StartOfBlock)
            start_pos += len(text)
            end_pos += len(text)

        cursor.insertText(text)
        cursor.endEditBlock()
        self.setTextCursor(cursor)
        self.__restore_selection(start_pos, end_pos)

    def duplicate_line(self):
        """
        Duplicate current line or selected text
        Paste the duplicated text *after* the current line/selected text
        """
        self.__duplicate_line_or_selection(after_current_line=True)

    def copy_line(self):
        """
        Copy current line or selected text
        Paste the duplicated text *before* the current line/selected text
        """
        self.__duplicate_line_or_selection(after_current_line=False)

    def __move_line_or_selection(self, after_current_line=True):
        """Move current line or selected text"""
        cursor = self.textCursor()
        cursor.beginEditBlock()
        start_pos, end_pos = self.__save_selection()
        if to_text_string(cursor.selectedText()):
            # Check if start_pos is at the start of a block
            cursor.setPosition(start_pos)
            cursor.movePosition(QTextCursor.StartOfBlock)
            start_pos = cursor.position()

            cursor.setPosition(end_pos)
            # Check if end_pos is at the start of a block: if so, starting
            # changes from the previous block
            cursor.movePosition(QTextCursor.StartOfBlock,
                                QTextCursor.KeepAnchor)
            if to_text_string(cursor.selectedText()):
                cursor.movePosition(QTextCursor.NextBlock)
                end_pos = cursor.position()
        else:
            cursor.movePosition(QTextCursor.StartOfBlock)
            start_pos = cursor.position()
            cursor.movePosition(QTextCursor.NextBlock)
            end_pos = cursor.position()
        cursor.setPosition(start_pos)
        cursor.setPosition(end_pos, QTextCursor.KeepAnchor)

        sel_text = to_text_string(cursor.selectedText())
        cursor.removeSelectedText()

        if after_current_line:
            text = to_text_string(cursor.block().text())
            start_pos += len(text) + 1
            end_pos += len(text) + 1
            cursor.movePosition(QTextCursor.NextBlock)
        else:
            cursor.movePosition(QTextCursor.PreviousBlock)
            text = to_text_string(cursor.block().text())
            start_pos -= len(text) + 1
            end_pos -= len(text) + 1
        cursor.insertText(sel_text)

        cursor.endEditBlock()
        self.setTextCursor(cursor)
        self.__restore_selection(start_pos, end_pos)

    def move_line_up(self):
        """Move up current line or selected text"""
        self.__move_line_or_selection(after_current_line=False)

    def move_line_down(self):
        """Move down current line or selected text"""
        self.__move_line_or_selection(after_current_line=True)

    def extend_selection_to_complete_lines(self):
        """Extend current selection to complete lines"""
        cursor = self.textCursor()
        start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
        cursor.setPosition(start_pos)
        cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
        if cursor.atBlockStart():
            cursor.movePosition(QTextCursor.PreviousBlock,
                                QTextCursor.KeepAnchor)
            cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
        self.setTextCursor(cursor)

    def delete_line(self):
        """Delete current line"""
        cursor = self.textCursor()
        if self.has_selected_text():
            self.extend_selection_to_complete_lines()
            start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
            cursor.setPosition(start_pos)
        else:
            start_pos = end_pos = cursor.position()
        cursor.beginEditBlock()
        cursor.setPosition(start_pos)
        cursor.movePosition(QTextCursor.StartOfBlock)
        while cursor.position() <= end_pos:
            cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
            if cursor.atEnd():
                break
            cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor)
        cursor.removeSelectedText()
        cursor.endEditBlock()
        self.ensureCursorVisible()

    #------Code completion / Calltips
    def show_calltip(self,
                     title,
                     text,
                     color='#2D62FF',
                     at_line=None,
                     at_position=None):
        """Show calltip"""
        if text is None or len(text) == 0:
            return
        # Saving cursor position:
        if at_position is None:
            at_position = self.get_position('cursor')
        self.calltip_position = at_position
        # Preparing text:
        weight = 'bold' if self.calltip_font.bold() else 'normal'
        size = self.calltip_font.pointSize()
        family = self.calltip_font.family()
        format1 = '<div style=\'font-size: %spt; color: %s\'>' % (size, color)
        format2 = '<hr><div style=\'font-family: "%s"; font-size: %spt; font-weight: %s\'>' % (
            family, size, weight)
        if isinstance(text, list):
            text = "\n    ".join(text)
        text = text.replace('\n', '<br>')
        if len(text) > self.calltip_size:
            text = text[:self.calltip_size] + " ..."
        tiptext = format1 + ('<b>%s</b></div>' % title) \
                  + format2 + text + "</div>"
        # Showing tooltip at cursor position:
        cx, cy = self.get_coordinates('cursor')
        if at_line is not None:
            cx = 5
            cursor = QTextCursor(self.document().findBlockByNumber(at_line -
                                                                   1))
            cy = self.cursorRect(cursor).top()
        point = self.mapToGlobal(QPoint(cx, cy))
        point.setX(point.x() + self.get_linenumberarea_width())
        QToolTip.showText(point, tiptext)

    def hide_tooltip_if_necessary(self, key):
        """Hide calltip when necessary"""
        try:
            calltip_char = self.get_character(self.calltip_position)
            before = self.is_cursor_before(self.calltip_position,
                                           char_offset=1)
            other = key in (Qt.Key_ParenRight, Qt.Key_Period, Qt.Key_Tab)
            if calltip_char not in ('?', '(') or before or other:
                QToolTip.hideText()
        except (IndexError, TypeError):
            QToolTip.hideText()

    def show_completion_widget(self, textlist, automatic=True):
        """Show completion widget"""
        self.completion_widget.show_list(textlist, automatic=automatic)

    def hide_completion_widget(self):
        """Hide completion widget"""
        self.completion_widget.hide()

    def show_completion_list(self,
                             completions,
                             completion_text="",
                             automatic=True):
        """Display the possible completions"""
        if len(completions) == 0 or completions == [completion_text]:
            return
        self.completion_text = completion_text
        # Sorting completion list (entries starting with underscore are
        # put at the end of the list):
        underscore = set(
            [comp for comp in completions if comp.startswith('_')])
        completions = sorted(set(completions)-underscore, key=str_lower)+\
                      sorted(underscore, key=str_lower)
        self.show_completion_widget(completions, automatic=automatic)

    def select_completion_list(self):
        """Completion list is active, Enter was just pressed"""
        self.completion_widget.item_selected()

    def insert_completion(self, text):
        if text:
            cursor = self.textCursor()
            cursor.movePosition(QTextCursor.PreviousCharacter,
                                QTextCursor.KeepAnchor,
                                len(self.completion_text))
            cursor.removeSelectedText()
            self.insert_text(text)

    def is_completion_widget_visible(self):
        """Return True is completion list widget is visible"""
        return self.completion_widget.isVisible()

    #------Standard keys
    def stdkey_clear(self):
        if not self.has_selected_text():
            self.moveCursor(QTextCursor.NextCharacter, QTextCursor.KeepAnchor)
        self.remove_selected_text()

    def stdkey_backspace(self):
        if not self.has_selected_text():
            self.moveCursor(QTextCursor.PreviousCharacter,
                            QTextCursor.KeepAnchor)
        self.remove_selected_text()

    def __get_move_mode(self, shift):
        return QTextCursor.KeepAnchor if shift else QTextCursor.MoveAnchor

    def stdkey_up(self, shift):
        self.moveCursor(QTextCursor.Up, self.__get_move_mode(shift))

    def stdkey_down(self, shift):
        self.moveCursor(QTextCursor.Down, self.__get_move_mode(shift))

    def stdkey_tab(self):
        self.insert_text(self.indent_chars)

    def stdkey_home(self, shift, ctrl, prompt_pos=None):
        """Smart HOME feature: cursor is first moved at 
        indentation position, then at the start of the line"""
        move_mode = self.__get_move_mode(shift)
        if ctrl:
            self.moveCursor(QTextCursor.Start, move_mode)
        else:
            cursor = self.textCursor()
            if prompt_pos is None:
                start_position = self.get_position('sol')
            else:
                start_position = self.get_position(prompt_pos)
            text = self.get_text(start_position, 'eol')
            indent_pos = start_position + len(text) - len(text.lstrip())
            if cursor.position() != indent_pos:
                cursor.setPosition(indent_pos, move_mode)
            else:
                cursor.setPosition(start_position, move_mode)
            self.setTextCursor(cursor)

    def stdkey_end(self, shift, ctrl):
        move_mode = self.__get_move_mode(shift)
        if ctrl:
            self.moveCursor(QTextCursor.End, move_mode)
        else:
            self.moveCursor(QTextCursor.EndOfBlock, move_mode)

    def stdkey_pageup(self):
        pass

    def stdkey_pagedown(self):
        pass

    def stdkey_escape(self):
        pass

    #----Qt Events
    def mousePressEvent(self, event):
        """Reimplement Qt method"""
        if os.name != 'posix' and event.button() == Qt.MidButton:
            self.setFocus()
            event = QMouseEvent(QEvent.MouseButtonPress, event.pos(),
                                Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
            QPlainTextEdit.mousePressEvent(self, event)
            QPlainTextEdit.mouseReleaseEvent(self, event)
            self.paste()
        else:
            QPlainTextEdit.mousePressEvent(self, event)

    def focusInEvent(self, event):
        """Reimplemented to handle focus"""
        self.emit(SIGNAL("focus_changed()"))
        self.emit(SIGNAL("focus_in()"))
        QPlainTextEdit.focusInEvent(self, event)

    def focusOutEvent(self, event):
        """Reimplemented to handle focus"""
        self.emit(SIGNAL("focus_changed()"))
        QPlainTextEdit.focusOutEvent(self, event)

    def wheelEvent(self, event):
        """Reimplemented to emit zoom in/out signals when Ctrl is pressed"""
        # This feature is disabled on MacOS, see Issue 1510:
        # http://code.google.com/p/spyderlib/issues/detail?id=1510
        if sys.platform != 'darwin':
            if event.modifiers() & Qt.ControlModifier:
                if event.delta() < 0:
                    self.emit(SIGNAL("zoom_out()"))
                elif event.delta() > 0:
                    self.emit(SIGNAL("zoom_in()"))
                return
        QPlainTextEdit.wheelEvent(self, event)
Exemple #11
0
class ConfigDialog(QDialog):
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self._layout = QVBoxLayout(self)
        self._tabdialog = QTabWidget(self)
        self._layout.addWidget(self._tabdialog)
        w = _config_dialog.Ui_config_dialog()
        w.setupUi(self._tabdialog)
        self.widgets = w
        
        self._buttonbox = QDialogButtonBox(QDialogButtonBox.Save|QDialogButtonBox.Cancel)
        self._buttonbox.setParent(self)
        signal_connect(self._buttonbox, SIGNAL("accepted()"), self.accept)
        signal_connect(self._buttonbox, SIGNAL("rejected()"), self.reject)
        self._layout.addWidget(self._buttonbox)
        
        self._layout.setContentsMargins(3,3,3,3)
        
        self.font = QFont()
        self.color = QColor()
        
        self.config = yobot_interfaces.component_registry.get_component("client-config")
        
        self.account_items = {}
        
        signal_connect(w.account_add, SIGNAL("clicked()"), lambda: self.add_modify_account(add=True))
        signal_connect(w.account_edit, SIGNAL("clicked()"), lambda: self.add_modify_account(add=False))
        signal_connect(w.account_del, SIGNAL("clicked()"), self.remove_account)
        
        signal_connect(w.select_color, SIGNAL("clicked()"), lambda: self.change_formatting(color=True))
        signal_connect(w.select_font, SIGNAL("clicked()"), lambda: self.change_formatting(font=True))
        
        signal_connect(w.agent_address, SIGNAL("editingFinished()"), self.change_agent)
        self.connect_global_bool(w.html_relsize, "appearance", "use_html_relsize")
        self.connect_global_bool(w.show_joinpart, "appearance", "show_joinpart")
        self.input_validated = True
        
        self.setWindowTitle("Yobot Configuration")
        
    def connect_global_bool(self, widget, dictname, optname, default=False):
        signal_connect(widget, SIGNAL("toggled(bool)"),
                       lambda b: self.config.globals.setdefault(dictname, {}).__setitem__(optname, b))
        
    def load_settings(self):
        w = self.widgets
        if not self.config:
            log_warn("config object not available! bailing")
            return
        #for font..
        appearance = self.config.globals.setdefault("appearance", {})
        family = appearance.get("font_family", None)
        size = appearance.get("font_size", None)
        color = appearance.get("font_color", None)
        
        if family: self.font.setFamily(family)
        if size: self.font.setPointSize(size)
        if color: self.color.setNamedColor(color)
        
        bold = appearance.get("font_bold", False)
        italic = appearance.get("font_italic", False)
        underline = appearance.get("font_underline", False)
        html_relsize = appearance.get("use_html_relsize", False)
        show_joinpart = appearance.get("show_joinpart", False)
        
        self.font.setBold(bold)
        self.font.setItalic(italic)
        self.font.setUnderline(underline)
        w.html_relsize.setChecked(html_relsize)
        w.show_joinpart.setChecked(show_joinpart)
        
        self.change_formatting()
        
        #for the agent...
        agent = self.config.globals.get("agent_address", None)
        if agent: w.agent_address.setText(agent)
        self.change_agent()
        #for accounts:
        for a in self.config.accounts:
            log_warn("got account", a)
            if a.get("name", None) and a.get("improto", None):
                #get name and icon
                name, icon = getProtoIconAndName(getattr(yobotproto, a["improto"], ""))
                log_debug(icon, name)
                i = QTreeWidgetItem((a["name"], name))
                i.setIcon(1, icon)
                i.setData(0, ITEM_PLACEHOLDER_ROLE, a)
                self.account_items[i] = a
                self.widgets.accounts.addTopLevelItem(i)
                
    
    def remove_account(self):
        #get current item:
        w = self.widgets
        item = w.accounts.currentItem()
        
        #get the index (ugh.. this is tedious)
        itemindex = w.accounts.indexOfTopLevelItem(item)
        if itemindex == -1:
            log_err("couldn't get index!")
            return
        
        account = self.account_items[item]
        #remove the item from the widget:
        w.accounts.takeTopLevelItem(itemindex)
        
        #find the account in our global config list
        index = -1
        for i in xrange(0, len(self.config.accounts)):
            a = self.config.accounts[i]
            if str(a["name"]) == str(account["name"]) and str(a["improto"]) == str(account["improto"]):
                index = i
                break
            else:
                pass
        if index >= 0:
            log_debug("index:", index)
            self.config.accounts.pop(index)
        #finally, remove it from the mapping
        self.account_items.pop(item)
    
    def add_modify_account(self, add=False):
        dlg = AccountSettingsDialog(self)
        if not add:
            item = self.widgets.accounts.currentItem()
            if not item:
                return
            account = self.account_items.get(item)
            if not account:
                return
            #account = item.data(0, ITEM_PLACEHOLDER_ROLE).toPyObject()
            dlg.fill_from(account)
        else:
            item = QTreeWidgetItem()
        result = dlg.exec_()
        
        if not result == QDialog.Accepted:
            return
        new_a = dlg.values
        
        item.setText(0, new_a["name"])
        #get icon and name...
        name, icon = getProtoIconAndName(getattr(yobotproto, new_a["improto"], -1))
        item.setText(1, name)
        item.setIcon(1, icon)
        if add:
            if self.account_exists(new_a):
                print "account already exists.. not adding"
                return
            item.setData(0, ITEM_PLACEHOLDER_ROLE, new_a)
            self.widgets.accounts.addTopLevelItem(item)
            self.config.accounts.append(new_a)
        else:
            account.update(new_a)
            
    def account_exists(self, d):
        for a in self.config.accounts:
            if d["name"] == a["name"] and d["improto"] == a["improto"]:
                return True
        return False
    
    def change_formatting(self, color=False, font=False):
        if color:
            _color = QColorDialog.getColor(self.color, self, "Select Color")
            if _color.isValid():
                self.color = _color
        elif font:
            self.font, _ = QFontDialog.getFont(self.font, self, "Select Font")
            
        widgetformatter(self.widgets.sample_text, self.font, self.color,
                        klass="QPlainTextEdit")
        
        #now, change the config objects..
        fmt = self.config.globals["appearance"]
        fmt.update({
            "font_family":str(self.font.family()),
            "font_size":int(self.font.pointSize()),
            "font_color":str(self.color.name()),
            "font_bold":bool(self.font.bold()),
            "font_italic":bool(self.font.italic()),
            "font_underline":bool(self.font.underline())
        })
    
    def change_agent(self):
        #bah.. the same boring thing as always
        s = str(self.widgets.agent_address.text())
        if len(s.rsplit(":", 1)) == 2 and not str.isdigit(s.rsplit(":",1)[1]):
            self.input_validated = False
            self.widgets.agent_address.setStyleSheet("background-color:red;")
        else:
            self.widgets.agent_address.setStyleSheet("background-color:green")
            if s:
                self.config.globals["agent_address"] = str(s)
            self.input_validated = True
            
            
    
    def accept(self):
        #do some stuff first, like save
        if self.input_validated:
            self.config.save()
            QDialog.accept(self)
        else:
            QErrorMessage(self).showMessage("Bad input.. (somewhere?)")
Exemple #12
0
def read_settings_API_3(stream, settings):
    """ Write all settings such as fonts for labels and legend.
    
    NOTE: This function doesn't return anything and changes
    the settings directly."""

    labelFont = QFont()
    legendFont = QFont()

    stream >> labelFont

    labelInterval = stream.readInt32()
    labelState = get_row_label_identifier(labelInterval)

    stream >> legendFont
    gridCellWidth = stream.readInt32()
    gridCellHeight = stream.readInt32()

    # make sure we parsed something sensible before
    # touching the settings
    if labelFont.family():
        settings.labelFont.value = labelFont

    if labelState:
        settings.rowLabelMode.value = labelState

    if legendFont.family():
        settings.legendFont.value = legendFont

    if gridCellWidth != 0:
        settings.gridCellWidth.value = gridCellWidth

    if gridCellHeight != 0:
        settings.gridCellHeight.value = gridCellHeight

    # new stuff in API_VERSION 2 and onward
    labelStart = stream.readInt32()
    settings.rowLabelStart.value = labelStart

    evenRowLabelLocation = stream.readInt32()
    settings.evenRowLabelLocation.value = \
            get_row_label_location_string(evenRowLabelLocation)

    highlightRows = stream.readInt32()
    settings.highlightRows.value = highlightRows

    highlightRowsOpacity = stream.readInt32()
    settings.highlightRowsOpacity.value = highlightRowsOpacity

    highlightRowsStart = stream.readInt32()
    settings.highlightRowsStart.value = highlightRowsStart

    highlightRowsColor = stream.readQString()
    if highlightRowsColor:
        settings.highlightRowsColor.value = highlightRowsColor

    # write rest of row/column settings
    # NOTE: The row settings aren't combined with the rest to
    # remain backward compatible.
    oddRowLabelLocation = stream.readInt32()
    settings.oddRowLabelLocation.value = \
            get_row_label_location_string(oddRowLabelLocation)

    rowLabelsShowInterval = stream.readInt32()
    settings.rowLabelsShowInterval.value = rowLabelsShowInterval

    rowLabelsShowIntervalStart = stream.readInt32()
    settings.rowLabelsShowIntervalStart.value = \
            rowLabelsShowIntervalStart

    columnLabelMode = stream.readInt32()
    settings.columnLabelMode.value = \
            get_column_label_identifier(columnLabelMode)

    columnLabelsShowInterval = stream.readInt32()
    settings.columnLabelsShowInterval.value = \
            columnLabelsShowInterval

    columnLabelsShowIntervalStart = stream.readInt32()
    settings.columnLabelsShowIntervalStart.value = \
            columnLabelsShowIntervalStart

    rowLabelsEditable = stream.readInt32()
    settings.rowLabelsEditable.value = rowLabelsEditable

    columnLabelsEditable = stream.readInt32()
    settings.columnLabelsEditable.value = columnLabelsEditable
Exemple #13
0
class TextEditBaseWidget(QPlainTextEdit, BaseEditMixin):
    """Text edit base widget"""
    BRACE_MATCHING_SCOPE = ('sof', 'eof')
    CELL_SEPARATORS = ('#%%', '# %%', '# <codecell>')
    
    def __init__(self, parent=None):
        QPlainTextEdit.__init__(self, parent)
        BaseEditMixin.__init__(self)
        self.setAttribute(Qt.WA_DeleteOnClose)
        
        self.extra_selections_dict = {}
        
        self.connect(self, SIGNAL('textChanged()'), self.changed)
        self.connect(self, SIGNAL('cursorPositionChanged()'),
                     self.cursor_position_changed)
        
        self.indent_chars = " "*4
        
        # Code completion / calltips
        if parent is not None:
            mainwin = parent
            while not isinstance(mainwin, QMainWindow):
                mainwin = mainwin.parent()
                if mainwin is None:
                    break
            if mainwin is not None:
                parent = mainwin
        self.completion_widget = CompletionWidget(self, parent)
        self.codecompletion_auto = False
        self.codecompletion_case = True
        self.codecompletion_single = False
        self.codecompletion_enter = False
        self.calltips = True
        self.calltip_position = None
        self.calltip_size = 600
        self.calltip_font = QFont()
        self.completion_text = ""
        
        # Highlight current line color
        self.currentline_color = QColor(Qt.red).lighter(190)

        # Brace matching
        self.bracepos = None
        self.matched_p_color = QColor(Qt.green)
        self.unmatched_p_color = QColor(Qt.red)
        
    def setup_calltips(self, size=None, font=None):
        self.calltip_size = size
        self.calltip_font = font
    
    def setup_completion(self, size=None, font=None):
        self.completion_widget.setup_appearance(size, font)
        
    def set_indent_chars(self, indent_chars):
        self.indent_chars = indent_chars
        
    def set_palette(self, background, foreground):
        """
        Set text editor palette colors:
        background color and caret (text cursor) color
        """
        palette = QPalette()
        palette.setColor(QPalette.Base, background)
        palette.setColor(QPalette.Text, foreground)
        self.setPalette(palette)


    #------Line number area
    def get_linenumberarea_width(self):
        """Return line number area width"""
        # Implemented in CodeEditor, but needed here for completion widget
        return 0


    #------Extra selections
    def get_extra_selections(self, key):
        return self.extra_selections_dict.get(key, [])

    def set_extra_selections(self, key, extra_selections):
        self.extra_selections_dict[key] = extra_selections
        
    def update_extra_selections(self):
        extra_selections = []
        for key, extra in list(self.extra_selections_dict.items()):
            if key == 'current_line':
                # Python 3 compatibility (weird): current line has to be 
                # highlighted first
                extra_selections = extra + extra_selections
            else:
                extra_selections += extra
        self.setExtraSelections(extra_selections)
        
    def clear_extra_selections(self, key):
        self.extra_selections_dict[key] = []
        self.update_extra_selections()
        
        
    def changed(self):
        """Emit changed signal"""
        self.emit(SIGNAL('modificationChanged(bool)'),
                  self.document().isModified())


    #------Highlight current line
    def highlight_current_line(self):
        """Highlight current line"""
        selection = QTextEdit.ExtraSelection()
#        selection.format.setProperty(QTextFormat.FullWidthSelection,
#                                     QVariant(True))
        selection.format.setBackground(self.currentline_color)
        selection.cursor = self.textCursor()
        selection.cursor.clearSelection()
        self.set_extra_selections('current_line', [selection])
        self.update_extra_selections()

    def unhighlight_current_line(self):
        """Unhighlight current line"""
        self.clear_extra_selections('current_line')


    #------Brace matching
    def find_brace_match(self, position, brace, forward):
        start_pos, end_pos = self.BRACE_MATCHING_SCOPE
        if forward:
            bracemap = {'(': ')', '[': ']', '{': '}'}
            text = self.get_text(position, end_pos)
            i_start_open = 1
            i_start_close = 1
        else:
            bracemap = {')': '(', ']': '[', '}': '{'}
            text = self.get_text(start_pos, position)
            i_start_open = len(text)-1
            i_start_close = len(text)-1

        while True:
            if forward:
                i_close = text.find(bracemap[brace], i_start_close)
            else:
                i_close = text.rfind(bracemap[brace], 0, i_start_close+1)
            if i_close > -1:
                if forward:
                    i_start_close = i_close+1
                    i_open = text.find(brace, i_start_open, i_close)
                else:
                    i_start_close = i_close-1
                    i_open = text.rfind(brace, i_close, i_start_open+1)
                if i_open > -1:
                    if forward:
                        i_start_open = i_open+1
                    else:
                        i_start_open = i_open-1
                else:
                    # found matching brace
                    if forward:
                        return position+i_close
                    else:
                        return position-(len(text)-i_close)
            else:
                # no matching brace
                return
    
    def __highlight(self, positions, color=None, cancel=False):
        if cancel:
            self.clear_extra_selections('brace_matching')
            return
        extra_selections = []
        for position in positions:
            if position > self.get_position('eof'):
                return
            selection = QTextEdit.ExtraSelection()
            selection.format.setBackground(color)
            selection.cursor = self.textCursor()
            selection.cursor.clearSelection()
            selection.cursor.setPosition(position)
            selection.cursor.movePosition(QTextCursor.NextCharacter,
                                          QTextCursor.KeepAnchor)
            extra_selections.append(selection)
        self.set_extra_selections('brace_matching', extra_selections)
        self.update_extra_selections()

    def cursor_position_changed(self):
        """Brace matching"""
        if self.bracepos is not None:
            self.__highlight(self.bracepos, cancel=True)
            self.bracepos = None
        cursor = self.textCursor()
        if cursor.position() == 0:
            return
        cursor.movePosition(QTextCursor.PreviousCharacter,
                            QTextCursor.KeepAnchor)
        text = to_text_string(cursor.selectedText())
        pos1 = cursor.position()
        if text in (')', ']', '}'):
            pos2 = self.find_brace_match(pos1, text, forward=False)
        elif text in ('(', '[', '{'):
            pos2 = self.find_brace_match(pos1, text, forward=True)
        else:
            return
        if pos2 is not None:
            self.bracepos = (pos1, pos2)
            self.__highlight(self.bracepos, color=self.matched_p_color)
        else:
            self.bracepos = (pos1,)
            self.__highlight(self.bracepos, color=self.unmatched_p_color)


    #-----Widget setup and options
    def set_codecompletion_auto(self, state):
        """Set code completion state"""
        self.codecompletion_auto = state
        
    def set_codecompletion_case(self, state):
        """Case sensitive completion"""
        self.codecompletion_case = state
        self.completion_widget.case_sensitive = state
        
    def set_codecompletion_single(self, state):
        """Show single completion"""
        self.codecompletion_single = state
        self.completion_widget.show_single = state
        
    def set_codecompletion_enter(self, state):
        """Enable Enter key to select completion"""
        self.codecompletion_enter = state
        self.completion_widget.enter_select = state
        
    def set_calltips(self, state):
        """Set calltips state"""
        self.calltips = state

    def set_wrap_mode(self, mode=None):
        """
        Set wrap mode
        Valid *mode* values: None, 'word', 'character'
        """
        if mode == 'word':
            wrap_mode = QTextOption.WrapAtWordBoundaryOrAnywhere
        elif mode == 'character':
            wrap_mode = QTextOption.WrapAnywhere
        else:
            wrap_mode = QTextOption.NoWrap
        self.setWordWrapMode(wrap_mode)
        
        
    #------Reimplementing Qt methods
    def copy(self):
        """
        Reimplement Qt method
        Copy text to clipboard with correct EOL chars
        """
        QApplication.clipboard().setText(self.get_selected_text())
        

    #------Text: get, set, ...
    def get_selection_as_executable_code(self):
        """Return selected text as a processed text,
        to be executable in a Python/IPython interpreter"""
        ls = self.get_line_separator()
        
        _indent = lambda line: len(line)-len(line.lstrip())
        
        line_from, line_to = self.get_selection_bounds()
        text = self.get_selected_text()
        if not text:
            return

        lines = text.split(ls)
        if len(lines) > 1:
            # Multiline selection -> eventually fixing indentation
            original_indent = _indent(self.get_text_line(line_from))
            text = (" "*(original_indent-_indent(lines[0])))+text
            
        # If there is a common indent to all lines, find it.
        # Moving from bottom line to top line ensures that blank
        # lines inherit the indent of the line *below* it,
        # which is the desired behavior.
        min_indent = 999
        current_indent = 0
        lines = text.split(ls)
        for i in range(len(lines)-1, -1, -1):
            line = lines[i]
            if line.strip():
                current_indent = _indent(line)
                min_indent = min(current_indent, min_indent)
            else:
                lines[i] = ' ' * current_indent
        if min_indent:
            lines = [line[min_indent:] for line in lines]

        # Remove any leading whitespace or comment lines
        # since they confuse the reserved word detector that follows below
        first_line = lines[0].lstrip()
        while first_line == '' or first_line[0] == '#':
            lines.pop(0)
            first_line = lines[0].lstrip()
        
        # Add an EOL character after indentation blocks that start with some 
        # Python reserved words, so that it gets evaluated automatically
        # by the console
        varname = re.compile('[a-zA-Z0-9_]*') # matches valid variable names
        maybe = False
        nextexcept = ()
        for n, line in enumerate(lines):
            if not _indent(line):
                word = varname.match(line).group()
                if maybe and word not in nextexcept:
                    lines[n-1] += ls
                    maybe = False
                if word:
                    if word in ('def', 'for', 'while', 'with', 'class'):
                        maybe = True
                        nextexcept = ()
                    elif word == 'if':
                        maybe = True
                        nextexcept = ('elif', 'else')
                    elif word == 'try':
                        maybe = True
                        nextexcept = ('except', 'finally')
        if maybe:
            if lines[-1].strip() == '':
                lines[-1] += ls
            else:
                lines.append(ls)
        
        return ls.join(lines)

    def get_cell_as_executable_code(self):
        """Return cell contents as executable code"""
        start_pos, end_pos = self.__save_selection()
        self.select_current_cell()
        text = self.get_selection_as_executable_code()
        self.__restore_selection(start_pos, end_pos)
        return text

    def is_cell_separator(self, cursor=None, block=None):
        """Return True if cursor (or text block) is on a block separator"""
        assert cursor is not None or block is not None
        if cursor is not None:
            cursor0 = QTextCursor(cursor)
            cursor0.select(QTextCursor.BlockUnderCursor)
            text = to_text_string(cursor0.selectedText())
        else:
            text = to_text_string(block.text())
        return text.lstrip().startswith(self.CELL_SEPARATORS)

    def select_current_cell(self):
        """Select cell under cursor
        cell = group of lines separated by CELL_SEPARATORS"""
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.StartOfBlock)
        cur_pos = prev_pos = cursor.position()
        # Moving to the next line that is not a separator, if we are
        # exactly at one of them
        while self.is_cell_separator(cursor):
            cursor.movePosition(QTextCursor.NextBlock)
            prev_pos = cur_pos
            cur_pos = cursor.position()
            if cur_pos == prev_pos:
                return
        # If not, move backwards to find the previous separator
        while not self.is_cell_separator(cursor):
            cursor.movePosition(QTextCursor.PreviousBlock)
            prev_pos = cur_pos
            cur_pos = cursor.position()
            if cur_pos == prev_pos:
                if self.is_cell_separator(cursor):
                    return
                else:
                    break
        cursor.setPosition(prev_pos)
        cell_at_file_start = cursor.atStart()
        # Once we find it (or reach the beginning of the file)
        # move to the next separator (or the end of the file)
        # so we can grab the cell contents
        while not self.is_cell_separator(cursor):
            cursor.movePosition(QTextCursor.NextBlock,
                                QTextCursor.KeepAnchor)
            cur_pos = cursor.position()
            if cur_pos == prev_pos:
                cursor.movePosition(QTextCursor.EndOfBlock,
                                    QTextCursor.KeepAnchor)
                break
            prev_pos = cur_pos
        # Do nothing if we moved from beginning to end without
        # finding a separator
        if cell_at_file_start and cursor.atEnd():
            return
        self.setTextCursor(cursor)

    def go_to_next_cell(self):
        """Go to the next cell of lines"""
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.NextBlock)
        cur_pos = prev_pos = cursor.position()
        while not self.is_cell_separator(cursor):
            # Moving to the next code cell
            cursor.movePosition(QTextCursor.NextBlock)
            prev_pos = cur_pos
            cur_pos = cursor.position()
            if cur_pos == prev_pos:
                return
        self.setTextCursor(cursor)

    def get_line_count(self):
        """Return document total line number"""
        return self.blockCount()

    def __save_selection(self):
        """Save current cursor selection and return position bounds"""
        cursor = self.textCursor()
        return cursor.selectionStart(), cursor.selectionEnd()

    def __restore_selection(self, start_pos, end_pos):
        """Restore cursor selection from position bounds"""
        cursor = self.textCursor()
        cursor.setPosition(start_pos)
        cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
        self.setTextCursor(cursor)

    def __duplicate_line_or_selection(self, after_current_line=True):
        """Duplicate current line or selected text"""
        cursor = self.textCursor()
        cursor.beginEditBlock()
        start_pos, end_pos = self.__save_selection()
        if to_text_string(cursor.selectedText()):
            cursor.setPosition(end_pos)
            # Check if end_pos is at the start of a block: if so, starting
            # changes from the previous block
            cursor.movePosition(QTextCursor.StartOfBlock,
                                QTextCursor.KeepAnchor)
            if not to_text_string(cursor.selectedText()):
                cursor.movePosition(QTextCursor.PreviousBlock)
                end_pos = cursor.position()
            
        cursor.setPosition(start_pos)
        cursor.movePosition(QTextCursor.StartOfBlock)
        while cursor.position() <= end_pos:
            cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
            if cursor.atEnd():
                cursor_temp = QTextCursor(cursor)
                cursor_temp.clearSelection()
                cursor_temp.insertText(self.get_line_separator())
                break
            cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor)            
        text = cursor.selectedText()
        cursor.clearSelection()
        
        if not after_current_line:
            # Moving cursor before current line/selected text
            cursor.setPosition(start_pos)
            cursor.movePosition(QTextCursor.StartOfBlock)
            start_pos += len(text)
            end_pos += len(text)
        
        cursor.insertText(text)
        cursor.endEditBlock()
        self.setTextCursor(cursor)
        self.__restore_selection(start_pos, end_pos)
    
    def duplicate_line(self):
        """
        Duplicate current line or selected text
        Paste the duplicated text *after* the current line/selected text
        """
        self.__duplicate_line_or_selection(after_current_line=True)
    
    def copy_line(self):
        """
        Copy current line or selected text
        Paste the duplicated text *before* the current line/selected text
        """
        self.__duplicate_line_or_selection(after_current_line=False)
        
    def __move_line_or_selection(self, after_current_line=True):
        """Move current line or selected text"""
        cursor = self.textCursor()
        cursor.beginEditBlock()
        start_pos, end_pos = self.__save_selection()
        if to_text_string(cursor.selectedText()):
            # Check if start_pos is at the start of a block
            cursor.setPosition(start_pos)
            cursor.movePosition(QTextCursor.StartOfBlock)
            start_pos = cursor.position()

            cursor.setPosition(end_pos)
            # Check if end_pos is at the start of a block: if so, starting
            # changes from the previous block
            cursor.movePosition(QTextCursor.StartOfBlock,
                                QTextCursor.KeepAnchor)
            if to_text_string(cursor.selectedText()):
                cursor.movePosition(QTextCursor.NextBlock)
                end_pos = cursor.position()
        else:
            cursor.movePosition(QTextCursor.StartOfBlock)
            start_pos = cursor.position()
            cursor.movePosition(QTextCursor.NextBlock)
            end_pos = cursor.position()
        cursor.setPosition(start_pos)
        cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
        
        sel_text = to_text_string(cursor.selectedText())
        cursor.removeSelectedText()
        
        if after_current_line:
            text = to_text_string(cursor.block().text())
            start_pos += len(text)+1
            end_pos += len(text)+1
            cursor.movePosition(QTextCursor.NextBlock)
        else:
            cursor.movePosition(QTextCursor.PreviousBlock)
            text = to_text_string(cursor.block().text())
            start_pos -= len(text)+1
            end_pos -= len(text)+1
        cursor.insertText(sel_text)

        cursor.endEditBlock()
        self.setTextCursor(cursor)
        self.__restore_selection(start_pos, end_pos)
    
    def move_line_up(self):
        """Move up current line or selected text"""
        self.__move_line_or_selection(after_current_line=False)
        
    def move_line_down(self):
        """Move down current line or selected text"""
        self.__move_line_or_selection(after_current_line=True)
        
    def extend_selection_to_complete_lines(self):
        """Extend current selection to complete lines"""
        cursor = self.textCursor()
        start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
        cursor.setPosition(start_pos)
        cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
        if cursor.atBlockStart():
            cursor.movePosition(QTextCursor.PreviousBlock,
                                QTextCursor.KeepAnchor)
            cursor.movePosition(QTextCursor.EndOfBlock,
                                QTextCursor.KeepAnchor)
        self.setTextCursor(cursor)
        
    def delete_line(self):
        """Delete current line"""
        cursor = self.textCursor()
        if self.has_selected_text():
            self.extend_selection_to_complete_lines()
            start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
            cursor.setPosition(start_pos)
        else:
            start_pos = end_pos = cursor.position()
        cursor.beginEditBlock()
        cursor.setPosition(start_pos)
        cursor.movePosition(QTextCursor.StartOfBlock)
        while cursor.position() <= end_pos:
            cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
            if cursor.atEnd():
                break
            cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor)
        cursor.removeSelectedText()
        cursor.endEditBlock()
        self.ensureCursorVisible()


    #------Code completion / Calltips
    def show_calltip(self, title, text, color='#2D62FF',
                     at_line=None, at_position=None):
        """Show calltip"""
        if text is None or len(text) == 0:
            return
        # Saving cursor position:
        if at_position is None:
            at_position = self.get_position('cursor')
        self.calltip_position = at_position
        # Preparing text:
        weight = 'bold' if self.calltip_font.bold() else 'normal'
        size = self.calltip_font.pointSize()
        family = self.calltip_font.family()
        format1 = '<div style=\'font-size: %spt; color: %s\'>' % (size, color)
        format2 = '<hr><div style=\'font-family: "%s"; font-size: %spt; font-weight: %s\'>' % (family, size, weight)
        if isinstance(text, list):
            text = "\n    ".join(text)
        text = text.replace('\n', '<br>')
        if len(text) > self.calltip_size:
            text = text[:self.calltip_size] + " ..."
        tiptext = format1 + ('<b>%s</b></div>' % title) \
                  + format2 + text + "</div>"
        # Showing tooltip at cursor position:
        cx, cy = self.get_coordinates('cursor')
        if at_line is not None:
            cx = 5
            cursor = QTextCursor(self.document().findBlockByNumber(at_line-1))
            cy = self.cursorRect(cursor).top()
        point = self.mapToGlobal(QPoint(cx, cy))
        point.setX(point.x()+self.get_linenumberarea_width())
        QToolTip.showText(point, tiptext)

    def hide_tooltip_if_necessary(self, key):
        """Hide calltip when necessary"""
        try:
            calltip_char = self.get_character(self.calltip_position)
            before = self.is_cursor_before(self.calltip_position,
                                           char_offset=1)
            other = key in (Qt.Key_ParenRight, Qt.Key_Period, Qt.Key_Tab)
            if calltip_char not in ('?', '(') or before or other:
                QToolTip.hideText()
        except (IndexError, TypeError):
            QToolTip.hideText()

    def show_completion_widget(self, textlist, automatic=True):
        """Show completion widget"""
        self.completion_widget.show_list(textlist, automatic=automatic)
        
    def hide_completion_widget(self):
        """Hide completion widget"""
        self.completion_widget.hide()

    def show_completion_list(self, completions, completion_text="",
                             automatic=True):
        """Display the possible completions"""
        if len(completions) == 0 or completions == [completion_text]:
            return
        self.completion_text = completion_text
        # Sorting completion list (entries starting with underscore are 
        # put at the end of the list):
        underscore = set([comp for comp in completions
                          if comp.startswith('_')])
        completions = sorted(set(completions)-underscore, key=str_lower)+\
                      sorted(underscore, key=str_lower)
        self.show_completion_widget(completions, automatic=automatic)
        
    def select_completion_list(self):
        """Completion list is active, Enter was just pressed"""
        self.completion_widget.item_selected()
        
    def insert_completion(self, text):
        if text:
            cursor = self.textCursor()
            cursor.movePosition(QTextCursor.PreviousCharacter,
                                QTextCursor.KeepAnchor,
                                len(self.completion_text))
            cursor.removeSelectedText()
            self.insert_text(text)

    def is_completion_widget_visible(self):
        """Return True is completion list widget is visible"""
        return self.completion_widget.isVisible()
    
        
    #------Standard keys
    def stdkey_clear(self):
        if not self.has_selected_text():
            self.moveCursor(QTextCursor.NextCharacter, QTextCursor.KeepAnchor)
        self.remove_selected_text()
    
    def stdkey_backspace(self):
        if not self.has_selected_text():
            self.moveCursor(QTextCursor.PreviousCharacter,
                            QTextCursor.KeepAnchor)
        self.remove_selected_text()

    def __get_move_mode(self, shift):
        return QTextCursor.KeepAnchor if shift else QTextCursor.MoveAnchor

    def stdkey_up(self, shift):
        self.moveCursor(QTextCursor.Up, self.__get_move_mode(shift))

    def stdkey_down(self, shift):
        self.moveCursor(QTextCursor.Down, self.__get_move_mode(shift))

    def stdkey_tab(self):
        self.insert_text(self.indent_chars)

    def stdkey_home(self, shift, ctrl, prompt_pos=None):
        """Smart HOME feature: cursor is first moved at 
        indentation position, then at the start of the line"""
        move_mode = self.__get_move_mode(shift)
        if ctrl:
            self.moveCursor(QTextCursor.Start, move_mode)
        else:
            cursor = self.textCursor()
            if prompt_pos is None:
                start_position = self.get_position('sol')
            else:
                start_position = self.get_position(prompt_pos)
            text = self.get_text(start_position, 'eol')
            indent_pos = start_position+len(text)-len(text.lstrip())
            if cursor.position() != indent_pos:
                cursor.setPosition(indent_pos, move_mode)
            else:
                cursor.setPosition(start_position, move_mode)
            self.setTextCursor(cursor)

    def stdkey_end(self, shift, ctrl):
        move_mode = self.__get_move_mode(shift)
        if ctrl:
            self.moveCursor(QTextCursor.End, move_mode)
        else:
            self.moveCursor(QTextCursor.EndOfBlock, move_mode)

    def stdkey_pageup(self):
        pass

    def stdkey_pagedown(self):
        pass

    def stdkey_escape(self):
        pass

                
    #----Qt Events
    def mousePressEvent(self, event):
        """Reimplement Qt method"""
        if os.name != 'posix' and event.button() == Qt.MidButton:
            self.setFocus()
            event = QMouseEvent(QEvent.MouseButtonPress, event.pos(),
                                Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
            QPlainTextEdit.mousePressEvent(self, event)
            QPlainTextEdit.mouseReleaseEvent(self, event)
            self.paste()
        else:
            QPlainTextEdit.mousePressEvent(self, event)

    def focusInEvent(self, event):
        """Reimplemented to handle focus"""
        self.emit(SIGNAL("focus_changed()"))
        self.emit(SIGNAL("focus_in()"))
        QPlainTextEdit.focusInEvent(self, event)
        
    def focusOutEvent(self, event):
        """Reimplemented to handle focus"""
        self.emit(SIGNAL("focus_changed()"))
        QPlainTextEdit.focusOutEvent(self, event)
    
    def wheelEvent(self, event):
        """Reimplemented to emit zoom in/out signals when Ctrl is pressed"""
        # This feature is disabled on MacOS, see Issue 1510:
        # http://code.google.com/p/spyderlib/issues/detail?id=1510
        if sys.platform != 'darwin':
            if event.modifiers() & Qt.ControlModifier:
                if event.delta() < 0:
                    self.emit(SIGNAL("zoom_out()"))
                elif event.delta() > 0:
                    self.emit(SIGNAL("zoom_in()"))
                return
        QPlainTextEdit.wheelEvent(self, event)
Exemple #14
0
def read_settings_API_3(stream, settings):
    """ Write all settings such as fonts for labels and legend.
    
    NOTE: This function doesn't return anything and changes
    the settings directly."""

    labelFont     = QFont()
    legendFont    = QFont()

    stream >> labelFont

    labelInterval = stream.readInt32()
    labelState = get_row_label_identifier(labelInterval)

    stream >> legendFont
    gridCellWidth = stream.readInt32()
    gridCellHeight = stream.readInt32()

    # make sure we parsed something sensible before 
    # touching the settings
    if labelFont.family():
        settings.labelFont.value = labelFont

    if labelState:
        settings.rowLabelMode.value = labelState

    if legendFont.family():
        settings.legendFont.value = legendFont

    if gridCellWidth != 0:
        settings.gridCellWidth.value = gridCellWidth

    if gridCellHeight != 0:
        settings.gridCellHeight.value = gridCellHeight

    # new stuff in API_VERSION 2 and onward
    labelStart = stream.readInt32()
    settings.rowLabelStart.value = labelStart

    evenRowLabelLocation = stream.readInt32()
    settings.evenRowLabelLocation.value = \
            get_row_label_location_string(evenRowLabelLocation)

    highlightRows = stream.readInt32()
    settings.highlightRows.value = highlightRows

    highlightRowsOpacity = stream.readInt32()
    settings.highlightRowsOpacity.value = highlightRowsOpacity

    highlightRowsStart = stream.readInt32()
    settings.highlightRowsStart.value = highlightRowsStart

    highlightRowsColor = stream.readQString()
    if highlightRowsColor:
        settings.highlightRowsColor.value = highlightRowsColor

    # write rest of row/column settings
    # NOTE: The row settings aren't combined with the rest to
    # remain backward compatible.
    oddRowLabelLocation = stream.readInt32()
    settings.oddRowLabelLocation.value = \
            get_row_label_location_string(oddRowLabelLocation)

    rowLabelsShowInterval = stream.readInt32()
    settings.rowLabelsShowInterval.value = rowLabelsShowInterval

    rowLabelsShowIntervalStart = stream.readInt32()
    settings.rowLabelsShowIntervalStart.value = \
            rowLabelsShowIntervalStart

    columnLabelMode = stream.readInt32()
    settings.columnLabelMode.value = \
            get_column_label_identifier(columnLabelMode)

    columnLabelsShowInterval = stream.readInt32()
    settings.columnLabelsShowInterval.value = \
            columnLabelsShowInterval

    columnLabelsShowIntervalStart = stream.readInt32()
    settings.columnLabelsShowIntervalStart.value = \
            columnLabelsShowIntervalStart

    rowLabelsEditable = stream.readInt32()
    settings.rowLabelsEditable.value = rowLabelsEditable

    columnLabelsEditable = stream.readInt32()
    settings.columnLabelsEditable.value = columnLabelsEditable
Exemple #15
0
class CharMap(QWidget):
    """A widget displaying a table of characters."""
    characterSelected = pyqtSignal(str)
    characterClicked = pyqtSignal(str)
    
    def __init__(self, parent=None):
        super(CharMap, self).__init__(parent)
        self._showToolTips = True
        self._showWhatsThis = True
        self._selected = -1
        self._column_count = 32
        self._square = 24
        self._range = (0, 0)
        self._font = QFont()
        
    def setRange(self, first, last):
        self._range = (first, last)
        self._selected = -1
        self.adjustSize()
        self.update()
    
    def range(self):
        return self._range
    
    def square(self):
        """Returns the width of one item (determined by font size)."""
        return self._square
    
    def select(self, charcode):
        """Selects the specified character (int or str)."""
        if not isinstance(charcode, int):
            charcode = ord(charcode)
        if not self._range[0] <= charcode <= self._range[1]:
            charcode = -1
        if self._selected != charcode:
            self._selected = charcode
            self.characterSelected.emit(chr(charcode))
            self.update()
    
    def character(self):
        """Returns the currently selected character, if any."""
        if self._selected != -1:
            return chr(self._selected)
    
    def setDisplayFont(self, font):
        self._font.setFamily(font.family())
        self.update()
    
    def displayFont(self):
        return QFont(self._font)
    
    def setDisplayFontSize(self, size):
        self._font.setPointSize(size)
        self._square = max(24, QFontMetrics(self._font).xHeight() * 3)
        self.adjustSize()
        self.update()
    
    def displayFontSize(self):
        return self._font.pointSize()
    
    def setDisplayFontSizeF(self, size):
        self._font.setPointSizeF(size)
        self._square = max(24, QFontMetrics(self._font).xHeight() * 3)
        self.adjustSize()
        self.update()
    
    def displayFontSizeF(self):
        return self._font.pointSizeF()
    
    def setColumnCount(self, count):
        """Sets how many columns should be used."""
        count = max(1, count)
        self._column_count = count
        self.adjustSize()
        self.update()
    
    def columnCount(self):
        return self._column_count
        
    def sizeHint(self):
        return self.sizeForColumnCount(self._column_count)

    def paintEvent(self, ev):
        rect = ev.rect()
        s = self._square
        rows = range(rect.top() // s, rect.bottom() // s + 1)
        cols = range(rect.left() // s, rect.right() // s + 1)
        
        painter = QPainter(self)
        painter.setPen(QPen(self.palette().color(QPalette.Window)))
        painter.setFont(self._font)
        metrics = QFontMetrics(self._font)
        
        # draw characters on white tiles
        tile = self.palette().color(QPalette.Base)
        selected_tile = self.palette().color(QPalette.Highlight)
        selected_tile.setAlpha(96)
        selected_box = self.palette().color(QPalette.Highlight)
        
        text_pen = QPen(self.palette().text())
        disabled_pen = QPen(self.palette().color(QPalette.Disabled, QPalette.Text))
        selection_pen = QPen(selected_box)
        for row in rows:
            for col in cols:
                char = row * self._column_count + col + self._range[0]
                if char > self._range[1]:
                    break
                printable = self.isprint(char)
                painter.setClipRect(col * s, row * s, s, s)
                if char == self._selected:
                    painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2, selected_tile)
                    painter.setPen(selection_pen)
                    painter.drawRect(col * s, row * s, s - 1, s - 1)
                elif printable:
                    painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2, tile)
                painter.setPen(text_pen if printable else disabled_pen)
                t = chr(char)
                x = col * s + s // 2 - metrics.width(t) // 2
                y = row * s + 4 + metrics.ascent()
                painter.drawText(x, y, t)
            else:
                continue
            break
    
    def sizeForColumnCount(self, count):
        """Returns the size the widget would have in a certain column count.
        
        This can be used in e.g. a resizable scroll area.
        
        """
        first, last = self._range
        rows = ((last - first) // count) + 1
        return QSize(count, rows) * self._square

    def columnCountForWidth(self, width):
        """Returns the number of columns that would fit into the given width."""
        return width // self._square

    def mousePressEvent(self, ev):
        charcode = self.charcodeAt(ev.pos())
        if charcode != -1 and self.isprint(charcode):
            self.select(charcode)
            if ev.button() != Qt.RightButton:
                self.characterClicked.emit(chr(charcode))
    
    def charcodeRect(self, charcode):
        """Returns the rectangular box around the given charcode, if any."""
        if self._range[0] <= charcode <= self._range[1]:
            row, col = divmod(charcode - self._range[0], self._column_count)
            s = self._square
            return QRect(col * s, row * s, s, s)
        
    def charcodeAt(self, position):
        row = position.y() // self._square
        col = position.x() // self._square
        if col <= self._column_count:
            charcode = self._range[0] + row * self._column_count + col
            if charcode <= self._range[1]:
                return charcode
        return -1

    def event(self, ev):
        if ev.type() == QEvent.ToolTip:
            if self._showToolTips:
                c = self.charcodeAt(ev.pos())
                if c:
                    text = self.getToolTipText(c)
                    if text:
                        rect = self.charcodeRect(c)
                        QToolTip.showText(ev.globalPos(), text, self, rect)
                        ev.accept()
                        return True
        elif ev.type() == QEvent.QueryWhatsThis:
            if self._showWhatsThis:
                ev.accept()
                return True
        elif ev.type() == QEvent.WhatsThis:
            ev.accept()
            if self._showWhatsThis:
                c = self.charcodeAt(ev.pos())
                text = self.getWhatsThisText(c) if c else None
                if text:
                    QWhatsThis.showText(ev.globalPos(), text, self)
                else:
                    QWhatsThis.leaveWhatsThisMode()
            return True
        return super(CharMap, self).event(ev)
    
    def getToolTipText(self, charcode):
        try:
            return unicodedata.name(chr(charcode))
        except ValueError:
            pass
    
    def getWhatsThisText(self, charcode):
        try:
            name = unicodedata.name(chr(charcode))
        except ValueError:
            return
        return whatsthis_html.format(
            self._font.family(), chr(charcode), name, charcode)
    
    def setShowToolTips(self, enabled):
        self._showToolTips = bool(enabled)
    
    def showToolTips(self):
        return self._showToolTips

    def setShowWhatsThis(self, enabled):
        self._showWhatsThis = bool(enabled)
    
    def showWhatsThis(self):
        return self._showWhatsThis

    def isprint(self, charcode):
        """Returns True if the given charcode is printable."""
        return isprint(charcode)
Exemple #16
0
class TextFormatData(object):
    """Encapsulates all settings in the Fonts & Colors page for a scheme."""
    def __init__(self, scheme):
        """Loads the data from scheme."""
        self.font = None
        self.baseColors = {}
        self.defaultStyles = {}
        self.allStyles = {}
        self.load(scheme)
        
    def load(self, scheme):
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)
        
        # load font
        self.font = QFont(s.value("fontfamily", "monospace"))
        self.font.setPointSizeF(float(s.value("fontsize", 10.0)))
        
        # load base colors
        s.beginGroup("basecolors")
        for name in baseColors:
            if s.contains(name):
                self.baseColors[name] = QColor(s.value(name))
            else:
                self.baseColors[name] = baseColorDefaults[name]()
        s.endGroup()
        
        # load default styles
        s.beginGroup("defaultstyles")
        for name in defaultStyles:
            self.defaultStyles[name] = f = QTextCharFormat(defaultStyleDefaults[name])
            s.beginGroup(name)
            loadTextFormat(f, s)
            s.endGroup()
        s.endGroup()
        
        # load specific styles
        s.beginGroup("allstyles")
        for group, styles in allStyles:
            self.allStyles[group]= {}
            s.beginGroup(group)
            for name in styles:
                default = allStyleDefaults[group].get(name)
                self.allStyles[group][name] = f = QTextCharFormat(default) if default else QTextCharFormat()
                s.beginGroup(name)
                loadTextFormat(f, s)
                s.endGroup()
            s.endGroup()
        s.endGroup()
        
    def save(self, scheme):
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)
        
        # save font
        s.setValue("fontfamily", self.font.family())
        s.setValue("fontsize", self.font.pointSizeF())
        
        # save base colors
        for name in baseColors:
            s.setValue("basecolors/"+name, self.baseColors[name].name())
        
        # save default styles
        s.beginGroup("defaultstyles")
        for name in defaultStyles:
            s.beginGroup(name)
            saveTextFormat(self.defaultStyles[name], s)
            s.endGroup()
        s.endGroup()
        
        # save all specific styles
        s.beginGroup("allstyles")
        for group, styles in allStyles:
            s.beginGroup(group)
            for name in styles:
                s.beginGroup(name)
                saveTextFormat(self.allStyles[group][name], s)
                s.endGroup()
            s.endGroup()
        s.endGroup()

    def textFormat(self, group, name):
        inherit = inherits[group].get(name)
        f = QTextCharFormat(self.defaultStyles[inherit]) if inherit else QTextCharFormat()
        f.merge(self.allStyles[group][name])
        return f
    
    def palette(self):
        """Returns a basic palette with text, background, selection and selection background filled in."""
        p = QApplication.palette()
        p.setColor(QPalette.Text, self.baseColors['text'])
        p.setColor(QPalette.Base, self.baseColors['background'])
        p.setColor(QPalette.HighlightedText, self.baseColors['selectiontext'])
        p.setColor(QPalette.Highlight, self.baseColors['selectionbackground'])
        return p
Exemple #17
0
class ZTextWidget(QWidget):
    width = 80
    height = 24
    cur_fg = 10
    cur_bg = 2
    cur_style = 0
    max_char = 0
    start_pos = 0
    #cursor_char = 0x258f
    #cursor_char = 0x005f
    cursor_char = unichr(0x2017)
    #cursor_char = 0x2582
    input_buf = []
    just_scrolled = False
    reading_line = False
    reverse_video = False
    _cursor_visible = False
    _ostream = None
    _input_buffer_printing = False
    _input_cursor_pos = 0
    returnPressed = pyqtSignal(QString)
    keyPressed = pyqtSignal(int)
    pbuffer = [None]*8
    pbuffer_painter = [None]*8
    game_area = QImage(640, 480, QImage.Format_RGB32)
    game_area_painter = QPainter(game_area)
    chartimer = None
    linetimer = None
    brush = QBrush(Qt.SolidPattern)
    ztoq_color = dict({2:Qt.black,
                       3:Qt.red,
                       4:Qt.green,
                       5:Qt.yellow,
                       6:Qt.blue,
                       7:Qt.magenta,
                       8:Qt.cyan,
                       9:Qt.white,
                       10:Qt.lightGray,
                       11:Qt.gray,
                       12:Qt.darkGray})

    def __init__(self,parent = None,flags = Qt.Widget):
        super(ZTextWidget,self).__init__(parent,flags)
        sp = QSizePolicy()
        sp.setHorizontalPolicy(QSizePolicy.Fixed)
        sp.setVerticalPolicy(QSizePolicy.Fixed)
        self.setSizePolicy(sp)
        self.setFocusPolicy(Qt.StrongFocus)
        self.pbuffer[0] = QImage(640,480,QImage.Format_RGB32)
        self.pbuffer[0].fill(0)
        font = self.font()
        self.normal_font = font
        self.fixed_font = QFont(font)
        self.fixed_font.setStyleHint(QFont.Monospace)
        self.fixed_font.setFamily(self.fixed_font.defaultFamily())
        self.fixed_font.setPointSize(9)
        print self.fixed_font.family()
        #self.setFont(self.normal_font)
        self.setFont(self.fixed_font)
        self.pbuffer_painter[0] = QPainter(self.pbuffer[0])
        self.pbuffer_painter[0].setFont(self.fixed_font)

        self.font_metrics = self.pbuffer_painter[0].fontMetrics()

        self.linesize = self.font_metrics.height()
        self.avgwidth = self.font_metrics.averageCharWidth()
        print self.font_metrics.averageCharWidth(), self.linesize, self.avgwidth
        print self.font_metrics.height()
        self.width = (self.pbuffer[0].width() - 4) / self.font_metrics.averageCharWidth()
        self.height = self.pbuffer[0].height() / self.linesize

        self.pbuffer_painter[0].setFont(self.normal_font)
        self.set_text_colour(self.cur_fg, 0)
        self.set_text_background_colour(self.cur_bg, 0)

    def paintEvent(self,e):
        painter = QPainter(self)
        painter.drawImage(0,0,self.game_area)

    def update_game_area(self):
        for i in xrange(8):
            if (self.pbuffer[i] != None):
                self.game_area_painter.drawImage(0,0,self.pbuffer[i])
        self.update()

    def scroll(self,painter):
        part = self.pbuffer[0].copy(0,self.linesize,self.pbuffer[0].width(),self.pbuffer[0].height()-self.linesize)
        #print 'Part height:', part.height(), 'width:', part.width()
        self.pbuffer[0].fill(self.ztoq_color[self.cur_bg])
        #print 'pbuffer[0] height:', self.pbuffer[0].height(), 'width:', self.pbuffer[0].width()
        painter.drawImage(0,0,part)
        #print 'pbuffer[0] height:', self.pbuffer[0].height(), 'width:', self.pbuffer[0].width()
        if (self.reading_line):
            self.just_scrolled = True

    def sizeHint(self):
        size = QSize()
        size.setWidth(640)
        size.setHeight(480)
        return size

    def set_max_input(self,m):
        self.max_char = m

    def show_cursor(self,window):
        self.lastwindow = window
        #self._input_cursor_pos = 0
        #print self._input_cursor_pos
        self.insert_pos = window.cursor
        self.insert_real_pos = window.cursor_real_pos
        if (self._cursor_visible != True): # If the cursor is already visible avoid multiplying it...
            self.input_buf.insert(self._input_cursor_pos, self.cursor_char)
        self._cursor_visible = True
        self.clean_input_buffer_from_screen()
        self.draw_input_buffer()
        #self.draw_cursor(window,True)

    def hide_cursor(self,window):
        self._cursor_visible = False
        del self.input_buf[self._input_cursor_pos]
        #self.draw_cursor(window,False)

    def keyPressEvent(self,e):
        if e.key() == Qt.Key_Left:
            if self._input_cursor_pos>0:
                c = self.input_buf.pop(self._input_cursor_pos)
                self._input_cursor_pos -= 1
                self.input_buf.insert(self._input_cursor_pos, c)
                self.clean_input_buffer_from_screen()
                self.draw_input_buffer()
            e.accept()
            self.keyPressed.emit(131)
        elif e.key() == Qt.Key_Right:
            if self._input_cursor_pos<(len(self.input_buf)-1):
                c = self.input_buf.pop(self._input_cursor_pos)
                self._input_cursor_pos += 1
                self.input_buf.insert(self._input_cursor_pos, c)
                self.clean_input_buffer_from_screen()
                self.draw_input_buffer()
            e.accept()
            self.keyPressed.emit(132)
        elif e.key() == Qt.Key_Up:
            # TODO: Up in history
            e.accept()
            self.keyPressed.emit(129)
            pass
        elif e.key() == Qt.Key_Down:
            # TODO: Down in history
            e.accept()
            self.keyPressed.emit(130)
            pass
        elif e.key() == Qt.Key_Backspace:
            if len(self.input_buf)>1: # If there IS something to delete
                self.clean_input_buffer_from_screen()
                del self.input_buf[self._input_cursor_pos-1]
                self._input_cursor_pos -= 1
                self.draw_input_buffer()
            # self.keyPressed.emit() # No keycode available for zscii
            e.accept()
        elif e.key() == Qt.Key_Delete:
            if self._input_cursor_pos < (len(self.input_buf) - 1):
                self.clean_input_buffer_from_screen()
                del self.input_buf[self._input_cursor_pos+1]
                self.draw_input_buffer()
            e.accept()
            self.keyPressed.emit(8)
        elif (e.key() == Qt.Key_Return) or (e.key() == Qt.Key_Enter):
            self.clean_input_buffer_from_screen()
            if (self._cursor_visible == True):
                self.hide_cursor(self.lastwindow)
            if (self.reading_line == True):
                self.draw_input_buffer()
            text = ''
            for i in self.input_buf:
                text += i
            #print text
            self.draw_text('\n', 1, self.lastwindow)
            self.keyPressed.emit(13)
            self._input_cursor_pos = 0
            self.input_buf = []
            self.returnPressed.emit(text)
            e.accept()
        elif ((e.key() >= Qt.Key_F1) and (e.key() <= Qt.Key_F12)):
            e.accept()
            self.keyPressed.emit(133 + e.key() - Qt.Key_F1)
        elif e.key() == Qt.Key_Escape:
            e.accept()
            self.keyPressed.emit(27)
        elif (e.text().isEmpty() == False):
            if (self.reading_line) and (len(self.input_buf) < self.max_char+1):
                self.clean_input_buffer_from_screen()
                self.input_buf.insert(self._input_cursor_pos, unicode(e.text()))
                self._input_cursor_pos += 1
                self.draw_input_buffer()
            e.accept()
            t = ord(str(e.text()[0])) # TODO: Check if we can handle multiple events at once
            if ((t > 31) and (t < 127)) or ((t > 154) and (t <252)):
                self.keyPressed.emit(t)
        else:
            e.ignore()

    def draw_input_buffer(self):
        # Prepare for redraw by setting appropriate cursor position
        tmp_pos = self.lastwindow.cursor
        tmp_real_pos = self.lastwindow.cursor_real_pos
        self.lastwindow.set_cursor_position(self.insert_pos[0], self.insert_pos[1])
        self.lastwindow.set_cursor_real_position(self.insert_real_pos[0], self.insert_real_pos[1])
        self._input_buffer_printing = True
        self.prints(self.input_buf, self.lastwindow)
        self._input_buffer_printing = False
        if (self.just_scrolled): # A new line scroll // Is it really necessary?
            self.just_scrolled = False
            self.lastwindow.set_cursor_position(tmp_pos[0], tmp_pos[1])
            self.lastwindow.set_cursor_real_position(tmp_real_pos[0], tmp_real_pos[1])
        else:
            self.lastwindow.set_cursor_position(tmp_pos[0], tmp_pos[1])
            self.lastwindow.set_cursor_real_position(tmp_real_pos[0], tmp_real_pos[1])
        #self.draw_cursor(self.lastwindow, self._cursor_visible)
        #print self.input_buf, len(self.input_buf), self.max_char
        self.update_game_area()

    def set_text_colour(self,fg, win):
        self.cur_fg = fg
        if (self.pbuffer_painter[win] == None):
            self.pbuffer_painter[win] = QPainter(self.pbuffer[win])
        painter = self.pbuffer_painter[win]
        painter.setPen(self.ztoq_color[self.cur_fg])

    def set_text_background_colour(self,bg, win):
        self.cur_bg = bg
        if (self.pbuffer_painter[win] == None):
            self.pbuffer_painter[win] = QPainter(self.pbuffer[win])
        painter = self.pbuffer_painter[win]
        self.brush.setColor(self.ztoq_color[self.cur_bg])
        painter.setBackground(self.brush)

    def set_font_style(self,s,win):
        if s == 0:
            self.cur_style = 0
        else:
            self.cur_style |= s
        # Now set the font accordingly
        newfont = self.font()
        # First reset the font
        newfont.setItalic(False)
        newfont.setFixedPitch(False)
        newfont.setBold(False)
        if (self.reverse_video == True):
            tmpbg = self.cur_bg
            self.set_text_background_colour(self.cur_fg,win)
            self.set_text_colour(tmpbg,win)
        self.reverse_video = False
        # And now check for extra style
        if ((self.cur_style & 1) == 1): # Reverse video
            self.reverse_video = True
            tmpbg = self.cur_bg
            self.set_text_background_colour(self.cur_fg,win)
            self.set_text_colour(tmpbg,win)
        if ((self.cur_style & 2) == 2): # Bold
            newfont.setBold(True)
        if ((self.cur_style & 4) == 4): # Italic
            newfont.setItalic(True)
        if ((self.cur_style & 8) == 8): # Fixed Pitch
            newfont.setFixedPitch(True)
        self.setFont(newfont)

    def read_line(self, window, callback, time, timeout_callback, reset):
        self.lastwindow = window
        #print reset
        if (reset == True):
            self.cur_pos = 0
        self.reading_line = True
        self.update_game_area()
        self.callback_object = callback
        QObject.connect(self, SIGNAL("returnPressed(QString)"), self.read_line_callback)
        if (self.linetimer == None):
            self.linetimer = QTimer()
            self.linetimer.setSingleShot(True)
        if (time <> 0):
            self.timeout_callback_object = timeout_callback
            QObject.connect(self.linetimer, SIGNAL('timeout()'), self.read_line_timeout_callback)
            self.linetimer.start(time * 100)

    def read_line_callback(self, string):
        if (self.linetimer != None):
            self.linetimer.stop()
        self.returnPressed.disconnect()
        self.callback_object(string)

    def read_line_timeout_callback(self):
        self.linetimer.timeout.disconnect()
        self.timeout_callback_object()

    def disconnect_read_line(self, callback):
        self.reading_line = False
        QObject.disconnect(self, SIGNAL("returnPressed(QString)"), callback)

    def read_char(self, window, callback, time, timeout_callback):
        self.update_game_area()
        self.lastwindow = window
        self.callback_object = callback
        QObject.connect(self, SIGNAL("keyPressed(int)"), self.read_char_callback)
        #print 'Connect char'
        if (self.chartimer == None):
            self.chartimer = QTimer()
            self.chartimer.setSingleShot(True)
        if (time <> 0):
            self.timeout_callback_object = timeout_callback
            QObject.connect(self.chartimer, SIGNAL('timeout()'), self.read_char_timeout_callback)
            self.chartimer.start(time * 100)

    def read_char_callback(self, key):
        if (self.chartimer != None):
            self.chartimer.stop()
        self.keyPressed.disconnect()
        self.callback_object(key)

    def read_char_timeout_callback(self):
        self.chartimer.timeout.disconnect()
        self.timeout_callback_object()

    def disconnect_read_char(self, callback):
        QObject.disconnect(self, SIGNAL("keyPressed(int)"), callback)
        #print 'Disconnect char'

    def prints(self, txt, window):
        txtlen = len(txt)
        if (txtlen == 1): # print_char got us here...
            self.draw_text(txt[0],1,window)
        else:
            lastspace = 0
            i = 0
            textbuffer = ''
            tblen = 0
            for w in txt:
                if (w == '\n' or w == self.cursor_char):
                    if (tblen>0): # If there is something to print
                        self.draw_text(textbuffer, tblen, window)
                        textbuffer = ''
                        tblen = 0
                    self.draw_text(w, 1, window)
                    if (w == '\n'): # \n is whitespace :-)
                        lastspace = i
                elif (w == ' '): # Space was found
                    if (lastspace == i-1): # Continuous spaces
                        textbuffer += w
                        tblen += 1
                    else:
                        self.draw_text(textbuffer, tblen, window)
                        self.draw_text(' ', 1, window)
                        textbuffer = ''
                        tblen = 0
                    lastspace = i
                else:
                    textbuffer += w
                    tblen += 1
                i += 1
            if (textbuffer != ''): # Buffer not empty
                self.draw_text(textbuffer, tblen, window)

    def draw_text(self, txt, txtlen, window):
        if ((txtlen>0) and not ((txt == self.cursor_char) and (self._cursor_visible == False))): # If there IS something to print
            if (self.pbuffer_painter[window.id] == None):
                self.brush.setColor(self.ztoq_color[self.cur_bg])
                self.pbuffer_painter[window.id] = QPainter(self.pbuffer[window.id])
                self.pbuffer_painter[window.id].setPen(self.ztoq_color[self.cur_fg])
                self.pbuffer_painter[window.id].setBackground(self.brush)

            painter = self.pbuffer_painter[window.id]

            # @type window ZWindow
            if (window.cursor == None):
                if (window.id == 0): # Main window
                    window.set_cursor_position(1, self.height)
                    window.set_cursor_real_position(2, self.height*(self.linesize-1))
                else:
                    window.set_cursor_position(1, 1)
                    window.set_cursor_real_position(2, self.linesize-1)

            if (txt=='\n'):
                if (window.cursor[1]==self.height):
                    if (window.scrolling):
                        self.scroll(painter)
                    window.set_cursor_position(1, window.cursor[1])
                    window.set_cursor_real_position(2, window.cursor_real_pos[1])
                else:
                    window.set_cursor_position(1, window.cursor[1]+1)
                    window.set_cursor_real_position(2, window.cursor_real_pos[1]+self.linesize)
            else:
                rect = QRectF(window.cursor_real_pos[0], window.cursor_real_pos[1], self.pbuffer[window.id].width()-window.cursor_real_pos[0], self.linesize)

                painter.setFont(self.font())
                #painter.setRenderHint(QPainter.TextAntialiasing)
                if (self._input_buffer_printing == False):
                    painter.setBackgroundMode(Qt.OpaqueMode)
                else:
                    painter.setBackgroundMode(Qt.TransparentMode)
                bounding_rect = painter.boundingRect(rect,txt)
                if (rect.contains(bounding_rect)):
                    #print rect.x(), rect.y(), rect.width(),rect.height(), txt, bounding_rect
                    painter.drawText(bounding_rect, txt)
                    if txt != self.cursor_char:
                        window.set_cursor_position(window.cursor[0]+txtlen, window.cursor[1])
                        window.set_cursor_real_position(rect.x()+bounding_rect.width(), rect.y())
                else: # There is not enough space
                    #print "Not enough space to print:", txt
                    self.scroll(painter)
                    window.set_cursor_position(1, self.height)
                    window.set_cursor_real_position(2, self.height*(self.linesize-1))
                    rect.setX(2)
                    rect.setY(window.cursor_real_pos[1])
                    rect.setWidth(self.pbuffer[window.id].width()-window.cursor_real_pos[0])
                    rect.setHeight(self.linesize)
                    bounding_rect = painter.boundingRect(rect,txt)
                    painter.drawText(bounding_rect, txt)
                    if txt != self.cursor_char:
                        window.set_cursor_position(window.cursor[0]+txtlen, window.cursor[1])
                        window.set_cursor_real_position(rect.x()+bounding_rect.width(), rect.y())

    def buffered_string(self, txt, window):
        # @type window ZWindow
        if (window.buffering):
            rect = QRect()
            rect.setX(window.cursor_real_pos[0])
            rect.setY(window.cursor_real_pos[1])
            rect.setWidth(window.width-window.cursor_real_pos[0])
            rect.setHeight(self.linesize)
            bounding_rect = painter.boundingRect(rect,txt)
            if (rect.contains(bounding_rect)): # string fits in this line
                return txt
        else:
            return txt

    def clean_input_buffer_from_screen(self):
        rect = QRectF()
        rect.setX(self.lastwindow.cursor_real_pos[0])
        rect.setY(self.lastwindow.cursor_real_pos[1])
        rect.setWidth(self.pbuffer[0].width()-self.lastwindow.cursor_real_pos[0]+1)
        rect.setHeight(self.linesize)
        txtbuffer = ''
        for w in self.input_buf:
            txtbuffer += w
        bounding_rect = self.pbuffer_painter[0].boundingRect(rect, txtbuffer)
        if (rect.contains(bounding_rect)): # string fits in this line
            self.pbuffer_painter[0].eraseRect(bounding_rect)
            #self.pbuffer_painter.drawRect(bounding_rect)
            #print 'Erasing rect', bounding_rect
        else:
            self.pbuffer_painter[0].eraseRect(rect)
            #print 'Erasing rect', rect
            # FIXME: clear next lines

    def clear(self):
        #print 'clearing...'
        self.game_area.fill(self.ztoq_color[self.cur_bg])
        for i in xrange(8):
            if (self.pbuffer[i] != None):
                self.pbuffer[i].fill(self.ztoq_color[self.cur_bg])

    def update_real_cursor_position(self, w):
        w.set_cursor_real_position(2+(w.cursor[0]-1)*self.avgwidth, (w.cursor[1]-1)*self.linesize)
        #print w.cursor, '->', w.cursor_real_pos

    def erase_window(self, w):
        if ((w.id >= 0) and (w.id < 8)):
            if (self.pbuffer_painter[w.id] == None):
                self.pbuffer_painter[w.id] = QPainter(self.pbuffer[w.id])
            self.pbuffer_painter[w.id].setPen(self.ztoq_color[self.cur_fg])
            self.brush.setColor(self.ztoq_color[self.cur_bg])
            self.pbuffer_painter[w.id].setBackground(self.brush)
            self.pbuffer_painter[w.id].setBackgroundMode(Qt.OpaqueMode)
            self.pbuffer_painter[w.id].eraseRect(QRectF(0, 0, self.pbuffer[w.id].width(), w.line_count*self.linesize))
            #print 2, 0, self.pbuffer[w.id].width()-2, w.line_count*self.linesize
        else:
            traceback.print_stack()
            print 'erase_window for window',w.id
            sys.exit()

    def split_window(self, lines, ver):
        #print 'Lines:', lines
        # Copy window 1 to window 0 if it already exists
        if (self.pbuffer[1] != None):
            self.pbuffer_painter[0].drawImage(0,0,self.pbuffer[1])

        if (lines == 0): # Unsplit
            #self.pbuffer[1].fill(self.ztoq_color(self.cur_bg))
            #del self.pbuffer_painter[1]
            #del self.pbuffer[1]
            self.pbuffer_painter[1] = None
            self.pbuffer[1] = None
        else:
            if (self.pbuffer[1] != None): # Window needs resizing
                tmp = self.pbuffer[1]
                #del self.pbuffer_painter[1]
                self.pbuffer_painter[1] = None
                self.pbuffer[1] = self.pbuffer[1].copy(0,0,self.pbuffer[1].width(),lines*self.linesize)
                #del tmp
            else: # New window
                self.pbuffer[1] = QImage(self.pbuffer[0].width(),lines*self.linesize,QImage.Format_RGB32)
                self.pbuffer[1].fill(0)
            if ver == 3:
                self.pbuffer[1].fill(self.ztoq_color[self.cur_bg])

    def stop_line_timer(self):
        if (self.linetimer != None):
            self.linetimer.stop()

    def stop_char_timer(self):
        if (self.chartimer != None):
            self.chartimer.stop()
Exemple #18
0
class TextFormatData(object):
    """Encapsulates all settings in the Fonts & Colors page for a scheme."""
    def __init__(self, scheme):
        """Loads the data from scheme."""
        self.font = None
        self.baseColors = {}
        self.defaultStyles = {}
        self.allStyles = {}
        self._inherits = {}
        self.load(scheme)
        
    def load(self, scheme):
        """Load the settings for the scheme. Called on init."""
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)
        
        # load font
        defaultfont = "Lucida Console" if os.name == "nt" else "monospace"
        self.font = QFont(s.value("fontfamily", defaultfont, type("")))
        self.font.setPointSizeF(s.value("fontsize", 10.0, float))
        
        # load base colors
        s.beginGroup("basecolors")
        for name in baseColors:
            if s.contains(name):
                self.baseColors[name] = QColor(s.value(name, "", type("")))
            else:
                self.baseColors[name] = baseColorDefaults[name]()
        s.endGroup()
        
        # get the list of supported styles from ly.colorize
        all_styles = ly.colorize.default_mapping()
        default_styles = set()
        for group, styles in all_styles:
            d = self._inherits[group] = {}
            for style in styles:
                if style.base:
                    default_styles.add(style.base)
                    d[style.name] = style.base
        
        default_scheme = ly.colorize.default_scheme
        
        # load default styles
        s.beginGroup("defaultstyles")
        for name in default_styles:
            self.defaultStyles[name] = f = QTextCharFormat()
            css = default_scheme[None].get(name)
            if css:
                css2fmt(css, f)
            s.beginGroup(name)
            self.loadTextFormat(f, s)
            s.endGroup()
        s.endGroup()
        
        # load specific styles
        s.beginGroup("allstyles")
        for group, styles in all_styles:
            self.allStyles[group]= {}
            s.beginGroup(group)
            for style in styles:
                self.allStyles[group][style.name] = f = QTextCharFormat()
                css = default_scheme[group].get(style.name)
                if css:
                    css2fmt(css, f)
                s.beginGroup(style.name)
                self.loadTextFormat(f, s)
                s.endGroup()
            s.endGroup()
        s.endGroup()
        
    def save(self, scheme):
        """Save the settings to the scheme."""
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)
        
        # save font
        s.setValue("fontfamily", self.font.family())
        s.setValue("fontsize", self.font.pointSizeF())
        
        # save base colors
        for name in baseColors:
            s.setValue("basecolors/"+name, self.baseColors[name].name())
        
        # save default styles
        s.beginGroup("defaultstyles")
        for name in defaultStyles:
            s.beginGroup(name)
            self.saveTextFormat(self.defaultStyles[name], s)
            s.endGroup()
        s.endGroup()
        
        # save all specific styles
        s.beginGroup("allstyles")
        for group, styles in ly.colorize.default_mapping():
            s.beginGroup(group)
            for style in styles:
                s.beginGroup(style.name)
                self.saveTextFormat(self.allStyles[group][style.name], s)
                s.endGroup()
            s.endGroup()
        s.endGroup()

    def textFormat(self, group, name):
        """Return a QTextCharFormat() for the specified group and name."""
        inherit = self._inherits[group].get(name)
        f = QTextCharFormat(self.defaultStyles[inherit]) if inherit else QTextCharFormat()
        f.merge(self.allStyles[group][name])
        return f
    
    def css_scheme(self):
        """Return a dictionary of css dictionaries representing this scheme.
        
        This can be fed to the ly.colorize.format_stylesheet() function.
        
        """
        scheme = {}
        # base/default styles
        d = scheme[None] = {}
        for name, fmt in self.defaultStyles.items():
            d[name] = fmt2css(fmt)
        # mode/group styles
        for mode, styles in self.allStyles.items():
            d = scheme[mode] = {}
            for name, fmt in styles.items():
                d[name] = fmt2css(fmt)
        return scheme
    
    def palette(self):
        """Return a basic palette with text, background, selection and selection background filled in."""
        p = QApplication.palette()
        p.setColor(QPalette.Text, self.baseColors['text'])
        p.setColor(QPalette.Base, self.baseColors['background'])
        p.setColor(QPalette.HighlightedText, self.baseColors['selectiontext'])
        p.setColor(QPalette.Highlight, self.baseColors['selectionbackground'])
        return p
        
    def saveTextFormat(self, fmt, settings):
        """(Internal) Store one QTextCharFormat in the QSettings instance."""
        if fmt.hasProperty(QTextFormat.FontWeight):
            settings.setValue('bold', fmt.fontWeight() >= 70)
        else:
            settings.remove('bold')
        if fmt.hasProperty(QTextFormat.FontItalic):
            settings.setValue('italic', fmt.fontItalic())
        else:
            settings.remove('italic')
        if fmt.hasProperty(QTextFormat.TextUnderlineStyle):
            settings.setValue('underline', fmt.fontUnderline())
        else:
            settings.remove('underline')
        if fmt.hasProperty(QTextFormat.ForegroundBrush):
            settings.setValue('textColor', fmt.foreground().color().name())
        else:
            settings.remove('textColor')
        if fmt.hasProperty(QTextFormat.BackgroundBrush):
            settings.setValue('backgroundColor', fmt.background().color().name())
        else:
            settings.remove('backgroundColor')
        if fmt.hasProperty(QTextFormat.TextUnderlineColor):
            settings.setValue('underlineColor', fmt.underlineColor().name())
        else:
            settings.remove('underlineColor')
        
    def loadTextFormat(self, fmt, settings):
        """(Internal) Merge values from the QSettings instance into the QTextCharFormat."""
        if settings.contains('bold'):
            fmt.setFontWeight(QFont.Bold if settings.value('bold', False, bool) else QFont.Normal)
        if settings.contains('italic'):
            fmt.setFontItalic(settings.value('italic', False, bool))
        if settings.contains('underline'):
            fmt.setFontUnderline(settings.value('underline', False, bool))
        if settings.contains('textColor'):
            fmt.setForeground(QColor(settings.value('textColor', '' , type(""))))
        if settings.contains('backgroundColor'):
            fmt.setBackground(QColor(settings.value('backgroundColor', '' , type(""))))
        if settings.contains('underlineColor'):
            fmt.setUnderlineColor(QColor(settings.value('underlineColor', '' , type(""))))
Exemple #19
0
class TextFormatData(object):
    """Encapsulates all settings in the Fonts & Colors page for a scheme."""
    def __init__(self, scheme):
        """Loads the data from scheme."""
        self.font = None
        self.baseColors = {}
        self.defaultStyles = {}
        self.allStyles = {}
        self.load(scheme)
        
    def load(self, scheme):
        """Load the settings for the scheme. Called on init."""
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)
        
        # load font
        self.font = QFont(s.value("fontfamily", "monospace"))
        self.font.setPointSizeF(float(s.value("fontsize", 10.0)))
        
        # load base colors
        s.beginGroup("basecolors")
        for name in baseColors:
            if s.contains(name):
                self.baseColors[name] = QColor(s.value(name))
            else:
                self.baseColors[name] = baseColorDefaults[name]()
        s.endGroup()
        
        # load default styles
        s.beginGroup("defaultstyles")
        for name in defaultStyles:
            self.defaultStyles[name] = f = QTextCharFormat(defaultStyleDefaults[name])
            s.beginGroup(name)
            self.loadTextFormat(f, s)
            s.endGroup()
        s.endGroup()
        
        # load specific styles
        s.beginGroup("allstyles")
        for group, styles in allStyles:
            self.allStyles[group]= {}
            s.beginGroup(group)
            for name in styles:
                default = allStyleDefaults[group].get(name)
                self.allStyles[group][name] = f = QTextCharFormat(default) if default else QTextCharFormat()
                s.beginGroup(name)
                self.loadTextFormat(f, s)
                s.endGroup()
            s.endGroup()
        s.endGroup()
        
    def save(self, scheme):
        """Save the settings to the scheme."""
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)
        
        # save font
        s.setValue("fontfamily", self.font.family())
        s.setValue("fontsize", self.font.pointSizeF())
        
        # save base colors
        for name in baseColors:
            s.setValue("basecolors/"+name, self.baseColors[name].name())
        
        # save default styles
        s.beginGroup("defaultstyles")
        for name in defaultStyles:
            s.beginGroup(name)
            self.saveTextFormat(self.defaultStyles[name], s)
            s.endGroup()
        s.endGroup()
        
        # save all specific styles
        s.beginGroup("allstyles")
        for group, styles in allStyles:
            s.beginGroup(group)
            for name in styles:
                s.beginGroup(name)
                self.saveTextFormat(self.allStyles[group][name], s)
                s.endGroup()
            s.endGroup()
        s.endGroup()

    def textFormat(self, group, name):
        """Return a QTextCharFormat() for the specified group and name."""
        inherit = inherits[group].get(name)
        f = QTextCharFormat(self.defaultStyles[inherit]) if inherit else QTextCharFormat()
        f.merge(self.allStyles[group][name])
        return f
    
    def palette(self):
        """Return a basic palette with text, background, selection and selection background filled in."""
        p = QApplication.palette()
        p.setColor(QPalette.Text, self.baseColors['text'])
        p.setColor(QPalette.Base, self.baseColors['background'])
        p.setColor(QPalette.HighlightedText, self.baseColors['selectiontext'])
        p.setColor(QPalette.Highlight, self.baseColors['selectionbackground'])
        return p
        
    def saveTextFormat(self, fmt, settings):
        """(Internal) Store one QTextCharFormat in the QSettings instance."""
        if fmt.hasProperty(QTextFormat.FontWeight):
            settings.setValue('bold', fmt.fontWeight() >= 70)
        else:
            settings.remove('bold')
        if fmt.hasProperty(QTextFormat.FontItalic):
            settings.setValue('italic', fmt.fontItalic())
        else:
            settings.remove('italic')
        if fmt.hasProperty(QTextFormat.TextUnderlineStyle):
            settings.setValue('underline', fmt.fontUnderline())
        else:
            settings.remove('underline')
        if fmt.hasProperty(QTextFormat.ForegroundBrush):
            settings.setValue('textColor', fmt.foreground().color().name())
        else:
            settings.remove('textColor')
        if fmt.hasProperty(QTextFormat.BackgroundBrush):
            settings.setValue('backgroundColor', fmt.background().color().name())
        else:
            settings.remove('backgroundColor')
        if fmt.hasProperty(QTextFormat.TextUnderlineColor):
            settings.setValue('underlineColor', fmt.underlineColor().name())
        else:
            settings.remove('underlineColor')
        
    def loadTextFormat(self, fmt, settings):
        """(Internal) Merge values from the QSettings instance into the QTextCharFormat."""
        if settings.contains('bold'):
            fmt.setFontWeight(QFont.Bold if settings.value('bold') in (True, 'true') else QFont.Normal)
        if settings.contains('italic'):
            fmt.setFontItalic(settings.value('italic') in (True, 'true'))
        if settings.contains('underline'):
            fmt.setFontUnderline(settings.value('underline') in (True, 'true'))
        if settings.contains('textColor'):
            fmt.setForeground(QColor(settings.value('textColor')))
        if settings.contains('backgroundColor'):
            fmt.setBackground(QColor(settings.value('backgroundColor')))
        if settings.contains('underlineColor'):
            fmt.setUnderlineColor(QColor(settings.value('underlineColor')))