Exemple #1
0
    def startDrag(self):
        """ this method is called whenever a user start to drag one of the label """

        #D( ALL, "dragging started..." )
        v = self._view
        lp = v.painter()
        fm = lp.fontmetrics()
        idx, _ = v.xy2coord( 0, self._startpos.y() )
        self._dragidx = idx
        label = self.model()[idx].label
        lineheight = v.lineheight()
        baseline = (lineheight + fm.ascent())/2
        width = fm.width(label)
        hotspot = QtCore.QPoint( width/2, lineheight/2 )
        drag = QtGui.QDrag(v)

        pixmap = QtGui.QPixmap(width, lineheight)
        p = QtGui.QPainter(pixmap)
        p.fillRect(pixmap.rect(), QtGui.QColor(191, 191, 127))
        p.setPen( QtCore.Qt.white )
        p.setFont( lp.font() )
        p.drawText(0, baseline, label)
        p.end()
        
        # fill in the data
        seq = self.model()[idx]
        mimedata = QtCore.QMimeData()
        text_data = ">%s\n%s\n" % (seq.label, seq.seq)
        mimedata.setText( text_data )
        mimedata.setData("application/x-fasta", text_data.encode('UTF-8'))

        drag.setMimeData(mimedata)
        drag.setPixmap(pixmap)
        drag.setHotSpot(hotspot)
        drag.exec_(QtCore.Qt.CopyAction)
Exemple #2
0
    def box(self, view):
        if self._box:
            return self._box

        left, _ = self.model().boundaries(self._startpos)
        _, right = self.model().boundaries(self._endpos)

        self._box = QtCore.QRect(left, 0, right - left,
                                 view._scrollarea.height())
        return self._box
Exemple #3
0
    def box(self):
        if self._box:
            return self._box

        curpos = self.curpos()
        if curpos < 0:
            return None

        left, right = self._view.model().boundaries(curpos)

        self._box = QtCore.QRect( left, 0, right - left, self._view._scrollarea.height() )
        return self._box
Exemple #4
0
 def box(self, view, margin=0):
     if not self._end:
         return None
     idx1, pos1 = self._begin
     idx2, pos2 = self._end
     start_corner = (min(idx1, idx2), min(pos1, pos2))
     end_corner = (max(idx1, idx2), max(pos1, pos2))
     lineheight = view.lineheight()
     charwidth = view.charwidth()
     x1 = start_corner[1] * charwidth
     y1 = start_corner[0] * lineheight
     x2 = (end_corner[1] + 1) * charwidth
     y2 = (end_corner[0] + 1) * lineheight
     return QtCore.QRect(x1, y1, x2 - x1, y2 - y1)
Exemple #5
0
class tracemodel_signals(QtCore.QObject):
    def __init__(self, parent):
        super(tracemodel_signals, self).__init__()
        self._parent = parent

    updateRange = QtCore.pyqtSignal(int, int)
    cursorMoved = QtCore.pyqtSignal(int)
    UpdatePosition = QtCore.pyqtSignal(int, int)
    TraceUpdated = QtCore.pyqtSignal(int, int)
    RegionUpdated = QtCore.pyqtSignal(object)
    ScaleChanged = QtCore.pyqtSignal()
Exemple #6
0
class IVerticalScrollBar(QtWidgets.QScrollBar):
    def __init__(self, pane, idx):
        super(IVerticalScrollBar, self).__init__(QtCore.Qt.Vertical)
        self._idx = idx
        self.setMinimumHeight(50)
        self._pane = pane
        self.valueChanged.connect(self.value_changed)

    def resizeEvent(self, ev):
        height = self._pane.height_hint()
        pagestep = self.height()
        if self.pageStep() != pagestep:
            self.setPageStep(pagestep)
        max_height = max(0, height - pagestep)
        if self.maximum() != max_height:
            self.setMaximum(max_height)

    def slideEvent(self, delta):
        """ when this vbar needed to be slide for a particular value """
        self.setValue(self.value() + delta)

    # cascading signal

    def value_changed(self, val):
        #self.emit( sig.VScrollSplitter, val, self._idx )
        self.VScrollSplitter.emit(val, self._idx)

    def wheelEvent(self, ev):
        offset = ev.angleDelta().y() / 5
        self.setValue(self.value() - offset)
        ev.accept()

    def widget(self):
        return self

    def setMaximum(self, val):
        super(IVerticalScrollBar, self).setMaximum(val)

    ##
    ## SIGNALS

    # this signal is emitted when the value of a particular vbar at index idx changes its value
    # signature: new_value, index
    VScrollSplitter = QtCore.pyqtSignal(int, int)
Exemple #7
0
 def sizeHint(self):
     return QtCore.QSize(600, 150)
Exemple #8
0
class qt_msasignals(QtCore.QObject):

    def __init__(self):
        super(qt_msasignals, self).__init__()


    RegionUpdated = QtCore.pyqtSignal( object )
    # coordinate region update; signature ( QRect )

    BlockSelectionUpdated = QtCore.pyqtSignal( object, object )
    # block selection update; signature ( (idx1, pos1), (idx2, pos2) )

    ColumnSelectionUpdated = QtCore.pyqtSignal( object )
    # column selection update; signature( [col1, col2, ...] )

    LabelSelectionUpdated = QtCore.pyqtSignal( object )


    SelectionUpdated = QtCore.pyqtSignal()
    # general selection being updated

    SelectionReset = QtCore.pyqtSignal()
    # general selection being reset

    SequenceUpdated = QtCore.pyqtSignal( int, int )
    # sequence update; signature: idx, pos

    ContentUpdated = QtCore.pyqtSignal()
    # whole content updated
    
    CaretMoved = QtCore.pyqtSignal(int, int, object)
    # caret movement

    CaretStopped = QtCore.pyqtSignal(object)
    # caret hidden


    SequenceTypeChanged = QtCore.pyqtSignal(object)
Exemple #9
0
class BaseFrame(QtWidgets.QFrame):
    """ BaseFrame

        This class holds single main pane (usually LabelPane), multiple other panes
        (mostly SequencePane), and single vertical scrollbar pane within single horizontal
        splitter.
        
        Main pane, where model is kept, is the vscrollbarpane 8-). Obviously,
        the only thing that will relatively remain the same for the whole evolution of thi
        software.

        Each pane can hold its own model so that it would be possible for different pane
        to have different model, e.g. a TranslatedSequencePane to have a translatedmodel.

    """
    def __init__(self, env, parent=None):
        super(BaseFrame, self).__init__(parent)

        self._env = env
        self._vsplit = self.env().split()
        self._panes = []
        self._vscrollbarpane = None
        self._layout = None
        self._splitter = ISplitter(QtCore.Qt.Horizontal)
        self._block_resize_event = False

        self.EnvironmentChanged.connect(self.update_environment)

    def mainpane(self):
        return self._vscrollbarpane

    def menupane(self):
        return self._panes[0]

    def model(self):
        return self.mainpane().model()

    def set_env(self, env):
        self._env = env

    def env(self):
        if not self._env:
            raise RuntimeError("env has not been set!")
        return self._env

    def lineheight(self):
        return self.env().lineheight()

    def set_lineheight(self, height):
        self.env().set_lineheight(height)

    def vsplit(self):
        return self._vsplit

    def set_vsplit(self, n):
        #print "set split"
        self._vsplit = n
        for p in self._panes:
            p.set_split(n)
        if self._vscrollbarpane:
            self._vscrollbarpane.set_split(n)

    def insert_pane(self, pane, idx=-1):
        if pane.env() is None:
            # if no env has been set up for the pane, get from this frame
            pane.set_env(self.env())
        pane.set_mainframe(self)
        pane.set_split(self.vsplit())
        if idx == -1:
            self._panes.append(pane)
            self._splitter.addWidget(pane)
        else:
            raise NotImplemented(
                'inserting pane at arbitrary position is not supported yet')

        if self._vscrollbarpane:
            # connect all signal/slot to VScrollbarPane
            self._vscrollbarpane.connect_pane(pane)

        # connect the rest of signal/slot
        pane.ActiveViewChanged.connect(self.set_activeview)

    def init_layout(self):
        self._layout = QtWidgets.QHBoxLayout()
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self._layout.addWidget(self._splitter, 1)
        if self._vscrollbarpane:
            self._layout.addWidget(self._vscrollbarpane, 0)
        self.setLayout(self._layout)

    def init_vscrollbarpane(self, pane):
        self._vscrollbarpane = pane
        self._vscrollbarpane.set_split(self.vsplit())

    # slots

    def set_activeview(self, view):
        self.parent().set_activepane(view.pane())

    def update_environment(self):
        for p in self._panes:
            p.update_environment()

    ##
    ## SIGNALS
    ## These signals will be propagated within this frame
    ##

    # EnvironmentChanged is emitted when changes occured in any of environment setting,
    # such as font resize etc; the object is the environment
    EnvironmentChanged = QtCore.pyqtSignal()
Exemple #10
0
    def draw_single_trace(self, minTp, maxTp, data, pen, p, scaleX, scaleY):

        p.setPen( pen )
        points = [ QtCore.QPoint( x * scaleX, data[x] * scaleY)
                        for x in range(max(0, minTp - 5), min(maxTp+5, len(data))) ]
        p.drawPolyline( QtGui.QPolygon(points) )
Exemple #11
0
 def update_tracepoint(self, start, end):
     """ start & end is position, not tracepoint """
     l, _ = self.model().boundaries(start)
     _, r = self.model().boundaries(end)
     self.update_content( QtCore.QRect( l, 0, r-l, self._splitter.widget(0).height()) )
Exemple #12
0
 def sizeHint(self):
     return QtCore.QSize(0, self._pane.footer_height())
Exemple #13
0
 def sizeHint(self):
     return QtCore.QSize(100, 100)
Exemple #14
0
 def sizeHint(self):
     """ provides hint for widget size, usually caled during resizeEvent """
     # ask this container pane for calculating width & height of data
     return QtCore.QSize(self.pane().width_hint(),
                         self.pane().height_hint())
Exemple #15
0
class BasePane(QtWidgets.QFrame):
    """ BasePane

        This class holds model, individual env, horizontal splitter, pane-sensitive
        statusbar and menubar

        Layout:
        _layout ->  header
                    splitter (n)
                    footer

    """

    have_hscrollbar = True
    splitter_class = ISplitter
    #_MenuBar_ = None
    _ToolBar_ = None
    _StatusBar_ = None
    _PaneActions_ = None

    def __init__(self, model, view_class=None, parent=None):
        super(BasePane, self).__init__(parent)
        #self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)

        self._model = model
        self._env = None
        self._painter = None  # class responsible for actual painting/drawing
        self._hscrollbar = None  # horizontal scroll bar
        self._actions = None  # pane-sensitive actions
        self._menubar = None  # pane-sensitive menubar
        self._statusbar = None  # pane-sensitive statusbar
        self._toolbar = None  # pane-sensitive toolbar
        self._layout = None
        self._header = None
        self._footer = None

        self._view_class = view_class
        self._mainframe = None

        self._splitter = self.splitter_class(QtCore.Qt.Vertical)

        if self._PaneActions_:
            self.set_custom_actions(self._PaneActions_(self))

        #    if self._MenuBar_:
        #        self._menubar = self._MenuBar_( self )
        #    if self._ToolBar_:
        #        self._toolbar = self._ToolBar_( self )

        if self._StatusBar_:
            self.set_statusbar(self._StatusBar_(self))

    def model(self):
        return self._model

    def env(self):
        assert self._env
        return self._env

    def custom_actions(self):
        return self._actions

    def set_custom_actions(self, actions):
        self._actions = actions

    def set_env(self, env):
        self._env = env

    def layout(self):
        assert self._layout
        return self._layout

    def mainframe(self):
        return self._mainframe

    def set_mainframe(self, mainframe):
        self._mainframe = mainframe

    def menubar(self):
        return self._MenuBar_(self)

    def set_menubar(self, menubar):
        self._menubar = menubar

    def statusbar(self):
        return self._statusbar

    def set_statusbar(self, statusbar):
        self._statusbar = statusbar

    def toolbar(self):
        return self._toolbar

    def set_toolbar(self, toolbar):
        self._toolbar = toolbar

    def painter(self):
        return self._painter

    def set_painter(self, painter=None):
        self._painter = painter

    def add_mainwidget(self, w):
        self._splitter.addWidget(w)

    def lineheight(self):
        return self.env().lineheight()

    def charwidth(self):
        return self.env().charwidth()

    def hscrollbar(self):
        return self._hscrollbar

    def split(self):
        return self._splitter.count()

    def init_hscrollbar(self):
        """ this function initialize horizontal scrollbar, further setting up of
            the scrollbar will be performed during resizeEvent by width_hint()
        """
        if self.have_hscrollbar:
            self._hscrollbar = QtWidgets.QScrollBar(QtCore.Qt.Horizontal)
            self._layout.addWidget(self._hscrollbar)
        else:
            self._layout.addSpacing(
                QtWidgets.QScrollBar(QtCore.Qt.Horizontal).sizeHint().height())

    def init_layout(self, header=None, footer=None):
        """ initialize the layout; this function needs to be called before everything else
        """
        self._layout = QtWidgets.QVBoxLayout()
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self._layout.addWidget(self._splitter, 1)
        self.setLayout(self._layout)

        self.init_hscrollbar()
        if header:
            self.set_header(header)
        if footer:
            self.set_footer(footer)
        self.init_signals()
        self.set_painter()

        # split is set to 1, but will be adjusted when this pane is inserted to frame
        self.set_split(1)

    def init_signals(self):
        """ connect all necessary signals """
        if self._hscrollbar:
            #self._hscrollbar.actionTriggered.connect( self.action_triggered )
            self._hscrollbar.valueChanged.connect(self.hslide)
        self._splitter.splitterMoved.connect(self.splitter_moved)

    def header(self):
        return self._header

    def set_header(self, header):
        if self._header is not None:
            self._layout.deleteWidget(0)
            del self._header

        self._header = header
        scrollarea = header.widget()
        scrollarea.setFixedHeight(header.sizeHint().height())
        self._layout.insertWidget(0, scrollarea, 0)

    def footer(self):
        return self._footer

    def set_footer(self, footer):
        if self._footer is not None:
            self._layout.deleteWidget(2)
            del self._footer

        self._footer = footer
        scrollarea = footer.widget()
        scrollarea.setFixedHeight(footer.sizeHint().height())
        self._layout.insertWidget(2, scrollarea, 0)

    def set_split(self, n):
        count = self._splitter.count()
        if n > count:
            for i in range(count, n):
                # create the view instance, and add its widget (scrollarea) to splitter
                # as well as the index
                c = self._view_class(self, i)
                w = c.widget()
                self._splitter.addWidget(w)
        elif n < count:
            for i in range(count - 1, n - 1, -1):
                w = self._splitter.widget(i)
                w.hide()
                w.setParent(None)
                w.destroy()
                del w

    # SLOTS

    def action_triggered(self, action):
        pass

    def hslide(self, hval):
        """ Slide all views in this pane manually by setting their respective
            horizontalScrollBar. This function is not meant to be called directly, only
            pane's viewable horizontal bar should call this function.
        """

        for i in range(0, self._layout.count() - 1):
            w = self._layout.itemAt(i).widget()
            if w == self._splitter:
                for j in range(0, self._splitter.count()):
                    self._splitter.widget(j).horizontalScrollBar().setValue(
                        hval)
            else:
                w.horizontalScrollBar().setValue(hval)

    def move_content_splitter(self, pos, idx, pane):
        """ only move our content splitter at particular idx to pos when we are not the
            sender, ie. not the one receiving focus/mouse movement
        """
        # XXX: refactor by using self.sender, eg: if self.sender() == self:
        if pane != self:
            self._splitter.blockSignals(True)
            self._splitter.moveSplitter(pos, idx)
            self._splitter.blockSignals(False)

    def splitter_moved(self, pos, idx):
        self.ContentSplitterMoved.emit(pos, idx, self)

    def update_view(self):
        for i in range(0, self._splitter.count()):
            w = self._splitter.widget(i)
            w.widget().update()
        if self.header(): self.header().update()
        if self.footer(): self.footer().update()

    def update_content(self, rect):
        if rect:
            #print rect.size()
            for i in range(0, self._splitter.count()):
                #print self._splitter.widget(i).widget()
                self._splitter.widget(i).widget().update(rect)

    def update_scale(self):
        for i in range(0, self._splitter.count()):
            self._splitter.widget(i).widget().update_scale()

    def vscroll_splitter(self, val, idx):
        """ vertically scroll a particular view within splitter;
            idx -> view index, val -> new value
        """
        self._splitter.widget(idx).verticalScrollBar().setValue(val)

    def focus_pane(self):
        self._splitter.widget(0).widget().setFocus()

    def setFocus(self, reason=None):
        if reason:
            super(BasePane, self).setFocus(reason)
        else:
            super(BasePane, self).setFocus()
        self.ActiveViewChanged.emit(self._splitter.widget(0).widget())

    def update_environment(self):
        self.set_painter()

    # HELPERS

    def width_hint(self):
        """ this function is mostly called by view's sizeHint when view is triggered
            with resizeEvent, must be implemented by deriving class
        """
        raise NotImplemented(
            'width_hint() must be provided by class derived from BasePane')

    def length_hint(self):
        raise NotImplemented('use width_hint() instead of length_hint()')

    def height_hint(self):
        """ calculate the height for displaying all data in view; warning: this function
            seems to be called excessively, probably need to provide a caching-based solution
        """
        return (len(self._model) + 2) * self.lineheight()

    def header_height(self):
        """ this function gets the synchronized height of all headers in all panes """
        # XXX: for now, just return a number
        return 30

    ##
    ## SIGNALS
    ## These signals will be propagated within this pane
    ##

    # vscrollsplitter is emitted when vertical scroll bar in VScrollbarPane is moved
    # signature: ?
    VScrollSplitter = QtCore.pyqtSignal(int, int)

    # ContentWheelEvent is emitted when mouse wheel event occured in this pane
    # signature: ?
    ContentWheelEvent = QtCore.pyqtSignal(object, int)

    # ContentSlideEvent is emitted when a view needs to be vertically scrolled
    # signature: delta_slide, splitter_index
    ContentSlideEvent = QtCore.pyqtSignal(int, int)

    # ContentSplitterMoved is emitted when a splitter with idx is moved
    # signature: pos, splitter_idx, sender_pane
    ContentSplitterMoved = QtCore.pyqtSignal(int, int, object)

    # ActiveViewChanged is emitted when a particular view gets a focus
    ActiveViewChanged = QtCore.pyqtSignal(object)

    # CursorMoved is emitted when caret / cursor is moved
    # signature: idx, pos
    CursorMoved = QtCore.pyqtSignal(int, int)
    HorizontalCursorMoved = QtCore.pyqtSignal(int)
    VerticalCursorMoved = QtCore.pyqtSignal(int)

    # update screen of view
    ContentUpdated = QtCore.pyqtSignal(object)

    @classmethod
    def set_menuclass(cls, impl):
        cls._MenuBar_ = impl

    @classmethod
    def set_statusbarclass(cls, impl):
        cls._StatusBar_ = impl

    @classmethod
    def set_paneactionclass(cls, impl):
        cls._PaneActions_ = impl
Exemple #16
0
 def sizeHint(self):
     #D(ALL, "ruler height: %d" % self.pane().header_height())
     return QtCore.QSize(self.pane().width_hint(),
                         self.pane().header_height())
Exemple #17
0
 def sizeHint(self):
     return QtCore.QSize(800, 600)