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 if isinstance(l3tree
, (ast
.aNone
, ast
.aList
)):
2460 warn_("displaying internal types as text; "
2461 "expect clobbered display for:")
2462 warn_(l3tree
.get_infix_string(40))
2464 self
._text
_orig
= l3tree
.l3_repr_dedented()
2465 self
._l3tree
= l3tree
2466 self
._subtrees
= [] # l3Base nodes.
2468 # Rendering options.
2469 self
._render
_mode
= rentab
.get_state(l3tree
)
2471 # Item cross-referencing.
2473 self
._container
= None
2478 # Undecorated state.
2482 self
._new
_text
_props
= None
2484 # Focus redirection.
2485 self
._focus
_dummy
= cnvs
.root().add(canvas
.CanvasItem
)
2486 self
._focus
_dummy
.hide()
2487 self
._focus
_dummy
.grab_focus()
2490 self
._root
_group
= cnvs
.root().add(canvas
.CanvasGroup
)
2491 self
._pup
= CommonPopup(self
)
2494 # Canvas registration. Must preceed children's construction.
2495 cnvs
.register_l3tree_pic(l3tree
._id
, self
)
2498 text_and_outline(self
)
2502 (row_par
, col_par
), _
= l3tree
.get_char_range()
2503 l_par
, t_par
, r_par
, b_par
= self
._ltext
.get_bounds()
2504 _
, _
, unit_y
= self
._canvas
.font_wh()
2506 do_subtrees
= render_only
2508 do_subtrees
= l3tree
.subtrees1()
2510 for sub
in do_subtrees
:
2511 # # print "Now:", sub
2513 disp_ch
= cnvs
.add_l3tree(sub
, rentab
, force_text
= True)
2514 disp_ch
.reparent(self
)
2515 l_ch
, t_ch
, r_ch
, b_ch
= disp_ch
._ltext
.get_bounds()
2518 # Get row, column offset.
2519 (row_ch
, col_ch
), _
= sub
.get_char_range()
2521 # Move into character position.
2522 disp_ch
.move((l_par
- l_ch
) + (col_ch
- col_par
),
2523 ((t_par
- t_ch
) + (row_ch
- row_par
)) * unit_y
)
2526 self
._subtrees
.append(disp_ch
)
2528 # Highlight outline.
2529 self
._outline
= None
2531 # Register for zooming.
2532 cnvs
.add_zoom_text(self
)
2535 self
.init_header(rentab
)
2536 self
.init_deco(rentab
)
2537 self
._root
_group
.show()
2540 self
.remember_x
= None
2541 self
.remember_y
= None
2544 l3Rawtext
.__init
__ = __init__
2547 def pre_popup_hook(self
):
2548 ''' Conditional popup menu additions.
2550 1. Possible file names
2553 # 2. Known Filepaths
2554 import l3lang
.external
.xmipp_wrap
as xm
2555 from l3gui
.l3canvas
import RenderTable
2556 def _display_img(fname
):
2557 storage
= self
.w_
.state_
.storage
2558 tree
, tid
= ast
.Native(fname
).setup(
2560 ast
.Env('dummy_env', None, None, storage
),
2562 tree
.set_outl_edges(self
.w_
, None)
2564 pic
= self
._canvas
.add_l3tree(tree
, RenderTable())
2565 lp
, tp
, rp
, bp
= pic
.get_bounds_world()
2566 lo
, to
, ro
, bo
= self
.get_bounds_world()
2567 pic
.move(ro
- lp
, to
- tp
)
2569 if (isinstance(self
._l3tree
, (ast
.String
)) and
2570 self
._l3tree
.isfile() and
2571 not getattr(self
, '_popup_known_filepaths_added', False)):
2572 map(self
._pup
.prepend
, [
2573 [gtk
.SeparatorMenuItem(), None],
2575 [ gtk
.MenuItem(".spi -> xmipp_show -sel <path>"),
2577 lambda *args
: xm
.show(sel
= self
._l3tree
.py_string()))],
2579 [ gtk
.MenuItem(".spi -> xmipp_show -vol <path>"),
2581 lambda *args
: xm
.show(vol
= self
._l3tree
.py_string()))],
2583 [ gtk
.MenuItem(".txt -> $EDITOR <path>"),
2586 os
.system(os
.path
.expandvars("$EDITOR %s &" % # clean up...
2587 self
._l3tree
.py_string())))],
2589 [ gtk
.MenuItem(".png -> view image"),
2592 _display_img(self
._l3tree
))],
2594 # The table display restructures a simple list; for file
2595 # content, this requires additions in file2ast, for every
2596 # file content type.
2597 [ gtk
.MenuItem(".hdf file -> insert as l3 list list"),
2598 ("activate", lambda *args
: self
._insert
_contents
(shape
='square'))],
2600 [ gtk
.MenuItem(".hdf file -> insert as l3 list"),
2601 ("activate", lambda *args
: self
._insert
_contents
() )],
2604 self
._popup
_known
_filepaths
_added
= True
2606 # 1. Possible file names
2607 elif (isinstance(self
._l3tree
, (ast
.String
, ast
.Symbol
, ast
.Member
)) and
2608 not getattr(self
, '_popup_file_paths_added', False)):
2610 va_l
= self
.get_values_list()
2612 # Remove invalid elements.
2613 va_l
= filter(lambda (id, va
):
2614 isinstance(va
, (ast
.String
, ast
.Symbol
,
2615 types
.StringType
)) and (id,va
),
2617 # Is there any content?
2619 map(self
._pup
.prepend
, [
2620 [gtk
.SeparatorMenuItem(), None],
2621 [ gtk
.MenuItem(".any -> insert (file path) list"),
2622 ( "activate", lambda *args
: self
.get_filepaths_list())],
2623 [ gtk
.MenuItem(".png -> insert (file path, image) list"),
2624 ( "activate", lambda *args
: self
.filep_img_list())],
2626 self
._popup
_file
_paths
_added
= True
2627 l3Rawtext
.pre_popup_hook
= pre_popup_hook
2629 def _insert_contents(self
, shape
= 'list'):
2630 # See also CommonPopup._insert_list
2631 from l3gui
.l3canvas
import RenderTable
2632 storage
= self
.w_
.state_
.storage
2634 fname
= self
._l3tree
2637 val
, val_id
= misc
.file2ast(fname
, shape
= shape
)\
2638 .setup(empty_parent(),
2639 ast
.Env('dummy_env', None, None, storage
),
2641 val
.set_outl_edges(self
.w_
, None)
2643 # Special emphasis for this non-permanent value list.
2644 val
.set_emphasis("valuelist")
2645 ## val.set_label('File contents of %d' % self._l3tree._id )
2646 val
.set_label('File contents of %s' % self
._l3tree
.py_string())
2649 pic
= cnvs
.add_l3tree(val
, RenderTable())
2651 # Position to the right of expression.
2652 lp
, tp
, rp
, bp
= pic
.get_bounds_world()
2653 lo
, to
, ro
, bo
= self
.get_bounds_world()
2654 pic
.move(ro
- lp
, to
- tp
)
2655 l3Rawtext
._insert
_contents
= _insert_contents
2658 def get_filepaths_list(self
):
2659 ''' Examine all values associated with self, and display those
2660 denoting valid file paths as list.
2662 from l3gui
.l3canvas
import RenderTable
2663 storage
= self
.w_
.state_
.storage
2666 va_l
= self
.get_values_list()
2668 # Remove invalid elements.
2669 va_l
= filter(lambda (id, va
):
2670 isinstance(va
, (ast
.String
, ast
.Symbol
,
2671 types
.StringType
)) and (id,va
),
2674 # Form "path/name" list.
2675 path_l
= [("%s/%s" % (storage
.load(id).dirpath(self
.w_
), va
)).strip('/')
2676 for (id, va
) in va_l
]
2678 # Keep only valid path names.
2679 path_l
= filter(lambda nm
: os
.path
.exists(nm
) and nm
, path_l
)
2682 # This is a (very) simplified ast.val2ast(), using ast.Filepath
2683 # instead of ast.String.
2685 val
, val_id
= ast
.List(ast
.aList(map(ast
.FilepathString
, path_l
))).setup(
2687 ast
.Env('dummy_env', None, None, storage
),
2689 val
.set_outl_edges(self
.w_
, None)
2691 # Special emphasis for this non-permanent value list.
2692 val
.set_emphasis("filelist")
2693 val
.set_label('File path list for %s' % self
._l3tree
.py_string() )
2695 # Form and position display.
2696 pic
= cnvs
.add_l3tree(val
, RenderTable())
2697 lp
, tp
, rp
, bp
= pic
.get_bounds_world()
2698 lo
, to
, ro
, bo
= self
.get_bounds_world()
2699 pic
.move(ro
- lp
, to
- tp
)
2700 l3Rawtext
.get_filepaths_list
= get_filepaths_list
2703 def filep_img_list(self
):
2704 ''' Examine all values associated with self, and display those
2705 denoting valid file paths as (name = <image>) list.
2707 from l3gui
.l3canvas
import RenderTable
2708 storage
= self
.w_
.state_
.storage
2711 va_l
= self
.get_values_list()
2713 # Remove invalid elements.
2714 va_l
= filter(lambda (id, va
):
2715 isinstance(va
, (ast
.String
, ast
.Symbol
,
2716 types
.StringType
)) and (id,va
),
2719 # Form "path/name" list.
2720 path_l
= [("%s/%s" % (storage
.load(id).dirpath(self
.w_
), va
)).strip('/')
2721 for (id, va
) in va_l
]
2723 # Keep only valid path names.
2724 path_l
= filter(lambda nm
: os
.path
.exists(nm
) and nm
, path_l
)
2727 # This is a (very) simplified ast.val2ast().
2729 from l3lang
.ast
import Set
, Tuple
, aList
, FilepathString
, Native
2730 val
, val_id
= ast
.List(ast
.aList(
2731 map(lambda path
: Set(Symbol(path
), Native(FilepathString(path
))),
2735 ast
.Env('dummy_env', None, None, storage
),
2737 val
.set_outl_edges(self
.w_
, None)
2739 # Special emphasis for this non-permanent value list.
2740 val
.set_emphasis("filelist")
2741 val
.set_label('File path list for `%s`' % self
._l3tree
.py_string() )
2743 # Form and position display.
2744 pic
= cnvs
.add_l3tree(val
, RenderTable())
2745 lp
, tp
, rp
, bp
= pic
.get_bounds_world()
2746 lo
, to
, ro
, bo
= self
.get_bounds_world()
2747 pic
.move(ro
- lp
, to
- tp
)
2748 l3Rawtext
.filep_img_list
= filep_img_list
2751 def init_params(self
):
2752 # Parameter settings, localized to allow subclass overrides
2753 self
._font
_desc
= self
.w_
.cp_
.rawtext_font
2754 self
._font
_size
= self
.w_
.cp_
.font_size
* 1.0 * pango
.SCALE
2755 self
._fill
_color
= "white"
2756 self
._outline
_color
= 'white'
2757 l3Rawtext
.init_params
= init_params
2759 def ed_new_size(self
, height
):
2760 # # self._edit_frame.set_property( "height", height )
2762 l3Rawtext
.ed_new_size
= ed_new_size
2765 def zoom(self
, factor
):
2766 l3Base
.zoom(self
, factor
)
2767 if self
._ltext
: # zooming while editing?
2768 self
._ltext
.set_property("size",
2769 self
.w_
.cp_
.font_size
* factor
* pango
.SCALE
)
2771 u1
, v1
, u2
, v2
= self
._ltext
.get_bounds()
2772 ox
, oy
= self
._ltext
_size
_1
2775 ppu
= self
._canvas
._pixpu
2776 ratio_h
= 1.0 * (u2
- u1
) * ppu
/ ox
2777 ratio_v
= 1.0 * (v2
- v1
) * ppu
/ oy
2778 return (ratio_h
, ratio_v
)
2780 return factor
, factor
2781 l3Rawtext
.zoom
= zoom
2783 def setup_marker(self
, marker
, container
):
2784 self
._marker
= marker
2785 self
._container
= container
2786 l3Nested
.setup_marker
= setup_marker
2787 l3Rawtext
.setup_marker
= setup_marker
2794 def start_edit(self
, _textview
, event
):
2795 if event
.type == gtk
.gdk
._2BUTTON
_PRESS
:
2796 if event
.button
== 1:
2797 # Remove text display.
2798 self
._new
_text
_props
= _get_props(self
._ltext
, [], "x", "y")
2799 self
._under
_destruction
= True
2800 self
._ltext
.destroy()
2802 # ... and the outline.
2803 self
._loutline
.destroy()
2804 self
._loutline
= None
2806 # Use new widget for editing.
2807 if isinstance(self
, l3Rawtext
):
2808 params
= self
.w_
.cp_
.textview
2810 params
= self
.w_
.cp_
.inline
2812 self
._editor
= TextEdit(self
.w_
,
2815 self
._canvas
._common
_tag
_table
,
2818 self
._editor
._view
.show()
2820 self
._editor
._view
.grab_focus()
2821 self
._under
_destruction
= "partial"
2824 l3Rawtext
.start_edit
= start_edit
2827 #* l3List / l3Map editing
2828 class l3List(l3Nested
):
2831 class l3ViewList(l3List
):
2834 class l3Map(l3Nested
):
2839 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
2841 l3tree
= w_
.state_
.storage
.load(tree_id
)
2842 assert isinstance(l3tree
, (ast
.Map
, ast
.List
, ast
.Tuple
))
2843 assert not isinstance(l3tree
, (ast
.cls_viewList
))
2844 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
2847 #*** Display elements.
2848 alist
= l3aList(w_
, cnvs
,
2851 root_group
= self
._root
_group
,
2857 head
= Label(w_
, cnvs
, self
._root
_group
, l3tree
.deco_title_text())
2862 expander
= uVisibleSymbol(w_
, cnvs
, self
._root
_group
,
2863 action
= lambda _
: self
.hide_subtree())
2868 flush_events() # Update bounding boxes
2869 LE
, TE
, RE
, BE
= expander
.get_bounds()
2870 LH
, TH
, RH
, BH
= head
.get_bounds()
2871 head
.move(RE
- LH
, TE
- TH
)
2873 LA
, TA
, _
, _
= alist
.get_bounds()
2874 alist
.move(LH
- LA
, BH
- TA
)
2883 self
._expander
= expander
2884 self
._l3tree
= l3tree
2887 self
._outline
= None
2889 # Item cross-referencing.
2891 self
._container
= None
2893 # Popup menu additions
2894 if isinstance(self
, l3Map
):
2895 map(self
._pup
.prepend
, [
2897 [ gtk
.SeparatorMenuItem(), None],
2899 [ gtk
.MenuItem("examine dir"),
2900 ( "activate", lambda *args
: self
.insert_view())],
2902 [ gtk
.MenuItem("print working directory (pwd)"),
2903 ( "activate", lambda *args
: self
.print_pwd())],
2908 self
.init_header(rentab
)
2909 self
.init_deco(rentab
)
2911 l3List
.__init
__ = __init__
2912 l3Map
.__init
__ = __init__
2915 def insert_view(self
):
2916 from l3gui
.l3canvas
import RenderTable
2917 storage
= self
.w_
.state_
.storage
2918 # Get the information.
2919 content
= self
.get_values_list()[0]
2922 val
, val_id
= ast
.val2ast(content
)\
2923 .setup(empty_parent(),
2924 ast
.Env('dummy_env', None, None, storage
),
2926 val
.set_outl_edges(self
.w_
, None)
2927 val
.set_label("Env listing")
2928 # Form and position display.
2929 pic
= self
._canvas
.add_l3tree(val
, RenderTable())
2930 lp
, tp
, rp
, bp
= pic
.get_bounds_world()
2931 lo
, to
, ro
, bo
= self
.get_bounds_world()
2932 pic
.move(ro
- lp
, to
- tp
)
2933 l3Map
.insert_view
= insert_view
2937 def print_pwd(self
):
2938 st
= self
.w_
.state_
.storage
2939 val
= st
.get_attribute(self
._l3tree
._id
, 'interp_result')
2940 if isinstance(val
, ast
.Env
):
2941 G
.logger
.message("Directory name is %s" % val
.directory_name())
2942 l3Map
.print_pwd
= print_pwd
2945 #* l3Set / l3If / l3Call
2946 class l3Set(l3Nested
):
2949 class l3If(l3Nested
):
2958 # ---------------------------------
2959 class l3IfOutline(l3Nested
):
2962 # ---------------------------------
2963 class l3IfLoop(l3Nested
):
2971 def continue_stop_pt(self
):
2972 lc
, tc
, rc
, bc
= self
._d
_loop
.get_bounds_world()
2973 return lc
+ (rc
- lc
)/10, bc
## parameters
2974 l3IfLoop
.continue_stop_pt
= continue_stop_pt
2976 def break_stop_pt(self
):
2977 lc
, tc
, rc
, bc
= self
.get_bounds_world()
2978 return rc
+ 4, bc
## parameters
2979 l3IfLoop
.break_stop_pt
= break_stop_pt
2982 # ---------------------------------
2983 # todo: combine l3If, l3IfLoop and l3IfWhile
2985 class l3IfWhile(l3Nested
):
2992 def continue_stop_pt(self
):
2993 lc
, tc
, rc
, bc
= self
._d
_loop
.get_bounds_world()
2994 return lc
+ (rc
- lc
)/10, bc
## parameters
2995 l3IfWhile
.continue_stop_pt
= continue_stop_pt
2997 def break_stop_pt(self
):
2998 lc
, tc
, rc
, bc
= self
.get_bounds_world()
2999 return rc
+ 4, bc
## parameters
3000 l3IfWhile
.break_stop_pt
= break_stop_pt
3003 # ---------------------------------
3004 class l3IfLoopContinue(l3Nested
):
3006 def continue_start_pt(self
):
3007 lc
, tc
, rc
, bc
= self
.get_bounds_world()
3008 return lc
, (tc
+ bc
) / 2
3009 l3IfLoopContinue
.continue_start_pt
= continue_start_pt
3012 # ---------------------------------
3013 class l3IfLoopBreak(l3Nested
):
3015 def break_start_pt(self
):
3016 lc
, tc
, rc
, bc
= self
.get_bounds_world()
3017 return rc
, (tc
+ bc
) / 2
3018 l3IfLoopBreak
.break_start_pt
= break_start_pt
3021 # ---------------------------------
3022 class l3Call(l3Nested
):
3027 def l3if_chooser(w_
, cnvs
, tree_id
, rentab
):
3029 Choose appropriate display class based on subtree structure.
3031 from l3lang
.ast
import Call
, Set
, MarkerTyped
, Symbol
, Function
, \
3032 aList
, If
, String
, Return
, Macro
, aNone
, Tuple
3033 l3tree
= w_
.state_
.storage
.load(tree_id
)
3034 assert isinstance(l3tree
, ast
.If
)
3038 # todo: use rentab to distinguish compact/expanded form?
3040 # Traverse parents' displays to see if self is inside a loop.
3042 for l3pic
in cnvs
.displayed_parents(l3tree
):
3043 if isinstance(l3pic
, l3IfLoop
):
3048 #*** if in_l3ifloop:
3052 # return LNAME(LARGS)
3056 aList([Return(Call(MarkerTyped(Symbol('LNAME'),
3058 MarkerTyped(Symbol('LARGS'),
3061 if ma
['LNAME'] == l3ifloop
._matcher
['LNAME']:
3063 return l3IfLoopContinue(w_
, cnvs
, tree_id
, rentab
)
3066 return l3IfLoopBreak(w_
, cnvs
, tree_id
, rentab
)
3074 aList([Return(Marker('_'))]),
3076 return l3IfLoopBreak(w_
, cnvs
, tree_id
, rentab
)
3088 aList([Set(MarkerTyped(Symbol('LNAME'), Symbol('symbol')),
3089 Function(MarkerTyped(Symbol('LARGS'), aList([])),
3090 MarkerTyped(Symbol('LBODY'), aList([])))),
3091 Call(MarkerTyped(Symbol('LNAME2'), Symbol('symbol')),
3092 MarkerTyped(Symbol('CARGS'), aList([])))]),
3094 if ma
['LNAME'] != ma
['LNAME2']:
3095 warn_("loop name mismatch; no special display")
3096 return l3If(w_
, cnvs
, tree_id
, rentab
)
3097 elif len(ma
['LARGS']) != len(ma
['CARGS']):
3098 warn_("arguments mismatched between loop definition and call")
3099 return l3If(w_
, cnvs
, tree_id
, rentab
)
3101 return l3IfLoop(w_
, cnvs
, tree_id
, rentab
, ma
)
3107 # def "_while_ID"():
3112 # return _while_ID()
3115 elif ma
.match(l3tree
,
3117 aList([Set(Marker('_'),
3119 aList([If(Call(Symbol('not'),
3120 Marker('COND-PARENT')),
3121 aList([Return(Marker('_'))]),
3123 Return(Call(Marker('_'),
3128 if ma
.match(ma
['COND-PARENT'], aList([Marker('COND')])):
3131 return ma
['COND-PARENT'][ ma
['COND-IDX'] ]
3132 ma
.get_cond
= get_cond
3133 return l3IfWhile(w_
, cnvs
, tree_id
, rentab
, ma
)
3143 # identify V, SEQ, and B. Only self and those are displayed.
3145 # See also l3lang/reader.py and If.setup()
3147 # print reader.parse('''
3151 # ! LEN = len(! ITEMS)
3157 # ! V = ! ITEMS[ ! IDX - 1 ]
3164 # The following pattern is from above, with manual fixes for
3165 # def "LOOP"() [ Set(Symbol('LOOP') ...) -> Set(Marker('LOOP'),...)]
3167 # Marker('B') [ aList([Marker('B')]) -> Marker('B') ]
3169 elif ma
.match(l3tree
,
3170 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([]))):
3172 v_parent
= w_
.state_
.storage
.load(ma
['V']._parent
)
3173 ma
.get_current_V
= (lambda :
3175 ma
.set_V
= ( lambda new
:
3176 v_parent
.replace_child(ma
.get_current_V()._id
, new
))
3177 seq_parent
= w_
.state_
.storage
.load(ma
['SEQ']._parent
)
3178 ma
.get_current_SEQ
= (lambda :
3180 ma
.set_SEQ
= ( lambda new
:
3181 seq_parent
.replace_child(ma
.get_current_SEQ()._id
, new
))
3182 ma
.get_B
= lambda : ma
['B']
3184 return l3IfFor(w_
, cnvs
, tree_id
, rentab
, ma
)
3185 # # return l3Rawtext(w_, cnvs, tree_id, rentab,
3186 # # render_only = [ma['V'], ma['SEQ'], ma['B']])
3190 return l3If(w_
, cnvs
, tree_id
, rentab
)
3193 ## wdgt.l3if_chooser = l3if_chooser
3197 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3202 l3tree
= w_
.state_
.storage
.load(tree_id
)
3203 assert isinstance(l3tree
, ast
.Set
)
3204 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3207 self
._marker
_points
= {} # marker -> point list
3214 d_lhs
= cnvs
.add_l3tree(l3tree
[0], rentab
)
3215 d_lhs
.reparent(self
)
3218 d_equal
= Label(w_
, cnvs
, self
._root
_group
, " = ")
3221 d_rhs
= cnvs
.add_l3tree(l3tree
[1], rentab
)
3222 d_rhs
.reparent(self
)
3225 d_lhs_marker
= self
.draw_marker()
3226 d_rhs_marker
= self
.draw_marker()
3227 d_lhs_marker
.lower_to_bottom()
3228 d_rhs_marker
.lower_to_bottom()
3230 # Inform obj of marker.
3231 d_lhs
.setup_marker(d_lhs_marker
, self
)
3232 d_rhs
.setup_marker(d_rhs_marker
, self
)
3235 self
._d
_equal
= d_equal
3238 self
._d
_lhs
_marker
= d_lhs_marker
3239 self
._d
_rhs
_marker
= d_rhs_marker
3240 self
._l3tree
= l3tree
3243 self
._align
_to
_lhs
()
3246 self
._outline
= None
3248 # Item cross-referencing.
3250 self
._container
= None
3253 d_lhs_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3254 d_rhs_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3257 self
.init_header(rentab
)
3258 self
.init_deco(rentab
)
3264 l3Set
.__init
__ = __init__
3266 def __init__(self
, w_
, cnvs
, tree_id
, rentab
, matcher
):
3268 l3tree
= w_
.state_
.storage
.load(tree_id
)
3269 assert isinstance(l3tree
, ast
.If
)
3270 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3275 self
._marker
_points
= {} # marker -> point list
3276 self
._matcher
= ma
= matcher
3277 self
._l3tree
= l3tree
3278 self
._deco
_cb
_buffer
= [] # callback list for add_item()
3282 d_loop
= Label(w_
, cnvs
, self
._root
_group
, "loop")
3283 d_body
= l3aList(w_
, cnvs
,
3286 root_group
= self
._root
_group
,
3292 # # d_cond_marker = self.draw_marker()
3293 # # d_cond_marker.lower_to_bottom()
3295 # Inform obj of marker.
3296 # # d_cond.setup_marker(d_cond_marker, self)
3299 # Align with respect to d_loop.
3303 ll
, tl
, rl
, bl
= d_loop
.get_bounds()
3304 lb
, tb
, rb
, bb
= d_body
.get_bounds()
3305 d_body
.move(ll
- lb
, bl
- tb
)
3307 # COND marker for child replacement.
3308 # # _, y, x, _ = d_if.get_bounds()
3309 # # u, v, _, _ = d_cond_marker.get_bounds()
3310 # # d_cond_marker.move(x - u + w_.cp_.exp_marker_hoff,
3311 # # y - v + w_.cp_.exp_marker_voff)
3314 # Indexed access. Match l3tree indexing where applicable.
3315 self
._d
_elements
= [
3328 self
._outline
= None
3330 # Item cross-referencing.
3332 self
._container
= None
3335 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3338 self
.init_header(rentab
)
3339 self
.init_deco(rentab
)
3342 l3IfOutline
.__init
__ = __init__
3344 def __init__(self
, w_
, cnvs
, tree_id
, rentab
, matcher
):
3346 l3tree
= w_
.state_
.storage
.load(tree_id
)
3347 assert isinstance(l3tree
, ast
.If
)
3348 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3353 self
._marker
_points
= {} # marker -> point list
3354 self
._matcher
= ma
= matcher
3355 self
._l3tree
= l3tree
3356 self
._deco
_cb
_buffer
= [] # callback list for add_item()
3360 d_loop
= Label(w_
, cnvs
, self
._root
_group
, "loop")
3361 d_body
= l3aList(w_
, cnvs
,
3364 root_group
= self
._root
_group
,
3370 # # d_cond_marker = self.draw_marker()
3371 # # d_cond_marker.lower_to_bottom()
3373 # Inform obj of marker.
3374 # # d_cond.setup_marker(d_cond_marker, self)
3377 # Align with respect to d_loop.
3381 ll
, tl
, rl
, bl
= d_loop
.get_bounds()
3382 lb
, tb
, rb
, bb
= d_body
.get_bounds()
3383 d_body
.move(ll
- lb
, bl
- tb
)
3385 # COND marker for child replacement.
3386 # # _, y, x, _ = d_if.get_bounds()
3387 # # u, v, _, _ = d_cond_marker.get_bounds()
3388 # # d_cond_marker.move(x - u + w_.cp_.exp_marker_hoff,
3389 # # y - v + w_.cp_.exp_marker_voff)
3392 # Indexed access. Match l3tree indexing where applicable.
3393 self
._d
_elements
= [
3406 self
._outline
= None
3408 # Item cross-referencing.
3410 self
._container
= None
3413 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3416 self
.init_header(rentab
)
3417 self
.init_deco(rentab
)
3420 l3IfLoop
.__init
__ = __init__
3422 def _update_refs(self
):
3425 ) = self
._d
_elements
3426 l3IfLoop
._update
_refs
= _update_refs
3429 def __init__(self
, w_
, cnvs
, tree_id
, rentab
, matcher
):
3431 l3tree
= w_
.state_
.storage
.load(tree_id
)
3432 assert isinstance(l3tree
, ast
.If
)
3433 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3438 self
._marker
_points
= {} # marker -> point list
3439 self
._matcher
= ma
= matcher
3440 self
._l3tree
= l3tree
3441 self
._deco
_cb
_buffer
= [] # callback list for add_item()
3445 d_loop
= Label(w_
, cnvs
, self
._root
_group
, "while")
3447 d_cond
= cnvs
.add_l3tree(ma
.get_cond(), rentab
)
3448 d_cond
.reparent(self
)
3450 d_body
= l3aList(w_
, cnvs
,
3453 root_group
= self
._root
_group
,
3459 d_cond_marker
= self
.draw_marker()
3460 d_cond_marker
.lower_to_bottom()
3462 # Inform obj of marker.
3463 d_cond
.setup_marker(d_cond_marker
, self
)
3466 # Align with respect to d_loop.
3470 llo
, tlo
, rlo
, blo
= d_loop
.get_bounds()
3471 lco
, tco
, rco
, bco
= d_cond
.get_bounds()
3472 d_cond
.move(rlo
+ w_
.cp_
.loop_cond_sep
- lco
, tlo
- tco
)
3474 lco
, tco
, rco
, bco
= d_cond
.get_bounds()
3475 lbo
, tbo
, rbo
, bbo
= d_body
.get_bounds()
3476 d_body
.move(lco
- lbo
, bco
- tbo
)
3478 # COND marker for child replacement.
3479 lco
, tco
, rco
, bco
= d_cond
.get_bounds()
3480 lma
, tma
, _
, _
= d_cond_marker
.get_bounds()
3481 d_cond_marker
.move(lco
- lma
+ w_
.cp_
.exp_marker_hoff
,
3482 tco
- tma
+ w_
.cp_
.exp_marker_voff
)
3485 # Indexed access. Match l3tree indexing where applicable.
3486 self
._d
_elements
= [
3498 self
._outline
= None
3500 # Item cross-referencing.
3502 self
._container
= None
3505 d_cond_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3508 self
.init_header(rentab
)
3509 self
.init_deco(rentab
)
3512 l3IfWhile
.__init
__ = __init__
3514 def _update_refs(self
):
3519 self
._d
_cond
_marker
,
3520 ) = self
._d
_elements
3521 l3IfWhile
._update
_refs
= _update_refs
3525 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3527 l3tree
= w_
.state_
.storage
.load(tree_id
)
3528 assert isinstance(l3tree
, ast
.If
)
3529 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3534 self
._marker
_points
= {} # marker -> point list
3535 self
._l3tree
= l3tree
3539 self
._d
_label
= Label(w_
, cnvs
, self
._root
_group
, "break")
3541 # Flow edge drawing.
3542 # The actual line is drawn after the enclosing l3IfLoop is
3544 def search_l3ifloop():
3545 for l3pic
in cnvs
.displayed_parents(l3tree
):
3546 if isinstance(l3pic
, l3IfLoop
):
3549 ifloop
= search_l3ifloop()
3551 if ifloop
is not None:
3553 return BreakLine(w_
, cnvs
, self
, ifloop
)
3554 ifloop
._deco
_cb
_buffer
.append(body
)
3555 # The line must not be drawn after self (or ifloop) is
3556 # deleted, or self (or an intermediate tree containing self)
3557 # is detached from ifloop.
3558 wref_ifloop
= weakref
.ref(ifloop
)
3560 if wref_ifloop() is None: return
3562 wref_ifloop()._deco
_cb
_buffer
.remove(body
)
3563 except ValueError: # Body removed already.
3565 self
.add_reparent_to_root_hook(rm_linedraw
)
3566 # Parents up to ifloop (excluded).
3567 tw
= ast
.TreeWork(self
.w_
.state_
.storage
)
3568 for par
in tw
.all_parents(l3tree
):
3569 if par
is ifloop
._l3tree
: break
3570 l3pic
= cnvs
._nodes
.get(par
._id
)
3571 if l3pic
is not None:
3572 l3pic
.add_reparent_to_root_hook(rm_linedraw
)
3575 self
._outline
= None
3577 # Item cross-referencing.
3579 self
._container
= None
3582 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3585 self
.init_header(rentab
)
3586 self
.init_deco(rentab
)
3589 l3IfLoopBreak
.__init
__ = __init__
3591 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3593 l3tree
= w_
.state_
.storage
.load(tree_id
)
3594 assert isinstance(l3tree
, ast
.If
)
3595 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3600 self
._marker
_points
= {} # marker -> point list
3601 self
._l3tree
= l3tree
3605 self
._d
_label
= Label(w_
, cnvs
, self
._root
_group
, "continue")
3607 # Flow edge drawing.
3608 # The actual line is drawn after the enclosing l3IfLoop is
3610 def search_l3ifloop():
3611 for l3pic
in cnvs
.displayed_parents(l3tree
):
3612 if isinstance(l3pic
, l3IfLoop
):
3615 ifloop
= search_l3ifloop()
3617 if ifloop
is not None:
3619 return ContinueLine(w_
, cnvs
, self
, ifloop
)
3620 ifloop
._deco
_cb
_buffer
.append(body
)
3621 # The line must not be drawn after self (or ifloop) is
3622 # deleted, or self (or an intermediate tree containing self)
3623 # is detached from ifloop.
3624 wref_ifloop
= weakref
.ref(ifloop
)
3626 print "******** rm_linedraw: removed ContinueLine"
3627 if wref_ifloop() is None: return
3629 wref_ifloop()._deco
_cb
_buffer
.remove(body
)
3630 except ValueError: # Body removed already.
3632 self
.add_reparent_to_root_hook(rm_linedraw
)
3633 # Parents up to ifloop (excluded).
3634 tw
= ast
.TreeWork(self
.w_
.state_
.storage
)
3635 for par
in tw
.all_parents(l3tree
):
3636 if par
is ifloop
._l3tree
: break
3637 l3pic
= cnvs
._nodes
.get(par
._id
)
3638 if l3pic
is not None:
3639 l3pic
.add_reparent_to_root_hook(rm_linedraw
)
3642 self
._outline
= None
3644 # Item cross-referencing.
3646 self
._container
= None
3649 # # d_cond_marker.connect("event", lambda *a: self.insert_event(*a))
3652 self
.init_header(rentab
)
3653 self
.init_deco(rentab
)
3656 l3IfLoopContinue
.__init
__ = __init__
3659 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3676 l3tree
= w_
.state_
.storage
.load(tree_id
)
3677 assert isinstance(l3tree
, ast
.If
)
3678 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3683 self
._marker
_points
= {} # marker -> point list
3689 d_if
= Label(w_
, cnvs
, self
._root
_group
, "If")
3692 d_cond
= cnvs
.add_l3tree(l3tree
[0], rentab
)
3693 d_cond
.reparent(self
)
3696 d_yes
= l3aList(w_
, cnvs
,
3699 root_group
= self
._root
_group
,
3705 d_else
= Label(w_
, cnvs
, self
._root
_group
, "else")
3708 d_no
= l3aList(w_
, cnvs
,
3711 root_group
= self
._root
_group
,
3717 d_cond_marker
= self
.draw_marker()
3718 d_cond_marker
.lower_to_bottom()
3720 # Inform obj of marker.
3721 d_cond
.setup_marker(d_cond_marker
, self
)
3724 # Align with respect to IF.
3728 _
, y
, x
, _
= d_if
.get_bounds()
3729 u
, v
, _
, _
= d_cond
.get_bounds()
3730 d_cond
.move(x
- u
, y
- v
)
3732 # COND marker for child replacement.
3733 _
, y
, x
, _
= d_if
.get_bounds()
3734 u
, v
, _
, _
= d_cond_marker
.get_bounds()
3735 d_cond_marker
.move(x
- u
+ w_
.cp_
.exp_marker_hoff
,
3736 y
- v
+ w_
.cp_
.exp_marker_voff
)
3739 x
, _
, _
, y
= d_cond
.get_bounds()
3740 u
, v
, _
, _
= d_yes
.get_bounds()
3741 d_yes
.move(x
- u
, y
- v
)
3744 x
, _
, _
, _
= d_if
.get_bounds()
3745 _
, _
, _
, y
= d_yes
.get_bounds()
3746 u
, v
, _
, _
= d_else
.get_bounds()
3747 d_else
.move(x
- u
, y
- v
)
3750 _
, _
, x
, _
= d_if
.get_bounds()
3751 _
, _
, _
, y
= d_else
.get_bounds()
3752 u
, v
, _
, _
= d_no
.get_bounds()
3753 d_no
.move(x
- u
, y
- v
)
3756 # Indexed access. Match l3tree indexing where applicable.
3757 self
._d
_elements
= [
3770 self
._l3tree
= l3tree
3773 self
._outline
= None
3775 # Item cross-referencing.
3777 self
._container
= None
3780 d_cond_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3783 self
.init_header(rentab
)
3784 self
.init_deco(rentab
)
3787 l3If
.__init
__ = __init__
3789 def _update_refs(self
):
3796 self
._d
_cond
_marker
,
3797 ) = self
._d
_elements
3798 l3If
._update
_refs
= _update_refs
3801 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
3811 l3tree
= w_
.state_
.storage
.load(tree_id
)
3812 assert isinstance(l3tree
, ast
.Call
)
3813 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
3818 self
._marker
_points
= {} # marker -> point list
3824 d_func
= cnvs
.add_l3tree(l3tree
[0], rentab
)
3825 d_func
.reparent(self
)
3828 d_selector
= Label(w_
, cnvs
, self
._root
_group
, " () ")
3831 d_args
= l3aList(w_
, cnvs
,
3834 root_group
= self
._root
_group
,
3840 d_func_marker
= self
.draw_marker()
3841 d_func_marker
.lower_to_bottom()
3843 # Inform obj of marker.
3844 d_func
.setup_marker(d_func_marker
, self
)
3847 # Align with respect to FUNC.
3851 lf
, tf
, rf
, bf
= d_func
.get_bounds()
3852 u
, v
, _
, _
= d_args
.get_bounds()
3853 d_args
.move(lf
- u
, bf
- v
)
3856 ls
, ts
, rs
, bs
= d_selector
.get_bounds()
3857 d_selector
.move(rf
- ls
, tf
- ts
)
3859 # FUNC marker for child replacement.
3860 x
, y
, _
, _
= d_func
.get_bounds()
3861 u
, v
, _
, _
= d_func_marker
.get_bounds()
3862 d_func_marker
.move(x
- u
+ w_
.cp_
.exp_marker_hoff
,
3863 y
- v
+ w_
.cp_
.exp_marker_voff
)
3866 # Indexed access. Match l3tree indexing where applicable.
3867 self
._d
_elements
= [
3878 self
._l3tree
= l3tree
3881 self
._outline
= None
3883 # Item cross-referencing.
3885 self
._container
= None
3888 d_func_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
3891 self
.init_header(rentab
)
3892 self
.init_deco(rentab
)
3895 l3Call
.__init
__ = __init__
3897 def _update_refs(self
):
3901 self
._d
_func
_marker
,
3903 ) = self
._d
_elements
3904 l3Call
._update
_refs
= _update_refs
3908 def _func_shift(self
):
3909 # Shifts needed when FUNC size changes
3911 _
, _
, fr
, fb
= self
._d
_func
.get_bounds()
3913 _
, _
, fr
, fb
= self
._d
_func
_marker
.get_bounds()
3915 _
, at
, _
, _
= self
._d
_args
.get_bounds()
3916 dy
= fb
- at
# Shift between OLD d_args and NEW d_func.
3917 self
._d
_args
.move(0, dy
)
3919 sl
, _
, _
, _
= self
._d
_selector
.get_bounds()
3920 self
._d
_selector
.move(fr
- sl
, 0)
3921 l3Call
._func
_shift
= _func_shift
3924 def _cond_shift(self
):
3925 # Shifts needed when COND size changes
3927 _
, _
, _
, y
= self
._d
_cond
.get_bounds()
3929 _
, _
, _
, y
= self
._d
_cond
_marker
.get_bounds()
3930 _
, v
, _
, _
= self
._d
_yes
.get_bounds()
3931 dy
= y
- v
# Shift between OLD d_yes and NEW d_cond.
3932 self
._d
_yes
.move(0, dy
)
3933 self
._d
_else
.move(0, dy
)
3934 self
._d
_no
.move(0, dy
)
3935 l3If
._cond
_shift
= _cond_shift
3937 def _cond_shift(self
):
3938 # Shifts needed when COND size changes
3940 _
, _
, _
, y
= self
._d
_cond
.get_bounds()
3942 _
, _
, _
, y
= self
._d
_cond
_marker
.get_bounds()
3943 _
, v
, _
, _
= self
._d
_body
.get_bounds()
3944 dy
= y
- v
# Shift between OLD d_yes and NEW d_cond.
3945 self
._d
_body
.move(0, dy
)
3946 l3IfWhile
._cond
_shift
= _cond_shift
3949 def _align_to_lhs(self
):
3953 # +------A---------A------+
3954 # | lhs | equal | rhs |
3955 # +------+---------+------+
3959 x
, y
, _
, _
= self
._d
_lhs
.get_bounds()
3960 u
, _
, _
, v
= self
._d
_lhs
_marker
.get_bounds()
3961 self
._d
_lhs
_marker
.move(x
- u
+ self
.w_
.cp_
.exp_marker_hoff
,
3962 y
+ self
._canvas
.font_ascent_units() +
3963 self
._canvas
.bbox_offset_units() - v
)
3966 _
, y
, x
, _
= self
._d
_lhs
.get_bounds()
3967 u
, v
, _
, _
= self
._d
_equal
.get_bounds()
3968 self
._d
_equal
.move(x
- u
, y
- v
)
3971 if self
._d
_rhs
!= None:
3972 _
, y
, x
, _
= self
._d
_equal
.get_bounds()
3973 u
, v
, _
, _
= self
._d
_rhs
.get_bounds()
3974 self
._d
_rhs
.move(x
- u
, y
- v
)
3977 # also see l3Set.insert
3978 x
, y
, _
, _
= self
._d
_rhs
.get_bounds()
3979 u
, _
, _
, v
= self
._d
_rhs
_marker
.get_bounds()
3980 ### self._canvas.bbox_wait(self._d_rhs_marker, self._d_rhs)
3981 self
._d
_rhs
_marker
.move(x
- u
+ self
.w_
.cp_
.exp_marker_hoff
,
3982 y
- v
+ self
._canvas
.font_ascent_units() +
3983 self
._canvas
.bbox_offset_units()
3985 l3Set
._align
_to
_lhs
= _align_to_lhs
3992 #* class l3IfFor members
3994 class l3IfFor(l3Nested
):
4003 class l3Function(l3Nested
):
4008 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
4010 # The blandest layout:
4023 l3tree
= w_
.state_
.storage
.load(tree_id
)
4024 assert isinstance(l3tree
, ast
.Function
)
4025 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
4035 d_function
= Label(w_
, cnvs
, self
._root
_group
, "Function")
4038 d_args
= l3aList(w_
, cnvs
,
4041 root_group
= self
._root
_group
,
4045 ### incorporate into cnvs.add_l3tree(l3tree[1]) ??
4048 d_body
= l3aList(w_
, cnvs
,
4051 root_group
= self
._root
_group
,
4055 ### incorporate into cnvs.add_l3tree(l3tree[1]) ??
4062 # Inform obj of marker.
4066 # Align with respect to FUNCTION.
4071 x
, _
, _
, y
= d_function
.get_bounds()
4072 u
, v
, _
, _
= d_args
.get_bounds()
4073 d_args
.move(x
- u
, y
- v
)
4076 x
, _
, _
, y
= d_args
.get_bounds()
4077 u
, v
, _
, _
= d_body
.get_bounds()
4078 d_body
.move(x
- u
, y
- v
)
4081 self
._d
_function
= d_function
4082 self
._d
_args
= d_args
4083 self
._d
_body
= d_body
4084 self
._l3tree
= l3tree
4087 self
._outline
= None
4089 # Item cross-referencing.
4091 self
._container
= None
4096 self
.init_header(rentab
)
4097 self
.init_deco(rentab
)
4100 l3Function
.__init
__ = __init__
4119 class l3Inline(l3Nested
):
4122 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
4126 # Also see l3Program / l3If.
4129 l3tree
= w_
.state_
.storage
.load(tree_id
)
4130 assert isinstance(l3tree
, ast
.Inline
)
4131 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
4136 self
._l3tree
= l3tree
4137 self
._marker
_points
= {} # marker -> point list
4141 head
= Label(w_
, cnvs
, self
._root
_group
, "Inline")
4144 pystr
= cnvs
.add_l3tree(l3tree
[0], rentab
)
4145 pystr
.reparent(self
)
4148 pystr_marker
= self
.draw_marker()
4149 pystr_marker
.lower_to_bottom()
4153 self
._pystr
_marker
= pystr_marker
4156 # Inform obj of marker.
4157 pystr
.setup_marker(pystr_marker
, self
)
4162 u
, _
, _
, v
= head
.get_bounds()
4163 x
, y
, _
, _
= pystr
.get_bounds()
4164 head
.move(x
- u
, y
- v
)
4166 sl
, st
, _
, _
= pystr
.get_bounds()
4167 ml
, mt
, _
, _
= pystr_marker
.get_bounds()
4168 pystr_marker
.move(sl
- ml
+ w_
.cp_
.exp_marker_hoff
,
4169 st
- mt
+ w_
.cp_
.exp_marker_voff
)
4172 self
._outline
= None
4174 # Item cross-referencing.
4176 self
._container
= None
4179 ### pystr_marker.connect("event", lambda *a: self.insert_event(*a))
4181 # Popup menu additions
4184 self
.init_header(rentab
)
4185 self
.init_deco(rentab
)
4187 l3Inline
.__init
__ = __init__
4190 def rebuild_tree(self
, text
):
4192 print 'inline text update finished'
4194 ### trap parse errors here
4195 tree
= reader
.parse("'''\n%s\n'''" % text
).body()
4196 tree
.setup(self
._l3tree
, self
.w_
.state_
.def_env
, self
.w_
.state_
.storage
)
4197 tree
.set_outl_edges(self
.w_
, None)
4199 # Replace original raw String().
4200 self
._l3tree
[0].deep_replace(tree
, self
.w_
.state_
.storage
)
4201 l3Inline
.rebuild_tree
= rebuild_tree
4204 class l3Native(l3Nested
):
4207 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
4212 # Also see l3Inline / l3Program / l3If.
4215 l3tree
= w_
.state_
.storage
.load(tree_id
)
4216 assert isinstance(l3tree
, ast
.Native
)
4217 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
4222 self
._l3tree
= l3tree
4224 value
= l3tree
.value()
4228 val_gen
= w_
.state_
.storage
.generator_of(id(value
))
4231 head
= Label(w_
, cnvs
, self
._root
_group
, "External value")
4233 head
= Label(w_
, cnvs
, self
._root
_group
,
4235 w_
.state_
.storage
.generator_of(id(value
))._id
4238 head
= uBlank(w_
, cnvs
, self
._root
_group
)
4240 # todo: actively link the label to the source expression.
4241 # This way, the native display can provide other functions itself,
4242 # and can be a full widget with independent event handling if
4246 # Note: canvas operations will destroy these value containers
4247 # occasionally, so values that are gtk widgets can be displayed
4250 # Avoid 'import EMAN2' dependency
4251 # Display emdata as image.
4252 if (value
.__class
__.__name
__ == 'EMData'):
4253 # For now, put an image handler here. Add a general handler
4255 pystr
= Image(w_
, cnvs
, self
._root
_group
, misc
.emdata2pixbuf(value
),
4258 # Display .png file as image ( display Native(String("foo.png")) )
4259 elif isinstance(value
, ast
.String
) and value
.isfile() and \
4260 value
.endswith(".png"):
4261 pystr
= Image(w_
, cnvs
, self
._root
_group
,
4262 misc
.png2pixbuf(value
.py_string()), parent
= self
)
4264 # Display matplotlib figures via in widgets.
4265 elif (value
.__class
__.__name
__ == 'Figure'):
4266 from matplotlib
.backends
.backend_gtk
import FigureCanvasGTK \
4268 pystr
= Widget(w_
, cnvs
, self
._root
_group
,
4269 FigureCanvas(value
), parent
= self
)
4271 # Avoid numpy dependency.
4272 elif (value
.__class
__.__name
__ == 'ndarray'):
4273 if len(value
.shape
) == 2:
4274 pystr
= Image(w_
, cnvs
, self
._root
_group
,
4275 misc
.arr2pix(value
), parent
= self
)
4277 pystr
= Label(w_
, cnvs
, self
._root
_group
,
4278 misc
.escape_markup(repr(value
)))
4281 pystr
= Label(w_
, cnvs
, self
._root
_group
,
4282 misc
.escape_markup(str(value
)))
4290 # Inform obj of marker.
4295 l1
, _
, _
, b1
= head
.get_bounds()
4296 l2
, t2
, _
, _
= pystr
.get_bounds()
4297 pystr
.move(l1
- l2
, b1
- t2
)
4301 self
._outline
= None
4303 # Item cross-referencing.
4305 self
._container
= None
4309 # Popup menu additions
4310 if isinstance(pystr
, Image
):
4311 map(self
._pup
.prepend
, [
4312 [gtk
.SeparatorMenuItem(), None],
4314 [ gtk
.MenuItem('set image size as default'),
4315 ( 'activate', lambda *args
: pystr
.set_default_size())],
4317 [ gtk
.MenuItem('shrink image 40%'),
4318 ('activate', lambda *args
: pystr
.scale(0.6))],
4320 [ gtk
.MenuItem('enlarge image 40%'),
4321 ('activate', lambda *args
: pystr
.scale(1.4))],
4326 self
.init_header(rentab
)
4327 self
.init_deco(rentab
)
4329 l3Native
.__init
__ = __init__
4333 class l3Program(l3Nested
):
4336 def __init__(self
, w_
, cnvs
, tree_id
, rentab
):
4338 l3tree
= w_
.state_
.storage
.load(tree_id
)
4339 if isinstance(self
, l3Program
):
4340 assert isinstance(l3tree
, ast
.Program
)
4342 assert isinstance(l3tree
, (ast
.Map
, ast
.cls_viewList
))
4343 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
4346 #*** Choose display elements.
4348 if l3tree
._outl
_type
== 'subtree':
4349 # Full display (the l3List default).
4350 alist
= l3aList(w_
, cnvs
,
4353 root_group
= self
._root
_group
,
4357 elif l3tree
._outl
_type
== 'flat':
4358 # This heading only; no body additions allowed.
4359 setup_alist
= l3tree
[0].setup_alist(w_
, l3tree
[0])
4360 alist
= l3aList(w_
, cnvs
,
4363 root_group
= self
._root
_group
,
4366 insertion_on_markers
= False,
4367 hide_markers
= True,
4369 elif l3tree
._outl
_type
== 'nested':
4370 # heading + subheadings only; no body additions/insertions
4371 # allowed. Removal is ok.
4372 alist
= l3aList(w_
, cnvs
,
4373 l3tree
._outl
_children
,
4375 root_group
= self
._root
_group
,
4378 insertion_on_markers
= False,
4379 hide_markers
= True,
4382 raise Exception("Invalid _outl_type. Internal error.")
4384 #*** Form the label.
4385 level
, index
= l3tree
.heading_index()
4386 # Use numbers for even levels, letters for odd.
4387 if (level
% 2) == 0:
4388 outline_symb
= string
.ascii_letters
[26 + index
% 26]
4390 outline_symb
= str(index
+ 1) # count from 1
4392 ttext
= l3tree
.deco_title_text()
4394 if ttext
.startswith("'''"):
4396 if ttext
.startswith("'") or ttext
.startswith('"'):
4399 head_text
= ("<b>" +
4404 head
= Label(w_
, cnvs
, self
._root
_group
, head_text
,
4405 font
= w_
.cp_
.viewlist_head_font
)
4409 # The actions cycle to the next view state.
4410 expander_fn
, expander_action
= {
4411 'flat': (uInvisibleSymbol
,
4412 lambda *args
: self
.view_as('nested')),
4413 'nested': (uPartiallyVisible
,
4414 lambda *args
: self
.view_as('subtree')),
4415 'subtree': (uVisibleSymbol
,
4416 lambda *args
: self
.view_as('flat')),
4417 }[ l3tree
.get_outline_type() ]
4419 expander
= expander_fn(w_
, cnvs
, self
._root
_group
,
4420 action
= expander_action
)
4425 flush_events() # Update bounding boxes
4426 LE
, TE
, RE
, BE
= expander
.get_bounds()
4427 LH
, TH
, RH
, BH
= head
.get_bounds()
4428 head
.move(RE
- LH
, TE
- TH
)
4430 LA
, TA
, _
, _
= alist
.get_bounds()
4431 alist
.move(LH
- LA
, BH
- TA
)
4434 head
.connect("event", lambda *a
: self
.head_event(*a
))
4441 self
._expander
= expander
4442 self
._l3tree
= l3tree
4445 self
._outline
= None
4447 # Item cross-referencing.
4449 self
._container
= None
4451 # Popup menu additions
4452 if isinstance(self
, l3Program
):
4453 map(self
._pup
.prepend
, [
4455 [gtk
.SeparatorMenuItem(), None],
4456 [ gtk
.MenuItem("run code"),
4457 ( "activate", lambda *args
: self
.run_code())],
4460 map(self
._pup
.prepend
, [
4462 [ gtk
.SeparatorMenuItem(), None],
4463 [ gtk
.MenuItem('view full contents'),
4464 ( 'activate', lambda *args
: self
.view_as('subtree'))],
4465 [ gtk
.MenuItem('view nested outlines'),
4466 ( 'activate', lambda *args
: self
.view_as('nested'))],
4467 [ gtk
.MenuItem('view this level only'),
4468 ( 'activate', lambda *args
: self
.view_as('flat'))],
4469 [ gtk
.SeparatorMenuItem(), None],
4470 [ gtk
.MenuItem('show values written'),
4471 ( 'activate', lambda *args
: self
.show_written_names())],
4472 [ gtk
.MenuItem('show values read'),
4473 ( 'activate', lambda *args
: self
.show_read_names())],
4478 self
.init_header(rentab
)
4479 self
.init_deco(rentab
)
4481 l3Program
.__init
__ = __init__
4482 l3ViewList
.__init
__ = __init__
4485 def view_as(self
, type):
4487 self
._l3tree
.set_outline(type)
4488 tw
= ast
.TreeWork(self
.w_
.state_
.storage
)
4489 root
= tw
.find_root(self
._l3tree
)
4491 root
.set_outl_edges(self
.w_
, None)
4493 self
._l3tree
.set_outl_edges(self
.w_
, None)
4494 self
.start_replace_visible()
4495 self
.w_
.with_fluids(body
,
4496 position_tree
= False)
4497 l3Program
.view_as
= view_as
4498 l3ViewList
.view_as
= view_as
4501 def show_written_names(self
):
4502 from l3gui
.l3canvas
import RenderTable
4505 ignored_syms
= re
.compile(r
'(IDX|ITEMS|LEN|LOOP)[0-9]+')
4508 view
, view_id
= ast
.viewList(aList([])).setup(
4510 self
._l3tree
.eval_env() or self
.w_
.state_
.def_env
,
4511 self
.w_
.state_
.storage
)
4513 for nd
in self
._l3tree
.top_down_truncate([ast
.Function
, ast
.Call
]):
4514 # Several choices exist concerning display of nested
4515 # bindings. These are not visible outside their scope in L3,
4516 # but can be accessed via the interface, and conceivably be
4517 # exported by the language in some way.
4518 # For simplicity, only show those names directly accessible
4520 if ma
.match(nd
, Set(Marker('lhs'), Marker('rhs')) ):
4521 if isinstance(ma
['lhs'], ast
.Symbol
):
4522 # Filter out internal names from FOR, WHILE, etc.
4523 if ignored_syms
.match(ma
['lhs'].py_string()) != None:
4526 node
, nid
= misc
.node_copy(self
.w_
, ma
['lhs'])
4527 view
.append_child(node
)
4529 view
.set_outl_edges(self
.w_
, None)
4530 view
.set_outline('subtree')
4533 view
.set_label('Values written by -->')
4535 # Display the structure.
4536 pic
= self
._canvas
.add_l3tree(view
, RenderTable())
4538 # Position to the left of expression.
4539 lp
, tp
, rp
, bp
= pic
.get_bounds_world()
4540 lo
, to
, ro
, bo
= self
.get_bounds_world()
4541 pic
.move(lo
- rp
, to
- tp
)
4543 l3Program
.show_written_names
= show_written_names
4544 l3ViewList
.show_written_names
= show_written_names
4547 def show_read_names(self
):
4548 from l3gui
.l3canvas
import RenderTable
4551 ignored_syms
= re
.compile(r
'(IDX|ITEMS|LEN|LOOP)[0-9]+')
4552 valid_ident
= re
.compile(r
'[a-zA-Z0-9_]+')
4553 ignored_lhs
= [] # Symbols to ignore.
4554 shown
= [] # Already included.
4557 # Prepare display list.
4558 view
, view_id
= ast
.viewList(aList([])).setup(
4560 self
._l3tree
.eval_env() or self
.w_
.state_
.def_env
,
4561 self
.w_
.state_
.storage
)
4563 for nd
in self
._l3tree
.top_down_truncate([]):
4564 if ma
.match(nd
, Set(Marker('lhs'), Marker('rhs')) ):
4565 if isinstance(ma
['lhs'], ast
.Symbol
):
4566 # Ignore names assigned to.
4567 ignored_lhs
.append(ma
['lhs'])
4568 # TODO: ignore names bound in Function argument list.
4570 # Filter out internal names from FOR, WHILE, etc.
4571 if ignored_syms
.match(ma
['lhs'].py_string()) != None:
4572 ignored_lhs
.append(ma
['lhs'])
4574 if isinstance(nd
, ast
.Symbol
) and \
4575 (nd
not in ignored_lhs
) and \
4576 (nd
not in shown
) and \
4577 valid_ident
.match(nd
.py_string()): # Ignore operators.
4578 node
, nid
= misc
.node_copy(self
.w_
, nd
)
4579 view
.append_child(node
)
4582 view
.set_outl_edges(self
.w_
, None)
4583 view
.set_outline('subtree')
4586 view
.set_label('Values read by -->')
4588 # Display the structure.
4589 pic
= self
._canvas
.add_l3tree(view
, RenderTable())
4591 # Position to the left of expression.
4592 lp
, tp
, rp
, bp
= pic
.get_bounds_world()
4593 lo
, to
, ro
, bo
= self
.get_bounds_world()
4594 pic
.move(lo
- rp
, to
- tp
)
4596 l3Program
.show_read_names
= show_read_names
4597 l3ViewList
.show_read_names
= show_read_names
4600 # Attach progress indicator to visible nodes.
4601 for nd
in self
.iter_visibles():
4602 nd
._l3tree
._pre
_interp
_hook
= misc
.DisplayInterp(self
.w_
, nd
)
4604 # Execute the program, redirecting stdout/err to the message handler.
4609 w_
.stdinouterr
.push()
4610 if not w_
.opts
.gui
.native_console
:
4611 w_
.message
.std_to_widget()
4612 ## sys.settrace (w_.message.idle) # MAJOR slowdown!
4614 pprint(self
._l3tree
.interpret(w_
.state_
.def_env
, w_
.state_
.storage
))
4616 if w_
.opts
.gui
.native_console
:
4617 raise # allow debugging via pdb.pm()
4619 tb
= sys
.exc_traceback
4622 traceback
.print_exception(sys
.exc_type
, sys
.exc_value
, tb
)
4624 w_
.message
.std_to_default()
4625 traceback
.print_exc()
4626 ## sys.settrace(None)
4627 # Restore stdin/out/err
4628 w_
.stdinouterr
.pop()
4629 # Remove progress indicators (assuming no editing happened during
4631 for nd
in self
.iter_visibles():
4632 nd
._l3tree
._pre
_interp
_hook
= None
4633 l3Program
.run_code
= run_code
4635 #* visit visible nodes
4636 # Visit visible nodes that have l3trees.
4637 # Taken from `def hide(...)` and adjusted. These need testing.
4638 def iter_visibles(self
):
4640 for ii
in self
._d
_elements
:
4641 for prop_iter
in ii
.iter_visibles():
4643 l3Loop
.iter_visibles
= iter_visibles
4645 def iter_visibles(self
):
4647 Label
.iter_visibles
= iter_visibles
4648 Image
.iter_visibles
= iter_visibles
4649 Widget
.iter_visibles
= iter_visibles
4650 uWidget
.iter_visibles
= iter_visibles
4651 Placeholder
.iter_visibles
= iter_visibles
4653 def iter_visibles(self
):
4654 raise DisplayError("Interface only: " + str(self
.__class
__))
4655 l3Base
.iter_visibles
= iter_visibles
4657 def iter_visibles(self
):
4658 # aLists are list subclasses and have no custom __deepcopy__, so
4659 # attaching anything to them causes copy problems during .interpret()
4661 for ch
in self
._dlist
:
4662 for prop_iter
in ch
.iter_visibles():
4664 l3aList
.iter_visibles
= iter_visibles
4666 def iter_visibles(self
):
4668 for sub
in self
._subtrees
:
4669 for prop_iter
in sub
.iter_visibles():
4671 l3Rawtext
.iter_visibles
= iter_visibles
4673 def iter_visibles(self
):
4675 for prop_iter
in self
._alist
.iter_visibles():
4677 for prop_iter
in self
._head
.iter_visibles():
4679 l3List
.iter_visibles
= iter_visibles
4680 l3Map
.iter_visibles
= iter_visibles
4682 def iter_visibles(self
):
4684 if self
._l3tree
._outl
_type
in ['subtree', 'nested']:
4685 for prop_iter
in self
._alist
.iter_visibles():
4687 for prop_iter
in self
._head
.iter_visibles():
4689 elif self
._l3tree
._outl
_type
== 'flat':
4692 raise Exception("Invalid _outl_type. Internal error.")
4693 l3ViewList
.iter_visibles
= iter_visibles
4695 def iter_visibles(self
):
4697 for prop_iter
in self
._d
_lhs
.iter_visibles():
4699 for prop_iter
in self
._d
_equal
.iter_visibles():
4701 for prop_iter
in self
._d
_rhs
.iter_visibles():
4703 l3Set
.iter_visibles
= iter_visibles
4705 def iter_visibles(self
):
4707 for prop_iter
in self
._d
_label
.iter_visibles():
4709 l3IfLoopBreak
.iter_visibles
= iter_visibles
4710 l3IfLoopContinue
.iter_visibles
= iter_visibles
4712 def iter_visibles(self
):
4714 for prop_iter
in self
._d
_loop
.iter_visibles():
4717 for prop_iter
in self
._d
_body
.iter_visibles():
4719 l3IfLoop
.iter_visibles
= iter_visibles
4722 def iter_visibles(self
):
4724 for prop_iter
in self
._d
_cond
_V
.iter_visibles():
4727 for prop_iter
in self
._d
_cond
_SEQ
.iter_visibles():
4730 for prop_iter
in self
._d
_body
.iter_visibles():
4732 l3IfFor
.iter_visibles
= iter_visibles
4734 def iter_visibles(self
):
4736 for prop_iter
in self
._d
_loop
.iter_visibles():
4739 for prop_iter
in self
._d
_cond
.iter_visibles():
4742 for prop_iter
in self
._d
_body
.iter_visibles():
4744 l3IfWhile
.iter_visibles
= iter_visibles
4746 def iter_visibles(self
):
4748 for prop_iter
in self
._d
_if
.iter_visibles():
4751 for prop_iter
in self
._d
_cond
.iter_visibles():
4754 for prop_iter
in self
._d
_yes
.iter_visibles():
4757 for prop_iter
in self
._d
_else
.iter_visibles():
4760 for prop_iter
in self
._d
_no
.iter_visibles():
4762 l3If
.iter_visibles
= iter_visibles
4764 def iter_visibles(self
):
4766 for prop_iter
in self
._d
_func
.iter_visibles():
4769 for prop_iter
in self
._d
_args
.iter_visibles():
4771 l3Call
.iter_visibles
= iter_visibles
4773 def iter_visibles(self
):
4775 for prop_iter
in self
._d
_function
.iter_visibles():
4778 for prop_iter
in self
._d
_args
.iter_visibles():
4781 for prop_iter
in self
._d
_body
.iter_visibles():
4783 l3Function
.iter_visibles
= iter_visibles
4785 def iter_visibles(self
):
4787 for prop_iter
in self
._alist
.iter_visibles():
4790 for prop_iter
in self
._head
.iter_visibles():
4792 l3Program
.iter_visibles
= iter_visibles
4794 def iter_visibles(self
):
4796 for prop_iter
in self
._pystr
.iter_visibles():
4799 for prop_iter
in self
._head
.iter_visibles():
4801 l3Inline
.iter_visibles
= iter_visibles
4802 l3Native
.iter_visibles
= iter_visibles
4807 self
._root
_group
.hide()
4808 for ii
in self
._d
_elements
:
4813 self
._root
_group
.hide()
4820 raise DisplayError("Interface only: " + str(self
.__class
__))
4824 self
._root
_group
.hide()
4825 for ch
in self
._dlist
:
4830 self
._root
_group
.hide()
4832 l3Rawtext
.hide
= hide
4835 self
._root
_group
.hide()
4842 self
._root
_group
.hide()
4844 self
._d
_equal
.hide()
4849 self
._root
_group
.hide()
4850 self
._d
_label
.hide()
4851 l3IfLoopBreak
.hide
= hide
4852 l3IfLoopContinue
.hide
= hide
4855 self
._root
_group
.hide()
4858 l3IfLoop
.hide
= hide
4861 self
._root
_group
.hide()
4865 l3IfWhile
.hide
= hide
4868 self
._root
_group
.hide()
4877 self
._root
_group
.hide()
4883 self
._root
_group
.hide()
4884 self
._d
_function
.hide()
4887 l3Function
.hide
= hide
4890 self
._root
_group
.hide()
4893 l3Program
.hide
= hide
4896 self
._root
_group
.hide()
4899 l3Inline
.hide
= hide
4900 l3Native
.hide
= hide
4905 def insert_event_shared(self
, item
, event
):
4906 if event
.type == gtk
.gdk
.BUTTON_PRESS
:
4907 if event
.button
== 2:
4908 if not self
.w_
.selector
.have_selection():
4909 self
.w_
.ten_second_message("No node selected.")
4912 self
.insert(item
, self
.w_
.selector
.get_selection())
4914 l3Call
.insert_event
= insert_event_shared
4915 l3Set
.insert_event
= insert_event_shared
4916 l3If
.insert_event
= insert_event_shared
4917 l3IfWhile
.insert_event
= insert_event_shared
4921 def append(self
, newobj
):
4922 self
.insert(len(self
._l3tree
), newobj
)
4923 l3aList
.append
= append
4925 def insert(self
, index
, newobj
):
4926 ### Remove any existing references to newobj in the CALLER --
4927 ### distinguish between MOVE and COPY.
4929 assert isinstance(newobj
, l3Base
)
4931 # Avoid special cases:
4932 if newobj
in self
._dlist
:
4933 self
.w_
.ten_second_message("Disconnect element before inserting "
4934 "into the same list.")
4937 if newobj
.contains_recursive(self
):
4938 self
.w_
.ten_second_message("Cannot insert list into itself.")
4941 if newobj
._canvas
!= self
._canvas
:
4942 self
.w_
.ten_second_message("Cannot move objects across displays. "
4947 newobj
.reparent(self
)
4949 # Draw new marker over insertion marker.
4950 ox1
, oy1
= marker_get_anchor(self
.w_
, self
._marker
_lst
[index
])
4952 if self
._l3tree
.getthe('layout') == 'horizontal':
4953 ox1
-= self
.w_
.cp_
.marker_padding
4954 ## oy1 += self.w_.cp_.marker_padding
4956 oy1
-= self
.w_
.cp_
.marker_padding
4958 if self
._hide
_markers
:
4959 newmarker
= self
.draw_marker(ox1
, oy1
, hidden_color
= 'white')
4961 newmarker
= self
.draw_marker(ox1
, oy1
)
4963 if self
._insertion
_on
_markers
:
4964 self
.bind_marker_events(newmarker
)
4967 if self
._l3tree
.getthe('layout') == 'horizontal':
4968 self
._adj
_h
_insert
(index
, newobj
, newmarker
)
4970 self
._adj
_v
_insert
(index
, newobj
, newmarker
)
4972 # Move following items in parent.
4974 self
._parent
.new_size_for(self
)
4976 # Update data and marker lists.
4977 if self
.w_
.fluid_ref(insert_l3_tree
= True):
4978 self
._l3tree
.insert_child_rec(index
,
4980 self
.w_
.state_
.storage
)
4981 if self
.w_
.fluid_ref(trace_gui_events
= False):
4982 print "insertion tree"
4983 self
._dlist
.insert(index
, newobj
)
4984 self
._marker
_lst
.insert(index
, newmarker
)
4988 # inform obj of marker
4989 newobj
.setup_marker(newmarker
, self
)
4991 l3aList
.insert
= insert
4993 def _adj_v_insert(self
, index
, newobj
, newmarker
):
4994 # Put object under marker.
4995 sl
, st
, sr
, sb
= marker_get_bounds(self
.w_
, newmarker
).pad_tb()
4996 ol
, ot
, _
, ob
= newobj
.get_bounds()
4997 newobj
.move(sl
- ol
, sb
- ot
)
4999 # Move following markers, labels and objects.
5000 shift_y
= (sb
- st
) + (ob
- ot
) ## + self.w_.cp_.marker_padding
5002 for itm
in self
._dlist
[index
: None]:
5003 itm
.move(0, shift_y
)
5005 for itm
in self
._marker
_lst
[index
: None]:
5006 itm
.move(0, shift_y
)
5007 l3aList
._adj
_v
_insert
= _adj_v_insert
5009 def _adj_h_insert(self
, index
, newobj
, newmarker
):
5010 # Put object under marker.
5011 sl
, st
, sr
, sb
= marker_get_bounds(self
.w_
, newmarker
).pad_lr()
5012 ol
, ot
, or_
, ob
= newobj
.get_bounds()
5013 newobj
.move(sr
- ol
, st
- ot
)
5015 # Move following markers, labels and objects.
5016 shift_x
= (sr
- sl
) + (or_
- ol
) ## + self.w_.cp_.marker_padding
5018 for itm
in self
._dlist
[index
: None]:
5019 itm
.move(shift_x
, 0)
5021 for itm
in self
._marker
_lst
[index
: None]:
5022 itm
.move(shift_x
, 0)
5023 l3aList
._adj
_h
_insert
= _adj_h_insert
5026 def insert(self
, marker
, newobj
):
5027 assert isinstance(newobj
, l3Base
)
5029 if marker
!= self
._d
_cond
_marker
:
5030 raise DisplayError("Insertion from wrong marker.")
5032 # Avoid special cases:
5033 if newobj
.contains_recursive(self
):
5034 self
.w_
.ten_second_message("Cannot insert if into itself.")
5037 if newobj
._canvas
!= self
._canvas
:
5038 self
.w_
.ten_second_message("Cannot move objects across displays. "
5043 old_entry
= self
._l3tree
.deref(0)
5044 slot_available(self
.w_
, old_entry
)
5047 self
._d
_cond
= d_cond
= newobj
5050 newobj
.reparent(self
)
5054 _
, y
, x
, _
= self
._d
_if
.get_bounds()
5055 u
, v
, _
, _
= self
._d
_cond
.get_bounds()
5056 d_cond
.move(x
+ self
.w_
.cp_
.loop_cond_sep
- u
, y
- v
)
5061 # Refresh decoration.
5064 # Move following items in parent.
5066 self
._parent
.new_size_for(self
)
5069 if self
.w_
.fluid_ref(insert_l3_tree
= True):
5070 self
._l3tree
.replace_child(old_entry
._id
, newobj
._l3tree
)
5072 # Inform obj of marker.
5073 newobj
.setup_marker(self
._d
_cond
_marker
, self
)
5075 l3If
.insert
= insert
5078 def insert(self
, marker
, newobj
):
5080 Insert new condition.
5082 assert isinstance(newobj
, l3Base
)
5084 if marker
!= self
._d
_cond
_marker
:
5085 raise DisplayError("Insertion from wrong marker.")
5087 # Avoid special cases:
5088 if newobj
.contains_recursive(self
):
5089 self
.w_
.ten_second_message("Cannot insert if into itself.")
5092 if newobj
._canvas
!= self
._canvas
:
5093 self
.w_
.ten_second_message("Cannot move objects across displays. "
5098 if len(self
._matcher
['COND-PARENT']) != 0:
5099 raise DisplayError("Insertion in occupied slot.")
5102 self
._d
_cond
= d_cond
= newobj
5105 newobj
.reparent(self
)
5109 _
, y
, x
, _
= self
._d
_loop
.get_bounds()
5110 u
, v
, _
, _
= self
._d
_cond
.get_bounds()
5111 d_cond
.move(x
+ self
.w_
.cp_
.loop_cond_sep
- u
, y
- v
)
5116 # Refresh decoration.
5119 # Move following items in parent.
5121 self
._parent
.new_size_for(self
)
5124 if self
.w_
.fluid_ref(insert_l3_tree
= True):
5125 self
._matcher
['COND-PARENT'].insert_child(
5126 self
._matcher
['COND-IDX'], newobj
._l3tree
)
5127 ## from: self._l3tree.replace_child(old_entry._id, newobj._l3tree)
5129 # Inform obj of marker.
5130 newobj
.setup_marker(self
._d
_cond
_marker
, self
)
5132 l3IfWhile
.insert
= insert
5135 def insert(self
, marker
, newobj
):
5136 assert isinstance(newobj
, l3Base
)
5138 if marker
!= self
._d
_func
_marker
:
5139 raise DisplayError("Insertion from wrong marker.")
5141 # Avoid special cases:
5142 if newobj
.contains_recursive(self
):
5143 self
.w_
.ten_second_message("Cannot insert if into itself.")
5146 if newobj
._canvas
!= self
._canvas
:
5147 self
.w_
.ten_second_message("Cannot move objects across displays. "
5152 old_entry
= self
._l3tree
.deref(0)
5153 slot_available(self
.w_
, old_entry
)
5156 self
._d
_func
= d_func
= newobj
5159 newobj
.reparent(self
)
5163 x
, y
, _
, _
= self
._d
_func
_marker
.get_bounds()
5164 u
, v
, _
, _
= self
._d
_func
.get_bounds()
5165 d_func
.move(x
- u
- self
.w_
.cp_
.exp_marker_hoff
,
5166 y
- v
- self
.w_
.cp_
.exp_marker_voff
)
5172 if self
.w_
.fluid_ref(insert_l3_tree
= True):
5173 self
._l3tree
.replace_child(old_entry
._id
, newobj
._l3tree
)
5175 # Refresh decoration.
5178 # Move following items in parent.
5180 self
._parent
.new_size_for(self
)
5182 # Inform obj of marker.
5183 newobj
.setup_marker(self
._d
_func
_marker
, self
)
5185 l3Call
.insert
= insert
5188 def insert(self
, marker
, newobj
):
5189 assert isinstance(newobj
, l3Base
)
5191 # Avoid special cases:
5192 if newobj
.contains_recursive(self
):
5193 self
.w_
.ten_second_message("Cannot insert if into itself.")
5196 if newobj
._canvas
!= self
._canvas
:
5197 self
.w_
.ten_second_message("Cannot move objects across displays. "
5201 if marker
== self
._d
_lhs
_marker
:
5203 old_entry
= self
._l3tree
.deref(0)
5204 slot_available(self
.w_
, old_entry
)
5206 # Check and update reference.
5207 self
._d
_lhs
= newobj
5210 newobj
.reparent(self
)
5212 # Position lhs w.r.t. marker
5214 x
, y
, _
, _
= self
._d
_lhs
_marker
.get_bounds()
5215 u
, v
, _
, _
= newobj
.get_bounds()
5216 newobj
.move(x
- u
- self
.w_
.cp_
.exp_marker_hoff
,
5217 y
- v
- self
.w_
.cp_
.exp_marker_voff
)
5220 self
._align
_to
_lhs
()
5223 if self
.w_
.fluid_ref(insert_l3_tree
= True):
5224 self
._l3tree
.replace_child(old_entry
._id
, newobj
._l3tree
)
5227 self
._d
_lhs
_marker
.hide()
5229 elif marker
== self
._d
_rhs
_marker
:
5231 old_entry
= self
._l3tree
.deref(1)
5232 slot_available(self
.w_
, old_entry
)
5234 # Check and update reference.
5235 self
._d
_rhs
= newobj
5238 newobj
.reparent(self
)
5241 # see also l3Set._align_to_lhs
5243 x
, _
, _
, y
= self
._d
_rhs
_marker
.get_bounds()
5244 u
, v
, _
, _
= newobj
.get_bounds()
5245 newobj
.move(x
- u
- self
.w_
.cp_
.exp_marker_hoff
,
5246 y
- v
- self
._canvas
.font_ascent_units() -
5247 self
._canvas
.bbox_offset_units()
5253 if self
.w_
.fluid_ref(insert_l3_tree
= True):
5254 self
._l3tree
.replace_child(old_entry
._id
, newobj
._l3tree
)
5257 self
._d
_rhs
_marker
.hide()
5260 raise DisplayError("Insertion from invalid marker.")
5262 # Refresh decoration.
5265 # Move following items in parent.
5267 self
._parent
.new_size_for(self
)
5269 # Inform obj of marker.
5270 newobj
.setup_marker(marker
, self
)
5273 l3Set
.insert
= insert
5278 def move(self
, dx
, dy
):
5279 self
._root
_group
.move(dx
, dy
)
5285 def move(self
, dx
, dy
):
5286 self
._root
_group
.move(dx
, dy
)
5288 self
._outline
.move(dx
, dy
)
5291 def move(self
, dx
, dy
):
5292 self
._root
_group
.move(dx
, dy
)
5298 def get_bounds_world(self
):
5299 i2w
= self
._root
_group
.get_property("parent").i2w
5300 x1
, y1
, x2
, y2
= self
.get_bounds()
5301 u1
, v1
= i2w(x1
, y1
)
5302 u2
, v2
= i2w(x2
, y2
)
5303 return u1
, v1
, u2
, v2
5304 l3Base
.get_bounds_world
= get_bounds_world
5305 Label
.get_bounds_world
= get_bounds_world
5306 Image
.get_bounds_world
= get_bounds_world
5307 Widget
.get_bounds_world
= get_bounds_world
5308 uWidget
.get_bounds_world
= get_bounds_world
5312 def get_bounds(self
):
5313 raise DisplayError("interface only")
5314 l3Base
.get_bounds
= get_bounds
5316 def get_bounds(self
):
5317 ### magic bound offset adjustment hack
5318 x
, y
, u
, v
= self
._root
_group
.get_bounds()
5320 # No adjustment when path is absent (like inserting or removing)
5321 if self
._deco
== None:
5322 # Good for "a = 2" (CanvasText at extremes), too much
5323 # for "<ph> = 2" (CanvasRect on left)
5324 return x
+ 0.5, y
+ 0.5, u
- 0.5, v
- 0.5
5325 # return x + 0.5, y + 0.5, u, v
5327 # With surrounding path decoration.
5329 adj
= (cp_
.deco
.outline_width
/ 2.0) * self
._canvas
._pixpu
5330 return x
+ adj
, y
+ adj
, u
- adj
, v
- adj
5332 # return x + 0.5, y + 0.5, u, v
5333 # return x + 0.5, y + 0.5, u - 0.5, v - 0.5
5335 l3Nested
.get_bounds
= get_bounds
5337 def get_bounds(self
):
5338 (ll
, tt
, rr
, bb
) = l3Nested
.get_bounds(self
)
5339 pad
= self
.w_
.cp_
.marker_padding
5340 return (ll
, tt
, rr
+ pad
, bb
+ pad
)
5341 l3Native
.get_bounds
= get_bounds
5343 # def get_bounds(self):
5344 # return self._root_group.get_bounds()
5345 # Placeholder.get_bounds = get_bounds
5347 def get_bounds(self
):
5348 ### magic bound offset adjustment hack
5349 le
, to
, ri
, bo
= self
._root
_group
.get_bounds()
5350 return le
, to
, ri
, bo
5351 # return x + 0.5, y + 0.5, u - 0.5, v - 0.5
5352 l3aList
.get_bounds
= get_bounds
5354 def get_bounds(self
):
5355 x
, y
, u
, v
= self
._root
_group
.get_bounds()
5356 # No adjustment when path is absent.
5357 if self
._deco
== None:
5358 ### magic bound offset adjustment hack
5359 return x
+ 0.5, y
+ 0.5, u
- 0.5, v
- 0.5
5361 # With surrounding path decoration.
5363 adj
= (cp_
.deco
.outline_width
/ 2.0) * self
._canvas
._pixpu
5364 return x
+ adj
, y
+ adj
, u
- adj
, v
- adj
5366 l3Rawtext
.get_bounds
= get_bounds
5368 def get_bounds(self
):
5369 ### magic bound offset adjustment hack
5370 x
, y
, u
, v
= self
._root
_group
.get_bounds()
5371 return x
+ 0.5, y
+ 0.5, u
- 0.5, v
- 0.5
5372 Label
.get_bounds
= get_bounds
5373 uWidget
.get_bounds
= get_bounds
5376 # libart's bounding boxes are a serious problem.
5378 # A rotated rectangle changes bounding box size, which is not
5379 # desirable here. So use an ellipse as background.
5380 # This didn't help, because the triangle is a path, for which the
5381 # bounding box is wrong anyway.
5383 # For this purpose, using symbol glyphs is a better approach anyway,
5384 # but fonts are not handled very well either...
5386 # Time to switch drawing/canvas engine.
5388 def get_bounds(self
):
5389 ### magic bound offset adjustment hack
5390 x
, y
, u
, v
= self
._root
_group
.get_bounds()
5391 return x
+ 0.5, y
+ 0.5, u
- 0.5, v
- 0.5
5392 uVisibleSymbol
.get_bounds
= get_bounds
5393 uPartiallyVisible
.get_bounds
= get_bounds
5394 uInvisibleSymbol
.get_bounds
= get_bounds
5396 def get_bounds(self
):
5397 x
, y
, u
, v
= self
._root
_group
.get_bounds()
5399 Widget
.get_bounds
= get_bounds
5400 Image
.get_bounds
= get_bounds
5403 def get_bounds(self
):
5404 return self
._root
_group
.get_bounds()
5405 l3IfLoopContinue
.get_bounds
= get_bounds
5406 l3IfLoopBreak
.get_bounds
= get_bounds
5409 #* Draw insertion markers
5410 def draw_marker_shared(self
):
5413 cp
.exp_marker_width
, 0,
5414 cp
.exp_marker_width
, cp
.exp_marker_height
,
5415 0 , cp
.exp_marker_height
,
5418 _marker
= self
._root
_group
.add(
5419 canvas
.CanvasPolygon
,
5420 fill_color
= "black",
5423 cap_style
= gtk
.gdk
.CAP_ROUND
,
5424 join_style
= gtk
.gdk
.JOIN_ROUND
,
5426 self
._marker
_points
[_marker
] = points
5428 l3Set
.draw_marker
= draw_marker_shared
5429 l3If
.draw_marker
= draw_marker_shared
5430 l3IfWhile
.draw_marker
= draw_marker_shared
5431 l3Call
.draw_marker
= draw_marker_shared
5432 l3Inline
.draw_marker
= draw_marker_shared
5434 #* Comments & headers
5436 # Fully movable text, but without any effect on execution.
5437 # These need most of the l3Rawtext functionality; a Label is grossly
5440 class l3Comment(l3Rawtext
):
5443 # # def __init__(self, *args, **kwds):
5444 # # l3Rawtext.__init__(self, *args, **kwds)
5445 # # l3Comment.__init__ = __init__
5447 def init_params(self
):
5448 self
._font
_desc
= self
.w_
.cp_
.comment_font
5449 self
._font
_size
= self
.w_
.cp_
.font_size_comments
* 1.0 * pango
.SCALE
5450 self
._fill
_color
= self
.w_
.cp_
.label_fill_color
5451 self
._outline
_color
= self
.w_
.cp_
.label_outline_color
5452 l3Comment
.init_params
= init_params
5455 #* Text editing support
5456 # Functions are in calling order.
5459 def rebuild_tree(self
, text
):
5461 ## print 'text_finished: parent: ', self._l3tree._parent
5462 if self
._l3tree
._parent
:
5463 parent
= self
.w_
.state_
.storage
.load( self
._l3tree
._parent
)
5465 parent
= empty_parent()
5467 ### trap parse errors here
5468 tree
= reader
.parse(text
).body()
5469 tree
.setup(parent
, self
.w_
.state_
.def_env
, self
.w_
.state_
.storage
)
5470 tree
.set_outl_edges(self
.w_
, None)
5473 if self
._l3tree
._parent
:
5474 self
._l3tree
.deep_replace(tree
, self
.w_
.state_
.storage
)
5477 l3Rawtext
.rebuild_tree
= rebuild_tree
5479 def ed_new_text(self
, text
):
5481 self
._text
_orig
= text
5482 text_and_outline(self
)
5484 # Resize from root node.
5486 # Adjust highlighting.
5488 # Avoid repositioning mess.
5491 self
._under
_destruction
= False
5492 l3Rawtext
.ed_new_text
= ed_new_text
5494 def ed_restore_text(self
):
5495 self
.ed_new_text(self
._text
_orig
)
5496 self
._under
_destruction
= False
5497 l3Rawtext
.ed_restore_text
= ed_restore_text
5499 def finish_edit(self
):
5500 # Remove decoration.
5502 # Refresh decoration.
5504 # Move following items in parent.
5506 self
._parent
.new_size_for(self
)
5507 l3Rawtext
.finish_edit
= finish_edit
5511 def rebuild_tree(self
, text
):
5513 tree
= ast
.Comment(text
)
5515 # Attach (logically) to node.
5517 self
.w_
.deco_table_
[ self
._parent
._l3tree
._id
] = tree
5519 tree
.setup(empty_parent(), self
.w_
.state_
.def_env
, self
.w_
.state_
.storage
)
5520 tree
.set_outl_edges(self
.w_
, None)
5523 l3Comment
.rebuild_tree
= rebuild_tree
5526 def ed_new_text(self
, text
):
5528 self
._text
_orig
= text
5529 # # text_and_outline(self)
5531 # Resize from root node.
5533 # Adjust highlighting.
5535 # Avoid repositioning mess.
5538 l3Comment
.ed_new_text
= ed_new_text
5541 def finish_edit(self
):
5542 # Refresh decoration.
5551 p1
._parent
.new_size_for(p1
)
5552 l3Comment
.finish_edit
= finish_edit
5555 #** l3ViewList / l3Program
5556 def ed_restore_text(self
):
5558 l3ViewList
.ed_restore_text
= ed_restore_text
5559 l3Program
.ed_restore_text
= ed_restore_text
5562 def rebuild_tree(self
, text
):
5564 self
._l3tree
.set_label(text
)
5565 self
.start_replace_visible()
5566 self
.w_
.with_fluids(body
,
5567 position_tree
= False)
5568 l3ViewList
.rebuild_tree
= rebuild_tree
5569 l3Program
.rebuild_tree
= rebuild_tree
5572 def ed_new_text(self
, text
):
5574 self
._text
_orig
= text
5576 # Adjust highlighting.
5578 # Avoid repositioning mess.
5581 l3ViewList
.ed_new_text
= ed_new_text
5582 l3Program
.ed_new_text
= ed_new_text
5585 def finish_edit(self
):
5586 # Refresh decoration.
5591 self
._parent
.new_size_for(self
)
5593 l3ViewList
.finish_edit
= finish_edit
5594 l3Program
.finish_edit
= finish_edit
5598 def prep_deco_text(self
):
5599 deco_t
= self
.w_
.deco_table_
5601 # Clear up prior temporaries.
5602 if deco_t
.has_key( self
._l3tree
._id
):
5603 if hasattr(deco_t
[ self
._l3tree
._id
], '_placeholder_temporary'):
5604 del deco_t
[ self
._l3tree
._id
]
5606 # Avoid empty display.
5607 # 1. No default text
5610 # 2. Override with explicit deco text.
5611 if deco_t
.has_key(self
._l3tree
._id
):
5612 deco_text
= deco_t
[self
._l3tree
._id
]
5614 # 3. Get automatic deco text for placeholder use, when no "good"
5615 # text is available.
5616 if deco_text
== "" and isinstance(self
, Placeholder
):
5617 deco_text
= self
._l3tree
.deco_title_text()
5619 deco_text
= "unlabeled code"
5621 # Set as default for this node.
5622 comm
= deco_t
[self
._l3tree
._id
] = ast
.Comment(deco_text
)
5623 comm
.setup(ast
.empty_parent(),
5624 self
.w_
.state_
.def_env
,
5625 self
.w_
.state_
.storage
)
5626 # Mark as temporary.
5627 comm
._placeholder
_temporary
= 1
5630 l3Nested
.prep_deco_text
= prep_deco_text
5631 l3Rawtext
.prep_deco_text
= prep_deco_text
5634 # Draw the header before the current contents of the _root_group.
5635 # Additions are made to the same _root_group.
5637 # Used after subclass __init__, before init_deco().
5639 def init_header(self
, rentab
):
5640 deco_text
= self
.prep_deco_text()
5643 # Create header and align H[eader] with S[elf].
5644 self
._header
= self
._canvas
.add_header_of(self
._l3tree
, rentab
)
5645 self
._header
.reparent(self
) # Only reparent the canvas group.
5647 ls
, ts
, rs
, bs
= self
.padded_bounds_world()
5648 lh
, th
, rh
, bh
= self
._header
.get_bounds_world()
5650 # Vertical alignment:
5651 if isinstance(self
, l3List
):
5652 # Header on top of label (hide the label)
5653 ll
, tl
, rl
, bl
= self
._head
.get_bounds_world()
5654 self
._header
.move(ll
- lh
, bl
- bh
)
5658 self
._header
.move(ls
- lh
, ts
- bh
)
5664 l3Nested
.init_header
= init_header
5665 l3Rawtext
.init_header
= init_header
5668 def init_header(self
, rentab
):
5669 deco_text
= self
.prep_deco_text()
5674 vl_type
= self
._l3tree
.get_outline_type()
5676 if vl_type
== 'flat':
5677 # Display only _head (label), ignore _header (comment).
5681 # Create header and align H[eader] with S[elf].
5682 self
._header
= self
._canvas
.add_header_of(self
._l3tree
, rentab
)
5683 self
._header
.reparent(self
) # Only reparent the canvas group.
5685 # # ls, ts, rs, bs = self.padded_bounds_world()
5686 lh
, th
, rh
, bh
= self
._header
.get_bounds()
5687 le
, te
, re
, be
= self
._expander
.get_bounds()
5688 ll
, tl
, rl
, bl
= self
._head
.get_bounds()
5689 la
, ta
, ra
, ba
= self
._alist
.get_bounds()
5691 # Vertical alignment:
5692 if vl_type
in ['nested', 'subtree']:
5700 # _header (comment, h)
5703 # Keep existing horizontal positioning for E, L, A; only H is
5705 self
._header
.move(la
- lh
, ta
- bh
) # H-A
5706 self
._head
.move(0, # L-A
5707 (ta
- (bh
- th
)) - bl
)
5708 self
._expander
.move(0, # E-A
5709 (ta
- (bh
- th
)) - be
)
5712 raise Exception("Invalid outline type. Internal error.")
5713 l3ViewList
.init_header
= init_header
5714 l3Program
.init_header
= init_header
5717 def refresh_header(self
):
5718 from l3gui
.l3canvas
import RenderTable
5719 # Delete header visuals (and reinsert with current settings).
5720 _safed(self
._header
)
5723 # todo: preserve rentab info?
5724 self
.init_header(RenderTable())
5726 l3Nested
.refresh_header
= refresh_header
5727 l3Rawtext
.refresh_header
= refresh_header
5732 #** drag / selection
5733 def drag_event(self
, item
, event
):
5734 if event
.type == gtk
.gdk
.BUTTON_PRESS
:
5735 if event
.button
== 1:
5736 if event
.state
& gtk
.gdk
.CONTROL_MASK
:
5737 self
.w_
.selector
.toggle_selection(self
)
5739 self
.w_
.selector
.set_selection(self
)
5741 self
._canvas
.grab_focus() # Ensure keystrokes go here.
5743 # sm: move group start
5744 self
.remember_x
= event
.x
5745 self
.remember_y
= event
.y
5748 elif event
.type == gtk
.gdk
.ENTER_NOTIFY
:
5749 # Alt + Shift + motion adds self to selection.
5750 if ((event
.state
& gtk
.gdk
.SHIFT_MASK
) and
5751 (event
.state
& gtk
.gdk
.MOD1_MASK
)):
5752 self
.w_
.selector
.add_to_selection(self
)
5755 elif event
.type == gtk
.gdk
.LEAVE_NOTIFY
:
5756 self
.w_
.cp_
.drag_state
= (None, None)
5758 elif event
.type == gtk
.gdk
.MOTION_NOTIFY
:
5759 if event
.state
& gtk
.gdk
.BUTTON1_MASK
:
5760 # Do not drag nested text, or the text of Inline.
5761 if isinstance(self
._parent
, (l3Rawtext
, l3Inline
)):
5762 (d_state
, _
) = self
.w_
.cp_
.drag_state
5763 if d_state
== "ds_dragging":
5766 self
.w_
.selector
.remove(self
)
5767 self
.w_
.cp_
.drag_state
= ("ds_start", (event
.x
, event
.y
))
5770 # Get the new position and move by the difference.
5773 # The button_press event above may not have occurred, so
5774 # ensure a valid prior position.
5775 if self
.remember_x
is None:
5776 self
.remember_x
= event
.x
5777 self
.remember_y
= event
.y
5781 dx
= new_x
- self
.remember_x
5782 dy
= new_y
- self
.remember_y
5784 self
.remember_x
= new_x
5785 self
.remember_y
= new_y
5787 # sm: detach item if needed.
5789 x
, y
= self
.get_anchor()
5790 u
, v
= marker_get_anchor(self
.w_
, self
._marker
)
5791 if self
.w_
.fluid_ref(trace_gui_events
= False):
5792 print "distance: ", abs(u
- x
) + abs(v
- y
)
5794 if (abs(u
- x
) + abs(v
- y
) >
5795 self
.w_
.cp_
.item_detach_distance
):
5797 self
._container
.detach(self
)
5798 self
._container
= None
5802 l3Rawtext
.drag_event
= drag_event
5804 def drag_event(self
, item
, event
):
5806 l3Comment
.drag_event
= drag_event
5808 def drag_event(self
, item
, event
):
5809 if event
.type == gtk
.gdk
.BUTTON_PRESS
:
5810 if event
.button
== 1:
5811 if event
.state
& gtk
.gdk
.CONTROL_MASK
:
5812 self
.w_
.selector
.toggle_selection(self
)
5814 self
.w_
.selector
.set_selection(self
)
5816 self
._canvas
.grab_focus() # Ensure keystrokes go here.
5818 # sm: move group start
5819 self
.remember_x
= event
.x
5820 self
.remember_y
= event
.y
5823 elif event
.type == gtk
.gdk
.ENTER_NOTIFY
:
5824 # Alt + Shift + motion adds self to selection.
5825 if ((event
.state
& gtk
.gdk
.SHIFT_MASK
) and
5826 (event
.state
& gtk
.gdk
.MOD1_MASK
)):
5827 self
.w_
.selector
.add_to_selection(self
)
5830 elif event
.type == gtk
.gdk
.MOTION_NOTIFY
:
5831 if event
.state
& gtk
.gdk
.BUTTON1_MASK
:
5833 # Get the new position and move by the difference.
5836 # The button_press event above may not have occurred, so
5837 # ensure a valid prior position.
5838 (d_state
, d_val
) = self
.w_
.cp_
.drag_state
5839 if d_state
== "ds_start":
5840 (self
.remember_x
, self
.remember_y
) = d_val
5841 self
.w_
.cp_
.drag_state
= ("ds_dragging", d_val
)
5843 if self
.remember_x
is None:
5844 self
.remember_x
= event
.x
5845 self
.remember_y
= event
.y
5849 dx
= new_x
- self
.remember_x
5850 dy
= new_y
- self
.remember_y
5852 self
.remember_x
= new_x
5853 self
.remember_y
= new_y
5856 # Detach from parent once self is far enough from marker.
5857 x
, y
= self
.get_anchor()
5858 u
, v
= marker_get_anchor(self
.w_
, self
._marker
)
5859 if self
.w_
.fluid_ref(trace_gui_events
= False):
5860 print "distance: ", abs(u
- x
) + abs(v
- y
)
5862 if (abs(u
- x
) + abs(v
- y
)) > self
.w_
.cp_
.item_detach_distance
:
5864 self
._container
.detach(self
)
5866 self
._container
= None
5867 misc
.single_event(_do
)
5871 l3Nested
.drag_event
= drag_event
5874 def drag_event(self
, item
, event
):
5875 if event
.type == gtk
.gdk
.BUTTON_PRESS
:
5876 if event
.button
== 1:
5877 if event
.state
& gtk
.gdk
.CONTROL_MASK
:
5878 self
.w_
.selector
.toggle_selection(self
)
5880 self
.w_
.selector
.set_selection(self
)
5882 self
._canvas
.grab_focus() # Ensure keystrokes go here.
5884 # sm: move group start
5885 self
.remember_x
= event
.x
5886 self
.remember_y
= event
.y
5889 elif event
.type == gtk
.gdk
.MOTION_NOTIFY
:
5890 if event
.state
& gtk
.gdk
.BUTTON1_MASK
:
5892 # Get the new position and move by the difference.
5897 dx
= new_x
- self
.remember_x
5898 dy
= new_y
- self
.remember_y
5900 self
.remember_x
= new_x
5901 self
.remember_y
= new_y
5905 l3aList
.drag_event
= drag_event
5909 def destroy_event(self
, item
, event
):
5910 if event
.type == gtk
.gdk
._2BUTTON
_PRESS
:
5911 if event
.button
== 3:
5912 self
._canvas
.remove_node_edge_all(self
)
5915 l3Rawtext
.destroy_event
= destroy_event
5919 def head_event(self
, item
, event
):
5920 # doubleclick-button-1 to edit.
5921 if event
.type == gtk
.gdk
._2BUTTON
_PRESS
:
5922 if event
.button
== 1:
5923 self
._editor
= TextEdit(self
.w_
,
5925 self
._l3tree
.deco_title_text(),
5926 self
._canvas
._common
_tag
_table
,
5929 self
._editor
._view
.show()
5930 self
._editor
._view
.grab_focus()
5933 l3ViewList
.head_event
= head_event
5934 l3Program
.head_event
= head_event
5940 #** l3Deco: Decoration around contents.
5941 # This includes the outlines, buttons (if
5942 # any) and the titlebar (if present)
5946 def __init__(self
, node
):
5947 # For full initialization example, see add_deco_to.
5949 # # not practical: self._node_id = node._l3tree._id
5950 # # cyclic: self._node = node
5953 self
._deco
_path
= None # art_path
5954 self
._deco
_path
_item
= None # canvas.CanvasBpath (holds _deco_path)
5955 self
._draw
_queue
= [] # See add_item()
5957 l3Deco
.__init
__ = __init__
5959 def add_item(self
, cnvsitem
):
5960 assert hasattr(cnvsitem
, "destroy")
5961 assert hasattr(cnvsitem
, "refresh")
5962 self
._draw
_queue
.append(cnvsitem
)
5963 l3Deco
.add_item
= add_item
5966 _safed(self
._deco
_path
_item
)
5967 for ii
in self
._draw
_queue
:
5970 self
._draw
_queue
= []
5971 self
._deco
_path
= None
5972 self
._deco
_path
_item
= None
5973 l3Deco
.destroy
= destroy
5976 def magnify_event(self
, item
, event
):
5977 if event
.type == gtk
.gdk
.ENTER_NOTIFY
:
5978 if self
.w_
.fluid_ref(trace_gui_events
= False):
5979 print "deco_magnify_event"
5980 item
.set_property("width_units",
5981 self
.w_
.cp_
.deco
.outline_width
*
5982 self
.w_
.cp_
.hover_magnification
)
5985 elif event
.type == gtk
.gdk
.LEAVE_NOTIFY
:
5986 if self
.w_
.fluid_ref(trace_gui_events
= False):
5987 print "deco_magnify_event"
5988 item
.set_property("width_units", self
.w_
.cp_
.deco
.outline_width
)
5990 l3Deco
.magnify_event
= magnify_event
5993 #** attach (add) deco to node
5994 def add_deco_to(node
, callbacks
= [], emphasis_for
= None):
5996 Produce and return the l3Deco for `node`.
5997 This routine puts an outline around `node`.
5999 `node` interface requirements:
6004 Every ballback cb must (1) be callable
6005 (2) return a canvasitem or l3Nested instance OB
6006 The returned Ob must satisfy the interface specified in add_item().
6009 the_deco
= l3Deco(node
)
6010 # Self-drawing items.
6011 for cb
in callbacks
:
6012 the_deco
.add_item(cb())
6014 # Bounds for the node body.
6015 ll1
, tt1
, rr1
, bb1
= node
.get_bounds_world()
6016 path_width
= node
.w_
.cp_
.deco
.outline_width
6017 if isinstance(node
, (l3Nested
, Label
)):
6018 padding
= 2 * path_width
6027 # Check for content, and inflate bounds to get a valid vector path.
6028 if rr1
- ll1
< 1: rr1
= ll1
+ 1.0
6029 if bb1
- tt1
< 1: bb1
= tt1
+ 1.0
6032 # Draw boundary path.
6034 the_deco
._deco
_path
= path_rectangle_rounded(ll1
, rr1
, tt1
, bb1
,
6035 0.5, 0.5, ### params
6039 bdry_path
= canvas
.path_def_new(the_deco
._deco
_path
)
6041 the_deco
._deco
_path
_item
= bdry_item
= node
._root
_group
.add(
6043 width_units
= path_width
,
6044 outline_color_rgba
= node
.w_
.cp_
.deco
.emph_color
[emphasis_for
],
6045 fill_color
= "green",
6046 cap_style
= gtk
.gdk
.CAP_ROUND
,
6047 join_style
= gtk
.gdk
.JOIN_ROUND
,
6050 the_deco
._deco
_path
_item
= bdry_item
= node
._root
_group
.add(
6052 width_units
= path_width
,
6053 outline_color_rgba
= node
.w_
.cp_
.deco
.outline_color
,
6054 fill_color
= "green",
6055 cap_style
= gtk
.gdk
.CAP_ROUND
,
6056 join_style
= gtk
.gdk
.JOIN_ROUND
,
6058 bdry_item
.set_bpath(bdry_path
)
6059 # Adjust coordinate offsets.
6060 l_bi
, t_bi
, r_bi
, b_bi_
= canvas_item_get_bounds_world(bdry_item
)
6061 bdry_item
.move(ll1
- l_bi
- path_width
, tt1
- t_bi
- path_width
)
6063 # Background coloring.
6064 the_deco
._background
= None
6067 bck
= the_deco
._background
= node
._root
_group
.add(
6071 # fill_color_rgba = node.w_.cp_.deco.outline_color,
6072 fill_color
= 'white',
6073 width_pixels
= node
.w_
.cp_
.outline_width_normal
,
6075 # Move background to bottom.
6076 bck
.lower_to_bottom()
6081 the_deco
._deco
_path
_item
.connect(
6082 "event", lambda *a
: the_deco
.magnify_event(*a
))
6089 def padded_bounds_world(self
):
6090 # Bounds for the node body.
6091 ll1
, tt1
, rr1
, bb1
= self
.get_bounds_world()
6092 path_width
= self
.w_
.cp_
.deco
.outline_width
6093 if isinstance(self
, l3Nested
):
6094 padding
= 2 * path_width
6103 # Check for content, and inflate bounds to get a valid vector path.
6104 if rr1
- ll1
< 1: rr1
= ll1
+ 1.0
6105 if bb1
- tt1
< 1: bb1
= tt1
+ 1.0
6111 return ll1
, tt1
, rr1
, bb1
6112 l3Nested
.padded_bounds_world
= padded_bounds_world
6113 l3Rawtext
.padded_bounds_world
= padded_bounds_world
6117 # Draw the border and other decorations around the current
6118 # contents of the _root_group.
6119 # Additions are made to the same _root_group.
6121 # Used *after* init_header().
6124 def init_deco(self
, rentab
):
6126 self
._deco
= add_deco_to(self
)
6127 l3Function
.init_deco
= init_deco
6129 def init_deco(self
, rentab
):
6131 ## self._deco = add_deco_to(self, callbacks = self._deco_cb_buffer)
6133 l3IfLoop
.init_deco
= init_deco
6134 l3IfWhile
.init_deco
= init_deco
6137 def init_deco(self
, rentab
):
6140 # Move the placeholder to the right of the header string, into
6142 if self
._header
!= None:
6143 l1
, t1
, r1
, b1
= self
._header
.get_bounds()
6144 l2
, t2
, r2
, b2
= self
._blank
.get_bounds()
6145 self
._blank
.move(l1
- r2
- self
.w_
.cp_
.placeholder
.padding
,
6148 # init_header must always provide a header for Placeholder.
6149 raise Exception("Invalid state in l3Nested.init_deco. "
6150 "No header found. Internal error")
6151 # Emphasize body / add outline.
6152 emph
= self
._l3tree
.get_emphasis()
6154 self
._deco
= add_deco_to(self
, emphasis_for
= emph
)
6158 Placeholder
.init_deco
= init_deco
6161 def init_deco(self
, rentab
):
6162 # Emphasize body / add outline.
6163 emph
= self
._l3tree
.get_emphasis()
6165 self
._deco
= add_deco_to(self
, emphasis_for
= emph
)
6168 l3Rawtext
.init_deco
= init_deco
6169 l3Nested
.init_deco
= init_deco
6174 def refresh_deco(self
):
6175 from l3gui
.l3canvas
import RenderTable
6176 # Remove decoration.
6182 # todo: preserve rentab info?
6183 self
.init_deco(RenderTable())
6185 l3Nested
.refresh_deco
= refresh_deco
6186 l3Rawtext
.refresh_deco
= refresh_deco
6190 def destroy_deco(self
):
6193 _safed(self
._header
)
6196 _safed(self
._root
_group
)
6197 del self
._root
_group
6200 l3Nested
.destroy_deco
= destroy_deco
6203 #** interactive modification
6204 def deco_change_label(self
, label
= None):
6205 # The following also works in "evaluate locally"
6207 print "enter new label:"
6209 label
= sys
.stdin
.readline().rstrip()
6211 assert isinstance(label
, StringType
), "Label must be a string."
6214 comm
= self
.w_
.deco_table_
[self
._l3tree
._id
] = ast
.Comment(label
)
6215 comm
.setup(ast
.empty_parent(),
6216 self
.w_
.state_
.def_env
,
6217 self
.w_
.state_
.storage
)
6219 # Refresh decoration.
6220 self
.refresh_header()
6225 self
._parent
.new_size_for(self
)
6226 l3Base
.deco_change_label
= deco_change_label
6228 def deco_add_comment(self
):
6231 comm
= self
.w_
.deco_table_
[self
._l3tree
._id
] = \
6232 ast
.Comment("double-click to edit")
6233 comm
.setup(ast
.empty_parent(),
6234 self
.w_
.state_
.def_env
,
6235 self
.w_
.state_
.storage
)
6237 # Refresh decoration.
6238 self
.refresh_header()
6243 self
._parent
.new_size_for(self
)
6244 l3Base
.deco_add_comment
= deco_add_comment
6247 #* Resizing / new_size_for
6249 def new_size_for(self
, child
):
6250 assert isinstance(child
, (l3Base
, l3aList
))
6252 index
= self
._dlist
.index(child
)
6254 raise DisplayError("nonexistent child.")
6257 if self
._l3tree
.getthe('layout') == 'horizontal':
6258 ml
, mt
, mr
, mb
= marker_get_bounds(
6259 self
.w_
, self
._marker
_lst
[index
]).pad_lr()
6260 cl
, ct
, cr
, cb
= child
.get_bounds()
6262 # Horizontal alignment:
6264 child
.move(mr
- cl
, mt
- ct
)
6265 # Move following markers, labels, and objects
6267 ml
, mt
, mr
, mb
= marker_get_bounds(
6268 self
.w_
, self
._marker
_lst
[index
+ 1]).pad_lr()
6269 cl
, ct
, cr
, cb
= child
.get_bounds()
6271 for itm
in self
._dlist
[index
+ 1 : None]:
6272 itm
.move(shift_x
, 0)
6273 for itm
in self
._marker
_lst
[index
+ 1 : None]:
6274 itm
.move(shift_x
, 0)
6277 ml
, mt
, mr
, mb
= marker_get_bounds(
6278 self
.w_
, self
._marker
_lst
[index
]).pad_tb()
6279 cl
, ct
, cr
, cb
= child
.get_bounds()
6282 # Vertical alignment:
6285 child
.move(ml
- cl
, mb
- ct
)
6286 # Move following markers, labels, and objects
6288 x
, y
, _
, _
= marker_get_bounds(
6289 self
.w_
, self
._marker
_lst
[index
+ 1]).pad_tb()
6290 _
, _
, u
, v
= child
.get_bounds()
6292 for itm
in self
._dlist
[index
+ 1 : None]:
6293 itm
.move(0, shift_y
)
6294 for itm
in self
._marker
_lst
[index
+ 1 : None]:
6295 itm
.move(0, shift_y
)
6299 self
._parent
.new_size_for(self
)
6301 l3aList
.new_size_for
= new_size_for
6305 def new_size_for(self
, child
):
6306 # Contained alist is updated; only forward request.
6308 self
._parent
.new_size_for(self
)
6309 l3Nested
.new_size_for
= new_size_for
6311 def new_size_for(self
, child
):
6312 # Contained value updated; only forward request.
6314 self
._parent
.new_size_for(self
)
6315 l3Native
.new_size_for
= new_size_for
6318 #*** if / set / call / function
6319 def new_size_for(self
, child
):
6321 # Shift contents vertically as needed.
6323 assert isinstance(child
, (l3Base
, l3aList
))
6325 # Find and apply shift.
6326 if child
== self
._d
_cond
:
6327 _
, _
, _
, y
= self
._d
_cond
.get_bounds()
6328 _
, v
, _
, _
= self
._d
_yes
.get_bounds()
6330 self
._d
_yes
.move(0, dy
)
6331 self
._d
_else
.move(0, dy
)
6332 self
._d
_no
.move(0, dy
)
6334 elif child
== self
._d
_yes
:
6335 _
, _
, _
, y
= self
._d
_yes
.get_bounds()
6336 _
, v
, _
, _
= self
._d
_else
.get_bounds()
6338 self
._d
_else
.move(0, dy
)
6339 self
._d
_no
.move(0, dy
)
6341 elif child
== self
._d
_no
:
6345 raise DisplayError("nonexistent child.")
6347 # Refresh decoration.
6352 self
._parent
.new_size_for(self
)
6354 l3If
.new_size_for
= new_size_for
6357 def new_size_for(self
, child
):
6359 # Shift contents vertically as needed.
6361 assert isinstance(child
, (l3Base
, l3aList
))
6363 # Find and apply shift.
6364 if child
is self
._d
_cond
:
6365 _
, _
, _
, bco
= self
._d
_cond
.get_bounds()
6366 _
, tbo
, _
, _
= self
._d
_body
.get_bounds()
6367 self
._d
_body
.move(0, bco
- tbo
)
6369 # Refresh decoration.
6374 self
._parent
.new_size_for(self
)
6376 l3IfWhile
.new_size_for
= new_size_for
6379 def new_size_for(self
, child
):
6381 # Shift contents vertically as needed.
6383 assert isinstance(child
, (l3Base
, l3aList
))
6385 # Find and apply shift.
6387 # Refresh decoration.
6392 self
._parent
.new_size_for(self
)
6394 l3IfLoop
.new_size_for
= new_size_for
6395 l3IfLoopBreak
.new_size_for
= new_size_for
6396 l3IfLoopContinue
.new_size_for
= new_size_for
6399 def new_size_for(self
, child
):
6401 # Shift contents as needed.
6403 assert isinstance(child
, (l3Base
, l3aList
))
6405 # Find and apply shift.
6406 if child
== self
._d
_lhs
:
6407 self
._align
_to
_lhs
()
6409 elif child
== self
._d
_rhs
:
6413 raise DisplayError("nonexistent child.")
6415 # Refresh decoration.
6420 self
._parent
.new_size_for(self
)
6421 l3Set
.new_size_for
= new_size_for
6424 def new_size_for(self
, child
):
6426 # Shift contents as needed.
6428 assert isinstance(child
, (l3Base
, l3aList
))
6430 # Find and apply shift.
6431 if child
== self
._d
_func
:
6434 elif child
== self
._d
_args
:
6438 raise DisplayError("nonexistent child.")
6440 # Refresh decoration.
6445 self
._parent
.new_size_for(self
)
6446 l3Call
.new_size_for
= new_size_for
6449 def new_size_for(self
, child
):
6451 # Shift contents vertically as needed.
6453 assert isinstance(child
, (l3Base
, l3aList
))
6455 # Find and apply shift.
6456 if child
== self
._d
_args
:
6457 _
, _
, _
, y
= self
._d
_args
.get_bounds()
6458 _
, v
, _
, _
= self
._d
_body
.get_bounds()
6460 self
._d
_body
.move(0, dy
)
6462 elif child
== self
._d
_body
:
6466 raise DisplayError("nonexistent child.")
6468 # Refresh decoration.
6473 self
._parent
.new_size_for(self
)
6475 l3Function
.new_size_for
= new_size_for
6478 #*** list / map / program
6479 def new_size_for(self
, child
):
6481 # Shift contents vertically as needed.
6483 assert isinstance(child
, (l3aList
,))
6485 # Find and apply shift.
6487 # Refresh decoration.
6492 self
._parent
.new_size_for(self
)
6494 l3Map
.new_size_for
= new_size_for
6495 l3List
.new_size_for
= new_size_for
6496 l3Program
.new_size_for
= new_size_for
6500 #** internal functions
6501 def marker_eval_local(self
, args
):
6502 # args: (menuitem, index)
6505 from code
import InteractiveConsole
6507 ic
= InteractiveConsole(ic_dict
)
6508 utils
.print_("==== marker index is %d ====" % args
[1] )
6509 ic
.interact("==== local console; exit with end-of-file (ctrl-d) ====")
6510 utils
.print_( "==== local console exit ====")
6511 l3aList
.marker_eval_local
= marker_eval_local
6513 def eval_local(self
, args
):
6514 # args: (menuitem, index)
6515 from l3gui
.cruft
.pylab
import Console
6516 name_s
= "Local Python Console\nfor %d" % self
._l3tree
._id
6520 lambda *args
: (self
.w_
.notebk_consoles
.destroy_page(name_s
),
6521 self
.w_
.stdinouterr
.pop()
6523 self
.w_
.notebk_consoles
.add_page(console
, name_s
)
6524 self
.w_
.stdinouterr
.push()
6525 console
.std_to_widget()
6526 console
.write("==== Local console; exit with end-of-file (ctrl-d) ====\n"
6527 "==== The name `self` is the instance. ====\n",
6530 misc
.show_consoles(self
.w_
)
6531 l3Base
.selection_eval_local
= eval_local
6532 l3Base
.eval_local
= eval_local
6533 l3aList
.eval_local
= eval_local
6536 def eval_local_console(self
, args
):
6538 # For use from calling console; this version stops the gui event
6540 from code
import InteractiveConsole
6542 ic
= InteractiveConsole(ic_dict
)
6544 # Simple combination of TxtConsole._raw_input and new_termconsole().
6545 # This is a good overview of the use of those parts.
6546 def _raw_input(prompt
=""):
6548 from threading
import Lock
6554 value
.append(raw_input(prompt
))
6556 value
.append(EOFError())
6559 thread
.start_new_thread(_do
, ())
6560 # Manual main loop until input is ready.
6561 while not lck
.acquire(False):
6564 if isinstance(value
[-1], Exception):
6568 ic
.raw_input = _raw_input
6569 ic
.interact("==== local console; exit with end-of-file (ctrl-d) ====")
6570 utils
.print_( "==== local console exit ====")
6571 l3Base
.eval_local_console
= eval_local_console
6576 def get_values_list(self
):
6577 ''' return ((id, value) list)'''
6578 return self
._l3tree
.get_values_list(self
.w_
)
6579 l3Base
.get_values_list
= get_values_list
6580 l3aList
.get_values_list
= get_values_list
6582 # # def dump_values(self):
6583 # # st = self.w_.state_.storage
6584 # # tw = ast.TreeWork(self.w_.state_.storage)
6586 # # # Toplevel id (static).
6587 # # c_id = self._l3tree._id
6588 # # G.logger.info("value of %d is %s" % (
6589 # # c_id, st.get_attribute(c_id, 'interp_result')))
6591 # # # Dynamic id(s).
6592 # # clone_l = st.get_attribute(c_id, "interp_clone")
6594 # # G.logger.info("%d has %d clones.\nValues:" % (c_id, len(clone_l)))
6596 # # for id in clone_l:
6597 # # G.logger.info("%d %s\n" %
6598 # # (id, st.get_attribute(id, 'interp_result')))
6600 # # G.logger.info("No clones of %d" % c_id)
6602 # # 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 # # print "----------------------"
6611 # # # Dynamic id(s).
6612 # # def _dynamic(c_id, lev):
6613 # # clone_l = st.get_attribute(c_id, "interp_clone")
6615 # # print ind*lev, "%d has %d clone(s):" % (c_id, len(clone_l))
6617 # # for id in clone_l:
6618 # # _dynamic(id, lev+1)
6620 # # print ind*lev, c_id, "has no clones;",\
6621 # # "value: ", st.get_attribute(c_id, 'interp_result')
6622 # # _dynamic(c_id, 0)
6625 def dump_values(self
):
6626 """Print a (potentially) nested tree of values for self and all clones.
6629 st
= self
.w_
.state_
.storage
6630 tw
= ast
.TreeWork(self
.w_
.state_
.storage
)
6632 # Toplevel id (static).
6633 c_id
= self
._l3tree
._id
6634 print "----------------------"
6637 def _dynamic(c_id
, lev
):
6638 clone_l
= st
.get_attribute(c_id
, "interp_clone")
6640 print ind
*lev
, "%d repeats %d time(s):" % (c_id
, len(clone_l
))
6645 print ind
*lev
, c_id
, "does not repeat;",\
6646 "value: ", st
.get_attribute(c_id
, 'interp_result')
6648 l3Base
.dump_values
= dump_values
6649 l3aList
.dump_values
= dump_values
6651 def get_value(self
, id):
6652 """Return the value corresponding to the numeric `id`.
6654 st
= self
.w_
.state_
.storage
6655 return st
.get_attribute(id, 'interp_result')
6656 l3Base
.get_value
= get_value
6657 l3aList
.get_value
= get_value
6660 def string_export(self
):
6662 st
= self
.w_
.state_
.storage
6663 tw
= ast
.TreeWork(self
.w_
.state_
.storage
)
6665 # Toplevel id (static).
6666 c_id
= self
._l3tree
._id
6667 print '---------------------------------'
6670 def _dynamic(c_id
, lev
):
6671 clone_l
= st
.get_attribute(c_id
, "interp_clone")
6673 # print ind*lev, "%d repeats %d time(s):" % (c_id, len(clone_l))
6677 # value in str() form
6678 val
= st
.get_attribute(c_id
, 'interp_result')
6682 print '---------------------------------'
6683 l3Base
.string_export
= string_export
6684 l3aList
.string_export
= string_export
6687 #* Subtree visibility
6690 def mark_as(self
, visibility
):
6692 self
._canvas
._vis
_tab
[self
._l3tree
._id
] = visibility
6694 # Background visibility indicator.
6697 self
._vis
_indic
.destroy()
6698 self
._vis
_indic
= None
6701 x1
, y1
, x2
, y2
= self
.get_bounds()
6702 pad
= self
.w_
.cp_
.highlight_padding
6708 # What depth to use?
6709 # Subtrees are in their own group; within that, the box is
6710 # always at the bottom.
6719 # The parent's bounding box should not change.
6721 add
= self
._parent
._root
_group
.add
6723 add
= self
._canvas
.root().add
6724 self
._vis
_indic
= add(
6729 outline_color
= 'black',
6730 width_pixels
= self
.w_
.cp_
.outline_width_normal
,
6732 self
._vis
_indic
.lower_to_bottom()
6734 if visibility
== "vis_hide":
6737 elif visibility
== "vis_show":
6740 elif visibility
== "vis_neutral":
6742 self
._vis
_indic
.destroy()
6743 self
._vis
_indic
= None
6746 raise DisplayError("Invalid visibility flag.")
6747 l3Base
.mark_as
= mark_as
6750 #** subtree swapping
6751 def start_replace_visible(self
):
6754 self
._parent
.replace_visible(self
)
6756 self
._canvas
.replace_visible(self
)
6757 self
.w_
.with_fluids(body
,
6758 detach_l3_tree
= False,
6759 insert_l3_tree
= False,
6761 l3Base
.start_replace_visible
= start_replace_visible
6763 def replace_visible(self
, child
):
6765 marker
= child
._marker
6766 l3tree
= child
._l3tree
6768 # Remove existing display.
6771 # Draw (visible) subtree.
6772 tree_disp
= self
._canvas
.start_add_l3tree(l3tree
)
6774 # Attach / move / reparent
6776 self
.insert(marker
, tree_disp
)
6780 l3Nested
.replace_visible
= replace_visible
6782 def replace_visible(self
, child
):
6784 index
= self
._dlist
.index(child
)
6785 l3tree
= child
._l3tree
6786 # # if isinstance(l3tree, ast.viewList):
6787 # # l3tree = l3tree._real_tree
6790 # Remove existing display.
6793 # Draw (visible) subtree.
6794 ### self._canvas._vis_tab.get_render_table(l3tree)
6795 tree_disp
= self
._canvas
.start_add_l3tree(l3tree
)
6799 self
.insert(index
, tree_disp
)
6803 self
._parent
.new_size_for(self
)
6804 l3aList
.replace_visible
= replace_visible
6807 #** Convenience combinations.
6808 def show_nested_lhs(self
):
6810 vista
= self
._canvas
._vis
_tab
6812 # Clear existing markings
6813 vista
.clear_tree( self
._l3tree
)
6816 self
.mark_as("vis_show")
6819 N
= 3 # maximum visible sublevel
6820 for nd
, dent
in self
._l3tree
.top_down_indented():
6822 vista
[nd
._id
] = "vis_hide"
6824 if ma
.match(nd
, Set(Marker('lhs'), Marker('rhs')) ):
6825 vista
[ma
['lhs']._id
] = "vis_show"
6826 vista
[ma
['rhs']._id
] = "vis_hide"
6829 self
.start_replace_visible()
6830 l3Base
.show_nested_lhs
= show_nested_lhs
6832 def show_one_subtree(self
):
6834 self
.mark_as("vis_show")
6835 self
._canvas
._vis
_tab
.hide_at(self
._l3tree
, 2) ### choose level
6836 self
.start_replace_visible()
6837 l3Base
.show_one_subtree
= show_one_subtree
6839 def show_subtree(self
):
6842 self
.mark_as("vis_show")
6843 self
.start_replace_visible()
6844 self
.w_
.with_fluids(body
, position_tree
= False)
6845 l3Base
.show_subtree
= show_subtree
6847 def show_full_subtree(self
):
6848 self
._canvas
._vis
_tab
.clear_tree( self
._l3tree
)
6849 # # self.mark_as("vis_show")
6850 self
.start_replace_visible()
6851 l3Base
.show_full_subtree
= show_full_subtree
6853 def hide_subtree(self
):
6855 self
.mark_as("vis_hide")
6856 self
.start_replace_visible()
6857 l3Base
.hide_subtree
= hide_subtree
6860 def hide_subtree(self
):
6861 # Redirect the hide request to the tree this comment is attached to.
6862 # Find key matching value -- deco_table_ maps (tree id -> comment)
6863 for tree_id
, comment
in self
.w_
.deco_table_
.iteritems():
6864 if comment
== self
._l3tree
: break
6865 l3tree
= self
._canvas
._nodes
[tree_id
]
6866 l3tree
.mark_as("vis_hide")
6867 l3tree
.start_replace_visible()
6868 l3Comment
.hide_subtree
= hide_subtree
6872 def detach_header(self
, header
):
6873 # Allow for multiple headers in the future.
6874 if header
!= self
._header
:
6875 raise Exception("detaching unknown header")
6877 # Reparent graphical parts.
6878 header
.reparent_to_root()
6881 # Update table data.
6882 # # if self.w_.deco_table_.has_key(self._l3tree._id):
6883 # # del self.w_.deco_table_[self._l3tree._id]
6885 # # print "WARNING: disconnected header was not known." \
6886 # # " Internal inconsistency."
6888 # Decoration and header must be separate when destroying
6889 # placeholder constructs (and others?).
6890 ## self.refresh_deco()
6892 # Move following items in parent.
6894 self
._parent
.new_size_for(self
)
6895 l3Base
.detach_header
= detach_header
6900 def add_reparent_to_root_hook(self
, func
):
6901 self
._reparent
_to
_root
_hook
.append(func
)
6902 l3Base
.add_reparent_to_root_hook
= add_reparent_to_root_hook
6903 l3aList
.add_reparent_to_root_hook
= add_reparent_to_root_hook
6904 Label
.add_reparent_to_root_hook
= add_reparent_to_root_hook
6905 Widget
.add_reparent_to_root_hook
= add_reparent_to_root_hook
6906 Image
.add_reparent_to_root_hook
= add_reparent_to_root_hook
6907 uWidget
.add_reparent_to_root_hook
= add_reparent_to_root_hook
6909 def _run_reparent_to_root_hook(self
):
6910 for hook
in self
._reparent
_to
_root
_hook
:
6912 self
._reparent
_to
_root
_hook
= []
6913 l3Base
._run
_reparent
_to
_root
_hook
= _run_reparent_to_root_hook
6914 l3aList
._run
_reparent
_to
_root
_hook
= _run_reparent_to_root_hook
6915 Label
._run
_reparent
_to
_root
_hook
= _run_reparent_to_root_hook
6916 Widget
._run
_reparent
_to
_root
_hook
= _run_reparent_to_root_hook
6917 Image
._run
_reparent
_to
_root
_hook
= _run_reparent_to_root_hook
6918 uWidget
._run
_reparent
_to
_root
_hook
= _run_reparent_to_root_hook
6921 #** editing and deletion
6923 def detach(self
, child
):
6924 # When drag distance from marker to item exceeds item_detach_distance,
6925 # detach the item. This criterion is implemented in
6926 # l3Rawtext.drag_event.
6928 index
= self
._dlist
.index(child
)
6929 marker
= self
._marker
_lst
[index
]
6931 # Reparent graphical parts.
6932 child
.reparent_to_root()
6934 # Shift following marker over to-be-detached marker. Also shift
6935 # following objects.
6936 sl
, st
, _
, _
= marker_get_bounds(self
.w_
, marker
)
6937 ol
, ot
, _
, _
= marker_get_bounds(self
.w_
, self
._marker
_lst
[index
+ 1])
6938 ## child.get_bounds() is off after the child was dragged.
6939 ## shift_y = (sy2 - st) + (oy2 - ot)
6940 if self
._l3tree
.getthe('layout') == 'horizontal':
6941 shift_x
= - (ol
- sl
)
6942 for itm
in self
._dlist
[index
+ 1 : None]:
6943 itm
.move(shift_x
, 0)
6944 for itm
in self
._marker
_lst
[index
+ 1 : None]:
6945 itm
.move(shift_x
, 0)
6949 shift_y
= - (ot
- st
)
6950 for itm
in self
._dlist
[index
+ 1 : None]:
6951 itm
.move(0, shift_y
)
6952 for itm
in self
._marker
_lst
[index
+ 1 : None]:
6953 itm
.move(0, shift_y
)
6956 # Move following items in parent.
6958 self
._parent
.new_size_for(self
)
6960 # Update data and marker lists.
6961 if self
.w_
.fluid_ref(detach_l3_tree
= True):
6962 self
._l3tree
[index
].detach_from_parent(self
.w_
.state_
.storage
)
6963 del self
._dlist
[index
]
6964 del self
._marker
_lst
[index
]
6966 # Delete detached marker.
6967 destroy_if_last(marker
)
6969 l3aList
.detach
= detach
6973 #*** l3Set / l3If / l3Call
6974 def detach(self
, child
):
6975 assert(child
is self
._d
_body
)
6977 # Reparent graphical parts.
6978 child
.reparent_to_root()
6985 # Refresh decoration.
6988 # Move following items in parent.
6990 self
._parent
.new_size_for(self
)
6993 if self
.w_
.fluid_ref(detach_l3_tree
= True):
6995 # _matcher['LBODY'] is fixed at match time -- manual editing
6997 self
._matcher
['LBODY'].detach_from_parent(self
.w_
.state_
.storage
)
7000 l3IfLoop
.detach
= detach
7002 def detach(self
, child
):
7003 # When drag distance from marker to item exceeds item_detach_distance,
7004 # detach the item. This criterion is implemented in
7005 # l3Rawtext.drag_event.
7007 if child
!= self
._d
_cond
:
7008 self
.detach_only(child
)
7011 # Reparent graphical parts.
7012 child
.reparent_to_root()
7020 # Refresh decoration.
7023 # Move following items in parent.
7025 self
._parent
.new_size_for(self
)
7028 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7029 self
._l3tree
[0].detach_from_parent(self
.w_
.state_
.storage
)
7032 l3If
.detach
= detach
7035 def detach(self
, child
):
7037 Detach the condition.
7039 # When drag distance from marker to item exceeds item_detach_distance,
7040 # detach the item. This criterion is implemented in
7041 # l3Rawtext.drag_event.
7043 if child
!= self
._d
_cond
:
7044 self
.detach_only(child
)
7047 # Reparent graphical parts.
7048 child
.reparent_to_root()
7056 # Refresh decoration.
7059 # Move following items in parent.
7061 self
._parent
.new_size_for(self
)
7064 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7065 self
._matcher
.get_cond().detach_from_parent(self
.w_
.state_
.storage
)
7067 l3IfWhile
.detach
= detach
7070 def detach(self
, child
):
7071 assert(child
== self
._pystr
)
7073 # Reparent graphical parts.
7074 child
.reparent_to_root()
7081 # Refresh decoration.
7084 # Move following items in parent.
7086 self
._parent
.new_size_for(self
)
7089 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7090 self
._l3tree
[0].detach_from_parent(self
.w_
.state_
.storage
)
7093 l3Inline
.detach
= detach
7095 def detach(self
, child
):
7096 if child
== self
._d
_func
:
7097 ### print "detach: ", self
7099 # Reparent graphical parts.
7100 child
.reparent_to_root()
7108 # Refresh decoration.
7111 # Move following items in parent.
7113 self
._parent
.new_size_for(self
)
7116 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7117 self
._l3tree
[0].detach_from_parent(self
.w_
.state_
.storage
)
7119 elif child
== self
._d
_args
:
7120 # aList children are only detached on deletion -- no shifting
7123 # Reparent graphical parts.
7124 child
.reparent_to_root()
7133 # Refresh decoration.
7136 # Move following items in parent.
7139 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7140 self
._l3tree
[1].detach_from_parent(self
.w_
.state_
.storage
)
7143 l3Call
.detach
= detach
7145 def detach(self
, child
):
7146 if child
== self
._d
_lhs
:
7147 # Reparent graphical parts.
7148 child
.reparent_to_root()
7156 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7157 self
._l3tree
[0].detach_from_parent(self
.w_
.state_
.storage
)
7160 self
._d
_lhs
_marker
.show()
7162 elif child
== self
._d
_rhs
:
7163 # Reparent graphical parts.
7164 child
.reparent_to_root()
7172 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7173 self
._l3tree
[1].detach_from_parent(self
.w_
.state_
.storage
)
7176 self
._d
_rhs
_marker
.show()
7179 raise DisplayError("Detaching invalid child.")
7181 ### print "detach: ", self
7183 # Refresh decoration.
7186 # Move following items in parent.
7188 self
._parent
.new_size_for(self
)
7190 l3Set
.detach
= detach
7192 #** internal use only
7194 # These types' children are never detached in editing; currently,
7195 # these functions are only called for object destruction.
7198 def detach(self
, child
):
7199 # This function is for internal use, not editing -- yet.
7201 if child
!= self
._alist
:
7202 raise DisplayError("Detaching invalid child.")
7204 ### print "detach: ", self
7206 # Reparent graphical parts.
7207 child
.reparent_to_root()
7214 # Refresh decoration.
7217 # Move following items in parent.
7219 self
._parent
.new_size_for(self
)
7222 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7223 self
._l3tree
[0].detach_from_parent(self
.w_
.state_
.storage
)
7226 l3List
.detach
= detach
7227 l3Map
.detach
= detach
7228 l3Program
.detach
= detach
7230 def detach(self
, child
):
7231 raise Exception("Native types cannot be detached. Internal error.")
7232 l3Native
.detach
= detach
7237 def detach_only(self
, child
):
7238 # Detach any child from self, without shifting, resizing, or
7239 # updating insertion markers.
7241 idx
= self
._d
_elements
.index(child
)
7243 raise DisplayError("Detaching invalid child.")
7245 ### print "detach: ", self
7247 # Reparent graphical parts.
7248 child
.reparent_to_root()
7251 self
._d
_elements
[idx
] = None
7256 # Refresh decoration.
7259 # Move following items in parent.
7262 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7263 self
._l3tree
[idx
].detach_from_parent(self
.w_
.state_
.storage
)
7264 l3If
.detach_only
= detach_only
7265 l3IfWhile
.detach_only
= detach_only
7270 def detach(self
, child
):
7271 if child
== self
._d
_args
:
7272 # Reparent graphical parts.
7273 child
.reparent_to_root()
7281 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7282 self
._l3tree
[0].detach_from_parent(self
.w_
.state_
.storage
)
7284 elif child
== self
._d
_body
:
7285 # Reparent graphical parts.
7286 child
.reparent_to_root()
7294 if self
.w_
.fluid_ref(detach_l3_tree
= True):
7295 self
._l3tree
[1].detach_from_parent(self
.w_
.state_
.storage
)
7298 raise DisplayError("Detaching invalid child.")
7300 ### print "detach: ", self
7302 # Refresh decoration.
7305 # Move following items in parent.
7307 self
._parent
.new_size_for(self
)
7309 l3Function
.detach
= detach
7313 def detach(self
, child
):
7314 # Skeleton detach method, for compatibility only.
7315 # Because Loop is a macro, none of the toplevel children can be
7316 # edited; but detach is also needed for destruction.
7318 # If detach is called for any child, it should be called for
7321 # Reparent graphical parts.
7322 child
.reparent_to_root()
7328 # Refresh decoration.
7330 # Move following items in parent.
7334 l3Loop
.detach
= detach
7338 #* destroy etc: l3 "widget" destruction functions.
7339 from copy
import deepcopy
, copy
7340 from l3gui
.misc
import _safed
7342 #** destroy subtree and display
7343 # .destroy() is recursive
7345 def add_destroy_hook(self
, func
):
7346 self
._destroy
_hook
.append(func
)
7347 l3Base
.add_destroy_hook
= add_destroy_hook
7348 l3aList
.add_destroy_hook
= add_destroy_hook
7349 Label
.add_destroy_hook
= add_destroy_hook
7350 Widget
.add_destroy_hook
= add_destroy_hook
7351 Image
.add_destroy_hook
= add_destroy_hook
7352 uWidget
.add_destroy_hook
= add_destroy_hook
7354 def _run_destroy_hook(self
):
7355 for hook
in self
._destroy
_hook
:
7357 del self
._destroy
_hook
7358 l3Base
._run
_destroy
_hook
= _run_destroy_hook
7359 l3aList
._run
_destroy
_hook
= _run_destroy_hook
7360 Label
._run
_destroy
_hook
= _run_destroy_hook
7361 Widget
._run
_destroy
_hook
= _run_destroy_hook
7362 Image
._run
_destroy
_hook
= _run_destroy_hook
7363 uWidget
._run
_destroy
_hook
= _run_destroy_hook
7368 self
._root
_group
.hide() # Much faster w/o display update.
7370 self
._vis
_indic
.destroy()
7371 self
._vis
_indic
= None
7373 self
._run
_destroy
_hook
()
7374 l3Base
.destroy
= destroy
7379 l3Base
.destroy(self
)
7381 if self
._container
!= self
._parent
:
7382 raise DisplayError("internal _container / _parent inconsistency.")
7385 self
._parent
.detach(self
)
7390 _safed(self
._header
)
7393 if self
.w_
.selector
.get_selection() == self
:
7394 self
.w_
.selector
.unselect()
7397 self
._container
= None
7400 l3Nested
.destroy
= destroy
7406 l3Nested
.destroy(self
)
7407 _safed(self
._d
_loop
)
7408 _safed(self
._d
_body
)
7409 l3Nested
.destroy_deco(self
)
7410 l3IfLoop
.destroy
= destroy
7413 l3Nested
.destroy(self
)
7414 _safed(self
._d
_label
)
7415 l3Nested
.destroy_deco(self
)
7416 l3IfLoopBreak
.destroy
= destroy
7417 l3IfLoopContinue
.destroy
= destroy
7420 l3Nested
.destroy(self
)
7423 _safed(self
._d
_cond
)
7425 _safed(self
._d
_else
)
7427 ### self._l3tree.delete(self.w_.state_.storage)
7428 l3Nested
.destroy_deco(self
)
7429 l3If
.destroy
= destroy
7432 l3Nested
.destroy(self
)
7433 _safed(self
._d
_loop
)
7434 _safed(self
._d
_cond
)
7435 _safed(self
._d
_body
)
7436 l3Nested
.destroy_deco(self
)
7437 l3IfWhile
.destroy
= destroy
7440 l3Nested
.destroy(self
)
7443 l3Nested
.destroy_deco(self
)
7444 Placeholder
.destroy
= destroy
7447 l3Nested
.destroy(self
)
7450 _safed(self
._d
_equal
)
7452 ### self._l3tree.delete(self.w_.state_.storage)
7453 l3Nested
.destroy_deco(self
)
7454 l3Set
.destroy
= destroy
7457 l3Nested
.destroy(self
)
7459 _safed(self
._d
_func
)
7460 _safed(self
._d
_args
)
7461 ### self._l3tree.delete(self.w_.state_.storage)
7462 l3Nested
.destroy_deco(self
)
7463 l3Call
.destroy
= destroy
7466 l3Nested
.destroy(self
)
7468 _safed(self
._d
_function
)
7469 _safed(self
._d
_args
)
7470 _safed(self
._d
_body
)
7472 ### self._l3tree.delete(self.w_.state_.storage)
7474 l3Nested
.destroy_deco(self
)
7475 l3Function
.destroy
= destroy
7478 l3Nested
.destroy(self
)
7481 ### self._l3tree.delete(self.w_.state_.storage)
7482 l3Nested
.destroy_deco(self
)
7483 l3List
.destroy
= destroy
7484 l3Map
.destroy
= destroy
7485 l3Program
.destroy
= destroy
7488 l3Nested
.destroy(self
)
7491 l3Nested
.destroy_deco(self
)
7492 l3Inline
.destroy
= destroy
7493 l3Native
.destroy
= destroy
7498 self
._root
_group
.hide() # Much faster w/o display update.
7500 self
._parent
.detach(self
)
7503 self
._container
= None
7505 if self
.w_
.selector
.get_selection() == self
:
7506 self
.w_
.selector
.unselect()
7508 # Remove other's _marker references first.
7509 for entry
in copy(self
._dlist
): # _dlist changes during deletion
7512 for mark
in copy(self
._marker
_lst
):
7515 ### self._l3tree.delete(self.w_.state_.storage)
7517 _safed(self
._root
_group
)
7518 del self
._root
_group
7520 self
._run
_destroy
_hook
()
7522 l3aList
.destroy
= destroy
7526 # .destroy order checks.
7527 self
._under
_destruction
= True
7529 self
._canvas
.remove_zoom_text(self
)
7531 l3Base
.destroy(self
)
7533 # For structures, _marker and _container are set.
7534 # For nested text fragments (only editable via text editing),
7535 # _container and _marker are not set.
7536 inside_text
= isinstance(self
._parent
, l3Rawtext
)
7538 if self
._container
!= self
._parent
:
7539 raise DisplayError("internal _parent / _marker inconsistency.")
7543 self
._parent
.detach(self
)
7546 self
._container
= None
7550 _safed(self
._header
)
7554 # self._container.detach(self)
7555 # self._marker = None
7556 # self._container = None
7558 if self
.w_
.selector
.get_selection() == self
:
7559 self
.w_
.selector
.unselect()
7561 # Destroy children first.
7562 for ch
in copy(self
._subtrees
):
7565 ### self._l3tree.delete(self.w_.state_.storage)
7567 # Destroy the display elements.
7569 _safed(self
._loutline
)
7570 _safed(self
._root
_group
)
7571 del self
._root
_group
7574 l3Rawtext
.destroy
= destroy
7577 # .destroy order checks.
7578 self
._under
_destruction
= True
7580 self
._canvas
.remove_zoom_text(self
)
7582 l3Base
.destroy(self
)
7585 if self
._container
!= None:
7586 raise DisplayError("internal marker inconsistency.")
7590 self
._parent
.detach_header(self
)
7593 self
._container
= None
7595 if self
.w_
.selector
.get_selection() == self
:
7596 self
.w_
.selector
.unselect()
7599 _safed(self
._loutline
)
7600 _safed(self
._root
_group
)
7601 del self
._root
_group
7604 l3Comment
.destroy
= destroy
7607 self
._canvas
.remove_zoom_text(self
)
7608 _safed(self
._loutline
)
7610 _safed(self
._root
_group
)
7612 self
._run
_destroy
_hook
()
7613 Label
.destroy
= destroy
7617 _safed(self
._root
_group
)
7618 self
._run
_destroy
_hook
()
7619 Widget
.destroy
= destroy
7620 Image
.destroy
= destroy
7621 uWidget
.destroy
= destroy
7624 #* Saving and loading of state.
7625 # The main entry points are `save_state` and `load_state`.
7626 from types
import IntType
, LongType
7628 from l3gui
.misc
import _get_props
, _set_props
7632 # The Canvas* instances are not extensible; either subclass them here for
7633 # smooth persistence -- or use a dispatch table.
7635 # Some of the more useful properties (width-units, char* version of
7636 # fill-color) are write-only. Subclasses could intercept and store
7638 # Generally, mirroring properties in a derived class (or elsewhere)
7639 # is not practical; many properties are changed via commands other
7640 # than .set() and .set_property(), and those changes need to be
7643 # So, rather than mirroring much of the gtk object tree, use only
7644 # attributes that are Read/Write, AND can be pickled if possible.
7646 # When absolutely necessary, provide special access functions for
7647 # specific properties.
7651 def st_TextBuffer(item
, prop_list
):
7652 ## item.get_text(*item.get_bounds())
7655 ## "tag-table", # GtkTextTagTable : Read / Write / Construct Only
7657 ## "text", # gchararray : Read / Write
7660 def st_TextTag(item
, prop_list
):
7663 ## "background", # gchararray : Write
7664 "background-full-height-set", # gboolean : Read / Write
7665 "background-full-height", # gboolean : Read / Write
7666 ## "background-gdk", # GdkColor : Read / Write
7667 ## "background-set", # gboolean : Read / Write
7668 ## "background-stipple", # GdkPixmap : Read / Write
7669 ## "background-stipple-set", # gboolean : Read / Write
7670 ## "direction", # GtkTextDirection : Read / Write
7671 "editable-set", # gboolean : Read / Write
7672 "editable", # gboolean : Read / Write
7673 "family-set", # gboolean : Read / Write
7674 "family", # gchararray : Read / Write
7675 "font", # gchararray : Read / Write
7676 ## "font-desc", # PangoFontDescription : Read / Write
7677 ## "foreground", # gchararray : Write
7678 ## "foreground-gdk", # GdkColor : Read / Write
7679 ## "foreground-set", # gboolean : Read / Write
7680 ## "foreground-stipple", # GdkPixmap : Read / Write
7681 ## "foreground-stipple-set", # gboolean : Read / Write
7682 ## "indent", # gint : Read / Write
7683 ## "indent-set", # gboolean : Read / Write
7684 ## "invisible", # gboolean : Read / Write
7685 ## "invisible-set", # gboolean : Read / Write
7686 ## "justification", # GtkJustification : Read / Write
7687 ## "justification-set", # gboolean : Read / Write
7688 ## "language", # gchararray : Read / Write
7689 ## "language-set", # gboolean : Read / Write
7690 ## "left-margin", # gint : Read / Write
7691 ## "left-margin-set", # gboolean : Read / Write
7692 ## "name", # gchararray : Read / Write / Construct Only
7693 ## "paragraph-background", # gchararray : Write
7694 ## "paragraph-background-gdk", # GdkColor : Read / Write
7695 ## "paragraph-background-set", # gboolean : Read / Write
7696 ## "pixels-above-lines", # gint : Read / Write
7697 ## "pixels-above-lines-set", # gboolean : Read / Write
7698 ## "pixels-below-lines", # gint : Read / Write
7699 ## "pixels-below-lines-set", # gboolean : Read / Write
7700 ## "pixels-inside-wrap", # gint : Read / Write
7701 ## "pixels-inside-wrap-set", # gboolean : Read / Write
7702 ## "right-margin", # gint : Read / Write
7703 ## "right-margin-set", # gboolean : Read / Write
7704 ## "rise", # gint : Read / Write
7705 ## "rise-set", # gboolean : Read / Write
7706 ## "scale", # gdouble : Read / Write
7707 ## "scale-set", # gboolean : Read / Write
7708 ## "size", # gint : Read / Write
7709 "size-set", # gboolean : Read / Write
7710 "size-points", # gdouble : Read / Write
7711 ## "stretch", # PangoStretch : Read / Write
7712 ## "stretch-set", # gboolean : Read / Write
7713 ## "strikethrough", # gboolean : Read / Write
7714 ## "strikethrough-set", # gboolean : Read / Write
7715 ## "style", # PangoStyle : Read / Write
7716 ## "style-set", # gboolean : Read / Write
7717 ## "tabs", # PangoTabArray : Read / Write
7718 ## "tabs-set", # gboolean : Read / Write
7719 ## "underline", # PangoUnderline : Read / Write
7720 ## "underline-set", # gboolean : Read / Write
7721 ## "variant", # PangoVariant : Read / Write
7722 ## "variant-set", # gboolean : Read / Write
7723 ## "weight", # gint : Read / Write
7724 ## "weight-set", # gboolean : Read / Write
7725 ## "wrap-mode", # GtkWrapMode : Read / Write
7726 ## "wrap-mode-set", # gboolean : Read / Write
7729 def st_TextView(item
, prop_list
):
7732 "accepts-tab", # gboolean : Read / Write
7733 ## "buffer", # GtkTextBuffer : Read / Write
7734 "cursor-visible", # gboolean : Read / Write
7735 "editable", # gboolean : Read / Write
7736 "indent", # gint : Read / Write
7737 ## "justification", # GtkJustification : Read / Write
7738 "left-margin", # gint : Read / Write
7739 "overwrite", # gboolean : Read / Write
7740 "pixels-above-lines", # gint : Read / Write
7741 "pixels-below-lines", # gint : Read / Write
7742 "pixels-inside-wrap", # gint : Read / Write
7743 "right-margin", # gint : Read / Write
7744 ## "tabs", # PangoTabArray : Read / Write
7745 ## "wrap-mode", # GtkWrapMode : Read / Write
7750 # List of readable & writeable display properties taken from the
7756 def st_CanvasShape(item
, prop_list
):
7757 # The fill-color-gdk is a C struct;
7758 # fill-color-rgba is a (platform-dependent?) value
7759 # The width-units property is needed for scaling.
7762 "cap-style", # GdkCapStyle : Read / Write
7763 "dash", # gpointer : Read / Write
7765 ## "fill-color", # gchararray : Write
7766 ## "fill-color-gdk", # GdkColor : Read / Write
7767 "fill-color-rgba", # guint : Read / Write
7769 "fill-stipple", # GdkDrawable : Read / Write
7770 "join-style", # GdkJoinStyle : Read / Write
7771 "miterlimit", # gdouble : Read / Write
7773 ## "outline-color", # gchararray : Write
7774 ## "outline-color-gdk", # GdkColor : Read / Write
7775 "outline-color-rgba", # guint : Read / Write
7777 "outline-stipple", # GdkDrawable : Read / Write
7778 "width-pixels", # guint : Read / Write
7779 # Do not use scaled units.
7780 ## "width-units", # gdouble : Write
7781 "wind", # guint : Read / Write
7786 def st_CanvasRE(item
, prop_list
):
7787 return _get_props(item
, prop_list
,
7788 "x1", # gdouble : Read / Write
7789 "x2", # gdouble : Read / Write
7790 "y1", # gdouble : Read / Write
7791 "y2", # gdouble : Read / Write
7793 # # Ignore these renderer-specific properties.
7794 # # return st_CanvasShape(item, prop_list)
7798 def st_CanvasPolygon(w_
, item
, prop_list
, creator
= None):
7800 prop_list
.append( ("points", creator
._marker
_points
[item
]) )
7802 ### This fails because of a bug in
7803 ### gnome_canvas_polygon_get_property().
7804 raise DisplayError("st_CanvasPolygon(internal): "
7805 "Missing creator arg.")
7806 _get_props(item
, prop_list
,
7807 "points", # GnomeCanvasPoints : Read / Write
7810 if w_
.fluid_ref(dump_ps
= False):
7811 pts
= creator
._marker
_points
[item
]
7814 print "% st_CanvasPolygon"
7816 print " %s %s gcmoveto" % i2w(pts
[0], pts
[1])
7817 for pt1
, pt2
in zip(pts
[2::2], pts
[3::2]):
7818 print " %s %s gclineto" % i2w(pt1
, pt2
)
7821 return st_CanvasShape(item
, prop_list
)
7825 def st_CanvasRect(w_
, item
, prop_list
):
7826 return st_CanvasRE(item
, prop_list
)
7830 def st_CanvasGroup(item
, prop_list
):
7831 return _get_props(item
, prop_list
,
7832 "x", # gdouble : Read / Write
7833 "y", # gdouble : Read / Write
7837 def st_CanvasText(w_
, item
, prop_list
):
7838 if w_
.fluid_ref(dump_ps
= False):
7839 get
= item
.get_property
7841 print "% st_CanvasText"
7842 x1
, y1
, _
, _
= item
.get_bounds()
7843 print " %s %s gcmoveto" % i2w(x1
, y1
)
7844 print ' (%s) gcshow' % (get("text"))
7848 "anchor", # GtkAnchorType : Read / Write
7849 ## None fails to restore.
7850 ## "attributes", # PangoAttrList : Read / Write
7851 "clip", # gboolean : Read / Write
7852 "clip-height", # gdouble : Read / Write
7853 "clip-width", # gdouble : Read / Write
7854 "family-set", # gboolean : Read / Write
7855 "family", # gchararray : Read / Write
7856 "fill-color", # gchararray : Read / Write
7857 ## "fill-color-gdk", # GdkColor : Read / Write
7858 "fill-color-rgba", # guint : Read / Write
7859 "fill-stipple", # GdkDrawable : Read / Write
7860 "font", # gchararray : Read / Write
7861 ## "font-desc", # PangoFontDescription : Read / Write
7862 "justification", # GtkJustification : Read / Write
7863 ## "markup", # gchararray : Write
7864 "rise-set", # gboolean : Read / Write
7865 "rise", # gint : Read / Write
7866 "scale-set", # gboolean : Read / Write
7867 "scale", # gdouble : Read / Write
7868 "size", # gint : Read / Write
7869 "size-set", # gboolean : Read / Write
7870 "size-points", # gdouble : Read / Write
7871 "stretch-set", # gboolean : Read / Write
7872 "stretch", # PangoStretch : Read / Write
7873 "strikethrough-set", # gboolean : Read / Write
7874 "strikethrough", # gboolean : Read / Write
7875 "style-set", # gboolean : Read / Write
7876 "style", # PangoStyle : Read / Write
7877 "text", # gchararray : Read / Write
7879 # property text-height is not writable text-height 2.28
7880 # property text-width is not writable text-width 1.68
7881 ## "text-height", # gdouble : Read / Write
7882 ## "text-width", # gdouble : Read / Write
7883 "underline-set", # gboolean : Read / Write
7884 "underline", # PangoUnderline : Read / Write
7885 "variant-set", # gboolean : Read / Write
7886 "variant", # PangoVariant : Read / Write
7887 "weight-set", # gboolean : Read / Write
7888 "weight", # gint : Read / Write
7889 "x", # gdouble : Read / Write
7890 "x-offset", # gdouble : Read / Write
7891 "y", # gdouble : Read / Write
7892 "y-offset", # gdouble : Read / Write
7897 def st_CanvasLine(w_
, item
, prop_list
):
7898 if w_
.fluid_ref(dump_ps
= False):
7899 pts
= item
.get_property("points")
7902 print "% st_CanvasLine"
7904 print " %s %s gcmoveto" % i2w(pts
[0], pts
[1])
7905 for pt1
, pt2
in zip(pts
[2::2], pts
[3::2]):
7906 print " %s %s gclineto" % i2w(pt1
, pt2
)
7911 "arrow-shape-a", # gdouble : Read / Write
7912 "arrow-shape-b", # gdouble : Read / Write
7913 "arrow-shape-c", # gdouble : Read / Write
7914 "cap-style", # GdkCapStyle : Read / Write
7915 "fill-color", # gchararray : Read / Write
7916 ## "fill-color-gdk", # GdkColor : Read / Write
7917 "fill-color-rgba", # guint : Read / Write
7918 "fill-stipple", # GdkDrawable : Read / Write
7919 "first-arrowhead", # gboolean : Read / Write
7920 "join-style", # GdkJoinStyle : Read / Write
7921 "last-arrowhead", # gboolean : Read / Write
7922 "line-style", # GdkLineStyle : Read / Write
7923 "points", # GnomeCanvasPoints : Read / Write
7924 "smooth", # gboolean : Read / Write
7925 "spline-steps", # guint : Read / Write
7926 ## "width-pixels", # guint : Read / Write
7927 "width-units", # gdouble : Read / Write
7932 def st_CanvasWidget(item
, prop_list
):
7935 ## "anchor", # GtkAnchorType : Read / Write
7936 "height", # gdouble : Read / Write
7937 "size-pixels", # gboolean : Read / Write
7938 ## "widget", # GtkWidget : Read / Write
7939 "width", # gdouble : Read / Write
7940 "x", # gdouble : Read / Write
7941 "y", # gdouble : Read / Write
7947 # Originally, the full display state was saved via recursion of the
7948 # display tree. This turned out to be a bad idea for file size,
7949 # reliabilty, and made using old state files impossible (just like a
7950 # well-known word processor).
7952 # Now, only the position information of the topmost object is
7955 # The traversal used and the data structuring may be
7956 # useful in other contexts (e.g., export to PDF), so the code is
7957 # retained here. Some original notes:
7959 # Pickling highly intertwined (graph-structured) state is tricky. The
7960 # get_state() members are arranged to produce a spanning tree traversal of
7961 # all data and avoid circularities.
7963 # For trees, starting pickling in a subtree and (randomly) getting the
7964 # parents is bad for pickling and reconstruction.
7966 # Also, there is some special state, the global
7968 # and multiple upward references like
7969 # self._canvas (circular -- parent)
7971 # This special state is saved only once, and the links restored in a
7974 def get_state(self
):
7977 _root_group
= st_CanvasGroup(self
._root
_group
, []),
7980 l3aList
.get_state
= get_state
7981 Label
.get_state
= get_state
7982 Widget
.get_state
= get_state
7983 Image
.get_state
= get_state
7984 uWidget
.get_state
= get_state
7986 def get_state(self
):
7987 return utils
.Shared(
7988 # # _l3tree = self._l3tree,
7989 _root_group
= st_CanvasGroup(self
._root
_group
, []),
7991 l3Base
.get_state
= get_state
7993 def get_state(self
):
7994 return utils
.Shared(
7995 l3base
= l3Base
.get_state(self
),
7996 # # _root_group = st_CanvasGroup(self._root_group, []),
7998 l3Rawtext
.get_state
= get_state
8000 def get_state(self
):
8001 return utils
.Shared(
8002 l3base
= l3Base
.get_state(self
),
8004 l3Nested
.get_state
= get_state
8007 def get_state(self
):
8009 CommonPopup
.get_state
= get_state
8011 #*** table formation
8013 def start_set_tables(l3tree
):
8015 Fill tables with values stored as attributes of an astType tree
8016 `l3tree`. Return a table of tables.
8018 from l3gui
.l3canvas
import RenderTable
8019 tables
= utils
.Shared(rentab
= RenderTable())
8020 l3tree
.set_tables(tables
)
8023 # These functions are intended to fully traverse the (display) widget
8024 # tree, and may be split into traversal iterators / main functions
8027 def set_tables(self
, tables
):
8028 l3Base
.set_tables(self
, tables
)
8029 tables
.rentab
.set_state(self
._l3tree
, self
._render
_mode
)
8030 l3Nested
.set_tables
= set_tables
8033 def set_tables(self
, tables
):
8034 l3Base
.set_tables(self
, tables
)
8035 tables
.rentab
.set_state(self
._l3tree
, self
._render
_mode
)
8036 for st
in self
._subtrees
:
8037 st
.set_tables(tables
)
8038 l3Rawtext
.set_tables
= set_tables
8040 def set_tables(self
, tables
):
8041 l3Rawtext
.set_tables(self
, tables
)
8042 l3Comment
.set_tables
= set_tables
8044 def set_tables(self
, tables
):
8045 l3List
.set_tables(self
, tables
)
8046 self
._alist
.set_tables(tables
)
8047 l3ViewList
.set_tables
= set_tables
8050 def set_tables(self
, tables
):
8051 l3Nested
.set_tables(self
, tables
)
8052 self
._alist
.set_tables(tables
)
8053 l3List
.set_tables
= set_tables
8054 l3Map
.set_tables
= set_tables
8057 def set_tables(self
, tables
):
8058 l3Nested
.set_tables(self
, tables
)
8065 ) = self
._d
_elements
8066 _d_cond
.set_tables(tables
)
8067 _d_yes
.set_tables(tables
)
8068 _d_no
.set_tables(tables
)
8069 l3If
.set_tables
= set_tables
8072 def set_tables(self
, tables
):
8073 l3Nested
.set_tables(self
, tables
)
8075 d_body
, ) = self
._d
_elements
8076 d_loop
.set_tables(tables
)
8077 d_body
.set_tables(tables
)
8078 l3IfOutline
.set_tables
= set_tables
8079 l3IfLoop
.set_tables
= set_tables
8082 def set_tables(self
, tables
):
8083 l3Nested
.set_tables(self
, tables
)
8088 ) = self
._d
_elements
8089 d_cond
.set_tables(tables
)
8090 d_body
.set_tables(tables
)
8091 l3IfWhile
.set_tables
= set_tables
8094 def set_tables(self
, tables
):
8095 l3Nested
.set_tables(self
, tables
)
8100 ) = self
._d
_elements
8101 _d_func
.set_tables(tables
)
8102 _d_args
.set_tables(tables
)
8103 l3Call
.set_tables
= set_tables
8106 def set_tables(self
, tables
):
8107 l3Nested
.set_tables(self
, tables
)
8108 self
._alist
.set_tables(tables
)
8109 l3Program
.set_tables
= set_tables
8112 def set_tables(self
, tables
):
8113 l3Nested
.set_tables(self
, tables
)
8114 self
._pystr
.set_tables(tables
)
8115 l3Inline
.set_tables
= set_tables
8118 def set_tables(self
, tables
):
8119 l3Nested
.set_tables(self
, tables
)
8120 self
._d
_function
.set_tables(tables
)
8121 self
._d
_args
.set_tables(tables
)
8122 self
._d
_body
.set_tables(tables
)
8123 l3Function
.set_tables
= set_tables
8126 def set_tables(self
, tables
):
8127 l3Nested
.set_tables(self
, tables
)
8128 self
._d
_lhs
.set_tables(tables
)
8129 self
._d
_rhs
.set_tables(tables
)
8130 l3Set
.set_tables
= set_tables
8133 def set_tables(self
, tables
):
8134 l3Nested
.set_tables(self
, tables
)
8135 Placeholder
.set_tables
= set_tables
8136 l3IfLoopBreak
.set_tables
= set_tables
8137 l3IfLoopContinue
.set_tables
= set_tables
8138 l3Native
.set_tables
= set_tables
8141 def set_tables(self
, tables
):
8143 Label
.set_tables
= set_tables
8144 Widget
.set_tables
= set_tables
8145 Image
.set_tables
= set_tables
8146 uWidget
.set_tables
= set_tables
8147 l3Base
.set_tables
= set_tables
8148 l3Deco
.set_tables
= set_tables
8151 def set_tables(self
, tables
):
8152 for itm
in self
._dlist
:
8153 itm
.set_tables(tables
)
8154 l3aList
.set_tables
= set_tables
8159 def find_root(self
):
8160 if self
._parent
!= None:
8161 return self
._parent
.find_root()
8163 return self
, self
._l3tree
._id
8164 l3Base
.find_root
= find_root
8165 l3aList
.find_root
= find_root
8168 # The reconstruction of the data structures is done in passes:
8169 # - form the spanning tree using loaded data
8170 # - reconnect graph edges.
8174 def set_state(self
, state
):
8175 _set_props(self
._root
_group
, state
._root
_group
)
8176 l3Base
.set_state
= set_state
8177 l3aList
.set_state
= set_state
8178 Label
.set_state
= set_state
8179 Widget
.set_state
= set_state
8180 Image
.set_state
= set_state
8181 uWidget
.set_state
= set_state
8183 def set_state(self
, state
):
8184 l3Base
.set_state(self
, state
.l3base
)
8185 # # _set_props(self._root_group, state._root_group)
8186 l3Rawtext
.set_state
= set_state
8188 def set_state(self
, state
):
8189 l3Base
.set_state(self
, state
.l3base
)
8190 l3Nested
.set_state
= set_state
8194 def set_state(self
, state
):
8196 CommonPopup
.set_state
= set_state
8200 # An experiment of grouping the members with the class definition,
8201 # instead of functional grouping.
8202 # As expected, this class grouping makes function-based additions much
8205 def continue_stop_pt(self
):
8207 lc
, tc
, rc
, bc
= self
._d
_loop
.get_bounds_world()
8208 return lc
+ (rc
- lc
)/10, bc
## parameters
8209 l3IfFor
.continue_stop_pt
= continue_stop_pt
8211 def break_stop_pt(self
):
8213 lc
, tc
, rc
, bc
= self
.get_bounds_world()
8214 return rc
+ 4, bc
## parameters
8215 l3IfFor
.break_stop_pt
= break_stop_pt
8218 def __init__(self
, w_
, cnvs
, tree_id
, rentab
, matcher
):
8220 l3tree
= w_
.state_
.storage
.load(tree_id
)
8221 assert isinstance(l3tree
, ast
.If
)
8222 l3Nested
.__init
__(self
, w_
, cnvs
, l3tree
, rentab
)
8227 self
._marker
_points
= {} # marker -> point list
8228 self
._matcher
= ma
= matcher
8229 self
._l3tree
= l3tree
8230 self
._deco
_cb
_buffer
= [] # callback list for add_item()
8235 d_loop_for
= Label(w_
, cnvs
, self
._root
_group
, "for")
8238 d_cond_V
= cnvs
.add_l3tree(ma
.get_current_V(), rentab
)
8239 d_cond_V
.reparent(self
)
8242 d_loop_in
= Label(w_
, cnvs
, self
._root
_group
, "in")
8245 d_cond_SEQ
= cnvs
.add_l3tree(ma
.get_current_SEQ(), rentab
)
8246 d_cond_SEQ
.reparent(self
)
8249 d_body
= l3aList(w_
, cnvs
,
8252 root_group
= self
._root
_group
,
8258 d_cond_V_marker
= self
.draw_marker()
8259 d_cond_V_marker
.lower_to_bottom()
8261 d_cond_SEQ_marker
= self
.draw_marker()
8262 d_cond_SEQ_marker
.lower_to_bottom()
8264 # Inform obj of marker.
8265 d_cond_V
.setup_marker(d_cond_V_marker
, self
)
8266 d_cond_SEQ
.setup_marker(d_cond_SEQ_marker
, self
)
8269 # Indexed access. Match l3tree indexing where applicable.
8270 self
._d
_elements
= [
8285 # Align display elements, starting from d_loop_for
8287 self
._align
_display
()
8290 self
._outline
= None
8292 # Item cross-referencing.
8294 self
._container
= None
8297 d_cond_V_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
8298 d_cond_SEQ_marker
.connect("event", lambda *a
: self
.insert_event(*a
))
8301 self
.init_header(rentab
)
8302 self
.init_deco(rentab
)
8305 l3IfFor
.__init
__ = __init__
8307 def _update_refs(self
):
8315 self
._d
_cond
_V
_marker
,
8316 self
._d
_cond
_SEQ
_marker
,
8317 ) = self
._d
_elements
8318 l3IfFor
._update
_refs
= _update_refs
8321 def _align_display(self
):
8324 # Align w.r.t. 'for'
8335 ) = self
._d
_elements
8339 l_for
, t_for
, r_for
, b_for
= d_loop_for
.get_bounds()
8340 l_v
, t_v
, r_v
, b_v
= d_cond_V
.get_bounds()
8341 d_cond_V
.move(r_for
+ w_
.cp_
.loop_cond_sep
- l_v
,
8343 # marker for child replacement.
8344 l_v
, t_v
, r_v
, b_v
= d_cond_V
.get_bounds()
8345 lma
, tma
, _
, _
= d_cond_V_marker
.get_bounds()
8346 d_cond_V_marker
.move(l_v
- lma
+ w_
.cp_
.exp_marker_hoff
,
8347 t_v
- tma
+ w_
.cp_
.exp_marker_voff
)
8350 l_v
, t_v
, r_v
, b_v
= d_cond_V
.get_bounds()
8351 l_in
, t_in
, r_in
, b_in
= d_loop_in
.get_bounds()
8352 d_loop_in
.move(r_v
+ w_
.cp_
.loop_cond_sep
- l_in
,
8356 l_seq
, t_seq
, r_seq
, b_seq
= d_cond_SEQ
.get_bounds()
8357 l_in
, t_in
, r_in
, b_in
= d_loop_in
.get_bounds()
8358 d_cond_SEQ
.move(r_in
+ w_
.cp_
.loop_cond_sep
- l_seq
,
8361 l_seq
, t_seq
, r_seq
, b_seq
= d_cond_SEQ
.get_bounds()
8362 lma
, tma
, _
, _
= d_cond_SEQ_marker
.get_bounds()
8363 d_cond_SEQ_marker
.move(l_seq
- lma
+ w_
.cp_
.exp_marker_hoff
,
8364 t_seq
- tma
+ w_
.cp_
.exp_marker_voff
)
8367 l_v
, t_v
, r_v
, b_v
= d_cond_V
.get_bounds()
8368 l_seq
, t_seq
, r_seq
, b_seq
= d_cond_SEQ
.get_bounds()
8369 l_b
, t_b
, r_b
, b_b
= d_body
.get_bounds()
8370 d_body
.move(l_for
- l_b
,
8371 max(b_v
, b_seq
) - t_b
)
8372 l3IfFor
._align
_display
= _align_display
8376 self
._root
_group
.hide()
8377 self
._d
_loop
_for
.hide()
8378 self
._d
_loop
_in
.hide()
8379 self
._d
_cond
_V
.hide()
8380 self
._d
_cond
_SEQ
.hide()
8385 def insert(self
, marker
, newobj
):
8387 # Insert new value or sequence
8389 assert isinstance(newobj
, l3Base
)
8391 # Avoid special cases:
8392 if newobj
.contains_recursive(self
):
8393 self
.w_
.ten_second_message("Cannot insert if into itself.")
8396 if newobj
._canvas
!= self
._canvas
:
8397 self
.w_
.ten_second_message("Cannot move objects across displays. "
8402 if marker
== self
._d
_cond
_V
_marker
:
8404 if not self
._matcher
.get_current_V().eql(ast
.aNone()):
8405 raise DisplayError("Insertion in occupied slot.")
8408 self
._d
_cond
_V
= d_cond_V
= newobj
8411 newobj
.reparent(self
)
8417 self
._align
_display
()
8419 # Refresh decoration.
8422 # Move following items in parent.
8424 self
._parent
.new_size_for(self
)
8427 if self
.w_
.fluid_ref(insert_l3_tree
= True):
8428 self
._matcher
.set_V(newobj
._l3tree
)
8430 # Inform obj of marker.
8431 newobj
.setup_marker(self
._d
_cond
_V
_marker
, self
)
8433 elif marker
== self
._d
_cond
_SEQ
_marker
:
8435 if not self
._matcher
.get_current_SEQ().eql(ast
.aNone()):
8436 raise DisplayError("Insertion in occupied slot.")
8439 self
._d
_cond
_SEQ
= d_cond_SEQ
= newobj
8442 newobj
.reparent(self
)
8448 self
._align
_display
()
8450 # Refresh decoration.
8453 # Move following items in parent.
8455 self
._parent
.new_size_for(self
)
8458 if self
.w_
.fluid_ref(insert_l3_tree
= True):
8459 self
._matcher
.set_SEQ(newobj
._l3tree
)
8461 # Inform obj of marker.
8462 newobj
.setup_marker(self
._d
_cond
_SEQ
_marker
, self
)
8465 raise DisplayError("Insertion from wrong marker.")
8466 l3IfFor
.insert
= insert
8469 def init_deco(self
, rentab
):
8471 self
._deco
= None ## add_deco_to(self, callbacks = self._deco_cb_buffer)
8472 l3IfFor
.init_deco
= init_deco
8475 def new_size_for(self
, child
):
8477 # Shift contents vertically as needed.
8479 assert isinstance(child
, (l3Base
, l3aList
))
8481 # Find and apply shift.
8482 if child
in [self
._d
_cond
_V
, self
._d
_cond
_SEQ
]:
8483 self
._align
_display
()
8485 # Refresh decoration.
8490 self
._parent
.new_size_for(self
)
8492 l3IfFor
.new_size_for
= new_size_for
8495 def detach(self
, child
):
8496 # When drag distance from marker to item exceeds item_detach_distance,
8497 # detach the item. This criterion is implemented in
8498 # l3Rawtext.drag_event.
8500 if child
== self
._d
_cond
_V
:
8502 self
._d
_cond
_V
= None
8503 the_child
= self
._matcher
.get_current_V()
8505 elif child
== self
._d
_cond
_SEQ
:
8507 self
._d
_cond
_SEQ
= None
8508 the_child
= self
._matcher
.get_current_SEQ()
8511 self
.detach_only(child
)
8514 # Reparent graphical parts.
8515 child
.reparent_to_root()
8518 # self._align_display()
8520 # Refresh decoration.
8523 # Move following items in parent.
8525 self
._parent
.new_size_for(self
)
8528 if self
.w_
.fluid_ref(detach_l3_tree
= True):
8529 the_child
.detach_from_parent(self
.w_
.state_
.storage
)
8531 l3IfFor
.detach
= detach
8535 l3Nested
.destroy(self
)
8536 _safed(self
._d
_loop
_for
)
8537 _safed(self
._d
_loop
_in
)
8538 _safed(self
._d
_cond
_SEQ
)
8539 _safed(self
._d
_cond
_V
)
8540 _safed(self
._d
_body
)
8541 l3Nested
.destroy_deco(self
)
8542 l3IfFor
.destroy
= destroy
8545 def set_tables(self
, tables
):
8546 l3Nested
.set_tables(self
, tables
)
8555 ) = self
._d
_elements
8556 d_cond_V
.set_tables(tables
)
8557 d_cond_SEQ
.set_tables(tables
)
8558 d_body
.set_tables(tables
)
8559 l3IfFor
.set_tables
= set_tables
8562 l3IfFor
.detach_only
= detach_only
8563 l3IfFor
.draw_marker
= draw_marker_shared
8564 l3IfFor
.insert_event
= insert_event_shared
8565 l3IfFor
.detach_only
= detach_only