13 trace variable moveNum w {::utils::validate::Integer 999 0}
14 trace variable epFile w {::utils::validate::Regexp {^(-|[a-h])?$}}
15 trace variable castling w {::utils::validate::Regexp {^(-|[KQkq]*)$}}
27 global boardSizes boardSize lite dark setupBd pastePiece toMove epFile moveNum
29 global setupStatus castling setupFen highcolor
30 if {[
winfo exists .setup]} {
return}
31 set setupBd [
lindex [
sc_pos board] 0]
36 wm title $w "Scid: $::tr(SetupBoard)"
42 ttk::frame $w.statusbar
44 grid $w.l -row 1 -column 0 -sticky news
45 grid rowconfigure $w 1 -weight 1
46 grid columnconfigure $w 0 -weight 1
47 grid $w.r -row 1 -column 4 -sticky news
48 grid $w.statusbar -row 2 -column 0 -columnspan 5 -sticky news
49 grid $w.buttons -row 3 -column 0 -columnspan 5 -sticky news
54 for {
set i 0} { $i < 64 } {
incr i} {
55 ::board::bind $w.l.bd $i <B1-Motion> "dragBoardPiece $w.l.bd %X %Y $i"
56 ::board::bind $w.l.bd $i <ButtonRelease-1> "setupBoardPiece $w.l.bd %X %Y"
58 grid $w.l.bd -sticky news
59 grid rowconfigure $w.l.bd 0 -weight 1
60 grid columnconfigure $w.l.bd 0 -weight 1
63 foreach psize $::boardSizes {
64 if {$psize >= 40} { break}
66 grid [ttk::frame $w.spacePiecesLeft -width 10] -row 1 -column 1 -sticky news
67 grid [ttk::frame $w.pieces] -row 1 -column 2 -sticky news
68 grid [ttk::frame $w.pieces.spaceTop -height 2] -row 0 -columnspan 2
69 grid [ttk::frame $w.pieces.w] -row 1 -column 0 -sticky news
70 grid [ttk::frame $w.pieces.b] -row 1 -column 1 -sticky news
71 foreach i {p n b r q k} {
72 foreach color {w b} value "[
string toupper $i] $i" {
73 ttk::radiobutton $w.pieces.$color.$i -image $color$i$psize -variable pastePiece -value $value -style Toolbutton
74 grid $w.pieces.$color.$i -column 0 -pady 2 -padx 2
79 ttk::checkbutton $w.pieces.rotate -text $::tr(Rotate) -image tb_BD_Flip -compound left \
80 -variable ::setupBoardFlipped -command {
81 set ::setupBd [string reverse $::setupBd]
82 set ::setupFen [makeSetupFen]
83 ::board::update .setup.l.bd $::setupBd
84 ::board::flip .setup.l.bd
85 set ::setupBoardFlipped [::board::isFlipped .setup.l.bd]
87 grid $w.pieces.rotate -row 2 -columnspan 2 -sticky news -padx 2 -pady 2
91 set toMove [
lindex {White Black} [
string equal [
lindex $origFen 1] b]]
92 ttk::frame $w.r.tomove
93 ttk::label $w.r.tomove.label -textvar ::tr(SideToMove:)
94 ttk::frame $w.r.tomove.buttons
95 ttk::radiobutton $w.r.tomove.buttons.w -text $::tr(White) -variable toMove -value White \
96 -command {set setupFen [makeSetupFen]}
97 ttk::radiobutton $w.r.tomove.buttons.b -text $::tr(Black) -variable toMove -value Black \
98 -command {set setupFen [makeSetupFen]}
100 pack $w.r.tomove -pady 7
101 pack $w.r.tomove.label -side top -pady 2
102 pack $w.r.tomove.buttons -side top
103 pack $w.r.tomove.buttons.w $w.r.tomove.buttons.b -side left
106 pack [ttk::frame $w.r.mid] -padx 5 -pady 5
108 set moveNum [
lindex $origFen 5]
109 ttk::frame $w.r.mid.movenum
110 ttk::label $w.r.mid.movenum.label -textvar ::tr(MoveNumber:)
111 ttk::entry $w.r.mid.movenum.e -width 3 -background white -textvariable moveNum
113 pack $w.r.mid.movenum -pady 10 -expand yes -fill x
114 pack $w.r.mid.movenum.label $w.r.mid.movenum.e -side left -anchor w -expand yes -fill x
116 set castling [
lindex $origFen 2]
117 ttk::frame $w.r.mid.castle
118 ttk::label $w.r.mid.castle.label -textvar ::tr(Castling:)
119 ttk::combobox $w.r.mid.castle.e -width 5 -textvariable castling -values {KQkq K Q k q - KQ kq Kk Kq Kkq Qk Qq Qkq KQk KQq}
121 pack $w.r.mid.castle -pady 10 -expand yes -fill x
122 pack $w.r.mid.castle.label $w.r.mid.castle.e -side left -anchor w -expand yes -fill x
124 set epFile [
string index [
lindex $origFen 3] 0]
125 ttk::frame $w.r.mid.ep
126 ttk::label $w.r.mid.ep.label -textvar ::tr(EnPassantFile:)
127 ttk::combobox $w.r.mid.ep.e -width 2 -textvariable epFile -values {- a b c d e f g h}
129 pack $w.r.mid.ep -pady 10 -expand yes -fill x
130 pack $w.r.mid.ep.label $w.r.mid.ep.e -side left -anchor w -expand yes -fill x
136 foreach i "$w.r.mid.ep.e $w.r.mid.castle.e $w.r.mid.movenum.e" {
137 bind $i <Any-KeyPress> {after idle {set setupFen [makeSetupFen]}}
139 after idle {set setupFen [makeSetupFen]}}
144 ttk::button $w.r.b.clear -textvar ::tr(EmptyBoard) -command {
145 set setupBd "................................................................"
146 ::board::update .setup.l.bd $setupBd
148 set setupFen [makeSetupFen]
150 ttk::button $w.r.b.initial -textvar ::tr(InitialBoard) -command {
151 setSetupBoardToFen %W "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
153 ttk::button $w.r.b.switchcolor -text $::tr(SwitchColors) -command {
154 regsub -all {(?:([A-Z])|([a-z]))} $::setupBd {[string tolower "\1"][string toupper "\2"]} invertCase
155 set ::setupBd [subst $invertCase]
156 set ::toMove [expr {$::toMove == "White" ? "Black" : "White"}]
157 regsub -all {(?:([A-Z])|([a-z]))} $::castling {[string tolower "\1"][string toupper "\2"]} invertCase
158 set ::castling [subst $invertCase]
160 ::board::update .setup.l.bd $setupBd
161 set ::setupFen [makeSetupFen]
163 ttk::button $w.r.b.flip -text $::tr(FlipBoard) -command {
164 ::board::flip .setup.l.bd
165 set ::setupBoardFlipped [::board::isFlipped .setup.l.bd]
168 pack $w.r.b -side top -pady 15
169 pack $w.r.b.clear -side top -padx 5 -pady 5 -fill x
170 pack $w.r.b.initial -side top -padx 5 -pady 5 -fill x
171 pack $w.r.b.switchcolor -side top -padx 5 -pady 5 -fill x
172 pack $w.r.b.flip -side top -padx 5 -pady 5 -fill x
175 ttk::button $w.buttons.ok -text "OK" -width 7 -command exitSetupBoard
176 ttk::button $w.buttons.cancel -textvar ::tr(Cancel) -command {destroy .setup}
177 pack [ttk::frame $w.buttons.spaceTop -height 4] -side top
178 pack $w.buttons.cancel -side right -padx 5
179 pack $w.buttons.ok -side right -padx 5
181 ttk::button .setup.paste -textvar ::tr(PasteFen) -command {
182 if {[catch {set setupFen [selection get -selection CLIPBOARD]} ]} {
183 # PRIMARY is the X selection, unsure about CLIPBOARD
184 if {[catch {set setupFen [selection get -selection PRIMARY]}]} { return }
186 setSetupBoardToFen %W $setupFen
188 ttk::button .setup.clear -textvar ::tr(ClearFen) -command {set setupFen ""}
190 ttk::combobox .setup.status -textvariable setupFen -height 10
191 bind .setup.status <<ComboboxSelected>> {setSetupBoardToFen %W $setupFen}
195 pack .setup.paste .setup.clear -in .setup.statusbar -side left
196 pack .setup.status -in .setup.statusbar -side right -expand yes -fill x -anchor w
198 bind $w.l <Configure> "::board::resizeAuto $w.l.bd \[grid bbox $w 0 1\]"
199 bind $w <Destroy> "if {\[string equal $w %W\]} { ::win::saveWinGeometry $w }"
200 bind $w <Escape> {destroy .setup}
206 proc setSetupBoardToFen {w setupFen} {
207 global setupBd toMove castling epFile moveNum
210 if {[
catch {
sc_game startBoard $setupFen} err]} {
213 set ::setupFen [
sc_pos fen]
214 set setupBd [
lindex [
sc_pos board] 0]
215 set toMove [
lindex {White Black} [
string equal [
lindex $setupFen 1] b]]
216 set castling [
lindex $setupFen 2]
217 set epFile [
string index [
lindex $setupFen 3] 0]
218 set moveNum [
lindex $setupFen 5]
231 proc makeSetupFen {} {
232 global setupFen setupBd moveNum toMove castling epFile
235 if {$errorStr != ""} {
236 set fenStr "Invalid board: "
237 append fenStr $errorStr
240 for {
set bRow 56} {$bRow >= 0} {
incr bRow -8} {
241 if {$bRow < 56} {
append fenStr "/"}
243 for {
set bCol 0} {$bCol < 8} {
incr bCol} {
244 set sq [
expr {$bRow + $bCol}]
245 set piece [
string index $setupBd $sq]
250 append fenStr $emptyRun
256 if {$emptyRun > 0} {
append fenStr $emptyRun}
258 append fenStr " " [
string tolower [
string index $toMove 0]] " "
259 if {$castling == ""} {
262 append fenStr $castling " "
264 if {$epFile == "" || $epFile == "-"} {
267 append fenStr $epFile
268 if {$toMove == "White"} {
275 append fenStr " 0 " $moveNum
285 proc validateSetup {} {
287 set wkCount 0
set bkCount 0
set wCount 0
set bCount 0
288 set wpCount 0
set bpCount 0
289 for {
set i 0} {$i < 64} {
incr i} {
290 set p [
string index $setupBd $i]
292 }
elseif {$p == "P"} {
incr wCount
incr wpCount
293 }
elseif {$p == "p"} {
incr bCount
incr bpCount
294 }
elseif {$p == "N" || $p == "B" || $p == "R" || $p == "Q"} {
296 }
elseif {$p == "n" || $p == "b" || $p == "r" || $p == "q"} {
298 }
elseif {$p == "K"} {
incr wCount
incr wkCount
299 }
elseif {$p == "k"} {
incr bCount
incr bkCount
300 }
else {
return "Invalid piece: $p"}
301 if {$p == "P" || $p == "p"} {
302 if {$i < 8} {
return "There must be no pawn in the 1st row"}
303 if {$i >= 56} {
return "There must be no pawn in the 8th row"}
306 if {$wkCount != 1} {
return "There must be one white king"
307 }
elseif {$bkCount != 1} {
return "There must be one black king"
308 }
elseif {$wCount > 16} {
return "Too many white pieces"
309 }
elseif {$bCount > 16} {
return "Too many black pieces"
310 }
elseif {$wpCount > 8} {
return "Too many white pawns"
311 }
elseif {$bpCount > 8} {
return "Too many black pawns"}
315 proc dragBoardPiece {w x y startSq} {
318 set tmp [
string index $::setupBd $startSq]
319 if {$tmp == "."} {
return}
320 set ::pastePiece $tmp
327 proc setupBoardPiece {w x y} {
328 global setupBd pastePiece setupFen
331 set newPiece $pastePiece
332 set oldPiece [
string index $setupBd $square]
336 if {$delSq == $square} {
return}
337 set setupBd [
string replace $setupBd $delSq $delSq "."]
340 if {$oldPiece == $newPiece} {
345 set setupBd [
string replace $setupBd $square $square $newPiece]
350 proc exitSetupBoard {} {
354 if {[
catch {
sc_game startBoard $setupFen} err]} {
369 proc fenErrorDialog {{msg {}}} {
370 if {[
winfo exists .setup]} {
371 tk_messageBox -icon info -type ok -title "Scid: Invalid FEN" -message $msg -parent .setup
373 tk_messageBox -icon info -type ok -title "Scid: Invalid FEN" -message $msg
386 if {! [
winfo exists $w]} { text $w}
388 $w insert end $fen sel
390 clipboard append $fen
403 if {[
catch {
set fenStr [selection get -selection CLIPBOARD]}]} {
404 catch {
set fenStr [selection get -selection PRIMARY]}
406 set fenStr [
string trim $fenStr]
408 set fenExplanation {FEN is the standard text representation of a chess position. As an example, the FEN representation of the standard starting position is:
409 "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"}
412 set msg "The current text selection is empty. To paste the start board, select some text that contains a position in FEN notation.\n\n$fenExplanation"
416 if {[
catch {
sc_game startBoard $fenStr}]} {
417 if {[
string length $fenStr] > 80} {
418 set fenStr [
string range $fenStr 0 80]
421 set msg "\"$fenStr\" is not a valid chess position in FEN notation.\n\n $fenExplanation"