source: tol/tolbase/lib/toltk/mulselec.tcl @ 0318d73

1941-docker-image-to-testdevel
Last change on this file since 0318d73 was 6d7779d, checked in by Jorge Pérez <josp.jorge@…>, 18 years ago

initial import

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@1 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 11.7 KB
Line 
1#/////////////////////////////////////////////////////////////////////////////
2# FILE    : mulselec.tcl
3# PURPOSE : This file contains a namespace called MultipleSelector with its
4#           functions. It's for creating a multiple selector of items and
5#           managing its events. A multiple selector consist of two listboxes:
6#           unselected (left) and selected (right) with items which you can
7#           move from one listbox to the other.
8#/////////////////////////////////////////////////////////////////////////////
9
10
11#/////////////////////////////////////////////////////////////////////////////
12# TESTING
13#/////////////////////////////////////////////////////////////////////////////
14# Put if {1} for testing this file.
15if {0} {
16  package require Tk
17  package require BWidget
18  # force BWidget autoload
19  Bitmap::use
20  set toltk_script_path [file dirname [info script]]
21  set toltk_images_path [file join ${toltk_script_path} images]
22  if { [lsearch $Bitmap::path $toltk_images_path] == -1 } {
23      lappend Bitmap::path [file join $toltk_script_path images]
24  }
25  package require msgcat
26  namespace import msgcat::*
27  ::msgcat::mclocale es
28  ::msgcat::mcload [file join $toltk_script_path msgs]
29}
30
31package require blistbox
32
33#/////////////////////////////////////////////////////////////////////////////
34  namespace eval MultipleSelector {
35#
36# PURPOSE: The purpose of this namespace is organize code and functions.
37#
38#/////////////////////////////////////////////////////////////////////////////
39}
40
41
42#/////////////////////////////////////////////////////////////////////////////
43  proc ::MultipleSelector::CreateToplevel { w unselvar selvar
44                                          {label1 "Not selected"}
45                                          {label2 "Selected"} } {
46#
47# PURPOSE: Creates a multiple selector in a modal toplevel window.
48#
49# PARAMETERS:
50#   w        -> widget's path (toplevel)
51#   unselvar -> name of the variable that has the unselected items
52#   selvar   -> name of the variable that has the selected items
53#   label1   -> label of the unselected listbox
54#   label2   -> label of the selected listbox
55#
56#/////////////////////////////////////////////////////////////////////////////
57
58  global _MS_QUIT
59  upvar #0 $unselvar unsel
60  upvar #0 $selvar   sel
61  variable widget
62  set label1 [mc $label1]
63  set label2 [mc $label2]
64 
65  toplevel $w
66 
67  # Dialog boxes should be transient with respect to their parent,
68  # so that they will always stay on top of their parent window.  However,
69  # some window managers will create the window as withdrawn if the parent
70  # window is withdrawn or iconified.  Combined with the grab we put on the
71  # window, this can hang the entire application.  Therefore we only make
72  # the dialog transient if the parent is viewable.
73  #
74  if { [winfo viewable [winfo toplevel [winfo parent $w]]] } {
75    wm transient $w [winfo toplevel [winfo parent $w]]
76  }   
77 
78  wm title $w [mc "Multiple Selector"]
79  wm protocol $w WM_DELETE_WINDOW "set _MS_QUIT 0"
80  #wm geometry $w +[winfo partent $w]150+100
81  wm geometry $w +350+200
82  CreateFrame $w.f $unsel $sel $label1 $label2
83 
84  set fb [frame $w.fb]
85  Button $fb.ok -image [::Bitmap::get accept] -relief link \
86                -text [mc "Accept"] -command "set _MS_QUIT 1" \
87                -helptext [mc "Accept selection"]
88  Button $fb.cancel -image [::Bitmap::get txt] -relief link \
89                    -text [mc "Cancel"] -command "set _MS_QUIT 0" \
90                    -helptext [mc "Cancel selection"]
91 
92  grid $fb.ok $fb.cancel
93  grid $w.f -sticky news
94  grid $w.fb -sticky ew -pady 2
95  grid rowconfigure    $w 0 -weight 1
96  grid columnconfigure $w 0 -weight 1
97 
98  set oldFocus [focus]
99  set oldGrab [grab current $w]
100  if {[string compare $oldGrab ""]} {
101    set grabStatus [grab status $oldGrab]
102  }
103 
104  grab $w
105  focus $w
106  tkwait variable _MS_QUIT
107 
108  if {$_MS_QUIT} {
109    set unsel [GetUnselected $w.f]
110    set sel   [GetSelected $w.f]
111  }   
112  catch {
113    focus $oldFocus
114  }
115  catch {
116    # It's possible that the window has already been destroyed,
117    # hence this "catch".  Delete the Destroy handler so that
118    # data(quit) doesn't get reset by it.
119 
120    #bind $w <Destroy> {}
121    destroy $w
122  }
123  if {[string compare $oldGrab ""]} {
124    if {[string compare $grabStatus "global"]} {
125      grab $oldGrab
126    } else {
127      grab -global $oldGrab
128    }
129  }
130}
131
132
133#/////////////////////////////////////////////////////////////////////////////
134  proc ::MultipleSelector::CreateFrame {w unsel sel
135                                       {label1 "Not selected"}
136                                       {label2 "Selected"} } {
137#
138# PURPOSE: Creates a multiple selector in a frame.
139#
140# PARAMETERS:
141#   w        -> widget's path (frame)
142#   unsel    -> list of unselected items
143#   sel      -> list of selected items
144#   label1   -> label of the unselected listbox
145#   label2   -> label of the selected listbox
146#
147# RETURN: Path of multiple selector
148#
149#/////////////////////////////////////////////////////////////////////////////
150
151  upvar #0 $w data
152  set label1 [mc $label1]
153  set label2 [mc $label2]
154
155  set data(OnChanged) ""
156
157  frame $w -class MultipleSelector
158  set left [frame $w.left]
159  set right [frame $w.right]
160
161  # listbox 1
162  label $w.l1 -text $label1 -bd 1 -relief raised
163  ScrolledWindow $w.sw1
164  blistbox $w.sw1.lb -selectmode extended \
165    -breadonly true -bkeypress true -bparent $w
166  $w.sw1 setwidget $w.sw1.lb
167  bind $w.sw1.lb <Button-1> +[list focus -force %W]
168  bind $w.sw1.lb <Double-Button-1> +[list ::MultipleSelector::LBLeftToRight $w]
169
170  # buttons
171  set bbox [ButtonBox $w.bb -orient vertical -spacing 0 -padx 4 -pady 1]
172  $bbox add -image [Bitmap::get play] -height 16 -width 16 \
173    -command [list ::MultipleSelector::LBLeftToRight $w] -relief link \
174    -helptext [mc "Moves selection from left to right"]
175  $bbox add -image [Bitmap::get backward] -height 16 -width 16 \
176    -command [list ::MultipleSelector::LBRightToLeft $w] -relief link \
177    -helptext [mc "Moves selection from right to left"]
178  $bbox add -image [Bitmap::get end] -height 16 -width 16 \
179    -command [list ::MultipleSelector::LBAllLeftToRight $w] -relief link \
180    -helptext [mc "Moves all from left to right"]
181  $bbox add -image [Bitmap::get begin] -height 16 -width 16 \
182    -command [list ::MultipleSelector::LBAllRightToLeft $w] -relief link \
183    -helptext [mc "Moves all from right to left"]
184
185  # listbox 2
186  label $w.l2 -text $label2 -bd 1 -relief raised
187  ScrolledWindow $w.sw2
188  blistbox $w.sw2.lb -selectmode extended \
189    -breadonly true -bkeypress true -bparent $w
190  $w.sw2 setwidget $w.sw2.lb
191  bind $w.sw2.lb <Button-1> +[list focus -force %W]
192  bind $w.sw2.lb <Double-Button-1> +[list ::MultipleSelector::LBRightToLeft $w]
193 
194  # fill the listbox
195  FillLB $w $unsel $sel
196
197  grid $w.l1   $bbox  $w.l2  -sticky news
198  grid $w.sw1  ^      $w.sw2 -sticky news
199  grid rowconfigure    $w 0 -weight 0
200  grid rowconfigure    $w 1 -weight 1
201  grid columnconfigure $w 0 -weight 1
202  grid columnconfigure $w 1 -pad 5
203  grid columnconfigure $w 2 -weight 1
204  update
205  bind <Destroy> $w [list ::MultipleSelector::KillData $w]
206  return $w
207}
208
209
210#/////////////////////////////////////////////////////////////////////////////
211  proc ::MultipleSelector::EvalOnChanged { w } {
212#
213# PURPOSE: Evaluates a procedure when any of the listboxes changes any of
214#          its items.
215#
216# PARAMETERS:
217#    w -> widget's path (frame). It stores data
218#
219#/////////////////////////////////////////////////////////////////////////////
220
221  upvar #0 $w data
222   
223  if { [string length $data(OnChanged)] } {
224    eval $data(OnChanged)
225  }
226}
227
228
229#/////////////////////////////////////////////////////////////////////////////
230  proc ::MultipleSelector::FillLB { w unsel sel } {
231#
232# PURPOSE: Fill unselected and selected listboxes of widget 'w'.
233#
234# PARAMETERS:
235#    w     -> widget's path
236#    unsel -> list of unselected items
237#    sel   -> list of selected items
238#
239#/////////////////////////////////////////////////////////////////////////////
240
241  $w.sw1.lb delete 0 end
242  $w.sw2.lb delete 0 end
243  foreach it $unsel {
244    $w.sw1.lb insert end $it
245  }
246  foreach it $sel {
247    $w.sw2.lb insert end $it
248  }
249  EvalOnChanged $w
250}
251
252#/////////////////////////////////////////////////////////////////////////////
253  proc ::MultipleSelector::OnChanged { w script } {
254#
255# PURPOSE: Stores a script to evaluate when a listbox changes.
256#
257# PARAMETERS:
258#    w      -> widget's path (stores data, the script in this case)
259#    script -> script to evaluate when a listbox changes
260#
261#/////////////////////////////////////////////////////////////////////////////
262  upvar #0 $w data
263
264  set data(OnChanged) $script
265}
266
267
268#/////////////////////////////////////////////////////////////////////////////
269  proc ::MultipleSelector::ListTransferSel {scr dst} {
270#
271# PURPOSE: Transfer selected items from scr listbox to dst listbox.
272#
273# PARAMETERS:
274#    scr -> source listbox path
275#    dst -> destination listbox path
276#
277#/////////////////////////////////////////////////////////////////////////////
278  foreach i [$scr curselection] {
279    $dst insert end [$scr get $i]
280  }
281}
282
283
284#/////////////////////////////////////////////////////////////////////////////
285  proc ::MultipleSelector::ListDeleteSel {w} {
286#
287# PURPOSE: Deletes selected items of a listbox
288#
289# PARAMETERS:
290#    w -> listbox's path
291#
292#/////////////////////////////////////////////////////////////////////////////
293  foreach i [lsort -integer -decreasing [$w curselection]] {
294    $w delete $i
295  }
296}
297
298
299#/////////////////////////////////////////////////////////////////////////////
300  proc ::MultipleSelector::LBLeftToRight { w } {
301#
302# PURPOSE: Moves selected items from unselected listbox to selected listbox
303#
304# PARAMETERS:
305#    w -> multiple selector's path
306#
307#/////////////////////////////////////////////////////////////////////////////
308  ListTransferSel $w.sw1.lb $w.sw2.lb
309  ListDeleteSel   $w.sw1.lb
310  EvalOnChanged $w
311}
312
313
314#/////////////////////////////////////////////////////////////////////////////
315  proc ::MultipleSelector::LBRightToLeft { w } {
316#
317# PURPOSE: Moves selected items from selected listbox to unselected listbox
318#
319# PARAMETERS:
320#    w -> multiple selector's path
321#
322#/////////////////////////////////////////////////////////////////////////////
323  ListTransferSel $w.sw2.lb $w.sw1.lb
324  ListDeleteSel   $w.sw2.lb   
325  EvalOnChanged $w
326}
327
328
329#/////////////////////////////////////////////////////////////////////////////
330  proc ::MultipleSelector::LBAllLeftToRight { w } {
331#
332# PURPOSE: Moves all items from unselected listbox to selected listbox
333#
334# PARAMETERS:
335#    w -> multiple selector's path
336#
337#/////////////////////////////////////////////////////////////////////////////
338  eval "$w.sw2.lb insert end [$w.sw1.lb get 0 end]"
339  $w.sw1.lb delete 0 end
340  EvalOnChanged $w
341}
342
343
344#/////////////////////////////////////////////////////////////////////////////
345  proc ::MultipleSelector::LBAllRightToLeft { w } {
346#
347# PURPOSE: Moves all items from selected listbox to unselected listbox
348#
349# PARAMETERS:
350#    w -> multiple selector's path
351#
352#/////////////////////////////////////////////////////////////////////////////
353  eval "$w.sw1.lb insert end [$w.sw2.lb get 0 end]"
354  $w.sw2.lb delete 0 end
355  EvalOnChanged $w
356}
357
358#/////////////////////////////////////////////////////////////////////////////
359  proc ::MultipleSelector::GetSelected { w } {
360#
361# PURPOSE: Gets item from selected listbox (rigth)
362#
363# PARAMETERS:
364#    w -> multiple selector's path
365#
366#/////////////////////////////////////////////////////////////////////////////
367  $w.sw2.lb get 0 end
368}
369
370
371#/////////////////////////////////////////////////////////////////////////////
372  proc ::MultipleSelector::GetUnselected { w } {
373#
374# PURPOSE: Gets item from unselected listbox (left)
375#
376# PARAMETERS:
377#    w -> multiple selector's path
378#
379#/////////////////////////////////////////////////////////////////////////////
380  $w.sw1.lb get 0 end
381}
Note: See TracBrowser for help on using the repository browser.