def submenu_from_name_value_pairs(nameval_pairs, newval_receiver_func, curval=None, mitem_value_func=None, indicate_defaultValue=False, defaultValue=None): #bruce 080312 revised to use same_vals (2 places) from utilities.debug import print_compact_traceback # do locally to avoid recursive import problem submenu = [] for name, value in nameval_pairs: text = name if indicate_defaultValue and same_vals(value, defaultValue): #bruce 070518 new feature text += " (default)" command = ( lambda ## event = None, func=newval_receiver_func, val=value: func(val)) mitem = (text, command, same_vals(curval, value) and 'checked' or None) if mitem_value_func is not None: try: res = "<no retval yet>" # for error messages res = mitem_value_func(mitem, value) if res is None: continue # let func tell us to skip this item ###k untested assert type(res) == type((1, 2)) mitem = res except: print_compact_traceback( "exception in mitem_value_func, or error in retval (%r): " % (res, )) #e improve, and atom_debug only pass submenu.append(mitem) return submenu
def getAxisEndAtomAtPosition(self, position): """ Returns the axis end atom of the 'currentStruct' of self's editCommand, at the given position. Example: If there are 4 Dnasegments being resized at the same time, the two resize handles will be at the average end positions. When you resize these segments using , for example , the right handle, it loops through the individual segments to resize those. While doing these, it needs to know the resize end axis atom. How to get that information? In self.updateAverageEndPoints() (which is called earlier), we create two lists for each end. Example: all end1 points are in self.endPoint_1_list (including their average end point which is self.end1) . So in this routine, we determine which of the list to use based on <position> (which is either of the average end points i.e. self.end1 or self.end2) and then check which of the endPoints of the editCommand's currentStruct lies in this list. @TODO: This method will be SLOW if there are large number of structures being edited at once (i.e. large self._structList) . Needs revision. Needs revision. We can't use a dictionary because dict.key cant be a Vector object (example dict[key] != ([1.0, 2.0, 3.0])) see the disabled code that tried to use has_key of dict. Need to come up with a better search algorithm. """ new_position = None for end in (self.end1, self.end2): if same_vals(position, end): if same_vals(end, self.end1): lst = self.endPoints_1 else: lst = self.endPoints_2 for e in self.editCommand.currentStruct.getAxisEndPoints(): for pos in lst: if same_vals(pos, e): new_position = e break if new_position is not None: break ##if e in lst: ##new_position = e ##break ##if self.endPointsDict.has_key(position): ##for end in self.editCommand.currentStruct.getAxisEndPoints(): ##if end in self.endPointsDict[position]: ##new_position = end ##break if new_position is not None: return self.editCommand.currentStruct.getAxisEndAtomAtPosition( new_position) return None
def _update_UI_do_updates(self): """ Overrides superclass method. @see: Command_PropertyManager._update_UI_do_updates() """ newSelectionParams = self._currentSelectionParams() current_struct_params = self._currentStructureParams() selection_params_unchanged = same_vals(newSelectionParams, self._previousSelectionParams) #introducing self._previousStructureParams and #adding structure_params_unchanged check to the 'if' condition below #fixes bug 2910. structure_params_unchanged = same_vals(self._previousStructureParams, current_struct_params) current_command_stack_params = self._currentCommandStackParams() #Check if command stack params changed since last call of this #PM update method. This is used to fix bugs like 2940 command_stack_params_unchanged = same_vals( self._previousCommandStackParams, current_command_stack_params) #No need to proceed if any of the selection/ structure and commandstack #parameters remained unchanged since last call. --- [CONDITION A] if selection_params_unchanged and \ structure_params_unchanged and \ command_stack_params_unchanged: return self._previousStructureParams = current_struct_params self._previousSelectionParams = newSelectionParams self._previousCommandStackParams = current_command_stack_params if structure_params_unchanged: #NOTE: We checked if either of the selection struct or command stack #parameters or both changed. (this was referred as '[CONDITION A]' #above). So, this condition (structure_params_unchanged)also means #either selection or command stack or both parameters were changed. if not command_stack_params_unchanged: #update the nanotube list widget *before* updating the selection if #the command stack changed. This ensures that the selection box #appears around the list widget items that are selected. self.updateNanotubesListWidget() selectedNanotubeSegments = newSelectionParams self.nanotubeListWidget.updateSelection(selectedNanotubeSegments) self.updateNanotubePropertiesButton() return self.updateNanotubesListWidget() return
def model_changed(self): """ When the editCommand is treated as a 'command' by the commandSequencer. this method will override basicCommand.model_changed. @WARNING: Ideally this property manager should implement both model_changed and selection_changed methods in the mode/command API. model_changed method will be used here when the selected atom is dragged, transmuted etc. The selection_changed method will be used when the selection (picking/ unpicking) changes. At present, selection_changed and model_changed methods are called too frequently that it doesn't matter which one you use. Its better to use only a single method for preformance reasons (at the moment). This should change when the original methods in the API are revised to be called at appropiraite time. """ newSelectionParams = self._currentSelectionParams() if same_vals(newSelectionParams, self.previousSelectionParams): return self.previousSelectionParams = newSelectionParams selectedSegments = newSelectionParams self.segmentListWidget.updateSelection(selectedSegments) if len(selectedSegments) == 1: self.editSegmentPropertiesButton.setEnabled(True) else: self.editSegmentPropertiesButton.setEnabled(False)
def command_update_UI(self): """ Extends superclass method. """ _superclass.command_update_UI(self) #Ths following code fixes a bug reported by Mark on 2008-11-10 #the bug is: #1. Insert DNA #2. Enter Break Strands command. Exit command. #3. Do a region selection to select the middle of the DNA duplex. #Notice that atoms are selected, not the strands/segment chunks. #The problem is the selection state is not changed back to the Select Chunks #the code that does this is in Enter_GraphicsMode. #(See SelectChunks_GraphicsMode) but when a command is 'resumed', that #method is not called. The fix for this is to check if the command stack #indicator changed in the command_update_state method, if it is changed #and if currentCommand is BuildDna_EditCommand, call the code that #ensures that chunks will be selected when you draw a selection lasso. #-- Ninad 2008-11-10 indicator = self.assy.command_stack_change_indicator() if same_vals(self.__previous_command_stack_change_indicator, indicator): return self.__previous_command_stack_change_indicator = indicator self.assy.selectChunksWithSelAtoms_noupdate() return
def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.model_changed() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return number_of_segments, isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: if not number_of_segments == 0: #disable all widgets self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s"%(why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segments" self.updateMessage(msg) self.updateListWidgets()
def set_constant_value(self, val): #061117, for use in StatePlace.py ###e probably set_constant_value should be renamed set_value, to fit with StateRefInterface [070312] """#doc [for now, using this is strictly an alternative to using compute_methods -- correctness of mixing them in one lval is not reviewed, and seems unlikely, with one exception: an initial compute_method can be provided for computing an initial value in case the value is asked for before being set, BUT IT'S AN ERROR IF THAT TRACKS ANY USAGE. So we enforce this by being in a variant subclass of Lval.] """ # note: this is inlined into _set_defaultValue ## if self.valid and self._value == val: # THIS HAS THE BUG of numeric arrays being == if any element is ==. ## if self.valid and not (self._value != val): # still not correct, but more often correct, and did fix my loss-of-drag bug... if self.valid and same_vals(self._value, val): pass # important optim, but in future, we might want to only sometimes do this # (eg have another variant class which doesn't do it) else: self._value = val # do this first, in case an outsider (violating conventions? At least for Lval, maybe not for us) # happens to notice self.valid being true during track_inval, so they won't be misled by an incorrect self._value if self.valid: self.track_inval() # (defined in SelfUsageTrackingMixin) # WARNING: self.valid is True for us during our call of track_inval, # but is False for Lval's call of it. # For our call, we only need to propogate invals if we were valid # (since if not, we propogated them when we became invalid, or # (more likely, assuming we're not mixing this with compute methods) [###k review re initial value compmethod] # we were never valid); but during that propogation, we'll remain valid # and have our new value available (permitting queries of it during inval propogation, # though that violates the convention used for the compute_method style). # [#e BTW isn't track_inval misnamed, since it's really to propogate or report our inval, not to track it?] else: self.valid = True pass return
def _previewStructure(self): """ Preview the structure and update the previous parameters attr (self.previousParams) @see: self.preview_or_finalize_structure """ #For certain edit commands, it is possible that self.struct is #not created. If so simply return (don't use assert self.struct) ##This is a commented out stub code for the edit controllers ##such as DNAEditCommand which take input from the user before ##creating the struct. TO BE REVISED -- Ninad20071009 #The following code is now used. Need to improve comments and # some refactoring -- Ninad 2007-10-24 if not self.hasValidStructure(): self.struct = self._createStructure() self.previousParams = self._gatherParameters() self.win.assy.changed() self.win.win_update() return self.win.assy.current_command_info(cmdname=self.cmdname) params = self._gatherParameters() if not same_vals(params, self.previousParams): self._modifyStructure(params) self.logMessage = str(self.cmd + "Previewing " + self.struct.name) self.previousParams = params self.win.assy.changed() self.win.win_update()
def do_we_need_to_recompute(self, context): """ Do we need to recompute, now that we're in the current state of the given context (for purposes of current values at keys, as computed by self._compute_current_value)? """ assert not self._recomputing if not self.valid: # following code would be wrong in this case return True for key, val in self.ordered_key_val_pairs(): # Note: doesn't call _track_use, which would be a noop. newval = self._compute_current_value(key, context) if not same_vals(val, newval): #e Could optim the test for specific keys; probably not worth it # though. #e Could optim self.before_recompute (for some callers) to leave # the values cached that were already found to be the same (by # prior iterations of this loop) # Note: We don't call self.invalidate() here, in case client # does nothing, current state changes, and it turns out we're # valid again. Clients doubting this matters and wanting to # optimize repeated calls of this (if they're not going to # recompute right away) can call it themselves. Most clients # needn't bother since they'll recompute right away. return True return False
def _finalizeStructure(self): """ Finalize the structure. This is a step just before calling Done method. to exit out of this command. Subclasses may overide this method @see: EditCommand_PM.ok_btn_clicked @see: DnaSegment_EditCommand where this method is overridden. """ if self.struct is None: return self.win.assy.current_command_info(cmdname=self.cmdname) params = self._gatherParameters() if not same_vals(params, self.previousParams): self._modifyStructure(params) if hasattr(self.struct, 'updateCosmeticProps'): self.struct.updateCosmeticProps() self.logMessage = str(self.cmd + "Created " + self.struct.name) #Do we need to set the self.previousParams even when the structure #is finalized? I think this is unnecessary but harmless to do. self.previousParams = params self.win.assy.changed() self.win.win_update()
def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.command_update_UI() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: #disable all widgets if self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s" % (why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg)
def model_changed(self): """ @see: DnaSegment_EditCommand.model_changed() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: #disable all widgets if self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s"%(why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg)
def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.command_update_UI() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return number_of_segments, \ crossover_search_pref_junk,\ bool_valid_segmentList_junk = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams #Ensures that there are only PAM3 DNA segments in the commad's tructure #list (command._structList. Call this before updating the list widgets! self.command.ensureValidSegmentList() self.updateListWidgets() self.command.updateCrossoverSites()
def _previewStructure(self): """ Preview the structure and update the previous parameters attr (self.previousParams) @see: self.preview_or_finalize_structure """ # For certain edit commands, it is possible that self.struct is # not created. If so simply return (don't use assert self.struct) ##This is a commented out stub code for the edit controllers ##such as DNAEditCommand which take input from the user before ##creating the struct. TO BE REVISED -- Ninad20071009 # The following code is now used. Need to improve comments and # some refactoring -- Ninad 2007-10-24 if self.struct is None: self.struct = self._createStructure() self.previousParams = self._gatherParameters() return self.win.assy.current_command_info(cmdname=self.cmdname) params = self._gatherParameters() if not same_vals(params, self.previousParams): self._modifyStructure(params) self.logMessage = str(self.cmd + "Previewing " + self.struct.name) self.previousParams = params self.win.assy.changed() self.win.win_update()
def _finalizeStructure(self): """ Finalize the structure. This is a step just before calling Done method. to exit out of this command. Subclasses may overide this method @see: EditCommand_PM.ok_btn_clicked @see: DnaSegment_EditCommand where this method is overridden. """ if self.struct is None: return self.win.assy.current_command_info(cmdname=self.cmdname) params = self._gatherParameters() if not same_vals(params, self.previousParams): self._modifyStructure(params) if hasattr(self.struct, "updateCosmeticProps"): self.struct.updateCosmeticProps() self.logMessage = str(self.cmd + "Created " + self.struct.name) # Do we need to set the self.previousParams even when the structure # is finalized? I think this is unnecessary but harmless to do. self.previousParams = params self.win.assy.changed() self.win.win_update()
def model_changed(self): """ Overrides basicMode.model_changed. @WARNING: Ideally this property manager should implement both model_changed and selection_changed methods in the mode API. model_changed method will be used here when the selected atom is dragged, transmuted etc. The selection_changed method will be used when the selection (picking/ unpicking) changes. At present, selection_changed and model_changed methods are called too frequently that it doesn't matter which one you use. Its better to use only a single method for preformance reasons (at the moment). This should change when the original methods in the API are revised to be called at appropiraite time. """ newSelectionParams = self._currentSelectionParams() if same_vals(newSelectionParams, self.previousSelectionParams): return self.previousSelectionParams = newSelectionParams #subclasses of BuildAtomsPM may not define self.selectedAtomPosGroupBox #so do the following check. if self.selectedAtomPosGroupBox: self._updateSelectedAtomPosGroupBox(newSelectionParams)
def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.model_changed() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return number_of_segments, isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: if not number_of_segments == 0: #disable all widgets self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s" % (why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segments" self.updateMessage(msg) self.updateListWidgets()
def _update_UI_do_updates(self): """ Overrides superclass method. @see: PasteFromClipboard_Command.command_update_internal_state() which is called before any command/ PM update UI. """ currentParams = self._current_model_changed_params() if same_vals(currentParams, self._previous_model_changed_params): return #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams self.update_clipboard_items() # Fixes bugs 1569, 1570, 1572 and 1573. mark 060306. # Note and bugfix, bruce 060412: doing this now was also causing # traceback bugs 1726, 1629, # and the traceback part of bug 1677, and some related #(perhaps unreported) bugs. # The problem was that this is called during pasteBond's addmol #(due to its addchild), before it's finished, # at a time when the .part structure is invalid (since the added # mol's .part has not yet been set). # To fix bugs 1726, 1629 and mitigate bug 1677, I revised the # interface to MMKit.update_clipboard_items # (in the manner which was originally recommented in #call_after_next_changed_members's docstring) # so that it only sets a flag and updates (triggering an MMKit # repaint event), deferring all UI effects to # the next MMKit event. pass
def done_msg(self): 'Returns the message to print after the OK button has been pressed.' if self.node_is_new: return "%s created." % self.name else: if not same_vals(self.previousParams, self.gather_parameters()): return "%s updated." % self.name else: return "%s unchanged." % self.name
def done_msg(self): 'Returns the message to print after the OK button has been pressed.' if self.node_is_new: return "%s created." % self.name else: if not same_vals( self.previousParams, self.gather_parameters()): return "%s updated." % self.name else: return "%s unchanged." % self.name
def __init__(self, name, dtype, prefs_key=False, non_debug=False, subs=()): #bruce 060124 added prefs_key & non_debug options #e for now, name is used locally (for UI, etc, and maybe for prefs db); # whether/how to find this obj using name is up to the caller self.name = name assert name and type(name) == type( "" ) #bruce 060124 added assert (don't know if this was already an implicit requirement) self.dtype = dtype # a DataType object self.value = self._dfltval = dtype.get_defaultValue( ) # might be changed below #bruce 070228 added self._dfltval if prefs_key: #bruce 060124 new feature if prefs_key is True: prefs_key = "_debug_pref_key:" + name #e should prefix depend on release-version?? assert type(prefs_key) == type( ""), "prefs_key must be True or a string" assert prefs_key # implied by the other asserts/ifs self.prefs_key = prefs_key import foundation.preferences as preferences # make sure env.prefs is initialized [bruce 070110 precaution] # (evidently ok this early, but not sure if needed -- it didn't fix the bug in a Choice of None I commented on today) self.value = env.prefs.get( prefs_key, self.value ) ###k guess about this being a fully ok way to store a default value # Note: until I fixed preferences.py today, this failed to store a default value when self.value was None. [bruce 070110] # note: in this case, self.value might not matter after this, but in case it does we keep it in sync before using it, # or use it only via self.current_value() [bruce 060209 bugfix] if self.print_changes and not same_vals( self.value, self._dfltval): #bruce 070228 new feature for debug_pref # note: we use same_vals to avoid bugs in case of tuples or lists of Numeric arrays. # note: this only does printing of initial value being non-default; # printing of changes by user is done elsewhere, and presently goes # to both history widget and console print. We'll follow the same policy # here -- but if it's too early to print to history widget, env.history # will print to console, and we don't want it to get printed there twice, # so we check for that before printing it to console ourselves. [bruce 071018] msg = "Note: %s (default %r) starts out %r" % \ (self, self._dfltval, self.value) ## + " %s" % self.starts_out_from_where if not getattr(env.history, 'too_early', False): print msg env.history.message(msg, quote_html=True, color='orange') pass self.non_debug = non_debug # show up in debug_prefs submenu even when ATOM-DEBUG is not set? self.subscribers = [ ] # note: these are only called for value changes due to debug menu for sub in subs: self.subscribe_to_changes(sub) self.subscribe_to_changes(self._fulfill_call_with_new_value) # note: creates reference cycle (harmless, since we're never destroyed) return
def getAxisEndAtomAtPosition(self, position): """ Given a position, return the axis end atom at that position (if it exists) """ axisEndAtom = None endAtom1, endAtom2 = self.getAxisEndAtoms() for atm in (endAtom1, endAtom2): if atm is not None and same_vals(position, atm.posn()): axisEndAtom = atm break return axisEndAtom
def command_update_internal_state(self): """ Extends the superclass method. @see:baseCommand.command_update_internal_state() for documentation """ #NOTE 2008-09-02: This method is called too often. It should exit early #if , for example , model_change_indicator didn't change. Need to #review and test to see if its okay to do so. [-- Ninad comment] _superclass.command_update_internal_state(self) #This MAY HAVE BUG. WHEN -- #debug pref 'call model_changed only when needed' is ON #See related bug 2729 for details. #The following code that updates te handle positions and the strand #sequence fixes bugs like 2745 and updating the handle positions #updating handle positions in command_update_UI instead of in #self.graphicsMode._draw_handles() is also a minor optimization #This can be further optimized by debug pref #'call command_update_UI only when needed' but its NOT done because of #an issue mentioned in bug 2729 - Ninad 2008-04-07 if self.grabbedHandle is not None: return current_model_change_indicator = self.assy.model_change_indicator() #This should be OK even when a subclass calls this method. #(the model change indicator is updated globally , using self.assy. ) if same_vals(current_model_change_indicator, self._previous_model_change_indicator): return self._previous_model_change_indicator = current_model_change_indicator #PAM5 segment resizing is not supported. #@see: self.hasResizableStructure() if not self.hasValidStructure(): return isStructResizable, why_not = self.hasResizableStructure() if not isStructResizable: self.handles = [] return elif len(self.handles) == 0: self._updateHandleList() self.updateHandlePositions() self._update_previousParams_in_model_changed()
def submenu_from_name_value_pairs( nameval_pairs, newval_receiver_func, curval = None, mitem_value_func = None, indicate_defaultValue = False, defaultValue = None ): #bruce 080312 revised to use same_vals (2 places) from utilities.debug import print_compact_traceback # do locally to avoid recursive import problem submenu = [] for name, value in nameval_pairs: text = name if indicate_defaultValue and same_vals(value, defaultValue): #bruce 070518 new feature text += " (default)" command = ( lambda ## event = None, func = newval_receiver_func, val = value : func(val) ) mitem = ( text, command, same_vals(curval, value) and 'checked' or None ) if mitem_value_func is not None: try: res = "<no retval yet>" # for error messages res = mitem_value_func(mitem, value) if res is None: continue # let func tell us to skip this item ###k untested assert type(res) == type((1, 2)) mitem = res except: print_compact_traceback("exception in mitem_value_func, or error in retval (%r): " % (res,)) #e improve, and atom_debug only pass submenu.append(mitem) return submenu
def _build_struct(self, previewing=False): """Private method. Called internally to build the structure by calling the (generator-specific) method build_struct (if needed) and processing its return value. """ params = self.gather_parameters() if self.struct is None: # no old structure, we are making a new structure # (fall through) pass elif not same_vals(params, self.previousParams): # parameters have changed, update existing structure self._revert_number() # (fall through, using old name) pass else: # old structure, parameters same as previous, do nothing return # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name if previewing: env.history.message(self.cmd + "Previewing " + name) else: env.history.message(self.cmd + "Creating " + name) self.remove_struct() self.previousParams = params self.struct = self.build_struct(name, params, -self.win.glpane.pov) self.win.assy.addnode(self.struct) # Do this if you want it centered on the previous center. # self.win.glpane.setViewFitToWindow(fast = True) # Do this if you want it centered on the origin. self.win.glpane.setViewRecenter(fast=True) self.win.win_update() # includes mt_update return
def get_strand_and_axis_endAtoms_at_resize_end(self): resizeEndStrandAtom = None resizeEndAxisAtom = None strandEndAtom1, strandEndAtom2 = self.struct.get_strand_end_base_atoms() if self.grabbedHandle is not None: for atm in (strandEndAtom1, strandEndAtom2): axisEndAtom = atm.axis_neighbor() if axisEndAtom: if same_vals(axisEndAtom.posn(), self.grabbedHandle.origin): resizeEndStrandAtom = atm resizeEndAxisAtom = axisEndAtom return (resizeEndStrandAtom, resizeEndAxisAtom)
def _build_struct(self, previewing = False): """Private method. Called internally to build the structure by calling the (generator-specific) method build_struct (if needed) and processing its return value. """ params = self.gather_parameters() if self.struct is None: # no old structure, we are making a new structure # (fall through) pass elif not same_vals( params, self.previousParams): # parameters have changed, update existing structure self._revert_number() # (fall through, using old name) pass else: # old structure, parameters same as previous, do nothing return # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name if previewing: env.history.message(self.cmd + "Previewing " + name) else: env.history.message(self.cmd + "Creating " + name) self.remove_struct() self.previousParams = params self.struct = self.build_struct(name, params, - self.win.glpane.pov) self.win.assy.addnode(self.struct) # Do this if you want it centered on the previous center. # self.win.glpane.setViewFitToWindow(fast = True) # Do this if you want it centered on the origin. self.win.glpane.setViewRecenter(fast = True) self.win.win_update() # includes mt_update return
def command_update_internal_state(self): """ Extends superclass method. @see: baseCommand.command_update_internal_state() @see: PastePropertyManager._update_UI_do_updates() """ _superclass.command_update_internal_state(self) currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams #This was earlier -- self.update_gui_0() self._update_pastables_list()
def model_changed(self): #check first if the plane object exists first if self.hasValidStructure() is None: return # piotr 080617 # fixed plane resizing bug - should return if the plane # is being interactively modified if self.propMgr.resized_from_glpane: return #see if values in PM has changed currentParams = self._gatherParameters() if same_vals(currentParams,self.propMgr.previousPMParams): return self.propMgr.previousPMParams = currentParams self._modifyStructure(currentParams)
def model_changed(self): #check first if the plane object exists first if self.hasValidStructure() is None: return # piotr 080617 # fixed plane resizing bug - should return if the plane # is being interactively modified if self.propMgr.resized_from_glpane: return #see if values in PM has changed currentParams = self._gatherParameters() if same_vals(currentParams, self.propMgr.previousPMParams): return self.propMgr.previousPMParams = currentParams self._modifyStructure(currentParams)
def _update_UI_check_change_indicators(self): """ This method does a basic check to see if something in the assembly changed since last call of this method. It compares various change indicators defined in assembly class against an attribute of this class. This class attr stores the previous values of all these change indicators when it was last called. @see: self.update_UI() """ current_change_indicators = (self.win.assy.model_change_indicator(), self.win.assy.selection_change_indicator(), self.win.assy.command_stack_change_indicator()) if same_vals(current_change_indicators, self._previous_all_change_indicators): return False self._previous_all_change_indicators = current_change_indicators return True
def _update_UI_check_change_indicators(self): """ This method does a basic check to see if something in the assembly changed since last call of this method. It compares various change indicators defined in assembly class against an attribute of this class. This class attr stores the previous values of all these change indicators when it was last called. @see: self.update_UI() """ current_change_indicators = ( self.win.assy.model_change_indicator(), self.win.assy.selection_change_indicator(), self.win.assy.command_stack_change_indicator()) if same_vals(current_change_indicators, self._previous_all_change_indicators): return False self._previous_all_change_indicators = current_change_indicators return True
def _updateStrandSequence_if_needed(self): if self.hasValidStructure(): new_numberOfBases = self.struct.getNumberOfBases() #@TODO Update self._previousParams again? #This NEEDS TO BE REVISED. BUG MENTIONED BELOW---- #we already update this in EditCommand class. But, it doesn't work for #the following bug -- 1. create a duplex with 5 basepairs, 2. resize #red strand to 2 bases. 3. Undo 4. Redo 5. Try to resize it again to #2 bases -- it doesn't work because self.previousParams stil stores #bases as 2 and thinks nothing got changed! Can we declare #self._previewStructure as a undiable state? Or better self._previousParams #should store self.struct and should check method return value #like self.struct.getNumberOfBases()--Ninad 2008-04-07 if self.previousParams is not None: if new_numberOfBases != self.previousParams[0]: self.propMgr.numberOfBasesSpinBox.setValue(new_numberOfBases) self.previousParams = self._gatherParameters() if not same_vals(new_numberOfBases, self._previousNumberOfBases): self.propMgr.updateSequence() self._previousNumberOfBases = new_numberOfBases
def do_we_need_to_recompute(self, context): """ Assume the client is in a context in which it *could* safely/correctly recompute, in terms of _compute_current_value being safe to call and returning the correct value for whatever keys a recomputation would pass to it (when passed the given context parameter). @return: whether the client needs to do its recomputation (True) or can reuse the result it got last time (and presumably cached) (False) See class docstring for more info. """ assert not self._recomputing if not self.valid: # the code below would be wrong in this case return True for key, val in self.ordered_key_val_pairs(): # Note: doesn't call self._track_use, which would be a noop. ###todo: clarify newval = self._compute_current_value(key, context) if not same_vals(val, newval): #e Could optim the test for specific keys; probably not worth it # though. ###TODO: OPTIM: Could optim self.before_recompute # (for some callers -- REVIEW, which ones exactly?) # to leave the values cached that were already found to be # the same (by prior iterations of this loop). # We'd do this by deleting the different values here # (and the not yet compared ones); # this would make the following note partly incorrect. # Note: We don't call self.invalidate() here, in case client # does nothing, current state changes, and it turns out we're # valid again. Clients doubting this matters, and which are not # going to recompute right away, and which want to optimize # repeated calls of this (by avoiding redoing the same_vals # tests) can call self.invalidate themselves. Most clients # needn't bother since they'll recompute right away. return True return False
def __init__(self, name, dtype, prefs_key = False, non_debug = False, subs = ()): #bruce 060124 added prefs_key & non_debug options #e for now, name is used locally (for UI, etc, and maybe for prefs db); # whether/how to find this obj using name is up to the caller self.name = name assert name and type(name) == type("") #bruce 060124 added assert (don't know if this was already an implicit requirement) self.dtype = dtype # a DataType object self.value = self._dfltval = dtype.get_defaultValue() # might be changed below #bruce 070228 added self._dfltval if prefs_key: #bruce 060124 new feature if prefs_key is True: prefs_key = "_debug_pref_key:" + name #e should prefix depend on release-version?? assert type(prefs_key) == type(""), "prefs_key must be True or a string" assert prefs_key # implied by the other asserts/ifs self.prefs_key = prefs_key import foundation.preferences as preferences # make sure env.prefs is initialized [bruce 070110 precaution] # (evidently ok this early, but not sure if needed -- it didn't fix the bug in a Choice of None I commented on today) self.value = env.prefs.get( prefs_key, self.value ) ###k guess about this being a fully ok way to store a default value # Note: until I fixed preferences.py today, this failed to store a default value when self.value was None. [bruce 070110] # note: in this case, self.value might not matter after this, but in case it does we keep it in sync before using it, # or use it only via self.current_value() [bruce 060209 bugfix] if self.print_changes and not same_vals(self.value, self._dfltval): #bruce 070228 new feature for debug_pref # note: we use same_vals to avoid bugs in case of tuples or lists of Numeric arrays. # note: this only does printing of initial value being non-default; # printing of changes by user is done elsewhere, and presently goes # to both history widget and console print. We'll follow the same policy # here -- but if it's too early to print to history widget, env.history # will print to console, and we don't want it to get printed there twice, # so we check for that before printing it to console ourselves. [bruce 071018] msg = "Note: %s (default %r) starts out %r" % \ (self, self._dfltval, self.value) ## + " %s" % self.starts_out_from_where if not getattr(env.history, 'too_early', False): print msg env.history.message(msg, quote_html = True, color = 'orange') pass self.non_debug = non_debug # show up in debug_prefs submenu even when ATOM-DEBUG is not set? self.subscribers = [] # note: these are only called for value changes due to debug menu for sub in subs: self.subscribe_to_changes(sub) self.subscribe_to_changes( self._fulfill_call_with_new_value ) # note: creates reference cycle (harmless, since we're never destroyed) return
def _update_UI_do_updates(self): """ Overrides superclass method. @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ if not DEBUG_BREAK_OPTIONS_FEATURE: return currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return basesBeforeNextBreak = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams self.command.updateBreakSites()
def _update_UI_do_updates(self): """ Overrides superclass method @warning: This is called frequently, even when nothing has changed. It's used to respond to other kinds of changes as well (e.g. to the selection). So it needs to be fast when nothing has changed. (It will be renamed accordingly in the API.) @see: Command_PropertyManager._updateUI_do_updates() """ newSelectionParams = self._currentSelectionParams() if same_vals(newSelectionParams, self.previousSelectionParams): return self.previousSelectionParams = newSelectionParams #subclasses of BuildAtomsPM may not define self.selectedAtomPosGroupBox #so do the following check. if self.selectedAtomPosGroupBox: self._updateSelectedAtomPosGroupBox(newSelectionParams)
def command_update_internal_state(self): """ Extends the superclass method. This method should replace model_changed() eventually. This method calss self.model_changed at the moment. @see:baseCommand.command_update_internal_state() for documentation @see: PlanePropertyManager._update_UI_do_updates() @see: PlanePropertyManager.update_spinboxes() @see: Plane.resizeGeometry() """ if not self.propMgr: print_compact_stack("bug: self.propMgr not defined when"\ "Plane_EditCommand.command_update_internal_state called."\ "Returning.") return #check first if the plane object exists first if not self.hasValidStructure(): return #NOTE: The following ensures that the image path and other display #prams are properly updated in the plane. Perhaps its better done using #env.prefs? Revising this code to fix bugs in resizing because #of the self._modifyStructure call. See also original code in #Revision 12982 -- Ninad 2008-09-19 currentDisplayParams = self.propMgr.getCurrrentDisplayParams() if same_vals(currentDisplayParams, self._previous_display_params): return self._previous_display_params = currentDisplayParams params = self._gatherParameters() self._modifyStructure(params)
def is_identity(self): # review: optimize? special fast case if data never modified? return same_vals( (self.translation, self.rotation), (_IDENTITY_TRANSLATION, _IDENTITY_ROTATION) )
def check_quats_near(q1, q2, msg=""): #bruce, circa 040924 """ Complain to stdout if two quats are not near; return whether they are. """ res = True #bruce 050518 bugfix -- was False (which totally disabled this) for i in [0, 1, 2, 3]: res = res and check_floats_near(q1[i],q2[i],msg+"[%d]"%i) return res # == test code [bruce 070227] if __name__ == '__main__': print "tests started" q1 = Q(1, 0, 0, 0) print q1, `q1` q2 = Q(V(0.6, 0.8, 0), 1) print q2, `q2` assert not (q1 == q2), "different quats equal!" # this bug was fixed on 070227 assert q1 != V(0, 0, 0) # this did print_compact_traceback after that was fixed; now that's fixed too # can't work yet: assert q2 * 2 == 2 * q2 # this means you have to run this from cad/src as ./ExecSubDir.py geometry/VQT.py from utilities.Comparison import same_vals q3 = Q(1, 0, 0, 0) assert same_vals( q1, q3 ), "BUG: not same_vals( Q(1,0,0,0), Q(1,0,0,0) )" print "tests done" # end
def current_value_is_not_default(self): #bruce 080312 return not same_vals(self.current_value(), self._dfltval)