typo fixed.
[l3full.git] / l3gui / widgets.py
blobf84ef77cc3cc462bd4832ebee418a190d222ac7f
2 # Author: Michael H. Hohn (mhhohn@lbl.gov)
4 # Copyright (c) 2006, The Regents of the University of California
6 # See legal.txt and license.txt
9 """
10 Canvas "widgets". These come in groups:
12 graphical analogs to l3's core types
13 as found in l3lang.ast.
14 They provide editing, dragging, and composition functionality,
15 and allow for graphical program construction (useful for
16 higher-level functions), and graphical program and data
17 examination.
19 simple display support
20 These are additional items needed for display, like
21 Placeholder and Header.
23 """
24 #* Header
26 # policy for flush_events
27 # To ensure proper sizing, flush_events is called after display
28 # additions are made.
29 # Using flush_events in every get_bounds() call slows display down
30 # significantly.
32 import sys, weakref, traceback, string, types, os
33 from math import floor, sqrt
34 from pprint import pprint
36 import pango
37 import gtk
38 import gobject
39 try:
40 import gnomecanvas as canvas
41 from gnomecanvas import MOVETO_OPEN, MOVETO, LINETO, CURVETO
42 except:
43 # Try backported version used in sparx.
44 import canvas
45 from canvas import MOVETO_OPEN, MOVETO, LINETO, CURVETO
47 import l3lang.globals as G
48 from l3lang import reader, ast, view, utils
49 from l3lang.ast import empty_parent, Set, Marker, Int, Call, Symbol, \
50 Macro, aList, List, Return, Member
51 import l3gui.misc as misc
52 from l3gui.misc import \
53 print_, \
54 warn_, \
55 DisplayError, \
56 flush_events, \
57 _get_props, \
58 _set_props, \
59 path_rectangle_rounded, \
60 canvas_item_get_bounds_world, \
61 destroy_if_last, \
62 _safed, \
63 Selectable,\
64 slot_available
67 #* key mappings
68 kn = gtk.gdk.keyval_from_name
69 key_Left = kn("Left")
70 key_Right = kn("Right")
71 key_Up = kn("Up")
72 key_Down = kn("Down")
73 key_Return = kn("Return")
74 key_Escape = kn("Escape")
75 key_Windows_L = kn("Super_L")
76 key_Alt_L = kn("Alt_L")
79 #* control flow lines (element display)
80 class ContinueLine:
81 pass
83 class BreakLine:
84 pass
86 def __init__(self, w_, cnvs, child, parent):
87 x1, y1 = child.continue_start_pt()
88 xn, yn = parent.continue_stop_pt()
90 # World to parent coordinates.
91 _, _, _, _, sx, sy = parent.i2w_affine(tuple(range(0,6)))
92 x1 -= sx
93 y1 -= sy
94 xn -= sx
95 yn -= sy
97 # Line moves left and up.
98 points = [x1, y1,
99 xn, y1,
100 xn, yn,]
101 self._line = parent._root_group.add(
102 canvas.CanvasLine,
103 fill_color = "green",
104 points = points,
105 width_units = 0.3,
106 cap_style = gtk.gdk.CAP_ROUND,
107 join_style = gtk.gdk.JOIN_ROUND,
109 ContinueLine.__init__ = __init__
112 def __init__(self, w_, cnvs, child, parent):
113 x1, y1 = child.break_start_pt()
114 xn, yn = parent.break_stop_pt()
116 # World to parent coordinates.
117 _, _, _, _, sx, sy = parent.i2w_affine(tuple(range(0,6)))
118 x1 -= sx
119 y1 -= sy
120 xn -= sx
121 yn -= sy
123 # Line moves right and down.
124 points = [x1, y1,
125 xn, y1,
126 xn, yn,]
127 self._line = parent._root_group.add(
128 canvas.CanvasLine,
129 fill_color = "red",
130 points = points,
131 width_units = 0.3,
132 cap_style = gtk.gdk.CAP_ROUND,
133 join_style = gtk.gdk.JOIN_ROUND,
135 BreakLine.__init__ = __init__
137 def destroy(self):
138 _safed(self._line)
139 self._line = None
140 ContinueLine.destroy = destroy
141 BreakLine.destroy = destroy
143 def refresh(self):
144 pass
145 ContinueLine.refresh = refresh
146 BreakLine.refresh = refresh
149 #* Label ( element header display )
150 class Label:
151 # Display of a textual element, inteded to be part of another
152 # construct. Thus, Label has no event handling of its own, no
153 # menu, no independent hiding, etc.
155 # Appearance similar to l3Rawtext.
156 pass
158 def __init__(self, w_, cnvs, root_group, header_text,
159 x = 0, y = 0, font = None, fill_color = "white"):
160 if font is None:
161 font = w_.cp_.label_font
163 # Outline follows l3Rawtext.__init__, but the contents are too
164 # distinct to merge.
165 self._destroy_hook = [] # (func -> None) list
166 self._reparent_to_root_hook = [] # (func -> None) list
168 self.w_ = w_
169 self._canvas = cnvs
171 # l3 tree.
173 # Item cross-referencing.
175 # Text edit state.
177 # Focus redirection.
179 # Display Group.
180 self._root_group = root_group.add(canvas.CanvasGroup)
182 # Display self.
183 if 1:
185 # Text content / format / scale
187 self._ltext = misc.GtkObjProxy(self._root_group.add(
188 canvas.CanvasText,
189 anchor = gtk.ANCHOR_NORTH_WEST,
190 x = x,
191 y = y,
192 size = self.w_.cp_.font_size_labels * 1.0 * pango.SCALE,
193 scale = 1.0,
194 scale_set = True,
195 font = font,
196 size_set = True,
197 markup = header_text,
199 self._ltext.show()
200 flush_events()
201 x1, y1, x2, y2 = self._ltext.get_bounds() # world units
202 # Reference size.
203 self._ltext_size_1 = ((x2 - x1) * self._canvas._pixpu,
204 (y2 - y1) * self._canvas._pixpu)
206 # Current scale size.
207 self._ltext.set_property(
208 "size",
209 self.w_.cp_.font_size_labels * self._canvas._abs_zoom * pango.SCALE)
211 self._canvas.add_zoom_text(self)
213 # Text events.
215 # Text outline.
216 x1, y1, x2, y2 = self._ltext.get_bounds() # world units
217 pad = w_.cp_.textview.outline_padding / cnvs._pixpu
218 x1 -= pad
219 y1 -= pad
220 x2 += pad
221 y2 += pad
223 self._loutline = self._root_group.add(
224 canvas.CanvasRect,
225 x1 = x1, y1 = y1,
226 x2 = x2, y2 = y2,
227 fill_color = fill_color,
228 outline_color = fill_color,
229 width_pixels = w_.cp_.header_outline_width,
231 self._loutline.lower(1)
232 self._loutline.show()
234 # Outline events.
236 # Display subtrees.
238 # Highlight outline.
240 # Borders etc.
241 Label.__init__ = __init__
243 def connect(self, *args):
244 self._root_group.connect(*args)
245 Label.connect = connect
247 def get_property(self, prop):
248 return self._root_group.get_property(prop)
249 Label.get_property = get_property
251 def set_property(self, prop, val):
252 return self._root_group.set_property(prop, val)
253 Label.set_property = set_property
255 #* Image ( element header display )
256 class Image:
257 # Display of an image, intended to be part of another
258 # construct. Thus, Image has no event handling of its own, no
259 # menu, no independent hiding, etc.
260 # See also class Label.
261 pass
263 def __init__(self, w_, cnvs, root_group, pixbuf,
264 x = 0, y = 0, parent = None):
266 # Outline follows l3Rawtext.__init__, but the contents are too
267 # distinct to merge.
268 self._destroy_hook = [] # (func -> None) list
269 self._reparent_to_root_hook = [] # (func -> None) list
271 self._parent = parent
272 self.w_ = w_
273 self._canvas = cnvs
274 self._img_scale = w_.cp_.image_scale
276 # l3 tree.
278 # Item cross-referencing.
280 # Text edit state.
282 # Focus redirection.
284 # Display Group.
285 self._root_group = root_group.add(canvas.CanvasGroup)
287 # Display self.
288 if w_.cp_.image_natural_size:
290 # Image content at original pixel size
292 # Display without aspect distortion.
293 pixwid = pixbuf.get_width()
294 pixhei = pixbuf.get_height()
295 self._ltext = misc.GtkObjProxy(self._root_group.add(
296 canvas.CanvasPixbuf,
297 x = x,
298 y = y,
299 anchor = gtk.ANCHOR_NORTH_WEST,
300 height_set = True,
301 width_set = True,
302 height_in_pixels = True,
303 width_in_pixels = True,
304 width = pixwid * self._img_scale,
305 height = pixhei * self._img_scale,
306 pixbuf = pixbuf,
308 self._ltext.show()
309 flush_events()
310 x1, y1, x2, y2 = self._ltext.get_bounds() # world units
312 else:
314 # Image content / format / scale
316 # Display without aspect distortion.
317 pixwid = pixbuf.get_width()
318 pixhei = pixbuf.get_height()
319 woh = min(1.0 * pixwid / pixhei, 1)
320 how = min(1.0 * pixhei / pixwid, 1)
321 self._ltext = misc.GtkObjProxy(self._root_group.add(
322 canvas.CanvasPixbuf,
323 x = x,
324 y = y,
325 anchor = gtk.ANCHOR_NORTH_WEST,
326 height_set = True,
327 width_set = True,
328 width = w_.cp_.image_width * woh * self._img_scale,
329 height = w_.cp_.image_height * how * self._img_scale,
330 pixbuf = pixbuf,
332 self._ltext.show()
333 flush_events()
334 x1, y1, x2, y2 = self._ltext.get_bounds() # world units
336 # Display subtrees.
338 # Highlight outline.
340 # Borders etc.
341 Image.__init__ = __init__
343 # # def resize(self, which, value):
344 # # # UNTESTED
345 # # ''' Resize the pixmap to `value` world units.
346 # # `which` is "width" or "height"
347 # # '''
348 # # assert which in ['width', 'height'], "`which` must be width or height"
349 # # self._ltext.set_property(which, value)
350 # # # Move following items in parent.
351 # # if self._parent:
352 # # self._parent.new_size_for(self)
353 # # Image.resize = resize
355 def scale(self, ratio):
356 get = self._ltext.get_property
357 set = self._ltext.set_property
359 set('height', get('height') * ratio)
360 set('width', get('width') * ratio)
362 # Move following items in parent.
363 if self._parent:
364 self._parent.new_size_for(self)
366 self._img_scale *= ratio
367 Image.scale = scale
369 def set_default_size(self):
370 self.w_.cp_.image_scale = self._img_scale
371 Image.set_default_size = set_default_size
374 def connect(self, *args):
375 self._root_group.connect(*args)
376 Image.connect = connect
378 def get_property(self, prop):
379 return self._root_group.get_property(prop)
380 Image.get_property = get_property
382 def set_property(self, prop, val):
383 return self._root_group.set_property(prop, val)
384 Image.set_property = set_property
386 #* Widget ( element header display )
387 class Widget:
388 # Display of an embedded widget, intended to be part of another
389 # canvas construct. Thus, Widget has no event handling of its own, no
390 # menu, no independent hiding, etc.
391 # See also class Label.
392 pass
394 def __init__(self, w_, cnvs, root_group, widget,
395 x = 0, y = 0, parent = None):
397 # Outline follows l3Rawtext.__init__, but the contents are too
398 # distinct to merge.
399 self._destroy_hook = [] # (func -> None) list
400 self._reparent_to_root_hook = [] # (func -> None) list
402 self._parent = parent
403 self.w_ = w_
404 self._canvas = cnvs
406 # l3 tree.
408 # Item cross-referencing.
410 # Text edit state.
412 # Focus redirection.
414 # Display Group.
415 self._root_group = root_group.add(canvas.CanvasGroup)
417 # Display self.
419 # Widget content at original pixel size
421 # Display without aspect distortion.
422 self._ltext = misc.GtkObjProxy(self._root_group.add(
423 canvas.CanvasWidget,
424 x = x,
425 y = y,
426 anchor = gtk.ANCHOR_NORTH_WEST,
427 size_pixels = False,
428 width = 40,
429 height = 30,
430 widget = widget,
432 self._ltext.show()
433 widget.show()
434 flush_events()
435 x1, y1, x2, y2 = self._ltext.get_bounds() # world units
437 # Display subtrees.
439 # Highlight outline.
441 # Borders etc.
442 pass
443 Widget.__init__ = __init__
445 def scale(self, ratio):
446 get = self._ltext.get_property
447 set = self._ltext.set_property
449 set('height', get('height') * ratio)
450 set('width', get('width') * ratio)
452 # Move following items in parent.
453 if self._parent:
454 self._parent.new_size_for(self)
456 Widget.scale = scale
459 def connect(self, *args):
460 self._root_group.connect(*args)
461 Widget.connect = connect
463 def get_property(self, prop):
464 return self._root_group.get_property(prop)
465 Widget.get_property = get_property
467 def set_property(self, prop, val):
468 return self._root_group.set_property(prop, val)
469 Widget.set_property = set_property
471 #* uWidget ( element header display )
472 class uWidget:
473 # Base class for trivial "widgets" like buttons.
475 # Full widgets
476 # a) make the display sluggish
477 # b) cannot mix (overlap) with the canvas elements
478 # c) do not nest with canvas items
480 # uWidgets are always added to another construct (like l3List) for
481 # a) convenience
482 # b) display aestetics
484 # uWidgets handle events only to call appropriate functions of the
485 # main construct.
486 # uWidgets provide no independent hiding, etc.
488 # See also class Label.
489 pass
491 def __init__(self, w_, cnvs, root_group,
492 action = (lambda _: None)):
494 # Comment outline follows l3Rawtext.__init__.
496 self._destroy_hook = [] # (func -> None) list
497 self._reparent_to_root_hook = [] # (func -> None) list
499 self.w_ = w_
500 self._canvas = cnvs
501 self._action = action
503 # l3 tree.
505 # Item cross-referencing.
507 # Text edit state.
509 # Focus redirection.
511 # Display Group.
512 self._root_group = root_group.add(canvas.CanvasGroup)
513 grp_trans = self._root_group.add(canvas.CanvasGroup)
514 grp_scale = grp_trans.add(canvas.CanvasGroup)
515 grp_obj = grp_scale.add(canvas.CanvasGroup)
517 self._grp_trans = grp_trans # Use to move
518 self._grp_scale = grp_scale # Use to scale.
519 self._grp_obj = grp_obj # Draw objects into this.
520 # Use .move to reposition for scaling center.
522 # Display self.
523 self.draw()
525 # Display subtrees.
527 # Highlight outline.
529 # Borders etc.
530 uWidget.__init__ = __init__
532 def connect(self, *args):
533 self._root_group.connect(*args)
534 uWidget.connect = connect
536 def get_property(self, prop):
537 return self._root_group.get_property(prop)
538 uWidget.get_property = get_property
540 def set_property(self, prop, val):
541 return self._root_group.set_property(prop, val)
542 uWidget.set_property = set_property
544 def draw(self):
545 raise Exception("uWidget.draw must be overridden.")
546 # self.draw is to be overriden in subclass.
547 # The following code serves as template.
549 # Default uWidget content.
551 self._ltext = misc.GtkObjProxy(self._grp_obj.add(
552 canvas.CanvasText,
553 anchor = gtk.ANCHOR_NORTH_WEST,
554 x = 0,
555 y = 0,
556 size = self.w_.cp_.font_size * 1.0 * pango.SCALE,
557 scale = 1.0,
558 scale_set = True,
559 font = None,
560 size_set = True,
561 markup = "uW",
563 self._ltext.show()
565 # Reference size.
566 flush_events()
567 x1, y1, x2, y2 = self._ltext.get_bounds() # world units
568 self._ltext_size_1 = ((x2 - x1) * self._canvas._pixpu,
569 (y2 - y1) * self._canvas._pixpu)
571 # Current scale size.
572 self._ltext.set_property(
573 "size",
574 self.w_.cp_.font_size * self._canvas._abs_zoom * pango.SCALE)
576 # Register for zooming.
577 # # self._canvas.add_zoom_text(self)
579 # Content events.
580 self.connect("event", lambda *a: self.button_event(*a))
581 uWidget.draw = draw
584 def button_event(self, item, event):
585 if event.type == gtk.gdk.BUTTON_RELEASE:
586 if event.button == 1:
587 # # print 'uWidget button press. Override method.'
588 self._action(event)
589 return True
590 uWidget.button_event = button_event
594 #** uBlank
595 class uBlank(uWidget):
596 '''Display a 1x1 pixel. Use to experiment with layout, without
597 removing code.
599 pass
601 #** uVisibleSymbol ( element header display )
602 class uVisibleSymbol(uWidget):
603 pass
606 #** uPartiallyVisible ( element header display )
607 class uPartiallyVisible(uWidget):
608 pass
611 #** uInvisibleSymbol ( element header display )
612 class uInvisibleSymbol(uWidget):
613 pass
616 #** common drawing
617 def _draw_common_triangle(self):
619 # Triangle right.
622 # This kind of glyph design is silly; using a predefined character
623 # is far preferable.
624 cp = self.w_.cp_
625 # width 1, height 2
626 points = [0 , 0,
627 1 , 1,
628 0 , 2,
629 0 , 0,
632 # Draw triangle.
633 self._ltext = misc.GtkObjProxy(self._grp_obj.add(
634 canvas.CanvasPolygon,
635 fill_color = "black",
636 points = points,
637 width_units = 0.2,
638 cap_style = gtk.gdk.CAP_ROUND,
639 join_style = gtk.gdk.JOIN_ROUND,
642 # Draw background / padding. This will also rotate / scale.
643 pad = self.w_.cp_.symbol_padding
645 # pad = 0.0
646 # self._loutline = misc.GtkObjProxy(self._grp_obj.add(
647 # canvas.CanvasRect,
648 # x1 = - pad,
649 # y1 = - pad,
650 # x2 = 1 + pad,
651 # y2 = 2 + pad,
652 # fill_color = "white",
653 # outline_color = "white",
654 # width_pixels = self.w_.cp_.outline_width_normal,
655 # ))
656 # self._loutline.lower(1)
658 # Reposition for scaling around center.
659 ll, tt, rr, bb = canvas_item_get_bounds_world(self._grp_obj)
660 self._grp_obj.move( -(ll + rr)/2, -(tt + bb)/2 )
662 # Scale.
663 sx = sy = cp.symbol_width / (1.0 - 0.0) # width from `points`
664 self._grp_scale.affine_relative( (sx, 0.0, 0.0, sy, 0.0, 0.0) )
666 # Now add background.
667 ll, tt, rr, bb = canvas_item_get_bounds_world(self._grp_scale)
668 self._loutline = misc.GtkObjProxy(self._grp_trans.add(
669 canvas.CanvasRect,
670 x1 = ll - pad,
671 y1 = tt - pad,
672 x2 = rr + pad,
673 y2 = bb + pad,
674 fill_color = "white",
675 outline_color = "white",
676 width_pixels = self.w_.cp_.outline_width_normal,
678 self._loutline.lower(1)
680 self._ltext.show()
682 # Content events.
683 self.connect("event", lambda *a: self.button_event(*a))
684 uWidget._draw_common_triangle = _draw_common_triangle
686 def draw(self):
687 self._draw_common_triangle()
688 uInvisibleSymbol.draw = draw
690 def draw(self):
692 # Triangle down & right.
694 self._draw_common_triangle()
696 # Rotate 45 deg.
697 self._grp_scale.affine_relative( misc.affine_rotate(45) )
698 uPartiallyVisible.draw = draw
700 def draw(self):
702 # Triangle down.
704 self._draw_common_triangle()
706 # Rotate 90 deg.
707 self._grp_scale.affine_relative( misc.affine_rotate(90) )
708 uVisibleSymbol.draw = draw
711 def draw(self):
712 # Draw triangle.
713 self._ltext = misc.GtkObjProxy(self._grp_obj.add(
714 canvas.CanvasRect,
715 x1 = 0,
716 y1 = 0,
717 x2 = 0.1,
718 y2 = 0.1,
719 fill_color = "white",
720 outline_color = "white",
721 width_pixels = self.w_.cp_.outline_width_normal,
724 self._ltext.show()
725 # Content events.
726 ## self.connect("event", lambda *a: self.button_event(*a))
727 uBlank.draw = draw
731 #* l3Base
732 class l3Base(Selectable):
733 pass
735 def __init__(self):
736 self._parent = None
737 self._destroy_hook = [] # (func -> None) list
738 self._reparent_to_root_hook = [] # (func -> None) list
739 self._vis_indic = None # visibility status indicator
741 # Selection menu.
742 self._selection_popup_cb = {} # menu item -> connection args
743 self._selection_popup = gtk.Menu() # dummy
744 self._selection_popup_list = [
745 [ gtk.MenuItem("print values in context"),
746 ("activate", lambda *args: self.selection_values_in_context(args) )],
748 [ gtk.MenuItem("evaluate locally"),
749 ("activate", lambda *args: self.selection_eval_local(args))],
751 [ gtk.MenuItem("evaluate locally, use console"),
752 ("activate", lambda *args: self.eval_local_console(args))],
754 [ gtk.MenuItem("item screenshot to /tmp/foo.png"),
755 ("activate", lambda *args: self.item_screenshot("/tmp/foo.png"))],
758 l3Base.__init__ = __init__
761 #** Screenshot of selected item to file
762 def item_screenshot(self, filename):
763 print "capturing image from RIGHT canvas."
764 # todo: get item's canvas
765 # todo: remove popup menu before capture.
766 view = self.w_.canvas.view
767 selection = self.w_.selector.get_selection()
768 (sl, st, sr, sb) = selection.get_bounds()
770 # Get selection corners.
771 # These are the canvas window coordinates.
772 (wl, wt) = map(int, view.world_to_window(sl, st))
773 (wr, wb) = map(int, view.world_to_window(sr, sb))
775 # Compute selection dimensions.
776 width = wr - wl
777 height = wb - wt
779 # Prepare pixbuf.
780 pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,
781 False, # has_alpha
782 8, # bits_per_sample
783 width,
784 height)
786 # get_from_drawable(src, cmap, src_x, src_y, dest_x, dest_y, width, height)
787 status = pixbuf.get_from_drawable(
788 view.window,
789 gtk.gdk.colormap_get_system(),
790 wl, wt,
791 0, 0,
792 width, height
795 if status == None:
796 print "capture failed"
798 pixbuf.save("/tmp/foo.png", "png")
799 l3Base.item_screenshot = item_screenshot
803 #** value display from selection
804 def selection_values_in_context(self, args):
805 # args: (menuitem)
806 st = self.w_.state_.storage
807 tw = ast.TreeWork(st)
809 l3nd = self.w_.selector.get_selection_list()
811 # Self is data source.
812 cctxt = tw.get_call_ctxt(self.getid())
814 # Form the call graph pruning list.
815 l3nd.remove(self)
817 # Show pruning list.
818 print "------------------------------------------------------------------"
819 print "Showing only data created through:"
820 for nd in l3nd:
821 print nd.l3tree().source_string()
823 # Get reduced calling context.
824 pruned = tw.prune_cctxt(
825 cctxt,
826 map(l3Base.getid, l3nd)) # Remaining selection for pruning.
828 # Display values
829 def id_v_ts(leaves):
830 print "clone id, clone timestamp, value"
831 print "--------------------------------------------"
832 for (lid, val) in leaves:
833 print "%s, %s, %s" % (lid, st.ie_.get_timestamp(lid), val)
834 id_v_ts(tw.cctxt_leaves(pruned))
836 pass
837 l3Base.selection_values_in_context = selection_values_in_context
841 #** ast related
842 def contains_recursive(self, other):
843 oid = other._l3tree._id
844 for node in self._l3tree.top_down():
845 # Note: aList([]) == aList([]) is always True
846 if node._id == oid:
847 return True
848 return False
849 l3Base.contains_recursive = contains_recursive
851 def l3tree(self):
852 return self._l3tree
853 l3Base.l3tree = l3tree
855 def getid(self):
856 return self._l3tree._id
857 l3Base.getid = getid
861 #** canvas display functions
862 def dump_bbox(self):
863 print "Bounds:", self.get_bounds_world()
864 l3Base.dump_bbox = dump_bbox
866 def zoom(self, factor):
867 return (factor, factor)
868 l3Base.zoom = zoom
870 def i2w_affine(self, tuple_):
871 return self._root_group.i2w_affine(tuple_)
872 l3Base.i2w_affine = i2w_affine
874 def get_anchor(self):
875 # Use upper left.
876 x, y, u, v = self.get_bounds()
877 return x, y
878 l3Base.get_anchor = get_anchor
881 #** structural
882 def reparent(self, newp):
883 assert isinstance(newp, (l3aList, l3Base))
885 # Remove from current parent.
886 if self._parent:
887 self._parent.detach(self)
888 self._parent = None
890 # Attach to new parent.
891 self._parent = newp
892 self._root_group.reparent(newp._root_group)
893 if self._outline:
894 # Avoid repositioning mess.
895 self.plain_view()
896 self.highlight()
897 l3Base.reparent = reparent
899 def reparent_to_root(self):
900 # Graphics.
901 self._run_reparent_to_root_hook()
903 _, _, _, _, x1, y1 = self.i2w_affine(tuple(range(0,6)))
904 self._root_group.reparent(self._canvas.root())
905 _, _, _, _, nx1, ny1 = self.i2w_affine(tuple(range(0,6)))
906 self._root_group.move(x1 - nx1, y1 - ny1)
908 # State.
909 self._parent = None
910 l3Base.reparent_to_root = reparent_to_root
913 #** Selection handling
914 def plain_view(self):
915 if not self._outline:
916 return
917 destroy_if_last(self._outline)
918 self._outline = None
919 l3Base.plain_view = plain_view
921 def highlight(self):
922 if self._outline:
923 return
924 flush_events()
926 # Draw outline.
927 x1, y1, x2, y2 = self.get_bounds_world()
928 pad = self.w_.cp_.highlight_padding
929 x1 -= pad
930 y1 -= pad
931 x2 += pad
932 y2 += pad
934 ### self._outline = self._root_group.get_property("parent").add(
935 self._outline = (self._canvas.root().add(
936 canvas.CanvasLine,
937 fill_color = "orange",
938 points = [x1, y1,
939 x2, y1,
940 x2, y2,
941 x1, y2,
942 x1, y1,
944 width_units = self.w_.cp_.highlight_thickness,
945 line_style = gtk.gdk.SOLID,
946 cap_style = gtk.gdk.CAP_ROUND,
947 join_style = gtk.gdk.JOIN_ROUND,
948 smooth = True,
949 spline_steps = 12,
951 ### self._loutline.set_property("fill-color", 'beige')
952 ### self._ltext.set_property("fill-color", 'beige')
954 # Event handling.
955 self._outline.connect("event", lambda *a: self.selection_popup_event(*a))
956 self._outline.connect("event", lambda *a: self.selection_magnify_event(*a))
957 pass
958 l3Base.highlight = highlight
961 def selection_popup_event(self, widget, event):
962 if event.type == gtk.gdk.BUTTON_PRESS:
963 if event.button == 3:
964 self.selection_init_popup()
965 self._selection_popup.popup(None, None, None,
966 event.button, event.time)
967 return True
968 return False
969 l3Base.selection_popup_event = selection_popup_event
972 def selection_init_popup(self):
973 # Prepare a popup menu including the original menu items (in
974 # _selection_popup_list) plus any inserted via selection_prepend().
976 new_menu = gtk.Menu()
977 for item, conargs in self._selection_popup_list:
979 # To insert menu items in new_menu, re-use existing widgets
980 # after removing them from their old menu.
981 if item.get_parent() == self._selection_popup:
982 if self._selection_popup_cb.has_key(item):
983 # Remove old event handler.
984 item.disconnect(self._selection_popup_cb[item])
985 self._selection_popup.remove(item)
986 new_menu.append( item )
988 # Connect new event handler.
989 if conargs != None:
990 # Callback arguments are (event name, handler)
991 args = tuple(conargs)
992 self._selection_popup_cb[item] = item.connect(*args)
993 item.show()
995 if self._selection_popup:
996 self._selection_popup.destroy()
998 self._selection_popup = new_menu
999 l3Base.selection_init_popup = selection_init_popup
1001 def selection_magnify_event(self, item, event):
1002 if event.type == gtk.gdk.ENTER_NOTIFY:
1003 if self.w_.fluid_ref(trace_gui_events = False):
1004 print "selection_magnify_event"
1005 item.set_property("width_units",
1006 self.w_.cp_.highlight_thickness *
1007 self.w_.cp_.hover_magnification)
1008 return False
1010 elif event.type == gtk.gdk.LEAVE_NOTIFY:
1011 if self.w_.fluid_ref(trace_gui_events = False):
1012 print "selection_magnify_event"
1013 item.set_property("width_units",
1014 self.w_.cp_.highlight_thickness)
1015 return False
1016 l3Base.selection_magnify_event = selection_magnify_event
1018 #* l3Nested editing
1019 class l3Nested(l3Base):
1020 pass
1022 def __init__(self, w_, cnvs, l3tree, rentab):
1023 l3Base.__init__(self)
1025 # Display.
1026 self._root_group = cnvs.root().add(canvas.CanvasGroup)
1027 self._pup = CommonPopup(self)
1028 self.explicit_title = None
1030 # Rendering options.
1031 self._render_mode = rentab.get_state(l3tree)
1033 # Headerless state.
1034 self._header = None
1036 # Undecorated state.
1037 self._deco = None
1039 # Events
1040 self._root_group.connect("event", lambda *a: self.drag_event(*a))
1042 # movement state
1043 self.remember_x = None
1044 self.remember_y = None
1046 # Canvas registration. Must preceed children's construction.
1047 cnvs.register_l3tree_pic(l3tree._id, self)
1048 l3Nested.__init__ = __init__
1051 #** special display
1052 def zoom(self, factor):
1053 return l3Base.zoom(self, factor)
1054 l3Nested.zoom = zoom
1058 #* Placeholder
1059 class Placeholder(l3Nested):
1060 pass
1062 def __init__(self, w_, cnvs, tree_id, rentab):
1063 # l3 tree.
1064 l3tree = w_.state_.storage.load(tree_id)
1065 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
1067 # Bindings to keep. ### move to nested.__init__
1068 self.w_ = w_
1069 self._canvas = cnvs
1070 self._marker_points = {} # marker -> point list
1071 self._l3tree = l3tree
1073 # Display elements.
1074 # # self._blank = self.draw_blank()
1075 self._blank = uInvisibleSymbol(w_, cnvs, self._root_group,
1076 action = lambda _: self.show_subtree())
1078 # Highlighting.
1079 self._outline = None
1081 # Item cross-referencing.
1082 self._marker = None
1083 self._container = None
1085 # Borders etc.
1086 # # l3Nested.init_deco(self)
1087 self.init_header(rentab)
1088 self.init_deco(rentab)
1090 # Event handling.
1091 ## self._blank.connect("event", lambda *a: self.expand_event(*a))
1092 Placeholder.__init__ = __init__
1094 #* TextEdit
1095 class TextEdit:
1096 pass
1098 def __init__(self, w_, l3parent, text, tag_table, cnvs, refpos = None):
1100 Interface of `l3parent` must include:
1101 ed_new_text
1102 ed_restore_text
1103 finish_edit
1104 rebuild_tree
1106 get_bounds_world (if `refpos` is not given)
1107 l3parent._canvas
1110 Typical calling sequence from `other`:
1112 other.start_edit -> TextEdit() (te)
1114 te handles its own events; the two possible exits are:
1116 te.text_aborted -> other.ed_restore_text
1117 -> other.finish_edit
1119 te.text_finished -> other.rebuild_tree(new_text)
1120 -> other.ed_new_text(new_text)
1121 -> other.finish_edit()
1123 self.w_ = w_
1124 self._l3parent = l3parent
1125 self._text_orig = text
1126 self._canvas = cnvs
1127 if refpos == None:
1128 l1, t1, _, _ = l3parent.get_bounds_world()
1129 else:
1130 l1, t1 = refpos
1132 # Edit Buffer.
1133 self._edit_buff = buff = gtk.TextBuffer(table = tag_table)
1134 buff.set_text(text)
1135 buff.apply_tag(l3parent._canvas._font_size_tag, *buff.get_bounds() )
1137 buff.connect_after("insert-text",
1138 lambda *a: self.re_tag_inserted_text(*a))
1140 # Edit View.
1141 self._view = gtk.TextView(buffer = buff)
1142 self._view.connect("key-press-event", lambda *a: self.on_keypress(*a))
1144 # Scrollbars.
1145 self._view_s = gtk.ScrolledWindow()
1146 self._view_s.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1147 self._view_s.add(self._view)
1149 # Ok button.
1150 self._ok = gtk.Button(label = "Ok", stock = gtk.STOCK_OK)
1151 self._ok.connect("clicked", lambda *a: self.text_finished())
1153 # Cancel button.
1154 self._cancel = gtk.Button(label = "Cancel", stock = gtk.STOCK_CANCEL)
1155 self._cancel.connect("clicked", lambda *a: self.text_aborted())
1157 # Assembly.
1158 # Top row.
1159 self._ass_r1 = gtk.HBox()
1160 self._ass_r1.pack_start(self._view_s, expand = True)
1161 # Bottom row.
1162 self._ass_r2 = gtk.HBox()
1163 self._ass_r2.pack_start(self._ok, expand = True)
1164 self._ass_r2.pack_start(self._cancel, expand = True)
1165 # Stack them
1166 self._ass_col = gtk.VBox()
1167 self._ass_col.pack_start(self._ass_r1, expand = True)
1168 self._ass_col.pack_start(self._ass_r2, expand = False)
1170 # Pop up edit window.
1171 # Positioning is controlled by the window manager.
1172 self._window = gtk.Window()
1173 self._window.set_property("title", "edit expression")
1174 self._window.set_property("window-position", gtk.WIN_POS_MOUSE)
1175 self._window.connect("delete-event", lambda *a: self.text_aborted())
1176 self._window.set_default_size(350, 200)
1177 self._window.set_border_width(0)
1178 self._window.add(self._ass_col)
1179 main_win = cnvs.get_parent()
1180 while not isinstance(main_win, gtk.Window):
1181 main_win = main_win.get_parent()
1182 self._window.set_transient_for(main_win)
1183 self._window.show_all()
1184 TextEdit.__init__ = __init__
1186 def on_keypress(self, widget, event):
1187 # Escape.
1188 if event.keyval == key_Escape:
1189 self.text_aborted()
1190 return True
1192 # Ctrl-Return
1193 if event.state & gtk.gdk.CONTROL_MASK:
1194 if event.keyval == key_Return:
1195 self.text_finished()
1196 return True
1198 return False
1199 TextEdit.on_keypress = on_keypress
1201 def text_aborted(self):
1202 # Paired with text_start (focus event?)
1203 if self.w_.fluid_ref(trace_gui_events = False):
1204 print "\ntext_aborted"
1206 # Remove editor before adding new text.
1207 del self._edit_buff
1208 self._window.destroy()
1210 # Update text.
1211 self._l3parent.ed_restore_text()
1213 # Finish.
1214 self._l3parent.finish_edit()
1215 TextEdit.text_aborted = text_aborted
1217 def text_finished(self):
1218 # Paired with text_start (focus event?)
1219 if self.w_.fluid_ref(trace_gui_events = False):
1220 print "\ntext_finished"
1222 # Get text.
1223 buf = self._edit_buff
1224 new_text = buf.get_text(*buf.get_bounds())
1226 # Remove editor before adding new text.
1227 del self._edit_buff
1228 self._window.destroy()
1230 # Update text.
1231 self._l3parent.rebuild_tree(new_text)
1232 self._l3parent.ed_new_text(new_text)
1234 # Finish.
1235 self._l3parent.finish_edit()
1236 TextEdit.text_finished = text_finished
1238 def re_tag_inserted_text(self, buffer, iter, text, length):
1239 # Keep new text at proper size etc.
1240 iter_to = iter.copy()
1241 if not iter.backward_chars(length):
1242 return False
1244 if iter.has_tag(self._l3parent._canvas._font_size_tag):
1245 return False
1247 buffer.apply_tag(self._l3parent._canvas._font_size_tag, iter, iter_to )
1248 return False
1249 TextEdit.re_tag_inserted_text = re_tag_inserted_text
1251 #* ExtProcConfirm
1252 class ExtProcConfirm:
1254 After running an external process (which may not return a useful
1255 status), provide
1256 Success
1257 Failed
1258 options, and a
1259 text area
1260 to attach any desired log information.
1262 pass
1264 def __init__(self, w_, cnvs, answer_store, text = ""):
1265 # See also TextEdit.
1267 # answer_store::
1268 # an empty list, to be populated with the user's response,
1269 # in the form [(status, log)]
1271 self.w_ = w_
1272 self._answer_store = answer_store
1273 self._text_orig = text
1274 self._canvas = cnvs
1276 # Edit Buffer.
1277 self._edit_buff = buff = gtk.TextBuffer(table = cnvs._common_tag_table)
1278 buff.set_text(text)
1279 buff.apply_tag(self._canvas._font_size_tag, *buff.get_bounds() )
1281 buff.connect_after("insert-text",
1282 lambda *a: self.re_tag_inserted_text(*a))
1284 # Edit View.
1285 self._view = gtk.TextView(buffer = buff)
1286 self._view.connect("key-press-event", lambda *a: self.on_keypress(*a))
1287 self._view.set_size_request(w_.cp_.width,
1288 w_.cp_.height) # Minimum viewport size.
1290 # Scrollbars.
1291 self._view_s = gtk.ScrolledWindow()
1292 self._view_s.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1293 self._view_s.add(self._view)
1295 # Ok button.
1296 self._ok = gtk.Button(stock = gtk.STOCK_YES)
1297 self._ok.connect("clicked", lambda *a: self.cmd_success())
1299 # Failed button.
1300 self._failed = gtk.Button(stock = gtk.STOCK_NO)
1301 self._failed.connect("clicked", lambda *a: self.cmd_failed())
1303 # Assembly.
1304 # Top row.
1305 self._ass_r1 = gtk.HBox()
1306 self._ass_r1.pack_start(self._view_s, expand = True)
1307 # Bottom row.
1308 self._ass_r2 = gtk.HBox()
1309 self._ass_r2.pack_start(self._ok, expand = True)
1310 self._ass_r2.pack_start(self._failed, expand = True)
1311 # Stack them
1312 self._ass_col = gtk.VBox()
1313 self._ass_col.pack_start(self._ass_r1, expand = True)
1314 self._ass_col.pack_start(self._ass_r2, expand = False)
1316 # Pop up edit window.
1317 # Positioning is controlled by the window manager.
1318 self._window = gtk.Window()
1319 self._window.set_property("title", "User query")
1320 self._window.set_property("window-position", gtk.WIN_POS_MOUSE)
1321 self._window.connect("delete-event", lambda *a: self.cmd_failed())
1322 self._window.set_border_width(0)
1323 self._window.add(self._ass_col)
1324 main_win = cnvs.get_parent()
1325 while not isinstance(main_win, gtk.Window):
1326 main_win = main_win.get_parent()
1327 self._window.set_transient_for(main_win)
1328 self._window.show_all()
1329 ExtProcConfirm.__init__ = __init__
1331 def on_keypress(self, widget, event):
1332 # Escape.
1333 if event.keyval == key_Escape:
1334 self.cmd_failed()
1335 return True
1337 # Ctrl-Return
1338 if event.state & gtk.gdk.CONTROL_MASK:
1339 if event.keyval == key_Return:
1340 self.cmd_success()
1341 return True
1343 return False
1344 ExtProcConfirm.on_keypress = on_keypress
1346 def cmd_failed(self):
1347 # Remove editor before adding new text.
1348 del self._edit_buff
1349 self._window.destroy()
1351 # Finish.
1352 self._answer_store.append( (1, "") ) # (status, log)
1353 ExtProcConfirm.cmd_failed = cmd_failed
1355 def cmd_success(self):
1356 # Get text.
1357 buf = self._edit_buff
1358 new_text = buf.get_text(*buf.get_bounds())
1360 # Remove editor before adding new text.
1361 del self._edit_buff
1362 self._window.destroy()
1364 # Finish.
1365 if new_text == self._text_orig:
1366 self._answer_store.append( (0, "success") ) # (status, log)
1367 else:
1368 self._answer_store.append( (0, new_text) ) # (status, log)
1369 ExtProcConfirm.cmd_success = cmd_success
1371 def re_tag_inserted_text(self, buffer, iter, text, length):
1372 # Keep new text at proper size etc.
1373 iter_to = iter.copy()
1374 if not iter.backward_chars(length):
1375 return False
1377 if iter.has_tag(self._canvas._font_size_tag):
1378 return False
1380 buffer.apply_tag(self._canvas._font_size_tag, iter, iter_to )
1381 return False
1382 ExtProcConfirm.re_tag_inserted_text = re_tag_inserted_text
1384 #* CommonPopup
1385 class CommonPopup:
1386 # Add-on for classes supporting the standard popups.
1388 def verify_interface(self, prim_node):
1389 # An interface base class check will not verify actual presence of
1390 # needed members. This function does.
1392 # However, constructors may not construct these in time for
1393 # this check...
1394 assert prim_node._root_group
1395 assert prim_node.destroy
1396 assert prim_node._l3tree
1397 assert prim_node.w_
1398 assert prim_node.mark_as
1401 def destroy_selected(self, node):
1402 sel = node.w_.selector
1403 items = sel.get_selection_list()
1404 sel.unselect()
1405 [self.start_destroy(itm) for itm in items]
1406 CommonPopup.destroy_selected = destroy_selected
1409 def start_destroy(self, node):
1410 w_ = node.w_
1412 # Hide the tree.
1413 node._root_group.hide()
1415 # Delete in steps.
1416 def body():
1417 node.destroy()
1418 node._l3tree.delete(w_.state_.storage)
1420 w_.with_fluids(body,
1421 detach_l3_tree = False,
1422 insert_l3_tree = False,
1424 pass
1425 CommonPopup.start_destroy = start_destroy
1427 def _insert_list(self, shape = 'list'):
1428 # Setup.
1429 from l3gui.l3canvas import RenderTable
1430 storage = self._prim_node.w_.state_.storage
1431 cnvs = self._prim_node._canvas
1433 # Get the values in the current calling context (path must pass
1434 # multiple selections), ignore None values.
1435 if 1:
1436 # From selection_values_in_context
1437 tw = ast.TreeWork(storage)
1438 l3nd = self._prim_node.w_.selector.get_selection_list()
1440 # Self._prim_node is data source.
1441 cctxt = tw.get_call_ctxt(self._prim_node.getid())
1443 # Form the call graph pruning list.
1444 try: l3nd.remove(self._prim_node)
1445 except ValueError: pass
1447 # Get reduced calling context.
1448 pruned = tw.prune_cctxt(
1449 cctxt,
1450 map(l3Base.getid, l3nd))
1452 # Warn if context is not unique.
1453 # TODO.
1455 # Available info: clone id, clone timestamp, value
1456 # (cid, storage.ie_.get_timestamp(cid), val)
1457 vals = [ val
1458 for (cid, val) in tw.cctxt_leaves(pruned)
1459 if val != None]
1461 # Use values of top-level node if nothing remains.
1462 if len(vals) == 0:
1463 vals = [val
1464 for (id_, val) in self._prim_node.get_values_list()
1465 if val != None]
1467 # For a list of length M, try a sqrt(M) * sqrt(M) layout.
1468 M = len(vals)
1469 if (M > 3) and shape == 'square':
1470 cols = int(floor(sqrt(M)))
1471 vals = [tuple(vals[ii : ii + cols]) for ii in range(0, M, cols)]
1473 # Convert to l3 ast
1474 val, val_id = \
1475 ast.val2ast( vals,
1476 file_contents =
1477 self._prim_node.w_.cp_.display_file_content)\
1478 .setup(empty_parent(),
1479 ast.Env('dummy_env', None, None, storage),
1480 storage)
1481 val.set_outl_edges(self._prim_node.w_, None)
1483 # Special emphasis for this non-permanent value list.
1484 val.set_emphasis("valuelist")
1486 # Add label with source string, or id if not available.
1487 ptree = self._prim_node._l3tree
1488 desc = ptree.source_substring()
1489 if desc == 'no_source':
1490 val.set_label('Value(s) for %d' % self._prim_node._l3tree._id )
1491 else:
1492 val.set_label('Value(s) for %s' % desc )
1494 # Retain source node id for later.
1495 val.setthe(value_source_tree_id =
1496 [v.l3tree()._id for v in l3nd + [self._prim_node]])
1498 # Display the structure.
1499 pic = cnvs.add_l3tree(val, RenderTable())
1501 # Position to the right of expression.
1502 lp, tp, rp, bp = pic.get_bounds_world()
1503 lo, to, ro, bo = self._prim_node.get_bounds_world()
1504 pic.move(ro - lp, to - tp)
1505 CommonPopup._insert_list = _insert_list
1508 def __init__(self, prim_node):
1509 self._prim_node = prim_node
1510 self._widget_cb = {}
1511 self._widget = gtk.Menu() # dummy
1513 self._popup_list = [
1515 [ gtk.MenuItem("add comment"),
1516 ("activate", lambda *args: prim_node.deco_add_comment() )],
1518 [ gtk.MenuItem("copy to clipboard (as raw text)"),
1519 ("activate", lambda *args: prim_node.w_.selector.copy_selection())],
1521 [ gtk.MenuItem("delete"),
1522 ("activate", lambda *args: self.start_destroy(prim_node))],
1524 [ gtk.MenuItem("delete selected"),
1525 ("activate", lambda *args: self.destroy_selected(prim_node))],
1527 [ gtk.MenuItem("dump code"),
1528 ("activate",
1529 lambda *args: view.print_info(prim_node.w_.state_.storage,
1530 prim_node._l3tree))],
1531 [ gtk.MenuItem("dump values"),
1532 ("activate",
1533 lambda *args: prim_node.dump_values() ) ],
1535 [ gtk.MenuItem("export values as string"),
1536 ("activate",
1537 lambda *args: prim_node.string_export() ) ],
1539 # # [ gtk.MenuItem("dump [values list]"),
1540 # # ("activate",
1541 # # lambda *args: pprint(prim_node.get_values_list()))],
1543 # # [ gtk.MenuItem("dump (values list) as l3 AST"),
1544 # # ("activate",
1545 # # lambda *args: pprint(ast.val2ast(prim_node.get_values_list())) )],
1547 [ gtk.MenuItem("insert values as l3 list"),
1548 ("activate", lambda *args: self._insert_list() )],
1550 [ gtk.MenuItem("insert values as l3 list list "),
1551 ("activate", lambda *args: self._insert_list(shape = 'square') )],
1553 [ gtk.MenuItem("evaluate locally"),
1554 ("activate", lambda *args: prim_node.eval_local(args))],
1556 [ gtk.MenuItem("evaluate locally, use console"),
1557 ("activate", lambda *args: prim_node.eval_local_console(args))],
1559 [ gtk.MenuItem("exit"),
1560 ("activate", lambda *args : gtk.main_quit() )],
1562 [ gtk.MenuItem("hide"),
1563 ("activate", lambda *args: prim_node.hide_subtree() )],
1565 [ gtk.MenuItem("select value"),
1566 ("activate",
1567 lambda *args: DataSelPopup(prim_node.w_, prim_node._l3tree))],
1570 # Pop up when l3 node is pressed.
1571 prim_node._root_group.connect("event", lambda *a: self.popup_event(*a))
1572 CommonPopup.__init__ = __init__
1575 #** pop-up base menu
1576 def init_popup(self):
1577 # Start new Menu.
1578 new_menu = gtk.Menu()
1580 # Tear-off item.
1581 mi = gtk.TearoffMenuItem()
1582 new_menu.append(mi)
1583 mi.show()
1585 # Run pre_popup_hook, if any.
1586 getattr(self._prim_node, "pre_popup_hook", lambda : None)()
1588 # Populate the Menu.
1589 for mi, conargs in self._popup_list:
1590 # Insert in new menu, re-using existing widgets.
1591 if mi.get_parent() == self._widget:
1592 if self._widget_cb.has_key(mi):
1593 mi.disconnect(self._widget_cb[mi]) # remove old event handler
1594 self._widget.remove(mi)
1595 new_menu.append( mi )
1596 # Connect new event handler.
1597 if conargs != None:
1598 self._widget_cb[mi] = mi.connect(*conargs)
1599 mi.show()
1601 if self._widget:
1602 self._widget.destroy()
1604 self._widget = new_menu
1605 CommonPopup.init_popup = init_popup
1607 def popup_event(self, widget, event):
1608 # Pop up on button-3 press.
1609 if event.type == gtk.gdk.BUTTON_PRESS:
1610 if event.button == 3:
1611 self.init_popup()
1612 self._widget.popup(None, None, None,
1613 event.button, event.time)
1614 return True
1615 return False
1616 CommonPopup.popup_event = popup_event
1619 #** menu additions
1620 def prepend(self, item_init):
1621 # Menu additions can be made at any time.
1623 # item_init has form
1624 # [ gtk.MenuItem("dump code"),
1625 # ("activate",
1626 # lambda *args: view.print_info(prim_node.w_.state_.storage,
1627 # prim_node._l3tree))]
1628 # or
1629 # [gtk.SeparatorMenuItem(), None]
1631 self._popup_list.insert(0, item_init)
1632 CommonPopup.prepend = prepend
1634 #* DataSelPopup
1635 class DataSelPopup:
1636 pass
1639 def __init__(self, w_, l3tree):
1640 self.w_ = w_
1641 self._l3tree = l3tree
1642 self._widget_cb = {}
1643 self._widget = gtk.Menu() # dummy
1645 self.init_popup()
1647 self._widget.popup(None, None, None, 1, 1)
1648 ## event.button, event.time)
1649 DataSelPopup.__init__ = __init__
1652 def traverse_values_list(self):
1653 # Produce a (menuitem, function) list for datum selection.
1654 st = self.w_.state_.storage
1655 c_id = self._l3tree._id
1657 # Dynamic id(s).
1658 clone_l = st.get_attribute(c_id, "interp_clone")
1659 if clone_l:
1660 G.logger.info("%d has %d clones.\nValues:" % (c_id, len(clone_l)))
1661 # todo: this should recurse?
1662 for id in clone_l:
1663 # todo: use loop (var, value) pairs, not just id
1664 yield [ gtk.MenuItem("clone %d" % id),
1665 ("activate",
1666 lambda *args: DataSelPopup(self.w_, st.load(id)))]
1667 else:
1668 # Toplevel or final id.
1669 yield [ gtk.MenuItem("value operations"),
1670 ("activate",
1671 # todo: ValueOperPopup
1672 lambda *args: DataSelPopup(self.w_, self._l3tree))]
1673 DataSelPopup.traverse_values_list = traverse_values_list
1676 def init_popup(self):
1677 # Start new Menu.
1678 new_menu = gtk.Menu()
1680 # Tear-off item.
1681 mi = gtk.TearoffMenuItem()
1682 new_menu.append(mi)
1683 mi.show()
1685 # Populate the Menu.
1686 for mi, conargs in self.traverse_values_list():
1687 # Insert in new menu, re-using existing widgets.
1688 if mi.get_parent() == self._widget:
1689 if self._widget_cb.has_key(mi):
1690 mi.disconnect(self._widget_cb[mi]) # remove old event handler
1691 self._widget.remove(mi)
1692 new_menu.append( mi )
1693 # Connect new event handler.
1694 if conargs != None:
1695 self._widget_cb[mi] = mi.connect(*conargs)
1696 mi.show()
1697 # Remove duplicate popups.
1698 if self._widget:
1699 self._widget.destroy()
1701 self._widget = new_menu
1702 DataSelPopup.init_popup = init_popup
1706 #* l3Loop
1707 # This construct is a MACRO using other l3 constructs.
1708 # Current restrictions:
1709 # - no editing of the loop name
1710 # a. requires synchronized replacements
1711 # b. but then, no customizable loop template is possible
1712 # c. so custom editing support is required
1714 class l3Loop(l3Nested):
1715 pass
1717 def __init__(self, w_, cnvs, tree_id, rentab):
1718 # layout:
1719 # loop CALL from FROMARGS
1720 # BODY
1722 # l3 tree.
1723 l3tree = w_.state_.storage.load(tree_id)
1724 assert isinstance(l3tree, ast.Loop)
1725 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
1727 # Bindings to keep.
1728 self.w_ = w_
1729 self._canvas = cnvs
1730 self._l3tree = l3tree
1732 # Highlighting.
1733 self._outline = None
1735 # Item cross-referencing.
1736 self._marker = None
1737 self._container = None
1739 # # self._marker_points = {} # marker -> point list
1742 # Create display elements.
1744 # loop
1745 d_loop = Label(w_, cnvs, self._root_group, "loop")
1747 # CALL
1749 ### Editing this tree requires updates to two other trees and is
1750 ### deferred for now.
1751 d_call = cnvs.add_l3tree(l3tree.l_view_call, rentab)
1752 d_call.reparent(self)
1754 # from
1755 d_from = Label(w_, cnvs, self._root_group, "from")
1757 # FROMARGS
1758 d_from_args = l3aList(w_, cnvs,
1759 l3tree.l_from_args[0],
1760 rentab,
1761 root_group = self._root_group,
1762 draggable = False,
1763 parent = self,
1766 # BODY
1767 d_body = l3aList(w_, cnvs,
1768 l3tree.l_body[0],
1769 rentab,
1770 root_group = self._root_group,
1771 draggable = False,
1772 parent = self,
1775 # Marker(s).
1776 # Only editing of the macro leaves makes sense. This implies
1777 # that the macro itself cannot be edited, greatly simplifying
1778 # the code.
1780 # Inform obj of marker.
1781 d_call.setup_marker(None, self) ### need marker substitute.
1783 # Bindings to keep.
1784 # Indexed access. Match l3tree indexing where applicable.
1785 self._d_elements = [
1786 # l3 ast.
1787 d_call,
1788 d_from_args,
1789 d_body,
1791 # Rest
1792 d_loop,
1793 d_from,
1795 self._update_refs()
1798 # Align display elements, starting from d_loop.
1800 self._align_display()
1802 # Event handling.
1804 # Borders etc.
1805 self.init_header(rentab)
1806 self.init_deco(rentab)
1808 pass
1809 l3Loop.__init__ = __init__
1811 def _update_refs(self):
1812 (self._d_call,
1813 self._d_from_args ,
1814 self._d_body ,
1816 self._d_loop ,
1817 self._d_from,
1818 ) = self._d_elements
1819 l3Loop._update_refs = _update_refs
1821 def _align_display(self):
1823 # Align display elements, starting from d_loop.
1825 flush_events()
1827 [d_call,
1828 d_from_args,
1829 d_body,
1831 d_loop,
1832 d_from,
1833 ] = self._d_elements
1834 # d_call
1835 l1, t1, r1, b1 = d_loop.get_bounds()
1836 l2, t2, r2, b2 = d_call.get_bounds()
1837 d_call.move(r1 - l2, t1 - t2)
1839 # d_from
1840 l1, t1, r1, b1 = d_call.get_bounds()
1841 l2, t2, r2, b2 = d_from.get_bounds()
1842 d_from.move(r1 - l2, t1 - t2)
1844 # d_from_args
1845 l1, t1, r1, b1 = d_from.get_bounds()
1846 l2, t2, r2, b2 = d_from_args.get_bounds()
1847 d_from_args.move(l1 - l2, b1 - t2)
1849 # d_body
1850 l1, t1, r1, b1 = d_call.get_bounds()
1851 l2, t2, r2, b2 = d_from_args.get_bounds()
1852 l3, t3, r3, b3 = d_body.get_bounds()
1853 # Should really use the lowest bound of (loop CALL from FROMARGS)...
1854 d_body.move(l1 - l3, max(b1, b2) - t3)
1855 pass
1856 l3Loop._align_display = _align_display
1859 def new_size_for(self, child):
1860 self._align_display()
1862 # Refresh decoration.
1863 self.refresh_deco()
1865 # Propagate.
1866 if self._parent:
1867 self._parent.new_size_for(self)
1868 return
1869 l3Loop.new_size_for = new_size_for
1871 def destroy(self):
1872 l3Nested.destroy(self)
1874 _safed(self._d_loop)
1875 _safed(self._d_from)
1876 _safed(self._d_call)
1877 _safed(self._d_from_args)
1878 _safed(self._d_body)
1879 ### self._l3tree.delete(self.w_.state_.storage)
1880 l3Nested.destroy_deco(self)
1881 l3Loop.destroy = destroy
1884 #* marker / label pair
1885 # Labels are the second type loosely connected to markers (display
1886 # items being the other). As for the marker/display connection,
1887 # separate lists are used to keep each, instead of one list holding
1888 # tuples.
1890 # Markers and Labels may move independently -- so they are not in a
1891 # canvasgroup.
1893 # class MarkerLabel:
1894 # __slots__ = ['marker', 'label']
1896 #* l3aList
1897 class l3aList(Selectable):
1898 ''' An l3aList is the actual display of aList content. All
1899 entries are stacked vertically.
1901 Every entry may be removed by dragging it out of the list.
1903 New entries are added by pasting (mouse-2) on an item separator.
1905 pass
1908 def l3tree(self):
1909 return self._l3tree
1910 l3aList.l3tree = l3tree
1913 #** init
1914 def __init__(self, w_, cnvs, l3tree, rentab,
1915 root_group = None,
1916 draggable = True,
1917 parent = None,
1918 insertion_on_markers = True,
1919 hide_markers = False,
1921 assert isinstance(l3tree, ast.aList)
1922 self._insertion_on_markers = insertion_on_markers
1923 self._hide_markers = hide_markers
1924 self._parent = parent
1925 self._canvas = cnvs
1926 self.w_ = w_
1927 self._l3tree = l3tree
1928 self._destroy_hook = [] # (func -> None) list
1929 self._reparent_to_root_hook = [] # (func -> None) list
1930 self._dlist = [] # child element list
1931 self._marker_lst = [] # (marker list)
1932 self._mark_ = 0 # (int) current mark position
1934 # Set up graphical base.
1935 if root_group:
1936 self._root_group = (root_group.add(canvas.CanvasGroup))
1937 else:
1938 self._root_group = (cnvs.root().add(canvas.CanvasGroup))
1940 if draggable:
1941 self._root_group.connect("event", lambda *a: self.drag_event(*a))
1943 # Canvas registration. Must preceed children's construction.
1944 cnvs.register_l3tree_pic(self._l3tree._id, self)
1946 # Set up nested elements.
1947 # The marker entry preceeds the list entry.
1948 self._dlist = [cnvs.add_l3tree(child, rentab) for child in l3tree.entries()]
1949 for itm in self._dlist:
1950 itm.reparent(self)
1952 if hide_markers:
1953 self._marker_lst = [ self.draw_marker(0, 0, hidden_color = 'white')]+\
1954 [ self.draw_marker(0, 0, hidden_color = 'white')
1955 for _ in l3tree.entries()]
1956 else:
1957 self._marker_lst = [ self.draw_marker(0, 0)]+\
1958 [ self.draw_marker(0, 0) for _ in l3tree.entries()]
1960 # Insert leader on left to force proper bounding box of self in parent.
1961 self._leader = self._root_group.add(
1962 canvas.CanvasLine,
1963 fill_color = 'white',
1964 first_arrowhead = 0,
1965 last_arrowhead = 0,
1966 width_pixels = 1,
1967 points = [ 0,0, self.w_.cp_.label_indent,0 ],
1970 # Position elements for bounding box correctness. See also .insert().
1971 flush_events()
1972 vpad = w_.cp_.marker_padding
1973 if self._l3tree.getthe('layout') == 'horizontal':
1974 self._adj_h(self.w_.cp_.label_indent, 0, self._marker_lst, self._dlist)
1975 else:
1976 self._adj_v(self.w_.cp_.label_indent, 0, self._marker_lst, self._dlist)
1978 # Marker menu.
1979 self._marker_widget_cb = {} # menu item -> connection args
1980 self._marker_widget = gtk.Menu() # dummy
1981 self._marker_popup_list = ([
1982 # args are (menuitem, marker index) (for now)
1983 [ gtk.MenuItem("evaluate locally"),
1984 ("activate", lambda *args: self.marker_eval_local(args))],
1986 [ gtk.MenuItem("set mark"),
1987 ("activate", lambda *args: self.marker_set_mark(*args))],
1989 [ gtk.MenuItem("select region (from here to mark)"),
1990 ("activate", lambda *args: self.marker_select_region(*args))],
1994 # Insert spacer under last marker to force proper bounding box of
1995 # self in parent.
1996 self._spacer_bottom = self._root_group.add(
1997 canvas.CanvasLine,
1998 fill_color = 'white',
1999 first_arrowhead = 0,
2000 last_arrowhead = 0,
2001 width_pixels = 1,
2002 points = [ 0, 0, self.w_.cp_.marker_width, 0],
2004 self._mv_spacer()
2006 # Event handling.
2007 if insertion_on_markers:
2008 for marker in self._marker_lst:
2009 self.bind_marker_events(marker)
2010 l3aList.__init__ = __init__
2012 def _mv_spacer(self):
2013 flush_events()
2014 spcr = self._spacer_bottom
2015 spcr.lower_to_bottom()
2016 lm, tm, rm, bm = marker_get_bounds(self.w_, self._marker_lst[-1]).pad_tb()
2017 ls, ts, rs, bs = spcr.get_bounds()
2018 spcr.move(lm - ls, bm - ts)
2019 l3aList._mv_spacer = _mv_spacer
2021 def _adj_v(self, ax, ay, newmarker, newobj):
2022 # Position child elements for vertical list.
2024 # Move marker.
2025 newmarker[0].move(ax, ay)
2027 if newobj:
2028 # Inform obj of marker
2029 newobj[0].setup_marker(newmarker[0], self)
2031 # Move object.
2032 ml, _, _, mb = marker_get_bounds(self.w_, newmarker[0]).pad_tb()
2033 ol, ot, _, ob = newobj[0].get_bounds()
2034 newobj[0].move(ml - ol, mb - ot)
2036 # Move following markers and objects
2037 self._adj_v(ml,
2038 mb + (ob - ot), # + vpad,
2039 newmarker[1:], newobj[1:])
2040 l3aList._adj_v = _adj_v
2043 def _adj_h(self, ax, ay, newmarker, newobj):
2044 # Position child elements for horizontal list.
2046 # Move marker.
2047 newmarker[0].move(ax, ay)
2049 if newobj:
2050 # Inform obj of marker
2051 newobj[0].setup_marker(newmarker[0], self)
2053 # Move object.
2054 ml, mt, mr, mb = marker_get_bounds(self.w_, newmarker[0]).pad_lr()
2055 ol, ot, or_, ob = newobj[0].get_bounds()
2056 newobj[0].move(mr - ol, mt - ot)
2058 # Move following markers and objects
2059 self._adj_h(mr + (or_ - ol), # + hpad,
2061 newmarker[1:], newobj[1:])
2062 l3aList._adj_h = _adj_h
2065 #** TextEdit interface
2066 def rebuild_tree(self, text):
2067 pass
2068 l3aList.rebuild_tree = rebuild_tree
2071 #** marker event handlers
2073 def marker_set_mark(self, menuitem, index):
2074 self._mark_ = index
2075 l3aList.marker_set_mark = marker_set_mark
2077 def marker_select_region(self, menuitem, index):
2078 self.verify_mark()
2079 # Order range.
2080 if index <= self._mark_:
2081 first, last = index, self._mark_
2082 else:
2083 first, last = self._mark_, index
2084 # Add items to selection.
2085 add = self.w_.selector.toggle_selection
2086 for ii in range(first, last):
2087 add(self._dlist[ii])
2088 l3aList.marker_select_region = marker_select_region
2090 def verify_mark(self):
2091 'Ensure the mark is a valid index.'
2092 mx = len(self._dlist)
2093 if self._mark_ > mx: self._mark_ = mx
2094 if self._mark_ < 0: self._mark_ = 0
2095 l3aList.verify_mark = verify_mark
2098 def bind_marker_events(self, marker):
2099 marker.connect("event", lambda *a: self.marker_handle_event(*a))
2100 l3aList.bind_marker_events = bind_marker_events
2102 def marker_handle_event(self, item, event):
2104 # Destroy item key sequence.
2106 if event.type == gtk.gdk._2BUTTON_PRESS:
2107 if event.button == 3:
2108 ### The whole list, all entries, or a single entry.
2109 pass
2110 return True
2112 if event.type == gtk.gdk.BUTTON_PRESS:
2114 # Range selection.
2116 if event.button == 1:
2117 if event.state & gtk.gdk.SHIFT_MASK:
2118 # shift-button-1: select range
2119 self.marker_select_region(None, self._marker_lst.index(item))
2120 return True
2122 else:
2123 # button-1: Start selection
2124 self.marker_set_mark(None, self._marker_lst.index(item))
2125 return True
2127 # Item insertion.
2129 if event.button == 2:
2130 if self.w_.fluid_ref(trace_gui_events = False):
2131 print "insert_event"
2132 if not self.w_.selector.have_selection():
2133 self.w_.ten_second_message("No node selected.")
2134 return True
2135 else:
2136 # Insert all selected nodes, retaining selection order.
2137 offset = self._marker_lst.index(item)
2138 for (index, node) in enumerate(self.w_.selector.
2139 get_selection_list()):
2140 self.insert(offset + index, node)
2141 return True
2143 # Marker popup menu.
2145 if event.button == 3:
2146 self.marker_init_popup(self._marker_lst.index(item))
2147 self._marker_widget.popup(None, None, None,
2148 event.button, event.time)
2149 return True
2151 # Marker magnification.
2153 if event.type == gtk.gdk.ENTER_NOTIFY:
2154 item.set_property("width_units",
2155 self.w_.cp_.marker_thickness *
2156 self.w_.cp_.hover_magnification)
2157 return True
2159 if event.type == gtk.gdk.LEAVE_NOTIFY:
2160 # canvas quirk: A button click on the enlarged marker
2161 # qualifies as LEAVE_NOTIFY only...
2162 gobject.timeout_add(
2163 100, lambda : item.set_property("width_units",
2164 self.w_.cp_.marker_thickness) )
2165 return True
2166 return False
2167 l3aList.marker_handle_event = marker_handle_event
2170 def marker_prepend(self, item_init):
2171 # Menu additions can be made at any time.
2173 # item_init has form
2174 # [ gtk.MenuItem("dump code"),
2175 # ("activate",
2176 # lambda *args: view.print_info(prim_node.w_.state_.storage,
2177 # prim_node._l3tree))]
2178 # or
2179 # [gtk.SeparatorMenuItem(), None]
2181 self._marker_popup_list.insert(0, item_init)
2182 l3aList.marker_prepend = marker_prepend
2184 def marker_init_popup(self, marker_idx):
2185 # Prepare a popup menu including the original menu items (in
2186 # _marker_popup_list) plus any inserted via marker_prepend().
2188 # The marker index is passed to the popup's handler.
2189 new_menu = gtk.Menu()
2190 for item, conargs in self._marker_popup_list:
2191 # Insert menu items in new menu, re-using existing widgets.
2192 if item.get_parent() == self._marker_widget:
2193 if self._marker_widget_cb.has_key(item):
2194 # remove old event handler
2195 item.disconnect(self._marker_widget_cb[item])
2196 self._marker_widget.remove(item)
2197 new_menu.append( item )
2198 # Connect new event handler.
2199 if conargs != None:
2200 # (event name, handler, marker_idx)
2201 args = tuple(list(conargs) + [marker_idx])
2202 self._marker_widget_cb[item] = item.connect(*args)
2203 item.show()
2205 if self._marker_widget:
2206 self._marker_widget.destroy()
2208 self._marker_widget = new_menu
2209 l3aList.marker_init_popup = marker_init_popup
2212 #** marker functions
2213 # # l3alist local marker tests
2214 # from widgets import marker_get_bounds, marker_get_anchor
2215 # ma = self.draw_marker(2,3)
2216 # print marker_get_bounds(self.w_, ma)
2217 # print marker_get_anchor(self.w_, ma)
2219 def draw_marker(self, ulx, uly, hidden_color = None):
2220 def _hline():
2221 # Horizontal line (Canvas object).
2222 cp = self.w_.cp_
2223 vpad = self.w_.cp_.marker_padding
2224 _marker = self._root_group.add(
2225 canvas.CanvasLine,
2226 fill_color = hidden_color or cp.marker_color,
2227 points = [ulx,
2228 uly + vpad,
2229 ulx + cp.marker_width,
2230 uly + cp.marker_height + vpad,
2232 width_units = cp.marker_thickness,
2233 line_style = gtk.gdk.SOLID,
2234 cap_style = gtk.gdk.CAP_ROUND,
2235 join_style = gtk.gdk.JOIN_ROUND,
2236 smooth = False,
2237 spline_steps = 12,
2239 return _marker
2240 def _vline():
2241 # Vertical line (Canvas object).
2242 cp = self.w_.cp_
2243 hpad = self.w_.cp_.marker_padding
2244 _marker = self._root_group.add(
2245 canvas.CanvasLine,
2246 fill_color = hidden_color or cp.marker_color,
2247 points = [ulx + hpad,
2248 uly,
2249 ulx + cp.tuple_marker_width + hpad,
2250 uly + cp.tuple_marker_height,
2252 width_units = cp.marker_thickness,
2253 line_style = gtk.gdk.SOLID,
2254 cap_style = gtk.gdk.CAP_ROUND,
2255 join_style = gtk.gdk.JOIN_ROUND,
2256 smooth = False,
2257 spline_steps = 12,
2259 return _marker
2260 return { None : _hline,
2261 'vertical': _hline,
2262 'horizontal': _vline,
2263 }[self._l3tree.getthe('layout')]()
2264 l3aList.draw_marker = draw_marker
2267 def i2w_affine(self, tuple_):
2268 return self._root_group.i2w_affine(tuple_)
2269 l3aList.i2w_affine = i2w_affine
2271 def reparent_to_root(self):
2272 # Graphics.
2273 self._run_reparent_to_root_hook()
2275 _, _, _, _, x1, y1 = self.i2w_affine(tuple(range(0,6)))
2276 self._root_group.reparent(self._canvas.root())
2277 _, _, _, _, nx1, ny1 = self.i2w_affine(tuple(range(0,6)))
2278 self._root_group.move(x1 - nx1, y1 - ny1)
2280 # State.
2281 self._parent = None
2282 l3aList.reparent_to_root = reparent_to_root
2285 #* generic marker functions
2286 def marker_get_properties(marker):
2287 # Collect opaque info for marker_to_head/plain
2288 return marker.get_property("points")
2290 def marker_get_anchor(w_, marker):
2291 x, y, u, v = marker.get_bounds()
2292 ### magic offset values...
2293 try:
2294 wid = marker.get_property("width_units") # get CURRENT setting
2295 except TypeError:
2296 wid = 0
2297 return (x + wid, y + wid)
2299 class mBounds(tuple):
2300 def set(self, **kw):
2301 self.__dict__.update(kw)
2302 return self
2304 def pad_tb(self):
2305 # Pad (marker) bounds on top/bottom.
2306 x, y, u, v = self
2307 vpad = self.w_.cp_.marker_padding
2308 return mBounds((x , y - vpad,
2309 u , v + vpad)).set(w_ = self.w_)
2310 mBounds.pad_tb = pad_tb
2312 def pad_lr(self):
2313 # Pad (marker) bounds on left / right.
2314 x, y, u, v = self
2315 vpad = self.w_.cp_.marker_padding
2316 return mBounds((x - vpad, y, u + vpad, v)).set(w_ = self.w_)
2317 mBounds.pad_lr = pad_lr
2319 ## mBounds((1,2, 3,4)).set(w_ = w_)
2320 ## mBounds((1,2, 3,4)).set(w_ = w_).pad_lr()
2322 def marker_get_bounds(w_, marker):
2323 x, y, u, v = marker.get_bounds()
2324 ### magic offset values...
2325 try:
2326 wid = marker.get_property("width_units") # get CURRENT setting
2327 except TypeError:
2328 wid = 0
2329 return mBounds((x + wid, y + wid, u - wid, v - wid)).set(w_ = w_)
2331 def marker_pad_tb(w_, bounds):
2332 # Pad (marker) bounds on top/bottom.
2333 x, y, u, v = bounds
2334 vpad = w_.cp_.marker_padding
2335 return (x , y - vpad, u , v + vpad)
2337 def marker_pad_lr(w_, bounds):
2338 # Pad (marker) bounds on left / right.
2339 x, y, u, v = bounds
2340 vpad = w_.cp_.marker_padding
2341 return (x - vpad, y, u + vpad, v)
2344 #* l3Rawtext
2345 #** init & misc.
2346 class l3Rawtext(l3Base):
2347 pass
2349 def text_and_outline(self):
2351 # Text content / format / scale
2353 ## rendering speed up
2354 if 0:
2355 self._root_group.move(+1000,0)
2356 if isinstance(self, l3Comment):
2357 # Allow pango text markup for comments.
2358 self._ltext = misc.GtkObjProxy(self._root_group.add(
2359 canvas.CanvasText,
2360 anchor = gtk.ANCHOR_NORTH_WEST,
2361 x = 0,
2362 y = 0,
2363 size = self._font_size,
2364 scale = 1.0,
2365 scale_set = True,
2366 ## font = self._font_desc,
2367 size_set = True,
2368 markup = "\n".join(view.leading_lines(self._text_orig,
2369 num_lines=10)),
2371 else:
2372 self._ltext = misc.GtkObjProxy(self._root_group.add(
2373 canvas.CanvasText,
2374 anchor = gtk.ANCHOR_NORTH_WEST,
2375 x = 0,
2376 y = 0,
2377 size = self._font_size,
2378 scale = 1.0,
2379 scale_set = True,
2380 font = self._font_desc,
2381 size_set = True,
2382 text = "\n".join(view.leading_lines(self._text_orig, num_lines=10)),
2384 # .destroy order checks.
2385 self._under_destruction = False
2386 def _check_destroy_order(widget):
2387 if not self._under_destruction:
2388 # An exception here will not give a useful
2389 # traceback. (event handling interferes?)
2390 print (".destroy from external source.")
2391 import pdb; pdb.set_trace()
2392 self._ltext.connect("destroy", _check_destroy_order)
2394 if self._new_text_props != None:
2395 _set_props(self._ltext, self._new_text_props)
2396 self._new_text_props = None
2398 self._ltext.show()
2399 flush_events()
2400 x1, y1, x2, y2 = self._ltext.get_bounds() # world units
2401 # Reference size.
2402 self._ltext_size_1 = ((x2 - x1) * self._canvas._pixpu,
2403 (y2 - y1) * self._canvas._pixpu)
2405 # Current scale size.
2406 self._ltext.set_property(
2407 "size",
2408 self.w_.cp_.font_size * self._canvas._abs_zoom * pango.SCALE)
2410 # Text events.
2411 self._ltext.connect("event", lambda *a: self.destroy_event(*a))
2412 self._ltext.connect("event", lambda *a: self.start_edit(*a))
2413 self._ltext.connect("event", lambda *a: self.drag_event(*a))
2415 # Text outline.
2416 # The CanvasText has TRANSPARENT background; here, it
2417 # needs to be opaque.
2418 x1, y1, x2, y2 = self._ltext.get_bounds() # world units
2419 pad = self.w_.cp_.textview.outline_padding / self._canvas._pixpu
2420 x1 -= pad
2421 y1 -= pad
2422 x2 += pad
2423 y2 += pad
2425 self._loutline = self._root_group.add(
2426 canvas.CanvasRect,
2427 x1 = x1, y1 = y1,
2428 x2 = x2, y2 = y2,
2429 fill_color = self._fill_color,
2430 outline_color = self._outline_color, ### black
2431 width_pixels = self.w_.cp_.outline_width_normal,
2434 self._loutline.lower(1)
2435 self._loutline.show()
2437 # Outline events.
2438 self._loutline.connect("event", lambda *a: self.drag_event(*a))
2440 # Ensure correct sizing.
2441 # # flush_events()
2442 # # self._root_group.move(-1000,0)
2443 ## rendering speed up
2444 if 0:
2445 self._root_group.move(-1000,0)
2446 flush_events()
2448 def __init__(self, w_, cnvs, tree_id, rentab, render_only = []):
2449 l3Base.__init__(self)
2450 self._canvas = cnvs
2451 self.w_ = w_
2453 # Parameters
2454 self.init_params()
2456 # l3 tree.
2457 l3tree = w_.state_.storage.load(tree_id)
2458 assert isinstance(l3tree, (ast.astType, ast.aNone, ast.aList)), \
2459 ("Cannot display %s" % l3tree)
2460 if isinstance(l3tree, (ast.aNone, ast.aList)):
2461 warn_("displaying internal types as text; "
2462 "expect clobbered display for:")
2463 warn_(l3tree.get_infix_string(40))
2465 self._text_orig = l3tree.l3_repr_dedented()
2466 self._l3tree = l3tree
2467 self._subtrees = [] # l3Base nodes.
2469 # Rendering options.
2470 self._render_mode = rentab.get_state(l3tree)
2472 # Item cross-referencing.
2473 self._marker = None
2474 self._container = None
2476 # Headerless state.
2477 self._header = None
2479 # Undecorated state.
2480 self._deco = None
2482 # Text edit state.
2483 self._new_text_props = None
2485 # Focus redirection.
2486 self._focus_dummy = cnvs.root().add(canvas.CanvasItem)
2487 self._focus_dummy.hide()
2488 self._focus_dummy.grab_focus()
2490 # Display Group
2491 self._root_group = cnvs.root().add(canvas.CanvasGroup)
2492 self._pup = CommonPopup(self)
2493 self._editor = None
2495 # Canvas registration. Must preceed children's construction.
2496 cnvs.register_l3tree_pic(l3tree._id, self)
2498 # Display self.
2499 text_and_outline(self)
2502 # Display subtrees.
2503 (row_par, col_par), _ = l3tree.get_char_range()
2504 l_par, t_par, r_par, b_par = self._ltext.get_bounds()
2505 _, _, unit_y = self._canvas.font_wh()
2506 if render_only:
2507 do_subtrees = render_only
2508 else:
2509 do_subtrees = l3tree.subtrees1()
2511 for sub in do_subtrees:
2512 # # print "Now:", sub
2513 # Display elements.
2514 disp_ch = cnvs.add_l3tree(sub, rentab, force_text = True)
2515 disp_ch.reparent(self)
2516 l_ch, t_ch, r_ch, b_ch = disp_ch._ltext.get_bounds()
2518 # Align.
2519 # Get row, column offset.
2520 (row_ch, col_ch), _ = sub.get_char_range()
2522 # Move into character position.
2523 disp_ch.move((l_par - l_ch) + (col_ch - col_par),
2524 ((t_par - t_ch) + (row_ch - row_par)) * unit_y)
2526 # Track for later.
2527 self._subtrees.append(disp_ch)
2529 # Highlight outline.
2530 self._outline = None
2532 # Register for zooming.
2533 cnvs.add_zoom_text(self)
2535 # Borders etc.
2536 self.init_header(rentab)
2537 self.init_deco(rentab)
2538 self._root_group.show()
2540 # movement state
2541 self.remember_x = None
2542 self.remember_y = None
2544 pass
2545 l3Rawtext.__init__ = __init__
2548 def pre_popup_hook(self):
2549 ''' Conditional popup menu additions.
2550 Additions for
2551 1. Possible file names
2552 2. Known Filepaths
2554 # 2. Known Filepaths
2555 import l3lang.external.xmipp_wrap as xm
2556 from l3gui.l3canvas import RenderTable
2557 def _display_img(fname):
2558 storage = self.w_.state_.storage
2559 tree, tid = ast.Native(fname).setup(
2560 empty_parent(),
2561 ast.Env('dummy_env', None, None, storage),
2562 storage)
2563 tree.set_outl_edges(self.w_, None)
2565 pic = self._canvas.add_l3tree(tree, RenderTable())
2566 lp, tp, rp, bp = pic.get_bounds_world()
2567 lo, to, ro, bo = self.get_bounds_world()
2568 pic.move(ro - lp, to - tp)
2570 if (isinstance(self._l3tree, (ast.String)) and
2571 self._l3tree.isfile() and
2572 not getattr(self, '_popup_known_filepaths_added', False)):
2573 map(self._pup.prepend, [
2574 [gtk.SeparatorMenuItem(), None],
2576 [ gtk.MenuItem(".spi -> xmipp_show -sel <path>"),
2577 ( "activate",
2578 lambda *args: xm.show(sel = self._l3tree.py_string()))],
2580 [ gtk.MenuItem(".spi -> xmipp_show -vol <path>"),
2581 ( "activate",
2582 lambda *args: xm.show(vol = self._l3tree.py_string()))],
2584 [ gtk.MenuItem(".txt -> $EDITOR <path>"),
2585 ( "activate",
2586 lambda *args:
2587 os.system(os.path.expandvars("$EDITOR %s &" % # clean up...
2588 self._l3tree.py_string())))],
2590 [ gtk.MenuItem(".png -> view image"),
2591 ( "activate",
2592 lambda *args:
2593 _display_img(self._l3tree))],
2595 # The table display restructures a simple list; for file
2596 # content, this requires additions in file2ast, for every
2597 # file content type.
2598 [ gtk.MenuItem(".hdf file -> insert as l3 list list"),
2599 ("activate", lambda *args: self._insert_contents(shape='square'))],
2601 [ gtk.MenuItem(".hdf file -> insert as l3 list"),
2602 ("activate", lambda *args: self._insert_contents() )],
2605 self._popup_known_filepaths_added = True
2607 # 1. Possible file names
2608 elif (isinstance(self._l3tree, (ast.String, ast.Symbol, ast.Member)) and
2609 not getattr(self, '_popup_file_paths_added', False)):
2610 # Get values.
2611 va_l = self.get_values_list()
2613 # Remove invalid elements.
2614 va_l = filter(lambda (id, va):
2615 isinstance(va, (ast.String, ast.Symbol,
2616 types.StringType)) and (id,va),
2617 va_l)
2618 # Is there any content?
2619 if len(va_l) > 0:
2620 map(self._pup.prepend, [
2621 [gtk.SeparatorMenuItem(), None],
2622 [ gtk.MenuItem(".any -> insert (file path) list"),
2623 ( "activate", lambda *args: self.get_filepaths_list())],
2624 [ gtk.MenuItem(".png -> insert (file path, image) list"),
2625 ( "activate", lambda *args: self.filep_img_list())],
2627 self._popup_file_paths_added = True
2628 l3Rawtext.pre_popup_hook = pre_popup_hook
2630 def _insert_contents(self, shape = 'list'):
2631 # See also CommonPopup._insert_list
2632 from l3gui.l3canvas import RenderTable
2633 storage = self.w_.state_.storage
2634 cnvs = self._canvas
2635 fname = self._l3tree
2637 # Convert to l3 ast
2638 val, val_id = misc.file2ast(fname, shape = shape)\
2639 .setup(empty_parent(),
2640 ast.Env('dummy_env', None, None, storage),
2641 storage)
2642 val.set_outl_edges(self.w_, None)
2644 # Special emphasis for this non-permanent value list.
2645 val.set_emphasis("valuelist")
2646 ## val.set_label('File contents of %d' % self._l3tree._id )
2647 val.set_label('File contents of %s' % self._l3tree.py_string())
2649 # Form display.
2650 pic = cnvs.add_l3tree(val, RenderTable())
2652 # Position to the right of expression.
2653 lp, tp, rp, bp = pic.get_bounds_world()
2654 lo, to, ro, bo = self.get_bounds_world()
2655 pic.move(ro - lp, to - tp)
2656 l3Rawtext._insert_contents = _insert_contents
2659 def get_filepaths_list(self):
2660 ''' Examine all values associated with self, and display those
2661 denoting valid file paths as list.
2663 from l3gui.l3canvas import RenderTable
2664 storage = self.w_.state_.storage
2665 cnvs = self._canvas
2666 # Get values.
2667 va_l = self.get_values_list()
2669 # Remove invalid elements.
2670 va_l = filter(lambda (id, va):
2671 isinstance(va, (ast.String, ast.Symbol,
2672 types.StringType)) and (id,va),
2673 va_l)
2675 # Form "path/name" list.
2676 path_l = [("%s/%s" % (storage.load(id).dirpath(self.w_), va)).strip('/')
2677 for (id, va) in va_l]
2679 # Keep only valid path names.
2680 path_l = filter(lambda nm: os.path.exists(nm) and nm, path_l)
2682 # Get l3 list.
2683 # This is a (very) simplified ast.val2ast(), using ast.Filepath
2684 # instead of ast.String.
2686 val, val_id = ast.List(ast.aList(map(ast.FilepathString, path_l))).setup(
2687 empty_parent(),
2688 ast.Env('dummy_env', None, None, storage),
2689 storage)
2690 val.set_outl_edges(self.w_, None)
2692 # Special emphasis for this non-permanent value list.
2693 val.set_emphasis("filelist")
2694 val.set_label('File path list for %s' % self._l3tree.py_string() )
2696 # Form and position display.
2697 pic = cnvs.add_l3tree(val, RenderTable())
2698 lp, tp, rp, bp = pic.get_bounds_world()
2699 lo, to, ro, bo = self.get_bounds_world()
2700 pic.move(ro - lp, to - tp)
2701 l3Rawtext.get_filepaths_list = get_filepaths_list
2704 def filep_img_list(self):
2705 ''' Examine all values associated with self, and display those
2706 denoting valid file paths as (name = <image>) list.
2708 from l3gui.l3canvas import RenderTable
2709 storage = self.w_.state_.storage
2710 cnvs = self._canvas
2711 # Get values.
2712 va_l = self.get_values_list()
2714 # Remove invalid elements.
2715 va_l = filter(lambda (id, va):
2716 isinstance(va, (ast.String, ast.Symbol,
2717 types.StringType)) and (id,va),
2718 va_l)
2720 # Form "path/name" list.
2721 path_l = [("%s/%s" % (storage.load(id).dirpath(self.w_), va)).strip('/')
2722 for (id, va) in va_l]
2724 # Keep only valid path names.
2725 path_l = filter(lambda nm: os.path.exists(nm) and nm, path_l)
2727 # Get l3 list.
2728 # This is a (very) simplified ast.val2ast().
2730 from l3lang.ast import Set, Tuple, aList, FilepathString, Native
2731 val, val_id = ast.List(ast.aList(
2732 map(lambda path : Set(Symbol(path), Native(FilepathString(path))),
2733 path_l)
2734 )).setup(
2735 empty_parent(),
2736 ast.Env('dummy_env', None, None, storage),
2737 storage)
2738 val.set_outl_edges(self.w_, None)
2740 # Special emphasis for this non-permanent value list.
2741 val.set_emphasis("filelist")
2742 val.set_label('File path list for `%s`' % self._l3tree.py_string() )
2744 # Form and position display.
2745 pic = cnvs.add_l3tree(val, RenderTable())
2746 lp, tp, rp, bp = pic.get_bounds_world()
2747 lo, to, ro, bo = self.get_bounds_world()
2748 pic.move(ro - lp, to - tp)
2749 l3Rawtext.filep_img_list = filep_img_list
2752 def init_params(self):
2753 # Parameter settings, localized to allow subclass overrides
2754 self._font_desc = self.w_.cp_.rawtext_font
2755 self._font_size = self.w_.cp_.font_size * 1.0 * pango.SCALE
2756 self._fill_color = "white"
2757 self._outline_color = 'white'
2758 l3Rawtext.init_params = init_params
2760 def ed_new_size(self, height):
2761 # # self._edit_frame.set_property( "height", height )
2762 pass
2763 l3Rawtext.ed_new_size = ed_new_size
2766 def zoom(self, factor):
2767 l3Base.zoom(self, factor)
2768 if self._ltext: # zooming while editing?
2769 self._ltext.set_property("size",
2770 self.w_.cp_.font_size * factor * pango.SCALE)
2771 ### flush_events()
2772 u1, v1, u2, v2 = self._ltext.get_bounds()
2773 ox, oy = self._ltext_size_1
2774 if ox == 0: ox = 1
2775 if oy == 0: oy = 1
2776 ppu = self._canvas._pixpu
2777 ratio_h = 1.0 * (u2 - u1) * ppu / ox
2778 ratio_v = 1.0 * (v2 - v1) * ppu / oy
2779 return (ratio_h, ratio_v)
2780 else:
2781 return factor, factor
2782 l3Rawtext.zoom = zoom
2784 def setup_marker(self, marker, container):
2785 self._marker = marker
2786 self._container = container
2787 l3Nested.setup_marker = setup_marker
2788 l3Rawtext.setup_marker = setup_marker
2791 #** events
2794 #*** start_edit
2795 def start_edit(self, _textview, event):
2796 if event.type == gtk.gdk._2BUTTON_PRESS:
2797 if event.button == 1:
2798 # To suppress editing of nested text, find first parent
2799 # expression that has a non-rawtext parent.
2800 def find_last_text_parent(nd):
2801 if nd._parent == None:
2802 return nd
2803 else:
2804 if isinstance(nd._parent, l3Rawtext):
2805 return find_last_text_parent(nd._parent)
2806 else:
2807 return nd
2808 if isinstance(self, l3Comment):
2809 node = self
2810 else:
2811 node = find_last_text_parent(self)
2813 # Remove text display.
2814 node._new_text_props = _get_props(node._ltext, [], "x", "y")
2815 node._under_destruction = True
2816 node._ltext.destroy()
2817 node._ltext = None
2818 # ... and the outline.
2819 node._loutline.destroy()
2820 node._loutline = None
2822 # Use new widget for editing.
2823 if isinstance(node, l3Rawtext):
2824 params = node.w_.cp_.textview
2825 else:
2826 params = node.w_.cp_.inline
2828 node._editor = TextEdit(node.w_,
2829 node,
2830 node._text_orig,
2831 node._canvas._common_tag_table,
2832 node._canvas,
2834 node._editor._view.show()
2836 node._editor._view.grab_focus()
2837 node._under_destruction = "partial"
2838 return True
2839 return False
2840 l3Rawtext.start_edit = start_edit
2843 #* l3List / l3Map editing
2844 class l3List(l3Nested):
2845 pass
2847 class l3ViewList(l3List):
2848 pass
2850 class l3Map(l3Nested):
2851 pass
2854 #** l3List.__init__
2855 def __init__(self, w_, cnvs, tree_id, rentab):
2856 # l3 tree.
2857 l3tree = w_.state_.storage.load(tree_id)
2858 assert isinstance(l3tree, (ast.Map, ast.List, ast.Tuple))
2859 assert not isinstance(l3tree, (ast.cls_viewList))
2860 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
2863 #*** Display elements.
2864 alist = l3aList(w_, cnvs,
2865 l3tree[0],
2866 rentab,
2867 root_group = self._root_group,
2868 draggable = False,
2869 parent = self,
2872 #*** Label.
2873 head = Label(w_, cnvs, self._root_group, l3tree.deco_title_text())
2876 # Expander
2878 expander = uVisibleSymbol(w_, cnvs, self._root_group,
2879 action = lambda _: self.hide_subtree())
2881 # Align.
2882 # Expander Head
2883 # Alist
2884 flush_events() # Update bounding boxes
2885 LE, TE, RE, BE = expander.get_bounds()
2886 LH, TH, RH, BH = head.get_bounds()
2887 head.move(RE - LH, TE - TH)
2889 LA, TA, _, _ = alist.get_bounds()
2890 alist.move(LH - LA, BH - TA)
2892 # Events.
2894 # Bindings to keep.
2895 self.w_ = w_
2896 self._canvas = cnvs
2897 self._alist = alist
2898 self._head = head
2899 self._expander = expander
2900 self._l3tree = l3tree
2902 # Highlighting.
2903 self._outline = None
2905 # Item cross-referencing.
2906 self._marker = None
2907 self._container = None
2909 # Popup menu additions
2910 if isinstance(self, l3Map):
2911 map(self._pup.prepend, [
2912 # Specials.
2913 [ gtk.SeparatorMenuItem(), None],
2915 [ gtk.MenuItem("examine dir"),
2916 ( "activate", lambda *args: self.insert_view())],
2918 [ gtk.MenuItem("print working directory (pwd)"),
2919 ( "activate", lambda *args: self.print_pwd())],
2923 # Borders etc.
2924 self.init_header(rentab)
2925 self.init_deco(rentab)
2926 pass
2927 l3List.__init__ = __init__
2928 l3Map.__init__ = __init__
2930 #** Env inspection
2931 def insert_view(self):
2932 from l3gui.l3canvas import RenderTable
2933 storage = self.w_.state_.storage
2934 # Get the information.
2935 content = self.get_values_list()[0]
2936 if content is None:
2937 content = []
2938 val, val_id = ast.val2ast(content)\
2939 .setup(empty_parent(),
2940 ast.Env('dummy_env', None, None, storage),
2941 storage)
2942 val.set_outl_edges(self.w_, None)
2943 val.set_label("Env listing")
2944 # Form and position display.
2945 pic = self._canvas.add_l3tree(val, RenderTable())
2946 lp, tp, rp, bp = pic.get_bounds_world()
2947 lo, to, ro, bo = self.get_bounds_world()
2948 pic.move(ro - lp, to - tp)
2949 l3Map.insert_view = insert_view
2952 #** pwd
2953 def print_pwd(self):
2954 st = self.w_.state_.storage
2955 val = st.get_attribute(self._l3tree._id, 'interp_result')
2956 if isinstance(val, ast.Env):
2957 G.logger.message("Directory name is %s" % val.directory_name())
2958 l3Map.print_pwd = print_pwd
2961 #* l3Set / l3If / l3Call
2962 class l3Set(l3Nested):
2963 pass
2965 class l3If(l3Nested):
2966 # Layout:
2967 # if COND:
2968 # YES
2969 # else:
2970 # NO
2971 pass
2974 # ---------------------------------
2975 class l3IfOutline(l3Nested):
2976 pass
2978 # ---------------------------------
2979 class l3IfLoop(l3Nested):
2980 # Layout:
2981 # loop
2982 # BODY
2984 pass
2987 def continue_stop_pt(self):
2988 lc, tc, rc, bc = self._d_loop.get_bounds_world()
2989 return lc + (rc - lc)/10, bc ## parameters
2990 l3IfLoop.continue_stop_pt = continue_stop_pt
2992 def break_stop_pt(self):
2993 lc, tc, rc, bc = self.get_bounds_world()
2994 return rc + 4, bc ## parameters
2995 l3IfLoop.break_stop_pt = break_stop_pt
2998 # ---------------------------------
2999 # todo: combine l3If, l3IfLoop and l3IfWhile
3001 class l3IfWhile(l3Nested):
3002 # Layout:
3003 # while COND
3004 # BODY
3006 pass
3008 def continue_stop_pt(self):
3009 lc, tc, rc, bc = self._d_loop.get_bounds_world()
3010 return lc + (rc - lc)/10, bc ## parameters
3011 l3IfWhile.continue_stop_pt = continue_stop_pt
3013 def break_stop_pt(self):
3014 lc, tc, rc, bc = self.get_bounds_world()
3015 return rc + 4, bc ## parameters
3016 l3IfWhile.break_stop_pt = break_stop_pt
3019 # ---------------------------------
3020 class l3IfLoopContinue(l3Nested):
3021 pass
3022 def continue_start_pt(self):
3023 lc, tc, rc, bc = self.get_bounds_world()
3024 return lc, (tc + bc) / 2
3025 l3IfLoopContinue.continue_start_pt = continue_start_pt
3028 # ---------------------------------
3029 class l3IfLoopBreak(l3Nested):
3030 pass
3031 def break_start_pt(self):
3032 lc, tc, rc, bc = self.get_bounds_world()
3033 return rc, (tc + bc) / 2
3034 l3IfLoopBreak.break_start_pt = break_start_pt
3037 # ---------------------------------
3038 class l3Call(l3Nested):
3039 pass
3042 #** if_chooser
3043 def l3if_chooser(w_, cnvs, tree_id, rentab):
3045 Choose appropriate display class based on subtree structure.
3047 from l3lang.ast import Call, Set, MarkerTyped, Symbol, Function, \
3048 aList, If, String, Return, Macro, aNone, Tuple
3049 l3tree = w_.state_.storage.load(tree_id)
3050 assert isinstance(l3tree, ast.If)
3052 ma = ast.Matcher()
3054 # todo: use rentab to distinguish compact/expanded form?
3056 # Traverse parents' displays to see if self is inside a loop.
3057 in_l3ifloop = False
3058 for l3pic in cnvs.displayed_parents(l3tree):
3059 if isinstance(l3pic, l3IfLoop):
3060 in_l3ifloop = True
3061 l3ifloop = l3pic
3062 break
3064 #*** if in_l3ifloop:
3065 if in_l3ifloop:
3066 # loop branches?
3067 # if COND:
3068 # return LNAME(LARGS)
3070 if ma.match(l3tree,
3071 If(Marker('_'),
3072 aList([Return(Call(MarkerTyped(Symbol('LNAME'),
3073 Symbol('_')),
3074 MarkerTyped(Symbol('LARGS'),
3075 aList([]))))]),
3076 Marker('_'))):
3077 if ma['LNAME'] == l3ifloop._matcher['LNAME']:
3078 # loop `continue`.
3079 return l3IfLoopContinue(w_, cnvs, tree_id, rentab)
3080 else:
3081 # loop `break`.
3082 return l3IfLoopBreak(w_, cnvs, tree_id, rentab)
3084 # loop break?
3085 # if COND:
3086 # return ARGS
3088 if ma.match(l3tree,
3089 If(Marker('_'),
3090 aList([Return(Marker('_'))]),
3091 Marker('_'))):
3092 return l3IfLoopBreak(w_, cnvs, tree_id, rentab)
3096 #*** loop form?
3097 # loop form?
3098 # if "loop":
3099 # def LNAME(LARGS):
3100 # LBODY
3101 # LNAME2(CARGS)
3102 if ma.match(l3tree,
3103 If(String('loop'),
3104 aList([Set(MarkerTyped(Symbol('LNAME'), Symbol('symbol')),
3105 Function(MarkerTyped(Symbol('LARGS'), aList([])),
3106 MarkerTyped(Symbol('LBODY'), aList([])))),
3107 Call(MarkerTyped(Symbol('LNAME2'), Symbol('symbol')),
3108 MarkerTyped(Symbol('CARGS'), aList([])))]),
3109 Marker('_'))):
3110 if ma['LNAME'] != ma['LNAME2']:
3111 warn_("loop name mismatch; no special display")
3112 return l3If(w_, cnvs, tree_id, rentab)
3113 elif len(ma['LARGS']) != len(ma['CARGS']):
3114 warn_("arguments mismatched between loop definition and call")
3115 return l3If(w_, cnvs, tree_id, rentab)
3116 else:
3117 return l3IfLoop(w_, cnvs, tree_id, rentab, ma)
3120 #*** while loop?
3121 # while loop?
3122 # if "while":
3123 # def "_while_ID"():
3124 # if not COND:
3125 # return
3126 # else:
3127 # BODY
3128 # return _while_ID()
3129 # _while_ID()
3131 elif ma.match(l3tree,
3132 If(String('while'),
3133 aList([Set(Marker('_'),
3134 Macro(aList([]),
3135 aList([If(Call(Symbol('not'),
3136 Marker('COND-PARENT')),
3137 aList([Return(Marker('_'))]),
3138 Marker('BODY')),
3139 Return(Call(Marker('_'),
3140 aList([])))]))),
3141 Call(Marker('_'),
3142 aList([]))]),
3143 aList([]))):
3144 if ma.match(ma['COND-PARENT'], aList([Marker('COND')])):
3145 ma['COND-IDX'] = 0
3146 def get_cond():
3147 return ma['COND-PARENT'][ ma['COND-IDX'] ]
3148 ma.get_cond = get_cond
3149 return l3IfWhile(w_, cnvs, tree_id, rentab, ma)
3152 #*** for loop?
3154 # For display of
3156 # for V in SEQ:
3159 # identify V, SEQ, and B. Only self and those are displayed.
3161 # See also l3lang/reader.py and If.setup()
3163 # print reader.parse('''
3164 # if "for":
3165 # ! ITEMS = ! SEQ
3166 # ! IDX = 0
3167 # ! LEN = len(! ITEMS)
3168 # # orig. for
3169 # def "LOOP"():
3170 # if ! IDX < ! LEN:
3171 # ! IDX = ! IDX + 1
3172 # # V in S.
3173 # ! V = ! ITEMS[ ! IDX - 1 ]
3174 # # Body B
3175 # [ ! B ]
3176 # # Iterate.
3177 # return ! LOOP()
3178 # ! LOOP()
3179 # ''')
3180 # The following pattern is from above, with manual fixes for
3181 # def "LOOP"() [ Set(Symbol('LOOP') ...) -> Set(Marker('LOOP'),...)]
3182 # and
3183 # Marker('B') [ aList([Marker('B')]) -> Marker('B') ]
3185 elif ma.match(l3tree,
3186 If(String('for'), aList([Set(Marker('ITEMS'), Marker('SEQ')), Set(Marker('IDX'), Int(0)), Set(Marker('LEN'), Call(Symbol('len'), aList([Marker('ITEMS')]))), Set(Marker('LOOP'), Macro(aList([]), aList([If(Call(Symbol('<'), aList([Marker('IDX'), Marker('LEN')])), aList([Set(Marker('IDX'), Call(Symbol('+'), aList([Marker('IDX'), Int(1)]))), Set(Marker('V'), Call(Member(Symbol('operator'), Symbol('getitem')), aList([Marker('ITEMS'), Call(Symbol('-'), aList([Marker('IDX'), Int(1)]))]))), List(Marker('B')), Return(Call(Marker('LOOP'), aList([])))]), aList([]))]))), Call(Marker('LOOP'), aList([]))]), aList([]))):
3188 v_parent = w_.state_.storage.load(ma['V']._parent)
3189 ma.get_current_V = (lambda :
3190 v_parent[0])
3191 ma.set_V = ( lambda new:
3192 v_parent.replace_child(ma.get_current_V()._id, new))
3193 seq_parent = w_.state_.storage.load(ma['SEQ']._parent)
3194 ma.get_current_SEQ = (lambda :
3195 seq_parent[1])
3196 ma.set_SEQ = ( lambda new:
3197 seq_parent.replace_child(ma.get_current_SEQ()._id, new))
3198 ma.get_B = lambda : ma['B']
3200 return l3IfFor(w_, cnvs, tree_id, rentab, ma)
3201 # # return l3Rawtext(w_, cnvs, tree_id, rentab,
3202 # # render_only = [ma['V'], ma['SEQ'], ma['B']])
3204 else:
3205 # plain if
3206 return l3If(w_, cnvs, tree_id, rentab)
3208 ## paste
3209 ## wdgt.l3if_chooser = l3if_chooser
3212 #** init
3213 def __init__(self, w_, cnvs, tree_id, rentab):
3214 # layout:
3215 # Lhs = Rhs
3217 # l3 tree.
3218 l3tree = w_.state_.storage.load(tree_id)
3219 assert isinstance(l3tree, ast.Set)
3220 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
3222 # Bindings to keep.
3223 self._marker_points = {} # marker -> point list
3224 self.w_ = w_
3225 self._canvas = cnvs
3228 # Display elements.
3229 # Lhs
3230 d_lhs = cnvs.add_l3tree(l3tree[0], rentab)
3231 d_lhs.reparent(self)
3233 # Equal
3234 d_equal = Label(w_, cnvs, self._root_group, " = ")
3236 # Rhs
3237 d_rhs = cnvs.add_l3tree(l3tree[1], rentab)
3238 d_rhs.reparent(self)
3240 # Marker(s).
3241 d_lhs_marker = self.draw_marker()
3242 d_rhs_marker = self.draw_marker()
3243 d_lhs_marker.lower_to_bottom()
3244 d_rhs_marker.lower_to_bottom()
3246 # Inform obj of marker.
3247 d_lhs.setup_marker(d_lhs_marker, self)
3248 d_rhs.setup_marker(d_rhs_marker, self)
3250 # Bindings to keep.
3251 self._d_equal = d_equal
3252 self._d_lhs = d_lhs
3253 self._d_rhs = d_rhs
3254 self._d_lhs_marker = d_lhs_marker
3255 self._d_rhs_marker = d_rhs_marker
3256 self._l3tree = l3tree
3258 # Align.
3259 self._align_to_lhs()
3261 # Highlighting.
3262 self._outline = None
3264 # Item cross-referencing.
3265 self._marker = None
3266 self._container = None
3268 # Event handling.
3269 d_lhs_marker.connect("event", lambda *a: self.insert_event(*a))
3270 d_rhs_marker.connect("event", lambda *a: self.insert_event(*a))
3272 # Borders etc.
3273 self.init_header(rentab)
3274 self.init_deco(rentab)
3276 # Hide markers.
3277 d_lhs_marker.hide()
3278 d_rhs_marker.hide()
3279 pass
3280 l3Set.__init__ = __init__
3282 def __init__(self, w_, cnvs, tree_id, rentab, matcher):
3283 # l3 tree.
3284 l3tree = w_.state_.storage.load(tree_id)
3285 assert isinstance(l3tree, ast.If)
3286 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
3288 # Bindings to keep.
3289 self.w_ = w_
3290 self._canvas = cnvs
3291 self._marker_points = {} # marker -> point list
3292 self._matcher = ma = matcher
3293 self._l3tree = l3tree
3294 self._deco_cb_buffer = [] # callback list for add_item()
3297 # Display elements.
3298 d_loop = Label(w_, cnvs, self._root_group, "loop")
3299 d_body = l3aList(w_, cnvs,
3300 ma['LBODY'],
3301 rentab,
3302 root_group = self._root_group,
3303 draggable = False,
3304 parent = self,
3307 # Marker(s).
3308 # # d_cond_marker = self.draw_marker()
3309 # # d_cond_marker.lower_to_bottom()
3311 # Inform obj of marker.
3312 # # d_cond.setup_marker(d_cond_marker, self)
3315 # Align with respect to d_loop.
3317 flush_events()
3319 ll, tl, rl, bl = d_loop.get_bounds()
3320 lb, tb, rb, bb = d_body.get_bounds()
3321 d_body.move(ll - lb, bl - tb)
3323 # COND marker for child replacement.
3324 # # _, y, x, _ = d_if.get_bounds()
3325 # # u, v, _, _ = d_cond_marker.get_bounds()
3326 # # d_cond_marker.move(x - u + w_.cp_.exp_marker_hoff,
3327 # # y - v + w_.cp_.exp_marker_voff)
3329 # Bindings to keep.
3330 # Indexed access. Match l3tree indexing where applicable.
3331 self._d_elements = [
3332 # l3 ast.
3333 d_loop,
3334 d_body,
3336 # Rest
3337 # # d_else,
3338 # # d_if,
3339 # # d_cond_marker,
3341 self._update_refs()
3343 # Highlighting.
3344 self._outline = None
3346 # Item cross-referencing.
3347 self._marker = None
3348 self._container = None
3350 # Event handling.
3351 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3353 # Borders etc.
3354 self.init_header(rentab)
3355 self.init_deco(rentab)
3357 pass
3358 l3IfOutline.__init__ = __init__
3360 def __init__(self, w_, cnvs, tree_id, rentab, matcher):
3361 # l3 tree.
3362 l3tree = w_.state_.storage.load(tree_id)
3363 assert isinstance(l3tree, ast.If)
3364 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
3366 # Bindings to keep.
3367 self.w_ = w_
3368 self._canvas = cnvs
3369 self._marker_points = {} # marker -> point list
3370 self._matcher = ma = matcher
3371 self._l3tree = l3tree
3372 self._deco_cb_buffer = [] # callback list for add_item()
3375 # Display elements.
3376 d_loop = Label(w_, cnvs, self._root_group, "loop")
3377 d_body = l3aList(w_, cnvs,
3378 ma['LBODY'],
3379 rentab,
3380 root_group = self._root_group,
3381 draggable = False,
3382 parent = self,
3385 # Marker(s).
3386 # # d_cond_marker = self.draw_marker()
3387 # # d_cond_marker.lower_to_bottom()
3389 # Inform obj of marker.
3390 # # d_cond.setup_marker(d_cond_marker, self)
3393 # Align with respect to d_loop.
3395 flush_events()
3397 ll, tl, rl, bl = d_loop.get_bounds()
3398 lb, tb, rb, bb = d_body.get_bounds()
3399 d_body.move(ll - lb, bl - tb)
3401 # COND marker for child replacement.
3402 # # _, y, x, _ = d_if.get_bounds()
3403 # # u, v, _, _ = d_cond_marker.get_bounds()
3404 # # d_cond_marker.move(x - u + w_.cp_.exp_marker_hoff,
3405 # # y - v + w_.cp_.exp_marker_voff)
3407 # Bindings to keep.
3408 # Indexed access. Match l3tree indexing where applicable.
3409 self._d_elements = [
3410 # l3 ast.
3411 d_loop,
3412 d_body,
3414 # Rest
3415 # # d_else,
3416 # # d_if,
3417 # # d_cond_marker,
3419 self._update_refs()
3421 # Highlighting.
3422 self._outline = None
3424 # Item cross-referencing.
3425 self._marker = None
3426 self._container = None
3428 # Event handling.
3429 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3431 # Borders etc.
3432 self.init_header(rentab)
3433 self.init_deco(rentab)
3435 pass
3436 l3IfLoop.__init__ = __init__
3438 def _update_refs(self):
3439 (self._d_loop,
3440 self._d_body ,
3441 ) = self._d_elements
3442 l3IfLoop._update_refs = _update_refs
3445 def __init__(self, w_, cnvs, tree_id, rentab, matcher):
3446 # l3 tree.
3447 l3tree = w_.state_.storage.load(tree_id)
3448 assert isinstance(l3tree, ast.If)
3449 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
3451 # Bindings to keep.
3452 self.w_ = w_
3453 self._canvas = cnvs
3454 self._marker_points = {} # marker -> point list
3455 self._matcher = ma = matcher
3456 self._l3tree = l3tree
3457 self._deco_cb_buffer = [] # callback list for add_item()
3460 # Display elements.
3461 d_loop = Label(w_, cnvs, self._root_group, "while")
3463 d_cond = cnvs.add_l3tree(ma.get_cond(), rentab)
3464 d_cond.reparent(self)
3466 d_body = l3aList(w_, cnvs,
3467 ma['BODY'],
3468 rentab,
3469 root_group = self._root_group,
3470 draggable = False,
3471 parent = self,
3474 # Marker(s).
3475 d_cond_marker = self.draw_marker()
3476 d_cond_marker.lower_to_bottom()
3478 # Inform obj of marker.
3479 d_cond.setup_marker(d_cond_marker, self)
3482 # Align with respect to d_loop.
3484 flush_events()
3486 llo, tlo, rlo, blo = d_loop.get_bounds()
3487 lco, tco, rco, bco = d_cond.get_bounds()
3488 d_cond.move(rlo + w_.cp_.loop_cond_sep - lco, tlo - tco)
3490 lco, tco, rco, bco = d_cond.get_bounds()
3491 lbo, tbo, rbo, bbo = d_body.get_bounds()
3492 d_body.move(lco - lbo, bco - tbo)
3494 # COND marker for child replacement.
3495 lco, tco, rco, bco = d_cond.get_bounds()
3496 lma, tma, _, _ = d_cond_marker.get_bounds()
3497 d_cond_marker.move(lco - lma + w_.cp_.exp_marker_hoff,
3498 tco - tma + w_.cp_.exp_marker_voff)
3500 # Bindings to keep.
3501 # Indexed access. Match l3tree indexing where applicable.
3502 self._d_elements = [
3503 # l3 ast.
3504 d_cond,
3505 d_body,
3507 # Rest
3508 d_loop,
3509 d_cond_marker,
3511 self._update_refs()
3513 # Highlighting.
3514 self._outline = None
3516 # Item cross-referencing.
3517 self._marker = None
3518 self._container = None
3520 # Event handling.
3521 d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3523 # Borders etc.
3524 self.init_header(rentab)
3525 self.init_deco(rentab)
3527 pass
3528 l3IfWhile.__init__ = __init__
3530 def _update_refs(self):
3531 (self._d_cond,
3532 self._d_body,
3534 self._d_loop,
3535 self._d_cond_marker,
3536 ) = self._d_elements
3537 l3IfWhile._update_refs = _update_refs
3541 def __init__(self, w_, cnvs, tree_id, rentab):
3542 # l3 tree.
3543 l3tree = w_.state_.storage.load(tree_id)
3544 assert isinstance(l3tree, ast.If)
3545 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
3547 # Bindings to keep.
3548 self.w_ = w_
3549 self._canvas = cnvs
3550 self._marker_points = {} # marker -> point list
3551 self._l3tree = l3tree
3554 # Display elements.
3555 self._d_label = Label(w_, cnvs, self._root_group, "break")
3557 # Flow edge drawing.
3558 # The actual line is drawn after the enclosing l3IfLoop is
3559 # complete.
3560 def search_l3ifloop():
3561 for l3pic in cnvs.displayed_parents(l3tree):
3562 if isinstance(l3pic, l3IfLoop):
3563 return l3pic
3564 return None
3565 ifloop = search_l3ifloop()
3567 if ifloop is not None:
3568 def body():
3569 return BreakLine(w_, cnvs, self, ifloop)
3570 ifloop._deco_cb_buffer.append(body)
3571 # The line must not be drawn after self (or ifloop) is
3572 # deleted, or self (or an intermediate tree containing self)
3573 # is detached from ifloop.
3574 wref_ifloop = weakref.ref(ifloop)
3575 def rm_linedraw():
3576 if wref_ifloop() is None: return
3577 try:
3578 wref_ifloop()._deco_cb_buffer.remove(body)
3579 except ValueError: # Body removed already.
3580 pass
3581 self.add_reparent_to_root_hook(rm_linedraw)
3582 # Parents up to ifloop (excluded).
3583 tw = ast.TreeWork(self.w_.state_.storage)
3584 for par in tw.all_parents(l3tree):
3585 if par is ifloop._l3tree: break
3586 l3pic = cnvs._nodes.get(par._id)
3587 if l3pic is not None:
3588 l3pic.add_reparent_to_root_hook(rm_linedraw)
3590 # Highlighting.
3591 self._outline = None
3593 # Item cross-referencing.
3594 self._marker = None
3595 self._container = None
3597 # Event handling.
3598 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3600 # Borders etc.
3601 self.init_header(rentab)
3602 self.init_deco(rentab)
3604 pass
3605 l3IfLoopBreak.__init__ = __init__
3607 def __init__(self, w_, cnvs, tree_id, rentab):
3608 # l3 tree.
3609 l3tree = w_.state_.storage.load(tree_id)
3610 assert isinstance(l3tree, ast.If)
3611 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
3613 # Bindings to keep.
3614 self.w_ = w_
3615 self._canvas = cnvs
3616 self._marker_points = {} # marker -> point list
3617 self._l3tree = l3tree
3620 # Display elements.
3621 self._d_label = Label(w_, cnvs, self._root_group, "continue")
3623 # Flow edge drawing.
3624 # The actual line is drawn after the enclosing l3IfLoop is
3625 # complete.
3626 def search_l3ifloop():
3627 for l3pic in cnvs.displayed_parents(l3tree):
3628 if isinstance(l3pic, l3IfLoop):
3629 return l3pic
3630 return None
3631 ifloop = search_l3ifloop()
3633 if ifloop is not None:
3634 def body():
3635 return ContinueLine(w_, cnvs, self, ifloop)
3636 ifloop._deco_cb_buffer.append(body)
3637 # The line must not be drawn after self (or ifloop) is
3638 # deleted, or self (or an intermediate tree containing self)
3639 # is detached from ifloop.
3640 wref_ifloop = weakref.ref(ifloop)
3641 def rm_linedraw():
3642 print "******** rm_linedraw: removed ContinueLine"
3643 if wref_ifloop() is None: return
3644 try:
3645 wref_ifloop()._deco_cb_buffer.remove(body)
3646 except ValueError: # Body removed already.
3647 pass
3648 self.add_reparent_to_root_hook(rm_linedraw)
3649 # Parents up to ifloop (excluded).
3650 tw = ast.TreeWork(self.w_.state_.storage)
3651 for par in tw.all_parents(l3tree):
3652 if par is ifloop._l3tree: break
3653 l3pic = cnvs._nodes.get(par._id)
3654 if l3pic is not None:
3655 l3pic.add_reparent_to_root_hook(rm_linedraw)
3657 # Highlighting.
3658 self._outline = None
3660 # Item cross-referencing.
3661 self._marker = None
3662 self._container = None
3664 # Event handling.
3665 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3667 # Borders etc.
3668 self.init_header(rentab)
3669 self.init_deco(rentab)
3671 pass
3672 l3IfLoopContinue.__init__ = __init__
3675 def __init__(self, w_, cnvs, tree_id, rentab):
3676 # layout:
3677 # +---------+
3678 # |if||COND |
3679 # +---------+
3680 # +----------+
3681 # | YES |
3682 # +----------+
3683 # +----+
3684 # |else|
3685 # +----+
3686 # +----------+
3687 # | NO |
3688 # +----------+
3691 # l3 tree.
3692 l3tree = w_.state_.storage.load(tree_id)
3693 assert isinstance(l3tree, ast.If)
3694 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
3696 # Bindings to keep.
3697 self.w_ = w_
3698 self._canvas = cnvs
3699 self._marker_points = {} # marker -> point list
3702 # Display elements.
3704 # if
3705 d_if = Label(w_, cnvs, self._root_group, "If")
3707 # COND
3708 d_cond = cnvs.add_l3tree(l3tree[0], rentab)
3709 d_cond.reparent(self)
3711 # YES
3712 d_yes = l3aList(w_, cnvs,
3713 l3tree[1],
3714 rentab,
3715 root_group = self._root_group,
3716 draggable = False,
3717 parent = self,
3720 # else
3721 d_else = Label(w_, cnvs, self._root_group, "else")
3723 # NO
3724 d_no = l3aList(w_, cnvs,
3725 l3tree[2],
3726 rentab,
3727 root_group = self._root_group,
3728 draggable = False,
3729 parent = self,
3732 # Marker(s).
3733 d_cond_marker = self.draw_marker()
3734 d_cond_marker.lower_to_bottom()
3736 # Inform obj of marker.
3737 d_cond.setup_marker(d_cond_marker, self)
3740 # Align with respect to IF.
3742 flush_events()
3743 # COND
3744 _, y, x, _ = d_if.get_bounds()
3745 u, v, _, _ = d_cond.get_bounds()
3746 d_cond.move(x - u, y - v)
3748 # COND marker for child replacement.
3749 _, y, x, _ = d_if.get_bounds()
3750 u, v, _, _ = d_cond_marker.get_bounds()
3751 d_cond_marker.move(x - u + w_.cp_.exp_marker_hoff,
3752 y - v + w_.cp_.exp_marker_voff)
3754 # YES
3755 x, _, _, y = d_cond.get_bounds()
3756 u, v, _, _ = d_yes.get_bounds()
3757 d_yes.move(x - u, y - v)
3759 # else
3760 x, _, _, _ = d_if.get_bounds()
3761 _, _, _, y = d_yes.get_bounds()
3762 u, v, _, _ = d_else.get_bounds()
3763 d_else.move(x - u, y - v)
3765 # NO
3766 _, _, x, _ = d_if.get_bounds()
3767 _, _, _, y = d_else.get_bounds()
3768 u, v, _, _ = d_no.get_bounds()
3769 d_no.move(x - u, y - v)
3771 # Bindings to keep.
3772 # Indexed access. Match l3tree indexing where applicable.
3773 self._d_elements = [
3774 # l3 ast.
3775 d_cond,
3776 d_yes,
3777 d_no,
3779 # Rest
3780 d_else,
3781 d_if,
3782 d_cond_marker,
3784 self._update_refs()
3786 self._l3tree = l3tree
3788 # Highlighting.
3789 self._outline = None
3791 # Item cross-referencing.
3792 self._marker = None
3793 self._container = None
3795 # Event handling.
3796 d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3798 # Borders etc.
3799 self.init_header(rentab)
3800 self.init_deco(rentab)
3802 pass
3803 l3If.__init__ = __init__
3805 def _update_refs(self):
3806 (self._d_cond,
3807 self._d_yes ,
3808 self._d_no ,
3810 self._d_else,
3811 self._d_if ,
3812 self._d_cond_marker,
3813 ) = self._d_elements
3814 l3If._update_refs = _update_refs
3817 def __init__(self, w_, cnvs, tree_id, rentab):
3818 # layout:
3819 # +-----+
3820 # |func | selector
3821 # +-----+
3822 # +----------+
3823 # | args |
3824 # +----------+
3826 # l3 tree.
3827 l3tree = w_.state_.storage.load(tree_id)
3828 assert isinstance(l3tree, ast.Call)
3829 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
3831 # Bindings to keep.
3832 self.w_ = w_
3833 self._canvas = cnvs
3834 self._marker_points = {} # marker -> point list
3837 # Display elements.
3839 # func
3840 d_func = cnvs.add_l3tree(l3tree[0], rentab)
3841 d_func.reparent(self)
3843 # Selector
3844 d_selector = Label(w_, cnvs, self._root_group, " () ")
3846 # args
3847 d_args = l3aList(w_, cnvs,
3848 l3tree[1],
3849 rentab,
3850 root_group = self._root_group,
3851 draggable = False,
3852 parent = self,
3855 # Marker(s).
3856 d_func_marker = self.draw_marker()
3857 d_func_marker.lower_to_bottom()
3859 # Inform obj of marker.
3860 d_func.setup_marker(d_func_marker, self)
3863 # Align with respect to FUNC.
3865 flush_events()
3866 # ARGS
3867 lf, tf, rf, bf = d_func.get_bounds()
3868 u, v, _, _ = d_args.get_bounds()
3869 d_args.move(lf - u, bf - v)
3871 # selector
3872 ls, ts, rs, bs = d_selector.get_bounds()
3873 d_selector.move(rf - ls, tf - ts)
3875 # FUNC marker for child replacement.
3876 x, y, _, _ = d_func.get_bounds()
3877 u, v, _, _ = d_func_marker.get_bounds()
3878 d_func_marker.move(x - u + w_.cp_.exp_marker_hoff,
3879 y - v + w_.cp_.exp_marker_voff)
3881 # Bindings to keep.
3882 # Indexed access. Match l3tree indexing where applicable.
3883 self._d_elements = [
3884 # l3 ast.
3885 d_func,
3886 d_args,
3888 # Rest
3889 d_func_marker,
3890 d_selector,
3892 self._update_refs()
3894 self._l3tree = l3tree
3896 # Highlighting.
3897 self._outline = None
3899 # Item cross-referencing.
3900 self._marker = None
3901 self._container = None
3903 # Event handling.
3904 d_func_marker.connect("event", lambda *a: self.insert_event(*a))
3906 # Borders etc.
3907 self.init_header(rentab)
3908 self.init_deco(rentab)
3910 pass
3911 l3Call.__init__ = __init__
3913 def _update_refs(self):
3914 ( self._d_func,
3915 self._d_args,
3917 self._d_func_marker,
3918 self._d_selector,
3919 ) = self._d_elements
3920 l3Call._update_refs = _update_refs
3923 #** misc.
3924 def _func_shift(self):
3925 # Shifts needed when FUNC size changes
3926 if self._d_func:
3927 _, _, fr, fb = self._d_func.get_bounds()
3928 else:
3929 _, _, fr, fb = self._d_func_marker.get_bounds()
3930 # FUNC
3931 _, at, _, _ = self._d_args.get_bounds()
3932 dy = fb - at # Shift between OLD d_args and NEW d_func.
3933 self._d_args.move(0, dy)
3934 # SELECTOR
3935 sl, _, _, _ = self._d_selector.get_bounds()
3936 self._d_selector.move(fr - sl, 0)
3937 l3Call._func_shift = _func_shift
3940 def _cond_shift(self):
3941 # Shifts needed when COND size changes
3942 if self._d_cond:
3943 _, _, _, y = self._d_cond.get_bounds()
3944 else:
3945 _, _, _, y = self._d_cond_marker.get_bounds()
3946 _, v, _, _ = self._d_yes.get_bounds()
3947 dy = y - v # Shift between OLD d_yes and NEW d_cond.
3948 self._d_yes.move(0, dy)
3949 self._d_else.move(0, dy)
3950 self._d_no.move(0, dy)
3951 l3If._cond_shift = _cond_shift
3953 def _cond_shift(self):
3954 # Shifts needed when COND size changes
3955 if self._d_cond:
3956 _, _, _, y = self._d_cond.get_bounds()
3957 else:
3958 _, _, _, y = self._d_cond_marker.get_bounds()
3959 _, v, _, _ = self._d_body.get_bounds()
3960 dy = y - v # Shift between OLD d_yes and NEW d_cond.
3961 self._d_body.move(0, dy)
3962 l3IfWhile._cond_shift = _cond_shift
3965 def _align_to_lhs(self):
3967 # Align.
3969 # +------A---------A------+
3970 # | lhs | equal | rhs |
3971 # +------+---------+------+
3972 flush_events()
3974 # LHS marker
3975 x, y, _, _ = self._d_lhs.get_bounds()
3976 u, _, _, v = self._d_lhs_marker.get_bounds()
3977 self._d_lhs_marker.move(x - u + self.w_.cp_.exp_marker_hoff,
3978 y + self._canvas.font_ascent_units() +
3979 self._canvas.bbox_offset_units() - v )
3981 # EQUAL
3982 _, y, x, _ = self._d_lhs.get_bounds()
3983 u, v, _, _ = self._d_equal.get_bounds()
3984 self._d_equal.move(x - u, y - v)
3986 # RHS
3987 if self._d_rhs != None:
3988 _, y, x, _ = self._d_equal.get_bounds()
3989 u, v, _, _ = self._d_rhs.get_bounds()
3990 self._d_rhs.move(x - u, y - v)
3992 # RHS marker
3993 # also see l3Set.insert
3994 x, y, _, _ = self._d_rhs.get_bounds()
3995 u, _, _, v = self._d_rhs_marker.get_bounds()
3996 ### self._canvas.bbox_wait(self._d_rhs_marker, self._d_rhs)
3997 self._d_rhs_marker.move(x - u + self.w_.cp_.exp_marker_hoff,
3998 y - v + self._canvas.font_ascent_units() +
3999 self._canvas.bbox_offset_units()
4001 l3Set._align_to_lhs = _align_to_lhs
4004 #** Events
4008 #* class l3IfFor members
4010 class l3IfFor(l3Nested):
4011 # Layout:
4012 # for V in SEQ
4015 pass
4018 #* l3Function
4019 class l3Function(l3Nested):
4020 pass
4023 #** init
4024 def __init__(self, w_, cnvs, tree_id, rentab):
4026 # The blandest layout:
4028 # +-----------+
4029 # | function |
4030 # +-----------+
4031 # ----+------+
4032 # | args |
4033 # +------+
4034 # ----+------+
4035 # | body |
4036 # +------+
4038 # l3 tree.
4039 l3tree = w_.state_.storage.load(tree_id)
4040 assert isinstance(l3tree, ast.Function)
4041 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
4043 # Bindings to keep.
4044 self.w_ = w_
4045 self._canvas = cnvs
4048 # Display elements.
4050 # function
4051 d_function = Label(w_, cnvs, self._root_group, "Function")
4053 # ARGS
4054 d_args = l3aList(w_, cnvs,
4055 l3tree[0],
4056 rentab,
4057 root_group = self._root_group,
4058 draggable = False,
4059 parent = self,
4061 ### incorporate into cnvs.add_l3tree(l3tree[1]) ??
4063 # BODY
4064 d_body = l3aList(w_, cnvs,
4065 l3tree[1],
4066 rentab,
4067 root_group = self._root_group,
4068 draggable = False,
4069 parent = self,
4071 ### incorporate into cnvs.add_l3tree(l3tree[1]) ??
4074 # Marker(s).
4078 # Inform obj of marker.
4082 # Align with respect to FUNCTION.
4084 flush_events()
4086 # ARGS
4087 x, _, _, y = d_function.get_bounds()
4088 u, v, _, _ = d_args.get_bounds()
4089 d_args.move(x - u, y - v)
4091 # BODY
4092 x, _, _, y = d_args.get_bounds()
4093 u, v, _, _ = d_body.get_bounds()
4094 d_body.move(x - u, y - v)
4096 # Bindings to keep.
4097 self._d_function = d_function
4098 self._d_args = d_args
4099 self._d_body = d_body
4100 self._l3tree = l3tree
4102 # Highlighting.
4103 self._outline = None
4105 # Item cross-referencing.
4106 self._marker = None
4107 self._container = None
4109 # Event handling.
4111 # Borders etc.
4112 self.init_header(rentab)
4113 self.init_deco(rentab)
4115 pass
4116 l3Function.__init__ = __init__
4120 #** events
4122 #*** no insertion
4125 #** no insert
4128 #** no detach
4131 #** no draw marker
4134 #* l3Inline
4135 class l3Inline(l3Nested):
4136 pass
4138 def __init__(self, w_, cnvs, tree_id, rentab):
4139 # layout:
4140 # inline STR
4142 # Also see l3Program / l3If.
4144 # l3 tree.
4145 l3tree = w_.state_.storage.load(tree_id)
4146 assert isinstance(l3tree, ast.Inline)
4147 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
4149 # Bindings to keep.
4150 self.w_ = w_
4151 self._canvas = cnvs
4152 self._l3tree = l3tree
4153 self._marker_points = {} # marker -> point list
4155 # Display elements.
4156 # Label.
4157 head = Label(w_, cnvs, self._root_group, "Inline")
4159 # Python string.
4160 pystr = cnvs.add_l3tree(l3tree[0], rentab)
4161 pystr.reparent(self)
4163 # Marker(s).
4164 pystr_marker = self.draw_marker()
4165 pystr_marker.lower_to_bottom()
4167 # Bindings to keep.
4168 self._pystr = pystr
4169 self._pystr_marker = pystr_marker
4170 self._head = head
4172 # Inform obj of marker.
4173 pystr.setup_marker(pystr_marker, self)
4175 # Align flush left.
4176 # pystr
4177 flush_events()
4178 u, _, _, v = head.get_bounds()
4179 x, y, _, _ = pystr.get_bounds()
4180 head.move(x - u, y - v)
4181 # pystr_marker
4182 sl, st, _, _ = pystr.get_bounds()
4183 ml, mt, _, _ = pystr_marker.get_bounds()
4184 pystr_marker.move(sl - ml + w_.cp_.exp_marker_hoff,
4185 st - mt + w_.cp_.exp_marker_voff)
4187 # Highlighting.
4188 self._outline = None
4190 # Item cross-referencing.
4191 self._marker = None
4192 self._container = None
4194 # Event handling.
4195 ### pystr_marker.connect("event", lambda *a: self.insert_event(*a))
4197 # Popup menu additions
4199 # Borders etc.
4200 self.init_header(rentab)
4201 self.init_deco(rentab)
4202 pass
4203 l3Inline.__init__ = __init__
4206 def rebuild_tree(self, text):
4207 # Form new tree.
4208 print 'inline text update finished'
4210 ### trap parse errors here
4211 tree = reader.parse("'''\n%s\n'''" % text).body()
4212 tree.setup(self._l3tree, self.w_.state_.def_env, self.w_.state_.storage)
4213 tree.set_outl_edges(self.w_, None)
4215 # Replace original raw String().
4216 self._l3tree[0].deep_replace(tree, self.w_.state_.storage)
4217 l3Inline.rebuild_tree = rebuild_tree
4219 #* l3Native
4220 class l3Native(l3Nested):
4221 pass
4223 def __init__(self, w_, cnvs, tree_id, rentab):
4224 # layout:
4225 # header
4226 # value
4228 # Also see l3Inline / l3Program / l3If.
4230 # l3 tree.
4231 l3tree = w_.state_.storage.load(tree_id)
4232 assert isinstance(l3tree, ast.Native)
4233 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
4235 # Bindings to keep.
4236 self.w_ = w_
4237 self._canvas = cnvs
4238 self._l3tree = l3tree
4240 value = l3tree.value()
4242 # Display elements.
4243 # Label.
4244 val_gen = w_.state_.storage.generator_of(id(value))
4245 if 0:
4246 if val_gen is None:
4247 head = Label(w_, cnvs, self._root_group, "External value")
4248 else:
4249 head = Label(w_, cnvs, self._root_group,
4250 "Value from %d" %
4251 w_.state_.storage.generator_of(id(value))._id
4254 head = uBlank(w_, cnvs, self._root_group)
4256 # todo: actively link the label to the source expression.
4257 # This way, the native display can provide other functions itself,
4258 # and can be a full widget with independent event handling if
4259 # desired.
4261 # Python value.
4262 # Note: canvas operations will destroy these value containers
4263 # occasionally, so values that are gtk widgets can be displayed
4264 # ONLY ONCE.
4266 # Avoid 'import EMAN2' dependency
4267 # Display emdata as image.
4268 if (value.__class__.__name__ == 'EMData'):
4269 # For now, put an image handler here. Add a general handler
4270 # later.
4271 pystr = Image(w_, cnvs, self._root_group, misc.emdata2pixbuf(value),
4272 parent = self)
4274 # Display .png file as image ( display Native(String("foo.png")) )
4275 elif isinstance(value, ast.String) and value.isfile() and \
4276 value.endswith(".png"):
4277 pystr = Image(w_, cnvs, self._root_group,
4278 misc.png2pixbuf(value.py_string()), parent = self)
4280 # Display matplotlib figures via in widgets.
4281 elif (value.__class__.__name__ == 'Figure'):
4282 from matplotlib.backends.backend_gtk import FigureCanvasGTK \
4283 as FigureCanvas
4284 pystr = Widget(w_, cnvs, self._root_group,
4285 FigureCanvas(value), parent = self)
4287 # Avoid numpy dependency.
4288 elif (value.__class__.__name__ == 'ndarray'):
4289 if len(value.shape) == 2:
4290 pystr = Image(w_, cnvs, self._root_group,
4291 misc.arr2pix(value), parent = self)
4292 else:
4293 pystr = Label(w_, cnvs, self._root_group,
4294 misc.escape_markup(repr(value)))
4295 # Generic display.
4296 else:
4297 pystr = Label(w_, cnvs, self._root_group,
4298 misc.escape_markup(str(value)))
4300 # Marker(s).
4302 # Bindings to keep.
4303 self._pystr = pystr
4304 self._head = head
4306 # Inform obj of marker.
4308 # Align flush left.
4309 # pystr
4310 flush_events()
4311 l1, _, _, b1 = head.get_bounds()
4312 l2, t2, _, _ = pystr.get_bounds()
4313 pystr.move(l1 - l2, b1 - t2)
4314 # pystr_marker
4316 # Highlighting.
4317 self._outline = None
4319 # Item cross-referencing.
4320 self._marker = None
4321 self._container = None
4323 # Event handling.
4325 # Popup menu additions
4326 if isinstance(pystr, Image):
4327 map(self._pup.prepend, [
4328 [gtk.SeparatorMenuItem(), None],
4330 [ gtk.MenuItem('set image size as default'),
4331 ( 'activate', lambda *args: pystr.set_default_size())],
4333 [ gtk.MenuItem('shrink image 40%'),
4334 ('activate', lambda *args: pystr.scale(0.6))],
4336 [ gtk.MenuItem('enlarge image 40%'),
4337 ('activate', lambda *args: pystr.scale(1.4))],
4341 # Borders etc.
4342 self.init_header(rentab)
4343 self.init_deco(rentab)
4344 pass
4345 l3Native.__init__ = __init__
4348 #* l3Program
4349 class l3Program(l3Nested):
4350 pass
4352 def __init__(self, w_, cnvs, tree_id, rentab):
4353 # l3 tree.
4354 l3tree = w_.state_.storage.load(tree_id)
4355 if isinstance(self, l3Program):
4356 assert isinstance(l3tree, ast.Program)
4357 else:
4358 assert isinstance(l3tree, (ast.Map, ast.cls_viewList))
4359 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
4362 #*** Choose display elements.
4363 # alist.
4364 if l3tree._outl_type == 'subtree':
4365 # Full display (the l3List default).
4366 alist = l3aList(w_, cnvs,
4367 l3tree[0],
4368 rentab,
4369 root_group = self._root_group,
4370 draggable = False,
4371 parent = self,
4373 elif l3tree._outl_type == 'flat':
4374 # This heading only; no body additions allowed.
4375 setup_alist = l3tree[0].setup_alist(w_, l3tree[0])
4376 alist = l3aList(w_, cnvs,
4377 setup_alist,
4378 rentab,
4379 root_group = self._root_group,
4380 draggable = False,
4381 parent = self,
4382 insertion_on_markers = False,
4383 hide_markers = True,
4385 elif l3tree._outl_type == 'nested':
4386 # heading + subheadings only; no body additions/insertions
4387 # allowed. Removal is ok.
4388 alist = l3aList(w_, cnvs,
4389 l3tree._outl_children,
4390 rentab,
4391 root_group = self._root_group,
4392 draggable = False,
4393 parent = self,
4394 insertion_on_markers = False,
4395 hide_markers = True,
4397 else:
4398 raise Exception("Invalid _outl_type. Internal error.")
4400 #*** Form the label.
4401 level, index = l3tree.heading_index()
4402 # Use numbers for even levels, letters for odd.
4403 if (level % 2) == 0:
4404 outline_symb = string.ascii_letters[26 + index % 26]
4405 else:
4406 outline_symb = str(index + 1) # count from 1
4408 ttext = l3tree.deco_title_text()
4409 # Strip quotes.
4410 if ttext.startswith("'''"):
4411 ttext = ttext[3:-3]
4412 if ttext.startswith("'") or ttext.startswith('"'):
4413 ttext = ttext[1:-1]
4415 head_text = ("<b>" +
4416 outline_symb +
4417 ". " +
4418 ttext +
4419 "</b>")
4420 head = Label(w_, cnvs, self._root_group, head_text,
4421 font = w_.cp_.viewlist_head_font)
4423 #*** Expander
4425 # The actions cycle to the next view state.
4426 expander_fn, expander_action = {
4427 'flat': (uInvisibleSymbol,
4428 lambda *args: self.view_as('nested')),
4429 'nested': (uPartiallyVisible,
4430 lambda *args: self.view_as('subtree')),
4431 'subtree': (uVisibleSymbol,
4432 lambda *args: self.view_as('flat')),
4433 }[ l3tree.get_outline_type() ]
4435 expander = expander_fn(w_, cnvs, self._root_group,
4436 action = expander_action)
4438 # Align.
4439 # Expander Head
4440 # Alist
4441 flush_events() # Update bounding boxes
4442 LE, TE, RE, BE = expander.get_bounds()
4443 LH, TH, RH, BH = head.get_bounds()
4444 head.move(RE - LH, TE - TH)
4446 LA, TA, _, _ = alist.get_bounds()
4447 alist.move(LH - LA, BH - TA)
4449 # Events.
4450 head.connect("event", lambda *a: self.head_event(*a))
4452 # Bindings to keep.
4453 self.w_ = w_
4454 self._canvas = cnvs
4455 self._alist = alist
4456 self._head = head
4457 self._expander = expander
4458 self._l3tree = l3tree
4460 # Highlighting.
4461 self._outline = None
4463 # Item cross-referencing.
4464 self._marker = None
4465 self._container = None
4467 # Popup menu additions
4468 if isinstance(self, l3Program):
4469 map(self._pup.prepend, [
4470 # Program specials.
4471 [gtk.SeparatorMenuItem(), None],
4472 [ gtk.MenuItem("run code"),
4473 ( "activate", lambda *args: self.run_code())],
4476 map(self._pup.prepend, [
4477 # Outline specials.
4478 [ gtk.SeparatorMenuItem(), None],
4479 [ gtk.MenuItem('view full contents'),
4480 ( 'activate', lambda *args: self.view_as('subtree'))],
4481 [ gtk.MenuItem('view nested outlines'),
4482 ( 'activate', lambda *args: self.view_as('nested'))],
4483 [ gtk.MenuItem('view this level only'),
4484 ( 'activate', lambda *args: self.view_as('flat'))],
4485 [ gtk.SeparatorMenuItem(), None],
4486 [ gtk.MenuItem('show values written'),
4487 ( 'activate', lambda *args: self.show_written_names())],
4488 [ gtk.MenuItem('show values read'),
4489 ( 'activate', lambda *args: self.show_read_names())],
4493 # Borders etc.
4494 self.init_header(rentab)
4495 self.init_deco(rentab)
4496 pass
4497 l3Program.__init__ = __init__
4498 l3ViewList.__init__ = __init__
4501 def view_as(self, type):
4502 def body():
4503 self._l3tree.set_outline(type)
4504 tw = ast.TreeWork(self.w_.state_.storage)
4505 root = tw.find_root(self._l3tree)
4506 if root:
4507 root.set_outl_edges(self.w_, None)
4508 else:
4509 self._l3tree.set_outl_edges(self.w_, None)
4510 self.start_replace_visible()
4511 self.w_.with_fluids(body,
4512 position_tree = False)
4513 l3Program.view_as = view_as
4514 l3ViewList.view_as = view_as
4517 def show_written_names(self):
4518 from l3gui.l3canvas import RenderTable
4519 import re
4521 ignored_syms = re.compile(r'(IDX|ITEMS|LEN|LOOP)[0-9]+')
4523 ma = ast.Matcher()
4524 view, view_id = ast.viewList(aList([])).setup(
4525 empty_parent(),
4526 self._l3tree.eval_env() or self.w_.state_.def_env,
4527 self.w_.state_.storage)
4529 for nd in self._l3tree.top_down_truncate([ast.Function, ast.Call]):
4530 # Several choices exist concerning display of nested
4531 # bindings. These are not visible outside their scope in L3,
4532 # but can be accessed via the interface, and conceivably be
4533 # exported by the language in some way.
4534 # For simplicity, only show those names directly accessible
4535 # here.
4536 if ma.match(nd, Set(Marker('lhs'), Marker('rhs')) ):
4537 if isinstance(ma['lhs'], ast.Symbol):
4538 # Filter out internal names from FOR, WHILE, etc.
4539 if ignored_syms.match(ma['lhs'].py_string()) != None:
4540 continue
4542 node, nid = misc.node_copy(self.w_, ma['lhs'])
4543 view.append_child(node)
4545 view.set_outl_edges(self.w_, None)
4546 view.set_outline('subtree')
4548 # Add label.
4549 view.set_label('Values written by -->')
4551 # Display the structure.
4552 pic = self._canvas.add_l3tree(view, RenderTable())
4554 # Position to the left of expression.
4555 lp, tp, rp, bp = pic.get_bounds_world()
4556 lo, to, ro, bo = self.get_bounds_world()
4557 pic.move(lo - rp, to - tp)
4558 pass
4559 l3Program.show_written_names = show_written_names
4560 l3ViewList.show_written_names = show_written_names
4563 def show_read_names(self):
4564 from l3gui.l3canvas import RenderTable
4565 import re
4567 ignored_syms = re.compile(r'(IDX|ITEMS|LEN|LOOP)[0-9]+')
4568 valid_ident = re.compile(r'[a-zA-Z0-9_]+')
4569 ignored_lhs = [] # Symbols to ignore.
4570 shown = [] # Already included.
4571 ma = ast.Matcher()
4573 # Prepare display list.
4574 view, view_id = ast.viewList(aList([])).setup(
4575 empty_parent(),
4576 self._l3tree.eval_env() or self.w_.state_.def_env,
4577 self.w_.state_.storage)
4579 for nd in self._l3tree.top_down_truncate([]):
4580 if ma.match(nd, Set(Marker('lhs'), Marker('rhs')) ):
4581 if isinstance(ma['lhs'], ast.Symbol):
4582 # Ignore names assigned to.
4583 ignored_lhs.append(ma['lhs'])
4584 # TODO: ignore names bound in Function argument list.
4586 # Filter out internal names from FOR, WHILE, etc.
4587 if ignored_syms.match(ma['lhs'].py_string()) != None:
4588 ignored_lhs.append(ma['lhs'])
4590 if isinstance(nd, ast.Symbol) and \
4591 (nd not in ignored_lhs) and \
4592 (nd not in shown) and \
4593 valid_ident.match(nd.py_string()): # Ignore operators.
4594 node, nid = misc.node_copy(self.w_, nd)
4595 view.append_child(node)
4596 shown.append(nd)
4598 view.set_outl_edges(self.w_, None)
4599 view.set_outline('subtree')
4601 # Add label.
4602 view.set_label('Values read by -->')
4604 # Display the structure.
4605 pic = self._canvas.add_l3tree(view, RenderTable())
4607 # Position to the left of expression.
4608 lp, tp, rp, bp = pic.get_bounds_world()
4609 lo, to, ro, bo = self.get_bounds_world()
4610 pic.move(lo - rp, to - tp)
4611 pass
4612 l3Program.show_read_names = show_read_names
4613 l3ViewList.show_read_names = show_read_names
4615 def run_code(self):
4616 # Attach progress indicator to visible nodes.
4617 for nd in self.iter_visibles():
4618 nd._l3tree._pre_interp_hook = misc.DisplayInterp(self.w_, nd)
4620 # Execute the program, redirecting stdout/err to the message handler.
4621 w_ = self.w_
4622 sys.stdout.flush()
4623 sys.stderr.flush()
4625 w_.stdinouterr.push()
4626 if not w_.opts.gui.native_console:
4627 w_.message.std_to_widget()
4628 ## sys.settrace (w_.message.idle) # MAJOR slowdown!
4629 try:
4630 pprint(self._l3tree.interpret(w_.state_.def_env, w_.state_.storage))
4631 except:
4632 if w_.opts.gui.native_console:
4633 raise # allow debugging via pdb.pm()
4634 try:
4635 tb = sys.exc_traceback
4636 if tb:
4637 tb = tb.tb_next
4638 traceback.print_exception(sys.exc_type, sys.exc_value, tb)
4639 except:
4640 w_.message.std_to_default()
4641 traceback.print_exc()
4642 ## sys.settrace(None)
4643 # Restore stdin/out/err
4644 w_.stdinouterr.pop()
4645 # Remove progress indicators (assuming no editing happened during
4646 # execution...)
4647 for nd in self.iter_visibles():
4648 nd._l3tree._pre_interp_hook = None
4649 l3Program.run_code = run_code
4651 #* visit visible nodes
4652 # Visit visible nodes that have l3trees.
4653 # Taken from `def hide(...)` and adjusted. These need testing.
4654 def iter_visibles(self):
4655 yield self
4656 for ii in self._d_elements:
4657 for prop_iter in ii.iter_visibles():
4658 yield prop_iter
4659 l3Loop.iter_visibles = iter_visibles
4661 def iter_visibles(self):
4662 return []
4663 Label.iter_visibles = iter_visibles
4664 Image.iter_visibles = iter_visibles
4665 Widget.iter_visibles = iter_visibles
4666 uWidget.iter_visibles = iter_visibles
4667 Placeholder.iter_visibles = iter_visibles
4669 def iter_visibles(self):
4670 raise DisplayError("Interface only: " + str(self.__class__))
4671 l3Base.iter_visibles = iter_visibles
4673 def iter_visibles(self):
4674 # aLists are list subclasses and have no custom __deepcopy__, so
4675 # attaching anything to them causes copy problems during .interpret()
4676 ## yield self
4677 for ch in self._dlist:
4678 for prop_iter in ch.iter_visibles():
4679 yield prop_iter
4680 l3aList.iter_visibles = iter_visibles
4682 def iter_visibles(self):
4683 yield self
4684 for sub in self._subtrees:
4685 for prop_iter in sub.iter_visibles():
4686 yield prop_iter
4687 l3Rawtext.iter_visibles = iter_visibles
4689 def iter_visibles(self):
4690 yield self
4691 for prop_iter in self._alist.iter_visibles():
4692 yield prop_iter
4693 for prop_iter in self._head.iter_visibles():
4694 yield prop_iter
4695 l3List.iter_visibles = iter_visibles
4696 l3Map.iter_visibles = iter_visibles
4698 def iter_visibles(self):
4699 yield self
4700 if self._l3tree._outl_type in ['subtree', 'nested']:
4701 for prop_iter in self._alist.iter_visibles():
4702 yield prop_iter
4703 for prop_iter in self._head.iter_visibles():
4704 yield prop_iter
4705 elif self._l3tree._outl_type == 'flat':
4706 pass
4707 else:
4708 raise Exception("Invalid _outl_type. Internal error.")
4709 l3ViewList.iter_visibles = iter_visibles
4711 def iter_visibles(self):
4712 yield self
4713 for prop_iter in self._d_lhs.iter_visibles():
4714 yield prop_iter
4715 for prop_iter in self._d_equal.iter_visibles():
4716 yield prop_iter
4717 for prop_iter in self._d_rhs.iter_visibles():
4718 yield prop_iter
4719 l3Set.iter_visibles = iter_visibles
4721 def iter_visibles(self):
4722 yield self
4723 for prop_iter in self._d_label.iter_visibles():
4724 yield prop_iter
4725 l3IfLoopBreak.iter_visibles = iter_visibles
4726 l3IfLoopContinue.iter_visibles = iter_visibles
4728 def iter_visibles(self):
4729 yield self
4730 for prop_iter in self._d_loop.iter_visibles():
4731 yield prop_iter
4733 for prop_iter in self._d_body.iter_visibles():
4734 yield prop_iter
4735 l3IfLoop.iter_visibles = iter_visibles
4738 def iter_visibles(self):
4739 yield self
4740 for prop_iter in self._d_cond_V.iter_visibles():
4741 yield prop_iter
4743 for prop_iter in self._d_cond_SEQ.iter_visibles():
4744 yield prop_iter
4746 for prop_iter in self._d_body.iter_visibles():
4747 yield prop_iter
4748 l3IfFor.iter_visibles = iter_visibles
4750 def iter_visibles(self):
4751 yield self
4752 for prop_iter in self._d_loop.iter_visibles():
4753 yield prop_iter
4755 for prop_iter in self._d_cond.iter_visibles():
4756 yield prop_iter
4758 for prop_iter in self._d_body.iter_visibles():
4759 yield prop_iter
4760 l3IfWhile.iter_visibles = iter_visibles
4762 def iter_visibles(self):
4763 yield self
4764 for prop_iter in self._d_if.iter_visibles():
4765 yield prop_iter
4767 for prop_iter in self._d_cond.iter_visibles():
4768 yield prop_iter
4770 for prop_iter in self._d_yes.iter_visibles():
4771 yield prop_iter
4773 for prop_iter in self._d_else.iter_visibles():
4774 yield prop_iter
4776 for prop_iter in self._d_no.iter_visibles():
4777 yield prop_iter
4778 l3If.iter_visibles = iter_visibles
4780 def iter_visibles(self):
4781 yield self
4782 for prop_iter in self._d_func.iter_visibles():
4783 yield prop_iter
4785 for prop_iter in self._d_args.iter_visibles():
4786 yield prop_iter
4787 l3Call.iter_visibles = iter_visibles
4789 def iter_visibles(self):
4790 yield self
4791 for prop_iter in self._d_function.iter_visibles():
4792 yield prop_iter
4794 for prop_iter in self._d_args.iter_visibles():
4795 yield prop_iter
4797 for prop_iter in self._d_body.iter_visibles():
4798 yield prop_iter
4799 l3Function.iter_visibles = iter_visibles
4801 def iter_visibles(self):
4802 yield self
4803 for prop_iter in self._alist.iter_visibles():
4804 yield prop_iter
4806 for prop_iter in self._head.iter_visibles():
4807 yield prop_iter
4808 l3Program.iter_visibles = iter_visibles
4810 def iter_visibles(self):
4811 yield self
4812 for prop_iter in self._pystr.iter_visibles():
4813 yield prop_iter
4815 for prop_iter in self._head.iter_visibles():
4816 yield prop_iter
4817 l3Inline.iter_visibles = iter_visibles
4818 l3Native.iter_visibles = iter_visibles
4821 #* hiding
4822 def hide(self):
4823 self._root_group.hide()
4824 for ii in self._d_elements:
4825 ii.hide()
4826 l3Loop.hide = hide
4828 def hide(self):
4829 self._root_group.hide()
4830 Label.hide = hide
4831 Image.hide = hide
4832 Widget.hide = hide
4833 uWidget.hide = hide
4835 def hide(self):
4836 raise DisplayError("Interface only: " + str(self.__class__))
4837 l3Base.hide = hide
4839 def hide(self):
4840 self._root_group.hide()
4841 for ch in self._dlist:
4842 ch.hide()
4843 l3aList.hide = hide
4845 def hide(self):
4846 self._root_group.hide()
4847 self._ltext.hide()
4848 l3Rawtext.hide = hide
4850 def hide(self):
4851 self._root_group.hide()
4852 self._alist.hide()
4853 self._head.hide()
4854 l3List.hide = hide
4855 l3Map.hide = hide
4857 def hide(self):
4858 self._root_group.hide()
4859 self._d_lhs.hide()
4860 self._d_equal.hide()
4861 self._d_rhs.hide()
4862 l3Set.hide = hide
4864 def hide(self):
4865 self._root_group.hide()
4866 self._d_label.hide()
4867 l3IfLoopBreak.hide = hide
4868 l3IfLoopContinue.hide = hide
4870 def hide(self):
4871 self._root_group.hide()
4872 self._d_loop.hide()
4873 self._d_body.hide()
4874 l3IfLoop.hide = hide
4876 def hide(self):
4877 self._root_group.hide()
4878 self._d_loop.hide()
4879 self._d_cond.hide()
4880 self._d_body.hide()
4881 l3IfWhile.hide = hide
4883 def hide(self):
4884 self._root_group.hide()
4885 self._d_if.hide()
4886 self._d_cond.hide()
4887 self._d_yes.hide()
4888 self._d_else.hide()
4889 self._d_no.hide()
4890 l3If.hide = hide
4892 def hide(self):
4893 self._root_group.hide()
4894 self._d_func.hide()
4895 self._d_args.hide()
4896 l3Call.hide = hide
4898 def hide(self):
4899 self._root_group.hide()
4900 self._d_function.hide()
4901 self._d_args.hide()
4902 self._d_body.hide()
4903 l3Function.hide = hide
4905 def hide(self):
4906 self._root_group.hide()
4907 self._alist.hide()
4908 self._head.hide()
4909 l3Program.hide = hide
4911 def hide(self):
4912 self._root_group.hide()
4913 self._pystr.hide()
4914 self._head.hide()
4915 l3Inline.hide = hide
4916 l3Native.hide = hide
4919 #* insert subtree
4920 #** event handler
4921 def insert_event_shared(self, item, event):
4922 if event.type == gtk.gdk.BUTTON_PRESS:
4923 if event.button == 2:
4924 if not self.w_.selector.have_selection():
4925 self.w_.ten_second_message("No node selected.")
4926 return False
4927 else:
4928 self.insert(item, self.w_.selector.get_selection())
4929 return False
4930 l3Call.insert_event = insert_event_shared
4931 l3Set.insert_event = insert_event_shared
4932 l3If.insert_event = insert_event_shared
4933 l3IfWhile.insert_event = insert_event_shared
4936 #** inserter
4937 def append(self, newobj):
4938 self.insert(len(self._l3tree), newobj)
4939 l3aList.append = append
4941 def insert(self, index, newobj):
4942 ### Remove any existing references to newobj in the CALLER --
4943 ### distinguish between MOVE and COPY.
4945 assert isinstance(newobj, l3Base)
4947 # Avoid special cases:
4948 if newobj in self._dlist:
4949 self.w_.ten_second_message("Disconnect element before inserting "
4950 "into the same list.")
4951 return
4953 if newobj.contains_recursive(self):
4954 self.w_.ten_second_message("Cannot insert list into itself.")
4955 return
4957 if newobj._canvas != self._canvas:
4958 self.w_.ten_second_message("Cannot move objects across displays. "
4959 "Copy instead.")
4960 return
4962 # Reparent object.
4963 newobj.reparent(self)
4965 # Draw new marker over insertion marker.
4966 ox1, oy1 = marker_get_anchor(self.w_, self._marker_lst[index])
4968 if self._l3tree.getthe('layout') == 'horizontal':
4969 ox1 -= self.w_.cp_.marker_padding
4970 ## oy1 += self.w_.cp_.marker_padding
4971 else:
4972 oy1 -= self.w_.cp_.marker_padding
4974 if self._hide_markers:
4975 newmarker = self.draw_marker(ox1, oy1, hidden_color = 'white')
4976 else:
4977 newmarker = self.draw_marker(ox1, oy1)
4979 if self._insertion_on_markers:
4980 self.bind_marker_events(newmarker)
4982 # Adjust positions.
4983 if self._l3tree.getthe('layout') == 'horizontal':
4984 self._adj_h_insert(index, newobj, newmarker)
4985 else:
4986 self._adj_v_insert(index, newobj, newmarker)
4988 # Move following items in parent.
4989 if self._parent:
4990 self._parent.new_size_for(self)
4992 # Update data and marker lists.
4993 if self.w_.fluid_ref(insert_l3_tree = True):
4994 self._l3tree.insert_child_rec(index,
4995 newobj._l3tree,
4996 self.w_.state_.storage)
4997 if self.w_.fluid_ref(trace_gui_events = False):
4998 print "insertion tree"
4999 self._dlist.insert(index, newobj)
5000 self._marker_lst.insert(index, newmarker)
5002 self._mv_spacer()
5004 # inform obj of marker
5005 newobj.setup_marker(newmarker, self)
5006 pass
5007 l3aList.insert = insert
5009 def _adj_v_insert(self, index, newobj, newmarker):
5010 # Put object under marker.
5011 sl, st, sr, sb = marker_get_bounds(self.w_, newmarker).pad_tb()
5012 ol, ot, _, ob = newobj.get_bounds()
5013 newobj.move(sl - ol, sb - ot)
5015 # Move following markers, labels and objects.
5016 shift_y = (sb - st) + (ob - ot) ## + self.w_.cp_.marker_padding
5018 for itm in self._dlist[index : None]:
5019 itm.move(0, shift_y)
5021 for itm in self._marker_lst[index : None]:
5022 itm.move(0, shift_y)
5023 l3aList._adj_v_insert = _adj_v_insert
5025 def _adj_h_insert(self, index, newobj, newmarker):
5026 # Put object under marker.
5027 sl, st, sr, sb = marker_get_bounds(self.w_, newmarker).pad_lr()
5028 ol, ot, or_, ob = newobj.get_bounds()
5029 newobj.move(sr - ol, st - ot)
5031 # Move following markers, labels and objects.
5032 shift_x = (sr - sl) + (or_ - ol) ## + self.w_.cp_.marker_padding
5034 for itm in self._dlist[index : None]:
5035 itm.move(shift_x, 0)
5037 for itm in self._marker_lst[index : None]:
5038 itm.move(shift_x, 0)
5039 l3aList._adj_h_insert = _adj_h_insert
5042 def insert(self, marker, newobj):
5043 assert isinstance(newobj, l3Base)
5045 if marker != self._d_cond_marker:
5046 raise DisplayError("Insertion from wrong marker.")
5048 # Avoid special cases:
5049 if newobj.contains_recursive(self):
5050 self.w_.ten_second_message("Cannot insert if into itself.")
5051 return
5053 if newobj._canvas != self._canvas:
5054 self.w_.ten_second_message("Cannot move objects across displays. "
5055 "Copy instead.")
5056 return
5058 # Validate slot.
5059 old_entry = self._l3tree.deref(0)
5060 slot_available(self.w_, old_entry)
5062 # Update reference.
5063 self._d_cond = d_cond = newobj
5065 # Reparent object.
5066 newobj.reparent(self)
5068 # Position COND.
5069 flush_events()
5070 _, y, x, _ = self._d_if.get_bounds()
5071 u, v, _, _ = self._d_cond.get_bounds()
5072 d_cond.move(x + self.w_.cp_.loop_cond_sep - u, y - v)
5074 # Reposition rest.
5075 self._cond_shift()
5077 # Refresh decoration.
5078 self.refresh_deco()
5080 # Move following items in parent.
5081 if self._parent:
5082 self._parent.new_size_for(self)
5084 # Update tree data.
5085 if self.w_.fluid_ref(insert_l3_tree = True):
5086 self._l3tree.replace_child(old_entry._id, newobj._l3tree)
5088 # Inform obj of marker.
5089 newobj.setup_marker(self._d_cond_marker, self)
5090 pass
5091 l3If.insert = insert
5094 def insert(self, marker, newobj):
5096 Insert new condition.
5098 assert isinstance(newobj, l3Base)
5100 if marker != self._d_cond_marker:
5101 raise DisplayError("Insertion from wrong marker.")
5103 # Avoid special cases:
5104 if newobj.contains_recursive(self):
5105 self.w_.ten_second_message("Cannot insert if into itself.")
5106 return
5108 if newobj._canvas != self._canvas:
5109 self.w_.ten_second_message("Cannot move objects across displays. "
5110 "Copy instead.")
5111 return
5113 # Validate slot.
5114 if len(self._matcher['COND-PARENT']) != 0:
5115 raise DisplayError("Insertion in occupied slot.")
5117 # Update reference.
5118 self._d_cond = d_cond = newobj
5120 # Reparent object.
5121 newobj.reparent(self)
5123 # Position COND.
5124 flush_events()
5125 _, y, x, _ = self._d_loop.get_bounds()
5126 u, v, _, _ = self._d_cond.get_bounds()
5127 d_cond.move(x + self.w_.cp_.loop_cond_sep - u, y - v)
5129 # Reposition rest.
5130 self._cond_shift()
5132 # Refresh decoration.
5133 self.refresh_deco()
5135 # Move following items in parent.
5136 if self._parent:
5137 self._parent.new_size_for(self)
5139 # Update tree data.
5140 if self.w_.fluid_ref(insert_l3_tree = True):
5141 self._matcher['COND-PARENT'].insert_child(
5142 self._matcher['COND-IDX'], newobj._l3tree)
5143 ## from: self._l3tree.replace_child(old_entry._id, newobj._l3tree)
5145 # Inform obj of marker.
5146 newobj.setup_marker(self._d_cond_marker, self)
5147 pass
5148 l3IfWhile.insert = insert
5151 def insert(self, marker, newobj):
5152 assert isinstance(newobj, l3Base)
5154 if marker != self._d_func_marker:
5155 raise DisplayError("Insertion from wrong marker.")
5157 # Avoid special cases:
5158 if newobj.contains_recursive(self):
5159 self.w_.ten_second_message("Cannot insert if into itself.")
5160 return
5162 if newobj._canvas != self._canvas:
5163 self.w_.ten_second_message("Cannot move objects across displays. "
5164 "Copy instead.")
5165 return
5167 # Validate slot.
5168 old_entry = self._l3tree.deref(0)
5169 slot_available(self.w_, old_entry)
5171 # Update reference.
5172 self._d_func = d_func = newobj
5174 # Reparent object.
5175 newobj.reparent(self)
5177 # Position FUNC.
5178 flush_events()
5179 x, y, _, _ = self._d_func_marker.get_bounds()
5180 u, v, _, _ = self._d_func.get_bounds()
5181 d_func.move(x - u - self.w_.cp_.exp_marker_hoff,
5182 y - v - self.w_.cp_.exp_marker_voff)
5184 # Reposition rest.
5185 self._func_shift()
5187 # Update tree data.
5188 if self.w_.fluid_ref(insert_l3_tree = True):
5189 self._l3tree.replace_child(old_entry._id, newobj._l3tree)
5191 # Refresh decoration.
5192 self.refresh_deco()
5194 # Move following items in parent.
5195 if self._parent:
5196 self._parent.new_size_for(self)
5198 # Inform obj of marker.
5199 newobj.setup_marker(self._d_func_marker, self)
5200 pass
5201 l3Call.insert = insert
5204 def insert(self, marker, newobj):
5205 assert isinstance(newobj, l3Base)
5207 # Avoid special cases:
5208 if newobj.contains_recursive(self):
5209 self.w_.ten_second_message("Cannot insert if into itself.")
5210 return
5212 if newobj._canvas != self._canvas:
5213 self.w_.ten_second_message("Cannot move objects across displays. "
5214 "Copy instead.")
5215 return
5217 if marker == self._d_lhs_marker:
5218 # Validate slot.
5219 old_entry = self._l3tree.deref(0)
5220 slot_available(self.w_, old_entry)
5222 # Check and update reference.
5223 self._d_lhs = newobj
5225 # Reparent object.
5226 newobj.reparent(self)
5228 # Position lhs w.r.t. marker
5229 flush_events()
5230 x, y, _, _ = self._d_lhs_marker.get_bounds()
5231 u, v, _, _ = newobj.get_bounds()
5232 newobj.move(x - u - self.w_.cp_.exp_marker_hoff,
5233 y - v - self.w_.cp_.exp_marker_voff)
5235 # Reposition.
5236 self._align_to_lhs()
5238 # Update tree data.
5239 if self.w_.fluid_ref(insert_l3_tree = True):
5240 self._l3tree.replace_child(old_entry._id, newobj._l3tree)
5242 # Hide markers.
5243 self._d_lhs_marker.hide()
5245 elif marker == self._d_rhs_marker:
5246 # Validate slot.
5247 old_entry = self._l3tree.deref(1)
5248 slot_available(self.w_, old_entry)
5250 # Check and update reference.
5251 self._d_rhs = newobj
5253 # Reparent object.
5254 newobj.reparent(self)
5256 # Position rhs.
5257 # see also l3Set._align_to_lhs
5258 flush_events()
5259 x, _, _, y = self._d_rhs_marker.get_bounds()
5260 u, v, _, _ = newobj.get_bounds()
5261 newobj.move(x - u - self.w_.cp_.exp_marker_hoff,
5262 y - v - self._canvas.font_ascent_units() -
5263 self._canvas.bbox_offset_units()
5266 # Reposition.
5268 # Update tree data.
5269 if self.w_.fluid_ref(insert_l3_tree = True):
5270 self._l3tree.replace_child(old_entry._id, newobj._l3tree)
5272 # Hide markers.
5273 self._d_rhs_marker.hide()
5275 else:
5276 raise DisplayError("Insertion from invalid marker.")
5278 # Refresh decoration.
5279 self.refresh_deco()
5281 # Move following items in parent.
5282 if self._parent:
5283 self._parent.new_size_for(self)
5285 # Inform obj of marker.
5286 newobj.setup_marker(marker, self)
5288 pass
5289 l3Set.insert = insert
5293 #* movement
5294 def move(self, dx, dy):
5295 self._root_group.move(dx, dy)
5296 Label.move = move
5297 Image.move = move
5298 Widget.move = move
5299 uWidget.move = move
5301 def move(self, dx, dy):
5302 self._root_group.move(dx, dy)
5303 if self._outline:
5304 self._outline.move(dx, dy)
5305 l3Base.move = move
5307 def move(self, dx, dy):
5308 self._root_group.move(dx, dy)
5309 l3aList.move = move
5312 #* bounding boxes
5313 #** world
5314 def get_bounds_world(self):
5315 i2w = self._root_group.get_property("parent").i2w
5316 x1, y1, x2, y2 = self.get_bounds()
5317 u1, v1 = i2w(x1, y1)
5318 u2, v2 = i2w(x2, y2)
5319 return u1, v1, u2, v2
5320 l3Base.get_bounds_world = get_bounds_world
5321 Label.get_bounds_world = get_bounds_world
5322 Image.get_bounds_world = get_bounds_world
5323 Widget.get_bounds_world = get_bounds_world
5324 uWidget.get_bounds_world = get_bounds_world
5327 #** local
5328 def get_bounds(self):
5329 raise DisplayError("interface only")
5330 l3Base.get_bounds = get_bounds
5332 def get_bounds(self):
5333 ### magic bound offset adjustment hack
5334 x, y, u, v = self._root_group.get_bounds()
5336 # No adjustment when path is absent (like inserting or removing)
5337 if self._deco == None:
5338 # Good for "a = 2" (CanvasText at extremes), too much
5339 # for "<ph> = 2" (CanvasRect on left)
5340 return x + 0.5, y + 0.5, u - 0.5, v - 0.5
5341 # return x + 0.5, y + 0.5, u, v
5342 else:
5343 # With surrounding path decoration.
5344 cp_ = self.w_.cp_
5345 adj = (cp_.deco.outline_width / 2.0) * self._canvas._pixpu
5346 return x + adj, y + adj, u - adj, v - adj
5347 # with header
5348 # return x + 0.5, y + 0.5, u, v
5349 # return x + 0.5, y + 0.5, u - 0.5, v - 0.5
5350 # return x, y, u, v
5351 l3Nested.get_bounds = get_bounds
5353 def get_bounds(self):
5354 (ll, tt, rr, bb) = l3Nested.get_bounds(self)
5355 pad = self.w_.cp_.marker_padding
5356 return (ll, tt, rr + pad, bb + pad)
5357 l3Native.get_bounds = get_bounds
5359 # def get_bounds(self):
5360 # return self._root_group.get_bounds()
5361 # Placeholder.get_bounds = get_bounds
5363 def get_bounds(self):
5364 ### magic bound offset adjustment hack
5365 le, to, ri, bo = self._root_group.get_bounds()
5366 return le, to, ri, bo
5367 # return x + 0.5, y + 0.5, u - 0.5, v - 0.5
5368 l3aList.get_bounds = get_bounds
5370 def get_bounds(self):
5371 x, y, u, v = self._root_group.get_bounds()
5372 # No adjustment when path is absent.
5373 if self._deco == None:
5374 ### magic bound offset adjustment hack
5375 return x + 0.5, y + 0.5, u - 0.5, v - 0.5
5376 else:
5377 # With surrounding path decoration.
5378 cp_ = self.w_.cp_
5379 adj = (cp_.deco.outline_width / 2.0) * self._canvas._pixpu
5380 return x + adj, y + adj, u - adj, v - adj
5381 # with header
5382 l3Rawtext.get_bounds = get_bounds
5384 def get_bounds(self):
5385 ### magic bound offset adjustment hack
5386 x, y, u, v = self._root_group.get_bounds()
5387 return x + 0.5, y + 0.5, u - 0.5, v - 0.5
5388 Label.get_bounds = get_bounds
5389 uWidget.get_bounds = get_bounds
5392 # libart's bounding boxes are a serious problem.
5394 # A rotated rectangle changes bounding box size, which is not
5395 # desirable here. So use an ellipse as background.
5396 # This didn't help, because the triangle is a path, for which the
5397 # bounding box is wrong anyway.
5399 # For this purpose, using symbol glyphs is a better approach anyway,
5400 # but fonts are not handled very well either...
5402 # Time to switch drawing/canvas engine.
5404 def get_bounds(self):
5405 ### magic bound offset adjustment hack
5406 x, y, u, v = self._root_group.get_bounds()
5407 return x + 0.5, y + 0.5, u - 0.5, v - 0.5
5408 uVisibleSymbol.get_bounds = get_bounds
5409 uPartiallyVisible.get_bounds = get_bounds
5410 uInvisibleSymbol.get_bounds = get_bounds
5412 def get_bounds(self):
5413 x, y, u, v = self._root_group.get_bounds()
5414 return x, y, u, v
5415 Widget.get_bounds = get_bounds
5416 Image.get_bounds = get_bounds
5419 def get_bounds(self):
5420 return self._root_group.get_bounds()
5421 l3IfLoopContinue.get_bounds = get_bounds
5422 l3IfLoopBreak.get_bounds = get_bounds
5425 #* Draw insertion markers
5426 def draw_marker_shared(self):
5427 cp = self.w_.cp_
5428 points = [0 , 0,
5429 cp.exp_marker_width , 0,
5430 cp.exp_marker_width , cp.exp_marker_height,
5431 0 , cp.exp_marker_height,
5432 0 , 0,
5434 _marker = self._root_group.add(
5435 canvas.CanvasPolygon,
5436 fill_color = "black",
5437 points = points,
5438 width_units = 0.2,
5439 cap_style = gtk.gdk.CAP_ROUND,
5440 join_style = gtk.gdk.JOIN_ROUND,
5442 self._marker_points[_marker] = points
5443 return _marker
5444 l3Set.draw_marker = draw_marker_shared
5445 l3If.draw_marker = draw_marker_shared
5446 l3IfWhile.draw_marker = draw_marker_shared
5447 l3Call.draw_marker = draw_marker_shared
5448 l3Inline.draw_marker = draw_marker_shared
5450 #* Comments & headers
5452 # Fully movable text, but without any effect on execution.
5453 # These need most of the l3Rawtext functionality; a Label is grossly
5454 # insufficient.
5456 class l3Comment(l3Rawtext):
5457 pass
5459 # # def __init__(self, *args, **kwds):
5460 # # l3Rawtext.__init__(self, *args, **kwds)
5461 # # l3Comment.__init__ = __init__
5463 def init_params(self):
5464 self._font_desc = self.w_.cp_.comment_font
5465 self._font_size = self.w_.cp_.font_size_comments * 1.0 * pango.SCALE
5466 self._fill_color = self.w_.cp_.label_fill_color
5467 self._outline_color = self.w_.cp_.label_outline_color
5468 l3Comment.init_params = init_params
5471 #* Text editing support
5472 # Functions are in calling order.
5474 #** l3Rawtext
5475 def rebuild_tree(self, text):
5476 # Form new tree.
5477 ## print 'text_finished: parent: ', self._l3tree._parent
5478 if self._l3tree._parent:
5479 parent = self.w_.state_.storage.load( self._l3tree._parent )
5480 else:
5481 parent = empty_parent()
5483 ### trap parse errors here
5484 tree = reader.parse(text).body()
5485 tree.setup(parent, self.w_.state_.def_env, self.w_.state_.storage)
5486 tree.set_outl_edges(self.w_, None)
5488 # Reparent.
5489 if self._l3tree._parent:
5490 self._l3tree.deep_replace(tree, self.w_.state_.storage)
5492 self._l3tree = tree
5493 l3Rawtext.rebuild_tree = rebuild_tree
5495 def ed_new_text(self, text):
5496 # Reset text.
5497 self._text_orig = text
5498 text_and_outline(self)
5500 # Resize from root node.
5502 # Adjust highlighting.
5503 if self._outline:
5504 # Avoid repositioning mess.
5505 self.plain_view()
5506 self.highlight()
5507 self._under_destruction = False
5508 l3Rawtext.ed_new_text = ed_new_text
5510 def ed_restore_text(self):
5511 self.ed_new_text(self._text_orig)
5512 self._under_destruction = False
5513 l3Rawtext.ed_restore_text = ed_restore_text
5515 def finish_edit(self):
5516 # Replace the display text with one that includes selectable
5517 # subtrees.
5518 self.start_replace_visible()
5520 # Remove decoration.
5521 pass
5523 # Refresh decoration.
5524 self.refresh_deco()
5525 # Move following items in parent.
5526 if self._parent:
5527 self._parent.new_size_for(self)
5528 l3Rawtext.finish_edit = finish_edit
5531 #** l3Comment
5532 def rebuild_tree(self, text):
5533 # Form new tree.
5534 tree = ast.Comment(text)
5536 # Attach (logically) to node.
5537 if self._parent:
5538 self.w_.deco_table_[ self._parent._l3tree._id ] = tree
5540 tree.setup(empty_parent(), self.w_.state_.def_env, self.w_.state_.storage)
5541 tree.set_outl_edges(self.w_, None)
5543 self._l3tree = tree
5544 l3Comment.rebuild_tree = rebuild_tree
5547 def ed_new_text(self, text):
5548 # Reset text.
5549 self._text_orig = text
5550 # # text_and_outline(self)
5552 # Resize from root node.
5554 # Adjust highlighting.
5555 if self._outline:
5556 # Avoid repositioning mess.
5557 self.plain_view()
5558 self.highlight()
5559 l3Comment.ed_new_text = ed_new_text
5562 def finish_edit(self):
5563 # Refresh decoration.
5564 self.refresh_deco()
5566 # Update geometry.
5567 if self._parent:
5568 p1 = self._parent
5569 p1.refresh_header()
5570 p1.refresh_deco()
5571 if p1._parent:
5572 p1._parent.new_size_for(p1)
5573 l3Comment.finish_edit = finish_edit
5576 #** l3ViewList / l3Program
5577 def ed_restore_text(self):
5578 pass
5579 l3ViewList.ed_restore_text = ed_restore_text
5580 l3Program.ed_restore_text = ed_restore_text
5583 def rebuild_tree(self, text):
5584 def body():
5585 self._l3tree.set_label(text)
5586 self.start_replace_visible()
5587 self.w_.with_fluids(body,
5588 position_tree = False)
5589 l3ViewList.rebuild_tree = rebuild_tree
5590 l3Program.rebuild_tree = rebuild_tree
5593 def ed_new_text(self, text):
5594 # Reset text.
5595 self._text_orig = text
5597 # Adjust highlighting.
5598 if self._outline:
5599 # Avoid repositioning mess.
5600 self.plain_view()
5601 self.highlight()
5602 l3ViewList.ed_new_text = ed_new_text
5603 l3Program.ed_new_text = ed_new_text
5606 def finish_edit(self):
5607 # Refresh decoration.
5608 self.refresh_deco()
5610 # Update geometry.
5611 if self._parent:
5612 self._parent.new_size_for(self)
5614 l3ViewList.finish_edit = finish_edit
5615 l3Program.finish_edit = finish_edit
5618 #** misc.
5619 def prep_deco_text(self):
5620 deco_t = self.w_.deco_table_
5622 # Clear up prior temporaries.
5623 if deco_t.has_key( self._l3tree._id ):
5624 if hasattr(deco_t[ self._l3tree._id ], '_placeholder_temporary'):
5625 del deco_t[ self._l3tree._id ]
5627 # Avoid empty display.
5628 # 1. No default text
5629 deco_text = ""
5631 # 2. Override with explicit deco text.
5632 if deco_t.has_key(self._l3tree._id):
5633 deco_text = deco_t[self._l3tree._id]
5635 # 3. Get automatic deco text for placeholder use, when no "good"
5636 # text is available.
5637 if deco_text == "" and isinstance(self, Placeholder):
5638 deco_text = self._l3tree.deco_title_text()
5639 if deco_text == "":
5640 deco_text = "unlabeled code"
5641 # Update deco info.
5642 # Set as default for this node.
5643 comm = deco_t[self._l3tree._id] = ast.Comment(deco_text)
5644 comm.setup(ast.empty_parent(),
5645 self.w_.state_.def_env,
5646 self.w_.state_.storage)
5647 # Mark as temporary.
5648 comm._placeholder_temporary = 1
5650 return deco_text
5651 l3Nested.prep_deco_text = prep_deco_text
5652 l3Rawtext.prep_deco_text = prep_deco_text
5655 # Draw the header before the current contents of the _root_group.
5656 # Additions are made to the same _root_group.
5658 # Used after subclass __init__, before init_deco().
5660 def init_header(self, rentab):
5661 deco_text = self.prep_deco_text()
5662 # Maybe add header.
5663 if deco_text != "":
5664 # Create header and align H[eader] with S[elf].
5665 self._header = self._canvas.add_header_of(self._l3tree, rentab)
5666 self._header.reparent(self) # Only reparent the canvas group.
5667 flush_events()
5668 ls, ts, rs, bs = self.padded_bounds_world()
5669 lh, th, rh, bh = self._header.get_bounds_world()
5671 # Vertical alignment:
5672 if isinstance(self, l3List):
5673 # Header on top of label (hide the label)
5674 ll, tl, rl, bl = self._head.get_bounds_world()
5675 self._header.move(ll - lh, bl - bh)
5676 else:
5677 # H[eader]
5678 # S[elf]
5679 self._header.move(ls - lh, ts - bh)
5680 else:
5681 # No header.
5682 self._header = None
5684 pass
5685 l3Nested.init_header = init_header
5686 l3Rawtext.init_header = init_header
5689 def init_header(self, rentab):
5690 deco_text = self.prep_deco_text()
5691 if deco_text == "":
5692 self._header = None
5693 return
5695 vl_type = self._l3tree.get_outline_type()
5697 if vl_type == 'flat':
5698 # Display only _head (label), ignore _header (comment).
5699 self._header = None
5700 return
5702 # Create header and align H[eader] with S[elf].
5703 self._header = self._canvas.add_header_of(self._l3tree, rentab)
5704 self._header.reparent(self) # Only reparent the canvas group.
5705 flush_events()
5706 # # ls, ts, rs, bs = self.padded_bounds_world()
5707 lh, th, rh, bh = self._header.get_bounds()
5708 le, te, re, be = self._expander.get_bounds()
5709 ll, tl, rl, bl = self._head.get_bounds()
5710 la, ta, ra, ba = self._alist.get_bounds()
5712 # Vertical alignment:
5713 if vl_type in ['nested', 'subtree']:
5714 # Layout:
5715 # E L
5719 # where:
5720 # _head (label, l)
5721 # _header (comment, h)
5722 # body (alist, a)
5724 # Keep existing horizontal positioning for E, L, A; only H is
5725 # new.
5726 self._header.move(la - lh, ta - bh) # H-A
5727 self._head.move(0, # L-A
5728 (ta - (bh - th)) - bl)
5729 self._expander.move(0, # E-A
5730 (ta - (bh - th)) - be)
5732 else:
5733 raise Exception("Invalid outline type. Internal error.")
5734 l3ViewList.init_header = init_header
5735 l3Program.init_header = init_header
5738 def refresh_header(self):
5739 from l3gui.l3canvas import RenderTable
5740 # Delete header visuals (and reinsert with current settings).
5741 _safed(self._header)
5742 self._header = None
5744 # todo: preserve rentab info?
5745 self.init_header(RenderTable())
5746 flush_events()
5747 l3Nested.refresh_header = refresh_header
5748 l3Rawtext.refresh_header = refresh_header
5751 #* event handling
5753 #** drag / selection
5754 def drag_event(self, item, event):
5755 if event.type == gtk.gdk.BUTTON_PRESS:
5756 if event.button == 1:
5757 if event.state & gtk.gdk.CONTROL_MASK:
5758 self.w_.selector.toggle_selection(self)
5759 else:
5760 self.w_.selector.set_selection(self)
5762 self._canvas.grab_focus() # Ensure keystrokes go here.
5764 # sm: move group start
5765 self.remember_x = event.x
5766 self.remember_y = event.y
5767 return True
5769 elif event.type == gtk.gdk.ENTER_NOTIFY:
5770 # Alt + Shift + motion adds self to selection.
5771 if ((event.state & gtk.gdk.SHIFT_MASK) and
5772 (event.state & gtk.gdk.MOD1_MASK)):
5773 self.w_.selector.add_to_selection(self)
5774 return True
5776 elif event.type == gtk.gdk.LEAVE_NOTIFY:
5777 self.w_.cp_.drag_state = (None, None)
5779 elif event.type == gtk.gdk.MOTION_NOTIFY:
5780 if event.state & gtk.gdk.BUTTON1_MASK:
5781 # Do not drag nested text, or the text of Inline.
5782 if isinstance(self._parent, (l3Rawtext, l3Inline)):
5783 (d_state, _) = self.w_.cp_.drag_state
5784 if d_state == "ds_dragging":
5785 return False
5786 else:
5787 self.w_.selector.remove(self)
5788 self.w_.cp_.drag_state = ("ds_start", (event.x, event.y))
5789 return False
5791 # Get the new position and move by the difference.
5793 # sm: move group
5794 # The button_press event above may not have occurred, so
5795 # ensure a valid prior position.
5796 if self.remember_x is None:
5797 self.remember_x = event.x
5798 self.remember_y = event.y
5800 new_x = event.x
5801 new_y = event.y
5802 dx = new_x - self.remember_x
5803 dy = new_y - self.remember_y
5804 self.move(dx, dy)
5805 self.remember_x = new_x
5806 self.remember_y = new_y
5808 # sm: detach item if needed.
5809 if self._marker:
5810 x, y = self.get_anchor()
5811 u, v = marker_get_anchor(self.w_, self._marker)
5812 if self.w_.fluid_ref(trace_gui_events = False):
5813 print "distance: ", abs(u - x) + abs(v - y)
5814 sys.stdout.flush()
5815 if (abs(u - x) + abs(v - y) >
5816 self.w_.cp_.item_detach_distance):
5817 self._marker = None
5818 self._container.detach(self )
5819 self._container = None
5821 return True
5822 return False
5823 l3Rawtext.drag_event = drag_event
5825 def drag_event(self, item, event):
5826 return self._parent.drag_event(item, event)
5827 l3Comment.drag_event = drag_event
5829 def drag_event(self, item, event):
5830 if event.type == gtk.gdk.BUTTON_PRESS:
5831 if event.button == 1:
5832 if event.state & gtk.gdk.CONTROL_MASK:
5833 self.w_.selector.toggle_selection(self)
5834 else:
5835 self.w_.selector.set_selection(self)
5837 self._canvas.grab_focus() # Ensure keystrokes go here.
5839 # sm: move group start
5840 self.remember_x = event.x
5841 self.remember_y = event.y
5842 return True
5844 elif event.type == gtk.gdk.ENTER_NOTIFY:
5845 # Alt + Shift + motion adds self to selection.
5846 if ((event.state & gtk.gdk.SHIFT_MASK) and
5847 (event.state & gtk.gdk.MOD1_MASK)):
5848 self.w_.selector.add_to_selection(self)
5849 return True
5851 elif event.type == gtk.gdk.MOTION_NOTIFY:
5852 if event.state & gtk.gdk.BUTTON1_MASK:
5854 # Get the new position and move by the difference.
5856 # sm: move group
5857 # The button_press event above may not have occurred, so
5858 # ensure a valid prior position.
5859 (d_state, d_val) = self.w_.cp_.drag_state
5860 if d_state == "ds_start":
5861 (self.remember_x, self.remember_y) = d_val
5862 self.w_.cp_.drag_state = ("ds_dragging", d_val)
5864 if self.remember_x is None:
5865 self.remember_x = event.x
5866 self.remember_y = event.y
5868 new_x = event.x
5869 new_y = event.y
5870 dx = new_x - self.remember_x
5871 dy = new_y - self.remember_y
5872 self.move(dx, dy)
5873 self.remember_x = new_x
5874 self.remember_y = new_y
5876 if self._marker:
5877 # Detach from parent once self is far enough from marker.
5878 x, y = self.get_anchor()
5879 u, v = marker_get_anchor(self.w_, self._marker)
5880 if self.w_.fluid_ref(trace_gui_events = False):
5881 print "distance: ", abs(u - x) + abs(v - y)
5882 sys.stdout.flush()
5883 if (abs(u - x) + abs(v - y)) > self.w_.cp_.item_detach_distance:
5884 def _do():
5885 self._container.detach(self)
5886 self._marker = None
5887 self._container = None
5888 misc.single_event(_do)
5889 return True
5891 return False
5892 l3Nested.drag_event = drag_event
5895 def drag_event(self, item, event):
5896 if event.type == gtk.gdk.BUTTON_PRESS:
5897 if event.button == 1:
5898 if event.state & gtk.gdk.CONTROL_MASK:
5899 self.w_.selector.toggle_selection(self)
5900 else:
5901 self.w_.selector.set_selection(self)
5903 self._canvas.grab_focus() # Ensure keystrokes go here.
5905 # sm: move group start
5906 self.remember_x = event.x
5907 self.remember_y = event.y
5908 return True
5910 elif event.type == gtk.gdk.MOTION_NOTIFY:
5911 if event.state & gtk.gdk.BUTTON1_MASK:
5913 # Get the new position and move by the difference.
5915 # sm: move group
5916 new_x = event.x
5917 new_y = event.y
5918 dx = new_x - self.remember_x
5919 dy = new_y - self.remember_y
5920 self.move(dx, dy)
5921 self.remember_x = new_x
5922 self.remember_y = new_y
5923 return True
5925 return False
5926 l3aList.drag_event = drag_event
5929 #** deletion
5930 def destroy_event(self, item, event):
5931 if event.type == gtk.gdk._2BUTTON_PRESS:
5932 if event.button == 3:
5933 self._canvas.remove_node_edge_all(self)
5934 self.destroy()
5935 return False
5936 l3Rawtext.destroy_event = destroy_event
5939 #** edit start
5940 def head_event(self, item, event):
5941 # doubleclick-button-1 to edit.
5942 if event.type == gtk.gdk._2BUTTON_PRESS:
5943 if event.button == 1:
5944 self._editor = TextEdit(self.w_,
5945 self,
5946 self._l3tree.deco_title_text(),
5947 self._canvas._common_tag_table,
5948 self._canvas,
5950 self._editor._view.show()
5951 self._editor._view.grab_focus()
5952 return True
5953 return False
5954 l3ViewList.head_event = head_event
5955 l3Program.head_event = head_event
5959 #* Decoration
5961 #** l3Deco: Decoration around contents.
5962 # This includes the outlines, buttons (if
5963 # any) and the titlebar (if present)
5964 class l3Deco:
5965 pass
5967 def __init__(self, node):
5968 # For full initialization example, see add_deco_to.
5970 # # not practical: self._node_id = node._l3tree._id
5971 # # cyclic: self._node = node
5972 self.w_ = node.w_
5974 self._deco_path = None # art_path
5975 self._deco_path_item = None # canvas.CanvasBpath (holds _deco_path)
5976 self._draw_queue = [] # See add_item()
5978 l3Deco.__init__ = __init__
5980 def add_item(self, cnvsitem):
5981 assert hasattr(cnvsitem, "destroy")
5982 assert hasattr(cnvsitem, "refresh")
5983 self._draw_queue.append(cnvsitem)
5984 l3Deco.add_item = add_item
5986 def destroy(self):
5987 _safed(self._deco_path_item)
5988 for ii in self._draw_queue:
5989 _safed(ii)
5991 self._draw_queue = []
5992 self._deco_path = None
5993 self._deco_path_item = None
5994 l3Deco.destroy = destroy
5997 def magnify_event(self, item, event):
5998 if event.type == gtk.gdk.ENTER_NOTIFY:
5999 if self.w_.fluid_ref(trace_gui_events = False):
6000 print "deco_magnify_event"
6001 item.set_property("width_units",
6002 self.w_.cp_.deco.outline_width *
6003 self.w_.cp_.hover_magnification)
6004 return False
6006 elif event.type == gtk.gdk.LEAVE_NOTIFY:
6007 if self.w_.fluid_ref(trace_gui_events = False):
6008 print "deco_magnify_event"
6009 item.set_property("width_units", self.w_.cp_.deco.outline_width)
6010 return False
6011 l3Deco.magnify_event = magnify_event
6014 #** attach (add) deco to node
6015 def add_deco_to(node, callbacks = [], emphasis_for = None):
6017 Produce and return the l3Deco for `node`.
6018 This routine puts an outline around `node`.
6020 `node` interface requirements:
6021 .get_bounds_world()
6023 ._root_group
6025 Every ballback cb must (1) be callable
6026 (2) return a canvasitem or l3Nested instance OB
6027 The returned Ob must satisfy the interface specified in add_item().
6030 the_deco = l3Deco(node)
6031 # Self-drawing items.
6032 for cb in callbacks:
6033 the_deco.add_item(cb())
6035 # Bounds for the node body.
6036 ll1, tt1, rr1, bb1 = node.get_bounds_world()
6037 path_width = node.w_.cp_.deco.outline_width
6038 if isinstance(node, (l3Nested, Label)):
6039 padding = 2 * path_width
6040 # Pad the content.
6041 ll1 -= padding
6042 tt1 -= padding
6043 rr1 += padding
6044 bb1 += padding
6045 else:
6046 padding = 0
6048 # Check for content, and inflate bounds to get a valid vector path.
6049 if rr1 - ll1 < 1: rr1 = ll1 + 1.0
6050 if bb1 - tt1 < 1: bb1 = tt1 + 1.0
6053 # Draw boundary path.
6055 the_deco._deco_path = path_rectangle_rounded(ll1, rr1, tt1, bb1,
6056 0.5, 0.5, ### params
6057 0.3, 0.3,
6059 # Draw path.
6060 bdry_path = canvas.path_def_new(the_deco._deco_path)
6061 if emphasis_for:
6062 the_deco._deco_path_item = bdry_item = node._root_group.add(
6063 canvas.CanvasBpath,
6064 width_units = path_width,
6065 outline_color_rgba = node.w_.cp_.deco.emph_color[emphasis_for],
6066 fill_color = "green",
6067 cap_style = gtk.gdk.CAP_ROUND,
6068 join_style = gtk.gdk.JOIN_ROUND,
6070 else:
6071 the_deco._deco_path_item = bdry_item = node._root_group.add(
6072 canvas.CanvasBpath,
6073 width_units = path_width,
6074 outline_color_rgba = node.w_.cp_.deco.outline_color,
6075 fill_color = "green",
6076 cap_style = gtk.gdk.CAP_ROUND,
6077 join_style = gtk.gdk.JOIN_ROUND,
6079 bdry_item.set_bpath(bdry_path)
6080 # Adjust coordinate offsets.
6081 l_bi, t_bi, r_bi, b_bi_ = canvas_item_get_bounds_world(bdry_item)
6082 bdry_item.move(ll1 - l_bi - path_width, tt1 - t_bi - path_width)
6084 # Background coloring.
6085 the_deco._background = None
6086 if emphasis_for:
6087 # Draw background.
6088 bck = the_deco._background = node._root_group.add(
6089 canvas.CanvasRect,
6090 x1 = ll1, y1 = tt1,
6091 x2 = rr1, y2 = bb1,
6092 # fill_color_rgba = node.w_.cp_.deco.outline_color,
6093 fill_color = 'white',
6094 width_pixels = node.w_.cp_.outline_width_normal,
6096 # Move background to bottom.
6097 bck.lower_to_bottom()
6100 # Event handling.
6102 the_deco._deco_path_item.connect(
6103 "event", lambda *a: the_deco.magnify_event(*a))
6105 return the_deco
6109 #** init_deco
6110 def padded_bounds_world(self):
6111 # Bounds for the node body.
6112 ll1, tt1, rr1, bb1 = self.get_bounds_world()
6113 path_width = self.w_.cp_.deco.outline_width
6114 if isinstance(self, l3Nested):
6115 padding = 2 * path_width
6116 # Pad the content.
6117 ll1 -= padding
6118 tt1 -= padding
6119 rr1 += padding
6120 bb1 += padding
6121 else:
6122 padding = 0
6124 # Check for content, and inflate bounds to get a valid vector path.
6125 if rr1 - ll1 < 1: rr1 = ll1 + 1.0
6126 if bb1 - tt1 < 1: bb1 = tt1 + 1.0
6128 # Headerless state.
6129 nrr1 = rr1
6130 nbb1 = bb1
6132 return ll1, tt1, rr1, bb1
6133 l3Nested.padded_bounds_world = padded_bounds_world
6134 l3Rawtext.padded_bounds_world = padded_bounds_world
6138 # Draw the border and other decorations around the current
6139 # contents of the _root_group.
6140 # Additions are made to the same _root_group.
6142 # Used *after* init_header().
6145 def init_deco(self, rentab):
6146 # Decorate body.
6147 self._deco = add_deco_to(self)
6148 l3Function.init_deco = init_deco
6150 def init_deco(self, rentab):
6151 # Decorate body.
6152 ## self._deco = add_deco_to(self, callbacks = self._deco_cb_buffer)
6153 self._deco = None
6154 l3IfLoop.init_deco = init_deco
6155 l3IfWhile.init_deco = init_deco
6158 def init_deco(self, rentab):
6159 # Decorate body.
6160 self._deco = None
6161 # Move the placeholder to the right of the header string, into
6162 # the header path.
6163 if self._header != None:
6164 l1, t1, r1, b1 = self._header.get_bounds()
6165 l2, t2, r2, b2 = self._blank.get_bounds()
6166 self._blank.move(l1 - r2 - self.w_.cp_.placeholder.padding,
6167 t1 - t2)
6168 else:
6169 # init_header must always provide a header for Placeholder.
6170 raise Exception("Invalid state in l3Nested.init_deco. "
6171 "No header found. Internal error")
6172 # Emphasize body / add outline.
6173 emph = self._l3tree.get_emphasis()
6174 if emph:
6175 self._deco = add_deco_to(self, emphasis_for = emph)
6176 else:
6177 self._deco = None
6179 Placeholder.init_deco = init_deco
6182 def init_deco(self, rentab):
6183 # Emphasize body / add outline.
6184 emph = self._l3tree.get_emphasis()
6185 if emph:
6186 self._deco = add_deco_to(self, emphasis_for = emph)
6187 else:
6188 self._deco = None
6189 l3Rawtext.init_deco = init_deco
6190 l3Nested.init_deco = init_deco
6194 #** refresh
6195 def refresh_deco(self):
6196 from l3gui.l3canvas import RenderTable
6197 # Remove decoration.
6198 _safed(self._deco)
6200 # Bodyless state
6201 self._deco = None
6203 # todo: preserve rentab info?
6204 self.init_deco(RenderTable())
6205 flush_events()
6206 l3Nested.refresh_deco = refresh_deco
6207 l3Rawtext.refresh_deco = refresh_deco
6210 #** destroy
6211 def destroy_deco(self):
6212 _safed(self._deco)
6213 self._deco = None
6214 _safed(self._header)
6215 self._header = None
6216 # ???
6217 _safed(self._root_group)
6218 del self._root_group
6220 return True
6221 l3Nested.destroy_deco = destroy_deco
6224 #** interactive modification
6225 def deco_change_label(self, label = None):
6226 # The following also works in "evaluate locally"
6227 if not label:
6228 print "enter new label:"
6229 sys.stdout.flush()
6230 label = sys.stdin.readline().rstrip()
6232 assert isinstance(label, StringType), "Label must be a string."
6234 # Update deco info.
6235 comm = self.w_.deco_table_[self._l3tree._id] = ast.Comment(label)
6236 comm.setup(ast.empty_parent(),
6237 self.w_.state_.def_env,
6238 self.w_.state_.storage)
6240 # Refresh decoration.
6241 self.refresh_header()
6242 self.refresh_deco()
6244 # Propagate.
6245 if self._parent:
6246 self._parent.new_size_for(self)
6247 l3Base.deco_change_label = deco_change_label
6249 def deco_add_comment(self):
6250 # Update deco info.
6252 comm = self.w_.deco_table_[self._l3tree._id] = \
6253 ast.Comment("double-click to edit")
6254 comm.setup(ast.empty_parent(),
6255 self.w_.state_.def_env,
6256 self.w_.state_.storage)
6258 # Refresh decoration.
6259 self.refresh_header()
6260 self.refresh_deco()
6262 # Propagate.
6263 if self._parent:
6264 self._parent.new_size_for(self)
6265 l3Base.deco_add_comment = deco_add_comment
6268 #* Resizing / new_size_for
6269 #** alist
6270 def new_size_for(self, child):
6271 assert isinstance(child, (l3Base, l3aList))
6272 try:
6273 index = self._dlist.index(child)
6274 except ValueError:
6275 raise DisplayError("nonexistent child.")
6277 # Reposition child.
6278 if self._l3tree.getthe('layout') == 'horizontal':
6279 ml, mt, mr, mb = marker_get_bounds(
6280 self.w_, self._marker_lst[index]).pad_lr()
6281 cl, ct, cr, cb = child.get_bounds()
6283 # Horizontal alignment:
6284 # M C
6285 child.move(mr - cl, mt - ct)
6286 # Move following markers, labels, and objects
6287 # Find shift.
6288 ml, mt, mr, mb = marker_get_bounds(
6289 self.w_, self._marker_lst[index + 1]).pad_lr()
6290 cl, ct, cr, cb = child.get_bounds()
6291 shift_x = cr - ml
6292 for itm in self._dlist[index + 1 : None]:
6293 itm.move(shift_x, 0)
6294 for itm in self._marker_lst[index + 1 : None]:
6295 itm.move(shift_x, 0)
6297 else:
6298 ml, mt, mr, mb = marker_get_bounds(
6299 self.w_, self._marker_lst[index]).pad_tb()
6300 cl, ct, cr, cb = child.get_bounds()
6303 # Vertical alignment:
6306 child.move(ml - cl, mb - ct)
6307 # Move following markers, labels, and objects
6308 # Find shift.
6309 x, y, _, _ = marker_get_bounds(
6310 self.w_, self._marker_lst[index + 1]).pad_tb()
6311 _, _, u, v = child.get_bounds()
6312 shift_y = v - y
6313 for itm in self._dlist[index + 1 : None]:
6314 itm.move(0, shift_y)
6315 for itm in self._marker_lst[index + 1 : None]:
6316 itm.move(0, shift_y)
6318 # Propagate.
6319 if self._parent:
6320 self._parent.new_size_for(self)
6321 return
6322 l3aList.new_size_for = new_size_for
6325 #** nested / native
6326 def new_size_for(self, child):
6327 # Contained alist is updated; only forward request.
6328 if self._parent:
6329 self._parent.new_size_for(self)
6330 l3Nested.new_size_for = new_size_for
6332 def new_size_for(self, child):
6333 # Contained value updated; only forward request.
6334 if self._parent:
6335 self._parent.new_size_for(self)
6336 l3Native.new_size_for = new_size_for
6339 #*** if / set / call / function
6340 def new_size_for(self, child):
6342 # Shift contents vertically as needed.
6344 assert isinstance(child, (l3Base, l3aList))
6346 # Find and apply shift.
6347 if child == self._d_cond:
6348 _, _, _, y = self._d_cond.get_bounds()
6349 _, v, _, _ = self._d_yes.get_bounds()
6350 dy = y - v
6351 self._d_yes.move(0, dy)
6352 self._d_else.move(0, dy)
6353 self._d_no.move(0, dy)
6355 elif child == self._d_yes:
6356 _, _, _, y = self._d_yes.get_bounds()
6357 _, v, _, _ = self._d_else.get_bounds()
6358 dy = y - v
6359 self._d_else.move(0, dy)
6360 self._d_no.move(0, dy)
6362 elif child == self._d_no:
6363 pass
6365 else:
6366 raise DisplayError("nonexistent child.")
6368 # Refresh decoration.
6369 self.refresh_deco()
6371 # Propagate.
6372 if self._parent:
6373 self._parent.new_size_for(self)
6374 return
6375 l3If.new_size_for = new_size_for
6378 def new_size_for(self, child):
6380 # Shift contents vertically as needed.
6382 assert isinstance(child, (l3Base, l3aList))
6384 # Find and apply shift.
6385 if child is self._d_cond:
6386 _, _, _, bco = self._d_cond.get_bounds()
6387 _, tbo, _, _ = self._d_body.get_bounds()
6388 self._d_body.move(0, bco - tbo)
6390 # Refresh decoration.
6391 self.refresh_deco()
6393 # Propagate.
6394 if self._parent:
6395 self._parent.new_size_for(self)
6396 return
6397 l3IfWhile.new_size_for = new_size_for
6400 def new_size_for(self, child):
6402 # Shift contents vertically as needed.
6404 assert isinstance(child, (l3Base, l3aList))
6406 # Find and apply shift.
6408 # Refresh decoration.
6409 self.refresh_deco()
6411 # Propagate.
6412 if self._parent:
6413 self._parent.new_size_for(self)
6414 return
6415 l3IfLoop.new_size_for = new_size_for
6416 l3IfLoopBreak.new_size_for = new_size_for
6417 l3IfLoopContinue.new_size_for = new_size_for
6420 def new_size_for(self, child):
6422 # Shift contents as needed.
6424 assert isinstance(child, (l3Base, l3aList))
6426 # Find and apply shift.
6427 if child == self._d_lhs:
6428 self._align_to_lhs()
6430 elif child == self._d_rhs:
6431 pass
6433 else:
6434 raise DisplayError("nonexistent child.")
6436 # Refresh decoration.
6437 self.refresh_deco()
6439 # Propagate.
6440 if self._parent:
6441 self._parent.new_size_for(self)
6442 l3Set.new_size_for = new_size_for
6445 def new_size_for(self, child):
6447 # Shift contents as needed.
6449 assert isinstance(child, (l3Base, l3aList))
6451 # Find and apply shift.
6452 if child == self._d_func:
6453 self._func_shift()
6455 elif child == self._d_args:
6456 pass
6458 else:
6459 raise DisplayError("nonexistent child.")
6461 # Refresh decoration.
6462 self.refresh_deco()
6464 # Propagate.
6465 if self._parent:
6466 self._parent.new_size_for(self)
6467 l3Call.new_size_for = new_size_for
6470 def new_size_for(self, child):
6472 # Shift contents vertically as needed.
6474 assert isinstance(child, (l3Base, l3aList))
6476 # Find and apply shift.
6477 if child == self._d_args:
6478 _, _, _, y = self._d_args.get_bounds()
6479 _, v, _, _ = self._d_body.get_bounds()
6480 dy = y - v
6481 self._d_body.move(0, dy)
6483 elif child == self._d_body:
6484 pass
6486 else:
6487 raise DisplayError("nonexistent child.")
6489 # Refresh decoration.
6490 self.refresh_deco()
6492 # Propagate.
6493 if self._parent:
6494 self._parent.new_size_for(self)
6495 return
6496 l3Function.new_size_for = new_size_for
6499 #*** list / map / program
6500 def new_size_for(self, child):
6502 # Shift contents vertically as needed.
6504 assert isinstance(child, (l3aList,))
6506 # Find and apply shift.
6508 # Refresh decoration.
6509 self.refresh_deco()
6511 # Propagate.
6512 if self._parent:
6513 self._parent.new_size_for(self)
6514 return
6515 l3Map.new_size_for = new_size_for
6516 l3List.new_size_for = new_size_for
6517 l3Program.new_size_for = new_size_for
6520 #* Introspection
6521 #** internal functions
6522 def marker_eval_local(self, args):
6523 # args: (menuitem, index)
6524 # For console use:
6525 if 0:
6526 from code import InteractiveConsole
6527 ic_dict = locals()
6528 ic = InteractiveConsole(ic_dict)
6529 utils.print_("==== marker index is %d ====" % args[1] )
6530 ic.interact("==== local console; exit with end-of-file (ctrl-d) ====")
6531 utils.print_( "==== local console exit ====")
6532 l3aList.marker_eval_local = marker_eval_local
6534 def eval_local(self, args):
6535 # args: (menuitem, index)
6536 from l3gui.cruft.pylab import Console
6537 name_s = "Local Python Console\nfor %d" % self._l3tree._id
6538 console = Console(
6539 self.w_, locals(),
6540 quit_handler =
6541 lambda *args: (self.w_.notebk_consoles.destroy_page(name_s),
6542 self.w_.stdinouterr.pop()
6544 self.w_.notebk_consoles.add_page(console, name_s)
6545 self.w_.stdinouterr.push()
6546 console.std_to_widget()
6547 console.write("==== Local console; exit with end-of-file (ctrl-d) ====\n"
6548 "==== The name `self` is the instance. ====\n",
6549 style='error')
6550 console.banner()
6551 misc.show_consoles(self.w_)
6552 l3Base.selection_eval_local = eval_local
6553 l3Base.eval_local = eval_local
6554 l3aList.eval_local = eval_local
6557 def eval_local_console(self, args):
6558 # args: (menuitem)
6559 # For use from calling console; this version stops the gui event
6560 # loop.
6561 from code import InteractiveConsole
6562 ic_dict = locals()
6563 ic = InteractiveConsole(ic_dict)
6565 # Simple combination of TxtConsole._raw_input and new_termconsole().
6566 # This is a good overview of the use of those parts.
6567 def _raw_input(prompt=""):
6568 import thread
6569 from threading import Lock
6570 import time
6571 lck = Lock()
6572 value = []
6573 def _do():
6574 try:
6575 value.append(raw_input(prompt))
6576 except EOFError:
6577 value.append(EOFError())
6578 lck.release()
6579 lck.acquire()
6580 thread.start_new_thread(_do, ())
6581 # Manual main loop until input is ready.
6582 while not lck.acquire(False):
6583 flush_events()
6584 time.sleep(0.01)
6585 if isinstance(value[-1], Exception):
6586 raise value[-1]
6587 return value[-1]
6589 ic.raw_input = _raw_input
6590 ic.interact("==== local console; exit with end-of-file (ctrl-d) ====")
6591 utils.print_( "==== local console exit ====")
6592 l3Base.eval_local_console = eval_local_console
6596 #** User functions.
6597 def get_values_list(self):
6598 ''' return ((id, value) list)'''
6599 return self._l3tree.get_values_list(self.w_)
6600 l3Base.get_values_list = get_values_list
6601 l3aList.get_values_list = get_values_list
6603 # # def dump_values(self):
6604 # # st = self.w_.state_.storage
6605 # # tw = ast.TreeWork(self.w_.state_.storage)
6607 # # # Toplevel id (static).
6608 # # c_id = self._l3tree._id
6609 # # G.logger.info("value of %d is %s" % (
6610 # # c_id, st.get_attribute(c_id, 'interp_result')))
6612 # # # Dynamic id(s).
6613 # # clone_l = st.get_attribute(c_id, "interp_clone")
6614 # # if clone_l:
6615 # # G.logger.info("%d has %d clones.\nValues:" % (c_id, len(clone_l)))
6617 # # for id in clone_l:
6618 # # G.logger.info("%d %s\n" %
6619 # # (id, st.get_attribute(id, 'interp_result')))
6620 # # else:
6621 # # G.logger.info("No clones of %d" % c_id)
6623 # # def dump_values(self):
6624 # # ind = " "
6625 # # st = self.w_.state_.storage
6626 # # tw = ast.TreeWork(self.w_.state_.storage)
6628 # # # Toplevel id (static).
6629 # # c_id = self._l3tree._id
6630 # # print "----------------------"
6632 # # # Dynamic id(s).
6633 # # def _dynamic(c_id, lev):
6634 # # clone_l = st.get_attribute(c_id, "interp_clone")
6635 # # if clone_l:
6636 # # print ind*lev, "%d has %d clone(s):" % (c_id, len(clone_l))
6638 # # for id in clone_l:
6639 # # _dynamic(id, lev+1)
6640 # # else:
6641 # # print ind*lev, c_id, "has no clones;",\
6642 # # "value: ", st.get_attribute(c_id, 'interp_result')
6643 # # _dynamic(c_id, 0)
6646 def dump_values(self):
6647 """Print a (potentially) nested tree of values for self and all clones.
6649 ind = " "
6650 st = self.w_.state_.storage
6651 tw = ast.TreeWork(self.w_.state_.storage)
6653 # Toplevel id (static).
6654 c_id = self._l3tree._id
6655 print "----------------------"
6657 # Dynamic id(s).
6658 def _dynamic(c_id, lev):
6659 clone_l = st.get_attribute(c_id, "interp_clone")
6660 if clone_l:
6661 print ind*lev, "%d repeats %d time(s):" % (c_id, len(clone_l))
6663 for id in clone_l:
6664 _dynamic(id, lev+1)
6665 else:
6666 print ind*lev, c_id, "does not repeat;",\
6667 "value: ", st.get_attribute(c_id, 'interp_result')
6668 _dynamic(c_id, 0)
6669 l3Base.dump_values = dump_values
6670 l3aList.dump_values = dump_values
6672 def get_value(self, id):
6673 """Return the value corresponding to the numeric `id`.
6675 st = self.w_.state_.storage
6676 return st.get_attribute(id, 'interp_result')
6677 l3Base.get_value = get_value
6678 l3aList.get_value = get_value
6681 def string_export(self):
6682 ind = " "
6683 st = self.w_.state_.storage
6684 tw = ast.TreeWork(self.w_.state_.storage)
6686 # Toplevel id (static).
6687 c_id = self._l3tree._id
6688 print '---------------------------------'
6690 # Dynamic id(s).
6691 def _dynamic(c_id, lev):
6692 clone_l = st.get_attribute(c_id, "interp_clone")
6693 if clone_l:
6694 # print ind*lev, "%d repeats %d time(s):" % (c_id, len(clone_l))
6695 for id in clone_l:
6696 _dynamic(id, lev+1)
6697 else:
6698 # value in str() form
6699 val = st.get_attribute(c_id, 'interp_result')
6700 if val != None:
6701 print val
6702 _dynamic(c_id, 0)
6703 print '---------------------------------'
6704 l3Base.string_export = string_export
6705 l3aList.string_export = string_export
6708 #* Subtree visibility
6710 #** marking
6711 def mark_as(self, visibility):
6712 # Mark in table.
6713 self._canvas._vis_tab[self._l3tree._id] = visibility
6715 # Background visibility indicator.
6716 def _draw(color):
6717 if self._vis_indic:
6718 self._vis_indic.destroy()
6719 self._vis_indic = None
6721 flush_events()
6722 x1, y1, x2, y2 = self.get_bounds()
6723 pad = self.w_.cp_.highlight_padding
6724 x1 -= pad
6725 y1 -= pad
6726 x2 += pad
6727 y2 += pad
6729 # What depth to use?
6730 # Subtrees are in their own group; within that, the box is
6731 # always at the bottom.
6733 # Tree
6734 # subtree1
6735 # subtree2
6736 # box2
6737 # box1
6738 # Box
6740 # The parent's bounding box should not change.
6741 if self._parent:
6742 add = self._parent._root_group.add
6743 else:
6744 add = self._canvas.root().add
6745 self._vis_indic = add(
6746 canvas.CanvasRect,
6747 x1 = x1, y1 = y1,
6748 x2 = x2, y2 = y2,
6749 fill_color = color,
6750 outline_color = 'black',
6751 width_pixels = self.w_.cp_.outline_width_normal,
6753 self._vis_indic.lower_to_bottom()
6755 if visibility == "vis_hide":
6756 _draw("grey80")
6758 elif visibility == "vis_show":
6759 _draw("white")
6761 elif visibility == "vis_neutral":
6762 if self._vis_indic:
6763 self._vis_indic.destroy()
6764 self._vis_indic = None
6766 else:
6767 raise DisplayError("Invalid visibility flag.")
6768 l3Base.mark_as = mark_as
6771 #** subtree swapping
6772 def start_replace_visible(self):
6773 def body():
6774 if self._parent:
6775 self._parent.replace_visible(self)
6776 else:
6777 self._canvas.replace_visible(self)
6778 self.w_.with_fluids(body,
6779 detach_l3_tree = False,
6780 insert_l3_tree = False,
6782 l3Base.start_replace_visible = start_replace_visible
6784 def replace_visible(self, child):
6785 # Collect info.
6786 marker = child._marker
6787 l3tree = child._l3tree
6789 # Remove existing display.
6790 child.destroy()
6792 # Draw (visible) subtree.
6793 tree_disp = self._canvas.start_add_l3tree(l3tree)
6795 # Attach / move / reparent
6796 flush_events()
6797 self.insert(marker, tree_disp)
6799 # Resize parent.
6800 pass
6801 l3Nested.replace_visible = replace_visible
6803 def replace_visible(self, child):
6804 # Collect info.
6805 index = self._dlist.index(child)
6806 l3tree = child._l3tree
6807 # # if isinstance(l3tree, ast.viewList):
6808 # # l3tree = l3tree._real_tree
6809 # # assert l3tree
6811 # Remove existing display.
6812 child.destroy()
6814 # Draw (visible) subtree.
6815 ### self._canvas._vis_tab.get_render_table(l3tree)
6816 tree_disp = self._canvas.start_add_l3tree(l3tree)
6818 # Attach it.
6819 flush_events()
6820 self.insert(index, tree_disp)
6822 # Resize parent.
6823 if self._parent:
6824 self._parent.new_size_for(self)
6825 l3aList.replace_visible = replace_visible
6828 #** Convenience combinations.
6829 def show_nested_lhs(self):
6830 # Combination.
6831 vista = self._canvas._vis_tab
6833 # Clear existing markings
6834 vista.clear_tree( self._l3tree )
6836 # Mark subtree.
6837 self.mark_as("vis_show")
6839 ma = ast.Matcher()
6840 N = 3 # maximum visible sublevel
6841 for nd, dent in self._l3tree.top_down_indented():
6842 if dent > N:
6843 vista[nd._id] = "vis_hide"
6844 else:
6845 if ma.match(nd, Set(Marker('lhs'), Marker('rhs')) ):
6846 vista[ma['lhs']._id] = "vis_show"
6847 vista[ma['rhs']._id] = "vis_hide"
6849 # Redisplay.
6850 self.start_replace_visible()
6851 l3Base.show_nested_lhs = show_nested_lhs
6853 def show_one_subtree(self):
6854 # Combination.
6855 self.mark_as("vis_show")
6856 self._canvas._vis_tab.hide_at(self._l3tree, 2) ### choose level
6857 self.start_replace_visible()
6858 l3Base.show_one_subtree = show_one_subtree
6860 def show_subtree(self):
6861 # Combination.
6862 def body():
6863 self.mark_as("vis_show")
6864 self.start_replace_visible()
6865 self.w_.with_fluids(body, position_tree = False)
6866 l3Base.show_subtree = show_subtree
6868 def show_full_subtree(self):
6869 self._canvas._vis_tab.clear_tree( self._l3tree )
6870 # # self.mark_as("vis_show")
6871 self.start_replace_visible()
6872 l3Base.show_full_subtree = show_full_subtree
6874 def hide_subtree(self):
6875 # Combination.
6876 self.mark_as("vis_hide")
6877 self.start_replace_visible()
6878 l3Base.hide_subtree = hide_subtree
6881 def hide_subtree(self):
6882 # Redirect the hide request to the tree this comment is attached to.
6883 # Find key matching value -- deco_table_ maps (tree id -> comment)
6884 for tree_id, comment in self.w_.deco_table_.iteritems():
6885 if comment == self._l3tree: break
6886 l3tree = self._canvas._nodes[tree_id]
6887 l3tree.mark_as("vis_hide")
6888 l3tree.start_replace_visible()
6889 l3Comment.hide_subtree = hide_subtree
6892 #* detach header
6893 def detach_header(self, header):
6894 # Allow for multiple headers in the future.
6895 if header != self._header:
6896 raise Exception("detaching unknown header")
6898 # Reparent graphical parts.
6899 header.reparent_to_root()
6900 self._header = None
6902 # Update table data.
6903 # # if self.w_.deco_table_.has_key(self._l3tree._id):
6904 # # del self.w_.deco_table_[self._l3tree._id]
6905 # # else:
6906 # # print "WARNING: disconnected header was not known." \
6907 # # " Internal inconsistency."
6909 # Decoration and header must be separate when destroying
6910 # placeholder constructs (and others?).
6911 ## self.refresh_deco()
6913 # Move following items in parent.
6914 if self._parent:
6915 self._parent.new_size_for(self)
6916 l3Base.detach_header = detach_header
6919 #* detach subtree
6920 #** hooks
6921 def add_reparent_to_root_hook(self, func):
6922 self._reparent_to_root_hook.append(func)
6923 l3Base.add_reparent_to_root_hook = add_reparent_to_root_hook
6924 l3aList.add_reparent_to_root_hook = add_reparent_to_root_hook
6925 Label.add_reparent_to_root_hook = add_reparent_to_root_hook
6926 Widget.add_reparent_to_root_hook = add_reparent_to_root_hook
6927 Image.add_reparent_to_root_hook = add_reparent_to_root_hook
6928 uWidget.add_reparent_to_root_hook = add_reparent_to_root_hook
6930 def _run_reparent_to_root_hook(self):
6931 for hook in self._reparent_to_root_hook:
6932 hook()
6933 self._reparent_to_root_hook = []
6934 l3Base._run_reparent_to_root_hook = _run_reparent_to_root_hook
6935 l3aList._run_reparent_to_root_hook = _run_reparent_to_root_hook
6936 Label._run_reparent_to_root_hook = _run_reparent_to_root_hook
6937 Widget._run_reparent_to_root_hook = _run_reparent_to_root_hook
6938 Image._run_reparent_to_root_hook = _run_reparent_to_root_hook
6939 uWidget._run_reparent_to_root_hook = _run_reparent_to_root_hook
6942 #** editing and deletion
6943 #*** l3aList
6944 def detach(self, child):
6945 # When drag distance from marker to item exceeds item_detach_distance,
6946 # detach the item. This criterion is implemented in
6947 # l3Rawtext.drag_event.
6949 index = self._dlist.index(child)
6950 marker = self._marker_lst[index]
6952 # Reparent graphical parts.
6953 child.reparent_to_root()
6955 # Shift following marker over to-be-detached marker. Also shift
6956 # following objects.
6957 sl, st, _, _ = marker_get_bounds(self.w_, marker)
6958 ol, ot, _, _ = marker_get_bounds(self.w_, self._marker_lst[index + 1])
6959 ## child.get_bounds() is off after the child was dragged.
6960 ## shift_y = (sy2 - st) + (oy2 - ot)
6961 if self._l3tree.getthe('layout') == 'horizontal':
6962 shift_x = - (ol - sl)
6963 for itm in self._dlist[index + 1 : None]:
6964 itm.move(shift_x, 0)
6965 for itm in self._marker_lst[index + 1 : None]:
6966 itm.move(shift_x, 0)
6967 del itm
6969 else:
6970 shift_y = - (ot - st)
6971 for itm in self._dlist[index + 1 : None]:
6972 itm.move(0, shift_y)
6973 for itm in self._marker_lst[index + 1 : None]:
6974 itm.move(0, shift_y)
6975 del itm
6977 # Move following items in parent.
6978 if self._parent:
6979 self._parent.new_size_for(self)
6981 # Update data and marker lists.
6982 if self.w_.fluid_ref(detach_l3_tree = True):
6983 self._l3tree[index].detach_from_parent_rec(self.w_.state_.storage)
6984 del self._dlist[index]
6985 del self._marker_lst[index]
6987 # Delete detached marker.
6988 destroy_if_last(marker)
6989 pass
6990 l3aList.detach = detach
6994 #*** l3Set / l3If / l3Call
6995 def detach(self, child):
6996 assert(child is self._d_body)
6998 # Reparent graphical parts.
6999 child.reparent_to_root()
7001 # Update reference.
7002 self._d_body = None
7004 # Shift body parts.
7006 # Refresh decoration.
7007 self.refresh_deco()
7009 # Move following items in parent.
7010 if self._parent:
7011 self._parent.new_size_for(self)
7013 # Update tree data.
7014 if self.w_.fluid_ref(detach_l3_tree = True):
7015 fail()
7016 # _matcher['LBODY'] is fixed at match time -- manual editing
7017 # invalidates it.
7018 self._matcher['LBODY'].detach_from_parent_rec(self.w_.state_.storage)
7020 pass
7021 l3IfLoop.detach = detach
7023 def detach(self, child):
7024 # When drag distance from marker to item exceeds item_detach_distance,
7025 # detach the item. This criterion is implemented in
7026 # l3Rawtext.drag_event.
7028 if child != self._d_cond:
7029 self.detach_only(child)
7030 return
7032 # Reparent graphical parts.
7033 child.reparent_to_root()
7035 # Update reference.
7036 self._d_cond = None
7038 # Shift body parts.
7039 self._cond_shift()
7041 # Refresh decoration.
7042 self.refresh_deco()
7044 # Move following items in parent.
7045 if self._parent:
7046 self._parent.new_size_for(self)
7048 # Update tree data.
7049 if self.w_.fluid_ref(detach_l3_tree = True):
7050 self._l3tree[0].detach_from_parent_rec(self.w_.state_.storage)
7052 pass
7053 l3If.detach = detach
7056 def detach(self, child):
7058 Detach the condition.
7060 # When drag distance from marker to item exceeds item_detach_distance,
7061 # detach the item. This criterion is implemented in
7062 # l3Rawtext.drag_event.
7064 if child != self._d_cond:
7065 self.detach_only(child)
7066 return
7068 # Reparent graphical parts.
7069 child.reparent_to_root()
7071 # Update reference.
7072 self._d_cond = None
7074 # Shift body parts.
7075 self._cond_shift()
7077 # Refresh decoration.
7078 self.refresh_deco()
7080 # Move following items in parent.
7081 if self._parent:
7082 self._parent.new_size_for(self)
7084 # Update tree data.
7085 if self.w_.fluid_ref(detach_l3_tree = True):
7086 self._matcher.get_cond().detach_from_parent_rec(self.w_.state_.storage)
7087 pass
7088 l3IfWhile.detach = detach
7091 def detach(self, child):
7092 assert(child == self._pystr)
7094 # Reparent graphical parts.
7095 child.reparent_to_root()
7097 # Update reference.
7098 self._pystr = None
7100 # Shift body parts.
7102 # Refresh decoration.
7103 self.refresh_deco()
7105 # Move following items in parent.
7106 if self._parent:
7107 self._parent.new_size_for(self)
7109 # Update tree data.
7110 if self.w_.fluid_ref(detach_l3_tree = True):
7111 self._l3tree[0].detach_from_parent_rec(self.w_.state_.storage)
7113 pass
7114 l3Inline.detach = detach
7116 def detach(self, child):
7117 if child == self._d_func:
7118 ### print "detach: ", self
7120 # Reparent graphical parts.
7121 child.reparent_to_root()
7123 # Update reference.
7124 self._d_func = None
7126 # Shift body parts.
7127 self._func_shift()
7129 # Refresh decoration.
7130 self.refresh_deco()
7132 # Move following items in parent.
7133 if self._parent:
7134 self._parent.new_size_for(self)
7136 # Update tree data.
7137 if self.w_.fluid_ref(detach_l3_tree = True):
7138 self._l3tree[0].detach_from_parent_rec(self.w_.state_.storage)
7140 elif child == self._d_args:
7141 # aList children are only detached on deletion -- no shifting
7142 # or resizing
7144 # Reparent graphical parts.
7145 child.reparent_to_root()
7147 # Update reference.
7148 self._d_args = None
7149 self._update_refs()
7151 # Shift body parts.
7152 pass
7154 # Refresh decoration.
7155 pass
7157 # Move following items in parent.
7159 # Update tree data.
7160 if self.w_.fluid_ref(detach_l3_tree = True):
7161 self._l3tree[1].detach_from_parent_rec(self.w_.state_.storage)
7163 pass
7164 l3Call.detach = detach
7166 def detach(self, child):
7167 if child == self._d_lhs:
7168 # Reparent graphical parts.
7169 child.reparent_to_root()
7171 # Update reference.
7172 self._d_lhs = None
7174 # Shift body parts.
7176 # Update tree data.
7177 if self.w_.fluid_ref(detach_l3_tree = True):
7178 self._l3tree[0].detach_from_parent_rec(self.w_.state_.storage)
7180 # Show markers.
7181 self._d_lhs_marker.show()
7183 elif child == self._d_rhs:
7184 # Reparent graphical parts.
7185 child.reparent_to_root()
7187 # Update reference.
7188 self._d_rhs = None
7190 # Shift body parts.
7192 # Update tree data.
7193 if self.w_.fluid_ref(detach_l3_tree = True):
7194 self._l3tree[1].detach_from_parent_rec(self.w_.state_.storage)
7196 # Show markers.
7197 self._d_rhs_marker.show()
7199 else:
7200 raise DisplayError("Detaching invalid child.")
7202 ### print "detach: ", self
7204 # Refresh decoration.
7205 self.refresh_deco()
7207 # Move following items in parent.
7208 if self._parent:
7209 self._parent.new_size_for(self)
7210 pass
7211 l3Set.detach = detach
7213 #** internal use only
7215 # These types' children are never detached in editing; currently,
7216 # these functions are only called for object destruction.
7218 #*** l3List
7219 def detach(self, child):
7220 # This function is for internal use, not editing -- yet.
7222 if child != self._alist:
7223 raise DisplayError("Detaching invalid child.")
7225 ### print "detach: ", self
7227 # Reparent graphical parts.
7228 child.reparent_to_root()
7230 # Update reference.
7231 self._alist = None
7233 # Shift body parts.
7235 # Refresh decoration.
7236 pass
7238 # Move following items in parent.
7239 if self._parent:
7240 self._parent.new_size_for(self)
7242 # Update tree data.
7243 if self.w_.fluid_ref(detach_l3_tree = True):
7244 self._l3tree[0].detach_from_parent_rec(self.w_.state_.storage)
7246 pass
7247 l3List.detach = detach
7248 l3Map.detach = detach
7249 l3Program.detach = detach
7251 def detach(self, child):
7252 raise Exception("Native types cannot be detached. Internal error.")
7253 l3Native.detach = detach
7257 #*** l3If
7258 def detach_only(self, child):
7259 # Detach any child from self, without shifting, resizing, or
7260 # updating insertion markers.
7261 try:
7262 idx = self._d_elements.index(child)
7263 except ValueError:
7264 raise DisplayError("Detaching invalid child.")
7266 ### print "detach: ", self
7268 # Reparent graphical parts.
7269 child.reparent_to_root()
7271 # Update reference.
7272 self._d_elements[idx] = None
7273 self._update_refs()
7275 # Shift body parts.
7277 # Refresh decoration.
7278 self.refresh_deco()
7280 # Move following items in parent.
7282 # Update tree data.
7283 if self.w_.fluid_ref(detach_l3_tree = True):
7284 self._l3tree[idx].detach_from_parent_rec(self.w_.state_.storage)
7285 l3If.detach_only = detach_only
7286 l3IfWhile.detach_only = detach_only
7290 #*** l3Function
7291 def detach(self, child):
7292 if child == self._d_args:
7293 # Reparent graphical parts.
7294 child.reparent_to_root()
7296 # Update reference.
7297 self._d_args = None
7299 # Shift body parts.
7301 # Update tree data.
7302 if self.w_.fluid_ref(detach_l3_tree = True):
7303 self._l3tree[0].detach_from_parent_rec(self.w_.state_.storage)
7305 elif child == self._d_body:
7306 # Reparent graphical parts.
7307 child.reparent_to_root()
7309 # Update reference.
7310 self._d_body = None
7312 # Shift body parts.
7314 # Update tree data.
7315 if self.w_.fluid_ref(detach_l3_tree = True):
7316 self._l3tree[1].detach_from_parent_rec(self.w_.state_.storage)
7318 else:
7319 raise DisplayError("Detaching invalid child.")
7321 ### print "detach: ", self
7323 # Refresh decoration.
7324 pass
7326 # Move following items in parent.
7327 if self._parent:
7328 self._parent.new_size_for(self)
7329 pass
7330 l3Function.detach = detach
7333 #*** l3Loop
7334 def detach(self, child):
7335 # Skeleton detach method, for compatibility only.
7336 # Because Loop is a macro, none of the toplevel children can be
7337 # edited; but detach is also needed for destruction.
7339 # If detach is called for any child, it should be called for
7340 # all children.
7342 # Reparent graphical parts.
7343 child.reparent_to_root()
7345 # Update reference.
7347 # Shift body parts.
7349 # Refresh decoration.
7351 # Move following items in parent.
7353 # Update tree data.
7354 pass
7355 l3Loop.detach = detach
7359 #* destroy etc: l3 "widget" destruction functions.
7360 from copy import deepcopy, copy
7361 from l3gui.misc import _safed
7363 #** destroy subtree and display
7364 # .destroy() is recursive
7365 #*** common hooks
7366 def add_destroy_hook(self, func):
7367 self._destroy_hook.append(func)
7368 l3Base.add_destroy_hook = add_destroy_hook
7369 l3aList.add_destroy_hook = add_destroy_hook
7370 Label.add_destroy_hook = add_destroy_hook
7371 Widget.add_destroy_hook = add_destroy_hook
7372 Image.add_destroy_hook = add_destroy_hook
7373 uWidget.add_destroy_hook = add_destroy_hook
7375 def _run_destroy_hook(self):
7376 for hook in self._destroy_hook:
7377 hook()
7378 del self._destroy_hook
7379 l3Base._run_destroy_hook = _run_destroy_hook
7380 l3aList._run_destroy_hook = _run_destroy_hook
7381 Label._run_destroy_hook = _run_destroy_hook
7382 Widget._run_destroy_hook = _run_destroy_hook
7383 Image._run_destroy_hook = _run_destroy_hook
7384 uWidget._run_destroy_hook = _run_destroy_hook
7387 #*** Base
7388 def destroy(self):
7389 self._root_group.hide() # Much faster w/o display update.
7390 if self._vis_indic:
7391 self._vis_indic.destroy()
7392 self._vis_indic = None
7394 self._run_destroy_hook()
7395 l3Base.destroy = destroy
7398 #**** Nested
7399 def destroy(self):
7400 l3Base.destroy(self)
7402 if self._container != self._parent:
7403 raise DisplayError("internal _container / _parent inconsistency.")
7405 if self._parent:
7406 self._parent.detach(self)
7407 self._parent = None
7409 # Headerless state.
7410 if self._header:
7411 _safed(self._header)
7412 self._header = None
7414 if self.w_.selector.get_selection() == self:
7415 self.w_.selector.unselect()
7417 self._marker = None
7418 self._container = None
7420 return True
7421 l3Nested.destroy = destroy
7425 #***** derived
7426 def destroy(self):
7427 l3Nested.destroy(self)
7428 _safed(self._d_loop)
7429 _safed(self._d_body)
7430 l3Nested.destroy_deco(self)
7431 l3IfLoop.destroy = destroy
7433 def destroy(self):
7434 l3Nested.destroy(self)
7435 _safed(self._d_label)
7436 l3Nested.destroy_deco(self)
7437 l3IfLoopBreak.destroy = destroy
7438 l3IfLoopContinue.destroy = destroy
7440 def destroy(self):
7441 l3Nested.destroy(self)
7443 _safed(self._d_if)
7444 _safed(self._d_cond)
7445 _safed(self._d_yes)
7446 _safed(self._d_else)
7447 _safed(self._d_no)
7448 ### self._l3tree.delete(self.w_.state_.storage)
7449 l3Nested.destroy_deco(self)
7450 l3If.destroy = destroy
7452 def destroy(self):
7453 l3Nested.destroy(self)
7454 _safed(self._d_loop)
7455 _safed(self._d_cond)
7456 _safed(self._d_body)
7457 l3Nested.destroy_deco(self)
7458 l3IfWhile.destroy = destroy
7460 def destroy(self):
7461 l3Nested.destroy(self)
7463 _safed(self._blank)
7464 l3Nested.destroy_deco(self)
7465 Placeholder.destroy = destroy
7467 def destroy(self):
7468 l3Nested.destroy(self)
7470 _safed(self._d_lhs)
7471 _safed(self._d_equal)
7472 _safed(self._d_rhs)
7473 ### self._l3tree.delete(self.w_.state_.storage)
7474 l3Nested.destroy_deco(self)
7475 l3Set.destroy = destroy
7477 def destroy(self):
7478 l3Nested.destroy(self)
7480 _safed(self._d_func)
7481 _safed(self._d_args)
7482 ### self._l3tree.delete(self.w_.state_.storage)
7483 l3Nested.destroy_deco(self)
7484 l3Call.destroy = destroy
7486 def destroy(self):
7487 l3Nested.destroy(self)
7489 _safed(self._d_function)
7490 _safed(self._d_args)
7491 _safed(self._d_body)
7493 ### self._l3tree.delete(self.w_.state_.storage)
7495 l3Nested.destroy_deco(self)
7496 l3Function.destroy = destroy
7498 def destroy(self):
7499 l3Nested.destroy(self)
7500 _safed(self._head)
7501 _safed(self._alist)
7502 ### self._l3tree.delete(self.w_.state_.storage)
7503 l3Nested.destroy_deco(self)
7504 l3List.destroy = destroy
7505 l3Map.destroy = destroy
7506 l3Program.destroy = destroy
7508 def destroy(self):
7509 l3Nested.destroy(self)
7510 _safed(self._head)
7511 _safed(self._pystr)
7512 l3Nested.destroy_deco(self)
7513 l3Inline.destroy = destroy
7514 l3Native.destroy = destroy
7517 #*** independent
7518 def destroy(self):
7519 self._root_group.hide() # Much faster w/o display update.
7520 if self._parent:
7521 self._parent.detach(self)
7522 self._parent = None
7523 self._marker = None
7524 self._container = None
7526 if self.w_.selector.get_selection() == self:
7527 self.w_.selector.unselect()
7529 # Remove other's _marker references first.
7530 for entry in copy(self._dlist): # _dlist changes during deletion
7531 _safed(entry)
7533 for mark in copy(self._marker_lst):
7534 _safed(mark)
7536 ### self._l3tree.delete(self.w_.state_.storage)
7538 _safed(self._root_group)
7539 del self._root_group
7541 self._run_destroy_hook()
7542 pass
7543 l3aList.destroy = destroy
7546 def destroy(self):
7547 # .destroy order checks.
7548 self._under_destruction = True
7550 self._canvas.remove_zoom_text(self)
7552 l3Base.destroy(self)
7554 # For structures, _marker and _container are set.
7555 # For nested text fragments (only editable via text editing),
7556 # _container and _marker are not set.
7557 inside_text = isinstance(self._parent, l3Rawtext)
7558 if not inside_text:
7559 if self._container != self._parent:
7560 raise DisplayError("internal _parent / _marker inconsistency.")
7562 if self._parent:
7563 if not inside_text:
7564 self._parent.detach(self)
7565 self._parent = None
7566 self._marker = None
7567 self._container = None
7569 # Headerless state.
7570 if self._header:
7571 _safed(self._header)
7572 self._header = None
7574 # if self._marker:
7575 # self._container.detach(self)
7576 # self._marker = None
7577 # self._container = None
7579 if self.w_.selector.get_selection() == self:
7580 self.w_.selector.unselect()
7582 # Destroy children first.
7583 for ch in copy(self._subtrees):
7584 _safed(ch)
7586 ### self._l3tree.delete(self.w_.state_.storage)
7588 # Destroy the display elements.
7589 _safed(self._ltext)
7590 _safed(self._loutline)
7591 _safed(self._root_group)
7592 del self._root_group
7593 del self._ltext
7594 del self._loutline
7595 l3Rawtext.destroy = destroy
7597 def destroy(self):
7598 # .destroy order checks.
7599 self._under_destruction = True
7601 self._canvas.remove_zoom_text(self)
7603 l3Base.destroy(self)
7605 # Diff.
7606 if self._container != None:
7607 raise DisplayError("internal marker inconsistency.")
7609 # Diff.
7610 if self._parent:
7611 self._parent.detach_header(self)
7612 self._parent = None
7613 self._marker = None
7614 self._container = None
7616 if self.w_.selector.get_selection() == self:
7617 self.w_.selector.unselect()
7619 _safed(self._ltext)
7620 _safed(self._loutline)
7621 _safed(self._root_group)
7622 del self._root_group
7623 del self._ltext
7624 del self._loutline
7625 l3Comment.destroy = destroy
7627 def destroy(self):
7628 self._canvas.remove_zoom_text(self)
7629 _safed(self._loutline)
7630 _safed(self._ltext)
7631 _safed(self._root_group)
7633 self._run_destroy_hook()
7634 Label.destroy = destroy
7636 def destroy(self):
7637 _safed(self._ltext)
7638 _safed(self._root_group)
7639 self._run_destroy_hook()
7640 Widget.destroy = destroy
7641 Image.destroy = destroy
7642 uWidget.destroy = destroy
7645 #* Saving and loading of state.
7646 # The main entry points are `save_state` and `load_state`.
7647 from types import IntType, LongType
7649 from l3gui.misc import _get_props, _set_props
7652 #** saving
7653 # The Canvas* instances are not extensible; either subclass them here for
7654 # smooth persistence -- or use a dispatch table.
7656 # Some of the more useful properties (width-units, char* version of
7657 # fill-color) are write-only. Subclasses could intercept and store
7658 # them.
7659 # Generally, mirroring properties in a derived class (or elsewhere)
7660 # is not practical; many properties are changed via commands other
7661 # than .set() and .set_property(), and those changes need to be
7662 # observed.
7664 # So, rather than mirroring much of the gtk object tree, use only
7665 # attributes that are Read/Write, AND can be pickled if possible.
7667 # When absolutely necessary, provide special access functions for
7668 # specific properties.
7671 #*** gtk widgets
7672 def st_TextBuffer(item, prop_list):
7673 ## item.get_text(*item.get_bounds())
7674 return _get_props(
7675 item, prop_list,
7676 ## "tag-table", # GtkTextTagTable : Read / Write / Construct Only
7677 # Not in pygtk
7678 ## "text", # gchararray : Read / Write
7681 def st_TextTag(item, prop_list):
7682 return _get_props(
7683 item, prop_list,
7684 ## "background", # gchararray : Write
7685 "background-full-height-set", # gboolean : Read / Write
7686 "background-full-height", # gboolean : Read / Write
7687 ## "background-gdk", # GdkColor : Read / Write
7688 ## "background-set", # gboolean : Read / Write
7689 ## "background-stipple", # GdkPixmap : Read / Write
7690 ## "background-stipple-set", # gboolean : Read / Write
7691 ## "direction", # GtkTextDirection : Read / Write
7692 "editable-set", # gboolean : Read / Write
7693 "editable", # gboolean : Read / Write
7694 "family-set", # gboolean : Read / Write
7695 "family", # gchararray : Read / Write
7696 "font", # gchararray : Read / Write
7697 ## "font-desc", # PangoFontDescription : Read / Write
7698 ## "foreground", # gchararray : Write
7699 ## "foreground-gdk", # GdkColor : Read / Write
7700 ## "foreground-set", # gboolean : Read / Write
7701 ## "foreground-stipple", # GdkPixmap : Read / Write
7702 ## "foreground-stipple-set", # gboolean : Read / Write
7703 ## "indent", # gint : Read / Write
7704 ## "indent-set", # gboolean : Read / Write
7705 ## "invisible", # gboolean : Read / Write
7706 ## "invisible-set", # gboolean : Read / Write
7707 ## "justification", # GtkJustification : Read / Write
7708 ## "justification-set", # gboolean : Read / Write
7709 ## "language", # gchararray : Read / Write
7710 ## "language-set", # gboolean : Read / Write
7711 ## "left-margin", # gint : Read / Write
7712 ## "left-margin-set", # gboolean : Read / Write
7713 ## "name", # gchararray : Read / Write / Construct Only
7714 ## "paragraph-background", # gchararray : Write
7715 ## "paragraph-background-gdk", # GdkColor : Read / Write
7716 ## "paragraph-background-set", # gboolean : Read / Write
7717 ## "pixels-above-lines", # gint : Read / Write
7718 ## "pixels-above-lines-set", # gboolean : Read / Write
7719 ## "pixels-below-lines", # gint : Read / Write
7720 ## "pixels-below-lines-set", # gboolean : Read / Write
7721 ## "pixels-inside-wrap", # gint : Read / Write
7722 ## "pixels-inside-wrap-set", # gboolean : Read / Write
7723 ## "right-margin", # gint : Read / Write
7724 ## "right-margin-set", # gboolean : Read / Write
7725 ## "rise", # gint : Read / Write
7726 ## "rise-set", # gboolean : Read / Write
7727 ## "scale", # gdouble : Read / Write
7728 ## "scale-set", # gboolean : Read / Write
7729 ## "size", # gint : Read / Write
7730 "size-set", # gboolean : Read / Write
7731 "size-points", # gdouble : Read / Write
7732 ## "stretch", # PangoStretch : Read / Write
7733 ## "stretch-set", # gboolean : Read / Write
7734 ## "strikethrough", # gboolean : Read / Write
7735 ## "strikethrough-set", # gboolean : Read / Write
7736 ## "style", # PangoStyle : Read / Write
7737 ## "style-set", # gboolean : Read / Write
7738 ## "tabs", # PangoTabArray : Read / Write
7739 ## "tabs-set", # gboolean : Read / Write
7740 ## "underline", # PangoUnderline : Read / Write
7741 ## "underline-set", # gboolean : Read / Write
7742 ## "variant", # PangoVariant : Read / Write
7743 ## "variant-set", # gboolean : Read / Write
7744 ## "weight", # gint : Read / Write
7745 ## "weight-set", # gboolean : Read / Write
7746 ## "wrap-mode", # GtkWrapMode : Read / Write
7747 ## "wrap-mode-set", # gboolean : Read / Write
7750 def st_TextView(item, prop_list):
7751 return _get_props(
7752 item, prop_list,
7753 "accepts-tab", # gboolean : Read / Write
7754 ## "buffer", # GtkTextBuffer : Read / Write
7755 "cursor-visible", # gboolean : Read / Write
7756 "editable", # gboolean : Read / Write
7757 "indent", # gint : Read / Write
7758 ## "justification", # GtkJustification : Read / Write
7759 "left-margin", # gint : Read / Write
7760 "overwrite", # gboolean : Read / Write
7761 "pixels-above-lines", # gint : Read / Write
7762 "pixels-below-lines", # gint : Read / Write
7763 "pixels-inside-wrap", # gint : Read / Write
7764 "right-margin", # gint : Read / Write
7765 ## "tabs", # PangoTabArray : Read / Write
7766 ## "wrap-mode", # GtkWrapMode : Read / Write
7770 #*** canvas items
7771 # List of readable & writeable display properties taken from the
7772 # documentation.
7776 #**** CanvasShape
7777 def st_CanvasShape(item, prop_list):
7778 # The fill-color-gdk is a C struct;
7779 # fill-color-rgba is a (platform-dependent?) value
7780 # The width-units property is needed for scaling.
7781 return _get_props(
7782 item, prop_list,
7783 "cap-style", # GdkCapStyle : Read / Write
7784 "dash", # gpointer : Read / Write
7786 ## "fill-color", # gchararray : Write
7787 ## "fill-color-gdk", # GdkColor : Read / Write
7788 "fill-color-rgba", # guint : Read / Write
7790 "fill-stipple", # GdkDrawable : Read / Write
7791 "join-style", # GdkJoinStyle : Read / Write
7792 "miterlimit", # gdouble : Read / Write
7794 ## "outline-color", # gchararray : Write
7795 ## "outline-color-gdk", # GdkColor : Read / Write
7796 "outline-color-rgba", # guint : Read / Write
7798 "outline-stipple", # GdkDrawable : Read / Write
7799 "width-pixels", # guint : Read / Write
7800 # Do not use scaled units.
7801 ## "width-units", # gdouble : Write
7802 "wind", # guint : Read / Write
7806 #**** CanvasRE
7807 def st_CanvasRE(item, prop_list):
7808 return _get_props(item, prop_list,
7809 "x1", # gdouble : Read / Write
7810 "x2", # gdouble : Read / Write
7811 "y1", # gdouble : Read / Write
7812 "y2", # gdouble : Read / Write
7814 # # Ignore these renderer-specific properties.
7815 # # return st_CanvasShape(item, prop_list)
7818 #**** CanvasPolygon
7819 def st_CanvasPolygon(w_, item, prop_list, creator = None):
7820 if creator:
7821 prop_list.append( ("points", creator._marker_points[item]) )
7822 else:
7823 ### This fails because of a bug in
7824 ### gnome_canvas_polygon_get_property().
7825 raise DisplayError("st_CanvasPolygon(internal): "
7826 "Missing creator arg.")
7827 _get_props(item, prop_list,
7828 "points", # GnomeCanvasPoints : Read / Write
7831 if w_.fluid_ref(dump_ps = False):
7832 pts = creator._marker_points[item]
7833 i2w = item.i2w
7835 print "% st_CanvasPolygon"
7836 if len(pts) >=2 :
7837 print " %s %s gcmoveto" % i2w(pts[0], pts[1])
7838 for pt1, pt2 in zip(pts[2::2], pts[3::2]):
7839 print " %s %s gclineto" % i2w(pt1, pt2)
7840 print " stroke"
7842 return st_CanvasShape(item, prop_list)
7845 #**** CanvasRect
7846 def st_CanvasRect(w_, item, prop_list):
7847 return st_CanvasRE(item, prop_list)
7850 #**** CanvasGroup
7851 def st_CanvasGroup(item, prop_list):
7852 return _get_props(item, prop_list,
7853 "x", # gdouble : Read / Write
7854 "y", # gdouble : Read / Write
7857 #**** CanvasText
7858 def st_CanvasText(w_, item, prop_list):
7859 if w_.fluid_ref(dump_ps = False):
7860 get = item.get_property
7861 i2w = item.i2w
7862 print "% st_CanvasText"
7863 x1, y1, _, _ = item.get_bounds()
7864 print " %s %s gcmoveto" % i2w(x1, y1)
7865 print ' (%s) gcshow' % (get("text"))
7867 return _get_props(
7868 item, prop_list,
7869 "anchor", # GtkAnchorType : Read / Write
7870 ## None fails to restore.
7871 ## "attributes", # PangoAttrList : Read / Write
7872 "clip", # gboolean : Read / Write
7873 "clip-height", # gdouble : Read / Write
7874 "clip-width", # gdouble : Read / Write
7875 "family-set", # gboolean : Read / Write
7876 "family", # gchararray : Read / Write
7877 "fill-color", # gchararray : Read / Write
7878 ## "fill-color-gdk", # GdkColor : Read / Write
7879 "fill-color-rgba", # guint : Read / Write
7880 "fill-stipple", # GdkDrawable : Read / Write
7881 "font", # gchararray : Read / Write
7882 ## "font-desc", # PangoFontDescription : Read / Write
7883 "justification", # GtkJustification : Read / Write
7884 ## "markup", # gchararray : Write
7885 "rise-set", # gboolean : Read / Write
7886 "rise", # gint : Read / Write
7887 "scale-set", # gboolean : Read / Write
7888 "scale", # gdouble : Read / Write
7889 "size", # gint : Read / Write
7890 "size-set", # gboolean : Read / Write
7891 "size-points", # gdouble : Read / Write
7892 "stretch-set", # gboolean : Read / Write
7893 "stretch", # PangoStretch : Read / Write
7894 "strikethrough-set", # gboolean : Read / Write
7895 "strikethrough", # gboolean : Read / Write
7896 "style-set", # gboolean : Read / Write
7897 "style", # PangoStyle : Read / Write
7898 "text", # gchararray : Read / Write
7900 # property text-height is not writable text-height 2.28
7901 # property text-width is not writable text-width 1.68
7902 ## "text-height", # gdouble : Read / Write
7903 ## "text-width", # gdouble : Read / Write
7904 "underline-set", # gboolean : Read / Write
7905 "underline", # PangoUnderline : Read / Write
7906 "variant-set", # gboolean : Read / Write
7907 "variant", # PangoVariant : Read / Write
7908 "weight-set", # gboolean : Read / Write
7909 "weight", # gint : Read / Write
7910 "x", # gdouble : Read / Write
7911 "x-offset", # gdouble : Read / Write
7912 "y", # gdouble : Read / Write
7913 "y-offset", # gdouble : Read / Write
7917 #**** CanvasLine
7918 def st_CanvasLine(w_, item, prop_list):
7919 if w_.fluid_ref(dump_ps = False):
7920 pts = item.get_property("points")
7921 i2w = item.i2w
7923 print "% st_CanvasLine"
7924 if len(pts) >=2 :
7925 print " %s %s gcmoveto" % i2w(pts[0], pts[1])
7926 for pt1, pt2 in zip(pts[2::2], pts[3::2]):
7927 print " %s %s gclineto" % i2w(pt1, pt2)
7928 print " stroke"
7930 return _get_props(
7931 item, prop_list,
7932 "arrow-shape-a", # gdouble : Read / Write
7933 "arrow-shape-b", # gdouble : Read / Write
7934 "arrow-shape-c", # gdouble : Read / Write
7935 "cap-style", # GdkCapStyle : Read / Write
7936 "fill-color", # gchararray : Read / Write
7937 ## "fill-color-gdk", # GdkColor : Read / Write
7938 "fill-color-rgba", # guint : Read / Write
7939 "fill-stipple", # GdkDrawable : Read / Write
7940 "first-arrowhead", # gboolean : Read / Write
7941 "join-style", # GdkJoinStyle : Read / Write
7942 "last-arrowhead", # gboolean : Read / Write
7943 "line-style", # GdkLineStyle : Read / Write
7944 "points", # GnomeCanvasPoints : Read / Write
7945 "smooth", # gboolean : Read / Write
7946 "spline-steps", # guint : Read / Write
7947 ## "width-pixels", # guint : Read / Write
7948 "width-units", # gdouble : Read / Write
7952 #**** CanvasWidget
7953 def st_CanvasWidget(item, prop_list):
7954 return _get_props(
7955 item, prop_list,
7956 ## "anchor", # GtkAnchorType : Read / Write
7957 "height", # gdouble : Read / Write
7958 "size-pixels", # gboolean : Read / Write
7959 ## "widget", # GtkWidget : Read / Write
7960 "width", # gdouble : Read / Write
7961 "x", # gdouble : Read / Write
7962 "y", # gdouble : Read / Write
7966 #*** local classes
7968 # Originally, the full display state was saved via recursion of the
7969 # display tree. This turned out to be a bad idea for file size,
7970 # reliabilty, and made using old state files impossible (just like a
7971 # well-known word processor).
7973 # Now, only the position information of the topmost object is
7974 # collected.
7976 # The traversal used and the data structuring may be
7977 # useful in other contexts (e.g., export to PDF), so the code is
7978 # retained here. Some original notes:
7980 # Pickling highly intertwined (graph-structured) state is tricky. The
7981 # get_state() members are arranged to produce a spanning tree traversal of
7982 # all data and avoid circularities.
7984 # For trees, starting pickling in a subtree and (randomly) getting the
7985 # parents is bad for pickling and reconstruction.
7987 # Also, there is some special state, the global
7988 # w_ == w_
7989 # and multiple upward references like
7990 # self._canvas (circular -- parent)
7992 # This special state is saved only once, and the links restored in a
7993 # separate pass.
7995 def get_state(self):
7997 st = utils.Shared(
7998 _root_group = st_CanvasGroup(self._root_group, []),
8000 return st
8001 l3aList.get_state = get_state
8002 Label.get_state = get_state
8003 Widget.get_state = get_state
8004 Image.get_state = get_state
8005 uWidget.get_state = get_state
8007 def get_state(self):
8008 return utils.Shared(
8009 # # _l3tree = self._l3tree,
8010 _root_group = st_CanvasGroup(self._root_group, []),
8012 l3Base.get_state = get_state
8014 def get_state(self):
8015 return utils.Shared(
8016 l3base = l3Base.get_state(self),
8017 # # _root_group = st_CanvasGroup(self._root_group, []),
8019 l3Rawtext.get_state = get_state
8021 def get_state(self):
8022 return utils.Shared(
8023 l3base = l3Base.get_state(self),
8025 l3Nested.get_state = get_state
8028 def get_state(self):
8029 return None
8030 CommonPopup.get_state = get_state
8032 #*** table formation
8034 def start_set_tables(l3tree):
8036 Fill tables with values stored as attributes of an astType tree
8037 `l3tree`. Return a table of tables.
8039 from l3gui.l3canvas import RenderTable
8040 tables = utils.Shared(rentab = RenderTable())
8041 l3tree.set_tables(tables)
8042 return tables
8044 # These functions are intended to fully traverse the (display) widget
8045 # tree, and may be split into traversal iterators / main functions
8046 # later.
8048 def set_tables(self, tables):
8049 l3Base.set_tables(self, tables)
8050 tables.rentab.set_state(self._l3tree, self._render_mode)
8051 l3Nested.set_tables = set_tables
8054 def set_tables(self, tables):
8055 l3Base.set_tables(self, tables)
8056 tables.rentab.set_state(self._l3tree, self._render_mode)
8057 for st in self._subtrees:
8058 st.set_tables(tables)
8059 l3Rawtext.set_tables = set_tables
8061 def set_tables(self, tables):
8062 l3Rawtext.set_tables(self, tables)
8063 l3Comment.set_tables = set_tables
8065 def set_tables(self, tables):
8066 l3List.set_tables(self, tables)
8067 self._alist.set_tables(tables)
8068 l3ViewList.set_tables = set_tables
8071 def set_tables(self, tables):
8072 l3Nested.set_tables(self, tables)
8073 self._alist.set_tables(tables)
8074 l3List.set_tables = set_tables
8075 l3Map.set_tables = set_tables
8078 def set_tables(self, tables):
8079 l3Nested.set_tables(self, tables)
8080 (_d_cond,
8081 _d_yes ,
8082 _d_no ,
8086 ) = self._d_elements
8087 _d_cond.set_tables(tables)
8088 _d_yes .set_tables(tables)
8089 _d_no .set_tables(tables)
8090 l3If.set_tables = set_tables
8093 def set_tables(self, tables):
8094 l3Nested.set_tables(self, tables)
8095 ( d_loop,
8096 d_body, ) = self._d_elements
8097 d_loop.set_tables(tables)
8098 d_body.set_tables(tables)
8099 l3IfOutline.set_tables = set_tables
8100 l3IfLoop.set_tables = set_tables
8103 def set_tables(self, tables):
8104 l3Nested.set_tables(self, tables)
8105 (d_cond,
8106 d_body,
8109 ) = self._d_elements
8110 d_cond.set_tables(tables)
8111 d_body.set_tables(tables)
8112 l3IfWhile.set_tables = set_tables
8115 def set_tables(self, tables):
8116 l3Nested.set_tables(self, tables)
8117 ( _d_func,
8118 _d_args,
8121 ) = self._d_elements
8122 _d_func.set_tables(tables)
8123 _d_args.set_tables(tables)
8124 l3Call.set_tables = set_tables
8127 def set_tables(self, tables):
8128 l3Nested.set_tables(self, tables)
8129 self._alist.set_tables(tables)
8130 l3Program.set_tables = set_tables
8133 def set_tables(self, tables):
8134 l3Nested.set_tables(self, tables)
8135 self._pystr.set_tables(tables)
8136 l3Inline.set_tables = set_tables
8139 def set_tables(self, tables):
8140 l3Nested.set_tables(self, tables)
8141 self._d_function.set_tables(tables)
8142 self._d_args.set_tables(tables)
8143 self._d_body.set_tables(tables)
8144 l3Function.set_tables = set_tables
8147 def set_tables(self, tables):
8148 l3Nested.set_tables(self, tables)
8149 self._d_lhs.set_tables(tables)
8150 self._d_rhs.set_tables(tables)
8151 l3Set.set_tables = set_tables
8154 def set_tables(self, tables):
8155 l3Nested.set_tables(self, tables)
8156 Placeholder.set_tables = set_tables
8157 l3IfLoopBreak.set_tables = set_tables
8158 l3IfLoopContinue.set_tables = set_tables
8159 l3Native.set_tables = set_tables
8162 def set_tables(self, tables):
8163 pass
8164 Label.set_tables = set_tables
8165 Widget.set_tables = set_tables
8166 Image.set_tables = set_tables
8167 uWidget.set_tables = set_tables
8168 l3Base.set_tables = set_tables
8169 l3Deco.set_tables = set_tables
8172 def set_tables(self, tables):
8173 for itm in self._dlist:
8174 itm.set_tables(tables)
8175 l3aList.set_tables = set_tables
8179 #*** find_root
8180 def find_root(self):
8181 if self._parent != None:
8182 return self._parent.find_root()
8183 else:
8184 return self, self._l3tree._id
8185 l3Base.find_root = find_root
8186 l3aList.find_root = find_root
8188 #** loading
8189 # The reconstruction of the data structures is done in passes:
8190 # - form the spanning tree using loaded data
8191 # - reconnect graph edges.
8194 #*** l3aList
8195 def set_state(self, state):
8196 _set_props(self._root_group, state._root_group)
8197 l3Base.set_state = set_state
8198 l3aList.set_state = set_state
8199 Label.set_state = set_state
8200 Widget.set_state = set_state
8201 Image.set_state = set_state
8202 uWidget.set_state = set_state
8204 def set_state(self, state):
8205 l3Base.set_state(self, state.l3base)
8206 # # _set_props(self._root_group, state._root_group)
8207 l3Rawtext.set_state = set_state
8209 def set_state(self, state):
8210 l3Base.set_state(self, state.l3base)
8211 l3Nested.set_state = set_state
8214 #*** CommonPopup
8215 def set_state(self, state):
8216 pass
8217 CommonPopup.set_state = set_state
8220 #* l3IfFor members
8221 # An experiment of grouping the members with the class definition,
8222 # instead of functional grouping.
8223 # As expected, this class grouping makes function-based additions much
8224 # more difficult.
8226 def continue_stop_pt(self):
8227 # todo.
8228 lc, tc, rc, bc = self._d_loop.get_bounds_world()
8229 return lc + (rc - lc)/10, bc ## parameters
8230 l3IfFor.continue_stop_pt = continue_stop_pt
8232 def break_stop_pt(self):
8233 # todo.
8234 lc, tc, rc, bc = self.get_bounds_world()
8235 return rc + 4, bc ## parameters
8236 l3IfFor.break_stop_pt = break_stop_pt
8239 def __init__(self, w_, cnvs, tree_id, rentab, matcher):
8240 # l3 tree.
8241 l3tree = w_.state_.storage.load(tree_id)
8242 assert isinstance(l3tree, ast.If)
8243 l3Nested.__init__(self, w_, cnvs, l3tree, rentab)
8245 # Bindings to keep.
8246 self.w_ = w_
8247 self._canvas = cnvs
8248 self._marker_points = {} # marker -> point list
8249 self._matcher = ma = matcher
8250 self._l3tree = l3tree
8251 self._deco_cb_buffer = [] # callback list for add_item()
8254 # Display elements.
8255 # -- for
8256 d_loop_for = Label(w_, cnvs, self._root_group, "for")
8258 # -- V
8259 d_cond_V = cnvs.add_l3tree(ma.get_current_V(), rentab)
8260 d_cond_V.reparent(self)
8262 # -- in
8263 d_loop_in = Label(w_, cnvs, self._root_group, "in")
8265 # -- SEQ
8266 d_cond_SEQ = cnvs.add_l3tree(ma.get_current_SEQ(), rentab)
8267 d_cond_SEQ.reparent(self)
8269 # -- B
8270 d_body = l3aList(w_, cnvs,
8271 ma.get_B(),
8272 rentab,
8273 root_group = self._root_group,
8274 draggable = False,
8275 parent = self,
8278 # Marker(s).
8279 d_cond_V_marker = self.draw_marker()
8280 d_cond_V_marker.lower_to_bottom()
8282 d_cond_SEQ_marker = self.draw_marker()
8283 d_cond_SEQ_marker.lower_to_bottom()
8285 # Inform obj of marker.
8286 d_cond_V.setup_marker(d_cond_V_marker, self)
8287 d_cond_SEQ.setup_marker(d_cond_SEQ_marker, self)
8289 # Bindings to keep.
8290 # Indexed access. Match l3tree indexing where applicable.
8291 self._d_elements = [
8292 # l3 ast.
8293 d_cond_V,
8294 d_cond_SEQ,
8295 d_body,
8297 # Rest
8298 d_loop_for,
8299 d_loop_in,
8300 d_cond_V_marker,
8301 d_cond_SEQ_marker,
8303 self._update_refs()
8306 # Align display elements, starting from d_loop_for
8308 self._align_display()
8310 # Highlighting.
8311 self._outline = None
8313 # Item cross-referencing.
8314 self._marker = None
8315 self._container = None
8317 # Event handling.
8318 d_cond_V_marker.connect("event", lambda *a: self.insert_event(*a))
8319 d_cond_SEQ_marker.connect("event", lambda *a: self.insert_event(*a))
8321 # Borders etc.
8322 self.init_header(rentab)
8323 self.init_deco(rentab)
8325 pass
8326 l3IfFor.__init__ = __init__
8328 def _update_refs(self):
8330 self._d_cond_V,
8331 self._d_cond_SEQ,
8332 self._d_body,
8334 self._d_loop_for,
8335 self._d_loop_in,
8336 self._d_cond_V_marker,
8337 self._d_cond_SEQ_marker,
8338 ) = self._d_elements
8339 l3IfFor._update_refs = _update_refs
8342 def _align_display(self):
8343 flush_events()
8345 # Align w.r.t. 'for'
8348 d_cond_V,
8349 d_cond_SEQ,
8350 d_body,
8352 d_loop_for,
8353 d_loop_in,
8354 d_cond_V_marker,
8355 d_cond_SEQ_marker,
8356 ) = self._d_elements
8358 w_ = self.w_
8359 # -- V
8360 l_for, t_for, r_for, b_for = d_loop_for.get_bounds()
8361 l_v, t_v, r_v, b_v = d_cond_V.get_bounds()
8362 d_cond_V.move(r_for + w_.cp_.loop_cond_sep - l_v,
8363 t_for - t_v)
8364 # marker for child replacement.
8365 l_v, t_v, r_v, b_v = d_cond_V.get_bounds()
8366 lma, tma, _, _ = d_cond_V_marker.get_bounds()
8367 d_cond_V_marker.move(l_v - lma + w_.cp_.exp_marker_hoff,
8368 t_v - tma + w_.cp_.exp_marker_voff)
8370 # -- in
8371 l_v, t_v, r_v, b_v = d_cond_V.get_bounds()
8372 l_in, t_in, r_in, b_in = d_loop_in.get_bounds()
8373 d_loop_in.move(r_v + w_.cp_.loop_cond_sep - l_in,
8374 t_v - t_in)
8376 # -- SEQ
8377 l_seq, t_seq, r_seq, b_seq = d_cond_SEQ.get_bounds()
8378 l_in, t_in, r_in, b_in = d_loop_in.get_bounds()
8379 d_cond_SEQ.move(r_in + w_.cp_.loop_cond_sep - l_seq,
8380 t_in - t_seq)
8381 # marker
8382 l_seq, t_seq, r_seq, b_seq = d_cond_SEQ.get_bounds()
8383 lma, tma, _, _ = d_cond_SEQ_marker.get_bounds()
8384 d_cond_SEQ_marker.move(l_seq - lma + w_.cp_.exp_marker_hoff,
8385 t_seq - tma + w_.cp_.exp_marker_voff)
8387 # -- B
8388 l_v, t_v, r_v, b_v = d_cond_V.get_bounds()
8389 l_seq, t_seq, r_seq, b_seq = d_cond_SEQ.get_bounds()
8390 l_b, t_b, r_b, b_b = d_body.get_bounds()
8391 d_body.move(l_for - l_b,
8392 max(b_v, b_seq) - t_b)
8393 l3IfFor._align_display = _align_display
8396 def hide(self):
8397 self._root_group.hide()
8398 self._d_loop_for.hide()
8399 self._d_loop_in.hide()
8400 self._d_cond_V.hide()
8401 self._d_cond_SEQ.hide()
8402 self._d_body.hide()
8403 l3IfFor.hide = hide
8406 def insert(self, marker, newobj):
8408 # Insert new value or sequence
8410 assert isinstance(newobj, l3Base)
8412 # Avoid special cases:
8413 if newobj.contains_recursive(self):
8414 self.w_.ten_second_message("Cannot insert if into itself.")
8415 return
8417 if newobj._canvas != self._canvas:
8418 self.w_.ten_second_message("Cannot move objects across displays. "
8419 "Copy instead.")
8420 return
8422 # Which marker?
8423 if marker == self._d_cond_V_marker:
8424 # Validate slot.
8425 if not self._matcher.get_current_V().eql(ast.aNone()):
8426 raise DisplayError("Insertion in occupied slot.")
8428 # Update reference.
8429 self._d_cond_V = d_cond_V = newobj
8431 # Reparent object.
8432 newobj.reparent(self)
8434 # Position COND.
8435 flush_events()
8437 # Reposition rest.
8438 self._align_display()
8440 # Refresh decoration.
8441 self.refresh_deco()
8443 # Move following items in parent.
8444 if self._parent:
8445 self._parent.new_size_for(self)
8447 # Update tree data.
8448 if self.w_.fluid_ref(insert_l3_tree = True):
8449 self._matcher.set_V(newobj._l3tree)
8451 # Inform obj of marker.
8452 newobj.setup_marker(self._d_cond_V_marker, self)
8454 elif marker == self._d_cond_SEQ_marker:
8455 # Validate slot.
8456 if not self._matcher.get_current_SEQ().eql(ast.aNone()):
8457 raise DisplayError("Insertion in occupied slot.")
8459 # Update reference.
8460 self._d_cond_SEQ = d_cond_SEQ = newobj
8462 # Reparent object.
8463 newobj.reparent(self)
8465 # Position COND.
8466 flush_events()
8468 # Reposition rest.
8469 self._align_display()
8471 # Refresh decoration.
8472 self.refresh_deco()
8474 # Move following items in parent.
8475 if self._parent:
8476 self._parent.new_size_for(self)
8478 # Update tree data.
8479 if self.w_.fluid_ref(insert_l3_tree = True):
8480 self._matcher.set_SEQ(newobj._l3tree)
8482 # Inform obj of marker.
8483 newobj.setup_marker(self._d_cond_SEQ_marker, self)
8485 else:
8486 raise DisplayError("Insertion from wrong marker.")
8487 l3IfFor.insert = insert
8490 def init_deco(self, rentab):
8491 # Decorate body.
8492 self._deco = None ## add_deco_to(self, callbacks = self._deco_cb_buffer)
8493 l3IfFor.init_deco = init_deco
8496 def new_size_for(self, child):
8498 # Shift contents vertically as needed.
8500 assert isinstance(child, (l3Base, l3aList))
8502 # Find and apply shift.
8503 if child in [self._d_cond_V, self._d_cond_SEQ]:
8504 self._align_display()
8506 # Refresh decoration.
8507 self.refresh_deco()
8509 # Propagate.
8510 if self._parent:
8511 self._parent.new_size_for(self)
8512 return
8513 l3IfFor.new_size_for = new_size_for
8516 def detach(self, child):
8517 # When drag distance from marker to item exceeds item_detach_distance,
8518 # detach the item. This criterion is implemented in
8519 # l3Rawtext.drag_event.
8521 if child == self._d_cond_V:
8522 # Update reference.
8523 self._d_cond_V = None
8524 the_child = self._matcher.get_current_V()
8526 elif child == self._d_cond_SEQ:
8527 # Update reference.
8528 self._d_cond_SEQ = None
8529 the_child = self._matcher.get_current_SEQ()
8531 else:
8532 self.detach_only(child)
8533 return
8535 # Reparent graphical parts.
8536 child.reparent_to_root()
8538 # Shift body parts.
8539 # self._align_display()
8541 # Refresh decoration.
8542 self.refresh_deco()
8544 # Move following items in parent.
8545 if self._parent:
8546 self._parent.new_size_for(self)
8548 # Update tree data.
8549 if self.w_.fluid_ref(detach_l3_tree = True):
8550 the_child.detach_from_parent_rec(self.w_.state_.storage)
8551 pass
8552 l3IfFor.detach = detach
8555 def destroy(self):
8556 l3Nested.destroy(self)
8557 _safed(self._d_loop_for)
8558 _safed(self._d_loop_in)
8559 _safed(self._d_cond_SEQ)
8560 _safed(self._d_cond_V)
8561 _safed(self._d_body)
8562 l3Nested.destroy_deco(self)
8563 l3IfFor.destroy = destroy
8566 def set_tables(self, tables):
8567 l3Nested.set_tables(self, tables)
8569 d_cond_V,
8570 d_cond_SEQ,
8571 d_body,
8576 ) = self._d_elements
8577 d_cond_V.set_tables(tables)
8578 d_cond_SEQ.set_tables(tables)
8579 d_body.set_tables(tables)
8580 l3IfFor.set_tables = set_tables
8583 l3IfFor.detach_only = detach_only
8584 l3IfFor.draw_marker = draw_marker_shared
8585 l3IfFor.insert_event = insert_event_shared
8586 l3IfFor.detach_only = detach_only