/Users/maurits/Documents/studie/afstuderen/biosphere/python/biosphere/gui_complex.py

Go to the documentation of this file.
00001 import wx
00002 
00003 
00004 class InputOutputShape:
00005     def __init__(self, parent, type='input', pos=(100, 100)):
00006         self.parentparent = parent
00007         self.typetype = type
00008         self.pospos = pos
00009         self.shownshown = True
00010         self.fullscreenfullscreen = False
00011         
00012         self.namename = type
00013         self.bmpbmp = wx.Bitmap('bitmaps/%s.png' % self.typetype[:-3])
00014         self.namebmpnamebmp = self.GetNameBitmapGetNameBitmap()
00015         
00016         # this will be the type this shape is connected to
00017         self.connectedToconnectedTo = None
00018     
00019     def Draw(self, dc, op = wx.COPY):
00020         if self.bmpbmp.Ok() and self.namebmpnamebmp.Ok():
00021             memDC = wx.MemoryDC()
00022             
00023             # draw name:
00024             memDC.SelectObject(self.namebmpnamebmp)
00025             if self.typetype == 'input':
00026                 dc.Blit(self.pospos[0] + self.bmpbmp.GetWidth()/2 - self.namebmpnamebmp.GetWidth()/2 - 10, 
00027                         self.pospos[1] - self.namebmpnamebmp.GetHeight(), 
00028                         self.namebmpnamebmp.GetWidth(), self.namebmpnamebmp.GetHeight(), 
00029                         memDC, 0, 0, op, True)
00030             else:
00031                 dc.Blit(self.pospos[0] + self.bmpbmp.GetWidth()/2 - self.namebmpnamebmp.GetWidth()/2 + 10, 
00032                     self.pospos[1] - self.namebmpnamebmp.GetHeight(), 
00033                     self.namebmpnamebmp.GetWidth(), self.namebmpnamebmp.GetHeight(), 
00034                     memDC, 0, 0, op, True)
00035             
00036             # draw image:
00037             memDC.SelectObject(self.bmpbmp)
00038             dc.Blit(self.pospos[0], self.pospos[1], 
00039                     self.bmpbmp.GetWidth(), self.bmpbmp.GetHeight(), 
00040                     memDC, 0, 0, op, True)
00041     
00042     def GetNameBitmap(self):
00043         font = wx.Font(11, wx.MODERN, wx.NORMAL, wx.NORMAL)
00044         textExtent = self.parentparent.GetFullTextExtent(self.namename, font)
00045         txtbmp = wx.EmptyBitmap(textExtent[0], textExtent[1])
00046         
00047         memDC = wx.MemoryDC()
00048         memDC.SelectObject(txtbmp)
00049         memDC.SetBackground(wx.Brush(wx.WHITE, wx.SOLID))
00050         memDC.Clear()
00051         memDC.SetTextForeground(wx.BLACK)
00052         memDC.SetFont(font)
00053         memDC.DrawText(self.namename, 0, 0)
00054         
00055         mask = wx.Mask(txtbmp, wx.WHITE)
00056         txtbmp.SetMask(mask)
00057         return txtbmp
00058     
00059     def Rename(self, name):
00060         self.namename = name
00061         self.namebmpnamebmp = self.GetNameBitmapGetNameBitmap()
00062     
00063     def HitTestBody(self, pt):
00064         rect = self.GetRectGetRect()
00065         if self.typetype == 'input':
00066             rect.width = rect.width - 20
00067         else:
00068             rect.x = rect.x + 20
00069             rect.width = rect.width - 20
00070         
00071         return rect.InsideXY(pt.x, pt.y)
00072     
00073     def HitTestArrow(self, pt):
00074         # TODO this can be much more efficiently!
00075         rect = self.GetRectGetRect()
00076         return rect.InsideXY(pt.x, pt.y) and not self.HitTestBodyHitTestBody(pt)
00077     
00078     def GetRect(self):
00079         return wx.Rect(self.pospos[0], self.pospos[1], 
00080                       self.bmpbmp.GetWidth(), self.bmpbmp.GetHeight())
00081     
00082 
00083 class DragShape:
00084     def __init__(self, parent, operation, name, pos=(100, 100)):
00085         # logical attributes:
00086         self.parentparent = parent
00087         self.operationoperation = operation
00088         
00089         # graphical attributes:
00090         self.namename = name
00091         self.bmpbmp = self.GetBitmapGetBitmap()
00092         self.namebmpnamebmp = self.GetNameBitmapGetNameBitmap()
00093         self.pospos = pos
00094         self.shownshown = True
00095         self.fullscreenfullscreen = False
00096         
00097     def Rename(self, name):
00098         self.namename = name
00099         self.namebmpnamebmp = self.GetNameBitmapGetNameBitmap()
00100     
00101     def GetBitmap(self):
00102         self.num_innum_in  = len(self.operationoperation.input.parts)
00103         self.num_outnum_out = len(self.operationoperation.output.parts)
00104         return wx.Bitmap('bitmaps/%dto%d.png' % (self.num_innum_in, self.num_outnum_out))
00105     
00106     def GetNameBitmap(self):
00107         font = wx.Font(11, wx.MODERN, wx.NORMAL, wx.NORMAL)
00108         textExtent = self.parentparent.GetFullTextExtent(self.namename, font)
00109         txtbmp = wx.EmptyBitmap(textExtent[0], textExtent[1])
00110         
00111         memDC = wx.MemoryDC()
00112         memDC.SelectObject(txtbmp)
00113         memDC.SetBackground(wx.Brush(wx.WHITE, wx.SOLID))
00114         memDC.Clear()
00115         memDC.SetTextForeground(wx.BLACK)
00116         memDC.SetFont(font)
00117         memDC.DrawText(self.namename, 0, 0)
00118         
00119         mask = wx.Mask(txtbmp, wx.WHITE)
00120         txtbmp.SetMask(mask)
00121         return txtbmp
00122 
00123     def HitTestBody(self, pt):
00124         rect = self.GetRectGetRect()
00125         if self.num_innum_in > 0:
00126             rect.x = rect.x + 27
00127             rect.width = rect.width - 27
00128         if self.num_outnum_out > 0:
00129             rect.width = rect.width - 27
00130         
00131         return rect.InsideXY(pt.x, pt.y)
00132     
00133     def HitTestArrow(self, pt):
00134         # TODO this can be much more efficiently!
00135         rect = self.GetRectGetRect()
00136         return rect.InsideXY(pt.x, pt.y) and not self.HitTestBodyHitTestBody(pt)
00137 
00138     def GetRect(self):
00139         return wx.Rect(self.pospos[0], self.pospos[1], 
00140                       self.bmpbmp.GetWidth(), self.bmpbmp.GetHeight())
00141 
00142     def Draw(self, dc, op = wx.COPY):
00143         if self.bmpbmp.Ok() and self.namebmpnamebmp.Ok():
00144             memDC = wx.MemoryDC()
00145             
00146             # draw name:
00147             memDC.SelectObject(self.namebmpnamebmp)
00148             dc.Blit(self.pospos[0] + self.bmpbmp.GetWidth()/2 - self.namebmpnamebmp.GetWidth()/2, 
00149                     self.pospos[1] - self.namebmpnamebmp.GetHeight(), 
00150                     self.namebmpnamebmp.GetWidth(), self.namebmpnamebmp.GetHeight(), 
00151                     memDC, 0, 0, op, True)
00152             
00153             # draw image:
00154             memDC.SelectObject(self.bmpbmp)
00155             dc.Blit(self.pospos[0], self.pospos[1], 
00156                     self.bmpbmp.GetWidth(), self.bmpbmp.GetHeight(), 
00157                     memDC, 0, 0, op, True)
00158 
00159 
00160 class Connection:
00161     def __init__(self, parent, input, output):
00162         # lookup table for connection endpoints:
00163         self.coordictcoordict = {'in.png': ([], [20]),
00164                          'out.png': ([20], []),
00165                     '0to1.png': ([], [31]),
00166                     '0to2.png': ([], [18, 43]),
00167                     '0to3.png': ([], [18, 43, 67]),
00168                     '0to4.png': ([], [18, 43, 67, 93]),
00169                     '0to5.png': ([], [18, 43, 67, 93, 118]),
00170                     '1to0.png': ([31], []),
00171                     '1to1.png': ([31], [31]),
00172                     '1to2.png': ([31], [18, 43]),
00173                     '1to3.png': ([43], [18, 43, 67]),
00174                     '1to4.png': ([56], [18, 43, 67, 93]),
00175                     '1to5.png': ([68], [18, 43, 67, 93, 118]),
00176                     '2to0.png': ([18, 43], []),
00177                     '2to1.png': ([18, 43], [31]),
00178                     '2to2.png': ([18, 43], [18, 43]),
00179                     '2to3.png': ([30, 56], [18, 43, 67]),
00180                     '2to4.png': ([43, 67], [18, 43, 67, 93]),
00181                     '2to5.png': ([43, 93], [18, 43, 67, 93, 118]),
00182                     '3to0.png': ([18, 43, 67], []),
00183                     '3to1.png': ([18, 43, 67], [43]),
00184                     '3to2.png': ([18, 43, 67], [30, 56]),
00185                     '3to3.png': ([18, 43, 67], [18, 43, 67]),
00186                     '3to4.png': ([30, 55, 80], [18, 43, 67, 93]),
00187                     '3to5.png': ([43, 67, 93], [18, 43, 67, 93, 118]),
00188                     '4to0.png': ([18, 43, 67, 93], []),
00189                     '4to1.png': ([18, 43, 67, 93], [55]),
00190                     '4to2.png': ([18, 43, 67, 93], [43, 67]),
00191                     '4to3.png': ([18, 43, 67, 93], [30, 55, 80]),
00192                     '4to4.png': ([18, 43, 67, 93], [18, 43, 67, 93]),
00193                     '4to5.png': ([31, 56, 81, 106], [18, 43, 67, 93, 118]),
00194                     '5to0.png': ([18, 43, 67, 93, 118], []),
00195                     '5to1.png': ([18, 43, 67, 93, 118], [67]),
00196                     '5to2.png': ([18, 43, 67, 93, 118], [43, 93]),
00197                     '5to3.png': ([18, 43, 67, 93, 118], [43, 67, 93]),
00198                     '5to4.png': ([18, 43, 67, 93, 118], [31, 56, 81, 106]),
00199                     '5to5.png': ([18, 43, 67, 93, 118], [18, 43, 67, 93, 118])
00200                     }
00201         
00202         self.parentparent = parent
00203         self.outputoutput = output # tuple (shape, op#)
00204         self.inputinput = input
00205         self.iposipos = None
00206         self.oposopos = None
00207         self.shownshown = True
00208         
00209         self.ibmpnameibmpname = '%dto%d.png' % (len(self.inputinput[0].operation.input.parts),
00210                                         len(self.inputinput[0].operation.output.parts))
00211         self.obmpnameobmpname = '%dto%d.png' % (len(self.outputoutput[0].operation.input.parts),
00212                                         len(self.outputoutput[0].operation.output.parts))
00213         
00214         self.CalculateCoordsCalculateCoords()
00215     
00216     def CalculateCoords(self):
00217         self.iposipos = self.GetCoordsForShapeGetCoordsForShape(self.inputinput[0], self.inputinput[1])
00218         self.oposopos = self.GetCoordsForShapeGetCoordsForShape(self.outputoutput[0],
00219                                            self.outputoutput[1], False)
00220     
00221     def GetCoordsForShape(self, shape, partno, input=True):
00222         if input:
00223             bmfname = self.ibmpnameibmpname
00224             if bmfname not in self.coordictcoordict:
00225                 return None
00226             else:
00227                 return (shape.pos[0] + 2,
00228                         shape.pos[1] + self.coordictcoordict[bmfname][0][partno])
00229         else:
00230             bmfname = self.obmpnameobmpname
00231             if bmfname not in self.coordictcoordict:
00232                 return None
00233             else:
00234                 return (shape.pos[0] - 2 + shape.bmp.GetWidth(),
00235                         shape.pos[1] + self.coordictcoordict[bmfname][1][partno])
00236     
00237     def Draw(self, dc):
00238         if self.iposipos and self.oposopos:
00239             dc.SetPen(wx.Pen('black', 2))
00240             dc.DrawLine(self.iposipos[0], self.iposipos[1],
00241                         self.oposopos[0], self.oposopos[1])
00242     
00243     def HitTest(self, pt):
00244         if not self.shownshown or not self.iposipos or not self.oposopos:
00245             return False
00246         
00247         # look if point is in square box:
00248         d = 8
00249         if pt.x < ipos[0]-d and pt.x < opos[0]-d or pt.x > ipos[0]+d and pt.x > opos[0]+d:
00250             return False
00251         if pt.x < ipos[1]-d and pt.x < opos[1]-d or pt.x > ipos[1]+d and pt.x > opos[1]+d:
00252             return False
00253         
00254         # calculate
00255         rc = float((d - b) / (c - a))
00256         if rc > 1.0 or rc < -1.0:
00257             # use y = f(x)
00258             pass
00259         else:
00260             # use x = f-1(y)
00261             pass
00262 
00263 class DragCanvas(wx.Panel):
00264     def __init__(self, parent, ID, definition = None):
00265         wx.Panel.__init__(self, parent, ID)
00266         self.defsdefs = definition
00267         
00268         # attributes for shape drawing and dragging:
00269         self.shapesshapes = []
00270         self.dragImagedragImage = None
00271         self.dragShapedragShape = None
00272         
00273         # attributes for arrow connecting:
00274         self.dragArrowdragArrow = None
00275         self.dragFirstdragFirst = None
00276         self.connectionsconnections = []
00277         self.selectedShapeselectedShape = None
00278 
00279         self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
00280         self.bg_bmpbg_bmp = wx.Bitmap('bitmaps/background.bmp')
00281         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
00282         self.SetBackgroundColour(wx.WHITE)
00283 
00284         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackgroundOnEraseBackground)
00285         self.Bind(wx.EVT_PAINT, self.OnPaintOnPaint)
00286         self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDownOnLeftDown)
00287         self.Bind(wx.EVT_LEFT_UP, self.OnLeftUpOnLeftUp)
00288         self.Bind(wx.EVT_MOTION, self.OnMotionOnMotion)
00289         self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightMouseDownOnRightMouseDown)
00290     
00291     def AddOperation(self, operation):
00292         shape_count = 1
00293         for s in self.shapesshapes:
00294             if s.operation.name == operation.name:
00295                 shape_count += 1
00296         if shape_count == 1:
00297             shape = DragShape(self, operation, operation.name)
00298         else:
00299             shape = DragShape(self, operation, 
00300                               '%s<%d>' % (operation.name, shape_count))
00301         self.shapesshapes.append(shape)
00302         self.Refresh()
00303     
00304     def AddInput(self):
00305         s = InputOutputShape(self)
00306         self.shapesshapes.append(s)
00307         self.Refresh()
00308     
00309     def AddOutput(self):
00310         s = InputOutputShape(self, type="output")
00311         self.shapesshapes.append(s)
00312         self.Refresh()
00313     
00314     def SetDefs(self, definition):
00315         # new definitions are set, so clear everything:
00316         self.defsdefs = definition
00317         self.ClearAllClearAll()
00318     
00319     def ClearAll(self):
00320         self.dragImagedragImage = None
00321         self.dragShapedragShape = None
00322         dc = wx.ClientDC(self)
00323         
00324         self.shapesshapes = []
00325         self.connectionsconnections = []
00326         self.TileBackgroundTileBackground(dc)
00327 
00328     # tile the background bitmap
00329     def TileBackground(self, dc):
00330         sz = self.GetClientSize()
00331         w = self.bg_bmpbg_bmp.GetWidth()
00332         h = self.bg_bmpbg_bmp.GetHeight()
00333 
00334         x = 0
00335         while x < sz.width:
00336             y = 0
00337             while y < sz.height:
00338                 dc.DrawBitmap(self.bg_bmpbg_bmp, x, y)
00339                 y += h
00340             x += w
00341 
00342     def DrawShapes(self, dc):
00343         for shape in self.shapesshapes:
00344             if shape.shown:
00345                 shape.Draw(dc)
00346         for connection in self.connectionsconnections:
00347             if connection.shown:
00348                 connection.Draw(dc)
00349     
00350     # This is actually a sophisticated 'hit test', but in this
00351     # case we're also determining which shape, if any, was 'hit'.
00352     def FindShapeBody(self, pt):
00353         for s in reversed(self.shapesshapes):
00354             if s.HitTestBody(pt):
00355                 return s
00356         return None
00357     
00358     def FindShapeArrow(self, pt):
00359         # returns the shape whose arrows were clicked:
00360         for s in reversed(self.shapesshapes):
00361             if s.HitTestArrow(pt):
00362                 return s
00363         return None
00364 
00365     def EraseShape(self, shape, dc):
00366         # Remove a shape from the display
00367         r = shape.GetRect()
00368         dc.SetClippingRect(r)
00369         self.TileBackgroundTileBackground(dc)
00370         self.DrawShapesDrawShapes(dc)
00371         dc.DestroyClippingRegion()
00372 
00373     # Clears the background, then redraws it. If the DC is passed, then
00374     # we only do so in the area so designated. Otherwise, it's the whole thing.
00375     def OnEraseBackground(self, evt):
00376         dc = evt.GetDC()
00377 
00378         if not dc:
00379             dc = wx.ClientDC(self)
00380             rect = self.GetUpdateRegion().GetBox()
00381             dc.SetClippingRect(rect)
00382         self.TileBackgroundTileBackground(dc)
00383 
00384     # Fired whenever a paint event occurs
00385     def OnPaint(self, evt):
00386         dc = wx.PaintDC(self)
00387         self.PrepareDC(dc)
00388         self.DrawShapesDrawShapes(dc)
00389 
00390     def OnRightMouseDown(self, event):
00391         shape = self.FindShapeBodyFindShapeBody(event.GetPosition())
00392         if shape:
00393             self.ClearArrowDraggingClearArrowDragging()
00394             self.ClearShapeDraggingClearShapeDragging()
00395             self.selectedShapeselectedShape = shape
00396             
00397             menu = self.MakeArrowMenuMakeArrowMenu(shape)
00398             self.PopupMenu(menu)
00399             menu.Destroy()
00400             
00401             self.selectedShapeselectedShape = None
00402         else:
00403             self.ClearArrowDraggingClearArrowDragging()
00404             self.ClearShapeDraggingClearShapeDragging()
00405 
00406     def ClearArrowDragging(self):
00407         self.dragArrowdragArrow = None
00408         self.dragFirstdragFirst = None
00409         self.selectedShapeselectedShape = None
00410     
00411     def ClearShapeDragging(self):
00412         self.dragShapedragShape = None
00413         self.dragImagedragImage = None
00414         self.selectedShapeselectedShape = None
00415     
00416     def HandleArrow(self, arrow):
00417         # start connecting shapes
00418         if not self.dragArrowdragArrow:
00419             # this is the first endpoint of a connection
00420             self.ClearArrowDraggingClearArrowDragging()
00421             self.ClearShapeDraggingClearShapeDragging()
00422             self.dragArrowdragArrow = arrow
00423             self.selectedShapeselectedShape = arrow
00424 
00425             menu = self.MakeArrowMenuMakeArrowMenu(arrow)
00426             self.PopupMenu(menu)
00427             menu.Destroy()
00428                 
00429             if self.dragFirstdragFirst:
00430                 self.dragArrowdragArrow = arrow # only set permanently if part is selected
00431             else:
00432                 self.dragArrowdragArrow = None
00433             self.selectedShapeselectedShape = None
00434         else:
00435             if arrow and arrow != self.dragArrowdragArrow:
00436                 # the user clicked on the second arrow:
00437                 self.dragArrowdragArrow = arrow
00438                 self.dragImagedragImage = None
00439                 self.dragShapedragShape = None
00440                 self.selectedShapeselectedShape = arrow
00441 
00442                 menu = self.MakeArrowMenuMakeArrowMenu(arrow)
00443                 self.PopupMenu(menu)
00444                 menu.Destroy()
00445                 
00446                 self.selectedShapeselectedShape = None
00447     
00448     # Left mouse button is down.
00449     def OnLeftDown(self, evt):
00450         # Did the mouse go down on one of our shapes?
00451         shape = self.FindShapeBodyFindShapeBody(evt.GetPosition())
00452 
00453         if shape and not self.dragArrowdragArrow:
00454             # we found a shape and we're not connecting, so we start dragging:
00455             self.ClearArrowDraggingClearArrowDragging()
00456             self.ClearShapeDraggingClearShapeDragging()
00457             
00458             self.dragShapedragShape = shape
00459             self.dragStartPos = evt.GetPosition()
00460         else:
00461             # we're not dragging
00462             if shape:
00463                 # there is a shape and an arrow already set: connect!
00464                 self.HandleArrowHandleArrow(shape)
00465                 return
00466             
00467             # maybe the user clicked on an arrow?
00468             arrow = self.FindShapeArrowFindShapeArrow(evt.GetPosition())
00469             if arrow:
00470                 self.HandleArrowHandleArrow(arrow)
00471             else:
00472                 # User clicked nowhere:
00473                 self.ClearArrowDraggingClearArrowDragging()
00474                 self.ClearShapeDraggingClearShapeDragging()
00475     
00476     def MakeArrowMenu(self, arrow):
00477         """Create the menu which is displayed when the user clicks
00478         on an in- or output arrow.
00479         """
00480         input_ids = 3000
00481         output_ids = 4000
00482         
00483         menu = wx.Menu()
00484         m = menu.Append(-1, 'Connect %s' % arrow.name)
00485         m.Enable(False)
00486         menu.AppendSeparator()
00487         
00488         if isinstance(arrow, DragShape):
00489             m = menu.Append(-1, 'Input:')
00490             m.Enable(False)
00491             for part in arrow.operation.input.parts:
00492                 m = menu.Append(input_ids,
00493                                 '%s (%s)' % (part.name, part.type.name))
00494                 self.Bind(wx.EVT_MENU, self.OnArrowMenuOnArrowMenu, m)
00495                 input_ids += 1
00496                     
00497             menu.AppendSeparator()
00498             m = menu.Append(-1, 'Output:')
00499             m.Enable(False)
00500             for part in arrow.operation.output.parts:
00501                 m = menu.Append(output_ids,
00502                                 '%s (%s)' % (part.name, part.type.name))
00503                 self.Bind(wx.EVT_MENU, self.OnArrowMenuOnArrowMenu, m)
00504                 output_ids += 1
00505         else:
00506             if arrow.type == 'input':
00507                 if arrow.connectedTo:
00508                     m = menu.Append(input_ids, 'Input (%s)' % arrow.connectedTo)
00509                     self.Bind(wx.EVT_MENU, self.OnArrowMenuOnArrowMenu, m)
00510                 else:
00511                     m = menu.Append(input_ids, 'Input')
00512                     self.Bind(wx.EVT_MENU, self.OnArrowMenuOnArrowMenu, m)
00513                 m = menu.Append(-1, 'Provide input')
00514                 self.Bind(wx.EVT_MENU, self.OnProvideInputOnProvideInput, m)
00515             else:
00516                 if arrow.connectedTo:
00517                     m = menu.Append(output_ids, 'Input (%s)' % arrow.connectedTo)
00518                     self.Bind(wx.EVT_MENU, self.OnArrowMenuOnArrowMenu, m)
00519                 else:
00520                     m = menu.Append(output_ids, 'Output')
00521                     self.Bind(wx.EVT_MENU, self.OnArrowMenuOnArrowMenu, m)
00522         
00523         menu.AppendSeparator()
00524         m = menu.Append(-1, 'Clear %s' % arrow.name)
00525         self.Bind(wx.EVT_MENU, self.OnClearShapeOnClearShape, m)
00526         m = menu.Append(-1, 'Rename %s' % arrow.name)
00527         self.Bind(wx.EVT_MENU, self.OnRenameShapeOnRenameShape, m)
00528                     
00529         return menu
00530     
00531     def OnClearShape(self, event):
00532         if self.selectedShapeselectedShape:
00533             to_remove = []
00534             for c in self.connectionsconnections:
00535                 if c.input[0] == self.selectedShapeselectedShape or c.output[0] == self.selectedShapeselectedShape:
00536                     to_remove.append(c)
00537             for c in to_remove:
00538                 self.connectionsconnections.remove(c)
00539             
00540             self.shapesshapes.remove(self.selectedShapeselectedShape)
00541             self.selectedShapeselectedShape = None
00542             self.Refresh()
00543     
00544     def OnRenameShape(self, event):
00545         if self.selectedShapeselectedShape:
00546             dlg = wx.TextEntryDialog(self, 'Please enter a new name.',
00547                                      'Rename', 'Python')
00548             dlg.SetValue(self.selectedShapeselectedShape.name)
00549             if dlg.ShowModal() == wx.ID_OK:
00550                 self.selectedShapeselectedShape.Rename(dlg.GetValue())
00551             dlg.Destroy()
00552             self.Refresh()
00553     
00554     def OnProvideInput(self, event):
00555         pass
00556     
00557     def OnArrowMenu(self, event):
00558         menu_id = event.GetId()
00559         if self.dragFirst == None:
00560             if menu_id >= 3000 and menu_id < 4000:
00561                 # input part selected:
00562                 self.dragFirst = (self.dragArrow,
00563                                   True, menu_id - 3000)
00564             else:
00565                 # output part selected:
00566                 self.dragFirst = (self.dragArrow,
00567                                   False, menu_id - 4000)
00568         else:
00569             # make the connection
00570             if menu_id >= 3000 and menu_id < 4000:
00571                 # input part selected:
00572                 second = (self.dragArrow, True, menu_id - 3000)
00573             else:
00574                 # output part selected:
00575                 second = (self.dragArrow, False, menu_id - 4000)
00576             self.MakeConnection(self.dragFirst, second)
00577             self.ClearArrowDragging()
00578     
00579     def MakeConnection(self, first, second):
00580         # look if it is an output to input connection:
00581         if first[1] == second[1]:
00582             self.PrintErrorAndStopConnectingPrintErrorAndStopConnecting('Must connect input to output or vice versa')
00583         elif isinstance(first[0], InputOutputShape) and isinstance(second[0], InputOutputShape):
00584             self.PrintErrorAndStopConnectingPrintErrorAndStopConnecting('Cannot connect input directly to output')
00585         elif first[1] and isinstance(first[0], InputOutputShape):
00586             self.MakeInputConnectionMakeInputConnection(first, second)
00587         elif second[1] and isinstance(second[0], InputOutputShape):
00588             self.MakeInputConnectionMakeInputConnection(second, first)
00589         elif not first[1] and isinstance(first[0], InputOutputShape):
00590             self.MakeOutputConnectionMakeOutputConnection(first, second)
00591         elif not second[1] and isinstance(second[0], InputOutputShape):
00592             self.MakeOutputConnectionMakeOutputConnection(second, first)
00593         
00594         else:
00595             # look if the types match and make connection:
00596             part1 = first[0].operation
00597             part2 = second[0].operation
00598             if first[1]: # first is the input
00599                 if part1.input.parts[first[2]].type.name != part2.output.parts[second[2]].type.name:
00600                     self.PrintErrorAndStopConnectingPrintErrorAndStopConnecting('Types don\'t match.')
00601                 else:
00602                     self.connectionsconnections.append(Connection(self,
00603                                                        (first[0], first[2]),
00604                                                        (second[0], second[2])))
00605             else: # the second one is the input
00606                 if part1.output.parts[first[2]].type.name != part2.input.parts[second[2]].type.name:
00607                     self.PrintErrorAndStopConnectingPrintErrorAndStopConnecting('Types don\'t match.')
00608                 else:
00609                     self.connectionsconnections.append(Connection(self,
00610                                                        (second[0], second[2]),
00611                                                        (first[0], first[2])))
00612         self.Refresh()
00613         
00614     def MakeInputConnection(self, input, other):
00615         pass
00616     
00617     def MakeOutputConnection(self, output, other):
00618         pass
00619     
00620     def PrintErrorAndStopConnecting(self, msg):
00621         dlg = wx.MessageDialog(self, msg, 'Connection Error', wx.OK|wx.ICON_ERROR)
00622         dlg.ShowModal()
00623         dlg.Destroy()
00624         self.ClearArrowDragging()
00625     
00626     def round(self, n, m):
00627         x = n / m
00628         if n <= x * n + m / 2:
00629             return x * m
00630         else:
00631             return (x + 1) * m
00632     
00633     # Left mouse button up.
00634     def OnLeftUp(self, evt):
00635         if not self.dragImagedragImage or not self.dragShapedragShape:
00636             self.dragImagedragImage = None
00637             self.dragShapedragShape = None
00638             evt.Skip()
00639             return
00640 
00641         # Hide the image, end dragging, and nuke out the drag image.
00642         self.dragImagedragImage.Hide()
00643         self.dragImagedragImage.EndDrag()
00644         self.dragImagedragImage = None
00645         
00646         # use rounding to make it snappy to grid:
00647         self.dragShapedragShape.pos = (
00648             self.roundround(self.dragShapedragShape.pos[0] + evt.GetPosition()[0] - self.dragStartPos[0], 10), 
00649             self.roundround(self.dragShapedragShape.pos[1] + evt.GetPosition()[1] - self.dragStartPos[1], 10)
00650             )
00651         
00652         # move the shape to the end of the shapes so it will be on top:
00653         for s in self.shapesshapes:
00654             if s == self.dragShapedragShape:
00655                 self.shapesshapes.remove(s)
00656         self.shapesshapes.append(self.dragShapedragShape)
00657         
00658         # show all connections to the shape:
00659         for c in self.connectionsconnections:
00660             if c.input[0] == self.dragShapedragShape or c.output[0] == self.dragShapedragShape:
00661                 c.CalculateCoords()
00662                 c.shown = True
00663         
00664         self.dragShapedragShape.shown = True
00665         self.RefreshRect(self.dragShapedragShape.GetRect())
00666         self.dragShapedragShape = None
00667         
00668         self.Refresh()
00669 
00670 
00671     # The mouse is moving
00672     def OnMotion(self, evt):
00673         # Ignore mouse movement if we're not dragging.
00674         if not self.dragShapedragShape or not evt.Dragging() or not evt.LeftIsDown():
00675             evt.Skip()
00676 
00677         # if we have a shape, but haven't started dragging yet
00678         if self.dragShapedragShape and not self.dragImagedragImage:
00679 
00680             # only start the drag after having moved a couple pixels
00681             tolerance = 2
00682             pt = evt.GetPosition()
00683             dx = abs(pt.x - self.dragStartPos.x)
00684             dy = abs(pt.y - self.dragStartPos.y)
00685             if dx <= tolerance and dy <= tolerance:
00686                 return
00687 
00688             # erase the shape since it will be drawn independently now
00689             dc = wx.ClientDC(self)
00690             self.dragShapedragShape.shown = False
00691             self.EraseShapeEraseShape(self.dragShapedragShape, dc)
00692             
00693             # also all connections to this shape:
00694             for c in self.connectionsconnections:
00695                 if c.input[0] == self.dragShapedragShape or c.output[0] == self.dragShapedragShape:
00696                     c.shown = False
00697             
00698             self.Refresh()
00699 
00700             self.dragImagedragImage = wx.DragImage(self.dragShapedragShape.bmp, 
00701                                           wx.StockCursor(wx.CURSOR_HAND))
00702 
00703             hotspot = self.dragStartPos - self.dragShapedragShape.pos
00704             self.dragImagedragImage.BeginDrag(hotspot, self, self.dragShapedragShape.fullscreen)
00705 
00706             self.dragImagedragImage.Move(pt)
00707             self.dragImagedragImage.Show()
00708             
00709         # if we have shape and image then move it, posibly highlighting another shape.
00710         elif self.dragShapedragShape and self.dragImagedragImage:
00711             # now move it and show it again if needed
00712             self.dragImagedragImage.Move(evt.GetPosition())
00713             self.dragImagedragImage.Show()
00714 
00715 
00716 class ComplexRequestPanel(wx.Panel):
00717     def __init__(self, parent, connector):
00718         wx.Panel.__init__(self, parent, -1)
00719         
00720         self.defsdefs = None
00721         self.selected_serviceselected_service = None
00722         self.selected_portselected_port = None
00723         self.selected_operationselected_operation = None
00724         
00725         self.connconn = connector
00726         self.InitLayoutInitLayout()
00727     
00728     def InitLayout(self):
00729         mainbox = wx.BoxSizer(wx.VERTICAL)
00730         canvasbox = wx.StaticBox(self, -1, 'Constructor Window')
00731         cbs = wx.StaticBoxSizer(canvasbox, wx.HORIZONTAL)
00732         self.canvascanvas = DragCanvas(self, -1, self.defsdefs)
00733         
00734         mainbox.Add(self.InitHeadlineRowInitHeadlineRow(), 0, wx.EXPAND|wx.ALIGN_TOP|wx.ALL, 5)
00735         cbs.Add(self.canvascanvas, 1, wx.EXPAND)
00736         mainbox.Add(cbs, 1, wx.EXPAND|wx.ALL, 5)
00737         self.SetSizer(mainbox)
00738         
00739     def InitHeadlineRow(self):
00740         headlinerow = wx.BoxSizer(wx.HORIZONTAL)
00741         
00742         headlinerow.Add(wx.StaticText(self, -1, 'Select:'), 0, 
00743                         wx.RIGHT, 5)
00744         
00745         self.servicesservices = wx.Choice(self, -1, choices=[])
00746         headlinerow.Add(self.servicesservices, 1)
00747         self.Bind(wx.EVT_CHOICE, self.OnServiceSelectedOnServiceSelected, self.servicesservices)
00748         
00749         headlinerow.Add(wx.StaticText(self, -1, '>'), 0, wx.LEFT|wx.RIGHT, 5)
00750         
00751         self.portsports = wx.Choice(self, -1, choices=[])
00752         self.Bind(wx.EVT_CHOICE, self.OnPortSelectedOnPortSelected, self.portsports)
00753         headlinerow.Add(self.portsports, 1)
00754         
00755         headlinerow.Add(wx.StaticText(self, -1, '>'), 0, wx.LEFT|wx.RIGHT, 5)
00756         
00757         self.operationsoperations = wx.Choice(self, -1, choices=[])
00758         self.Bind(wx.EVT_CHOICE, self.OnOperationSelectedOnOperationSelected, self.operationsoperations)
00759         headlinerow.Add(self.operationsoperations, 1)
00760         
00761         headlinerow.Add(wx.StaticText(self, -1, 'or'), 0, wx.LEFT, 5)
00762         
00763         btn = wx.Button(self, -1, 'Add Input')
00764         self.Bind(wx.EVT_BUTTON, self.OnInputAddOnInputAdd, btn)
00765         headlinerow.Add(btn, 0, wx.LEFT, 5)
00766         
00767         btn = wx.Button(self, -1, 'Add Output')
00768         self.Bind(wx.EVT_BUTTON, self.OnOutputAddOnOutputAdd, btn)
00769         headlinerow.Add(btn, 0, wx.LEFT, 5)
00770         
00771         headlinerow.Add((5, -1), 1)
00772         
00773         btn = wx.Button(self, -1, 'Clear')
00774         self.Bind(wx.EVT_BUTTON, self.OnClearStructureOnClearStructure, btn)
00775         headlinerow.Add(btn, 0, wx.ALIGN_RIGHT|wx.RIGHT, 5)
00776         
00777         btn = wx.Button(self, -1, 'Execute')
00778         self.Bind(wx.EVT_BUTTON, self.OnExecuteOnExecute, btn)
00779         headlinerow.Add(btn, 0, wx.ALIGN_RIGHT)
00780         
00781         return headlinerow
00782     
00783     def OnInputAdd(self, event):
00784         self.canvascanvas.AddInput()
00785     
00786     def OnOutputAdd(self, event):
00787         self.canvascanvas.AddOutput()
00788     
00789     def OnServiceSelected(self, event):
00790         # clear the other two boxes and any selected ports and ops:
00791         self.portsports.Clear()
00792         self.operationsoperations.Clear()
00793         self.selected_serviceselected_service = None
00794         self.selected_portselected_port = None
00795         self.selected_operationselected_operation = None
00796         
00797         if self.defsdefs:
00798             sel = event.GetString()
00799             for s in self.defsdefs.services:
00800                 if s.name == sel:
00801                     self.selected_serviceselected_service = s
00802                     self.portsports.AppendItems([pt.name for pt in s.ports])
00803                     break
00804     
00805     def OnPortSelected(self, event):
00806         self.operationsoperations.Clear()
00807         self.selected_portselected_port = None
00808         self.selected_operationselected_operation = None
00809         
00810         if self.selected_serviceselected_service:
00811             sel = event.GetString()
00812             for p in self.selected_serviceselected_service.ports:
00813                 if p.name == sel:
00814                     self.selected_portselected_port = p
00815                     self.operationsoperations.AppendItems([op.name for op in p.type.operations])
00816                     break
00817     
00818     def OnOperationSelected(self, event):
00819         self.selected_operationselected_operation = None
00820         if self.selected_portselected_port:
00821             sel = event.GetString()
00822             for op in self.selected_portselected_port.type.operations:
00823                 if op.name == sel:
00824                     self.selected_operationselected_operation = op
00825                     self.canvascanvas.AddOperation(self.selected_operationselected_operation)
00826     
00827     def SetDefs(self, defs):
00828         self.ClearDefinitionsClearDefinitions()
00829         self.defsdefs = defs
00830         self.canvascanvas.SetDefs(defs)
00831         if self.defsdefs:
00832             for svc in self.defsdefs.services:
00833                 self.servicesservices.Append(svc.name)
00834     
00835     def OnExecute(self, event):
00836         pass
00837     
00838     def OnClearStructure(self, event):
00839         self.canvas.ClearAll()
00840     
00841     def ClearDefinitions(self):
00842         self.defsdefs = None
00843         self.selected_serviceselected_service = None
00844         self.selected_portselected_port = None
00845         self.selected_operationselected_operation = None
00846         self.ClearServiceListsClearServiceLists()
00847     
00848     def ClearServiceLists(self):
00849         self.servicesservices.Clear()
00850         self.operationsoperations.Clear()
00851         self.portsports.Clear()
00852         

Generated on Tue Jul 17 09:50:53 2007 for Bio-SPHERE by  doxygen 1.5.1