~ubuntu-branches/ubuntu/gutsy/amsn/gutsy

« back to all changes in this revision

Viewing changes to utils/BWidget-1.7.0/utils.tcl

  • Committer: Bazaar Package Importer
  • Author(s): Theodore Karkoulis
  • Date: 2006-01-04 15:26:02 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104152602-ipe1yg00rl3nlklv
Tags: 0.95-1
New Upstream Release (closes: #345052, #278575).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# ----------------------------------------------------------------------------
 
2
#  utils.tcl
 
3
#  This file is part of Unifix BWidget Toolkit
 
4
#  $Id: utils.tcl,v 1.1 2004/12/03 00:31:24 tjikkun Exp $
 
5
# ----------------------------------------------------------------------------
 
6
#  Index of commands:
 
7
#     - GlobalVar::exists
 
8
#     - GlobalVar::setvarvar
 
9
#     - GlobalVar::getvarvar
 
10
#     - BWidget::assert
 
11
#     - BWidget::clonename
 
12
#     - BWidget::get3dcolor
 
13
#     - BWidget::XLFDfont
 
14
#     - BWidget::place
 
15
#     - BWidget::grab
 
16
#     - BWidget::focus
 
17
# ----------------------------------------------------------------------------
 
18
 
 
19
namespace eval GlobalVar {
 
20
    proc use {} {}
 
21
}
 
22
 
 
23
 
 
24
namespace eval BWidget {
 
25
    variable _top
 
26
    variable _gstack {}
 
27
    variable _fstack {}
 
28
    proc use {} {}
 
29
}
 
30
 
 
31
 
 
32
# ----------------------------------------------------------------------------
 
33
#  Command GlobalVar::exists
 
34
# ----------------------------------------------------------------------------
 
35
proc GlobalVar::exists { varName } {
 
36
    return [uplevel \#0 [list info exists $varName]]
 
37
}
 
38
 
 
39
 
 
40
# ----------------------------------------------------------------------------
 
41
#  Command GlobalVar::setvar
 
42
# ----------------------------------------------------------------------------
 
43
proc GlobalVar::setvar { varName value } {
 
44
    return [uplevel \#0 [list set $varName $value]]
 
45
}
 
46
 
 
47
 
 
48
# ----------------------------------------------------------------------------
 
49
#  Command GlobalVar::getvar
 
50
# ----------------------------------------------------------------------------
 
51
proc GlobalVar::getvar { varName } {
 
52
    return [uplevel \#0 [list set $varName]]
 
53
}
 
54
 
 
55
 
 
56
# ----------------------------------------------------------------------------
 
57
#  Command GlobalVar::tracevar
 
58
# ----------------------------------------------------------------------------
 
59
proc GlobalVar::tracevar { cmd varName args } {
 
60
    return [uplevel \#0 [list trace $cmd $varName] $args]
 
61
}
 
62
 
 
63
 
 
64
 
 
65
# ----------------------------------------------------------------------------
 
66
#  Command BWidget::lreorder
 
67
# ----------------------------------------------------------------------------
 
68
proc BWidget::lreorder { list neworder } {
 
69
    set pos     0
 
70
    set newlist {}
 
71
    foreach e $neworder {
 
72
        if { [lsearch -exact $list $e] != -1 } {
 
73
            lappend newlist $e
 
74
            set tabelt($e)  1
 
75
        }
 
76
    }
 
77
    set len [llength $newlist]
 
78
    if { !$len } {
 
79
        return $list
 
80
    }
 
81
    if { $len == [llength $list] } {
 
82
        return $newlist
 
83
    }
 
84
    set pos 0
 
85
    foreach e $list {
 
86
        if { ![info exists tabelt($e)] } {
 
87
            set newlist [linsert $newlist $pos $e]
 
88
        }
 
89
        incr pos
 
90
    }
 
91
    return $newlist
 
92
}
 
93
 
 
94
 
 
95
# ----------------------------------------------------------------------------
 
96
#  Command BWidget::assert
 
97
# ----------------------------------------------------------------------------
 
98
proc BWidget::assert { exp {msg ""}} {
 
99
    set res [uplevel 1 expr $exp]
 
100
    if { !$res} {
 
101
        if { $msg == "" } {
 
102
            return -code error "Assertion failed: {$exp}"
 
103
        } else {
 
104
            return -code error $msg
 
105
        }
 
106
    }
 
107
}
 
108
 
 
109
 
 
110
# ----------------------------------------------------------------------------
 
111
#  Command BWidget::clonename
 
112
# ----------------------------------------------------------------------------
 
113
proc BWidget::clonename { menu } {
 
114
    set path     ""
 
115
    set menupath ""
 
116
    set found    0
 
117
    foreach widget [lrange [split $menu "."] 1 end] {
 
118
        if { $found || [winfo class "$path.$widget"] == "Menu" } {
 
119
            set found 1
 
120
            append menupath "#" $widget
 
121
            append path "." $menupath
 
122
        } else {
 
123
            append menupath "#" $widget
 
124
            append path "." $widget
 
125
        }
 
126
    }
 
127
    return $path
 
128
}
 
129
 
 
130
 
 
131
# ----------------------------------------------------------------------------
 
132
#  Command BWidget::getname
 
133
# ----------------------------------------------------------------------------
 
134
proc BWidget::getname { name } {
 
135
    if { [string length $name] } {
 
136
        set text [option get . "${name}Name" ""]
 
137
        if { [string length $text] } {
 
138
            return [parsetext $text]
 
139
        }
 
140
    }
 
141
    return {}
 
142
 }
 
143
 
 
144
 
 
145
# ----------------------------------------------------------------------------
 
146
#  Command BWidget::parsetext
 
147
# ----------------------------------------------------------------------------
 
148
proc BWidget::parsetext { text } {
 
149
    set result ""
 
150
    set index  -1
 
151
    set start  0
 
152
    while { [string length $text] } {
 
153
        set idx [string first "&" $text]
 
154
        if { $idx == -1 } {
 
155
            append result $text
 
156
            set text ""
 
157
        } else {
 
158
            set char [string index $text [expr {$idx+1}]]
 
159
            if { $char == "&" } {
 
160
                append result [string range $text 0 $idx]
 
161
                set    text   [string range $text [expr {$idx+2}] end]
 
162
                set    start  [expr {$start+$idx+1}]
 
163
            } else {
 
164
                append result [string range $text 0 [expr {$idx-1}]]
 
165
                set    text   [string range $text [expr {$idx+1}] end]
 
166
                incr   start  $idx
 
167
                set    index  $start
 
168
            }
 
169
        }
 
170
    }
 
171
    return [list $result $index]
 
172
}
 
173
 
 
174
 
 
175
# ----------------------------------------------------------------------------
 
176
#  Command BWidget::get3dcolor
 
177
# ----------------------------------------------------------------------------
 
178
proc BWidget::get3dcolor { path bgcolor } {
 
179
    foreach val [winfo rgb $path $bgcolor] {
 
180
        lappend dark [expr {60*$val/100}]
 
181
        set tmp1 [expr {14*$val/10}]
 
182
        if { $tmp1 > 65535 } {
 
183
            set tmp1 65535
 
184
        }
 
185
        set tmp2 [expr {(65535+$val)/2}]
 
186
        lappend light [expr {($tmp1 > $tmp2) ? $tmp1:$tmp2}]
 
187
    }
 
188
    return [list [eval format "#%04x%04x%04x" $dark] [eval format "#%04x%04x%04x" $light]]
 
189
}
 
190
 
 
191
 
 
192
# ----------------------------------------------------------------------------
 
193
#  Command BWidget::XLFDfont
 
194
# ----------------------------------------------------------------------------
 
195
proc BWidget::XLFDfont { cmd args } {
 
196
    switch -- $cmd {
 
197
        create {
 
198
            set font "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"
 
199
        }
 
200
        configure {
 
201
            set font [lindex $args 0]
 
202
            set args [lrange $args 1 end]
 
203
        }
 
204
        default {
 
205
            return -code error "XLFDfont: commande incorrect: $cmd"
 
206
        }
 
207
    }
 
208
    set lfont [split $font "-"]
 
209
    if { [llength $lfont] != 15 } {
 
210
        return -code error "XLFDfont: description XLFD incorrect: $font"
 
211
    }
 
212
 
 
213
    foreach {option value} $args {
 
214
        switch -- $option {
 
215
            -foundry { set index 1 }
 
216
            -family  { set index 2 }
 
217
            -weight  { set index 3 }
 
218
            -slant   { set index 4 }
 
219
            -size    { set index 7 }
 
220
            default  { return -code error "XLFDfont: option incorrecte: $option" }
 
221
        }
 
222
        set lfont [lreplace $lfont $index $index $value]
 
223
    }
 
224
    return [join $lfont "-"]
 
225
}
 
226
 
 
227
 
 
228
 
 
229
# ----------------------------------------------------------------------------
 
230
#  Command BWidget::place
 
231
# ----------------------------------------------------------------------------
 
232
#
 
233
# Notes:
 
234
#  For Windows systems with more than one monitor the available screen area may
 
235
#  have negative positions. Geometry settings with negative numbers are used
 
236
#  under X to place wrt the right or bottom of the screen. On windows, Tk
 
237
#  continues to do this. However, a geometry such as 100x100+-200-100 can be
 
238
#  used to place a window onto a secondary monitor. Passing the + gets Tk
 
239
#  to pass the remainder unchanged so the Windows manager then handles -200
 
240
#  which is a position on the left hand monitor.
 
241
#  I've tested this for left, right, above and below the primary monitor.
 
242
#  Currently there is no way to ask Tk the extent of the Windows desktop in 
 
243
#  a multi monitor system. Nor what the legal co-ordinate range might be.
 
244
#
 
245
proc BWidget::place { path w h args } {
 
246
    variable _top
 
247
 
 
248
    update idletasks
 
249
    set reqw [winfo reqwidth  $path]
 
250
    set reqh [winfo reqheight $path]
 
251
    if { $w == 0 } {set w $reqw}
 
252
    if { $h == 0 } {set h $reqh}
 
253
 
 
254
    set arglen [llength $args]
 
255
    if { $arglen > 3 } {
 
256
        return -code error "BWidget::place: bad number of argument"
 
257
    }
 
258
 
 
259
    if { $arglen > 0 } {
 
260
        set where [lindex $args 0]
 
261
        set list  [list "at" "center" "left" "right" "above" "below"]
 
262
        set idx   [lsearch $list $where]
 
263
        if { $idx == -1 } {
 
264
            return -code error [BWidget::badOptionString position $where $list]
 
265
        }
 
266
        if { $idx == 0 } {
 
267
            set err [catch {
 
268
                # purposely removed the {} around these expressions - [PT]
 
269
                set x [expr int([lindex $args 1])]
 
270
                set y [expr int([lindex $args 2])]
 
271
            }]
 
272
            if { $err } {
 
273
                return -code error "BWidget::place: incorrect position"
 
274
            }
 
275
            if {$::tcl_platform(platform) == "windows"} {
 
276
                # handle windows multi-screen. -100 != +-100
 
277
                if {[string index [lindex $args 1] 0] != "-"} {
 
278
                    set x "+$x"
 
279
                }
 
280
                if {[string index [lindex $args 2] 0] != "-"} {
 
281
                    set y "+$y"
 
282
                }
 
283
            } else {
 
284
                if { $x >= 0 } {
 
285
                    set x "+$x"
 
286
                }
 
287
                if { $y >= 0 } {
 
288
                    set y "+$y"
 
289
                }
 
290
            }
 
291
        } else {
 
292
            if { $arglen == 2 } {
 
293
                set widget [lindex $args 1]
 
294
                if { ![winfo exists $widget] } {
 
295
                    return -code error "BWidget::place: \"$widget\" does not exist"
 
296
                }
 
297
            } else {
 
298
                set widget .
 
299
            }
 
300
            set sw [winfo screenwidth  $path]
 
301
            set sh [winfo screenheight $path]
 
302
            if { $idx == 1 } {
 
303
                if { $arglen == 2 } {
 
304
                    # center to widget
 
305
                    set x0 [expr {[winfo rootx $widget] + ([winfo width  $widget] - $w)/2}]
 
306
                    set y0 [expr {[winfo rooty $widget] + ([winfo height $widget] - $h)/2}]
 
307
                } else {
 
308
                    # center to screen
 
309
                    set x0 [expr {([winfo screenwidth  $path] - $w)/2 - [winfo vrootx $path]}]
 
310
                    set y0 [expr {([winfo screenheight $path] - $h)/2 - [winfo vrooty $path]}]
 
311
                }
 
312
                set x "+$x0"
 
313
                set y "+$y0"
 
314
                if {$::tcl_platform(platform) != "windows"} {
 
315
                    if { $x0+$w > $sw } {set x "-0"; set x0 [expr {$sw-$w}]}
 
316
                    if { $x0 < 0 }      {set x "+0"}
 
317
                    if { $y0+$h > $sh } {set y "-0"; set y0 [expr {$sh-$h}]}
 
318
                    if { $y0 < 0 }      {set y "+0"}
 
319
                }
 
320
            } else {
 
321
                set x0 [winfo rootx $widget]
 
322
                set y0 [winfo rooty $widget]
 
323
                set x1 [expr {$x0 + [winfo width  $widget]}]
 
324
                set y1 [expr {$y0 + [winfo height $widget]}]
 
325
                if { $idx == 2 || $idx == 3 } {
 
326
                    set y "+$y0"
 
327
                    if {$::tcl_platform(platform) != "windows"} {
 
328
                        if { $y0+$h > $sh } {set y "-0"; set y0 [expr {$sh-$h}]}
 
329
                        if { $y0 < 0 }      {set y "+0"}
 
330
                    }
 
331
                    if { $idx == 2 } {
 
332
                        # try left, then right if out, then 0 if out
 
333
                        if { $x0 >= $w } {
 
334
                            set x "+[expr {$x0-$sw}]"
 
335
                        } elseif { $x1+$w <= $sw } {
 
336
                            set x "+$x1"
 
337
                        } else {
 
338
                            set x "+0"
 
339
                        }
 
340
                    } else {
 
341
                        # try right, then left if out, then 0 if out
 
342
                        if { $x1+$w <= $sw } {
 
343
                            set x "+$x1"
 
344
                        } elseif { $x0 >= $w } {
 
345
                            set x "+[expr {$x0-$sw}]"
 
346
                        } else {
 
347
                            set x "-0"
 
348
                        }
 
349
                    }
 
350
                } else {
 
351
                    set x "+$x0"
 
352
                    if {$::tcl_platform(platform) != "windows"} {
 
353
                        if { $x0+$w > $sw } {set x "-0"; set x0 [expr {$sw-$w}]}
 
354
                        if { $x0 < 0 }      {set x "+0"}
 
355
                    }
 
356
                    if { $idx == 4 } {
 
357
                        # try top, then bottom, then 0
 
358
                        if { $h <= $y0 } {
 
359
                            set y "+[expr {$y0-$sh}]"
 
360
                        } elseif { $y1+$h <= $sh } {
 
361
                            set y "+$y1"
 
362
                        } else {
 
363
                            set y "+0"
 
364
                        }
 
365
                    } else {
 
366
                        # try bottom, then top, then 0
 
367
                        if { $y1+$h <= $sh } {
 
368
                            set y "+$y1"
 
369
                        } elseif { $h <= $y0 } {
 
370
                            set y "+[expr {$y0-$sh}]"
 
371
                        } else {
 
372
                            set y "-0"
 
373
                        }
 
374
                    }
 
375
                }
 
376
            }
 
377
        }
 
378
        wm geometry $path "${w}x${h}${x}${y}"
 
379
    } else {
 
380
        wm geometry $path "${w}x${h}"
 
381
    }
 
382
    update idletasks
 
383
}
 
384
 
 
385
 
 
386
# ----------------------------------------------------------------------------
 
387
#  Command BWidget::grab
 
388
# ----------------------------------------------------------------------------
 
389
proc BWidget::grab { option path } {
 
390
    variable _gstack
 
391
 
 
392
    if { $option == "release" } {
 
393
        catch {::grab release $path}
 
394
        while { [llength $_gstack] } {
 
395
            set grinfo  [lindex $_gstack end]
 
396
            set _gstack [lreplace $_gstack end end]
 
397
            foreach {oldg mode} $grinfo {
 
398
                if { ![string equal $oldg $path] && [winfo exists $oldg] } {
 
399
                    if { $mode == "global" } {
 
400
                        catch {::grab -global $oldg}
 
401
                    } else {
 
402
                        catch {::grab $oldg}
 
403
                    }
 
404
                    return
 
405
                }
 
406
            }
 
407
        }
 
408
    } else {
 
409
        set oldg [::grab current]
 
410
        if { $oldg != "" } {
 
411
            lappend _gstack [list $oldg [::grab status $oldg]]
 
412
        }
 
413
        if { $option == "global" } {
 
414
            ::grab -global $path
 
415
        } else {
 
416
            ::grab $path
 
417
        }
 
418
    }
 
419
}
 
420
 
 
421
 
 
422
# ----------------------------------------------------------------------------
 
423
#  Command BWidget::focus
 
424
# ----------------------------------------------------------------------------
 
425
proc BWidget::focus { option path {refocus 1} } {
 
426
    variable _fstack
 
427
 
 
428
    if { $option == "release" } {
 
429
        while { [llength $_fstack] } {
 
430
            set oldf [lindex $_fstack end]
 
431
            set _fstack [lreplace $_fstack end end]
 
432
            if { ![string equal $oldf $path] && [winfo exists $oldf] } {
 
433
                if {$refocus} {catch {::focus -force $oldf}}
 
434
                return
 
435
            }
 
436
        }
 
437
    } elseif { $option == "set" } {
 
438
        lappend _fstack [::focus]
 
439
        ::focus -force $path
 
440
    }
 
441
}
 
442
 
 
443
# BWidget::refocus --
 
444
#
 
445
#       Helper function used to redirect focus from a container frame in 
 
446
#       a megawidget to a component widget.  Only redirects focus if
 
447
#       focus is already on the container.
 
448
#
 
449
# Arguments:
 
450
#       container       container widget to redirect from.
 
451
#       component       component widget to redirect to.
 
452
#
 
453
# Results:
 
454
#       None.
 
455
 
 
456
proc BWidget::refocus {container component} {
 
457
    if { [string equal $container [::focus]] } {
 
458
        ::focus $component
 
459
    }
 
460
    return
 
461
}
 
462
 
 
463
# BWidget::badOptionString --
 
464
#
 
465
#       Helper function to return a proper error string when an option
 
466
#       doesn't match a list of given options.
 
467
#
 
468
# Arguments:
 
469
#       type    A string that represents the type of option.
 
470
#       value   The value that is in-valid.
 
471
#       list    A list of valid options.
 
472
#
 
473
# Results:
 
474
#       None.
 
475
proc BWidget::badOptionString {type value list} {
 
476
    set last [lindex $list end]
 
477
    set list [lreplace $list end end]
 
478
    return "bad $type \"$value\": must be [join $list ", "], or $last"
 
479
}
 
480
 
 
481
 
 
482
proc BWidget::wrongNumArgsString { string } {
 
483
    return "wrong # args: should be \"$string\""
 
484
}
 
485
 
 
486
 
 
487
proc BWidget::read_file { file } {
 
488
    set fp [open $file]
 
489
    set x  [read $fp [file size $file]]
 
490
    close $fp
 
491
    return $x
 
492
}
 
493
 
 
494
 
 
495
proc BWidget::classes { class } {
 
496
    variable use
 
497
 
 
498
    ${class}::use
 
499
    set classes [list $class]
 
500
    if {![info exists use($class)]} { return }
 
501
    foreach class $use($class) {
 
502
        eval lappend classes [classes $class]
 
503
    }
 
504
    return [lsort -unique $classes]
 
505
}
 
506
 
 
507
 
 
508
proc BWidget::library { args } {
 
509
    variable use
 
510
 
 
511
    set libs    [list widget init utils]
 
512
    set classes [list]
 
513
    foreach class $args {
 
514
        ${class}::use
 
515
        eval lappend classes [classes $class]
 
516
    }
 
517
 
 
518
    eval lappend libs [lsort -unique $classes]
 
519
 
 
520
    set library ""
 
521
    foreach lib $libs {
 
522
        if {![info exists use($lib,file)]} {
 
523
            set file [file join $::BWIDGET::LIBRARY $lib.tcl]
 
524
        } else {
 
525
            set file [file join $::BWIDGET::LIBRARY $use($lib,file).tcl]
 
526
        }
 
527
        append library [read_file $file]
 
528
    }
 
529
 
 
530
    return $library
 
531
}
 
532
 
 
533
 
 
534
proc BWidget::inuse { class } {
 
535
    variable ::Widget::_inuse
 
536
 
 
537
    if {![info exists _inuse($class)]} { return 0 }
 
538
    return [expr $_inuse($class) > 0]
 
539
}
 
540
 
 
541
 
 
542
proc BWidget::write { filename {mode w} } {
 
543
    variable use
 
544
 
 
545
    if {![info exists use(classes)]} { return }
 
546
 
 
547
    set classes [list]
 
548
    foreach class $use(classes) {
 
549
        if {![inuse $class]} { continue }
 
550
        lappend classes $class
 
551
    }
 
552
 
 
553
    set fp [open $filename $mode]
 
554
    puts $fp [eval library $classes]
 
555
    close $fp
 
556
 
 
557
    return
 
558
}
 
559
 
 
560
 
 
561
# BWidget::bindMouseWheel --
 
562
#
 
563
#       Bind mouse wheel actions to a given widget.
 
564
#
 
565
# Arguments:
 
566
#       widget - The widget to bind.
 
567
#
 
568
# Results:
 
569
#       None.
 
570
proc BWidget::bindMouseWheel { widget } {
 
571
    bind $widget <MouseWheel>         {%W yview scroll [expr {-%D/24}]  units}
 
572
    bind $widget <Shift-MouseWheel>   {%W yview scroll [expr {-%D/120}] pages}
 
573
    bind $widget <Control-MouseWheel> {%W yview scroll [expr {-%D/120}] units}
 
574
 
 
575
    bind $widget <Button-4> {event generate %W <MouseWheel> -delta  120}
 
576
    bind $widget <Button-5> {event generate %W <MouseWheel> -delta -120}
 
577
}