Пример #1
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
Пример #2
0
def checkbox_pref_OLDER(
        prefs_key,
        label,
        dflt=False):  # renamed 061215 late, since newer one is better
    "#doc"
    if type(label) == type(""):
        label = TextRect(label, 1, 20)
    return SimpleRow(CenterY(checkbox_v3(PrefsKey_StateRef(prefs_key, dflt))),
                     CenterY(label))  # align = CenterY is nim
Пример #3
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
Пример #4
0
class _MT_try2_node_helper(DelegatingInstanceOrExpr):
    """
    [private helper expr class for MT_try2]
    One MT item view -- specific to one node, one whole MT, and one (possibly time-varying) position with it.
    """
    # args ####e REORDER THEM
    node = Arg(ModelNode, doc = "any node that needs to be displayed in this MT")
        ###e NOTE: type coercion to this is nim; while that's true, we use helper functions like node_name(node) below;
        # once type coercion is implemented
        # (or simulated by hand by wrapping this arg with a helper expr like ModelTreeNode_trivial_glue),
        #  we could instead use node.mt_name, etc.)
    mt = Arg(MT_try2, doc = "the whole MT view, in which we store MT items for nodes, and keep other central state or prefs if needed")
    name_suffix = Option(str, "")
    initial_open = Option(bool, False, doc = "initial value of boolean state 'open'; only used when this item is first created")
        ##e should ask the node itself for the initial value of open (e.g. so new groups, trying to start open, can do so),
        # and also advise it when we open/close it, in case it wants to make that state persistent in some manner
        
    # WARNING: compare to MT_try1 -- lots of copied code after this point
    # WARNING: the comments are also copied, and not yet reviewed much for their new context! (so they could be wrong or obs) ###k
    
    # state refs
    open = State(bool, initial_open)
    
    # other formulae
    ###e optim: some of these could have shared instances over this class, since they don't depend on _self; should autodetect this
    # Note, + means openable (ie closed), - means closable (ie open) -- this is the Windows convention (I guess; not sure about Linux)
    # and until now I had them reversed. This is defined in two files and in more than one place in one of them. [bruce 070123]
    open_icon   = Overlay(Rect(0.4), TextRect('-',1,1))
    closed_icon = Overlay(Rect(0.4), TextRect('+',1,1))
    openclose_spacer = Spacer(0.4)
        #e or Invisible(open_icon); otoh that's no simpler, since open_icon & closed_icon have to be same size anyway

    # the openclose icon, when open or close is visible (i.e. for openable nodes)
    openclose_visible = Highlightable(
        If( open, open_icon, closed_icon ),
        on_press = Set(open, not_Expr(open)),
        sbar_text = getattr_Expr( _self, '_e_serno') #070301 this permits finding out how often MT gets remade/shared
            # (results as of 070301: remade when main instance is, even if going back to a prior testexpr, out of _19i & _30i)
     )
    
    openclose_slot = If( call_Expr(node_openable, node), openclose_visible, openclose_spacer )


    if 0:
        # cross-highlighting experiment, 070210, but disabled since approach seems wrong (as explained in comment)
        yellow = DZ = 'need to import these'
        indicator_over_obj_center = Center(Rect(0.4, 0.4, yellow))
        position_over_obj_center = node.center + DZ * 3 ###BUG: DZ does not point towards screen if trackballing was done
            ###STUB:
            # - should be drawn in a fixed close-to-screen plane, or cov plane (if obscuring is not an issue),
            #   - so indicator size is constant in pixels, even in perspective view (I guess),
            #   - also so it's not obscured (especially by node itself) -- or, draw it in a way visible behind obscuring things (might be a better feature)
            # - what we draw here should depend on what node is
            # - we also want to draw a line from type icon to node indicator (requires transforming coords differently)
            # - needs to work if node.center is not defined (use getattr_Expr - but what dflt? or use some Ifs about it)
        pointer_to_obj = DrawInCenter( Translate( indicator_over_obj_center, position_over_obj_center))
            #bug: Translate gets neutralized by DrawInCorner [fixed now]
            ###BUG: fundamentally wrong -- wrong coord system. We wanted DrawInAbsCoords or really DrawInThingsCoords,
            # but this is not well-defined (if thing drawn multiply) or easy (see comments about the idea in projection.py).
    else:
        # What we want instead is to set a variable which affects how the obj is drawn.
        # If this was something all objs compared themselves to, then all objs would track its use (when they compared)
        # and therefore want to redraw when we changed it! Instead we need only the involved objs (old & new value) to redraw,
        # so we need a dict from obj to this flag (drawing prefs set by this MT). Maybe the app would pass this dict to MT_try2
        # as an argument. It would be a dict of individually trackable state elements. (Key could be node_id, I guess.)
        # ### TRY IT SOMETIME -- for now, cross-highlighting experiment is disabled.
        pointer_to_obj = None

    # selection indications can use this
    node_is_selected = call_Expr( mt_node_selected, node)
    kluge_icon_color = If( node_is_selected, blue, green)
    sbar_format_for_name = If( node_is_selected, "%s (selected)", "%s")
    
    ###STUB for the type_icon ##e the Highlightable would be useful on the label too
    icon = Highlightable(
        Rect(0.4, 0.4, kluge_icon_color), ##stub; btw, would be easy to make color show hiddenness or type, bfr real icons work
        Overlay( Rect(0.4, 0.4, ave_colors(0.1, white, kluge_icon_color)),
                 #070216 mix white into the color like DraggableObject does
                 pointer_to_obj ),
        sbar_text = format_Expr( sbar_format_for_name, call_Expr(node_name, node) )
     )
    
    ##e selection behavior too

    label = DisplayListChunk(
        # added DisplayListChunk 070213 late -- does it speed it up? not much; big new-item slowness bug remains. retain, since doesn't hurt.
        TextRect( call_Expr(node_name, node) + name_suffix )
     )
        ###e will need revision to Node or proxy for it, so node.name is usage/mod-tracked
        ##e selection behavior too --
        #e probably not in these items but in the surrounding Row (incl invis bg? maybe not, in case model appears behind it!)
        ##e italic for disabled nodes
        ##e support cmenu
    
    delegate = SimpleRow(
        CenterY(openclose_slot),
        SimpleColumn(
            SimpleRow(CenterY(icon), CenterY(label)),
                #070124 added CenterY, hoping to improve text pixel alignment (after drawfont2 improvements) -- doesn't work
            If( open,
                _MT_try2_kids_helper( call_Expr(node_kids, node) , _self.mt ), # 070218 added _self.mt -- always intended, first used now
                None
                    # Note: this None used to be Spacer(0), due to a bug mentioned in a comment in ToggleShow.py
                    # (but unfortunately not explained there -- it just says "I wanted None here, but it exposes a logic bug,
                    # not trivial to fix, discuss in If or Column" -- my recollected bug-theory is described just below).
                    # On 070302 I confirmed that None seems to work (even in testexpr_18i with a group of 2 chunks, plus two more below).
                    # I don't fully know why it works, since I thought the bug was that SimpleColumn's None specialcase
                    # didn't run, since the element was not None but the If, and then delegating lbox attrs to None didn't work.
                    # (Fixable by using the newer If that evals, but for some reason that's not yet standard, I guess just because
                    # I didn't have time to test it enough or think it through fully re ipath or instance caching or something.)
                    # But as long as it works, use it -- ask Qs later. A recent perhaps-related change: None is allowed in drawkid.
                    # (A memory scrap -- does instantiating None conceivably produce a spacer?? ###k)
             )
         )
     )
    pass # end of class _MT_try2_node_helper