summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Smith <bruce@nanorex.com>2008-06-05 23:08:05 +0000
committerBruce Smith <bruce@nanorex.com>2008-06-05 23:08:05 +0000
commita0a64d45f1762e76c7cf89a682b904a9289167a9 (patch)
treedb83702082ad5d415ec7dbdf35863488c37a37bd
parent18404ad7afa1f5473128ffdf9006e007b2d5d830 (diff)
downloadnanoengineer-theirix-a0a64d45f1762e76c7cf89a682b904a9289167a9.tar.gz
nanoengineer-theirix-a0a64d45f1762e76c7cf89a682b904a9289167a9.zip
partial implem of extra display lists in chunks, has bugs
-rwxr-xr-xcad/src/foundation/env.py2
-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.py4
-rwxr-xr-xcad/src/model/chem.py179
-rwxr-xr-xcad/src/model/chunk.py67
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
"""