source: tol/tolbase/lib/mkWidgets1.3/Tabcontrol.tcl @ 32535cc

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

adding more types to config, added mkWidget1.3

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

  • Property mode set to 100644
File size: 12.1 KB
Line 
1package require Metawidget
2
3# name: Tabcontrol
4# args: args: option-value pairs for metawidget configuration
5# defines the internal widgets and private variables. initializes the -width
6# option by calling its member function.
7metawidget create Tabcontrol {
8  frame $this.tabs -border 2 -relief flat   ;# contains all rows and tabs
9  label $this.actv -border 2 -relief raised ;# the active tab is also a frame
10  frame $this.work -border 2 -relief raised ;# the work area
11  frame $this.gbar -border 0                ;# a gray line to hide the lower
12                                            ;# ...border of the active tab
13  my iWorkY    0  ;# y-coordinate where the work area begins
14  my iAutoW    0  ;# minimum width of $this.tabs, if -width in auto mode
15  my lAllTabs  {} ;# list of all defined tab names
16  my sActTab   {} ;# name of the currently active tab
17  my wActWin   {} ;# the active tab's associated user widget
18
19  -width 100%
20
21  bind $this <Configure> "$this _drawTabs"  ;# to update tab geometry if resized
22} {} -default tabs
23
24# name: _drawTabs
25# args: -
26# redraws the tabs. called when resized or tabs are configured. basically
27# calculates the new geometry of the tabs container $this.tabs, of the
28# the active tab $this.actv and the line that hides its lower border.
29# the work area's top pixel coordinate is also adjusted.
30metawidget proc Tabcontrol _drawTabs {} {
31  # position tab container depending on -width option.
32  switch [my sWmode] {
33    pct { place $this.tabs -x 0 -y 0 -relh 1 -relw [my iWidth] -w 0    }
34    abs { place $this.tabs -x 0 -y 0 -relh 1 -w    [my iWidth] -relw 0 }
35    req { place $this.tabs -x 0 -y 0 -relh 1 -w    [my iAutoW] -relw 0 }
36  }
37
38  # if an active tab is set, places the $this.actv window exactly over it,
39  # but sizes it slightly bigger. places the $this.gbar frame so that
40  # $this.actv and $this.work look like one window.
41  if { [my sActTab] != {} } {
42    set iX [winfo x [my wTab]]
43    set iY [expr [winfo y [my wRow]]-2]
44    set iW [expr [winfo w [my wTab]]+4]
45    set iH [expr [winfo h [my wRow]]+2]
46
47    place $this.actv -x $iX -y $iY -w $iW -h $iH
48    place $this.gbar -x [expr $iX+1] -y [expr $iY+$iH-2] -w [expr $iW-2] -h 2
49    place $this.work -x 0 -y [my iWorkY] -relw 1 -h [expr [winfo height $this.tabs]-[my iWorkY]]
50  }
51}
52
53# name: _findTab
54# args: sTab: Tab name to retrieve data for
55# raises an exception, if the tab doesn't exist. otherwise, returns
56# the tab's properties: widget name, row, user window and command.
57metawidget proc Tabcontrol _findTab { sTab } {
58  if { ! [myinfo exists aTabs($sTab)] } {
59    error "Tabcontrol $this: No such tab '$sTab'"
60  }
61
62  return [my aTabs($sTab)]
63}
64
65# name: _calcGeom
66# args: -
67# calculates the minimum required with of the container $this.tabs, so that
68# the labels of all tabs are completely visible. retrieves the 'required with'
69# of all tab rows and calculates the longest one. used when -width is 'auto'.
70# also calculates the top border of the work area.
71metawidget proc Tabcontrol _calcGeom {} {
72  update
73
74  set iAutoW 0
75  foreach wWindow [winfo children $this.tabs] {
76    set iWidth [winfo reqw $wWindow]
77    if { $iWidth < $iAutoW } continue
78    set iAutoW $iWidth
79  }
80  my iAutoW [expr $iAutoW+4]
81
82  set iWorkY 2
83  foreach wWindow [winfo children $this.tabs] {
84    incr iWorkY [expr [winfo reqh $wWindow]-2]
85  }
86  my iWorkY $iWorkY
87}
88
89# name: _updateActive
90# args: -
91# make the active tab look like the original tab (which stays in its row)
92# remember: all tabs are simply packed into their row frame. to make a tab
93# look raised, the $this.actv frame is configured to look like the
94# to-be-raised tab and placed over it slighly bigger by the _drawTabs function.
95metawidget proc Tabcontrol _updateActive {} {
96  if { [my sActTab] == {} } return
97
98  $this.actv config -text  [[my wTab] cget -text]  -image  [[my wTab] cget -image]  \
99                    -backg [[my wTab] cget -backg] -foreg  [[my wTab] cget -foreg]  \
100                    -font  [[my wTab] cget -font]  -cursor [[my wTab] cget -cursor] \
101                    -under [[my wTab] cget -under] -anchor [[my wTab] cget -anchor] \
102                    -padx  [[my wTab] cget -padx]  -pady   [[my wTab] cget -pady]
103}
104
105# name: -width
106# args: sWidth: new width value
107# option member. controls the width of the container $this.tabs and its
108# behaviour when the toplevel is resized. sWidth can be 'auto', an integer,
109# or an integer followed by a percent sign. sets the two private variables
110# sWmode and iWidth accordingly. they are used in the _drawTabs member.
111metawidget proc Tabcontrol -width { sWidth } {
112  if { [regexp {^([0-9]+)%$} $sWidth sDummy iWidth] } {
113    my sWmode pct
114    my iWidth [expr $iWidth/100.]
115  } elseif { [regexp {^[0-9]+$} $sWidth iWidth] } {
116    my sWmode abs
117    my iWidth $iWidth
118  } elseif { $sWidth == "auto" } {
119    my sWmode req
120    my iWidth [my iAutoW]
121  } else {
122    error "Tabcontrol $this: Bad width $sWidth. Must be an integer, integer% or 'auto'"
123  }
124
125  my -width $sWidth
126  _drawTabs
127}
128
129# name: insert
130# args: sTab: name of the new tab
131#       iRow: row to place the tab in
132#       args: option-value pairs for tab configuration
133# defines and displays a new tab. derives the row's widget name and eventually
134# creates it if it doesn't exist. creates a label for the tab and packs it
135# into its row. initializes tab properties.
136metawidget proc Tabcontrol insert { sTab iRow args } {
137  if { [myinfo exists aTabs($sTab)] } {
138    error "Tabcontrol $this: Tab '$sTab' already exists"
139  }
140
141  set wRow $this.tabs.row$iRow    ;# wRow is child of $this.tabs
142  set wTab $wRow.tab$sTab         ;# wTab is child of wRow
143
144  if { ! [myinfo exists lTabs$iRow] } {  ;# if wRow doesn't exist
145    frame $wRow -border 0         ;# then create it and
146    my lTabs$iRow {}              ;# initialize a list for all its tabs
147  }
148
149  # create tab widget, simply pack it on the left, create mouse click binding
150  label $wTab -border 2 -relief raised
151  pack $wTab -side left -ipadx 2 -fill both -expand 1
152  bind $wTab <1> "$this invoke $sTab"
153
154  my aTabs($sTab) [list $wTab $iRow {} {}]          ;# initialize tab prop/s
155  eval tabconfigure {$sTab} -text {$sTab} $args     ;# configure it a bit
156
157  _calcGeom         ;# update required width
158  invoke $sTab      ;# and raise the new tab
159
160  # add tab to the all-tabs list and to the row-specific list
161  my lAllTabs   [mkw.lextend [my lAllTabs] $sTab]
162  my lTabs$iRow [mkw.lextend [my lTabs$iRow] $sTab]
163}
164
165# name: delete
166# args: sTab: tab to delete
167# deletes a tab. displays another tab, if there's one left.
168metawidget proc Tabcontrol delete { sTab } {
169  mkw.lassign [_findTab $sTab] wTab iRow wWindow
170
171  pack forget $wWindow
172  destroy $wTab
173  unmy aTabs($sTab)
174
175  # update all-tabs list and row-specific list
176  my lAllTabs   [mkw.lshrink [my lAllTabs] $sTab]
177  my lTabs$iRow [mkw.lshrink [my lTabs$iRow] $sTab]
178
179  # if there is some other tab left and the deleted tab was active, then
180  # raise the other tab. otherwise hide the $this.actv frame.
181  if { [llength [my lAllTabs]] } {
182    if { $sTab == [my sActTab] } {
183      invoke [lindex [my lAllTabs] 0]
184    }
185
186    _calcGeom
187    _drawTabs
188  } else {
189    place forget $this.actv
190    place forget $this.gbar
191    my sActTab {}
192  }
193}
194
195# name: tabconfigure
196# args: sTab: tab to be configured
197#       args: option-value pairs
198# configures a tab. the two special options -window and -command are stored
199# in the tab's property list (no immediate action required). all other options
200# are passed to the tab's widget.
201metawidget proc Tabcontrol tabconfigure { sTab args } {
202  mkw.lassign [_findTab $sTab] wTab
203
204  set lArgs [mkw.options $args * {-window *} {-command *}]
205
206  if { [info exists -window] } {
207    my aTabs($sTab) [lreplace [my aTabs($sTab)] 2 2 ${-window}]
208  }
209
210  if { [info exists -command] } {
211    my aTabs($sTab) [lreplace [my aTabs($sTab)] 3 3 ${-command}]
212  }
213
214  eval $wTab config $lArgs
215
216  _calcGeom
217  _drawTabs
218  _updateActive
219}
220
221# name: tabcget
222# args: sTab: tab to retrieve option value for
223#       sOption: name of an option
224# retrieves an option value of a tab. either returns a tab property value for
225# one of the special options -window and -command, or tries to get it directly
226# from the tab's widget.
227metawidget proc Tabcontrol tabcget { sTab sOption } {
228  mkw.lassign [_findTab $sTab] wTab iRow wWindow sCommand
229
230  set wRow $this.tabs.row$iRow.tab$sTab
231  set wTab $wRow.tab$sTab
232
233  switch -- $sOption {
234    -window   { return $wWindow }
235    -command  { return $sCommand }
236    default  { return [$wTab cget $sOption] }
237  }
238}
239
240# name: invoke
241# args: sTab: tab to raise
242# raises a tab, i.e. makes it look like in the foreground and displays its
243# associated user window. Also, the row with the active tab is always the lowest
244# one. therefore the rows are rearranged.
245metawidget proc Tabcontrol invoke { sTab } {
246  mkw.lassign [_findTab $sTab] wTab iRow wWindow sCommand
247
248  catch { pack forget [my wActWin ] }  ;# hide user-widget from active tab
249  my wTab $wTab                        ;# update private variables...
250  my wRow [winfo parent $wTab]         ;# ...needed later e.g. for _drawTabs
251  my sActTab $sTab
252  my wActWin $wWindow
253
254  # rearrange rows so that the one with the new active tab is at the bottom.
255  set iY 0
256  set lRows [mkw.lshrink [lsort [winfo children $this.tabs]] [my wRow]]
257  foreach wRow [linsert $lRows end [my wRow]] {
258    raise $wRow
259    place $wRow -x 0 -y $iY -relw 1
260    incr iY [expr [winfo reqheight $wRow]-2]
261  }
262
263  # pack and raise the new tab's user-widget, if it exists
264  if { [winfo exist $wWindow] } {
265    pack $wWindow -in $this.work -padx 2 -pady 2 -fill both -expand 1
266    raise $wWindow
267  }
268
269  update
270  _drawTabs
271  _updateActive
272
273  if { $sCommand != {} } {
274    eval $sCommand    ;# eventually execute the tab's command, if there is one
275  }
276}
277
278# name: get
279# args: sWhat: row number or 'active' or nothing
280# returns all tabs, the active tab or the tabs of a given row.
281metawidget proc Tabcontrol get { {sWhat {}} } {
282  if { $sWhat == {} } {
283    return [my lAllTabs]
284  } elseif { $sWhat == "active" } {
285    return [my sActTab]
286  } elseif { [regexp {^[0-9]+$} $sWhat] } {
287    return [my lTabs$sWhat]
288  } else {
289    error "Tabcontrol $this: Bad index $sWhat. Should be active, an integer or nothing."
290  }
291}
292
293# name: bind
294# args: sTab: tab to set binding for (or get from)
295#       args: arguments for the bind command
296# creates or retrieves bindings for the given tab.
297metawidget proc Tabcontrol bind_ { sTab args } {
298  mkw.lassign [_findTab $sTab] wRow wTab
299  eval bind $wTab $args
300}
301
302metawidget command Tabcontrol _drawTabs _drawTabs
303
304metawidget command Tabcontrol insert    insert
305metawidget command Tabcontrol delete    delete
306metawidget command Tabcontrol tabconfigure tabconfigure
307metawidget command Tabcontrol tabcget   tabcget
308metawidget command Tabcontrol invoke    invoke
309metawidget command Tabcontrol get       get
310metawidget command Tabcontrol bind      bind_
311
312metawidget option  Tabcontrol -width    -width
313
314proc test {} {
315  global iTabno
316  set iTabno 0
317
318  wm minsize . 200 200
319
320  [text .code] insert end [info body test]
321
322  frame .fwid -border 2 -relief groove
323  pack [radiobutton .fwid.auto -text "Set it to Auto mode"  -value 0 -command {.tabs config -width auto}] -anchor w
324  pack [radiobutton .fwid.half -text "Half of window width" -value 1 -command {.tabs config -width 50%}] -anchor w
325  pack [radiobutton .fwid.full -text "Full width of window" -value 2 -command {.tabs config -width 100%}] -anchor w
326  pack [radiobutton .fwid.exct -text "Exactly 300 pixels"   -value 3 -command {.tabs config -width 300}] -anchor w
327
328  frame .fcrt
329  pack [button .fcrt.tcre -text "Create a tab" -command {
330    incr iTabno
331    label .lbl$iTabno -text "This is tab $iTabno" -font {Helvetica 24} -bg white
332    .tabs insert Tab$iTabno 1 -window .lbl$iTabno
333  }] -fill x
334  pack [button .fcrt.tdel -text "Delete last tab" -command {
335    .tabs delete Tab$iTabno
336    destroy .lbl$iTabno
337    incr iTabno -1
338  }] -fill x
339
340  tabcontrol .tabs -width auto
341  pack .tabs -fill both -expand 1 -padx 10 -pady 10
342
343  .tabs insert width  0 -text "Change Width" -window .fwid -underline 7
344  .tabs insert edit   0 -text "Create Tabs"  -window .fcrt -underline 7
345  .tabs insert source 0 -text "View Source"  -window .code -underline 5
346  .tabs invoke width
347
348  bind . <Alt-w> {.tabs invoke width}
349  bind . <Alt-t> {.tabs invoke edit}
350  bind . <Alt-s> {.tabs invoke source}
351}
352
353#test
Note: See TracBrowser for help on using the repository browser.