class Boxed(InstanceMacro): # 070316 slightly revised """ Boxed(widget) is a boxed version of widget -- it looks like widget, centered inside a rectangular frame. Default options are pixelgap = 4 (in pixels), borderwidth = 4 (in pixels), bordercolor = white. [#e These can be changed in the env in the usual way. [nim]] @warning: some deprecated but commonly used options are given in model units, not in pixels (probably a design flaw). """ #e (Does Boxed want a clipped option, like DraggablyBoxed has? What about just Rect?) # WARNING: would not work if it inherited from Widget2D, # since it would pick up Widget2D default values for lbox attrs like btop. [unconfirmed but likely; 061127 comment] # args thing = Arg(Widget2D) # options borderwidth = Option(int, 4) # 070305 new feature -- specified in pixels borderthickness = Option(Width, borderwidth * PIXELS) # old alternative (worse since caller has to multiply by PIXELS); commonly used, but deprecated as of 070305 # (warning: borderthickness is still used as an internal formula when not supplied) # (WARNING: supplying both forms is an error, but is not detected; # this might cause bugs that are hard for the user to figure out # if the different option forms were used in successive customizations of the same expr) pixelgap = Option( int, 4 ) # 070305 new feature [#e rename gap? bordergap? (change all gap options to being in pixels?)] # (maybe not yet tested with nonzero passed-in values) gap = Option(Width, pixelgap * PIXELS) # old alternative (worse since caller has to multiply by PIXELS), commonly used, but deprecated as of 070305 # (see also the comments for borderthickness) # (warning: gap is still used as an internal formula when not supplied) bordercolor = Option(Color, white) # internal formulae extra1 = gap + borderthickness ww = thing.width + 2 * extra1 #k I'm not sure that all Widget2Ds have width -- if not, make it so ##e [061114] hh = thing.height + 2 * extra1 rectframe = RectFrame(ww, hh, thickness=borderthickness, color=bordercolor) # appearance -- note, rectframe appearing first is significant, since lbox attrs are delegated to it. _value = Overlay( Translate(rectframe, -V_expr(thing.bleft + extra1, thing.bbottom + extra1)), #e can't we clarify this somehow? thing) pass
def _expr_for_overlay_imagename(imagename, dx=0, dy=0): # WARNING: this is not optimized (see comment for _expr_for_imagename()). image_expr = _overlay_image(imagename) # NOTE: If the desired dx,dy depends on other settings, # like whether one or two CC buttons are shown, # then it's simplest to make more variants of this expr, # with dx, dy hardcoded differently in each one. # Or if that's not practical, let me know and I'll # revise the code that draws this to accomodate that variability. # Also make sure to revise the code that calls each one # (i.e. a modified copy of _expr_instance_for_overlay_imagename) # to use a different "index" even when using the same imagename. # (For example, it could include dx,dy in the index.) # [bruce 080324] return DrawInCorner(corner=UPPER_RIGHT)(Overlay( Spacer(22 * PIXELS), Translate(image_expr, V_expr(dx * PIXELS, dy * PIXELS, 0)), ))
class TestIterator_alsoobsnow_nevertried(InstanceMacro): """ simple iterator which makes two instances of the same arg """ #e for debug, we should make args to pass to this which show their ipaths as text! thing = Arg(Maker(Widget)) # Maker? ExprFor? ProducerOf? Producer? Expr? w1 = Instance(thing) #k is number of evals correct in principle? internal uses of Instance assumed the expr was literal, were they wrong? # analyzing the code: this calls _i_inst with (an arg that evaluated to) getattr_Expr(_self, 'thing'), # and to instantiate that, it evals it, returning (I think) whatever self.thing is, which should be an instance of the arg. # This may make no sense but it's predicted that self.w1 and self.w2 should be instances, and the same one, of the arg. # that's wrong [thing's formula instantiates once too much, Instance(thing) once too little since I meant, I guess, I(*thing)] # , but it's not what I seem to be seeing, which is w1.width below running on either a non-instance # or something with a non-instance inside it. The non-instance is Translate, w1 should be a Boxed, so maybe that's consistent # if there's an error in Boxed. So I'm adding sanity checks to zome of: Boxed, Overlay, InstanceMacro, Translate. ###DOIT ## print "w1 before ExprsMeta = %r" % (w1,) ### w2 = Instance(thing) # kluge since we don't have Row yet: _value = Overlay( w1, Translate(w2, V_expr(w1.width + 4 * PIXELS, 0,0))) pass
class Widget2D(Widget): """1. superclass for widget instances with 2D layout boxes (with default layout-box formulas). Also an expr-forming helper class, in this role (as is any InstanceOrExpr). 2. can coerce most drawable instances into (1). WARNING: I DON'T YET KNOW IF THOSE TWO ROLES ARE COMPATIBLE. """ # default layout-box formulas # bright is bbox size on right, bleft on left (both positive or zero) #e rename, bright is a word printnim("lbox defaults are not customizable -- wrong??") #k is this still true?? if so, is it wrong? IIRC old cmts suggest a fix... [070121] bright = 0 btop = 0 bleft = 0 bbottom = 0 ## width = bleft + bright # this would be ok if bleft etc were exprs; since they're constants we have to say _self explicitly ## height = bbottom + btop width = _self.bleft + _self.bright height = _self.bbottom + _self.btop center = V_expr( (_self.bright - _self.bleft) / 2.0, (_self.btop - _self.bbottom) / 2.0, 0.0) # 070227 moved here from Rect pass # end of class Widget2D
class BottomCenter(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dx = (thing.bleft - thing.bright) / 2.0 dy = +thing.bbottom delegate = Translate(thing, V_expr(dx, dy, 0))
class TopCenter(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dx = (thing.bleft - thing.bright) / 2.0 dy = -thing.btop delegate = Translate(thing, V_expr(dx, dy, 0))
class BottomLeft(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dx = +thing.bleft dy = +thing.bbottom delegate = Translate(thing, V_expr(dx, dy, 0))
class CenterLeft(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dx = +thing.bleft dy = (thing.bbottom - thing.btop) / 2.0 delegate = Translate(thing, V_expr(dx, dy, 0))
class TopLeft(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dx = +thing.bleft dy = -thing.btop delegate = Translate(thing, V_expr(dx, dy, 0))
class AlignmentExpr(DelegatingInstanceOrExpr): # doesn't work yet, see below thing = Arg(Widget2D) dx = 0 # override in some subclasses dy = 0 delegate = Translate(thing, V_expr(dx, dy, 0)) pass
class CenterX(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dx = (thing.bleft - thing.bright) / 2.0 delegate = Translate(thing, V_expr(dx, 0, 0))
class Bottom(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dy = +thing.bbottom delegate = Translate(thing, V_expr(0, dy, 0))
class Top(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dy = -thing.btop delegate = Translate(thing, V_expr(0, dy, 0))
class DraggablyBoxed( Boxed ): # 070316; works 070317 [testexpr_36] before ww,hh State or resizable, and again (_36b) after them # inherit args, options, formulae from Boxed thing = _self.thing ###k WONT WORK unless we kluge ExprsMeta to remove this assignment from the namespace -- which we did. ###e not sure this is best syntax though. attr = _super.attr implies it'd work inside larger formulae, but it can't; # attr = Boxed.attr might be ok, whether it can work is not reviewed; it too might imply what _super does, falsely I think. extra1 = _self.extra1 borderthickness = _self.borderthickness rectframe = _self.rectframe # a pure expr # new options resizable = Option(bool, False, doc="whether to make it resizable at lower right") # works 070317 10pm (testexpr_36b) except for a few ###BUGS [updated info 070318 7pm]: # + [fixed] the wrong corner resizes (top right) (logic bug) # + [fixed] resizer doesn't move (understood -- wrong expr for its posn; commented below) # - negative sizes allowed (missing feature - limit the drag - need new DragBehavior feature) # - no clipping to interior of rectframe (missing feature - draw something clipped) # - perspective view ought to work, but entirely ###UNTESTED. # also, cosmetic bugs: # - resizer doesn't follow mouse in rotated coordsys, even in ortho view (though it's still useable). # (This is not surprising -- we're using the wrong kind of DragBehavior as a simple kluge.) # - the resizer is ugly, in shape & color. clipped = Option( bool, False, doc="###doc") #070322 new feature ### make True default after testing? # state # WARNING: due to ipath persistence, if you revise dflt_expr you apparently need to restart ne1 to see the change. ## ww = State(Width, thing.width + 2 * extra1) # replaces non-state formula in superclass -- seems to work ## hh = State(Width, thing.height + 2 * extra1) ## # now we just need a way to get a stateref to, effectively, the 3-tuple (ww,hh,set-value-discarder) ... instead, use whj: whj = State(Vector, V_expr(thing.width + 2 * extra1, -thing.height - 2 * extra1, 0)) #e not sure this is sound in rotated coordsys translation = State(Vector, ORIGIN) # override super formulae ww = whj[0] # seems to work hh = neg_Expr( whj[1] ) # negative is needed since drag down (negative Y direction) needs to increase height # (guess: neg_Expr wouldn't be needed if we used an appropriate new DragBehavior in resizer, # rather than our current klugy use of SimpleDragBehavior) # appearance rectframe_h = Instance( Highlightable( ## rectframe(bordercolor=green),####### cust is just to see if it works -- it doesn't, i guess i sort of know why ##bug: __call__ of <getattr_Expr#8243: (S._self, <constant_Expr#8242: 'rectframe'>)> with: () {'bordercolor': (0.0, 1.0, 0.0)} ##AssertionError: getattr exprs are not callable TopLeft(rectframe), #e different colored hover-highlighted version?? for now, just use sbar_text to know you're there. sbar_text= "draggable box frame", # this disappears on press -- is that intended? ###k behavior=SimpleDragBehavior( # arg1: the highlightable _self.rectframe_h, # arg2: a write-capable reference to _self.translation ## fails - evalled at compile time, not an expr: LvalueFromObjAndAttr( _self, 'translation'), ###BUG: why didn't anything complain when that bug caused the state value to be an add_Expr, not a number-array? call_Expr(LvalueFromObjAndAttr, _self, 'translation'), #e alternate forms for this that we might want to make work: # - getattr_StateRef(_self, 'translation') # simple def of the above # - StateRef_for( _self.translation ) # turns any lvalue into a stateref! Name is not good enough, though. ))) resizer = Instance( Highlightable( Center(Rect(extra1, extra1)), #e also try BottomRight highlighted=Center(Rect(extra1, extra1, white)), pressed=_my.highlighted, sbar_text="resize the box frame", behavior=SimpleDragBehavior( _self.resizer, call_Expr(LvalueFromObjAndAttr, _self, 'whj')))) ###BUG: in Boxed, rectframe comes first, so lbox attrs are delegated to it. We should do that too -- # but right now we draw it later in order to obscure the thing if they overlap. With clipping we won't need that -- # but without clipping we will. If the latter still matters, we need a version of Overlay with delegation != drawing order, # or, to delegate appearance and layout to different instances ourselves. (Or just to define new formulae for lbox -- easiest.) #e drawme = Instance( Overlay( If( clipped, Clipped( thing, planes=[ call_Expr(clip_to_right_of_x0, -thing.bleft - extra1 + ww - borderthickness), # note: the (- borderthickness) term makes the clipping reach exactly # to the inner rectframe edge. Without it, clipping would reach to the outer edge, # which for 3d objects inside the frame can cause them to obscure it. # (Other interesting values are (- extra1) and (- borderthickness/2.0), # but they both look worse, IMHO.) call_Expr(clip_below_y0, thing.btop + extra1 - hh + borderthickness) ]), thing, ), Translate(rectframe_h, V_expr(-thing.bleft - extra1, thing.btop + extra1)), If( resizable, ## Translate( resizer, V_expr( thing.bright + extra1, - thing.bbottom - extra1)) ###WRONG - this posn is fixed by thing's lbox dims, not affected by ww, hh; # will the fix be clearer if we use a TopLeft alignment expr? # It'd be hard to use it while maintaining thing's origin for use by external alignment -- # but maybe there's no point in doing that. Translate( resizer, V_expr(-thing.bleft - extra1 + ww, thing.btop + extra1 - hh))))) _value = Translate( drawme, ## DisplayListChunk( drawme), ###k this DisplayListChunk might break the Highlightable in rectframe_h ##### translation) pass # end of class DraggablyBoxed
class Left(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dx = +thing.bleft delegate = Translate(thing, V_expr(dx, 0, 0))
class Right(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dx = -thing.bright delegate = Translate(thing, V_expr(dx, 0, 0))
class CenterY(DelegatingInstanceOrExpr): thing = Arg(Widget2D) dy = (thing.bbottom - thing.btop) / 2.0 delegate = Translate(thing, V_expr(0, dy, 0))