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
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
19 simple display support
20 These are additional items needed for display, like
21 Placeholder and Header.
26 # policy for flush_events
27 # To ensure proper sizing, flush_events is called after display
29 # Using flush_events in every get_bounds() call slows display down
32 import sys
, weakref
, traceback
, string
, types
, os
33 from math
import floor
, sqrt
34 from pprint
import pprint
40 import gnomecanvas
as canvas
41 from gnomecanvas
import MOVETO_OPEN
, MOVETO
, LINETO
, CURVETO
43 # Try backported version used in sparx.
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 \
59 path_rectangle_rounded
, \
60 canvas_item_get_bounds_world
, \
68 kn
= gtk
.gdk
.keyval_from_name
70 key_Right
= kn("Right")
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)
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)))
97 # Line moves left and up.
101 self
._line
= parent
._root
_group
.add(
103 fill_color
= "green",
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)))
123 # Line moves right and down.
127 self
._line
= parent
._root
_group
.add(
132 cap_style
= gtk
.gdk
.CAP_ROUND
,
133 join_style
= gtk
.gdk
.JOIN_ROUND
,
135 BreakLine
.__init
__ = __init__
140 ContinueLine
.destroy
= destroy
141 BreakLine
.destroy
= destroy
145 ContinueLine
.refresh
= refresh
146 BreakLine
.refresh
= refresh
149 #* Label ( element header display )
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.
158 def __init__(self
, w_
, cnvs
, root_group
, header_text
,
159 x
= 0, y
= 0, font
= None, fill_color
= "white"):
161 font
= w_
.cp_
.label_font
163 # Outline follows l3Rawtext.__init__, but the contents are too
165 self
._destroy
_hook
= [] # (func -> None) list
166 self
._reparent
_to
_root
_hook
= [] # (func -> None) list
173 # Item cross-referencing.
180 self
._root
_group
= root_group
.add(canvas
.CanvasGroup
)
185 # Text content / format / scale
187 self
._ltext
= misc
.GtkObjProxy(self
._root
_group
.add(
189 anchor
= gtk
.ANCHOR_NORTH_WEST
,
192 size
= self
.w_
.cp_
.font_size_labels
* 1.0 * pango
.SCALE
,
197 markup
= header_text
,
201 x1
, y1
, x2
, y2
= self
._ltext
.get_bounds() # world units
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(
209 self
.w_
.cp_
.font_size_labels
* self
._canvas
._abs
_zoom
* pango
.SCALE
)
211 self
._canvas
.add_zoom_text(self
)
216 x1
, y1
, x2
, y2
= self
._ltext
.get_bounds() # world units
217 pad
= w_
.cp_
.textview
.outline_padding
/ cnvs
._pixpu
223 self
._loutline
= self
._root
_group
.add(
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()
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 )
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.
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
268 self
._destroy
_hook
= [] # (func -> None) list
269 self
._reparent
_to
_root
_hook
= [] # (func -> None) list
271 self
._parent
= parent
274 self
._img
_scale
= w_
.cp_
.image_scale
278 # Item cross-referencing.
285 self
._root
_group
= root_group
.add(canvas
.CanvasGroup
)
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(
299 anchor
= gtk
.ANCHOR_NORTH_WEST
,
302 height_in_pixels
= True,
303 width_in_pixels
= True,
304 width
= pixwid
* self
._img
_scale
,
305 height
= pixhei
* self
._img
_scale
,
310 x1
, y1
, x2
, y2
= self
._ltext
.get_bounds() # world units
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(
325 anchor
= gtk
.ANCHOR_NORTH_WEST
,
328 width
= w_
.cp_
.image_width
* woh
* self
._img
_scale
,
329 height
= w_
.cp_
.image_height
* how
* self
._img
_scale
,
334 x1
, y1
, x2
, y2
= self
._ltext
.get_bounds() # world units
341 Image
.__init
__ = __init__
343 # # def resize(self, which, value):
345 # # ''' Resize the pixmap to `value` world units.
346 # # `which` is "width" or "height"
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.
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.
364 self
._parent
.new_size_for(self
)
366 self
._img
_scale
*= ratio
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 )
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.
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
399 self
._destroy
_hook
= [] # (func -> None) list
400 self
._reparent
_to
_root
_hook
= [] # (func -> None) list
402 self
._parent
= parent
408 # Item cross-referencing.
415 self
._root
_group
= root_group
.add(canvas
.CanvasGroup
)
419 # Widget content at original pixel size
421 # Display without aspect distortion.
422 self
._ltext
= misc
.GtkObjProxy(self
._root
_group
.add(
426 anchor
= gtk
.ANCHOR_NORTH_WEST
,
435 x1
, y1
, x2
, y2
= self
._ltext
.get_bounds() # world units
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.
454 self
._parent
.new_size_for(self
)
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 )
473 # Base class for trivial "widgets" like buttons.
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
482 # b) display aestetics
484 # uWidgets handle events only to call appropriate functions of the
486 # uWidgets provide no independent hiding, etc.
488 # See also class Label.
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
501 self
._action
= action
505 # Item cross-referencing.
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.
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
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(
553 anchor
= gtk
.ANCHOR_NORTH_WEST
,
556 size
= self
.w_
.cp_
.font_size
* 1.0 * pango
.SCALE
,
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(
574 self
.w_
.cp_
.font_size
* self
._canvas
._abs
_zoom
* pango
.SCALE
)
576 # Register for zooming.
577 # # self._canvas.add_zoom_text(self)
580 self
.connect("event", lambda *a
: self
.button_event(*a
))
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.'
590 uWidget
.button_event
= button_event
595 class uBlank(uWidget
):
596 '''Display a 1x1 pixel. Use to experiment with layout, without
601 #** uVisibleSymbol ( element header display )
602 class uVisibleSymbol(uWidget
):
606 #** uPartiallyVisible ( element header display )
607 class uPartiallyVisible(uWidget
):
611 #** uInvisibleSymbol ( element header display )
612 class uInvisibleSymbol(uWidget
):
617 def _draw_common_triangle(self
):
622 # This kind of glyph design is silly; using a predefined character
633 self
._ltext
= misc
.GtkObjProxy(self
._grp
_obj
.add(
634 canvas
.CanvasPolygon
,
635 fill_color
= "black",
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
646 # self._loutline = misc.GtkObjProxy(self._grp_obj.add(
652 # fill_color = "white",
653 # outline_color = "white",
654 # width_pixels = self.w_.cp_.outline_width_normal,
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 )
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(
674 fill_color
= "white",
675 outline_color
= "white",
676 width_pixels
= self
.w_
.cp_
.outline_width_normal
,
678 self
._loutline
.lower(1)
683 self
.connect("event", lambda *a
: self
.button_event(*a
))
684 uWidget
._draw
_common
_triangle
= _draw_common_triangle
687 self
._draw
_common
_triangle
()
688 uInvisibleSymbol
.draw
= draw
692 # Triangle down & right.
694 self
._draw
_common
_triangle
()
697 self
._grp
_scale
.affine_relative( misc
.affine_rotate(45) )
698 uPartiallyVisible
.draw
= draw
704 self
._draw
_common
_triangle
()
707 self
._grp
_scale
.affine_relative( misc
.affine_rotate(90) )
708 uVisibleSymbol
.draw
= draw
713 self
._ltext
= misc
.GtkObjProxy(self
._grp
_obj
.add(
719 fill_color
= "white",
720 outline_color
= "white",
721 width_pixels
= self
.w_
.cp_
.outline_width_normal
,
726 ## self.connect("event", lambda *a: self.button_event(*a))
732 class l3Base(Selectable
):
737 self
._destroy
_hook
= [] # (func -> None) list
738 self
._reparent
_to
_root
_hook
= [] # (func -> None) list
739 self
._vis
_indic
= None # visibility status indicator
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.
780 pixbuf
= gtk
.gdk
.Pixbuf(gtk
.gdk
.COLORSPACE_RGB
,
786 # get_from_drawable(src, cmap, src_x, src_y, dest_x, dest_y, width, height)
787 status
= pixbuf
.get_from_drawable(
789 gtk
.gdk
.colormap_get_system(),
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
):
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.
818 print "------------------------------------------------------------------"
819 print "Showing only data created through:"
821 print nd
.l3tree().source_string()
823 # Get reduced calling context.
824 pruned
= tw
.prune_cctxt(
826 map(l3Base
.getid
, l3nd
)) # Remaining selection for pruning.
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
))
837 l3Base
.selection_values_in_context
= selection_values_in_context
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
849 l3Base
.contains_recursive
= contains_recursive
853 l3Base
.l3tree
= l3tree
856 return self
._l3tree
._id
861 #** canvas display functions
863 print "Bounds:", self
.get_bounds_world()
864 l3Base
.dump_bbox
= dump_bbox
866 def zoom(self
, factor
):
867 return (factor
, factor
)
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
):
876 x
, y
, u
, v
= self
.get_bounds()
878 l3Base
.get_anchor
= get_anchor
882 def reparent(self
, newp
):
883 assert isinstance(newp
, (l3aList
, l3Base
))
885 # Remove from current parent.
887 self
._parent
.detach(self
)
890 # Attach to new parent.
892 self
._root
_group
.reparent(newp
._root
_group
)
894 # Avoid repositioning mess.
897 l3Base
.reparent
= reparent
899 def reparent_to_root(self
):
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
)
910 l3Base
.reparent_to_root
= reparent_to_root
913 #** Selection handling
914 def plain_view(self
):
915 if not self
._outline
:
917 destroy_if_last(self
._outline
)
919 l3Base
.plain_view
= plain_view
927 x1
, y1
, x2
, y2
= self
.get_bounds_world()
928 pad
= self
.w_
.cp_
.highlight_padding
934 ### self._outline = self._root_group.get_property("parent").add(
935 self
._outline
= (self
._canvas
.root().add(
937 fill_color
= "orange",
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
,
951 ### self._loutline.set_property("fill-color", 'beige')
952 ### self._ltext.set_property("fill-color", 'beige')
955 self
._outline
.connect("event", lambda *a
: self
.selection_popup_event(*a
))
956 self
._outline
.connect("event", lambda *a
: self
.selection_magnify_event(*a
))
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
)
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.
990 # Callback arguments are (event name, handler)
991 args
= tuple(conargs
)
992 self
._selection
_popup
_cb
[item
] = item
.connect(*args
)
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
)
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
)
1016 l3Base
.selection_magnify_event
= selection_magnify_event
1019 class l3Nested(l3Base
):
1022 def __init__(self
, w_
, cnvs
, l3tree
, rentab
):
1023 l3Base
.__init
__(self
)
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
)
1036 # Undecorated state.
1040 self
._root
_group
.connect("event", lambda *a
: self
.drag_event(*a
))
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__
1052 def zoom(self
, factor
):
1053 return l3Base
.zoom(self
, factor
)
1054 l3Nested
.zoom
= zoom
1059 class Placeholder(l3Nested
):
1062 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
1064 l3tree
= w_
.state_
.storage
.load(tree_id
)
1065 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
1067 # Bindings to keep. ### move to nested.__init__
1070 self
._marker
_points
= {} # marker -> point list
1071 self
._l3tree
= l3tree
1074 # # self._blank = self.draw_blank()
1075 self
._blank
= uInvisibleSymbol(w_
, cnvs
, self
._root
_group
,
1076 action
= lambda _
: self
.show_subtree())
1079 self
._outline
= None
1081 # Item cross-referencing.
1083 self
._container
= None
1086 # # l3Nested.init_deco(self)
1087 self
.init_header(rentab
)
1088 self
.init_deco(rentab
)
1091 ## self._blank.connect("event", lambda *a: self.expand_event(*a))
1092 Placeholder
.__init
__ = __init__
1098 def __init__(self
, w_
, l3parent
, text
, tag_table
, cnvs
, refpos
= None):
1100 Interface of `l3parent` must include:
1106 get_bounds_world (if `refpos` is not given)
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()
1124 self
._l3parent
= l3parent
1125 self
._text
_orig
= text
1128 l1
, t1
, _
, _
= l3parent
.get_bounds_world()
1133 self
._edit
_buff
= buff
= gtk
.TextBuffer(table
= tag_table
)
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
))
1141 self
._view
= gtk
.TextView(buffer = buff
)
1142 self
._view
.connect("key-press-event", lambda *a
: self
.on_keypress(*a
))
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
)
1150 self
._ok
= gtk
.Button(label
= "Ok", stock
= gtk
.STOCK_OK
)
1151 self
._ok
.connect("clicked", lambda *a
: self
.text_finished())
1154 self
._cancel
= gtk
.Button(label
= "Cancel", stock
= gtk
.STOCK_CANCEL
)
1155 self
._cancel
.connect("clicked", lambda *a
: self
.text_aborted())
1159 self
._ass
_r
1 = gtk
.HBox()
1160 self
._ass
_r
1.pack_start(self
._view
_s
, expand
= True)
1162 self
._ass
_r
2 = gtk
.HBox()
1163 self
._ass
_r
2.pack_start(self
._ok
, expand
= True)
1164 self
._ass
_r
2.pack_start(self
._cancel
, expand
= True)
1166 self
._ass
_col
= gtk
.VBox()
1167 self
._ass
_col
.pack_start(self
._ass
_r
1, expand
= True)
1168 self
._ass
_col
.pack_start(self
._ass
_r
2, 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
):
1188 if event
.keyval
== key_Escape
:
1193 if event
.state
& gtk
.gdk
.CONTROL_MASK
:
1194 if event
.keyval
== key_Return
:
1195 self
.text_finished()
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.
1208 self
._window
.destroy()
1211 self
._l3parent
.ed_restore_text()
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"
1223 buf
= self
._edit
_buff
1224 new_text
= buf
.get_text(*buf
.get_bounds())
1226 # Remove editor before adding new text.
1228 self
._window
.destroy()
1231 self
._l3parent
.rebuild_tree(new_text
)
1232 self
._l3parent
.ed_new_text(new_text
)
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
):
1244 if iter.has_tag(self
._l3parent
._canvas
._font
_size
_tag
):
1247 buffer.apply_tag(self
._l3parent
._canvas
._font
_size
_tag
, iter, iter_to
)
1249 TextEdit
.re_tag_inserted_text
= re_tag_inserted_text
1252 class ExtProcConfirm
:
1254 After running an external process (which may not return a useful
1260 to attach any desired log information.
1264 def __init__(self
, w_
, cnvs
, answer_store
, text
= ""):
1265 # See also TextEdit.
1268 # an empty list, to be populated with the user's response,
1269 # in the form [(status, log)]
1272 self
._answer
_store
= answer_store
1273 self
._text
_orig
= text
1277 self
._edit
_buff
= buff
= gtk
.TextBuffer(table
= cnvs
._common
_tag
_table
)
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
))
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.
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
)
1296 self
._ok
= gtk
.Button(stock
= gtk
.STOCK_YES
)
1297 self
._ok
.connect("clicked", lambda *a
: self
.cmd_success())
1300 self
._failed
= gtk
.Button(stock
= gtk
.STOCK_NO
)
1301 self
._failed
.connect("clicked", lambda *a
: self
.cmd_failed())
1305 self
._ass
_r
1 = gtk
.HBox()
1306 self
._ass
_r
1.pack_start(self
._view
_s
, expand
= True)
1308 self
._ass
_r
2 = gtk
.HBox()
1309 self
._ass
_r
2.pack_start(self
._ok
, expand
= True)
1310 self
._ass
_r
2.pack_start(self
._failed
, expand
= True)
1312 self
._ass
_col
= gtk
.VBox()
1313 self
._ass
_col
.pack_start(self
._ass
_r
1, expand
= True)
1314 self
._ass
_col
.pack_start(self
._ass
_r
2, 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
):
1333 if event
.keyval
== key_Escape
:
1338 if event
.state
& gtk
.gdk
.CONTROL_MASK
:
1339 if event
.keyval
== key_Return
:
1344 ExtProcConfirm
.on_keypress
= on_keypress
1346 def cmd_failed(self
):
1347 # Remove editor before adding new text.
1349 self
._window
.destroy()
1352 self
._answer
_store
.append( (1, "") ) # (status, log)
1353 ExtProcConfirm
.cmd_failed
= cmd_failed
1355 def cmd_success(self
):
1357 buf
= self
._edit
_buff
1358 new_text
= buf
.get_text(*buf
.get_bounds())
1360 # Remove editor before adding new text.
1362 self
._window
.destroy()
1365 if new_text
== self
._text
_orig
:
1366 self
._answer
_store
.append( (0, "success") ) # (status, log)
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
):
1377 if iter.has_tag(self
._canvas
._font
_size
_tag
):
1380 buffer.apply_tag(self
._canvas
._font
_size
_tag
, iter, iter_to
)
1382 ExtProcConfirm
.re_tag_inserted_text
= re_tag_inserted_text
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
1394 assert prim_node
._root
_group
1395 assert prim_node
.destroy
1396 assert prim_node
._l3tree
1398 assert prim_node
.mark_as
1401 def destroy_selected(self
, node
):
1402 sel
= node
.w_
.selector
1403 items
= sel
.get_selection_list()
1405 [self
.start_destroy(itm
) for itm
in items
]
1406 CommonPopup
.destroy_selected
= destroy_selected
1409 def start_destroy(self
, node
):
1413 node
._root
_group
.hide()
1418 node
._l3tree
.delete(w_
.state_
.storage
)
1420 w_
.with_fluids(body
,
1421 detach_l3_tree
= False,
1422 insert_l3_tree
= False,
1425 CommonPopup
.start_destroy
= start_destroy
1427 def _insert_list(self
, shape
= 'list'):
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.
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(
1450 map(l3Base
.getid
, l3nd
))
1452 # Warn if context is not unique.
1455 # Available info: clone id, clone timestamp, value
1456 # (cid, storage.ie_.get_timestamp(cid), val)
1458 for (cid
, val
) in tw
.cctxt_leaves(pruned
)
1461 # Use values of top-level node if nothing remains.
1464 for (id_
, val
) in self
._prim
_node
.get_values_list()
1467 # For a list of length M, try a sqrt(M) * sqrt(M) layout.
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
)]
1477 self
._prim
_node
.w_
.cp_
.display_file_content
)\
1478 .setup(empty_parent(),
1479 ast
.Env('dummy_env', None, None, 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
)
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"),
1529 lambda *args
: view
.print_info(prim_node
.w_
.state_
.storage
,
1530 prim_node
._l3tree
))],
1531 [ gtk
.MenuItem("dump values"),
1533 lambda *args
: prim_node
.dump_values() ) ],
1535 [ gtk
.MenuItem("export values as string"),
1537 lambda *args
: prim_node
.string_export() ) ],
1539 # # [ gtk.MenuItem("dump [values list]"),
1541 # # lambda *args: pprint(prim_node.get_values_list()))],
1543 # # [ gtk.MenuItem("dump (values list) as l3 AST"),
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"),
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
):
1578 new_menu
= gtk
.Menu()
1581 mi
= gtk
.TearoffMenuItem()
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.
1598 self
._widget
_cb
[mi
] = mi
.connect(*conargs
)
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:
1612 self
._widget
.popup(None, None, None,
1613 event
.button
, event
.time
)
1616 CommonPopup
.popup_event
= popup_event
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"),
1626 # lambda *args: view.print_info(prim_node.w_.state_.storage,
1627 # prim_node._l3tree))]
1629 # [gtk.SeparatorMenuItem(), None]
1631 self
._popup
_list
.insert(0, item_init
)
1632 CommonPopup
.prepend
= prepend
1639 def __init__(self
, w_
, l3tree
):
1641 self
._l3tree
= l3tree
1642 self
._widget
_cb
= {}
1643 self
._widget
= gtk
.Menu() # dummy
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
1658 clone_l
= st
.get_attribute(c_id
, "interp_clone")
1660 G
.logger
.info("%d has %d clones.\nValues:" % (c_id
, len(clone_l
)))
1661 # todo: this should recurse?
1663 # todo: use loop (var, value) pairs, not just id
1664 yield [ gtk
.MenuItem("clone %d" % id),
1666 lambda *args
: DataSelPopup(self
.w_
, st
.load(id)))]
1668 # Toplevel or final id.
1669 yield [ gtk
.MenuItem("value operations"),
1671 # todo: ValueOperPopup
1672 lambda *args
: DataSelPopup(self
.w_
, self
._l3tree
))]
1673 DataSelPopup
.traverse_values_list
= traverse_values_list
1676 def init_popup(self
):
1678 new_menu
= gtk
.Menu()
1681 mi
= gtk
.TearoffMenuItem()
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.
1695 self
._widget
_cb
[mi
] = mi
.connect(*conargs
)
1697 # Remove duplicate popups.
1699 self
._widget
.destroy()
1701 self
._widget
= new_menu
1702 DataSelPopup
.init_popup
= init_popup
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
):
1717 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
1719 # loop CALL from FROMARGS
1723 l3tree
= w_
.state_
.storage
.load(tree_id
)
1724 assert isinstance(l3tree
, ast
.Loop
)
1725 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
1730 self
._l3tree
= l3tree
1733 self
._outline
= None
1735 # Item cross-referencing.
1737 self
._container
= None
1739 # # self._marker_points = {} # marker -> point list
1742 # Create display elements.
1745 d_loop
= Label(w_
, cnvs
, self
._root
_group
, "loop")
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
)
1755 d_from
= Label(w_
, cnvs
, self
._root
_group
, "from")
1758 d_from_args
= l3aList(w_
, cnvs
,
1759 l3tree
.l_from_args
[0],
1761 root_group
= self
._root
_group
,
1767 d_body
= l3aList(w_
, cnvs
,
1770 root_group
= self
._root
_group
,
1776 # Only editing of the macro leaves makes sense. This implies
1777 # that the macro itself cannot be edited, greatly simplifying
1780 # Inform obj of marker.
1781 d_call
.setup_marker(None, self
) ### need marker substitute.
1784 # Indexed access. Match l3tree indexing where applicable.
1785 self
._d
_elements
= [
1798 # Align display elements, starting from d_loop.
1800 self
._align
_display
()
1805 self
.init_header(rentab
)
1806 self
.init_deco(rentab
)
1809 l3Loop
.__init
__ = __init__
1811 def _update_refs(self
):
1818 ) = self
._d
_elements
1819 l3Loop
._update
_refs
= _update_refs
1821 def _align_display(self
):
1823 # Align display elements, starting from d_loop.
1833 ] = self
._d
_elements
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
)
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
)
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
)
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
)
1856 l3Loop
._align
_display
= _align_display
1859 def new_size_for(self
, child
):
1860 self
._align
_display
()
1862 # Refresh decoration.
1867 self
._parent
.new_size_for(self
)
1869 l3Loop
.new_size_for
= new_size_for
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
1890 # Markers and Labels may move independently -- so they are not in a
1893 # class MarkerLabel:
1894 # __slots__ = ['marker', 'label']
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.
1910 l3aList
.l3tree
= l3tree
1914 def __init__(self
, w_
, cnvs
, l3tree
, rentab
,
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
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.
1936 self
._root
_group
= (root_group
.add(canvas
.CanvasGroup
))
1938 self
._root
_group
= (cnvs
.root().add(canvas
.CanvasGroup
))
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
:
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()]
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(
1963 fill_color
= 'white',
1964 first_arrowhead
= 0,
1967 points
= [ 0,0, self
.w_
.cp_
.label_indent
,0 ],
1970 # Position elements for bounding box correctness. See also .insert().
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
)
1976 self
._adj
_v
(self
.w_
.cp_
.label_indent
, 0, self
._marker
_lst
, self
._dlist
)
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
1996 self
._spacer
_bottom
= self
._root
_group
.add(
1998 fill_color
= 'white',
1999 first_arrowhead
= 0,
2002 points
= [ 0, 0, self
.w_
.cp_
.marker_width
, 0],
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
):
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.
2025 newmarker
[0].move(ax
, ay
)
2028 # Inform obj of marker
2029 newobj
[0].setup_marker(newmarker
[0], self
)
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
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.
2047 newmarker
[0].move(ax
, ay
)
2050 # Inform obj of marker
2051 newobj
[0].setup_marker(newmarker
[0], self
)
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
):
2068 l3aList
.rebuild_tree
= rebuild_tree
2071 #** marker event handlers
2073 def marker_set_mark(self
, menuitem
, index
):
2075 l3aList
.marker_set_mark
= marker_set_mark
2077 def marker_select_region(self
, menuitem
, index
):
2080 if index
<= self
._mark
_:
2081 first
, last
= index
, self
._mark
_
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.
2112 if event
.type == gtk
.gdk
.BUTTON_PRESS
:
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
))
2123 # button-1: Start selection
2124 self
.marker_set_mark(None, self
._marker
_lst
.index(item
))
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.")
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
)
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
)
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
)
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
) )
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"),
2176 # lambda *args: view.print_info(prim_node.w_.state_.storage,
2177 # prim_node._l3tree))]
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.
2200 # (event name, handler, marker_idx)
2201 args
= tuple(list(conargs
) + [marker_idx
])
2202 self
._marker
_widget
_cb
[item
] = item
.connect(*args
)
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):
2221 # Horizontal line (Canvas object).
2223 vpad
= self
.w_
.cp_
.marker_padding
2224 _marker
= self
._root
_group
.add(
2226 fill_color
= hidden_color
or cp
.marker_color
,
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
,
2241 # Vertical line (Canvas object).
2243 hpad
= self
.w_
.cp_
.marker_padding
2244 _marker
= self
._root
_group
.add(
2246 fill_color
= hidden_color
or cp
.marker_color
,
2247 points
= [ulx
+ hpad
,
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
,
2260 return { None : _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
):
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
)
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...
2294 wid
= marker
.get_property("width_units") # get CURRENT setting
2297 return (x
+ wid
, y
+ wid
)
2299 class mBounds(tuple):
2300 def set(self
, **kw
):
2301 self
.__dict
__.update(kw
)
2305 # Pad (marker) bounds on top/bottom.
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
2313 # Pad (marker) bounds on left / right.
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...
2326 wid
= marker
.get_property("width_units") # get CURRENT setting
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.
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.
2340 vpad
= w_
.cp_
.marker_padding
2341 return (x
- vpad
, y
, u
+ vpad
, v
)
2346 class l3Rawtext(l3Base
):
2349 def text_and_outline(self
):
2351 # Text content / format / scale
2353 ## rendering speed up
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(
2360 anchor
= gtk
.ANCHOR_NORTH_WEST
,
2363 size
= self
._font
_size
,
2366 ## font = self._font_desc,
2368 markup
= "\n".join(view
.leading_lines(self
._text
_orig
,
2372 self
._ltext
= misc
.GtkObjProxy(self
._root
_group
.add(
2374 anchor
= gtk
.ANCHOR_NORTH_WEST
,
2377 size
= self
._font
_size
,
2380 font
= self
._font
_desc
,
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
2400 x1
, y1
, x2
, y2
= self
._ltext
.get_bounds() # world units
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(
2408 self
.w_
.cp_
.font_size
* self
._canvas
._abs
_zoom
* pango
.SCALE
)
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
))
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
2425 self
._loutline
= self
._root
_group
.add(
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()
2438 self
._loutline
.connect("event", lambda *a
: self
.drag_event(*a
))
2440 # Ensure correct sizing.
2442 # # self._root_group.move(-1000,0)
2443 ## rendering speed up
2445 self
._root
_group
.move(-1000,0)
2448 def __init__(self
, w_
, cnvs
, tree_id
, rentab
, render_only
= []):
2449 l3Base
.__init
__(self
)
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.
2474 self
._container
= None
2479 # Undecorated 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()
2491 self
._root
_group
= cnvs
.root().add(canvas
.CanvasGroup
)
2492 self
._pup
= CommonPopup(self
)
2495 # Canvas registration. Must preceed children's construction.
2496 cnvs
.register_l3tree_pic(l3tree
._id
, self
)
2499 text_and_outline(self
)
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()
2507 do_subtrees
= render_only
2509 do_subtrees
= l3tree
.subtrees1()
2511 for sub
in do_subtrees
:
2512 # # print "Now:", sub
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()
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
)
2527 self
._subtrees
.append(disp_ch
)
2529 # Highlight outline.
2530 self
._outline
= None
2532 # Register for zooming.
2533 cnvs
.add_zoom_text(self
)
2536 self
.init_header(rentab
)
2537 self
.init_deco(rentab
)
2538 self
._root
_group
.show()
2541 self
.remember_x
= None
2542 self
.remember_y
= None
2545 l3Rawtext
.__init
__ = __init__
2548 def pre_popup_hook(self
):
2549 ''' Conditional popup menu additions.
2551 1. Possible file names
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(
2561 ast
.Env('dummy_env', None, None, 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>"),
2578 lambda *args
: xm
.show(sel
= self
._l3tree
.py_string()))],
2580 [ gtk
.MenuItem(".spi -> xmipp_show -vol <path>"),
2582 lambda *args
: xm
.show(vol
= self
._l3tree
.py_string()))],
2584 [ gtk
.MenuItem(".txt -> $EDITOR <path>"),
2587 os
.system(os
.path
.expandvars("$EDITOR %s &" % # clean up...
2588 self
._l3tree
.py_string())))],
2590 [ gtk
.MenuItem(".png -> view image"),
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)):
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
),
2618 # Is there any content?
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
2635 fname
= self
._l3tree
2638 val
, val_id
= misc
.file2ast(fname
, shape
= shape
)\
2639 .setup(empty_parent(),
2640 ast
.Env('dummy_env', None, None, 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())
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
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
),
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
)
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(
2688 ast
.Env('dummy_env', None, None, 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
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
),
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
)
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
))),
2736 ast
.Env('dummy_env', None, None, 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 )
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
)
2772 u1
, v1
, u2
, v2
= self
._ltext
.get_bounds()
2773 ox
, oy
= self
._ltext
_size
_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
)
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
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:
2804 if isinstance(nd
._parent
, l3Rawtext
):
2805 return find_last_text_parent(nd
._parent
)
2808 if isinstance(self
, l3Comment
):
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()
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
2826 params
= node
.w_
.cp_
.inline
2828 node
._editor
= TextEdit(node
.w_
,
2831 node
._canvas
._common
_tag
_table
,
2834 node
._editor
._view
.show()
2836 node
._editor
._view
.grab_focus()
2837 node
._under
_destruction
= "partial"
2840 l3Rawtext
.start_edit
= start_edit
2843 #* l3List / l3Map editing
2844 class l3List(l3Nested
):
2847 class l3ViewList(l3List
):
2850 class l3Map(l3Nested
):
2855 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
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
,
2867 root_group
= self
._root
_group
,
2873 head
= Label(w_
, cnvs
, self
._root
_group
, l3tree
.deco_title_text())
2878 expander
= uVisibleSymbol(w_
, cnvs
, self
._root
_group
,
2879 action
= lambda _
: self
.hide_subtree())
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
)
2899 self
._expander
= expander
2900 self
._l3tree
= l3tree
2903 self
._outline
= None
2905 # Item cross-referencing.
2907 self
._container
= None
2909 # Popup menu additions
2910 if isinstance(self
, l3Map
):
2911 map(self
._pup
.prepend
, [
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())],
2924 self
.init_header(rentab
)
2925 self
.init_deco(rentab
)
2927 l3List
.__init
__ = __init__
2928 l3Map
.__init
__ = __init__
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]
2938 val
, val_id
= ast
.val2ast(content
)\
2939 .setup(empty_parent(),
2940 ast
.Env('dummy_env', None, None, 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
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
):
2965 class l3If(l3Nested
):
2974 # ---------------------------------
2975 class l3IfOutline(l3Nested
):
2978 # ---------------------------------
2979 class l3IfLoop(l3Nested
):
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
):
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
):
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
):
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
):
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
)
3054 # todo: use rentab to distinguish compact/expanded form?
3056 # Traverse parents' displays to see if self is inside a loop.
3058 for l3pic
in cnvs
.displayed_parents(l3tree
):
3059 if isinstance(l3pic
, l3IfLoop
):
3064 #*** if in_l3ifloop:
3068 # return LNAME(LARGS)
3072 aList([Return(Call(MarkerTyped(Symbol('LNAME'),
3074 MarkerTyped(Symbol('LARGS'),
3077 if ma
['LNAME'] == l3ifloop
._matcher
['LNAME']:
3079 return l3IfLoopContinue(w_
, cnvs
, tree_id
, rentab
)
3082 return l3IfLoopBreak(w_
, cnvs
, tree_id
, rentab
)
3090 aList([Return(Marker('_'))]),
3092 return l3IfLoopBreak(w_
, cnvs
, tree_id
, rentab
)
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([])))]),
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
)
3117 return l3IfLoop(w_
, cnvs
, tree_id
, rentab
, ma
)
3123 # def "_while_ID"():
3128 # return _while_ID()
3131 elif ma
.match(l3tree
,
3133 aList([Set(Marker('_'),
3135 aList([If(Call(Symbol('not'),
3136 Marker('COND-PARENT')),
3137 aList([Return(Marker('_'))]),
3139 Return(Call(Marker('_'),
3144 if ma
.match(ma
['COND-PARENT'], aList([Marker('COND')])):
3147 return ma
['COND-PARENT'][ ma
['COND-IDX'] ]
3148 ma
.get_cond
= get_cond
3149 return l3IfWhile(w_
, cnvs
, tree_id
, rentab
, ma
)
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('''
3167 # ! LEN = len(! ITEMS)
3173 # ! V = ! ITEMS[ ! IDX - 1 ]
3180 # The following pattern is from above, with manual fixes for
3181 # def "LOOP"() [ Set(Symbol('LOOP') ...) -> Set(Marker('LOOP'),...)]
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 :
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 :
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']])
3206 return l3If(w_
, cnvs
, tree_id
, rentab
)
3209 ## wdgt.l3if_chooser = l3if_chooser
3213 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3218 l3tree
= w_
.state_
.storage
.load(tree_id
)
3219 assert isinstance(l3tree
, ast
.Set
)
3220 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3223 self
._marker
_points
= {} # marker -> point list
3230 d_lhs
= cnvs
.add_l3tree(l3tree
[0], rentab
)
3231 d_lhs
.reparent(self
)
3234 d_equal
= Label(w_
, cnvs
, self
._root
_group
, " = ")
3237 d_rhs
= cnvs
.add_l3tree(l3tree
[1], rentab
)
3238 d_rhs
.reparent(self
)
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
)
3251 self
._d
_equal
= d_equal
3254 self
._d
_lhs
_marker
= d_lhs_marker
3255 self
._d
_rhs
_marker
= d_rhs_marker
3256 self
._l3tree
= l3tree
3259 self
._align
_to
_lhs
()
3262 self
._outline
= None
3264 # Item cross-referencing.
3266 self
._container
= None
3269 d_lhs_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3270 d_rhs_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3273 self
.init_header(rentab
)
3274 self
.init_deco(rentab
)
3280 l3Set
.__init
__ = __init__
3282 def __init__(self
, w_
, cnvs
, tree_id
, rentab
, matcher
):
3284 l3tree
= w_
.state_
.storage
.load(tree_id
)
3285 assert isinstance(l3tree
, ast
.If
)
3286 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
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()
3298 d_loop
= Label(w_
, cnvs
, self
._root
_group
, "loop")
3299 d_body
= l3aList(w_
, cnvs
,
3302 root_group
= self
._root
_group
,
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.
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)
3330 # Indexed access. Match l3tree indexing where applicable.
3331 self
._d
_elements
= [
3344 self
._outline
= None
3346 # Item cross-referencing.
3348 self
._container
= None
3351 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3354 self
.init_header(rentab
)
3355 self
.init_deco(rentab
)
3358 l3IfOutline
.__init
__ = __init__
3360 def __init__(self
, w_
, cnvs
, tree_id
, rentab
, matcher
):
3362 l3tree
= w_
.state_
.storage
.load(tree_id
)
3363 assert isinstance(l3tree
, ast
.If
)
3364 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
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()
3376 d_loop
= Label(w_
, cnvs
, self
._root
_group
, "loop")
3377 d_body
= l3aList(w_
, cnvs
,
3380 root_group
= self
._root
_group
,
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.
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)
3408 # Indexed access. Match l3tree indexing where applicable.
3409 self
._d
_elements
= [
3422 self
._outline
= None
3424 # Item cross-referencing.
3426 self
._container
= None
3429 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3432 self
.init_header(rentab
)
3433 self
.init_deco(rentab
)
3436 l3IfLoop
.__init
__ = __init__
3438 def _update_refs(self
):
3441 ) = self
._d
_elements
3442 l3IfLoop
._update
_refs
= _update_refs
3445 def __init__(self
, w_
, cnvs
, tree_id
, rentab
, matcher
):
3447 l3tree
= w_
.state_
.storage
.load(tree_id
)
3448 assert isinstance(l3tree
, ast
.If
)
3449 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
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()
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
,
3469 root_group
= self
._root
_group
,
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.
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
)
3501 # Indexed access. Match l3tree indexing where applicable.
3502 self
._d
_elements
= [
3514 self
._outline
= None
3516 # Item cross-referencing.
3518 self
._container
= None
3521 d_cond_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3524 self
.init_header(rentab
)
3525 self
.init_deco(rentab
)
3528 l3IfWhile
.__init
__ = __init__
3530 def _update_refs(self
):
3535 self
._d
_cond
_marker
,
3536 ) = self
._d
_elements
3537 l3IfWhile
._update
_refs
= _update_refs
3541 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3543 l3tree
= w_
.state_
.storage
.load(tree_id
)
3544 assert isinstance(l3tree
, ast
.If
)
3545 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3550 self
._marker
_points
= {} # marker -> point list
3551 self
._l3tree
= l3tree
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
3560 def search_l3ifloop():
3561 for l3pic
in cnvs
.displayed_parents(l3tree
):
3562 if isinstance(l3pic
, l3IfLoop
):
3565 ifloop
= search_l3ifloop()
3567 if ifloop
is not None:
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
)
3576 if wref_ifloop() is None: return
3578 wref_ifloop()._deco
_cb
_buffer
.remove(body
)
3579 except ValueError: # Body removed already.
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
)
3591 self
._outline
= None
3593 # Item cross-referencing.
3595 self
._container
= None
3598 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3601 self
.init_header(rentab
)
3602 self
.init_deco(rentab
)
3605 l3IfLoopBreak
.__init
__ = __init__
3607 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3609 l3tree
= w_
.state_
.storage
.load(tree_id
)
3610 assert isinstance(l3tree
, ast
.If
)
3611 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3616 self
._marker
_points
= {} # marker -> point list
3617 self
._l3tree
= l3tree
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
3626 def search_l3ifloop():
3627 for l3pic
in cnvs
.displayed_parents(l3tree
):
3628 if isinstance(l3pic
, l3IfLoop
):
3631 ifloop
= search_l3ifloop()
3633 if ifloop
is not None:
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
)
3642 print "******** rm_linedraw: removed ContinueLine"
3643 if wref_ifloop() is None: return
3645 wref_ifloop()._deco
_cb
_buffer
.remove(body
)
3646 except ValueError: # Body removed already.
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
)
3658 self
._outline
= None
3660 # Item cross-referencing.
3662 self
._container
= None
3665 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3668 self
.init_header(rentab
)
3669 self
.init_deco(rentab
)
3672 l3IfLoopContinue
.__init
__ = __init__
3675 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3692 l3tree
= w_
.state_
.storage
.load(tree_id
)
3693 assert isinstance(l3tree
, ast
.If
)
3694 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3699 self
._marker
_points
= {} # marker -> point list
3705 d_if
= Label(w_
, cnvs
, self
._root
_group
, "If")
3708 d_cond
= cnvs
.add_l3tree(l3tree
[0], rentab
)
3709 d_cond
.reparent(self
)
3712 d_yes
= l3aList(w_
, cnvs
,
3715 root_group
= self
._root
_group
,
3721 d_else
= Label(w_
, cnvs
, self
._root
_group
, "else")
3724 d_no
= l3aList(w_
, cnvs
,
3727 root_group
= self
._root
_group
,
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.
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
)
3755 x
, _
, _
, y
= d_cond
.get_bounds()
3756 u
, v
, _
, _
= d_yes
.get_bounds()
3757 d_yes
.move(x
- u
, y
- v
)
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
)
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
)
3772 # Indexed access. Match l3tree indexing where applicable.
3773 self
._d
_elements
= [
3786 self
._l3tree
= l3tree
3789 self
._outline
= None
3791 # Item cross-referencing.
3793 self
._container
= None
3796 d_cond_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3799 self
.init_header(rentab
)
3800 self
.init_deco(rentab
)
3803 l3If
.__init
__ = __init__
3805 def _update_refs(self
):
3812 self
._d
_cond
_marker
,
3813 ) = self
._d
_elements
3814 l3If
._update
_refs
= _update_refs
3817 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3827 l3tree
= w_
.state_
.storage
.load(tree_id
)
3828 assert isinstance(l3tree
, ast
.Call
)
3829 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3834 self
._marker
_points
= {} # marker -> point list
3840 d_func
= cnvs
.add_l3tree(l3tree
[0], rentab
)
3841 d_func
.reparent(self
)
3844 d_selector
= Label(w_
, cnvs
, self
._root
_group
, " () ")
3847 d_args
= l3aList(w_
, cnvs
,
3850 root_group
= self
._root
_group
,
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.
3867 lf
, tf
, rf
, bf
= d_func
.get_bounds()
3868 u
, v
, _
, _
= d_args
.get_bounds()
3869 d_args
.move(lf
- u
, bf
- v
)
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
)
3882 # Indexed access. Match l3tree indexing where applicable.
3883 self
._d
_elements
= [
3894 self
._l3tree
= l3tree
3897 self
._outline
= None
3899 # Item cross-referencing.
3901 self
._container
= None
3904 d_func_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3907 self
.init_header(rentab
)
3908 self
.init_deco(rentab
)
3911 l3Call
.__init
__ = __init__
3913 def _update_refs(self
):
3917 self
._d
_func
_marker
,
3919 ) = self
._d
_elements
3920 l3Call
._update
_refs
= _update_refs
3924 def _func_shift(self
):
3925 # Shifts needed when FUNC size changes
3927 _
, _
, fr
, fb
= self
._d
_func
.get_bounds()
3929 _
, _
, fr
, fb
= self
._d
_func
_marker
.get_bounds()
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
)
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
3943 _
, _
, _
, y
= self
._d
_cond
.get_bounds()
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
3956 _
, _
, _
, y
= self
._d
_cond
.get_bounds()
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
):
3969 # +------A---------A------+
3970 # | lhs | equal | rhs |
3971 # +------+---------+------+
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
)
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
)
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
)
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
4008 #* class l3IfFor members
4010 class l3IfFor(l3Nested
):
4019 class l3Function(l3Nested
):
4024 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
4026 # The blandest layout:
4039 l3tree
= w_
.state_
.storage
.load(tree_id
)
4040 assert isinstance(l3tree
, ast
.Function
)
4041 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
4051 d_function
= Label(w_
, cnvs
, self
._root
_group
, "Function")
4054 d_args
= l3aList(w_
, cnvs
,
4057 root_group
= self
._root
_group
,
4061 ### incorporate into cnvs.add_l3tree(l3tree[1]) ??
4064 d_body
= l3aList(w_
, cnvs
,
4067 root_group
= self
._root
_group
,
4071 ### incorporate into cnvs.add_l3tree(l3tree[1]) ??
4078 # Inform obj of marker.
4082 # Align with respect to FUNCTION.
4087 x
, _
, _
, y
= d_function
.get_bounds()
4088 u
, v
, _
, _
= d_args
.get_bounds()
4089 d_args
.move(x
- u
, y
- v
)
4092 x
, _
, _
, y
= d_args
.get_bounds()
4093 u
, v
, _
, _
= d_body
.get_bounds()
4094 d_body
.move(x
- u
, y
- v
)
4097 self
._d
_function
= d_function
4098 self
._d
_args
= d_args
4099 self
._d
_body
= d_body
4100 self
._l3tree
= l3tree
4103 self
._outline
= None
4105 # Item cross-referencing.
4107 self
._container
= None
4112 self
.init_header(rentab
)
4113 self
.init_deco(rentab
)
4116 l3Function
.__init
__ = __init__
4135 class l3Inline(l3Nested
):
4138 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
4142 # Also see l3Program / l3If.
4145 l3tree
= w_
.state_
.storage
.load(tree_id
)
4146 assert isinstance(l3tree
, ast
.Inline
)
4147 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
4152 self
._l3tree
= l3tree
4153 self
._marker
_points
= {} # marker -> point list
4157 head
= Label(w_
, cnvs
, self
._root
_group
, "Inline")
4160 pystr
= cnvs
.add_l3tree(l3tree
[0], rentab
)
4161 pystr
.reparent(self
)
4164 pystr_marker
= self
.draw_marker()
4165 pystr_marker
.lower_to_bottom()
4169 self
._pystr
_marker
= pystr_marker
4172 # Inform obj of marker.
4173 pystr
.setup_marker(pystr_marker
, self
)
4178 u
, _
, _
, v
= head
.get_bounds()
4179 x
, y
, _
, _
= pystr
.get_bounds()
4180 head
.move(x
- u
, y
- v
)
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
)
4188 self
._outline
= None
4190 # Item cross-referencing.
4192 self
._container
= None
4195 ### pystr_marker.connect("event", lambda *a: self.insert_event(*a))
4197 # Popup menu additions
4200 self
.init_header(rentab
)
4201 self
.init_deco(rentab
)
4203 l3Inline
.__init
__ = __init__
4206 def rebuild_tree(self
, text
):
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
4220 class l3Native(l3Nested
):
4223 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
4228 # Also see l3Inline / l3Program / l3If.
4231 l3tree
= w_
.state_
.storage
.load(tree_id
)
4232 assert isinstance(l3tree
, ast
.Native
)
4233 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
4238 self
._l3tree
= l3tree
4240 value
= l3tree
.value()
4244 val_gen
= w_
.state_
.storage
.generator_of(id(value
))
4247 head
= Label(w_
, cnvs
, self
._root
_group
, "External value")
4249 head
= Label(w_
, cnvs
, self
._root
_group
,
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
4262 # Note: canvas operations will destroy these value containers
4263 # occasionally, so values that are gtk widgets can be displayed
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
4271 pystr
= Image(w_
, cnvs
, self
._root
_group
, misc
.emdata2pixbuf(value
),
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 \
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
)
4293 pystr
= Label(w_
, cnvs
, self
._root
_group
,
4294 misc
.escape_markup(repr(value
)))
4297 pystr
= Label(w_
, cnvs
, self
._root
_group
,
4298 misc
.escape_markup(str(value
)))
4306 # Inform obj of marker.
4311 l1
, _
, _
, b1
= head
.get_bounds()
4312 l2
, t2
, _
, _
= pystr
.get_bounds()
4313 pystr
.move(l1
- l2
, b1
- t2
)
4317 self
._outline
= None
4319 # Item cross-referencing.
4321 self
._container
= None
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))],
4342 self
.init_header(rentab
)
4343 self
.init_deco(rentab
)
4345 l3Native
.__init
__ = __init__
4349 class l3Program(l3Nested
):
4352 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
4354 l3tree
= w_
.state_
.storage
.load(tree_id
)
4355 if isinstance(self
, l3Program
):
4356 assert isinstance(l3tree
, ast
.Program
)
4358 assert isinstance(l3tree
, (ast
.Map
, ast
.cls_viewList
))
4359 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
4362 #*** Choose display elements.
4364 if l3tree
._outl
_type
== 'subtree':
4365 # Full display (the l3List default).
4366 alist
= l3aList(w_
, cnvs
,
4369 root_group
= self
._root
_group
,
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
,
4379 root_group
= self
._root
_group
,
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
,
4391 root_group
= self
._root
_group
,
4394 insertion_on_markers
= False,
4395 hide_markers
= True,
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]
4406 outline_symb
= str(index
+ 1) # count from 1
4408 ttext
= l3tree
.deco_title_text()
4410 if ttext
.startswith("'''"):
4412 if ttext
.startswith("'") or ttext
.startswith('"'):
4415 head_text
= ("<b>" +
4420 head
= Label(w_
, cnvs
, self
._root
_group
, head_text
,
4421 font
= w_
.cp_
.viewlist_head_font
)
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
)
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
)
4450 head
.connect("event", lambda *a
: self
.head_event(*a
))
4457 self
._expander
= expander
4458 self
._l3tree
= l3tree
4461 self
._outline
= None
4463 # Item cross-referencing.
4465 self
._container
= None
4467 # Popup menu additions
4468 if isinstance(self
, l3Program
):
4469 map(self
._pup
.prepend
, [
4471 [gtk
.SeparatorMenuItem(), None],
4472 [ gtk
.MenuItem("run code"),
4473 ( "activate", lambda *args
: self
.run_code())],
4476 map(self
._pup
.prepend
, [
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())],
4494 self
.init_header(rentab
)
4495 self
.init_deco(rentab
)
4497 l3Program
.__init
__ = __init__
4498 l3ViewList
.__init
__ = __init__
4501 def view_as(self
, type):
4503 self
._l3tree
.set_outline(type)
4504 tw
= ast
.TreeWork(self
.w_
.state_
.storage
)
4505 root
= tw
.find_root(self
._l3tree
)
4507 root
.set_outl_edges(self
.w_
, None)
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
4521 ignored_syms
= re
.compile(r
'(IDX|ITEMS|LEN|LOOP)[0-9]+')
4524 view
, view_id
= ast
.viewList(aList([])).setup(
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
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:
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')
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
)
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
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.
4573 # Prepare display list.
4574 view
, view_id
= ast
.viewList(aList([])).setup(
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
)
4598 view
.set_outl_edges(self
.w_
, None)
4599 view
.set_outline('subtree')
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
)
4612 l3Program
.show_read_names
= show_read_names
4613 l3ViewList
.show_read_names
= show_read_names
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.
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!
4630 pprint(self
._l3tree
.interpret(w_
.state_
.def_env
, w_
.state_
.storage
))
4632 if w_
.opts
.gui
.native_console
:
4633 raise # allow debugging via pdb.pm()
4635 tb
= sys
.exc_traceback
4638 traceback
.print_exception(sys
.exc_type
, sys
.exc_value
, tb
)
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
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
):
4656 for ii
in self
._d
_elements
:
4657 for prop_iter
in ii
.iter_visibles():
4659 l3Loop
.iter_visibles
= iter_visibles
4661 def iter_visibles(self
):
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()
4677 for ch
in self
._dlist
:
4678 for prop_iter
in ch
.iter_visibles():
4680 l3aList
.iter_visibles
= iter_visibles
4682 def iter_visibles(self
):
4684 for sub
in self
._subtrees
:
4685 for prop_iter
in sub
.iter_visibles():
4687 l3Rawtext
.iter_visibles
= iter_visibles
4689 def iter_visibles(self
):
4691 for prop_iter
in self
._alist
.iter_visibles():
4693 for prop_iter
in self
._head
.iter_visibles():
4695 l3List
.iter_visibles
= iter_visibles
4696 l3Map
.iter_visibles
= iter_visibles
4698 def iter_visibles(self
):
4700 if self
._l3tree
._outl
_type
in ['subtree', 'nested']:
4701 for prop_iter
in self
._alist
.iter_visibles():
4703 for prop_iter
in self
._head
.iter_visibles():
4705 elif self
._l3tree
._outl
_type
== 'flat':
4708 raise Exception("Invalid _outl_type. Internal error.")
4709 l3ViewList
.iter_visibles
= iter_visibles
4711 def iter_visibles(self
):
4713 for prop_iter
in self
._d
_lhs
.iter_visibles():
4715 for prop_iter
in self
._d
_equal
.iter_visibles():
4717 for prop_iter
in self
._d
_rhs
.iter_visibles():
4719 l3Set
.iter_visibles
= iter_visibles
4721 def iter_visibles(self
):
4723 for prop_iter
in self
._d
_label
.iter_visibles():
4725 l3IfLoopBreak
.iter_visibles
= iter_visibles
4726 l3IfLoopContinue
.iter_visibles
= iter_visibles
4728 def iter_visibles(self
):
4730 for prop_iter
in self
._d
_loop
.iter_visibles():
4733 for prop_iter
in self
._d
_body
.iter_visibles():
4735 l3IfLoop
.iter_visibles
= iter_visibles
4738 def iter_visibles(self
):
4740 for prop_iter
in self
._d
_cond
_V
.iter_visibles():
4743 for prop_iter
in self
._d
_cond
_SEQ
.iter_visibles():
4746 for prop_iter
in self
._d
_body
.iter_visibles():
4748 l3IfFor
.iter_visibles
= iter_visibles
4750 def iter_visibles(self
):
4752 for prop_iter
in self
._d
_loop
.iter_visibles():
4755 for prop_iter
in self
._d
_cond
.iter_visibles():
4758 for prop_iter
in self
._d
_body
.iter_visibles():
4760 l3IfWhile
.iter_visibles
= iter_visibles
4762 def iter_visibles(self
):
4764 for prop_iter
in self
._d
_if
.iter_visibles():
4767 for prop_iter
in self
._d
_cond
.iter_visibles():
4770 for prop_iter
in self
._d
_yes
.iter_visibles():
4773 for prop_iter
in self
._d
_else
.iter_visibles():
4776 for prop_iter
in self
._d
_no
.iter_visibles():
4778 l3If
.iter_visibles
= iter_visibles
4780 def iter_visibles(self
):
4782 for prop_iter
in self
._d
_func
.iter_visibles():
4785 for prop_iter
in self
._d
_args
.iter_visibles():
4787 l3Call
.iter_visibles
= iter_visibles
4789 def iter_visibles(self
):
4791 for prop_iter
in self
._d
_function
.iter_visibles():
4794 for prop_iter
in self
._d
_args
.iter_visibles():
4797 for prop_iter
in self
._d
_body
.iter_visibles():
4799 l3Function
.iter_visibles
= iter_visibles
4801 def iter_visibles(self
):
4803 for prop_iter
in self
._alist
.iter_visibles():
4806 for prop_iter
in self
._head
.iter_visibles():
4808 l3Program
.iter_visibles
= iter_visibles
4810 def iter_visibles(self
):
4812 for prop_iter
in self
._pystr
.iter_visibles():
4815 for prop_iter
in self
._head
.iter_visibles():
4817 l3Inline
.iter_visibles
= iter_visibles
4818 l3Native
.iter_visibles
= iter_visibles
4823 self
._root
_group
.hide()
4824 for ii
in self
._d
_elements
:
4829 self
._root
_group
.hide()
4836 raise DisplayError("Interface only: " + str(self
.__class
__))
4840 self
._root
_group
.hide()
4841 for ch
in self
._dlist
:
4846 self
._root
_group
.hide()
4848 l3Rawtext
.hide
= hide
4851 self
._root
_group
.hide()
4858 self
._root
_group
.hide()
4860 self
._d
_equal
.hide()
4865 self
._root
_group
.hide()
4866 self
._d
_label
.hide()
4867 l3IfLoopBreak
.hide
= hide
4868 l3IfLoopContinue
.hide
= hide
4871 self
._root
_group
.hide()
4874 l3IfLoop
.hide
= hide
4877 self
._root
_group
.hide()
4881 l3IfWhile
.hide
= hide
4884 self
._root
_group
.hide()
4893 self
._root
_group
.hide()
4899 self
._root
_group
.hide()
4900 self
._d
_function
.hide()
4903 l3Function
.hide
= hide
4906 self
._root
_group
.hide()
4909 l3Program
.hide
= hide
4912 self
._root
_group
.hide()
4915 l3Inline
.hide
= hide
4916 l3Native
.hide
= hide
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.")
4928 self
.insert(item
, self
.w_
.selector
.get_selection())
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
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.")
4953 if newobj
.contains_recursive(self
):
4954 self
.w_
.ten_second_message("Cannot insert list into itself.")
4957 if newobj
._canvas
!= self
._canvas
:
4958 self
.w_
.ten_second_message("Cannot move objects across displays. "
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
4972 oy1
-= self
.w_
.cp_
.marker_padding
4974 if self
._hide
_markers
:
4975 newmarker
= self
.draw_marker(ox1
, oy1
, hidden_color
= 'white')
4977 newmarker
= self
.draw_marker(ox1
, oy1
)
4979 if self
._insertion
_on
_markers
:
4980 self
.bind_marker_events(newmarker
)
4983 if self
._l3tree
.getthe('layout') == 'horizontal':
4984 self
._adj
_h
_insert
(index
, newobj
, newmarker
)
4986 self
._adj
_v
_insert
(index
, newobj
, newmarker
)
4988 # Move following items in 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
,
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
)
5004 # inform obj of marker
5005 newobj
.setup_marker(newmarker
, self
)
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.")
5053 if newobj
._canvas
!= self
._canvas
:
5054 self
.w_
.ten_second_message("Cannot move objects across displays. "
5059 old_entry
= self
._l3tree
.deref(0)
5060 slot_available(self
.w_
, old_entry
)
5063 self
._d
_cond
= d_cond
= newobj
5066 newobj
.reparent(self
)
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
)
5077 # Refresh decoration.
5080 # Move following items in parent.
5082 self
._parent
.new_size_for(self
)
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
)
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.")
5108 if newobj
._canvas
!= self
._canvas
:
5109 self
.w_
.ten_second_message("Cannot move objects across displays. "
5114 if len(self
._matcher
['COND-PARENT']) != 0:
5115 raise DisplayError("Insertion in occupied slot.")
5118 self
._d
_cond
= d_cond
= newobj
5121 newobj
.reparent(self
)
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
)
5132 # Refresh decoration.
5135 # Move following items in parent.
5137 self
._parent
.new_size_for(self
)
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
)
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.")
5162 if newobj
._canvas
!= self
._canvas
:
5163 self
.w_
.ten_second_message("Cannot move objects across displays. "
5168 old_entry
= self
._l3tree
.deref(0)
5169 slot_available(self
.w_
, old_entry
)
5172 self
._d
_func
= d_func
= newobj
5175 newobj
.reparent(self
)
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
)
5188 if self
.w_
.fluid_ref(insert_l3_tree
= True):
5189 self
._l3tree
.replace_child(old_entry
._id
, newobj
._l3tree
)
5191 # Refresh decoration.
5194 # Move following items in parent.
5196 self
._parent
.new_size_for(self
)
5198 # Inform obj of marker.
5199 newobj
.setup_marker(self
._d
_func
_marker
, self
)
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.")
5212 if newobj
._canvas
!= self
._canvas
:
5213 self
.w_
.ten_second_message("Cannot move objects across displays. "
5217 if marker
== self
._d
_lhs
_marker
:
5219 old_entry
= self
._l3tree
.deref(0)
5220 slot_available(self
.w_
, old_entry
)
5222 # Check and update reference.
5223 self
._d
_lhs
= newobj
5226 newobj
.reparent(self
)
5228 # Position lhs w.r.t. marker
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
)
5236 self
._align
_to
_lhs
()
5239 if self
.w_
.fluid_ref(insert_l3_tree
= True):
5240 self
._l3tree
.replace_child(old_entry
._id
, newobj
._l3tree
)
5243 self
._d
_lhs
_marker
.hide()
5245 elif marker
== self
._d
_rhs
_marker
:
5247 old_entry
= self
._l3tree
.deref(1)
5248 slot_available(self
.w_
, old_entry
)
5250 # Check and update reference.
5251 self
._d
_rhs
= newobj
5254 newobj
.reparent(self
)
5257 # see also l3Set._align_to_lhs
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()
5269 if self
.w_
.fluid_ref(insert_l3_tree
= True):
5270 self
._l3tree
.replace_child(old_entry
._id
, newobj
._l3tree
)
5273 self
._d
_rhs
_marker
.hide()
5276 raise DisplayError("Insertion from invalid marker.")
5278 # Refresh decoration.
5281 # Move following items in parent.
5283 self
._parent
.new_size_for(self
)
5285 # Inform obj of marker.
5286 newobj
.setup_marker(marker
, self
)
5289 l3Set
.insert
= insert
5294 def move(self
, dx
, dy
):
5295 self
._root
_group
.move(dx
, dy
)
5301 def move(self
, dx
, dy
):
5302 self
._root
_group
.move(dx
, dy
)
5304 self
._outline
.move(dx
, dy
)
5307 def move(self
, dx
, dy
):
5308 self
._root
_group
.move(dx
, dy
)
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
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
5343 # With surrounding path decoration.
5345 adj
= (cp_
.deco
.outline_width
/ 2.0) * self
._canvas
._pixpu
5346 return x
+ adj
, y
+ adj
, u
- adj
, v
- adj
5348 # return x + 0.5, y + 0.5, u, v
5349 # return x + 0.5, y + 0.5, u - 0.5, v - 0.5
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
5377 # With surrounding path decoration.
5379 adj
= (cp_
.deco
.outline_width
/ 2.0) * self
._canvas
._pixpu
5380 return x
+ adj
, y
+ adj
, u
- adj
, v
- adj
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()
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
):
5429 cp
.exp_marker_width
, 0,
5430 cp
.exp_marker_width
, cp
.exp_marker_height
,
5431 0 , cp
.exp_marker_height
,
5434 _marker
= self
._root
_group
.add(
5435 canvas
.CanvasPolygon
,
5436 fill_color
= "black",
5439 cap_style
= gtk
.gdk
.CAP_ROUND
,
5440 join_style
= gtk
.gdk
.JOIN_ROUND
,
5442 self
._marker
_points
[_marker
] = points
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
5456 class l3Comment(l3Rawtext
):
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.
5475 def rebuild_tree(self
, text
):
5477 ## print 'text_finished: parent: ', self._l3tree._parent
5478 if self
._l3tree
._parent
:
5479 parent
= self
.w_
.state_
.storage
.load( self
._l3tree
._parent
)
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)
5489 if self
._l3tree
._parent
:
5490 self
._l3tree
.deep_replace(tree
, self
.w_
.state_
.storage
)
5493 l3Rawtext
.rebuild_tree
= rebuild_tree
5495 def ed_new_text(self
, text
):
5497 self
._text
_orig
= text
5498 text_and_outline(self
)
5500 # Resize from root node.
5502 # Adjust highlighting.
5504 # Avoid repositioning mess.
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
5518 self
.start_replace_visible()
5520 # Remove decoration.
5523 # Refresh decoration.
5525 # Move following items in parent.
5527 self
._parent
.new_size_for(self
)
5528 l3Rawtext
.finish_edit
= finish_edit
5532 def rebuild_tree(self
, text
):
5534 tree
= ast
.Comment(text
)
5536 # Attach (logically) to node.
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)
5544 l3Comment
.rebuild_tree
= rebuild_tree
5547 def ed_new_text(self
, text
):
5549 self
._text
_orig
= text
5550 # # text_and_outline(self)
5552 # Resize from root node.
5554 # Adjust highlighting.
5556 # Avoid repositioning mess.
5559 l3Comment
.ed_new_text
= ed_new_text
5562 def finish_edit(self
):
5563 # Refresh decoration.
5572 p1
._parent
.new_size_for(p1
)
5573 l3Comment
.finish_edit
= finish_edit
5576 #** l3ViewList / l3Program
5577 def ed_restore_text(self
):
5579 l3ViewList
.ed_restore_text
= ed_restore_text
5580 l3Program
.ed_restore_text
= ed_restore_text
5583 def rebuild_tree(self
, text
):
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
):
5595 self
._text
_orig
= text
5597 # Adjust highlighting.
5599 # Avoid repositioning mess.
5602 l3ViewList
.ed_new_text
= ed_new_text
5603 l3Program
.ed_new_text
= ed_new_text
5606 def finish_edit(self
):
5607 # Refresh decoration.
5612 self
._parent
.new_size_for(self
)
5614 l3ViewList
.finish_edit
= finish_edit
5615 l3Program
.finish_edit
= finish_edit
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
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()
5640 deco_text
= "unlabeled code"
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
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()
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.
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
)
5679 self
._header
.move(ls
- lh
, ts
- bh
)
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()
5695 vl_type
= self
._l3tree
.get_outline_type()
5697 if vl_type
== 'flat':
5698 # Display only _head (label), ignore _header (comment).
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.
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']:
5721 # _header (comment, h)
5724 # Keep existing horizontal positioning for E, L, A; only H is
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
)
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
)
5744 # todo: preserve rentab info?
5745 self
.init_header(RenderTable())
5747 l3Nested
.refresh_header
= refresh_header
5748 l3Rawtext
.refresh_header
= refresh_header
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
)
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
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
)
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":
5787 self
.w_
.selector
.remove(self
)
5788 self
.w_
.cp_
.drag_state
= ("ds_start", (event
.x
, event
.y
))
5791 # Get the new position and move by the difference.
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
5802 dx
= new_x
- self
.remember_x
5803 dy
= new_y
- self
.remember_y
5805 self
.remember_x
= new_x
5806 self
.remember_y
= new_y
5808 # sm: detach item if needed.
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
)
5815 if (abs(u
- x
) + abs(v
- y
) >
5816 self
.w_
.cp_
.item_detach_distance
):
5818 self
._container
.detach(self
)
5819 self
._container
= None
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
)
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
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
)
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.
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
5870 dx
= new_x
- self
.remember_x
5871 dy
= new_y
- self
.remember_y
5873 self
.remember_x
= new_x
5874 self
.remember_y
= new_y
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
)
5883 if (abs(u
- x
) + abs(v
- y
)) > self
.w_
.cp_
.item_detach_distance
:
5885 self
._container
.detach(self
)
5887 self
._container
= None
5888 misc
.single_event(_do
)
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
)
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
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.
5918 dx
= new_x
- self
.remember_x
5919 dy
= new_y
- self
.remember_y
5921 self
.remember_x
= new_x
5922 self
.remember_y
= new_y
5926 l3aList
.drag_event
= drag_event
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
)
5936 l3Rawtext
.destroy_event
= destroy_event
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_
,
5946 self
._l3tree
.deco_title_text(),
5947 self
._canvas
._common
_tag
_table
,
5950 self
._editor
._view
.show()
5951 self
._editor
._view
.grab_focus()
5954 l3ViewList
.head_event
= head_event
5955 l3Program
.head_event
= head_event
5961 #** l3Deco: Decoration around contents.
5962 # This includes the outlines, buttons (if
5963 # any) and the titlebar (if present)
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
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
5987 _safed(self
._deco
_path
_item
)
5988 for ii
in self
._draw
_queue
:
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
)
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
)
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:
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
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
6060 bdry_path
= canvas
.path_def_new(the_deco
._deco
_path
)
6062 the_deco
._deco
_path
_item
= bdry_item
= node
._root
_group
.add(
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
,
6071 the_deco
._deco
_path
_item
= bdry_item
= node
._root
_group
.add(
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
6088 bck
= the_deco
._background
= node
._root
_group
.add(
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()
6102 the_deco
._deco
_path
_item
.connect(
6103 "event", lambda *a
: the_deco
.magnify_event(*a
))
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
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
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
):
6147 self
._deco
= add_deco_to(self
)
6148 l3Function
.init_deco
= init_deco
6150 def init_deco(self
, rentab
):
6152 ## self._deco = add_deco_to(self, callbacks = self._deco_cb_buffer)
6154 l3IfLoop
.init_deco
= init_deco
6155 l3IfWhile
.init_deco
= init_deco
6158 def init_deco(self
, rentab
):
6161 # Move the placeholder to the right of the header string, into
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
,
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()
6175 self
._deco
= add_deco_to(self
, emphasis_for
= emph
)
6179 Placeholder
.init_deco
= init_deco
6182 def init_deco(self
, rentab
):
6183 # Emphasize body / add outline.
6184 emph
= self
._l3tree
.get_emphasis()
6186 self
._deco
= add_deco_to(self
, emphasis_for
= emph
)
6189 l3Rawtext
.init_deco
= init_deco
6190 l3Nested
.init_deco
= init_deco
6195 def refresh_deco(self
):
6196 from l3gui
.l3canvas
import RenderTable
6197 # Remove decoration.
6203 # todo: preserve rentab info?
6204 self
.init_deco(RenderTable())
6206 l3Nested
.refresh_deco
= refresh_deco
6207 l3Rawtext
.refresh_deco
= refresh_deco
6211 def destroy_deco(self
):
6214 _safed(self
._header
)
6217 _safed(self
._root
_group
)
6218 del self
._root
_group
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"
6228 print "enter new label:"
6230 label
= sys
.stdin
.readline().rstrip()
6232 assert isinstance(label
, StringType
), "Label must be a string."
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()
6246 self
._parent
.new_size_for(self
)
6247 l3Base
.deco_change_label
= deco_change_label
6249 def deco_add_comment(self
):
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()
6264 self
._parent
.new_size_for(self
)
6265 l3Base
.deco_add_comment
= deco_add_comment
6268 #* Resizing / new_size_for
6270 def new_size_for(self
, child
):
6271 assert isinstance(child
, (l3Base
, l3aList
))
6273 index
= self
._dlist
.index(child
)
6275 raise DisplayError("nonexistent 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:
6285 child
.move(mr
- cl
, mt
- ct
)
6286 # Move following markers, labels, and objects
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()
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)
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
6309 x
, y
, _
, _
= marker_get_bounds(
6310 self
.w_
, self
._marker
_lst
[index
+ 1]).pad_tb()
6311 _
, _
, u
, v
= child
.get_bounds()
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
)
6320 self
._parent
.new_size_for(self
)
6322 l3aList
.new_size_for
= new_size_for
6326 def new_size_for(self
, child
):
6327 # Contained alist is updated; only forward request.
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.
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()
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()
6359 self
._d
_else
.move(0, dy
)
6360 self
._d
_no
.move(0, dy
)
6362 elif child
== self
._d
_no
:
6366 raise DisplayError("nonexistent child.")
6368 # Refresh decoration.
6373 self
._parent
.new_size_for(self
)
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.
6395 self
._parent
.new_size_for(self
)
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.
6413 self
._parent
.new_size_for(self
)
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
:
6434 raise DisplayError("nonexistent child.")
6436 # Refresh decoration.
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
:
6455 elif child
== self
._d
_args
:
6459 raise DisplayError("nonexistent child.")
6461 # Refresh decoration.
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()
6481 self
._d
_body
.move(0, dy
)
6483 elif child
== self
._d
_body
:
6487 raise DisplayError("nonexistent child.")
6489 # Refresh decoration.
6494 self
._parent
.new_size_for(self
)
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.
6513 self
._parent
.new_size_for(self
)
6515 l3Map
.new_size_for
= new_size_for
6516 l3List
.new_size_for
= new_size_for
6517 l3Program
.new_size_for
= new_size_for
6521 #** internal functions
6522 def marker_eval_local(self
, args
):
6523 # args: (menuitem, index)
6526 from code
import InteractiveConsole
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
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",
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
):
6559 # For use from calling console; this version stops the gui event
6561 from code
import InteractiveConsole
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
=""):
6569 from threading
import Lock
6575 value
.append(raw_input(prompt
))
6577 value
.append(EOFError())
6580 thread
.start_new_thread(_do
, ())
6581 # Manual main loop until input is ready.
6582 while not lck
.acquire(False):
6585 if isinstance(value
[-1], Exception):
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
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")
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')))
6621 # # G.logger.info("No clones of %d" % c_id)
6623 # # def dump_values(self):
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")
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)
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.
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 "----------------------"
6658 def _dynamic(c_id
, lev
):
6659 clone_l
= st
.get_attribute(c_id
, "interp_clone")
6661 print ind
*lev
, "%d repeats %d time(s):" % (c_id
, len(clone_l
))
6666 print ind
*lev
, c_id
, "does not repeat;",\
6667 "value: ", st
.get_attribute(c_id
, 'interp_result')
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
):
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 '---------------------------------'
6691 def _dynamic(c_id
, lev
):
6692 clone_l
= st
.get_attribute(c_id
, "interp_clone")
6694 # print ind*lev, "%d repeats %d time(s):" % (c_id, len(clone_l))
6698 # value in str() form
6699 val
= st
.get_attribute(c_id
, 'interp_result')
6703 print '---------------------------------'
6704 l3Base
.string_export
= string_export
6705 l3aList
.string_export
= string_export
6708 #* Subtree visibility
6711 def mark_as(self
, visibility
):
6713 self
._canvas
._vis
_tab
[self
._l3tree
._id
] = visibility
6715 # Background visibility indicator.
6718 self
._vis
_indic
.destroy()
6719 self
._vis
_indic
= None
6722 x1
, y1
, x2
, y2
= self
.get_bounds()
6723 pad
= self
.w_
.cp_
.highlight_padding
6729 # What depth to use?
6730 # Subtrees are in their own group; within that, the box is
6731 # always at the bottom.
6740 # The parent's bounding box should not change.
6742 add
= self
._parent
._root
_group
.add
6744 add
= self
._canvas
.root().add
6745 self
._vis
_indic
= add(
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":
6758 elif visibility
== "vis_show":
6761 elif visibility
== "vis_neutral":
6763 self
._vis
_indic
.destroy()
6764 self
._vis
_indic
= None
6767 raise DisplayError("Invalid visibility flag.")
6768 l3Base
.mark_as
= mark_as
6771 #** subtree swapping
6772 def start_replace_visible(self
):
6775 self
._parent
.replace_visible(self
)
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
):
6786 marker
= child
._marker
6787 l3tree
= child
._l3tree
6789 # Remove existing display.
6792 # Draw (visible) subtree.
6793 tree_disp
= self
._canvas
.start_add_l3tree(l3tree
)
6795 # Attach / move / reparent
6797 self
.insert(marker
, tree_disp
)
6801 l3Nested
.replace_visible
= replace_visible
6803 def replace_visible(self
, child
):
6805 index
= self
._dlist
.index(child
)
6806 l3tree
= child
._l3tree
6807 # # if isinstance(l3tree, ast.viewList):
6808 # # l3tree = l3tree._real_tree
6811 # Remove existing display.
6814 # Draw (visible) subtree.
6815 ### self._canvas._vis_tab.get_render_table(l3tree)
6816 tree_disp
= self
._canvas
.start_add_l3tree(l3tree
)
6820 self
.insert(index
, tree_disp
)
6824 self
._parent
.new_size_for(self
)
6825 l3aList
.replace_visible
= replace_visible
6828 #** Convenience combinations.
6829 def show_nested_lhs(self
):
6831 vista
= self
._canvas
._vis
_tab
6833 # Clear existing markings
6834 vista
.clear_tree( self
._l3tree
)
6837 self
.mark_as("vis_show")
6840 N
= 3 # maximum visible sublevel
6841 for nd
, dent
in self
._l3tree
.top_down_indented():
6843 vista
[nd
._id
] = "vis_hide"
6845 if ma
.match(nd
, Set(Marker('lhs'), Marker('rhs')) ):
6846 vista
[ma
['lhs']._id
] = "vis_show"
6847 vista
[ma
['rhs']._id
] = "vis_hide"
6850 self
.start_replace_visible()
6851 l3Base
.show_nested_lhs
= show_nested_lhs
6853 def show_one_subtree(self
):
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
):
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
):
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
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()
6902 # Update table data.
6903 # # if self.w_.deco_table_.has_key(self._l3tree._id):
6904 # # del self.w_.deco_table_[self._l3tree._id]
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.
6915 self
._parent
.new_size_for(self
)
6916 l3Base
.detach_header
= detach_header
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
:
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
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)
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
)
6977 # Move following items in 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
)
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()
7006 # Refresh decoration.
7009 # Move following items in parent.
7011 self
._parent
.new_size_for(self
)
7014 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7016 # _matcher['LBODY'] is fixed at match time -- manual editing
7018 self
._matcher
['LBODY'].detach_from_parent_rec(self
.w_
.state_
.storage
)
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
)
7032 # Reparent graphical parts.
7033 child
.reparent_to_root()
7041 # Refresh decoration.
7044 # Move following items in parent.
7046 self
._parent
.new_size_for(self
)
7049 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7050 self
._l3tree
[0].detach_from_parent_rec(self
.w_
.state_
.storage
)
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
)
7068 # Reparent graphical parts.
7069 child
.reparent_to_root()
7077 # Refresh decoration.
7080 # Move following items in parent.
7082 self
._parent
.new_size_for(self
)
7085 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7086 self
._matcher
.get_cond().detach_from_parent_rec(self
.w_
.state_
.storage
)
7088 l3IfWhile
.detach
= detach
7091 def detach(self
, child
):
7092 assert(child
== self
._pystr
)
7094 # Reparent graphical parts.
7095 child
.reparent_to_root()
7102 # Refresh decoration.
7105 # Move following items in parent.
7107 self
._parent
.new_size_for(self
)
7110 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7111 self
._l3tree
[0].detach_from_parent_rec(self
.w_
.state_
.storage
)
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()
7129 # Refresh decoration.
7132 # Move following items in parent.
7134 self
._parent
.new_size_for(self
)
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
7144 # Reparent graphical parts.
7145 child
.reparent_to_root()
7154 # Refresh decoration.
7157 # Move following items in parent.
7160 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7161 self
._l3tree
[1].detach_from_parent_rec(self
.w_
.state_
.storage
)
7164 l3Call
.detach
= detach
7166 def detach(self
, child
):
7167 if child
== self
._d
_lhs
:
7168 # Reparent graphical parts.
7169 child
.reparent_to_root()
7177 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7178 self
._l3tree
[0].detach_from_parent_rec(self
.w_
.state_
.storage
)
7181 self
._d
_lhs
_marker
.show()
7183 elif child
== self
._d
_rhs
:
7184 # Reparent graphical parts.
7185 child
.reparent_to_root()
7193 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7194 self
._l3tree
[1].detach_from_parent_rec(self
.w_
.state_
.storage
)
7197 self
._d
_rhs
_marker
.show()
7200 raise DisplayError("Detaching invalid child.")
7202 ### print "detach: ", self
7204 # Refresh decoration.
7207 # Move following items in parent.
7209 self
._parent
.new_size_for(self
)
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.
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()
7235 # Refresh decoration.
7238 # Move following items in parent.
7240 self
._parent
.new_size_for(self
)
7243 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7244 self
._l3tree
[0].detach_from_parent_rec(self
.w_
.state_
.storage
)
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
7258 def detach_only(self
, child
):
7259 # Detach any child from self, without shifting, resizing, or
7260 # updating insertion markers.
7262 idx
= self
._d
_elements
.index(child
)
7264 raise DisplayError("Detaching invalid child.")
7266 ### print "detach: ", self
7268 # Reparent graphical parts.
7269 child
.reparent_to_root()
7272 self
._d
_elements
[idx
] = None
7277 # Refresh decoration.
7280 # Move following items in parent.
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
7291 def detach(self
, child
):
7292 if child
== self
._d
_args
:
7293 # Reparent graphical parts.
7294 child
.reparent_to_root()
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()
7315 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7316 self
._l3tree
[1].detach_from_parent_rec(self
.w_
.state_
.storage
)
7319 raise DisplayError("Detaching invalid child.")
7321 ### print "detach: ", self
7323 # Refresh decoration.
7326 # Move following items in parent.
7328 self
._parent
.new_size_for(self
)
7330 l3Function
.detach
= detach
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
7342 # Reparent graphical parts.
7343 child
.reparent_to_root()
7349 # Refresh decoration.
7351 # Move following items in parent.
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
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
:
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
7389 self
._root
_group
.hide() # Much faster w/o display update.
7391 self
._vis
_indic
.destroy()
7392 self
._vis
_indic
= None
7394 self
._run
_destroy
_hook
()
7395 l3Base
.destroy
= destroy
7400 l3Base
.destroy(self
)
7402 if self
._container
!= self
._parent
:
7403 raise DisplayError("internal _container / _parent inconsistency.")
7406 self
._parent
.detach(self
)
7411 _safed(self
._header
)
7414 if self
.w_
.selector
.get_selection() == self
:
7415 self
.w_
.selector
.unselect()
7418 self
._container
= None
7421 l3Nested
.destroy
= destroy
7427 l3Nested
.destroy(self
)
7428 _safed(self
._d
_loop
)
7429 _safed(self
._d
_body
)
7430 l3Nested
.destroy_deco(self
)
7431 l3IfLoop
.destroy
= destroy
7434 l3Nested
.destroy(self
)
7435 _safed(self
._d
_label
)
7436 l3Nested
.destroy_deco(self
)
7437 l3IfLoopBreak
.destroy
= destroy
7438 l3IfLoopContinue
.destroy
= destroy
7441 l3Nested
.destroy(self
)
7444 _safed(self
._d
_cond
)
7446 _safed(self
._d
_else
)
7448 ### self._l3tree.delete(self.w_.state_.storage)
7449 l3Nested
.destroy_deco(self
)
7450 l3If
.destroy
= destroy
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
7461 l3Nested
.destroy(self
)
7464 l3Nested
.destroy_deco(self
)
7465 Placeholder
.destroy
= destroy
7468 l3Nested
.destroy(self
)
7471 _safed(self
._d
_equal
)
7473 ### self._l3tree.delete(self.w_.state_.storage)
7474 l3Nested
.destroy_deco(self
)
7475 l3Set
.destroy
= destroy
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
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
7499 l3Nested
.destroy(self
)
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
7509 l3Nested
.destroy(self
)
7512 l3Nested
.destroy_deco(self
)
7513 l3Inline
.destroy
= destroy
7514 l3Native
.destroy
= destroy
7519 self
._root
_group
.hide() # Much faster w/o display update.
7521 self
._parent
.detach(self
)
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
7533 for mark
in copy(self
._marker
_lst
):
7536 ### self._l3tree.delete(self.w_.state_.storage)
7538 _safed(self
._root
_group
)
7539 del self
._root
_group
7541 self
._run
_destroy
_hook
()
7543 l3aList
.destroy
= destroy
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
)
7559 if self
._container
!= self
._parent
:
7560 raise DisplayError("internal _parent / _marker inconsistency.")
7564 self
._parent
.detach(self
)
7567 self
._container
= None
7571 _safed(self
._header
)
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
):
7586 ### self._l3tree.delete(self.w_.state_.storage)
7588 # Destroy the display elements.
7590 _safed(self
._loutline
)
7591 _safed(self
._root
_group
)
7592 del self
._root
_group
7595 l3Rawtext
.destroy
= destroy
7598 # .destroy order checks.
7599 self
._under
_destruction
= True
7601 self
._canvas
.remove_zoom_text(self
)
7603 l3Base
.destroy(self
)
7606 if self
._container
!= None:
7607 raise DisplayError("internal marker inconsistency.")
7611 self
._parent
.detach_header(self
)
7614 self
._container
= None
7616 if self
.w_
.selector
.get_selection() == self
:
7617 self
.w_
.selector
.unselect()
7620 _safed(self
._loutline
)
7621 _safed(self
._root
_group
)
7622 del self
._root
_group
7625 l3Comment
.destroy
= destroy
7628 self
._canvas
.remove_zoom_text(self
)
7629 _safed(self
._loutline
)
7631 _safed(self
._root
_group
)
7633 self
._run
_destroy
_hook
()
7634 Label
.destroy
= destroy
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
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
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
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.
7672 def st_TextBuffer(item
, prop_list
):
7673 ## item.get_text(*item.get_bounds())
7676 ## "tag-table", # GtkTextTagTable : Read / Write / Construct Only
7678 ## "text", # gchararray : Read / Write
7681 def st_TextTag(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
):
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
7771 # List of readable & writeable display properties taken from the
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.
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
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)
7819 def st_CanvasPolygon(w_
, item
, prop_list
, creator
= None):
7821 prop_list
.append( ("points", creator
._marker
_points
[item
]) )
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
]
7835 print "% st_CanvasPolygon"
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
)
7842 return st_CanvasShape(item
, prop_list
)
7846 def st_CanvasRect(w_
, item
, prop_list
):
7847 return st_CanvasRE(item
, prop_list
)
7851 def st_CanvasGroup(item
, prop_list
):
7852 return _get_props(item
, prop_list
,
7853 "x", # gdouble : Read / Write
7854 "y", # gdouble : Read / Write
7858 def st_CanvasText(w_
, item
, prop_list
):
7859 if w_
.fluid_ref(dump_ps
= False):
7860 get
= item
.get_property
7862 print "% st_CanvasText"
7863 x1
, y1
, _
, _
= item
.get_bounds()
7864 print " %s %s gcmoveto" % i2w(x1
, y1
)
7865 print ' (%s) gcshow' % (get("text"))
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
7918 def st_CanvasLine(w_
, item
, prop_list
):
7919 if w_
.fluid_ref(dump_ps
= False):
7920 pts
= item
.get_property("points")
7923 print "% st_CanvasLine"
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
)
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
7953 def st_CanvasWidget(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
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
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
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
7995 def get_state(self
):
7998 _root_group
= st_CanvasGroup(self
._root
_group
, []),
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
):
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
)
8044 # These functions are intended to fully traverse the (display) widget
8045 # tree, and may be split into traversal iterators / main functions
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
)
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
)
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
)
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
)
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
):
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
8180 def find_root(self
):
8181 if self
._parent
!= None:
8182 return self
._parent
.find_root()
8184 return self
, self
._l3tree
._id
8185 l3Base
.find_root
= find_root
8186 l3aList
.find_root
= find_root
8189 # The reconstruction of the data structures is done in passes:
8190 # - form the spanning tree using loaded data
8191 # - reconnect graph edges.
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
8215 def set_state(self
, state
):
8217 CommonPopup
.set_state
= set_state
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
8226 def continue_stop_pt(self
):
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
):
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
):
8241 l3tree
= w_
.state_
.storage
.load(tree_id
)
8242 assert isinstance(l3tree
, ast
.If
)
8243 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
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()
8256 d_loop_for
= Label(w_
, cnvs
, self
._root
_group
, "for")
8259 d_cond_V
= cnvs
.add_l3tree(ma
.get_current_V(), rentab
)
8260 d_cond_V
.reparent(self
)
8263 d_loop_in
= Label(w_
, cnvs
, self
._root
_group
, "in")
8266 d_cond_SEQ
= cnvs
.add_l3tree(ma
.get_current_SEQ(), rentab
)
8267 d_cond_SEQ
.reparent(self
)
8270 d_body
= l3aList(w_
, cnvs
,
8273 root_group
= self
._root
_group
,
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
)
8290 # Indexed access. Match l3tree indexing where applicable.
8291 self
._d
_elements
= [
8306 # Align display elements, starting from d_loop_for
8308 self
._align
_display
()
8311 self
._outline
= None
8313 # Item cross-referencing.
8315 self
._container
= None
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
))
8322 self
.init_header(rentab
)
8323 self
.init_deco(rentab
)
8326 l3IfFor
.__init
__ = __init__
8328 def _update_refs(self
):
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
):
8345 # Align w.r.t. 'for'
8356 ) = self
._d
_elements
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
,
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
)
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
,
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
,
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
)
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
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()
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.")
8417 if newobj
._canvas
!= self
._canvas
:
8418 self
.w_
.ten_second_message("Cannot move objects across displays. "
8423 if marker
== self
._d
_cond
_V
_marker
:
8425 if not self
._matcher
.get_current_V().eql(ast
.aNone()):
8426 raise DisplayError("Insertion in occupied slot.")
8429 self
._d
_cond
_V
= d_cond_V
= newobj
8432 newobj
.reparent(self
)
8438 self
._align
_display
()
8440 # Refresh decoration.
8443 # Move following items in parent.
8445 self
._parent
.new_size_for(self
)
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
:
8456 if not self
._matcher
.get_current_SEQ().eql(ast
.aNone()):
8457 raise DisplayError("Insertion in occupied slot.")
8460 self
._d
_cond
_SEQ
= d_cond_SEQ
= newobj
8463 newobj
.reparent(self
)
8469 self
._align
_display
()
8471 # Refresh decoration.
8474 # Move following items in parent.
8476 self
._parent
.new_size_for(self
)
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
)
8486 raise DisplayError("Insertion from wrong marker.")
8487 l3IfFor
.insert
= insert
8490 def init_deco(self
, rentab
):
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.
8511 self
._parent
.new_size_for(self
)
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
:
8523 self
._d
_cond
_V
= None
8524 the_child
= self
._matcher
.get_current_V()
8526 elif child
== self
._d
_cond
_SEQ
:
8528 self
._d
_cond
_SEQ
= None
8529 the_child
= self
._matcher
.get_current_SEQ()
8532 self
.detach_only(child
)
8535 # Reparent graphical parts.
8536 child
.reparent_to_root()
8539 # self._align_display()
8541 # Refresh decoration.
8544 # Move following items in parent.
8546 self
._parent
.new_size_for(self
)
8549 if self
.w_
.fluid_ref(detach_l3_tree
= True):
8550 the_child
.detach_from_parent_rec(self
.w_
.state_
.storage
)
8552 l3IfFor
.detach
= detach
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
)
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