summaryrefslogtreecommitdiff
path: root/cad/src/dna/commands/DnaStrand/DnaStrand_ResizeHandle.py
blob: 4c3f2ace89b3786bea3d988793619a0f30025bec (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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# Copyright 2008 Nanorex, Inc.  See LICENSE file for details. 
"""
DnaStrand_ResizeHandle.py

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

History: 
Created on 2008-02-14

TODO: as of 2008-02-14
- Attributes such as height_ref need to be renamed. But this should really be done
  in the superclass exprs.DraggableHandle_AlongLine. 
- Needs refactoring. Shares common things with DnaSegment_ResizeHandle . 
  Really the only difference is the handle appearance. See if renaming 
  DnaSegment_ResizeHandle and then using it as a common class makes sense. 

"""
from exprs.attr_decl_macros import Option
from exprs.attr_decl_macros import State
from exprs.Set              import Action
from exprs.__Symbols__      import _self

from exprs.Overlay          import Overlay
from exprs.ExprsConstants   import Drawable
from exprs.ExprsConstants   import Color
from exprs.ExprsConstants   import Boolean
from exprs.ExprsConstants   import Width
from exprs.ExprsConstants   import Point
from exprs.ExprsConstants   import ORIGIN, DX

from exprs.If_expr import If_expr

from exprs.dna_ribbon_view  import Cylinder
from exprs.Rect             import Sphere
   
import foundation.env as env
from utilities.prefs_constants import hoverHighlightingColor_prefs_key
from utilities.prefs_constants import selectionColor_prefs_key
from utilities.constants import purple

from geometry.VQT import V
from exprs.DraggableHandle import DraggableHandle_AlongLine

class DnaStrand_ResizeHandle(DraggableHandle_AlongLine):
    """
    Provides a resize handle for editing the length of an existing Dna Strand. 
    """
    
    #Handle color will be changed depending on whether the handle is grabbed
    # [bruce 080409 revised some details of this to fix bug 2747]
    
    handleColor = Option(Color, purple) # formula from caller
        # (in current usage, a state variable in caller)

    handleIsGrabbed = State(Boolean, False)
        # Note: this might not be needed if we passed more args to
        # Highlightable (namely, the appearance when pressed);
        # that would also be more reliable, since as it is, any failure for
        # on_release to be called would leave the handle stuck in the
        # grabbed state; client code would be wise to sometimes reset
        # this state. Also, it seems rare to ever see this selection color
        # since the handle is usually highlighted and yellow while dragging it.
        # [Depending on the highlight and selection drawing mode.  Russ 080530]
        # So this state could probably just be removed, with all uses of
        # _currentHandleColor changes to uses of handleColor.
        # [bruce 080409]
    
    _currentHandleColor = If_expr( handleIsGrabbed,
                                   env.prefs[selectionColor_prefs_key],
                                   _self.handleColor)
        
    #The caller-specified formula that determines the radius (of the sphere) of this handle. 
    #See DnaStrand_EditCommand._determine_resize_handle_radius() for more 
    #details
    sphereRadius = Option(Width, 1.5)
        
    #Appearance of the handle. (note that it uses all the code from exprs module
    # and needs more documentation there). 
    #See exprs.Rect.Sphere for definition of a drawable 'Sphere' object.
    
    appearance = Overlay(
            Sphere(_self.sphereRadius, 
                   _self._currentHandleColor, 
                   center = ORIGIN + _self.direction * 3.0 * _self.sphereRadius),
                   
            Cylinder((ORIGIN, 
                      ORIGIN + _self.direction * 2.2 * _self.sphereRadius),
                      0.6 * _self.sphereRadius,
                      _self._currentHandleColor))
    
    #Handle appearance when highlighted
    # [this probably doesn't need to be an Option, since the client never
    #  passes it [bruce 080409 comment]]
    HHColor = env.prefs[hoverHighlightingColor_prefs_key]
    appearance_highlighted = Option(
        Drawable,
        Overlay(
            Sphere(_self.sphereRadius, 
                   HHColor, 
                   center = ORIGIN + _self.direction * 3.0 * _self.sphereRadius),
                   
            Cylinder((ORIGIN,  
                      ORIGIN + _self.direction * 2.2 * _self.sphereRadius),
                     0.6* _self.sphereRadius , 
                     HHColor)),
            doc = "handle appearance when highlighted")
     

    #Stateusbar text. Variable needs to be renamed in superclass. 
    sbar_text = Option(str, 
                       "Drag the handle to resize the strand", 
                       doc = "Statusbar text on mouseover")
    
    #Command object specified as an 'Option' during instantiation of the class
    #see DnaSegment_EditCommand class definition. 
    command =  Option(Action, 
                      doc = 'The Command which instantiates this handle')
    
    #Current position of the handle. i.e. it is the position of the handle 
    #under the mouse. (its differert than the 'orifinal position) 
    #This variable is used in self.command.graphicsMode to draw a rubberband 
    #line  and also to specify the endPoint2 of the structure while modifying 
    #it. See DnaSegment_EditCommand.modifyStructure for details. 
    if _self.origin is not None:
        currentPosition = _self.origin + _self.direction * _self.height_ref.value
    else:
        currentPosition = ORIGIN
        
    
    #Fixed end of the structure (self.command.struct) ..meaning that end won't 
    #move while user grabbs and draggs this handle (attached to a the other 
    #'moving endPoint) . This variable is used to specify endPoint1 of the 
    #structure while modifyin it.  See DnaSegment_EditCommand.modifyStructure 
    #and self.on_release for details.
    fixedEndOfStructure = Option(Point, 
                                 V(0, 0, 0))
    
    #If this is false, the 'highlightable' object i.e. this handle 
    #won't be drawn. See DraggableHandle.py for the declararion of 
    #the delegate(that defines a Highlightable) We define a If_Exprs to check 
    #whether to draw the highlightable object. 
    should_draw = State(bool, True)
    
    def ORIG_NOT_USED_hasValidParamsForDrawing(self):
        """
        NOT USED AS OF 2008-04-02
        Returns True if the handles origin and direction are not 'None'. 
        
        @see: DnaStrand_GraphicsMode._draw_handles() where the caller
              uses this to decide whether this handle can be drawn without 
              a problem. 
        """
        #NOTE: Better to do it in the drawing code of this class? 
        #But it uses a delegate to draw stuff (see class Highlightable)
        #May be we should pass this method to that delegate as an optional 
        #argument -- Ninad 2008-04-02
        if self.origin is None or self.direction is None:
            return  False
       
        return True
    
    
    def hasValidParamsForDrawing(self):
        """
        Returns True if the handles origin and direction are not 'None'. 
        
        @see: DnaStrand_GraphicsMode._draw_handles() where the caller
              uses this to decide whether this handle can be drawn without 
              a problem. 
        
        """
        
        #NOTE: Better to do it in the drawing code of this class? 
        #But it uses a delegate to draw stuff (see class Highlightable)
        #May be we should pass this method to that delegate as an optional 
        #argument -- Ninad 2008-04-02
        
        #@Bug: Create a duplex; Enter Dna strand edit command, 
        # then shorten it such that it removes some bases of the strand from the
        #original duplex. Hit undo; click on the right handle, and shorten it again
        #sometimes it gives a traceback. in drawing the highlightable 
        #this could be because self.should_draw flag is not getting updated.
        
            
        #NOTES: If this method is used, you will also need to define the 
        #delegate in class DraggableHandle as --
        #delegate = If_Exprs(_self.should_draw, Highlightable(....))
        if self.origin is None or self.direction is None:
            self.should_draw = False
        else:
            self.should_draw = True
        
        return self.should_draw
            
       
    def on_press(self):  
        """
        Actions when handle is pressed (grabbed, during leftDown event)
        @see: B{SelectChunks.GraphicsMode.leftDown}
        @see: B{DnaStrand_EditCommand.grabbedHandle} 
        @see: B{DnaStrand_GraphicsMode.Draw} (which uses some attributes of 
             the current grabbed handle of the command. 
        @see: B{DragHandle_API}
        """
        #Change the handle color when handle is grabbed. See declaration of 
        #self.handleColor in the class definition. 
      
        ## self._currentHandleColor = env.prefs[selectionColor_prefs_key]
        self.handleIsGrabbed = True
        
        #assign 'self' as the curent grabbed handle of the command. 
        self.command.grabbedHandle = self
    
    def on_drag(self):
        """
        Method called while dragging this handle .
        @see: B{DragHandle_API}
        """
        pass
        #The following call is disabled. Instead updating this spinbox 
        #is done by the command.getCursorText method . See that method for 
        #details
        ##self.command.update_numberOfBases()
    
    def on_release(self):
        """
        This method gets called during leftUp (when the handle is released)
        @see: B{DnaStrand_EditCommand.modifyStructure}
        @see: self.on_press
        @see: B{SelectChunks.GraphicsMode.leftUp}
        @see: B{DragHandle_API}
        """
        ## self._currentHandleColor = self.handleColor
        self.handleIsGrabbed = False
        
        if self.command and hasattr(self.command, 'modifyStructure'): 
            self.command.modifyStructure()
            #Clear the grabbed handle attribute (the handle is no longer 
            #grabbed)
            self.command.grabbedHandle = None