Viewer.py
changeset 666 d4bb66691248
parent 658 89d20745b061
child 667 baab9eb5b8ad
--- a/Viewer.py	Sat Mar 31 15:03:50 2012 +0200
+++ b/Viewer.py	Sat Mar 31 15:08:18 2012 +0200
@@ -340,7 +340,6 @@
         message.ShowModal()
         message.Destroy()
 
-
 """
 Class that implements a Viewer based on a wx.ScrolledWindow for drawing and 
 manipulating graphic elements
@@ -355,103 +354,165 @@
             else:
                 event(self, function)
     
-    # Create Alignment Menu items
-    def _init_coll_AlignmentMenu_Items(self, parent):
+    # Add list of menu items to the given menu
+    def AddMenuItems(self, menu, items):
+        for item in items:
+            if item is None:
+                menu.AppendSeparator()
+            else:
+                id, kind, text, help, callback = item
+                AppendMenu(menu, help=help, id=id, kind=kind, text=text)
+                # Link menu event to corresponding called functions
+                self.Bind(wx.EVT_MENU, callback, id=id)
+    
+    # Add Block Pin Menu items to the given menu
+    def AddBlockPinMenuItems(self, menu, connector):
+        [ID_NO_MODIFIER, ID_NEGATED, ID_RISING_EDGE, 
+         ID_FALLING_EDGE] = [wx.NewId() for i in xrange(4)]
+        
         # Create menu items
-        AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS0,
-              kind=wx.ITEM_NORMAL, text=_(u'Left'))
-        AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS1,
-              kind=wx.ITEM_NORMAL, text=_(u'Center'))
-        AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS2,
-              kind=wx.ITEM_NORMAL, text=_(u'Right'))
-        parent.AppendSeparator()
-        AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS4,
-              kind=wx.ITEM_NORMAL, text=_(u'Top'))
-        AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS5,
-              kind=wx.ITEM_NORMAL, text=_(u'Middle'))
-        AppendMenu(parent, help='', id=ID_VIEWERALIGNMENTMENUITEMS6,
-              kind=wx.ITEM_NORMAL, text=_(u'Bottom'))
-        # Link menu event to corresponding called functions
-        self.Bind(wx.EVT_MENU, self.OnAlignLeftMenu,
-              id=ID_VIEWERALIGNMENTMENUITEMS0)
-        self.Bind(wx.EVT_MENU, self.OnAlignCenterMenu,
-              id=ID_VIEWERALIGNMENTMENUITEMS1)
-        self.Bind(wx.EVT_MENU, self.OnAlignRightMenu,
-              id=ID_VIEWERALIGNMENTMENUITEMS2)
-        self.Bind(wx.EVT_MENU, self.OnAlignTopMenu,
-              id=ID_VIEWERALIGNMENTMENUITEMS4)
-        self.Bind(wx.EVT_MENU, self.OnAlignMiddleMenu,
-              id=ID_VIEWERALIGNMENTMENUITEMS5)
-        self.Bind(wx.EVT_MENU, self.OnAlignBottomMenu,
-              id=ID_VIEWERALIGNMENTMENUITEMS6)
-    
-    # Create Contextual Menu items
-    def _init_coll_ContextualMenu_Items(self, parent):
+        self.AddMenuItems(menu, [
+            (ID_NO_MODIFIER, wx.ITEM_RADIO, _(u'No Modifier'), '', self.OnNoModifierMenu),
+            (ID_NEGATED, wx.ITEM_RADIO, _(u'Negated'), '', self.OnNegatedMenu),
+            (ID_RISING_EDGE, wx.ITEM_RADIO, _(u'Rising Edge'), '', self.OnRisingEdgeMenu),
+            (ID_FALLING_EDGE, wx.ITEM_RADIO, _(u'Falling Edge'), '', self.OnFallingEdgeMenu)])
+        
+        type = self.Controler.GetEditedElementType(self.TagName, self.Debug)
+        menu.Enable(ID_RISING_EDGE, type != "function")
+        menu.Enable(ID_FALLING_EDGE, type != "function")
+        
+        if connector.IsNegated():
+            menu.Check(ID_NEGATED, True)
+        elif connector.GetEdge() == "rising":
+            menu.Check(ID_RISING_EDGE, True)
+        elif connector.GetEdge() == "falling":
+            menu.Check(ID_FALLING_EDGE, True)
+        else:
+            menu.Check(ID_NO_MODIFIER, True)
+        
+    # Add Alignment Menu items to the given menu
+    def AddAlignmentMenuItems(self, menu):
+        [ID_ALIGN_LEFT, ID_ALIGN_CENTER, ID_ALIGN_RIGHT,
+         ID_ALIGN_TOP, ID_ALIGN_MIDDLE, ID_ALIGN_BOTTOM,
+        ] = [wx.NewId() for i in xrange(6)]
+        
         # Create menu items
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS0,
-              kind=wx.ITEM_RADIO, text=_(u'No Modifier'))
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS1,
-              kind=wx.ITEM_RADIO, text=_(u'Negated'))
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS2,
-              kind=wx.ITEM_RADIO, text=_(u'Rising Edge'))
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS3,
-              kind=wx.ITEM_RADIO, text=_(u'Falling Edge'))
-        parent.AppendSeparator()
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS5,
-              kind=wx.ITEM_NORMAL, text=_(u'Add Wire Segment'))
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS6,
-              kind=wx.ITEM_NORMAL, text=_(u'Delete Wire Segment'))
-        parent.AppendSeparator()
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS8,
-              kind=wx.ITEM_NORMAL, text=_(u'Add Divergence Branch'))
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS9,
-              kind=wx.ITEM_NORMAL, text=_(u'Delete Divergence Branch'))
-        parent.AppendSeparator()
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS11,
-              kind=wx.ITEM_NORMAL, text=_(u'Clear Execution Order'))
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS12,
-              kind=wx.ITEM_NORMAL, text=_(u'Reset Execution Order'))
-        parent.AppendSeparator()
-        parent.AppendMenu(ID_VIEWERCONTEXTUALMENUITEMS14, _("Alignment"), self.AlignmentMenu)
-        parent.AppendSeparator()
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS16,
-              kind=wx.ITEM_NORMAL, text=_(u'Edit Block'))
-        AppendMenu(parent, help='', id=ID_VIEWERCONTEXTUALMENUITEMS17,
-              kind=wx.ITEM_NORMAL, text=_(u'Delete'))
-        # Link menu event to corresponding called functions
-        self.Bind(wx.EVT_MENU, self.OnNoModifierMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS0)
-        self.Bind(wx.EVT_MENU, self.OnNegatedMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS1)
-        self.Bind(wx.EVT_MENU, self.OnRisingEdgeMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS2)
-        self.Bind(wx.EVT_MENU, self.OnFallingEdgeMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS3)
-        self.Bind(wx.EVT_MENU, self.OnAddSegmentMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS5)
-        self.Bind(wx.EVT_MENU, self.OnDeleteSegmentMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS6)
-        self.Bind(wx.EVT_MENU, self.OnAddBranchMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS8)
-        self.Bind(wx.EVT_MENU, self.OnDeleteBranchMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS9)
-        self.Bind(wx.EVT_MENU, self.OnClearExecutionOrderMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS11)
-        self.Bind(wx.EVT_MENU, self.OnResetExecutionOrderMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS12)
-        self.Bind(wx.EVT_MENU, self.OnEditBlockMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS16)
-        self.Bind(wx.EVT_MENU, self.OnDeleteMenu,
-              id=ID_VIEWERCONTEXTUALMENUITEMS17)
-    
-    # Create and initialize Contextual Menu
-    def _init_menus(self):
-        self.AlignmentMenu = wx.Menu(title='')
-        self.ContextualMenu = wx.Menu(title='')
-        
-        self._init_coll_AlignmentMenu_Items(self.AlignmentMenu)
-        self._init_coll_ContextualMenu_Items(self.ContextualMenu)
-    
+        self.AddMenuItems(menu, [
+            (ID_ALIGN_LEFT, wx.ITEM_NORMAL, _(u'Left'), '', self.OnAlignLeftMenu),
+            (ID_ALIGN_CENTER, wx.ITEM_NORMAL, _(u'Center'), '', self.OnAlignCenterMenu), 
+            (ID_ALIGN_RIGHT, wx.ITEM_NORMAL, _(u'Right'), '', self.OnAlignRightMenu),
+            None,
+            (ID_ALIGN_TOP, wx.ITEM_NORMAL, _(u'Top'), '', self.OnAlignTopMenu), 
+            (ID_ALIGN_MIDDLE, wx.ITEM_NORMAL, _(u'Middle'), '', self.OnAlignMiddleMenu),
+            (ID_ALIGN_BOTTOM, wx.ITEM_NORMAL, _(u'Bottom'), '', self.OnAlignBottomMenu)])
+    
+    # Add Wire Menu items to the given menu
+    def AddWireMenuItems(self, menu, delete=False):
+        [ID_ADD_SEGMENT, ID_DELETE_SEGMENT] = [wx.NewId() for i in xrange(2)]
+        
+        # Create menu items
+        self.AddMenuItems(menu, [
+            (ID_ADD_SEGMENT, wx.ITEM_NORMAL, _(u'Add Wire Segment'), '', self.OnAddSegmentMenu),
+            (ID_DELETE_SEGMENT, wx.ITEM_NORMAL, _(u'Delete Wire Segment'), '', self.OnDeleteSegmentMenu)])
+    
+        menu.Enable(ID_DELETE_SEGMENT, delete)
+    
+    # Add Divergence Menu items to the given menu
+    def AddDivergenceMenuItems(self, menu, delete=False):
+        [ID_ADD_BRANCH, ID_DELETE_BRANCH] = [wx.NewId() for i in xrange(2)]
+        
+        # Create menu items
+        self.AddMenuItems(menu, [
+            (ID_ADD_BRANCH, wx.ITEM_NORMAL, _(u'Add Divergence Branch'), '', self.OnAddBranchMenu),
+            (ID_DELETE_BRANCH, wx.ITEM_NORMAL, _(u'Delete Divergence Branch'), '', self.OnDeleteBranchMenu)])
+        
+        menu.Enable(ID_DELETE_BRANCH, delete)
+    
+    # Add Add Menu items to the given menu
+    def AddAddMenuItems(self, menu):
+        [ID_ADD_BLOCK, ID_ADD_VARIABLE, ID_ADD_CONNECTION,
+         ID_ADD_COMMENT] = [wx.NewId() for i in xrange(4)]
+        
+        # Create menu items
+        self.AddMenuItems(menu, [
+            (ID_ADD_BLOCK, wx.ITEM_NORMAL, _(u'Block'), '', self.GetAddMenuCallBack(self.AddNewBlock)),
+            (ID_ADD_VARIABLE, wx.ITEM_NORMAL, _(u'Variable'), '', self.GetAddMenuCallBack(self.AddNewVariable)),
+            (ID_ADD_CONNECTION, wx.ITEM_NORMAL, _(u'Connection'), '', self.GetAddMenuCallBack(self.AddNewConnection)),
+            None])
+        
+        if self.CurrentLanguage != "FBD":
+            [ID_ADD_POWER_RAIL, ID_ADD_CONTACT, ID_ADD_COIL,
+            ] = [wx.NewId() for i in xrange(3)]
+            
+            # Create menu items
+            self.AddMenuItems(menu, [
+                (ID_ADD_POWER_RAIL, wx.ITEM_NORMAL, _(u'Power Rail'), '', self.GetAddMenuCallBack(self.AddNewPowerRail)),
+                (ID_ADD_CONTACT, wx.ITEM_NORMAL, _(u'Contact'), '', self.GetAddMenuCallBack(self.AddNewContact))])
+                
+            if self.CurrentLanguage != "SFC":
+                self.AddMenuItems(menu, [
+                     (ID_ADD_COIL, wx.ITEM_NORMAL, _(u'Coil'), '', self.GetAddMenuCallBack(self.AddNewCoil))])
+            
+            menu.AppendSeparator()
+        
+        if self.CurrentLanguage == "SFC":
+            [ID_ADD_INITIAL_STEP, ID_ADD_STEP, ID_ADD_TRANSITION, 
+             ID_ADD_ACTION_BLOCK, ID_ADD_DIVERGENCE, ID_ADD_JUMP,
+            ] = [wx.NewId() for i in xrange(6)]
+            
+            # Create menu items
+            self.AddMenuItems(menu, [
+                (ID_ADD_INITIAL_STEP, wx.ITEM_NORMAL, _(u'Initial Step'), '', self.GetAddMenuCallBack(self.AddNewStep, True)),
+                (ID_ADD_STEP, wx.ITEM_NORMAL, _(u'Step'), '', self.GetAddMenuCallBack(self.AddNewStep)),
+                (ID_ADD_TRANSITION, wx.ITEM_NORMAL, _(u'Transition'), '', self.GetAddMenuCallBack(self.AddNewTransition)),
+                (ID_ADD_ACTION_BLOCK, wx.ITEM_NORMAL, _(u'Action Block'), '', self.GetAddMenuCallBack(self.AddNewActionBlock)),
+                (ID_ADD_DIVERGENCE, wx.ITEM_NORMAL, _(u'Divergence'), '', self.GetAddMenuCallBack(self.AddNewDivergence)),
+                (ID_ADD_JUMP, wx.ITEM_NORMAL, _(u'Jump'), '', self.GetAddMenuCallBack(self.AddNewJump)),
+                None])
+        
+        self.AddMenuItems(menu, [
+             (ID_ADD_COMMENT, wx.ITEM_NORMAL, _(u'Comment'), '', self.GetAddMenuCallBack(self.AddNewComment))])
+        
+    # Add Default Menu items to the given menu
+    def AddDefaultMenuItems(self, menu, edit=False, block=False):
+        if block:
+            [ID_EDIT_BLOCK, ID_DELETE] = [wx.NewId() for i in xrange(2)]
+        
+            # Create menu items
+            self.AddMenuItems(menu, [
+                 (ID_EDIT_BLOCK, wx.ITEM_NORMAL, _(u'Edit Block'), '', self.OnEditBlockMenu),
+                 (ID_DELETE, wx.ITEM_NORMAL, _(u'Delete'), '', self.OnDeleteMenu)])
+        
+            menu.Enable(ID_EDIT_BLOCK, edit)
+        
+        else:
+            [ID_CLEAR_EXEC_ORDER, ID_RESET_EXEC_ORDER] = [wx.NewId() for i in xrange(2)]
+        
+            # Create menu items
+            self.AddMenuItems(menu, [
+                 (ID_CLEAR_EXEC_ORDER, wx.ITEM_NORMAL, _(u'Clear Execution Order'), '', self.OnClearExecutionOrderMenu),
+                 (ID_RESET_EXEC_ORDER, wx.ITEM_NORMAL, _(u'Reset Execution Order'), '', self.OnResetExecutionOrderMenu)])
+            
+            menu.AppendSeparator()
+            
+            add_menu = wx.Menu(title='')
+            self.AddAddMenuItems(add_menu)
+            menu.AppendMenu(-1, _(u'Add'), add_menu)
+        
+        menu.AppendSeparator()
+        
+        [ID_CUT, ID_COPY, ID_PASTE] = [wx.NewId() for i in xrange(3)]
+        
+        # Create menu items
+        self.AddMenuItems(menu, [
+             (ID_CUT, wx.ITEM_NORMAL, _(u'Cut'), '', self.GetClipboardCallBack(self.Cut)),
+             (ID_COPY, wx.ITEM_NORMAL, _(u'Copy'), '', self.GetClipboardCallBack(self.Copy)),
+             (ID_PASTE, wx.ITEM_NORMAL, _(u'Paste'), '', self.GetAddMenuCallBack(self.Paste))])
+        
+        menu.Enable(ID_CUT, block)
+        menu.Enable(ID_COPY, block)
+        menu.Enable(ID_PASTE, self.ParentWindow.GetCopyBuffer() is not None)
+        
     def _init_Editor(self, prnt):
         self.Editor = wx.ScrolledWindow(prnt, name="Viewer", 
             pos=wx.Point(0, 0), size=wx.Size(0, 0), 
@@ -464,8 +525,6 @@
         EditorPanel.__init__(self, parent, tagname, window, controler, debug)
         DebugViewer.__init__(self, controler, debug)
         
-        self._init_menus()
-        
         # Adding a rubberband to Viewer
         self.rubberBand = RubberBand(viewer=self)
         self.Editor.SetBackgroundColour(wx.Colour(255,255,255))
@@ -1217,92 +1276,49 @@
             else:
                 menu.Enable(new_id, False)
             self.Editor.PopupMenu(menu)
+            menu.Destroy()
 
     def PopupBlockMenu(self, connector = None):
+        menu = wx.Menu(title='')
         if connector is not None and connector.IsCompatible("BOOL"):
-            type = self.Controler.GetEditedElementType(self.TagName, self.Debug)
-            self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, True)
-            self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS1, True)
-            self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS2, type != "function")
-            self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS3, type != "function")
+            self.AddBlockPinMenuItems(menu, connector)
         else:
-            self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False)
-            self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS1, False)
-            self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS2, False)
-            self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS3, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS5, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS6, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS8, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS9, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, self.SelectedElement.GetType() in self.Controler.GetProjectPouNames(self.Debug))
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, True)
-        if connector is not None:
-            if connector.IsNegated():
-                self.ContextualMenu.Check(ID_VIEWERCONTEXTUALMENUITEMS1, True)
-            elif connector.GetEdge() == "rising":
-                self.ContextualMenu.Check(ID_VIEWERCONTEXTUALMENUITEMS2, True)
-            elif connector.GetEdge() == "falling":
-                self.ContextualMenu.Check(ID_VIEWERCONTEXTUALMENUITEMS3, True)
-            else:
-                self.ContextualMenu.Check(ID_VIEWERCONTEXTUALMENUITEMS0, True)
-        self.Editor.PopupMenu(self.ContextualMenu)
+            edit = self.SelectedElement.GetType() in self.Controler.GetProjectPouNames(self.Debug)
+            self.AddDefaultMenuItems(menu, block=True, edit=edit)
+        self.Editor.PopupMenu(menu)
+        menu.Destroy()
     
     def PopupWireMenu(self, delete=True):
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS1, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS2, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS3, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS5, True)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS6, delete)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS8, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS9, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, True)
-        self.Editor.PopupMenu(self.ContextualMenu)
-    
+        menu = wx.Menu(title='')
+        self.AddWireMenuItems(menu, delete)
+        menu.AppendSeparator()
+        self.AddDefaultMenuItems(menu, block=True)
+        self.Editor.PopupMenu(menu)
+        menu.Destroy()
+        
     def PopupDivergenceMenu(self, connector):
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS1, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS2, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS3, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS5, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS6, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS8, True)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS9, connector)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, True)
-        self.Editor.PopupMenu(self.ContextualMenu)
+        menu = wx.Menu(title='')
+        self.AddDivergenceMenuItems(menu, connector)
+        menu.AppendSeparator()
+        self.AddDefaultMenuItems(menu, block=True)
+        self.Editor.PopupMenu(menu)
+        menu.Destroy()
     
     def PopupGroupMenu(self):
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS1, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS2, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS3, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS5, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS6, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS8, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS9, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, True)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, True)
-        self.Editor.PopupMenu(self.ContextualMenu)
-    
-    def PopupDefaultMenu(self, block = True):
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS0, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS1, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS2, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS3, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS5, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS6, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS8, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS9, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS14, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS16, False)
-        self.ContextualMenu.Enable(ID_VIEWERCONTEXTUALMENUITEMS17, block)
-        self.Editor.PopupMenu(self.ContextualMenu)
+        menu = wx.Menu(title='')
+        align_menu = wx.Menu(title='')
+        self.AddAlignmentMenuItems(align_menu)
+        menu.AppenMenu(-1, _(u'Alignment'), align_menu)
+        menu.AppendSeparator()
+        self.AddDefaultMenuItems(menu, block=True)
+        self.Editor.PopupMenu(menu)
+        menu.Destroy()
+        
+    def PopupDefaultMenu(self, block=True):
+        menu = wx.Menu(title='')
+        self.AddDefaultMenuItems(menu, block=block)
+        self.Editor.PopupMenu(menu)
+        menu.Destroy()
 
 #-------------------------------------------------------------------------------
 #                            Menu items functions
@@ -1407,6 +1423,16 @@
         self.RefreshBuffer()
         self.RefreshView()
 
+    def GetAddMenuCallBack(self, func, *args):
+        def AddMenuCallBack(event):
+            wx.CallAfter(func, self.rubberBand.GetCurrentExtent(), *args)
+        return AddMenuCallBack
+
+    def GetClipboardCallBack(self, func):
+        def ClipboardCallback(event):
+            wx.CallAfter(func)
+        return ClipboardCallback
+
 #-------------------------------------------------------------------------------
 #                          Mouse event functions
 #-------------------------------------------------------------------------------
@@ -1427,6 +1453,7 @@
         event.Skip()
     
     def OnViewerLeftDown(self, event):
+        self.Editor.CaptureMouse()
         if self.Mode == MODE_SELECTION:
             dc = self.GetLogicalDC()
             pos = event.GetLogicalPosition(dc)
@@ -1605,9 +1632,12 @@
             self.StartScreenPos = None
         if self.Mode != MODE_SELECTION and not self.SavedMode:
             wx.CallAfter(self.ParentWindow.ResetCurrentMode)
+        if self.Editor.HasCapture():
+            self.Editor.ReleaseMouse()
         event.Skip()
     
     def OnViewerMiddleDown(self, event):
+        self.Editor.CaptureMouse()
         self.StartMousePos = event.GetPosition()
         self.StartScreenPos = self.GetScrollPos(wx.HORIZONTAL), self.GetScrollPos(wx.VERTICAL)
         event.Skip()
@@ -1615,9 +1645,12 @@
     def OnViewerMiddleUp(self, event):
         self.StartMousePos = None
         self.StartScreenPos = None
+        if self.Editor.HasCapture():
+            self.Editor.ReleaseMouse()
         event.Skip()
     
     def OnViewerRightDown(self, event):
+        self.Editor.CaptureMouse()
         if self.Mode == MODE_SELECTION:
             element = self.FindElement(event)
             if self.SelectedElement is not None and self.SelectedElement != element:
@@ -1633,6 +1666,10 @@
         event.Skip()
     
     def OnViewerRightUp(self, event):
+        dc = self.GetLogicalDC()
+        self.rubberBand.Reset()
+        self.rubberBand.OnLeftDown(event, dc, self.Scaling)
+        self.rubberBand.OnLeftUp(event, dc, self.Scaling)
         if self.SelectedElement is not None:
             if self.Debug:
                 Graphic_Element.OnRightUp(self.SelectedElement, event, self.GetLogicalDC(), self.Scaling)
@@ -1641,6 +1678,8 @@
             wx.CallAfter(self.SetCurrentCursor, 0)
         elif not self.Debug:
             self.PopupDefaultMenu(False)
+        if self.Editor.HasCapture():
+            self.Editor.ReleaseMouse()
         event.Skip()
     
     def OnViewerLeftDClick(self, event):
@@ -1672,6 +1711,8 @@
         event.Skip()
     
     def OnViewerMotion(self, event):
+        if self.Editor.HasCapture() and not event.Dragging():
+            return
         refresh = False
         dc = self.GetLogicalDC()
         pos = GetScaledEventPosition(event, dc, self.Scaling)
@@ -2794,16 +2835,20 @@
             text = self.Controler.GetEditedElementInstancesCopy(self.TagName, blocks, wires, self.Debug)
             self.ParentWindow.SetCopyBuffer(text)
             
-    def Paste(self):
+    def Paste(self, bbx=None):
         if not self.Debug:
             element = self.ParentWindow.GetCopyBuffer()
-            mouse_pos = self.Editor.ScreenToClient(wx.GetMousePosition())
-            middle = wx.Rect(0, 0, *self.Editor.GetClientSize()).InsideXY(mouse_pos.x, mouse_pos.y)
-            if middle:
-                x, y = self.CalcUnscrolledPosition(mouse_pos.x, mouse_pos.y)
+            if bbx is None:
+                mouse_pos = self.Editor.ScreenToClient(wx.GetMousePosition())
+                middle = wx.Rect(0, 0, *self.Editor.GetClientSize()).InsideXY(mouse_pos.x, mouse_pos.y)
+                if middle:
+                    x, y = self.CalcUnscrolledPosition(mouse_pos.x, mouse_pos.y)
+                else:
+                    x, y = self.CalcUnscrolledPosition(0, 0)
+                new_pos = [int(x / self.ViewScale[0]), int(y / self.ViewScale[1])]
             else:
-                x, y = self.CalcUnscrolledPosition(0, 0)
-            new_pos = [int(x / self.ViewScale[0]), int(y / self.ViewScale[1])]
+                middle = True
+                new_pos = [bbx.x, bbx.y]
             result = self.Controler.PasteEditedElementInstances(self.TagName, element, new_pos, middle, self.Debug)
             if not isinstance(result, (StringType, UnicodeType)):
                 self.RefreshBuffer()
@@ -2927,6 +2972,8 @@
 #-------------------------------------------------------------------------------
 
     def OnScrollWindow(self, event):
+        if self.Editor.HasCapture():
+            return
         if wx.Platform == '__WXMSW__':
             wx.CallAfter(self.RefreshVisibleElements)
         elif event.GetOrientation() == wx.HORIZONTAL: