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
|
# Copyright 2007 Nanorex, Inc. See LICENSE file for details.
"""
pallettes.py
$Id$
"""
from exprs.Highlightable import Highlightable
from exprs.world import World
from exprs.Boxed import Boxed
from exprs.draggable import DraggableObject
from utilities.constants import blue, green
from exprs.Exprs import or_Expr, format_Expr
from exprs.instance_helpers import DelegatingInstanceOrExpr
from exprs.attr_decl_macros import ArgExpr, Option, State
from exprs.ExprsConstants import PIXELS, ORIGIN
from exprs.__Symbols__ import Anything, _self
class PalletteWell(DelegatingInstanceOrExpr):
"""A place in the UI which can make copies of its expr for dragging to whereever you want [not fully working yet]
"""
# experimental, really a stub, 070212 -- but sort of works! (as tested in dna_ribbon_view.py)
expr = ArgExpr(Anything) #e not really Anything, but some interface ##e should really be StateArg
world = Option(World) ###e find in env, instead?? maybe not, since in typical cases we might rather make in some parent in
# the model anyway, which depends on which kind of obj we are and which pallette we're in...
# maybe we even need a make-function to be passed in.
# If it was an arg, it'd be natural as arg1 (since this is like a method on the world);
# but since it might become a dynamic env var, I'll use an option for now.
# If it was a dynamic var by default but could be some container obj, an option would be good for that too (renamed #e).
type = Option(str, doc = "type of thing to tell world we're making [type, api subject to change]")
###BUG: passing type to world.make_and_add is nim
what_to_make_nickname = or_Expr(type, "something") #e classname of expr, after burrowing? some other namelike attr of expr?
# (note, hard to have that, unless expr is a new special Instance type of "makable" rather than a bare expr --
# and it probably ought to be. ##e)
sbar_text = Option(str, format_Expr("make %s", what_to_make_nickname) )
_what_to_make = DraggableObject(_self.expr)
##e rename DraggableObject -> Draggable? I misrecalled it as that... and "object" is arguably redundant.
_newobj = State(Anything, None) # set internally to an object we create during _self.on_press
delegate = Highlightable(
Boxed(expr, borderthickness = 2 * PIXELS), # plain
###BUG: Boxed fails with exprs that don't have bleft, with a very hard to decipher exception
Boxed(expr, borderthickness = 2 * PIXELS, bordercolor = blue), # highlight
Boxed(expr, borderthickness = 2 * PIXELS, bordercolor = green), # [pressed] green signifies "going" (mainly, green != blue)
on_press = _self.on_press,
on_drag = _newobj.on_drag,
on_release = _newobj.on_release,
sbar_text = sbar_text ###e UI DESIGN: need to also pass sbar text (or a func to get it from selobj) for use during the drag
)
def on_press(self):
# make a new object
self._newobj = self.world.make_and_add( self._what_to_make)
##e also pass the type option, taken from a new _self option?
###e UI DESIGN FLAW: we should probably not actually make the object until the drag starts...
# better, make something now, but only a fake, cursor-like object (not placed in the model or its tree)
# (maybe a thumbnail image made from expr? maybe use PixelGrabber on self, to get it?? #e)
# and only make a real model object when the drag *ends* (in a suitable mouse position -- otherwise cancel the make).
if 'kluge 070328, revised 070401': ###e see also comments in class World, 070401
self._newobj.copy_saved_coordsys_from( self.world._coordsys_holder )
# start a drag of the new object; first figure out where, in world coordinates, and in the depth plane
# in which you want the new object to appear (and move the object there -- without that it'll be at the origin)
point_in_newobj_coords = self._newobj.current_event_mousepoint(plane = ORIGIN)
### LOGIC BUG: this seems to work, but it presumbly has this bug: in current implem, self._newobj's local coordsys
# can't be available yet, since it's never been drawn! So it presumably gives out a debug message I've been seeing
# ("saved modelview_matrix is None, not using it")
# and uses global modelview coords, which happen to be the same in the current test (in dna_ribbon_view.py).
###KLUGE: use ORIGIN (which we know) in place of center of view (which we don't) -- only correct when no trackballing
self._newobj.motion = point_in_newobj_coords
###KLUGE since it centers new obj on mouse, even if mousedown was not centered on sample obj
###BUG (confirmed): I bet the point would be wrong in perspective view, unless we first corrected the depth plane,
# then reasked for point.
# trying that 070217 -- But how to fix? To correct the plane, we need to flush the DraggableObject in self._newobj, at least,
# before current_event_mousepoint is likely to use correct coords (actually I'm not sure -- ###TEST)
# but we can't since not all objects define .move (need to ###FIX sometime).
## self._newobj.flush()
# so try this even though it might not work:
## point_in_newobj_coords_2 = self._newobj.current_event_mousepoint(plane = ORIGIN)
### but now, what do we do with this point???
# print "debug note: compare these points:",point_in_newobj_coords, point_in_newobj_coords_2 # result: identical coords.
# so it doesn't work and doesn't even make sense yet... i probably can't proceed until the logic bug above is fixed.
# There's also the issue of different object size on-screen if it's shown at a different depth.
# (Unless that could help us somehow, in showing the depth? doubtful.)
### UI DESIGN FLAWS: the new obj is obscured, and there is no visual indication you "grabbed it", tho you did.
# (actually there is one, if you wait long enough and didn't happen to grab it right on the center! but it's subtle --
# and worse, it's arguably due to a bug.)
##e would box border color change help? or box "dissolve"?? (ie temporarily remove the box)
# or we might need to hide the pallette well (or make it translucent or not depth-writing)
###e need sbar messages, some message that you grabbed it (which would mitigate the visual flaw above)
self._newobj.on_press() # needed so its on_drag and on_release behave properly when we delegate to them above
return
pass # end of class PalletteWell
# end
|