source: trunk/gui/scripts/editor.tcl @ 1

Last change on this file since 1 was 1, checked in by mmc, 19 years ago

initial import

File size: 9.4 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: editor - pop-up editor for little bits of text
3#
4#  This widget acts as a pop-up editor for small text fields.  It
5#  pops up on top of any text field, accepts edits, and then attempts
6#  to validate and apply changes back to the underlying widget.
7#
8#  This widget uses a number of callbacks to handle communication
9#  with the underlying widget:
10#
11#  -activatecommand .... Should return a key/value list with the
12#                        following elements:
13#                          x ...... root x coordinate for editor
14#                          y ...... root y coordinate for editor
15#                          w ...... width of text being edited
16#                          h ...... height of text being edited
17#                          text ... initial text for the editor
18#
19#  -validatecommand .... Invoked with the new value as an argument.
20#                        Should return 1 if the value is okay, and
21#                        0 otherwise.
22#
23#  -applycommand ....... Invoked with the new value as an argument.
24#                        Should apply the new value to the underlying
25#                        widget.
26#
27# ======================================================================
28#  AUTHOR:  Michael McLennan, Purdue University
29#  Copyright (c) 2004  Purdue Research Foundation, West Lafayette, IN
30# ======================================================================
31package require Itk
32
33option add *Editor.background white widgetDefault
34option add *Editor.outline black widgetDefault
35option add *Editor.borderwidth 1 widgetDefault
36option add *Editor.relief flat widgetDefault
37option add *Editor.selectBorderWidth 0 widgetDefault
38
39itcl::class Rappture::Editor {
40    inherit itk::Toplevel
41
42    itk_option define -outline outline Outline ""
43    itk_option define -activatecommand activateCommand ActivateCommand ""
44    itk_option define -validatecommand validateCommand ValidateCommand ""
45    itk_option define -applycommand applyCommand ApplyCommand ""
46
47    constructor {args} { # defined below }
48
49    public method activate {}
50    public method deactivate {args}
51    public method value {newval}
52
53    protected method _click {x y}
54    protected method _resize {}
55    protected variable _loc   ;# array of editor location parameters
56}
57                                                                               
58itk::usual Editor {
59    keep -cursor -font
60}
61
62# ----------------------------------------------------------------------
63# CONSTRUCTOR
64# ----------------------------------------------------------------------
65itcl::body Rappture::Editor::constructor {args} {
66    wm overrideredirect $itk_component(hull) yes
67    wm withdraw $itk_component(hull)
68
69    itk_option remove hull.background hull.borderwidth
70    component hull configure -borderwidth 1
71
72    itk_component add editor {
73        entry $itk_interior.editor -highlightthickness 0
74    } {
75        usual
76        keep -relief
77        ignore -highlightthickness
78        ignore -highlightcolor
79        ignore -highlightbackground
80    }
81    pack $itk_component(editor) -expand yes -fill both
82
83    bind $itk_component(editor) <KeyPress> \
84        [itcl::code $this _resize]
85    bind $itk_component(editor) <KeyPress-Return> \
86        [itcl::code $this deactivate]
87    bind $itk_component(editor) <KeyPress-Escape> \
88        [itcl::code $this deactivate -abort]
89    bind $itk_component(editor) <ButtonPress> \
90        [itcl::code $this _click %X %Y]
91
92    eval itk_initialize $args
93}
94
95# ----------------------------------------------------------------------
96# USAGE: activate
97#
98# Clients use this to start the editing process on the underlying
99# widget.  This pops up the editor with the current text from the
100# underlying widget and allows the user to edit the text.  The editor
101# remains up until it is deactivated.
102# ----------------------------------------------------------------------
103itcl::body Rappture::Editor::activate {} {
104    set e $itk_component(editor)
105
106    set info ""
107    if {[string length $itk_option(-activatecommand)] > 0} {
108        set status [catch {uplevel #0 $itk_option(-activatecommand)} info]
109        if {$status != 0} {
110            bgerror $info
111            return
112        }
113    }
114
115    #
116    # Pull out the location information from the values passed back
117    # from the activation command.  We must have at least an x,y
118    # coordinate.  If we get width and height too, then use it.
119    # If not, figure out the width and height based on the size
120    # of the string.
121    #
122    array set vals $info
123    if {![info exists vals(x)] || ![info exists vals(y)]} {
124        return
125    }
126    set _loc(x) $vals(x)
127    set _loc(y) $vals(y)
128    set _loc(w) [expr {([info exists vals(w)]) ? $vals(w) : 0}]
129    set _loc(h) [expr {([info exists vals(h)]) ? $vals(h) : 0}]
130
131    $itk_component(editor) delete 0 end
132    if {[info exists vals(text)]} {
133        $itk_component(editor) insert end $vals(text)
134    }
135    $itk_component(editor) select from 0
136    $itk_component(editor) select to end
137
138    _resize
139    wm deiconify $itk_component(hull)
140    raise $itk_component(hull)
141    focus $itk_component(editor)
142
143    # try to grab the pointer, and keep trying...
144    update
145    while {[catch {grab set -global $itk_component(editor)}]} {
146        after 100
147    }
148}
149
150# ----------------------------------------------------------------------
151# USAGE: deactivate ?-abort?
152#
153# This is invoked automatically whenever the user presses Enter or
154# Escape in the editor.  Clients can also use it explicitly to
155# deactivate the editor.
156#
157# If the -abort flag is specified, then the editor is taken down
158# without any validation or application of the result.  Otherwise,
159# we validate the contents of the editor and apply the change back
160# to the widget.
161# ----------------------------------------------------------------------
162itcl::body Rappture::Editor::deactivate {args} {
163    # take down any error cue that might be up
164    ::Rappture::Tooltip::cue hide
165
166    if {$args == "-abort"} {
167        grab release $itk_component(editor)
168        wm withdraw $itk_component(hull)
169        return
170    }
171
172    set str [$itk_component(editor) get]
173
174    #
175    # If there's a -validatecommand option, then invoke the code
176    # now to check the new value.
177    #
178    if {[string length $itk_option(-validatecommand)] > 0} {
179        set cmd "uplevel #0 [list $itk_option(-validatecommand) [list $str]]"
180        if {[catch $cmd result]} {
181            bgerror $result
182            set result 1
183        }
184        if {$result == 0} {
185            bell
186            $itk_component(editor) select from 0
187            $itk_component(editor) select to end
188            $itk_component(editor) icursor end
189            focus $itk_component(editor)
190            return
191        }
192    }
193
194    grab release $itk_component(editor)
195    wm withdraw $itk_component(hull)
196
197    #
198    # If there's an -applycommand option, then invoke the code
199    # now to apply the new value.
200    #
201    if {[string length $itk_option(-applycommand)] > 0} {
202        set cmd "uplevel #0 [list $itk_option(-applycommand) [list $str]]"
203        if {[catch $cmd result]} {
204            bgerror $result
205            return
206        }
207    }
208}
209
210# ----------------------------------------------------------------------
211# USAGE: value <newval>
212#
213# Clients use this to suggest a new value, particular when they've
214# caught an error in the editing process.  For example, if the user's
215# value is below the minimum allowed value, a client would call this
216# method to suggest the minimum value.
217# ----------------------------------------------------------------------
218itcl::body Rappture::Editor::value {newval} {
219    $itk_component(editor) delete 0 end
220    $itk_component(editor) insert end $newval
221}
222
223# ----------------------------------------------------------------------
224# USAGE: _click <X> <Y>
225#
226# This is invoked automatically whenever the user clicks somewhere
227# inside or outside of the editor.  If the <X>,<Y> coordinate is
228# outside the editor, then we assume the user is done and wants to
229# take the editor down.  Otherwise, we do nothing, and let the entry
230# bindings take over.
231# ----------------------------------------------------------------------
232itcl::body Rappture::Editor::_click {x y} {
233    if {[winfo containing $x $y] != $itk_component(editor)} {
234        deactivate
235    }
236}
237
238# ----------------------------------------------------------------------
239# USAGE: _resize
240#
241# Invoked automatically as each key is pressed in the editor.
242# Resizes the editor so that it is just big enough to show all
243# of the text within it.
244# ----------------------------------------------------------------------
245itcl::body Rappture::Editor::_resize {} {
246    set e $itk_component(editor)
247    set str [$e get]
248    set fnt [$e cget -font]
249
250    set w [expr {[font measure $fnt $str]+20}]
251    set w [expr {($w < $_loc(w)) ? $_loc(w) : $w}]
252    if {$w+$_loc(x) >= [winfo screenwidth $e]} {
253        set w [expr {[winfo screenwidth $e]-$_loc(x)}]
254    }
255
256    set h [expr {[font metrics $fnt -linespace]+4}]
257    set h [expr {($h < $_loc(h)) ? $_loc(h) : $h}]
258    if {$h+$_loc(y) >= [winfo screenwidth $e]} {
259        set h [expr {[winfo screenwidth $e]-$_loc(y)}]
260    }
261
262    wm geometry $itk_component(hull) "${w}x${h}+$_loc(x)+$_loc(y)"
263}
264
265# ----------------------------------------------------------------------
266# CONFIGURATION OPTION: -outline
267# ----------------------------------------------------------------------
268itcl::configbody Rappture::Editor::outline {
269    component hull configure -background $itk_option(-outline)
270}
Note: See TracBrowser for help on using the repository browser.