class _color_toggler(DelegatingInstanceOrExpr):
    ###WRONGnesses:
    # - Q: shouldn't we be toggling a flag or enum or int, and separately mapping that to a color to show?
    #   A: Yes, unless we're for general raw color images -- but as a StateArray test this doesn't matter.
    # args
    color_ref = Arg(StateRef, doc="stateref to a color variable"
                    )  ###e can we tell StateRef what the value type should be?
    # appearance/behavior
    delegate = Boxed(
        Highlightable(
            Rect(1, 1, color_ref.value),
            on_press=Set(color_ref.value,
                         call_Expr(_self.toggle_color, color_ref.value)),
            sbar_text=
            "click to change color"  #e give index in StateArray, let that be an arg? (if so, is it a fancy stateref option?)
        ),
        pixelgap=
        0,  #e rename -- but to what? bordergap? just gap? (change all gap options to being in pixels?)
        borderwidth=
        1,  ###BUG: some of these border edges are 2 pixels, depending on pixel alignment with actual screen
        bordercolor=black)

    def toggle_color(self, color):
        r, g, b = color
        return (
            b, r, g
        )  # this permits toggling through the cyclic color sequence red, green, blue in that order
        #e or we could rotate that color-cube on the same diagonal axis but less than 1/3 turn,
        # to get more colors, if we didn't mind renormalizing them etc...

    pass
예제 #2
0
class checkbox_pref(InstanceMacro):
    #e rename -- Checkbox(...), with various kinds of args to say what state it uses in different ways?
    #e make it one of several prefs controls for other types of pref and control
    #e generalize to all named state -- e.g. see also LocalVariable_StateRef -- permit passing in the stateref?
    #e get dflt label from stateref??
    # note: this was split out of kluge_dragtool_state_checkbox_expr 061214,
    # extended here into a def (later renamed checkbox_pref_OLDER), then a class
    prefs_key = Arg(str)
    label = Arg(Anything)  # string or Widget2D
    dflt = ArgOrOption(bool, False)
    sbar_text = Option(str, '')
    use_label = If(call_Expr(lambda label: type(label) == type(""), label),
                   TextRect(label), label)  ## was TextRect(label,1,20)
    use_sbar_text = or_Expr(
        sbar_text,
        If(call_Expr(lambda label: type(label) == type(""), label), label, ""))
    stateref = Instance(PrefsKey_StateRef(prefs_key, dflt))
    # note: without Instance here, next line stateref.value says (correctly):
    ## AssertionError: compute method asked for on non-Instance <PrefsKey_StateRef#47221(a)>
    var = stateref.value
    checkbox = If(
        var,
        checkbox_image('mac_checkbox_on.png'),
        checkbox_image('mac_checkbox_off.png'),
    )
    _value = DisplayListChunk(
        Highlightable(
            SimpleRow(CenterY(checkbox),
                      CenterY(use_label)),  # align = CenterY is nim
            ## on_press = Set(debug_evals_of_Expr(stateref.value), not_Expr(var) ), #070119 debug_evals_of_Expr - worked
            on_press=_self.on_press,
            # the following works too, but I wanted to intercept it to add some py code [070305]:
            ## Set( stateref.value, not_Expr(var) ),
            sbar_text=use_sbar_text))
    # note: using DisplayListChunk in _value works & is faster [070103]
    #070124 comment: the order DisplayListChunk( Highlightable( )) presumably means that the selobj
    # (which draws the highlightable's delegate) doesn't include the displist; doesn't matter much;
    # that CenterY(use_label) inside might be ok, or might be a bug which is made up for by the +0.5 I'm adding to drawfont2
    # in testdraw.py today -- not sure.
    incr_drawable = Instance(
        Boxed(CenterY(checkbox), pixelgap=0, bordercolor=gray, borderwidth=2))

    # I tried orange as a warning color -- means the checkbox reflects an intention but not yet the reality.
    # But it was annoyingly too visible. So I'll try gray.
    # If all colorboxeds are unpopular, then try an image that has a little spray of lines coming from the center, instead.
    def on_press(self):
        self.stateref.value = not self.stateref.value  # was, in the expr: Set( stateref.value, not_Expr(var) )

        ###e revise this code to use self.draw_incrementally once that's refiled into Highlightable ###e
        def func(self=self):
            self.incr_drawable.draw()
            ## self.draw() # includes the label - probably a waste but who cares
            self.env.glpane.swapBuffers()  # update display [needed]

        ran_already_flag, funcres = self.run_OpenGL_in_local_coords(
            func)  # this method runs in the Highlightable made in _value
        assert ran_already_flag
        return

    pass  # end of class checkbox_pref
예제 #3
0
class MainCommandToolButton(DelegatingInstanceOrExpr): #e rename?
    "Toolbutton for one of the main tools like Features, Build, Sketch -- class hierarchy subject to revision"
    # args
    toolbar = Arg(Toolbar) # our parent - #e rename parent_toolbar? to distinguish from our flyout_toolbar.
    toolname = Arg(str) #e.g. "Build"
    command = Arg(Command, doc = "the command invoked by pressing this toolbutton (might be transient or long lasting)") ###k type ok? 
    subtools = Arg(list_Expr) # list of subtools (for cmenu or flyout), with None as a separator -- or as an ignored missing elt??
        # like menu_spec items?
        # Q: can they contain their own conditions, or just let the list be made using Ifs or filters?
        # A: subtools can contain their own conditions, for being shown, enabled, etc. they are ui elements, not just operations.
    #e also one for its toolbar, esp if it's a mutually exclusive pressed choice -- and ways to cause related cmd/propmgr to be entered
    # state
    pressed = State(bool, False, doc = "whether this button should appear pressed right now")
    # formulae
    plain_bordercolor =       If(pressed, gray, white)
    highlighted_bordercolor = If(pressed, gray, blue)
    pressed_in_bordercolor =  If(pressed, gray, green) # green = going to do something on_release_in
    pressed_out_bordercolor = If(pressed, gray, white) # white = not going to do anything on_release_out
    # appearance
    delegate = Highlightable(
        plain =       Boxed(TextRect(toolname), bordercolor = plain_bordercolor),
        highlighted = Boxed(TextRect(toolname), bordercolor = highlighted_bordercolor), #e submenu is nim
        pressed_in  = Boxed(TextRect(toolname), bordercolor = pressed_in_bordercolor),
        pressed_out = Boxed(TextRect(toolname), bordercolor = pressed_out_bordercolor),
        sbar_text = format_Expr( "%s (click for flyout [nim]; submenu is nim)", toolname ),
        on_release_in = _self.on_release_in,
        cmenu_obj = _self ###IMPLEM cmenu_obj option alias or renaming; or call it cmenu_maker??
    )
    # repr? with self.toolname. Need to recall how best to fit in -- repr_info? ##e
    # actions
    def on_release_in(self):
        if not self.pressed:
            print "on_release_in %s" % self.toolname
            self.pressed = True #e for now -- later we might let main toolbar decide if this is ok
            #e incremental redraw to look pressed right away? or let toolbar decide?
            self.toolbar._advise_got_pressed(self)
        else:
            #### WRONG but not yet another way to unpress:
            self.pressed = False
            print "unpressed -- not normal in real life!"###
        return #e stub
    def cmenu_spec(self, highlightable): ###IMPLEM this simpler cmenu API (if it still seems good)
        return map( self.menuitem_for_subtool, self.subtools ) ###e how can that func tell us to leave out one, or incl a sequence?
    def menuitem_for_subtool(self, subtool):
        # stub, assume not None etc
        return ( subtool.name, subtool.cmd_invoke )
    pass
예제 #4
0
class ChoiceButton(InstanceMacro):
    """ChoiceButton(choiceval, choiceref, content, background, background_off) [most args optional]
    displays and permits control of a choice variable stored externally in choiceref,
    looking like Overlay(background, content) or Overlay(background_off, content)
    when its own choice value is chosen or unchosen (ie equal or unequal to the stored one), respectively.
       Most args are optional with useful defaults, or can be given as simpler convenience types (eg colors or text);
    all args but choiceval can be given as named options, which is useful for customization.
       (Example: it's useful to put several of these with the same choiceref but different choicevals into a Column.
    This can be done by mapping one customized variant over a list of choicevals.)
       The choosing-action occurs on_press of entire thing -- this is not yet changeable
    (to other kinds of button actions), but should be. #e
    """
    # args
    choiceval = Arg(Anything)
        #e declare it as having to be constant per-Instance? Or can it legally vary?? I guess it could;
        # and I guess it's no error, just weird, for two of these (eg in a column) to share the same choiceval;
        # in fact, if they're physically separated it's not even weird.

    sbar_text = Option(str, format_Expr("%s", _self.choiceval)) # mouseover text for statusbar

    choiceref = ArgOrOption(StateRef) ###k need value-type??

    content = ArgOrOption(stubtype, TextRect(format_Expr("%s", _self.choiceval)) ) # Widget2D or something "displayable" in one (eg text or color); defaults to displayed choiceval;
        # can caller pass a formula in terms of the other options to _self?
        # Maybe, but not by saying _self! _this(ChoiceButton) == _my? [yes -- _my is now implemented, 061205]

    background = ArgOrOption(stubtype, Rect(_self.width, _self.height, lightblue) ) # Widget2D, or color (used in Rect a bit larger than content)
    
    background_off = ArgOrOption(stubtype, Spacer(_self.width, _self.height)) # ditto, defaults to transparent
        ##k problem: what we want is to compute an lbox and then use this here in the spacer... or align the content... or ....
        ##e note that a lot of people find it more convenient to pass around a size, or even pass around a rect,
        # than to always work with 4 or 6 rect-related attrs...

    # formulae
    chosen = eq_Expr( choiceref.value, choiceval) #k
    ## print "chosen is",chosen

    ###k assume useful conversions of named options happened already
    ###e use _value; is it as simple as renaming it delegate and using DelegatingMixin?? Can InstanceMacro do it for us??
    # [if we use one of those, be careful not to inherit from Widget2D here, due to its lbox defaults!]
    _value = Highlightable( Overlay( SpacerFor(Boxed(content)),
                                         # kluge to make room around content in _self.width and _self.height,
                                         # and make those non-circular; WRONG because won't be properly aligned with backgrounds,
                                         # even if content itself would be;
                                         # could fix by shifting, but better to figure out how to have better rectlike size options ###e
                                     Overlay( ###KLUGE since "Overlay is a stub which only works with exactly two args"
                                         If(chosen, background, background_off),
                                         content ),
                                     ),
                            ## old code: on_press = SetStateRefValue(choiceref, choiceval),
                            # try this code 061211 1113a -- it works, use it:
                            on_press = Set(choiceref.value, choiceval),
                                ##e probably best to say Set(choiceref.value, choiceval), but I think that's nim -- not sure --
                                # should retest it after Set is revised later today to work with arg1 being lval eg getattr_Expr [061204]
                            sbar_text = sbar_text
                           )
    pass # end of class ChoiceButton
예제 #5
0
class PixelTester(
        InstanceOrExpr, DelegatingMixin
):  # ought to be InstanceMacro but trying this alternate style just to see it
    # args
    testexpr = Arg(Widget2D)  # instantiated right here, hope that's ok
    testname = Arg(str)  # required for now, used to form filename
    # value
    filename = format_Expr("/tmp/%s.jpg", testname)
    delegate = SimpleColumn(
        TextRect(
            "saved image from PRIOR session, in blue box"
        ),  # kluge: execute this first, so we read file before writing it
        Boxed(bordercolor=blue)(Image(filename)),
        Spacer(0.3),
        TextRect("live widget, in purple box"),
        Boxed(bordercolor=purple)(PixelGrabber(testexpr, filename)),

        ##e and put current session image here, for comparison, or put top on in a tab control for flicker test
    )
    pass  # end of class PixelTester
예제 #6
0
class PM_from_groups(
        DelegatingInstanceOrExpr
):  ###e refile into demo_ui or so, and call it on [make_polyline3d_PG(somearg)]
    "Make a Property Manager UI from a list of groupbox content widgets (eg columns of field editors) and other info."
    # args
    groups = Arg(list_Expr)
    #e in future these groups need to come with more attrs, like group titles
    # (WAIT, they already do have a title attr which we don't use here!),
    # whether they're closable and if so whether initially closed...
    # and they might include their own Boxed already...
    # the type decl might say we want a list of PropertyGroupBoxes,
    # with autoconversion of ParameterGroups to those...
    message = Option(
        str, "(PM message goes here)"
    )  # this has to be already split into lines, for now; all indentation is stripped

    # formulae
    def _C_use_message(self):
        lines = self.message.split('\n')
        lines = [line.strip() for line in lines]
        lines = filter(None, lines)
        return '\n'.join(lines)

    use_message = _self.use_message
    # appearance
    message_box = Boxed(TextRect(use_message), gap=0, bordercolor=yellow)
    group_box_column = MapListToExpr(
        KLUGE_for_passing_expr_classes_as_functions_to_ArgExpr(
            Boxed),  ###e change to a GroupBox, with a title from the group...
        groups,
        KLUGE_for_passing_expr_classes_as_functions_to_ArgExpr(SimpleColumn))
    delegate = SimpleColumn(
        Left(message_box),
        Left(group_box_column),
    )
    pass
예제 #7
0
class ActionButton(DelegatingInstanceOrExpr):  # 070104 quick prototype
    "ActionButton(command, text) is something the user can press to run command, which looks like a button."
    # args/options
    command = Arg(Action)  #e default which prints?
    text = Arg(str, "<do it>"
               )  #e default text should be extracted from the command somehow
    button = Arg(
        Widget2D, Rect(15. * PIXELS)
    )  # can it be left out so only text label is used? ideally we'd have text with special border...
    enabled = Option(
        bool, True
    )  # whether the button should look enabled, and whether the command will run when the button is operated
    # formulae
    use_label = TextRect(text)  ## TextRect(text,1,20)###e revise
    plain_button = CenterY(button)
    highlighted_button = Boxed(
        plain_button,  # note: despite the name, this is only shown as the highlighted form when enabled is true
        bordercolor=
        blue,  # should color adapt to bg? is it a bad idea to put this over bg rather than over button?
        borderthickness=1.5 * PIXELS,
        gap=1 * PIXELS,
    )  ###k ????   -- note, this doesn't include the label -- ok?
    plain = DisplayListChunk(SimpleRow(
        plain_button, CenterY(use_label)))  # align = CenterY is nim
    highlighted = DisplayListChunk(
        SimpleRow(highlighted_button, CenterY(use_label), pixelgap=0.5))
    #k ok to wrap with DisplayListChunk? [seems so]
    ### KLUGE: without the pixelgap adjustment (to this particular weird-looking value, i guess),
    # the label moves to the right when highlighted, due to the Boxed being used to position it in the row.
    ### BUG: CenterY is not perfectly working. Guess -- lbox for TextRect is slightly wrong.
    ### IDEA: make the borderthickness for Boxed negative so the border is over the edge of the plain button. Might look better.
    ##e Note: we have no "pressed" appearance, since by the next time we get drawn, the command is already drawn and we ought to be
    # back to normal. Someday we should do a transient incremental redraw of just this button, with a "pressed and acting" appearance,
    # which can then go back to normal when the operation completes and does a regular full redraw.
    # Alternatively, we could switch to using buttons with an on_release_in action only,
    # and then have ordinarily-drawn pressed etc looks. [070227 comment]
    # update 070305: let's try to fix that:

    # appearances for optional willdoit-flicker (confirms unambiguously that the button was hit and will do something) [070307]
    # [ideally the computation & side effects could overlap the willdoit flicker in time,
    #  but they don't now, which is one reason the flicker is optional]
    incr_drawable_willdo1 = Instance(
        SimpleRow(highlighted_button(bordercolor=yellow),
                  pixelgap=0.5))  # label not needed here
    incr_drawable_willdo2 = Instance(
        SimpleRow(highlighted_button(bordercolor=blue), pixelgap=0.5))
    # note: yellow/blue (matching the usual ending & starting colors which bracket the flicker) looks much better than black/white

    # what it looks like while we're computing/doing its effects:
    incr_drawable_doing = Instance(
        SimpleRow(
            highlighted_button(bordercolor=orange),
            ## CenterY(use_label), [removed -- see comment for why -- might be added back]
            pixelgap=0.5))
    # orange warns you that it's not yet done, is also bright & active for action;
    ### UI FLAW: the orange/yellow distinction is annoying, so it's really only desirable for debugging,
    # since it shows that the instantiation time is significant but only happens on the first use of a button.
    # Probably the distinction (and its redraw happening at all) should be a debug_pref or so. ###FIX
    # (But if there is no distinction, we may want to be sure to redraw the label now if there is any chance it can be different --
    #  but in current code there's not, since we haven't changed state it might depend on by the time we draw it.
    #  BTW I wonder if redrawing the label (i.e. instantiating this instance of it) ever takes significant time itself?? #k)

    # what it looks like while we're redrawing (after finishing its internal effects):
    incr_drawable_done = Instance(
        SimpleRow(highlighted_button(bordercolor=yellow),
                  pixelgap=0.5))  # label not needed here

    # yellow means done -- not sure makes sense -- note green means "can do" in some controls

    def doit(self):
        """This runs when the user clicks on the button.
        WARNING: it's NOT just self.do_action() (the public method self's clients, like scripts, can call to do the same action) --
        it calls that, but it also has graphical effects.
        [It may or may not be public (in the Action interface) in the end. If it is, it'll be renamed. #e]
        """
        if self.enabled:
            # do some incremental drawing [new feature 070305, revised 070307]
            ###BUG (in some client code of this class):
            # this won't be able to make clear button quickly show it's disabled until client code is revised and maybe selobj-bugfixed ###DOIT
            if debug_pref(
                    "testmode: ActionButton willdoit-flicker?",
                    # When set, this flickers the button, like how the mac confirms a menu item choice.
                    # Conclusion after testing: it works fine, and usually looks ok,
                    # but is redundant with "yellow during redraw",
                    # so as long as that's slow enough to see, this has no point and is also making it even slower,
                    # so leave it turned off by default.
                    Choice_boolean_False,
                    prefs_key='A9 devel/exprs/action flicker'):
                # works [retest###], but I won't make it True by default [070307]
                ##e someday do this in a way that does not tie up the thread during this, e.g. by letting paintGL do it;
                # for now it's just experimental for its graphics effects and as a speed test,
                # and will probably be turned off after testing
                for i in range(4):
                    if i % 2 == 0:
                        self.draw_incrementally(self.incr_drawable_willdo1)
                    else:
                        self.draw_incrementally(self.incr_drawable_willdo2)
                    # print i, # very fast
                    # todo: delay, if needed to make this visible -- using time.time to delay only if draw timing was not long enough
                    # (with no delay it's almost too fast too see -- sometime I should write the code to measure the actual speed)
                    # (for now assume it's always very fast, so just delay a fixed amount using time.sleep)
                    time.sleep(1.0 / 3 / 4)  # 1/3 sec, spread over 4 sleeps
            self.draw_incrementally(
                self.incr_drawable_doing
            )  # this method runs in the Highlightable made in delegate
            print "ActionButton: doing %r for %r" % (self.text, self
                                                     )  ### remove self?
            ##e optim note: this shows self is a different obj each time (at least for make dna cyl button)...
            # I guess this is due to dna_ribbon_view_toolcorner_expr_maker being a function that makes an expr
            # which runs again at least on every use of the button (maybe more -- not sure exactly how often).
            # Should fix that (and it's not this file's fault -- just that the print stmt above reveals the problem).
            self.do_action()
            self.draw_incrementally(self.incr_drawable_done)
            pass
        else:
            print "ActionButton: not enabled, so not doing %r for %r" % (
                self.text, self)  # remove when works [reenabled 070307 ####]
            pass
        return

    def do_action(self):
        "#doc -- public, also used internally; see doit comment for doc, for now"
        res = self.command()
        if res is not None:
            print "unexpected: %r cmd %r retval was not None: %r" % (
                self,
                self.text,
                res,
            )  #e remove if happens legitimately
        return

    ###e refile these:
    def draw_incrementally(
            self, thing):  #070307 #e refile (as for next method below)
        "#doc"
        self._incrementally_draw_OpenGL(
            thing.draw
        )  #e or call a variant method of thing, which defaults to thing.draw?? nah, use an env var?

    def _incrementally_draw_OpenGL(
        self, func
    ):  #070307 #e rename ###e refile into IorE someday, and into Highlightable for now, i think
        """helper method for incremental drawing by user event handling methods (not part of self.draw called by paintGL).
        [#doc better]
        func should contain OpenGL commands for incrementally drawing, in self's coords (but not the swapbuffers at the end).
           Guess at a requirement within func: [which should be removed and is prob not real now, see below]
        # don't use drawkid! (because we're not inside a draw method)
        # (but will this cause trouble for draw methods inside this?? ### NEEDS REVIEW)
        [but instead we might as well make sure that drawkid's parent-seeing alg will not be messed up, since it'll be used
        inside whatever subthing draws we call, anyway]
        """

        ###e undefined in API so far: what if func says "draw later" (eg for transparency) -- do we do all that too, before we return??
        # guess: yes, but we'll need special drawing-env settings to tell primitives inside func that we're doing incremental drawing,
        # since it'll affect things like whether it's ok to write into the depth buffer for transparent objs obscuring visible ones
        # (useful for glselect code but would mess up subsequent incr drawing).
        def func1(self=self, func=func):
            res = func()
            self.env.glpane.swapBuffers()  # update display [needed]
            return res

        ran_already_flag, funcres = self.run_OpenGL_in_local_coords(func1)
        # note: this runs in self or first delegate that's a Highlightable, for now; that determines its gl state & coordsys
        assert ran_already_flag
        return funcres

    #e should we change to doing the action on_release_in, rather than on_press?
    delegate = Highlightable(
        plain,  ##e should this depend on enabled? probably yes, but probably the caller has to pass in the disabled form.
        ###e at least for the Mac, maybe it also ought to depend on whether the application is active (frontmost) and will respond to clicks.
        If(
            enabled, highlighted, plain
        ),  # revised 070109 to depend on enabled [#k does this cause the delegate expr itself to be remade??]
        on_press=_self.doit,
        # note: there was a bug in the prior form of this, "on_press = command" -- command to do should depend on enabled --
        ##e but i'm not sure if If(enabled,command,None) will work properly ###k TRY IT -- nevermind, using _self.doit now [070208]
        sbar_text=text
        #e should sbar_text depend on enabled?? yes, but need to revise callers then too -- some of which make the text depend on it
    )
    pass  # end of class ActionButton
예제 #8
0
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