1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
|
#!/usr/bin/tclsh
# Part of MCU 8051 IDE ( http://https://sourceforge.net/projects/mcu8051ide/ )
############################################################################
# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 by Martin Ošmera #
# martin.osmera@gmail.com #
# #
# Copyright (C) 2014 by Moravia Microsystems, s.r.o. #
# martin.osmera@gmail.com #
# #
# This program is free software; you can redistribute it and#or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the #
# Free Software Foundation, Inc., #
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
############################################################################
# >>> File inclusion guard
if { ! [ info exists _SYMBOL_VIEWER_TCL ] } {
set _SYMBOL_VIEWER_TCL _
# <<< File inclusion guard
# --------------------------------------------------------------------------
# DESCRIPTION
# Implements assembly language symbols viewer (from code listing)
# --------------------------------------------------------------------------
class SymbolViewer {
## Class variables
# Int: Counter of object intances
public common count 0
# Font: Just normal font used in the table
public common normal_font [font create \
-family $::DEFAULT_FIXED_FONT \
-size [expr {int(-14 * $::font_size_factor)}] \
-weight normal \
]
# Font: Bold font (the same size as $normal_font)
public common bold_font [font create \
-family $::DEFAULT_FIXED_FONT \
-size [expr {int(-14 * $::font_size_factor)}] \
-weight bold \
]
if {$::MICROSOFT_WINDOWS} {
# it's better to do not use bold font for this purpose on MS Windows®
set bold_font $normal_font
}
# Dialog configuration
public common config_list $::CONFIG(SYMBOL_VIEWER_CONFIG)
## Private object variables
private variable obj_idx ;# Int: Current object number
private variable symbol_table_data {} ;# List: Data loaded from the code listing (see func. open_file)
private variable current_line {} ;# List: Current line data (selected lide in the table)
private variable opened_file {} ;# String: Full file name of the currently loaded code listing file
private variable win ;# Widget: Dialog window
private variable menu ;# Widget: Popup menu for the text widget
private variable main_frame ;# Widget: Dialog main frame
private variable reload_but ;# Widget: Button "Reload"
private variable search_entry ;# Widget: EntryBox "Search"
private variable clear_but ;# Widget: Button "Clear search entrybox"
private variable status_bar_lbl ;# Widget: Status bar label widget
private variable opened_file_lbl ;# Widget: Label on statusbar showing name of currently opened file
private variable text_widget ;# Widget: Text widget containing the table of symbols
constructor {} {
# Create dialog window
set win [toplevel .symbolviewer$count -class {Defined symbols} -bg ${::COMMON_BG_COLOR}]
set obj_idx $count
incr count
# Create dialog GUI
set main_frame [frame $win.main_frame]
create_gui ;# Create widgets
create_menus ;# Create menus
create_tags ;# Create text tags
create_bindings ;# Set event bindings
# Set values for checkboxes in panel "Display"
set i 0
foreach name {DATA IDATA XDATA CODE BIT Number used unused} {
set ::SymbolViewer::display_${obj_idx}($name) [lindex $config_list $i]
incr i
}
# Set values for radiobuttons in panel "Sort by"
set ::SymbolViewer::sort_by_${obj_idx} [lindex $config_list $i]
incr i
set ::SymbolViewer::sort_by_order_${obj_idx} [lindex $config_list $i]
incr i
# Finalize GUI
pack $main_frame -fill both -expand 1 -padx 5 -pady 5
bindtags $win [list $win Toplevel all .]
focus -force $search_entry
# Configure dialog window
wm iconphoto $win ::ICONS::16::symbol
wm title $win [mc "Assembly symbol table - MCU 8051 IDE"]
wm minsize $win 520 350
wm protocol $win WM_DELETE_WINDOW "$this close_window"
update
catch {
wm geometry $win [regsub {^\=?\d+x\d+} [lindex $config_list $i] \
[regsub {\+\d+\+\d+$} [wm geometry $win] {}] \
]
}
# Set ...
incr i
set ::SymbolViewer::display_${obj_idx}(Special) [lindex $config_list $i]
if {[subst -nocommands "\$::SymbolViewer::display_${obj_idx}(Special)"] == {}} {
set ::SymbolViewer::display_${obj_idx}(Special) 1
}
}
destructor {
# Save tool configuration
if {[llength $config_list] < 12} {
set config_list [list {} {} {} {} {} {} {} {} {} {} {} {}]
}
set i 0
foreach name {DATA IDATA XDATA CODE BIT Number used unused} {
lset config_list $i [subst -nocommands "\$::SymbolViewer::display_${obj_idx}($name)"]
incr i
}
lset config_list $i [subst -nocommands "\$::SymbolViewer::sort_by_${obj_idx}"]
incr i
lset config_list $i [subst -nocommands "\$::SymbolViewer::sort_by_order_${obj_idx}"]
incr i
lset config_list $i [wm geometry $win]
incr i
lset config_list $i [subst -nocommands "\$::SymbolViewer::display_${obj_idx}(Special)"]
# Clean up
unset ::SymbolViewer::sort_by_${obj_idx}
unset ::SymbolViewer::sort_by_order_${obj_idx}
array unset ::SymbolViewer::display_${obj_idx}
# Remove dialog window
destroy $win
}
## Create menus
# @return void
private method create_menus {} {
## Create text widget popup menu
set menu [menu $text_widget.menu]
$menu add command -label [mc "Copy symbol name"] -compound left \
-underline 12 -command "$this text_copy_proc name"
$menu add command -label [mc "Copy hex value"] -compound left \
-underline 5 -command "$this text_copy_proc hex"
$menu add command -label [mc "Copy dec value"] -compound left \
-underline 5 -command "$this text_copy_proc dec"
$menu add separator
$menu add command -label [mc "Copy line"] -compound left \
-underline 1 -command "$this text_copy_proc line" \
-image ::ICONS::16::editcopy -accelerator {Ctrl+C}
}
## Set event bindings for window widgets
# @return void
private method create_bindings {} {
bind $text_widget <ButtonRelease-3> "$this invoke_popup_menu %X %Y %x %y; break"
bind $text_widget <<Selection>> "false_selection $text_widget; break"
bind $text_widget <Button-1> "focus %W; $this select_line %x %y"
bind $text_widget <Key-Down> "$this key_down"
bind $text_widget <Key-Up> "$this key_up"
bind $text_widget <Control-Key-c> "$this text_copy_proc line; break"
bind $win <Control-Key-o> "$this open_file_dialog; break"
bind $win <Key-F5> "$this reload; break"
bind $win <Control-Key-q> "$this close_window; break"
bindtags $search_entry [list $search_entry TEntry $win all .]
bindtags $text_widget [list $text_widget Text $win all .]
}
## Create text tags
# @return void
private method create_tags {} {
$text_widget tag configure type_DATA -foreground {#00DD00}
$text_widget tag configure type_IDATA -foreground {#0000DD}
$text_widget tag configure type_XDATA -foreground {#DD0000}
$text_widget tag configure type_CODE -foreground {#00DDDD}
$text_widget tag configure type_BIT -foreground {#AA8800}
$text_widget tag configure type_Special -foreground {#AA00FF}
$text_widget tag configure type_Number -foreground {#DD00DD}
$text_widget tag configure used_YES -foreground {#00DD00}
$text_widget tag configure used_NO -foreground {#DD0000}
$text_widget tag configure tag_sel -background {#DDDDDD} -font $bold_font
$text_widget tag configure nth_row -background ${::COMMON_BG_COLOR}
$text_widget tag raise tag_sel nth_row
}
## Create window widgets
# @return void
private method create_gui {} {
# Create window frames
set top_frame [frame $main_frame.top_frame] ;# Button "Open"+"Reload" + Search bar
set middle_frame [frame $main_frame.middle_frame] ;# Table of symbols
set bottom_frame [frame $main_frame.bottom_frame] ;# Display options
set sbar_frame [frame $main_frame.sbar_frame] ;# Status bar
## Create status bar
set status_bar_lbl [label $sbar_frame.main_lbl \
-justify left -anchor w \
]
set opened_file_lbl [label $sbar_frame.opened_file_lbl -fg {#0000DD}]
pack $status_bar_lbl -fill x -side left
pack $opened_file_lbl -side right -after $status_bar_lbl
## Create top frame
# Button "Open file"
pack [ttk::button $top_frame.open_but \
-image ::ICONS::16::fileopen \
-text [mc "Open *.LST"] \
-compound left \
-command "$this open_file_dialog" \
] -side left
DynamicHelp::add $top_frame.open_but \
-text [mc "Load table of symbols from list file (*.lst)\n\tOnly for: ASEM-51, MCU8051IDE and ASM51"]
set_locat_status_tip $top_frame.open_but [mc "Open code listing"]
# Button "Reload"
set reload_but [ttk::button $top_frame.reload_but \
-image ::ICONS::16::reload \
-text [mc "Reload"] \
-compound left \
-command "$this reload" \
-state disabled \
]
pack $reload_but -side left -padx 5
set_locat_status_tip $reload_but [mc "Reload opened file"]
## Create search bar
set top_r_frame [frame $top_frame.right_frame]
# - Label
pack [label $top_r_frame.search_lbl \
-text [mc "Search:"] \
] -side left
# - Entry
set search_entry [ttk::entry $top_r_frame.search_entry \
-validate all \
-validatecommand "$this search_validate %P" \
]
DynamicHelp::add $search_entry \
-text [mc "Search for symbol by its name or value"]
set_locat_status_tip $search_entry [mc "Search for symbol"]
pack $search_entry -side left
# - Button
set clear_but [ttk::button $top_r_frame.clear_but \
-state disabled \
-style Flat.TButton \
-image ::ICONS::16::clear_left \
-command "$search_entry delete 0 end" \
]
set_locat_status_tip $clear_but [mc "Clear search entry box"]
pack $clear_but -side left
pack $top_r_frame -side right
## Create table of symbols
set middle_l_frame [frame $middle_frame.left_frame -bd 1 -relief sunken]
pack [label $middle_l_frame.header_lbl \
-bg white -padx 0 -pady 0 -width 0 \
-text [mc "Symbol\t\t\t\tType\tHEX\tDEC\tUsed"] \
-font $bold_font -anchor w -justify left \
] -fill x
pack [ttk::separator $middle_l_frame.sep \
-orient horizontal \
] -fill x
set text_widget [text $middle_l_frame.text \
-bg white -width 0 -height 0 -bd 0 -relief flat \
-yscrollcommand "$middle_frame.scrollbar set" \
-cursor left_ptr -font $normal_font \
-state disabled \
]
pack $text_widget -fill both -expand 1
pack $middle_l_frame -side left -fill both -expand 1
pack [ttk::scrollbar $middle_frame.scrollbar \
-orient vertical -command "$text_widget yview" \
] -fill y -side right -after $middle_l_frame
## Create display options
set main_opt_frame [ttk::labelframe \
$bottom_frame.main_opt_frm \
-text [mc "Display"] \
-padding 10 \
]
set row 0
set col 0
set i 0
foreach name {DATA IDATA XDATA CODE BIT Number Special} {
if {$col > 2} {
set col 0
incr row
}
grid [checkbutton $main_opt_frame.cb_x_$i \
-text $name -onvalue 1 -offvalue 0 \
-variable ::SymbolViewer::display_${obj_idx}($name) \
-command "$this refresh" \
] -sticky w -row $row -column $col
incr i
incr col
}
incr row
grid [ttk::separator $main_opt_frame.sep \
-orient horizontal \
] -sticky we -row $row -column 0 -columnspan 3
incr row
grid [checkbutton $main_opt_frame.cb_x_us \
-text [mc "Used symbols"] -onvalue 1 -offvalue 0 \
-variable ::SymbolViewer::display_${obj_idx}(used) \
-command "$this refresh" \
] -sticky w -row $row -column 0 -columnspan 3
incr row
grid [checkbutton $main_opt_frame.cb_x_uus \
-text [mc "Unused symbols"] -onvalue 1 -offvalue 0 \
-variable ::SymbolViewer::display_${obj_idx}(unused) \
-command "$this refresh" \
] -sticky w -row $row -column 0 -columnspan 3
pack $main_opt_frame -side left -fill y -anchor n -padx 5
# Create frame "Sort by"
set sort_by_frame [ttk::labelframe \
$bottom_frame.sort_by_frm \
-text [mc "Sort by"] \
-padding 10 \
]
set row 0
set col 0
set i 0
foreach name {{Symbol name} Type {Hex value} {Dec value} {Usage}} {
if {$col > 2} {
set col 0
incr row
}
grid [radiobutton $sort_by_frame.rb_x_$i \
-text $name -value $i \
-variable ::SymbolViewer::sort_by_${obj_idx} \
-command "$this refresh" \
] -sticky w -row $row -column $col
incr i
incr col
}
incr row
grid [ttk::separator $sort_by_frame.sep \
-orient horizontal \
] -sticky we -row $row -column 0 -columnspan 3
incr row
grid [radiobutton $sort_by_frame.rb_x_inc \
-text [mc "Incremental order"] -value 0 \
-variable ::SymbolViewer::sort_by_order_${obj_idx} \
-command "$this refresh" \
] -sticky w -row $row -column 0 -columnspan 3
incr row
grid [radiobutton $sort_by_frame.rb_x_dec \
-text [mc "Decremental order"] -value 1 \
-variable ::SymbolViewer::sort_by_order_${obj_idx} \
-command "$this refresh" \
] -sticky w -row $row -column 0 -columnspan 3
pack $sort_by_frame -side left -fill y -anchor n -padx 10
# Pack window frames
pack $top_frame -fill x
pack $middle_frame -fill both -expand 1 -pady 7
pack $bottom_frame -fill x
pack $sbar_frame -fill x
}
## Set local statusbar tip
# @parm Widget widget - Target widget
# @parm String text - Statusbar tip itselft
# @return void
private method set_locat_status_tip {widget text} {
bind $widget <Enter> [list $status_bar_lbl configure -text $text]
bind $widget <Leave> [list $status_bar_lbl configure -text {}]
}
## Close dialog window
# @return void
public method close_window {} {
::itcl::delete object $this
}
## Invoke file selection dialog to load a new table of symbols for LST file
# @return void
public method open_file_dialog {} {
# Determinate initial directory
if {$opened_file == {}} {
if {${::X::project_menu_locked}} {
set directory {~}
} else {
set directory [${::X::actualProject} cget -projectPath]
}
} else {
set directory [file dirname $opened_file]
}
# Invoke project selection dialog
KIFSD::FSD ::fsd \
-title [mc "Load symbol table - MCU 8051 IDE"] \
-directory $directory -master $win \
-defaultmask 0 -multiple 0 -filetypes [list \
[list [mc "Code listing"] {*.lst} ] \
[list [mc "All files"] {*} ] \
]
# Open the selected after press of OK button
::fsd setokcmd "
::fsd deactivate
$this open_file 0 \[::fsd get\]"
::fsd activate ;# Activate the dialog
}
## Reload opened file if any
# @return void
public method reload {} {
open_file 0 $opened_file
}
## Try to open LST file and load table of symbols from it
# @parm Bool ignore_errors - Ignore erros while opening the file
# @parm String filename - Name of file to load
# @return void
public method open_file {ignore_errors filename} {
if {[catch {
set file [open $filename r]
}]} then {
if {!$ignore_errors} {
tk_messageBox \
-parent $win \
-type ok \
-icon warning \
-title [mc "Invalid file"] \
-message [mc "Unable to use selected file. Please check your permissions. File: '%s'" $filename]
}
return
}
# Parse file
set symbol_table_data {}
set read_line 0
set line {}
set name {}
set addr {}
set type {}
set used 1
while {![eof $file]} {
set used 1
set line [gets $file]
# Empty line - stop reading
if {![string length [string trimright $line " \f"]]} {
set read_line 0
continue
# MCU 8051 IDE Assembler symbol table
} elseif {![string first {SYMBOL TABLE:} $line]} {
set read_line 1
continue
# ASEM-51 Assembler symbol table
} elseif {![string first {------------------------------------------------------------} $line]} {
set read_line 2
continue
}
# MCU 8051 IDE Assembler symbol
if {$read_line == 1} {
if {![regexp {^(\?\?)?\w+} $line name]} {
continue
}
if {![regexp {[\w\s]+$} $line line]} {
continue
}
set type [lindex $line 0]
if {$type == {S}} {
set addr [lindex $line end]
} else {
set addr [string replace [lindex $line 2] end end]
}
# Determinate whether symbol is used
if {[lindex $line end-1] == {NOT} || [lindex $line end-2] == {NOT}} {
set used 0
}
# ASEM-51 Assembler symbol
} elseif {$read_line == 2} {
# Remove dangerous characters
regsub -all {\{\}\"\"} $line {} line
if {[llength $line] < 4} {
set used 0
}
set addr [lindex $line 2]
set name [lindex $line 0]
set type [string index [lindex $line 1] 0]
# Hexadecimal address must be 4 characters long
if {!($type == {S} || $type == {R})} {
set addr "[string repeat 0 [expr {4 - [string length $addr]}]]$addr"
}
# This line is not a part of symbol table
} else {
continue
}
# Address must be a valid hexadecimal value
if {![string is xdigit -strict $addr] && !($type == {S} || $type == {R})} {
continue
}
# Create new register watch
if {[string length $name] > 31} {
set name [string range $name 0 27]
append name {...}
}
if {$type == {S} || $type == {R}} {
lappend symbol_table_data [list $name $type $addr {0} $used]
} else {
lappend symbol_table_data [list $name $type $addr [expr "0x$addr"] $used]
}
}
set opened_file $filename
$reload_but configure -state normal
$opened_file_lbl configure -text [file tail $filename]
close $file
refresh
}
## Sort list of loaded symbols according to user settings
# @return void
private method sort_table {} {
if {[subst -nocommands "\$::SymbolViewer::sort_by_order_${obj_idx}"]} {
set order {-decreasing}
} else {
set order {-increasing}
}
set index [subst -nocommands "\$::SymbolViewer::sort_by_${obj_idx}"]
if {$index == 3} {
set type {-integer}
} else {
set type {-dictionary}
}
set symbol_table_data [lsort $order $type -index $index $symbol_table_data]
}
## Filter record with the given type and use flag
# @parm Char type - Record type
# @parm Bool used - Used flag
# @return List - {$long_type $long_used} or {0}
private method filter_record {type used} {
# Adjust symbol type
switch -- $type {
{D} {set type {DATA}}
{I} {set type {IDATA}}
{X} {set type {XDATA}}
{C} {set type {CODE}}
{B} {set type {BIT}}
{N} {set type {Number}}
{S} {set type {Special}}
{R} {set type {Special}}
}
if {![subst -nocommands "\$::SymbolViewer::display_${obj_idx}($type)"]} {
return 0
}
# Adjust flag USED
if {$used} {
if {![subst -nocommands "\$::SymbolViewer::display_${obj_idx}(used)"]} {
return 0
}
set used [mc "YES"]
} else {
if {![subst -nocommands "\$::SymbolViewer::display_${obj_idx}(unused)"]} {
return 0
}
set used [mc "NO"]
}
return [list $type $used]
}
## Refresh table of symbols (reload contents of the text widget from $symbol_table_data)
# @return void
public method refresh {} {
# There must be something loaded
if {$opened_file == {}} {
return
}
# Save data of the selected line
if {$current_line != {}} {
set current_line [$text_widget get $current_line.0 [list $current_line.0 lineend]]
set current_line [list \
[lindex $current_line 0] [lindex $current_line 1] \
[lindex $current_line 2] [lindex $current_line 3] \
[lindex $current_line 4] \
]
lset current_line 1 [string index [lindex $current_line 1] 0]
if {[lindex $current_line 4] == {YES}} {
lset current_line 4 1
} else {
lset current_line 4 0
}
}
# Sort loaded table of symbols
sort_table
# Clear the text widget
$text_widget configure -state normal
$text_widget delete 0.0 end
# Load table of symbols to the text widget
set idx 0 ;# Int: Symbol number (just index in the table, nothing more)
set name {} ;# String: Symbol name defined in source code
set type {} ;# Char: Symbol type (see func. code)
set hexv {} ;# String: Hexadecimal symbol value
set decv {} ;# Int: Decimal symbol value
set used {} ;# Bool: Symbol used in source code
set cur_found 0 ;# Bool: Current line found
foreach symbol_def $symbol_table_data {
set name [lindex $symbol_def 0]
set type [lindex $symbol_def 1]
set hexv [lindex $symbol_def 2]
set decv [lindex $symbol_def 3]
set used [lindex $symbol_def 4]
# Filter record
set used [filter_record $type $used]
if {$used == {0}} {
continue
}
set type [lindex $used 0]
set used [lindex $used 1]
# Insert new record into the table
$text_widget insert insert $name
$text_widget insert insert [string repeat { } [expr {32 - [string length $name]}]]
$text_widget insert insert $type
$text_widget insert insert [string repeat { } [expr {8 - [string length $type]}]]
$text_widget tag add type_${type} insert-8c insert
if {$type == {Special}} {
$text_widget insert insert $hexv
$text_widget insert insert [string repeat { } [expr {16 - [string length $hexv]}]]
} else {
$text_widget insert insert $hexv
$text_widget insert insert { }
$text_widget insert insert $decv
$text_widget insert insert [string repeat { } [expr {8 - [string length $decv]}]]
}
$text_widget insert insert $used
$text_widget tag add used_${used} insert-3c insert
$text_widget insert insert "\n"
if {!($idx % 3)} {
$text_widget tag add nth_row insert-1l insert
}
# Try to find the selected line
if {!$cur_found && [string equal $current_line $symbol_def]} {
set cur_found 1
set current_line $idx
incr current_line
}
incr idx
}
# Restore selection
if {$cur_found} {
$text_widget tag add tag_sel $current_line.0 $current_line.0+1l
$text_widget see $current_line.0
} else {
set current_line {}
}
# Disable the text widget and clear search entrybox
$text_widget configure -state disabled
$search_entry delete 0 end
}
## Select line in the table (event: <Button-1>)
# @parm Int x - Relative X coordinate
# @parm Int y - Relative Y coordinate
# @return void
public method select_line {x y} {
set current_line [expr {int([$text_widget index @$x,$y])}]
if {$current_line == int([$text_widget index end])-1} {
set current_line {}
return
}
$search_entry delete 0 end
$text_widget tag remove tag_sel 0.0 end
$text_widget tag add tag_sel $current_line.0 $current_line.0+1l
}
## Search entrybox validator
# @parm String string - String to validate (search for)
# @return Bool - always 1
public method search_validate {string} {
# Not empty string
if {[string length $string]} {
set string [string tolower [string trimleft $string 0]]
$clear_but configure -state normal
# Empty string -> abort
} else {
$search_entry configure -style TEntry
$clear_but configure -state disabled
return 1
}
# Search in the table
set i 0
set found_idx -1
foreach symbol_def $symbol_table_data {
set name [string tolower [lindex $symbol_def 0]]
set type [lindex $symbol_def 1]
set hexv [string trimleft [string tolower [lindex $symbol_def 2]] 0]
set decv [lindex $symbol_def 3]
set used [lindex $symbol_def 4]
if {[filter_record $type $used] == {0}} {
continue
}
if {![string first $string $name]} {
set found_idx $i
break
}
if {![string first $string $hexv]} {
set found_idx $i
break
}
if {![string first $string $decv]} {
set found_idx $i
break
}
incr i
}
set current_line {}
$text_widget tag remove tag_sel 0.0 end
# String not found
if {$found_idx == -1} {
$search_entry configure -style StringNotFound.TEntry
# String found
} else {
set current_line [expr {$found_idx + 1}]
$text_widget tag add tag_sel $current_line.0 $current_line.0+1l
$text_widget see $current_line.0
$search_entry configure -style StringFound.TEntry
}
return 1
}
## Event handler of the text widget <Key-Up>
# Select line above the currently selected one
# @return void
public method key_up {} {
if {$current_line == {} || $current_line < 2} {
return
}
incr current_line -1
$text_widget tag remove tag_sel 0.0 end
$text_widget tag add tag_sel $current_line.0 $current_line.0+1l
$search_entry delete 0 end
}
## Event handler of the text widget <Key-Down>
# Select line below the currently selected one
# @return void
public method key_down {} {
if {$current_line == {} || $current_line >= ([$text_widget index end] - 2)} {
return
}
incr current_line
$text_widget tag remove tag_sel 0.0 end
$text_widget tag add tag_sel $current_line.0 $current_line.0+1l
$search_entry delete 0 end
}
## Invoke text widget popup menu
# @parm Int X - Absolute mouse pointer X coordinate
# @parm Int Y - Absolute mouse pointer X coordinate
# @parm Int x - Relative mouse pointer X coordinate
# @parm Int y - Relative mouse pointer X coordinate
# @return void
public method invoke_popup_menu {X Y x y} {
select_line $x $y
if {$current_line == {}} {
set state disabled
} else {
set state normal
}
foreach entry {{Copy symbol name} {Copy hex value} {Copy dec value} {Copy line}} {
$menu entryconfigure [::mc $entry] -state $state
}
tk_popup $menu $X $Y
}
## Copy piece of the table into clipboard
# @parm Char mode - What to copy
# name - Symbol name
# hex - Symbol hexadecimal value
# dec - Symbol decimal value
# line - Whole symbol definition
# @return void
public method text_copy_proc {mode} {
switch -- $mode {
{name} {
set s 0
set e 31
}
{hex} {
set s 39
set e 44
}
{dec} {
set s 47
set e 52
}
{line} {
set s 0
set e 63
}
}
clipboard clear
clipboard append [string trim [$text_widget get $current_line.$s $current_line.$e]]
}
}
# >>> File inclusion guard
}
# <<< File inclusion guard
|