File: dialog.tcl

package info (click to toggle)
moomps 4.6-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 2,444 kB
  • ctags: 2,307
  • sloc: tcl: 34,882; sh: 167; makefile: 91
file content (245 lines) | stat: -rw-r--r-- 10,817 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# copyright (C) 1997-2005 Jean-Luc Fontaine (mailto:jfontain@free.fr)
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu

# $Id: dialog.tcl,v 2.28 2005/01/02 00:45:07 jfontain Exp $


class dialogBox {}

proc dialogBox::dialogBox {this parentPath args} composite {[new toplevel $parentPath] $args} {
    set path $widget::($this,path)
    wm group $path .                                                 ;# for proper window manager (windowmaker for example) behavior
    wm withdraw $path        ;# hide the window till all contained widgets are created so we will be able to know its requested size
    composite::manage $this [new frame $path -relief sunken -borderwidth 1 -height 2] separator [new frame $path] buttons
    set buttons $composite::($this,buttons,path)
    composite::manage $this [new button $buttons -text [mc OK]] ok [new button $buttons -text [mc Cancel]] cancel\
        [new button $buttons -text [mc Help]] help [new button $buttons -text [mc Close]] close
    grid $composite::($this,separator,path) -column 0 -row 1 -sticky ew -pady 2
    grid $buttons -column 0 -row 2 -sticky nsew
    grid rowconfigure $path 0 -weight 1
    grid columnconfigure $path 0 -weight 1
    wm protocol $path WM_DELETE_WINDOW "dialogBox::close $this"
    composite::complete $this
}

proc dialogBox::~dialogBox {this} {
    if {[string length $composite::($this,-deletecommand)] > 0} {
        uplevel #0 $composite::($this,-deletecommand)                                       ;# always invoke command at global level
    }
}

proc dialogBox::options {this} {
    return [list\
        [list -buttons o]\
        [list -command {} {}]\
        [list -closecommand {} {}]\
        [list -default {} {}]\
        [list -deletecommand {} {}]\
        [list -die 1 1]\
        [list -enterreturn 1 1]\
        [list -grab local]\
        [list -helpcommand {} {}]\
        [list -labels {} {}]\
        [list -otherbuttons {} {}]\
        [list -title {Dialog box}]\
        [list -transient 1]\
        [list -x 0]\
        [list -y 0]\
    ]
}

proc dialogBox::set-buttons {this value} {
    set path $widget::($this,path)
    if {$composite::($this,complete)} {
        error {option -buttons cannot be set dynamically}
    }
    if {![regexp {^[chox]+$} $value]} {
        error "bad buttons value \"$value\": must be a combination of c, h, o and x"
    }
    if {[string first h $value] >= 0} {
        set button $composite::($this,help,path)
        pack $button -side left -expand 1 -pady 3 -padx 3
        widget::configure $composite::($this,help) -command "dialogBox::help $this"
        bind $path <KeyPress-F1> "$button configure -relief sunken"
        bind $path <KeyRelease-F1> "$button configure -relief raised; dialogBox::help $this"
    }
    set ok [expr {[string first o $value] >= 0}]
    if {$ok} {
        set button $composite::($this,ok,path)
        pack $button -side left -expand 1 -pady 3
        widget::configure $composite::($this,ok) -command "dialogBox::oked $this"
        updateOKBindings $this
    }
    set cancel [expr {[string first c $value] >= 0}]
    if {$cancel} {
        set button $composite::($this,cancel,path)
        pack $button -side left -expand 1 -pady 3
        widget::configure $composite::($this,cancel) -command "dialogBox::close $this"
        bind $path <KeyPress-Escape> "$button configure -relief sunken"
        bind $path <KeyRelease-Escape> "$button configure -relief raised; dialogBox::close $this"
    }
    if {[string first x $value] >= 0} {
        set button $composite::($this,close,path)
        pack $button -side left -expand 1 -pady 3
        widget::configure $composite::($this,close) -command "dialogBox::close $this"
        set keys {}
        if {!$ok} {
            foreach key {Return KP_Enter} {
                bind $path <KeyPress-$key> "$button configure -relief sunken"
                bind $path <KeyRelease-$key> "$button configure -relief raised; dialogBox::close $this 1"
            }
        }
        if {!$cancel} {
            bind $path <KeyPress-Escape> "$button configure -relief sunken"
            bind $path <KeyRelease-Escape> "$button configure -relief raised; dialogBox::close $this 1"
        }
    }
}

proc dialogBox::set-otherbuttons {this value} {
    if {$composite::($this,complete)} {
        error {option -default cannot be set dynamically}
    }
    set buttons $composite::($this,buttons,path)
    foreach name $value {
        composite::manage $this [new button $buttons -text $name] $name                        ;# user can change default text later
        pack $composite::($this,$name,path) -side left -expand 1 -pady 3 -padx 3
    }
}

proc dialogBox::set-default {this value} {                                                 ;# value is stored at the composite level
    if {$composite::($this,complete)} {
        error {option -default cannot be set dynamically}
    }
    switch $composite::($this,-default) {
        o {$composite::($this,ok,path) configure -default active}
        c {$composite::($this,cancel,path) configure -default active}
        x {$composite::($this,close,path) configure -default active}
        default {
            error "bad default value \"$value\": must be o, c or x"
        }
    }
}

proc dialogBox::set-command {this value} {}                                  ;# do nothing, values are stored at the composite level
# last chance to prevent dialog box closing. use a procedure that returns a boolean, true if closing is allowed:
proc dialogBox::set-closecommand {this value} {}
proc dialogBox::set-deletecommand {this value} {}
proc dialogBox::set-die {this value} {}
proc dialogBox::set-helpcommand {this value} {}

proc dialogBox::set-enterreturn {this value} {
    updateOKBindings $this
}

proc dialogBox::set-grab {this value} {
    switch $value {
        global {grab -global $widget::($this,path)}
        local {grab $widget::($this,path)}
        release {grab release $widget::($this,path)}
        default {
            error "bad grab value \"$value\": must be global, local or release"
        }
    }
}

proc dialogBox::set-title {this value} {
    wm title $widget::($this,path) $value
}

foreach option {-x -y} {
    proc dialogBox::set$option {this value} {
        if {[winfo ismapped $widget::($this,path)]} {
            place $this                            ;# if window if not visible, it will be positioned at the time it becomes visible
        }
    }
}

proc dialogBox::set-transient {this value} {
    if {$value} {
        wm transient $widget::($this,path) .
    } else {
        wm transient $widget::($this,path) {}
    }
}

proc dialogBox::set-labels {this value} {                                       ;# flat list of button code, label, button code, ...
    foreach {code label} $value {
        switch $code {
            c {composite::configure $this cancel -text $label}
            h {composite::configure $this help -text $label}
            o {composite::configure $this ok -text $label}
            x {composite::configure $this close -text $label}
            default {error "bad button code \"$code\": must be c, h, o or x"}
        }
    }
}

proc dialogBox::display {this path} {                                                ;# must be invoked for dialog box to be visible
    if {[string length $path] == 0} {                                                         ;# undisplay, remove related resources
        if {[info exists ($this,displayed)]} {
            grid forget $($this,displayed)
            unset ($this,displayed)
        }
        return
    }
    if {[info exists ($this,displayed)]} {
        error "a widget ($($this,displayed)) is already displayed"
    }
    set ($this,displayed) $path
    grid $path -in $widget::($this,path) -column 0 -row 0 -sticky nsew
    place $this
}

proc dialogBox::oked {this {enterOrReturn 0}} {                         ;# whether Enter or Return key is at the origin of the event
    if {\
        $enterOrReturn &&\
        (!$composite::($this,-enterreturn) || [string equal [widget::cget $composite::($this,ok) -state] disabled])\
    } return                                                                              ;# also do nothing when button is disabled
    if {[string length $composite::($this,-command)] > 0} {                          ;# invoke eventually command for the dialog box
        uplevel #0 $composite::($this,-command)                            ;# always invoke command at global level as tk buttons do
    }
    if {[info exists composite::($this,-die)] && $composite::($this,-die)} {
        delete $this                                                        ;# dialog box may already have been destroyed in command
    }
}

proc dialogBox::close {this {enterOrReturn 0}} {
    if {\
        $enterOrReturn &&\
        (!$composite::($this,-enterreturn) || [string equal [widget::cget $composite::($this,close) -state] disabled])\
    } return                                                                              ;# also do nothing when button is disabled
    if {([string length $composite::($this,-closecommand)] > 0) && ![uplevel #0 $composite::($this,-closecommand)]} return
    delete $this
}

proc dialogBox::place {this} {                                                          ;# make sure no part of widget is off screen
    update idletasks                                                                                 ;# make sure sizes are accurate
    set path $widget::($this,path)
    set x [minimum $composite::($this,-x) [expr {[winfo screenwidth $path] - [winfo reqwidth $path]}]]
    set y [minimum $composite::($this,-y) [expr {[winfo screenheight $path] - [winfo reqheight $path]}]]
    wm geometry $path +$x+$y
    wm deiconify $path                                                                                        ;# now show the window
}

proc dialogBox::help {this} {
    if {[string length $composite::($this,-helpcommand)] > 0} {                                    ;# eventually invoke help command
        uplevel #0 $composite::($this,-helpcommand)                        ;# always invoke command at global level as tk buttons do
    }
}

proc dialogBox::updateOKBindings {this} {
    set path $widget::($this,path)
    if {$composite::($this,-enterreturn)} {
        set button $composite::($this,ok,path)
        foreach key {Return KP_Enter} {
            bind $path <KeyPress-$key> "$button configure -relief sunken"
            bind $path <KeyRelease-$key> "$button configure -relief raised; dialogBox::oked $this 1"
        }
    } else {
        foreach key {Return KP_Enter} {
            bind $path <KeyPress-$key> {}
            bind $path <KeyRelease-$key> {}
        }
    }
}