def paintEvent(self, e):
     """
     Paints this editor.
     """
     # Paint the editor
     super(Editor, self).paintEvent(e)
     # Paint a line between the editor and the line number area
     x = self.contentOffset().x() + self.document().documentMargin() \
         + self._line_offset
     p = QtGui.QPainter(self.viewport())
     p.setPen(QtGui.QPen(QtGui.QColor('#ddd')))
     rect = e.rect()
     p.drawLine(x, rect.top(), x, rect.bottom())
 def __init__(self, document):
     super(ModelHighlighter, self).__init__(document)
     # Highlighting rules
     self._rules = []
     # Numbers
     style = QtGui.QTextCharFormat()
     style.setForeground(QtGui.QColor(255, 0, 255))
     pattern = QtCore.QRegExp(r'\b[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?\b')
     self._rules.append((pattern, style))
     # Keywords
     style = QtGui.QTextCharFormat()
     style.setForeground(QtGui.QColor(0, 96, 0))
     style.setFontWeight(QtGui.QFont.Bold)
     for keyword in self.KEYWORDS:
         pattern = QtCore.QRegExp(r'\b' + keyword + r'\b')
         self._rules.append((pattern, style))
     # Meta-data coloring (overrules previous formatting)
     self._meta_style = QtGui.QTextCharFormat()
     self._meta_style.setForeground(QtGui.QColor(128, 128, 192))
     pattern = QtCore.QRegExp(r':.*')
     self._rules.append((pattern, self._meta_style))
     # Strings (overrule previous formatting, except when commented)
     self._string_start = QtCore.QRegExp(r'"""')
     self._string_stop = QtCore.QRegExp(r'"""')
     self._comment_start = QtCore.QRegExp(r'#[^\n]*')
     # Comments (overrule all other formatting)
     style = QtGui.QTextCharFormat()
     style.setForeground(QtGui.QColor(20, 20, 255))
     pattern = QtCore.QRegExp(r'#[^\n]*')
     self._rules.append((pattern, style))
Ejemplo n.º 3
0
    def _line_number_area_paint(self, area, event):
        """ Repaints the line number area. """
        # Area to repaint
        rect = event.rect()
        etop = rect.top()
        ebot = rect.bottom()

        # Font metrics
        metrics = self.fontMetrics()
        height = metrics.height()
        width = area.width()

        # Create painter, set font color
        painter = QtGui.QPainter(area)
        painter.fillRect(rect, self._palette.button())
        painter.setPen(self._palette.buttonText().color())

        # Get top and bottom of first visible block
        block = self.firstVisibleBlock()
        geom = self.blockBoundingGeometry(block)
        btop = int(geom.translated(self.contentOffset()).top())
        bbot = int(btop + geom.height())

        # Iterate over visible blocks
        count = block.blockNumber()
        while block.isValid() and btop <= ebot:
            count += 1
            if block.isVisible() and bbot >= etop:
                painter.drawText(
                    0, btop, width - 4, height, Qt.AlignRight, str(count))
            block = block.next()
            btop = bbot
            bbot += int(self.blockBoundingRect(block).height())
Ejemplo n.º 4
0
 def action_set_frame(self, frame):
     """
     Move to a specific frame.
     """
     # Check frame index
     nt, ny, nx = self._data.shape()
     frame = int(frame)
     if frame < 0 or frame >= nt:
         frame = 0
     # Update
     if self._video_iframe != frame or True:
         self._video_iframe = frame
         # Update slider
         if self._slider.value() != frame:
             self._slider.setValue(self._video_iframe)
         # Update frame/time information
         self._frame_field.setText(str(frame))
         self._time_field.setText(str(self._data.time()[frame]))
         # Update scene
         image = self._video_frames[self._video_iframe]
         image = QtGui.QImage(image, nx, ny, QtGui.QImage.Format_ARGB32)
         self._video_pixmap.convertFromImage(image)
         self._video_item.setPixmap(self._video_pixmap)  # qt5
     # Update graph area
     self._graph_area.set_position(self._video_iframe)
Ejemplo n.º 5
0
 def __init__(self, *args):
     super(VideoScene, self).__init__(*args)
     self.setBackgroundBrush(QtGui.QColor(192, 192, 192))
     self._w = None
     self._h = None
     self._p = None
     self.resize(1, 1, 0)
 def _line_number_area_paint(self, area, event):
     """
     Repaints the line number area.
     """
     # Repaint area
     rect = event.rect()
     etop = rect.top()
     ebot = rect.bottom()
     # Repaint metrics
     metrics = self.fontMetrics()
     height = metrics.height()
     width = area.width()
     # Create painter, get font metrics
     painter = QtGui.QPainter(area)
     painter.fillRect(rect, COLOR_BG_LINE_NUMBER)
     # Get top and bottom of first block
     block = self.firstVisibleBlock()
     geom = self.blockBoundingGeometry(block)
     btop = geom.translated(self.contentOffset()).top()
     bbot = btop + geom.height()
     # Iterate over blocks
     count = block.blockNumber()
     while block.isValid() and btop <= ebot:
         count += 1
         if block.isVisible() and bbot >= etop:
             painter.drawText(0, btop, width, height, Qt.AlignRight,
                              str(count))
         block = block.next()
         btop = bbot
         bbot += self.blockBoundingRect(block).height()
Ejemplo n.º 7
0
    def paintEvent(self, event):
        """
        Draws all the graphs.
        """
        if self._data is None:
            return

        # Create painter
        painter = QtGui.QPainter()
        painter.begin(self)

        # Fill background
        painter.fillRect(self.rect(), QtGui.QBrush(Qt.white))

        # Create coordinate system for graphs
        painter.scale(self.width(), self.height())
        painter.setRenderHint(QtGui.QPainter.Antialiasing)

        # Create pen
        pen = QtGui.QPen()
        pen.setWidth(0)

        # Draw frozen graphs
        colors = iter(self._color_cycle)
        for path in self._frozen.values():
            try:
                pen.setColor(next(colors))
            except StopIteration:
                colors = iter(self._color_cycle)
                pen.setColor(next(colors))
            painter.setPen(pen)
            painter.drawPath(path)

        # Draw temp graph
        if self._temp_path:
            pen.setColor(self._color_temp)
            painter.setPen(pen)
            painter.drawPath(self._temp_path)

        # Show time indicator
        pen.setColor(Qt.red)
        painter.setPen(pen)
        t = (self._position - self._tmin) / self._trange
        painter.drawLine(QtCore.QLineF(t, 0, t, 1))

        # Finish
        painter.end()
Ejemplo n.º 8
0
 def action_extract_colormap_image(self):
     """
     Extracts the current colormap to an image file.
     """
     if not self._data:
         QtWidgets.QMessageBox.warning(
             self, TITLE, '<h1>No data to export.</h1>'
             '<p>Please open a data file first.</p>')
         return
     fname = QtWidgets.QFileDialog.getSaveFileName(
         self,
         'Extract colormap to image file',
         self._path,
         filter=FILTER_IMG)[0]
     if fname:
         fname = str(fname)
         ext = os.path.splitext(fname)[1][1:].upper()
         if ext not in IMAGE_TYPES:
             QtWidgets.QMessageBox.warning(
                 self, TITLE, '<h1>Image type not recognized.</h1>'
                 '<p>Unknown image type "' + str(ext) + '".</p>')
             return
         # Get min and max of data
         data = self._data.get2d(self._variable)
         lower = np.min(data)
         upper = np.max(data)
         # Create image
         nx = 200
         ny = 800
         image = myokit.ColorMap.image(self._colormap, nx, ny)
         image = QtGui.QImage(image, nx, ny, QtGui.QImage.Format_ARGB32)
         painter = QtGui.QPainter(image)
         painter.drawText(10, 15, str(upper))
         painter.drawText(10, ny - 5, str(lower))
         painter.end()
         # Save
         image.save(fname, ext)
Ejemplo n.º 9
0
    def graph(self, variable, x, y):
        """
        Adds temporary graph to this widget.
        """
        if self._data is None:
            return

        # Create index, check for duplicates
        variable = self._last_variable = str(variable)
        x, y = int(x), int(y)
        index = (x, y, variable)
        if index == self._temp_index:
            return
        if index in self._frozen:
            self._temp_index = self._temp_path = None
            self.update()
            return

        # Get scaling info
        try:
            ymin, ymax = self._scaling[variable]
        except KeyError:
            data = self._data.get2d(variable)
            ymin = np.min(data)
            ymax = np.max(data)
            d = ymax - ymin
            ymin -= 0.05 * d
            ymax += 0.05 * d
            if ymin == ymax:
                ymin -= 1
                ymax += 1
            self._scaling[variable] = (ymin, ymax)

        # Create path, using real time and scaled y data
        xx = iter(self._time_scaled)
        yy = (self._data.trace(variable, x, y) - ymin) / (ymax - ymin)
        yy = iter(1 - yy)
        path = QtGui.QPainterPath()
        x, y = next(xx), next(yy)
        path.moveTo(x, y)
        for i in range(1, len(self._time)):
            x, y = next(xx), next(yy)
            path.lineTo(x, y)
        self._temp_index = index
        self._temp_path = path

        # Update!
        self.update()
Ejemplo n.º 10
0
def icon():
    icons = [
        'icon-datablock-viewer.ico',
        'icon-datablock-viewer-16.xpm',
        'icon-datablock-viewer-24.xpm',
        'icon-datablock-viewer-32.xpm',
        'icon-datablock-viewer-48.xpm',
        'icon-datablock-viewer-64.xpm',
        'icon-datablock-viewer-96.xpm',
        'icon-datablock-viewer-128.xpm',
        'icon-datablock-viewer-256.xpm',
    ]
    icon = QtGui.QIcon()
    for i in icons:
        icon.addFile(os.path.join(myokit.DIR_DATA, 'gui', i))
    return icon
Ejemplo n.º 11
0
 def action_set_colormap(self, name):
     """
     Loads the ColorMap specified by ``name``.
     """
     name = str(name)
     if not myokit.ColorMap.exists(name):
         return  # Silent return?
     # Set colormap
     self._colormap = name
     # Update colormap controls
     self._colormap_select.setCurrentIndex(
         self._colormap_select.findText(self._colormap))
     if self._data:
         # Update variable display
         nt, ny, nx = self._data.shape()
         nx = self._colormap_size
         image = myokit.ColorMap.image(self._colormap, nx, ny)
         image = QtGui.QImage(image, nx, ny, QtGui.QImage.Format_ARGB32)
         self._colormap_pixmap.convertFromImage(image)
         self._colormap_item.setPixmap(self._colormap_pixmap)  # qt5
         self.action_set_variable(self._variable)
Ejemplo n.º 12
0
 def action_extract_frame_image(self):
     """
     Extracts the current frame to an image file.
     """
     if not self._data:
         QtWidgets.QMessageBox.warning(
             self, TITLE, '<h1>No data to export.</h1>'
             '<p>Please open a data file first.</p>')
         return
     fname = QtWidgets.QFileDialog.getSaveFileName(
         self, 'Extract frame to image file', self._path,
         filter=FILTER_IMG)[0]
     if fname:
         fname = str(fname)
         ext = os.path.splitext(fname)[1][1:].upper()
         if ext not in IMAGE_TYPES:
             QtWidgets.QMessageBox.warning(
                 self, TITLE, '<h1>Image type not recognized.</h1>'
                 '<p>Unknown image type "' + str(ext) + '".</p>')
             return
         nt, ny, nx = self._data.shape()
         image = self._video_frames[self._video_iframe]
         image = QtGui.QImage(image, nx, ny, QtGui.QImage.Format_ARGB32)
         image.save(fname, ext)
 def __init__(self, document):
     super(ProtocolHighlighter, self).__init__(document)
     # Highlighting rules
     self._rules = []
     # Numbers
     style = QtGui.QTextCharFormat()
     style.setForeground(QtGui.QColor(255, 0, 255))
     pattern = QtCore.QRegExp(r'\b[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?\b')
     self._rules.append((pattern, style))
     # Keyword "next"
     style = QtGui.QTextCharFormat()
     style.setForeground(QtGui.QColor(255, 0, 255))
     pattern = QtCore.QRegExp(r'\bnext\b')
     self._rules.append((pattern, style))
     # Comments
     style = QtGui.QTextCharFormat()
     style.setForeground(QtGui.QColor(20, 20, 255))
     pattern = QtCore.QRegExp(r'#[^\n]*')
     self._rules.append((pattern, style))
 def keyPressEvent(self, event):
     """
     Qt event: A key was pressed.
     """
     # Get key and modifiers
     key = event.key()
     mod = event.modifiers()
     # Possible modifiers:
     #  NoModifier
     #  ShiftModifier, ControlModifier, AltModifiier
     #  MetaModifier (i.e. super key)
     #  KeyPadModifier (button is part of keypad)
     #  GroupSwitchModifier (x11 thing)
     # Ignore the keypad modifier, we don't care!
     if mod & Qt.KeypadModifier:
         mod = mod ^ Qt.KeypadModifier  # xor!
     # Actions per key/modifier combination
     if key == Qt.Key_Tab and mod == Qt.NoModifier:
         # Indent
         cursor = self.textCursor()
         start, end = cursor.selectionStart(), cursor.selectionEnd()
         if cursor.hasSelection():
             # Add single tab to all lines in selection
             cursor.beginEditBlock()  # Undo grouping
             doc = self.document()
             b = doc.findBlock(start)
             e = doc.findBlock(end).next()
             while b != e:
                 cursor.setPosition(b.position())
                 cursor.insertText(TABS * SPACE)
                 b = b.next()
             cursor.endEditBlock()
         else:
             # Insert spaces until next tab stop
             pos = cursor.positionInBlock()
             cursor.insertText((TABS - pos % TABS) * SPACE)
     elif key == Qt.Key_Backtab and mod == Qt.ShiftModifier:
         # Dedent all lines in selection (or single line if no selection)
         '''
         cursor = self.textCursor()
         start, end = cursor.selectionStart(), cursor.selectionEnd()
         cursor.beginEditBlock() # Undo grouping
         doc = self.document()
         # Get blocks in selection
         blocks = []
         b = doc.findBlock(start)
         while b.isValid() and b.position() <= end:
             blocks.append(b)
             b = b.next()
         # Dedent
         for b in blocks:
             t = b.text()
             p1 = b.position()
             p2 = p1 + min(4, len(t) - len(t.lstrip()))
             c = self.textCursor()
             c.setPosition(p1)
             c.setPosition(p2, QtGui.QTextCursor.KeepAnchor)
             c.removeSelectedText()
         cursor.endEditBlock()
         '''
         # This silly method is required because of a bug in qt4/qt5
         cursor = self.textCursor()
         start, end = cursor.selectionStart(), cursor.selectionEnd()
         first = self.document().findBlock(start)
         q = 0
         new_text = []
         new_start, new_end = start, end
         b = QtGui.QTextBlock(first)
         while b.isValid() and b.position() <= end:
             t = b.text()
             p = min(4, len(t) - len(t.lstrip()))
             new_text.append(t[p:])
             if b == first:
                 new_start -= p
             new_end -= p
             q += p
             b = b.next()
         last = b.previous()
         new_start = max(new_start, first.position())
         new_end = max(new_end, new_start)
         if q > 0:
             # Cut text, replace with new
             cursor.beginEditBlock()
             cursor.setPosition(first.position())
             cursor.setPosition(last.position() + last.length() - 1,
                                QtGui.QTextCursor.KeepAnchor)
             cursor.removeSelectedText()
             cursor.insertText('\n'.join(new_text))
             cursor.endEditBlock()
             # Set new cursor
             cursor.setPosition(new_start)
             cursor.setPosition(new_end, QtGui.QTextCursor.KeepAnchor)
             self.setTextCursor(cursor)
     elif key == Qt.Key_Enter or key == Qt.Key_Return:
         # Enter/Return with modifier is overruled here to mean nothing
         # This is very important as the default for shift-enter is to
         # start a new line within the same block (this can't happen with
         # copy-pasting, so it's safe to just catch it here).
         if mod == Qt.NoModifier:
             # "Smart" enter:
             #   - If selection, selection is deleted
             #   - Else, autoindenting is performed
             cursor = self.textCursor()
             cursor.beginEditBlock()
             if cursor.hasSelection():
                 # Replace selection with newline,
                 cursor.removeSelectedText()
                 cursor.insertBlock()
             else:
                 # Insert new line with correct indenting
                 b = self.document().findBlock(cursor.position())
                 t = b.text()
                 i = t[:len(t) - len(t.lstrip())]
                 i = i[:cursor.positionInBlock()]
                 cursor.insertBlock()
                 cursor.insertText(i)
             cursor.endEditBlock()
             # Scroll if necessary
             self.ensureCursorVisible()
     elif key == Qt.Key_Home and (mod == Qt.NoModifier
                                  or mod == Qt.ShiftModifier):
         # Plain home button: move to start of line
         # If Control is used: Jump to start of document
         # Ordinary home button: Jump to first column or first
         # non-whitespace character
         cursor = self.textCursor()
         block = cursor.block()
         cp = cursor.position()
         bp = block.position()
         if cp != bp:
             # Jump to first column
             newpos = bp
             # Smart up/down:
             self._last_column = 0
         else:
             # Already at first column: Jump to first non-whitespace or
             # end of line if all whitespace
             t = block.text()
             indent = len(t) - len(t.lstrip())
             newpos = bp + indent
             # Smart up/down:
             self._last_column = indent
         # If Shift is used: only move position (keep anchor, i.e. select)
         anchor = (QtGui.QTextCursor.KeepAnchor if mod == Qt.ShiftModifier
                   else QtGui.QTextCursor.MoveAnchor)
         cursor.setPosition(newpos, anchor)
         self.setTextCursor(cursor)
     elif key == Qt.Key_Home and (mod == Qt.ControlModifier or mod
                                  == Qt.ControlModifier & Qt.ShiftModifier):
         # Move to start of document
         # If Shift is used: only move position (keep anchor, i.e. select)
         anchor = (QtGui.QTextCursor.KeepAnchor if mod == Qt.ShiftModifier
                   else QtGui.QTextCursor.MoveAnchor)
         cursor = self.textCursor()
         cursor.setPosition(0, anchor)
         self.setTextCursor(cursor)
     elif key in (Qt.Key_Up, Qt.Key_Down, Qt.Key_PageUp, Qt.Key_PageDown) \
             and (mod == Qt.NoModifier or mod == Qt.ShiftModifier):
         # Move cursor up/down
         # Maintain the column position, even when the current row doesn't
         # have as many characters. Reset this behavior as soon as a
         # left/right home/end action is made or whenever the text is
         # changed.
         # Set up operation
         anchor = (QtGui.QTextCursor.KeepAnchor if mod == Qt.ShiftModifier
                   else QtGui.QTextCursor.MoveAnchor)
         operation = \
             QtGui.QTextCursor.PreviousBlock if key in (
                 Qt.Key_Up, Qt.Key_PageUp) else QtGui.QTextCursor.NextBlock
         n = 1 if key in (Qt.Key_Up,
                          Qt.Key_Down) else (self._blocks_per_page - 3)
         # Move
         cursor = self.textCursor()
         if self._last_column is None:
             # Update "smart" column
             self._last_column = cursor.positionInBlock()
         if cursor.movePosition(operation, anchor, n):
             column = min(cursor.block().length() - 1, self._last_column)
             cursor.setPosition(cursor.position() + column, anchor)
         else:
             # Up/Down beyond document start/end? Move cursor to document
             # start/end and update last column
             if operation == QtGui.QTextCursor.NextBlock:
                 cursor.movePosition(QtGui.QTextCursor.EndOfBlock, anchor)
             else:
                 cursor.movePosition(QtGui.QTextCursor.StartOfBlock, anchor)
             self._last_column = cursor.positionInBlock()
         self.setTextCursor(cursor)
     elif key in (Qt.Key_Left, Qt.Key_Right,
                  Qt.Key_End) and not (mod & Qt.AltModifier):
         # Allow all modifiers except alt
         # Reset smart up/down behavior
         self._last_column = None
         # Pass to parent class
         super(Editor, self).keyPressEvent(event)
     elif key == Qt.Key_Insert and mod == Qt.NoModifier:
         # Insert/replace
         self.setOverwriteMode(not self.overwriteMode())
     else:
         # Default keyboard shortcuts / functions:
         # Backspace             OK
         # Delete                OK
         # Control+C             OK
         # Control+V             OK
         # Control+X             OK
         # Control+Insert        OK
         # Shift+Insert          OK
         # Shift+Delete          OK
         # Control+Z             OK
         # Control+Y             OK
         # LeftArrow             Overwritten (maintained)
         # RightArrow            Overwritten (maintained)
         # UpArrow               Overwritten (maintained)
         # DownArrow             Overwritten (maintained)
         # Control+RightArrow    OK (Jump to next word)
         # Control+LeftArrow     OK (Jump to previous word)
         # Control+UpArrow       Removed
         # Control+Down Arrow    Removed
         # PageUp                Overwritten (maintained)
         # PageDown              Overwritten (maintained)
         # Home                  Overwritten (maintained)
         # End                   Overwritten (maintained)
         # Control+Home          Overwritten (maintained)
         # Control+End           Overwritten (maintained)
         # Alt+Wheel             OK (Horizontal scrolling)
         # Control+Wheel         OK (Fast scrolling)
         # Control+K             Removed
         # Not listed, but very important:
         # Shift-Enter           Starts new line within the same block!
         #                       Definitely removed
         # Ctrl-i                Undocumented, but inserts tab...
         ctrl_ignore = (Qt.Key_K, Qt.Key_I)
         if mod == Qt.ControlModifier and key in ctrl_ignore:
             # Control-K: ignore
             pass
         elif key == Qt.Key_Up or key == Qt.Key_Down:
             # Up/down with modifiers: ignore
             pass
         else:
             # Let parent class handle it
             super(Editor, self).keyPressEvent(event)
    def __init__(self, document):
        super(ScriptHighlighter, self).__init__(document)

        # Highlighting rules
        self._rules = []

        # Numbers
        style = QtGui.QTextCharFormat()
        style.setForeground(QtGui.QColor(255, 0, 255))
        pattern = QtCore.QRegExp(r'\b[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?\b')
        self._rules.append((pattern, style))

        # True/False/None
        style = QtGui.QTextCharFormat()
        style.setForeground(QtGui.QColor(255, 0, 255))
        pattern = QtCore.QRegExp(r'\bTrue\b')
        self._rules.append((pattern, style))
        pattern = QtCore.QRegExp(r'\bFalse\b')
        self._rules.append((pattern, style))
        pattern = QtCore.QRegExp(r'\bNone\b')
        self._rules.append((pattern, style))

        # Built-in essential functions
        style = QtGui.QTextCharFormat()
        style.setForeground(QtGui.QColor(0, 128, 128))
        for func in _PYFUNC:
            pattern = QtCore.QRegExp(r'\b' + str(func) + r'\b')
            self._rules.append((pattern, style))

        # Keywords
        import keyword
        style = QtGui.QTextCharFormat()
        style.setForeground(QtGui.QColor(0, 96, 0))
        style.setFontWeight(QtGui.QFont.Bold)
        for kw in keyword.kwlist:
            pattern = QtCore.QRegExp(r'\b' + kw + r'\b')
            self._rules.append((pattern, style))

        # Strings
        self._string_style = QtGui.QTextCharFormat()
        self._string_style.setForeground(QtGui.QColor(255, 0, 255))
        pattern = QtCore.QRegExp(r'"([^"\\]|\\")*"')
        self._rules.append((pattern, self._string_style))
        pattern = QtCore.QRegExp(r"'([^'\\]|\\')*'")
        self._rules.append((pattern, self._string_style))

        # Multi-line strings
        self._string1 = QtCore.QRegExp(r"'''")
        self._string2 = QtCore.QRegExp(r'"""')

        # Comments
        style = QtGui.QTextCharFormat()
        style.setForeground(QtGui.QColor(20, 20, 255))
        pattern = QtCore.QRegExp(r'#[^\n]*')
        self._rules.append((pattern, style))
from __future__ import absolute_import, division
from __future__ import print_function, unicode_literals

import myokit
from myokit.gui import Qt, QtCore, QtGui, QtWidgets

# GUI components
# Constants
SPACE = ' '
TABS = 4
INDENT = SPACE * TABS
BRACKETS = {'(': ')', ')': '(', '[': ']', ']': '['}
BRACKETS_CLOSE = (')', ']')
FONT = myokit.gui.qtMonospaceFont()
FONT.setPointSize(11)
COLOR_CURRENT_LINE = QtGui.QColor(230, 230, 240)
COLOR_BG_LINE_NUMBER = QtGui.QColor(230, 230, 230)
COLOR_BG_BRACKET = QtGui.QColor(210, 210, 210)


# Classes & methods
class Editor(QtWidgets.QPlainTextEdit):
    """
    Source code editor used in Myokit.

    Provides the signal ``find_action(str)`` which is fired everything a find
    action occurred with a description that can be used in an application's
    status bar.
    """
    # Signal: Find action happened, update with text
    # Attributes: (description)
Ejemplo n.º 17
0
def _check_for_dark_mode(palette):
    """
    Checks the default editor background color, and adjusts the colour scheme
    if it looks like dark-mode is enabled.
    """
    c = palette.base().color()
    c = (c.blueF() + c.greenF() + c.redF()) / 3
    dark = c < 0.5

    # Don't mess with these directly: Use the SVG in myokit-docs
    if not dark:
        STYLE_HEADER.setForeground(QtGui.QColor(0, 31, 231))
        STYLE_COMMENT.setForeground(QtGui.QColor(103, 161, 107))
        STYLE_ANNOT_KEY.setForeground(QtGui.QColor(0, 31, 231))
        STYLE_ANNOT_VAL.setForeground(QtGui.QColor(57, 115, 214))
        STYLE_KEYWORD_1.setForeground(QtGui.QColor(0, 128, 0))
        STYLE_KEYWORD_1.setFontWeight(QtGui.QFont.Bold)
        STYLE_KEYWORD_2.setForeground(QtGui.QColor(0, 128, 128))
        STYLE_LITERAL.setForeground(QtGui.QColor(255, 20, 215))
        STYLE_INLINE_UNIT.setForeground(QtGui.QColor(128, 0, 128))
    else:
        STYLE_HEADER.setForeground(QtGui.QColor(98, 178, 255))
        STYLE_COMMENT.setForeground(QtGui.QColor(153, 153, 153))
        STYLE_ANNOT_KEY.setForeground(QtGui.QColor(179, 179, 179))
        STYLE_ANNOT_VAL.setForeground(QtGui.QColor(171, 177, 205))
        STYLE_KEYWORD_1.setForeground(QtGui.QColor(10, 195, 87))
        STYLE_KEYWORD_1.setFontWeight(QtGui.QFont.Bold)
        STYLE_KEYWORD_2.setForeground(QtGui.QColor(10, 195, 87))
        STYLE_LITERAL.setForeground(QtGui.QColor(255, 223, 12))
        STYLE_INLINE_UNIT.setForeground(QtGui.QColor(168, 152, 33))

        global COLOR_SELECTED_LINE
        COLOR_SELECTED_LINE = QtGui.QColor(70, 70, 70)
Ejemplo n.º 18
0
    def __init__(self, parent, title, var, func, args):
        super(VarGrapher, self).__init__(parent)
        self.setFixedSize(700, 600)
        self.setWindowTitle(title)

        # Figure panel
        self._figure = matplotlib.figure.Figure()
        self._canvas = backend.FigureCanvasQTAgg(self._figure)
        self._toolbar = backend.NavigationToolbar2QT(self._canvas, self)

        # Variable panel
        self._variable_widget = QtWidgets.QWidget()

        # Button panel
        self._button_widget = QtWidgets.QWidget()

        # Central widget
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self._canvas)
        layout.addWidget(self._toolbar)
        layout.addWidget(self._variable_widget)
        layout.addWidget(self._button_widget)
        self.setLayout(layout)

        # Get function handle, information object
        self._func = func
        self._args = args
        self._var = var

        # Variable ranges
        grid = QtWidgets.QGridLayout()
        self._bounds = {}
        for k, lhs in enumerate(self._args):
            var = lhs.var()
            # Guess appropriate bounds
            if var.label() == 'membrane_potential' or \
                    var.name().lower() in ['v', 'voltage', 'potential']:
                if var.unit() == myokit.units.volt:
                    lohi = (-0.1, 0.1)
                else:
                    lohi = (-100.0, 100.0)
            else:
                v = lhs.eval()
                if v >= 0 and v <= 1:
                    lohi = (0.0, 1.0)
                elif v < 0:
                    lohi = (-50, 50)
                else:
                    lohi = (0, 100)
            # Row and column of first widget in grid
            row = k // 2
            col = (k % 2) * 3
            # Add label
            label = QtWidgets.QLabel(var.qname())
            grid.addWidget(label, row, col)
            # Add lower and upper bound or single value
            if k < 2:
                # Lower
                editlo = QtWidgets.QLineEdit()
                editlo.setValidator(QtGui.QDoubleValidator())
                editlo.setText(str(lohi[0]))
                grid.addWidget(editlo, row, col + 1)
                # Upper
                edithi = QtWidgets.QLineEdit()
                edithi.setValidator(QtGui.QDoubleValidator())
                edithi.setText(str(lohi[1]))
                grid.addWidget(edithi, row, col + 2)
                self._bounds[lhs] = (editlo, edithi)
            else:
                # Single, fixed value
                v = 0.5 * (lohi[0] + lohi[1])
                edit = QtWidgets.QLineEdit(str(v))
                edit.setReadOnly(True)
                grid.addWidget(edit, row, col + 1)
                self._bounds[lhs] = (edit, edit)
        self._variable_widget.setLayout(grid)

        # Buttons
        layout = QtWidgets.QHBoxLayout()

        # Graph button
        button = QtWidgets.QPushButton('Refresh')
        button.clicked.connect(self.action_draw)
        layout.addWidget(button)

        # Close button
        button = QtWidgets.QPushButton('Close')
        button.clicked.connect(self.close)
        layout.addWidget(button)
        self._button_widget.setLayout(layout)

        # Draw!
        self.action_draw()
Ejemplo n.º 19
0
    def load_data_file(self, fname):
        """
        Attempts to load the given data block 2d file.
        """
        self._timer.stop()
        # Fix path
        fname = os.path.abspath(str(fname))
        self._path = os.path.dirname(fname)
        # Try loading file.
        self.statusBar().showMessage('Loading ' + str(fname))
        n = 1000000
        pd = QtWidgets.QProgressDialog('Loading data file...', 'Cancel', 0, n)
        pd.setWindowModality(Qt.WindowModal)
        pd.setValue(0)

        class Reporter(myokit.ProgressReporter):
            def __init__(self, pd):
                self._pd = pd

            def enter(self, msg=None):
                pass

            def exit(self):
                pass

            def update(self, f):
                self._pd.setValue((int)(n * f))
                return not self._pd.wasCanceled()

        reporter = Reporter(pd)
        try:
            data = myokit.DataBlock2d.load(fname, progress=reporter)
            del (reporter)
        except myokit.DataBlockReadError:
            pd.reset()
            self.statusBar().showMessage('Load failed.')
            QtWidgets.QMessageBox.warning(
                self, TITLE, '<h1>Unable to read file.</h1>'
                '<p>The given filename <code>' + str(fname) + '</code>'
                ' could not be read as a <code>myokit.DataBlock2d</code>.</p>')
            return
        except Exception as e:
            pd.reset()
            self.statusBar().showMessage('Load failed.')
            self.display_exception()
            return
        finally:
            if pd.wasCanceled():
                self.statusBar().showMessage('Load canceled.')
                return
        # Don't load empty files
        if data.len2d() < 1:
            self.statusBar().showMessage('Load failed: empty file.')
            QtWidgets.QMessageBox.warning(
                self, TITLE, '<h1>Unable to read file.</h1>'
                '<p>The given filename <code>' + str(fname) + '</code>'
                ' does not contain any 2d data.</p>')
            return
        # File loaded okay
        self.statusBar().showMessage('File loaded succesfully.')
        self._file = fname
        self._data = data
        self.update_window_title()
        # Update recent file list
        try:
            # Remove fname from recent files list
            i = self._recent_files.index(fname)
            self._recent_files = self._recent_files[:i] \
                + self._recent_files[i+1:]
        except ValueError:
            pass
        self._recent_files.insert(0, fname)
        self._recent_files = self._recent_files[:N_RECENT_FILES]
        self.update_recent_files_menu()
        # Update video scene
        nt, ny, nx = self._data.shape()
        self._colormap_size = max(int(0.05 * nx), 1)
        self._video_scene.clear()
        self._video_scene.resize(nx, ny, 2 * self._colormap_size)
        self._video_view.resizeEvent()
        self._video_iframe = 0
        # Add empty video item to video scene
        self._video_pixmap = QtGui.QPixmap(nx, ny)
        self._video_item = QtWidgets.QGraphicsPixmapItem(self._video_pixmap)
        self._video_scene.addItem(self._video_item)
        # Add empty colormap item to video scene
        self._colormap_pixmap = QtGui.QPixmap(self._colormap_size, ny)
        self._colormap_item = QtWidgets.QGraphicsPixmapItem(
            self._colormap_pixmap)
        self._colormap_item.setPos(nx + self._colormap_size, 0)
        self._video_scene.addItem(self._colormap_item)
        # Move slider to correct position
        self._slider.setMaximum(nt)
        self._slider.setPageStep(int(nt / 20))
        # Update controls
        for i in range(self._variable_select.count(), 0, -1):
            self._variable_select.removeItem(i - 1)
        variable = None
        for name in data.keys2d():
            self._variable_select.addItem(name)
            if variable is None or name in ('membrane.V', 'membrane.v'):
                variable = name
        self.action_set_variable(variable)
        self.action_set_colormap(self._colormap)
        # Update graph area
        self._graph_area.set_data(self._data)
Ejemplo n.º 20
0
 def __init__(self, filename=None):
     super(DataBlockViewer, self).__init__()
     # Set application icon
     self.setWindowIcon(icon())
     # Set size, center
     self.resize(800, 600)
     self.setMinimumSize(600, 400)
     qr = self.frameGeometry()
     cp = QtWidgets.QDesktopWidget().availableGeometry().center()
     qr.moveCenter(cp)
     self.move(qr.topLeft())
     # Status bar
     self._label_cursor = QtWidgets.QLabel()
     self.statusBar().addPermanentWidget(self._label_cursor)
     self.statusBar().showMessage('Ready')
     # Menu bar
     self.create_menu()
     # Timer
     self._timer_interval = 50
     self._timer = QtCore.QTimer(self)
     self._timer.setInterval(self._timer_interval)
     self._timer.setSingleShot(False)
     self._timer.timeout.connect(self.action_next_frame)
     self._timer_paused = False
     try:
         self._timer.setTimerType(Qt.PreciseTimer)
     except AttributeError:
         pass  # Qt4 uses precise timer by default
     # Video widget
     self._video_scene = VideoScene()
     self._video_scene.mouse_moved.connect(self.event_mouse_move)
     self._video_scene.single_click.connect(self.event_single_click)
     self._video_scene.double_click.connect(self.event_double_click)
     self._video_view = VideoView(self._video_scene)
     #self._video_view.setViewport(QtOpenGL.QGLWidget())
     self._video_pixmap = None
     self._video_item = None
     self._video_frames = None
     self._video_iframe = None
     self._colormap_pixmap = None
     self._colormap_item = None
     # Video slider
     self._slider = QtWidgets.QSlider(Qt.Horizontal)
     self._slider.setTickPosition(QtWidgets.QSlider.NoTicks)
     #self._slider.setTickPosition(QtWidgets.QSlider.TicksBothSides)
     self._slider.setSingleStep(1)
     self._slider.setMinimum(0)
     self._slider.setMaximum(0)
     self._slider.sliderPressed.connect(self.action_pause_timer)
     self._slider.sliderReleased.connect(self.action_depause_timer)
     self._slider.valueChanged.connect(self.action_set_frame)
     # Controls
     style = QtWidgets.QApplication.style()
     # Play button
     self._play_icon_play = style.standardIcon(style.SP_MediaPlay)
     self._play_icon_pause = style.standardIcon(style.SP_MediaPause)
     self._play_button = QtWidgets.QPushButton()
     self._play_button.setIcon(self._play_icon_play)
     self._play_button.pressed.connect(self.action_start_stop)
     # Frame indicator
     self._frame_label = QtWidgets.QLabel('Frame')
     self._frame_field = QtWidgets.QLineEdit('0')
     self._frame_field.setReadOnly(True)
     self._frame_field.setMaxLength(6)
     self._frame_field.setMaximumWidth(100)
     self._frame_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
     # Time indicator
     self._time_label = QtWidgets.QLabel('Time')
     self._time_field = QtWidgets.QLineEdit('0')
     self._time_field.setReadOnly(True)
     self._time_field.setMaxLength(6)
     self._time_field.setMaximumWidth(100)
     self._time_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
     # Speed indicator
     self._rate_label = QtWidgets.QLabel('Delay')
     self._rate_field = QtWidgets.QLineEdit(str(self._timer_interval))
     self._rate_field.setValidator(QtGui.QIntValidator(1, 2**20, self))
     self._rate_field.editingFinished.connect(self.event_rate_changed)
     self._rate_field.setMaximumWidth(100)
     self._rate_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
     # Graph controls
     self._graph_clear_button = QtWidgets.QPushButton('Clear graphs')
     self._graph_clear_button.pressed.connect(self.action_clear_graphs)
     # Variable selection
     self._variable_select = QtWidgets.QComboBox()
     self._variable_select.activated.connect(self.event_variable_selected)
     self._variable_select.setMinimumWidth(120)
     # Colormap selection
     self._colormap = myokit.ColorMap.names().next()
     self._colormap_select = QtWidgets.QComboBox()
     for cmap in myokit.ColorMap.names():
         self._colormap_select.addItem(cmap)
     self._colormap_select.activated.connect(self.event_colormap_selected)
     self._colormap_select.setMinimumWidth(120)
     # Control layout
     self._control_layout = QtWidgets.QHBoxLayout()
     self._control_layout.addWidget(self._play_button)
     self._control_layout.addWidget(self._frame_label)
     self._control_layout.addWidget(self._frame_field)
     self._control_layout.addWidget(self._time_label)
     self._control_layout.addWidget(self._time_field)
     self._control_layout.addWidget(self._rate_label)
     self._control_layout.addWidget(self._rate_field)
     self._control_layout.addWidget(self._graph_clear_button)
     self._control_layout.addWidget(self._variable_select)
     self._control_layout.addWidget(self._colormap_select)
     # Graph area
     self._graph_area = GraphArea()
     self._graph_area.mouse_moved.connect(self.event_mouse_move)
     # Video Layout
     self._video_layout = QtWidgets.QVBoxLayout()
     self._video_layout.addWidget(self._video_view)
     self._video_layout.addWidget(self._slider)
     self._video_layout.addLayout(self._control_layout)
     self._video_widget = QtWidgets.QWidget()
     self._video_widget.setLayout(self._video_layout)
     # Central layout
     self._central_widget = QtWidgets.QSplitter(Qt.Vertical)
     self._central_widget.addWidget(self._video_widget)
     self._central_widget.addWidget(self._graph_area)
     self.setCentralWidget(self._central_widget)
     # Current path, current file, recent files
     self._path = QtCore.QDir.currentPath()
     self._file = None
     self._recent_files = []
     # Current data block, display variable
     self._data = None
     self._variable = None
     # Load settings from ini file
     self.load_config()
     self.update_window_title()
     # Set controls to correct values
     self._colormap_select.setCurrentIndex(
         self._colormap_select.findText(self._colormap))
     self._rate_field.setText(str(self._timer_interval))
     self._timer.setInterval(self._timer_interval)
     # Pause video playback during resize
     self._resize_timer = QtCore.QTimer()
     self._resize_timer.timeout.connect(self._resize_timeout)
     self._video_view.resize_event.connect(self._resize_started)
     # Attempt to load selected file
     if filename and os.path.isfile(filename):
         self.load_data_file(filename)
Ejemplo n.º 21
0
 def __init__(self, parent, sim_method, output_stream, duration=1000):
     super(Explorer, self).__init__(parent)
     self.setWindowTitle('Myokit Explorer')
     self._sim_method = sim_method
     self._stream = output_stream
     # Set guess for run times
     guess_pre = 0
     guess_run = duration
     # Explorer data
     self._data = None
     self._keys = None
     # Fix background color of line edits
     self.setStyleSheet('QLineEdit{background: white;}')
     # Create top widgets
     label1 = QtWidgets.QLabel('Run unlogged for ')
     label2 = QtWidgets.QLabel(' and then log for ')
     self._pre_field = QtWidgets.QLineEdit(str(guess_pre))
     self._pre_valid = QtGui.QDoubleValidator()
     self._pre_valid.setBottom(0)
     self._pre_field.setValidator(self._pre_valid)
     self._run_field = QtWidgets.QLineEdit(str(guess_run))
     self._run_valid = QtGui.QDoubleValidator()
     self._run_valid.setBottom(0)
     self._run_field.setValidator(self._run_valid)
     self._clear_button = QtWidgets.QPushButton('Clear graphs')
     self._clear_button.clicked.connect(self.action_clear)
     self._run_button = QtWidgets.QPushButton('Run')
     self._run_button.clicked.connect(self.action_run)
     # Create graph widgets
     self._axes = None
     self._figure = matplotlib.figure.Figure()
     self._canvas = backend.FigureCanvasQTAgg(self._figure)
     self._toolbar = backend.NavigationToolbar2QT(self._canvas, self)
     self._select_x = QtWidgets.QComboBox()
     self._select_x.currentIndexChanged.connect(self.combo_changed)
     self._select_y = QtWidgets.QComboBox()
     self._select_y.currentIndexChanged.connect(self.combo_changed)
     # Create bottom widgets
     self._close_button = QtWidgets.QPushButton('Close')
     self._close_button.clicked.connect(self.action_close)
     # Create button layout
     button_layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.LeftToRight)
     button_layout.addWidget(label1)
     button_layout.addWidget(self._pre_field)
     button_layout.addWidget(label2)
     button_layout.addWidget(self._run_field)
     button_layout.addWidget(self._clear_button)
     button_layout.addWidget(self._run_button)
     # Create graph options layout
     graph_option_layout = QtWidgets.QBoxLayout(
         QtWidgets.QBoxLayout.LeftToRight)
     graph_option_layout.addWidget(self._select_x)
     graph_option_layout.addWidget(self._select_y)
     # Create bottom layout
     bottom_layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.LeftToRight)
     bottom_layout.addWidget(self._close_button)
     # Create central layout
     layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.TopToBottom)
     layout.addLayout(button_layout)
     layout.addLayout(graph_option_layout)
     layout.addWidget(self._canvas)
     layout.addWidget(self._toolbar)
     layout.addLayout(bottom_layout)
     self.setLayout(layout)
Ejemplo n.º 22
0
# Constants
SPACE = ' '
TABS = 4
INDENT = SPACE * TABS
BRACKETS = {
    '(': ')',
    ')': '(',
    '[': ']',
    ']': '['
}
BRACKETS_CLOSE = (')', ']')
FONT = myokit.gui.qtMonospaceFont()
FONT.setPointSize(11)

# Component and model headers
STYLE_HEADER = QtGui.QTextCharFormat()

# Comments
STYLE_COMMENT = QtGui.QTextCharFormat()

# Model annotations (including meta, labels, and units)
STYLE_ANNOT_KEY = QtGui.QTextCharFormat()
STYLE_ANNOT_VAL = QtGui.QTextCharFormat()

# Language keywords
STYLE_KEYWORD_1 = QtGui.QTextCharFormat()
STYLE_KEYWORD_2 = QtGui.QTextCharFormat()

# Literals: Numbers in model/protocol, Also booleans and strings in script
STYLE_LITERAL = QtGui.QTextCharFormat()
STYLE_INLINE_UNIT = QtGui.QTextCharFormat()