示例#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
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
示例#3
0
class SimpleColumn(Widget2D): #061115
    #e or use InstanceMacro using Overlay & Translate? Could work, but slower and not needed... might help in CL with fancier gaps.
    ## a0 = Arg(Widget2D) # note: this probably doesn't preclude caller from passing None, and even if it does, nothing enforces that yet;
        # if caller does pass None (to this or to Overlay), best thing is probably to replace this with Pass = Rect(0,0,white)
        # and use it as a drawable, but have special case to use no gap under it -- or the equiv, as a simple change
        # to our btop formula so it's 0 if not a0 -- which is already done, so maybe there's no need to worry about a0 = None.
        # Maybe it should be an optional arg like the others. [061115]
    a0 = Arg(Widget2D, None) # even the first arg can be missing, as when applying it to a list of no elts [061205]
    a1 = Arg(Widget2D, None)
    a2 = Arg(Widget2D, None)
    a3 = Arg(Widget2D, None)
    a4 = Arg(Widget2D, None)
    a5 = Arg(Widget2D, None) # use ArgList here when that works
    a6 = Arg(Widget2D, None)
    a7 = Arg(Widget2D, None)
    a8 = Arg(Widget2D, None)
    a9 = Arg(Widget2D, None)
    a10 = Arg(Widget2D, None)
    a11 = Arg(Widget2D, None) # the 12th arg is 1 too many
    toomany = Instance(TextRect("too many args to SimpleColumn"))
        #070212 added Instance to fix mysterious bug manifesting as this debug output:
        ## getattr_debugprint: <lexenv_ipath_Expr... <TextRect#2331(a)>> has no 'bleft'
    args = list_Expr(a0,a1,a2,a3,a4,a5, a6,a7,a8,a9,a10, # could say or_Expr(a0, Spacer(0)) but here is not where it matters
                     and_Expr(a11, toomany)
                     )
    
    ## gap = Option(Width, 3 * PIXELS)
    pixelgap = Option(float, 3) # 070104 int -> float
    gap = pixelgap * PIXELS

    print_lbox = Option(bool, False) #061127 for debugging; should be harmless; never tested (target bug got diagnosed in another way)
    
    drawables = call_Expr(lambda args: filter(None, args) , args)
    ## empty = not drawables ###e BUG: needs more Expr support, I bet; as it is, likely to silently be a constant False; not used internally
    empty = not_Expr(drawables)
    bleft = call_Expr(lambda drawables: max([arg.bleft for arg in drawables] + [0]) , drawables)
        # 070211 arg.bleft -> getattr_debugprint(arg, 'bleft')
    bright = call_Expr(lambda drawables: max([arg.bright for arg in drawables] + [0]) , drawables)
    height = call_Expr(lambda drawables, gap: sum([arg.height for arg in drawables]) + gap * max(len(drawables)-1,0) , drawables, gap)
    ## btop = a0 and a0.btop or 0  # bugfix -- use _Expr forms instead; i think this form silently turned into a0.btop [061205]
    btop = or_Expr( and_Expr( a0, a0.btop), 0)
    bbottom = height - btop
    def draw(self):
        if self.print_lbox:
            print "print_lbox: %r lbox attrs are %r" % (self, (self.bleft, self.bright, self.bbottom, self.btop))
        glPushMatrix()
        prior = None
        for a in self.drawables:
            if prior:
                # move from prior to a
                dy = prior.bbottom + self.gap + a.btop
                glTranslatef(0,-dy,0) # positive is up, but Column progresses down
            prior = a
            self.drawkid(a) ## a.draw()
        glPopMatrix()
        return
    pass # end of class SimpleColumn or SimpleColumn_OLD
示例#4
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
示例#5
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
示例#6
0
class Overlay(InstanceOrExpr, DelegatingMixin):
    "Overlay has the size of its first arg, but draws all its args in the same place, with the same origin."
    # Note: we can't inherit from Widget2D, or we'd fail to delegate
    # e.g. bright to self.delegate, and pick up the default value instead!
    # I'm not yet sure whether the proper fix is to handle those defaults in some other way
    # (e.g. as a last-resort delegate of some sort -- maybe we could say right here (to a fancier
    #  version of DelegatingMixin), if you don't find the attr in self.delegate, look in Widget2D).
    # See also comments in InstanceMacro, about the same issue for it.
    # [061210 grabbing SimpleColumn's scheme for permitting up to 10 args, though ArgList is nim]
    a0 = Arg(
        Widget2D, None
    )  # so it's not a bug to call it with no args, as when applying it to a list of no elts [061205]
    a1 = Arg(Widget2D, None)
    a2 = Arg(Widget2D, None)
    a3 = Arg(Widget2D, None)
    a4 = Arg(Widget2D, None)
    a5 = Arg(Widget2D, None)
    a6 = Arg(Widget2D, None)
    a7 = Arg(Widget2D, None)
    a8 = Arg(Widget2D, None)
    a9 = Arg(Widget2D, None)
    a10 = Arg(Widget2D, None)
    a11 = Arg(Widget2D, None)
    args = list_Expr(
        a0,
        a1,
        a2,
        a3,
        a4,
        a5,
        a6,
        a7,
        a8,
        a9,
        a10,  # could say or_Expr(a0, Spacer(0)) but here is not where it matters
        and_Expr(a11, TextRect("too many args in Overlay")))

    delegate = or_Expr(a0, Spacer(0))  ## _self.a0 # needed by DelegatingMixin

    ##    args = list_Expr(arg0, arg1) # not sure if [arg0, arg1] would work, but I doubt it --
    ###e should make it work sometime, if possible (e.g. by delving inside all literal list ns-values in ExprsMeta)
    #e add an option to make each element slightly closer, maybe just as a depth increment? makes hover highlighting more complicated...
    def draw(self):
        args = self.args  # this order is correct since we set glDepthFunc to GL_LEQUAL (not GL_LESS)
        for a in args:
            self.drawkid(a)
            #e We'd like this to work properly for little filled polys drawn over big ones.
            # We might need something like z translation or depth offset or "decal mode"(??).
            # [later 070404: "decal mode" is probably unrelated -- GL_DECAL is for combining a texture with a non-textured color/alpha,
            #  not related to using depth buffer when resulting textured object is drawn. Is "decal" used to mean anything else?? #k]
            # Different depth test would be best [done now -- GL_LEQUAL], but roundoff error might make it wrong...
            # This is definitely needed for overdrawing like that to work, but it's low priority for now.
            # Callers can kluge it using Closer, though that's imperfect in perspective mode (or when viewpoint is rotated).
            # [Or glDepthRange, now used for highlight drawing in GLPane as of 070921.]

    pass  # Overlay
示例#7
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
示例#8
0
class TextEditField(DelegatingInstanceOrExpr):
    text = State(
        str, "(empty)"
    )  #e dflt should be an arg, or more to the point, the text should come from a stateref ###DOIT
    label = Option(str, "(field label)")
    dialog_title = Option(str, "(title)")
    dflt_dialog_label = "enter some text; use @@@ for \\n"  # a public class attr (for clients to use in longer labels)
    dialog_label = Option(str, dflt_dialog_label)
    delegate = Highlightable(
        SimpleRow(
            Top(TextRect(label)), Top(TextRect(text))
        ),  #e long enough? too long? nlines ok? # Top is for when >1 line in text
        #e highlight form with blue border?
        on_doubleclick=_self.
        on_doubleclick,  # on_press -> on_doubleclick -- probably better
        sbar_text="double-click to edit textfield",
        #e cmenu binding too?
    )

    def on_doubleclick(self):
        ok, text = grab_text_using_dialog(default=self.text,
                                          title=self.dialog_title,
                                          label=self.dialog_label)
        if ok:
            #e unicode?? (see cad/src MT Node renaming code, or Node.name mmp code, or the Comment Node,
            # for example code that can handle it)
            #e filter through a func about what's acceptable?
            # if it fails, repeat dialog with more specific label?
            # strip whitespace? etc
            # eventually customize all that, for now just do what's most useful right here
            text = text.strip()
            self.text = text  # changes state
        else:
            print "cancelled text edit, old text remains: %r" % (
                self.text, )  #e some other place to put a message in the UI?
        return

    pass
示例#9
0
class SimpleRow(Widget2D):
    # copy of SimpleColumn, but bbottom <-> bright, btop <-> bleft, width <- height, and 0,-dy -> dx,0, basically
    a0 = Arg(Widget2D, None)
    a1 = Arg(Widget2D, None)
    a2 = Arg(Widget2D, None)
    a3 = Arg(Widget2D, None)
    a4 = Arg(Widget2D, None)
    a5 = Arg(Widget2D, None)  # use ArgList here when that works
    a6 = Arg(Widget2D, None)
    a7 = Arg(Widget2D, None)
    a8 = Arg(Widget2D, None)
    a9 = Arg(Widget2D, None)
    a10 = Arg(Widget2D, None)
    a11 = Arg(Widget2D, None)
    toomany = Instance(TextRect("too many args to SimpleRow"))
    args = list_Expr(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
                     and_Expr(a11, toomany))

    pixelgap = Option(int, 3)
    gap = pixelgap * PIXELS

    drawables = call_Expr(lambda args: filter(None, args), args)
    empty = not_Expr(drawables)
    btop = call_Expr(
        lambda drawables: max([arg.btop for arg in drawables] + [0]),
        drawables)
    bbottom = call_Expr(
        lambda drawables: max([arg.bbottom for arg in drawables] + [0]),
        drawables)
    width = call_Expr(
        lambda drawables, gap: sum([arg.width for arg in drawables]) + gap *
        max(len(drawables) - 1, 0), drawables, gap)
    bleft = or_Expr(and_Expr(a0, a0.bleft), 0)
    bright = width - bleft

    def draw(self):
        glPushMatrix()
        prior = None
        for a in self.drawables:
            if prior:
                # move from prior to a
                dx = prior.bright + self.gap + a.bleft
                glTranslatef(dx, 0,
                             0)  # positive is right, and Row progresses right
            prior = a
            self.drawkid(a)  ## a.draw()
        glPopMatrix()
        return

    pass  # end of class SimpleRow
示例#10
0
def ChoiceRow( nchoices, dflt = 0, **kws): ##e should be an InstanceMacro, not a def! doesn't work to be customized this way.
    "#doc"
    #e nim: Row -- esp on list like this -- Row( map(...)) -- so use SimpleRow
    return Apply(
        lambda stateref_expr, nchoices = nchoices, dflt = dflt, kws = kws:
            SimpleRow( # stateref_expr will be a Symbol when this lambda is run, to produce an expr, once only
                SimpleRow( * map( ChoiceButton(choiceref = stateref_expr, **kws), range(nchoices) ) ), # choose
                TextRect( format_Expr( "choice is %%r (default %s)" % dflt, stateref_expr.value ), 1, 30) # show choice
            ),
        LocalVariable_StateRef(int, dflt)
            # LocalState, combining this and the Apply?
                # or, just a stateref to some fixed state somewhere... whose instance has .value I can get or set? use that for now.
                ##k is there any way to use the new-061203 State macro for this?
    )
示例#11
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
示例#12
0
class main_ui_layout(DelegatingInstanceOrExpr):
    #e rename? is it not only the ui, but the entire app? (selection, files, etc)
    #e merge in the App obj from test.py, and the _recent_tests system in some form?

    # args (none yet)

    # internal state - permanent
    ###e note: when we reload and remake this instance, we'd prefer it if the world state stayed unchanged (as i presume it does)
    # but if the default_tool instance and toolstack state got remade. The lack of the latter has been confusing me
    # since changes to ui code aren't working. I think this is a difference between a ui and operations layer (should change)
    # vs model data layer (should not change even tho the op methods on it can change). So when I can put these things into layers
    # (not only State, but even Instance or attrs within them) and make those sensitive to reload, that will help.
    # In the meantime -- if I could kluge Instance and State to take an option to control this
    # (like index = exprs_globals.reload_counter)
    # it might help.... #####TRYIT SOMETIME, and BE CAREFUL UNTIL I DO.
    world = Instance(World())
    default_tool = Instance(DefaultToolRun())

    # internal state - varying
    toolstack = State(list_Expr, [
        default_tool
    ])  # always has at least one tool on it; a stack of Instances not exprs
    # maybe the better term for this is something like command & subcommand
    current_tool = toolstack[
        -1]  # last tool on the stack is current; exiting it will pop the stack (Instance not expr)
    ##e (add a type-assertion (as opposed to type-coercion) primitive, so I can say "this is an Instance" in the code?)
    # NOTE: this is not strictly speaking a tool, but ONE RUN of a tool. That might be important enough to rename it for,
    # to ToolRun or maybe ActiveTool or RunningTool or ToolInUse or ToolBeingUsed...
    # [but note, obj might remain around on history or in Undo stack, even when no longer being used],
    # since we also have to deal with Tools in the sense of Tool Run Producers, eg toolbuttons. ###e

    # parts of the appearance
    registry = find_or_make_global_command_registry(
    )  ## None ###STUB, will fail --
    ## AttributeError: 'NoneType' object has no attribute 'command_for_toolname'
    toolstack_ref = None  ###STUB
    toolbar = Instance(
        MainToolbar(registry, ["Features", "Build", "Sketch"],
                    toolstack_ref))  #e arg order?
    ###e args/opts for what tools to show -- maybe their cmdnames & it loads them from elsewhere
    #e add row of tool buttons, and flyout toolbar; use ChoiceRow?? the things should probably look pressed...
    # they might need cmenus (find out what the deal is with the cmenus i see in the ui mockup - related to flyouts?
    #    yes, it's like this: main tools have cmenus with subtools, and if you pick one, main tool and its subtool both look pressed
    # I'll need new specialized controls.py classes for these; new super Control for all kinds of controls?? (not sure why...)
    propmgr = SimpleColumn(
        TextRect(
            "(property manager)"),  #e possibly to become a tab control tab
        DebugPrintAttrs(
            current_tool.property_manager
        )  # must be None if we don't want one visible; otherwise an Instance
        ###BUG: DebugPrintAttrs shows that it's a spacer -- I guess IorE turns None into one when it instantiates? Make it a false one??
    )
    mt = SimpleColumn(
        TextRect(
            "(model tree)"
        ),  #e possibly to become a tab control tab, but only when we're in the left channel
        MT_try2(world)  #e rename to  "Feature Manager" ??
        ##e soon, MT should be not on whole world but on model or cur. part, a specific obj in the world
    )
    graphics_area = _self.world
    ##e ditto for what we show here, except it might not be the exact same object, and it will really be shown in a way
    # that depends on both the current display style and the current tool (command & subcommand)
    graphics_area_topright_buttons = current_tool.graphics_area_topright_buttons
    # overall appearance
    delegate = Overlay(
        # stuff in the corners -- note, these don't use the corner constants for standalone tests like PM_CORNER
        DrawInCorner(corner=UPPER_LEFT)(
            SimpleColumn(
                toolbar,
                #e add tab control
                SimpleRow(
                    If(
                        current_tool.property_manager, Top(propmgr), None
                    ),  #k None?? prob ok now, see demo_MT comment 070302 ###k
                    Top(mt)
                ),  #e actually we'd then put a splitter & glpane-like-thing...
                #e anything just below the propmgr?
            )),
        DrawInCorner(corner=UPPER_RIGHT)
        (  ##e of graphics area, not entire screen...
            graphics_area_topright_buttons  ### WRONG, these should go under the main toolbar area on the right
            # (but we don't yet have any 2dwidgets which expand to fill the available space, except DrawInCorner of entire screen)
            # (this won't matter once the toolbar is done entirely in Qt, so we don't need to correct it for now)
        ),
        #e other corners? "... an area (view) on the right side
        # of the main window for accessing the part library, on-line documentation, etc"
        # the main graphics area
        #e [this too ought to go under the toolbar and to the right of the propmgr, but that can wait until they're fully in Qt]
        graphics_area)
    pass
示例#13
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
示例#14
0
class TextState(InstanceMacro):  # rename?
    text = State(str, "initial text", doc="text")
    _value = TextRect(text)  # need size?
    pass
示例#15
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
示例#16
0
class ToggleShow(InstanceMacro):
    # args
    thing = Arg(Widget2D)
    label = Arg(Widget2D, TextRect("label")) #e or coerce text into a 1-line TextRect -- how do we declare that intent??

    if 0: # first make it work with a self-made stateref only, imitating Highlightable, using transient state
        stateref = Arg(StateRef, Automatic) ###k assumes the dflt can be a way to make one, not a literal one

        ## Q: how does each stateref we have, e.g. the one here meant for 'open', relate to StatePlace args
        # we might make or get from a superclass? (like the ones now in Highlightable.py but to be moved to a super of it)
        # if caller passes one, no need for our own, but to make our own, we'd make it in a StatePlace of our own, I think. ##e 061117

    if 0 and 'maybe':
        ##e might need to also say it's supposed to be boolean
        # note, on 070115 I revised StateRef (still a stub) but might have broken it due to the arg being passed here (not tested)
        stateref = Arg(StateRef(bool), Automatic)

        ##e and also spell out the default location -- assume ipath itself can be coerced into the full stateref

        stateref = Arg(StateRef(bool), _self.ipath)

        ####k is ipath local to something like _self, or only rel to the entire model?? his matters if we name the statepath here!

        stateref = Arg(StateRef(bool), _my_node.open) ###k assumes _my_node.open can be an lval even after _my_node is bound! ####k


        ##e or we could spell out the default stateref as _self.ipath, assuming that can be coerced into one --
        # of course it can't, we also need to say it's boolean (openQ: open is true, closed is false) and with what encoding.
        # but come to think of it, that is not part of the arg, right? the arg is "some boolean state"... hmm, i guess it is.
        # but the arg can also be "where to store the state, of whatever kind you want". And we say the type and encoding
        # if the arg doesn't -- as if the caller can supply partial info in the arg, and we supply defaults rather than
        # making them get made up by the bare argtype -- which could work by just using a fancified argtype created here.
        # which the Arg macro could make for us somehow... but that can all wait for later. For now,
        # we can detect the boolean type by how we try to use the arg, i guess... not sure, maybe just say it right here.
        # and the default encoding for bools (known to the bool type, not custom to us) is fine.

    if 1: # works fine, but as of 061126 late, comment out the remaining stmt, since done in InstanceOrExpr superclass rather than here
        pass ## transient_state = StatePlace('transient') #e move into super along with the ones in Highlightable of which this is a copy
        #e rename stateref to be specific for open, maybe open_stateref, in that if 0 code above
        # devel scratch: transient_state is an attr_accessor, which lets you do getattr and setattr.
        # but what we want it to do for us is tell us an lval for the attr 'open'
        # so we can retain that, attached to self.open somehow -- as its actual lval, maybe? not sure.
        # but much like that, since get or set self.open should work that way.
        # so a stateref (instance of StateRef) is basically an instance which acts as an lval... and can be attached to an attr.
        # But ExprsMeta right now insists on making its own lval, being passed a formula. Should we kluge-adapt to that or change it?
        # Guess: better & maybe easier to change it. So we have a new kind of object, not a formula (or a special kind of one),
        # to use as an rhs and process by ExprsMeta. It's not an lval, that's per-Instance. Is it a formula for making an lval?###
        # But it might be semantically different, since we don't store the lval as the value for self.open,
        # but as the value for its lval. hmm.... can we tell ExprsMeta to do this by an assignment to open
        # of a wrapped formula? it means, get the lval not by making one whose vals come from this formula
        # but make a property whose lvals come from this formula (which should be per-instance but time-constant, maybe,
        # tho if not time constant, it might be ok -- not sure ##e).

        ## open = State('transient','open')
            ### hmm... maybe 'open' needn't be passed if it gets it like Arg or Option does... maybe the kind is also default something?
            # so: open = State()? bt say the type and dfault val -- like I did in this:
            # staterefs.py: 181:     LocalState( lambda x = State(int, 1): body(x.value, x.value = 1) ) #

        # see if this gets the expected asfail: it does! [061121 late]
        ## set_default_attrs( transient_state, open = True)

    if 0: # this will be real code someday when no longer nim, but use an easier way first.
        open = State(bool, True) # default 'kind' of state depends on which layer this object is in, or something else about its class
            # but for now make it always transient_state
            # this is a macro like Option
            # it takes exprs for type & initial val
            #  but those are only evalled in _init_instance or so -- not yet well defined what happens if they time-vary
            # and note, that form doesn't yet let you point the state into a storage place other than _self.ipath... should it??
            # but the importance is, now in python you use self.open for get and set, just as you'd expect for an instance var.

    else:
        def get_open(self): #k
            return self.transient_state.open
        def set_open(self, val): #k
            self.transient_state.open = val
            return
        open = property(get_open, set_open)
        pass

    def _init_instance(self):
        super(ToggleShow, self)._init_instance()
        set_default_attrs( self.transient_state, open = True)

    # constants
    # 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))

    if 0:
        open_icon   = TextRect('-',1,1) #stub
        closed_icon = TextRect('+',1,1) #stub
    else:
        ####@@@@ I vaguely recall that Highlightable didn't work on text!
        # and indeed, highlighting doesn't seem to be working on those.
        # if so, the above'll need revision until that's fixed.
        # BUT, with these grays anyway, clicks on the text are working. But it might be because the grays are behind them. ###k
        if 0 and 'varying rect sizes':
            # how it was during debugging
            open_icon   = Overlay(Rect(0.5,1), TextRect('-',1,1)) # added 0.5 061120 1018p temp debug kluge
            closed_icon = Overlay(Rect(1,0.5), TextRect('+',1,1)) #061120 changed impicit 1 -> 0.5
        else:
            # easier on the mouse-hand and eye
            open_icon   = Overlay(Rect(0.4), TextRect('-',1,1)) # added 0.5 061120 1018p temp debug kluge
            closed_icon = Overlay(Rect(0.4), TextRect('+',1,1)) #061120 changed impicit 1 -> 0.5

    # _value, and helper formulae

    ## open = stateref.value # can we make it work to say Set(open, newval) after this?? ####k
        # the hard part would be: eval arg1, but not quite all the way. we'd need a special eval mode for lvals.
        # it'd be related to the one for simplify, but different, since for (most) subexprs it'd go all the way.
    ## openclose = If( open, open_icon, closed_icon )

    # Status as of 061121 421p: both if 0 and if 1 cases seem to work fine, provided you restart when changing between them.
    # (Testing was not extensive, so it might turn out that avoiding other reloads is also needed.)
    # The known bugfixes that led to this:
    # - selobj = None in some places (not sure which are needed).
    # - no usage/change tracking by stateplaces that get set during draw (or that contain glname -- don't know if that matters).
    # - no usage/change tracking by set_default_attrs.
    # And other changes that might be helping:
    # - don't recycle glnames.
    # - some others I forget, which are marked by 061120 (or maybe 061121)
    #   in comments or stringlits (in this or other files).
    #  - don't track_use on exception in Lval get_value (BUT, i suspect it's actually wrong not to; see cmt there 061121)
    #  - more conservative selobj_still_ok
    #  - mode.update_selobj(event) in leftClick and ReleasedOn
    #  - self.inval(mode) #k needed? (done in two places per method, guess is neither is needed)
    #
    # Soon, the needed or not of the above workarounds should be sorted out,
    # and most of the following debugging-log commentary should be removed. #e

    if 1:
        openclose = Highlightable( If_kluge( open, open_icon, closed_icon ),
                                   on_press = _self.toggle_open,
                                   sbar_text = _this(Highlightable).ipath # this line just for debugging
                                   )
            ##e we should optim Highlightable's gl_update eagerness
            # for when some of its states look the same as others!
            # (no gl_update needed then, at least not just for that change --
            #  note, this is a special case of the inval optim for when something was changed to an equal value)
            #e someday be able to say:
            # on_press = Set( open, not_Expr(open) )
            ## silly: on_press = lambda open = open: open = not open # no, open = not open can't work
            # in fact, you can't use "lambda open = open", since open has to be replaced by ExprsMeta

            ##k can on_press be an expr to eval, instead of a (constant expr for a) func to call?? ####k
            ## on_press = call_Expr( lambda xxx: self.open = not self.open, xxx) # no, no assignment in lambda
        pass
    else:
        # so try this form 155p - bug of not working is gone, but now, it always draws the + form! Is it drawing the old one
        # due to same glname? no (I guess), they should have different names!
        # is it drawing old one due to not realizing that one is obs? ######where i am
        # is it failing to invalidate the drawing effect of this instance? (after all, who is it that sees the usage of open?
        # it must be glpane as if we were using a prefs variable here! is that sufficient?? does it work ok re selobj system???###)
        # IS THE CHOICE OF DELEGATE being invalled? I think so, since I see the alignment calcs get updated,
        # or is that just the live gltranslate inside the draw method?
        # HEY, when I covered up the glpane with this app, then uncovered it, suddenly I see the new selobj,
        # then the conjunction of both! how can that be? thes are similar to whgat I sawe earlier. conclusion: weird update bugs
        # in selobj/highlight system, i guess. (maybe it does the main draw and highlight draw on different objects?
        # try altering color, or using 4 images not 2. ###)
        # now it sems that mouse around on the closed that looks like open is what makes it look like clsed, or like both.
        # yes, repeatable, for either change of state. Ok, try that in 'if 1' case of this. ### siilar but not identical
        # and that time is again does get stuck into the closed state, with the grayrect no longer optiming redraws re stencil buffer.
        # .. reviewing code in Highlightable, I see some things to try -- see its 061120 comments.
        # ... I did all that, and the 'gray becomes inactive bug' in 'if 1 openclose case' is still there. howbout the if 0 case?
        # [later: i think that still had some bad bugs too, not much changed.]
        # for more, see string lits containing 061120, and for a log see big cmt just below here.
        openclose = If_kluge( open,
##                              Highlightable(open_icon,   on_press = _self.toggle_open, sbar_text = _self.ipath),
##                              Highlightable(closed_icon, on_press = _self.toggle_open, sbar_text = _self.ipath),
                              ###BUG - same ipaths? NO, I USED _self BUT MEANT _this(Highlightable)!!! AAArgh! ##k works now?? yes
          Highlightable(open_icon,   on_press = _self.toggle_open, sbar_text = _this(Highlightable).ipath),
          Highlightable(closed_icon, on_press = _self.toggle_open, sbar_text = _this(Highlightable).ipath),
                    )
        pass

    def toggle_open(self):
        if 'yet another shot in the dark 061120 1001p':
            self.env.glpane.selobj = None ##### THIS SEEMS TO FIX THE BUG, at least together with other potshots and if 0 openclose.
            # theory: old selobjs are being drawn highlighted even when not drawn normally. they mask the real stuff.
            # but with if 1 openclose it doesn't fix the different bug (gets wedged into closed state). why not???
            # this is with no recycling of names, and also selobj=None in recycler.
            # guess: in if 1, the same glname is used... but it's same literal selobj too, right? and remaking is turned off.
            # I don't have a theory for 'if 1' bug cause, or for why it only affects the inner thing, not outer one.
            # Does it only affect that after it's once been hidden? ### if so, is it "you were selobj and then not drawn" that makes it
            # happen? that might fit the data but I don't see how that could work.
            # So I added a 2nd 0.5 so neither gray rect form covers the other. but first inner close hits the bug of making it
            # inactive and act non-highlighted. so i wondered if the glname really only covers the openclose? code says so.
            # I added a try/except to be sure the PopName occurs; not triggered during this if 1 bug.
            #
            # Stopping for night 061120 1027p, summary: I understand some bug causes but not all; wish I could see inside the glselect
            # reasoning, so plan to add debug prints to glpane. Need to think thru its assumptions re chaotic glname/selobj/size/
            # whether-drawn situation, see which are wrong, which might cause the bug. Also - can event processing occur during
            # paintGL? I hope not, but verify. Also maybe GLPane needs to track frame numbers for selobjs being drawn,
            # stencil bits being made, vs selobj state mods as tracked by inval....
            #
            # update 061121 953a, where I am: after basic fixes elsewhere [some stateplaces not tracked, some usage tracking disallowed],
            # and still using all kluge/workarounds from 061120, bug seems totally fixed for if 0 case, all or most for if 1 ##k.
            # IIRC it was slightly remaining before some usage tracking disallowed, but that is not complaining, which is suspicious.
            # Anyway, if if 1 works too, plan is to gradually remove the kluges and clean up and keep it working.
            # BUT it looks like if 1 (using reloaded code) has a bug of some disallowed usage... details to follow.
            # BUT after restart I don't see it. BTW I recently reenabled reloading -- could that have fixed some bugs (how???),
            # or could it be that they now occur after reloading but not before it?? indeed, this is after changing if 1->0 and reload,
            # and looks like it might relate to old state being there, and
            ###### WHAT IF RELOADED CODE USES THE SAME STATE DIFFERENTLY AND HAS A BUG? #####
            # [but, that bug aside, there is still a real problem with whatever usage tracking this
            #  set_default_attrs is doing. [fixed now]]


        if 0: #061121 822p i've been using if 1 forever, let's see if if 0 works here: it does! either is ok, given the open property.
            old = self.transient_state.open
            self.transient_state.open = new = not old
            ## print "toggle_open changed self.transient_state.open from %r to %r" % (old, new,)
        else:
            old = self.open
            self.open = new = not old
            ## print "toggle_open changed self.open from %r to %r" % (old, new,)
            # [obs cmt re open property, but was it talking about that or a partly working State decl? as of 061121 I can't remember:]
                # should work but doesn't, see bug in notesfile, it delegates self.open eval to _value: 061118 late
                # (or is it just because the val was not initialized? GUESS, YES ###k)
                ## self.open = not self.open ### can this work??? it will call set of self.open -- what does the descriptor do for that?
                # (asfail, or not have __set__ at all?? FIND OUT. the notesfile says the same thing but for a different Q, what was it?)
                ## WE SHOULD MAKE THIS WORK even if we also make on_press = Set( open, not_Expr(open) ) work, since it's so natural.
        ### BTW what is it that will notice the inval, and the usage of this when we drew, and know that gl_update is needed?
        # the same thing that would know a display list content was invalid -- but where is it in our current code (if anywhere)?
        # I vaguely recall a discussion of that issue, in the displist chunk code or notesfile, weeks ago.
        # some way to have lvals representing displist contents or frame buffer contents, whose inval means an update is needed.
        printnim("toggle_open might do a setattr which is not legal yet, and (once that's fixed) might not properly gl_update yet")
        return

    _value = SimpleRow(
        openclose,
        SimpleColumn(
            label,
            If_kluge( open,
                      thing,
                      TextRect("<closed>") #####BUG: I wanted None here, but it exposes a logic bug,
                          # not trivial to fix, discuss in If or Column [see also a discussion in demo_MT.py, 070302];
                          ##e Spacer(0) can also be tried here [##e should what to show here be an arg??]
                      )
        )
    )

##    if 0: # if 0 for now, since this happens, as semiexpected:
##        ## AssertionError: compute method asked for on non-Instance <SimpleRow#3566(a) at 0xe708cb0>
##
##        ##e do we want to make the height always act as if it's open? I think not... but having a public open_height attr
##        # (and another one for closed_height) might be useful for some callers (e.g. to draw a fixed-sized box that can hold either state).
##        # Would the following defns work:?
##
##        # (They might not work if SimpleRow(...).attr fails to create a getattr_Expr! I suspect it doesn't. ####k )
##
##        # [WARNING: too inefficient even if they work, due to extra instance of thing -- see comment for a fix]
##        open_height = SimpleRow(
##            open_icon,
##            SimpleColumn(
##                label,
##                thing
##            )).height   ##k if this works, it must mean the SimpleRow gets instantiated, or (unlikely)
##                        # can report its height even without that. As of 061116 I think it *will* get instantiated from this defn,
##                        # but I was recently doubting whether it *should* (see recent discussions of TestIterator etc).
##                        # If it won't, I think wrapping it with Instance() should solve the problem (assuming height is deterministic).
##                        # If height is not deterministic, the soln is to make open_instance and closed_instance (sharing instances
##                        # of label), then display one of them, report height of both. (More efficient, too -- only one instance of thing.)
##                        # (Will the shared instance of label have an ipath taken from one of its uses, or something else?
##                        #  Guess: from the code that creates it separately.)
##
##        closed_height = SimpleRow(
##            closed_icon,
##            SimpleColumn( # this entire subexpr is probably equivalent to label, but using this form makes it more clearly correct
##                label,
##                None
##            )).height

    pass # end of class ToggleShow
示例#17
0
class MainToolbar(Toolbar): ###e how is the Main one different from any other one??? not in any way I yet thought of...
    # unless its flyout feature is unique... or maybe it has the behavior of deciding what to look like, inside it??
    # Nah, its client needs to provide the spec that, even if MainToolbar then does the work... but if it *can* do the work,
    # that might count... maybe it's just that it has no parent toolbar?
    #e rename
    """The main toolbar that contains (for example) Features, Build, Sketch, Dimension (tool names passed as an arg),
    with their associated flyout toolbars,
    and maintains the state (passed as a stateref) of what tool/subtool is active.
    """
    # args
    registry = Arg( CommandRegistry, doc = "the place in which tool name -> tool code mapping is registered, and in which subtools are found")
    #e the app object in which the tools operate?
    #e the world which they affect?
    toolnames = Arg(list_Expr, doc = "list of names of main tools")
    toolstack_ref = Arg(StateRef, doc = "external state which should be maintained to show what tool & subtool is active now")
    # formulae
    # appearance
    delegate = SimpleRow(
        MapListToExpr( _self.toolbutton_for_toolname,                       
                      toolnames,
                      KLUGE_for_passing_expr_classes_as_functions_to_ArgExpr(SimpleRow) ),
        TextRect("flyout goes here")
     )
    def toolbutton_for_toolname(self, toolname):
        assert type(toolname) == type("")
        registry = self.registry
        ## expr = Boxed(TextRect(toolname)) # stub
        #e look up commands from registry ### LOGIC BUG: don't we get the toolname/cmd pair from the reg? if so,
        # then at this stage, just look up cmd from a local cache we made of cmds that go with our names for them.
        # But in current code, toolnames were passed in. Nevermind.
        command = registry.command_for_toolname(toolname) ###STUB - at least since retval might be None
            # [also, terms are messed up -- straighten out cmd vs tool, use same for main and sub]
            # [maybe: a command is something you do, and a command is "invoke a tool", ie start it (does not imply finishing it) --
            #  but i don't like that much -- what i look up here is the longlived-thing-maker (toolrun maker),
            #  not a subr that invokes it. otoh what abt toolbuttons that have immediate effect, no longlived thing created?
            #  their presence means i *do* have to look up a command, which when run *might* change toolstack state.]
        subtools = registry.subtools_for_command(command) ###STUB??
        expr = MainCommandToolButton( self, toolname, command, subtools)
        #e is it ok about MapListToExpr that it makes us instantiate this ourselves? Can't it guess a cache index on its own?
        #e related Q: can we make it easier, eg using nim InstanceDict or (working) _CV_ rule?
        instance = self.Instance( expr, "#" + toolname)
        return instance
    def _advise_got_pressed(self, button):
        print "my button %r with toolname %r says it got pressed" % (button, button.toolname)
        ###STUB - do the following:
        #e decide if legal at this time
        #e set it as the next running button
        
        #e unpress other buttons (and finish or cancel their runs if needed) (maybe only if their actions are incompat in parallel??)
        # e.g. something like:
        ## while toolstack_ref.get_value()[-1].is_incompatible_with(something):
        ##    didit = toolstack_ref.get_value()[-1].force_finish(something)
        ##    if not didit:
        ##        # oops, still in some prior command (and what about some we already popped out of? restore them?
        ##        # no, don't pop out yet, unless we want that...)
        
        #e start a new ToolRun of this button's command
        #e put it on the stack we were passed (that way its flyout gets displayed, and its pm gets displayed)
        #e update our flyout and PM if needed (for example, by figuring out what subcommands have been registered with this name)
        #e update other stuff not yet used, like a display/edit style, various filters...
        return
    pass