Bug with Scaling, MiddleButton, Wire modifications fixed.
authorlbessard
Thu, 19 Mar 2009 18:10:12 +0100
changeset 331 9106d66bd204
parent 330 d803ba077da0
child 332 555124c752ec
Bug with Scaling, MiddleButton, Wire modifications fixed.
Adding support for:
- Adjust one or more elements to grid
- Select All elements in a Viewer
- Maximize Viewer in Window
GraphicViewer.py
PLCOpenEditor.py
SFCViewer.py
Viewer.py
graphics/GraphicCommons.py
--- a/GraphicViewer.py	Wed Mar 18 16:42:12 2009 +0100
+++ b/GraphicViewer.py	Thu Mar 19 18:10:12 2009 +0100
@@ -194,6 +194,9 @@
     def RefreshScaling(self, refresh=True):
         pass
     
+    def SelectAll(self):
+        pass
+    
     def AddPoint(self, tick, value):
         self.Datas.append((float(tick), {True:1., False:0.}.get(value, float(value))))
         if self.CurrentValue + self.CurrentRange == len(self.Datas) - 1:
--- a/PLCOpenEditor.py	Wed Mar 18 16:42:12 2009 +0100
+++ b/PLCOpenEditor.py	Thu Mar 19 18:10:12 2009 +0100
@@ -283,6 +283,8 @@
                   kind=wx.ITEM_NORMAL, text=u'Program')
             AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION,
                   kind=wx.ITEM_NORMAL, text=u'Configuration')
+            AppendMenu(parent, help='', id=wx.ID_SELECTALL,
+                  kind=wx.ITEM_NORMAL, text=u'Select All\tCTRL+A')
             AppendMenu(parent, help='', id=wx.ID_DELETE,
                   kind=wx.ITEM_NORMAL, text=u'Delete')
         self.Bind(wx.EVT_MENU, self.OnRefreshMenu, id=wx.ID_REFRESH)
@@ -304,6 +306,7 @@
                   id=ID_PLCOPENEDITOREDITMENUADDPROGRAM)
             self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu,
                   id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION)
+            self.Bind(wx.EVT_MENU, self.OnSelectAllMenu, id=wx.ID_SELECTALL)
             self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=wx.ID_DELETE)
 
     def _init_coll_HelpMenu_Items(self, parent):
@@ -662,6 +665,11 @@
         else:
             self.SetTitle(name)
 
+    def RefreshScaling(self):
+        for i in xrange(self.TabsOpened.GetPageCount()):
+            editor = self.TabsOpened.GetPage(i)
+            editor.RefreshScaling()
+
     def ShowProperties(self):
         old_values = self.Controler.GetProjectProperties(self.Debug)
         dialog = ProjectDialog(self)
@@ -675,9 +683,7 @@
                 self.RefreshFileMenu()
                 self.RefreshEditMenu()
                 self.RefreshTypesTree()
-                for i in xrange(self.TabsOpened.GetPageCount()):
-                    editor = self.TabsOpened.GetPage(i)
-                    editor.RefreshScaling()
+                self.RefreshScaling()
         dialog.Destroy()
 
     def OnCloseFrame(self, event):
@@ -1002,21 +1008,31 @@
                 self.EditMenu.Enable(wx.ID_REDO, redo)
                 self.EditMenu.Enable(wx.ID_ADD, True)
                 self.EditMenu.Enable(wx.ID_DELETE, True)
+                if self.TabsOpened.GetPageCount() > 0:
+                    self.EditMenu.Enable(wx.ID_CUT, True)
+                    self.EditMenu.Enable(wx.ID_COPY, True)
+                    if self.CopyBuffer is not None:
+                        self.EditMenu.Enable(wx.ID_PASTE, True)
+                    else:
+                        self.EditMenu.Enable(wx.ID_PASTE, False)
+                    self.EditMenu.Enable(wx.ID_SELECTALL, True)
+                else:
+                    self.EditMenu.Enable(wx.ID_CUT, False)
+                    self.EditMenu.Enable(wx.ID_COPY, False)
+                    self.EditMenu.Enable(wx.ID_PASTE, False)
+                    self.EditMenu.Enable(wx.ID_SELECTALL, False)
         else:
             self.EditMenu.Enable(wx.ID_REFRESH, False)
             if not self.Debug:
                 self.EditMenu.Enable(wx.ID_UNDO, False)
                 self.EditMenu.Enable(wx.ID_REDO, False)
+                self.EditMenu.Enable(wx.ID_CUT, False)
+                self.EditMenu.Enable(wx.ID_COPY, False)
+                self.EditMenu.Enable(wx.ID_PASTE, False)
+                self.EditMenu.Enable(wx.ID_SELECTALL, False)
                 self.EditMenu.Enable(wx.ID_ADD, False)
                 self.EditMenu.Enable(wx.ID_DELETE, False)
-        if not self.Debug:
-            self.EditMenu.Enable(wx.ID_CUT, True)
-            self.EditMenu.Enable(wx.ID_COPY, True)
-            if self.CopyBuffer is not None:
-                self.EditMenu.Enable(wx.ID_PASTE, True)
-            else:
-                self.EditMenu.Enable(wx.ID_PASTE, False)
-
+    
     def OnRefreshMenu(self, event):
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
@@ -1049,6 +1065,7 @@
         self.RefreshTypesTree()
         self.RefreshInstancesTree()
         self.RefreshLibraryTree()
+        self.RefreshScaling()
         event.Skip()
     
     def OnRedoMenu(self, event):
@@ -1070,6 +1087,7 @@
         self.RefreshTypesTree()
         self.RefreshInstancesTree()
         self.RefreshLibraryTree()
+        self.RefreshScaling()
         event.Skip()
 
     def OnCutMenu(self, event):
@@ -1096,6 +1114,13 @@
             control.ProcessEvent(event)
         event.Skip()
     
+    def OnSelectAllMenu(self, event):
+        selected = self.TabsOpened.GetSelection()        
+        if selected != -1:
+            window = self.TabsOpened.GetPage(selected)
+            window.SelectAll()
+        event.Skip()
+    
     def OnDeleteMenu(self, event):
         window = self.FindFocus()
         if window == self.TypesTree:
@@ -1242,6 +1267,16 @@
             else:
                 self.TabsOpened.SetPageText(idx, "-".join(words[1:]))
 
+    def GetTabsOpenedDClickFunction(self, window):
+        def OnTabsOpenedDClick(event):
+            pane = self.AUIManager.GetPane(self.TabsOpened)
+            if pane.IsMaximized():
+                self.AUIManager.RestorePane(pane)
+            else:
+                self.AUIManager.MaximizePane(pane)
+            self.AUIManager.Update()
+            event.Skip()
+        return OnTabsOpenedDClick
 
 #-------------------------------------------------------------------------------
 #                         Types Tree Management Functions
@@ -1604,6 +1639,9 @@
             elif elementtype == ITEM_DATATYPE:
                 new_window = DataTypeEditor(self.TabsOpened, tagname, self, self.Controler)
                 self.TabsOpened.AddPage(new_window, "")
+            if wx.VERSION >= (2, 6, 0):
+                children = self.TabsOpened.GetChildren()
+                children[len(children) - 1].Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(new_window))  
             self.VariablePanelIndexer.ChangeVariablePanel(tagname)
             openedidx = self.IsOpened(tagname)
             old_selected = self.TabsOpened.GetSelection()
@@ -3918,7 +3956,7 @@
     
     def _init_coll_MainSizer_Items(self, parent):
         parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
-        parent.AddSizer(self.ControlPanelSizer, 0, border=0, flag=wx.GROW)
+        parent.AddSizer(self.ControlPanelSizer, 0, border=5, flag=wx.GROW|wx.ALL)
     
     def _init_coll_MainSizer_Growables(self, parent):
         parent.AddGrowableCol(0)
@@ -3954,9 +3992,9 @@
 
     def _init_sizers(self):
         self.MainSizer = wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=0)
-        self.ControlPanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
+        self.ControlPanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
         self.ChoicePanelSizer = wx.GridSizer(cols=1, hgap=5, rows=4, vgap=5)
-        self.ButtonPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=0)
+        self.ButtonPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
         
         self._init_coll_MainSizer_Items(self.MainSizer)
         self._init_coll_MainSizer_Growables(self.MainSizer)
@@ -4084,7 +4122,7 @@
             self.ReturnType.Enable(False)
             self.staticText1.Hide()
             self.ReturnType.Hide()
-        
+            
         self.VariablesGrid.SetTable(self.Table)
         self.VariablesGrid.SetRowLabelSize(0)
         for col in range(self.Table.GetNumberCols()):
--- a/SFCViewer.py	Wed Mar 18 16:42:12 2009 +0100
+++ b/SFCViewer.py	Thu Mar 19 18:10:12 2009 +0100
@@ -170,7 +170,7 @@
         elif self.Mode == MODE_SELECTION:
             dc = self.GetLogicalDC()
             pos = event.GetLogicalPosition(dc)
-            if event.ShiftDown():
+            if event.ShiftDown() and not event.ControlDown() and self.SelectedElement is not None:
                 element = self.FindElement(pos, True)
                 if element and not self.IsWire(element):
                     if isinstance(self.SelectedElement, Graphic_Group):
@@ -186,6 +186,7 @@
                         self.SelectedElement = element
                     elif len(elements) == 1:
                         self.SelectedElement = elements[0]
+                    self.SelectedElement.SetSelected(True)
             else:
                 element = self.FindElement(pos)
                 if self.SelectedElement and self.SelectedElement != element:
--- a/Viewer.py	Wed Mar 18 16:42:12 2009 +0100
+++ b/Viewer.py	Thu Mar 19 18:10:12 2009 +0100
@@ -1068,6 +1068,14 @@
                 elements.append(element)
         return elements
 
+    def SelectAll(self):
+        if self.SelectedElement is not None:
+            self.SelectedElement.SetSelected(False)
+        self.SelectedElement = Graphic_Group(self)
+        for element in self.GetElements():
+            self.SelectedElement.SelectElement(element)
+        self.SelectedElement.SetSelected(True)
+    
 #-------------------------------------------------------------------------------
 #                           Popup menu functions
 #-------------------------------------------------------------------------------
@@ -1285,7 +1293,7 @@
         if self.Mode == MODE_SELECTION:
             dc = self.GetLogicalDC()
             pos = event.GetLogicalPosition(dc)
-            if event.ShiftDown() and self.SelectedElement is not None:
+            if event.ShiftDown() and not event.ControlDown() and self.SelectedElement is not None:
                 element = self.FindElement(pos, True)
                 if element is not None:
                     if isinstance(self.SelectedElement, Graphic_Group):
@@ -1487,8 +1495,15 @@
         if self.Mode == MODE_SELECTION and self.SelectedElement is not None:
             if self.Debug:
                 Graphic_Element.OnLeftDClick(self.SelectedElement, event, self.GetLogicalDC(), self.Scaling)
-            elif event.ControlDown() and self.IsBlock(self.SelectedElement) and self.SelectedElement.GetType() in self.Controler.GetProjectPouNames(self.Debug):
-                self.ParentWindow.EditProjectElement(ITEM_POU, self.SelectedElement.GetType())
+            elif event.ControlDown() and not event.ShiftDown():
+                if self.IsBlock(self.SelectedElement) and self.SelectedElement.GetType() in self.Controler.GetProjectPouNames(self.Debug):
+                    self.ParentWindow.EditProjectElement(ITEM_POU, self.SelectedElement.GetType())
+            elif event.ControlDown() and event.ShiftDown():
+                movex, movey = self.SelectedElement.AdjustToScaling(self.Scaling)
+                self.SelectedElement.RefreshModel()
+                self.RefreshBuffer()
+                if movex != 0 or movey != 0:
+                    self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(movex, movey)), False)
             else:
                 self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
         event.Skip()
@@ -1502,8 +1517,8 @@
                 new_pos = event.GetPosition()
                 xmax = self.GetScrollRange(wx.HORIZONTAL) - self.GetScrollThumb(wx.HORIZONTAL)
                 ymax = self.GetScrollRange(wx.VERTICAL) - self.GetScrollThumb(wx.VERTICAL)
-                scrollx = max(0, self.StartScreenPos[0] + (new_pos[0] - self.StartMousePos[0]) * self.ViewScale[0] / SCROLLBAR_UNIT)
-                scrolly = max(0, self.StartScreenPos[1] + (new_pos[1] - self.StartMousePos[1]) * self.ViewScale[1] / SCROLLBAR_UNIT)
+                scrollx = max(0, self.StartScreenPos[0] - (new_pos[0] - self.StartMousePos[0]) / SCROLLBAR_UNIT)
+                scrolly = max(0, self.StartScreenPos[1] - (new_pos[1] - self.StartMousePos[1]) / SCROLLBAR_UNIT)
                 if scrollx > xmax or scrolly > ymax:
                     self.RefreshScrollBars(max(0, scrollx - xmax), max(0, scrolly - ymax))
                     self.Scroll(scrollx, scrolly)
@@ -2692,8 +2707,10 @@
                 dc = self.GetLogicalDC()
                 pos = event.GetLogicalPosition(dc)
                 mouse_pos = event.GetPosition()
-                factor = 0.75 ** rotation
-                self.SetScale(self.ViewScale[0] * factor, self.ViewScale[1] * factor)
+                factor = 1.414 ** rotation
+                xscale = max(0.125, min(self.ViewScale[0] * factor, 8))
+                yscale = max(0.125, min(self.ViewScale[0] * factor, 8))
+                self.SetScale(xscale, yscale)
                 self.Scroll(round(pos.x * self.ViewScale[0] - mouse_pos.x) / SCROLLBAR_UNIT,
                             round(pos.y * self.ViewScale[1] - mouse_pos.y) / SCROLLBAR_UNIT)
                 self.RefreshScrollBars()
@@ -2731,17 +2748,17 @@
             width, height = self.GetVirtualSize()
             width = int(max(width, xstart * SCROLLBAR_UNIT + window_size[0]) / self.ViewScale[0])
             height = int(max(height, ystart * SCROLLBAR_UNIT + window_size[1]) / self.ViewScale[1])
-            dc.DrawRectangle(0, 0, width, height)
+            dc.DrawRectangle(1, 1, width, height)
         if self.PageSize is not None and not printing:
             dc.SetPen(self.PagePen)
             xstart, ystart = self.GetViewStart()
             window_size = self.GetClientSize()
-            for x in xrange(self.PageSize[0] - (xstart * SCROLLBAR_UNIT) % self.PageSize[0], window_size[0], self.PageSize[0]):
-                dc.DrawLine(xstart * SCROLLBAR_UNIT + x + 1, ystart * SCROLLBAR_UNIT, 
-                            xstart * SCROLLBAR_UNIT + x + 1, ystart * SCROLLBAR_UNIT + window_size[1])
-            for y in xrange(self.PageSize[1] - (ystart * SCROLLBAR_UNIT) % self.PageSize[1], window_size[1], self.PageSize[1]):
-                dc.DrawLine(xstart * SCROLLBAR_UNIT, ystart * SCROLLBAR_UNIT + y + 1, 
-                            xstart * SCROLLBAR_UNIT + window_size[0], ystart * SCROLLBAR_UNIT + y + 1)
+            for x in xrange(self.PageSize[0] - (xstart * SCROLLBAR_UNIT) % self.PageSize[0], int(window_size[0] / self.ViewScale[0]), self.PageSize[0]):
+                dc.DrawLine(xstart * SCROLLBAR_UNIT + x + 1, int(ystart * SCROLLBAR_UNIT / self.ViewScale[0]), 
+                            xstart * SCROLLBAR_UNIT + x + 1, int((ystart * SCROLLBAR_UNIT + window_size[1]) / self.ViewScale[0]))
+            for y in xrange(self.PageSize[1] - (ystart * SCROLLBAR_UNIT) % self.PageSize[1], int(window_size[1] / self.ViewScale[1]), self.PageSize[1]):
+                dc.DrawLine(int(xstart * SCROLLBAR_UNIT / self.ViewScale[0]), ystart * SCROLLBAR_UNIT + y + 1, 
+                            int((xstart * SCROLLBAR_UNIT + window_size[0]) / self.ViewScale[1]), ystart * SCROLLBAR_UNIT + y + 1)
         
         # Draw all elements
         for comment in self.Comments:
--- a/graphics/GraphicCommons.py	Wed Mar 18 16:42:12 2009 +0100
+++ b/graphics/GraphicCommons.py	Thu Mar 19 18:10:12 2009 +0100
@@ -115,6 +115,16 @@
     (2, 3) : 5
 }
 
+def round_scaling(x, n, constraint=0):
+    fraction = float(x) / float(n)
+    if constraint == - 1:
+        xround = int(fraction)
+    else:
+        xround = round(fraction)
+        if constraint == 1 and int(fraction) == xround:
+            xround += 1
+    return xround * n
+
 """
 Basic vector operations for calculate wire points
 """
@@ -371,6 +381,10 @@
     def GetSize(self):
         return self.Size.GetWidth(), self.Size.GetHeight()
     
+    # Returns the minimum element size
+    def GetMinSize(self):
+        return 0, 0
+    
     # Refresh the element Bounding Box
     def RefreshBoundingBox(self):
         self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1])
@@ -566,6 +580,20 @@
         self.Move(x, y)
         self.SetSize(width, height)
     
+    # Moves and Resizes the element for fitting scaling
+    def AdjustToScaling(self, scaling):
+        if scaling is not None:
+            movex = round_scaling(self.Pos.x, scaling[0]) - self.Pos.x
+            movey = round_scaling(self.Pos.y, scaling[1]) - self.Pos.y
+            min_width, min_height = self.GetMinSize()
+            width = max(round_scaling(min_width, scaling[0], 1),
+                        round_scaling(self.Size.width, scaling[0]))
+            height = max(round_scaling(min_height, scaling[1], 1),
+                         round_scaling(self.Size.height, scaling[1]))
+            self.Resize(movex, movey, width, height)
+            return movex, movey
+        return 0, 0
+    
     # Refreshes the element state according to move defined and handle selected
     def ProcessDragging(self, movex, movey, event, scaling, width_fac = 1, height_fac = 1):
         handle_type, handle = self.Handle
@@ -579,7 +607,7 @@
             if handle[0] == 1:
                 movex = max(-self.BoundingBox.x, movex)
                 if scaling is not None:
-                    movex = -(round(float(width - movex) / float(scaling[0])) * scaling[0] - width)
+                    movex = -(round_scaling(width - movex, scaling[0]) - width)
                 x = movex
                 if event.ShiftDown():
                     width -= 2 * movex
@@ -587,7 +615,7 @@
                     width -= movex
             elif handle[0] == 3:
                 if scaling is not None:
-                    movex = round(float(width + movex) / float(scaling[0])) * scaling[0] - width
+                    movex = round_scaling(width + movex, scaling[0]) - width
                 if event.ShiftDown():
                     x = -movex
                     width += 2 * movex
@@ -596,7 +624,7 @@
             if handle[1] == 1:
                 movey = max(-self.BoundingBox.y, movey)
                 if scaling is not None:
-                    movey = -(round(float(height - movey) / float(scaling[1])) * scaling[1] - height)
+                    movey = -(round_scaling(height - movey, scaling[1]) - height)
                 y = movey
                 if event.ShiftDown():
                     height -= 2 * movey
@@ -604,7 +632,7 @@
                     height -= movey
             elif handle[1] == 3:
                 if scaling is not None:
-                    movey = round(float(height + movey) / float(scaling[1])) * scaling[1] - height
+                    movey = round_scaling(height + movey, scaling[1]) - height
                 if event.ShiftDown():
                     y = -movey
                     height += 2 * movey
@@ -630,8 +658,8 @@
             movex = max(-self.BoundingBox.x, movex)
             movey = max(-self.BoundingBox.y, movey)
             if scaling is not None:
-                movex = round(float(self.Pos.x + movex) / float(scaling[0])) * scaling[0] - self.Pos.x
-                movey = round(float(self.Pos.y + movey) / float(scaling[1])) * scaling[1] - self.Pos.y
+                movex = round_scaling(self.Pos.x + movex, scaling[0]) - self.Pos.x
+                movey = round_scaling(self.Pos.y + movey, scaling[1]) - self.Pos.y
             if event.ControlDown():
                 self.CurrentDrag.x = self.CurrentDrag.x + movex
                 self.CurrentDrag.y = self.CurrentDrag.y + movey
@@ -900,6 +928,15 @@
     def GetSize(self):
         return self.BoundingBox.width, self.BoundingBox.height
 
+    # Moves and Resizes the group elements for fitting scaling
+    def AdjustToScaling(self, scaling):
+        movex_max = movey_max = 0
+        for element in self.Elements:
+            movex, movey = element.AdjustToScaling(scaling)
+            movex_max = max(movex_max, abs(movex))
+            movey_max = max(movey_max, abs(movey))
+        return movex_max, movey_max
+    
     # Change the variable that indicates if this element is highlighted
     def SetHighlighted(self, highlighted):
         for element in self.Elements:
@@ -1397,6 +1434,39 @@
     def SetSize(width, height):
         pass
     
+    # Moves and Resizes the element for fitting scaling
+    def AdjustToScaling(self, scaling):
+        if scaling is not None:
+            movex_max = movey_max = 0
+            for idx, point in enumerate(self.Points):
+                if 0 < idx < len(self.Points) - 1:
+                    movex = round_scaling(point.x, scaling[0]) - point.x
+                    movey = round_scaling(point.y, scaling[1]) - point.y
+                    if idx == 1:
+                        if self.Segments[0][0] == 0:
+                            movex = 0
+                        elif (point.x + movex - self.Points[0].x) * self.Segments[0][0] < MIN_SEGMENT_SIZE:
+                            movex = round_scaling(self.Points[0].x + MIN_SEGMENT_SIZE * self.Segments[0][0], scaling[0], self.Segments[0][0]) - point.x
+                        if self.Segments[0][1] == 0:
+                            movey = 0
+                        elif (point.y + movey - self.Points[0].y) * self.Segments[0][1] < MIN_SEGMENT_SIZE:
+                            movey = round_scaling(self.Points[0].y + MIN_SEGMENT_SIZE * self.Segments[0][1], scaling[0], self.Segments[0][1]) - point.y
+                    elif idx == len(self.Points) - 2:
+                        if self.Segments[-1][0] == 0:
+                            movex = 0
+                        elif (self.Points[-1].x - (point.x + movex)) * self.Segments[-1][0] < MIN_SEGMENT_SIZE:
+                            movex = round_scaling(self.Points[-1].x + MIN_SEGMENT_SIZE * self.Segments[0][0], scaling[0], self.Segments[0][0]) - point.x
+                        if self.Segments[-1][1] == 0:
+                            movey = 0
+                        elif (self.Points[-1].y - (point.y + movey)) * self.Segments[-1][1] < MIN_SEGMENT_SIZE:
+                            movey = round_scaling(self.Points[-1].y - MIN_SEGMENT_SIZE * self.Segments[-1][1], scaling[1], -self.Segments[-1][1]) - point.y
+                    movex_max = max(movex_max, movex)
+                    movey_max = max(movey_max, movey)
+                    point.x += movex
+                    point.y += movey
+            return movex_max, movey_max
+        return 0, 0
+    
     # Returns connector to which start point is connected
     def GetStartConnected(self):
         return self.StartConnected
@@ -2029,7 +2099,11 @@
             if self.Segments[idx] in (NORTH, SOUTH):
                 start_x = self.Points[idx].x
                 if scaling is not None:
-                    movex = round(float(self.Points[idx].x + movex) / float(scaling[0])) * scaling[0] - self.Points[idx].x
+                    movex = round_scaling(self.Points[idx].x + movex, scaling[0]) - self.Points[idx].x
+                    if idx == 1 and (self.Points[1].x + movex - self.Points[0].x) * self.Segments[0][0] < MIN_SEGMENT_SIZE:
+                        movex = round_scaling(self.Points[0].x + MIN_SEGMENT_SIZE * self.Segments[0][0], scaling[0], self.Segments[0][0]) - self.Points[idx].x
+                    elif idx == len(self.Segments) - 2 and (self.Points[-1].x - (self.Points[-2].x + movex)) * self.Segments[-1][0] < MIN_SEGMENT_SIZE:
+                        movex = round_scaling(self.Points[-1].x - MIN_SEGMENT_SIZE * self.Segments[-1][0], scaling[0], -self.Segments[-1][0]) - self.Points[idx].x
                 self.Points[idx].x += movex
                 self.Points[idx + 1].x += movex
                 self.GeneratePoints()
@@ -2038,7 +2112,11 @@
             elif self.Segments[idx] in (EAST, WEST):
                 start_y = self.Points[idx].y
                 if scaling is not None:
-                    movey = round(float(self.Points[idx].y + movey) / float(scaling[1])) * scaling[1] - self.Points[idx].y
+                    movey = round_scaling(self.Points[idx].y + movey, scaling[1]) - self.Points[idx].y
+                    if idx == 1 and (self.Points[1].y + movey - self.Points[0].y) * self.Segments[0][1] < MIN_SEGMENT_SIZE:
+                        movex = round_scaling(self.Points[0].y + MIN_SEGMENT_SIZE * self.Segments[0][1], scaling[0], self.Segments[0][1]) - self.Points[idx].y
+                    elif idx == len(self.Segments) - 2 and (self.Points[-1].y - (self.Points[-2].y + movey)) * self.Segments[-1][1] < MIN_SEGMENT_SIZE:
+                        movey = round_scaling(self.Points[idx].y - MIN_SEGMENT_SIZE * self.Segments[-1][1], scaling[1], -self.Segments[-1][1]) - self.Points[idx].y
                 self.Points[idx].y += movey
                 self.Points[idx + 1].y += movey
                 self.GeneratePoints()
@@ -2220,8 +2298,8 @@
             movex = max(-self.Points[handle].x + POINT_RADIUS, movex)
             movey = max(-self.Points[handle].y + POINT_RADIUS, movey)
             if scaling is not None:
-                movex = round(float(self.Points[handle].x + movex) / float(scaling[0])) * scaling[0] - self.Points[handle].x
-                movey = round(float(self.Points[handle].y + movey) / float(scaling[1])) * scaling[1] - self.Points[handle].y
+                movex = round_scaling(self.Points[handle].x + movex, scaling[0]) - self.Points[handle].x
+                movey = round_scaling(self.Points[handle].y + movey, scaling[1]) - self.Points[handle].y
             # Try to connect point to a connector
             new_pos = wx.Point(self.Points[handle].x + movex, self.Points[handle].y + movey)
             connector = self.Parent.FindBlockConnector(new_pos, self.GetConnectionDirection())