FreeCAD

Форк
0
323 строки · 12.8 Кб
1
# ***************************************************************************
2
# *   (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net>                  *
3
# *   (c) 2009, 2010 Ken Cline <cline@frii.com>                             *
4
# *   (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de>           *
5
# *                                                                         *
6
# *   This file is part of the FreeCAD CAx development system.              *
7
# *                                                                         *
8
# *   This program is free software; you can redistribute it and/or modify  *
9
# *   it under the terms of the GNU Lesser General Public License (LGPL)    *
10
# *   as published by the Free Software Foundation; either version 2 of     *
11
# *   the License, or (at your option) any later version.                   *
12
# *   for detail see the LICENCE text file.                                 *
13
# *                                                                         *
14
# *   FreeCAD is distributed in the hope that it will be useful,            *
15
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
16
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
17
# *   GNU Library General Public License for more details.                  *
18
# *                                                                         *
19
# *   You should have received a copy of the GNU Library General Public     *
20
# *   License along with FreeCAD; if not, write to the Free Software        *
21
# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
22
# *   USA                                                                   *
23
# *                                                                         *
24
# ***************************************************************************
25
"""Provides GUI tools to move objects in the 3D space."""
26
## @package gui_move
27
# \ingroup draftguitools
28
# \brief Provides GUI tools to move objects in the 3D space.
29

30
## \addtogroup draftguitools
31
# @{
32
from PySide.QtCore import QT_TRANSLATE_NOOP
33

34
import FreeCAD as App
35
import FreeCADGui as Gui
36
import Draft_rc
37
import DraftVecUtils
38
import draftutils.groups as groups
39
import draftutils.todo as todo
40
import draftguitools.gui_base_original as gui_base_original
41
import draftguitools.gui_tool_utils as gui_tool_utils
42
import draftguitools.gui_trackers as trackers
43

44
from draftutils.messages import _msg, _err, _toolmsg
45
from draftutils.translate import translate
46
from draftguitools.gui_subelements import SubelementHighlight
47

48
# The module is used to prevent complaints from code checkers (flake8)
49
True if Draft_rc.__name__ else False
50

51

52
class Move(gui_base_original.Modifier):
53
    """Gui Command for the Move tool."""
54

55
    def GetResources(self):
56
        """Set icon, menu and tooltip."""
57

58
        return {'Pixmap': 'Draft_Move',
59
                'Accel': "M, V",
60
                'MenuText': QT_TRANSLATE_NOOP("Draft_Move", "Move"),
61
                'ToolTip': QT_TRANSLATE_NOOP("Draft_Move", "Moves the selected objects from one base point to another point.\nIf the \"copy\" option is active, it will create displaced copies.\nCTRL to snap, SHIFT to constrain.")}
62

63
    def Activated(self):
64
        """Execute when the command is called."""
65
        super().Activated(name="Move",
66
                          is_subtool=isinstance(App.activeDraftCommand,
67
                                                SubelementHighlight))
68
        if not self.ui:
69
            return
70
        self.ghosts = []
71
        self.get_object_selection()
72

73
    def get_object_selection(self):
74
        """Get the object selection."""
75
        if Gui.Selection.getSelectionEx():
76
            return self.proceed()
77
        self.ui.selectUi(on_close_call=self.finish)
78
        _msg(translate("draft", "Select an object to move"))
79
        self.call = \
80
            self.view.addEventCallback("SoEvent", gui_tool_utils.selectObject)
81

82
    def proceed(self):
83
        """Continue with the command after a selection has been made."""
84
        if self.call:
85
            self.view.removeEventCallback("SoEvent", self.call)
86
        self.selected_objects = Gui.Selection.getSelection()
87
        self.selected_objects = \
88
            groups.get_group_contents(self.selected_objects,
89
                                      addgroups=True,
90
                                      spaces=True,
91
                                      noarchchild=True)
92
        self.selected_subelements = Gui.Selection.getSelectionEx()
93
        self.ui.lineUi(title=translate("draft", self.featureName), icon="Draft_Move")
94
        self.ui.modUi()
95
        if self.copymode:
96
            self.ui.isCopy.setChecked(True)
97
        self.ui.xValue.setFocus()
98
        self.ui.xValue.selectAll()
99
        self.call = self.view.addEventCallback("SoEvent", self.action)
100
        _toolmsg(translate("draft", "Pick start point"))
101

102
    def finish(self, cont=False):
103
        """Terminate the operation.
104

105
        Parameters
106
        ----------
107
        cont: bool or None, optional
108
            Restart (continue) the command if `True`, or if `None` and
109
            `ui.continueMode` is `True`.
110
        """
111
        self.end_callbacks(self.call)
112
        for ghost in self.ghosts:
113
            ghost.finalize()
114
        super().finish()
115
        if cont or (cont is None and self.ui and self.ui.continueMode):
116
            todo.ToDo.delayAfter(self.Activated, [])
117

118
    def action(self, arg):
119
        """Handle the 3D scene events.
120

121
        This is installed as an EventCallback in the Inventor view.
122

123
        Parameters
124
        ----------
125
        arg: dict
126
            Dictionary with strings that indicates the type of event received
127
            from the 3D view.
128
        """
129
        if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
130
            self.finish()
131
        elif arg["Type"] == "SoLocation2Event":
132
            self.handle_mouse_move_event(arg)
133
        elif (arg["Type"] == "SoMouseButtonEvent"
134
              and arg["State"] == "DOWN"
135
              and arg["Button"] == "BUTTON1"):
136
            self.handle_mouse_click_event(arg)
137

138
    def handle_mouse_move_event(self, arg):
139
        """Handle the mouse when moving."""
140
        for ghost in self.ghosts:
141
            ghost.off()
142
        self.point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
143
        if len(self.node) > 0:
144
            last = self.node[len(self.node) - 1]
145
            self.vector = self.point.sub(last)
146
            for ghost in self.ghosts:
147
                ghost.move(self.vector)
148
                ghost.on()
149
        if self.extendedCopy:
150
            if not gui_tool_utils.hasMod(arg, gui_tool_utils.get_mod_alt_key()):
151
                self.finish()
152
        gui_tool_utils.redraw3DView()
153

154
    def handle_mouse_click_event(self, arg):
155
        """Handle the mouse when the first button is clicked."""
156
        if not self.ghosts:
157
            self.set_ghosts()
158
        if not self.point:
159
            return
160
        self.ui.redraw()
161
        if self.node == []:
162
            self.node.append(self.point)
163
            self.ui.isRelative.show()
164
            for ghost in self.ghosts:
165
                ghost.on()
166
            _toolmsg(translate("draft", "Pick end point"))
167
            if self.planetrack:
168
                self.planetrack.set(self.point)
169
        else:
170
            last = self.node[0]
171
            self.vector = self.point.sub(last)
172
            self.move(self.ui.isCopy.isChecked()
173
                      or gui_tool_utils.hasMod(arg, gui_tool_utils.get_mod_alt_key()))
174
            if gui_tool_utils.hasMod(arg, gui_tool_utils.get_mod_alt_key()):
175
                self.extendedCopy = True
176
            else:
177
                self.finish(cont=None)
178

179
    def set_ghosts(self):
180
        """Set the ghost to display."""
181
        for ghost in self.ghosts:
182
            ghost.remove()
183
        if self.ui.isSubelementMode.isChecked():
184
            self.ghosts = self.get_subelement_ghosts()
185
        else:
186
            self.ghosts = [trackers.ghostTracker(self.selected_objects)]
187

188
    def get_subelement_ghosts(self):
189
        """Get ghost for the subelements (vertices, edges)."""
190
        import Part
191

192
        ghosts = []
193
        for sel in Gui.Selection.getSelectionEx("", 0):
194
            for sub in sel.SubElementNames if sel.SubElementNames else [""]:
195
                if "Vertex" in sub or "Edge" in sub:
196
                    shape = Part.getShape(sel.Object, sub, needSubElement=True, retType=0)
197
                    ghosts.append(trackers.ghostTracker(shape))
198
        return ghosts
199

200
    def move(self, is_copy=False):
201
        """Perform the move of the subelements or the entire object."""
202
        if self.ui.isSubelementMode.isChecked():
203
            self.move_subelements(is_copy)
204
        else:
205
            self.move_object(is_copy)
206

207
    def move_subelements(self, is_copy):
208
        """Move the subelements."""
209
        Gui.addModule("Draft")
210
        try:
211
            if is_copy:
212
                self.commit(translate("draft", "Copy"),
213
                            self.build_copy_subelements_command())
214
            else:
215
                self.commit(translate("draft", "Move"),
216
                            self.build_move_subelements_command())
217
        except Exception:
218
            _err(translate("draft", "Some subelements could not be moved."))
219

220
    def build_copy_subelements_command(self):
221
        """Build the string to commit to copy the subelements."""
222
        import Part
223

224
        command = []
225
        arguments = []
226
        E = len("Edge")
227
        for obj in self.selected_subelements:
228
            for index, subelement in enumerate(obj.SubObjects):
229
                if not isinstance(subelement, Part.Edge):
230
                    continue
231
                _edge_index = int(obj.SubElementNames[index][E:]) - 1
232
                _cmd = '['
233
                _cmd += 'FreeCAD.ActiveDocument.'
234
                _cmd += obj.ObjectName + ', '
235
                _cmd += str(_edge_index) + ', '
236
                _cmd += DraftVecUtils.toString(self.vector)
237
                _cmd += ']'
238
                arguments.append(_cmd)
239

240
        all_args = ', '.join(arguments)
241
        command.append('Draft.copy_moved_edges([' + all_args + '])')
242
        command.append('FreeCAD.ActiveDocument.recompute()')
243
        return command
244

245
    def build_move_subelements_command(self):
246
        """Build the string to commit to move the subelements."""
247
        import Part
248

249
        command = []
250
        V = len("Vertex")
251
        E = len("Edge")
252
        for obj in self.selected_subelements:
253
            for index, subelement in enumerate(obj.SubObjects):
254
                if isinstance(subelement, Part.Vertex):
255
                    _vertex_index = int(obj.SubElementNames[index][V:]) - 1
256
                    _cmd = 'Draft.move_vertex'
257
                    _cmd += '('
258
                    _cmd += 'FreeCAD.ActiveDocument.'
259
                    _cmd += obj.ObjectName + ', '
260
                    _cmd += str(_vertex_index) + ', '
261
                    _cmd += DraftVecUtils.toString(self.vector)
262
                    _cmd += ')'
263
                    command.append(_cmd)
264
                elif isinstance(subelement, Part.Edge):
265
                    _edge_index = int(obj.SubElementNames[index][E:]) - 1
266
                    _cmd = 'Draft.move_edge'
267
                    _cmd += '('
268
                    _cmd += 'FreeCAD.ActiveDocument.'
269
                    _cmd += obj.ObjectName + ', '
270
                    _cmd += str(_edge_index) + ', '
271
                    _cmd += DraftVecUtils.toString(self.vector)
272
                    _cmd += ')'
273
                    command.append(_cmd)
274
        command.append('FreeCAD.ActiveDocument.recompute()')
275
        return command
276

277
    def move_object(self, is_copy):
278
        """Move the object."""
279
        _doc = 'FreeCAD.ActiveDocument.'
280
        _selected = self.selected_objects
281

282
        objects = '['
283
        objects += ', '.join([_doc + obj.Name for obj in _selected])
284
        objects += ']'
285
        Gui.addModule("Draft")
286

287
        _cmd = 'Draft.move'
288
        _cmd += '('
289
        _cmd += objects + ', '
290
        _cmd += DraftVecUtils.toString(self.vector) + ', '
291
        _cmd += 'copy=' + str(is_copy)
292
        _cmd += ')'
293
        _cmd_list = [_cmd,
294
                     'FreeCAD.ActiveDocument.recompute()']
295

296
        _mode = "Copy" if is_copy else "Move"
297
        self.commit(translate("draft", _mode),
298
                    _cmd_list)
299

300
    def numericInput(self, numx, numy, numz):
301
        """Validate the entry fields in the user interface.
302

303
        This function is called by the toolbar or taskpanel interface
304
        when valid x, y, and z have been entered in the input fields.
305
        """
306
        self.point = App.Vector(numx, numy, numz)
307
        if not self.node:
308
            self.node.append(self.point)
309
            self.ui.isRelative.show()
310
            self.ui.isCopy.show()
311
            for ghost in self.ghosts:
312
                ghost.on()
313
            _toolmsg(translate("draft", "Pick end point"))
314
        else:
315
            last = self.node[-1]
316
            self.vector = self.point.sub(last)
317
            self.move(self.ui.isCopy.isChecked())
318
            self.finish(cont=None)
319

320

321
Gui.addCommand('Draft_Move', Move())
322

323
## @}
324

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.