-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathstatusbar.tcl
430 lines (380 loc) · 13.2 KB
/
statusbar.tcl
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# ----------------------------------------------------------------------------
# statusbar.tcl ---
# This file is part of Unifix BWidget Toolkit
# $Id: statusbar.tcl,v 1.91 2009/09/06 21:42:14 oberdorfer Exp $
# ----------------------------------------------------------------------------
# Create a status bar Tk widget
#
# Provides a status bar to be placed at the bottom of a toplevel.
# Currently does not support being placed in a toplevel that has
# gridding applied (via widget -setgrid or wm grid).
#
# Ensure that the widget is placed at the very bottom of the toplevel,
# otherwise the resize behavior may behave oddly.
# ------------------------------------------------------------------------
#
package require Tk 8.3
if {0} {
proc sample {} {
# sample usage
eval destroy [winfo children .]
pack [text .t -width 0 -height 0] -fill both -expand 1
set sbar .s
StatusBar $sbar
pack $sbar -side bottom -fill x
set f [$sbar getframe]
# Specify -width 1 for the label widget so it truncates nicely
# instead of requesting large sizes for long messages
set w [label $f.status -width 1 -anchor w -textvariable ::STATUS]
set ::STATUS "This is a status message"
# give the entry weight, as we want it to be the one that expands
$sbar add $w -weight 1
# BWidget's progressbar
set w [ProgressBar $f.bpbar -orient horizontal \
-variable ::PROGRESS -bd 1 -relief sunken]
set ::PROGRESS 50
$sbar add $w
}
}
namespace eval StatusBar {
Widget::define StatusBar statusbar
Widget::declare StatusBar {
{-background Color "SystemWindow" 0}
{-borderwidth TkResource 0 0 frame}
{-relief TkResource flat 0 frame}
{-showseparator Boolean 1 0}
{-showresizesep Boolean 0 0}
{-showresize Boolean 1 0}
{-width TkResource 100 0 frame}
{-height TkResource 18 0 frame}
{-ipad String 1 0}
{-pad String 0 0}
{-bg Synonym -background}
{-bd Synonym -borderwidth}
}
# -background, -borderwidth and -relief apply to outer frame, but relief
# should be left flat for proper look
Widget::addmap StatusBar "" :cmd {
-background {} -width {} -height {} -borderwidth {} -relief {}
}
Widget::addmap StatusBar "" .sbar {
-background {}
}
Widget::addmap StatusBar "" .resize {
-background {}
}
Widget::addmap StatusBar "" .hsep {
-background {}
}
# -pad provides general padding around the status bar
# -ipad provides padding around each status bar item
# Padding can be a list of {padx pady}
variable HaveMarlett \
[expr {[lsearch -exact [font families] "Marlett"] != -1}]
bind StatusResize <1> \
[namespace code [list begin_resize %W %X %Y]]
bind StatusResize <B1-Motion> \
[namespace code [list continue_resize %W %X %Y]]
bind StatusResize <ButtonRelease-1> \
[namespace code [list end_resize %W %X %Y]]
bind StatusBar <Destroy> [list StatusBar::_destroy %W]
# PNG version has partial alpha transparency for better look
variable pngdata {
iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAFM0aXcAAAABGdBTUEAAYagM
eiWXwAAAGJJREFUGJW9kVEOgCAMQzs8GEezN69fkKlbUAz2r3l5NGTA+pCU+Q
IA5sv39wGgZKClZGBhJMVTklRr3VNwMz04mVfQzQiEm79EkrYZycxIkq8kkv2
v6RFGku9TUrj8RGr9AGy6mhv2ymLwAAAAAElFTkSuQmCC
}
variable gifdata {
R0lGODlhDwAPAJEAANnZ2f///4CAgD8/PyH5BAEAAAAALAAAAAAPAA8AAAJEh
I+py+1IQvh4IZlG0Qg+QshkAokGQfAvZCBIhG8hA0Ea4UPIQJBG+BAyEKQhCH
bIQAgNEQCAIA0hAyE0AEIGgjSEDBQAOw==
}
if {[package provide img::png] != ""} {
image create photo ::StatusBar::resizer -format PNG -data $pngdata
} else {
image create photo ::StatusBar::resizer -format GIF -data $gifdata
}
}
# ------------------------------------------------------------------------
# Command StatusBar::create
# ------------------------------------------------------------------------
proc StatusBar::create { path args } {
variable _widget
variable HaveMarlett
# Allow for img::png loaded after initial source
if {[package provide img::png] != ""} {
variable pngdata
::StatusBar::resizer configure -format PNG -data $pngdata
}
Widget::init StatusBar $path $args
eval [list frame $path -class StatusBar] [Widget::subcget $path :cmd]
foreach {padx pady} [_padval [Widget::cget $path -pad]] \
{ipadx ipady} [_padval [Widget::cget $path -ipad]] { break }
if {[BWidget::using ttk]} {
set sbar [ttk::frame $path.sbar -padding [list $padx $pady]]
} else {
set sbar [eval [list frame $path.sbar -padx $padx -pady $pady] \
[Widget::subcget $path .sbar]]
}
if {[string equal $::tcl_platform(platform) "windows"]} {
set cursor size_nw_se
} else {
set cursor sizing; # bottom_right_corner ??
}
set resize [eval [list label $path.resize] \
[Widget::subcget $path .resize] \
[list -borderwidth 0 -relief flat -anchor se \
-cursor $cursor -anchor se -padx 0 -pady 0]]
if {$HaveMarlett} {
$resize configure -font "Marlett -16" -text \u006f
} else {
$resize configure -image ::StatusBar::resizer
}
bindtags $resize [list all [winfo toplevel $path] StatusResize $resize]
if {[BWidget::using ttk]} {
set fsep [ttk::separator $path.hsep -orient horizontal]
} else {
set fsep [eval [list frame $path.hsep -bd 1 -height 2 -relief sunken] \
[Widget::subcget $path .hsep]]
}
set sep [_sep $path sepresize {}]
grid $fsep -row 0 -column 0 -columnspan 3 -sticky ew
grid $sbar -row 1 -column 0 -sticky news
grid $sep -row 1 -column 1 -sticky ns -padx $ipadx -pady $ipady
grid $resize -row 1 -column 2 -sticky news
grid columnconfigure $path 0 -weight 1
if {![Widget::cget $path -showseparator]} {
grid remove $fsep
}
if {![Widget::cget $path -showresize]} {
grid remove $sep $resize
} elseif {![Widget::cget $path -showresizesep]} {
grid remove $sep
}
set _widget($path,items) {}
return [Widget::create StatusBar $path]
}
# ------------------------------------------------------------------------
# Command StatusBar::configure
# ------------------------------------------------------------------------
proc StatusBar::configure { path args } {
variable _widget
set res [Widget::configure $path $args]
foreach {chshow chshowrsep chshowsep chipad chpad} \
[Widget::hasChangedX $path -showresize -showresizesep -showseparator \
-ipad -pad] { break }
if {$chshow} {
set show [Widget::cget $path -showresize]
set showrsep [Widget::cget $path -showresizesep]
if {$show} {
if {$showrsep} {
grid $path.sepresize
}
grid $path.resize
} else {
grid remove $path.sepresize $path.resize
}
}
if {$chshowsep} {
if {$show} {
grid $path.hsep
} else {
grid remove $path.hsep
}
}
if {$chipad} {
foreach {ipadx ipady} [_padval [Widget::cget $path -ipad]] { break }
foreach w [grid slaves $path.sbar] {
grid configure $w -padx $ipadx -pady $ipady
}
}
if {$chpad} {
foreach {padx pady} [_padval [Widget::cget $path -pad]] { break }
if {[string equal [winfo class $path.sbar] "TFrame"]} {
$path.sbar configure -padding [list $padx $pady]
} else {
$path.sbar configure -padx $padx -pady $pady
}
}
return $res
}
# ------------------------------------------------------------------------
# Command StatusBar::cget
# ------------------------------------------------------------------------
proc StatusBar::cget { path option } {
return [Widget::cget $path $option]
}
# ------------------------------------------------------------------------
# Command StatusBar::getframe
# ------------------------------------------------------------------------
proc StatusBar::getframe {path} {
# This is the frame that users should place their statusbar widgets in
return $path.sbar
}
# ------------------------------------------------------------------------
# Command StatusBar::add
# ------------------------------------------------------------------------
proc StatusBar::add {path w args} {
variable _widget
array set opts [list \
-weight 0 \
-separator 1 \
-sticky news \
-pad [Widget::cget $path -ipad] \
]
foreach {key val} $args {
if {[info exists opts($key)]} {
set opts($key) $val
} else {
set msg "unknown option \"$key\", must be one of: "
append msg [join [lsort [array names opts]] {, }]
return -code error $msg
}
}
foreach {ipadx ipady} [_padval $opts(-pad)] { break }
set sbar $path.sbar
foreach {cols rows} [grid size $sbar] break
# Add separator if requested, and we aren't the first element
if {$opts(-separator) && $cols != 0} {
set sep [_sep $path sep[winfo name $w]]
# only append name, to distinguish us from them
lappend _widget($path,items) [winfo name $sep]
grid $sep -in $sbar -row 0 -column $cols \
-sticky ns -padx $ipadx -pady $ipady
incr cols
}
lappend _widget($path,items) $w
grid $w -in $sbar -row 0 -column $cols -sticky $opts(-sticky) \
-padx $ipadx -pady $ipady
grid columnconfigure $sbar $cols -weight $opts(-weight)
return $w
}
# ------------------------------------------------------------------------
# Command StatusBar::delete
# ------------------------------------------------------------------------
proc StatusBar::remove {path args} {
variable _widget
set destroy [string equal [lindex $args 0] "-destroy"]
if {$destroy} {
set args [lrange $args 1 end]
}
foreach w $args {
set idx [lsearch -exact $_widget($path,items) $w]
if {$idx == -1 || ![winfo exists $w]} {
# ignore unknown or non-widget items (like our separators)
continue
}
# separator is always previous item
set sidx [expr {$idx - 1}]
set sep [lindex $_widget($path,items) $sidx]
if {[string match .* $sep]} {
# not one of our separators
incr sidx
} elseif {$sep != ""} {
# destroy separator too
set sep $path.sbar.$sep
destroy $sep
}
if {$destroy} {
destroy $w
} else {
grid forget $w
}
if {$idx == 0} {
# separator of next item is no longer necessary
set sep [lindex $_widget($path,items) [expr {$idx + 1}]]
if {$sep != "" && ![string match .* $sep]} {
incr idx
set sep $path.sbar.$sep
destroy $sep
}
}
set _widget($path,items) [lreplace $_widget($path,items) $sidx $idx]
}
}
# ------------------------------------------------------------------------
# Command StatusBar::delete
# ------------------------------------------------------------------------
proc StatusBar::delete {path args} {
return [StatusBar::remove $path -destroy $args]
}
# ------------------------------------------------------------------------
# Command StatusBar::items
# ------------------------------------------------------------------------
proc StatusBar::items {path} {
variable _widget
return $_widget($path,items)
}
proc StatusBar::_sep {path name {sub .sbar}} {
if {[BWidget::using ttk]} {
return [ttk::separator $path$sub.$name -orient vertical]
} else {
return [frame $path$sub.$name -bd 1 -width 2 -relief sunken]
}
}
proc StatusBar::_padval {padval} {
set len [llength $padval]
foreach {a b} $padval { break }
if {$len == 0 || $len > 2} {
return -code error \
"invalid pad value \"$padval\", must be 1 or 2 pixel values"
} elseif {$len == 1} {
return [list $a $a]
} elseif {$len == 2} {
return $padval
}
}
# ------------------------------------------------------------------------
# Command StatusBar::_destroy
# ------------------------------------------------------------------------
proc StatusBar::_destroy { path } {
variable _widget
variable resize
array unset widget $path,*
array unset resize $path.resize,*
Widget::destroy $path
}
# The following proc handles the mouse click on the resize control. It stores
# the original size of the window and the initial coords of the mouse relative
# to the root.
proc StatusBar::begin_resize {w rootx rooty} {
variable resize
set t [winfo toplevel $w]
set relx [expr {$rootx - [winfo rootx $t]}]
set rely [expr {$rooty - [winfo rooty $t]}]
set resize($w,x) $relx
set resize($w,y) $rely
set resize($w,w) [winfo width $t]
set resize($w,h) [winfo height $t]
set resize($w,winc) 1
set resize($w,hinc) 1
set resize($w,grid) [wm grid $t]
}
# The following proc handles mouse motion on the resize control by asking the
# wm to adjust the size of the window.
proc StatusBar::continue_resize {w rootx rooty} {
variable resize
if {[llength $resize($w,grid)]} {
# at this time, we don't know how to handle gridded resizing
return
}
set t [winfo toplevel $w]
set relx [expr {$rootx - [winfo rootx $t]}]
set rely [expr {$rooty - [winfo rooty $t]}]
set width [expr {$relx - $resize($w,x) + $resize($w,w)}]
set height [expr {$rely - $resize($w,y) + $resize($w,h)}]
if {$width < 0} { set width 0 }
if {$height < 0} { set height 0 }
wm geometry $t ${width}x${height}
if {[string equal $::tcl_platform(platform) "windows"]} {
update idletasks
}
}
# The following proc cleans up when the user releases the mouse button.
proc StatusBar::end_resize {w rootx rooty} {
variable resize
#continue_resize $w $rootx $rooty
#wm grid $t $resize($w,grid)
array unset resize $w,*
}