Преглед изворни кода

- optimized the Move Tool
- added support for key-based panning in 3D graphic engine. Moving the mouse wheel while pressing the CTRL key will pan up-down and while pressing SHIFT key will pan left-right

Marius Stanciu пре 6 година
родитељ
комит
3bebc16725

+ 108 - 103
FlatCAMApp.py

@@ -7996,7 +7996,7 @@ class App(QtCore.QObject):
         except Exception as e:
             App.log.debug("App.on_mouse_click_over_plot() --> Outside plot? --> %s" % str(e))
 
-    def on_double_click_over_plot(self, event):
+    def on_mouse_double_click_over_plot(self, event):
         if event.button == 1:
             self.doubleclick = True
 
@@ -8207,7 +8207,12 @@ class App(QtCore.QObject):
         """
         poly_selection = Polygon([start_pos, (end_pos[0], start_pos[1]), end_pos, (start_pos[0], end_pos[1])])
 
+        # delete previous selection shape
         self.delete_selection_shape()
+
+        # make all objects inactive
+        self.collection.set_all_inactive()
+        
         for obj in self.collection.get_list():
             try:
                 # select the object(s) only if it is enabled (plotted)
@@ -11510,7 +11515,7 @@ class App(QtCore.QObject):
         self.mm = self.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move_over_plot)
         self.mp = self.plotcanvas.graph_event_connect('mouse_press', self.on_mouse_click_over_plot)
         self.mr = self.plotcanvas.graph_event_connect('mouse_release', self.on_mouse_click_release_over_plot)
-        self.mdc = self.plotcanvas.graph_event_connect('mouse_double_click', self.on_double_click_over_plot)
+        self.mdc = self.plotcanvas.graph_event_connect('mouse_double_click', self.on_mouse_double_click_over_plot)
 
         # Keys over plot enabled
         self.kp = self.plotcanvas.graph_event_connect('key_press', self.ui.keyPressEvent)
@@ -11844,107 +11849,107 @@ class App(QtCore.QObject):
         self.options.update(self.defaults)
         self.options_write_form()
 
-    def on_options_project2app(self):
-        """
-        Callback for Options->Transfer Options->Project=>App. Copies options
-        from project defaults to application defaults.
-
-        :return: None
-        """
-
-        self.report_usage("on_options_project2app")
-
-        self.options_read_form()
-        self.defaults.update(self.options)
-        self.defaults_write_form()
-
-    def on_options_project2object(self):
-        """
-        Callback for Options->Transfer Options->Project=>Object. Copies options
-        from project defaults to the currently selected object.
-
-        :return: None
-        """
-
-        self.report_usage("on_options_project2object")
-
-        self.options_read_form()
-        obj = self.collection.get_active()
-        if obj is None:
-            self.inform.emit('[WARNING_NOTCL] %s' %
-                             _("No object selected."))
-            return
-        for option in self.options:
-            if option.find(obj.kind + "_") == 0:
-                oname = option[len(obj.kind) + 1:]
-                obj.options[oname] = self.options[option]
-        obj.to_form()  # Update UI
-
-    def on_options_object2project(self):
-        """
-        Callback for Options->Transfer Options->Object=>Project. Copies options
-        from the currently selected object to project defaults.
-
-        :return: None
-        """
-
-        self.report_usage("on_options_object2project")
-
-        obj = self.collection.get_active()
-        if obj is None:
-            self.inform.emit('[WARNING_NOTCL] %s' %
-                             _("No object selected."))
-            return
-        obj.read_form()
-        for option in obj.options:
-            if option in ['name']:  # TODO: Handle this better...
-                continue
-            self.options[obj.kind + "_" + option] = obj.options[option]
-        self.options_write_form()
-
-    def on_options_object2app(self):
-        """
-        Callback for Options->Transfer Options->Object=>App. Copies options
-        from the currently selected object to application defaults.
-
-        :return: None
-        """
-
-        self.report_usage("on_options_object2app")
-
-        obj = self.collection.get_active()
-        if obj is None:
-            self.inform.emit('[WARNING_NOTCL] %s' %
-                             _("No object selected."))
-            return
-        obj.read_form()
-        for option in obj.options:
-            if option in ['name']:  # TODO: Handle this better...
-                continue
-            self.defaults[obj.kind + "_" + option] = obj.options[option]
-        self.defaults_write_form()
-
-    def on_options_app2object(self):
-        """
-        Callback for Options->Transfer Options->App=>Object. Copies options
-        from application defaults to the currently selected object.
-
-        :return: None
-        """
-
-        self.report_usage("on_options_app2object")
-
-        self.defaults_read_form()
-        obj = self.collection.get_active()
-        if obj is None:
-            self.inform.emit('[WARNING_NOTCL] %s' %
-                             _("No object selected."))
-            return
-        for option in self.defaults:
-            if option.find(obj.kind + "_") == 0:
-                oname = option[len(obj.kind) + 1:]
-                obj.options[oname] = self.defaults[option]
-        obj.to_form()  # Update UI
+    # def on_options_project2app(self):
+    #     """
+    #     Callback for Options->Transfer Options->Project=>App. Copies options
+    #     from project defaults to application defaults.
+    #
+    #     :return: None
+    #     """
+    #
+    #     self.report_usage("on_options_project2app")
+    #
+    #     self.options_read_form()
+    #     self.defaults.update(self.options)
+    #     self.defaults_write_form()
+
+    # def on_options_project2object(self):
+    #     """
+    #     Callback for Options->Transfer Options->Project=>Object. Copies options
+    #     from project defaults to the currently selected object.
+    #
+    #     :return: None
+    #     """
+    #
+    #     self.report_usage("on_options_project2object")
+    #
+    #     self.options_read_form()
+    #     obj = self.collection.get_active()
+    #     if obj is None:
+    #         self.inform.emit('[WARNING_NOTCL] %s' %
+    #                          _("No object selected."))
+    #         return
+    #     for option in self.options:
+    #         if option.find(obj.kind + "_") == 0:
+    #             oname = option[len(obj.kind) + 1:]
+    #             obj.options[oname] = self.options[option]
+    #     obj.to_form()  # Update UI
+
+    # def on_options_object2project(self):
+    #     """
+    #     Callback for Options->Transfer Options->Object=>Project. Copies options
+    #     from the currently selected object to project defaults.
+    #
+    #     :return: None
+    #     """
+    #
+    #     self.report_usage("on_options_object2project")
+    #
+    #     obj = self.collection.get_active()
+    #     if obj is None:
+    #         self.inform.emit('[WARNING_NOTCL] %s' %
+    #                          _("No object selected."))
+    #         return
+    #     obj.read_form()
+    #     for option in obj.options:
+    #         if option in ['name']:  # TODO: Handle this better...
+    #             continue
+    #         self.options[obj.kind + "_" + option] = obj.options[option]
+    #     self.options_write_form()
+
+    # def on_options_object2app(self):
+    #     """
+    #     Callback for Options->Transfer Options->Object=>App. Copies options
+    #     from the currently selected object to application defaults.
+    #
+    #     :return: None
+    #     """
+    #
+    #     self.report_usage("on_options_object2app")
+    #
+    #     obj = self.collection.get_active()
+    #     if obj is None:
+    #         self.inform.emit('[WARNING_NOTCL] %s' %
+    #                          _("No object selected."))
+    #         return
+    #     obj.read_form()
+    #     for option in obj.options:
+    #         if option in ['name']:  # TODO: Handle this better...
+    #             continue
+    #         self.defaults[obj.kind + "_" + option] = obj.options[option]
+    #     self.defaults_write_form()
+
+    # def on_options_app2object(self):
+    #     """
+    #     Callback for Options->Transfer Options->App=>Object. Copies options
+    #     from application defaults to the currently selected object.
+    #
+    #     :return: None
+    #     """
+    #
+    #     self.report_usage("on_options_app2object")
+    #
+    #     self.defaults_read_form()
+    #     obj = self.collection.get_active()
+    #     if obj is None:
+    #         self.inform.emit('[WARNING_NOTCL] %s' %
+    #                          _("No object selected."))
+    #         return
+    #     for option in self.defaults:
+    #         if option.find(obj.kind + "_") == 0:
+    #             oname = option[len(obj.kind) + 1:]
+    #             obj.options[oname] = self.defaults[option]
+    #     obj.to_form()  # Update UI
 
 
 class ArgsThread(QtCore.QObject):

+ 2 - 0
README.md

@@ -13,6 +13,8 @@ CAD program, and create G-Code for Isolation routing.
 
 - fixed the Gerber Parser convert units unnecessary usage. The only units conversion should be done when creating the new object, after the parsing
 - more fixes in Rules Check Tool
+- optimized the Move Tool
+- added support for key-based panning in 3D graphic engine. Moving the mouse wheel while pressing the CTRL key will pan up-down and while pressing SHIFT key will pan left-right
 
 11.10.2019
 

+ 2 - 2
flatcamEditors/FlatCAMExcEditor.py

@@ -2814,7 +2814,7 @@ class FlatCAMExcEditor(QtCore.QObject):
             self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
             self.app.plotcanvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
             self.app.plotcanvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
-            self.app.plotcanvas.graph_event_disconnect('mouse_double_click', self.app.on_double_click_over_plot)
+            self.app.plotcanvas.graph_event_disconnect('mouse_double_click', self.app.on_mouse_double_click_over_plot)
         else:
             self.app.plotcanvas.graph_event_disconnect(self.app.mp)
             self.app.plotcanvas.graph_event_disconnect(self.app.mm)
@@ -2844,7 +2844,7 @@ class FlatCAMExcEditor(QtCore.QObject):
         self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
                                                               self.app.on_mouse_click_release_over_plot)
         self.app.mdc = self.app.plotcanvas.graph_event_connect('mouse_double_click',
-                                                               self.app.on_double_click_over_plot)
+                                                               self.app.on_mouse_double_click_over_plot)
         self.app.collection.view.clicked.connect(self.app.collection.on_mouse_down)
 
         if self.app.is_legacy is False:

+ 2 - 2
flatcamEditors/FlatCAMGeoEditor.py

@@ -3390,7 +3390,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
             self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
             self.app.plotcanvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
             self.app.plotcanvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
-            self.app.plotcanvas.graph_event_disconnect('mouse_double_click', self.app.on_double_click_over_plot)
+            self.app.plotcanvas.graph_event_disconnect('mouse_double_click', self.app.on_mouse_double_click_over_plot)
         else:
 
             self.app.plotcanvas.graph_event_disconnect(self.app.mp)
@@ -3437,7 +3437,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
         self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
                                                               self.app.on_mouse_click_release_over_plot)
         self.app.mdc = self.app.plotcanvas.graph_event_connect('mouse_double_click',
-                                                               self.app.on_double_click_over_plot)
+                                                               self.app.on_mouse_double_click_over_plot)
         # self.app.collection.view.clicked.connect(self.app.collection.on_mouse_down)
 
         if self.app.is_legacy is False:

+ 2 - 2
flatcamEditors/FlatCAMGrbEditor.py

@@ -3582,7 +3582,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
             self.canvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
             self.canvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
             self.canvas.graph_event_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
-            self.canvas.graph_event_disconnect('mouse_double_click', self.app.on_double_click_over_plot)
+            self.canvas.graph_event_disconnect('mouse_double_click', self.app.on_mouse_double_click_over_plot)
         else:
             self.canvas.graph_event_disconnect(self.app.mp)
             self.canvas.graph_event_disconnect(self.app.mm)
@@ -3623,7 +3623,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
         self.app.mp = self.canvas.graph_event_connect('mouse_press', self.app.on_mouse_click_over_plot)
         self.app.mm = self.canvas.graph_event_connect('mouse_move', self.app.on_mouse_move_over_plot)
         self.app.mr = self.canvas.graph_event_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
-        self.app.mdc = self.canvas.graph_event_connect('mouse_double_click', self.app.on_double_click_over_plot)
+        self.app.mdc = self.canvas.graph_event_connect('mouse_double_click', self.app.on_mouse_double_click_over_plot)
         self.app.collection.view.clicked.connect(self.app.collection.on_mouse_down)
 
         if self.app.is_legacy is False:

+ 40 - 0
flatcamGUI/PlotCanvas.py

@@ -12,6 +12,7 @@ import logging
 from flatcamGUI.VisPyCanvas import VisPyCanvas, time, Color
 from flatcamGUI.VisPyVisuals import ShapeGroup, ShapeCollection, TextCollection, TextGroup, Cursor
 from vispy.scene.visuals import InfiniteLine, Line
+
 import numpy as np
 from vispy.geometry import Rect
 
@@ -103,6 +104,8 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
         # Keep VisPy canvas happy by letting it be "frozen" again.
         self.freeze()
 
+        self.graph_event_connect('mouse_wheel', self.on_mouse_scroll)
+
     # draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
     # all CNC have a limited workspace
     def draw_workspace(self):
@@ -250,6 +253,43 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
         self.cursor_v_line.set_data(pos=pos[0], color=self.line_color)
         self.view.scene.update()
 
+    def on_mouse_scroll(self, event):
+        # key modifiers
+        modifiers = event.modifiers
+        pan_delta_x = self.fcapp.defaults["global_gridx"]
+        pan_delta_y = self.fcapp.defaults["global_gridy"]
+        curr_pos = event.pos
+
+        # Controlled pan by mouse wheel
+        if 'Shift' in modifiers:
+            p1 = np.array(curr_pos)[:2]
+
+            if event.delta[1] > 0:
+                curr_pos[0] -= pan_delta_x
+            else:
+                curr_pos[0] += pan_delta_x
+            p2 = np.array(curr_pos)[:2]
+            self.view.camera.pan(p2 - p1)
+        elif 'Control' in modifiers:
+            p1 = np.array(curr_pos)[:2]
+
+            if event.delta[1] > 0:
+                curr_pos[1] += pan_delta_y
+            else:
+                curr_pos[1] -= pan_delta_y
+            p2 = np.array(curr_pos)[:2]
+            self.view.camera.pan(p2 - p1)
+
+
+        if self.fcapp.grid_status() == True:
+            pos_canvas = self.translate_coords(curr_pos)
+            pos = self.fcapp.geo_editor.snap(pos_canvas[0], pos_canvas[1])
+
+            # Update cursor
+            self.fcapp.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
+                                           symbol='++', edge_color=self.fcapp.cursor_color_3D,
+                                           size=self.fcapp.defaults["global_cursor_size"])
+
     def new_text_group(self, collection=None):
         if collection:
             return TextGroup(collection)

+ 9 - 6
flatcamGUI/VisPyCanvas.py

@@ -133,6 +133,9 @@ class Camera(scene.PanZoomCamera):
         if event.handled or not self.interactive:
             return
 
+        # key modifiers
+        modifiers = event.mouse_event.modifiers
+
         # Limit mouse move events
         last_event = event.last_event
         t = time.time()
@@ -147,21 +150,21 @@ class Camera(scene.PanZoomCamera):
             event.handled = True
             return
 
-        # Scrolling
+        # ################### Scrolling ##########################
         BaseCamera.viewbox_mouse_event(self, event)
 
         if event.type == 'mouse_wheel':
-            center = self._scene_transform.imap(event.pos)
-            scale = (1 + self.zoom_factor) ** (-event.delta[1] * 30)
-            self.limited_zoom(scale, center)
+            if not modifiers:
+                center = self._scene_transform.imap(event.pos)
+                scale = (1 + self.zoom_factor) ** (-event.delta[1] * 30)
+                self.limited_zoom(scale, center)
             event.handled = True
 
         elif event.type == 'mouse_move':
             if event.press_event is None:
                 return
 
-            modifiers = event.mouse_event.modifiers
-
+            # ################ Panning ############################
             # self.pan_button_setting is actually self.FlatCAM.APP.defaults['global_pan_button']
             if event.button == int(self.pan_button_setting) and not modifiers:
                 # Translate

+ 40 - 42
flatcamTools/ToolMove.py

@@ -97,12 +97,16 @@ class ToolMove(FlatCAMTool):
             sel_obj_list = self.app.collection.get_selected()
             if sel_obj_list:
                 self.app.inform.emit(_("MOVE: Click on the Start point ..."))
+
+                # if we have an object selected then we can safely activate the mouse events
+                self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_move)
+                self.mp = self.app.plotcanvas.graph_event_connect('mouse_press', self.on_left_click)
+                self.kr = self.app.plotcanvas.graph_event_connect('key_release', self.on_key_press)
+
                 # draw the selection box
-                self.draw_sel_bbox(obj_list=sel_obj_list)
+                self.draw_sel_bbox()
             else:
-                self.setVisible(False)
-                # signal that there is no command active
-                self.app.command_active = None
+                self.toggle()
                 self.app.inform.emit('[WARNING_NOTCL] %s' % _("MOVE action cancelled. No object(s) to move."))
 
     def on_left_click(self, event):
@@ -148,8 +152,9 @@ class ToolMove(FlatCAMTool):
                     dx = pos[0] - self.point1[0]
                     dy = pos[1] - self.point1[1]
 
-                    # move only the objects selected and plotted
-                    obj_list = [obj for obj in self.app.collection.get_selected() if obj.options['plot']]
+                    # move only the objects selected and plotted and visible
+                    obj_list = [obj for obj in self.app.collection.get_selected()
+                                if obj.options['plot'] and obj.visible is True]
 
                     def job_move(app_obj):
                         with self.app.proc_container.new(_("Moving...")) as proc:
@@ -254,47 +259,40 @@ class ToolMove(FlatCAMTool):
             self.toggle()
         return
 
-    def draw_sel_bbox(self, obj_list):
+    def draw_sel_bbox(self):
         xminlist = []
         yminlist = []
         xmaxlist = []
         ymaxlist = []
 
-        if not obj_list:
-            self.app.inform.emit('[WARNING_NOTCL] %s' % _("Object(s) not selected"))
-            self.toggle()
-        else:
-            # if we have an object selected then we can safely activate the mouse events
-            self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_move)
-            self.mp = self.app.plotcanvas.graph_event_connect('mouse_press', self.on_left_click)
-            self.kr = self.app.plotcanvas.graph_event_connect('key_release', self.on_key_press)
-
-            # first get a bounding box to fit all
-            for obj in obj_list:
-                # don't move disabled objects, move only plotted objects
-                if obj.options['plot']:
-                    xmin, ymin, xmax, ymax = obj.bounds()
-                    xminlist.append(xmin)
-                    yminlist.append(ymin)
-                    xmaxlist.append(xmax)
-                    ymaxlist.append(ymax)
-
-            # get the minimum x,y and maximum x,y for all objects selected
-            xminimal = min(xminlist)
-            yminimal = min(yminlist)
-            xmaximal = max(xmaxlist)
-            ymaximal = max(ymaxlist)
-
-            p1 = (xminimal, yminimal)
-            p2 = (xmaximal, yminimal)
-            p3 = (xmaximal, ymaximal)
-            p4 = (xminimal, ymaximal)
-
-            self.old_coords = [p1, p2, p3, p4]
-            self.draw_shape(Polygon(self.old_coords))
-
-            if self.app.is_legacy is True:
-                self.sel_shapes.redraw()
+        obj_list = self.app.collection.get_selected()
+
+        # first get a bounding box to fit all
+        for obj in obj_list:
+            # don't move disabled objects, move only plotted objects
+            if obj.options['plot']:
+                xmin, ymin, xmax, ymax = obj.bounds()
+                xminlist.append(xmin)
+                yminlist.append(ymin)
+                xmaxlist.append(xmax)
+                ymaxlist.append(ymax)
+
+        # get the minimum x,y and maximum x,y for all objects selected
+        xminimal = min(xminlist)
+        yminimal = min(yminlist)
+        xmaximal = max(xmaxlist)
+        ymaximal = max(ymaxlist)
+
+        p1 = (xminimal, yminimal)
+        p2 = (xmaximal, yminimal)
+        p3 = (xmaximal, ymaximal)
+        p4 = (xminimal, ymaximal)
+
+        self.old_coords = [p1, p2, p3, p4]
+        self.draw_shape(Polygon(self.old_coords))
+
+        if self.app.is_legacy is True:
+            self.sel_shapes.redraw()
 
     def update_sel_bbox(self, pos):
         self.delete_shape()