Home | History | Annotate | Download | only in JetCreator
      1 """
      2  File:  
      3  JetSegGraph.py
      4  
      5  Contents and purpose:
      6  Draws the event graph and progress bar
      7  
      8  Copyright (c) 2008 Android Open Source Project
      9  
     10  Licensed under the Apache License, Version 2.0 (the "License");
     11  you may not use this file except in compliance with the License.
     12  You may obtain a copy of the License at
     13  
     14       http://www.apache.org/licenses/LICENSE-2.0
     15  
     16  Unless required by applicable law or agreed to in writing, software
     17  distributed under the License is distributed on an "AS IS" BASIS,
     18  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     19  See the License for the specific language governing permissions and
     20  limitations under the License.
     21 """
     22 
     23 
     24 import  wx
     25 import logging
     26 
     27 from JetUtils import *
     28 from JetDefs import *
     29 
     30 GRAPH_COLORS = [
     31                 '#C0E272',
     32                 '#85CF89',
     33                 '#CF9683',
     34                 '#749EDE',
     35                 '#9FB5B1',
     36                 '#B095BF',
     37                 '#FE546D',
     38                 '#B3BB97',
     39                 '#FFFFB8',
     40                 
     41                 ]
     42 
     43 PROGRESS_BAR = '#0000CC'
     44 EOS_BAR = '#095000'
     45 APP_BAR = '#B3BB97'
     46 
     47                     
     48 class Marker():
     49     """ Defines portions of the graph for events """
     50     def __init__(self, sEventType, iEventId, sName, sStartMbt, sEndMbt, iStartMeasure, ppqn):
     51         self.sEventType = sEventType
     52         self.iEventId = iEventId
     53         self.sName = sName
     54         self.StartMbt = ConvertStrTimeToTuple(sStartMbt)
     55         self.EndMbt = ConvertStrTimeToTuple(sEndMbt)
     56         self.iStartMeasure = iStartMeasure
     57         self.iStart = 0
     58         self.iEnd = 0
     59         self.iWidth = 0
     60         self.iHeight = 0
     61         self.iTop = 0
     62         self.iUpdate = False  
     63         self.sColor = '#FFFFB8'  
     64         self.ppqn = ppqn
     65         self.isDirty = False
     66                 
     67     def CalcCoord(self, step, height, ColorFct):
     68         """ Calculates the coordinates in pixels for graphing the shaded regions """
     69         #measures

     70         iStartM = self.StartMbt[0] - self.iStartMeasure
     71         iEndM = self.EndMbt[0] - self.iStartMeasure
     72         self.iStart = step * iStartM
     73         self.iEnd = step * iEndM
     74         #beats

     75         self.iStart = self.iStart + ((step / 4.0) * (self.StartMbt[1]-1))
     76         self.iEnd = self.iEnd + ((step / 4.0) * (self.EndMbt[1]-1))
     77         #ticks

     78         pctTickOfBeat = (float(self.StartMbt[2]) / float(self.ppqn))
     79         self.iStart = self.iStart + ((pctTickOfBeat * (step / 4.0)))
     80         pctTickOfBeat = (float(self.EndMbt[2]) / float(self.ppqn))
     81         self.iEnd = self.iEnd + ((pctTickOfBeat * (step / 4.0)))
     82         
     83         self.iWidth = self.iEnd - self.iStart
     84         
     85         self.iHeight = height
     86         self.sColor = ColorFct()
     87         self.iUpdate = False  
     88 
     89 class SegmentGraph(wx.Panel):
     90     """ Draws the player graph bar """
     91     def __init__(self, parent, pos=wx.DefaultPosition, size=wx.DefaultSize, ClickCallbackFct=None, showLabels=True, showClips=True, showAppEvts=True):
     92         wx.Panel.__init__(self, parent, -1, pos=pos, size=size, style=wx.BORDER_STATIC)
     93         self.iLocationInMs = 0
     94         self.iLengthInMs = 0
     95         self.iLengthInMeasures = 0
     96         self.iMarkerTop = 15
     97         self.iScaleTop = 0
     98         self.iEdges = 5
     99         self.iStartMeasure = 0
    100         self.iMidiMode = False
    101         self.ClickCallbackFct = ClickCallbackFct
    102         self.iColor = 0
    103         self.showLabels = showLabels
    104         self.showClips = showClips
    105         self.showAppEvts = showAppEvts
    106         
    107         self.font = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, 'Courier')
    108 
    109         self.Markers = []
    110         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
    111         self.Bind(wx.EVT_PAINT, self.OnPaint)
    112         self.Bind(wx.EVT_SIZE, self.OnSize)
    113         self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
    114 
    115         #initialize buffer

    116         self.OnSize(None)
    117         
    118     def ClearGraph(self):
    119         """ Clears the graph values """
    120         self.iLocationInMs = 0
    121         self.iLengthInMs = 0
    122         self.iLengthInMeasures = 0
    123         self.iMarkerTop = 15
    124         self.iScaleTop = 0
    125         self.iEdges = 5
    126         self.iStartMeasure = 0
    127         self.iMidiMode = False
    128         self.iColor = 0        
    129         self.Markers = []
    130         self.iLocationInMs = 0
    131         self.DoDrawing()
    132         
    133     def LoadSegment(self, segment, segMarker=None, iMidiMode=False, showLabels=True, showClips=True, showAppEvts=True):
    134         """ Loads up the segment drawing the graph """
    135         if segment is None:
    136             self.ClearGraph()
    137             return None
    138         self.iMidiMode = iMidiMode
    139         self.showLabels = showLabels
    140         self.showClips = showClips
    141         self.showAppEvts = showAppEvts
    142         self.Markers = []
    143         self.iLocationInMs = 0
    144         info = MidiSegInfo(segment)        
    145         #disable graph for debugging

    146         #return info               

    147         self.iLengthInMs = info.iLengthInMs
    148         self.ppqn = info.ppqn
    149         self.StartMbt = mbtFct(ConvertStrTimeToTuple(segment.start), 1)
    150         self.EndMbt = mbtFct(ConvertStrTimeToTuple(segment.end), 1)
    151         self.LengthMbt = None
    152         self.iStartMeasure = self.StartMbt[0]
    153         self.iLengthInMeasures = self.EndMbt[0] - self.StartMbt[0]
    154         
    155         for jet_event in segment.jetevents:
    156             if self.showClips and jet_event.event_type == JetDefs.E_CLIP:
    157                 self.AddMarker(JetDefs.E_CLIP, jet_event.event_id, jet_event.event_name, mbtFct(jet_event.event_start,1), mbtFct(jet_event.event_end,1), self.iStartMeasure, self.ppqn)
    158             elif jet_event.event_type == JetDefs.E_EOS:
    159                 self.AddMarker(JetDefs.E_EOS, jet_event.event_id, jet_event.event_name, mbtFct(jet_event.event_end,1), mbtFct(jet_event.event_end,1), self.iStartMeasure, self.ppqn)
    160             elif self.showAppEvts and jet_event.event_type == JetDefs.E_APP:
    161                 self.AddMarker(JetDefs.E_APP, jet_event.event_id, jet_event.event_name, mbtFct(jet_event.event_start,1), mbtFct(jet_event.event_end,1), self.iStartMeasure, self.ppqn)
    162         
    163         if segMarker is not None:
    164             self.AddMarker(JetDefs.E_CLIP, 0, segMarker[0], mbtFct(segMarker[1],1), mbtFct(segMarker[2],1), self.iStartMeasure, self.ppqn)
    165             
    166         self.DoDrawing()
    167         return info
    168 
    169     def AddMarker(self, sEventType, iEventId, sName, sStartMbt, sEndMbt, iStartMeasure, ppqn):
    170         """ Adds a marker to the list """
    171         if not CompareMbt(sStartMbt, sEndMbt):
    172             sEndMbt = sStartMbt
    173         self.Markers.append(Marker(sEventType, iEventId, sName, sStartMbt, sEndMbt, iStartMeasure, ppqn))
    174         
    175     def OnLeftDown(self, event):
    176         """ Calls the function assicated with an event """
    177         pt = event.GetPosition()
    178         for Marker in self.Markers:
    179             if pt[0] >= Marker.iStart and pt[0] <= Marker.iEnd and pt[1] >= Marker.iTop and pt[1] <= Marker.iTop + Marker.iHeight:
    180                 if self.ClickCallbackFct != None:
    181                     self.ClickCallbackFct(Marker.sName, Marker.iEventId)
    182                
    183     def GetAColor(self):
    184         """ Gets a color """
    185         color = GRAPH_COLORS[self.iColor]
    186         self.iColor = self.iColor + 1
    187         if self.iColor >= len(GRAPH_COLORS):
    188             self.iColor = 0
    189         return color
    190     
    191     def OnSize(self, event=None):
    192         """ Repaints for resizing of screen """
    193         if OsWindows():
    194             # The Buffer init is done here, to make sure the buffer is always

    195             # the same size as the Window

    196             Size  = self.GetClientSizeTuple()
    197     
    198             # Make new offscreen bitmap: this bitmap will always have the

    199             # current drawing in it, so it can be used to save the image to

    200             # a file, or whatever.

    201             self._Buffer = wx.EmptyBitmap(*Size)
    202         self.DoDrawing(None)
    203         if event is not None:
    204             event.Skip()
    205         
    206     def OnPaint(self, event=None):
    207         """ Painting of windows """
    208         if OsWindows():
    209             dc = wx.BufferedPaintDC(self, self._Buffer)
    210         else:
    211             dc = wx.AutoBufferedPaintDC(self)
    212             dc.Background = wx.Brush(wx.WHITE)
    213         self.DoDrawing(dc)
    214 
    215     def DoDrawing(self, dc=None):
    216         """ Does the actual drawing of the control """
    217         if dc is None:
    218             if OsWindows():
    219                 dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
    220             else:
    221                 dc = wx.AutoBufferedPaintDC(self)
    222                 dc.Background = wx.Brush(wx.WHITE)
    223                 
    224         dc.Clear()
    225         
    226         self.iColor = 0
    227         gWidth, gHeight = self.GetSize()
    228         gWidth = gWidth - (self.iEdges * 2)
    229         step = int(gWidth / (self.iLengthInMeasures + .01))
    230         
    231         for Marker in self.Markers:
    232             Marker.CalcCoord(step, gHeight, self.GetAColor)
    233 
    234         """ eliminate overlaps; establish colors """
    235         iClips = 0
    236         iMarkers = 0
    237         for index, Marker in enumerate(self.Markers):
    238             if Marker.sEventType == JetDefs.E_CLIP:
    239                 iClips = iClips + 1
    240                 iOverlaps = 1
    241                 for index1, Marker1 in enumerate(self.Markers):
    242                     if Marker.sEventType == JetDefs.E_CLIP:
    243                         if index != index1 and not Marker1.iUpdate:
    244                             if Marker.iStart <= Marker1.iStart and Marker.iEnd <= Marker1.iEnd and Marker.iEnd >= Marker1.iStart:
    245                                 iOverlaps = iOverlaps + 1
    246                                 Marker.iUpdate = True
    247                                 Marker1.iUpdate = True
    248                             if not Marker.iUpdate and Marker.iStart >= Marker1.iStart and Marker.iEnd >= Marker1.iEnd and Marker.iStart <= Marker1.iEnd:
    249                                 iOverlaps = iOverlaps + 1
    250                                 Marker.iUpdate = True
    251                                 Marker1.iUpdate = True
    252                 if iOverlaps > 1:
    253                     iTop = 0
    254                     for index1, Marker1 in enumerate(self.Markers):
    255                         if Marker.sEventType == JetDefs.E_CLIP:
    256                             if Marker1.iUpdate:
    257                                 Marker1.iHeight = gHeight / iOverlaps
    258                                 Marker1.iTop = iTop * Marker1.iHeight
    259                                 iTop = iTop + 1
    260             elif Marker.sEventType == JetDefs.E_APP:
    261                 iMarkers = iMarkers + 1
    262 
    263         for Marker in self.Markers:
    264             if Marker.sEventType == JetDefs.E_CLIP:
    265                 dc.SetPen(wx.Pen(Marker.sColor))
    266                 dc.SetBrush(wx.Brush(Marker.sColor))
    267                 dc.DrawRectangle(Marker.iStart + self.iEdges, Marker.iTop, Marker.iWidth, Marker.iHeight)
    268                 width, height = dc.GetTextExtent(Marker.sName)
    269                 k = ((Marker.iStart + Marker.iEnd) / 2) - (width/2) + self.iEdges
    270                 if self.showLabels or self.iMidiMode:
    271                     dc.DrawText(Marker.sName, k, ((Marker.iTop+Marker.iHeight/2) - (height*.5)))
    272                 if self.iMidiMode:
    273                     self.iMidiModeStart = Marker.iStart
    274             elif Marker.sEventType == JetDefs.E_EOS:
    275                 dc.SetPen(wx.Pen(EOS_BAR))
    276                 dc.SetBrush(wx.Brush(EOS_BAR))
    277                 dc.DrawRectangle(Marker.iStart + self.iEdges, Marker.iTop, 1, Marker.iHeight)                
    278                 width, height = dc.GetTextExtent(Marker.sName)
    279                 k = Marker.iStart - (width/2) + self.iEdges
    280                 dc.DrawText(Marker.sName, k, ((Marker.iTop+Marker.iHeight/2) - (height*.5)))
    281             elif Marker.sEventType == JetDefs.E_APP:
    282                 dc.SetPen(wx.Pen(APP_BAR))
    283                 dc.SetBrush(wx.Brush(APP_BAR))
    284                 dc.DrawRectangle(Marker.iStart + self.iEdges, Marker.iTop, 1, Marker.iHeight)                
    285                 width, height = dc.GetTextExtent(Marker.sName)
    286                 k = Marker.iStart - (width/2) + self.iEdges
    287                 if self.showLabels or self.iMidiMode:
    288                     dc.DrawText(Marker.sName, k, ((Marker.iTop+Marker.iHeight/2) - (height*.5)))
    289 
    290 
    291         """ Draw scale """
    292         if gWidth == 0:
    293             iDiv = 50
    294         else:
    295             iDiv = (gWidth)/18
    296         if iDiv == 0:
    297             iDiv = 50
    298         scale = ((self.iLengthInMeasures / iDiv) + 1)
    299         if scale == 0:
    300             scale = 1
    301         beatStep = step / 4.0
    302         dc.SetFont(self.font)
    303         j = 0
    304         lastEnd = 0
    305         num = range(self.iStartMeasure, self.iStartMeasure + self.iLengthInMeasures + 1, 1)
    306         dc.SetPen(wx.Pen('#5C5142'))
    307         for i in range(0, (self.iLengthInMeasures+1)*step, step):
    308             k = i + self.iEdges
    309             dc.DrawLine(k, self.iScaleTop, k, self.iScaleTop+8)
    310             if i != (self.iLengthInMeasures)*step:
    311                 for iBeat in range(1,4):
    312                     k = i+(iBeat * beatStep) + self.iEdges
    313                     dc.DrawLine(k, self.iScaleTop, k, self.iScaleTop+4)
    314             width, height = dc.GetTextExtent(str(num[j]))
    315             k = i-(width/2) + self.iEdges
    316             if k > lastEnd:
    317                 if j == 0 or (j % scale) == 0:
    318                     dc.DrawText(str(num[j]), k, self.iScaleTop+8)
    319                 lastEnd = k + width
    320             j = j + 1
    321 
    322         """ Updates the location bar in case screen moved or resized """
    323         if self.iLocationInMs > 0 and self.iLengthInMs > 0:
    324             iOffset = 0
    325             if self.iMidiMode:
    326                 iOffset = self.iMidiModeStart
    327             
    328             till = gWidth * (self.iLocationInMs / self.iLengthInMs)
    329             dc.SetPen(wx.Pen(PROGRESS_BAR))
    330             dc.SetBrush(wx.Brush(PROGRESS_BAR))
    331             dc.DrawRectangle(self.iEdges + iOffset, gHeight-6, till, 3)
    332 
    333     def UpdateLocation(self, iLocationInMs):
    334         """ Updates the location bar """
    335         #disable graph for debugging

    336         #return info               

    337         
    338         self.iLocationInMs = iLocationInMs
    339         if self.iLocationInMs > 0 and self.iLengthInMs > 0:
    340             if OsWindows():
    341                 dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
    342             else:
    343                 dc = wx.AutoBufferedPaintDC(self)
    344                 dc.Background = wx.Brush(wx.WHITE)
    345             
    346             iOffset = 0
    347             if self.iMidiMode:
    348                 iOffset = self.iMidiModeStart
    349             
    350             gWidth, gHeight = self.GetSize()
    351             gWidth = gWidth - (self.iEdges * 2)
    352         
    353             till = gWidth * (self.iLocationInMs / self.iLengthInMs)
    354             dc.SetPen(wx.Pen(PROGRESS_BAR))
    355             dc.SetBrush(wx.Brush(PROGRESS_BAR))
    356             dc.DrawRectangle(self.iEdges + iOffset, gHeight-6, till, 3)
    357             self.isDirty = True
    358         else:
    359             if self.isDirty:
    360                 self.DoDrawing()
    361                 self.isDirty = False
    362