summaryrefslogtreecommitdiff
path: root/cad/src/dna/commands/DnaSegment/DnaSegment_GraphicsMode.py
blob: 6db95a222704ece5709d8793f79db0aa64204c46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# Copyright 2008-2009 Nanorex, Inc.  See LICENSE file for details.
"""
Graphics mode intended to be used while in DnaSegment_EditCommand.
While in this command, user can
(a) Highlight and then left drag the resize handles located at the
    two 'axis endpoints' of thje segment to change its length.
(b) Highlight and then left drag any axis atom (except the two end axis atoms)
    to translate the  whole segment along the axis
(c) Highlight and then left drag any strand atom to rotate the segment around
    its axis.

    Note that implementation b and c may change slightly if we implement special
    handles to do these oprations.

@author: Ninad
@version: $Id$
@copyright: 2008-2009 Nanorex, Inc.  See LICENSE file for details.

History:
Created 2008-01-25

TODO: as of 2008-02-01:
- This graphics mode uses some duplicated code from Move_GraphicsMode
(for rotating or translating about own axis .. its a small portion and simpler
to understand) and also from DnaLine_GM (mainly the drawing code).
Ideally, it should switch to these graphics modes while remaining in the same
command (using command.switchGraphicsModeTo method) But it poses problems.
Issues related to use of DnaLine_GM are mentioned in DnaSegment_EditCommand.
In future, we may need to incorporate more functionality from these graphics
modes so this should be refactored then.

- Need to review methods in self.leftDrag and self.leftDown ..there might be
 some bugs...not sure.

"""

import foundation.env as env
from dna.commands.BuildDna.BuildDna_GraphicsMode import BuildDna_GraphicsMode
from graphics.drawing.drawDnaRibbons import drawDnaRibbons
from graphics.drawing.CS_draw_primitives import drawcylinder
from utilities.constants import darkred, black, orange
from model.chem import Atom
from utilities.prefs_constants import dnaSegmentResizeHandle_discRadius_prefs_key
from utilities.prefs_constants import dnaSegmentResizeHandle_discThickness_prefs_key

from geometry.VQT import norm

SPHERE_RADIUS = 2.0
SPHERE_DRAWLEVEL = 2

_superclass = BuildDna_GraphicsMode

class DnaSegment_GraphicsMode(BuildDna_GraphicsMode):
    """
    Graphics mode for DnaSegment_EditCommand.
    """
    _sphereColor = darkred
    _sphereOpacity = 0.5

    #The flag that decides whether to draw the handles. This flag is
    #set during left dragging, when no handle is 'grabbed'. This optimizes the
    #drawing code as it skips handle drawing code and also the computation
    #of handle positions each time the mouse moves
    #@see self.Draw_other, and comments in superclass, for more details
    _handleDrawingRequested = True

    #Some left drag variables used to drag the whole segment along axis or
    #rotate the segment around its own axis of for free drag translation
    _movablesForLeftDrag = []

    #The common center is the center about which the list of movables (the segment
    #contents are rotated.
    #@see: self.leftADown where this is set.
    #@see: self.leftDrag where it is used.
    _commonCenterForRotation = None
    _axis_for_constrained_motion = None

    #Flags that decide the type of left drag.
    #@see: self.leftADown where it is set and self.leftDrag where these are used
    _translateAlongAxis = False
    _rotateAboutAxis = False
    _freeDragWholeStructure = False

    cursor_over_when_LMB_pressed = ''

    def Enter_GraphicsMode(self):
        _superclass.Enter_GraphicsMode(self)
        #Precaution
        self.clear_leftA_variables()

    def bareMotion(self, event):
        """
        @see: self.update_cursor_for_no_MB
        """
        value = _superclass.bareMotion(self, event)

        #When the cursor is over a specific atom, we need to display
        #a different icon. (e.g. when over a strand atom, it should display
        # rotate cursor)
        self.update_cursor()

        return value

    def update_cursor_for_no_MB(self):
        """
        Update the cursor for Select mode (Default implementation).
        """
        _superclass.update_cursor_for_no_MB(self)

        #minor optimization -- don't go further into the method if
        #nothing is highlighted i.e. self.o.selobj is None.
        if self.o.selobj is None:
            return

        if self.command and hasattr(self.command.struct, 'isAncestorOf'):
            if not self.command.struct.isAncestorOf(self.o.selobj):
                return

            if self.o.modkeys is None:
                if isinstance(self.o.selobj, Atom):
                    if self.o.selobj.element.role == 'strand':
                        self.o.setCursor(self.win.rotateAboutCentralAxisCursor)
                    else:
                        self.o.setCursor(self.win.translateAlongCentralAxisCursor)


    def clear_leftA_variables(self):
        self._movablesForLeftDrag = []
        self._commonCenterForRotation = None
        self._axis_for_constrained_motion = None
        _translateAlongAxis = False
        _rotateAboutAxis = False
        _freeDragWholeStructure = False

    def _leftDown_preparation_for_dragging(self, objectUnderMouse, event):
        """
        Handle left down event. Preparation for rotation and/or selection
        This method is called inside of self.leftDown.
        @param event: The mouse left down event.
        @type  event: QMouseEvent instance
        @see: self.leftDown
        @see: self.leftDragRotation
        Overrides _superclass._leftDown_preparation_for_dragging
        """
        self.o.SaveMouse(event)
        self.picking = True
        self.dragdist = 0.0
        farQ_junk, self.movingPoint = self.dragstart_using_GL_DEPTH( event)
        self.leftADown(objectUnderMouse, event)

    def Draw_other(self):
        """
        Draw handles (if any) of our DnaSegment.
        
        @see:self._drawCursorText()
        @see:self._drawHandles()
        """
        _superclass.Draw_other(self)
        if self._handleDrawingRequested:
            self._drawHandles()


    def _drawHandles(self):
        """
        Draw the handles for the command.struct
        
        @see: DnaSegment_EditCommand.getDnaRibbonParams()
        @see: self._drawCursorText()
        @see: self.Draw_other()
        """
        if self.command and self.command.hasValidStructure():
            for handle in self.command.handles:
                if handle.hasValidParamsForDrawing():
                    handle.draw()

            self._drawDnaRubberbandLine()


    def _drawDnaRubberbandLine(self):

        handleType = ''
        if self.command.grabbedHandle is not None:
            if self.command.grabbedHandle in [self.command.rotationHandle1,
                                              self.command.rotationHandle2]:
                handleType = 'ROTATION_HANDLE'
            else:
                handleType = 'RESIZE_HANDLE'

        if handleType and handleType == 'RESIZE_HANDLE':

            params = self.command.getDnaRibbonParams()
            if params:
                end1, end2, basesPerTurn, duplexRise, ribbon1_start_point, \
                    ribbon2_start_point, ribbon1_direction, ribbon2_direction,\
                    ribbon1Color, ribbon2Color = params


                #Note: The displayStyle argument for the rubberband line should
                #really be obtained from self.command.struct. But the struct
                #is a DnaSegment (a Group) and doesn't have attr 'display'
                #Should we then obtain this information from one of its strandChunks?
                #but what if two strand chunks and axis chunk are rendered
                #in different display styles? since situation may vary, lets
                #use self.glpane.displayMode for rubberbandline displayMode
                drawDnaRibbons(self.glpane,
                               end1,
                               end2,
                               basesPerTurn,
                               duplexRise,
                               self.glpane.scale,
                               self.glpane.lineOfSight,
                               self.glpane.displayMode,
                               ribbonThickness = 4.0,
                               ribbon1_start_point = ribbon1_start_point,
                               ribbon2_start_point = ribbon2_start_point,
                               ribbon1_direction = ribbon1_direction,
                               ribbon2_direction = ribbon2_direction,
                               ribbon1Color = ribbon1Color,
                               ribbon2Color = ribbon2Color,
                               )
                        
            #Draw the text next to the cursor that gives info about
            #number of base pairs etc
            self._drawCursorText()
        return

    pass

# end