1# Copyright (C) 1987-2015 by Jeffery P. Hansen 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License along 14# with this program; if not, write to the Free Software Foundation, Inc., 15# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16# 17# Last edit by hansen on Sat Jan 31 08:14:59 2009 18# 19 20############################################################################# 21# 22# This file contains tcl scripts for creating and managing menus (except 23# popup menus). 24# 25# Menu states: 26# edit Normal edit mode is active 27# interface-all Top-level interface screen 28# interface-block Interface editor on a normal block is active 29# interface-symbol Interface editor on a symbol block is active 30# simulate Simulator is active 31# 32# Special Flags: 33# D Create only if debug mode is active 34# X If mode guard failed, do not create entry 35# 36# Base Flags: 37# C Active only if cutable object is selected 38# P Active only if pasteable object in cut buffer 39# U Active only if undoable actions exist 40# R Active only if redoable actions exist 41# b Symbol bitmap operations are active 42# p Symbol port operations are active 43# 44# 45namespace eval Menu { 46 variable accelTable 47 variable state edit 48 variable menuId 49 variable flags 50 array set flags {D 0 C 0 P 0 U 0 R 0 X 0} 51 52 variable baseFlags {C P R U b p} 53 variable baseFlagEntries 54 55 variable editorMenus {file edit tool simulate format module make help} 56 variable scopeMenus {scope_file scope_sim scope_trace scope_help} 57 58 # Name func. Flags Mode 59 variable menuButtonData { 60 {file - - *} 61 {edit - - *} 62 {tool - - {edit interface-*}} 63 {simulate - - {simulate}} 64 {module - - *} 65 {format - - edit} 66 {make gat_makeMakeMenu - edit} 67 {help - - *} 68 {scope_file - - *} 69 {scope_sim - - *} 70 {scope_trace - - *} 71 {scope_help - - *} 72 } 73 74 75 # 76 # This table contains information about all menu data. The entry names should have 77 # the form "name.ent" where "name" defines which menu it should belong to. The text 78 # for the menu is taken from the message "menu.name.ent" (e.g., for "file.new", the 79 # message tag will be "menu.file.new") 80 # 81 # Entry Name Action Image Sel. Image Var. Flags Mode 82 variable menuEntryData { 83 {file.new newFile file_new - - - *} 84 {file.open loadFile file_open - - - *} 85 {file.save saveFile file_save - - - *} 86 {file.saveas saveAsFile file_saveas - - - *} 87 {file.separator - - - - - *} 88 {file.print print file_print - - - *} 89 {file.separator - - - - - *} 90 {file.openlib loadLibrary file_lib - - - *} 91 {file.cprop editCProps i_circprops - - - *} 92 {file.separator - - - - X interface-symbol} 93 {file.import importImage symed_import - - X interface-symbol} 94 {file.export exportImage symed_export - - X interface-symbol} 95 {file.separator - - - - - *} 96 {file.quit exit emptytool - - - *} 97 98 {edit.undo undo back - - U {edit interface-*}} 99 {edit.redo redo forward - - R {edit interface-*}} 100 {edit.separator - - - - X {edit interface-symbol}} 101 {edit.cut cutToBuf edit_cut - - XC {edit}} 102 {edit.copy copyToBuf edit_copy - - XC {edit}} 103 {edit.paste yankFromBuf edit_paste - - XP {edit}} 104 {edit.cut seCutToBuf edit_cut - - XC {interface-symbol}} 105 {edit.copy seCopyToBuf edit_copy - - XC {interface-symbol}} 106 {edit.paste seYankFromBuf edit_paste - - XP {interface-symbol}} 107 {edit.overlay seOverlayFromBuf edit_overlay - - XP {interface-symbol}} 108 {edit.selall selectAll emptytool - - X edit} 109 {edit.find findObject edit_find - - X {edit simulate}} 110 111 {edit.separator - - - - X {edit simulate}} 112 {edit.zoomin zoomIn zoom_in - - X {edit simulate}} 113 {edit.zoomout zoomOut zoom_out - - X {edit simulate}} 114 {edit.separator - - - - X interface-symbol} 115 {edit.zoomin seZoomIn zoom_in - - X interface-symbol} 116 {edit.zoomout seZoomOut zoom_out - - X interface-symbol} 117 118 {edit.separator - - - - X interface-symbol} 119 {edit.rshift seRShiftBits arrow0 - - X interface-symbol} 120 {edit.lshift seLShiftBits arrow180 - - X interface-symbol} 121 {edit.ushift seUShiftBits arrow90 - - X interface-symbol} 122 {edit.dshift seDShiftBits arrow270 - - X interface-symbol} 123 {edit.cwrotate seCWRotate symed_cwrotate - - X interface-symbol} 124 {edit.ccwrotate seCCWRotate symed_ccwrotate - - X interface-symbol} 125 126 {edit.separator - - - - X interface-symbol} 127 {edit.pcwrotate seCWRotPort symed_pcrot - - X interface-symbol} 128 {edit.pccwrotate seCCWRotPort symed_pccrot - - X interface-symbol} 129 130 {edit.separator - - - - X interface-symbol} 131 {edit.autobold seBoldBits symed_autobold - - X interface-symbol} 132 133 {tool.move editMode mov_curs mov_curs_S mode=1 X {edit interface-all interface-block}} 134 {tool.cutw cutMode cut_curs cut_curs_S mode=0 X {edit interface-all interface-block}} 135 {tool.inv invertMode inv_curs inv_curs_S mode=2 X edit} 136 {tool.bitw sizeMode size_curs size_curs_S mode=9 X {edit interface-all interface-block}} 137 {tool.debug debugMode bug_curs bug_curs_S mode=12 XD edit} 138 139 {tool.point null symed_point symed_point_S SymbolEdit::emode=point X interface-symbol} 140 {tool.line null symed_line symed_line_S SymbolEdit::emode=line X interface-symbol} 141 {tool.rect null symed_rect symed_rect_S SymbolEdit::emode=rect X interface-symbol} 142 {tool.fillrect null symed_fillrect symed_fillrect_S SymbolEdit::emode=fillrect X interface-symbol} 143 {tool.port null symed_port symed_port_S SymbolEdit::emode=port X interface-symbol} 144 {tool.select null symed_select symed_select_S SymbolEdit::emode=select X interface-symbol} 145 146 147 {tool.separator - - - - X edit} 148 {tool.rep replicate replicate - - - *} 149 150 {tool.separator - - - - - *} 151 {tool.options editOptions emptytool - - - *} 152 {tool.tclshell shellWindow emptytool - - D *} 153 154 {simulate.begin startSimulator simstart - - X {edit interface-*}} 155 {simulate.end endSimulator simstart - - X simulate} 156 {simulate.separator - - - - X simulate} 157 {simulate.run simRun sim_go - - X simulate} 158 {simulate.pause simStop sim_stop - - X simulate} 159 {simulate.step simStep sim_step - - X simulate} 160 {simulate.cycle simCycleOrRotate sim_clock - - X simulate} 161 {simulate.break editBreakpoints sim_break - - X simulate} 162 {simulate.script doSimScript sim_script - - X simulate} 163 {simulate.separator - - - - X simulate} 164 {simulate.load simLoadMem sim_load - - X simulate} 165 {simulate.dump simDumpMem sim_dump - - X simulate} 166 {simulate.view simViewMem sim_view - - X simulate} 167 {simulate.separator - - - - X simulate} 168 {simulate.addprobe toggleProbe emptytool - - X simulate} 169 170 {module.open openMod blk_open - - - *} 171 {module.close closeMod blk_close - - - *} 172 {module.separator - - - - X edit} 173 {module.interface -cascade editintr - - X edit} 174 {module.interface.edit editBlockDesc - - - - *} 175 {module.interface.set setBlockDesc - - - - *} 176 {module.interface.update updateInterface - - - - *} 177 {module.interface.updateall updateAllInterface - - - - *} 178 {module.interface.auto autoGenerateCanvas - - - - *} 179 180 {module.separator - - - - X {edit interface-*}} 181 {module.new blockNew blk_new - - X {edit interface-*}} 182 {module.del blockDelete blk_delete - - X {edit interface-*}} 183 {module.copy blockCopy blk_copy - - X {edit interface-*}} 184 {module.rename blockRename blk_rename - - X {edit interface-*}} 185 {module.claim blockClaim blk_claim - - X {edit interface-*}} 186 {module.setroot blockSetRoot blk_root - - X {edit interface-*}} 187 {module.prop blockProp i_modprops - - X {edit interface-*}} 188 189 {format.addport addPort addport - - - *} 190 {format.separator - - - - - *} 191 {format.anchor anchor anchor - - - *} 192 {format.unanchor unAnchor unanchor - - - *} 193 {format.separator - - - - X edit} 194 {format.algnv vAlign edit_valgn - - X edit} 195 {format.algnh hAlign edit_halgn - - X edit} 196 {format.separator - - - - - *} 197 {format.settech -cascade emptytool - - - *} 198 {format.rot -cascade rotation0 - - X edit} 199 {format.rot.0 rot0 rotation0 rotation0_S rot=0 X edit} 200 {format.rot.90 rot90 rotation90 rotation90_S rot=1 X edit} 201 {format.rot.180 rot180 rotation180 rotation180_S rot=2 X edit} 202 {format.rot.270 rot270 rotation270 rotation270_S rot=3 X edit} 203 {format.rot.separator -separator - - - - edit} 204 {format.rot.rotate simCycleOrRotate edit_rotate - - X edit} 205 {format.rot.brotate backRotate edit_brotate - - X edit} 206 {format.prop editProps i_gateprops - - - *} 207 208 {help.about showAbout about - - - *} 209 {help.license showLicense gnuhead - - - *} 210 {help.doc showDocumentation helpdoc - - - *} 211 {help.separator - - - - - *} 212 {help.home loadWelcome helpdoc - - - edit} 213 {help.tut loadTutorial helpdoc - - - edit} 214 {help.example loadExample helpdoc - - - edit} 215 216 {scope_file.ptrace printTrace file_print - - - *} 217 {scope_file.close endSimulator simstart - - - *} 218 219 {scope_sim.run simRun sim_go - - - *} 220 {scope_sim.pause simStop sim_stop - - - *} 221 {scope_sim.step simStep sim_step - - - *} 222 {scope_sim.cycle simCycleOrRotate sim_clock - - - *} 223 {scope_sim.break editBreakpoints sim_break - - - *} 224 {scope_sim.script doSimScript sim_script - - - *} 225 {scope_sim.separator - - - - - *} 226 {scope_sim.load simLoadMem sim_load - - - *} 227 {scope_sim.dump simDumpMem sim_dump - - - *} 228 {scope_sim.separator - - - - - *} 229 {scope_sim.addprobe toggleProbe emptytool - - - *} 230 231 {scope_trace.zoomin scopeZoomIn zoom_in - - - *} 232 {scope_trace.zoomout scopeZoomOut zoom_out - - - *} 233 234 {scope_help.about showAbout about - - - *} 235 {scope_help.license showLicense gnuhead - - - *} 236 {scope_help.doc showDocumentation helpdoc - - - *} 237 } 238 239 proc menuEntry {m cLabel args} { 240 global menuCommandTable 241 variable accelTable 242 243 set command "" 244 set radio 0 245 set state normal 246 set variable "" 247 set value "" 248 set image "" 249 set selectimage "" 250 set menu "" 251 parseargs $args {-command -state -variable -value -radio -image -selectimage -menu} 252 253 parseName $cLabel label underline 254 255 set accelerator "" 256 if {[info exists accelTable($command)]} { 257 set accelerator $accelTable($command) 258 } 259 260 set index "" 261 262 # 263 # The -image, -selectimage and -compound options are not supported before Tk 8.4, so 264 # we must check for an error and be ready to generate menu entries without symbols. 265 # 266 if {$menu != ""} { 267 safeeval $::menu_forbidden $m add cascade -label $label -underline $underline -menu $menu \ 268 -state $state -image $image -compound left 269 set index [$m index end] 270 } elseif {$radio} { 271 if { $image != "" } { 272 safeeval $::menu_forbidden $m add radiobutton -label $label -underline $underline -command $command \ 273 -state $state -variable $variable -value $value \ 274 -image $image -selectimage $selectimage -compound left -indicatoron 0 -accelerator $accelerator 275 set index [$m index end] 276 } else { 277 $m add radiobutton -label $label -underline $underline -command $command \ 278 -state $state -variable $variable -value $value -accelerator $accelerator 279 set index [$m index end] 280 } 281 } else { 282 safeeval $::menu_forbidden $m add command -label $label -underline $underline -command $command \ 283 -state $state -image $image -compound left -accelerator $accelerator 284 set index [$m index end] 285 } 286 287 # 288 # This is a kludge to exclude popup menus. 289 # 290 if {! [string match ".pop_*" $m ] } { 291 set idx [$m index end] 292 lappend menuCommandTable($command) ${idx}:$m 293 } 294 295 return $index 296 } 297 298 proc parseName {cName _name _ul} { 299 upvar $_name name 300 upvar $_ul ul 301 302 set name "" 303 set ul -1 304 if { [scan $cName "%d:%\[^\n\]" ul name] != 2 } { 305 set name $cName 306 } 307 } 308 309 ############################################################################# 310 # 311 # Rebuild the menus for $tag. 312 # 313 proc rebuildMenu {tag} { 314 variable menuId 315 316 foreach m $menuId($tag) { 317 if {$tag == "make"} continue 318 $m delete 0 end 319 foreach sm [winfo children $m] { 320 $sm delete 0 end 321 } 322 makeMenu $m $tag 323 } 324 } 325 326 proc rebuildAll {} { 327 variable menuButtonData 328 variable menuId 329 variable state 330 variable baseFlags 331 variable baseFlagEntries 332 333 # 334 # Clear the base flags 335 # 336 foreach f $baseFlags { 337 set baseFlagEntries($f) {} 338 } 339 340 foreach b $menuButtonData { 341 set name [lindex $b 0] 342 set func [lindex $b 1] 343 set flags [lindex $b 2] 344 set gstate [lindex $b 3] 345 346 set itemstate disabled 347 foreach x $gstate { 348 if {[string match $x $state]} { 349 set itemstate normal 350 } 351 } 352 353 foreach m $menuId($name) { 354 catch { [winfo parent $m] configure -state $itemstate } 355 } 356 357 if {$itemstate == "normal" } { 358 catch { rebuildMenu $name } 359 } 360 } 361 } 362 363 364 365 ############################################################################# 366 # 367 # Make the menu for $tag in the menu $w 368 # 369 proc makeMenu {m tag} { 370 variable menuEntryData 371 variable menuButtonData 372 variable menuId 373 variable flags 374 variable state 375 variable baseFlags 376 variable baseFlagEntries 377 378 # 379 # Register the menu. 380 # 381 if {![info exists menuId($tag)]} {set menuId($tag) {}} 382 if {[lsearch $menuId($tag) $m] < 0} { 383 lappend menuId($tag) $m 384 } 385 386 # 387 # If a custom creation function is specified, use that function and return. 388 # 389 set button [assocg $tag $menuButtonData] 390 if {[lindex $button 1] != "-"} { 391 [lindex $button 1] $m 392 return 393 } 394 395 # 396 # Create the menu entries 397 # 398 foreach entry $menuEntryData { 399 set name "" 400 set action "" 401 set image "" 402 set simage "" 403 set varval "" 404 lscan $entry name action image simage varval gflags gstate 405 406 # 407 # Seprate name into chars before last "." and chars after last "." 408 # 409 set lname [string map {. " "} $name] 410 set mname [lindex $lname 0] 411 set ename [lindex $lname 1] 412 413 if {$mname != $tag } continue 414 415 # 416 # Check to see if we are disabled due to a guarded state 417 # 418 set itemstate disabled 419 foreach x $gstate { 420 if {[string match $x $state]} { 421 set itemstate normal 422 } 423 } 424 425 # 426 # If we are disabled due to a guarded state and the X flag is set, then ignore this entry. 427 # 428 if {[string first "X" $gflags] >= 0 && $itemstate != "normal"} { 429 continue 430 } 431 432 # 433 # If debug flag is required, but not set, then ignore this entry 434 # 435 if {[string first "D" $gflags] >= 0 && !$flags(D)} { 436 continue 437 } 438 439 # 440 # Test other regular flags. Set item to disabled if the test fails. 441 # 442 foreach f $baseFlags { 443 if {[info exists flags($f)] && !$flags($f) } { 444 if {[string first $f $gflags] >= 0 } { 445 set itemstate disabled 446 } 447 } 448 } 449 450 if {$image != "" && $image != "-"} { set image [gifI $image.gif]} { set image "" } 451 if {$simage != "" && $simage != "-"} { set simage [gifI $simage.gif]} { set simage "" } 452 453 set index "" 454 455 if {[llength $lname] > 2} { 456 set subm [string map {" " .} [lrange $lname 1 [expr [llength $lname]-2]]] 457 set em $m.$subm 458 set lname {} 459 } else { 460 set em $m 461 } 462 463 catch { menu $em } 464 if { $ename == "separator" || $action == "-separator"} { 465 # This is a spearator entry 466 $em add separator 467 set index [$em index last] 468 } elseif { $action == "-cascade" } { 469 # This is an cascade parent 470 set submenu $em.$ename 471 catch { menu $em.$ename -tearoff 0} 472 set index [menuEntry $em [m menu.$name] -menu $submenu -image $image -state $itemstate] 473 } elseif { $varval != "-"} { 474 set var "" 475 set val "" 476 scan $varval "%\[^=\]=%s" var val 477 set index [menuEntry $em [m menu.$name] -command Action::$action -radio 1 \ 478 -variable $var -value $val -image $image -selectimage $simage -state $itemstate] 479 } else { 480 # This is a normal command entry 481 set index [menuEntry $em [m menu.$name] -command Action::$action -image $image -state $itemstate] 482 } 483 484 # 485 # Record menu entries that use 486 # 487 for {set i 0} {$i < [string length $gflags] } { incr i } { 488 set f [string index $gflags $i] 489 if {[string is alnum $f] && [lsearch $baseFlags $f] >= 0 } { 490 if {![info exists baseFlagEntries($f)] || [lsearch $baseFlagEntries($f) [list $em $index] ] < 0 } { 491 lappend baseFlagEntries($f) [list $em $index] 492 } 493 } 494 } 495 496 } 497 } 498 499 500 ###################################################################### 501 # 502 # This procedure builds the actual menu bar. It is assumed that the frame 503 # for the menu bar has already been created. 504 # 505 proc makeBar {w type} { 506 variable menuButtonData 507 variable menuEntryData 508 variable menuId 509 variable baseFlags 510 variable baseFlagEntries 511 variable editorMenus 512 variable scopeMenus 513 514 switch $type { 515 editor { set menuList $editorMenus } 516 scope { set menuList $scopeMenus } 517 } 518 519 # 520 # Clear the base flags 521 # 522 foreach f $baseFlags { 523 set baseFlagEntries($f) {} 524 } 525 526 frame $w -takefocus 1 527 528 # 529 # Initialize menuId for all buttons if necessary 530 # 531 foreach button $menuButtonData { 532 set name [lindex $button 0] 533 534 if {![info exists menuId($name)]} { 535 set menuId($name) {} 536 } 537 } 538 539 # 540 # Create the menu buttons 541 # 542 foreach button $menuList { 543 set data [assocg $button $menuButtonData] 544 set name [lindex $data 0] 545 set func [lindex $data 1] 546 547 parseName [m menu.$name] label ul 548 menubutton $w.$name -text $label -underline $ul -menu $w.$name.menu 549 pack $w.$name -in $w -side left 550 551 makeMenu $w.$name.menu $name 552 } 553 554# bind $w <FocusIn> { puts FocusIn } 555# bind $w <FocusOut> { puts FocusOut } 556 } 557 558 ############################################################################# 559 # 560 # Register a key sequence with a command. 561 # 562 # Parameters: 563 # cmd Name of command to register. 564 # keyseq Key sequenc corresponding to a command. 565 # 566 proc setAccelerator {cmd keyseq} { 567 variable accelTable 568 569 set accelTable($cmd) $keyseq 570 } 571 572 ############################################################################# 573 # 574 # Set or clear flags that can control menu appearance 575 # 576 proc setFlags args { 577 variable flags 578 variable baseFlags 579 variable baseFlagEntries 580 581 set state 1 582 set estate "normal" 583 set rebuild 0 584 585 foreach f $args { 586 if {$f == "-clear"} { 587 set state 0 588 set itemstate disabled 589 } elseif {$f == "-set"} { 590 set state 1 591 set itemstate normal 592 } elseif {[lsearch $baseFlags $f] >= 0 } { 593 if { $flags($f) == $state } continue 594 set flags($f) $state 595 596 foreach p $baseFlagEntries($f) { 597 [lindex $p 0] entryconfigure [lindex $p 1] -state $itemstate 598 } 599 } else { 600 if { $flags($f) == $state } continue 601 set flags($f) $state 602 set rebuild 1 603 } 604 } 605 606 if {$rebuild} { 607 rebuildAll 608 } 609 } 610 611 ############################################################################# 612 # 613 # Inform the menu manager of the current tkgate mode. 614 # 615 proc setState {s} { 616 variable state 617 618 if {$s == $state } return 619 620 set state $s 621 rebuildAll 622 } 623} 624