diff options
author | Andrej Shadura <andrewsh@debian.org> | 2018-05-08 15:59:29 +0200 |
---|---|---|
committer | Andrej Shadura <andrewsh@debian.org> | 2018-05-08 15:59:29 +0200 |
commit | 5b8466f7fae0e071c0f4eda13051c93313910028 (patch) | |
tree | 7061957f770e5e245ba00666dad912a2d44e7fdc /lib/rightpanel |
Import Upstream version 1.3.7
Diffstat (limited to 'lib/rightpanel')
-rwxr-xr-x | lib/rightpanel/hwmanager.tcl | 419 | ||||
-rwxr-xr-x | lib/rightpanel/instructiondetails.tcl | 1755 | ||||
-rwxr-xr-x | lib/rightpanel/regwatches.tcl | 2120 | ||||
-rwxr-xr-x | lib/rightpanel/rightpanel.tcl | 2273 | ||||
-rwxr-xr-x | lib/rightpanel/subprograms.tcl | 704 |
5 files changed, 7271 insertions, 0 deletions
diff --git a/lib/rightpanel/hwmanager.tcl b/lib/rightpanel/hwmanager.tcl new file mode 100755 index 0000000..0e27941 --- /dev/null +++ b/lib/rightpanel/hwmanager.tcl @@ -0,0 +1,419 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 by Martin Ošmera # +# 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. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Provides panel for managing hardware plugins (e.g. Programmer, ICD, etc.) +# -------------------------------------------------------------------------- + +class HwManager { + ## COMMON + common PLUGIN_SEARCH_PATHS { + ../hwplugins + /usr/share/mcu8051ide/hwplugins + /usr/local/share/mcu8051ide/hwplugins + } + common inst_plg_count 0 ;# Int: Number of installed plugins + + ## PRIVATE + private variable parent ;# Widget: parent widget + private variable gui_initialized 0 ;# Bool: GUI initialized + + private variable main_frame ;# Widget: Main frame + private variable pagesmanager ;# Widget: Pages manager for plugins GUI + private variable plg_combobox ;# Widget: Plugin selection combobox + private variable plg_refresh_but ;# Widget: Button "Refresh avaliable plugins" + private variable ins_plugin_namespaces {} ;# List of Strings: Namespaces of installed (initialized) plugins + private variable ins_plugin_names {} ;# List of Strings: Names of installed (initialized) plugins + private variable avl_plugin_files {} ;# List of Strings: Full filenames of avaliable plugins + private variable avl_plugin_names {} ;# List of Strings: Names of avaliable plugins + + # List: Configuraion list of this panel (for session management) + private variable local_config [lindex $::CONFIG(HW_MANAGER_CONFIG) 0] + # List: Names of plugins with saved configuration (for session management) + private variable plugin_config_0 [lindex $::CONFIG(HW_MANAGER_CONFIG) 1] + # List: Configuration lists for plugins with saved configuration (for session management) + private variable plugin_config_1 [lindex $::CONFIG(HW_MANAGER_CONFIG) 2] + + + constructor {} { + } + + destructor { + # Order all plugins to free their resources + hw_man_kill_childern + } + + ## Kill all child processes + # @return void + public method hw_man_kill_childern {} { + foreach ns $ins_plugin_namespaces name $ins_plugin_names { + + if {[catch { + ${ns}::dispose + }]} { + plugin_error $name $ns + } + } + } + + ## Prepare this panel for initialization of its GUI + # MUST BE called before "CreateHwManagerGUI" + # @parm Widget _parent - Frame where this panel would be created + # @return void + public method PrepareHwManager {_parent} { + set parent $_parent + set gui_initialized 0 + } + + ## Finalize initialization of this panel + # @return void + public method CreateHwManagerGUI {} { + if {$gui_initialized} {return} + set gui_initialized 1 + + # Create main GUI parts + set main_frame [frame $parent.main_frame] + set top_frame [frame $main_frame.top] + set pagesmanager [PagesManager $main_frame.pagesmanager -background {#eeeeee}] + + ## Create parts of top panel + # Label "HW" + pack [label $top_frame.plg_label \ + -text [mc "HW:"] \ + ] -side left + # Combobox of avaliable/installed plugins + set plg_combobox [ttk::combobox $top_frame.plg_cbbox \ + -exportselection 1 \ + -width 0 \ + -state readonly \ + ] + DynamicHelp::add $plg_combobox -text [mc "List avaliable or installed HW plugins"] + bind $plg_combobox <<ComboboxSelected>> "$this hw_manager_plg_cbs" + pack $plg_combobox -fill x -expand 1 -side left + setStatusTip -widget $plg_combobox -text [mc "Avaliable/installed plugins"] + # Button "Refresh" + set plg_refresh_but [ttk::button $top_frame.plg_refresh_but \ + -image ::ICONS::16::reload \ + -command "$this hw_manager_refresh_plugins" \ + -style Flat.TButton \ + ] + DynamicHelp::add $top_frame.plg_refresh_but \ + -text [mc "Refresh list avaliable or installed HW plugins"] + pack $plg_refresh_but -side left + setStatusTip -widget $plg_refresh_but -text [mc "Refresh"] + # Fill in the combobox + hw_manager_refresh_plugins + + # Show GUI of the plugin from the last session + set idx [lsearch -ascii -exact [$plg_combobox cget -values] [lindex $local_config 0]] + if {$idx != -1} { + $plg_combobox current $idx + hw_manager_plg_cbs + } + + # Pack top frame, create separator and pack the pages manager + pack $top_frame -fill x + pack [ttk::separator $main_frame.sep \ + -orient horizontal \ + ] -fill x -pady 5 + pack $pagesmanager -fill both -expand 1 + pack $main_frame -fill both -expand 1 + } + + ## Refresh list avaliable or installed HW plugins + # @return void + public method hw_manager_refresh_plugins {} { + if {!$gui_initialized} {CreateHwManagerGUI} + if {${::CLI_OPTION(no-plugins)}} {return} + + set avl_plugin_files [list] + set avl_plugin_names [list] + + # Search for avaliable plugins + foreach dir $PLUGIN_SEARCH_PATHS { + set dir [file join ${::LIB_DIRNAME} $dir] + catch { ;# For Microsoft Windows it has to be enclosed by catch + foreach file [glob -directory $dir -nocomplain -types f *.tcl] { + if {[lsearch -ascii -exact $avl_plugin_names [file tail [file rootname $file]]] != -1} { + continue + } + lappend avl_plugin_files $file + lappend avl_plugin_names [regsub -all {_} [file tail [file rootname $file]] { }] + } + } + } + + # Adjust the combobox + $plg_combobox configure -values $avl_plugin_names + } + + ## Switch plugin + # @parm String plugin_name - Plugin to switch to + # @return void + public method hw_manager_switch_plugin {plugin_name} { + if {!$gui_initialized} {CreateHwManagerGUI} + if {${::CLI_OPTION(no-plugins)}} {return} + + # Install the plugin if it wasn't installed yet + if {[lsearch -ascii -exact $ins_plugin_names $plugin_name] == -1} { + # Check if the selected plugin is really avaliable + if {[lsearch -ascii -exact $avl_plugin_names $plugin_name] == -1} { + return + } + + # Install the plugin (means initialize) + lappend ins_plugin_names $plugin_name + lappend ins_plugin_namespaces [ \ + hw_manager_install_plugin $plugin_name [lindex \ + $avl_plugin_files \ + [lsearch -ascii -exact $avl_plugin_names $plugin_name] \ + ] + ] + } + + # Adjust the combobox of avaliable/installed plugins + $pagesmanager raise [regsub -all {\s} $plugin_name {_}] + } + + ## "Change command" for the combobox of avaliable/installed plugins + # Switches the selected plugin + # @return void + public method hw_manager_plg_cbs {} { + if {!$gui_initialized} {CreateHwManagerGUI} + hw_manager_switch_plugin [$plg_combobox get] + } + + ## Install plugin (means initialize) + # @parm String plugin_name - Plugin name + # @parm String file_path - Full path to the plugin main file + # @return String - Plugin namespace + public method hw_manager_install_plugin {plugin_name file_path} { + if {!$gui_initialized} {CreateHwManagerGUI} + if {${::CLI_OPTION(no-plugins)}} {return} + set plg_ns {} + + if {[catch { + set frame [$pagesmanager add [regsub -all {\s} $plugin_name {_}]] + set plg_ns "::HwManager::plugin_ns::$inst_plg_count" + incr inst_plg_count + + namespace eval $plg_ns "source {$file_path}" + + set min_ide_ver [subst "\$${plg_ns}::MIN_IDE_VER"] + if {[package vcompare $min_ide_ver $::VERSION] == 1} { + tk_messageBox \ + -title [mc "Too old version"] \ + -type ok -icon warning \ + -message [mc "Plugin %s requires MCU 8051 IDE version %s and above, please upgrade your MCU 8051 IDE" $plugin_name $min_ide_ver] + } + + ${plg_ns}::init $frame $this $plg_ns [file dirname $file_path] + + set idx [lsearch $plugin_config_0 $plugin_name] + if {$idx != -1} { + ${plg_ns}::restore_session [lindex $plugin_config_1 $idx] + } + }]} { + plugin_error $plugin_name $plg_ns + } + + return $plg_ns + } + + ## Handle plugin error and display error message + # @parm String plugin_name - Name of the plugin + # @parm String plugin_ns - Namespace of the plugin + # @return void + private method plugin_error {plugin_name plugin_ns} { + + # Try to gain some informations about the crashed plugin + set plugin_ver {not defined} + set plugin_author {not defined} + set authors_email {not defined} + set err_info $::errorInfo + catch {set plugin_ver [subst "\$${plugin_ns}::P_VERSION"]} + catch {set plugin_author [subst "\$${plugin_ns}::AUTHOR"]} + catch {set authors_email [subst "\$${plugin_ns}::EMAIL"]} + + # Print error message to stadrad error output + puts stderr "\n\n" + puts stderr [string repeat {=} 64] + puts stderr "PLUGIN ERROR:" + puts stderr [string repeat {-} 64] + puts stderr "Plugin name:\t$plugin_name" + puts stderr "Plugin version:\t$plugin_ver" + puts stderr "Author:\t\t$plugin_author <$authors_email>" + puts stderr [string repeat {-} 64] + puts stderr $err_info + puts stderr [string repeat {=} 64] + puts stderr "\n\n" + + # Save log file + if {![catch {set log_file [open [file join ${::X::defaultDirectory} mcu8051ide_plugin_errors.log] a]}]} { + puts $log_file "\n\n" + puts $log_file [string repeat {=} 64] + puts $log_file "PLUGIN ERROR:" + puts $log_file [string repeat {-} 64] + puts $log_file "Plugin name:\t$plugin_name" + puts $log_file "Plugin version:\t$plugin_ver" + puts $log_file "Author:\t\t$plugin_author <$authors_email>" + puts $log_file [string repeat {-} 64] + puts $log_file $err_info + puts $log_file [string repeat {=} 64] + puts $log_file "\n\n" + close $log_file + } + + # Display GUI error message + set dialog [toplevel .plugin_error -bg {#EEEEEE}] + + # Create window frames + set main_dlg_frame [frame $dialog.main_frame] + set top_frame [frame $main_dlg_frame.top_frame -bg {#EE0000}] + set middle_frame [frame $main_dlg_frame.middle_frame] + set bottom_frame [frame $main_dlg_frame.bottom_frame] + + # Create window header + pack [label $top_frame.header_lbl \ + -text [mc "PLUGIN ERROR"] \ + -bg {#EE0000} -fg {#FFFFFF} \ + -font [font create \ + -family helvetica \ + -size -24 \ + -weight bold \ + ] \ + ] -side left -fill x -expand 1 + + # Create error message text and scrollbar + pack [text $middle_frame.text \ + -bg {white} -bd 0 \ + -yscrollcommand "$middle_frame.scrollbar set" \ + -width 0 -height 0 -relief flat -wrap word \ + ] -side left -fill both -expand 1 -padx 5 -pady 5 + bind $middle_frame.text <Button-1> {focus %W} + pack [ttk::scrollbar $middle_frame.scrollbar \ + -orient vertical \ + -command "$middle_frame.text yview" \ + ] -fill y -side right + + # Create button "Close" + pack [ttk::button $bottom_frame.ok \ + -text [mc "Close"] \ + -style GreenBg.TButton \ + -command " + grab release $dialog + destroy $dialog + " \ + ] -side right + focus -force $bottom_frame.ok + + # Display error message + $middle_frame.text insert insert [mc "Plugin name:\t%s\n" $plugin_name] + $middle_frame.text insert insert [mc "Plugin version:\t%s\n" $plugin_ver] + $middle_frame.text insert insert [mc "Author:\t\t%s <%s>\n" $plugin_author $authors_email] + $middle_frame.text insert insert "\n" + $middle_frame.text insert insert $err_info + $middle_frame.text insert insert "\n" + $middle_frame.text configure -state disabled + + # Pack window frames + pack $top_frame -fill x -anchor n + pack $middle_frame -fill both -expand 1 + pack $bottom_frame -fill x + pack $main_dlg_frame -fill both -expand 1 -padx 5 -pady 5 + + # Configure dialog window + set x [expr {[winfo screenwidth $dialog] / 2 - 225}] + set y [expr {[winfo screenheight $dialog] / 2 - 125}] + wm iconphoto $dialog ::ICONS::16::bug + wm title $dialog [mc "PLUGIN ERROR - MCU 8051 IDE"] + wm minsize $dialog 450 250 + wm geometry $dialog =550x250+$x+$y + wm protocol $dialog WM_DELETE_WINDOW " + grab release $dialog + destroy $dialog" + update + raise $dialog + grab $dialog + wm transient $dialog . + tkwait window $dialog + } + + ## Ask all plugins wheather they are ready for exit + # @return Bool - 1 == Exit allowed; 0 == Exit DENIED + public method hw_manager_comfirm_exit {} { + if {!$gui_initialized} {return 1} + + foreach plg_name $ins_plugin_names plg_ns $ins_plugin_namespaces { + set busy_flag 0 + catch { + set busy_flag [${plg_ns}::is_busy] + } + if {$busy_flag} { + if {[tk_messageBox \ + -parent . \ + -type yesno \ + -icon question \ + -title [mc "Hardware is busy"] \ + -message [mc "Plugin \"%s\" is busy.\nDo you really want to close the program ?" $plg_name] + ] != {yes}} { + return 0 + } + } + } + + return 1 + } + + ## Get configuration list for this panel (intented for sessions management) + # @return void + public method hw_manager_get_cfg {} { + if {!$gui_initialized} { + return [list $local_config $plugin_config_0 $plugin_config_1] + } + + set local_config {} + set plugin_config_0 {} + set plugin_config_1 {} + + # Get panel configuration + lappend local_config [$plg_combobox get] + + # Get plugins configuration + foreach plg_name $ins_plugin_names plg_ns $ins_plugin_namespaces { + set idx [lsearch -ascii -exact $plugin_config_0 $plg_name] + + set config [${plg_ns}::save_session] + + if {$idx == -1} { + lappend plugin_config_0 $plg_name + lappend plugin_config_1 $config + } { + lset plugin_config_1 $idx $config + } + } + + return [list $local_config $plugin_config_0 $plugin_config_1] + } +} diff --git a/lib/rightpanel/instructiondetails.tcl b/lib/rightpanel/instructiondetails.tcl new file mode 100755 index 0000000..0c7efaf --- /dev/null +++ b/lib/rightpanel/instructiondetails.tcl @@ -0,0 +1,1755 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 by Martin Ošmera # +# 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. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Implements tab "Instruction details" on the Right Panel +# -------------------------------------------------------------------------- + +class InstructionDetails { + + ## COMMON + # Conter of instances + common count 0 + # Font for instruction details + common instruction_font [font create -size -12 -family $::DEFAULT_FIXED_FONT] + ## Highlighting tags for instruction details + # { + # {tag_name foreground_color ?bold_or_italic?} + # ... + # } + common instruction_tags { + {tag_code8 #00AA00 0} + {tag_code11 #00AA33 0} + {tag_code16 #00AA55 0} + {tag_imm8 #FF0000 0} + {tag_imm16 #FF0055 0} + {tag_data #88DD00 0} + {tag_bit #555588 0} + {tag_DPTR #0000FF 1} + {tag_A #3300DD 1} + {tag_AB #8800FF 1} + {tag_SFR #0000FF 1} + {tag_indr #FF0000 1} + {tag_1 #00DD00} + {tag_2 #AAAA00} + {tag_3 #FF0000} + {tag_4 #8800FF} + {tag_5 #0000FF} + } + + ## Detail description of each directive + # Format: { + # {directive} {description} + # {directive} {description} + # {directive} {description} + # . . + # . . + # . . + # } + common HELP_FOR_DIRECTIVES {} + common HELP_FOR_DIRECTIVES_RAW { + elseif {Conditional assembly\n\nSyntax:\n ELSEIF <expr>\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSEIF SOMETHING_ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only} + ifn {IF Not, conditional assembly\n\nSyntax:\n IFN <expr>\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n} + elseifn {ELSE IF Not\n\nSyntax:\n ELSEIFN <expr>\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSEIFN SOMETHING_ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only} + ifdef {IF DEFined\n\nSyntax:\n IFDEF <symbol>\n\nExample:\n IFDEF CND\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n} + elseifdef {ELSE IF DEFined\n\nSyntax:\n ELSEIFDEF <symbol>\n\nExample:\n IFDEF(2 * 4 - CND)\n MOV A, #20h\n ELSEIFDEF SOMETHING_ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only} + ifndef {IF Not DEFined\n\nSyntax:\n IFNDEF <symbol>\n\nExample:\n IFNDEF CND\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n} + elseifndef {ELSE IF Not DEFined\n\nSyntax:\n ELSEIFNDEF <symbol>\n\nExample:\n IFDEF CND\n MOV A, #20h\n ELSEIFNDEF SOMETHING_ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only} + ifb {IF Black\n\nSyntax:\n IFB <literal>\n\nExample:\n IFB <CND>\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only} + elseifb {ELSE IF Black\n\nSyntax:\n ELSEIFB <literal>\n\nExample:\n IFB <CND>\n MOV A, #20h\n ELSEIFB <SOMETHING_ELSE>\n MOV A, #40h\n ENDIF\n\literal:\n Supported by ASEM-51 only} + ifnb {IF Not Black\n\nSyntax:\n IFNB <literal>\n\nExample:\n IFNB <CND>\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only} + elseifnb {ELSE IF Not Black\n\nSyntax:\n ELSEIFNB <literal>\n\nExample:\n IFB <CND>\n MOV A, #20h\n ELSEIFNB <SOMETHING_ELSE>\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only} + rept {REPeaT Macro\n\nSyntax:\n REPT <expr>\n\nExample:\n REPT 5\n NOP\n ENDM\n\n} + times {REPeaT Macro\n\nSyntax:\n TIMES <expr>\n\nExample:\n TIMES 5\n NOP\n ENDM\n\nNote:\n Supported by native assembler only} + name {define module NAME\n\nSyntax:\n NAME <name>\n\nExample:\n NAME my_2nd_program\n\nNote:\n Supported by ASEM-51 only} + if {Conditional assembly\n\nSyntax:\n IF <expr>\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n} + else {Conditional assembly\n\nSyntax:\n ELSE\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n} + endif {Conditional assembly\n\nSyntax:\n ENDIF\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n} + endm {END of Macro definition\n\nSyntax:\n ENDM\n\nExample:\n ABC MACRO\n MOV B, #12d\n ENDM\n\n} + end {END of the program\n\nSyntax:\n END\n\nExample:\n END\n\n} + exitm {premature end of macro expansion\n\nSyntax:\n EXITM\n\nExample:\n ABC MACRO\n MOV B, #12d\n EXITM\n NOP\n ENDM\n\n} + list {enable code LISTing\n\nSyntax:\n LIST\n\nExample:\n NOP\n NOLIST\n NOP\n NOP\n LIST\n NOP\n\n} + nolist {disabled code listing\n\nSyntax:\n NOLIST\n\nExample:\n NOP\n NOLIST\n NOP\n NOP\n LIST\n NOP\n\n} + dseg {switch to DATA segment \[at address\]\n\nSyntax:\n DSEG \[AT <expr>\]\n\nExample:\n DSEG at 20d\n\n} + iseg {switch to IDATA segment \[at address\]\n\nSyntax:\n ISEG \[AT <expr>\]\n\nExample:\n ISEG at 10d\n\n} + bseg {switch to BIT segment \[at address\]\n\nSyntax:\n BSEG \[AT <expr>\]\n\nExample:\n BSEG at 5d\n\n} + xseg {switch to XDATA segment \[at address\]\n\nSyntax:\n XSEG \[AT <expr>\]\n\nExample:\n XSEG at 30d\n\n} + cseg {switch to CODE segment \[at address\]\n\nSyntax:\n CSEG \[AT <expr>\]\n\nExample:\n CSEG at 40d\n\n} + flag {define a FLAG bit\n\nSyntax:\n <symbol> FLAG <expr>\n\nExample:\n F4 FLAG 16h\n\nNote:\n Deprecated directive. Consider directive BIT instead.} + skip {SKIP bytes in the code memory\n\nSyntax:\n SKIP <expr>\n\nExample:\n SKIP 5\n\n} + equ {EQUivalent\n\nSyntax:\n <symbol> EQU <expr>\n\nExample:\n ABC EQU R0\n XYZ EQU 4Eh+12\n\n} + bit {define BIT address\n\nSyntax:\n <symbol> BIT <expr>\n\nExample:\n ABC BIT P4.5\n\n} + set {SET numeric variable or variable register\n\nSyntax:\n <symbol> SET <expr>\n <symbol> SET <register>\n\nExample:\n ALPHA SET R0\N ALPHA SET 42*BETA\n\n} + code {define address in the CODE memory\n\nSyntax:\n <symbol> CODE <expr>\n\nExample:\n TBL CODE 600h\n\n} + data {define address in the DATA memory\n\nSyntax:\n <symbol> DATA <expr>\n\nExample:\n UIV DATA 20h\n\n} + idata {define address in the Internal DATA memory\n\nSyntax:\n <symbol> IDATA <expr>\n\nExample:\n UIV IDATA 20h\n\n} + xdata {define address in the External DATA memory\n\nSyntax:\n <symbol> XDATA <expr>\n\nExample:\n UIV XDATA 400h\n\n} + macro {MACRO definition\n\nSyntax:\n <macro> MACRO \[<arg0> \[,<arg1> ... \]\n\n\nExample:\n ABC MACRO X\n MOV X, #12d\n ENDM\n\n} + ds {Define Space\n\nSyntax:\n DS <expr>\n\nExample:\n DS 2+4\n\n} + dw {Define Words\n\nSyntax:\n DW <expr1> \[,<expr2> ... \]\n\nExample:\n DW 0,02009H,2009,4171\n\n} + db {Define Bytes\n\nSyntax:\n DB <expr1> \[,<expr2> ... \]\n\nExample:\n DB 24,'August',09,(2*8+24)/8\n\n} + dbit {Define BITs\n\nSyntax:\n DBIT <expr>\n\nExample:\n DBIT 4+2\n\n} + include {INCLUDE an external source code\n\nSyntax:\n INCLUDE <filename>\n\nExample:\n INCLUDE 'my file.asm'\n\n} + org {ORiGin of segment location\n\nSyntax:\n ORG <expr>\n\nExample:\n ORG 0Bh\n\n} + using {USING register banks\n\nSyntax:\n USING <expr>\n\nExample:\n USING 2\n\n} + byte {define BYTE address in the data memory\n\nSyntax:\n <symbol> BYTE <expr>\n\nExample:\n UIV BYTE 20h\n\nNote:\n Deprecated directive. Consider directive DATA instead.} + + {$cond} {List full IFxx .. ENDIF\n\nSyntax:\n \$COND\n\nExample:\n \$COND\n\nNote:\n Supported by ASEM-51 only} + {$nocond} {Don't list lines in false branches\n\nSyntax:\n \$NOCOND\n\nExample:\n \$NOCOND\n\nNote:\n Supported by ASEM-51 only} + {$condonly} {List assembled lines only\n\nSyntax:\n \$CONDONLY\n\nExample:\n \$CONDONLY\n\nNote:\n Supported by ASEM-51 only} + {$date} {Inserts date string into page header\n\nSyntax:\n \$DATE(string)\n\nExample:\n \$DATE(1965-12-31)\n\n} + {$da} {Inserts date string into page header\n\nSyntax:\n \$DATE(string)\n\nExample:\n \$DATE(1965-12-31)\n\n} + {$debug} {Include debug information\n\nSyntax:\n \$DEBUG\n\nExample:\n \$DEBUG\n\nNote:\n Supported by ASEM-51 only} + {$db} {Include debug information\n\nSyntax:\n \$DB\n\nExample:\n \$DB\n\nNote:\n Supported by ASEM-51 only} + {$nodebug} {Don't include debug information\n\nSyntax:\n \$NODEBUG\n\nExample:\n \$NODEBUG\n\nNote:\n Supported by ASEM-51 only} + {$nodb} {Don't include debug information\n\nSyntax:\n \$NODB\n\nExample:\n \$NODB\n\nNote:\n Supported by ASEM-51 only} + {$eject} {Start a new page in list file\n\nSyntax:\n \$EJECT\n\nExample:\n \$EJECT\n\n} + {$ej} {Start a new page in list file\n\nSyntax:\n \$EJ\n\nExample:\n \$EJ\n\n} + {$error} {Force a user-defined error\n\nSyntax:\n \$ERROR(string)\n\nExample:\n \$ERROR(Impossible combination ...)\n\nNote:\n Supported by ASEM-51 only} + {$warning} {Force a user-defined warning\n\nSyntax:\n \$WARNING(string)\n\nExample:\n \$WARNING(Testing only !)\n\nNote:\n Supported by ASEM-51 only} + {$ge} {List macro calls and expansion lines\n\nSyntax:\n \$GE\n\nExample:\n \$GE\n\nNote:\n Supported by ASEM-51 only} + {$gen} {List macro calls and expansion lines\n\nSyntax:\n \$GEN\n\nExample:\n \$GEN\n\nNote:\n Supported by ASEM-51 only} + {$noge} {List macro calls only\n\nSyntax:\n \$NOGE\n\nExample:\n \$NOGE\n\nNote:\n Supported by ASEM-51 only} + {$nogen} {List macro calls only\n\nSyntax:\n \$NOGEN\n\nExample:\n \$NOGEN\n\nNote:\n Supported by ASEM-51 only} + {$go} {List expansion lines only\n\nSyntax:\n \$GO\n\nExample:\n \$GO\n\nNote:\n Supported by ASEM-51 only} + {$genonly} {List expansion lines only\n\nSyntax:\n \$GENONLY\n\nExample:\n \$GENONLY\n\nNote:\n Supported by ASEM-51 only} + {$include} {Include a source file\n\nSyntax:\n \$INCLUDE(string)\n\nExample:\n \$INCLUDE(somefile.asm)\n\n} + {$inc} {Include a source file\n\nSyntax:\n \$INC(string)\n\nExample:\n \$INC(somefile.asm)\n\n} + {$list} {List subsequent source lines\n\nSyntax:\n \$LIST\n\nExample:\n \$LIST\n\n} + {$li} {List subsequent source lines\n\nSyntax:\n \$LI\n\nExample:\n \$LI\n\n} + {$noli} {Don't list subsequent source lines\n\nSyntax:\n \$NOLI\n\nExample:\n \$NOLI\n\n} + {$nolist} {Don't list subsequent source lines\n\nSyntax:\n \$NOLIST\n\nExample:\n \$NOLIST\n\n} + {$macro} {Reserve n % of free memory for macros\n\nSyntax:\n \$MACRO(int)\n\nExample:\n \$MACRO(50)\n\nNote:\n Supported by ASEM-51 only} + {$mr} {Reserve n % of free memory for macros\n\nSyntax:\n \$MR(int)\n\nExample:\n \$MR(50)\n\nNote:\n Supported by ASEM-51 only} + {$nomr} {Reserve all for the symbol table\n\nSyntax:\n \$NOMR\n\nExample:\n \$NOMR\n\nNote:\n Supported by ASEM-51 only} + {$nomacro} {Reserve all for the symbol table\n\nSyntax:\n \$NOMACRO\n\nExample:\n \$NOMACRO\n\nNote:\n Supported by ASEM-51 only} + {$mod51} {Enable predefined SFR symbols\n\nSyntax:\n \$MOD51\n\nExample:\n \$MOD51\n\nNote:\n Supported by ASEM-51 only} + {$mo} {Enable predefined SFR symbols\n\nSyntax:\n \$MO\n\nExample:\n \$MO\n\nNote:\n Supported by ASEM-51 only} + {$nomod} {Disable predefined SFR symbols\n\nSyntax:\n \$NOMOD\n\nExample:\n \$NOMOD\n\n} + {$nomo} {Disable predefined SFR symbols\n\nSyntax:\n \$NOMO\n\nExample:\n \$NOMO\n\n} + {$nomod51} {Disable predefined SFR symbols\n\nSyntax:\n \$NOMOD51\n\nExample:\n \$NOMOD51\n\n} + {$nobuiltin} {Don't list predefined symbols\n\nSyntax:\n \$NOBUILTIN\n\nExample:\n \$NOBUILTIN\n\nNote:\n Supported by ASEM-51 only} + {$notabs} {Don't use tabs in list file\n\nSyntax:\n \$NOTABS\n\nExample:\n \$NOTABS\n\nNote:\n Supported by ASEM-51 only} + {$paging} {Enable listing page formatting\n\nSyntax:\n \$LIST\n\nExample:\n \$PAGING\n\n} + {$pi} {Enable listing page formatting\n\nSyntax:\n \$PI\n\nExample:\n \$PI\n\n} + {$nopi} {Disable listing page formatting\n\nSyntax:\n \$NOPI\n\nExample:\n \$NOPI\n\n} + {$nopaging} {Disable listing page formatting\n\nSyntax:\n \$NOPAGING\n\nExample:\n \$NOPAGING\n\n} + {$pagelength} {Set lines per page for listing\n\nSyntax:\n \$PAGELENGTH(int)\n\nExample:\n \$PAGELENGTH(64)\n\n} + {$pl} {Set lines per page for listing\n\nSyntax:\n \$PL(int)\n\nExample:\n \$PL(64)\n\n} + {$pagewidth} {Set columns per line for listing\n\nSyntax:\n \$PAGEWIDTH(int)\n\nExample:\n \$PAGEWIDTH(132)\n\n} + {$pw} {Set columns per line for listing\n\nSyntax:\n \$PW(int)\n\nExample:\n \$PW(132)\n\n} + {$philips} {Switch on 83C75x family support\n\nSyntax:\n \$PHILIPS\n\nExample:\n \$PHILIPS\n\nNote:\n Supported by ASEM-51 only} + {$save} {Save current \$LIST/\$GEN/\$COND\n\nSyntax:\n \$SAVE\n\nExample:\n \$SAVE\n\nNote:\n Supported by ASEM-51 only} + {$sa} {Save current \$LIST/\$GEN/\$COND\n\nSyntax:\n \$SA\n\nExample:\n \$SA\n\nNote:\n Supported by ASEM-51 only} + {$restore} {Restore old \$LIST/\$GEN/\$COND\n\nSyntax:\n \$RESTORE\n\nExample:\n \$RESTORE\n\nNote:\n Supported by ASEM-51 only} + {$rs} {Restore old \$LIST/\$GEN/\$COND\n\nSyntax:\n \$RS\n\nExample:\n \$RS\n\nNote:\n Supported by ASEM-51 only} + {$symbols} {Create symbol table\n\nSyntax:\n \$SYMBOLS\n\nExample:\n \$SYMBOLS\n\n} + {$sb} {Create symbol table\n\nSyntax:\n \$SB\n\nExample:\n \$SB\n\n} + {$nosymbols} {Don't create symbol table\n\nSyntax:\n \$NOSYMBOLS\n\nExample:\n \$NOSYMBOLS\n\n} + {$nosb} {Don't create symbol table\n\nSyntax:\n \$NOSB\n\nExample:\n \$NOSB\n\n} + {$title} {Inserts title string into page header\n\nSyntax:\n \$TITLE(string)\n\nExample:\n \$TITLE(My firts code)\n\n} + {$tt} {Inserts title string into page header\n\nSyntax:\n \$TT(string)\n\nExample:\n \$TT(My firts code)\n\n} + {$xref} {Create cross reference\n\nSyntax:\n \$XREF\n\nExample:\n \$XREF\n\nNote:\n Supported by ASEM-51 only} + {$xr} {Create cross reference\n\nSyntax:\n \$XR\n\nExample:\n \$XR\n\nNote:\n Supported by ASEM-51 only} + {$noxref} {Don't create cross reference\n\nSyntax:\n \$NOXREF\n\nExample:\n \$NOXREF\n\nNote:\n Supported by ASEM-51 only} + {$noxr} {Don't create cross reference\n\nSyntax:\n \$NOXR\n\nExample:\n \$NOXR\n\nNote:\n Supported by ASEM-51 only} + {$noobject} {Do not create Intel HEX file\n\nSyntax:\n \$NOOBJECT\n\nExample:\n \$NOOBJECT\n\nNote:\n Supported by native assembler only} + {$object} {Specify file name for Intel HEX\n\nSyntax:\n \$OBJECT(string)\n\nExample:\n \$OBJECT(my_hex.hex)\n\nNote:\n Supported by native assembler only} + {$print} {Specify file name for list file\n\nSyntax:\n \$PRINT(string)\n\nExample:\n \$PRINT(my_list.lst)\n\nNote:\n Supported by native assembler only} + {$noprint} {Do not create list file at all\n\nSyntax:\n \$NOPRINT\n\nExample:\n \$NOPRINT\n\nNote:\n Supported by native assembler only} + {$nomacrosfirst} {Define and expand macro instruction after! conditional assembly and definitions of constants\n\nSyntax:\n \$NOMACROSFIRTS\n\nExample:\n \$NOMACROSFIRTS\n\nNote:\n Supported by native assembler only} + } + + ## Detail description of each instruction + # Format: { + # {INSTRUCTION OPR0, OPR1 ...} { + # {description} + # {class} + # {note} + # {affected flags in order: C OV AC, for instance "{0 X 1}"} + # } + # } + common INSTRUCTION_DESCRIPTION { + {ADD A, Rn} { + {Add register to Accumulator} + {Arithmetic Operations} + {} + {X X X} + } + {ADD A, direct} { + {Add direct byte to Accumulator} + {Arithmetic Operations} + {} + {X X X} + } + {ADD A, @Ri} { + {Add indirect RAM to Accumulator} + {Arithmetic Operations} + {} + {X X X} + } + {ADD A, #data} { + {Add immediate data to Accumulator} + {Arithmetic Operations} + {} + {X X X} + } + {ADDC A, Rn} { + {Add register to Accumulator with Carry} + {Arithmetic Operations} + {} + {X X X} + } + {ADDC A, direct} { + {Add direct byte to Accumulator with Carry} + {Arithmetic Operations} + {} + {X X X} + } + {ADDC A, @Ri} { + {Add indirect RAM to Accumulator with Carry} + {Arithmetic Operations} + {} + {X X X} + } + {ADDC A, #data} { + {Add immediate data to Acc with Carry} + {Arithmetic Operations} + {} + {X X X} + } + {SUBB A, Rn} { + {Subtract Register from Acc with borrow} + {Arithmetic Operations} + {} + {X X X} + } + {SUBB A, direct} { + {Subtract direct byte from Acc with borrow} + {Arithmetic Operations} + {} + {X X X} + } + {SUBB A, @Ri} { + {Subtract indirect RAM from ACC with borrow} + {Arithmetic Operations} + {} + {X X X} + } + {SUBB A, #data} { + {Subtract immediate data from Acc with borrow} + {Arithmetic Operations} + {} + {X X X} + } + {INC A} { + {Increment Accumulator} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {INC Rn} { + {Increment register} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {INC direct} { + {Increment direct byte} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {INC @Ri} { + {Increment direct RAM} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {DEC A} { + {Decrement Accumulator} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {DEC Rn} { + {Decrement Register} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {DEC direct} { + {Decrement direct byte} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {DEC @Ri} { + {Decrement indirect RAM} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {INC DPTR} { + {Increment Data Pointer} + {Arithmetic Operations} + {Read-Modify-Write} + {} + } + {MUL AB} { + {Multiply A & B} + {Arithmetic Operations} + {} + {0 X {}} + } + {DIV AB} { + {Divide A by B} + {Arithmetic Operations} + {} + {0 X {}} + } + {DA A} { + {Decimal Adjust Accumulator} + {Arithmetic Operations} + {} + {X {} {}} + } + + + {ANL A, Rn} { + {AND Register to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ANL A, direct} { + {AND direct byte to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ANL A, @Ri} { + {AND indirect RAM to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ANL A, #data} { + {AND immediate data to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ANL direct, A} { + {AND Accumulator to direct byte} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ANL direct, #data} { + {AND immediate data to direct byte} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ORL A, Rn} { + {OR register to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ORL A, direct} { + {OR direct byte to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ORL A, @Ri} { + {OR indirect RAM to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ORL A, #data} { + {OR immediate data to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ORL direct, A} { + {OR Accumulator to direct byte} + {Logical Operations} + {Read-Modify-Write} + {} + } + {ORL direct, #data} { + {OR immediate data to direct byte} + {Logical Operations} + {Read-Modify-Write} + {} + } + {XRL A, Rn} { + {Exclusive-OR register to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {XRL A, direct} { + {Exclusive-OR direct byte to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {XRL A, @Ri} { + {Exclusive-OR indirect RAM to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {XRL A, #data} { + {Exclusive-OR immediate data to Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {XRL direct, A} { + {Exclusive-OR Accumulator to direct byte} + {Logical Operations} + {Read-Modify-Write} + {} + } + {XRL direct, #data} { + {Exclusive-OR immediate data to direct byte} + {Logical Operations} + {Read-Modify-Write} + {} + } + {CLR A} { + {Clear Accumulator} + {Logical Operations} + {} + {} + } + {CPL A} { + {Complement Accumulator} + {Logical Operations} + {Read-Modify-Write} + {} + } + {RL A} { + {Rotate Accumulator Left} + {Logical Operations} + {} + {} + } + {RLC A} { + {Rotate Accumulator Left through the Carry} + {Logical Operations} + {} + {X {} {}} + } + {RR A} { + {Rotate Accumulator Right} + {Logical Operations} + {} + {} + } + {RRC A} { + {Rotate Accumulator Right through the Carry} + {Logical Operations} + {} + {X {} {}} + } + {SWAP A} { + {Swap nibbles within the Accumulator} + {Logical Operations} + {} + {} + } + + + + {MOV A, Rn} { + {Move register to Accumulator} + {Data Transfer} + {} + {} + } + {MOV A, direct} { + {Move direct byte to Accumulator} + {Data Transfer} + {} + {} + } + {MOV A, @Ri} { + {Move indirect RAM to Accumulator} + {Data Transfer} + {} + {} + } + {MOV A, #data} { + {Move immediate data to Accumulator} + {Data Transfer} + {} + {} + } + {MOV Rn, A} { + {Move Accumulator to register} + {Data Transfer} + {} + {} + } + {MOV Rn, direct} { + {Move direct byte to register} + {Data Transfer} + {} + {} + } + {MOV Rn, #data} { + {Move immediate data to register} + {Data Transfer} + {} + {} + } + {MOV direct, A} { + {Move Accumulator to direct byte} + {Data Transfer} + {} + {} + } + {MOV direct, Rn} { + {Move register to direct byte} + {Data Transfer} + {} + {} + } + {MOV direct, direct} { + {Move direct byte to direct} + {Data Transfer} + {} + {} + } + {MOV direct, @Ri} { + {Move indirect RAM to direct byte} + {Data Transfer} + {} + {} + } + {MOV direct, #data} { + {Move immediate data to direct byte} + {Data Transfer} + {} + {} + } + {MOV @Ri, A} { + {Move Accumulator to indirect RAM} + {Data Transfer} + {} + {} + } + {MOV @Ri, direct} { + {Move direct byte to indirect RAM} + {Data Transfer} + {} + {} + } + {MOV @Ri, #data} { + {Move immediate data to indirect RAM} + {Data Transfer} + {} + {} + } + {MOV DPTR, #data16} { + {Load Data Pointer with a 16-bit constant} + {Data Transfer} + {} + {} + } + {MOVC A, @A+DPTR} { + {Move Code byte relative to DPTR to Acc} + {Data Transfer} + {} + {} + } + {MOVC A, @A+PC} { + {Move Code byte relative to PC to Acc} + {Data Transfer} + {} + {} + } + {MOVX A, @Ri} { + {Move External RAM (8-bit addr) to Acc} + {Data Transfer} + {} + {} + } + {MOVX A, @DPTR} { + {Move Exernal RAM (16-bit addr) to Acc} + {Data Transfer} + {} + {} + } + {MOVX @Ri, A} { + {Move Acc to External RAM (8-bit addr)} + {Data Transfer} + {} + {} + } + {MOVX @DPTR, A} { + {Move Acc to External RAM (16-bit addr)} + {Data Transfer} + {} + {} + } + {PUSH direct} { + {Push direct byte onto stack} + {Data Transfer} + {} + {} + } + {POP direct} { + {Pop direct byte from stack} + {Data Transfer} + {} + {} + } + {XCH A, Rn} { + {Exchange register with Accumulator} + {Data Transfer} + {} + {} + } + {XCH A, direct} { + {Exchange direct byte with Accumulator} + {Data Transfer} + {} + {} + } + {XCH A, @Ri} { + {Exchange indirect RAM with Accumulator} + {Data Transfer} + {} + {} + } + {XCHD A, @Ri} { + {Exchange low-order Digit indirect RAM with Acc} + {Data Transfer} + {} + {} + } + + + {CLR C} { + {Clear Carry} + {Boolean Variable Manipulation} + {} + {0 {} {}} + } + {CLR bit} { + {Clear direct bit} + {Boolean Variable Manipulation} + {Read-Modify-Write} + {} + } + {SETB C} { + {Set Carry} + {Boolean Variable Manipulation} + {} + {1 {} {}} + } + {SETB bit} { + {Set direct bit} + {Boolean Variable Manipulation} + {Read-Modify-Write} + {} + } + {CPL C} { + {Complement Carry} + {Boolean Variable Manipulation} + {Read-Modify-Write} + {X {} {}} + } + {CPL bit} { + {Complement direct bit} + {Boolean Variable Manipulation} + {Read-Modify-Write} + {} + } + {ANL C, bit} { + {AND direct bit to CARRY} + {Boolean Variable Manipulation} + {Read-Modify-Write} + {X {} {}} + } + {ANL C, /bit} { + {AND complement of direct bit to Carry} + {Boolean Variable Manipulation} + {Read-Modify-Write} + {X {} {}} + } + {ORL C, bit} { + {OR direct bit to Carry} + {Boolean Variable Manipulation} + {} + {X {} {}} + } + {ORL C, /bit} { + {OR complement of direct bit to Carry} + {Boolean Variable Manipulation} + {} + {X {} {}} + } + {MOV C, bit} { + {Move direct bit to Carry} + {Boolean Variable Manipulation} + {} + {X {} {}} + } + {MOV bit, C} { + {Move Carry to direct bit} + {Boolean Variable Manipulation} + {Read-Modify-Write} + {} + } + {JC rel} { + {Jump if Carry is set} + {Boolean Variable Manipulation} + {} + {} + } + {JNC rel} { + {Jump if Carry not set} + {Boolean Variable Manipulation} + {} + {} + } + {JB bit, rel} { + {Jump if direct Bit is set} + {Boolean Variable Manipulation} + {} + {} + } + {JNB bit, rel} { + {Jump if direct Bit is Not set} + {Boolean Variable Manipulation} + {} + {} + } + {JBC bit, rel} { + {Jump if direct Bit is set & clear bit} + {Boolean Variable Manipulation} + {Read-Modify-Write} + {} + } + + + {ACALL addr11} { + {Absolute Subroutine Call} + {Program Branching} + {} + {} + } + {LCALL addr16} { + {Long Subroutine Call} + {Program Branching} + {} + {} + } + {RET } { + {Return from Subroutine} + {Program Branching} + {} + {} + } + {RETI } { + {Return from interrupt} + {Program Branching} + {} + {} + } + {AJMP addr11} { + {Absolute Jump} + {Program Branching} + {} + {} + } + {LJMP addr16} { + {Long Jump} + {Program Branching} + {} + {} + } + {SJMP rel} { + {Short Jump (relative addr)} + {Program Branching} + {} + {} + } + {JMP @A+DPTR} { + {Jump indirect relative to the DPTR} + {Program Branching} + {} + {} + } + {JZ rel} { + {Jump if Accumulator is Zero} + {Program Branching} + {} + {} + } + {JNZ rel} { + {Jump if Accumulator is Not Zero} + {Program Branching} + {} + {} + } + {CJNE A, direct, rel} { + {Compare direct byte to Acc and Jump if Not Equal} + {Program Branching} + {} + {X {} {}} + } + {CJNE A, #data, rel} { + {Compare immediate to Acc and Jump if Not Equal} + {Program Branching} + {} + {X {} {}} + } + {CJNE Rn, #data, rel} { + {Compare immediate to register and Jump if Not Equal} + {Program Branching} + {} + {X {} {}} + } + {CJNE @Ri, #data, rel} { + {Compare immediate to indirect and Jump if Not Equal} + {Program Branching} + {} + {X {} {}} + } + {DJNZ Rn, rel} { + {Decrement register and Jump if Not Zero} + {Program Branching} + {Read-Modify-Write} + {} + } + {DJNZ direct, rel} { + {Decrement direct byte and Jump if Not Zero} + {Program Branching} + {Read-Modify-Write} + {} + } + {NOP } { + {No Operation} + {Program Branching} + {} + {} + } + } + + ## PRIVATE + private variable instruction_text {} ;# Widget: ID of text widget of tab "Instruction details" + private variable instruction_menu ;# Widget: Popup menu for the text widget + private variable instruction_label ;# Widget: ID of label above instruction details + private variable header_text ;# Widget: Text header + private variable instruction_last {} ;# String: Last instruction shown in details window + private variable parent {} ;# Widget: GUI parent + private variable gui_initialized 0 ;# Bool: GUI initialized + private variable gui_preparing 0 ;# Bool: Prearing panel GUI + private variable enabled 0 ;# Bool: enable procedures which are needless while loading project + + private variable help_win_index 0 ;# Int: Index of help window object (just some number) + private variable ins_help_win_enabled 1 ;# Bool: Enable instruction help window + private variable ins_help_win_created 0 ;# Bool: Help window widgets are ready to be mapped by geometry manager + private variable ins_help_win_visible 0 ;# Bool: Flag help window visible + private variable ins_help_window {} ;# Widget: Help window itself + private variable help_win_title ;# Widget: Title label (should contain instruction name and operands) + ## Array of Widgets: Labels containing certain information + # Avaliable keys are: description, length, execution_time, opcode, note and class + private variable help_win_labels + + constructor {} { + incr count + } + + destructor { + } + + ## Prepare object for creating its GUI + # @parm Widget _parent - GUI parent widget + # @return void + public method PrepareInstructionDetails {_parent} { + set parent $_parent + set gui_initialized 0 + } + + ## Create GUI of tab "Instruction details" + # @return void + public method CreateInstructionDetailsGUI {} { + if {$gui_initialized || $gui_preparing || ${::Editor::editor_to_use}} {return} + set gui_preparing 1 + + # Create frames + set body_frame [frame $parent.frm_rightPanel_instruction_body] + set text_frame [frame $body_frame.frm_rightPanel_instruction_txt -bd 1 -relief sunken] + set header_frame [frame $parent.frm_rightPanel_instruction_header] + + # Button "Show legend" + set button [ttk::button \ + $header_frame.but_rightPanel_instruction_legend \ + -image ::ICONS::16::help \ + -style Flat.TButton \ + -command "$this rightPanel_ins_legend" \ + ] + DynamicHelp::add $header_frame.but_rightPanel_instruction_legend \ + -text [mc "Show legend"] + pack $button -side right -fill none -expand 0 + setStatusTip -widget $button -text [mc "Show legend"] + + # Tab header (instruction name) + set instruction_label [label $header_frame.lbl_rightPanel_instruction_header \ + -fg {#0000FF} \ + -anchor w \ + -padx {20px} \ + -font [font create -weight {bold} -size -17 -family $::DEFAULT_FIXED_FONT] \ + ] + pack $instruction_label -side left -fill x -expand 1 + setStatusTip -widget $instruction_label -text [mc "Instruction name"] + + # Create popup menu for instruction text and its header + set instruction_menu [menu $text_frame.popup_menu -tearoff 0] + $instruction_menu add command -label "Configure" -compound left \ + -command {::configDialogs::rightPanel::mkDialog 1} \ + -underline 0 -image ::ICONS::16::configure + + # Text header + set header_text [text $text_frame.txt_rightPanel_instruction_hdr \ + -cursor left_ptr \ + -font $instruction_font \ + -bg {#DDDDDD} \ + -height 1 \ + -bd 0 \ + -exportselection 0 \ + ] + bind $header_text <ButtonRelease-3> "tk_popup $instruction_menu %X %Y; break" + bind $header_text <Key-Menu> "tk_popup $instruction_menu %X %Y; break" + bindtags $header_text $header_text + + # Instruction details text + set instruction_text [text $text_frame.txt_rightPanel_instruction \ + -yscrollcommand "$body_frame.src_rightPanel_instruction set" \ + -cursor left_ptr -state disabled -wrap word \ + -font $instruction_font -bd 0 -exportselection 0 \ + ] + # Create scrollbar + pack [ttk::scrollbar $body_frame.src_rightPanel_instruction \ + -orient vertical -command "$instruction_text yview" \ + ] -side right -fill y + + setStatusTip -widget $instruction_text -text [mc "Instruction operands"] + bind $instruction_text <ButtonRelease-3> "tk_popup $instruction_menu %X %Y; break" + bind $instruction_text <Key-Menu> "tk_popup $instruction_menu %X %Y; break" + bind $instruction_text <<Selection>> {false_selection %W} + bind $instruction_text <Motion> "$this rightPanel_ins_text_motion %x %y %X %Y" + bind $instruction_text <Leave> "+$this rightPanel_ins_hide_ins_help_window" + + $instruction_text delete 1.0 end + $instruction_text tag configure tag_sel -background #CCCCFF + $instruction_text tag configure tag_sel0 -background #E0FFE0 + rightPanel_refresh_instruction_highlighting + $instruction_text tag configure tag_bold -font [font create \ + -size -12 -family $::DEFAULT_FIXED_FONT -weight {bold}] + + # Pack parts of text frame (Instruction details text, Text header) + pack $header_text -side top -fill x + pack $instruction_text -side bottom -fill both -expand 1 + pack $text_frame -side left -fill both -expand 1 + + # Pack all remaining frames + pack $header_frame -side top -fill x + pack $body_frame -side bottom -fill both -expand 1 + + set gui_initialized 1 + } + + ## Invoke legend window for "Instruction details" + # @return void + public method rightPanel_ins_legend {} { + # Destroy legend window + if {[winfo exists .rightPanel_legend]} { + grab release .rightPanel_legend + destroy .rightPanel_legend + return + } + set x [expr {[winfo pointerx .] - 380}] + set y [winfo pointery .] + + # Create legend window + set win [toplevel .rightPanel_legend -class {Help} -bg {#EEEEEE}] + set frame [frame $win.f -bg {#555555} -bd 0 -padx 1 -pady 1] + wm overrideredirect $win 1 + + # Click to close + bind $win <Button-1> "grab release $win; destroy $win" + + # Create header "-- click to close --" + pack [label $frame.lbl_header \ + -text [mc "-- click to close --"] \ + -bg {#FFFF55} -font $::smallfont\ + -fg {#000000} -anchor c \ + ] -side top -anchor c -fill x + + # Create text widget + set text [text $frame.text \ + -bg {#FFFFCC} \ + -exportselection 0 \ + -takefocus 0 \ + -cursor left_ptr \ + -bd 0 -relief flat \ + ] + + pack $frame -fill both -expand 1 + + # Create text tags + $this right_panel_create_highlighting_tags $text $instruction_tags 0 + $text tag configure tag_sel \ + -relief raised \ + -borderwidth 1 \ + -background #F8F8F8 + $text tag configure tag_desc + + ## Fill text widget + # "code8" + set idx [$text index insert] + $text insert end [mc "code8"] + $text tag add tag_code8 $idx insert + set idx [$text index insert] + $text insert end [mc "\t8 bit offset for relative jump\n"] + $text tag add tag_desc $idx insert + # "code11" + set idx [$text index insert] + $text insert end [mc "code11"] + $text tag add tag_code11 $idx insert + set idx [$text index insert] + $text insert end [mc "\t11 bit program memory address\n"] + $text tag add tag_desc $idx insert + # "code16" + set idx [$text index insert] + $text insert end [mc "code16"] + $text tag add tag_code16 $idx insert + set idx [$text index insert] + $text insert end [mc "\t16 bit program memory address\n"] + $text tag add tag_desc $idx insert + # "imm8" + set idx [$text index insert] + $text insert end [mc "imm8"] + $text tag add tag_imm8 $idx insert + set idx [$text index insert] + $text insert end [mc "\t8 bit constant data\n"] + $text tag add tag_desc $idx insert + # "imm16" + set idx [$text index insert] + $text insert end [mc "imm16"] + $text tag add tag_imm16 $idx insert + set idx [$text index insert] + $text insert end [mc "\t16 bit constant data\n"] + $text tag add tag_desc $idx insert + # "data" + set idx [$text index insert] + $text insert end [mc "data"] + $text tag add tag_data $idx insert + set idx [$text index insert] + $text insert end [mc "\tinternal data memory or SFR direct address\n"] + $text tag add tag_desc $idx insert + # "bit" + set idx [$text index insert] + $text insert end [mc "bit"] + $text tag add tag_bit $idx insert + set idx [$text index insert] + $text insert end [mc "\tbit memory direct address\n"] + $text tag add tag_desc $idx insert + + $text insert end "\n" + # "DPTR" + set idx [$text index insert] + $text insert end "DPTR" + $text tag add tag_DPTR $idx insert + set idx [$text index insert] + $text insert end [mc "\tData PoinTeR register (16 bit)\n"] + $text tag add tag_desc $idx insert + # "A" + set idx [$text index insert] + $text insert end "A" + $text tag add tag_A $idx insert + set idx [$text index insert] + $text insert end [mc "\tPrimary work register\n"] + $text tag add tag_desc $idx insert + # "AB" + set idx [$text index insert] + $text insert end "AB" + $text tag add tag_AB $idx insert + set idx [$text index insert] + $text insert end [mc "\tAccumulator\n"] + $text tag add tag_desc $idx insert + + $text insert end "\n" + # "R0..R7" + set idx [$text index insert] + $text insert end "R0..R7" + $text tag add tag_SFR $idx insert + set idx [$text index insert] + $text insert end [mc "\tRegisters of active bank\n"] + $text tag add tag_desc $idx insert + # "C" + set idx [$text index insert] + $text insert end "C" + $text tag add tag_SFR $idx insert + set idx [$text index insert] + $text insert end [mc "\tCarry flag\n"] + $text tag add tag_desc $idx insert + # "@R0 ..." + set idx [$text index insert] + $text insert end "@R0 ..." + $text tag add tag_indr $idx insert + set idx [$text index insert] + $text insert end [mc "\tIndirect address"] + $text tag add tag_desc $idx insert + + # Show the text + $text configure -state disabled + pack $text -side bottom -fill both -expand 1 + + # Show the window + wm geometry $win "=380x280+$x+$y" + update + catch { + grab -global $win + } + } + + ## Clear instruction details window + # @return void + public method rightPanel_ins_clear {} { + if {!$enabled || ${::Editor::editor_to_use}} {return} + if {!$gui_initialized} {CreateInstructionDetailsGUI} + $instruction_text configure -state normal + $instruction_text delete 1.0 end + $instruction_text configure -state disabled + $instruction_label configure -text {} + + set instruction_last {} + rightPanel_ins_hide_ins_help_window + set help_win_index 0 + } + + ## Refresh highlighting tags in "Instruction details" + # @return void + public method rightPanel_refresh_instruction_highlighting {} { + if {${::Editor::editor_to_use}} {return} + if {!$gui_initialized && !$gui_preparing} {return} + $this right_panel_create_highlighting_tags \ + $instruction_text $instruction_tags 0 + } + + ## Unset current selection in "Instruction details" window + # @return void + public method rightPanel_ins_unselect {} { + if {!$enabled || ${::Editor::editor_to_use}} {return} + if {!$gui_initialized} {return} + + $instruction_text tag remove tag_sel 1.0 end + if {$::CONFIG(VALIDATION_LEVEL) == 2} { + $instruction_label configure -fg {#FF0000} + } { + $instruction_label configure -fg {#0000FF} + } + } + + ## Change current selection in "Instruction details" window + # @parm Bool perfect_match - Operand matches exactly + # @parm List list_of_indexes - Lines to select (benining from zero) (eg. '0 4 9') + # @return void + public method rightPanel_ins_select {perfect_match list_of_indexes} { + if {!$enabled || ${::Editor::editor_to_use}} {return} + if {!$gui_initialized} {return} + if {[$instruction_label cget -text] == {}} {return} + $instruction_label configure -fg {#0000FF} + if {$perfect_match} { + set tag tag_sel + } { + set tag tag_sel0 + } + foreach line $list_of_indexes { + incr line + $instruction_text tag add $tag $line.0 "$line.0+1l" + } + $instruction_text see $line.0 + } + + ## Change current directive in "Instruction details" window + # @parm Char type - 'C' == Control; 'D' == Directive + # @parm String directive - directive name + # @return void + public method rightPanel_dir_change {type directive} { + if {!$enabled || ${::Editor::editor_to_use}} {return} + if {!$gui_initialized} {return} + + regsub {^\.} $directive {} directive + set directive [string tolower $directive] + if {$instruction_last == $directive} {return} + set instruction_last $directive + + set ins_help_win_enabled 0 + + # Change content of tab header + if {$type == {D}} { + set clr {#00AADD} + } { + set clr {#00AADD} + } + set dir_up [string toupper $directive] + $instruction_label configure -text $dir_up -fg $clr + $header_text delete 1.0 end + + # Enable and clear the text widget + $instruction_text configure -state normal + $instruction_text delete 1.0 end + + set idx [lsearch -ascii -exact $HELP_FOR_DIRECTIVES $directive] + if {$idx == -1} { + $instruction_text insert end [mc "no help available for this directive"] + } { + incr idx + $instruction_text insert end [lindex $HELP_FOR_DIRECTIVES $idx] + } + + # Create highlight tags + $instruction_text tag add tag_DPTR 1.0 {1.0 lineend} + $instruction_text tag add tag_AB 3.0 {3.0 lineend} + $instruction_text tag add tag_AB 6.0 {6.0 lineend} + $instruction_text tag add tag_indr {end-2l linestart} {end-2l lineend} + + # Disable the widget + $instruction_text configure -state disabled + } + + ## Change current instruction in "Instruction details" window + # @parm String instruction - instruction name + # @return void + public method rightPanel_ins_change {instruction} { + if {!$enabled || ${::Editor::editor_to_use}} {return} + if {!$gui_initialized} {return} + + set instruction [string tolower $instruction] + if {$instruction_last == $instruction} {return} + set instruction_last $instruction + + set ins_help_win_enabled 0 + + # Change content of tab header + $instruction_label configure -text [string toupper $instruction] -fg {#0000FF} + $header_text delete 1.0 end + $header_text insert 1.0 "Opr 0\tOpr 1\tOpr 2\tLen Code Time" + + # Find given instruction in compilers instruction set definition + if {[lsearch -ascii -exact ${::CompilerConsts::AllInstructions} $instruction] == -1} {return} + + # Enable and clear the text widget + $instruction_text configure -state normal + $instruction_text delete 1.0 end + + # Display instruction details + set data {} + foreach line [lindex $::CompilerConsts::InstructionDefinition($instruction) 1] { + # Write operands + for {set i 0} {$i < 3} {incr i} { + set startIndex [$instruction_text index insert] + set opr [lindex $line [list 0 $i]] + + # Adjust operand + if {[lsearch -ascii -exact {code8 code11 code16 imm8 imm16 data bit} $opr] == -1} { + set opr [string toupper $opr] + } + + # Insert operand + $instruction_text insert insert $opr + $instruction_text insert insert "\t" + + # Highlight operand + switch -- $opr { + {code8} { ;# 8 bit offset for relative jump + $instruction_text tag add tag_code8 $startIndex insert-1c + } + {code11} { ;# 11 bit program memory address + $instruction_text tag add tag_code11 $startIndex insert-1c + } + {code16} { ;# 16 bit program memory address + $instruction_text tag add tag_code16 $startIndex insert-1c + } + {imm8} { ;# 8 bit constant data + $instruction_text tag add tag_imm8 $startIndex insert-1c + } + {imm16} { ;# 16 bit constant data + $instruction_text tag add tag_imm16 $startIndex insert-1c + } + {data} { ;# internal data memory or SFR direct address + $instruction_text tag add tag_data $startIndex insert-1c + } + {bit} { ;# bit memory direct address + $instruction_text tag add tag_bit $startIndex insert-1c + } + {DPTR} { ;# Data PoinTeR register (16 bit) + $instruction_text tag add tag_DPTR $startIndex insert-1c + } + {A} { ;# Primary work register (Accumulator) + $instruction_text tag add tag_A $startIndex insert-1c + } + {AB} { ;# Accumulator + $instruction_text tag add tag_AB $startIndex insert-1c + } + default { ;# SFR or indirect address + # Indirect address + if {[string index $opr 0] == {@}} { + $instruction_text tag add tag_indr $startIndex insert-1c + # SFR + } { + $instruction_text tag add tag_SFR $startIndex insert-1c + } + } + } + } + + # Write length + $instruction_text insert insert " " + set startIndex [$instruction_text index insert] + set num [lindex $line 1] + $instruction_text insert insert $num + if {$num > 0 && $num < 6} { + $instruction_text tag add "tag_$num" $startIndex insert + } + + # Write OP code + $instruction_text insert insert " " + $instruction_text insert insert [string toupper [lindex $line 2]] + + # Write time + $instruction_text insert insert " " + set startIndex [$instruction_text index insert] + set num [lindex $line 4] + $instruction_text insert insert $num + if {$num > 0 && $num < 6} { + $instruction_text tag add "tag_$num" $startIndex insert + } + + # Set last 9 characters to bold font + $instruction_text tag add tag_bold {insert-9c} insert + $instruction_text insert insert "\n" + } + + # Disable the widget + $instruction_text configure -state disabled + + # Update help window + if {$ins_help_win_visible} { + set idx $help_win_index + set help_win_index 0 + show_ins_help_window $idx + } + + set ins_help_win_enabled 1 + } + + ## Set flag enabled + # @parm Bool bool - New value + # @return void + public method right_panel_instruction_details_set_enabled {bool} { + set enabled $bool + } + + ## Handles Motion event on the text widget + # @param Int x - Relative mouse pointer position + # @param Int y - Relative mouse pointer position + # @param Int X - Absolute mouse pointer position + # @param Int Y - Absolute mouse pointer position + # @return void + public method rightPanel_ins_text_motion {x y X Y} { + if {!$ins_help_win_enabled} {return} + set index [$instruction_text index @$x,$y] + set index [expr {int($index)}] + if {$help_win_index == $index} { + move_ins_help_window $X $Y + return + } + set help_win_index $index + + show_ins_help_window $index + } + + ## Move instruction help window + # @param Int X - Absolute mouse pointer position + # @param Int Y - Absolute mouse pointer position + # @return void + private method move_ins_help_window {X Y} { + if {!$ins_help_win_visible} { + return + } + + # Determinate main window geometry + set geometry [split [wm geometry .] {+}] + set limits [split [lindex $geometry 0] {x}] + + # Adjust X and Y + set x_coord [expr {$X - 5 - [lindex $geometry 1]}] + set y_coord [expr {$Y - 20 - [lindex $geometry 2]}] + + if {$y_coord > ([lindex $limits 1] - 220)} {incr y_coord -240} + + # Show the window + catch { + place $ins_help_window -anchor ne -x $x_coord -y $y_coord -width 300 + raise $ins_help_window + } + } + + ## Show instruction help window + # @param Int index - Line number + # @return void + private method show_ins_help_window {index} { + # Create help window widget + if {!$ins_help_win_created} { + create_ins_help_window + } + # Hide window if there is nothing to show + if {[$instruction_text compare $index.0 == end]} { + rightPanel_ins_hide_ins_help_window + return + } + + # Set help window visibility flag + set ins_help_win_visible 1 + + # Determinate instruction name (and possibly abort the process) + incr index -1 + set instruction [string tolower [$instruction_label cget -text]] + if {![string length $instruction]} { + rightPanel_ins_hide_ins_help_window + return + } + # Check if the instruction is really an instruction + if {[lsearch -ascii -exact ${::CompilerConsts::AllInstructions} $instruction] == -1} {return} + + # Modify instruction name if nessesary + switch -- $instruction { + {jmp} { + switch -- $index { + 1 {set instruction {ljmp}} + 2 {set instruction {ajmp}} + 3 {set instruction {sjmp}} + } + set index 0 + } + } + + # Obtain detailed informations about the instruction + set operands_tmp [list] + set instruction_def [lindex $::CompilerConsts::InstructionDefinition($instruction) [list 1 $index]] + set operands [lindex $instruction_def 0] + foreach operand $operands { + switch -glob -- $operand { + a - + c - + ab - + @dptr - + @a+dptr - + @a+pc - + dptr { + set operand [string toupper $operand] + } + r? { + set operand {Rn} + } + @r? { + set operand {@Ri} + } + imm8 { + set operand {#data} + } + imm16 { + set operand {#data16} + } + code8 { + set operand {rel} + } + code11 { + set operand {addr11} + } + code16 { + set operand {addr16} + } + bit { + set operand {bit} + } + /bit { + set operand {/bit} + } + data { + set operand {direct} + } + } + lappend operands_tmp $operand + } + set operands [join $operands_tmp {, }] + set instruction [string toupper $instruction] + + # Modify detailed informations + set title "$instruction\t$operands" + + set ins_length [lindex $instruction_def 1] + set opcode [string toupper [lindex $instruction_def 2]] + if {[string length $ins_length]} { + append opcode [string repeat {-} [expr {($ins_length - 1) * 2}]] + } + + set ins_description [lsearch -ascii -exact $INSTRUCTION_DESCRIPTION $title] + if {$ins_description == -1} { + rightPanel_ins_hide_ins_help_window + return + } + incr ins_description + set ins_description [lindex $INSTRUCTION_DESCRIPTION $ins_description] + + # Fill in the help window + $help_win_title configure -text $title + $help_win_labels(description) configure -text [mc [lindex $ins_description 0]] + $help_win_labels(length) configure -text $ins_length + $help_win_labels(execution_time) configure -text [lindex $instruction_def 4] + $help_win_labels(opcode) configure -text "0x$opcode" + $help_win_labels(note) configure -text [mc [lindex $ins_description 2]] + $help_win_labels(class) configure -text [mc [lindex $ins_description 1]] + foreach i_0 {0 1 2 } \ + i_1 {C OV AC } \ + i_2 {C_l OV_l AC_l } \ + { + set txt [lindex $ins_description [list 3 $i_0]] + switch -- $txt { + X {set clr {#00AAFF}} + 0 {set clr {#DD0000}} + 1 {set clr {#00CC00}} + default {set clr {#888888}} + } + $help_win_labels($i_1) configure -text $txt -fg $clr + $help_win_labels($i_2) configure -fg $clr + } + } + + ## Hide instruction help window + # @return void + public method rightPanel_ins_hide_ins_help_window {} { + if {!$ins_help_win_visible} { + return + } + + set help_win_index 0 + set ins_help_win_visible 0 + catch { + place forget $ins_help_window + } + } + + ## Create instruciton help window + # @return void + private method create_ins_help_window {} { + set ins_help_win_created 1 + + # Create main parts of the window + set ins_help_window [frame .ins_help_window${count} -bd 0 -bg {#BBBBFF} -padx 2 -pady 2] + pack [frame $ins_help_window.top -bg {#BBBBFF}] -fill x -expand 1 + pack [label $ins_help_window.top.img -bg {#BBBBFF} -image ::ICONS::16::info] -side left + pack [label $ins_help_window.top.tit -bg {#BBBBFF} -justify left -anchor w] -side left -fill x -expand 1 + pack [frame $ins_help_window.msg -bg {#FFFFFF} -padx 10 -pady 5] -fill both -expand 1 + set help_win_title "$ins_help_window.top.tit" + + ## Create other parts of the window + # Descripton + set i 0 + set help_win_labels(description) [ \ + label $ins_help_window.msg.r_$i \ + -pady 0 -bg {#FFFFFF} \ + -highlightthickness 0 \ + -wraplength 260 -justify left \ + ] + grid $help_win_labels(description) -row $i -column 0 -columnspan 2 -sticky w + incr i + # - (separator) + grid [ttk::separator $ins_help_window.msg.sep \ + -orient horizontal \ + ] -row $i -column 0 -columnspan 2 -sticky we + # Class + incr i + grid [label $ins_help_window.msg.l_$i \ + -pady 0 -fg {#0000AA} \ + -bg {#FFFFFF} \ + -highlightthickness 0 \ + -text [mc "Class:"] \ + ] -row $i -column 0 -sticky w + set help_win_labels(class) [ \ + label $ins_help_window.msg.r_$i \ + -pady 0 -bg {#FFFFFF} \ + -highlightthickness 0 \ + ] + grid $help_win_labels(class) -row $i -column 1 -sticky w + incr i + # Flags + grid [label $ins_help_window.msg.l_$i \ + -pady 0 -fg {#0000AA} \ + -highlightthickness 0 \ + -text [mc "Flags:"] \ + -bg {#FFFFFF} \ + ] -row $i -column 0 -sticky nw + + set flags_frm [frame $ins_help_window.msg.flags_frm \ + -bg {#888888} \ + ] + grid $flags_frm -row $i -column 1 -sticky w + incr i + # Length + grid [label $ins_help_window.msg.l_$i \ + -pady 0 -fg {#0000AA} \ + -highlightthickness 0 \ + -text [mc "Length:"] \ + -bg {#FFFFFF} \ + ] -row $i -column 0 -sticky w + set help_win_labels(length) [ \ + label $ins_help_window.msg.r_$i \ + -pady 0 -bg {#FFFFFF} \ + -highlightthickness 0 \ + ] + grid $help_win_labels(length) -row $i -column 1 -sticky w + incr i + # Time + grid [label $ins_help_window.msg.l_$i \ + -pady 0 -fg {#0000AA} \ + -highlightthickness 0 \ + -text [mc "Time:"] \ + -bg {#FFFFFF} \ + ] -row $i -column 0 -sticky w + set help_win_labels(execution_time) [ \ + label $ins_help_window.msg.r_$i \ + -pady 0 -bg {#FFFFFF} \ + -highlightthickness 0 \ + ] + grid $help_win_labels(execution_time) -row $i -column 1 -sticky w + incr i + # OPCODE + grid [label $ins_help_window.msg.l_$i \ + -pady 0 -fg {#0000AA} \ + -highlightthickness 0 \ + -text [mc "OPCODE:"] \ + -bg {#FFFFFF} \ + ] -row $i -column 0 -sticky w + set help_win_labels(opcode) [ \ + label $ins_help_window.msg.r_$i \ + -pady 0 -bg {#FFFFFF} \ + -highlightthickness 0 \ + ] + grid $help_win_labels(opcode) -row $i -column 1 -sticky w + incr i + # Note + grid [label $ins_help_window.msg.l_$i \ + -pady 0 -fg {#0000AA} \ + -highlightthickness 0 \ + -text [mc "Note:"] \ + -bg {#FFFFFF} \ + ] -row $i -column 0 -sticky w + set help_win_labels(note) [ \ + label $ins_help_window.msg.r_$i \ + -pady 0 -bg {#FFFFFF} \ + -highlightthickness 0 \ + ] + grid $help_win_labels(note) -row $i -column 1 -sticky w + ## Table of flags + # Flag C + set help_win_labels(C_l) [ \ + label $flags_frm.ll_C \ + -bg {#FFFFFF} \ + -pady 0 \ + -highlightthickness 0 \ + -text "C" \ + ] + grid $help_win_labels(C_l) -row 0 -column 0 -sticky nswe -padx 1 -pady 1 + set help_win_labels(C) [ \ + label $flags_frm.lr_C \ + -bg {#FFFFFF} \ + -pady 0 \ + -highlightthickness 0 \ + ] + grid $help_win_labels(C) -row 1 -column 0 -sticky nswe -padx 1 -pady 1 + # Flag OV + set help_win_labels(OV_l) [ \ + label $flags_frm.ll_OV \ + -bg {#FFFFFF} \ + -pady 0 \ + -highlightthickness 0 \ + -text "OV" \ + ] + grid $help_win_labels(OV_l) -row 0 -column 1 -sticky nswe -padx 1 -pady 1 + set help_win_labels(OV) [ \ + label $flags_frm.lr_OV \ + -bg {#FFFFFF} \ + -pady 0 \ + -highlightthickness 0 \ + ] + grid $help_win_labels(OV) -row 1 -column 1 -sticky nswe -padx 1 -pady 1 + # Flag AC + set help_win_labels(AC_l) [ \ + label $flags_frm.ll_AC \ + -bg {#FFFFFF} \ + -pady 0 \ + -highlightthickness 0 \ + -text "AC" \ + ] + grid $help_win_labels(AC_l) -row 0 -column 2 -sticky nswe -padx 1 -pady 1 + set help_win_labels(AC) [ \ + label $flags_frm.lr_AC \ + -bg {#FFFFFF} -bd 1 \ + -pady 0 \ + -highlightthickness 0 \ + ] + grid $help_win_labels(AC) -row 1 -column 2 -sticky nswe -padx 1 -pady 1 + # (finalize creation of table of flags) + grid columnconfigure $ins_help_window.msg 0 -minsize 80 + grid columnconfigure $ins_help_window.msg 1 -weight 1 + } + + proc initialize {} { + set l [llength $HELP_FOR_DIRECTIVES_RAW] + for {set i 0; set j 1} {$i < $l} {incr i 2; incr j 2} { + lappend HELP_FOR_DIRECTIVES [lindex $HELP_FOR_DIRECTIVES_RAW $i] + lappend HELP_FOR_DIRECTIVES [mc [subst [lindex $HELP_FOR_DIRECTIVES_RAW $j]]] + } + } +} + +# Initialize +::InstructionDetails::initialize diff --git a/lib/rightpanel/regwatches.tcl b/lib/rightpanel/regwatches.tcl new file mode 100755 index 0000000..ad5e433 --- /dev/null +++ b/lib/rightpanel/regwatches.tcl @@ -0,0 +1,2120 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 by Martin Ošmera # +# 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. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Implements register watches (part of Right Panel) +# -------------------------------------------------------------------------- + +class RegWatches { + + ## COMMON + common watches_set_shortcuts {} ;# Currently set shortcuts for register watches + common watches_shortcuts_cat {watches} ;# Key shortcut categories related to register watches + # Counter of embedded entry widgets in register watches + common watch_entry_count 0 + # Conter of instances + common count 0 + ## Highlighting tags for register watches + # { + # {tag_name foreground_color ?bold_or_italic?} + # ... + # } + common watch_text_tags { + {tag_Baddr #DD0000 1} + {tag_Xaddr #AA00FF 1} + {tag_Eaddr #00AAFF 1} + {tag_addr #0000DD 1} + {tag_name #8888DD {}} + } + common regfont [font create -family $::DEFAULT_FIXED_FONT -size -14] + # Popup menu for register watches + common WATCHMENU { + {command {Move top} {$watches:top} 0 "rightPanel_watch_move_top" + {top} "Move this register watch to the top of list"} + {command {Move up} {$watches:up} 0 "rightPanel_watch_move_up" + {1uparrow} "Move this register watch up"} + {command {Move down} {$watches:down} 1 "rightPanel_watch_move_down" + {1downarrow} "Move this register watch down"} + {command {Move bottom} {$watches:bottom} 2 "rightPanel_watch_move_bottom" + {bottom} "Move this register watch to the bottom of list"} + {separator} + {command {Remove} {$watches:remove} 2 "rightPanel_watch_remove" + {button_cancel} "Remove this register watch from the list"} + {separator} + {command {Remove all} {$watches:remove_all} 0 "rightPanel_watch_clear" + {editdelete} "Clear the list of register watches"} + {separator} + {command {Save} {} 0 "rightPanel_watch_save {} 1" {filesave} + "Save this list to a file"} + {command {Configure} {} 0 "rightPanel_configure 0" {configure} + "Configure this panel"} + } + # Configuration menu + common CONFMENU { + {cascade {Sort by} 0 "" .sort false 1 { + {command {Name} {} 0 "rightPanel_watch_sort_by N" {} + ""} + {command {Address} {} 0 "rightPanel_watch_sort_by A" {} + ""} + {command {Type} {} 0 "rightPanel_watch_sort_by T" {} + ""} + {separator} + {radiobutton "Incremental" {} ::RegWatches::sorting_order 1 + {} 0 ""} + {radiobutton "Decremental" {} ::RegWatches::sorting_order 0 + {} 0 ""} + }} + {command {Remove all} {} 0 "rightPanel_watch_clear" {editdelete} + ""} + {separator} + {checkbutton {Autoload from code listing} {} {::RegWatches::menu_autoload} 1 0 0 + {rightPanel_watch_toggle_autoload_flag}} + } + + ## PRIVATE + private variable enabled 0 ;# Bool: enable procedures which are needless while loading project + private variable obj_idx ;# Number of this object + private variable parent ;# Widget: parent widget + private variable gui_initialized 0 ;# Bool: GUI initialized + + private variable conf_button ;# Widget: Configuration button + private variable conf_menu {} ;# Configuration menu + private variable watch_menu ;# ID of popup menu for "Register watches" + private variable watch_text ;# ID of text widget representing list of register watches + private variable watch_remove_button ;# ID of button "Remove watch" - Register watches + private variable watch_new_button ;# ID of button "New watch" - Register watches + private variable watch_add_button ;# ID of button "Add watch" - Register watches + private variable watch_addr_entry ;# ID of entry "Address" - Register watches + private variable watch_search_entry ;# ID of entry "Search" - Register watches + private variable watch_search_clear ;# ID of button "Clear search entry" - Register watches + + # Bool: Autoload from LST file + private variable autoload_flag [lindex $::CONFIG(REGWATCHES_CONFIG) 0] + private variable watches_modified 0 ;# Bool: Register watches definition modified + private variable search_val_in_progress 0 ;# Bool: Search entry validation in porgress + private variable watch_file_name {} ;# Name of file currently loaded in register watches + private variable watch_curLine 0 ;# Current line in list of register watches + private variable watch_AN_valid_ena 1 ;# Bool: Enable validation of address entry in register watches + private variable validator_engaged 0 ;# Bool: Address entry validation in progress + private variable watches_enabled 0 ;# Bool: Entry widgets in register watches enabled + + private variable watch_addrs {} ;# List - {hex_addr hex_addr ...} + ## Array of Lists - info about particular watch + # format: $watch_data($hex_addr) -> {regName textVariable} + # note: embedded entry path == $watch_text.$textVariable + private variable watch_data + + + ## Object constructor + constructor {} { + incr count + set obj_idx $count + } + + ## Object destructor + destructor { + if {$gui_initialized} { + # Remove status bar tips for popup menus + menu_Sbar_remove $watch_menu + + # Unallocate GUI related variables + unset RightPanel::watch_addr$obj_idx + unset RightPanel::watch_name$obj_idx + } + } + + ## Prepare object for creating its GUI + # @parm Widget _parent - GUI parent widget + # @parm String watches_file - Definition file for register watches + # @return void + public method PrepareRegWatches {_parent filename} { + set parent $_parent + set watch_file_name $filename + set gui_initialized 0 + } + + ## Create GUI of register watches + # @return void + public method CreateRegWatchesGUI {} { + if {$gui_initialized} {return} + set gui_initialized 1 + + # Top frame + set icon_bar [frame $parent.frm_rightPanel_watch_iconBar] + # Bottom frame + set text_frame [frame $parent.frm_rightPanel_watch_txt] + # Toolbar + set tool_bar [frame $parent.frm_rightPanel_watch_toolBar] + + # Button "Configure" + set button [ttk::button $icon_bar.conf_but \ + -image ::ICONS::16::configure \ + -command "$this rightPanel_watch_cfg_menu" \ + -style Flat.TButton \ + ] + set conf_button $button + pack $button -side left -padx 3 + # Separator + pack [ttk::separator $icon_bar.sep_rightPanel_watch_ib_sepm0 \ + -orient vertical \ + ] -side left -fill y -padx 3 + # Button "Save" + set button [ttk::button $icon_bar.but_rightPanel_watch_save \ + -image ::ICONS::16::filesave \ + -command "$this rightPanel_watch_save {} 1" \ + -style Flat.TButton \ + ] + pack $button -side left -padx 3 + DynamicHelp::add $button -text [mc "Save"] + setStatusTip -widget $button \ + -text [mc "Save"] + # Button "Save as" + set button [ttk::button $icon_bar.but_rightPanel_watch_saveas \ + -image ::ICONS::16::filesaveas \ + -command "$this rightPanel_watch_saveas" \ + -style Flat.TButton \ + ] + pack $button -side left -padx 3 + DynamicHelp::add $button -text [mc "Save under a different filename"] + setStatusTip -widget $button \ + -text [mc "Save under a different filename"] + # Separator + pack [ttk::separator $icon_bar.sep_rightPanel_watch_ib_sep0 \ + -orient vertical \ + ] -side left -fill y -padx 3 + # Button "Open" + set button [ttk::button $icon_bar.but_rightPanel_watch_open \ + -image ::ICONS::16::fileopen \ + -command "$this rightPanel_watch_open" \ + -style Flat.TButton \ + ] + pack $button -side left -padx 3 + DynamicHelp::add $button -text [mc "Open *.wtc file"] + setStatusTip -widget $button \ + -text [mc "Open *.wtc file"] + # Button "Import" + set button [ttk::button $icon_bar.but_rightPanel_watch_imp \ + -image ::ICONS::16::fileimport \ + -style Flat.TButton \ + -command "$this rightPanel_watch_import" \ + ] + pack $button -side left -padx 3 + DynamicHelp::add $button -text [mc "Import list of registers from code listing or WTC file"] + setStatusTip -widget $button \ + -text [mc "Import list of registers from *.lst or *.wtc file"] + # Entry "Search" + set watch_search_entry [ttk::entry $icon_bar.search_entry \ + -validate key \ + -width 0 \ + -validatecommand "$this rightPanel_watch_search_validate %P" \ + ] + DynamicHelp::add $watch_search_entry \ + -text [mc "Enter your search string here"] + pack $watch_search_entry -side left -fill x -expand 1 + setStatusTip -widget $watch_search_entry \ + -text [mc "Search for a name"] + # Button "Clear search string" + set watch_search_clear [ttk::button $icon_bar.clear_search \ + -image ::ICONS::16::clear_left \ + -command "$watch_search_entry delete 0 end" \ + -state disabled \ + -style Flat.TButton \ + ] + DynamicHelp::add $icon_bar.clear_search -text [mc "Clear search string"] + pack $watch_search_clear -side right -after $watch_search_entry + setStatusTip -widget $icon_bar.clear_search \ + -text [mc "Clear search string"] + + # Entry "Address" + set entry [ttk::entry $tool_bar.ent_rightPanel_watch_addr \ + -textvariable RightPanel::watch_addr$count \ + -validatecommand "$this rightPanel_watch_addr_validate %P" \ + -validate key \ + -width 4 \ + ] + DynamicHelp::add $entry \ + -text [mc "Register address:\n 1 or 2 digits\tinternal RAM (not SFR)\n 3 digits\t\texpanded RAM\n 4 digits\t\texternal RAM\n dot and 2 digits\tBit"] + setStatusTip -widget $entry \ + -text [mc "Register address or bit address"] + grid $entry -sticky w -row 2 -column 1 + bind $entry <Return> "$this rightPanel_watch_add" + bind $entry <KP_Enter> "$this rightPanel_watch_add" + + # Entry "Name" + set entry [ttk::entry $tool_bar.ent_rightPanel_watch_name \ + -textvariable RightPanel::watch_name$count \ + -validatecommand "$this rightPanel_watch_name_validate %P" \ + -validate key \ + -width 20 \ + ] + setStatusTip -widget $entry \ + -text [mc "Name of the watch. Any string."] + grid $entry -sticky w -row 2 -column 2 -padx 3 + bind $entry <Return> "$this rightPanel_watch_add" + bind $entry <KP_Enter> "$this rightPanel_watch_add" + # Button "Add" + set watch_add_button [ttk::button $tool_bar.but_rightPanel_watch_add \ + -image ::ICONS::16::add \ + -command "$this rightPanel_watch_add" \ + -style Flat.TButton \ + ] + DynamicHelp::add $watch_add_button -text [mc "Add this entry to register watches"] + setStatusTip -widget $watch_add_button \ + -text [mc "Add this entry to register watches"] + grid $watch_add_button -sticky w -row 2 -column 3 + # Button "New" + set watch_new_button [ttk::button $tool_bar.but_rightPanel_watch_new \ + -image ::ICONS::16::filenew \ + -command "$this rightPanel_watch_new" \ + -style Flat.TButton \ + ] + DynamicHelp::add $watch_new_button -text [mc "New register watches entry"] + setStatusTip -widget $watch_new_button \ + -text [mc "Create new register watch"] + grid $watch_new_button -sticky w -row 2 -column 4 + # Button "Remove" + set watch_remove_button [ttk::button $tool_bar.but_rightPanel_watch_remove \ + -image ::ICONS::16::button_cancel \ + -command "$this rightPanel_watch_remove" \ + -style Flat.TButton \ + ] + DynamicHelp::add $watch_remove_button -text [mc "Remove this entry"] + setStatusTip -widget $watch_remove_button \ + -text [mc "Remove this entry"] + grid $watch_remove_button -sticky w -row 2 -column 5 + # Label "Addr" + set watch_addr_entry [label $tool_bar.lbl_rightPanel_watch_addr \ + -text [mc "Addr"] \ + -font ${Simulator_GUI::smallfont} \ + -fg ${Simulator_GUI::small_color} \ + ] + grid $watch_addr_entry -row 1 -column 1 + # Label "Register name" + grid [label $tool_bar.lbl_rightPanel_watch_name \ + -text [mc "Register name"] \ + -font ${Simulator_GUI::smallfont} \ + -fg ${Simulator_GUI::small_color} \ + ] -row 1 -column 2 + + # Create text widget representing list of register watches + set watch_text [text $text_frame.txt_rightPanel_watch \ + -yscrollcommand "$text_frame.src_rightPanel_watch set" \ + -bg {#FFFFFF} -font $regfont \ + -cursor left_ptr \ + -state disabled -exportselection 0 \ + ] + # Create text tags + $this right_panel_create_highlighting_tags $watch_text $watch_text_tags -1 + $watch_text tag configure tag_curLine -background ${::RightPanel::selection_color_dark} + + # Create scrollbar + pack [ttk::scrollbar $text_frame.src_rightPanel_watch \ + -orient vertical \ + -command "$watch_text yview" \ + ] -side right -fill y + pack $watch_text -side left -fill both -expand 1 + # Create event bindings + bind $watch_text <ButtonRelease-3> "$this rightPanel_watch_popupmenu %X %Y %x %y; break" + bind $watch_text <Button-1> "$this rightPanel_watch_click %x %y; break" + bind $watch_text <<Selection>> "false_selection $watch_text; break" + bind $watch_text <Key-Menu> {break} + + # Pack frames + pack $tool_bar -side bottom -anchor w + pack $icon_bar -side top -fill x + pack $text_frame -side top -fill both -expand 1 + rightPanel_watch_switch_line 1 + + # Create popup menu + set watch_menu $parent.menu_rightPanel_watch + regwatches_makePopupMenu + + # Refresh highlighting tags + rightPanel_refresh_regwatches_highlighting + + # Open definition file + if {$watch_file_name != {}} { + rightPanel_watch_openfile $watch_file_name . 0 + } + } + + ## Sort register watches + # @parm Char sorting_key + # N - Sort by name + # A - Sort by address + # T - Sort by type + # @return void + public method rightPanel_watch_sort_by {sorting_key} { + # Pack all watches into one sigle list + set list_to_sort [list] + set type {} + foreach addr [array names watch_data] { + + switch -- [string length $addr] { + 4 { + set type {X} + } + 3 { + if {[string index $addr 0] == {.}} { + set type {B} + } { + set type {E} + } + } + default { + set type {D} + } + } + + lappend list_to_sort [list $addr [lindex $watch_data($addr) 0] $type] + } + + # Incremental sorting order + if {$::RegWatches::sorting_order} { + set order {-increasing} + # Decremental sorting order + } { + set order {-decreasing} + } + + switch -- $sorting_key { + N { ;# Name + set index 1 + } + A { ;# Address + set index 0 + } + T { ;# Type + set index 2 + } + } + + # Sort the list + set list_to_sort [lsort -dictionary $order -index $index $list_to_sort] + + # Refill the panel + rightPanel_watch_clear 1 + foreach entry $list_to_sort { + set addr [lindex $entry 0] + set name [lindex $entry 1] + + rightPanel_watch_add $addr $name + } + } + + ## Perform autoload on simulator start + # @parm String filename - Code listinf file + # @return void + public method rightPanel_watch_autoload {filename} { + if {!$autoload_flag} {return} + if {![file exists $filename]} {return} + + rightPanel_watch_import_file $filename . + } + + ## Autoload flag toggled (this function should be invoked from configuration menu) + # @return void + public method rightPanel_watch_toggle_autoload_flag {} { + set autoload_flag $::RegWatches::menu_autoload + } + + ## Get configuration list + # @return void + public method rightPanel_watch_get_config {} { + return [list $::RegWatches::menu_autoload $::RegWatches::sorting_order] + } + + ## Create configuration menu + # @return void + private method create_conf_menu {} { + if {$conf_menu != {}} { + return + } + set conf_menu $parent.conf_menu + menuFactory $CONFMENU $conf_menu 0 "$this " 0 {} + + watch_disEna_buttons + } + + ## Invoke configuration menu + # @return void + public method rightPanel_watch_cfg_menu {} { + create_conf_menu + + set x [winfo rootx $conf_button] + set y [winfo rooty $conf_button] + incr y [winfo height $conf_button] + + set ::RegWatches::menu_autoload $autoload_flag + tk_popup $conf_menu $x $y + } + + ## Refresh highlighting tags + # @return void + public method rightPanel_refresh_regwatches_highlighting {} { + if {!$gui_initialized} {return} + $this right_panel_create_highlighting_tags $watch_text $watch_text_tags -1 + } + + ## Recreate popup menu + # @return void + public method regwatches_makePopupMenu {} { + if {!$gui_initialized} {return} + if {[winfo exists $watch_menu]} {destroy $watch_menu} + menuFactory $WATCHMENU $watch_menu 0 "$this " 0 {} + } + + + ## Retrun name of file currently loaded in register watches + # @return String - filename + public method getWatchesFileName {} { + # Determinate project root path + set prj_path [$this cget -projectPath] + append prj_path {/} + + # Return relative directory location + if {![string first $prj_path $watch_file_name]} { + return [string range $watch_file_name [string length $prj_path] end] + # Return absolute directory location + } { + return $watch_file_name + } + } + + ## (Re)set dynamic shortcuts for the given entry widget + # @parm Widget entry - Target entry widget + # @return void + private method watch_entry_shortcuts_reset {entry} { + if {!$gui_initialized} {return} + + # Unset previous configuration + foreach key $watches_set_shortcuts { + bind $entry <$key> {} + } + set set_shortcuts {} + + # Iterate over shortcuts definition + foreach block ${::SHORTCUTS_LIST} { + # Determinate category + set category [lindex $block 0] + if {[lsearch $watches_shortcuts_cat $category] == -1} {continue} + + # Determinate definition list and its length + set block [lreplace $block 0 2] + set len [llength $block] + + # Iterate over definition list and create bindings + for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} { + # Determinate key sequence + set key [lindex $block $i] + if {[catch { + set key $::SHORTCUTS_DB($category:$key) + }]} then { + continue + } + if {$key == {}} {continue} + + # Create and register new binding + lappend watches_set_shortcuts $key + set cmd [subst [lindex $block [list $j 1]]] + append cmd {;break} + bind $entry <$key> $cmd + } + } + } + + ## Get adjusted value of address entry (register watches) + # @parm String string - input data ("\n" == get value from entry widget) + # @return String - result address + private method get_watchAddr {string} { + + # Evaluate input string + if {$string == {} || $string == {.}} { + return { .00} + } + if {$string == "\n"} { + set string [subst "\$::RightPanel::watch_addr${obj_idx}"] + regsub {^\s+} $string {} string + } + if {[string index $string 0] == {.}} { + set string [string replace $string 0 0] + set bit_addr 1 + } { + set bit_addr 0 + } + + # Adjust address + set len [string length $string] + if {$len > 2} { + if {$len != 4} { + set string " $string" + } + } { + if {$len == 1} { + set string "0$string" + } + set string " $string" + } + + # Resturn result + if {$bit_addr} { + return [string replace $string 1 1 {.}] + } { + return [string toupper $string] + } + } + + ## Get adjusted value of register name (Register watches) + # @parm String string - input data ("\n" == get value from entry widget) + # @return String - resulting register name + private method get_watchName {string} { + # Conditionaly get value from entry widget + if {$string == "\n"} { + set string [subst "\$::RightPanel::watch_name${obj_idx}"] + regsub {\t+$} $string {} string + } + + # Adjust resulting string + set len [string length $string] + append string [string repeat { } [expr {23 - $len}]] + + # Return result + return $string + } + + ## Validate content of address entry - Register watches + # @parm String value - input value + # @return Bool - result + public method rightPanel_watch_addr_validate {value} { + + # Check if validation is enabled + if {!$watch_AN_valid_ena} {return 1} + + # Check for allowed length + if {[string length $value] > 4} { + return 0 + } + + # Check for allowed characters + if {!([regexp {^[A-Fa-f0-9]*$} $value] || [regexp {^\.[A-Fa-f0-9]{0,2}$} $value])} { + return 0 + } + + # Change content of address field in register watches text widget + if {$watch_curLine != 0 && $value != {}} { + + # Get address + set value [get_watchAddr $value] + regsub {^\s+} $value {} real_value + + # Check it the desired address is unique + if {[lsearch -ascii -exact $watch_addrs $real_value] != -1} { + Sbar [mc "Unable to assign, address is already in use"] + return 1 + } + + # Modify variables related to the current entry + set idx [expr {$watch_curLine - 1}] + set addr [lindex $watch_addrs $idx] + set var [lindex $watch_data($addr) 1] + set watch_data($real_value) $watch_data($addr) + unset watch_data($addr) + lset watch_addrs $idx $real_value + + # Synchronize + $watch_text.$var configure -state normal + rightPanel_watch_sync $real_value + $watch_text.$var configure -fg ${Simulator::normal_color} + if {!$watches_enabled || [read_from_simulator $real_value] == {--}} { + $watch_text.$var configure -state disabled + } + + # Enable entry watches text widget + $watch_text configure -state normal + + # Change content of address field + $watch_text delete $watch_curLine.0 $watch_curLine.4 + $watch_text insert $watch_curLine.0 $value + + # Bit -> Byte + if {[string index $addr 0] == {.} && [string index $real_value 0] != {.}} { + $watch_text.$var configure -width 2 + help_window_hide + + # Byte -> Bit + } elseif {[string index $addr 0] != {.} && [string index $real_value 0] == {.}} { + $watch_text.$var configure -width 1 + help_window_hide + } + + # Highlight address field + set len [string length $real_value] + if {$len == 4} { + set addr_tag {tag_Xaddr} + } elseif {$len == 3 && ([string index $real_value 0] == {.})} { + set addr_tag {tag_Baddr} + } elseif {$len == 3} { + set addr_tag {tag_Eaddr} + } else { + set addr_tag {tag_addr} + } + $watch_text tag add $addr_tag $watch_curLine.0 $watch_curLine.4 + + # Change selection + $watch_text tag remove tag_curLine 1.0 end + $watch_text tag add tag_curLine $watch_curLine.0 "$watch_curLine.0 + 1 line" + + $watch_text configure -state disabled + + # Adjust help window + help_window_update_addr $addr $real_value + bind $watch_text.[lindex $watch_data($real_value) 1] <Enter> \ + "$this create_help_window_ram ${real_value}h; help_window_variable_addr" + + # Adjust flag: modified + set watches_modified 1 + } + + # Success + return 1 + } + + ## Validate content of register name entry - Register watches + # @parm String value - input value + # @return Bool - result + public method rightPanel_watch_name_validate {value} { + # Check if validation is enabled + if {!$watch_AN_valid_ena} {return 1} + + # Check for allowed length + if {[string length $value] > 23} { + return 0 + } + + # Change content of register name field in register watches text widget + if {$watch_curLine != 0} { + # Local variables + set name [get_watchName $value] ;# Register name + + # Change reg. name in object variable watch_data + lset watch_data([lindex $watch_addrs [expr {$watch_curLine - 1}]]) 0 [string trimright $value] + + # Enable list of watches widget + $watch_text configure -state normal + + # Change current register name + $watch_text delete $watch_curLine.5 "$watch_curLine.0 lineend - 1 char" + $watch_text insert $watch_curLine.5 $name + + # Restore reg. name text tag + $watch_text tag add tag_name $watch_curLine.5 $watch_curLine.28 + + # Adjust selection + $watch_text tag remove tag_curLine 1.0 end + $watch_text tag add tag_curLine $watch_curLine.0 "$watch_curLine.0 + 1 line" + + # Disable list of watches widget + $watch_text configure -state disabled + + # Adjust status modified + set watches_modified 1 + } + + # Success + $watch_search_entry delete 0 end + return 1 + } + + ## Validate content of embedded entries in list of register watches + # @parm String addr - hexadecimal representation of register addres + # @parm String value - string to validate + # @return Bool - result + public method rightPanel_watch_value_validate {addr value} { + if {$validator_engaged} {return 1} + set validator_engaged 1 + + # Check for allowed length + if {[string length $value] > 2} { + set validator_engaged 0 + return 0 + } + + # Check for allowed characters + if {![regexp {^[A-Fa-f0-9]*$} $value]} { + set validator_engaged 0 + return 0 + } + + ## Synchronize new content with simulator engine + if {[string index $addr 0] == {.}} { + set addr [string replace $addr 0 0] + set bit_addr 1 + } { + set bit_addr 0 + } + set dec_addr [expr "0x$addr"] + # Bit + if {$bit_addr} { + if {$value == {}} { + set value 0 + } + if {![regexp {^[01]?$} $value]} { + set validator_engaged 0 + return 0 + } + $this setBit $dec_addr $value + + # External RAM + } elseif {[string length $addr] == 4} { + $this setXdata $dec_addr $value + $this Simulator_XDATA_sync $addr + + # Expanded RAM + } elseif {[string length $addr] == 3} { + $this setEram $dec_addr $value + $this Simulator_XDATA_sync $addr + + # Internal RAM + } else { + $this setData $dec_addr $value + $this SimGUI_disable_sync + $this Simulator_GUI_sync I $dec_addr + $this SimGUI_enable_sync + } + + if {$bit_addr} { + set addr .$addr + } + $watch_text.[lindex $watch_data($addr) 1] configure -fg ${Simulator::normal_color} + + # Synchronize with help window + help_window_update $addr $value + + # Done ... + set validator_engaged 0 + return 1 + } + + ## Enable entry widgets in register watches + # AFFECT ALL ENTRIES (not only valid ones) !!! + # @return void + public method rightPanel_watch_force_enable {} { + if {!$gui_initialized} {CreateRegWatchesGUI} + + set watches_enabled 1 + foreach addr $watch_addrs { + $watch_text.[lindex $watch_data($addr) 1] configure -state normal + } + } + + ## Enable entry widgets in register watches + # Affect only entries with valid address (implemented on current MCU) + # @return void + public method rightPanel_watch_enable {} { + if {!$gui_initialized} {CreateRegWatchesGUI} + + set watches_enabled 1 + foreach addr $watch_addrs { + if {[string index $addr 0] == {.}} { + set addr [string replace $addr 0 0] + set bit_addr 1 + } { + set bit_addr 0 + } + set dec_addr [expr "0x$addr"] + set len [string length $addr] + + # Bit + if {$bit_addr} { + if {$dec_addr > 0x7F} { + if {![$this simulator_is_sfr_avaliable [$this getRegOfBit $dec_addr]]} { + continue + } + } + set addr ".$addr" + + # Internal RAM + } elseif {$len < 3} { + if {$dec_addr >= [lindex [$this cget -procData] 3]} { + continue + } + + # Expanded RAM + } elseif {$len == 3} { + if {$dec_addr >= [lindex [$this cget -procData] 8]} { + continue + } + + # External RAM + } else { + if {$dec_addr >= [$this cget -P_option_mcu_xdata]} { + continue + } + } + + $watch_text.[lindex $watch_data($addr) 1] configure -state normal + } + } + + ## Disable all entry widgets in register watches + # @return void + public method rightPanel_watch_disable {} { + if {!$gui_initialized} {return} + + set watches_enabled 0 + foreach addr $watch_addrs { + $watch_text.[lindex $watch_data($addr) 1] configure -state disabled + } + } + ## Select line in list of register watches + # @parm Int x - relative X coordinate + # @parm Int y - relative Y coordinate + # @return void + public method rightPanel_watch_click {x y} { + rightPanel_watch_switch_line [expr {int([$watch_text index @$x,$y])}] + $watch_search_entry delete 0 end + } + + ## Change current line in register watches + # @parm Int row - target line + # @return void + public method rightPanel_watch_switch_line {row} { + if {!$gui_initialized} {return} + set watch_AN_valid_ena 0 + + # Determinate number of the last row + set end [$watch_text index end] + set end [expr {int($end) - 1}] + + # Restore previous state of the last selected entry box + if {$watch_curLine} { + set addr [lindex $watch_addrs [expr {$watch_curLine - 1}]] + set var [lindex $watch_data($addr) 1] + $watch_text.$var selection clear + $watch_text.$var configure \ + -disabledbackground {#FFFFFF} \ + -bg {#FFFFFF} + } + + # Enable/Disable buttons and Clear/Keep entry widgets at the bottom + if {$row == $end} { + $watch_remove_button configure -state disabled + $watch_new_button configure -state disabled + $watch_add_button configure -state normal + set watch_curLine 0 + $watch_text tag remove tag_curLine 1.0 end + set ::RightPanel::watch_name${obj_idx} {} + set ::RightPanel::watch_addr${obj_idx} {} + set watch_AN_valid_ena 1 + return 0 + } { + set watch_curLine $row + $watch_remove_button configure -state normal + $watch_new_button configure -state normal + $watch_add_button configure -state disabled + } + + # Determinate text indexes + set idx0 "$row.0" + set idx1 [expr {$row + 1}] + append idx1 {.0} + + # Set selection tag + $watch_text tag remove tag_curLine 1.0 end + $watch_text tag add tag_curLine $idx0 $idx1 + + # Adjust content of entry widgets at the bottom + set addr [lindex $watch_addrs [expr {$watch_curLine - 1}]] + set name [lindex $watch_data($addr) 0] + set var [lindex $watch_data($addr) 1] + + set ::RightPanel::watch_name${obj_idx} [string trimright $name] + set ::RightPanel::watch_addr${obj_idx} [string trimright $addr] + + # Change foreground color of current value entry + $watch_text.$var configure \ + -fg ${Simulator::normal_color} \ + -bg ${::RightPanel::selection_color_dark} \ + -disabledbackground ${::RightPanel::selection_color_dark} + + # Focus on value entry + focus $watch_text.$var + $watch_text.$var selection range 0 end + $watch_text see $row.0 + + set watch_AN_valid_ena 1 + } + + ## Create a new register watch + # @parm String - Hex address, {} == Content of address entry + # @parm String - Register name, {} == Content of name entry + # @return void + public method rightPanel_watch_add args { + # Local variables + set row [$watch_text index end] ;# Last row in the list + set row [expr {int($row) - 1}] + set addr [lindex $args 0] ;# Register address (Hex String) + set name [lindex $args 1] ;# Watch name + set shortAddr {} ;# Register address (Hex Number) + + if {$addr == {} || $name == {}} { + set addr [get_watchAddr "\n"] + set name [get_watchName "\n"] + set no_sbar 0 + } { + set addr [get_watchAddr $addr] + set name [get_watchName $name] + set no_sbar 1 + } + set shortAddr [regsub {^\s*} $addr {}] + + # Check address validity + if {$shortAddr == {}} { + if {!$no_sbar} { + Sbar [mc "You must specify the register address."] + } + return 0 + } + if {[lsearch -ascii -exact $watch_addrs $shortAddr] != -1} { + if {!$no_sbar} { + Sbar [mc "Specified address is already used."] + } + return 0 + } + + # Enable text widget + $watch_text configure -state normal + # Insert address and watch name + $watch_text insert end "$addr $name" + # Insert text tags + regsub {^ +} $addr {} addr + set entry [watch_create_entry $addr $row $watch_entry_count] + $watch_text window create end -window $entry -pady 0 + $watch_text insert end "\n" + set len [string length $addr] + if {$len == 4} { + set addr_tag {tag_Xaddr} + } elseif {$len == 3 && ([string index $addr 0] == {.})} { + set addr_tag {tag_Baddr} + } elseif {$len == 3} { + set addr_tag {tag_Eaddr} + } else { + set addr_tag {tag_addr} + } + $watch_text tag add $addr_tag $row.0 $row.4 + $watch_text tag add tag_name $row.5 $row.28 + # Disable text widget + $watch_text configure -state disabled + + # Register new watch + regsub {\t+$} $name {} name + lappend watch_addrs $addr + set watch_data($addr) [list $name $watch_entry_count] + + # Synchronize + rightPanel_watch_sync $addr + $entry configure -fg ${Simulator::normal_color} + + # Enable/Disable the entry widget + if {!$watches_enabled} { + $entry configure -state disabled + } + + incr watch_entry_count + + # Reevaluate button states + watch_disEna_buttons + + # Clear search entry + $watch_search_entry delete 0 end + + # Adjust status modified + set watches_modified 1 + } + + ## Create entry widget for embedding in list of watches + # @parm String addr - hexadecimal register address + # @parm Int row - target row in text widget + # @parm Variable var - entry text variable + # @return Widget - resulting entry widget + private method watch_create_entry {addr row var} { + if {[string index $addr 0] == {.}} { + set width 1 + } { + set width 2 + } + + # Create entry widget + set entry [entry $watch_text.$var \ + -width $width \ + -font ${::Simulator_GUI::entry_font} \ + -bg {#FFFFFF} -validate key \ + -takefocus 0 -highlightthickness 0 \ + -disabledbackground {#FFFFFF} \ + -vcmd "$this rightPanel_watch_value_validate $addr %P" \ + -bd 0 -justify right \ + ] + + # Set event bindings + bind $entry <Button-1> "$this rightPanel_watch_switch_line $row" + bind $entry <Key-Up> "$this rightPanel_watch_up 1" + bind $entry <Key-Down> "$this rightPanel_watch_down 1" + bind $entry <Key-Next> "$this rightPanel_watch_down 4" + bind $entry <Key-Prior> "$this rightPanel_watch_up 4" + bind $entry <Motion> {help_window_show %X %Y} + bind $entry <Leave> {help_window_hide} + bind $entry <Enter> "$this create_help_window_ram ${addr}h; help_window_variable_addr" + bind $entry <Button-4> "$watch_text yview scroll -5 units" + bind $entry <Button-5> "$watch_text yview scroll +5 units" + watch_entry_shortcuts_reset $entry + + # Return entry reference + return $entry + } + + ## Clear highlight for all registers + # @return void + public method rightPanel_watch_clear_highlight {} { + if {!$gui_initialized} {return} + + foreach addr $watch_addrs { + $watch_text.[lindex $watch_data($addr) 1] configure -fg ${Simulator::normal_color} + } + } + + ## Clear highlight for the given register + # @return void + public method rightPanel_watch_unhighlight {addr} { + if {!$gui_initialized} {return} + + if {[lsearch $watch_addrs $addr] == -1} { + return + } + $watch_text.[lindex $watch_data($addr) 1] configure -fg ${Simulator::normal_color} + } + + ## Move current watch to the top + # @return void + public method rightPanel_watch_move_top {} { + rightPanel_watch_move 1 + } + + ## Move current watch to up + # @return void + public method rightPanel_watch_move_up {} { + # Determinate target line + set target_line [expr {$watch_curLine - 1}] + if {$target_line == 0} {return 0} + # Move watch + rightPanel_watch_move $target_line + } + + ## Move current watch to down + # @return void + public method rightPanel_watch_move_down {} { + # Determinate target line + set target_line [expr {$watch_curLine + 1}] + set end [$watch_text index end] + set end [expr {int($end) - 1}] + if {$target_line == $end} {return 0} + # Move watch + rightPanel_watch_move $target_line + } + + ## Move current watch to the bottom + # @return void + public method rightPanel_watch_move_bottom {} { + # Determinate target line + set target_line [$watch_text index end] + set target_line [expr {int($target_line) - 2}] + # Move watch + rightPanel_watch_move $target_line + } + + ## Move current watch to the given line + # @parm Int target_line - target line + # @return void + private method rightPanel_watch_move {target_line} { + # Validate current line value + if {$watch_curLine == 0} {return} + + # Local variables + set cur_idx [expr {$watch_curLine - 1}] ;# index in $watch_addrs -- current line + set trg_idx [expr {$target_line - 1}] ;# index in $watch_addrs -- target line + set addr [lindex $watch_addrs $cur_idx] ;# register address + set name [lindex $watch_data($addr) 0] ;# watch name + set var [lindex $watch_data($addr) 1] ;# textvariable of the value entry + + # Modify variables related to the watch + set watch_addrs [lreplace $watch_addrs $cur_idx $cur_idx] + set watch_addrs [linsert $watch_addrs $trg_idx $addr] + + # Enable the widget + $watch_text configure -state normal + # Change textual content + $watch_text delete $watch_curLine.0 "$watch_curLine.0 + 1 line linestart" + $watch_text insert $target_line.0 "[get_watchAddr $addr] [get_watchName $name]\n" + # Destroy the current entry widget + destroy $watch_text.$var + # Change embedded entry + set entry [watch_create_entry $addr $target_line $var] + $watch_text window create [list $target_line.0 lineend] -window $entry -pady 0 + set len [string length $addr] + if {$len == 4} { + set addr_tag {tag_Xaddr} + } elseif {$len == 3 && ([string index [string trim $addr] 0] == {.})} { + set addr_tag {tag_Baddr} + } elseif {$len == 3} { + set addr_tag {tag_Eaddr} + } { + set addr_tag {tag_addr} + } + # Restore text tags + $watch_text tag add $addr_tag $target_line.0 $target_line.4 + $watch_text tag add tag_name $target_line.5 $target_line.28 + # Disable the widget + $watch_text configure -state disabled + + # Synchronize entry widget content + rightPanel_watch_sync $addr + + # Enable/Disable the entry widget + if {!$watches_enabled} { + $entry configure -state disabled + } + + # Set current line + set watch_curLine $target_line + rightPanel_watch_switch_line $target_line + + # Clear search entry + $watch_search_entry delete 0 end + + # Adjust status modified + set watches_modified 1 + } + + ## Change current line in list of register watches to the line above the current one + # @parm Int lines - number of lines to skip - 1 + # @return void + public method rightPanel_watch_up {lines} { + # Determinate number of last row in the widget + set end [$watch_text index end] + set end [expr {int($end) - 2}] + + # Change current line (logicaly) + set line $watch_curLine + incr line -$lines + if {$line < 1} { + set line 1 + } + + # Change current line (physicaly) + $watch_text see $watch_curLine.0 + rightPanel_watch_switch_line $line + + # Clear search entry + $watch_search_entry delete 0 end + } + + ## Change current line in list of register watches to the line below the current one + # @parm Int lines - number of lines to skip - 1 + # @return void + public method rightPanel_watch_down {lines} { + # Determinate number of last row in the widget + set end [$watch_text index end] + set end [expr {int($end) - 2}] + + # Change current line (logicaly) + set line $watch_curLine + incr line $lines + if {$line > $end} { + set line $end + } + + # Change current line (physicaly) + $watch_text see $watch_curLine.0 + rightPanel_watch_switch_line $line + + # Clear search entry + $watch_search_entry delete 0 end + } + + ## Binding for button "New" (Clears entry widgets at the bottom and unselect current watch) + # @return void + public method rightPanel_watch_new {} { + set end [$watch_text index end] + set end [expr {int($end) - 1}] + rightPanel_watch_switch_line $end + + # Clear search entry + $watch_search_entry delete 0 end + } + + ## Remove the current register watch + # @return void + public method rightPanel_watch_remove {} { + # Determinate register address + set addr [lindex $watch_addrs [expr {$watch_curLine - 1}]] + # Destroy value entry + set var [lindex $watch_data($addr) 1] + destroy $watch_text.$var + # Unregister watch + unset watch_data($addr) + set idx [lsearch $watch_addrs $addr] + set watch_addrs [lreplace $watch_addrs $idx $idx] + + # Remove watch from the text widget + $watch_text configure -state normal + $watch_text delete $watch_curLine.0 "$watch_curLine.0 + 1 line" + $watch_text configure -state disabled + + # Change current line + if {$watch_curLine > [llength $watch_addrs]} { + set watch_curLine [llength $watch_addrs] + } + if {$watch_curLine} { + rightPanel_watch_switch_line $watch_curLine + } + + # Reevaluate button states + watch_disEna_buttons + # Clear search entry + $watch_search_entry delete 0 end + # Adjust status modified + set watches_modified 1 + } + + ## Save watches definition to a file + # @parm String filename - Target filename or an empty string + # @parm Bool force = 0 - Do not ask for overwrite + # @return void + public method rightPanel_watch_save args { + if {!$gui_initialized} {CreateRegWatchesGUI} + + set filename [lindex $args 0] + set force [lindex $args 1] + if {$filename != {}} { + set watch_file_name $filename + } + if {$force != {1}} { + set force 0 + } + + # If no filename specified -> invoke dislog "Save as" + if {$watch_file_name == {}} { + rightPanel_watch_saveas + + # Save file + } { + # Set new filename + if {!$::MICROSOFT_WINDOWS} { ;# POSIX way + if {![regexp "^(~|/)" $watch_file_name]} { + set filename "[$this cget -ProjectDir]/$watch_file_name" + } + } { ;# Microsoft windows way + if {![regexp "^\w:" $watch_file_name]} { + set filename [file join [$this cget -ProjectDir] $watch_file_name] + } + } + + set watch_file_name [file normalize $watch_file_name] + # Adjust file extension + if {![regexp {\.wtc$} $watch_file_name]} { + append watch_file_name {.wtc} + } + + if {[file exists $watch_file_name] && [file isfile $watch_file_name]} { + # Ask user for overwrite existing file + if {!$force && [tk_messageBox \ + -type yesno \ + -icon question \ + -parent . \ + -title [mc "Overwrite file"] \ + -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $watch_file_name]] + ] != {yes} + } { + return + } + # Create a backup file + catch { + file rename -force $watch_file_name "$watch_file_name~" + } + } + if {[catch { + set file [open $watch_file_name w 420] + }]} { + if {[winfo exists .fsd]} { + set parent .fsd + } { + set parent . + } + tk_messageBox -type ok \ + -parent $parent -icon warning \ + -title [mc "Error - MCU 8051 IDE"] \ + -message [mc "Unable to access file \"%s\", check your permissions." $watch_file_name] + return + } + + # Write file header + puts $file "# Watches definition file -- ${::APPNAME}" + puts $file "# Date: [clock format [clock seconds] -format {%D}]" + + # Write watches definition + puts -nonewline $file [regsub -all -line {\s+$} [$watch_text get 1.0 end] {}] + + # Finish + close $file + Sbar [mc "Definitions saved to \"%s\"" $watch_file_name] + + # Adjust status modified + set watches_modified 0 + } + } + + ## Invoke dialog "Save as" - Register watches + # @return void + public method rightPanel_watch_saveas {} { + + # Abort if there is already opened some file selection dialog + if {[winfo exists .fsd]} {return} + + # Invoke the dialog + KIFSD::FSD ::fsd \ + -title [mc "Save watches - MCU 8051 IDE"] \ + -directory [$this cget -ProjectDir] \ + -defaultmask 0 -multiple 0 -filetypes { + {{MCU 8051 IDE watch definition} {*.wtc} } + {{All files} {*} } + } + # Save file after press of OK button + ::fsd setokcmd { + set ::filename [::fsd get] + if {$::filename != {} && ![file isdirectory $::filename]} { + ${::X::actualProject} rightPanel_watch_save $::filename + } + } + # Activate the dialog + ::fsd activate + } + + ## Open and process watches definition file + # @parm String filename - name of source file + # @parm Widget parent - GUI parent (for error dialogs) + # @parm Bool clear - Clear watches before loading + # @return Bool - result + public method rightPanel_watch_openfile {filename parent clear} { + if {!$gui_initialized} {CreateRegWatchesGUI} + + # Normalize filename + if {!$::MICROSOFT_WINDOWS} { ;# POSIX way + if {![regexp "^(~|/)" $filename]} { + set filename "[$this cget -projectPath]/$filename" + } + } { ;# Microsoft windows way + if {![regexp "^\w:" $filename]} { + set filename [file join [$this cget -projectPath] $filename] + } + } + set filename [file normalize $filename] + + # Set new watches filename + set watch_file_name $filename + + # Open file + if {[catch { + set file [open $filename r] + }]} then { + tk_messageBox -parent $parent -icon warning -type ok \ + -title [mc "File access error"] \ + -message [mc "Unable to read file '%s'" $filename] + set watch_file_name {} + return 0 + } + + # Verify input data validity + while {![eof $file]} { + set line [gets $file] + + # Skip comments and empty lines + if {[regexp {^\s*#} $line]} {continue} + if {[regexp {^\s*$} $line]} {continue} + + # Local variables + regexp {^\s*\.?\w+} $line addr ;# Register address + regsub {^\s*\.?\w+\s*} $line {} name ;# Watch name + regsub {\s+$} $name {} name + + # Check for address and name validity + if { + ![regexp {^\s*\.?[A-Fa-f0-9]+$} $addr] || + [string length $addr] > 4 || + [string length $name] > 23 + } { + tk_messageBox \ + -title [mc "Corrupted file"] \ + -icon error -type ok -parent $parent \ + -message [mc "file: %s is eighter corrupted or it is not a file in expected format." $filename] + return 0 + } + } + + # Clear watches + if {$clear} { + rightPanel_watch_clear 1 + } + + # Parse input data + seek $file 0 + while {![eof $file]} { + set line [gets $file] + + # Skip comments and empty lines + if {[regexp {^\s*#} $line]} {continue} + if {[regexp {^\s*$} $line]} {continue} + + regexp {^\s*\.?\w+} $line addr ;# Register address + regsub {^\s*\.?\w+\s*} $line {} name ;# Watch name + set addr [string trimleft $addr] + set name [string trimright $name] + + # Create new register watch + rightPanel_watch_add $addr $name + } + + # Deselect all + rightPanel_watch_new + + # Reevaluate button states (icon bar) + watch_disEna_buttons + + # Adjust status modified + set watches_modified 0 + + # Success + close $file + return 1 + } + + ## Invoke dialog "Open file" + # @return void + public method rightPanel_watch_open {} { + # Invoke the dialog + KIFSD::FSD ::fsd \ + -title [mc "Load watches from file - MCU 8051 IDE"] \ + -directory [$this cget -ProjectDir] -autoclose 0 \ + -defaultmask 0 -multiple 0 -filetypes { + {{MCU 8051 IDE watches definition} {*.wtc} } + {{All files} {*} } + } + + # Open file after press of OK button + fsd setokcmd { + # Get chosen file name + set filename [::fsd get] + if {[${X::actualProject} rightPanel_watch_openfile $filename [::fsd get_window_name] 1]} { + ::fsd deactivate + delete object fsd + } + } + + # Activate the dialog + fsd activate + } + + ## Invoke dialog "Import file" + # @return void + public method rightPanel_watch_import {} { + # Invoke the dialog + KIFSD::FSD ::fsd \ + -title [mc "Import file - MCU 8051 IDE"] \ + -directory [$this cget -ProjectDir] -autoclose 0 \ + -defaultmask 0 -multiple 0 -filetypes { + {{Code listing} {*.lst} } + {{MCU 8051 IDE watches definition} {*.wtc} } + {{All files} {*} } + } + + # Open file after press of OK button + fsd setokcmd { + # Get chosen file name + set filename [::fsd get] + if {[${X::actualProject} rightPanel_watch_import_file $filename [::fsd get_window_name]]} { + ::fsd deactivate + delete object fsd + } + } + + # Activate the dialog + fsd activate + } + + ## Import file + # @parm String filename - Name of source file (*.lst or *.wtc) + # @parm Widget parent - GUI parent (for error dialogs) + # @return Bool - result + public method rightPanel_watch_import_file {filename parent} { + if {!$gui_initialized} {CreateRegWatchesGUI} + + # Determinate file type + set filename [file normalize [file join [$this cget -ProjectDir] $filename]] + set file_type 0 + switch -- [file extension $filename] { + {.wtc} { ;# Watches definition file + set file_type 1 + } + {.lst} { ;# Code listing + set file_type 2 + } + default { ;# Try to detect file type by file header + catch { + set file [open $filename r] + if {[string first {# Watches definition file} [gets $file]] == 0} { + set file_type 1 + } + close $file + } + } + } + + # Unknown file type + if {!$file_type} { + tk_messageBox \ + -parent . \ + -type ok \ + -icon warning \ + -title [mc "Unknown file"] \ + -message [mc "Unable to recognize file format"] + return 0 + } + + # ----------------------------------------------------------------------- + ## WTC file - load and exit procedure + # ----------------------------------------------------------------------- + if {$file_type == 1} { + return [rightPanel_watch_openfile $filename $parent 0] + } + + + # ----------------------------------------------------------------------- + # LST file + # ----------------------------------------------------------------------- + + # Try to open file + if {[catch { + set file [open $filename r] + }]} { + tk_messageBox \ + -parent . \ + -type ok \ + -icon warning \ + -title [mc "File access error"] \ + -message [mc "Unable to open file:\n'%s'" $filename] + return 0 + } + + # Parse file + set read_line 0 + set line {} + set name {} + set addr {} + set type {} + set bita 0 + while {![eof $file]} { + set bita 0 + 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] + + # Ignore all types except address + if {[lindex $line 1] != {ADDR}} { + continue + } + + # Internal data memory + if {$type == {D} || $type == {I}} { + set addr [string range [lindex $line 2] 2 3] + # External data memory (inluding ERAM, EEPROM, etc.) + } elseif {$type == {X}} { + set addr [string range [lindex $line 2] 0 3] + # Bit addressable area + } elseif {$type == {B}} { + set bita 1 + set addr [string range [lindex $line 2] 2 3] + # Another type of memory -> IGNORE + } else { + continue + } + + # Ignore unused symbols + if {[lindex $line end-1] == {NOT} || [lindex $line end-2] == {NOT}} { + continue + } + + # ASEM-51 Assembler symbol + } elseif {$read_line == 2} { + # Remove dangerous characters + regsub -all {\{\}\"\"} $line {} line + + # Ignore unused symbols + if {[llength $line] < 4} { + continue + } + + # Determinate address and symbol name + set type [lindex $line 1] + set addr [lindex $line 2] + set name [lindex $line 0] + + # Accept only internal and external data memory + if {$type != {IDATA} && $type != {DATA} && $type != {XDATA} && $type != {BIT}} { + continue + } + if {$type == {BIT}} { + set bita 1 + } + + # This line is not a part of symbol table + } else { + continue + } + + # Address must be a valid hexadecimal value + if {![string is xdigit -strict $addr]} { + continue + } + + # Exclude SFR's + if {[lsearch -ascii -exact ${::ASMsyntaxHighlight::spec_registers} $name] != -1} { + continue + } + + # Create new register watch + if {[string length $name] > 23} { + set name [string range $name 0 16] + append name {..} + } + + if {$bita} { + set addr .$addr + } + + rightPanel_watch_add $addr $name + set watches_modified 1 + } + + # Finalize + rightPanel_watch_new + watch_disEna_buttons + close $file + return 1 + } + + ## Remove all register watches + # Bool force = 0 - Don't ask user for comfirmation + # @return void + public method rightPanel_watch_clear args { + if {!$gui_initialized} {CreateRegWatchesGUI} + + # Parse arguments + set force [lindex $args 0] + if {$force == {}} { + set force 0 + } + + # Ask user for comfirmation + if {!$force} { + if {[tk_messageBox \ + -parent . \ + -type yesno \ + -icon question \ + -title [mc "Are you sure ?"] \ + -message [mc "Do you really want to clear the panel ?"] + ] != {yes}} { + return + } + } + + # Clear text widget + $watch_text configure -state normal + $watch_text delete 1.0 end + $watch_text configure -state disabled + + # Destroy all embedded entry widgets + foreach addr $watch_addrs { + destroy $watch_text.[lindex $watch_data($addr) 1] + } + + # Clear entries on the bottom bar + set watch_curLine 0 + set ::RightPanel::watch_name${obj_idx} {} + set ::RightPanel::watch_addr${obj_idx} {} + + # Unregister all watches + set watch_addrs {} + catch { + array unset watch_data + } + + # Reevaluate button states (icon bar) + watch_disEna_buttons + + # Adjust status modified + set watches_modified 1 + } + + ## Search for the given string in the list of register watches -- search entry validator + # @parm String content - String to find/validate + # @return Bool - result + public method rightPanel_watch_search_validate {content} { + if {$search_val_in_progress} {return 0} + set search_val_in_progress 1 + + # Enable/Disable button "Clear search entry" + if {$content == {}} { + $watch_search_clear configure -state disabled + } { + $watch_search_clear configure -state normal + } + + # Validate search string + if {[regexp {^\s*$} $content]} { + $watch_search_entry configure -style TEntry + set search_val_in_progress 0 + return 1 + } + if {[string length $content] > 23} { + set search_val_in_progress 0 + return 0 + } + + # Search for the given string + set i 1 + set content [string trimright $content] + set content [string tolower $content] + foreach addr $watch_addrs { + if {![string first $content [string tolower [lindex $watch_data($addr) 0]]]} { + $watch_search_entry configure -style StringFound.TEntry + rightPanel_watch_switch_line $i + focus $watch_search_entry + set search_val_in_progress 0 + return 1 + } + incr i + } + + # String not found + $watch_search_entry configure -style StringNotFound.TEntry + set search_val_in_progress 0 + return 1 + } + + ## Syncronize all register watches + # @return void + public method rightPanel_watch_sync_all {} { + if {!$gui_initialized} {CreateRegWatchesGUI} + + # Iterate over addresses + foreach addr $watch_addrs { + # Synchronize + rightPanel_watch_sync $addr + # Clear highligh + set var [lindex $watch_data($addr) 1] + $watch_text.$var configure -fg ${Simulator::normal_color} + } + } + + ## Read value from simulator engine + # @parm String addr - hexadecimal register address + # @return String - hexadecimal value or {--} + private method read_from_simulator {addr} { + ## Determinate address type (Bit / Internal / Enternal / Expanded) + if {[string index $addr 0] == {.}} { + set addr [string replace $addr 0 0] + if {![string length $addr]} { + return {--} + } + set bit_addr 1 + } { + set bit_addr 0 + } + set len [string length $addr] + set val {--} + set addr_dec [expr "0x$addr"] + + # Bit + if {$bit_addr} { + if {$addr_dec > 0x7F} { + if {[$this simulator_is_sfr_avaliable [$this getRegOfBit $addr_dec]]} { + set val [$this getBit $addr_dec] + } + } { + set val [$this getBit $addr_dec] + } + + # Internal RAM + } elseif {$len < 3} { + # Normalize address + if {$len == 1} { + set addr "0$addr" + } + # Get register value + if {$addr_dec < [lindex [$this cget -procData] 3]} { + set val [$this getData $addr_dec] + } + + # Expanded RAM + } elseif {$len == 3} { + if {$addr_dec < [lindex [$this cget -procData] 8]} { + set val [$this getEram $addr_dec] + } + + # External RAM + } elseif {$len == 4} { + if {$addr_dec < [$this cget -P_option_mcu_xdata]} { + set val [$this getXdata $addr_dec] + } + } + + return $val + } + + ## Synchronize all bits in the specified SFR + # @parm Int dec_addr - SFR register address + # @return void + public method rightPanel_watch_sync_sfr {dec_addr} { + if {$validator_engaged} { + return + } + if {$dec_addr % 8} { + return + } + + for {set i 0} {$i < 8} {incr i} { + rightPanel_watch_sync .[format %X $dec_addr] + incr dec_addr + } + } + + ## Synchronize one register watch + # @parm String addr - hexadecimal register address + # @return Bool - result + public method rightPanel_watch_sync {addr} { + if {$validator_engaged} {return 1} + if {!$gui_initialized} {CreateRegWatchesGUI} + + # Detect bit address + if {[string index $addr 0] == {.}} { + set bit_addr 1 + } { + set bit_addr 0 + } + + # Get register value + set val [read_from_simulator $addr] + + # Synchronize bits in the given register + if {!$validator_engaged && [string length $addr] == 2} { + set dec_addr [expr "0x$addr"] + + if {$dec_addr >= 0x20 && $dec_addr <= 0x2F} { + set dec_addr [expr {($dec_addr - 0x20) * 8}] + for {set i 0} {$i < 8} {incr i} { + + set hex_addr [format %X $dec_addr] + if {[string length $hex_addr] == 1} { + set hex_addr "0$hex_addr" + } + rightPanel_watch_sync .$hex_addr + incr dec_addr + } + } + } + + # Check for watch presence + if {[lsearch -ascii -exact $watch_addrs $addr] == -1} { + return 0 + } + + # Normalize register value + if {!$bit_addr && [string length $val] == 1} { + set val "0$val" + } + + set var [lindex $watch_data($addr) 1] + set path $watch_text.$var ;# Path to watch entry widget + + # Determinate original value + set original_val [$watch_text.$var get] + + # Highlight value entry + if { "0x$original_val" != "0x$val"} { + $path configure -fg ${Simulator::highlight_color} + } + + # Set new entry value + set validator_engaged 1 + $watch_text.$var delete 0 end + $watch_text.$var insert 0 $val + set validator_engaged 0 + + # Synchronize with help window + help_window_update $addr $val + + # Done ... + return 1 + } + + ## Enable/Disable buttons on watches icon bar + # @return void + private method watch_disEna_buttons {} { + if {!$gui_initialized} {return} + + if {[$watch_text index end] == {2.0}} { + set state {disabled} + } { + set state {normal} + } + + if {$conf_menu != {}} { + $conf_menu entryconfigure [::mc "Sort by"] -state $state + $conf_menu entryconfigure [::mc "Remove all"] -state $state + } + } + + ## Get status modified for register watches + # @return Bool - true if register watches were modified + public method rightPanel_watch_modified {} { + return $watches_modified + } + + ## Invoke register watches popup menu + # @parm Int X - absolute X coordinate + # @parm Int Y - absolute Y coordinate + # @parm Int x - relative X coordinate + # @parm Int y - relative Y coordinate + # @return void + public method rightPanel_watch_popupmenu {X Y x y} { + # Change current line + rightPanel_watch_click $x $y + + ## Enable/Disable menu items + + # If address entry is not empty -> disable all + set addr [subst "\$::RightPanel::watch_addr${obj_idx}"] + if {$addr != {}} { + set end [$watch_text index end] + } { + set end {2.0} + } + # Empty list + if {$end == {2.0}} { + $watch_menu entryconfigure [::mc "Move top"] -state disabled + $watch_menu entryconfigure [::mc "Move up"] -state disabled + $watch_menu entryconfigure [::mc "Move down"] -state disabled + $watch_menu entryconfigure [::mc "Move bottom"] -state disabled + $watch_menu entryconfigure [::mc "Remove"] -state disabled + $watch_menu entryconfigure [::mc "Remove all"] -state disabled + # One item + } elseif {$end == {3.0}} { + $watch_menu entryconfigure [::mc "Move top"] -state disabled + $watch_menu entryconfigure [::mc "Move up"] -state disabled + $watch_menu entryconfigure [::mc "Move down"] -state disabled + $watch_menu entryconfigure [::mc "Move bottom"] -state disabled + $watch_menu entryconfigure [::mc "Remove"] -state normal + $watch_menu entryconfigure [::mc "Remove all"] -state normal + # More items + } else { + # First item + if {$watch_curLine == 1} { + $watch_menu entryconfigure [::mc "Move top"] -state disabled + $watch_menu entryconfigure [::mc "Move up"] -state disabled + $watch_menu entryconfigure [::mc "Move down"] -state normal + $watch_menu entryconfigure [::mc "Move bottom"] -state normal + # Last item + } elseif {$watch_curLine == ($end - 2)} { + $watch_menu entryconfigure [::mc "Move top"] -state normal + $watch_menu entryconfigure [::mc "Move up"] -state normal + $watch_menu entryconfigure [::mc "Move down"] -state disabled + $watch_menu entryconfigure [::mc "Move bottom"] -state disabled + # Any other item + } else { + $watch_menu entryconfigure [::mc "Move top"] -state normal + $watch_menu entryconfigure [::mc "Move up"] -state normal + $watch_menu entryconfigure [::mc "Move down"] -state normal + $watch_menu entryconfigure [::mc "Move bottom"] -state normal + } + $watch_menu entryconfigure [::mc "Remove"] -state normal + $watch_menu entryconfigure [::mc "Remove all"] -state normal + } + + # Invoke popup menu + tk_popup $watch_menu $X $Y + } + + + ## Create bindings for defined key shortcuts -- register watches + # @return void + public method rightPanel_watch_shortcuts_reevaluate {} { + if {!$gui_initialized} {return} + foreach addr $watch_addrs { + watch_entry_shortcuts_reset watch_text.[lindex $watch_data($addr) 1] + } + } + + ## Set flag enabled + # @parm Bool bool - New value + # @return void + public method right_panel_watches_set_enabled {bool} { + set enabled $bool + } +} + +set ::RegWatches::menu_autoload [lindex $::CONFIG(REGWATCHES_CONFIG) 0] +set ::RegWatches::sorting_order [lindex $::CONFIG(REGWATCHES_CONFIG) 1] diff --git a/lib/rightpanel/rightpanel.tcl b/lib/rightpanel/rightpanel.tcl new file mode 100755 index 0000000..061f1f5 --- /dev/null +++ b/lib/rightpanel/rightpanel.tcl @@ -0,0 +1,2273 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 by Martin Ošmera # +# 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. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Implements Right Panel +# Right Panel Notebook consist of: +# - List of bookmarks +# - List of breakpoints +# - List of register watches +# - Instruction details +# - List of active subprograms +# -------------------------------------------------------------------------- + +# Import nesesary sources +source "${::LIB_DIRNAME}/rightpanel/regwatches.tcl" ;# Register watches +source "${::LIB_DIRNAME}/rightpanel/instructiondetails.tcl" ;# Instruction details +source "${::LIB_DIRNAME}/rightpanel/subprograms.tcl" ;# List of active subprograms +source "${::LIB_DIRNAME}/rightpanel/hwmanager.tcl" ;# Hardware tools manager + +class RightPanel { + inherit RegWatches InstructionDetails SubPrograms HwManager + + ## COMMON + # Conter of instances + common count 0 + # Background color for selected rows -- light + common selection_color {#EEFFDD} + # Background color for selected rows -- dark + common selection_color_dark {#DDDDFF} + # Default font size for text widgets + common fontSize ${Editor::fontSize} + # Default font family for text widgets + common fontFamily ${Editor::fontFamily} + # Font used in Editor + common editor_font [font create -size -$fontSize -family $fontFamily] + # Definition of popup menu for bookmark list + common BOOKMARKMENU { + {command {Remove} {$edit:bookmark} 0 "editor_procedure {} Bookmark {}" + {button_cancel} "Add/Remove editor bookmark to/from current line"} + {separator} + {command {Previous} {} 0 "rightPanel_bm_up" {1uparrow} + "Goto previous bookmark"} + {command {Next} {} 0 "rightPanel_bm_up" {1downarrow} + "Goto next bookmark"} + {separator} + {command {Remove all} {} 0 "editor_procedure {} clear_all_bookmarks {}" + {editdelete} "Remove all bookmarks from the editor"} + } + # Definition of popup menu for breakpoint list + common BREAKPOINTMENU { + {command {Remove} {$edit:breakpoint} 0 "editor_procedure {} Breakpoint {}" + {button_cancel} "Add/Remove editor breakpoint to/from current line"} + {separator} + {command {Previous} {} 0 "rightPanel_bp_up" {1uparrow} + "Goto previous breakpoint"} + {command {Next} {} 0 "rightPanel_bp_up" {1downarrow} + "Goto next breakpoint"} + {separator} + {command {Remove all} {} 0 "editor_procedure {} clear_all_breakpoints {}" + {editdelete} "Remove all breakpoints from the editor"} + } + # Definition of popup menu for symbols list + common SYMBOLSKMENU {} + + ## PRIVATE + private variable notebook_frame ;# ID of panel main frame + private variable notebook ;# ID of panel NoteBook + private variable bookmarks ;# ID of tab "Bookmarks" + private variable breakpoints ;# ID of tab "Breakpoints" + private variable watches ;# ID of tab "Register watches" + private variable instruction ;# ID of tab "Instruction details" + private variable subprograms ;# ID of tab "Active subprograms" + private variable hwmanager ;# ID of tab "Hardware manager" + private variable table_of_symbols ;# ID of tab "Table of symbols" + private variable obj_idx ;# Number of this object + + private variable bookmarks_menu ;# ID of popup menu for "Bookmarks" + private variable breakpoints_menu ;# ID of popup menu for "Breakpoints" + private variable symbols_menu ;# ID of popup menu for "Symbol list" + + private variable bm_pagesManager ;# ID of pages manager for tab "Bookmarks" + private variable bp_pagesManager ;# ID of pages manager for tab "Breakpoints" + private variable sm_pagesManager ;# ID of pages manager for tab "Symbol list" + + private variable bookmarks_lineNumbers ;# ID of text widget showing line numbers - tab "Bookmarks" + private variable breakpoints_lineNumbers ;# ID of text widget showing line numbers - tab "Breakpoints" + private variable bookmarks_text ;# ID of list of bookmarks (text widget) - tab "Bookmarks" + private variable breakpoints_text ;# ID of list of breakpoints (text widget) - tab "Breakpoints" + private variable bm_up_button ;# ID of button "Up" - tab "Bookmarks" + private variable bm_down_button ;# ID of button "Down" - tab "Bookmarks" + private variable bm_clear_button ;# ID of button "Clear all" - tab "Bookmarks" + private variable bp_up_button ;# ID of button "Up" - tab "Breakpoints" + private variable bp_down_button ;# ID of button "Down" - tab "Breakpoints" + private variable bp_clear_button ;# ID of button "Clear all" - tab "Breakpoints" + private variable sm_text ;# ID of symbol list text widget - tab "Symbols" + private variable sm_lineNumbers ;# ID of text widget showing line numbers - tab "Symbols" + + private variable LIST_bookmarks_lineNumbers {} ;# List of $bookmarks_lineNumbers (for each editor) + private variable LIST_breakpoints_lineNumbers {} ;# List of $breakpoints_lineNumbers (for each editor) + private variable LIST_bookmarks_text {} ;# List of $bookmarks_text (for each editor) + private variable LIST_breakpoints_text {} ;# List of $breakpoints_text (for each editor) + private variable LIST_bm_up_button {} ;# List of $bm_up_button (for each editor) + private variable LIST_bm_down_button {} ;# List of $bm_down_button (for each editor) + private variable LIST_bm_clear_button {} ;# List of $bm_clear_button (for each editor) + private variable LIST_bp_up_button {} ;# List of $bp_up_button (for each editor) + private variable LIST_bp_down_button {} ;# List of $bp_down_button (for each editor) + private variable LIST_bp_clear_button {} ;# List of $bp_clear_button (for each editor) + private variable LIST_sm_text {} ;# List of $sm_text (for each editor) + private variable LIST_sm_lineNumbers {} ;# List of $sm_lineNumbers (for each editor) + + private variable bm_bp_pages_list {} ;# List of editor numbers present in the panel + private variable editors_count 0 ;# Counter of added editors + private variable current_editor_idx 0 ;# Int: Index of currently active editor + + private variable block_select 0 ;# Bool: Block selection of an item for certain procedures + private variable search_val_in_progress 0 ;# Bool: Search procedure is in progress + + private variable button_bar ;# ID of button bar which replaces notebook on hide + private variable redraw_pane_in_progress 0 ;# (see procedure right_panel_redraw_pane) + private variable parentPane ;# ID of parent container (some frame) + private variable last_PanelSize ;# Last panel widgth + private variable PanelSize $::CONFIG(RIGHT_PANEL_SIZE) ;# Current panel width + private variable active_page $::CONFIG(RIGHT_PANEL_ACTIVE_PAGE) ;# ID of the active page + private variable PanelVisible $::CONFIG(RIGHT_PANEL) ;# Bool: is panel visible + + private variable enabled 0 ;# Bool: enable procedures which are needless while loading project + + ## Object constructor + constructor {} { + incr count + set obj_idx $count + } + + ## Object destructor + destructor { + # Clean up GUI + destroy $notebook_frame + + # Remove status bar tips for popup menus + menu_Sbar_remove $bookmarks_menu + menu_Sbar_remove $breakpoints_menu + } + + ## Create right panel + # @parm Widget notebookframe - frame where to pack NoteBook + # @parm Widget ParentPane - parent paned window + # @parm String watches_file - definition file for register watches + # @return void + public method Initialize_rightPanel {notebookframe ParentPane watches_file} { + + # Object variables + set parentPane $ParentPane ;# Parent container (some frame) + # Main frame of this panel + set notebook_frame $notebookframe + + ## Create NoteBook + set notebook [NoteBook $notebook_frame.ntb_rightPanel \ + -side top -bg {#EEEEEE} \ + -arcradius 4 \ + ] + + # Register notebook status bar tips + notebook_Sbar_set {rightpanel} [list \ + Bookmarks [mc "List of bookmarks in the current editor"] \ + Breakpoints [mc "List of breakpoints in the current editor"] \ + Instruction [mc "Details for instruction on the current line"] \ + Watches [mc "Register watches (for internal data memory, external data memory, expanded data memory and bits)"] \ + Subprograms [mc "List of active subprograms"] \ + Symbols [mc "Symbol list"] \ + Hardware [mc "Hardware manager"] \ + Hide [mc "Hide the panel"] \ + ] + $notebook bindtabs <Enter> "notebook_Sbar rightpanel" + $notebook bindtabs <Leave> "Sbar {} ;#" + + # + # Create tabs + # + + if {!${::Editor::editor_to_use}} { + # Tab "Bookmarks" + set bookmarks [$notebook insert end [mc "Bookmarks"] \ + -image ::ICONS::16::bookmark_toolbar \ + -raisecmd "$this rightPanel_set_active_page Bookmarks" \ + -helptext [mc "List of bookmarks in editor (Ctrl+6)"] \ + ] + # Tab "Breakpoints" + set breakpoints [$notebook insert end [mc "Breakpoints"] \ + -image ::ICONS::16::flag \ + -raisecmd "$this rightPanel_set_active_page Breakpoints" \ + -helptext [mc "List of breakpoints in editor (Ctrl+7)"] \ + ] + # Tab "Symbols" + set table_of_symbols [$notebook insert end [mc "Symbols"] \ + -image ::ICONS::16::_blockdevice \ + -raisecmd "$this rightPanel_set_active_page Symbols" \ + -helptext [mc "Symbol List"] \ + ] + # Tab "Instruction" + set instruction [$notebook insert end [mc "Instruction"] \ + -image ::ICONS::16::info \ + -raisecmd "$this rightPanel_set_active_page Instruction" \ + -helptext [mc "Instruction details (Ctrl+8)"] \ + -createcmd [list $this CreateInstructionDetailsGUI] \ + ] + } + # Tab "Watches" + set watches [$notebook insert end [mc "Watches"] \ + -image ::ICONS::16::player_playlist \ + -raisecmd "$this rightPanel_set_active_page Watches" \ + -helptext [mc "Register watches (Ctrl+9)"] \ + -createcmd [list $this CreateRegWatchesGUI] \ + ] + # Tab "Subprograms" + set subprograms [$notebook insert end [mc "Subprograms"] \ + -image ::ICONS::16::queue \ + -raisecmd "$this rightPanel_set_active_page Subprograms"\ + -helptext [mc "Active subprograms (Ctrl+0)"] \ + -createcmd [list $this CreateSubProgramsGUI] \ + ] + # Tab "Hardware manager" + set hwmanager [$notebook insert end [mc "Hardware"] \ + -image ::ICONS::16::kcmpci \ + -raisecmd "$this rightPanel_set_active_page Hardware" \ + -helptext [mc "Hardware manager"] \ + -createcmd [list $this CreateHwManagerGUI] \ + ] + + # Tab "Hide" + $notebook insert end [mc "Hide"] \ + -image ::ICONS::16::2rightarrow \ + -raisecmd "$this right_panel_show_hide" \ + -helptext [mc "Hide the panel"] + + # Prepare panel componenets but do not create GUI elements + PrepareRegWatches $watches $watches_file + PrepareSubPrograms $subprograms + PrepareHwManager $hwmanager + + if {!${::Editor::editor_to_use}} { + PrepareInstructionDetails $instruction + } + + + ## Create Button bar + # Button "Show" + set button_bar [frame $notebook_frame.button_bar] + pack [ttk::button $button_bar.but_show \ + -image ::ICONS::16::2leftarrow \ + -style ToolButton.TButton \ + -command "$this right_panel_show_hide" \ + ] + DynamicHelp::add $button_bar.but_show -text [mc "Show the panel"] + setStatusTip -widget $button_bar.but_show -text [mc "Show the panel"] + # Separator + pack [ttk::separator $button_bar.sep -orient horizontal] -fill x -pady 2 + # Button "Hardware manager" + pack [ttk::button $button_bar.but_hwman \ + -image ::ICONS::16::kcmpci \ + -style ToolButton.TButton \ + -command "$this rightPanel_show_up Hardware" \ + ] + DynamicHelp::add $button_bar.but_hwman -text [mc "Hardware tools"] + setStatusTip -widget $button_bar.but_hwman \ + -text [mc "Hardware tools manager"] + # Button "Active Subprograms" + pack [ttk::button $button_bar.but_subprog \ + -image ::ICONS::16::queue \ + -style ToolButton.TButton \ + -command "$this rightPanel_show_up Subprograms" \ + ] + DynamicHelp::add $button_bar.but_subprog -text [mc "Active subprograms (Ctrl+0)"] + setStatusTip -widget $button_bar.but_subprog \ + -text [mc "List of active subprograms"] + # Button "Register watches" + pack [ttk::button $button_bar.but_reg_watch \ + -image ::ICONS::16::player_playlist \ + -style ToolButton.TButton \ + -command "$this rightPanel_show_up Watches" \ + ] + DynamicHelp::add $button_bar.but_reg_watch -text [mc "MCU register watches (Ctrl+9)"] + setStatusTip -widget $button_bar.but_reg_watch \ + -text [mc "Register watches for internal data memory, external data memory and expanded data memory"] + if {!${::Editor::editor_to_use}} { + # Button "Instruction details" + pack [ttk::button $button_bar.but_ins_det \ + -image ::ICONS::16::info \ + -style ToolButton.TButton \ + -command "$this rightPanel_show_up Instruction" \ + -state [expr {${::Editor::editor_to_use} ? {disabled} : {!disabled}}] \ + ] + DynamicHelp::add $button_bar.but_ins_det -text [mc "Instruction details (Ctrl+8)"] + setStatusTip -widget $button_bar.but_ins_det \ + -text [mc "Details for instruction on the current line"] + # Button "Symbol List" + pack [ttk::button $button_bar.but_symbols \ + -image ::ICONS::16::_blockdevice \ + -style ToolButton.TButton \ + -command "$this rightPanel_show_up Symbols" \ + -state [expr {${::Editor::editor_to_use} ? {disabled} : {!disabled}}] \ + ] + DynamicHelp::add $button_bar.but_symbols -text [mc "Symbol List"] + setStatusTip -widget $button_bar.but_symbols \ + -text [mc "Symbol List"] + # Button "Breakpoints" + pack [ttk::button $button_bar.but_breakpoints \ + -image ::ICONS::16::flag \ + -style ToolButton.TButton \ + -command "$this rightPanel_show_up Breakpoints" \ + -state [expr {${::Editor::editor_to_use} ? {disabled} : {!disabled}}] \ + ] + DynamicHelp::add $button_bar.but_breakpoints -text [mc "List of breakpoints in editor (Ctrl+7)"] + setStatusTip -widget $button_bar.but_breakpoints \ + -text [mc "List of breakpoints in the current editor"] + # Button "Bookmarks" + pack [ttk::button $button_bar.but_bookmarks \ + -image ::ICONS::16::bookmark_toolbar \ + -style ToolButton.TButton \ + -command "$this rightPanel_show_up Bookmarks" \ + -state [expr {${::Editor::editor_to_use} ? {disabled} : {!disabled}}] \ + ] + DynamicHelp::add $button_bar.but_bookmarks -text [mc "List of bookmarks in editor (Ctrl+6)"] + setStatusTip -widget $button_bar.but_bookmarks \ + -text [mc "List of bookmarks in the current editor"] + } + + if {!${::Editor::editor_to_use}} { + # Pack pages managers + set bm_pagesManager [PagesManager $bookmarks.pgm_rightPanel_bm -background {#eeeeee}] + pack $bm_pagesManager -expand 1 -fill both + $bm_pagesManager compute_size + + set bp_pagesManager [PagesManager $breakpoints.pgm_rightPanel_pm -background {#eeeeee}] + pack $bp_pagesManager -expand 1 -fill both + $bp_pagesManager compute_size + + set sm_pagesManager [PagesManager $table_of_symbols.sm_pagesManager -background {#eeeeee}] + pack $sm_pagesManager -expand 1 -fill both + $sm_pagesManager compute_size + + # Create popup menus + set bookmarks_menu $notebook_frame.menu_rightPanel_bookmarks + set breakpoints_menu $notebook_frame.menu_rightPanel_breakpoints + set symbols_menu $notebook_frame.menu_rightPanel_symbols + menuFactory $BREAKPOINTMENU $breakpoints_menu 0 "$this " 0 {} + menuFactory $BOOKMARKMENU $bookmarks_menu 0 "$this " 0 {} + menuFactory $SYMBOLSKMENU $symbols_menu 0 "$this " 0 {} + } + + + # + # Post-initialization + # + + bind $parentPane <ButtonRelease-1> "$this right_panel_set_size" + + # Show panel GUI components + if {$PanelVisible} { + # Show NoteBook + $parentPane paneconfigure $notebook_frame -minsize 295 + pack $notebook -expand 1 -fill both + $parentPane configure -sashwidth 2 + + if {[catch { + $notebook raise $active_page + if { + ${::Editor::editor_to_use} && + ([lsearch {Bookmarks Breakpoints Instruction Symbols} $active_page] != -1) + } { + set active_page {Watches} + $notebook raise {Watches} + } + }]} { + set active_page {Watches} + $notebook raise {Watches} + } + } { + # Show button bar + $parentPane paneconfigure $notebook_frame -minsize 0 + pack $button_bar -anchor nw + $parentPane configure -sashwidth 0 + bind $parentPane <Button> {break} + set last_PanelSize $PanelSize + set PanelSize 60 + } + } + + ## Synchronously scroll list of bookmarks and its line numbers + # @parm Char - what (m == Bookmarks; p == Breakpoints; s == Symbols) + # @parm String - string "moveto" + # @parm Float - number between 0.0 and 1.0 (0.0 == 'start', 1.0 == 'end') + # @return void + public method rightPanel_scroll args { + # Local variables + set what [lindex $args 0] + set cmd [lindex $args 1] ;# Scroll command (moveto, scroll and such) + set frac [lindex $args 2] ;# Fraction where to move + set units [lindex $args 3] ;# Units (optonal) + + switch -- $what { + {m} { ;# Bookmarks + set lnb $bookmarks_lineNumbers + set txt $bookmarks_text + } + {p} { ;# Breakpoints + set lnb $breakpoints_lineNumbers + set txt $breakpoints_text + } + {s} { ;# Symbols + set lnb $sm_lineNumbers + set txt $sm_text + } + } + + if {$units == {}} { + $lnb yview $cmd $frac + $txt yview $cmd $frac + } { + $lnb yview $cmd $frac $units + $txt yview $cmd $frac $units + } + } + + ## Set position for scrollbar and line numbers in bookmark list + # @parm Char what - (m == Bookmarks; p == Breakpoints; s == Symbols) + # @parm Widget scrollbar - ID of scrollbar widget to adjust + # @parm Float fraction0 - y position + # @parm Float fraction1 - x position + # @return Bool - result + public method rightPanel_scrollSet {what scrollbar fraction0 fraction1} { + switch -- $what { + {m} { ;# Bookmarks + set txt $bookmarks_text + } + {p} { ;# Breakpoints + set txt $breakpoints_text + } + {s} { ;# Symbols + set txt $sm_text + } + } + + if {![winfo exists $txt]} { + return 0 + } + + catch { + if {$fraction0 == {0.0} && $fraction1 == {1.0}} { + if {[winfo ismapped $scrollbar]} { + pack forget $scrollbar + } + } { + if {![winfo ismapped $scrollbar]} { + pack $scrollbar -side right -fill y -after $txt + } + } + } + + + $scrollbar set $fraction0 $fraction1 + rightPanel_scroll $what moveto $fraction0 + + return 1 + } + + ## Refresh font settings for all text widgets in the panel + # @parm Bool for_all - 0 == only for the current editor; 1 == for all editors + # @return void + public method rightPanel_refresh_font_settings {for_all} { + if {${::Editor::editor_to_use}} {return} + if {$for_all} { + foreach widget $LIST_bookmarks_lineNumbers { + $widget configure -font ${Editor::defaultFont_bold} + } + + foreach widget $LIST_breakpoints_lineNumbers { + $widget configure -font ${Editor::defaultFont_bold} + } + + set i 0 + foreach widget $LIST_bookmarks_text { + $widget configure -font ${Editor::defaultFont_bold} + ASMsyntaxHighlight::create_tags $widget ${Editor::fontSize} ${Editor::fontFamily} + set language [$this editor_procedure $i get_language {}] + if {$language == 1} { + CsyntaxHighlight::create_tags \ + $widget ${Editor::fontSize} ${Editor::fontFamily} + } elseif {$language == 2} { + LSTsyntaxHighlight::create_tags \ + $widget ${Editor::fontSize} ${Editor::fontFamily} + } + incr i + } + + set i 0 + foreach widget $LIST_breakpoints_text { + $widget configure -font ${Editor::defaultFont_bold} + ASMsyntaxHighlight::create_tags $widget ${Editor::fontSize} ${Editor::fontFamily} + set language [$this editor_procedure $i get_language {}] + if {$language == 1} { + CsyntaxHighlight::create_tags \ + $widget ${Editor::fontSize} ${Editor::fontFamily} + } elseif {$language == 2} { + LSTsyntaxHighlight::create_tags \ + $widget ${Editor::fontSize} ${Editor::fontFamily} + } + incr i + } + } { + $bookmarks_lineNumbers configure -font ${Editor::defaultFont_bold} + $bookmarks_text configure -font ${Editor::defaultFont_bold} + $breakpoints_lineNumbers configure -font ${Editor::defaultFont_bold} + $breakpoints_text configure -font ${Editor::defaultFont_bold} + $sm_lineNumbers configure -font ${Editor::defaultFont_bold} + $sm_text configure -font ${Editor::defaultFont_bold} + + ASMsyntaxHighlight::create_tags $bookmarks_text ${Editor::fontSize} ${Editor::fontFamily} + ASMsyntaxHighlight::create_tags $breakpoints_text ${Editor::fontSize} ${Editor::fontFamily} + set language [$this editor_procedure {end} get_language {}] + if {$language == 1} { + CsyntaxHighlight::create_tags \ + $bookmarks_text ${Editor::fontSize} ${Editor::fontFamily} + CsyntaxHighlight::create_tags \ + $breakpoints_text ${Editor::fontSize} ${Editor::fontFamily} + } elseif {$language == 2} { + CsyntaxHighlight::create_tags \ + $bookmarks_text ${Editor::fontSize} ${Editor::fontFamily} + CsyntaxHighlight::create_tags \ + $breakpoints_text ${Editor::fontSize} ${Editor::fontFamily} + } + + create_tags_in_symbol_list + } + } + + ## Create highlight tag for list of bookmarks and breakpoints for the current editor + # @return void + public method rightPanel_add_Editor__create_menu_and_tags {} { + if {${::Editor::editor_to_use}} {return} + ASMsyntaxHighlight::create_tags $breakpoints_text $fontSize $fontFamily + ASMsyntaxHighlight::create_tags $bookmarks_text $fontSize $fontFamily + set language [$this editor_procedure {end} get_language {}] + if {$language == 1} { + rightPanel_bm_bp_create_c_hg_tags + } elseif {$language == 2} { + rightPanel_bm_bp_create_lst_hg_tags + } + + create_tags_in_symbol_list + } + + ## Create highlighting tags in the text widget in the "List of Symbols" + # @return void + private method create_tags_in_symbol_list {} { + set tags_to_define [list tag_label tag_constant tag_normal tag_macro] + foreach tag_def [concat ${::ASMsyntaxHighlight::hightlight_tags} ${::CsyntaxHighlight::hightlight_tags}] { + if {[lsearch -ascii -exact $tags_to_define [lindex $tag_def 0]] == -1} { + continue + } + + # Create array of tag attributes + for {set i 0} {$i < 5} {incr i} { + set tag_def_item($i) [lindex $tag_def $i] + } + + # Foreground color + if {$tag_def_item(1) == {}} { + set tag_def_item(1) black + } + # Fonr slant + if {$tag_def_item(3) == 1} { + set tag_def_item(3) italic + } { + set tag_def_item(3) roman + } + # Font weight + if {$tag_def_item(4) == 1} { + set tag_def_item(4) bold + } { + set tag_def_item(4) normal + } + + # Create the tag in the target text widget + $sm_text tag configure $tag_def_item(0) \ + -foreground $tag_def_item(1) \ + -font [font create \ + -overstrike $tag_def_item(2) \ + -slant $tag_def_item(3) \ + -weight $tag_def_item(4) \ + -size -$::Editor::fontSize \ + -family $::Editor::fontFamily \ + ] + } + + # Create tag for C function + $sm_text tag configure tag_c_func \ + -foreground {#0000DD} \ + -font ${::Editor::defaultFont} + } + + ## Create highlighting tags for Codelisting for the current editor + # @return void + public method rightPanel_bm_bp_create_lst_hg_tags {} { + LSTsyntaxHighlight::create_tags $breakpoints_text $fontSize $fontFamily + LSTsyntaxHighlight::create_tags $bookmarks_text $fontSize $fontFamily + } + ## Create highlighting tags for C language for the current editor + # @return void + public method rightPanel_bm_bp_create_c_hg_tags {} { + CsyntaxHighlight::create_tags $breakpoints_text $fontSize $fontFamily + CsyntaxHighlight::create_tags $bookmarks_text $fontSize $fontFamily + } + + ## Add new list of bookmarks and list of breakpoints for new editor + # @parm Bool create_menu_and_tags - Create popup menus and highlighting tags + # @return void + public method rightPanel_add_Editor {create_menu_and_tags} { + if {${::Editor::editor_to_use}} {return} + + # Local variables + set bm_page [$bm_pagesManager add $editors_count] ;# ID of current bookmarks page + set bp_page [$bp_pagesManager add $editors_count] ;# ID of current breakpoints page + set sm_page [$sm_pagesManager add $editors_count] ;# ID of current page in symbol list + + # Register new editor + set current_editor_idx $editors_count + lappend bm_bp_pages_list $editors_count + incr editors_count ;# increment counter of editors + + + # + # Create tab "Bookmarks" + # + + ## Create icon bar (up, down, bookmark, clear all) + # Create button frame + set button_frame [frame $bm_page.frm_rightPanel_bm_button_frame] + pack $button_frame -side top -fill x + # Button "Up" + set bm_up_button [ttk::button $button_frame.but_rightPanel_bm_up \ + -image ::ICONS::16::1uparrow \ + -state disabled \ + -command "$this rightPanel_bm_up" \ + -style ToolButton.TButton \ + ] + pack $bm_up_button -side left + DynamicHelp::add $bm_up_button -text [mc "Move to previous bookmark"] + setStatusTip -widget $bm_up_button \ + -text [mc "Goto to line of previous bookmark"] + # Button "Down" + set bm_down_button [ttk::button $button_frame.but_rightPanel_bm_down \ + -image ::ICONS::16::1downarrow \ + -state disabled \ + -command "$this rightPanel_bm_down" \ + -style ToolButton.TButton \ + ] + pack $bm_down_button -side left + DynamicHelp::add $bm_down_button -text [mc "Move to the next bookmark"] + setStatusTip -widget $bm_down_button \ + -text [mc "Goto to line of next bookmark"] + # Separator + pack [ttk::separator $button_frame.but_rightPanel_bm_sep \ + -orient vertical \ + ] -side left -fill y -padx 2 + # Button "Bookmark" + set button [ttk::button $button_frame.but_rightPanel_bm_bookmark \ + -image ::ICONS::16::bookmark_add \ + -command "$this editor_procedure {} Bookmark {}" \ + -style ToolButton.TButton \ + ] + pack $button -side left + DynamicHelp::add $button -text [mc "Add/Remove bookmark on the current line"] + setStatusTip -widget $button \ + -text [mc "Add/Remove bookmark on the current line in editor"] + # Button "Clear all" + set bm_clear_button [ttk::button $button_frame.but_rightPanel_bm_clear \ + -image ::ICONS::16::editdelete \ + -state disabled \ + -command "$this editor_procedure {} clear_all_bookmarks {}" \ + -style ToolButton.TButton \ + ] + pack $bm_clear_button -side right + DynamicHelp::add $bm_clear_button -text [mc "Clear all bookmarks"] + setStatusTip -widget $bm_clear_button \ + -text [mc "Clear all bookmarks from editor"] + + # Create text frame (Contains: text widget, scrollbar, LineNumbers) + set text_frame [frame $bm_page.frm_rightPanel_bm_text_frame -bd 1 -relief sunken] + pack $text_frame -fill both -expand 1 -side bottom + + # Create scrollbar + set scrollbar [ttk::scrollbar \ + $text_frame.scr_rightPanel_bookmars \ + -orient vertical \ + -command "$this rightPanel_scroll m" \ + ] + # Create line numbers + set bookmarks_lineNumbers [text $text_frame.txt_rightPanel_bm_lineNumbers \ + -yscrollcommand "$this rightPanel_scrollSet m $scrollbar" \ + -cursor left_ptr \ + -width 1 -height 1 \ + -bg gray \ + -fg white \ + -relief flat \ + -bd 1 \ + -state disabled \ + -exportselection 0 \ + -takefocus 0 \ + -font ${Editor::defaultFont_bold} \ + ] + $bookmarks_lineNumbers tag configure right -justify right + # Create list of bookmarks + set bookmarks_text [text $text_frame.txt_rightPanel_bookmars \ + -cursor left_ptr -state disabled -width 1 -height 1 \ + -wrap none -exportselection 0 -bd 1 -relief flat \ + -yscrollcommand "$this rightPanel_scrollSet m $scrollbar" \ + -font ${Editor::defaultFont_bold} \ + ] + $bookmarks_text tag configure curLine \ + -borderwidth 1 \ + -relief raised \ + -background ${::RightPanel::selection_color} + + # Set bindings + bind $bookmarks_text <<Selection>> "false_selection $bookmarks_text; break" + bind $bookmarks_text <Button-1> "$this rightPanel_xx_txt_click m %x %y; break" + bind $bookmarks_text <ButtonRelease-3> "$this rightPanel_bm_popupmenu %X %Y %x %y; break; break" + bind $bookmarks_lineNumbers <ButtonRelease-3> "$this rightPanel_bm_popupmenu %X %Y %x %y; break; break" + bind $bookmarks_text <Key-Menu> {break} + bind $bookmarks_lineNumbers <<Selection>> "false_selection $bookmarks_lineNumbers; break" + + # Pack components of "Text frame" + pack $bookmarks_lineNumbers -side left -fill y + pack $bookmarks_text -side left -expand 1 -fill both + + + # + # Breakpoints tab + # + + ## Create icon bar (up, down, breakpoint, clear all) + # Create button frame + set button_frame [frame $bp_page.frm_rightPanel_bp_button_frame] + pack $button_frame -side top -fill x + # Button "Up" + set bp_up_button [ttk::button $button_frame.but_rightPanel_bp_up \ + -image ::ICONS::16::1uparrow \ + -state disabled \ + -command "$this rightPanel_bp_up" \ + -style ToolButton.TButton \ + ] + pack $bp_up_button -side left + DynamicHelp::add $bp_up_button -text [mc "Move to previous breakpoint"] + setStatusTip -widget $bp_up_button \ + -text [mc "Goto to line of previous breakpoint"] + # Button "Down" + set bp_down_button [ttk::button $button_frame.but_rightPanel_bp_down \ + -image ::ICONS::16::1downarrow \ + -state disabled \ + -command "$this rightPanel_bp_down" \ + -style ToolButton.TButton \ + ] + pack $bp_down_button -side left + DynamicHelp::add $bp_down_button -text [mc "Move to next breakpoint"] + setStatusTip -widget $bp_down_button \ + -text [mc "Goto to line of next breakpoint"] + # Separator + pack [ttk::separator $button_frame.but_rightPanel_bp_sep \ + -orient vertical \ + ] -side left -fill y -padx 2 + # Button "Breakpoint" + set button [ttk::button $button_frame.but_rightPanel_bp_breakpoint \ + -image ::ICONS::16::flag \ + -command "$this editor_procedure {} Breakpoint {}" \ + -style ToolButton.TButton \ + ] + pack $button -side left + DynamicHelp::add $button -text [mc "Add/Remove breakpoint on the current line"] + setStatusTip -widget $button \ + -text [mc "Add/Remove breakpoint on the current line in editor"] + # Buttton "Clear all" + set bp_clear_button [ttk::button $button_frame.but_rightPanel_bp_clear \ + -image ::ICONS::16::editdelete \ + -state disabled \ + -command "$this editor_procedure {} clear_all_breakpoints {}" \ + -style ToolButton.TButton \ + ] + pack $bp_clear_button -side right + DynamicHelp::add $bp_clear_button -text [mc "Clear all breakpoints"] + setStatusTip -widget $bp_clear_button \ + -text [mc "Clear all breakpoints from editor"] + + # Create text frame (Contains: text widget, scrollbar, LineNumbers) + set text_frame [frame $bp_page.frm_rightPanel_bp_text_frame -bd 1 -relief sunken] + pack $text_frame -fill both -expand 1 -side bottom + + # Create scrollbar + set scrollbar [ttk::scrollbar \ + $text_frame.scr_rightPanel_breakpoints \ + -orient vertical \ + -command "$this rightPanel_scroll p" \ + ] + # Create line numbers + set breakpoints_lineNumbers [text $text_frame.txt_rightPanel_bp_lineNumbers \ + -yscrollcommand "$this rightPanel_scrollSet p $scrollbar" \ + -cursor left_ptr \ + -width 1 -height 1 \ + -exportselection 0 \ + -bg gray \ + -fg white \ + -relief flat \ + -bd 1 \ + -state disabled \ + -takefocus 0 \ + -font ${Editor::defaultFont_bold} \ + ] + $breakpoints_lineNumbers tag configure right -justify right + # Create list of breakpoints + set breakpoints_text [text $text_frame.txt_rightPanel_breakpoints \ + -cursor left_ptr -state disabled \ + -wrap none -exportselection 0 -bd 1 -relief flat \ + -font ${Editor::defaultFont_bold} -width 1 -height 1 \ + -yscrollcommand "$this rightPanel_scrollSet p $scrollbar" \ + ] + $breakpoints_text tag configure curLine \ + -borderwidth 1 \ + -relief raised \ + -background ${::RightPanel::selection_color} + + # Pack widgets of the text frame + pack $breakpoints_lineNumbers -side left -fill y + pack $breakpoints_text -side left -expand 1 -fill both + + # Set bindings + bind $breakpoints_text <<Selection>> "false_selection $breakpoints_text; break" + bind $breakpoints_text <Button-1> "$this rightPanel_xx_txt_click p %x %y; break" + bind $breakpoints_text <ButtonRelease-3> "$this rightPanel_bp_popupmenu %X %Y %x %y; break; break" + bind $breakpoints_lineNumbers <ButtonRelease-3> "$this rightPanel_bp_popupmenu %X %Y %x %y; break; break" + bind $breakpoints_text <Key-Menu> {break} + bind $breakpoints_lineNumbers <<Selection>> "false_selection $breakpoints_lineNumbers; break" + + + # + # Symbol list + # + + ## Create icon bar (up, down, breakpoint, clear all) + # Create button frame + set button_frame [frame $sm_page.button_frame] + pack $button_frame -side top -fill x + # Button "Refresh" + set refresh_but [ttk::button $button_frame.refresh_but \ + -image ::ICONS::16::reload \ + -command "$this rightPanel_refresh_symbols" \ + -style ToolButton.TButton \ + ] + pack $refresh_but -side left + DynamicHelp::add $refresh_but -text [mc "Reevaluate"] + setStatusTip -widget $refresh_but \ + -text [mc "Reevaluate ..."] + + # Button "Clear search string" + set sm_search_clear [ttk::button $button_frame.clear_search \ + -image ::ICONS::16::clear_left \ + -style Flat.TButton \ + -command "$button_frame.search_entry delete 0 end" \ + -state disabled \ + ] + DynamicHelp::add $button_frame.clear_search -text [mc "Clear search string"] + pack $sm_search_clear -side right + setStatusTip -widget $sm_search_clear \ + -text [mc "Clear search string"] + # Entry "Search" + set sm_search_entry [ttk::entry $button_frame.search_entry \ + -validate key \ + -width 0 \ + -validatecommand "$this rightPanel_sm_search_validate %P %W $sm_search_clear" \ + ] + DynamicHelp::add $sm_search_entry -text [mc "Search for a constant, variable, function or macro"] + pack $sm_search_entry -side right -fill x -expand 1 + setStatusTip -widget $sm_search_entry \ + -text [mc "Search for a constant, variable, function or macro"] + # Label "Search:" + pack [label $button_frame.search_lbl -text [mc " Search:"]] -side right + + # Create text frame (Contains: text widget, scrollbar, LineNumbers) + set text_frame [frame $sm_page.text_frame -bd 1 -relief sunken] + pack $text_frame -fill both -expand 1 -side bottom + + # Create scrollbar + set scrollbar [ttk::scrollbar $text_frame.scr \ + -orient vertical \ + -command "$this rightPanel_scroll s" \ + ] + set sm_lineNumbers [text $text_frame.ln \ + -yscrollcommand "$this rightPanel_scrollSet s $scrollbar" \ + -cursor left_ptr -width 1 \ + -exportselection 0 -bg gray \ + -height 1 -fg white \ + -relief flat -bd 1 \ + -state disabled -takefocus 0 \ + -font ${Editor::defaultFont_bold} \ + ] + $sm_lineNumbers tag configure right -justify right + set sm_text [text $text_frame.txt \ + -cursor left_ptr -state disabled \ + -wrap none -exportselection 0 -bd 1 -relief flat \ + -font ${Editor::defaultFont_bold} -width 1 -height 1 \ + -yscrollcommand "$this rightPanel_scrollSet s $scrollbar" \ + ] + $sm_text tag configure curLine \ + -borderwidth 1 \ + -relief raised \ + -background ${::RightPanel::selection_color} + + # Pack widgets of the text frame + pack $scrollbar -side right -fill y + pack $sm_lineNumbers -side left -fill y + pack $sm_text -side left -expand 1 -fill both + + # Set bindings + bind $sm_text <<Selection>> "false_selection $sm_text; break" + bind $sm_text <Button-1> "$this rightPanel_xx_txt_click s %x %y; break" + bind $sm_text <Key-Menu> {break} + bind $sm_text <ButtonRelease-3> {break} + bind $sm_lineNumbers <<Selection>> "false_selection $sm_lineNumbers; break" + bind $sm_lineNumbers <Key-Menu> {break} + bind $sm_lineNumbers <ButtonRelease-3> {break} + + ## FINISH + + # Append create d widgets to lists + lappend LIST_bookmarks_lineNumbers $bookmarks_lineNumbers + lappend LIST_breakpoints_lineNumbers $breakpoints_lineNumbers + lappend LIST_bookmarks_text $bookmarks_text + lappend LIST_breakpoints_text $breakpoints_text + lappend LIST_bm_up_button $bm_up_button + lappend LIST_bm_down_button $bm_down_button + lappend LIST_bm_clear_button $bm_clear_button + lappend LIST_bp_up_button $bp_up_button + lappend LIST_bp_down_button $bp_down_button + lappend LIST_bp_clear_button $bp_clear_button + lappend LIST_sm_text $sm_text + lappend LIST_sm_lineNumbers $sm_lineNumbers + + if {$create_menu_and_tags} { + rightPanel_add_Editor__create_menu_and_tags + } + } + + ## Enable/Disable buttons on Bookmarks+Breakpoints icon bar + # @return void + private method bm_bp_disEna_buttons {} { + + # Bookmarks + set end [$bookmarks_text index end] + switch -- $end { + {2.0} { ;# Empty list + $bm_up_button configure -state disabled + $bm_down_button configure -state disabled + $bm_clear_button configure -state disabled + } + {3.0} { ;# One item + $bm_up_button configure -state disabled + $bm_down_button configure -state disabled + $bm_clear_button configure -state normal + } + default { ;# More items + $bm_up_button configure -state normal + $bm_down_button configure -state normal + $bm_clear_button configure -state normal + } + } + + # Breakpoints + set end [$breakpoints_text index end] + switch -- $end { + {2.0} { ;# Empty list + $bp_up_button configure -state disabled + $bp_down_button configure -state disabled + $bp_clear_button configure -state disabled + } + {3.0} { ;# One item + $bp_up_button configure -state disabled + $bp_down_button configure -state disabled + $bp_clear_button configure -state normal + } + default { ;# More items + $bp_up_button configure -state normal + $bp_down_button configure -state normal + $bp_clear_button configure -state normal + } + } + } + + ## Recreate popup menus + # @return void + public method rightPanel_makePopupMenu {} { + regwatches_makePopupMenu + + if {[winfo exists $breakpoints_menu]} {destroy $breakpoints_menu} + if {[winfo exists $bookmarks_menu]} {destroy $bookmarks_menu} + menuFactory $BREAKPOINTMENU $breakpoints_menu 0 "$this " 0 {} + menuFactory $BOOKMARKMENU $bookmarks_menu 0 "$this " 0 {} + } + + ## Invoke bookmarks popup menu + # @parm Int X - Absolute X coordinate + # @parm Int Y - Absolute Y coordinate + # @parm Int x - Relative X coordinate + # @parm Int y - Relative Y coordinate + # @return void + public method rightPanel_bm_popupmenu {X Y x y} { + + # Change position in the list + rightPanel_xx_txt_click m $x $y + + # Enable/Disable menu items + set end [$bookmarks_text index end] + switch -- $end { + {2.0} { ;# Empty list + $bookmarks_menu entryconfigure [::mc "Remove"] -state disabled + $bookmarks_menu entryconfigure [::mc "Next"] -state disabled + $bookmarks_menu entryconfigure [::mc "Previous"] -state disabled + $bookmarks_menu entryconfigure [::mc "Remove all"] -state disabled + } + {3.0} { ;# One item + $bookmarks_menu entryconfigure [::mc "Remove"] -state normal + $bookmarks_menu entryconfigure [::mc "Next"] -state disabled + $bookmarks_menu entryconfigure [::mc "Previous"] -state disabled + $bookmarks_menu entryconfigure [::mc "Remove all"] -state normal + } + default { ;# More items + $bookmarks_menu entryconfigure [::mc "Remove"] -state normal + $bookmarks_menu entryconfigure [::mc "Next"] -state normal + $bookmarks_menu entryconfigure [::mc "Previous"] -state normal + $bookmarks_menu entryconfigure [::mc "Remove all"] -state normal + } + } + + # Invoke the menu + tk_popup $bookmarks_menu $X $Y + } + + ## Invoke breakpoints popup menu + # @parm Int X - Absolute X coordinate + # @parm Int Y - Absolute Y coordinate + # @parm Int x - Relative X coordinate + # @parm Int y - Relative Y coordinate + # @return void + public method rightPanel_bp_popupmenu {X Y x y} { + + # Change position in the list + rightPanel_xx_txt_click p $x $y + + # Enable/Disable menu items + set end [$breakpoints_text index end] + switch -- $end { + {2.0} { ;# Empty list + $breakpoints_menu entryconfigure [::mc "Remove"] -state disabled + $breakpoints_menu entryconfigure [::mc "Next"] -state disabled + $breakpoints_menu entryconfigure [::mc "Previous"] -state disabled + $breakpoints_menu entryconfigure [::mc "Remove all"] -state disabled + } + {3.0} { ;# One item + $breakpoints_menu entryconfigure [::mc "Remove"] -state normal + $breakpoints_menu entryconfigure [::mc "Next"] -state disabled + $breakpoints_menu entryconfigure [::mc "Previous"] -state disabled + $breakpoints_menu entryconfigure [::mc "Remove all"] -state normal + } default { ;# More items + $breakpoints_menu entryconfigure [::mc "Remove"] -state normal + $breakpoints_menu entryconfigure [::mc "Next"] -state normal + $breakpoints_menu entryconfigure [::mc "Previous"] -state normal + $breakpoints_menu entryconfigure [::mc "Remove all"] -state normal + } + } + + # Invoke the menu + tk_popup $breakpoints_menu $X $Y + } + + ## Remove editor from the list + # @parm Int idx - editor index + # @return void + public method rightPanel_remove_Editor {idx} { + if {${::Editor::editor_to_use}} {return} + + # Remove pages from pages managers + $bm_pagesManager delete [lindex $bm_bp_pages_list $idx] + $bp_pagesManager delete [lindex $bm_bp_pages_list $idx] + $sm_pagesManager delete [lindex $bm_bp_pages_list $idx] + set bm_bp_pages_list [lreplace $bm_bp_pages_list $idx $idx] + + # Remove widget references from its lists + set LIST_bookmarks_lineNumbers [lreplace $LIST_bookmarks_lineNumbers $idx $idx] + set LIST_breakpoints_lineNumbers [lreplace $LIST_breakpoints_lineNumbers $idx $idx] + set LIST_bookmarks_text [lreplace $LIST_bookmarks_text $idx $idx] + set LIST_breakpoints_text [lreplace $LIST_breakpoints_text $idx $idx] + set LIST_bm_up_button [lreplace $LIST_bm_up_button $idx $idx] + set LIST_bm_down_button [lreplace $LIST_bm_down_button $idx $idx] + set LIST_bm_clear_button [lreplace $LIST_bm_clear_button $idx $idx] + set LIST_bp_up_button [lreplace $LIST_bp_up_button $idx $idx] + set LIST_bp_down_button [lreplace $LIST_bp_down_button $idx $idx] + set LIST_bp_clear_button [lreplace $LIST_bp_clear_button $idx $idx] + set LIST_sm_text [lreplace $LIST_sm_text $idx $idx] + set LIST_sm_lineNumbers [lreplace $LIST_sm_lineNumbers $idx $idx] + } + + ## Change the current editor + # @parm Int idx - editor index + # @return void + public method rightPanel_switch_editor {idx} { + if {${::Editor::editor_to_use}} {return} + + set current_editor_idx $idx + rightPanel_switch_page $idx + rightPanel_switch_editor_vars $idx + } + + ## Change the current page in pages managers + # @parm Int idx - editor index + # @return void + public method rightPanel_switch_page {idx} { + if {${::Editor::editor_to_use}} {return} + + set current_editor_idx $idx + $bm_pagesManager raise [lindex $bm_bp_pages_list $idx] + $bp_pagesManager raise [lindex $bm_bp_pages_list $idx] + $sm_pagesManager raise [lindex $bm_bp_pages_list $idx] + + if {$active_page == {Symbols}} { + catch {$this editor_procedure {} comp_win_highlight_all_in_background {}} + } + } + + ## Change current editor but don not affect GUI + # @parm Int idx - editor index + # @return void + public method rightPanel_switch_editor_vars {idx} { + if {${::Editor::editor_to_use}} {return} + + # Set active widgets + set current_editor_idx $idx + set bookmarks_lineNumbers [lindex $LIST_bookmarks_lineNumbers $idx] + set breakpoints_lineNumbers [lindex $LIST_breakpoints_lineNumbers $idx] + set bookmarks_text [lindex $LIST_bookmarks_text $idx] + set breakpoints_text [lindex $LIST_breakpoints_text $idx] + set bm_up_button [lindex $LIST_bm_up_button $idx] + set bm_down_button [lindex $LIST_bm_down_button $idx] + set bm_clear_button [lindex $LIST_bm_clear_button $idx] + set bp_up_button [lindex $LIST_bp_up_button $idx] + set bp_down_button [lindex $LIST_bp_down_button $idx] + set bp_clear_button [lindex $LIST_bp_clear_button $idx] + set sm_text [lindex $LIST_sm_text $idx] + set sm_lineNumbers [lindex $LIST_sm_lineNumbers $idx] + } + + + ## Binding for event <Button-1> for list of ... + # Change selection in the widget and change current line in the editor + # @parm Char - what (m == Bookmarks; p == Breakpoints; s == Symbols) + # @parm Int x - relative X coordinate + # @parm Int y - relative Y coordinate + # @return Bool - result + public method rightPanel_xx_txt_click {what x y} { + if {$block_select} {return} + + switch -- $what { + {m} { ;# Bookmarks + set lnb $bookmarks_lineNumbers + set txt $bookmarks_text + } + {p} { ;# Breakpoints + set lnb $breakpoints_lineNumbers + set txt $breakpoints_text + } + {s} { ;# Symbols + set lnb $sm_lineNumbers + set txt $sm_text + } + } + + # Determinate line number + set lineNum [rightPanel_txt_click $txt $lnb $x $y] + if {$lineNum == {}} {return 0} + + # Change current line in the editor + set block_select 1 + $this editor_procedure {} goto $lineNum + update idle + set block_select 0 + + return 1 + } + + ## Determinate line number and select the line + # @parm Widget txt_widget - ID of the text widget + # @parm Widget ln_widget - ID of line numbers widget + # @parm Int x - relative X coordinate + # @parm Int y - relative X coordinate + # @return Int - line number (from line numbers panel) + private method rightPanel_txt_click {txt_widget ln_widget x y} { + set idx [$txt_widget index @$x,$y] + + # Determinate traslated line number + set lineNum [$ln_widget get [list $idx linestart] [list $idx lineend]] + + # Select the line + if {$lineNum != {}} { + $txt_widget tag remove curLine 1.0 end + $txt_widget tag add curLine [list $idx linestart] [list $idx+1l linestart] + } + + # Retrun result + return $lineNum + } + + ## If the given line contain bookmark then select it in the list + # This function should be called after change line in the editor + # @parm Int lineNum - line number + # @return Bool - result + public method rightPanel_bm_select {lineNum} { + if {!$enabled || $block_select} {return} + if {![info exists bookmarks_text]} {return} + + # Check for bookmark presence + set idx0 [lsearch -ascii -exact [$bookmarks_lineNumbers get 1.0 end] $lineNum] + if {$idx0 == -1} {return 0} + + # Select the line + incr idx0 + set idx1 $idx0 + incr idx1 + $bookmarks_text tag remove curLine 1.0 end + $bookmarks_text tag add curLine $idx0.0 $idx1.0 + $bookmarks_text see $idx0.0 + return 1 + } + + ## If the given line contain bookmark then select it in the list + # This function should be called after change line in the editor + # @parm Int lineNum - line number + # @return Bool - result + public method rightPanel_bp_select {lineNum} { + if {!$enabled || $block_select} {return} + if {![info exists breakpoints_text]} {return} + + # Check for bookmark presence + set idx0 [lsearch [$breakpoints_lineNumbers get 1.0 end] $lineNum] + if {$idx0 == -1} {return 0} + + # Select the line + incr idx0 + set idx1 $idx0 + incr idx1 + $breakpoints_text tag remove curLine 1.0 end + $breakpoints_text tag add curLine $idx0.0 $idx1.0 + $breakpoints_text see $idx0.0 + return 1 + } + + ## Unset selection in list of bookmarks + # @return void + public method rightPanel_bm_unselect {} { + if {!$enabled || $block_select} {return} + if {![info exists bookmarks_text]} {return} + $bookmarks_text tag remove curLine 1.0 end + } + + ## Unset selection in list of breakpoints + # @return void + public method rightPanel_bp_unselect {} { + if {!$enabled || $block_select} {return} + if {![info exists breakpoints_text]} {return} + $breakpoints_text tag remove curLine 1.0 end + } + + ## Copy line from the editor to target widget and preserve highlight + # @parm Widget target_widget - target widget, where to copy the line + # @parm TextIndex idx - target text index + # @parm Int lineNum - source line number + # @parm Int editor_idx - editor index + # @return void + private method insert_text {target_widget idx lineNum editor_idx} { + + # Copy text + set line [$this editor_procedure $editor_idx getLineContent $lineNum] + regsub -all {\t} $line { } line + append line "\n" + $target_widget insert $idx $line + + # Gain list of text tags in source widget + set ranges [$this editor_procedure $editor_idx getTagsRanges $lineNum] + # Determinate row in the target widget + if {$idx == {end}} { + set row [$target_widget index end] + set row [expr {int($row) - 2}] + } { + set row [expr {int($idx)}] + } + # Iterate over source text tags and add them to target widget + foreach range $ranges { + # Local variables + set tag [lindex $range 0] ;# Text tag + set range [lindex $range 1] ;# Tag range + set range_len [llength $range] ;# Number of indexes in tag range + + # Iterate over ranges + for {set i 0} {$i < $range_len} {incr i} { + + # Translate indexes + set idx0 [lindex $range $i] + regsub {^\d+} $idx0 $row idx0 + incr i + set idx1 [lindex $range $i] + regsub {^\d+} $idx1 $row idx1 + + # Set tag + $target_widget tag add $tag $idx0 $idx1 + } + } + } + + ## Add bookmark to the list + # @parm Int lineNum - line number in the editor + # @return void + public method rightPanel_add_bookmark {lineNum} { + if {$block_select} {return} + + ## Determinate target text index + set indexes [$bookmarks_lineNumbers get 1.0 end] + + set idx -1 + set i 0 + foreach line $indexes { + incr i + if {$line > $lineNum} { + set idx $i + break + } + } + + if {$idx == -1} { + set idx {end} + } { + append idx {.0} + } + + # Enable widgets + $bookmarks_lineNumbers configure -state normal + $bookmarks_text configure -state normal + + # Insert new line to line numbers + $bookmarks_lineNumbers insert $idx "$lineNum\n" + adjust_width $bookmarks_lineNumbers + + # Insert text to the list + insert_text $bookmarks_text $idx $lineNum {} + + # Disable widgets + $bookmarks_lineNumbers configure -state disabled + $bookmarks_text configure -state disabled + + # Reevaluate icon bar button states + bm_bp_disEna_buttons + } + + ## Remove bookmark from the list + # @parm Int lineNum - line number (in Editor) + # @return void + public method rightPanel_remove_bookmark {lineNum} { + if {$block_select} {return} + + # Determinate start and end index + set idx [lsearch [$bookmarks_lineNumbers get 1.0 end] $lineNum] + if {$idx == -1} {return} + + set idx0 [expr {int($idx) + 1}] + set idx1 [expr {int($idx) + 2}] + + # Enable widgets + $bookmarks_lineNumbers configure -state normal + $bookmarks_text configure -state normal + + # Remove line from line numbers + $bookmarks_lineNumbers delete $idx0.0 $idx1.0 + adjust_width $bookmarks_lineNumbers + + # Remove line from the list + $bookmarks_text delete $idx0.0 $idx1.0 + + # Disable widgets + $bookmarks_lineNumbers configure -state disabled + $bookmarks_text configure -state disabled + + # Reevaluate icon bar button states + bm_bp_disEna_buttons + } + + ## Add breakpoint to the list + # @parm Int lineNum - line number in the editor + # @return void + public method rightPanel_add_breakpoint {lineNum} { + if {$block_select} {return} + + ## Determinate target text index + set indexes [$breakpoints_lineNumbers get 1.0 end] + + set idx -1 + set i 0 + foreach line $indexes { + incr i + if {$line > $lineNum} { + set idx $i + break + } + } + + if {$idx == -1} { + set idx {end} + } { + append idx {.0} + } + + # Enable widgets + $breakpoints_lineNumbers configure -state normal + $breakpoints_text configure -state normal + + # Insert new line to line numbers + $breakpoints_lineNumbers insert $idx "$lineNum\n" + adjust_width $breakpoints_lineNumbers + + # Insert text to the list + insert_text $breakpoints_text $idx $lineNum {} + + # Disable widgets + $breakpoints_lineNumbers configure -state disabled + $breakpoints_text configure -state disabled + + # Reevaluate icon bar button states + bm_bp_disEna_buttons + } + + ## Remove breakpoint from the list + # @parm Int lineNum - line number (in Editor) + # @return void + public method rightPanel_remove_breakpoint {lineNum} { + if {$block_select} {return} + + # Determinate start and end index + set idx [lsearch [$breakpoints_lineNumbers get 1.0 end] $lineNum] + if {$idx == -1} {return} + + set idx0 [expr {int($idx) + 1}] + set idx1 [expr {int($idx) + 2}] + + # Enable widgets + $breakpoints_lineNumbers configure -state normal + $breakpoints_text configure -state normal + + # Remove line from line numbers + $breakpoints_lineNumbers delete $idx0.0 $idx1.0 + adjust_width $breakpoints_lineNumbers + + # Remove line from the list + $breakpoints_text delete $idx0.0 $idx1.0 + + # Disable widgets + $breakpoints_lineNumbers configure -state disabled + $breakpoints_text configure -state disabled + + # Reevaluate icon bar button states + bm_bp_disEna_buttons + } + + ## Adjust width of given text widget to fit lenght of the last line + # @parm Widget widget - target text widget + # @return void + private method adjust_width {widget} { + $widget configure -width [string length [lindex [$widget get end-2l end] end]] + + catch { + $widget tag add right 0.0 end + } + } + + ## Binding for button "Up" (Bookmarks icon bar) - select bookmark above the current line + # @return void + public method rightPanel_bm_up {} { + + # Gain list of bookmarks (line numbers) + set lineNumbers [$bookmarks_lineNumbers get 1.0 end] + if {[llength $lineNumbers] == 0} {return} + + # Get current line in the editor + set curLineNum [$this editor_procedure {} get_current_line_number {}] + + # Find nearest bookmark + set lineNum [lindex $lineNumbers end] + set idx -2 + foreach line $lineNumbers { + incr idx + if {$line >= $curLineNum} { + if {$idx >= 0} { + set lineNum [lindex $lineNumbers $idx] + } + break + } + } + + # Select designated bookmark and jump to its line + rightPanel_bm_select $lineNum + $this editor_procedure {} goto $lineNum + } + + ## Binding for button "Up" (Breakpoints icon bar) - select breakpoint above the current line + # @return void + public method rightPanel_bp_up {} { + + # Gain list of breakpoints (line numbers) + set lineNumbers [$breakpoints_lineNumbers get 1.0 end] + if {[llength $lineNumbers] == 0} {return} + + # Get current line in the editor + set curLineNum [$this editor_procedure {} get_current_line_number {}] + + # Find nearest breakpoint + set lineNum [lindex $lineNumbers end] + set idx -2 + foreach line $lineNumbers { + incr idx + if {$line >= $curLineNum} { + if {$idx >= 0} { + set lineNum [lindex $lineNumbers $idx] + } + break + } + } + + # Select designated breakpoint and jump to its line + rightPanel_bp_select $lineNum + $this editor_procedure {} goto $lineNum + } + + ## Binding for button "Down" (Bookmarks icon bar) - select bookmark below the current line + # @return void + public method rightPanel_bm_down {} { + # Gain list of bookmarks (line numbers) + set lineNumbers [$bookmarks_lineNumbers get 1.0 end] + if {[llength $lineNumbers] == 0} {return} + + # Get current line in the editor + set curLineNum [$this editor_procedure {} get_current_line_number {}] + + # Find nearest bookmark + set lineNum [lindex $lineNumbers 0] + set idx -1 + foreach line $lineNumbers { + incr idx + if {$line > $curLineNum} { + set lineNum [lindex $lineNumbers $idx] + break + } + } + + # Select designated bookmark and jump to its line + rightPanel_bm_select $lineNum + $this editor_procedure {} goto $lineNum + } + + ## Binding for button "Down" (Breakpoints icon bar) - select breakpoint below the current line + # @return void + public method rightPanel_bp_down {} { + # Gain list of breakpoints (line numbers) + set lineNumbers [$breakpoints_lineNumbers get 1.0 end] + if {[llength $lineNumbers] == 0} {return} + + # Get current line in the editor + set curLineNum [$this editor_procedure {} get_current_line_number {}] + + # Find nearest breakpoint + set lineNum [lindex $lineNumbers 0] + set idx -1 + foreach line $lineNumbers { + incr idx + if {$line > $curLineNum} { + set lineNum [lindex $lineNumbers $idx] + break + } + } + + # Select designated breakpoint and jump to its line + rightPanel_bp_select $lineNum + $this editor_procedure {} goto $lineNum + } + + ## Remove all bookmarks from the list + # @return void + public method rightPanel_clear_all_bookmarks {} { + # Enable widgets + $bookmarks_lineNumbers configure -state normal + $bookmarks_text configure -state normal + # Clear text widgets + $bookmarks_lineNumbers delete 1.0 end + adjust_width $bookmarks_lineNumbers + $bookmarks_text delete 1.0 end + # Disable widgets + $bookmarks_lineNumbers configure -state disabled + $bookmarks_text configure -state disabled + + # Reevaluate button states (icon bar) + bm_bp_disEna_buttons + } + + ## Remove all breapoints editor + # @return void + public method rightPanel_clear_all_breakpoints {} { + # Enable widgets + $breakpoints_lineNumbers configure -state normal + $breakpoints_text configure -state normal + # Clear text widgets + $breakpoints_lineNumbers delete 1.0 end + adjust_width $breakpoints_lineNumbers + $breakpoints_text delete 1.0 end + # Disable widgets + $breakpoints_lineNumbers configure -state disabled + $breakpoints_text configure -state disabled + + # Reevaluate button states (icon bar) + bm_bp_disEna_buttons + } + + ## Manage list of bookmarks - some lines have been removed from editor widget + # @parm Int start_line - start of deleted area + # @parm Int end_line - end of deleted area + # @return void + public method rightPanel_remove_bookmarks {start_line end_line} { + + # Gain list of bookmarks + set lineNumbers [$bookmarks_lineNumbers get 1.0 end] + + ## Determinate start and end text indexes (list of bookmarks) + + # Start index + set start_idx {} + set idx 0 + foreach line $lineNumbers { + incr idx + if {$line >= $start_line} { + set start_idx $idx.0 + break + } + } + + # End index + set end_idx {end} + set idx 0 + foreach line $lineNumbers { + incr idx + if {$line > $end_line} { + if {$idx != 0} { + set end_idx $idx.0 + } + break + } + } + + # Default start index + if {$start_idx == {}} { + if {[lindex $lineNumbers end] != $end_line} { + return + } { + set start_idx 1.0 + } + } + + # Determinate number of lines to remove + set diff [expr {$end_line - $start_line + 1}] + + # Enable line numbers + $bookmarks_lineNumbers configure -state normal + # Gain list of lines to recomputation + set lineNumbers [$bookmarks_lineNumbers get $end_idx end] + # Remove lines from line numbers + $bookmarks_lineNumbers delete $start_idx end + if {[llength [$bookmarks_lineNumbers get 1.0 end]] != 0} { + $bookmarks_lineNumbers insert end "\n" + } + # Compute missing lines in line numbers + foreach line $lineNumbers { + $bookmarks_lineNumbers insert end [expr {$line - $diff}] + $bookmarks_lineNumbers insert end "\n" + } + # Finish adjustemnt of line numbers + adjust_width $bookmarks_lineNumbers + $bookmarks_lineNumbers configure -state disabled + + # Remove lines from list of bookmarks + $bookmarks_text configure -state normal + $bookmarks_text delete $start_idx $end_idx + $bookmarks_text configure -state disabled + + # Reevaluate button states (icon bar) + bm_bp_disEna_buttons + } + + ## Manage list of breakpoints - some lines have been removed from editor widget + # @parm Int start_line - start of deleted area + # @parm Int end_line - end of deleted area + # @return void + public method rightPanel_remove_breakpoints {start_line end_line} { + + # Gain list of breakpoints + set lineNumbers [$breakpoints_lineNumbers get 1.0 end] + + ## Determinate start and end text indexes (list of breakpoints) + + # Start index + set start_idx {} + set idx 0 + foreach line $lineNumbers { + incr idx + if {$line >= $start_line} { + set start_idx $idx.0 + break + } + } + + # End index + set end_idx {end} + set idx 0 + foreach line $lineNumbers { + incr idx + if {$line > $end_line} { + if {$idx != 0} { + set end_idx $idx.0 + } + break + } + } + + # Default start index + if {$start_idx == {}} { + if {[lindex $lineNumbers end] != $end_line} { + return + } { + set start_idx 1.0 + } + } + + # Determinate number of lines to remove + set diff [expr {$end_line - $start_line + 1}] + + # Enable line numbers + $breakpoints_lineNumbers configure -state normal + # Gain list of lines to recomputation + set lineNumbers [$breakpoints_lineNumbers get $end_idx end] + # Remove lines from line numbers + $breakpoints_lineNumbers delete $start_idx end + if {[llength [$breakpoints_lineNumbers get 1.0 end]] != 0} { + $breakpoints_lineNumbers insert end "\n" + } + # Compute missing lines in line numbers + foreach line $lineNumbers { + $breakpoints_lineNumbers insert end [expr {$line - $diff}] + $breakpoints_lineNumbers insert end "\n" + } + # Finish adjustemnt of line numbers + adjust_width $breakpoints_lineNumbers + $breakpoints_lineNumbers configure -state disabled + + # Remove lines from list of breakpoints + $breakpoints_text configure -state normal + $breakpoints_text delete $start_idx $end_idx + $breakpoints_text configure -state disabled + + # Reevaluate button states (icon bar) + bm_bp_disEna_buttons + } + + ## Clear the list of symbols + # @return void + public method rightPanel_clear_symbol_list {} { + $sm_lineNumbers configure -state normal + $sm_text configure -state normal + + $sm_lineNumbers delete 0.0 end + $sm_text delete 0.0 end + adjust_width $sm_lineNumbers + + $sm_lineNumbers configure -state disabled + $sm_text configure -state disabled + } + + ## Refresh the list of symbols + # @return void + public method rightPanel_refresh_symbols {} { + rightPanel_clear_symbol_list + + $this editor_procedure {} autocompletion_turned_on {} + $this editor_procedure {} clear_autocompletion_list {} + $this editor_procedure {} comp_win_highlight_all_in_background {} + } + + ## Validator for search entrybox in the list of symbols + # @parm String content - A string to search for + # @parm Widget widget - Search entrybox widget + # @parm Widget clr_b - Clear button + # @return Bool - Success + public method rightPanel_sm_search_validate {content widget clr_b} { + # No recursion ... + if {$search_val_in_progress} {return 0} + set search_val_in_progress 1 + + # Empty string + if {![string length $content]} { + $widget configure -style TEntry + $clr_b configure -state disabled + + set search_val_in_progress 0 + return 1 + + # Not empty string + } { + $clr_b configure -state normal + } + + # Perform the search + set content [string toupper $content] + set e [expr {int([$sm_text index insert])}] + for {set i 1} {$i < $e} {incr i} { + if {![string first $content [string toupper [$sm_text get $i.0 [list $i.0 lineend]]]]} { + $widget configure -style StringFound.TEntry + + $sm_text tag remove curLine 1.0 end + $sm_text tag add curLine [list $i.0 linestart] [list $i.0+1l linestart] + + set block_select 1 + $this editor_procedure {} goto $i + update idle + set block_select 0 + set search_val_in_progress 0 + return 1 + } + } + + $widget configure -style StringNotFound.TEntry + set search_val_in_progress 0 + return 1 + } + + ## Adjust list of symbols + # @parm Int lineNum - Line number + # @parm String symbol_name - Symbol name + # @parm Int symbol_type - + # 0 - Label + # 1 - Constant + # 2 - Something else + # 3 - Macro + # @parm Bool add__remove - 1 == Add; 0 == Remove + # @return void + public method rightPanel_adjust_symbol_list {lineNum symbol_name symbol_type add__remove} { + $sm_lineNumbers configure -state normal + $sm_text configure -state normal + + # Add symbol + if {$add__remove} { + set indexes [$sm_lineNumbers get 1.0 end] + + set idx -1 + set i 0 + foreach line $indexes { + incr i + if {$line > $lineNum} { + set idx $i + break + } + } + + if {$idx == -1} { + set idx [$sm_text index {end-1l}] + } { + append idx {.0} + } + + $sm_lineNumbers insert $idx "$lineNum\n" + $sm_text insert $idx "$symbol_name\n" + + switch -- $symbol_type { + 0 { ;# Label + set tag {tag_label} + } + 1 { ;# Constant + set tag {tag_constant} + } + 2 { ;# C variable + set tag {tag_normal} + } + 3 { ;# Macro + set tag {tag_macro} + } + 7 { ;# C function + set tag {tag_c_func} + } + default { + set tag {} + } + } + + if {$tag != {}} { + $sm_text tag add $tag $idx [list $idx lineend] + } + + # Remove symbol + } { + if {$lineNum == {all}} { + set idx [list] + set e [expr {int([$sm_lineNumbers index end]) - 1}] + for {set i 0} {$i < $e} {incr i} { + lappend idx $i + } + } { + set idx [lsearch -all [$sm_lineNumbers get 1.0 end] $lineNum] + } + + if {$idx == {}} { + return + } + foreach i $idx { + incr i + if {[string equal [$sm_text get $i.0 [list $i.0 lineend]] $symbol_name]} { + $sm_text delete $i.0 $i.0+1l + $sm_lineNumbers delete $i.0 $i.0+1l + break + } + } + } + + adjust_width $sm_lineNumbers + $sm_lineNumbers configure -state disabled + $sm_text configure -state disabled + } + + ## Shift list of symbols by certain number of lines + # @parm Int lineNum - Starting line + # @parm Int length - Number of lines to shift by + # @return void + public method rightPanel_shift_symbols {lineNum length} { + if {![info exists sm_lineNumbers]} {return} + + # Get list of bookmarks + set lineNumbers [$sm_lineNumbers get 1.0 end] + + # Deterinate start index + set start_idx {} + set idx 0 + foreach line $lineNumbers { + incr idx + if {$line >= $lineNum} { + set start_idx $idx.0 + break + } + } + + if {$start_idx == {}} {return} + + # Adjust line numbers + $sm_lineNumbers configure -state normal + set lineNumbers [$sm_lineNumbers get $start_idx end] + $sm_lineNumbers delete $start_idx end + if {[llength [$sm_lineNumbers get 1.0 end]] != 0} { + $sm_lineNumbers insert end "\n" + } + foreach line $lineNumbers { + $sm_lineNumbers insert end [expr {$line + $length}] + $sm_lineNumbers insert end "\n" + } + adjust_width $sm_lineNumbers + $sm_lineNumbers configure -state disabled + } + + ## Manage list of bookmarks - some lines have been added to editor widget + # @parm Int lineNum - line number + # @parm Int length - number of lines + # @return void + public method rightPanel_shift_bookmarks {lineNum length} { + if {![info exists bookmarks_lineNumbers]} {return} + + # Get list of bookmarks + set lineNumbers [$bookmarks_lineNumbers get 1.0 end] + + # Deterinate start index + set start_idx {} + set idx 0 + foreach line $lineNumbers { + incr idx + if {$line >= $lineNum} { + set start_idx $idx.0 + break + } + } + + if {$start_idx == {}} {return} + + # Adjust line numbers + $bookmarks_lineNumbers configure -state normal + set lineNumbers [$bookmarks_lineNumbers get $start_idx end] + $bookmarks_lineNumbers delete $start_idx end + if {[llength [$bookmarks_lineNumbers get 1.0 end]] != 0} { + $bookmarks_lineNumbers insert end "\n" + } + foreach line $lineNumbers { + $bookmarks_lineNumbers insert end [expr {$line + $length}] + $bookmarks_lineNumbers insert end "\n" + } + adjust_width $bookmarks_lineNumbers + $bookmarks_lineNumbers configure -state disabled + } + + ## Manage list of breakpoints - some lines have been added to editor widget + # @parm Int lineNum - line number + # @parm Int length - number of lines + # @return void + public method rightPanel_shift_breakpoints {lineNum length} { + if {![info exists bookmarks_lineNumbers]} {return} + + # Get list of bookmarks + set lineNumbers [$breakpoints_lineNumbers get 1.0 end] + + # Deterinate start index + set start_idx {} + set idx 0 + foreach line $lineNumbers { + incr idx + if {$line >= $lineNum} { + set start_idx $idx.0 + break + } + } + + if {$start_idx == {}} {return} + + # Adjust line numbers + $breakpoints_lineNumbers configure -state normal + set lineNumbers [$breakpoints_lineNumbers get $start_idx end] + $breakpoints_lineNumbers delete $start_idx end + if {[llength [$breakpoints_lineNumbers get 1.0 end]] != 0} { + $breakpoints_lineNumbers insert end "\n" + } + foreach line $lineNumbers { + $breakpoints_lineNumbers insert end [expr {$line + $length}] + $breakpoints_lineNumbers insert end "\n" + } + adjust_width $breakpoints_lineNumbers + $breakpoints_lineNumbers configure -state disabled + } + + ## Invoke right panel configuration dialog + # This function takes any list of arguments + # @return void + public method rightPanel_configure args { + ::configDialogs::rightPanel::mkDialog $args + } + + ## Return true if this panel is in visible state + # @return Bool - result + public method isRightPanelVisible {} {return $PanelVisible} + + ## Get width of the panel + # @return Int - width in pixels + public method getRightPanelSize {} { + if {$PanelVisible} { + return $PanelSize + } { + return $last_PanelSize + } + } + + ## Get ID of currently active page + # @return String - the ID + public method getRightPanelActivePage {} {return $active_page} + + ## Show/Hide this panel + # @return void + public method right_panel_show_hide {} { + # Hide the panel + if {$PanelVisible} { + $parentPane paneconfigure $notebook_frame -minsize 0 + + pack forget $notebook ;# Hide notebook + set last_PanelSize $PanelSize ;# Save current panel width + set PanelSize 60 ;# Change panel width + right_panel_redraw_pane ;# Redraw panel + + # Show button bar + pack $button_bar -anchor nw + # Hide pane sash + $parentPane configure -sashwidth 0 + bind $parentPane <Button> {break} + # Set panel visibility flag + set PanelVisible 0 + + # Show the panel + } { + $parentPane paneconfigure $notebook_frame -minsize 295 + + # Hide button bar + pack forget $button_bar + # Show panel notebook + set PanelSize $last_PanelSize + right_panel_redraw_pane + $notebook raise $active_page + pack $notebook -expand 1 -fill both + # Show pane sash + $parentPane configure -sashwidth 2 + bind $parentPane <Button> {} + # Set panel visibility flag + set PanelVisible 1 + } + } + + ## Change panel active page + # @parm String page - ID of the page to show + # @return void + public method rightPanel_show_up {page} { + if {!$PanelVisible} right_panel_show_hide + $notebook raise $page + } + + ## Set active page but do not show it + # @parm String pageName - ID of the page + # @return void + public method rightPanel_set_active_page {pageName} { + switch -- $active_page { + {Symbols} { + catch { + $this editor_procedure {} comp_win_highlight_all_in_background {} + } + } + {Instruction} { + right_panel_instruction_details_set_enabled 0 + } + } + + set active_page $pageName + + switch -- $active_page { + {Symbols} { + catch { + $this editor_procedure {} comp_win_highlight_all_in_background {} + } + } + {Instruction} { + right_panel_instruction_details_set_enabled $enabled + catch { + $this editor_procedure {} adjust_instruction_details {} + } + } + } + } + + ## Set panel width acording to current sash position + # @return void + public method right_panel_set_size {} { + set PanelSize [lindex [$parentPane sash coord 0] 0] + set PanelSize [expr {${::WIN_GEOMETRY_width} - $PanelSize}] + } + + ## Redraw panel (move pane sash) acorning to current value of $PanelSize + # @return void + public method right_panel_redraw_pane {} { + if {$redraw_pane_in_progress} { + after 50 "$this right_panel_redraw_pane" + return + } + set redraw_pane_in_progress 1 + + update + $parentPane sash place 0 [expr {${::WIN_GEOMETRY_width} - $PanelSize}] 0 + update + + set redraw_pane_in_progress 0 + } + + ## Create text tags inteded for "Instruction details" + # @parm Widget widget - tagret text widget + # @parm List definition_list - List of tags to create ({tag_name fg_color ?bold_or_italic?} ...) + # @parm Bool use_editor_font - Use font family and size from code editor + # @return void + public method right_panel_create_highlighting_tags {widget definition_list use_editor_font} { + if {$use_editor_font == 1} { + set font $fontFamily + set size $fontSize + } elseif {$use_editor_font == -1} { + set font $::DEFAULT_FIXED_FONT + set size -14 + } { + set font $::DEFAULT_FIXED_FONT + set size -12 + } + + # Iterate over tags definition + foreach tag $definition_list { + + # Explicit flag "Bold or Italic" + if {[lindex $tag 2] != {}} { + # Bold font + if {[lindex $tag 2]} { + $widget tag configure [lindex $tag 0] \ + -foreground [lindex $tag 1] \ + -font [font create -size $size \ + -family $font \ + -weight {bold} \ + -slant {roman}] + # Italic font + } { + $widget tag configure [lindex $tag 0] \ + -foreground [lindex $tag 1] \ + -font [font create -size $size \ + -family $font \ + -weight {normal} \ + -slant {italic}] + } + + # No bold, no italic + } { + $widget tag configure [lindex $tag 0] \ + -foreground [lindex $tag 1] \ + -font [font create -size $size \ + -family $font \ + -weight {normal} \ + -slant {roman}] + } + } + } + + ## Enable selections in list of bookmarks and breakpoints and enbale instruction details + # @return void + public method rightPanel_enable {} { + set enabled 1 + $this right_panel_watches_set_enabled $enabled + $this right_panel_instruction_details_set_enabled $enabled + } + + ## Disable selections in list of bookmarks and breakpoints and enbale instruction details + # @return void + public method rightPanel_disable {} { + set enabled 0 + $this right_panel_watches_set_enabled $enabled + $this right_panel_instruction_details_set_enabled $enabled + } +} diff --git a/lib/rightpanel/subprograms.tcl b/lib/rightpanel/subprograms.tcl new file mode 100755 index 0000000..6385266 --- /dev/null +++ b/lib/rightpanel/subprograms.tcl @@ -0,0 +1,704 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 by Martin Ošmera # +# 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. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Provides panel for watching subprogram calls +# -------------------------------------------------------------------------- + +class SubPrograms { + ## COMMON + common fsd_filename {} ;# Filename choosen by FSD + # Main font for the text widget + common main_font [font create \ + -family {helvetica} \ + -size -14 \ + ] + # Bold font for the text widget + common bold_font [font create \ + -family {helvetica} \ + -size -14 -weight {bold} \ + ] + # Font for status bar below the text box + common large_font [font create \ + -family {helvetica} \ + -size -14 \ + ] + # Bold font for status bar below the text box + common large_bold_font [font create \ + -family {helvetica} \ + -size -14 -weight {bold} \ + ] + + ## PRIVATE + private variable parent ;# Widget: parent widget + private variable gui_initialized 0 ;# Bool: GUI initialized + + private variable text_widget ;# Widget: Text widget containg almost all the information + private variable scrollbar ;# Widget: Scrollbar for the text widget + private variable enable_chbut ;# Widget: Check button "Enable" + private variable intr_chbut ;# Widget: Check button "Include interrupts" + private variable total_val_lbl ;# Widget: Label containg the count of subprograms recorded + private variable menu {} ;# Widget: Popup menu for the text widget + private variable enabled 1 ;# Bool: Panel active + private variable ena_intr 1 ;# Bool: Taking interrupts enabled + private variable return_but ;# Widget: Button "RETURN" + private variable save_but ;# Widget: Button "Save" + private variable clear_but ;# Widget: Button "Clear" + private variable count 0 ;# Int: Number of subprograms mentioned in the text widget + private variable menu_source {} ;# String: Auxiliary variable for the popup menu -- Source address + private variable menu_target {} ;# String: Auxiliary variable for the popup menu -- Target address + + constructor {} { + } + + destructor { + if {$gui_initialized} { + menu_Sbar_remove $menu + } + } + + ## Prepare this panel for initialization of its GUI + # MUST BE called before "CreateSubProgramsGUI" + # @parm Widget _parent - Frame where this panel would be created + # @return void + public method PrepareSubPrograms {_parent} { + set parent $_parent + set gui_initialized 0 + load_config $::CONFIG(SUBP_MON_CONFIG) + } + + ## Finalize initialization of this panel + # @return void + public method CreateSubProgramsGUI {} { + create_gui + subprograms_create_tags + create_menus + set_bindings + } + + ## Get configuration list for this panel + # @return void + public method subprograms_get_config {} { + return [list $enabled $ena_intr] + } + + ## Load configuration list for this panel + # @parm List conf - Configuration list + # @return void + private method load_config {conf} { + if {![regexp {^[01] [01]$} $conf]} { + return + } + set enabled [lindex $conf 0] + set ena_intr [lindex $conf 1] + } + + ## Create all widgets which this panel consist of + # @return void + private method create_gui {} { + if {$gui_initialized} {return} + set gui_initialized 1 + + # Create top frame (checkbuttons) + set top_frame [frame $parent.top] + set enable_chbut [checkbutton $top_frame.enable_chbut \ + -text [mc "Enable"] \ + -command "$this subprograms_dis_ena" \ + ] + set intr_chbut [checkbutton $top_frame.intr_chbut \ + -text [mc "Include interrupts"] \ + -command "$this subprograms_intr_yesno" \ + ] + pack $enable_chbut -side left -padx 10 + pack $intr_chbut -side left -padx 10 + + # Adjust check buttons + if {$enabled} { + $enable_chbut select + } { + $enable_chbut deselect + } + if {$ena_intr} { + $intr_chbut select + } { + $intr_chbut deselect + } + + # Create button frame (Buttons: Save, Clear and Return) + set button_frame [frame $parent.button_frame] + set return_but [ttk::button $button_frame.return_but \ + -text [mc "RETURN"] \ + -compound left \ + -image ::ICONS::16::button_cancel \ + -command "$this subprograms_force_return" \ + -state disabled \ + -width 6 \ + ] + set clear_but [ttk::button $button_frame.clear_but \ + -text [mc "Clear"] \ + -style Flat.TButton \ + -compound left \ + -state disabled \ + -image ::ICONS::16::editdelete \ + -command "$this subprograms_clear" \ + -width 5 \ + ] + set save_but [ttk::button $button_frame.filesaveas \ + -text [mc "Save"] \ + -style Flat.TButton \ + -compound left \ + -state disabled \ + -image ::ICONS::16::filesaveas \ + -command "$this subprograms_save" \ + -width 5 \ + ] + pack $save_but -pady 0 -side left + pack $clear_but -pady 0 -side left -padx 5 + pack $return_but -pady 0 -side right + + # Create middle frame (text widget and its scrollbar) + set middle_frame [frame $parent.middle] + set text_widget [text $middle_frame.text \ + -yscrollcommand "$middle_frame.scrollbar set" \ + -bg {#FFFFFF} -width 0 -height 0 \ + -font $main_font -insertontime 0 -wrap none \ + -cursor left_ptr -takefocus 0 \ + -tabstyle wordprocessor \ + ] + set scrollbar [ttk::scrollbar $middle_frame.scrollbar \ + -orient vertical \ + -command "$text_widget yview" \ + ] + pack $text_widget -side left -fill both -expand 1 + pack $scrollbar -side right -fill y -after $text_widget + + # Create bottom frame + set bottom_frame [frame $parent.bottom] + pack [label $bottom_frame.total_lbl \ + -text [mc "TOTAL: "] -font $large_font \ + -fg {#555555} \ + ] -side left + set total_val_lbl [label $bottom_frame.total_val_lbl \ + -font $large_bold_font -text {0} \ + ] + pack $total_val_lbl -side left + + # Pack all main frames + pack $top_frame -fill x + pack $button_frame -fill x + pack $middle_frame -fill both -expand 1 + pack $bottom_frame -fill x -side bottom + } + + ## Set event bindings for the text widget + # @return void + private method set_bindings {} { + foreach event { + <B1-Enter> <B1-Leave> + <B2-Motion> <Button-5> <Button-4> + <MouseWheel> + } { + bind $text_widget $event [bind Text $event] + } + bind $text_widget <Button-1> "$this subprograms_click %x %y" + bind $text_widget <ButtonRelease-3> "$this subprograms_popup %x %y %X %Y" + bindtags $text_widget $text_widget + } + + ## Create popup menu for the text widget + # @return void + private method create_menus {} { + set menu "$text_widget.popup_menu" + if {[winfo exists $menu]} {destroy $menu} + menuFactory { + {command {Go to source line} {} 0 "subprograms_menu_action 0" + {goto} "Navigate code editor to the line from which this subprogram was invoked"} + {command {Go to target line} {} 0 "subprograms_menu_action 1" + {goto} "Navigate code editor to the line from where this subprogram resides"} + {separator} + {command {Copy source address to clipboard} {} 0 "subprograms_menu_action 2" + {editcopy} "Copy return address to clipboard (hexadecimal representation)"} + {command {Copy target address to clipboard} {} 0 "subprograms_menu_action 3" + {editcopy} "Copy address where this subprogram begins to the clipboard"} + {separator} + {command {Remove this} {} 0 "subprograms_menu_action 4" + {editdelete} "Remove this entry"} + } $menu 0 "$this " 0 {} + } + + ## Create highlighting tags for the text widget + # @return void + private method subprograms_create_tags {} { + $text_widget tag configure tag_sel -borderwidth 1 -relief raised + $text_widget tag configure tag_from -foreground {#00AA00} + $text_widget tag configure tag_to -foreground {#0000AA} + $text_widget tag configure tag_ins -font $bold_font + $text_widget tag configure tag_first -background {#DDDDDD} + } + + ## Toggle state enabled for whole panel + # @return void + public method subprograms_dis_ena {} { + set enabled [expr {!$enabled}] + if {$enabled} subprograms_clear + } + + ## Toggle flag "Enable interrupts" + # @return void + public method subprograms_intr_yesno {} { + set ena_intr [expr {!$ena_intr}] + } + + ## Event handler for the text widget: <Button-1> + # @parm Int x - Relative pointer position + # @parm Int y - Relative pointer position + # @return void + public method subprograms_click {x y} { + set menu_source {} + set menu_target {} + $text_widget configure -state normal + + # Remove selection and determinate line number + $text_widget tag remove tag_sel 1.0 end + set line [expr {int([$text_widget index @$x,$y])}] + + # Adjust selection + if {$line % 3} { + set line [expr {($line / 3) * 3}] + if {($line / 3) < $count} { + # Set selection + incr line + $text_widget tag add tag_sel $line.0 [expr {$line+2}].0 + + # Determinate source address of the selected subprogram + regexp {\w+\s*$} [$text_widget get \ + $line.0 [list $line.0 lineend] \ + ] menu_target + set menu_target [string trimright $menu_target { h}] + if {![string is xdigit $menu_target]} { + set menu_target {} + } + + # Determinate target address of the selected subprogram + regexp {\w+\s*$} [$text_widget get \ + [expr {$line + 1}].0 \ + [list [expr {$line + 1}].0 lineend] \ + ] menu_source + set menu_source [string trimright $menu_source { h}] + if {![string is xdigit $menu_source]} { + set menu_source {} + } + } + } + + # Disable the text widget again + $text_widget configure -state disabled + } + + ## Perform certain menu action (popup menu for the text widget) + # @parm Int action - ID of action to execute + # @return void + public method subprograms_menu_action {action} { + switch -- $action { + 0 { ;# Action: "Go to source line" + if {$menu_source != {}} { + goto_line [expr {"0x$menu_source" - 1}] + } + } + 1 { ;# Action: "Go to target line" + if {$menu_target != {}} { + goto_line [expr "0x$menu_target"] + } + } + 2 { ;# Action: "Copy source address to clipboard" + clipboard clear + clipboard append $menu_source + } + 3 { ;# Action: "Copy target address to clipboard" + clipboard clear + clipboard append $menu_target + } + 4 { ;# Remove this entry + if {[llength [$text_widget tag nextrange tag_sel 1.0]]} { + $text_widget configure -state normal + $text_widget delete tag_sel.first tag_sel.last+1l + $text_widget configure -state disabled + } + } + } + } + + ## Action: "Go to source line" / "Go to target line" + # @parm Int address - Address in code memory + # @return void + private method goto_line {address} { + # Resolve line number and source address + set line [$this simulator_address2line $address] + set address [$this simulator_line2address [lindex $line 0] [lindex $line 1]] + + # Line resolved + if {$line != {}} { + # Simulator is running + if {[$this is_frozen]} { + $this setPC $address + $this Simulator_sync_PC_etc + $this move_simulator_line $line + # Simulator is not running + } { + set filename [$this simulator_get_filename [lindex $line 1]] + set filename [file tail $filename] + if {[$this fucus_specific_editor $filename 0]} { + $this editor_procedure {} goto [lindex $line 0] + } + } + # Line unresolved + } { + tk_messageBox \ + -parent . \ + -title [mc "Line not found"] \ + -message [mc "There is no matching line in the source code"] + } + } + + ## Invoke popup menu for the text widget + # @parm Int x - Relative position of mouse pointer + # @parm Int y - Relative position of mouse pointer + # @parm Int X - Absolute position of mouse pointer + # @parm Int Y - Absolute position of mouse pointer + # @return void + public method subprograms_popup {x y X Y} { + # Adjust selection + subprograms_click $x $y + + # Determinate line and what to do with the menu + set line [expr {int([$text_widget index @$x,$y])}] + if {$line % 3} { + set line [expr {$line / 3}] + if {$line >= $count} { + set state {disabled} + } { + set state {normal} + } + } { + set state {disabled} + } + + # Adjust states of certain items in the menu + foreach entry { + {Go to source line} + {Go to target line} + {Copy source address to clipboard} + {Copy target address to clipboard} + {Remove this} + } { + $menu entryconfigure [::mc $entry] -state $state + } + + # Invoke the menu + tk_popup $menu $X $Y + } + + ## Register subprogram call + # @parm Int type - Invoked by: 0 == LCALL; 1 == ACALL; 2 == Interrupt; 3 == LCALL or ACALL + # @parm Int from - Source address (return address) + # @parm Int to - Target address + # @return void + public method subprograms_call {type from to} { + if {!$enabled} {return} + if {!$gui_initialized} CreateSubProgramsGUI + + # Determinate string to print as an instruction + switch -- $type { + 0 {set ins " LCALL\t"} + 1 {set ins " ACALL\t"} + 2 { + set ins " Interrupt\t" + if {!$ena_intr} { + return + } + } + 3 {set ins " CALL\t"} + } + + # Convert value of source address to hexadecimal representation + if {$from < 0} { + set from {-----} + } { + set from [format %X $from] + set len [string length $from] + if {$len < 4} { + set from "[string repeat {0} [expr {4 - $len}]]$from" + } + append from {h} + } + + # Convert value of target address to hexadecimal representation + if {$to < 0} { + set to {-----} + } { + set to [format %X $to] + set len [string length $to] + if {$len < 4} { + set to "[string repeat {0} [expr {4 - $len}]]$to" + } + append to {h} + } + + # Enable the text widget + $text_widget configure -state normal + + # Insert separator + if {$count} { + $text_widget insert 1.0 "\n" + } + + # Print return address + $text_widget insert 1.0 "\n" + $text_widget insert 1.0 [mc " Return address:\t"] + set idx [$text_widget index {1.0 lineend}] + $text_widget insert {1.0 lineend} $from + $text_widget tag add tag_from $idx {1.0 lineend} + + # Print type and target address + $text_widget insert 1.0 "\n" + $text_widget insert 1.0 "$ins\t" + $text_widget tag add tag_ins 1.0 {1.0 lineend} + set idx [$text_widget index {1.0 lineend}] + $text_widget insert {1.0 lineend} $to + $text_widget tag add tag_to $idx {1.0 lineend} + + $text_widget tag remove tag_first 1.0 end + $text_widget tag add tag_first 1.0 3.0 + + # Disable the text widget, adjust button bar, labels on the bottom + $text_widget configure -state disabled + incr count + $total_val_lbl configure -text $count + disena_buttonbar $count + } + + ## Disable or enable buttons on the button bar + # @parm Bool bool - 1 == enable; 0 == diable + # @return void + private method disena_buttonbar {bool} { + if {$bool} { + set state {normal} + } { + set state {disabled} + } + $return_but configure -state $state + $clear_but configure -state $state + $save_but configure -state $state + } + + ## Register return for subprogram + # @parm Bool intr__sub - 0 == Common subprogram; 1== Interrupt + # @return void + public method subprograms_return {intr__sub} { + if {!$enabled} {return} + if {!$count} {return} + if {$intr__sub && !$ena_intr} {return} + if {!$gui_initialized} CreateSubProgramsGUI + + $text_widget configure -state normal + $text_widget delete 1.0 4.0 + $text_widget configure -state disabled + incr count -1 + if {$count} { + $text_widget tag remove tag_first 1.0 end + $text_widget tag add tag_first 1.0 3.0 + } + $total_val_lbl configure -text $count + disena_buttonbar $count + } + + ## Clear the text widget + # @return void + public method subprograms_clear {} { + if {!$gui_initialized} {return} + set count 0 + $total_val_lbl configure -text 0 + $text_widget configure -state normal + $text_widget delete 1.0 end + $text_widget configure -state disabled + disena_buttonbar 0 + } + + ## Enable or disable this panel + # @parm Bool bool - 1 == Enable; 0 == Disbale + # @return void + public method subprograms_setEnabled {bool} { + if {!$gui_initialized} {return} + if {!$bool} { + $return_but configure -state disabled + } + } + + ## Force return from active subprogram (the topmost entry) + # Binding for button "RETURN" on the button bar + # @return void + public method subprograms_force_return {} { + if {![regexp {^\s*\w+} [$text_widget get 1.0 3.0] word]} { + return + } + set word [string trim $word] + if {$word == {Interrupt}} { + set word 1 + } { + set word 0 + } + $this simulator_return_from_SP $word + } + + ## Invoke file selection dialog to save file + # Binding for button "Save" on the button bar + # @return void + public method subprograms_save {} { + + # Invoke the dialog + catch {delete object fsd} + KIFSD::FSD fsd \ + -title [mc "Save file - MCU 8051 IDE"] \ + -directory [$this cget -projectPath] \ + -defaultmask 0 -multiple 0 -filetypes { + {{Plain text} {*.txt} } + {{All files} {*} } + } + + # Ok button + fsd setokcmd { + set fsd_filename [::SubPrograms::fsd get] + if {!$::MICROSOFT_WINDOWS} { ;# POSIX way + if {![regexp "^(~|/)" $fsd_filename]} { + set filename "[${::X::actualProject} cget -ProjectDir]/$fsd_filename" + } + } { ;# Microsoft windows way + if {![regexp "^\w:" $fsd_filename]} { + set filename [file join [${::X::actualProject} cget -ProjectDir] $fsd_filename] + } + } + + set ::SubPrograms::fsd_filename [file normalize $fsd_filename] + } + + # Activate the dialog + fsd activate + if {$fsd_filename != {}} { + subprograms_save_proc $fsd_filename + } + } + + ## Save content of the text widget under certain filename + # @parm String filename - Target filename + # @return void + public method subprograms_save_proc {filename} { + # Adjust file extension + if {[file extension [file tail $filename]] != {.txt}} { + append filename {.txt} + } + # Make backup copy of the file + if {[file exists $filename] && [file isfile $filename]} { + # Ask user for overwrite existing file + if {[tk_messageBox \ + -type yesno \ + -icon question \ + -parent . \ + -title [mc "Overwrite file"] \ + -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $filename]] + ] != {yes} + } { + return + } + # Create a backup file + catch { + file rename -force $filename "$filename~" + } + } + # Try to open the file + if {[catch { + set file [open $filename w 420] + }]} { + tk_messageBox \ + -parent . \ + -icon warning \ + -type ok \ + -title [mc "Permission denied"] \ + -message [mc "Unable to write to file:\n\"%s\"" $filename] + return + } + # Write content of the text widget into the file and close the file + puts -nonewline $file [$text_widget get 1.0 end] + close $file + } + + ## Get number of recorder active subprograms + # @return Int - Count + public method subprograms_get_count {} { + if {!$gui_initialized} {return 0} + return $count + } + + ## Get content for purpose of program hibernation + # @return String - Text + public method subprograms_get_formated_content {} { + if {!$gui_initialized} {return {}} + set result {} + set source {} + set target {} + set type {} + set line_num 0 + + foreach line [split [$text_widget get 1.0 end] "\n"] { + if {$line == {}} { + if {$source != {} && $target != {} && $type != {}} { + lappend result [list $source $target $type] + } + set line 0 + set source {} + set target {} + set type {} + continue + } + if {$line_num} { + regexp {\w+\s*$} $line source + set source [string range $source 0 3] + set source [expr "0x$source"] + } { + regexp {\w+\s*$} $line target + set target [string range $target 0 3] + set target [expr "0x$target"] + + regexp {^\s*\w+} $line type + switch -- [string trim $type] { + {LCALL} {set type 0} + {ACALL} {set type 1} + {Interrupt} {set type 2} + {CALL} {set type 3} + } + } + incr line_num + } + return $result + } +} |