diff options
author | Bruce Smith <bruce@nanorex.com> | 2008-06-05 23:08:05 +0000 |
---|---|---|
committer | Bruce Smith <bruce@nanorex.com> | 2008-06-05 23:08:05 +0000 |
commit | a0a64d45f1762e76c7cf89a682b904a9289167a9 (patch) | |
tree | db83702082ad5d415ec7dbdf35863488c37a37bd | |
parent | 18404ad7afa1f5473128ffdf9006e007b2d5d830 (diff) | |
download | nanoengineer-theirix-a0a64d45f1762e76c7cf89a682b904a9289167a9.tar.gz nanoengineer-theirix-a0a64d45f1762e76c7cf89a682b904a9289167a9.zip |
partial implem of extra display lists in chunks, has bugs
-rwxr-xr-x | cad/src/foundation/env.py | 2 | ||||
-rw-r--r-- | cad/src/graphics/drawing/special_drawing.py (renamed from cad/src/scratch/chunk-extra-displists.py) | 370 | ||||
-rw-r--r-- | cad/src/model/BorrowerChunk.py | 4 | ||||
-rwxr-xr-x | cad/src/model/chem.py | 179 | ||||
-rwxr-xr-x | cad/src/model/chunk.py | 67 |
5 files changed, 423 insertions, 199 deletions
diff --git a/cad/src/foundation/env.py b/cad/src/foundation/env.py index 816965a09..4fbde7cb2 100755 --- a/cad/src/foundation/env.py +++ b/cad/src/foundation/env.py @@ -93,6 +93,8 @@ def mainwindow(): #bruce 051209 return _mainWindow +mainWindow = mainwindow # alias which should become the new name of that function [bruce 080605] + def debug(): #bruce 060222 """ Should debug checks be run, and debug messages be printed, and debug options offered in menus? diff --git a/cad/src/scratch/chunk-extra-displists.py b/cad/src/graphics/drawing/special_drawing.py index 72981789a..62df364c1 100644 --- a/cad/src/scratch/chunk-extra-displists.py +++ b/cad/src/graphics/drawing/special_drawing.py @@ -1,10 +1,15 @@ # Copyright 2008 Nanorex, Inc. See LICENSE file for details. """ -chunk-extra-displists.py - scratch file to help with extra_displist code in class chunk +special_drawing.py - help class Chunk do special drawing in extra display lists @author: Bruce @version: $Id$ -@copyright: 2008 Nanorex, Inc. See LICENSE file for details. +@copyright: 2008 Nanorex, Inc. See LICENSE file for details. + +TODO: + +Eventually, this should be divided into general and specific modules, +with some parts refiled into foundations. """ from graphics.drawing.ColorSorter import ColorSorter @@ -13,153 +18,57 @@ from graphics.drawing.ColorSorter import ColorSortedDisplayList from utilities.Comparison import same_vals from foundation.state_utils import copy_val -class ExtraChunkDisplayList(object): - """ - Holds one ColorSortedDisplayList used for doing some kind of extra - drawing associated with a Chunk but not drawn as part of its main - CSDL, along with the state that determines whether this CSDL is invalid, - and under what conditions it will remain valid. - - Helps figure out when to invalidate it, redraw it, etc. - """ - - # class constants - - _comparator_class = None # subclass must override, with a subclass of UsedValueTrackerAndComparator - - # default values of instance variables - - valid = False - - def __init__(self): - self.csdl = ColorSortedDisplayList() - self._drawing_functions = [] # needed? - self.comparator = self._comparator_class() - return - - # == methods related to the client compiling its *main* display list - # (not this extra one, but that's when it finds out what goes into - # this extra one, or that it needs it at all) - - def _before_client_main_recompile(self): #e rename? - self._drawing_functions = [] - return - - def add_another_drawing_function(self, func): # during client main recompile - self._drawing_functions.append( func) - return - - def _after_client_main_recompile(self): #e rename? - return +import foundation.env as env - # == methods for drawing self (with or without recompiling) - - def draw_but_first_recompile_if_needed(self, glpane, selected = False, highlighted = False, wantlist = True): - """ - Recompile self as needed, then draw. - Only make internal display lists (in cases where we need to remake them) - if wantlist is true. +from foundation.changes import SubUsageTrackingMixin - @param selected: whether to draw in selected or plain style. (The same csdl handles both.) +from utilities.debug import print_compact_traceback - @param highlighted: whether to draw highlighted, or not. (The same csdl handles both.) - """ - if not self.valid or self.comparator.do_we_need_to_recompute(): ##### also compare havelist, if some data not tracked - self._draw_by_remaking(glpane, selected, highlighted, wantlist) - else: - self._draw_by_reusing(glpane, selected, highlighted) - return +# == - def _draw_by_remaking(self, glpane, selected, highlighted, wantlist): - """ - """ - # modified from similar code in Chunk.draw - if wantlist: - match_checking_code = self.begin_tracking_usage() ##### REQUIRES superclass - ColorSorter.start(self.csdl) +class _USE_CURRENT_class(object): + def __getitem__(self, key): + # get the "current glpane" and its graphicsMode + # (for purposes of determining modes & prefs) + # (how we do it is not necessarily a kluge, given that this is being + # used to define a constant value for use when a better one was + # not passed) + win = env.mainWindow() + glpane = win.glpane + graphicsMode = glpane.graphicsMode + # let the graphicsMode interpret the prefs key, + # in case it wants to override it with a local pref + # (or conceivably, someday, track it in a different way) try: - self._do_drawing() + res = graphicsMode.get_prefs_value(key) ##### IMPLEM except: - print_compact_traceback("bug: exception in %r._do_drawing, skipping the rest: " % self) - pass - if wantlist: - ColorSorter.finish() - self._glpane = glpane # needed by self.inval_display_list for gl_update - self.end_tracking_usage( match_checking_code, self.inval_display_list ) - return + ##### REENABLE THIS when api method is there: +## msg = "routine-for-now bug: exception in %r.get_prefs_value(%r), falling back to env.prefs" % \ +## (graphicsMode, key) +## print_compact_traceback(msg + ": ") + res = env.prefs[key] + return res + pass - def _draw_by_reusing(self, glpane, selected, highlighted): - """ - """ - # see also: code in Chunk.draw which uses its self.displist - self.csdl.draw(selected = selected, highlighted = highlighted) - return +USE_CURRENT = _USE_CURRENT_class() - # == - def invalidate(self): - self.valid = False - return +# kinds of special drawing (only one so far) - def inval_display_list(self): - """ - This is meant to be called when something whose usage we tracked - (while making our display list) next changes. - """ - self.invalidate() - self._glpane.gl_update() # self._glpane should always exist - return - - # == - - def _do_drawing(self): - # drawsphere(...), drawcylinder(...), drawpolycone(...), and so on. - for func in self._drawing_functions: - func() ### args?? e.g. self? some drawing prefs?? - return +SPECIAL_DRAWING_STRAND_END = 'SPECIAL_DRAWING_STRAND_END' - ### REVIEW below here, probably obs - - def set_input_data(self, data): - """ - The client chunk has computed new data which determines - (along with its own state?) what we should draw. - Store it, and if it differs from old data, invalidate. - """ - if not same_vals( self._data, data): - self._data = copy_val(data) - self.invalidate() - return - def set_validity_data(self, vdata): - # for havelist contents i guess? - if not same_vals( self._vdata, vdata): - self._vdata = copy_val(vdata) - self.invalidate() - return - pass +ALL_SPECIAL_DRAWING_KINDS = [SPECIAL_DRAWING_STRAND_END] -# == -class StrandEnd_ExtraChunkDisplayList(ExtraChunkDisplayList): - """ - """ - # note about current usage by client code (chunk drawing code): - # this will be created on demand when something being drawn - # during a chunk's main displist (CSDL) compile - # wants to put things into a StrandEnd display list instead, - # since that might need recompiling more often than the main one. - # The chunk knows which subclass of ExtraChunkDisplayList to use - # for each type of extra drawing, and allocates one on demand. - # Then the object doing the drawing will give us a function - # to use for redrawing itself, passing it to add_another_drawing_function. +# === - # subclass constants - - _comparator_class = StrandEnd_UsedValueTrackerAndComparator - - pass # end of class - -# ====== +# usage tracking functions +# +# when the dust settles, the general class here +# should be moved into foundation (related to changes.py) +# and the specific one into a module for the strand-end-specific +# part of this, unless it turns out to be more general than that +# (applying potentially to all prefs values). class UsedValueTrackerAndComparator(object): """ @@ -195,7 +104,9 @@ class UsedValueTrackerAndComparator(object): self._recomputing = True return - def get_value(self, key, context): ##### @@@@@ CALL THIS SOMEHOW in place of env.prefs when drawing extra displist contents + def get_value(self, key, context): + ##### @@@@@ CALL THIS SOMEHOW in place of env.prefs when drawing extra displist contents -- + ### need to make a "prefs value object" (stores glpane) to pass to draw funcs, which looks up keys by calling this ###### """ ... call this while redoing the client computation... It will record the value it returns, both to optimize repeated calls, @@ -278,7 +189,7 @@ class UsedValueTrackerAndComparator(object): # == -class StrandEnd_UsedValueTrackerAndComparator(UsedValueTrackerAndComparator): +class StrandEnd_UsedValueTrackerAndComparator(UsedValueTrackerAndComparator): ##### RENAME: specific to special drawing, not strand end """ ... if necessary, reset and re-track the values used this time... knows how to compute them... """ @@ -299,3 +210,188 @@ class StrandEnd_UsedValueTrackerAndComparator(UsedValueTrackerAndComparator): return method() pass + +# === + +class ExtraChunkDisplayList(object, SubUsageTrackingMixin): + """ + Holds one ColorSortedDisplayList used for doing some kind of extra + drawing associated with a Chunk but not drawn as part of its main + CSDL, along with the state that determines whether this CSDL is invalid, + and under what conditions it will remain valid. + + Helps figure out when to invalidate it, redraw it, etc. + """ + + # class constants + + _comparator_class = None # subclass must override, with a subclass of UsedValueTrackerAndComparator + + # default values of instance variables + + valid = False + + def __init__(self): + self.csdl = ColorSortedDisplayList() + self.comparator = self._comparator_class() + self.before_client_main_recompile() # get ready right away + return + + # == methods related to the client compiling its *main* display list + # (not this extra one, but that's when it finds out what goes into + # this extra one, or that it needs it at all) + + def before_client_main_recompile(self): #e rename? + self._drawing_functions = [] + return + + def add_another_drawing_function(self, func): # during client main recompile + self._drawing_functions.append( func) + return + + def after_client_main_recompile(self): #e rename? + return + + # == methods for drawing self (with or without recompiling) + + def draw_but_first_recompile_if_needed(self, glpane, selected = False, highlighted = False, wantlist = True): + """ + Recompile self as needed, then draw. + Only make internal display lists (in cases where we need to remake them) + if wantlist is true. + + @param selected: whether to draw in selected or plain style. (The same csdl handles both.) + + @param highlighted: whether to draw highlighted, or not. (The same csdl handles both.) + """ + if not self.valid or self.comparator.do_we_need_to_recompute(): ##### also compare havelist, if some data not tracked + self._draw_by_remaking(glpane, selected, highlighted, wantlist) + else: + self._draw_by_reusing(glpane, selected, highlighted) + return + + def _draw_by_remaking(self, glpane, selected, highlighted, wantlist): + """ + """ + # modified from similar code in Chunk.draw + if wantlist: + match_checking_code = self.begin_tracking_usage() + # note: method defined in superclass, SubUsageTrackingMixin + ColorSorter.start(self.csdl) + try: + self._do_drawing() + except: + print_compact_traceback("bug: exception in %r._do_drawing, skipping the rest: " % self) + pass + if wantlist: + ColorSorter.finish() + self._glpane = glpane # needed by self.inval_display_list for gl_update + self.end_tracking_usage( match_checking_code, self.inval_display_list ) + return + + def _draw_by_reusing(self, glpane, selected, highlighted): + """ + """ + # see also: code in Chunk.draw which uses its self.displist + self.csdl.draw(selected = selected, highlighted = highlighted) + return + + # == + + def invalidate(self): + self.valid = False + return + + def inval_display_list(self): + """ + This is meant to be called when something whose usage we tracked + (while making our display list) next changes. + """ + self.invalidate() + self._glpane.gl_update() # self._glpane should always exist + return + + # == + + def _do_drawing(self): + # drawsphere(...), drawcylinder(...), drawpolycone(...), and so on. + args = self._construct_args_for_drawing_functions() + for func in self._drawing_functions: + func(*args) + return + + def _construct_args_for_drawing_functions(self): + assert 0, "subclass must implement" + + pass # end of class ExtraChunkDisplayList + +# == + +class StrandEnd_ExtraChunkDisplayList(ExtraChunkDisplayList): ##### RENAME, it's for any special drawing, not just strand ends + """ + """ + # note about current usage by client code (chunk drawing code): + # this will be created on demand when something being drawn + # during a chunk's main displist (CSDL) compile + # wants to put things into a StrandEnd display list instead, + # since that might need recompiling more often than the main one. + # The chunk knows which subclass of ExtraChunkDisplayList to use + # for each type of extra drawing, and allocates one on demand. + # Then the object doing the drawing will give us a function + # to use for redrawing itself, passing it to add_another_drawing_function. + + # subclass constants + + _comparator_class = StrandEnd_UsedValueTrackerAndComparator + + # overridden methods + + def _construct_args_for_drawing_functions(self): + prefs_value_finder = USE_CURRENT # KLUGE, but should partly work -- + # we should construct one that uses the current glpane, + # but this one knows how to find it... + # but WRONG since it fails to do tracking as it ought to... through our own get_value call, with context = the GM. #####FIX + return (prefs_value_finder,) + + pass # end of class + +# === + +class Chunk_SpecialDrawingHandler(object): + """ + A kind of SpecialDrawingHandler for a Chunk. + (There is not yet any other kind; what we know about class Chunk + is mainly the names of a few of its attributes we use and modify, + namely ###doc.) + + A SpecialDrawingHandler is .... #doc + """ + def __init__(self, chunk, classes): + self.chunk = chunk + self.classes = classes + def should_defer(self, special_drawing_kind): + assert special_drawing_kind in ALL_SPECIAL_DRAWING_KINDS + return self.classes.has_key(special_drawing_kind) + def draw_by_calling_with_prefsvalues(self, special_drawing_kind, func): #e rename? + # print "fyi: draw_by_calling_with_prefsvalues got", special_drawing_kind, func # this happens + extra_displist = self._get_extra_displist(special_drawing_kind) + extra_displist.add_another_drawing_function( func) ##### make sure called with one arg, a prefsvalues object + return + def _get_extra_displist(self, special_drawing_kind): + """ + Find or make, and return, the right kind of ExtraChunkDisplayList + for the given special_drawing_kind. + """ + extra_displists = self.chunk.extra_displists # cache dict for this kind + try: + return extra_displists[special_drawing_kind] + except KeyError: + class1 = self.classes[special_drawing_kind] + new = class1() #k args? + extra_displists[special_drawing_kind] = new + return new + pass + pass # end of class + +# end + diff --git a/cad/src/model/BorrowerChunk.py b/cad/src/model/BorrowerChunk.py index 382957063..ba92fc0e6 100644 --- a/cad/src/model/BorrowerChunk.py +++ b/cad/src/model/BorrowerChunk.py @@ -148,7 +148,7 @@ class BorrowerChunk(Chunk): return # from take_atomset - # instead of overriding draw_displist, it's enough to define _colorfunc and _dispfunc to help it: + # instead of overriding _draw_for_main_display_list, it's enough to define _colorfunc and _dispfunc to help it: def _colorfunc(self, atm): """ Define this to use atm's home mol's color instead of self.color, and also so that self._dispfunc gets called @@ -159,7 +159,7 @@ class BorrowerChunk(Chunk): return self.origmols[atm.key].drawing_color() def _dispfunc(self, atm): origmol = self.origmols[atm.key] - glpane = origmol.glpane # set shortly before this call, in origmol.draw_displist (kluge) + glpane = origmol.glpane # set shortly before this call, in origmol._draw_for_main_display_list (kluge) disp = origmol.get_dispdef(glpane) return disp def restore_atoms_to_their_homes(self): diff --git a/cad/src/model/chem.py b/cad/src/model/chem.py index f8fe2f8c0..225ff0d32 100755 --- a/cad/src/model/chem.py +++ b/cad/src/model/chem.py @@ -179,6 +179,9 @@ from dna.operations.crossovers import crossover_menu_spec from model.PAM_Atom_methods import PAM_Atom_methods +from graphics.drawing.special_drawing import USE_CURRENT +from graphics.drawing.special_drawing import SPECIAL_DRAWING_STRAND_END + # == debug_1779 = False # do not commit with True, but leave the related code in for now [bruce 060414] @@ -1590,7 +1593,7 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): pass return glname - def draw(self, glpane, dispdef, col, level): + def draw(self, glpane, dispdef, col, level, special_drawing_handler = None, special_drawing_prefs = USE_CURRENT): """ Draw this atom (self), using an appearance which depends on whether it is picked (selected) @@ -1613,6 +1616,27 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): """ assert not self.__killed + # review: future: should we always compute _draw_atom_style here, + # just once, so we can pass it to methods below such as howdraw, + # and avoid calling it multiple times in other methods below? + +## print "got special_drawing_handler %r, special_drawing_prefs %r" % \ +## (special_drawing_handler, special_drawing_prefs) ########################## + + if special_drawing_handler and ( + self._draw_atom_style(special_drawing_handler = special_drawing_handler) == + 'special_drawing_handler' + ): + # defer all drawing of self to special_drawing_handler [bruce 080605] + def func(special_drawing_prefs, args = (glpane, dispdef, col, level)): + self.draw(*args, **dict(special_drawing_prefs = special_drawing_prefs)) + special_drawing_handler.draw_by_calling_with_prefsvalues( + SPECIAL_DRAWING_STRAND_END, func ) + return + + # if we didn't defer, we don't need to use special_drawing_handler at all + del special_drawing_handler + glname = self.get_glname(glpane) disp = default_display_mode # to be returned in case of early exception @@ -1634,8 +1658,10 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): ColorSorter.pushName(glname) try: if disp in [diTrueCPK, diBALL, diTUBES]: - self.draw_atom_sphere(color, pos, drawrad, level, dispdef) - self.draw_wirespheres(glpane, disp, pos, pickedrad) + self.draw_atom_sphere(color, pos, drawrad, level, dispdef, + special_drawing_prefs = special_drawing_prefs ) + self.draw_wirespheres(glpane, disp, pos, pickedrad, + special_drawing_prefs = special_drawing_prefs ) except: ColorSorter.popName() glPopName() @@ -1668,16 +1694,30 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): # bruce 070409 split this out of draw_atom_sphere; # 070424 revised return value (None -> "") - def _draw_atom_style(self): + def _draw_atom_style(self, special_drawing_handler = None, special_drawing_prefs = None): ##### TODO: pass one of these args to each call """ [private helper method for L{draw_atom_sphere}, and perhaps related methods like L{draw_wirespheres}] Return a short hardcoded string (known to L{draw_atom_sphere}) saying in what style to draw the atom's sphere. + + @param special_drawing_handler: if not None, an object to which all drawing + which is dependent on special_drawing_prefs + needs to be deferred. In this method, this + argument is used only for tests + which let us tell the caller whether we need + to defer to it. + + @param special_drawing_prefs: an object that knows how to find out + how to draw strand ends. Never passed + along with special_drawing_handler -- only passed + if we're doing drawing which was *already* + deferred do that. @return: Returns one of the following values: - "" (Not None) means to draw an actual sphere. + - "special_drawing_handler" means to defer drawing to the special_drawing_handler. - "arrowhead-in" means to draw a 5' arrowhead. - "arrowhead-out" means to draw a 3' arrowhead. - "do not draw" means don't draw anything. @@ -1703,44 +1743,90 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): return 'bondpoint-stub' #k this might need to correspond with related code in Bond.draw if self.element.bonds_can_be_directional: #bruce 070415, correct end-arrowheads # note: as of mark 071014, this can happen for self being a Singlet - bool_arrowsOnFivePrimeEnds = env.prefs[arrowsOnFivePrimeEnds_prefs_key] - bool_arrowsOnThreePrimeEnds = env.prefs[arrowsOnThreePrimeEnds_prefs_key] - - if not bool_arrowsOnFivePrimeEnds and self.isFivePrimeEndAtom(): - return 'five_prime_end_atom' - elif not bool_arrowsOnThreePrimeEnds and self.isThreePrimeEndAtom(): - return 'three_prime_end_atom' - - bond = self.strand_end_bond() - # never non-None if self has two bonds with directions set - # (assuming no errors) -- i.e. for -Ss3-X, only non-None - # for the X, never for the Ss3 - # [bruce 080604 quick analysis, should re-review] - if bond is not None: - # Determine how singlets of strand open bonds should be drawn. - # draw_bond_main() takes care of drawing bonds accordingly. - # - mark 2007-10-20. - if bond.isFivePrimeOpenBond() and bool_arrowsOnFivePrimeEnds: - return 'arrowhead-in' - elif bond.isThreePrimeOpenBond() and bool_arrowsOnThreePrimeEnds: - return 'arrowhead-out' + + # figure out whether to defer drawing to special_drawing_handler [bruce 080605] + if self.isFivePrimeEndAtom() or \ + self.isThreePrimeEndAtom() or \ + self.strand_end_bond() is not None: + if special_drawing_handler and \ + special_drawing_handler.should_defer( SPECIAL_DRAWING_STRAND_END): + # tell caller to defer drawing self to special_drawing_handler + return 'special_drawing_handler' else: - return 'do not draw' - #e REVIEW: does Bond.draw need to be updated due to this, if "draw bondpoints as stubs" is True? - #e REVIEW: Do we want to draw even an isolated Pe (with bondpoint) as a cone, in case it's in MMKit, - # since it usually looks like a cone when it's correctly used? Current code won't do that. - #e Maybe add option to draw the dir == 0 case too, to point out you ought to propogate the direction + # draw using the values in special_drawing_prefs + res = self._draw_atom_style_using_special_drawing_prefs( special_drawing_prefs ) + if res: + return res pass pass + return "" # from _draw_atom_style + + def _draw_atom_style_using_special_drawing_prefs(self, special_drawing_prefs): + """ + [private helper for _draw_atom_style] + """ + #bruce 080605 split this out, revised it + assert special_drawing_prefs, "need special_drawing_prefs" ##### BUG: will fail in max_pixel_radius until fixed! + # note: for optimal redraw (by avoiding needless remakes of some + # display lists), only access each of the values this can provide + # when that value is actually needed to do the drawing. + + if self.isFivePrimeEndAtom(): + # (this happens even if self.isThreePrimeEndAtom() is also true + # (which may happen for a length-1 PAM3 strand); + # I guess that's either ok or good [bruce 080605 comment]) + if not special_drawing_prefs[arrowsOnFivePrimeEnds_prefs_key]: + return 'five_prime_end_atom' + elif self.isThreePrimeEndAtom(): + if not special_drawing_prefs[arrowsOnThreePrimeEnds_prefs_key]: + return 'three_prime_end_atom' + + bond = self.strand_end_bond() + # never non-None if self has two bonds with directions set + # (assuming no errors) -- i.e. for -Ss3-X, only non-None + # for the X, never for the Ss3 + # [bruce 080604 quick analysis, should re-review] + if bond is not None: + # Determine how singlets of strand open bonds should be drawn. + # draw_bond_main() takes care of drawing bonds accordingly. + # - mark 2007-10-20. + if bond.isFivePrimeOpenBond(): + if special_drawing_prefs[arrowsOnFivePrimeEnds_prefs_key]: + return 'arrowhead-in' + elif bond.isThreePrimeOpenBond(): + if special_drawing_prefs[arrowsOnThreePrimeEnds_prefs_key]: + return 'arrowhead-out' + else: + return 'do not draw' + #e REVIEW: does Bond.draw need to be updated due to this, if "draw bondpoints as stubs" is True? + #e REVIEW: Do we want to draw even an isolated Pe (with bondpoint) as a cone, in case it's in MMKit, + # since it usually looks like a cone when it's correctly used? Current code won't do that. + #e Maybe add option to draw the dir == 0 case too, to point out you ought to propogate the direction + pass return "" - def draw_atom_sphere(self, color, pos, drawrad, level, dispdef, abs_coords = False): + def draw_atom_sphere(self, + color, + pos, + drawrad, + level, + dispdef, + abs_coords = False, + special_drawing_prefs = USE_CURRENT + ): """ #doc - [dispdef can be None if not known to caller] + + @param dispdef: can be None if not known to caller + + @param special_drawing_handler: see _draw_atom_style for related doc + + @param special_drawing_prefs: see _draw_atom_style for doc + + @return: None """ #bruce 060630 split this out for sharing with draw_in_abs_coords - style = self._draw_atom_style() + style = self._draw_atom_style( special_drawing_prefs = special_drawing_prefs) if style == 'do not draw': if disable_do_not_draw_open_bonds(): ## or self._dna_updater__error: # (first cond is a debug_pref for debugging -- bruce 080122) @@ -1788,10 +1874,10 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): #Following implements custom arrowhead colors for the 3' and 5' end #(can be changed using Preferences > Dna page) Feature implemented #for Rattlesnake v1.0.1 - bool_custom_arrowhead_color = env.prefs[ + bool_custom_arrowhead_color = special_drawing_prefs[ useCustomColorForFivePrimeArrowheads_prefs_key] if bool_custom_arrowhead_color and not abs_coords: - arrowColor = env.prefs[ + arrowColor = special_drawing_prefs[ dnaStrandFivePrimeArrowheadsCustomColor_prefs_key] elif style == 'arrowhead-out': @@ -1801,10 +1887,10 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): #Following implements custom arrowhead colors for the 3' and 5' end #(can be changed using Preferences > Dna page) Feature implemented #for Rattlesnake v1.0.1 - bool_custom_arrowhead_color = env.prefs[ + bool_custom_arrowhead_color = special_drawing_prefs[ useCustomColorForThreePrimeArrowheads_prefs_key] if bool_custom_arrowhead_color and not abs_coords: - arrowColor = env.prefs[ + arrowColor = special_drawing_prefs[ dnaStrandThreePrimeArrowheadsCustomColor_prefs_key] else: assert 0 @@ -1860,30 +1946,30 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): ) elif style == 'five_prime_end_atom': sphereColor = color - bool_custom_color = env.prefs[ + bool_custom_color = special_drawing_prefs[ useCustomColorForFivePrimeArrowheads_prefs_key] if bool_custom_color and not abs_coords: - sphereColor = env.prefs[ + sphereColor = special_drawing_prefs[ dnaStrandFivePrimeArrowheadsCustomColor_prefs_key] drawsphere(sphereColor, pos, drawrad, level) elif style == 'three_prime_end_atom': sphereColor = color - bool_custom_color = env.prefs[ + bool_custom_color = special_drawing_prefs[ useCustomColorForThreePrimeArrowheads_prefs_key] if bool_custom_color and not abs_coords: - sphereColor = env.prefs[ + sphereColor = special_drawing_prefs[ dnaStrandThreePrimeArrowheadsCustomColor_prefs_key] drawsphere(sphereColor, pos, drawrad, level) else: if style: print "bug (ignored): unknown _draw_atom_style return value for %r: %r" % (self, style,) drawsphere(color, pos, drawrad, level) - return + return # from draw_atom_sphere - def draw_wirespheres(self, glpane, disp, pos, pickedrad): + def draw_wirespheres(self, glpane, disp, pos, pickedrad, special_drawing_prefs = USE_CURRENT): #bruce 060315 split this out of self.draw so I can add it to draw_in_abs_coords - if self._draw_atom_style().startswith('arrowhead-'): + if self._draw_atom_style(special_drawing_prefs = special_drawing_prefs).startswith('arrowhead-'): # compensate for the cone (drawn by draw_atom_sphere in this case) being bigger than the sphere [bruce 070409] pickedrad *= debug_pref("Pe pickedrad ratio", Choice([1.8, 1.9, 1.7, 1.0])) #### if self.picked: # (do this even if disp == diINVISIBLE or diLINES [bruce comment 050825]) @@ -2156,7 +2242,10 @@ class Atom( PAM_Atom_methods, AtomBase, InvalMixin, StateMixin, Selobj_API): drawrad = self.selatom_radius() # slightly larger than normal drawing radius drawrad *= factor #bruce 080214 new feature ## drawsphere(color, pos, drawrad, level) # always draw, regardless of display mode - self.draw_atom_sphere(color, pos, drawrad, level, None, abs_coords = True) + self.draw_atom_sphere(color, pos, drawrad, level, None, + abs_coords = True, + special_drawing_prefs = USE_CURRENT + ) #bruce 070409 bugfix (draw_atom_sphere); important if it's really a cone return diff --git a/cad/src/model/chunk.py b/cad/src/model/chunk.py index f0296f3e8..fd263905c 100755 --- a/cad/src/model/chunk.py +++ b/cad/src/model/chunk.py @@ -114,8 +114,6 @@ from graphics.drawing.ColorSorter import ColorSortedDisplayList ##from constants import PickedColor from utilities.prefs_constants import hoverHighlightingColor_prefs_key from utilities.prefs_constants import selectionColor_prefs_key -from graphics.drawing.gl_lighting import startPatternedDrawing -from graphics.drawing.gl_lighting import endPatternedDrawing from utilities.constants import gensym, genKey @@ -144,14 +142,21 @@ from commands.ChunkProperties.ChunkProp import ChunkProp from dna.model.Dna_Constants import getComplementSequence - from operations.bond_chains import grow_directional_bond_chain import graphics.drawing.drawing_globals as drawing_globals + from graphics.drawing.gl_lighting import apply_material +from graphics.drawing.gl_lighting import startPatternedDrawing +from graphics.drawing.gl_lighting import endPatternedDrawing from graphics.drawables.Selobj import Selobj_API +from graphics.drawing.special_drawing import USE_CURRENT +from graphics.drawing.special_drawing import SPECIAL_DRAWING_STRAND_END +from graphics.drawing.special_drawing import StrandEnd_ExtraChunkDisplayList +from graphics.drawing.special_drawing import Chunk_SpecialDrawingHandler + _inval_all_bonds_counter = 1 #bruce 050516 @@ -2018,13 +2023,9 @@ class Chunk(NodeWithAtomContents, InvalMixin, # of a matching glEndList) in which any subsequent glNewList is an # invalid operation. (Also done in shape.py; not needed in drawer.py.) try: - self.draw_displist(glpane, disp, (hd, delegate_draw_atoms, delegate_draw_chunk)) - ##### pass special-list-policy args? - # incl kind -> class, wantlist, self.extra_displists for where to put them - # or self to ask all that stuff (already passed of course). - # this needs to add things to self.extra_displists as needed + self._draw_for_main_display_list(glpane, disp, (hd, delegate_draw_atoms, delegate_draw_chunk), wantlist) except: - print_compact_traceback("exception in Chunk.draw_displist ignored: ") + print_compact_traceback("exception in Chunk._draw_for_main_display_list ignored: ") if wantlist: ColorSorter.finish() # grantham 20051205 @@ -2269,10 +2270,43 @@ class Chunk(NodeWithAtomContents, InvalMixin, continue return - def draw_displist(self, glpane, disp0, hd_info): + def _draw_for_main_display_list(self, glpane, disp0, hd_info, wantlist): """ [private submethod of self.draw] - """ + + Draw the contents of our main display list, which the caller + has already opened for compile and execute (or the equivalent, + if it's a ColorSortedDisplayList object) if wantlist is true, + or doesn't want to open otherwise (so we do immediate mode + drawing then). + + Also (if self attrs permit and wantlist argument is true) + capture functions for deferred drawing into new instances + of appropriate subclasses of ExtraChunkDisplayList added to + self.extra_displists, so that some aspects of our atoms and bonds + can be drawn from separate display lists, to avoid remaking our + main one whenever those need to change. + """ + if wantlist and debug_pref("use special_drawing_handlers? (not yet working)", + Choice_boolean_False, + non_debug = True, + prefs_key = True): + # set up the right kind of special_drawing_handler for self; + # this will be passed to the draw calls of our atoms and bonds + # [new feature, bruce 080605] + special_drawing_classes = { # todo: move into a class constant + SPECIAL_DRAWING_STRAND_END: StrandEnd_ExtraChunkDisplayList, + } + self.special_drawing_handler = \ + Chunk_SpecialDrawingHandler( self, special_drawing_classes ) + else: + self.special_drawing_handler = None + + del wantlist # for now; bruce 080605 ##### + # incl kind -> class, wantlist, self.extra_displists for where to put them + # or self to ask all that stuff (already passed of course). + # this needs to add things to self.extra_displists as needed + #bruce 050513 optimizing this somewhat; 060608 revising it if debug_pref("GLPane: report remaking of chunk display lists?", Choice_boolean_False, @@ -2466,7 +2500,7 @@ class Chunk(NodeWithAtomContents, InvalMixin, That might change, e.g. if we made chunks able to show their axes, name, bbox, etc. """ - #bruce 060608 split this out of draw_displist + #bruce 060608 split this out of _draw_for_main_display_list return def drawing_color(self): #bruce 080210 split this out, used in Atom.drawing_color @@ -2497,7 +2531,7 @@ class Chunk(NodeWithAtomContents, InvalMixin, """ return color - def standard_draw_atoms(self, glpane, disp0): #bruce 060608 split this out of draw_displist + def standard_draw_atoms(self, glpane, disp0): #bruce 060608 split this out of _draw_for_main_display_list """ [private submethod of self.draw:] @@ -2555,7 +2589,10 @@ class Chunk(NodeWithAtomContents, InvalMixin, # end bruce hack 041014, except for use of color rather than # self.color in atom.draw (but not in bond.draw -- good??) - atomdisp = atom.draw(glpane, disp, color, drawLevel) + atomdisp = atom.draw( + glpane, disp, color, drawLevel, + special_drawing_handler = self.special_drawing_handler + ) #bruce 050513 optim: if self and atom display modes don't need to draw bonds, # we can skip drawing bonds here without checking whether their other atoms @@ -2598,7 +2635,7 @@ class Chunk(NodeWithAtomContents, InvalMixin, pass else: print "Source of current atom:", atom_source - return # from standard_draw_atoms (submethod of draw_displist) + return # from standard_draw_atoms (submethod of _draw_for_main_display_list) def overdraw_hotspot(self, glpane, disp): # bruce 050131 (atom_debug only); [unknown later date] now always active """ |