FreeCAD

Форк
0
/
gui_tool_utils.py 
349 строк · 10.7 Кб
1
# ***************************************************************************
2
# *   (c) 2009 Yorik van Havre <yorik@uncreated.net>                        *
3
# *   (c) 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 utility functions that are used by many Draft Gui Commands.
26

27
These functions are used by different command classes in the `DraftTools`
28
module. We assume that the graphical interface was already loaded
29
as they operate on selections and graphical properties.
30
"""
31
## @package gui_tool_utils
32
# \ingroup draftguitools
33
# \brief Provides utility functions that are used by many Draft Gui Commands.
34

35
## \addtogroup draftguitools
36
# @{
37
import FreeCAD as App
38
import FreeCADGui as Gui
39
import WorkingPlane
40
from draftutils import gui_utils
41
from draftutils import params
42
from draftutils import utils
43
from draftutils.messages import _wrn
44

45
# Set modifier keys from the parameter database
46
MODS = ["shift", "ctrl", "alt"]
47

48

49
def get_mod_constrain_key():
50
    return MODS[params.get_param("modconstrain")]
51

52

53
def get_mod_snap_key():
54
    return MODS[params.get_param("modsnap")]
55

56

57
def get_mod_alt_key():
58
    return MODS[params.get_param("modalt")]
59

60

61
def format_unit(exp, unit="mm"):
62
    """Return a formatting string to set a number to the correct unit."""
63
    return App.Units.Quantity(exp, App.Units.Length).UserString
64

65

66
formatUnit = format_unit
67

68

69
def select_object(arg):
70
    """Handle the selection of objects depending on buttons pressed.
71

72
    This is a scene event handler, to be called from the Draft tools
73
    when they need to select an object.
74
    ::
75
        self.call = self.view.addEventCallback("SoEvent", select_object)
76

77
    Parameters
78
    ----------
79
    arg: Coin event
80
        The Coin event received from the 3D view.
81

82
        If it is of type Keyboard and the `ESCAPE` key, it runs the `finish`
83
        method of the active command.
84

85
        If Ctrl key is pressed, multiple selection is enabled until the
86
        button is released.
87
        Then it runs the `proceed` method of the active command
88
        to continue with the command's logic.
89
    """
90
    if arg["Type"] == "SoKeyboardEvent":
91
        if arg["Key"] == "ESCAPE":
92
            App.activeDraftCommand.finish()
93
            # TODO: this part raises a coin3D warning about scene traversal.
94
            # It needs to be fixed.
95
    elif not arg["CtrlDown"] and Gui.Selection.hasSelection():
96
        App.activeDraftCommand.proceed()
97

98

99
selectObject = select_object
100

101

102
def has_mod(args, mod):
103
    """Check if args has a specific modifier.
104

105
    Parameters
106
    ----------
107
    args: Coin event
108
        The Coin event received from the 3D view.
109

110
    mod: str
111
        A string indicating the modifier, either `'shift'`, `'ctrl'`,
112
        or `'alt'`.
113

114
    Returns
115
    -------
116
    bool
117
        It returns `args["ShiftDown"]`, `args["CtrlDown"]`,
118
        or `args["AltDown"]`, depending on the passed value of `mod`.
119
    """
120
    if mod == "shift":
121
        return args["ShiftDown"]
122
    elif mod == "ctrl":
123
        return args["CtrlDown"]
124
    elif mod == "alt":
125
        return args["AltDown"]
126

127

128
hasMod = has_mod
129

130

131
def set_mod(args, mod, state):
132
    """Set a specific modifier state in args.
133

134
    Parameters
135
    ----------
136
    args: Coin event
137
        The Coin event received from the 3D view.
138

139
    mod: str
140
        A string indicating the modifier, either `'shift'`, `'ctrl'`,
141
        or `'alt'`.
142

143
    state: bool
144
        The boolean value of `state` is assigned to `args["ShiftDown"]`,
145
        `args["CtrlDown"]`, or `args["AltDown"]`
146
        depending on `mod`.
147
    """
148
    if mod == "shift":
149
        args["ShiftDown"] = state
150
    elif mod == "ctrl":
151
        args["CtrlDown"] = state
152
    elif mod == "alt":
153
        args["AltDown"] = state
154

155

156
setMod = set_mod
157

158

159
def get_point(target, args, noTracker=False):
160
    """Return a constrained 3D point and its original point.
161

162
    It is used by the Draft tools.
163

164
    Parameters
165
    ----------
166
    target: object (class)
167
        The target object with a `node` attribute. If this is present,
168
        return the last node, otherwise return `None`.
169

170
        In the Draft tools, `target` is essentially the same class
171
        of the Gui command, that is, `self`. Therefore, this method
172
        probably makes more sense as a class method.
173

174
    args: Coin event
175
        The Coin event received from the 3D view.
176

177
    noTracker: bool, optional
178
        It defaults to `False`.
179
        If it is `True`, the tracking line will not be displayed.
180

181
    Returns
182
    -------
183
    CoinPoint, Base::Vector3, str
184
        It returns a tuple with some information.
185

186
        The first is the Coin point returned by `Snapper.snap`
187
        or by the `ActiveView`; the second is that same point
188
        turned into an `App.Vector`,
189
        and the third is some information of the point
190
        returned by the `Snapper` or by the `ActiveView`.
191
    """
192
    ui = Gui.draftToolBar
193
    if not ui.mouse:
194
        return None, None, None
195

196
    if target.node:
197
        last = target.node[-1]
198
    else:
199
        last = None
200

201
    smod = has_mod(args, get_mod_snap_key())
202
    cmod = has_mod(args, get_mod_constrain_key())
203
    point = None
204

205
    if hasattr(Gui, "Snapper"):
206
        point = Gui.Snapper.snap(args["Position"],
207
                                 lastpoint=last,
208
                                 active=smod,
209
                                 constrain=cmod,
210
                                 noTracker=noTracker)
211
        info = Gui.Snapper.snapInfo
212
        mask = Gui.Snapper.affinity
213
    if not point:
214
        p = Gui.ActiveDocument.ActiveView.getCursorPos()
215
        point = Gui.ActiveDocument.ActiveView.getPoint(p)
216
        info = Gui.ActiveDocument.ActiveView.getObjectInfo(p)
217
        mask = None
218

219
    ctrlPoint = App.Vector(point)
220
    wp = WorkingPlane.get_working_plane(update=False)
221
    if target.node:
222
        if target.featureName == "Rectangle":
223
            ui.displayPoint(point, target.node[0], plane=wp, mask=mask)
224
        else:
225
            ui.displayPoint(point, target.node[-1], plane=wp, mask=mask)
226
    else:
227
        ui.displayPoint(point, plane=wp, mask=mask)
228
    return point, ctrlPoint, info
229

230

231
getPoint = get_point
232

233

234
def set_working_plane_to_object_under_cursor(mouseEvent):
235
    """Align the working plane to the face under the cursor.
236

237
    The working plane is only aligned if it is `'auto'`.
238

239
    Parameters
240
    ----------
241
    mouseEvent: Coin event
242
        Coin mouse event.
243

244
    Returns
245
    -------
246
    App::DocumentObject or None
247
        The parent object the face belongs to, if alignment occurred, or None.
248
    """
249
    objectUnderCursor = gui_utils.get_3d_view().getObjectInfo((
250
        mouseEvent["Position"][0],
251
        mouseEvent["Position"][1]))
252

253
    if not objectUnderCursor:
254
        return None
255
    if "Face" not in objectUnderCursor["Component"]:
256
        return None
257
    wp = WorkingPlane.get_working_plane(update=False)
258
    if not wp.auto:
259
        return None
260

261
    import Part
262
    if "ParentObject" in objectUnderCursor:
263
        obj = objectUnderCursor["ParentObject"]
264
        sub = objectUnderCursor["SubName"]
265
    else:
266
        obj = App.ActiveDocument.getObject(objectUnderCursor["Object"])
267
        sub = objectUnderCursor["Component"]
268
    shape = Part.getShape(obj, sub, needSubElement=True, retType=0)
269

270
    if wp.align_to_face(shape, _hist_add=False):
271
        wp.auto = True
272
        return obj
273

274
    return None
275

276

277
setWorkingPlaneToObjectUnderCursor = set_working_plane_to_object_under_cursor
278

279

280
def set_working_plane_to_selected_object():
281
    """Align the working plane to a preselected face.
282

283
    The working plane is only aligned if it is `'auto'`.
284

285
    Returns
286
    -------
287
    App::DocumentObject or None
288
        The parent object the face belongs to, if alignment occurred, or None.
289
    """
290
    wp = WorkingPlane.get_working_plane(update=False)
291
    if not wp.auto:
292
        return None
293

294
    sels = Gui.Selection.getSelectionEx("", 0)
295

296
    if len(sels) == 1 \
297
            and len(sels[0].SubObjects) == 1 \
298
            and sels[0].SubObjects[0].ShapeType == "Face":
299
        import Part
300
        shape = Part.getShape(sels[0].Object,
301
                              sels[0].SubElementNames[0],
302
                              needSubElement=True,
303
                              retType=0)
304

305
        if wp.align_to_face(shape, _hist_add=False):
306
            wp.auto = True
307
            return sels[0].Object
308

309
    return None
310

311

312
setWorkingPlaneToSelectedObject = set_working_plane_to_selected_object
313

314

315
def get_support(mouseEvent=None):
316
    """"Align the working plane to a preselected face or the face under the cursor.
317

318
    The working plane is only aligned if it is `'auto'`.
319

320
    Parameters
321
    ----------
322
    mouseEvent: Coin event, optional
323
        Defaults to `None`.
324
        Coin mouse event.
325

326
    Returns
327
    -------
328
    App::DocumentObject or None
329
        The parent object the face belongs to, if alignment occurred, or None.
330
    """
331
    if mouseEvent is None:
332
        return set_working_plane_to_selected_object()
333
    return set_working_plane_to_object_under_cursor(mouseEvent)
334

335

336
getSupport = get_support
337

338

339
def redraw_3d_view():
340
    """Force a redraw of 3D view or do nothing if it fails."""
341
    try:
342
        Gui.ActiveDocument.ActiveView.redraw()
343
    except AttributeError as err:
344
        _wrn(err)
345

346

347
redraw3DView = redraw_3d_view
348

349
## @}
350

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

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

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

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