summaryrefslogtreecommitdiff
path: root/cad/src/graphics/drawables/Selobj.py
blob: 17a007475b4ae558917394cb3b94b60fd1271e3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# Copyright 2006-2009 Nanorex, Inc.  See LICENSE file for details.
"""
Selobj.py -- provides class Selobj_API, [### WHICH WILL BE RENAMED, ALONG WITH THIS FILE]
which documents the interface from the GLPane to drawable objects which need
to detect whether the mouse touches them, i.e. mainly for
"hover-highlightable" objects, and from other code to whatever such
objects are stored in glpane.selobj (since they are actually under the
mouse).

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

Current status [bruce 080116]:

This partly formalizes an informal API used by GLPane and some
Commands and GraphicsModes to handle hover-highlightable
drawable objects, which has optional methods for some optional
abilities they can have, like a different highlight appearance,
an ability to provide a context menu, or an ability to
provide a DragHandler.

There is unfortunately not yet a single consistent API
for "drawables" in NE1. For example, many classes have
draw or Draw methods, but these can have two or three
different arg signatures in different class hierarchies.

The Selobj_API is not a general "drawable API" but covers
most ways in which a drawable object might interact
with the mouse. As currently constructed it's unideal in
several ways, e.g. its methods have no consistent naming
convention, and the semantics for "using the default behavior"
is often "don't provide the method", which means we can't
provide a default or stub implementation in class Selobj_API
itself (effectively an "interface class") or we'd break code.

And, in reality it's probably at least two APIs mushed
together. And certainly it's unclearly named.

The confusion apparent in the docstring and comments of
Selobj.py (class Selobj_API) reflects all this.

This can and should all be cleaned up, but we're unlikely
to do much of that before FNANO '08. In the meantime, making
the classes that provide the existing "selobj interface"
say they do so is at least a start, since the set of things
to look at to understand all this is more clearly defined.

To clarify: this commit [080116] does not change any behavior or rename
any methods. It only adds an empty superclass to all existing
classes which use methods from the preexisting informal
"selobj interface", thereby partially formalizing the interface.
(It formalizes which classes provide it, though with no detection of
errors in this, but it does not formalize what methods are part
of it -- the comments in Selobj.py are the most we have in that
direction.)

===

### REVIEW: is that really two different interfaces? The GLPane,
finding the selobj via glname, could ask it to return the value
to actually store in glpane.selobj.
First interface is " an object (drawable) which notices the mouse over it",
second is "an object which handles events for the object
under the mouse"... they might not be in 1-1 correspondence
when we have good support for nested glnames!

sort of like a mouse-sensitive drawable vs a mouse-handling model object...
or a mouse event handler for a model object... or for a drawable (or a
nested chain of them, depending on glname nesting for e.g. stereo, or
repeated identical parts)

Note: a drag-handler (see DragHandler.py) and a "selobj" are often the same
object, but obeying a different API; drag_handlers are return values from
a Selobj_API-interface method (which often returns self).

Implementation note: in the current code, all such objects ask
the GLPane (actually the global env module, but ideally a GL Context
representative) to allocate them a "glname" for use during GL_SELECT drawing,
but this implementation may change or be augmented, both for efficiency and to
work for transparent objects.

Note: most objects which implement this interface don't currently [070913]
inherit class Selobj_API. Since the methods in it needn't be overridden,
most client code tests for their presence, and in some cases runs non-noop
default code if they are not found. This should be revised so that all
implementors inherit this class, and so that the default code is moved
to default methods in this class.

WARNING: Until that revision is done, adding this superclass to existing
objects would break code in the GLPane or in modes, which relies on testing
for the lack of presence of certain methods in this API to decide when
to run its own default code instead of calling those methods. Or at least
it would if this class had any methods defined in it ... maybe we should leave
the methods out, add the superclass, then move the methods and their
client-supplied default code into this class gradually.

The init code which allocates a glname should also be moved into an init
method in this class.

Current classes which should inherit this interface include Atom, Bond, Jig,
and Highlightable, and others which have comments about "selobj interface",
e.g. in Plane and DirectionArrow modules.

All comments about either "selobj interface" or "Drawable API" may relate to
this and should be revised. See also scratch/Drawable.py.

Some documentation about this interface exists in exprs/Highlightable.py and
GLPane.py.

Module classification:

Seems most like graphics_behavior_api, but revisit when it's done.
[bruce 071215]
"""

# possible names for this class:
# - class MouseSensor_interface (in file MouseSensor.py? or MouseSensor_interface.py?)
# - class MouseSensitive -- maybe that grammar (adjective) means _interface can be
#   implied? not sure.
# And should the methods start with a prefix like MouseSensor_ ?

class Selobj_API:
    """
    ###doc
    WARNING: API details (method names, arglists) are subject to change.
    """
    ### see list of methods below -- but don't add any method stubs here
    # for now, or some code will break (as explained in module docstring).

    # some *new* api methods and attrs can safely be added here:

    _selobj_colorsorter_safe = False #bruce 090311

    def nodes_containing_selobj(self): #bruce 080507
        """
        Return a list (not a tuple) of all nodes that contain self,
        in innermost-to-outermost order if convenient. If self bridges
        multiple leaf nodes (e.g. if self is an external bond), include
        all those leaf nodes (and all their containing nodes) in the result,
        but in that case, the order of nodes within the result is undefined,
        and whether the result might contain some nodes twice is undefined.
        """
        return []

    pass

# comment moved from exprs/Highlightable.py, edited here :

# == selobj interface

###e should define a class for the selobj interface; see classes Highlightable and
# _UNKNOWN_SELOBJ_class for an example --

# methods desired by glpane for analyzing hits, responding to them

# - object.glname (?)
#    [note, not really a public attribute; e.g. class Atom made it private
#     and introduced get_glname method on 080220]
# - and the env table for glname to object -- in future that goes to first kind of obj,
#  it returns 2nd kind [note: being moved from env to assy as of bruce 080220]
#   (and does glpane need to remember more than just one selobj it returns??)

# and by mode for passing on events:

# - leftClick
# - make_selobj_cmenu_items

# by glpane for drawing selobj -- not sure how to classify these -- but only done on one
#  object so i think it's on the 2nd interface

# - selobj_still_ok, [glpane asks mode(?), default implem asks selobj]
# - draw_in_abs_coords,
# - highlight_color_for_modkeys
# - mouseover_statusbar_message (used in GLPane.set_selobj)

# other things looked at on a selobj:
# - getInformationString (maybe not on all objects??)
# - killed
# - glname (might be a kluge)
# - part (only on some kinds?)

# see also: _UNKNOWN_SELOBJ_class


# new, 070919 - here are the distinct interfaces...
"""
gl select hit detector - for an object with a glname, which draws inside it - must draw in
a special way

related opengl names: glSelectBuffer, glselect/glname in our own related internal names,
glRenderMode(GL_SELECT)

class GL_SELECT_HitDetector_Mixin

(other kinds of hit detectors - they'd need geometric info in api, but would not need to
draw at all, let alone specially -- except insofar as to record unambiguously when they
did get drawn, ie whether they are really in the scene, and if so under what coordsys that
was (when in display lists). maybe "draw" means "add self to that frame scene tree"?? or
maybe we imitate glselect and repeat the draw in a special way? as my partly done expr
draw reform was trying to do, for its own hit detection to work inside display lists...)

==

ObjectUnderMouse_interface - for anything which can be returned as the object under the
mouse, then queried about what to do, or even about how to draw itself specially (over its
ordinary representation, which may have to be drawn too, being in a display list).

glpane.selobj rename to glpane.objectUnderMouse (someday)

selobj - an object assignable to glpane.selobj - should provide actions in ui for mouse
events over it - highlightable, draggable, ... mouse sensitive - handler of mouse events -
can ask for this obj under mouse -

==

Q: is being overdrawn specially, a different interface than being objectUnderMouse?
evidence: objUnderMouse might say "here are the objects to overdraw specially" and they
might be more than just it. It would call all their drawing code with special flags (look
highlighted in certain way) and in abs coords... latter might be fixed if we reimplemented
how this works as a separate drawing pass, someday.

but note that in current code this object also gets first dibs at providing the next
detected hit using stencil buffer... hmm... what does stencil buffer say about how all
these interfaces have to be related?

###
Can I factor out the related code from the GLPane, while I'm doing this? And fix some bugs
and add required new APIs at same time (fix bugs in highlightable vs displists, add api
for region sel, and for multiple highlighted objects for single obj under mouse)

==

region selection interface - a node which contains region-selectable things and control
points for them
"""


### REVIEW: should check_target_depth_fudge_factor
# be an attribute of each object which can be drawn as selobj, instead of an attr of the mode?
# (as of 070921 it's an optional mode attr, default value supplied by its client, GLPane.)


# outtake??
        ####@@@@ TODO -- rename draw_in_abs_coords and make it imply highlighting so obj knows whether to get bigger
        # (note: having it always draw selatoms bigger, as if highlighted, as it does now, would probably be ok in hit-test,
        #  since false positives in hit test are ok, but this is not used in hit test; and it's probably wrong in depth-test
        #  of glselect_dict objs (where it *is* used), resulting in "premonition of bigger size" when hit test passed... ###bug);
        # make provisions elsewhere for objs "stuck as selobj" even if tests to retain that from stencil are not done
        # (and as optim, turn off stencil drawing then if you think it probably won't be needed after last draw you'll do)



# end