Scid  4.6.5
win.tcl
Go to the documentation of this file.
1 # Copyright (C) 2008-2009 Pascal Georges
2 # Copyright (C) 2013-2016 Fulvio Benini
3 #
4 # This file is part of Scid (Shane's Chess Information Database).
5 #
6 # Scid is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation.
9 #
10 # Scid is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Scid. If not, see <http://www.gnu.org/licenses/>.
17 
18 # ::utils::win::Centre
19 #
20 # Centres a window on the screen.
21 #
22 proc ::utils::win::Centre {w} {
23  if { $::docking::USE_DOCKING } { return}
24  wm withdraw $w
25  update idletasks
26  set x [expr {[winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
27  - [winfo vrootx .]}]
28  set y [expr {[winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
29  - [winfo vrooty .]}]
30  wm geom $w +$x+$y
31  wm deiconify $w
32 }
33 
34 ################################################################################
35 #
36 # DockingFramework
37 #
38 # Code is inspired by
39 # http://wiki.tcl.tk/21846
40 # which is published under BSD license
41 #
42 ################################################################################
43 
44 namespace eval docking {
45  # associates notebook to paned window
46  variable tbs
47 
48  # keep tracks of active tab for each notebook
49  array set activeTab {}
50  # associates notebook with a boolean value indicating the tab has changed
51  array set changedTab {}
52 
53  variable tbcnt 0
54  array set notebook_name {}
55 }
56 
57 ################################################################################
58 # find notebook, corresponding to path
59 proc ::docking::find_tbn {path} {
60  variable tbs
61 
62  if {$path=="" || ![winfo exists $path]} { return ""}
63  # already a managed notebook?
64  if {[info exists tbs($path)]} {
65  return $path
66  }
67  # managed notebooks have the form .toplevel.tbn#
68  # pages within notebooks should also have the path .toplevel.page#
69  set spath [split $path "."]
70  if {[winfo toplevel $path]=="."} {
71  set path [join [lrange $path 0 1] "."]
72  } else {
73  set path [join [lrange $path 0 2] "."]
74  }
75 
76  # is it a managed notebook?
77  if {[info exists tbs($path)]} {
78  return $path
79  }
80 
81  # try to find notebook that manages this page
82  foreach tb [array names tbs] {
83  if {[get_class $tb] != "TNotebook"} {
84  continue
85  }
86  if {[lsearch -exact [$tb tabs] $path]>=0} {
87  return $tb
88  }
89  }
90 
91  return {}
92 }
93 
94 ################################################################################
95 # added paned window of other direction, move a notebook there and create a new notebook
96 proc ::docking::embed_tbn {tbn anchor} {
97  variable tbcnt
98  variable tbs
99  set pw $tbs($tbn)
100  if {$anchor=="w" || $anchor=="e"} {
101  set orient "horizontal"
102  } else {
103  set orient "vertical"
104  }
105  # create new paned window
106  set npw [ttk::panedwindow $pw.pw$tbcnt -orient $orient]
107  incr tbcnt
108  # move old notebook
109  set i [lsearch -exact [$pw panes] $tbn]
110  $pw forget $tbn
111  if {$i>=[llength [$pw panes]]} {
112  $pw add $npw -weight 1
113  } else {
114  $pw insert $i $npw -weight 1
115  }
116  # add new notebook
117  set ntb [ttk::notebook [winfo toplevel $pw].tb$tbcnt]
118  incr tbcnt
119  set tbs($tbn) $npw
120  set tbs($ntb) $npw
121  # make sure correct order
122  if {$anchor=="n" || $anchor=="w"} {
123  $npw add $ntb -weight 1
124  $npw add $tbn -weight 1
125  } else {
126  $npw add $tbn -weight 1
127  $npw add $ntb -weight 1
128  }
129  return $ntb
130 }
131 
132 ################################################################################
133 # add a new notebook to the side anchor of the notebook tbn
134 proc ::docking::add_tbn {tbn anchor} {
135  variable tbcnt
136  variable tbs
137 
138  set pw $tbs($tbn)
139  set orient [$pw cget -orient]
140 
141  # if orientation of the uplevel panedwindow is consistent with anchor, just add the pane
142  if {$orient=="horizontal" && ($anchor=="w" || $anchor=="e")} {
143  set i [lsearch -exact [$pw panes] $tbn]
144  if {$anchor=="e"} { incr i}
145  set tbn [ttk::notebook [winfo toplevel $pw].tb$tbcnt]
146  incr tbcnt
147  set tbs($tbn) $pw
148  if {$i>=[llength [$pw panes]]} {
149  $pw add $tbn -weight 1
150  } else {
151  $pw insert $i $tbn -weight 1
152  }
153  } elseif {$orient=="vertical" && ($anchor=="n" || $anchor=="s")} {
154  set i [lsearch -exact [$pw panes] $tbn]
155  if {$anchor=="s"} { incr i}
156  set tbn [ttk::notebook [winfo toplevel $pw].tb$tbcnt]
157  incr tbcnt
158  set tbs($tbn) $pw
159  if {$i>=[llength [$pw panes]]} {
160  $pw add $tbn -weight 1
161  } else {
162  $pw insert $i $tbn -weight 1
163  }
164  } else {
165  # orientation of the uplevel panedwindow is opposite to the anchor
166  # need to add new panedwindow
167  set tbn [embed_tbn $tbn $anchor]
168  }
169  return $tbn
170 }
171 
172 ################################################################################
173 proc ::docking::get_class {path} {
174  if {![winfo exists $path]} {
175  return ""
176  }
177  return [lindex [bindtags $path] 1]
178 }
179 
180 ################################################################################
181 # always keep .pw paned window
182 proc ::docking::_cleanup_tabs {srctab} {
183  variable tbs
184 
185  # if srctab is empty, then remove it
186  if {[llength [$srctab tabs]]==0} {
187  destroy $srctab
188  set pw $tbs($srctab)
189  unset tbs($srctab)
190 
191  while {[llength [$pw panes]]==0} {
192  set parent [winfo parent $pw]
193 
194  if {$pw == ".pw"} {
195  break
196  }
197  destroy $pw
198  set pw $parent
199  }
200 
201  }
202 }
203 ################################################################################
204 # cleans up a window when it was closed without calling the notebook menu
205 proc ::docking::cleanup { w { origin "" } } {
206  if {$w == $origin || $origin == ""} {
207  set dockw ".fdock[string range $w 1 end]"
208  set tab [::docking::find_tbn $dockw]
209  if {$tab != ""} {
210  $tab forget $dockw
212  catch { unset ::docking::notebook_name($dockw)}
214  }
215  after idle "if {[winfo exists $dockw]} { destroy $dockw }"
216  catch { focus .main}
217  }
218 }
219 ################################################################################
220 proc ::docking::isUndocked { w } {
221  set w ".fdock[string range $w 1 end]"
222  return [expr { [winfo exists $w] && [winfo toplevel $w] == $w }]
223 }
224 ################################################################################
225 proc ::docking::move_tab {srctab dsttab} {
226  variable tbs
227  # move tab
228  set f [$srctab select]
229  set o [$srctab tab $f]
230  $srctab forget $f
231  eval $dsttab add $f $o
232  raise $f
233  $dsttab select $f
234  _cleanup_tabs $srctab
235 }
236 
237 variable ::docking::c_path {}
238 
239 ################################################################################
240 proc ::docking::start_motion {path} {
241  variable c_path
242  if {[winfo exists .ctxtMenu]} {
243  destroy .ctxtMenu
244  }
245  if {$path!=$c_path} {
246  set c_path [find_tbn $path]
247  }
248 }
249 ################################################################################
250 proc ::docking::motion {path} {
251  variable c_path
252  if {$c_path==""} { return}
253 
254  $c_path configure -cursor exchange
255 }
256 ################################################################################
257 proc ::docking::end_motion {w x y} {
258  variable c_path
259 
260  bind TNotebook <ButtonRelease-1> [namespace code {::docking::show_menu %W %X %Y}]
261 
262  if {$c_path==""} { return}
263  set path [winfo containing $x $y]
264  if {$path == ""} {
265  return
266  }
267  $path configure -cursor {}
268 
269  set t [find_tbn $path]
270  if {$t!=""} {
271  if {$t==$c_path} {
272  # we stayed on the same notebook, so display the menu
273  show_menu $w $x $y
274 
275  if {[$c_path identify [expr $x-[winfo rootx $c_path]] [expr $y-[winfo rooty $c_path]]]!=""} {
276  set c_path {}
277  return
278  }
279  }
280  if {$t!=$c_path} {
281  move_tab $c_path $t
282  }
283  }
284  set c_path {}
285 
287 
288 }
289 ################################################################################
290 proc ::docking::show_menu { path x y} {
291  variable c_path
292 
293  if {[winfo exists .ctxtMenu]} {
294  destroy .ctxtMenu
295  }
296 
297  if {$path!=$c_path} {
298  set c_path [find_tbn $path]
299  }
300 
301  # HACK ! Because notebooks may also be used inside internal windows
302  if {! [info exists ::docking::changedTab($c_path)] } {
303  return
304  }
305 
306  set localX [expr $x - [winfo rootx $path]]
307  set localY [expr $y - [winfo rooty $path]]
308  set tab [$path identify tab $localX $localY]
309  if {$tab == ""} { return}
310  set iconW 20
311  if {$tab == 0} {
312  set isIcon [expr {$localX < $iconW ? 1 : 0}]
313  } else {
314  set isIcon [expr [$path identify tab [expr $localX - $iconW] $localY] != $tab]
315  }
316 
317  # display window's menu (workaround for windows where the menu
318  # of embedded toplevels is not displayed. The menu must be of the form $w.menu
319  if {$isIcon} {
320  set f [lindex [$path tabs] $tab]
321  set m [getMenu $f]
322  if { [winfo exists $m] } {
323  tk_popup $m [winfo pointerx .] [winfo pointery .]
324  } else {
325  if {$f != ".fdockmain"} { ::docking::close $c_path}
326  }
327  }
328 
329 }
330 ################################################################################
331 # returns the menu name of a toplevel window (must be in the form $w.menu)
332 # f is the frame embedding the toplevel (.fdock$w)
333 proc ::docking::getMenu {f} {
334  if { [scan $f ".fdock%s" tl] != 1 || $f == ".fdockmain"} {
335  return ""
336  }
337  return ".$tl.menu"
338 }
339 ################################################################################
340 # Toggles menu visibility
341 # f is the frame embedding the toplevel (.fdock$w)
342 proc ::docking::setMenuVisibility { f show } {
343 
344  if { [scan $f ".fdock%s" tl] != 1 || $f == ".fdockmain"} {
345  return
346  }
347  set tl ".$tl"
348 
349  if { $show == "true" || $show == "1" } {
350  $tl configure -menu "$tl.menu"
351  } else {
352  $tl configure -menu {}
353  }
354 
355 }
356 
357 ################################################################################
358 proc ::docking::tabChanged {path} {
359  update
360  #TODO: the update is dangerous!
361  #For example the windows may be destroyed
362  if {! [winfo exists $path] } { return}
363 
364  # HACK ! Because notebooks may also be used inside internal windows
365  if { ! [ info exists ::docking::activeTab($path)] } {
366  return
367  }
368 
369  if { [$path select] != $::docking::activeTab($path)} {
370  set ::docking::activeTab($path) [$path select]
371  set ::docking::changedTab($path) 1
372  }
373 }
374 
375 ################################################################################
376 
377 bind TNotebook <ButtonRelease-1> {::docking::show_menu %W %X %Y}
378 
379 bind TNotebook <ButtonPress-1> +[ list ::docking::start_motion %W]
380 
381 bind TNotebook <B1-Motion> {
382  ::docking::motion %W
383  bind TNotebook <ButtonRelease-1> {::docking::end_motion %W %X %Y}
384 }
385 
386 bind TNotebook <Escape> {
387  if {[winfo exists .ctxtMenu]} {
388  destroy .ctxtMenu
389  }
390 }
391 
392 bind TNotebook <ButtonPress-$::MB3> {::docking::ctx_menu %W %x %y}
393 bind TNotebook <<NotebookTabChanged>> {::docking::tabChanged %W}
394 
395 ################################################################################
396 #
397 ################################################################################
398 proc ::docking::ctx_cmd {path anchor} {
399  variable c_path
400 
401  if {$path!=$c_path} {
402  set c_path [find_tbn $path]
403  }
404 
405  if {$c_path==""} {
406  puts "WARNING c_path null in ctx_cmd"
407  return
408  }
409 
410  set tbn [add_tbn $path $anchor]
411  move_tab $c_path $tbn
412 
413  set c_path {}
414 
416 }
417 ################################################################################
418 proc ::docking::ctx_menu {w x y} {
419 
420  # HACK ! Because notebooks may also be used inside internal windows
421  if {! [info exists ::docking::changedTab($w)] } {
422  return
423  }
424 
425  if {[catch { $w select @$x,$y}]} { return}
426  update idletasks
427  set mctxt .ctxtMenu
428  if { [winfo exists $mctxt] } {
429  destroy $mctxt
430  }
431 
432  menu $mctxt -tearoff 0
433  set state "normal"
434  if { [llength [$w tabs]] <= 1} {
435  set state "disabled"
436  }
437  $mctxt add command -label [ ::tr DockTop] -state $state -command "::docking::ctx_cmd $w n"
438  $mctxt add command -label [ ::tr DockBottom] -state $state -command "::docking::ctx_cmd $w s"
439  $mctxt add command -label [ ::tr DockLeft] -state $state -command "::docking::ctx_cmd $w w"
440  $mctxt add command -label [ ::tr DockRight] -state $state -command "::docking::ctx_cmd $w e"
441  # Main board can not be closed or undocked
442  if { [$w select] != ".fdockmain" } {
443  $mctxt add separator
444  $mctxt add command -label [ ::tr Undock] -command "::docking::undock $w"
445  $mctxt add command -label [ ::tr Close] -command " ::docking::close $w"
446  }
447  tk_popup $mctxt [winfo pointerx .] [winfo pointery .]
448 }
449 ################################################################################
450 proc ::docking::close {w} {
451  set tabid [$w select]
452  if {[winfo exists $tabid]} {
453  $w forget $tabid
454  destroy $tabid
455  }
456  _cleanup_tabs $w
458 }
459 ################################################################################
460 proc ::docking::undock {srctab} {
461  variable tbs
462  if {[llength [$srctab tabs]]==1 && [llength [array names tbs]]==1} { return}
463 
464  set f [$srctab select]
465  if {! [winfo exists $f]} { return}
466 
467  set name [$srctab tab $f -text]
468  set o [$srctab tab $f]
469 
470  $srctab forget $f
471  _cleanup_tabs $srctab
472 
473  wm manage $f
474 
475  setMenuVisibility $f true
476 
477  wm title $f "Scid: $name"
478  setWinLocation $f
479  setWinSize $f
480 
481  # Uncomment this code to dock windows that have been previously undocked
482  # wm protocol $f WM_DELETE_WINDOW [namespace code [list __dock $f]]
483 
484  wm deiconify $f
485  set ::docking::notebook_name($f) [list $srctab $o]
487 }
488 
489 ################################################################################
490 proc ::docking::__dock {wnd} {
491  variable tbs
492 
493  setMenuVisibility $wnd false
494 
495  set name [wm title $wnd]
496  wm withdraw $wnd
497  wm forget $wnd
498 
499  set d $::docking::notebook_name($wnd)
500 
501  set dsttab [lindex $d 0]
502  set o [lindex $d 1]
503 
504  if {![winfo exists $dsttab]} {
505  set dsttab [lindex [array names tbs] 0]
506  }
507  eval $dsttab add $wnd $o
508  raise $wnd
509  $dsttab select $wnd
510 }
511 
512 ################################################################################
513 # The coefficients for the selections of the container Notebook
514 # have been calculated doing a linear regression of this matrix:
515 # board tabs tabs^2 similar sim^2 sim^3 area fitness
516 # 0 0 0 0 0 0 0,9 120900
517 # 0 0 0 0 0 0 0,5 120500
518 # 0 0 0 0 0 0 0,1 120100
519 # 0 5 25 5 25 125 0,9 99900
520 # 0 5 25 5 25 125 0,5 99500
521 # 0 5 25 5 25 125 0,1 99100
522 # 0 3 9 3 9 27 0,9 93900
523 # 0 3 9 3 9 27 0,5 93500
524 # 0 3 9 3 9 27 0,1 93100
525 # 0 2 4 2 4 8 0,9 87900
526 # 0 2 4 2 4 8 0,5 87500
527 # 0 2 4 2 4 8 0,1 87100
528 # 0 4 16 3 9 27 0,9 81900
529 # 0 4 16 3 9 27 0,5 81500
530 # 0 4 16 3 9 27 0,1 81100
531 # 0 3 9 2 4 8 0,9 75900
532 # 0 3 9 2 4 8 0,5 75500
533 # 0 3 9 2 4 8 0,1 75100
534 # 0 2 4 1 1 1 0,9 69900
535 # 0 2 4 1 1 1 0,5 69500
536 # 0 2 4 1 1 1 0,1 69100
537 # 0 3 9 1 1 1 0,9 63900
538 # 0 3 9 1 1 1 0,5 63500
539 # 0 3 9 1 1 1 0,1 63100
540 # 0 2 4 1 1 1 0,9 57900
541 # 0 2 4 1 1 1 0,5 57500
542 # 0 2 4 1 1 1 0,1 57100
543 # 0 1 1 0 0 0 0,9 39900
544 # 0 1 1 0 0 0 0,5 39500
545 # 0 1 1 0 0 0 0,1 39100
546 # 0 3 9 0 0 0 0,9 33900
547 # 0 3 9 0 0 0 0,5 33500
548 # 0 3 9 0 0 0 0,1 33100
549 # 1 2 4 1 1 1 0,9 9900
550 # 1 2 4 1 1 1 0,5 9500
551 # 1 2 4 1 1 1 0,1 9100
552 # 1 1 1 0 0 0 0,9 7900
553 # 1 1 1 0 0 0 0,5 7500
554 # 1 1 1 0 0 0 0,1 7100
555 # 1 2 4 0 0 0 0,9 5900
556 # 1 2 4 0 0 0 0,5 5500
557 # 1 2 4 0 0 0 0,1 5100
558 # Improving the matrix and recalculating can improve the select algorithm
559 proc ::docking::add_tab { {path} {title} } {
560  variable tbs
561 
562  if { $::docking::layout_dest_notebook == ""} {
563  set dsttab {}
564  set best_fitting ""
565  foreach tb [array names ::docking::tbs] {
566  if {[::docking::get_class $tb] != "TNotebook"} { continue}
567 
568  set tabs [$tb tabs]
569 
570  # Features
571  set feat(0) 1
572  set coeff(0) "105622.84"
573  # number of boards
574  set feat(1) [llength [lsearch -all -regexp $tabs ".*main"]]
575  set coeff(1) "-48019.31"
576  # number of tabs
577  set feat(2) [llength $tabs]
578  set coeff(2) "-51266.84"
579  # number of tabs^2
580  set feat(3) [expr { $feat(2) * $feat(2) }]
581  set coeff(3) "8661.97"
582  # number of similar windows
583  set name_striptrailnum [regsub {\d*$} $path ""]
584  set feat(4) [llength [lsearch -all -regexp $tabs ".*$name_striptrailnum.*"]]
585  set coeff(4) "29942.45"
586  # number of similar windows^2
587  set feat(5) [expr { $feat(4) * $feat(4) }]
588  set coeff(5) "-3053.05"
589  # number of similar windows^3
590  set feat(6) [expr { $feat(4) * $feat(4) * $feat(4) }]
591  set coeff(6) "-323.52"
592  # ratio between the area of the notebook and the screen
593  set feat(7) [expr { double([winfo width $tb] * [winfo height $tb]) }]
594  set feat(7) [expr { $feat(7) / ([winfo screenwidth $tb] * [winfo screenheight $tb]) }]
595  set coeff(7) "1000"
596 
597  set fit 0;
598  for {set i 0} {$i < [array size feat]} {incr i} {
599  set fit [expr { $fit + $feat($i) * $coeff($i)}]
600  }
601 
602  if {$best_fitting == "" || $fit > $best_fitting} {
603  set best_fitting $fit
604  set dsttab $tb
605  }
606  }
607  } else {
608  set dsttab $::docking::layout_dest_notebook
609  }
610 
611  $dsttab add $path -text "$title"
612  setMenuMark $dsttab $path
613  $dsttab select $path
614 }
615 ################################################################################
616 # display a blue triangle showing the tab has a menu associated
617 proc ::docking::setMenuMark { nb tab} {
618  if { $tab == ".fdockpgnWin" || [string match "\.fdocktreeWin*" $tab] || $tab == ".fdockccWindow" || \
619  $tab == ".fdockoprepWin" || $tab == ".fdockcrosstabWin" } {
620  $nb tab $tab -image tb_menu -compound left
621  } else {
622  $nb tab $tab -image tb_close -compound left
623  }
624 }
625 ################################################################################
626 # Layout management
627 ################################################################################
628 
629 set ::docking::layout_tbcnt 0
630 
631 # associates pw -> notebook list
632 array set ::docking::layout_notebook {}
633 
634 # associates notebook -> list of tabs
635 array set ::docking::layout_tabs {}
636 
637 # the notebook into which to create a new tab
638 set ::docking::layout_dest_notebook ""
639 
640 ################################################################################
641 # saves layout (bail out if some windows cannot be restored like FICS)
642 proc ::docking::layout_save { slot } {
643  if {! $::docking::USE_DOCKING} { return}
644  #TODo: Save FICS window
645 
646  # on Windows the geometry is false if the window was maximized (x and y offsets are the ones before the maximization)
647  set geometry [wm geometry .]
648  set ::docking::layout_list($slot) [list [list "MainWindowGeometry" $geometry]]
649  if {[wm state .] == "zoomed"} {
650  if { [scan $geometry "%dx%d+%d+%d" w h x y] == 4 } {
651  set geometry "${w}x${h}+0+0"
652  set ::docking::layout_list($slot) [list [list "MainWindowGeometry" $geometry "zoomed"]]
653  }
654  }
655 
656  lappend ::docking::layout_list($slot) [ layout_save_pw .pw]
657 }
658 ################################################################################
659 proc ::docking::layout_save_pw {pw} {
660  set ret {}
661 
662  # record sash position for each panes
663  set sashpos {}
664  for {set i 0} {$i < [ expr [llength [$pw panes]] -1]} {incr i} {
665  lappend sashpos [$pw sashpos $i]
666  }
667  lappend ret [list $pw [$pw cget -orient] $sashpos]
668 
669  foreach p [$pw panes] {
670  if {[get_class $p] == "TNotebook"} {
671  set wins [$p tabs]
672  set glistWins [lsearch -all $wins ".fdockglistWin*"]
673  set i [llength $glistWins]
674  while {$i > 1} {
675  incr i -1
676  set remove [lindex $glistWins $i]
677  set wins [lreplace $wins $remove $remove]
678  }
679  lappend ret [list "TNotebook" $p $wins]
680  }
681  if {[get_class $p] == "TPanedwindow"} {
682  lappend ret [ list "TPanedwindow" [layout_save_pw $p]]
683  }
684  }
685 
686  return $ret
687 }
688 
689 ################################################################################
690 # restores paned windows and internal notebooks
691 proc ::docking::layout_restore_pw { data } {
692  foreach elt $data {
693  set type [lindex $elt 0]
694 
695  if {$type == "MainWindowGeometry"} {
696  wm geometry . [lindex $elt 1]
697  layout_restore_pw [lindex $data 1]
698  if {[lindex $elt 2] == "zoomed"} {
699  if { $::windowsOS || $::macOS } {
700  wm state . zoomed
701  } else {
702  wm attributes . -zoomed
703  }
704  }
705  break
706  } elseif {$type == "TPanedwindow"} {
707  layout_restore_pw [lindex $elt 1]
708 
709  } elseif {$type == "TNotebook"} {
710  set name [lindex $elt 1]
711  set tabs [lindex $elt 2]
712  ::docking::layout_restore_nb $pw $name $tabs
713 
714  } else {
715  set pw [lindex $elt 0]
716  set orient [lindex $elt 1]
717  # we have sash geometry
718  if {[llength $elt] > 2} {
719  lappend ::docking::sashpos [ list $pw [lindex $elt 2]]
720  }
721  if { $pw == ".pw"} { continue}
722  # build a new pw
723  ttk::panedwindow $pw -orient $orient
724 
725  set parent [string range $pw 0 [expr [string last "." $pw]-1]]
726  $parent add $pw -weight 1
727  }
728 
729  }
730 
731 }
732 ################################################################################
733 # Sash position
734 ################################################################################
735 proc ::docking::restoreGeometry {} {
736  foreach elt $::docking::sashpos {
737  set pw [lindex $elt 0]
738  set sash [lindex $elt 1]
739  set i 0
740  foreach pos $sash {
741  update
742  $pw sashpos $i $pos
743  incr i
744  }
745  }
746 }
747 ################################################################################
748 # restores a notebook in a pre-existing panedwindow
749 # panewindow -> pw
750 # widget name -> name
751 # data to make tabs -> data (list of names which can be used to trigger the correct windows)
752 proc ::docking::layout_restore_nb { pw name tabs} {
753  variable tbcnt
754  variable tbs
755 
756  set nb [ttk::notebook $name]
757  incr tbcnt
758  if {[scan $name ".tb%d" tmp] == 1} {
759  if {$tmp >= $tbcnt} {
760  set tbcnt [ expr $tmp +1]
761  }
762  }
763 
764  set tbs($nb) $pw
765  $pw add $nb -weight 1
766  set ::docking::tbs($nb) $pw
767  lappend ::docking::restoring_nb $nb
768  set ::docking::restoring_tabs($nb) $tabs
769 }
770 
771 proc ::docking::restore_tabs {} {
772  set old_dest $::docking::layout_dest_notebook
773  foreach nb $::docking::restoring_nb {
774  foreach d $::docking::restoring_tabs($nb) {
775  set ::docking::layout_dest_notebook $nb
776  if { $d == ".fdockmain" } {
777  $nb add $d -text $::tr(Board)
778  raise $d
779  }
780  if { $d == ".fdockpgnWin" } { ::pgn::OpenClose ; ::pgn::Refresh 1}
781  if { $d == ".fdockanalysisWin1" } { ::makeAnalysisWin 1 0 0}
782  if { $d == ".fdockanalysisWin2" } { ::makeAnalysisWin 2 0 0}
783  if { $d == ".fdockbaseWin" } { ::windows::switcher::Open}
784  if { $d == ".fdockbookWin" } { ::book::open}
785  if { $d == ".fdockecograph" } { ::windows::eco::OpenClose}
786  if { $d == ".fdocktbWin" } { ::tb::Open}
787  if { $d == ".fdockcommentWin" } { ::makeCommentWin}
788  if { [string first ".fdockglistWin" $d] != -1 } { ::windows::gamelist::Open}
789  if { $d == ".fdockccWindow" } {::CorrespondenceChess::CCWindow}
790  if { [ scan $d ".fdocktreeWin%d" base] == 1 } { ::tree::make $base}
791  if { $d == ".fdockoprepWin" } { ::optable::makeReportWin}
792  update
793  update idletasks
794  }
795  }
796 
797  set ::docking::layout_dest_notebook $old_dest
798  foreach nb $::docking::restoring_nb {
799  set ::docking::restoring_tabs($nb) {}
800  }
801  set ::docking::restoring_nb {}
802 }
803 
804 ################################################################################
805 proc ::docking::layout_restore { slot } {
806  variable tbcnt
807  variable tbs
808  bind TNotebook <<NotebookTabChanged>> {}
809 
810  # if no layout recorded, retry with the last used
811  if { $::docking::layout_list($slot) == {} } {
812  if { $slot != "auto" } { ::docking::layout_restore "auto"}
813  return
814  }
815 
816  closeAll {.pw}
817  set tbcnt 0
818  array set ::docking::notebook_name {}
819  array set ::docking::tbs {}
820  set ::docking::sashpos {}
821  if {[info exists ::docking::restoring_nb]} {
822  foreach nb $::docking::restoring_nb {
823  set ::docking::restoring_tabs($nb) {}
824  }
825  set ::docking::restoring_nb {}
826  }
827 
828  layout_restore_pw $::docking::layout_list($slot)
830 
831  array set ::docking::activeTab {}
833 
834  bind TNotebook <<NotebookTabChanged>> {::docking::tabChanged %W}
835  after idle ::docking::restore_tabs
836 }
837 ################################################################################
838 # for every notebook, keeps track of the last selected tab to see if the local menu can be popped up or not
839 proc ::docking::setTabStatus { } {
840  variable tbs
841  array set ::docking::activeTab {}
842  array set ::docking::changedTab {}
843 
844  foreach nb [array names tbs] {
845  set ::docking::activeTab($nb) [$nb select]
846  set ::docking::changedTab($nb) 0
847  }
848 
849 }
850 ################################################################################
851 # erase all mapped windows, except .main
852 proc ::docking::closeAll {pw} {
853 
854  foreach p [$pw panes] {
855 
856  if {[get_class $p] == "TPanedwindow"} {
858  }
859 
860  if {[get_class $p] == "TNotebook"} {
861  foreach tabid [$p tabs] {
862  $p forget $tabid
863  if {$tabid != ".fdockmain"} {
864  destroy $tabid
865  }
866  _cleanup_tabs $p
867  }
868  }
869 
870  destroy $p
871  }
872 }
873 
874 ################################################################################
875 if {$::docking::USE_DOCKING} {
876  pack [ttk::panedwindow .pw -orient vertical] -fill both -expand true
877  .pw add [ttk::notebook .nb] -weight 1
878 
879  set docking::tbs(.nb) .pw
880 
881 }
882