| Home | Trees | Indices | Help |
|
|---|
|
|
1 # Natural Language Toolkit: graphical representations package
2 #
3 # Copyright (C) 2001-2008 NLTK Project
4 # Author: Edward Loper <[email protected]>
5 # URL: <http://nltk.org>
6 # For license information, see LICENSE.TXT
7 #
8 # $Id: __init__.py 6339 2008-07-30 01:54:47Z stevenbird $
9
10 """
11 Tools for graphically displaying and interacting with the objects and
12 processing classes defined by the Toolkit. These tools are primarily
13 intended to help students visualize the objects that they create.
14
15 The graphical tools are typically built using X{canvas widgets}, each
16 of which encapsulates the graphical elements and bindings used to
17 display a complex object on a Tkinter C{Canvas}. For example, NLTK
18 defines canvas widgets for displaying trees and directed graphs, as
19 well as a number of simpler widgets. These canvas widgets make it
20 easier to build new graphical tools and demos. See the class
21 documentation for L{CanvasWidget} for more information.
22
23 The C{nltk.draw} module defines the abstract C{CanvasWidget} base
24 class, and a number of simple canvas widgets. The remaining canvas
25 widgets are defined by submodules, such as L{nltk.draw.tree}.
26
27 The C{nltk.draw} module also defines L{CanvasFrame}, which
28 encapsulates a C{Canvas} and its scrollbars. It uses a
29 L{ScrollWatcherWidget} to ensure that all canvas widgets contained on
30 its canvas are within the scroll region.
31
32 Acknowledgements: Many of the ideas behind the canvas widget system
33 are derived from C{CLIG}, a Tk-based grapher for linguistic data
34 structures. For more information, see U{the CLIG
35 homepage<http://www.ags.uni-sb.de/~konrad/clig.html>}.
36
37 @group Graphical Demonstrations: rdparser, srparser, chart
38 @group Widgets: tree, cfg, plot
39 @group Abstract Widget Superclasses: CanvasWidget, AbstractContainerWidget
40 @sort: CanvasWidget, AbstractContainerWidget
41 @group Canvas Widgets: BoxWidget, BracketWidget, OvalWidget, ParenWidget,
42 ScrollWatcherWidget, SequenceWidget, SpaceWidget, StackWidget,
43 SymbolWidget, TextWidget
44 @sort: TextWidget, SymbolWidget, BoxWidget, OvalWidget, ParenWidget,
45 BracketWidget, SequenceWidget, StackWidget, SpaceWidget,
46 ScrollWatcherWidget
47 @group Tkinter Widgets: CanvasFrame, EntryDialog, ShowText
48 """
49 from Tkinter import *
50
51 ##//////////////////////////////////////////////////////
52 ## CanvasWidget
53 ##//////////////////////////////////////////////////////
54
56 """
57 A collection of graphical elements and bindings used to display a
58 complex object on a Tkinter C{Canvas}. A canvas widget is
59 responsible for managing the C{Canvas} tags and callback bindings
60 necessary to display and interact with the object. Canvas widgets
61 are often organized into hierarchies, where parent canvas widgets
62 control aspects of their child widgets.
63
64 Each canvas widget is bound to a single C{Canvas}. This C{Canvas}
65 is specified as the first argument to the C{CanvasWidget}'s
66 constructor.
67
68 Attributes
69 ==========
70 Each canvas widget can support a variety of X{attributes}, which
71 control how the canvas widget is displayed. Some typical examples
72 attributes are C{color}, C{font}, and C{radius}. Each attribute
73 has a default value. This default value can be overridden in the
74 constructor, using keyword arguments of the form
75 C{attribute=value}:
76
77 >>> cn = CanvasText(c, 'test', color='red')
78
79 Attribute values can also be changed after a canvas widget has
80 been constructed, using the C{__setitem__} operator:
81
82 >>> cn['font'] = 'times'
83
84 The current value of an attribute value can be queried using the
85 C{__getitem__} operator:
86
87 >>> cn['color']
88 red
89
90 For a list of the attributes supported by a type of canvas widget,
91 see its class documentation.
92
93 Interaction
94 ===========
95 The attribute C{'draggable'} controls whether the user can drag a
96 canvas widget around the canvas. By default, canvas widgets
97 are not draggable.
98
99 C{CanvasWidget} provides callback support for two types of user
100 interaction: clicking and dragging. The method C{bind_click}
101 registers a callback function that is called whenever the canvas
102 widget is clicked. The method C{bind_drag} registers a callback
103 function that is called after the canvas widget is dragged. If
104 the user clicks or drags a canvas widget with no registered
105 callback function, then the interaction event will propagate to
106 its parent. For each canvas widget, only one callback function
107 may be registered for an interaction event. Callback functions
108 can be deregistered with the C{unbind_click} and C{unbind_drag}
109 methods.
110
111 Subclassing
112 ===========
113 C{CanvasWidget} is an abstract class. Subclasses are required to
114 implement the following methods:
115
116 - C{__init__}: Builds a new canvas widget. It must perform the
117 following three tasks (in order):
118 - Create any new graphical elements.
119 - Call C{_add_child_widget} on each child widget.
120 - Call the C{CanvasWidget} constructor.
121 - C{_tags}: Returns a list of the canvas tags for all graphical
122 elements managed by this canvas widget, not including
123 graphical elements managed by its child widgets.
124 - C{_manage}: Arranges the child widgets of this canvas widget.
125 This is typically only called when the canvas widget is
126 created.
127 - C{_update}: Update this canvas widget in response to a
128 change in a single child.
129
130 For C{CanvasWidget}s with no child widgets, the default
131 definitions for C{_manage} and C{_update} may be used.
132
133 If a subclass defines any attributes, then it should implement
134 C{__getitem__} and C{__setitem__}. If either of these methods is
135 called with an unknown attribute, then they should propagate the
136 request to C{CanvasWidget}.
137
138 Most subclasses implement a number of additional methods that
139 modify the C{CanvasWidget} in some way. These methods must call
140 C{parent.update(self)} after making any changes to the canvas
141 widget's graphical elements. The canvas widget must also call
142 C{parent.update(self)} after changing any attribute value that
143 affects the shape or position of the canvas widget's graphical
144 elements.
145
146 @type __canvas: C{Tkinter.Canvas}
147 @ivar __canvas: This C{CanvasWidget}'s canvas.
148
149 @type __parent: C{CanvasWidget} or C{None}
150 @ivar __parent: This C{CanvasWidget}'s hierarchical parent widget.
151 @type __children: C{list} of C{CanvasWidget}
152 @ivar __children: This C{CanvasWidget}'s hierarchical child widgets.
153
154 @type __updating: C{boolean}
155 @ivar __updating: Is this canvas widget currently performing an
156 update? If it is, then it will ignore any new update requests
157 from child widgets.
158
159 @type __draggable: C{boolean}
160 @ivar __draggable: Is this canvas widget draggable?
161 @type __press: C{event}
162 @ivar __press: The ButtonPress event that we're currently handling.
163 @type __drag_x: C{int}
164 @ivar __drag_x: Where it's been moved to (to find dx)
165 @type __drag_y: C{int}
166 @ivar __drag_y: Where it's been moved to (to find dy)
167 @type __callbacks: C{dictionary}
168 @ivar __callbacks: Registered callbacks. Currently, four keys are
169 used: C{1}, C{2}, C{3}, and C{'drag'}. The values are
170 callback functions. Each callback function takes a single
171 argument, which is the C{CanvasWidget} that triggered the
172 callback.
173 """
175 """
176 Create a new canvas widget. This constructor should only be
177 called by subclass constructors; and it should be called only
178 X{after} the subclass has constructed all graphical canvas
179 objects and registered all child widgets.
180
181 @param canvas: This canvas widget's canvas.
182 @type canvas: C{Tkinter.Canvas}
183 @param parent: This canvas widget's hierarchical parent.
184 @type parent: C{CanvasWidget}
185 @param attribs: The new canvas widget's attributes.
186 """
187 if self.__class__ == CanvasWidget:
188 raise TypeError, 'CanvasWidget is an abstract base class'
189
190 if not isinstance(canvas, Canvas):
191 raise TypeError('Expected a canvas!')
192
193 self.__canvas = canvas
194 self.__parent = parent
195
196 # If the subclass constructor called _add_child_widget, then
197 # self.__children will already exist.
198 if not hasattr(self, '_CanvasWidget__children'): self.__children = []
199
200 # Is this widget hidden?
201 self.__hidden = 0
202
203 # Update control (prevents infinite loops)
204 self.__updating = 0
205
206 # Button-press and drag callback handling.
207 self.__press = None
208 self.__drag_x = self.__drag_y = 0
209 self.__callbacks = {}
210 self.__draggable = 0
211
212 # Set up attributes.
213 for (attr, value) in attribs.items(): self[attr] = value
214
215 # Manage this canvas widget
216 self._manage()
217
218 # Register any new bindings
219 for tag in self._tags():
220 self.__canvas.tag_bind(tag, '<ButtonPress-1>',
221 self.__press_cb)
222 self.__canvas.tag_bind(tag, '<ButtonPress-2>',
223 self.__press_cb)
224 self.__canvas.tag_bind(tag, '<ButtonPress-3>',
225 self.__press_cb)
226
227 ##//////////////////////////////////////////////////////
228 ## Inherited methods.
229 ##//////////////////////////////////////////////////////
230
232 """
233 @return: A bounding box for this C{CanvasWidget}. The bounding
234 box is a tuple of four coordinates, M{(xmin, ymin, xmax,
235 ymax)}, for a rectangle which encloses all of the canvas
236 widget's graphical elements. Bounding box coordinates are
237 specified with respect to the C{Canvas}'s coordinate
238 space.
239 @rtype: C{4-tuple} of C{int}s
240 """
241 if self.__hidden: return (0,0,0,0)
242 if len(self.tags()) == 0: raise ValueError('No tags')
243 return self.__canvas.bbox(*self.tags())
244
246 """
247 @return: The width of this canvas widget's bounding box, in
248 its C{Canvas}'s coordinate space.
249 @rtype: C{int}
250 """
251 if len(self.tags()) == 0: raise ValueError('No tags')
252 bbox = self.__canvas.bbox(*self.tags())
253 return bbox[2]-bbox[0]
254
256 """
257 @return: The height of this canvas widget's bounding box, in
258 its C{Canvas}'s coordinate space.
259 @rtype: C{int}
260 """
261 if len(self.tags()) == 0: raise ValueError('No tags')
262 bbox = self.__canvas.bbox(*self.tags())
263 return bbox[3]-bbox[1]
264
266 """
267 @return: The hierarchical parent of this canvas widget.
268 C{self} is considered a subpart of its parent for
269 purposes of user interaction.
270 @rtype: C{CanvasWidget} or C{None}
271 """
272 return self.__parent
273
275 """
276 @return: A list of the hierarchical children of this canvas
277 widget. These children are considered part of C{self}
278 for purposes of user interaction.
279 @rtype: C{list} of C{CanvasWidget}
280 """
281 return self.__children
282
284 """
285 @return: The canvas that this canvas widget is bound to.
286 @rtype: C{Tkinter.Canvas}
287 """
288 return self.__canvas
289
291 """
292 Move this canvas widget by a given distance. In particular,
293 shift the canvas widget right by C{dx} pixels, and down by
294 C{dy} pixels. Both C{dx} and C{dy} may be negative, resulting
295 in leftward or upward movement.
296
297 @type dx: C{int}
298 @param dx: The number of pixels to move this canvas widget
299 rightwards.
300 @type dy: C{int}
301 @param dy: The number of pixels to move this canvas widget
302 downwards.
303 @rtype: C{None}
304 """
305 if dx == dy == 0: return
306 for tag in self.tags():
307 self.__canvas.move(tag, dx, dy)
308 if self.__parent: self.__parent.update(self)
309
311 """
312 Move this canvas widget to the given location. In particular,
313 shift the canvas widget such that the corner or side of the
314 bounding box specified by C{anchor} is at location (C{x},
315 C{y}).
316
317 @param x,y: The location that the canvas widget should be moved
318 to.
319 @param anchor: The corner or side of the canvas widget that
320 should be moved to the specified location. C{'N'}
321 specifies the top center; C{'NE'} specifies the top right
322 corner; etc.
323 """
324 x1,y1,x2,y2 = self.bbox()
325 if anchor == 'NW': self.move(x-x1, y-y1)
326 if anchor == 'N': self.move(x-x1/2-x2/2, y-y1)
327 if anchor == 'NE': self.move(x-x2, y-y1)
328 if anchor == 'E': self.move(x-x2, y-y1/2-y2/2)
329 if anchor == 'SE': self.move(x-x2, y-y2)
330 if anchor == 'S': self.move(x-x1/2-x2/2, y-y2)
331 if anchor == 'SW': self.move(x-x1, y-y2)
332 if anchor == 'W': self.move(x-x1, y-y1/2-y2/2)
333
335 """
336 Remove this C{CanvasWidget} from its C{Canvas}. After a
337 C{CanvasWidget} has been destroyed, it should not be accessed.
338
339 Note that you only need to destroy a top-level
340 C{CanvasWidget}; its child widgets will be destroyed
341 automatically. If you destroy a non-top-level
342 C{CanvasWidget}, then the entire top-level widget will be
343 destroyed.
344
345 @raise ValueError: if this C{CanvasWidget} has a parent.
346 @rtype: C{None}
347 """
348 if self.__parent is not None:
349 self.__parent.destroy()
350 return
351
352 for tag in self.tags():
353 self.__canvas.tag_unbind(tag, '<ButtonPress-1>')
354 self.__canvas.tag_unbind(tag, '<ButtonPress-2>')
355 self.__canvas.tag_unbind(tag, '<ButtonPress-3>')
356 self.__canvas.delete(*self.tags())
357 self.__canvas = None
358
360 """
361 Update the graphical display of this canvas widget, and all of
362 its ancestors, in response to a change in one of this canvas
363 widget's children.
364
365 @param child: The child widget that changed.
366 @type child: C{CanvasWidget}
367 """
368 if self.__hidden or child.__hidden: return
369 # If we're already updating, then do nothing. This prevents
370 # infinite loops when _update modifies its children.
371 if self.__updating: return
372 self.__updating = 1
373
374 # Update this CanvasWidget.
375 self._update(child)
376
377 # Propagate update request to the parent.
378 if self.__parent: self.__parent.update(self)
379
380 # We're done updating.
381 self.__updating = 0
382
384 """
385 Arrange this canvas widget and all of its descendants.
386
387 @rtype: C{None}
388 """
389 if self.__hidden: return
390 for child in self.__children: child.manage()
391 self._manage()
392
407
409 """
410 Set the value of the attribute C{attr} to C{value}. See the
411 class documentation for a list of attributes supported by this
412 canvas widget.
413
414 @rtype: C{None}
415 """
416 if attr == 'draggable':
417 self.__draggable = value
418 else:
419 raise ValueError('Unknown attribute %r' % attr)
420
422 """
423 @return: the value of the attribute C{attr}. See the class
424 documentation for a list of attributes supported by this
425 canvas widget.
426 @rtype: (any)
427 """
428 if attr == 'draggable':
429 return self.__draggable
430 else:
431 raise ValueError('Unknown attribute %r' % attr)
432
434 """
435 @return: a string representation of this canvas widget.
436 @rtype: C{string}
437 """
438 return '<%s>' % self.__class__.__name__
439
441 """
442 Temporarily hide this canvas widget.
443
444 @rtype: C{None}
445 """
446 self.__hidden = 1
447 for tag in self.tags():
448 self.__canvas.itemconfig(tag, state='hidden')
449
451 """
452 Show a hidden canvas widget.
453
454 @rtype: C{None}
455 """
456 self.__hidden = 0
457 for tag in self.tags():
458 self.__canvas.itemconfig(tag, state='normal')
459
466
467 ##//////////////////////////////////////////////////////
468 ## Callback interface
469 ##//////////////////////////////////////////////////////
470
472 """
473 Register a new callback that will be called whenever this
474 C{CanvasWidget} is clicked on.
475
476 @type callback: C{function}
477 @param callback: The callback function that will be called
478 whenever this C{CanvasWidget} is clicked. This function
479 will be called with this C{CanvasWidget} as its argument.
480 @type button: C{int}
481 @param button: Which button the user should use to click on
482 this C{CanvasWidget}. Typically, this should be 1 (left
483 button), 3 (right button), or 2 (middle button).
484 """
485 self.__callbacks[button] = callback
486
488 """
489 Register a new callback that will be called after this
490 C{CanvasWidget} is dragged. This implicitly makes this
491 C{CanvasWidget} draggable.
492
493 @type callback: C{function}
494 @param callback: The callback function that will be called
495 whenever this C{CanvasWidget} is clicked. This function
496 will be called with this C{CanvasWidget} as its argument.
497 """
498 self.__draggable = 1
499 self.__callbacks['drag'] = callback
500
502 """
503 Remove a callback that was registered with C{bind_click}.
504
505 @type button: C{int}
506 @param button: Which button the user should use to click on
507 this C{CanvasWidget}. Typically, this should be 1 (left
508 button), 3 (right button), or 2 (middle button).
509 """
510 try: del self.__callbacks[button]
511 except: pass
512
514 """
515 Remove a callback that was registered with C{bind_drag}.
516 """
517 try: del self.__callbacks['drag']
518 except: pass
519
520 ##//////////////////////////////////////////////////////
521 ## Callback internals
522 ##//////////////////////////////////////////////////////
523
525 """
526 Handle a button-press event:
527 - record the button press event in C{self.__press}
528 - register a button-release callback.
529 - if this CanvasWidget or any of its ancestors are
530 draggable, then register the appropriate motion callback.
531 """
532 # If we're already waiting for a button release, then ignore
533 # this new button press.
534 if (self.__canvas.bind('<ButtonRelease-1>') or
535 self.__canvas.bind('<ButtonRelease-2>') or
536 self.__canvas.bind('<ButtonRelease-3>')):
537 return
538
539 # Unbind motion (just in case; this shouldn't be necessary)
540 self.__canvas.unbind('<Motion>')
541
542 # Record the button press event.
543 self.__press = event
544
545 # If any ancestor is draggable, set up a motion callback.
546 # (Only if they pressed button number 1)
547 if event.num == 1:
548 widget = self
549 while widget is not None:
550 if widget['draggable']:
551 widget.__start_drag(event)
552 break
553 widget = widget.parent()
554
555 # Set up the button release callback.
556 self.__canvas.bind('<ButtonRelease-%d>' % event.num,
557 self.__release_cb)
558
560 """
561 Begin dragging this object:
562 - register a motion callback
563 - record the drag coordinates
564 """
565 self.__canvas.bind('<Motion>', self.__motion_cb)
566 self.__drag_x = event.x
567 self.__drag_y = event.y
568
570 """
571 Handle a motion event:
572 - move this object to the new location
573 - record the new drag coordinates
574 """
575 self.move(event.x-self.__drag_x, event.y-self.__drag_y)
576 self.__drag_x = event.x
577 self.__drag_y = event.y
578
580 """
581 Handle a release callback:
582 - unregister motion & button release callbacks.
583 - decide whether they clicked, dragged, or cancelled
584 - call the appropriate handler.
585 """
586 # Unbind the button release & motion callbacks.
587 self.__canvas.unbind('<ButtonRelease-%d>' % event.num)
588 self.__canvas.unbind('<Motion>')
589
590 # Is it a click or a drag?
591 if (event.time - self.__press.time < 100 and
592 abs(event.x-self.__press.x) + abs(event.y-self.__press.y) < 5):
593 # Move it back, if we were dragging.
594 if self.__draggable and event.num == 1:
595 self.move(self.__press.x - self.__drag_x,
596 self.__press.y - self.__drag_y)
597 self.__click(event.num)
598 elif event.num == 1:
599 self.__drag()
600
601 self.__press = None
602
604 """
605 If this C{CanvasWidget} has a drag callback, then call it;
606 otherwise, find the closest ancestor with a drag callback, and
607 call it. If no ancestors have a drag callback, do nothing.
608 """
609 if self.__draggable:
610 if self.__callbacks.has_key('drag'):
611 cb = self.__callbacks['drag']
612 try:
613 cb(self)
614 except:
615 print 'Error in drag callback for %r' % self
616 elif self.__parent is not None:
617 self.__parent.__drag()
618
620 """
621 If this C{CanvasWidget} has a drag callback, then call it;
622 otherwise, find the closest ancestor with a click callback, and
623 call it. If no ancestors have a click callback, do nothing.
624 """
625 if self.__callbacks.has_key(button):
626 cb = self.__callbacks[button]
627 #try:
628 cb(self)
629 #except:
630 # print 'Error in click callback for %r' % self
631 # raise
632 elif self.__parent is not None:
633 self.__parent.__click(button)
634
635 ##//////////////////////////////////////////////////////
636 ## Child/parent Handling
637 ##//////////////////////////////////////////////////////
638
640 """
641 Register a hierarchical child widget. The child will be
642 considered part of this canvas widget for purposes of user
643 interaction. C{_add_child_widget} has two direct effects:
644 - It sets C{child}'s parent to this canvas widget.
645 - It adds C{child} to the list of canvas widgets returned by
646 the C{child_widgets} member function.
647
648 @param child: The new child widget. C{child} must not already
649 have a parent.
650 @type child: C{CanvasWidget}
651 """
652 if not hasattr(self, '_CanvasWidget__children'): self.__children = []
653 if child.__parent is not None:
654 raise ValueError('%s already has a parent', child)
655 child.__parent = self
656 self.__children.append(child)
657
659 """
660 Remove a hierarchical child widget. This child will no longer
661 be considered part of this canvas widget for purposes of user
662 interaction. C{_add_child_widget} has two direct effects:
663 - It sets C{child}'s parent to C{None}.
664 - It removes C{child} from the list of canvas widgets
665 returned by the C{child_widgets} member function.
666
667 @param child: The child widget to remove. C{child} must be a
668 child of this canvas widget.
669 @type child: C{CanvasWidget}
670 """
671 self.__children.remove(child)
672 child.__parent = None
673
674 ##//////////////////////////////////////////////////////
675 ## Defined by subclass
676 ##//////////////////////////////////////////////////////
677
686
688 """
689 Arrange the child widgets of this canvas widget. This method
690 is called when the canvas widget is initially created. It is
691 also called if the user calls the C{manage} method on this
692 canvas widget or any of its ancestors.
693
694 @rtype: C{None}
695 """
696 pass
697
708
709 ##//////////////////////////////////////////////////////
710 ## Basic widgets.
711 ##//////////////////////////////////////////////////////
712
714 """
715 A canvas widget that displays a single string of text.
716
717 Attributes:
718 - C{color}: the color of the text.
719 - C{font}: the font used to display the text.
720 - C{justify}: justification for multi-line texts. Valid values
721 are C{left}, C{center}, and C{right}.
722 - C{width}: the width of the text. If the text is wider than
723 this width, it will be line-wrapped at whitespace.
724 - C{draggable}: whether the text can be dragged by the user.
725 """
727 """
728 Create a new text widget.
729
730 @type canvas: C{Tkinter.Canvas}
731 @param canvas: This canvas widget's canvas.
732 @type text: C{string}
733 @param text: The string of text to display.
734 @param attribs: The new canvas widget's attributes.
735 """
736 self._text = text
737 self._tag = canvas.create_text(1, 1, text=text)
738 CanvasWidget.__init__(self, canvas, **attribs)
739
741 if attr in ('color', 'font', 'justify', 'width'):
742 if attr == 'color': attr = 'fill'
743 self.canvas().itemconfig(self._tag, {attr:value})
744 else:
745 CanvasWidget.__setitem__(self, attr, value)
746
748 if attr == 'width':
749 return int(self.canvas().itemcget(self._tag, attr))
750 elif attr in ('color', 'font', 'justify'):
751 if attr == 'color': attr = 'fill'
752 return self.canvas().itemcget(self._tag, attr)
753 else:
754 return CanvasWidget.__getitem__(self, attr)
755
757
759 """
760 @return: The text displayed by this text widget.
761 @rtype: C{string}
762 """
763 return self.canvas().itemcget(self._tag, 'TEXT')
764
766 """
767 Change the text that is displayed by this text widget.
768
769 @type text: C{string}
770 @param text: The string of text to display.
771 @rtype: C{None}
772 """
773 self.canvas().itemconfig(self._tag, text=text)
774 if self.parent() is not None:
775 self.parent().update(self)
776
779
781 """
782 A canvas widget that displays special symbols, such as the
783 negation sign and the exists operator. Symbols are specified by
784 name. Currently, the following symbol names are defined: C{neg},
785 C{disj}, C{conj}, C{lambda}, C{merge}, C{forall}, C{exists},
786 C{subseteq}, C{subset}, C{notsubset}, C{emptyset}, C{imp},
787 C{rightarrow}, C{equal}, C{notequal}, C{epsilon}.
788
789 Attributes:
790 - C{color}: the color of the text.
791 - C{draggable}: whether the text can be dragged by the user.
792
793 @cvar SYMBOLS: A dictionary mapping from symbols to the character
794 in the C{symbol} font used to render them.
795 """
796 SYMBOLS = {'neg':'\330', 'disj':'\332', 'conj': '\331',
797 'lambda': '\154', 'merge': '\304',
798 'forall': '\042', 'exists': '\044',
799 'subseteq': '\315', 'subset': '\314',
800 'notsubset': '\313', 'emptyset': '\306',
801 'imp': '\336', 'rightarrow': chr(222), #'\256',
802 'equal': '\75', 'notequal': '\271',
803 'intersection': '\307', 'union': '\310',
804 'epsilon': 'e',
805 }
806
808 """
809 Create a new symbol widget.
810
811 @type canvas: C{Tkinter.Canvas}
812 @param canvas: This canvas widget's canvas.
813 @type symbol: C{string}
814 @param symbol: The name of the symbol to display.
815 @param attribs: The new canvas widget's attributes.
816 """
817 attribs['font'] = 'symbol'
818 TextWidget.__init__(self, canvas, '', **attribs)
819 self.set_symbol(symbol)
820
822 """
823 @return: the name of the symbol that is displayed by this
824 symbol widget.
825 @rtype: C{string}
826 """
827 return self._symbol
828
830 """
831 Change the symbol that is displayed by this symbol widget.
832
833 @type symbol: C{string}
834 @param symbol: The name of the symbol to display.
835 """
836 if not SymbolWidget.SYMBOLS.has_key(symbol):
837 raise ValueError('Unknown symbol: %s' % symbol)
838 self._symbol = symbol
839 self.set_text(SymbolWidget.SYMBOLS[symbol])
840
843
844 # A staticmethod that displays all symbols.
846 """
847 Open a new Tkinter window that displays the entire alphabet
848 for the symbol font. This is useful for constructing the
849 L{SymbolWidget.SYMBOLS} dictionary.
850 """
851 top = Tk()
852 def destroy(e, top=top): top.destroy()
853 top.bind('q', destroy)
854 Button(top, text='Quit', command=top.destroy).pack(side='bottom')
855 text = Text(top, font=('helvetica', -size), width=20, height=30)
856 text.pack(side='left')
857 sb=Scrollbar(top, command=text.yview)
858 text['yscrollcommand']=sb.set
859 sb.pack(side='right', fill='y')
860 text.tag_config('symbol', font=('symbol', -size))
861 for i in range(256):
862 if i in (0,10): continue # null and newline
863 for k,v in SymbolWidget.SYMBOLS.items():
864 if v == chr(i):
865 text.insert('end', '%-10s\t' % k)
866 break
867 else:
868 text.insert('end', '%-10d \t' % i)
869 text.insert('end', '[%s]\n' % chr(i), 'symbol')
870 top.mainloop()
871 symbolsheet = staticmethod(symbolsheet)
872
873
875 """
876 An abstract class for canvas widgets that contain a single child,
877 such as C{BoxWidget} and C{OvalWidget}. Subclasses must define
878 a constructor, which should create any new graphical elements and
879 then call the C{AbstractCanvasContainer} constructor. Subclasses
880 must also define the C{_update} method and the C{_tags} method;
881 and any subclasses that define attributes should define
882 C{__setitem__} and C{__getitem__}.
883 """
885 """
886 Create a new container widget. This constructor should only
887 be called by subclass constructors.
888
889 @type canvas: C{Tkinter.Canvas}
890 @param canvas: This canvas widget's canvas.
891 @param child: The container's child widget. C{child} must not
892 have a parent.
893 @type child: C{CanvasWidget}
894 @param attribs: The new canvas widget's attributes.
895 """
896 self._child = child
897 self._add_child_widget(child)
898 CanvasWidget.__init__(self, canvas, **attribs)
899
901 self._update(self._child)
902
904 """
905 @return: The child widget contained by this container widget.
906 @rtype: C{CanvasWidget}
907 """
908 return self._child
909
911 """
912 Change the child widget contained by this container widget.
913
914 @param child: The new child widget. C{child} must not have a
915 parent.
916 @type child: C{CanvasWidget}
917 @rtype: C{None}
918 """
919 self._remove_child_widget(self._child)
920 self._add_child_widget(child)
921 self._child = child
922 self.update(child)
923
928
930 """
931 A canvas widget that places a box around a child widget.
932
933 Attributes:
934 - C{fill}: The color used to fill the interior of the box.
935 - C{outline}: The color used to draw the outline of the box.
936 - C{width}: The width of the outline of the box.
937 - C{margin}: The number of pixels space left between the child
938 and the box.
939 - C{draggable}: whether the text can be dragged by the user.
940 """
942 """
943 Create a new box widget.
944
945 @type canvas: C{Tkinter.Canvas}
946 @param canvas: This canvas widget's canvas.
947 @param child: The child widget. C{child} must not have a
948 parent.
949 @type child: C{CanvasWidget}
950 @param attribs: The new canvas widget's attributes.
951 """
952 self._child = child
953 self._margin = 1
954 self._box = canvas.create_rectangle(1,1,1,1)
955 canvas.tag_lower(self._box)
956 AbstractContainerWidget.__init__(self, canvas, child, **attribs)
957
959 if attr == 'margin': self._margin = value
960 elif attr in ('outline', 'fill', 'width'):
961 self.canvas().itemconfig(self._box, {attr:value})
962 else:
963 CanvasWidget.__setitem__(self, attr, value)
964
966 if attr == 'margin': return self._margin
967 elif attr == 'width':
968 return float(self.canvas().itemcget(self._box, attr))
969 elif attr in ('outline', 'fill', 'width'):
970 return self.canvas().itemcget(self._box, attr)
971 else:
972 return CanvasWidget.__getitem__(self, attr)
973
975 (x1, y1, x2, y2) = child.bbox()
976 margin = self._margin + self['width']/2
977 self.canvas().coords(self._box, x1-margin, y1-margin,
978 x2+margin, y2+margin)
979
981
983 """
984 A canvas widget that places a oval around a child widget.
985
986 Attributes:
987 - C{fill}: The color used to fill the interior of the oval.
988 - C{outline}: The color used to draw the outline of the oval.
989 - C{width}: The width of the outline of the oval.
990 - C{margin}: The number of pixels space left between the child
991 and the oval.
992 - C{draggable}: whether the text can be dragged by the user.
993 - C{double}: If true, then a double-oval is drawn.
994 """
996 """
997 Create a new oval widget.
998
999 @type canvas: C{Tkinter.Canvas}
1000 @param canvas: This canvas widget's canvas.
1001 @param child: The child widget. C{child} must not have a
1002 parent.
1003 @type child: C{CanvasWidget}
1004 @param attribs: The new canvas widget's attributes.
1005 """
1006 self._child = child
1007 self._margin = 1
1008 self._oval = canvas.create_oval(1,1,1,1)
1009 self._circle = attribs.pop('circle', False)
1010 self._double = attribs.pop('double', False)
1011 if self._double:
1012 self._oval2 = canvas.create_oval(1,1,1,1)
1013 else:
1014 self._oval2 = None
1015 canvas.tag_lower(self._oval)
1016 AbstractContainerWidget.__init__(self, canvas, child, **attribs)
1017
1019 c = self.canvas()
1020 if attr == 'margin': self._margin = value
1021 elif attr == 'double':
1022 if value==True and self._oval2 is None:
1023 # Copy attributes & position from self._oval.
1024 x1, y1, x2, y2 = c.bbox(self._oval)
1025 w = self['width']*2
1026 self._oval2 = c.create_oval(x1-w, y1-w, x2+w, y2+w,
1027 outline=c.itemcget(self._oval, 'outline'),
1028 width=c.itemcget(self._oval, 'width'))
1029 c.tag_lower(self._oval2)
1030 if value==False and self._oval2 is not None:
1031 c.delete(self._oval2)
1032 self._oval2 = None
1033 elif attr in ('outline', 'fill', 'width'):
1034 c.itemconfig(self._oval, {attr:value})
1035 if self._oval2 is not None and attr!='fill':
1036 c.itemconfig(self._oval2, {attr:value})
1037 if self._oval2 is not None and attr!='fill':
1038 self.canvas().itemconfig(self._oval2, {attr:value})
1039 else:
1040 CanvasWidget.__setitem__(self, attr, value)
1041
1043 if attr == 'margin': return self._margin
1044 elif attr == 'double': return self._double is not None
1045 elif attr == 'width':
1046 return float(self.canvas().itemcget(self._oval, attr))
1047 elif attr in ('outline', 'fill', 'width'):
1048 return self.canvas().itemcget(self._oval, attr)
1049 else:
1050 return CanvasWidget.__getitem__(self, attr)
1051
1052 # The ratio between inscribed & circumscribed ovals
1053 RATIO = 1.4142135623730949
1054
1056 R = OvalWidget.RATIO
1057 (x1, y1, x2, y2) = child.bbox()
1058 margin = self._margin
1059
1060 # If we're a circle, pretend our contents are square.
1061 if self._circle:
1062 dx, dy = abs(x1-x2), abs(y1-y2)
1063 if dx > dy:
1064 y = (y1+y2)/2
1065 y1, y2 = y-dx/2, y+dx/2
1066 elif dy > dx:
1067 x = (x1+x2)/2
1068 x1, x2 = x-dy/2, x+dy/2
1069
1070 # Find the four corners.
1071 left = int(( x1*(1+R) + x2*(1-R) ) / 2)
1072 right = left + int((x2-x1)*R)
1073 top = int(( y1*(1+R) + y2*(1-R) ) / 2)
1074 bot = top + int((y2-y1)*R)
1075 self.canvas().coords(self._oval, left-margin, top-margin,
1076 right+margin, bot+margin)
1077 if self._oval2 is not None:
1078 self.canvas().coords(self._oval2, left-margin+2, top-margin+2,
1079 right+margin-2, bot+margin-2)
1080
1086
1088 """
1089 A canvas widget that places a pair of parenthases around a child
1090 widget.
1091
1092 Attributes:
1093 - C{color}: The color used to draw the parenthases.
1094 - C{width}: The width of the parenthases.
1095 - C{draggable}: whether the text can be dragged by the user.
1096 """
1098 """
1099 Create a new parenthasis widget.
1100
1101 @type canvas: C{Tkinter.Canvas}
1102 @param canvas: This canvas widget's canvas.
1103 @param child: The child widget. C{child} must not have a
1104 parent.
1105 @type child: C{CanvasWidget}
1106 @param attribs: The new canvas widget's attributes.
1107 """
1108 self._child = child
1109 self._oparen = canvas.create_arc(1,1,1,1, style='arc',
1110 start=90, extent=180)
1111 self._cparen = canvas.create_arc(1,1,1,1, style='arc',
1112 start=-90, extent=180)
1113 AbstractContainerWidget.__init__(self, canvas, child, **attribs)
1114
1116 if attr == 'color':
1117 self.canvas().itemconfig(self._oparen, outline=value)
1118 self.canvas().itemconfig(self._cparen, outline=value)
1119 elif attr == 'width':
1120 self.canvas().itemconfig(self._oparen, width=value)
1121 self.canvas().itemconfig(self._cparen, width=value)
1122 else:
1123 CanvasWidget.__setitem__(self, attr, value)
1124
1126 if attr == 'color':
1127 return self.canvas().itemcget(self._oparen, 'outline')
1128 elif attr == 'width':
1129 return self.canvas().itemcget(self._oparen, 'width')
1130 else:
1131 return CanvasWidget.__getitem__(self, attr)
1132
1134 (x1, y1, x2, y2) = child.bbox()
1135 width = max((y2-y1)/6, 4)
1136 self.canvas().coords(self._oparen, x1-width, y1, x1+width, y2)
1137 self.canvas().coords(self._cparen, x2-width, y1, x2+width, y2)
1138
1140
1142 """
1143 A canvas widget that places a pair of brackets around a child
1144 widget.
1145
1146 Attributes:
1147 - C{color}: The color used to draw the brackets.
1148 - C{width}: The width of the brackets.
1149 - C{draggable}: whether the text can be dragged by the user.
1150 """
1152 """
1153 Create a new bracket widget.
1154
1155 @type canvas: C{Tkinter.Canvas}
1156 @param canvas: This canvas widget's canvas.
1157 @param child: The child widget. C{child} must not have a
1158 parent.
1159 @type child: C{CanvasWidget}
1160 @param attribs: The new canvas widget's attributes.
1161 """
1162 self._child = child
1163 self._obrack = canvas.create_line(1,1,1,1,1,1,1,1)
1164 self._cbrack = canvas.create_line(1,1,1,1,1,1,1,1)
1165 AbstractContainerWidget.__init__(self, canvas, child, **attribs)
1166
1168 if attr == 'color':
1169 self.canvas().itemconfig(self._obrack, fill=value)
1170 self.canvas().itemconfig(self._cbrack, fill=value)
1171 elif attr == 'width':
1172 self.canvas().itemconfig(self._obrack, width=value)
1173 self.canvas().itemconfig(self._cbrack, width=value)
1174 else:
1175 CanvasWidget.__setitem__(self, attr, value)
1176
1178 if attr == 'color':
1179 return self.canvas().itemcget(self._obrack, 'outline')
1180 elif attr == 'width':
1181 return self.canvas().itemcget(self._obrack, 'width')
1182 else:
1183 return CanvasWidget.__getitem__(self, attr)
1184
1186 (x1, y1, x2, y2) = child.bbox()
1187 width = max((y2-y1)/8, 2)
1188 self.canvas().coords(self._obrack, x1, y1, x1-width, y1,
1189 x1-width, y2, x1, y2)
1190 self.canvas().coords(self._cbrack, x2, y1, x2+width, y1,
1191 x2+width, y2, x2, y2)
1192
1194
1196 """
1197 A canvas widget that keeps a list of canvas widgets in a
1198 horizontal line.
1199
1200 Attributes:
1201 - C{align}: The vertical alignment of the children. Possible
1202 values are C{'top'}, C{'center'}, and C{'bottom'}. By
1203 default, children are center-aligned.
1204 - C{space}: The amount of horizontal space to place between
1205 children. By default, one pixel of space is used.
1206 - C{ordered}: If true, then keep the children in their
1207 original order.
1208 """
1210 """
1211 Create a new sequence widget.
1212
1213 @type canvas: C{Tkinter.Canvas}
1214 @param canvas: This canvas widget's canvas.
1215 @param children: The widgets that should be aligned
1216 horizontally. Each child must not have a parent.
1217 @type children: C{list} of C{CanvasWidget}
1218 @param attribs: The new canvas widget's attributes.
1219 """
1220 self._align = 'center'
1221 self._space = 1
1222 self._ordered = False
1223 self._children = list(children)
1224 for child in children: self._add_child_widget(child)
1225 CanvasWidget.__init__(self, canvas, **attribs)
1226
1228 if attr == 'align':
1229 if value not in ('top', 'bottom', 'center'):
1230 raise ValueError('Bad alignment: %r' % value)
1231 self._align = value
1232 elif attr == 'space': self._space = value
1233 elif attr == 'ordered': self._ordered = value
1234 else: CanvasWidget.__setitem__(self, attr, value)
1235
1237 if attr == 'align': return value
1238 elif attr == 'space': return self._space
1239 elif attr == 'ordered': return self._ordered
1240 else: return CanvasWidget.__getitem__(self, attr)
1241
1243
1245 if self._align == 'top': return top
1246 if self._align == 'bottom': return bot
1247 if self._align == 'center': return (top+bot)/2
1248
1250 # Align all children with child.
1251 (left, top, right, bot) = child.bbox()
1252 y = self._yalign(top, bot)
1253 for c in self._children:
1254 (x1, y1, x2, y2) = c.bbox()
1255 c.move(0, y-self._yalign(y1,y2))
1256
1257 if self._ordered and len(self._children) > 1:
1258 index = self._children.index(child)
1259
1260 x = right + self._space
1261 for i in range(index+1, len(self._children)):
1262 (x1, y1, x2, y2) = self._children[i].bbox()
1263 if x > x1:
1264 self._children[i].move(x-x1, 0)
1265 x += x2-x1 + self._space
1266
1267 x = left - self._space
1268 for i in range(index-1, -1, -1):
1269 (x1, y1, x2, y2) = self._children[i].bbox()
1270 if x < x2:
1271 self._children[i].move(x-x2, 0)
1272 x -= x2-x1 + self._space
1273
1275 if len(self._children) == 0: return
1276 child = self._children[0]
1277
1278 # Align all children with child.
1279 (left, top, right, bot) = child.bbox()
1280 y = self._yalign(top, bot)
1281
1282 index = self._children.index(child)
1283
1284 # Line up children to the right of child.
1285 x = right + self._space
1286 for i in range(index+1, len(self._children)):
1287 (x1, y1, x2, y2) = self._children[i].bbox()
1288 self._children[i].move(x-x1, y-self._yalign(y1,y2))
1289 x += x2-x1 + self._space
1290
1291 # Line up children to the left of child.
1292 x = left - self._space
1293 for i in range(index-1, -1, -1):
1294 (x1, y1, x2, y2) = self._children[i].bbox()
1295 self._children[i].move(x-x2, y-self._yalign(y1,y2))
1296 x -= x2-x1 + self._space
1297
1300
1301 # Provide an alias for the child_widgets() member.
1302 children = CanvasWidget.child_widgets
1303
1305 """
1306 Replace the child canvas widget C{oldchild} with C{newchild}.
1307 C{newchild} must not have a parent. C{oldchild}'s parent will
1308 be set to C{None}.
1309
1310 @type oldchild: C{CanvasWidget}
1311 @param oldchild: The child canvas widget to remove.
1312 @type newchild: C{CanvasWidget}
1313 @param newchild: The canvas widget that should replace
1314 C{oldchild}.
1315 """
1316 index = self._children.index(oldchild)
1317 self._children[index] = newchild
1318 self._remove_child_widget(oldchild)
1319 self._add_child_widget(newchild)
1320 self.update(newchild)
1321
1323 """
1324 Remove the given child canvas widget. C{child}'s parent will
1325 be set ot None.
1326
1327 @type child: C{CanvasWidget}
1328 @param child: The child canvas widget to remove.
1329 """
1330 index = self._children.index(child)
1331 del self._children[index]
1332 self._remove_child_widget(child)
1333 if len(self._children) > 0:
1334 self.update(self._children[0])
1335
1337 """
1338 Insert a child canvas widget before a given index.
1339
1340 @type child: C{CanvasWidget}
1341 @param child: The canvas widget that should be inserted.
1342 @type index: C{int}
1343 @param index: The index where the child widget should be
1344 inserted. In particular, the index of C{child} will be
1345 C{index}; and the index of any children whose indices were
1346 greater than equal to C{index} before C{child} was
1347 inserted will be incremented by one.
1348 """
1349 self._children.insert(index, child)
1350 self._add_child_widget(child)
1351
1353 """
1354 A canvas widget that keeps a list of canvas widgets in a vertical
1355 line.
1356
1357 Attributes:
1358 - C{align}: The horizontal alignment of the children. Possible
1359 values are C{'left'}, C{'center'}, and C{'right'}. By
1360 default, children are center-aligned.
1361 - C{space}: The amount of vertical space to place between
1362 children. By default, one pixel of space is used.
1363 - C{ordered}: If true, then keep the children in their
1364 original order.
1365 """
1367 """
1368 Create a new stack widget.
1369
1370 @type canvas: C{Tkinter.Canvas}
1371 @param canvas: This canvas widget's canvas.
1372 @param children: The widgets that should be aligned
1373 vertically. Each child must not have a parent.
1374 @type children: C{list} of C{CanvasWidget}
1375 @param attribs: The new canvas widget's attributes.
1376 """
1377 self._align = 'center'
1378 self._space = 1
1379 self._ordered = False
1380 self._children = list(children)
1381 for child in children: self._add_child_widget(child)
1382 CanvasWidget.__init__(self, canvas, **attribs)
1383
1385 if attr == 'align':
1386 if value not in ('left', 'right', 'center'):
1387 raise ValueError('Bad alignment: %r' % value)
1388 self._align = value
1389 elif attr == 'space': self._space = value
1390 elif attr == 'ordered': self._ordered = value
1391 else: CanvasWidget.__setitem__(self, attr, value)
1392
1394 if attr == 'align': return value
1395 elif attr == 'space': return self._space
1396 elif attr == 'ordered': return self._ordered
1397 else: return CanvasWidget.__getitem__(self, attr)
1398
1400
1402 if self._align == 'left': return left
1403 if self._align == 'right': return right
1404 if self._align == 'center': return (left+right)/2
1405
1407 # Align all children with child.
1408 (left, top, right, bot) = child.bbox()
1409 x = self._xalign(left, right)
1410 for c in self._children:
1411 (x1, y1, x2, y2) = c.bbox()
1412 c.move(x-self._xalign(x1,x2), 0)
1413
1414 if self._ordered and len(self._children) > 1:
1415 index = self._children.index(child)
1416
1417 y = bot + self._space
1418 for i in range(index+1, len(self._children)):
1419 (x1, y1, x2, y2) = self._children[i].bbox()
1420 if y > y1:
1421 self._children[i].move(0, y-y1)
1422 y += y2-y1 + self._space
1423
1424 y = top - self._space
1425 for i in range(index-1, -1, -1):
1426 (x1, y1, x2, y2) = self._children[i].bbox()
1427 if y < y2:
1428 self._children[i].move(0, y-y2)
1429 y -= y2-y1 + self._space
1430
1432 if len(self._children) == 0: return
1433 child = self._children[0]
1434
1435 # Align all children with child.
1436 (left, top, right, bot) = child.bbox()
1437 x = self._xalign(left, right)
1438
1439 index = self._children.index(child)
1440
1441 # Line up children below the child.
1442 y = bot + self._space
1443 for i in range(index+1, len(self._children)):
1444 (x1, y1, x2, y2) = self._children[i].bbox()
1445 self._children[i].move(x-self._xalign(x1,x2), y-y1)
1446 y += y2-y1 + self._space
1447
1448 # Line up children above the child.
1449 y = top - self._space
1450 for i in range(index-1, -1, -1):
1451 (x1, y1, x2, y2) = self._children[i].bbox()
1452 self._children[i].move(x-self._xalign(x1,x2), y-y2)
1453 y -= y2-y1 + self._space
1454
1457
1458 # Provide an alias for the child_widgets() member.
1459 children = CanvasWidget.child_widgets
1460
1462 """
1463 Replace the child canvas widget C{oldchild} with C{newchild}.
1464 C{newchild} must not have a parent. C{oldchild}'s parent will
1465 be set to C{None}.
1466
1467 @type oldchild: C{CanvasWidget}
1468 @param oldchild: The child canvas widget to remove.
1469 @type newchild: C{CanvasWidget}
1470 @param newchild: The canvas widget that should replace
1471 C{oldchild}.
1472 """
1473 index = self._children.index(oldchild)
1474 self._children[index] = newchild
1475 self._remove_child_widget(oldchild)
1476 self._add_child_widget(newchild)
1477 self.update(newchild)
1478
1480 """
1481 Remove the given child canvas widget. C{child}'s parent will
1482 be set ot None.
1483
1484 @type child: C{CanvasWidget}
1485 @param child: The child canvas widget to remove.
1486 """
1487 index = self._children.index(child)
1488 del self._children[index]
1489 self._remove_child_widget(child)
1490 if len(self._children) > 0:
1491 self.update(self._children[0])
1492
1494 """
1495 Insert a child canvas widget before a given index.
1496
1497 @type child: C{CanvasWidget}
1498 @param child: The canvas widget that should be inserted.
1499 @type index: C{int}
1500 @param index: The index where the child widget should be
1501 inserted. In particular, the index of C{child} will be
1502 C{index}; and the index of any children whose indices were
1503 greater than equal to C{index} before C{child} was
1504 inserted will be incremented by one.
1505 """
1506 self._children.insert(index, child)
1507 self._add_child_widget(child)
1508
1510 """
1511 A canvas widget that takes up space but does not display
1512 anything. C{SpaceWidget}s can be used to add space between
1513 elements. Each space widget is characterized by a width and a
1514 height. If you wish to only create horizontal space, then use a
1515 height of zero; and if you wish to only create vertical space, use
1516 a width of zero.
1517 """
1519 """
1520 Create a new space widget.
1521
1522 @type canvas: C{Tkinter.Canvas}
1523 @param canvas: This canvas widget's canvas.
1524 @type width: C{int}
1525 @param width: The width of the new space widget.
1526 @type height: C{int}
1527 @param height: The height of the new space widget.
1528 @param attribs: The new canvas widget's attributes.
1529 """
1530 # For some reason,
1531 if width > 4: width -= 4
1532 if height > 4: height -= 4
1533 self._tag = canvas.create_line(1, 1, width, height, fill='')
1534 CanvasWidget.__init__(self, canvas, **attribs)
1535
1536 # note: width() and height() are already defined by CanvasWidget.
1538 """
1539 Change the width of this space widget.
1540
1541 @param width: The new width.
1542 @type width: C{int}
1543 @rtype: C{None}
1544 """
1545 [x1, y1, x2, y2] = self.bbox()
1546 self.canvas().coords(self._tag, x1, y1, x1+width, y2)
1547
1549 """
1550 Change the height of this space widget.
1551
1552 @param height: The new height.
1553 @type height: C{int}
1554 @rtype: C{None}
1555 """
1556 [x1, y1, x2, y2] = self.bbox()
1557 self.canvas().coords(self._tag, x1, y1, x2, y1+height)
1558
1560
1562
1564 """
1565 A special canvas widget that adjusts its C{Canvas}'s scrollregion
1566 to always include the bounding boxes of all of its children. The
1567 scroll-watcher widget will only increase the size of the
1568 C{Canvas}'s scrollregion; it will never decrease it.
1569 """
1571 """
1572 Create a new scroll-watcher widget.
1573
1574 @type canvas: C{Tkinter.Canvas}
1575 @param canvas: This canvas widget's canvas.
1576 @type children: C{list} of C{CanvasWidget}
1577 @param children: The canvas widgets watched by the
1578 scroll-watcher. The scroll-watcher will ensure that these
1579 canvas widgets are always contained in their canvas's
1580 scrollregion.
1581 @param attribs: The new canvas widget's attributes.
1582 """
1583 for child in children: self._add_child_widget(child)
1584 CanvasWidget.__init__(self, canvas, **attribs)
1585
1587 """
1588 Add a new canvas widget to the scroll-watcher. The
1589 scroll-watcher will ensure that the new canvas widget is
1590 always contained in its canvas's scrollregion.
1591
1592 @param canvaswidget: The new canvas widget.
1593 @type canvaswidget: C{CanvasWidget}
1594 @rtype: C{None}
1595 """
1596 self._add_child_widget(canvaswidget)
1597 self.update(canvaswidget)
1598
1600 """
1601 Remove a canvas widget from the scroll-watcher. The
1602 scroll-watcher will no longer ensure that the new canvas
1603 widget is always contained in its canvas's scrollregion.
1604
1605 @param canvaswidget: The canvas widget to remove.
1606 @type canvaswidget: C{CanvasWidget}
1607 @rtype: C{None}
1608 """
1609 self._remove_child_widget(canvaswidget)
1610
1612
1614 self._adjust_scrollregion()
1615
1617 """
1618 Adjust the scrollregion of this scroll-watcher's C{Canvas} to
1619 include the bounding boxes of all of its children.
1620 """
1621 bbox = self.bbox()
1622 canvas = self.canvas()
1623 scrollregion = [int(n) for n in canvas['scrollregion'].split()]
1624 if len(scrollregion) != 4: return
1625 if (bbox[0] < scrollregion[0] or bbox[1] < scrollregion[1] or
1626 bbox[2] > scrollregion[2] or bbox[3] > scrollregion[3]):
1627 scrollregion = ('%d %d %d %d' %
1628 (min(bbox[0], scrollregion[0]),
1629 min(bbox[1], scrollregion[1]),
1630 max(bbox[2], scrollregion[2]),
1631 max(bbox[3], scrollregion[3])))
1632 canvas['scrollregion'] = scrollregion
1633
1634 ##//////////////////////////////////////////////////////
1635 ## Canvas Frame
1636 ##//////////////////////////////////////////////////////
1637
1639 """
1640 A C{Tkinter} frame containing a canvas and scrollbars.
1641 C{CanvasFrame} uses a C{ScrollWatcherWidget} to ensure that all of
1642 the canvas widgets contained on its canvas are within its
1643 scrollregion. In order for C{CanvasFrame} to make these checks,
1644 all canvas widgets must be registered with C{add_widget} when they
1645 are added to the canvas; and destroyed with C{destroy_widget} when
1646 they are no longer needed.
1647
1648 If a C{CanvasFrame} is created with no parent, then it will create
1649 its own main window, including a "Done" button and a "Print"
1650 button.
1651 """
1653 """
1654 Create a new C{CanvasFrame}.
1655
1656 @type parent: C{Tkinter.BaseWidget} or C{Tkinter.Tk}
1657 @param parent: The parent C{Tkinter} widget. If no parent is
1658 specified, then C{CanvasFrame} will create a new main
1659 window.
1660 @param kw: Keyword arguments for the new C{Canvas}. See the
1661 documentation for C{Tkinter.Canvas} for more information.
1662 """
1663 # If no parent was given, set up a top-level window.
1664 if parent is None:
1665 self._parent = Tk()
1666 self._parent.title('NLTK')
1667 self._parent.bind('<Control-p>', lambda e: self.print_to_file())
1668 self._parent.bind('<Control-x>', self.destroy)
1669 self._parent.bind('<Control-q>', self.destroy)
1670 else:
1671 self._parent = parent
1672
1673 # Create a frame for the canvas & scrollbars
1674 self._frame = frame = Frame(self._parent)
1675 self._canvas = canvas = Canvas(frame, **kw)
1676 xscrollbar = Scrollbar(self._frame, orient='horizontal')
1677 yscrollbar = Scrollbar(self._frame, orient='vertical')
1678 xscrollbar['command'] = canvas.xview
1679 yscrollbar['command'] = canvas.yview
1680 canvas['xscrollcommand'] = xscrollbar.set
1681 canvas['yscrollcommand'] = yscrollbar.set
1682 yscrollbar.pack(fill='y', side='right')
1683 xscrollbar.pack(fill='x', side='bottom')
1684 canvas.pack(expand=1, fill='both', side='left')
1685
1686 # Set initial scroll region.
1687 scrollregion = '0 0 %s %s' % (canvas['width'], canvas['height'])
1688 canvas['scrollregion'] = scrollregion
1689
1690 self._scrollwatcher = ScrollWatcherWidget(canvas)
1691
1692 # If no parent was given, pack the frame, and add a menu.
1693 if parent is None:
1694 self.pack(expand=1, fill='both')
1695 self._init_menubar()
1696
1708
1710 """
1711 Print the contents of this C{CanvasFrame} to a postscript
1712 file. If no filename is given, then prompt the user for one.
1713
1714 @param filename: The name of the file to print the tree to.
1715 @type filename: C{string}
1716 @rtype: C{None}
1717 """
1718 if filename is None:
1719 from tkFileDialog import asksaveasfilename
1720 ftypes = [('Postscript files', '.ps'),
1721 ('All files', '*')]
1722 filename = asksaveasfilename(filetypes=ftypes,
1723 defaultextension='.ps')
1724 if not filename: return
1725 (x0, y0, w, h) = self.scrollregion()
1726 self._canvas.postscript(file=filename, x=x0, y=y0,
1727 width=w+2, height=h+2,
1728 pagewidth=w+2, # points = 1/72 inch
1729 pageheight=h+2, # points = 1/72 inch
1730 pagex=0, pagey=0)
1731
1733 """
1734 @return: The current scroll region for the canvas managed by
1735 this C{CanvasFrame}.
1736 @rtype: 4-tuple of C{int}
1737 """
1738 (x1, y1, x2, y2) = self._canvas['scrollregion'].split()
1739 return (int(x1), int(y1), int(x2), int(y2))
1740
1742 """
1743 @return: The canvas managed by this C{CanvasFrame}.
1744 @rtype: C{Tkinter.Canvas}
1745 """
1746 return self._canvas
1747
1749 """
1750 Register a canvas widget with this C{CanvasFrame}. The
1751 C{CanvasFrame} will ensure that this canvas widget is always
1752 within the C{Canvas}'s scrollregion. If no coordinates are
1753 given for the canvas widget, then the C{CanvasFrame} will
1754 attempt to find a clear area of the canvas for it.
1755
1756 @type canvaswidget: C{CanvasWidget}
1757 @param canvaswidget: The new canvas widget. C{canvaswidget}
1758 must have been created on this C{CanvasFrame}'s canvas.
1759 @type x: C{int}
1760 @param x: The initial x coordinate for the upper left hand
1761 corner of C{canvaswidget}, in the canvas's coordinate
1762 space.
1763 @type y: C{int}
1764 @param y: The initial y coordinate for the upper left hand
1765 corner of C{canvaswidget}, in the canvas's coordinate
1766 space.
1767 """
1768 if x is None or y is None:
1769 (x, y) = self._find_room(canvaswidget, x, y)
1770
1771 # Move to (x,y)
1772 (x1,y1,x2,y2) = canvaswidget.bbox()
1773 canvaswidget.move(x-x1,y-y1)
1774
1775 # Register with scrollwatcher.
1776 self._scrollwatcher.add_child(canvaswidget)
1777
1779 """
1780 Try to find a space for a given widget.
1781 """
1782 (left, top, right, bot) = self.scrollregion()
1783 w = widget.width()
1784 h = widget.height()
1785
1786 if w >= (right-left): return (0,0)
1787 if h >= (bot-top): return (0,0)
1788
1789 # Move the widget out of the way, for now.
1790 (x1,y1,x2,y2) = widget.bbox()
1791 widget.move(left-x2-50, top-y2-50)
1792
1793 if desired_x is not None:
1794 x = desired_x
1795 for y in range(top, bot-h, (bot-top-h)/10):
1796 if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5):
1797 return (x,y)
1798
1799 if desired_y is not None:
1800 y = desired_y
1801 for x in range(left, right-w, (right-left-w)/10):
1802 if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5):
1803 return (x,y)
1804
1805 for y in range(top, bot-h, (bot-top-h)/10):
1806 for x in range(left, right-w, (right-left-w)/10):
1807 if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5):
1808 return (x,y)
1809 return (0,0)
1810
1812 """
1813 Remove a canvas widget from this C{CanvasFrame}. This
1814 deregisters the canvas widget, and destroys it.
1815 """
1816 self.remove_widget(canvaswidget)
1817 canvaswidget.destroy()
1818
1822
1824 """
1825 Pack this C{CanvasFrame}. See the documentation for
1826 C{Tkinter.Pack} for more information.
1827 """
1828 self._frame.pack(cnf, **kw)
1829 # Adjust to be big enough for kids?
1830
1832 """
1833 Destroy this C{CanvasFrame}. If this C{CanvasFrame} created a
1834 top-level window, then this will close that window.
1835 """
1836 if self._parent is None: return
1837 self._parent.destroy()
1838 self._parent = None
1839
1841 """
1842 Enter the Tkinter mainloop. This function must be called if
1843 this frame is created from a non-interactive program (e.g.
1844 from a secript); otherwise, the frame will close as soon as
1845 the script completes.
1846 """
1847 if in_idle(): return
1848 self._parent.mainloop(*args, **kwargs)
1849
1850 ##//////////////////////////////////////////////////////
1851 ## Text display
1852 ##//////////////////////////////////////////////////////
1853
1855 """
1856 A C{Tkinter} window used to display a text. C{ShowText} is
1857 typically used by graphical tools to display help text, or similar
1858 information.
1859 """
1862 if width is None or height is None:
1863 (width, height) = self.find_dimentions(text, width, height)
1864
1865 # Create the main window.
1866 if root is None:
1867 self._top = top = Tk()
1868 else:
1869 self._top = top = Toplevel(root)
1870 top.title(title)
1871
1872 b = Button(top, text='Ok', command=self.destroy)
1873 b.pack(side='bottom')
1874
1875 tbf = Frame(top)
1876 tbf.pack(expand=1, fill='both')
1877 scrollbar = Scrollbar(tbf, orient='vertical')
1878 scrollbar.pack(side='right', fill='y')
1879 textbox = Text(tbf, wrap='word', width=width,
1880 height=height, **textbox_options)
1881 textbox.insert('end', text)
1882 textbox['state'] = 'disabled'
1883 textbox.pack(side='left', expand=1, fill='both')
1884 scrollbar['command'] = textbox.yview
1885 textbox['yscrollcommand'] = scrollbar.set
1886
1887 # Make it easy to close the window.
1888 top.bind('q', self.destroy)
1889 top.bind('x', self.destroy)
1890 top.bind('c', self.destroy)
1891 top.bind('<Return>', self.destroy)
1892 top.bind('<Escape>', self.destroy)
1893
1894 # Focus the scrollbar, so they can use up/down, etc.
1895 scrollbar.focus()
1896
1898 lines = text.split('\n')
1899 if width is None:
1900 maxwidth = max([len(line) for line in lines])
1901 width = min(maxwidth, 80)
1902
1903 # Now, find height.
1904 height = 0
1905 for line in lines:
1906 while len(line) > width:
1907 brk = line[:width].rfind(' ')
1908 line = line[brk:]
1909 height += 1
1910 height += 1
1911 height = min(height, 25)
1912
1913 return (width, height)
1914
1919
1921 """
1922 Enter the Tkinter mainloop. This function must be called if
1923 this window is created from a non-interactive program (e.g.
1924 from a secript); otherwise, the window will close as soon as
1925 the script completes.
1926 """
1927 if in_idle(): return
1928 self._top.mainloop(*args, **kwargs)
1929
1930 ##//////////////////////////////////////////////////////
1931 ## Entry dialog
1932 ##//////////////////////////////////////////////////////
1933
1935 """
1936 A dialog box for entering
1937 """
1938 - def __init__(self, parent, original_text='', instructions='',
1939 set_callback=None, title=None):
1940 self._parent = parent
1941 self._original_text = original_text
1942 self._set_callback = set_callback
1943
1944 width = max(30, len(original_text)*3/2)
1945 self._top = Toplevel(parent)
1946
1947 if title: self._top.title(title)
1948
1949 # The text entry box.
1950 entryframe = Frame(self._top)
1951 entryframe.pack(expand=1, fill='both', padx=5, pady=5,ipady=10)
1952 if instructions:
1953 l=Label(entryframe, text=instructions)
1954 l.pack(side='top', anchor='w', padx=30)
1955 self._entry = Entry(entryframe, width=width)
1956 self._entry.pack(expand=1, fill='x', padx=30)
1957 self._entry.insert(0, original_text)
1958
1959 # A divider
1960 divider = Frame(self._top, borderwidth=1, relief='sunken')
1961 divider.pack(fill='x', ipady=1, padx=10)
1962
1963 # The buttons.
1964 buttons = Frame(self._top)
1965 buttons.pack(expand=0, fill='x', padx=5, pady=5)
1966 b = Button(buttons, text='Cancel', command=self._cancel, width=8)
1967 b.pack(side='right', padx=5)
1968 b = Button(buttons, text='Ok', command=self._ok,
1969 width=8, default='active')
1970 b.pack(side='left', padx=5)
1971 b = Button(buttons, text='Apply', command=self._apply, width=8)
1972 b.pack(side='left')
1973
1974 self._top.bind('<Return>', self._ok)
1975 self._top.bind('<Control-q>', self._cancel)
1976 self._top.bind('<Escape>', self._cancel)
1977
1978 self._entry.focus()
1979
1981 self._entry.delete(0,'end')
1982 self._entry.insert(0, self._original_text)
1983 if self._set_callback:
1984 self._set_callback(self._original_text)
1985
1990
1994
1998
2003
2004 ##//////////////////////////////////////////////////////
2005 ## Colorized List
2006 ##//////////////////////////////////////////////////////
2007
2009 """
2010 An abstract base class for displaying a colorized list of items.
2011 Subclasses should define:
2012 - L{_init_colortags}, which sets up Text color tags that
2013 will be used by the list.
2014 - L{_item_repr}, which returns a list of (text,colortag)
2015 tuples that make up the colorized representation of the
2016 item.
2017 @note: Typically, you will want to register a callback for
2018 C{'select'} that calls L{mark} on the given item.
2019 """
2021 """
2022 Construct a new list.
2023
2024 @param parent: The Tk widget that contains the colorized list
2025 @param items: The initial contents of the colorized list.
2026 @param options:
2027 """
2028 self._parent = parent
2029 self._callbacks = {}
2030
2031 # Which items are marked?
2032 self._marks = {}
2033
2034 # Initialize the Tkinter frames.
2035 self._init_itemframe(options.copy())
2036
2037 # Set up key & mouse bindings.
2038 self._textwidget.bind('<KeyPress>', self._keypress)
2039 self._textwidget.bind('<ButtonPress>', self._buttonpress)
2040
2041 # Fill in the given CFG's items.
2042 self._items = None
2043 self.set(items)
2044
2045 #////////////////////////////////////////////////////////////
2046 # Abstract methods
2047 #////////////////////////////////////////////////////////////
2048
2056
2058 """
2059 Return a list of (text, colortag) tuples that make up the
2060 colorized representation of the item. Colorized
2061 representations may not span multiple lines. I.e., the text
2062 strings returned may not contain newline characters.
2063 """
2064 raise AssertionError, 'Abstract base class'
2065
2066 #////////////////////////////////////////////////////////////
2067 # Item Access
2068 #////////////////////////////////////////////////////////////
2069
2071 """
2072 @return: A list of the items contained by this list.
2073 """
2074 if index is None:
2075 return self._items[:]
2076 else:
2077 return self._items[index]
2078
2080 """
2081 Modify the list of items contained by this list.
2082 """
2083 items = list(items)
2084 if self._items == items: return
2085 self._items = list(items)
2086
2087 self._textwidget['state'] = 'normal'
2088 self._textwidget.delete('1.0', 'end')
2089 for item in items:
2090 for (text, colortag) in self._item_repr(item):
2091 assert '\n' not in text, 'item repr may not contain newline'
2092 self._textwidget.insert('end', text, colortag)
2093 self._textwidget.insert('end', '\n')
2094 # Remove the final newline
2095 self._textwidget.delete('end-1char', 'end')
2096 self._textwidget.mark_set('insert', '1.0')
2097 self._textwidget['state'] = 'disabled'
2098 # Clear all marks
2099 self._marks.clear()
2100
2102 """
2103 Remove highlighting from the given item; or from every item,
2104 if no item is given.
2105 @raise ValueError: If C{item} is not contained in the list.
2106 @raise KeyError: If C{item} is not marked.
2107 """
2108 if item is None:
2109 self._marks.clear()
2110 self._textwidget.tag_remove('highlight', '1.0', 'end+1char')
2111 else:
2112 index = self._items.index(item)
2113 del self._marks[item]
2114 (start, end) = ('%d.0' % (index+1), '%d.0' % (index+2))
2115 self._textwidget.tag_remove('highlight', start, end)
2116
2118 """
2119 Highlight the given item.
2120 @raise ValueError: If C{item} is not contained in the list.
2121 """
2122 self._marks[item] = 1
2123 index = self._items.index(item)
2124 (start, end) = ('%d.0' % (index+1), '%d.0' % (index+2))
2125 self._textwidget.tag_add('highlight', start, end)
2126
2128 """
2129 Remove any current highlighting, and mark the given item.
2130 @raise ValueError: If C{item} is not contained in the list.
2131 """
2132 self.unmark()
2133 self.mark(item)
2134
2136 """
2137 Adjust the view such that the given item is visible. If
2138 the item is already visible, then do nothing.
2139 """
2140 index = self._items.index(item)
2141 self._textwidget.see('%d.0' % (index+1))
2142
2143 #////////////////////////////////////////////////////////////
2144 # Callbacks
2145 #////////////////////////////////////////////////////////////
2146
2148 """
2149 Register a callback function with the list. This function
2150 will be called whenever the given event occurs.
2151
2152 @param event: The event that will trigger the callback
2153 function. Valid events are: click1, click2, click3,
2154 space, return, select, up, down, next, prior, move
2155 @param func: The function that should be called when
2156 the event occurs. C{func} will be called with a
2157 single item as its argument. (The item selected
2158 or the item moved to).
2159 """
2160 if event == 'select': events = ['click1', 'space', 'return']
2161 elif event == 'move': events = ['up', 'down', 'next', 'prior']
2162 else: events = [event]
2163
2164 for e in events:
2165 self._callbacks.setdefault(e,{})[func] = 1
2166
2168 """
2169 Deregister a callback function. If C{func} is none, then
2170 all callbacks are removed for the given event.
2171 """
2172 if event is None: events = self._callbacks.keys()
2173 elif event == 'select': events = ['click1', 'space', 'return']
2174 elif event == 'move': events = ['up', 'down', 'next', 'prior']
2175 else: events = [event]
2176
2177 for e in events:
2178 if func is None: del self._callbacks[e]
2179 else:
2180 try: del self._callbacks[e][func]
2181 except: pass
2182
2183 #////////////////////////////////////////////////////////////
2184 # Tkinter Methods
2185 #////////////////////////////////////////////////////////////
2186
2190
2194
2198
2199 #////////////////////////////////////////////////////////////
2200 # Internal Methods
2201 #////////////////////////////////////////////////////////////
2202
2204 self._itemframe = Frame(self._parent)
2205
2206 # Create the basic Text widget & scrollbar.
2207 options.setdefault('background', '#e0e0e0')
2208 self._textwidget = Text(self._itemframe, **options)
2209 self._textscroll = Scrollbar(self._itemframe, takefocus=0,
2210 orient='vertical')
2211 self._textwidget.config(yscrollcommand = self._textscroll.set)
2212 self._textscroll.config(command=self._textwidget.yview)
2213 self._textscroll.pack(side='right', fill='y')
2214 self._textwidget.pack(expand=1, fill='both', side='left')
2215
2216 # Initialize the colorization tags
2217 self._textwidget.tag_config('highlight', background='#e0ffff',
2218 border='1', relief='raised')
2219 self._init_colortags(self._textwidget, options)
2220
2221 # How do I want to mark keyboard selection?
2222 self._textwidget.tag_config('sel', foreground='')
2223 self._textwidget.tag_config('sel', foreground='', background='',
2224 border='', underline=1)
2225 self._textwidget.tag_lower('highlight', 'sel')
2226
2228 if not self._callbacks.has_key(event): return
2229 if 0 <= itemnum < len(self._items):
2230 item = self._items[itemnum]
2231 else:
2232 item = None
2233 for cb_func in self._callbacks[event].keys():
2234 cb_func(item)
2235
2241
2243 if event.keysym == 'Return' or event.keysym == 'space':
2244 insert_point = self._textwidget.index('insert')
2245 itemnum = int(insert_point.split('.')[0])-1
2246 self._fire_callback(event.keysym.lower(), itemnum)
2247 return
2248 elif event.keysym == 'Down': delta='+1line'
2249 elif event.keysym == 'Up': delta='-1line'
2250 elif event.keysym == 'Next': delta='+10lines'
2251 elif event.keysym == 'Prior': delta='-10lines'
2252 else: return 'continue'
2253
2254 self._textwidget.mark_set('insert', 'insert'+delta)
2255 self._textwidget.see('insert')
2256 self._textwidget.tag_remove('sel', '1.0', 'end+1char')
2257 self._textwidget.tag_add('sel', 'insert linestart', 'insert lineend')
2258
2259 insert_point = self._textwidget.index('insert')
2260 itemnum = int(insert_point.split('.')[0])-1
2261 self._fire_callback(event.keysym.lower(), itemnum)
2262
2263 return 'break'
2264
2265 ##//////////////////////////////////////////////////////
2266 ## Improved OptionMenu
2267 ##//////////////////////////////////////////////////////
2268
2271 self._callback = options.get('command')
2272 if 'command' in options: del options['command']
2273
2274 # Create a variable
2275 self._variable = variable = StringVar()
2276 if len(values) > 0:
2277 variable.set(values[0])
2278
2279 kw = {"borderwidth": 2, "textvariable": variable,
2280 "indicatoron": 1, "relief": RAISED, "anchor": "c",
2281 "highlightthickness": 2}
2282 kw.update(options)
2283 Widget.__init__(self, master, "menubutton", kw)
2284 self.widgetName = 'tk_optionMenu'
2285 self._menu = Menu(self, name="menu", tearoff=0,)
2286 self.menuname = self._menu._w
2287
2288 self._values = []
2289 for value in values: self.add(value)
2290
2291 self["menu"] = self._menu
2292
2294 if value in self._values: return
2295 def set(value=value): self.set(value)
2296 self._menu.add_command(label=value, command=set)
2297 self._values.append(value)
2298
2303
2305 # Might raise indexerror: pass to parent.
2306 i = self._values.index(value)
2307 del self._values[i]
2308 self._menu.delete(i, i)
2309
2314
2316 """Destroy this widget and the associated menu."""
2317 Menubutton.destroy(self)
2318 self._menu = None
2319
2320 ##//////////////////////////////////////////////////////
2321 ## Helpers
2322 ##//////////////////////////////////////////////////////
2323
2325 """
2326 @rtype: C{boolean}
2327 @return: true if this function is run within idle. Tkinter
2328 programs that are run in idle should never call C{Tk.mainloop}; so
2329 this function should be used to gate all calls to C{Tk.mainloop}.
2330
2331 @warning: This function works by checking C{sys.stdin}. If the
2332 user has modified C{sys.stdin}, then it may return incorrect
2333 results.
2334 """
2335 import sys, types
2336 return (type(sys.stdin) == types.InstanceType and \
2337 sys.stdin.__class__.__name__ == 'PyShell')
2338
2339 ##//////////////////////////////////////////////////////
2340 ## Test code.
2341 ##//////////////////////////////////////////////////////
2342
2350 def color(cw):
2351 from random import randint
2352 cw['color'] = '#ff%04d' % randint(0,9999)
2353
2354 cf = CanvasFrame(closeenough=10, width=300, height=300)
2355 c = cf.canvas()
2356 ct3 = TextWidget(c, 'hiya there', draggable=1)
2357 ct2 = TextWidget(c, 'o o\n||\n___\n U', draggable=1, justify='center')
2358 co = OvalWidget(c, ct2, outline='red')
2359 ct = TextWidget(c, 'o o\n||\n\\___/', draggable=1, justify='center')
2360 cp = ParenWidget(c, ct, color='red')
2361 cb = BoxWidget(c, cp, fill='cyan', draggable=1, width=3, margin=10)
2362 equation = SequenceWidget(c,
2363 SymbolWidget(c, 'forall'), TextWidget(c, 'x'),
2364 SymbolWidget(c, 'exists'), TextWidget(c, 'y: '),
2365 TextWidget(c, 'x'), SymbolWidget(c, 'notequal'),
2366 TextWidget(c, 'y'))
2367 space = SpaceWidget(c, 0, 30)
2368 cstack = StackWidget(c, cb, ct3, space, co, equation, align='center')
2369 foo = TextWidget(c, 'try clicking\nand dragging',
2370 draggable=1, justify='center')
2371 cs = SequenceWidget(c, cstack, foo)
2372 zz = BracketWidget(c, cs, color='green4', width=3)
2373 cf.add_widget(zz, 60, 30)
2374
2375 cb.bind_click(fill)
2376 ct.bind_click(color)
2377 co.bind_click(fill)
2378 ct2.bind_click(color)
2379 ct3.bind_click(color)
2380
2381 cf.mainloop()
2382 #ShowText(None, 'title', ((('this is text'*150)+'\n')*5))
2383
2384 if __name__ == '__main__':
2385 demo()
2386
2387 from cfg import *
2388 from chart import *
2389 from plot import *
2390 from rdparser import *
2391 from srparser import *
2392 from tree import *
2393 from dispersion import dispersion_plot
2394 from rechunkparser import RegexpChunkDemo
2395 from concordance import pos_concordance
2396
2397 # Make sure that nltk.draw.cfg and nltk.draw.tree refer to the correct
2398 # modules (and not to nltk.cfg & nltk.tree)
2399 import cfg, tree
2400
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0beta1 on Wed Aug 27 15:09:07 2008 | http://epydoc.sourceforge.net |