summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAndrej Shadura <andrewsh@debian.org>2018-05-08 15:59:29 +0200
committerAndrej Shadura <andrewsh@debian.org>2018-05-08 15:59:29 +0200
commit5b8466f7fae0e071c0f4eda13051c93313910028 (patch)
tree7061957f770e5e245ba00666dad912a2d44e7fdc /lib
Import Upstream version 1.3.7
Diffstat (limited to 'lib')
-rwxr-xr-xlib/X.tcl10648
-rwxr-xr-xlib/bottompanel/bottomnotebook.tcl469
-rwxr-xr-xlib/bottompanel/calculator.tcl2071
-rwxr-xr-xlib/bottompanel/cvarsview.tcl1303
-rwxr-xr-xlib/bottompanel/find_in_files.tcl750
-rwxr-xr-xlib/bottompanel/graph.tcl714
-rwxr-xr-xlib/bottompanel/graph_wdg.tcl1115
-rwxr-xr-xlib/bottompanel/messages.tcl632
-rwxr-xr-xlib/bottompanel/terminal.tcl135
-rwxr-xr-xlib/bottompanel/todo.tcl1496
-rwxr-xr-xlib/cli.tcl725
-rwxr-xr-xlib/compiler/assembler.tcl595
-rwxr-xr-xlib/compiler/codelisting.tcl1169
-rwxr-xr-xlib/compiler/compiler.tcl557
-rwxr-xr-xlib/compiler/compilerconsts.tcl873
-rwxr-xr-xlib/compiler/disassembler.tcl664
-rwxr-xr-xlib/compiler/external_compiler.tcl1076
-rwxr-xr-xlib/compiler/preprocessor.tcl5184
-rwxr-xr-xlib/configdialogs/compiler_config.tcl1875
-rwxr-xr-xlib/configdialogs/configdialogs.tcl51
-rwxr-xr-xlib/configdialogs/custom_commands_config.tcl418
-rwxr-xr-xlib/configdialogs/editor_config.tcl2148
-rwxr-xr-xlib/configdialogs/global_config.tcl318
-rwxr-xr-xlib/configdialogs/rightpanel_config.tcl498
-rwxr-xr-xlib/configdialogs/shortcuts_config.tcl1015
-rwxr-xr-xlib/configdialogs/simulator_config.tcl423
-rwxr-xr-xlib/configdialogs/terminal_config.tcl374
-rwxr-xr-xlib/configdialogs/toolbar_config.tcl706
-rwxr-xr-xlib/custom_command.tcl98
-rwxr-xr-xlib/dialogs/errorhandler.tcl172
-rwxr-xr-xlib/dialogs/fsd.tcl2775
-rwxr-xr-xlib/dialogs/my_tk_messageBox.tcl283
-rwxr-xr-xlib/dialogs/selectmcu.tcl1537
-rwxr-xr-xlib/dialogs/tips.tcl375
-rwxr-xr-xlib/editor/ASMsyntaxhighlight.tcl1675
-rwxr-xr-xlib/editor/Csyntaxhighlight.tcl853
-rwxr-xr-xlib/editor/LSTsyntaxhighlight.tcl443
-rwxr-xr-xlib/editor/R_ASMsyntaxhighlight.tcl1232
-rwxr-xr-xlib/editor/autocompletion.tcl838
-rwxr-xr-xlib/editor/commandline.tcl1275
-rwxr-xr-xlib/editor/editor.tcl2786
-rwxr-xr-xlib/editor/eventhandlers.tcl781
-rwxr-xr-xlib/editor/exports.tcl486
-rwxr-xr-xlib/editor/generalproc.tcl2288
-rwxr-xr-xlib/environment.tcl3184
-rwxr-xr-xlib/external_command.tcl143
-rwxr-xr-xlib/leftpanel/filelist.tcl4824
-rwxr-xr-xlib/leftpanel/fsbrowser.tcl1164
-rwxr-xr-xlib/leftpanel/sfrwatches.tcl620
-rwxr-xr-xlib/lib/Math.tcl954
-rwxr-xr-xlib/lib/hexeditor.tcl2705
-rwxr-xr-xlib/lib/ihextools.tcl523
-rwxr-xr-xlib/lib/innerwindow.tcl360
-rwxr-xr-xlib/lib/settings.tcl293
-rwxr-xr-xlib/main.tcl699
-rwxr-xr-xlib/maintab.tcl425
-rwxr-xr-xlib/pale/leddisplay.tcl707
-rwxr-xr-xlib/pale/ledmatrix.tcl982
-rwxr-xr-xlib/pale/ledpanel.tcl543
-rwxr-xr-xlib/pale/matrixkeypad.tcl889
-rwxr-xr-xlib/pale/multiplexedleddisplay.tcl1179
-rwxr-xr-xlib/pale/pale.tcl991
-rwxr-xr-xlib/pale/simplekeypad.tcl670
-rwxr-xr-xlib/pale/virtual_hw_component.tcl423
-rwxr-xr-xlib/project.tcl868
-rwxr-xr-xlib/rightpanel/hwmanager.tcl419
-rwxr-xr-xlib/rightpanel/instructiondetails.tcl1755
-rwxr-xr-xlib/rightpanel/regwatches.tcl2120
-rwxr-xr-xlib/rightpanel/rightpanel.tcl2273
-rwxr-xr-xlib/rightpanel/subprograms.tcl704
-rwxr-xr-xlib/simulator/bitmap.tcl510
-rwxr-xr-xlib/simulator/engine/engine_auxiliary_alo_functions.tcl171
-rwxr-xr-xlib/simulator/engine/engine_backward_stepping.tcl126
-rwxr-xr-xlib/simulator/engine/engine_control.tcl759
-rwxr-xr-xlib/simulator/engine/engine_core.tcl274
-rwxr-xr-xlib/simulator/engine/engine_external_interface_management.tcl1115
-rwxr-xr-xlib/simulator/engine/engine_hibernation.tcl205
-rwxr-xr-xlib/simulator/engine/engine_initialization_cleanup.tcl340
-rwxr-xr-xlib/simulator/engine/engine_instructions.tcl1596
-rwxr-xr-xlib/simulator/engine/engine_mcu_configuration.tcl555
-rwxr-xr-xlib/simulator/engine/engine_memory_management.tcl387
-rwxr-xr-xlib/simulator/engine/engine_opcodes.tcl435
-rwxr-xr-xlib/simulator/engine/engine_virtual_hw_controller.tcl1413
-rwxr-xr-xlib/simulator/hibernate.tcl1051
-rwxr-xr-xlib/simulator/interruptmonitor.tcl1246
-rwxr-xr-xlib/simulator/sfrmap.tcl523
-rwxr-xr-xlib/simulator/simulator.tcl1202
-rwxr-xr-xlib/simulator/simulator_gui.tcl3986
-rwxr-xr-xlib/simulator/stackmonitor.tcl519
-rwxr-xr-xlib/simulator/stopwatch.tcl702
-rwxr-xr-xlib/simulator/virtual_uart_term.tcl646
-rwxr-xr-xlib/utilities/asciichart.tcl752
-rwxr-xr-xlib/utilities/baseconvertor.tcl912
-rwxr-xr-xlib/utilities/eightsegment.tcl509
-rwxr-xr-xlib/utilities/hexeditdlg.tcl1793
-rwxr-xr-xlib/utilities/notes.tcl896
-rwxr-xr-xlib/utilities/rs232debugger.tcl1460
-rwxr-xr-xlib/utilities/speccalc.tcl2390
-rwxr-xr-xlib/utilities/symbol_viewer.tcl837
99 files changed, 113626 insertions, 0 deletions
diff --git a/lib/X.tcl b/lib/X.tcl
new file mode 100755
index 0000000..0875d3d
--- /dev/null
+++ b/lib/X.tcl
@@ -0,0 +1,10648 @@
+#!/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 various dialogs and various variables for various things"
+# For instance the "Go to" dialog is placed here
+# --------------------------------------------------------------------------
+
+# Dialog for selecting MCU and loading MCU details from definition file
+source "${::LIB_DIRNAME}/dialogs/selectmcu.tcl"
+
+namespace eval X {
+
+ ## General
+ variable unsaved_projects {} ;# List: List of project object marked as "unsaved"
+ variable critical_procedure_in_progress 1 ;# Bool: Disable critical procedures (like compilation, start simulator, etc.)
+ variable foo_procedure_in_progress 0 ;# Bool: Disables some non-critical procedures
+ variable last_WIN_GEOMETRY {} ;# Last window geometry (main window)
+ variable actualProject {} ;# Object: Current project
+ variable openedProjects {} ;# List of opened projects (Object references)
+ variable actualProjectIdx -1 ;# Index of the current project in $openedProjects
+ variable project_menu_locked 1 ;# Bool: Indicates than there is at least one opened project
+ if {!$::MICROSOFT_WINDOWS} {
+ variable defaultDirectory ${::env(HOME)} ;# Default directory
+ } {
+ variable defaultDirectory ${::env(USERPROFILE)} ;# Default directory
+ }
+ variable simulator_enabled {} ;# List of booleans: Simulator engaged
+ variable editor_lines ;# Number of lines in the current editor
+ variable fsd_result {} ;# Value returnded by file selection dialog (in some cases)
+ variable projectmenu {.project_menu} ;# ID of Popup menu for project tabs
+ variable projectmenu_project {} ;# Object: project selected by project popup menu
+ variable selectedView ;# Int: Selected editor by editor statusbar popup menu
+ variable open_f_external_editor 0 ;# Bool: Use procedure __open to open new file for embedded external editor
+ variable file_recent_files {} ;# List: recently opened files
+ variable project_recent_files {} ;# List: recently opened projects
+ variable vhw_recent_files {} ;# List: recently opened Virtual HW files
+ # List of supported processors
+ variable avaliable_processors [::SelectMCU::get_avaliable_processors]
+ variable procedure_exit_in_progress 0 ;# Bool: proc "__exit" in progress
+
+ ## Doxygen
+ variable doxygen_run_doxywizard 0 ;# Bool: Run doxywizard
+ variable doxygen_build_api_doc 0 ;# Bool: Build API documentation
+ variable doxygen_pid 0 ;# Int: Doxygen PID
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+
+ ## ASCII chart
+ variable ascii_chart_win_object {} ;# Object: ASCII chart window object
+
+ ## 8-segment LED editor
+ variable eightsegment_editors {} ;# List: All 8-segment LED display editors invoked
+
+ ## Base convertor
+ variable base_convertors {} ;# List: All base convertor objects
+
+ ## Special calculator
+ variable spec_calc_objects {} ;# List: All special calculator objects
+
+ ## UART/RS232 debugger
+ variable rs232debugger_objects {} ;# List: All "RS232 debugger" objects
+
+ ## Dialog "Go to"
+ variable goto ;# Line where to go
+
+ ## Function "Auto-indent"
+ variable reformat_code_abort ;# Bool: Abort function 'reformat_code'
+
+ ## Dialog "Find"
+ variable find_String ;# Search string
+ variable find_forward_index ;# Search index for forward search
+ variable find_backward_index ;# Search index for backward search
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_notCS ;# Bool: Case insensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable find_allow_selection ;# Bool: There is some selected text in editor
+ variable find_retry_search ;# Bool: Search restarted from begining/end
+ variable find_back_dir ;# Bool: Search backwards (real option)
+ variable find_history {} ;# List of the last 10 search strings
+ variable find_next_prev_in_P 0 ;# Bool: Procedure 'find_next_prev' in progress
+
+ ## Dialog "Replace"
+ variable replace_String ;# String to replace
+ variable replace_Replacement ;# Replacement for the search string
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_prompt ;# Bool: Prompt on replace
+ variable replace_prompt_opened 0 ;# Bool: Replace prompt dialog opened
+ variable replace_prompt_return_value ;# Replace prompt dialog return value
+ variable replace_prompt_geometry ;# Geometry of replace prompt dialog window
+ variable replace_search_history {} ;# List of the last 10 search strings
+ variable replace_repl_history {} ;# List of the last 10 replacement strings
+
+ ## Dialog "Select directory"
+ variable select_directory_var {} ;# Selected directory
+
+ ## Dialog "New project"
+ variable project_new_name ;# Name of the new project
+ variable project_new_dir ;# Directory of the new project
+
+ ## Variable common for "New project" and "Edit project"
+ variable project_new_processor ;# Processor type (e.g. "8051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable project_new_max_xcode ;# Int: Maximum valid value of external program memory
+ variable project_new_xd_chb ;# Widget: XDATA enable checkbutton
+ variable project_new_xd_scl ;# Widget: XDATA scale
+ variable project_new_xd_spb ;# Widget: XDATA spinbox
+ variable project_new_xc_chb ;# Widget: XCODE enable checkbutton
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ ## Dialog "Edit project"
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_authors ;# Project authors
+ variable project_edit_description ;# Project description
+ variable project_edit_clock ;# Default clock rate
+ variable project_edit_main_file ;# Project main file
+ variable project_edit_main_file_clr_but ;# Widget: Project main file clear button
+ # Some default project values
+ # format: {{variable value} {variable value} ...}
+ variable project_edit_defaults {
+ {project_edit_family 8051 }
+ {project_edit_clock 12000 }
+ {project_edit_calc_rad Dec }
+ {project_edit_calc_ang rad }
+ }
+
+ ## Functions related to project management (save, load)
+ variable project_watches_file ;# File of register watches of the current poject
+ variable project_todo ;# Todo text
+ variable project_graph ;# Graph configuration list
+ variable project_calculator ;# Calculator list (display contents, etc.)
+ variable project_other_options ;# Other project options
+ variable project_compiler_options ;# Compiler options
+ variable project_files ;# List of project files (special format)
+ variable project_file ;# Full name of the project file
+ variable project_dir ;# Path to project directory
+
+ ## Compilation related variables
+ variable compilation_success_callback {} ;# String: Indented for HW plugins
+ variable compilation_fail_callback {} ;# String: Indented for HW plugins
+ variable compilation_mess_project {} ;# Object: Project related to running compilation
+ variable compilation_successfull 1 ;# Bool: Compilation successfull
+ variable compilation_in_progress 0 ;# Bool: Compiler engaged
+ variable compilation_progress 0 ;# Variable for compilation progressbar
+ variable compiler_pid 0 ;# Int: PID of external compiler if used
+ variable compilation_start_simulator 0 ;# Bool: Start simulator after successful compilation
+ variable compile_this_file_only 0 ;# Bool: Compile the current file only
+
+ ## Dialog "Select input/uotput file"
+ variable input_file ;# Input file
+ variable output_file ;# Output file
+ variable IO ;# Bool: 1 == choose input file; 0 == choose output file
+
+ ### Dialogs "Hex->Bin; Bin->Hex; Sim->Hex; Sim->Bin; Nomalize Hex"
+ # Type of conversion
+ # 0 == Bin -> Hex
+ # 1 == Hex -> Bin
+ # 2 == Sim -> Hex
+ # 3 == Sim -> Bin
+ variable hex__bin
+
+ ## XDATA/CODE/ERAM/EEPROM/UNI memory hexadecimal editors
+ variable opended_code_mem_windows {} ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects {} ;# List of CODE memory hex editor objects
+ variable opended_xdata_mem_windows {} ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects {} ;# List of XDATA memory hex editor objects
+ variable opended_eram_windows {} ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects {} ;# List of ERAM hex editor objects
+ variable opended_eeprom_mem_windows {} ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects {} ;# List of data EEPROM hex editor objects
+ variable opended_eeprom_wr_bf_windows {} ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects {} ;# List of data EEPROM write buffer hex editor objects
+ variable eeprom_wr_buf_counter 0 ;# Counter of EEPROM write buffer hex editor objects
+ variable saving_progress 0 ;# Variable for progressbars representing saving progress
+ variable abort_saving 0 ;# Bool: Abort saving of IHEX8 file
+ variable independent_hexeditor_count 0 ;# Counter of intances of independent hexadecimal editor
+
+ # Path to file defining the last session
+ variable session_file "${::CONFIG_DIR}/last_session.conf"
+
+ ## Dialog "Cleanup project folder"
+ # GLOB patterns in certain order !
+ variable cleanup_masks {
+ *.asm~ *.lst~ *.sim~ *.hex~
+ *.bin~ *.html~ *.tex~ *.wtc~
+ *.mcu8051ide~ *.m5ihib~ *.cdb~ *.ihx~
+ *.adf~ *.omf~ *.map~ *.c~
+ *.h~ *.vhc~ *.vhw~ *.txt~
+ *~
+
+ *.lst *.sim *.hex *.bin *.html *.tex *.m5ihib
+ *.noi *.obj *.map *.p *.mac *.i *.ihx
+ *.adf *.adb *.rel *.cdb *.mem *.lnk *.sym
+ *.omf *.rst *.hashes *bak
+ }
+
+ ## Dialog "Change letter case"
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ ## Dialog "Line to address"
+ variable line2pc ;# Int: Selected line in source code
+ variable line2pc_jump 1 ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable line2pc_line_max ;# Int: Number of lines in the source code
+ variable line2pc_value_lbl ;# Widget: Label containing PC value
+ variable line2pc_new_value ;# Int: Resolved address or {}
+ variable line2pc_org_line ;# Int: Original line
+ variable line2pc_ok_button ;# Widget: Button "OK"
+ variable line2pc_file_number ;# Int: File number
+
+ ## Dialog "File statistics"
+ variable statistics_counter 0 ;# Int: Counter of invocations of this dialog
+
+ ## Project details window
+ variable PROJECTDETAILSWIN ;# ID of project details window
+ variable projectdetails_last_project {} ;# Project object of the last project details window
+
+ ## Cutom commands related variables
+ variable custom_cmd_dialog_index 0 ;# Index of results dialog (to keep win IDs unique)
+ variable custom_command_cmd ;# Array of custom commands (shell scripts)
+ variable custom_command_options ;# Array of Lists of custom command options
+ variable custom_command_desc ;# Array of custom command descriptions
+ variable custom_command_PID ;# Array of custom command PIDs (Process IDentifiers)
+ variable custom_command_NUM ;# Array of custom command numbers
+ variable custom_command_counter 0 ;# Counter of custom command invocations
+
+ ## Initialize custom commands related variables
+ # Shell scripts
+ set custom_command_cmd(0) [mc "echo \"This is a custom command\"\necho \"\tYou can configure it in Main menu->Configure->Edit user commands.\"\necho \"\tCustom commands are intended for running external programs from this IDE (e.g. program uploaders)\""]
+ append custom_command_cmd(0) "\n\necho \"\nThis is a custom command\"\necho \"\tYou can configure it in Main menu->Configure->Edit user commands.\"\necho \"\tCustom commands are intended for running external programs from this IDE (e.g. program uploaders)\""
+ set custom_command_cmd(1) $custom_command_cmd(0)
+ set custom_command_cmd(2) $custom_command_cmd(0)
+ # Command options
+ set custom_command_options(0) {0 1 0}
+ set custom_command_options(1) $custom_command_options(0)
+ set custom_command_options(2) $custom_command_options(0)
+ # Command descritpions
+ set custom_command_desc(0) [mc "More: Main menu -> Configure -> Edit user commands"]
+ set custom_command_desc(1) $custom_command_desc(0)
+ set custom_command_desc(2) $custom_command_desc(0)
+ # Command Thread IDentifiers
+ set custom_command_PID(0) {}
+ set custom_command_PID(1) $custom_command_PID(0)
+ set custom_command_PID(2) $custom_command_PID(0)
+ # Custom command numbers
+ set custom_command_NUM(0) {}
+ set custom_command_NUM(1) $custom_command_NUM(0)
+ set custom_command_NUM(2) $custom_command_NUM(0)
+
+ ## Menu and Toolbar related variables
+ # Menu bar items which require opened project
+ variable mainmenu_project_dependent_buttons {
+ { ".mainMenu"
+ { "Edit" "View" "Simulator" "Virtual MCU" "Virtual HW" "Tools"}
+ } { ".mainMenu.project"
+ { "Save" "Edit project" "Close without saving" "Save and close"}
+ } { ".mainMenu.file"
+ { "New" "Open" "Open recent" "Save" "Save as" "Save all" "Close" "Close all" "File statistics"}
+ } { ".mainMenu.configure"
+ { "Configure Compiler"}
+ }
+ }
+ # Menu bar items which require ENGAGED simulator
+ variable mainmenu_simulator_engaged {
+ { ".mainMenu.simulator"
+ { "Step" "Step over" "Animate" "Run"
+ "Jump to line" "Find cursor" "Step back" "Clear highlight"
+ "Hiberante program" "Resume hibernated program"
+ }
+ } { ".mainMenu.virtual_mcu"
+ { "Reset" }
+ }
+ }
+ # Menu bar items which require DISENGAGED simulator
+ variable mainmenu_simulator_disengaged {
+ { ".mainMenu.file"
+ { "New" "Open" "Close" "Close all"}
+ } { ".mainMenu.edit"
+ { "Undo" "Redo" "Cut" "Paste" "Replace"
+ "Comment" "Uncomment" "Indent" "Unindent"}
+ } { ".mainMenu.display"
+ { "Read only mode" "Reload"}
+ }
+ { ".mainMenu.simulator"
+ { "Debug this file only" }
+ } { ".mainMenu.tools"
+ { "Compile" "Disassemble" "Encoding" "End of line"
+ "Auto indent" "Change letter case" "Document current function"
+ "Compile this file"}
+ }
+ }
+ # Menu bar items which are not avaliable when editor is in read only mode
+ variable mainmenu_editor_readonly {
+ { ".mainMenu.edit"
+ { "Undo" "Redo" "Cut" "Paste" "Replace"
+ "Comment" "Uncomment" "Indent" "Unindent"}
+ } { ".mainMenu.tools"
+ { "Auto indent" "Change letter case" "Document current function"}
+ }
+ }
+ # Menu bar items which are not avaliable only for C language
+ variable mainmenu_editor_c_only {
+ { ".mainMenu.tools"
+ { "Document current function"}
+ }
+ }
+ # Menu bar items which are not avaliable when external embedded editor is used
+ variable mainmenu_editor_external_na {
+ {.mainMenu.tools {
+ {Encoding} {End of line}
+ {Auto indent} {Change letter case}
+ {Export as XHTML} {Export as LaTeX}
+ {Auto indent} {Change letter case}
+ {Document current function}
+ }
+ } {.mainMenu.file {
+ {Save} {Save as}
+ {Save all} {File statistics}
+ }
+ } {.mainMenu.display {
+ {Read only mode} {Switch to command line}
+ {Highlight} {Show/Hide line numbers}
+ {Reload} {Show/Hide icon border}
+ }
+ } {.mainMenu.simulator {
+ {Find cursor} {Jump to line}
+ }
+ } {.mainMenu {
+ {Edit}
+ }
+ }
+ }
+
+ # Toolbar buttons which require opened project
+ variable toolbar_project_dependent_buttons {
+ new open save save_as save_all close close_all undo redo cut
+ copy paste find findnext findprev replace goto reload clear
+ proj_save proj_edit proj_close proj_close_imm show_code_mem
+ show_ext_mem start_sim reset step stepover animate run
+ assemble disasm reformat_code toHTML toLaTeX cleanup custom0
+ custom1 custom2 change_case forward back clear_hg intrmon
+ hibernate resume stepback find_sim_cur line2addr show_exp_mem
+ sfrmap show_eeprom show_eem_wr_b stopwatch bitmap
+
+ ledpanel leddisplay ledmatrix mleddisplay simplekeypad
+ matrixkeypad vhw_open vhw_load vhw_save vhw_saveas
+ vhw_remove_all
+
+ stack
+ }
+ # Toolbar buttons which require ENGAGED simulator
+ variable toolbar_simulator_engaged {
+ reset step stepover animate run clear_hg
+ find_sim_cur line2addr stepback hibernate resume
+ }
+ # Toolbar buttons which require DISENGAGED simulator
+ variable toolbar_simulator_disengaged {
+ new open close close_all undo redo cut
+ copy paste replace reload assemble start_sim0
+ disasm reformat_code change_case assemble0
+ }
+ # Toolbar items which are not avaliable when editor is in read only mode
+ variable toolbar_editor_readonly {
+ undo redo cut paste replace reformat_code change_case
+ }
+ # Toolbar items which are not avaliable only for C language
+ variable toolbar_editor_c_only {
+ }
+ # Toolbar items which are not avaliable when external embedded editor is used
+ variable toolbar_editor_external_na {
+ save save_as undo redo cut
+ copy paste find findnext findprev
+ replace goto reload reformat_code change_case
+ toHTML toLaTeX find_sim_cur line2addr save_all
+ }
+
+ ## This function should be immediately after load of environment.tcl
+ # @return void
+ proc initialize {} {
+ variable projectmenu ;# ID of Popup menu for project tabs
+
+ menuFactory {
+ {command "Save" "$project:proj_save" 0
+ {__project_pmenu_save}
+ "filesave" "Save this project"}
+ {command "Edit project" "$project:proj_edit" 0
+ {__project_pmenu_edit}
+ "configure" "Edit additional project detail"}
+ {separator}
+ {command "Save and close" "$project:proj_close" 1
+ {__project_pmenu_close}
+ "fileclose" "Save and close this project"}
+ {command "Close without saving" "$project:proj_clsimm" 0
+ {__project_pmenu_close_imm}
+ "no" "Close this project"}
+ {separator}
+ {command "Move left" "" 5
+ {__project_move_to_left}
+ "1leftarrow" "Move this tab to right the beginning of the tab bar"}
+ {command "Move right" "" 5
+ {__project_move_to_right}
+ "1rightarrow" "Move this tab to right the end of the tab bar"}
+ {separator}
+ {command "Move to beginning" "" 8
+ {__project_move_to_beginning}
+ "2leftarrow" "Move this tab to right the beginning of the tab bar"}
+ {command "Move to end" "" 9
+ {__project_move_to_end}
+ "2rightarrow" "Move this tab to right the end of the tab bar"}
+ } $projectmenu 0 "::X::" 0 {}
+ }
+
+ ## Switch current project
+ # @parm String project_name - Project object reference
+ # @return void
+ proc switch_project {project_name} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable openedProjects ;# List of opened projects (Object references)
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+
+ # Ensure that autocompletion window is closed
+ ::Editor::close_completion_popup_window_NOW
+
+ if {$actualProjectIdx != -1 && ([lindex $simulator_enabled $actualProjectIdx] == 1)} {
+ if {[$actualProject sim_stepover_in_progress]} {
+ $actualProject sim_stepover
+ } elseif {[$actualProject sim_run_in_progress]} {
+ $actualProject sim_run
+ } elseif {[$actualProject sim_anim_in_progress]} {
+ $actualProject sim_animate
+ }
+ }
+
+ set actualProject [string trimleft $project_name {:}]
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+
+ disaena_menu_toolbar_for_current_project
+ adjust_title
+
+ $actualProject adjust_compiler_settings
+ }
+
+ ## Enable / Disable menu and toolbar item acording to current state of current project
+ # @return void
+ proc disaena_menu_toolbar_for_current_project {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+
+ # This procedure requires at least one opened project
+ if {$project_menu_locked} {return}
+
+ # Adjust state simulator related menu/toolbar items
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ Unlock_simulator_menu
+
+ # Enable / Disabled stepback buttons
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ } {
+ Lock_simulator_menu
+ adjust_mainmenu_and_toolbar_to_editor \
+ ${::editor_RO_MODE} \
+ [expr {1 == [$actualProject editor_procedure {} get_language {}]}]
+ }
+
+ ## Disable/Enable menu+toolbar entries related to simulator controls which depends on current MCU
+ disena_simulator_menu $actualProject
+ }
+
+ ## Disable/Enable menu+toolbar entries related to simulator
+ # +controls which depends on current MCU
+ # @parm Object project - Current project
+ # @return void
+ proc disena_simulator_menu {project} {
+ # Enable/Disable controls related to hexadecimal editors
+ ena_dis_menu_buttons 0 {{ ".mainMenu.virtual_mcu"
+ { "Show XDATA memory" "Show ERAM" "Show EEPROM write buffer" "Show Data EEPROM"}
+ }}
+ ena_dis_iconBar_buttons 0 .mainIconBar. {
+ show_ext_mem show_exp_mem show_eeprom show_eem_wr_b
+ }
+ set toolbar {}
+ set mainmenu {}
+ if {[lindex [$project cget -procData] 8]} {
+ lappend toolbar {show_exp_mem}
+ lappend mainmenu {Show ERAM}
+ }
+ if {[$project cget -P_option_mcu_xdata]} {
+ lappend toolbar {show_ext_mem}
+ lappend mainmenu {Show XDATA memory}
+ }
+ if {[lindex [$project cget -procData] 32]} {
+ lappend toolbar {show_eeprom}
+ lappend toolbar {show_eem_wr_b}
+ lappend mainmenu {Show EEPROM write buffer}
+ lappend mainmenu {Show Data EEPROM}
+ }
+ ena_dis_menu_buttons 1 [list [list {.mainMenu.virtual_mcu} $mainmenu]]
+ ena_dis_iconBar_buttons 1 .mainIconBar. $toolbar
+ }
+
+ ## Ensure than simulator isn't engaged
+ # @parm Bool message - Invoke error message if simulator is engaged
+ # @return Bool - result (1 == is engaged; 0 == is not engaged)
+ proc simulator_must_be_disabled {message} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+
+ if {[lindex $simulator_enabled $actualProjectIdx] == {}} {
+ return 1
+ }
+
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ if {$message} {
+ tk_messageBox \
+ -title [mc "Unable to compile"] \
+ -icon info \
+ -type ok \
+ -message [mc "Simulator is engaged, shutdown the simulator first."]
+ }
+ return 1
+ }
+
+ return 0
+ }
+
+ ## New file
+ # @return void
+ proc __new {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # Use dialog "Open file" to create new file with embedded external editor
+ if {${::Editor::editor_to_use}} {
+ __open 1
+ return
+ }
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Create new editor
+ $actualProject editor_new
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Open file
+ # @parm Bool = 0 - 1 == New file (for embedded external editor); 0 == Open an existing file
+ # @return void
+ proc __open args {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable open_f_external_editor ;# Bool: Use procedure __open to open new file for embedded external editor
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Parse input arguments
+ set open_f_external_editor [lindex $args 0]
+ if {$open_f_external_editor != 1} {
+ set title [mc "Open file - MCU 8051 IDE"]
+ set open_f_external_editor 0
+ } {
+ set title [mc "New file - MCU 8051 IDE"]
+ set open_f_external_editor 1
+ }
+
+ # Invoke the file selection dialog
+ switch -- [file extension [lindex [$actualProject editor_procedure {} getFileName {}] 1]] {
+ {.asm} {set defaultmask 0}
+ {.c} {set defaultmask 1}
+ {.h} {set defaultmask 2}
+ {.lst} {set defaultmask 3}
+ default {set defaultmask 4}
+ }
+ set directory [lindex [$actualProject editor_procedure {} getFileName {}] 0]
+ if {$directory == {.}} {
+ set directory [$actualProject cget -projectPath]
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title $title -directory $directory \
+ -defaultmask $defaultmask -multiple 1 -filetypes [list \
+ [list [mc "Assembly language"] {*.asm}] \
+ [list [mc "C source"] {*.c}] \
+ [list [mc "C header"] {*.h}] \
+ [list [mc "Code listing"] {*.lst}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ fsd setokcmd {
+ foreach filename [X::fsd get] {
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+
+ if {[file isdirectory $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent . \
+ -title [mc "Operation aborted"] \
+ -message [mc "The file you choosed appears to be a directory:\n%s\n\nSuch an operation doesn't make sense." $filename]
+ continue
+ }
+
+ # Open the specified file
+ if {${::X::open_f_external_editor} || [file exists $filename]} {
+ if {[${X::actualProject} openfile $filename 1 \
+ [X::fsd get_window_name] def def 0 0 {}] != {}
+ } {
+ ${X::actualProject} switch_to_last
+ update idle
+ ${X::actualProject} editor_procedure {} parseAll {}
+
+ # Make LST read only
+ if {[file extension $filename] == {.lst}} {
+ set ::editor_RO_MODE 1
+ ${X::actualProject} switch_editor_RO_MODE
+ }
+
+ ::X::recent_files_add 1 $filename
+ }
+ } {
+ ${X::actualProject} editor_new
+ ${X::actualProject} save_as $filename
+ if {!${::Editor::editor_to_use}} {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent [::X::fsd get_window_name] \
+ -title [mc "File not found - MCU 8051 IDE"] \
+ -message [mc "The selected file do not exist:\n%s" $filename]
+ }
+ }
+ }
+ }
+
+ # activate the dialog
+ fsd activate
+
+ adjust_title
+ set critical_procedure_in_progress 0
+ }
+
+ ## Save file
+ # @return void
+ proc __save {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Save file
+ $actualProject editor_procedure {} save {}
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Save file under different filename
+ # @return void
+ proc __save_as {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Invoke the dialog
+ set filename [$actualProject editor_procedure {} getFileName {}]
+ switch -- [file extension [lindex $filename 1]] {
+ {.asm} {set defaultmask 0}
+ {.c} {set defaultmask 1}
+ {.h} {set defaultmask 2}
+ default {set defaultmask 3}
+ }
+ set directory [lindex [$actualProject editor_procedure {} getFileName {}] 0]
+ if {$directory == {.}} {
+ set directory [$actualProject cget -projectPath]
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -initialfile [lindex $filename 1] \
+ -title [mc "Save file - MCU 8051 IDE"] \
+ -directory $directory \
+ -defaultmask $defaultmask -multiple 0 -filetypes {
+ {{Assembly language} {*.asm} }
+ {{C source} {*.c} }
+ {{C header} {*.h} }
+ {{All files} {*} }
+ }
+
+ # Save file after press of OK button
+ fsd setokcmd {
+ set filename [X::fsd get]
+ ${X::actualProject} save_as $filename
+ }
+
+ # activate the dialog
+ fsd activate
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Save all opened file of the current project
+ # @return void
+ proc __save_all {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Save all opended files
+ $actualProject editor_save_all
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Close the curent file
+ # @return void
+ proc __close {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Close file
+ $actualProject editor_close 1 {}
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Close all opended files
+ # @return void
+ proc __close_all {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Close all files
+ $actualProject editor_close_all 1 0
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Take back the last operation
+ # @return void
+ proc __undo {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Undo
+ $actualProject editor_procedure {} undo {}
+ }
+
+ ## Take back the last undo operation
+ # @return void
+ proc __redo {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Redo
+ $actualProject editor_procedure {} redo {}
+ }
+
+ ## Copy selected text to clipboard
+ # @return void
+ proc __copy {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Copy
+ $actualProject editor_procedure {} copy {}
+ }
+
+ ## Cut selected text (copy to clipboard and remove)
+ # @return void
+ proc __cut {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Cut
+ $actualProject editor_procedure {} cut {}
+ }
+
+ ## Paste text from clipboard
+ # @return void
+ proc __paste {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Paste
+ $actualProject editor_procedure {} paste {}
+ }
+
+ ## Indent selected text or the current line
+ # @return void
+ proc __indent {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Indent
+ $actualProject editor_procedure {} indent {}
+ }
+
+ ## Unindent selected text or the current line
+ # @return void
+ proc __unindent {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Unindent
+ $actualProject editor_procedure {} unindent {}
+ }
+
+ ## Invoke find dialog
+ # @return void
+ proc __find {} {
+ variable actualProject ;# Object: Current project
+ variable find_String ;# Search string
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable find_allow_selection ;# Bool: There is some selected text in editor
+ variable find_history ;# List of the last 10 search strings
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {${::Editor::editor_to_use}} {return}
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Determinate selected text
+ set selectedText [$actualProject editor_procedure {} getselection {}]
+ if {$selectedText != {}} {
+ set find_String $selectedText
+ }
+
+ # Create a new toplevel window for the dialog
+ set win [toplevel .find -class {Find dialog} -bg {#EEEEEE}]
+
+ # String to search for
+ label $win.findLabel -compound left -image ::ICONS::16::find -text [mc "Text to find:"]
+ set findFrame [ttk::labelframe $win.findFrame \
+ -labelwidget $win.findLabel \
+ -relief flat \
+ ]
+ pack $findFrame -fill x -expand 1 -pady 10 -padx 5
+ pack [ttk::combobox $findFrame.entry \
+ -textvariable X::find_String \
+ -exportselection 0 \
+ -values $find_history \
+ ] -fill x -expand 1 -padx 10
+ DynamicHelp::add $findFrame.entry -text [mc "String to find"]
+
+ # Create and pack options labelframe
+ label $win.optionsLabel -compound left -image ::ICONS::16::configure -text [mc "Options"]
+ set optionsFrame [ttk::labelframe $win.optionsFrame \
+ -labelwidget $win.optionsLabel \
+ ]
+ pack $optionsFrame -fill both -expand 1 -padx 10
+
+ # Determinate wheather there is some selected text
+ if {[$actualProject editor_procedure {} getselection {}] == {}} {
+ set find_allow_selection 0
+ } {
+ set find_allow_selection 1
+ }
+
+ # Create matrix of option checkbuttons
+ set col 0 ;# Grid column
+ set row 0 ;# Grid row
+ foreach opt { CS back cur sel reg } \
+ txt { "Case sensitive" "Backwards" "From cursor" "Selected text" "Regular expr." } \
+ helptext {
+ {Case sensitive search}
+ {Search backwards from the specified location}
+ {Start search from cursor instead of begining}
+ {Search within selected text only}
+ {Use search string as regular expression}
+ } \
+ {
+ # Disable/Enable "in selection" checkbox
+ if {$opt == {sel} && !$find_allow_selection} {
+ set state disabled
+ set X::find_option_sel 0
+ } {
+ set state normal
+ }
+
+ # Create checkbutton
+ grid [checkbutton $optionsFrame.option_$opt \
+ -text [mc $txt] \
+ -variable X::find_option_$opt \
+ -state $state \
+ ] -column $col -row $row -sticky wns
+ DynamicHelp::add $optionsFrame.option_$opt -text $helptext
+
+ incr col
+ if {$col == 2} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::find_FIND} \
+ ] -side left -padx 2
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::find_CANCEL} \
+ ] -side left -padx 2
+ pack $buttonFrame -pady 5
+
+ # Events binding (Enter == Find; Escape == Cancel)
+ bind $win <KeyRelease-Return> {X::find_FIND; break}
+ bind $win <KeyRelease-KP_Enter> {X::find_FIND; break}
+ bind $win <KeyRelease-Escape> {X::find_CANCEL; break}
+
+ # Nessesary window manager options -- for modal window
+ wm iconphoto $win ::ICONS::16::find
+ wm title $win [mc "Find - MCU 8051 IDE"]
+ wm minsize $win 300 210
+ wm protocol $win WM_DELETE_WINDOW {
+ X::find_CANCEL
+ }
+ wm transient $win .
+ update
+ raise $win
+ catch {grab $win}
+ focus $findFrame.entry
+ catch {
+ $findFrame.entry.e selection range 0 end
+ }
+ tkwait window $win
+ }
+
+ ## Cancel find dialog -- auxiliary procedure for '__find'
+ # @return void
+ proc find_CANCEL {} {
+ if {![winfo exists .find]} {return}
+
+ destroy .find
+ grab release .find
+ }
+
+ ## Perform search -- auxiliary procedure for '__find'
+ # @return Bool - result
+ proc find_FIND {} {
+ variable actualProject ;# Object: Current project
+ variable find_allow_selection ;# Bool: There is some selected text in editor
+ variable find_String ;# Search string
+ variable find_forward_index ;# Search index for forward search
+ variable find_backward_index ;# Search index for backward search
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_notCS ;# Bool: Case insensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable find_retry_search ;# Bool: Search restarted from begining/end
+ variable find_back_dir ;# Bool: Search backwards (real option)
+ variable find_history ;# List of the last 10 search strings
+
+ # Append search string to history
+ if {[lsearch -exact -ascii $find_history $find_String] == -1} {
+ lappend find_history $find_String
+ }
+ # History mustn't contain more than 10 items
+ if {[llength $find_history] > 10} {
+ set find_history [lrange $find_history [expr {[llength $find_history] - 10}] end]
+ }
+
+ # New search
+ set find_retry_search 0 ;# Search has not been restarted
+ set find_back_dir $find_option_back ;# Search backwards/forwards
+
+ # Cancel the find dialog
+ find_CANCEL
+
+ # Check for validity of the search string
+ if {$find_String == {}} {
+ return 0
+ }
+
+ # Adjust option "Search in selected text"
+ set find_option_notCS [expr {!$find_option_CS}]
+ if {!$find_allow_selection} {
+ set option_sel 0
+ } {
+ set option_sel $find_option_sel
+ }
+
+ # Perform search
+ set result [$actualProject editor_procedure {} find [list \
+ $find_option_cur $find_option_back \
+ $find_option_reg $find_option_notCS \
+ $option_sel {} \
+ $find_String]]
+
+ # Search failed -> show error message
+ if {[lindex $result 0] == -1} {
+ tk_messageBox -icon warning \
+ -parent . -type ok \
+ -title [mc "Unable to execute"] \
+ -message [lindex $result 1]
+ return 0
+ }
+
+ # Set search indexes
+ set find_backward_index [lindex $result 0]
+ set find_forward_index [lindex $result 1]
+
+ # Finalize
+ set matches [lindex $result 2]
+ Sbar [mc "Search result: %s matches found" $matches] ;# Show final result
+ if {$matches == 0} retry_search ;# Ask for retry
+
+ # Success
+ return 1
+ }
+
+ ## Retry search -- auxiliary procedure for '__find'
+ # Useful when search cursor reach begining/end of the document
+ # @return Bool result
+ proc retry_search {} {
+ variable find_retry_search ;# Bool: Search restarted from begining/end
+ variable find_String ;# Search string
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_backward_index ;# Search index for backward search
+ variable find_forward_index ;# Search index for forward search
+ variable find_back_dir ;# Bool: Search backwards (real option)
+ variable find_next_prev_in_P ;# Bool: Procedure 'find_next_prev' in progress
+
+ # There is only one allowed retry
+ if {$find_retry_search || !$find_option_cur} {
+ set find_retry_search 0
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "Find - %s" ${::APPNAME}] \
+ -message [mc "Search string '%s' not found !" $find_String] \
+ -parent .
+ set find_next_prev_in_P 0
+ return
+ }
+
+ set find_option_cur_tmp $find_option_cur ;# Search cursor
+ set find_retry_search 1 ;# This is the first retry
+
+ # Backward search
+ if {$find_back_dir} {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -title [mc "Find - %s" ${::APPNAME}] \
+ -message [mc "Begining of document reached\n\nContinue from end ?"] \
+ ]} {
+ set find_next_prev_in_P 0
+ set find_backward_index end
+ set find_forward_index 1.0
+ set find_option_cur 0
+ # Retry search
+ find_next_prev [expr {!$find_option_back}]
+ }
+
+ # Forward search
+ } {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -title [mc "Find - %s" ${::APPNAME}] \
+ -message [mc "End of document reached\n\nContinue from begining ?"] \
+ ]} {
+ set find_next_prev_in_P 0
+ set find_backward_index end
+ set find_forward_index 1.0
+ set find_option_cur 0
+ # Retry search
+ find_next_prev $find_option_back
+ }
+ }
+
+ set find_next_prev_in_P 0
+ set find_option_cur $find_option_cur_tmp
+ set find_retry_search 0
+ }
+
+ ## Find next occurence of the search string
+ # @return void
+ proc __find_next {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Perform search
+ find_next_prev 0
+ }
+
+ ## Find previous occurence of the search string
+ # @return void
+ proc __find_prev {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Perform search
+ find_next_prev 1
+ }
+
+ ## Find next/previous occurence of the search string
+ # @parm Bool back_dir - Search backwards
+ # @return void
+ proc find_next_prev {back_dir} {
+ variable actualProject ;# Object: Current project
+ variable find_String ;# Search string
+ variable find_backward_index ;# Search index for backward search
+ variable find_forward_index ;# Search index for forward search
+ variable find_option_notCS ;# Bool: Case insensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable find_retry_search ;# Bool: Search restarted from begining/end
+ variable find_back_dir ;# Bool: Search backwards (real option)
+ variable find_next_prev_in_P ;# Bool: Procedure 'find_next_prev' in progress
+
+ # This function is not avaliable for exeternal embedded editors
+ if {${::Editor::editor_to_use}} {return}
+
+ # This function cannot run multithreaded
+ if {$find_next_prev_in_P} {return}
+ set find_next_prev_in_P 1
+
+ # Check for valid search index
+ if {![info exists find_backward_index]} {
+ Sbar [mc "Editor: Nothing to search ..."]
+ set find_next_prev_in_P 0
+ return
+ }
+
+ # Determinate direction
+ set find_back_dir [expr {$find_option_back ^ $back_dir}]
+
+ # Determinate start index
+ if {$find_option_cur} {
+ set editor [[$actualProject get_current_editor_object] cget -editor]
+ if {$find_back_dir} {
+ if {[$editor compare $find_forward_index == insert]} {
+ $editor mark set insert $find_backward_index
+ }
+ } {
+ if {[$editor compare $find_backward_index == insert]} {
+ $editor mark set insert $find_forward_index
+ }
+ }
+ set index insert
+ } {
+ if {$find_back_dir} {
+ set index $find_backward_index
+ } {
+ set index $find_forward_index
+ }
+ }
+
+ # Perform search
+ set result [$actualProject editor_procedure {} find [list \
+ $find_option_cur $find_back_dir \
+ $find_option_reg $find_option_notCS \
+ $find_option_sel $index \
+ $find_String]]
+
+ # Set search indexes
+ set find_backward_index [lindex $result 0]
+ set find_forward_index [lindex $result 1]
+
+ # Finalize
+ set matches [lindex $result 2]
+ Sbar [mc "Search result: %s matches found" $matches] ;# Show final result
+ if {$matches == 0} retry_search ;# Retry search if this one failed
+ set find_next_prev_in_P 0
+ }
+
+ ## Invoke dialog to replace one string with another (in editor)
+ # @return void
+ proc __replace {} {
+ variable actualProject ;# Object: Current project
+ variable replace_String ;# String to replace
+ variable replace_Replacement ;# Replacement for the search string
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_prompt ;# Bool: Prompt on replace
+ variable replace_search_history ;# List of the last 10 search strings
+ variable replace_repl_history ;# List of the last 10 replacement strings
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {${::Editor::editor_to_use}} {return}
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Determinate selected text
+ set selectedText [$actualProject editor_procedure {} getselection {}]
+ if {$selectedText != {}} {
+ set replace_String $selectedText
+ }
+
+ # Create a new toplevel window for the dialog
+ set win [toplevel .replace -class {Replace dialog} -bg {#EEEEEE}]
+
+ # Create labelframe "String to find"
+ label $win.findLabel -compound left -image ::ICONS::16::find -text [mc "Text to find: "]
+ set findFrame [ttk::labelframe $win.findFrame \
+ -labelwidget $win.findLabel \
+ -relief flat \
+ ]
+ pack $findFrame -fill x -expand 1 -pady 10 -padx 5
+ pack [ttk::combobox $findFrame.entry \
+ -textvariable X::replace_String \
+ -exportselection 0 \
+ -values $replace_search_history \
+ ] -fill x -expand 1 -padx 10
+ DynamicHelp::add $findFrame.entry -text [mc "String to replace"]
+ pack $findFrame
+
+ # Create labelframe "Replace with"
+ set replaceFrame [ttk::labelframe $win.replaceFrame \
+ -text [mc "Replace with:"] \
+ -relief flat \
+ ]
+ pack $replaceFrame -fill x -expand 1 -pady 5 -padx 5
+ pack [ttk::combobox $replaceFrame.entry \
+ -textvariable X::replace_Replacement \
+ -exportselection 0 \
+ -values $replace_repl_history \
+ ] -fill x -expand 1 -padx 10
+ DynamicHelp::add $replaceFrame.entry -text [mc "Replacement for search string"]
+
+ # Create and pack options checkboxes labelframe
+ label $win.optionsLabel -compound left -image ::ICONS::16::configure -text "Options"
+ set optionsFrame [ttk::labelframe $win.optionsFrame \
+ -labelwidget $win.optionsLabel \
+ ]
+ pack $optionsFrame -fill both -expand 1 -padx 10
+
+ # Create matrix of option checkboxes
+ set col 0 ;# Grid column
+ set row 0 ;# Grid row
+ foreach opt { CS back cur reg prompt} \
+ txt { "Case sensitive" "Backwards" "From cursor" "Regular expr." "Prompt on replace"} \
+ helptext {
+ {Case sensitive search}
+ {Search backwards from the specified location}
+ {Start search from cursor instead of begining}
+ {Use search string as regular expression}
+ {Prompt on replace}
+ } {
+
+ # Create checkbutton
+ grid [checkbutton $optionsFrame.option_$opt \
+ -text [mc $txt] \
+ -variable X::replace_option_$opt \
+ ] -column $col -row $row -sticky wns
+ DynamicHelp::add $optionsFrame.option_$opt -text $helptext
+
+ incr col
+ if {$col == 2} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::replace_REPLACE} \
+ ] -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::replace_CANCEL} \
+ ] -side left
+ pack $buttonFrame -pady 5
+
+ # Events binding (Enter == Replace; Escape == Cancel)
+ bind $win <KeyRelease-Return> {X::replace_REPLACE; break}
+ bind $win <KeyRelease-KP_Enter> {X::replace_REPLACE; break}
+ bind $win <KeyRelease-Escape> {X::replace_CANCEL; break}
+
+ # Nessesary window manager options -- for modal window
+ wm iconphoto $win ::ICONS::16::find
+ wm title $win [mc "Replace - MCU 8051 IDE"]
+ wm minsize $win 300 270
+ wm protocol $win WM_DELETE_WINDOW {
+ X::replace_CANCEL
+ }
+ wm transient $win .
+ update
+ raise $win
+ catch {grab $win}
+ focus $findFrame.entry
+ catch {
+ $findFrame.entry.e selection range 0 end
+ }
+ tkwait window $win
+ }
+
+ ## Perform replacement -- auxiliary procedure for '__replace'
+ # @return Bool - result
+ proc replace_REPLACE {} {
+ variable actualProject ;# Object: Current project
+ variable replace_String ;# String to replace
+ variable replace_Replacement ;# Replacement for the search string
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_prompt ;# Bool: Prompt on replace
+ variable replace_search_history ;# List of the last 10 search strings
+ variable replace_repl_history ;# List of the last 10 replacement strings
+
+ # Append search string to history
+ if {[lsearch -exact -ascii $replace_search_history $replace_String] == -1} {
+ lappend replace_search_history $replace_String
+ }
+ # History mustn't contain more than 10 items
+ if {[llength $replace_search_history] > 10} {
+ set replace_search_history [lrange $replace_search_history \
+ [expr {[llength $replace_search_history] - 10}] end]
+ }
+
+ # Append replace string to history
+ if {[lsearch -exact -ascii $replace_repl_history $replace_Replacement] == -1} {
+ lappend replace_repl_history $replace_Replacement
+ }
+ # History mustn't contain more than 10 items
+ if {[llength $replace_repl_history] > 10} {
+ set replace_repl_history [lrange \
+ $replace_repl_history \
+ [expr {[llength $replace_repl_history] - 10}] \
+ end \
+ ]
+ }
+
+ # Cancel the replace dialog
+ replace_CANCEL
+
+ # Perform replacement
+ set replace_option_notCS [expr {!$replace_option_CS}]
+ if {![$actualProject editor_procedure {} replace [list \
+ $replace_option_cur $replace_option_back \
+ $replace_option_reg $replace_option_notCS \
+ $replace_String $replace_Replacement \
+ $replace_option_prompt X::replace_prompt]
+ ]} {
+ if {!$replace_option_cur} {return}
+
+ set replace_option_cur_tmp $replace_option_cur
+ set replace_option_cur 0
+
+ # Retry search
+ if {$replace_option_back} {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -title [mc "Replace - %s" ${::APPNAME}] \
+ -message [mc "Begining of document reached\n\nContinue from end ?"] \
+ ]} {
+ replace_REPLACE
+ }
+ } {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -title [mc "Replace - %s" ${::APPNAME}] \
+ -message [mc "End of document reached\n\nContinue from begining ?"] \
+ ]} {
+ replace_REPLACE
+ }
+ }
+
+ set replace_option_cur $replace_option_cur_tmp
+ }
+ }
+
+ ## Cancel replace dialog -- auxiliary procedure for '__replace'
+ # @return bool
+ proc replace_CANCEL {} {
+ destroy .replace
+ grab release .replace
+ }
+
+ ## Invoke dialog "Replace confirmation"
+ # @return bool
+ proc replace_prompt {} {
+ variable replace_prompt_opened ;# Bool: Replace prompt dialog opened
+ variable replace_prompt_return_value ;# Replace prompt dialog return value
+ variable replace_prompt_geometry ;# Geometry of replace prompt dialog window
+
+ # Dialog already opened -> close it
+ if {$replace_prompt_opened} {
+ replace_prompt_DESTROY
+ # Open the dialog
+ } {
+ set replace_prompt_opened 1
+
+ # Create dialog window and restore previous geometry
+ toplevel .replace_prompt -class {Replace prompt dialog} -bg {#EEEEEE}
+ if {[info exists replace_prompt_geometry]} {
+ wm geometry .replace_prompt $replace_prompt_geometry
+ }
+
+ # Create window header
+ pack [frame .replace_prompt.topFrame] -fill x -expand 1
+ pack [label .replace_prompt.topFrame.image \
+ -image ::ICONS::32::help \
+ ] -side left -padx 10
+ pack [label .replace_prompt.topFrame.label \
+ -text [mc "Found an occurence of your search term.\nWhat do you want to do ?"] \
+ ] -fill both -expand 1 -side right
+
+ # Create separator
+ pack [ttk::separator .replace_prompt.separator -orient horizontal] -fill x -expand 1
+ pack [frame .replace_prompt.buttonFrame] -fill x -expand 1
+
+ # Create buttuns
+ foreach id { repl relp_close repl_all find_next close } \
+ text { "Replace" "Replace & close" "Replace all" "Find next" "Close" } \
+ val { 0 1 2 3 4 } \
+ under { 0 2 8 0 0 } {
+
+ pack [ttk::button .replace_prompt.buttonFrame.$id \
+ -text [mc $text] -underline $under \
+ -command "X::replace_prompt_return $val;set wait 1;unset wait" \
+ ] -fill x -expand 1 -side left -padx 5
+ }
+
+ # Set key-events bindings
+ bind .replace_prompt <Alt-Key-r> {
+ X::replace_prompt_return 0
+ set wait 1
+ unset wait
+ break
+ }
+ bind .replace_prompt <Alt-Key-p> {
+ X::replace_prompt_return 1
+ set wait 1
+ unset wait
+ break
+ }
+ bind .replace_prompt <Alt-Key-a> {
+ X::replace_prompt_return 2
+ set wait 1
+ unset wait
+ break
+ }
+ bind .replace_prompt <Alt-Key-f> {
+ X::replace_prompt_return 3
+ set wait 1
+ unset wait
+ break
+ }
+ bind .replace_prompt <Alt-Key-c> {
+ X::replace_prompt_return 4
+ set wait 1
+ unset wait
+ break
+ }
+
+ # Nessesary window manager options -- modal window
+ wm iconphoto .replace_prompt ::ICONS::16::help
+ wm title .replace_prompt [mc "Replace confirmation - %s" ${::APPNAME}]
+ wm minsize .replace_prompt 480 100
+ wm protocol .replace_prompt WM_DELETE_WINDOW {
+ X::replace_prompt_DESTROY
+ }
+ wm transient .replace_prompt .
+ raise .replace_prompt
+
+ vwait ::wait
+ return $replace_prompt_return_value
+ }
+ }
+
+ ## Cancel replace prompt dialog -- auxiliary procedure for 'replace_prompt'
+ # @return bool
+ proc replace_prompt_DESTROY {} {
+ variable replace_prompt_opened ;# Bool: Replace prompt dialog opened
+ variable replace_prompt_geometry ;# Geometry of replace prompt dialog window
+
+ # Save the current dialog geometry
+ set replace_prompt_geometry [wm geometry .replace_prompt]
+
+ # Destroy dislog window
+ destroy .replace_prompt
+ set replace_prompt_opened 0
+ }
+
+ ## Cancel replace prompt dialog and set its return value
+ # @parm Int val - result value of the dialog
+ # @return void
+ proc replace_prompt_return {val} {
+ variable replace_prompt_return_value ;# Replace prompt dialog return value
+
+ set replace_prompt_return_value $val
+ replace_prompt_DESTROY
+ }
+
+ ## Select all text in the editor
+ # @return void
+ proc __select_all {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Select all
+ $actualProject editor_procedure {} select_all {}
+ }
+
+ ## Invoke dialog "Go to"
+ # If simulator is engaged the run this: __simulator_set_PC_by_line
+ # @return void
+ proc __goto {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable goto ;# Line where to go
+ variable editor_lines ;# Number of lines in the current editor
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ __simulator_set_PC_by_line
+ return
+ }
+
+ set goto [$actualProject editor_actLineNumber]
+ set editor_lines [$actualProject editor_linescount]
+
+ # Create dialog window
+ set goto_opened 1
+ set win [toplevel .goto -class {Goto dialog} -bg {#EEEEEE}]
+
+ # Create window label frame
+ label $win.header -text [mc "Go to line"] -image ::ICONS::16::goto -compound left
+ set topFrame [ttk::labelframe $win.topFrame -labelwidget $win.header -relief flat]
+ pack $topFrame -expand 1 -fill x -padx 10
+
+ # Create scale widget
+ pack [ttk::scale $topFrame.scale \
+ -from 1 -to $editor_lines \
+ -orient horizontal \
+ -variable X::goto \
+ -command "
+ set ::X::goto \[expr {int(\${::X::goto})}\]
+ $topFrame.spinbox selection range 0 end
+ #" \
+ ] -side left -expand 1 -fill x -padx 2
+ DynamicHelp::add $topFrame.scale \
+ -text [mc "Graphical representation of line where to go"]
+
+ # Create spinbox widget
+ pack [spinbox $topFrame.spinbox \
+ -from 1 -to $editor_lines \
+ -textvariable X::goto \
+ -validate key \
+ -validatecommand {X::goto_validate %P} \
+ -width 6 \
+ -command "$topFrame.spinbox selection range 0 end" \
+ ] -side left
+ DynamicHelp::add $topFrame.spinbox -text [mc "Line where to go"]
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame .goto.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::goto_OK} \
+ ] -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::goto_CANCEL} \
+ ] -side left
+ pack $buttonFrame -pady 5
+
+ # Events binding (Enter == Ok, Esc == CANCEL)
+ bind $win <KeyRelease-Return> {X::goto_OK; break}
+ bind $win <KeyRelease-KP_Enter> {X::goto_OK; break}
+ bind $win <KeyRelease-Escape> {X::goto_CANCEL; break}
+
+ # Focus on the Spinbox
+ focus $topFrame.spinbox
+ $topFrame.spinbox selection range 0 end
+
+ # Nessesary window manager options -- modal window
+ wm iconphoto $win ::ICONS::16::goto
+ wm title $win [mc "Goto line - MCU 8051 IDE"]
+ wm minsize $win 200 100
+ wm protocol $win WM_DELETE_WINDOW {
+ X::goto_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Validate value of spinbox in the Go to dialog -- auxiliary procedure for '__goto'
+ # @parm
+ # @return bool
+ proc goto_validate {value} {
+ variable editor_lines ;# Number of lines in the current editor
+
+ if {$value > $editor_lines} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Cancel Go to dialog -- auxiliary procedure for '__goto'
+ # @return bool
+ proc goto_CANCEL {} {
+ destroy .goto
+ grab release .goto
+ }
+
+ ## Go to line -- auxiliary procedure for '__goto'
+ # @return bool
+ proc goto_OK {} {
+ variable actualProject ;# Object: Current project
+ variable goto ;# Line where to go
+
+ # Go to the specified line
+ $actualProject editor_procedure {} goto $goto
+ # Destroy dialog window
+ goto_CANCEL
+ }
+
+ ## Comment block of selected text in the editor
+ # @return void
+ proc __comment {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Comment
+ $actualProject editor_procedure {} comment {}
+ }
+
+ ## Uncomment block of selected text in the editor
+ # @return void
+ proc __uncomment {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Uncomment
+ $actualProject editor_procedure {} uncomment {}
+ }
+
+ ## Reload the current file
+ # @return void
+ proc __reload {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Reload
+ $actualProject filelist_reload_file
+ }
+
+ ## Invoke directory selection dialog
+ # @parm Widget master - GUI parent
+ # @return void
+ proc select_directory {master} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+ variable select_directory_var {} ;# Selected directory
+ variable defaultDirectory ;# Default directory
+
+ # Determinate initial directory
+ if {$project_menu_locked} {
+ set directory {~}
+ } {
+ set directory [$actualProject cget -projectPath]
+ }
+
+ # Invoke the dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Choose directory - MCU 8051 IDE"] \
+ -directory $directory -fileson 0 -master $master
+
+ # Save choice to variable select_directory_var
+ fsd setokcmd {
+ set X::select_directory_var [X::fsd get]
+ }
+
+ fsd activate ;# Activate the dialog
+
+ # Return path to the selected directory
+ return $select_directory_var
+ }
+
+ ## Invoke dialog "New Project"
+ # @return void
+ proc __proj_new {} {
+ variable avaliable_processors ;# List of supported processors
+ variable actualProject ;# Object: Current project
+ variable project_new_name ;# Name of the new project
+ variable project_new_dir ;# Directory of the new project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_new_processor {AT89S52};# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena 0 ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena 0 ;# Bool: XCODE memory connected
+ variable project_new_xdata 0 ;# Int: Amount of XDATA memory
+ variable project_new_xcode 0 ;# Int: Amount of XCODE memory
+ variable project_new_max_xcode 0 ;# Int: Maximum valid value of external program memory
+ variable project_new_xd_chb ;# Widget: XDATA enable checkbutton
+ variable project_new_xd_scl ;# Widget: XDATA scale
+ variable project_new_xd_spb ;# Widget: XDATA spinbox
+ variable project_new_xc_chb ;# Widget: XCODE enable checkbutton
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ if {$critical_procedure_in_progress} {return}
+
+ # Create dialog window
+ set win [toplevel .project_new -class {New project} -bg {#EEEEEE}]
+
+ # Create window header (text and some icon)
+ set header [frame $win.header]
+
+ pack [label $header.image -image ::ICONS::32::wizard] -padx 10 -side left
+ pack [label $header.text \
+ -text [mc "Create a new project.\n All entries are required. Other options --> edit project."] \
+ ] -side left -expand 1 -fill x
+ pack $header -fill both -expand 1
+
+ # Create labelframe "General"
+ set genaral_labelframe [ttk::labelframe $win.general -text [mc "General"]]
+
+ # Entry "Project name"
+ set name [ttk::labelframe $genaral_labelframe.name \
+ -text [mc "Project name"] \
+ -relief flat \
+ ]
+ pack [ttk::entry $name.entry \
+ -textvariable X::project_new_name \
+ -width 20 \
+ ] -fill x -expand 1
+ DynamicHelp::add $name.entry -text [mc "Name of XML file representing the project"]
+ pack $name -fill x -expand 1 -padx 10 -pady 5
+
+ # Entry "Project directory"
+ set dir [ttk::labelframe $genaral_labelframe.dir \
+ -text [mc "Project directory"] \
+ -relief flat \
+ ]
+ pack [ttk::entry $dir.entry \
+ -textvariable X::project_new_dir \
+ -width 20 \
+ ] -side left -fill x -expand 1
+ DynamicHelp::add $dir.entry -text [mc "Directory where the project file should be located"]
+
+ pack [ttk::button $dir.choose \
+ -image ::ICONS::16::fileopen \
+ -style Flat.TButton \
+ -command {
+ set foo [X::select_directory .project_new]
+ if {$foo != {}} {
+ set X::project_new_dir $foo
+ }
+ unset foo
+ } \
+ ] -side left
+ DynamicHelp::add $dir.choose -text [mc "Choose destination location"]
+
+ pack $dir -fill x -expand 1 -padx 10 -pady 5
+ pack $genaral_labelframe -fill both -expand 1 -pady 10 -padx 10
+
+ # Create labelframe "Processor"
+ set proc_frame [ttk::labelframe $win.proc_frame -text [mc "Processor"]]
+ set proc_frame_top [frame $proc_frame.top]
+ set proc_frame_middle [frame $proc_frame.middle]
+ set proc_frame_middle_left [ttk::labelframe $proc_frame_middle.middle \
+ -padding 5 -text [mc "XDATA"]]
+ set proc_frame_middle_right [ttk::labelframe $proc_frame_middle.right \
+ -padding 5 -text [mc "XCODE"]]
+
+ # Create components of top frame (Type: <ComboBox> <Button>)
+ pack [label $proc_frame_top.lbl -text [mc "Type:"]] -side left
+ pack [ttk::combobox $proc_frame_top.combo \
+ -values $avaliable_processors \
+ -state readonly \
+ -textvariable ::X::project_new_processor \
+ ] -side left -fill x -fill x
+ bind $proc_frame_top.combo <<ComboboxSelected>> {::X::proj_new_mcu_changed}
+ DynamicHelp::add $proc_frame_top.combo -text [mc "Selected uC"]
+
+ pack [ttk::button $proc_frame_top.but \
+ -text [mc "Select MCU"] \
+ -image ::ICONS::16::back \
+ -compound left \
+ -command {::X::proj_new_select_mcu .project_new} \
+ ] -side right -after $proc_frame_top.combo -padx 10
+ DynamicHelp::add $proc_frame_top.but -text [mc "Choose processor from database"]
+
+ # Create components of XDATA labelframe
+ set project_new_xd_chb [checkbutton $proc_frame_middle_left.checkbutton \
+ -variable ::X::project_new_xdata_ena \
+ -text [mc "Enable"] \
+ -command ::X::proj_new_xdata_disena \
+ ]
+ pack $project_new_xd_chb -anchor w
+ DynamicHelp::add $proc_frame_middle_left.checkbutton \
+ -text [mc "Connect external data memory"]
+ set proc_frame_left_btm [frame $proc_frame_middle_left.btm]
+ set project_new_xd_scl [ttk::scale $proc_frame_left_btm.scale \
+ -orient horizontal \
+ -variable ::X::project_new_xdata \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::X::project_new_xdata \[expr {int(\${::X::project_new_xdata})}\]
+ $proc_frame_left_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $project_new_xd_scl \
+ -text [mc "Amount of external data memory"]
+ pack $project_new_xd_scl -fill x -side left -expand 1 -padx 2
+ set project_new_xd_spb [spinbox $proc_frame_left_btm.spinbox \
+ -textvariable ::X::project_new_xdata \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::SelectMCU::validate_xdata %P} \
+ -command "$proc_frame_left_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $project_new_xd_spb \
+ -text [mc "Amount of external data memory"]
+ pack $project_new_xd_spb -side right -after $project_new_xd_scl
+ pack $proc_frame_left_btm -fill both -expand 1
+
+ # Create components of XCODE labelframe
+ set project_new_xc_chb [checkbutton $proc_frame_middle_right.checkbutton \
+ -variable ::X::project_new_xcode_ena \
+ -text [mc "Enable"] \
+ -command ::X::proj_new_xcode_disena \
+ ]
+ pack $project_new_xc_chb -anchor w
+ DynamicHelp::add $proc_frame_middle_right.checkbutton \
+ -text [mc "Connect external program memory"]
+ set proc_frame_right_btm [frame $proc_frame_middle_right.btm]
+ set project_new_xc_scl [ttk::scale $proc_frame_right_btm.scale \
+ -orient horizontal \
+ -variable ::X::project_new_xcode \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::X::project_new_xcode \[expr {int(\${::X::project_new_xcode})}\]
+ $proc_frame_right_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $project_new_xc_scl \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $project_new_xc_scl -fill x -side left -expand 1 -padx 2
+ set project_new_xc_spb [spinbox $proc_frame_right_btm.spinbox \
+ -textvariable ::X::project_new_xcode \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::X::proj_new_validate_xcode %P} \
+ -command "$proc_frame_right_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $project_new_xc_spb \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $project_new_xc_spb -side right -after $project_new_xc_scl
+ pack $proc_frame_right_btm -fill both -expand 1
+
+ pack $proc_frame_top -anchor w -pady 10 -padx 10 -fill x
+ pack $proc_frame_middle_left -side left -fill x -expand 1 -padx 7
+ pack $proc_frame_middle_right -side left -fill x -expand 1 -padx 7
+ pack $proc_frame_middle -fill both -expand 1 -pady 5
+ pack $proc_frame -fill both -expand 1 -padx 10 -pady 10
+
+ # Create 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::project_new_OK} \
+ ] -side left -padx 5
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::project_new_CANCEL} \
+ ] -side left -padx 5
+ pack $buttonFrame -pady 5
+
+ # Adjust XDATA & XCODE controls
+ proj_new_mcu_changed
+
+ # Events binding (Enter == Ok; Escape == Cancel)
+ bind $win <Key-Return> {X::project_new_OK; break}
+ bind $win <Key-KP_Enter> {X::project_new_OK; break}
+ bind $win <Key-Escape> {X::project_new_CANCEL; break}
+
+ # Nessesary window manager options -- modal window
+ wm iconphoto $win ::ICONS::16::filenew
+ wm title $win [mc "New project - MCU 8051 IDE"]
+ wm minsize $win 400 400
+ wm protocol $win WM_DELETE_WINDOW {
+ X::project_new_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Binding for processor type combobox -modifycmd
+ # Usage: ComboBox -modifycmd ::X::proj_new_mcu_changed
+ # This function gets informations about selected processor
+ # and adjusts XCODE & XDATA memory constrols.
+ # @return void
+ proc proj_new_mcu_changed {} {
+ variable project_new_processor ;# Processor type (e.g. "8051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_max_xcode ;# Int: Maximum valid value of external program memory
+ variable project_new_xd_chb ;# Widget: XDATA enable checkbutton
+ variable project_new_xc_chb ;# Widget: XCODE enable checkbutton
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ # Get processor details
+ set details [::SelectMCU::get_processor_details $project_new_processor]
+ if {$details == {}} {
+ puts stderr "Unknown error occured in ::X::proj_new_mcu_changed !\nPlease check your installation."
+ return
+ }
+
+ # Enable/Disable XDATA memory enable checkbutton
+ if {[lindex $details 0] != {yes}} {
+ set project_new_xdata_ena 0
+ $project_new_xd_chb configure -state disabled
+ } {
+ $project_new_xd_chb configure -state normal
+ }
+
+ # Enable/Disable XCODE memory enable checkbutton
+ if {[lindex $details 1] != {yes}} {
+ set project_new_xcode_ena 0
+ $project_new_xc_chb configure -state disabled
+ } {
+ $project_new_xc_chb configure -state normal
+ }
+
+ # Adjust XCODE memory scale & spinbox maximum value
+ set project_new_max_xcode [expr {0xFFFF - ([lindex $details 2] * 1024)}]
+ $project_new_xc_scl configure -to $project_new_max_xcode
+ $project_new_xc_spb configure -to $project_new_max_xcode
+
+ # Enable/Disable XDATA & XCODE scale + XDATA & XCODE spinbox
+ proj_new_xdata_disena
+ proj_new_xcode_disena
+ }
+
+ ## Enable/Disable XDATA scale & spinbox acording to $project_new_xdata_ena
+ # @return void
+ proc proj_new_xdata_disena {} {
+ variable project_new_xd_scl ;# Widget: XDATA scale
+ variable project_new_xd_spb ;# Widget: XDATA spinbox
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+
+ # Enable
+ if {$project_new_xdata_ena} {
+ $project_new_xd_scl state !disabled
+ $project_new_xd_spb configure -state normal
+ # Disable
+ } {
+ $project_new_xd_scl state disabled
+ $project_new_xd_spb configure -state disabled
+ }
+ }
+
+ ## Enable/Disable XCODE scale & spinbox acording to $project_new_xcode_ena
+ # @return void
+ proc proj_new_xcode_disena {} {
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+
+ # Enable
+ if {$project_new_xcode_ena} {
+ $project_new_xc_scl state !disabled
+# $project_new_xc_scl configure -troughcolor {#FFFFFF}
+ $project_new_xc_spb configure -state normal
+ # Disable
+ } {
+ $project_new_xc_scl state disabled
+# $project_new_xc_scl configure -troughcolor {#AAAAAA}
+ $project_new_xc_spb configure -state disabled
+ }
+ }
+
+ ## Validate content of XCODE spinbox
+ # @parm String string - string to validate
+ # @return Bool - true if validation successful
+ proc proj_new_validate_xcode {string} {
+ variable project_new_max_xcode ;# Int: Maximum valid value of external program memory
+ if {![string is digit $string]} {
+ return 0
+ }
+ if {$string == {}} {
+ return 1
+ }
+ if {$string < 0 || $string > $project_new_max_xcode} {
+ return 0
+ }
+ return 1
+ }
+
+ ## Invoke MCU selection dialog
+ # @parm Widget win - parent window
+ # @return void
+ proc proj_new_select_mcu {win} {
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+
+ # Determinate initial XDATA memory for the dialog
+ if {$project_new_xdata_ena} {
+ set xdata $project_new_xdata
+ } {
+ set xdata 0
+ }
+ # Determinate initial XCODE memory for the dialog
+ if {$project_new_xcode_ena} {
+ set xcode $project_new_xcode
+ } {
+ set xcode 0
+ }
+
+ # Invoke dialog
+ set result [SelectMCU::activate $win [list $project_new_processor $xdata $xcode]]
+ if {$result == {}} {
+ return
+ }
+
+ # Process results
+ set project_new_processor [lindex $result 0]
+ set project_new_xdata [lindex $result 1]
+ set project_new_xcoda [lindex $result 2]
+ proj_new_mcu_changed
+
+ # Adjust XCODE & XDATA checkbuttons
+ if {$project_new_xdata} {
+ set project_new_xdata_ena 1
+ } {
+ set project_new_xdata_ena 0
+ }
+ if {$project_new_xcode} {
+ set project_new_xcode_ena 1
+ } {
+ set project_new_xcode_ena 0
+ }
+ }
+
+ ## Cancel dialog "Create new project" -- auxiliary procedure for '__proj_new'
+ # @return void
+ proc project_new_CANCEL {} {
+ grab release .project_new
+ destroy .project_new
+ }
+
+ ## Create new project -- auxiliary procedure for '__proj_new'
+ # @return void
+ proc project_new_OK {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+ variable project_new_name ;# Name of the new project
+ variable project_new_dir ;# Directory of the new project
+ variable project_edit_defaults ;# Some default project values
+ variable project_edit_clock ;# Default clock rate
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable openedProjects ;# List of opened projects (Object references)
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # This is critical procedure
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check for presence of all nessesary informations
+ if {$project_new_dir == {} || $project_new_name == {}} {
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "Ivalid request"] \
+ -message [mc "Both entries in section general must be filled."] \
+ -parent .project_new
+ set critical_procedure_in_progress 0
+ return 0
+ }
+
+ # Adjust project directory
+ regsub {[\\\/]$} $project_new_dir {} project_new_dir
+
+ # Check for validity of the specified directory
+ if {![file exists $project_new_dir] || ![file isdirectory $project_new_dir]} {
+ # Ask for creating a new directory
+ set result [tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent .project_new \
+ -title [mc "Create directory - MCU 8051 IDE"] \
+ -message [mc "The specified directory does not exist do you want to create it ?"] \
+ ]
+ if {$result == {yes}} {
+ # (Yes) -> Create new directory
+ if {[catch {file mkdir $project_new_dir}]} {
+ tk_messageBox \
+ -icon error \
+ -parent .project_new \
+ -type ok \
+ -title [mc "File access error"] \
+ -message [mc "Creation of directory '%s' FAILED !\nPlease check your permissions." $project_new_dir]
+ set critical_procedure_in_progress 0
+ return 0
+ }
+ # (No) -> Cancel
+ } else {
+ set critical_procedure_in_progress 0
+ return 0
+ }
+ } {
+ # Check if this the project does not already exist
+ if {[file exists "$project_new_dir/$project_new_name.mcu8051ide"]} {
+ # Ask for owerwrite
+ if {
+ ![tk_messageBox \
+ -icon question \
+ -type yesno \
+ -default no \
+ -parent .project_new \
+ -title [mc "File already exists - MCU 8051 IDE"] \
+ -message [mc "Some project with the same name already exists in the specified directory. \nDo you want to overwrite it ?"] \
+ ]
+ } {
+ # (No) -> Cancel
+ set critical_procedure_in_progress 0
+ return 0
+ }
+ }
+ }
+
+ # Close the dialog window
+ project_new_CANCEL
+
+ # Set project values to defaults
+ foreach default $project_edit_defaults {
+ switch -- [lindex $default 0] {
+ {project_edit_calc_rad} {
+ set calc_radix [lindex $default 1]
+ }
+ {project_edit_calc_ang} {
+ set calc_angle [lindex $default 1]
+ }
+ default {
+ set [lindex $default 0] [lindex $default 1]
+ }
+ }
+ }
+ set project_new_xdata [expr {int($project_new_xdata)}]
+ set project_new_xcode [expr {int($project_new_xcode)}]
+ set project_data [list \
+ [list {} [clock format [clock seconds] -format {%D}] {}]\
+ [list [file tail [file normalize ~]] {} {}] \
+ [list \
+ $project_new_processor \
+ $project_edit_clock \
+ $project_new_xdata \
+ $project_new_xcode] \
+ [list {} {} {} 1] \
+ [list {y} 0 0 \
+ [string repeat 0 170] \
+ [string repeat 0 170] \
+ [string repeat 0 170] \
+ {state} \
+ ] \
+ [list {} {}] \
+ [list $calc_radix $calc_angle {} {} {} {} {} {}] \
+ {} {} \
+ [list 0 [list {} {} 0 {}]] \
+ ]
+
+ # Create a new project file
+ if {[catch {
+ set prj_file [open "$project_new_dir/$project_new_name.mcu8051ide" w 420]
+ }]} then {
+ # Failed
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon error \
+ -message [mc "Unable to write to file:\n\"%s\"" $project_new_dir/$project_new_name.mcu8051ide]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Fill in the file with project definition data
+ puts -nonewline $prj_file [Project::create_project_file_as_string $project_data]
+ close $prj_file
+ set done 0
+
+ # Insure than the project descriptor is unique
+ set projectDescriptor [regsub -all -- {\s} $project_new_name {-}]
+ regsub -all {[\\\/\.\,`\!@#\$%\^&:\;\|\*\"\(\)\[\]\{\}]} $projectDescriptor \
+ {_} projectDescriptor
+
+ if {[lsearch -exact -ascii ${X::openedProjects} $projectDescriptor] != -1} {
+ append project_new_name {(0)}
+ append projectDescriptor {_0}
+
+ while 1 {
+ if {[lsearch -exact -ascii ${X::openedProjects} $projectDescriptor] == -1} {break}
+
+ regexp {\d+$} $projectDescriptor index
+ regsub {_\d+$} $projectDescriptor {} projectDescriptor
+
+ regexp {\d+\)$} $project_new_name index
+ set index [string trimright $index {\)}]
+ regsub {\(\d+\)$} $project_new_name {} project_new_name
+
+ incr index
+ append project_new_name "($index)"
+ append projectDescriptor "_$index"
+ }
+ }
+
+ # Show project notebook
+ if {$project_menu_locked} {
+ pack .mainFrame.mainNB -expand 1 -fill both
+ }
+
+ # Open created project
+ lappend openedProjects $projectDescriptor
+ lappend simulator_enabled 0
+ MainTab ::$projectDescriptor $project_new_name $project_new_dir $project_new_name.mcu8051ide $project_data
+ switch_project $projectDescriptor
+
+ ::X::recent_files_add 0 [file join [file normalize $project_new_dir] $project_new_name.mcu8051ide]
+
+ # Project opened
+ if {$project_menu_locked} {
+ Unlock_project_menu
+ }
+ disaena_menu_toolbar_for_current_project
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Disable menu items and functions functions which are
+ # avaliable only if there is at least one opened project
+ # @return void
+ proc Lock_project_menu {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable toolbar_project_dependent_buttons ;# Toolbar buttons which require opened project
+ variable mainmenu_project_dependent_buttons ;# Menu bar items which require opened project
+
+ # Hide project notebook
+ pack forget .mainFrame.mainNB
+
+ # Disable menu items
+ set project_menu_locked 1
+ ena_dis_menu_buttons 0 $mainmenu_project_dependent_buttons
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_project_dependent_buttons
+ adjust_mm_and_tb_ext_editor
+ }
+
+ ## Enable menu items and functions functions which are avaliable only if there
+ # is at least one opened project and create NoteBook for project tabs
+ # @return void
+ proc Unlock_project_menu {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable toolbar_project_dependent_buttons ;# Toolbar buttons which require opened project
+ variable mainmenu_project_dependent_buttons ;# Menu bar items which require opened project
+ variable toolbar_simulator_engaged ;# Toolbar buttons which require ENGAGED simulator
+ variable mainmenu_simulator_engaged ;# Menu bar items which require ENGAGED simulator
+
+ # Enable menu items
+ set project_menu_locked 0
+ ena_dis_menu_buttons 1 $mainmenu_project_dependent_buttons
+ ena_dis_menu_buttons 0 $mainmenu_simulator_engaged
+ ena_dis_iconBar_buttons 1 .mainIconBar. $toolbar_project_dependent_buttons
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_simulator_engaged
+ adjust_mm_and_tb_ext_editor
+ }
+
+ ## Disable menu entries and toolbar buttons which are functional on when simulator is on
+ # @return void
+ proc Lock_simulator_menu {} {
+ variable toolbar_simulator_disengaged ;# Toolbar buttons which require DISENGAGED simulator
+ variable toolbar_simulator_engaged ;# Toolbar buttons which require ENGAGED simulator
+ variable mainmenu_simulator_engaged ;# Menu bar items which require ENGAGED simulator
+ variable mainmenu_simulator_disengaged ;# Menu bar items which require DISENGAGED simulator
+
+ ena_dis_menu_buttons 1 $mainmenu_simulator_disengaged
+ ena_dis_menu_buttons 0 $mainmenu_simulator_engaged
+ ena_dis_iconBar_buttons 1 .mainIconBar. $toolbar_simulator_disengaged
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_simulator_engaged
+ adjust_mm_and_tb_ext_editor
+ }
+
+ ## Enable menu entries and toolbar buttons which are functional on when simulator is on
+ # @return void
+ proc Unlock_simulator_menu {} {
+ variable toolbar_simulator_disengaged ;# Toolbar buttons which require DISENGAGED simulator
+ variable toolbar_simulator_engaged ;# Toolbar buttons which require ENGAGED simulator
+ variable mainmenu_simulator_engaged ;# Menu bar items which require ENGAGED simulator
+ variable mainmenu_simulator_disengaged ;# Menu bar items which require DISENGAGED simulator
+
+ ena_dis_menu_buttons 0 $mainmenu_simulator_disengaged
+ ena_dis_menu_buttons 1 $mainmenu_simulator_engaged
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_simulator_disengaged
+ ena_dis_iconBar_buttons 1 .mainIconBar. $toolbar_simulator_engaged
+ adjust_mm_and_tb_ext_editor
+ }
+
+ ## Open project
+ # @return void
+ proc __proj_open {} {
+ variable defaultDirectory ;# Default directory
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Invoke project selection dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Open project - MCU 8051 IDE"] \
+ -directory $defaultDirectory \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{MCU 8051 IDE project} {*.mcu8051ide} }
+ {{All files} {*} }
+ }
+
+ # Open the selected after press of OK button
+ fsd setokcmd {
+ set filename [X::fsd get]
+ X::fsd deactivate
+ if {![Project::open_project_file $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent . \
+ -title [mc "Error - MCU 8051 IDE"] \
+ -message [mc "Unable to load file: %s" $filename]
+ } {
+ ${::X::actualProject} editor_procedure {} highlight_visible_area {}
+ ::X::recent_files_add 0 $filename
+ }
+ }
+
+ fsd activate ;# Activate the dialog
+
+ adjust_title
+ disaena_menu_toolbar_for_current_project
+ set critical_procedure_in_progress 0
+ }
+
+ ## Retrieve project related data from object of the current project
+ # @parm Bool all_info - All data (include todo list and such)
+ # @return void
+ proc Project_retrieve_data_from_application {all_info} {
+ variable actualProject ;# Object: Current project
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_authors ;# Project authors
+ variable project_edit_description ;# Project description
+ variable project_edit_main_file ;# Project main file
+ variable project_watches_file ;# File of register watches definition
+ variable project_todo ;# Todo text
+ variable project_graph ;# Graph configuration list
+ variable project_calculator ;# Calculator list (display contents, etc.)
+ variable project_other_options ;# Other project options
+ variable project_compiler_options ;# Compiler options
+ variable project_files ;# List of project files (special format)
+ variable project_file ;# Full name of the project file
+ variable project_dir ;# Path to project directory
+ variable project_edit_clock ;# Default clock rate
+ variable project_scenario_file ;# Scenario file
+
+ set project_edit_version [ $actualProject cget -P_information_version ]
+ set project_edit_date [ $actualProject cget -P_information_date ]
+ set project_edit_authors [ $actualProject cget -G_information_authors ]
+ set project_edit_copyright [ $actualProject cget -G_information_copyright ]
+ set project_edit_licence [ $actualProject cget -G_information_licence ]
+ set project_edit_clock [ $actualProject cget -P_option_clock ]
+ set project_edit_description [ $actualProject cget -project_description ]
+ set project_new_processor [ $actualProject cget -P_option_mcu_type ]
+ set project_new_xdata [ $actualProject cget -P_option_mcu_xdata ]
+ set project_new_xcode [ $actualProject cget -P_option_mcu_xcode ]
+ set project_edit_main_file [ $actualProject cget -P_option_main_file ]
+ set project_new_xdata_ena 0
+ set project_new_xcode_ena 0
+ if {$project_new_xdata} {set project_new_xdata_ena 1}
+ if {$project_new_xcode} {set project_new_xcode_ena 1}
+ if {$all_info} {
+ set project_graph [ $actualProject graph_get_config ]
+ set project_todo [ $actualProject TodoProc_read_text_as_sgml ]
+ set project_calculator [ $actualProject get_calculator_list ]
+ set project_other_options [ $actualProject cget -other_options ]
+ set project_files [ $actualProject get_project_files_list ]
+ set project_file [ $actualProject cget -projectFile ]
+ set project_dir [ $actualProject cget -projectPath ]
+ set project_watches_file [ $actualProject getWatchesFileName ]
+ set project_scenario_file [ $actualProject pale_get_scenario_filename ]
+ set project_compiler_options [ $actualProject get_compiler_config ]
+ }
+ }
+
+ ## Free some resources reserved by procedure 'Project_retrieve_data_from_application'
+ # @return void
+ proc Project_RDFA_cleanup {} {
+ variable project_watches_file {} ;# File of register watches of the current poject
+ variable project_scenario_file {} ;# Scenario file
+ variable project_todo {} ;# Todo text
+ variable project_graph {} ;# Graph configuration list
+ variable project_calculator {} ;# Calculator list (display contents, etc.)
+ variable project_other_options {} ;# Other project options
+ variable project_compiler_options {} ;# Compiler options
+ variable project_files {} ;# List of project files (special format)
+ variable project_file {} ;# Full name of the project file
+ variable project_dir {} ;# Path to project directory
+ variable project_edit_clock {} ;# Default clock rate
+ }
+
+ ## Save the current project
+ # @return void
+ proc __proj_save {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_authors ;# Project authors
+ variable project_edit_description ;# Project description
+ variable project_edit_clock ;# Default clock rate
+ variable project_edit_main_file ;# Project main file
+ variable project_todo ;# Todo text
+ variable project_graph ;# Graph configuration list
+ variable project_calculator ;# Calculator list (display contents, etc.)
+ variable project_other_options ;# Other project options
+ variable project_compiler_options ;# Compiler options
+ variable project_files ;# List of project files (special format)
+ variable project_file ;# Full name of the project file
+ variable project_dir ;# Path to project directory
+ variable project_watches_file ;# File of register watches of the current poject
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable project_scenario_file ;# Scenario file
+
+ if {$project_menu_locked} {return}
+
+ # This is critical procedure
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Save register watches definition file
+ if {[$actualProject rightPanel_watch_modified]} {
+ $actualProject rightPanel_watch_save {} 1
+ }
+
+ # Save PALE Virtual HW connections
+ if {[$actualProject pale_modified]} {
+ $actualProject pale_save_scenario_file
+ }
+
+ # Create project definition data
+ Project_retrieve_data_from_application 1
+ set project_data [list \
+ [list \
+ [Project::escape_curlies $project_edit_version] \
+ [Project::escape_curlies $project_edit_date] \
+ ${::VERSION}] \
+ [list \
+ $project_edit_authors \
+ [Project::escape_curlies $project_edit_copyright] \
+ [Project::escape_curlies $project_edit_licence]] \
+ [list \
+ $project_new_processor \
+ $project_edit_clock \
+ $project_new_xdata \
+ $project_new_xcode] \
+ [list \
+ $project_watches_file \
+ $project_scenario_file \
+ $project_edit_main_file \
+ [$actualProject get_file_switching_enabled]] \
+ $project_graph \
+ [list \
+ [Project::escape_curlies $project_edit_description] \
+ [Project::escape_curlies $project_todo]] \
+ $project_calculator \
+ [Project::escape_curlies $project_other_options] \
+ [list $project_compiler_options] \
+ $project_files \
+ ]
+
+ set project_data [Project::create_project_file_as_string $project_data]
+ set filename "$project_dir/$project_file"
+ Project_RDFA_cleanup
+
+ # Create backup copy for the project file
+ if {[file exists $filename]} {
+ catch {
+ file rename -force $filename "$filename~"
+ }
+ }
+
+ # Save project definition file
+ if {[catch {
+ set prj_file [open $filename w 420]
+ }]} then {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to write to file:\n\"%s\"" $filename]
+ set critical_procedure_in_progress 0
+ return
+ }
+ puts -nonewline $prj_file $project_data
+ close $prj_file
+
+ # Done ...
+ Sbar [mc "Project saved to %s" $filename]
+ set critical_procedure_in_progress 0
+ }
+
+ ## Invoke dialog "Edit project"
+ # @return void
+ proc __proj_edit {} {
+ variable actualProject ;# Object: Current project
+ variable avaliable_processors ;# List of supported processors
+
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_authors ;# Project authors
+ variable project_edit_description ;# Project description
+ variable project_edit_clock ;# Default clock rate
+ variable project_edit_main_file ;# Project main file
+
+ variable project_edit_main_file_clr_but ;# Widget: Project main file clear button
+
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ variable project_new_processor {8051} ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena 0 ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena 0 ;# Bool: XCODE memory connected
+ variable project_new_xdata 0 ;# Int: Amount of XDATA memory
+ variable project_new_xcode 0 ;# Int: Amount of XCODE memory
+ variable project_new_max_xcode 0 ;# Int: Maximum valid value of external program memory
+ variable project_new_xd_chb ;# Widget: XDATA enable checkbutton
+ variable project_new_xd_scl ;# Widget: XDATA scale
+ variable project_new_xd_spb ;# Widget: XDATA spinbox
+ variable project_new_xc_chb ;# Widget: XCODE enable checkbutton
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Retrieve existing informations about the project
+ Project_retrieve_data_from_application 0
+
+ # Create dialog window
+ set win [toplevel .project_edit -class {Edit project} -bg {#EEEEEE}]
+
+ # Create main frames (top.left; top.right; bottom)
+ set top_frame [frame $win.top]
+ set bottom_frame [frame $win.bottom]
+ set top_left_frame [frame $top_frame.left]
+ set top_right_frame [frame $top_frame.right]
+
+ ## GENERAL INFORMATION (version, date, authors, copyright, licence)
+ label $win.lb_general_info_label \
+ -compound left \
+ -text [mc "General information"] \
+ -image ::ICONS::16::contents
+ set lb_general_info [ttk::labelframe $top_left_frame.lb_general_info \
+ -labelwidget $win.lb_general_info_label -padding 7 \
+ ]
+ pack $lb_general_info -fill both -expand 1
+
+ set bframe [frame $lb_general_info.bframe]
+ pack $bframe -fill x -expand 1 -anchor w
+
+ # version
+ grid [Label $bframe.version_label \
+ -text [mc "Version"] \
+ -helptext [mc "Project version (any string)"] \
+ ] -row 1 -column 1 -sticky w
+ grid [ttk::entry $bframe.version_entry \
+ -textvariable X::project_edit_version \
+ -validate key \
+ -validatecommand {::X::project_edit_validate %P} \
+ ] -row 1 -column 2 -sticky we -columnspan 2
+ DynamicHelp::add $bframe.version_entry -text [mc "Project version (any string)"]
+
+ # date
+ grid [Label $bframe.date_label \
+ -text [mc "Date"] \
+ -helptext [mc "Project last update"] \
+ ] -row 2 -column 1 -sticky w
+ grid [ttk::entry $bframe.date_entry \
+ -textvariable X::project_edit_date \
+ -validate key \
+ -validatecommand {::X::project_edit_validate %P} \
+ ] -row 2 -column 2 -sticky we
+ DynamicHelp::add $bframe.date_entry -text [mc "Project last update"]
+
+ # button 'today'
+ grid [ttk::button $bframe.now \
+ -style Flat.TButton \
+ -takefocus 0 \
+ -image ::ICONS::16::today \
+ -command {X::project_edit_today} \
+ ] -row 2 -column 3 -sticky e
+ DynamicHelp::add $bframe.now -text [mc "Fill date entry with the current date"]
+
+ # copyright
+ grid [Label $bframe.copyright_label \
+ -text [mc "Copyright"] \
+ -helptext [mc "Copyright information"] \
+ ] -row 3 -column 1 -sticky w
+ grid [ttk::entry $bframe.copyright_entry \
+ -textvariable X::project_edit_copyright \
+ -validate key \
+ -validatecommand {::X::project_edit_validate %P} \
+ ] -row 3 -column 2 -sticky we -columnspan 2
+ DynamicHelp::add $bframe.copyright_entry -text [mc "Copyright information"]
+
+ # licence
+ grid [Label $bframe.licence_label \
+ -text [mc "Licence"] \
+ -helptext [mc "Name of the licence"] \
+ ] -row 4 -column 1 -sticky w
+ grid [ttk::entry $bframe.licence_entry \
+ -textvariable X::project_edit_licence \
+ -validate key \
+ -validatecommand {::X::project_edit_validate %P} \
+ ] -row 4 -column 2 -sticky we -columnspan 2
+ DynamicHelp::add $bframe.licence_entry -text [mc "Name of the licence"]
+
+ # authors
+ set tframe [frame .project_edit.top.left.lb_general_info.tframe]
+ pack $tframe -fill both -expand 1 -padx 5
+ pack [Label $tframe.label \
+ -text [mc "Authors:"] \
+ -helptext {List of project authors (one per line)} \
+ ] -anchor w
+ pack [frame $tframe.frame] -fill both -expand 1
+
+ pack [text $tframe.frame.text \
+ -width 0 -height 0 \
+ -yscrollcommand "$tframe.frame.scrollbar set" \
+ ] -fill both -expand 1 -side left
+ $tframe.frame.text insert end $project_edit_authors
+ pack [ttk::scrollbar $tframe.frame.scrollbar \
+ -orient vertical \
+ -command "$tframe.frame.text yview" \
+ ] -fill y -side right
+
+ ## Simulator & Compiler (MCU type, XDATA + XCODE memory + CLOCK)
+ label $win.lb_compiler_label \
+ -compound left \
+ -text [mc "Processor"] \
+ -image ::ICONS::16::kcmmemory
+ set lb_compiler [ttk::labelframe $top_right_frame.lb_compiler \
+ -labelwidget $win.lb_compiler_label \
+ ]
+ set proc_frame_top0 [frame $lb_compiler.top0]
+ set proc_frame_top1 [frame $lb_compiler.top1]
+ set proc_frame_middle [frame $lb_compiler.middle]
+ set proc_frame_middle_left [ttk::labelframe $proc_frame_middle.middle \
+ -padding 5 -text [mc "XDATA"]]
+ set proc_frame_middle_right [ttk::labelframe $proc_frame_middle.right \
+ -padding 5 -text [mc "XCODE"]]
+
+ # MCU clock frequency
+ grid [Label $proc_frame_top1.clock_label \
+ -text [mc "Clock \[kHz\]:"] -width 11 -anchor w \
+ -helptext [mc "Default clock used by simulator engine"] \
+ ] -row 0 -column 1 -sticky w
+ grid [ttk::entry $proc_frame_top1.clock_entry \
+ -width 10 \
+ -textvariable X::project_edit_clock \
+ -validate key \
+ -validatecommand {::X::project_edit_CLOCK_validate %P} \
+ ] -row 0 -column 3 -sticky w
+ DynamicHelp::add $proc_frame_top1.clock_entry \
+ -text [mc "Default clock used by simulator engine"]
+
+ # Main file
+ grid [Label $proc_frame_top1.file_label \
+ -text [mc "Main file:"] -width 11 -anchor w \
+ -helptext [mc "Project main file (e.g. main.c)\n(empty string means always compile current file)"] \
+ ] -row 1 -column 1 -sticky w
+ set project_edit_main_file_clr_but [ttk::button \
+ $proc_frame_top1.clear_but \
+ -style Flat.TButton \
+ -takefocus 0 \
+ -image ::ICONS::16::locationbar_erase \
+ -command {set ::X::project_edit_main_file {}} \
+ -state disabled \
+ ]
+ DynamicHelp::add $proc_frame_top1.clear_but -text [mc "Clear"]
+ grid $project_edit_main_file_clr_but -row 1 -column 2 -sticky w
+ grid [ttk::entry $proc_frame_top1.file_entry \
+ -width 25 \
+ -validate all \
+ -validatecommand {::X::proj_edit_mf_validator %P} \
+ -textvariable X::project_edit_main_file \
+ ] -row 1 -column 3 -sticky we
+ DynamicHelp::add $proc_frame_top1.file_entry \
+ -text [mc "Project main file (e.g. main.c)\n(empty string means always compile current file)"]
+ grid [ttk::button $proc_frame_top1.file_select_but \
+ -style Flat.TButton \
+ -takefocus 0 \
+ -image ::ICONS::16::fileopen \
+ -command {X::project_edit_select_main_file} \
+ ] -row 1 -column 4 -sticky e -pady 5
+ DynamicHelp::add $proc_frame_top1.file_select_but -text [mc "Select main file"]
+
+ # Create components of top frame (Type: <ComboBox> <Button>)
+ pack [label $proc_frame_top0.lbl -text [mc "Type:"] -width 14 -anchor w] -side left
+ pack [ttk::combobox $proc_frame_top0.combo \
+ -values $avaliable_processors \
+ -state readonly \
+ -textvariable ::X::project_new_processor\
+ ] -side left -fill x
+ bind $proc_frame_top0.combo <<ComboboxSelected>> {::X::proj_new_mcu_changed}
+ DynamicHelp::add $proc_frame_top0.combo -text [mc "Selected uC"]
+
+ pack [ttk::button $proc_frame_top0.but \
+ -text [mc "Select MCU"] \
+ -image ::ICONS::16::back \
+ -compound left \
+ -command {::X::proj_new_select_mcu .project_edit} \
+ ] -side right -after $proc_frame_top0.combo -padx 5
+ DynamicHelp::add $proc_frame_top0.combo -text [mc "Choose processor from database"]
+
+ # Create components of XDATA labelframe
+ set project_new_xd_chb [checkbutton $proc_frame_middle_left.checkbutton \
+ -variable ::X::project_new_xdata_ena \
+ -text [mc "Enable"] \
+ -command ::X::proj_new_xdata_disena \
+ ]
+ pack $project_new_xd_chb -anchor w
+ DynamicHelp::add $proc_frame_middle_left.checkbutton \
+ -text [mc "Connect external data memory"]
+ set proc_frame_left_btm [frame $proc_frame_middle_left.btm]
+ set project_new_xd_scl [ttk::scale $proc_frame_left_btm.scale \
+ -orient horizontal \
+ -variable ::X::project_new_xdata \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::X::project_new_xdata \[expr {int(\${::X::project_new_xdata})}\]
+ $proc_frame_left_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $project_new_xd_scl \
+ -text [mc "Size of external data memory"]
+ pack $project_new_xd_scl -fill x -side left -expand 1 -padx 2
+ set project_new_xd_spb [spinbox $proc_frame_left_btm.spinbox \
+ -textvariable ::X::project_new_xdata \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::SelectMCU::validate_xdata %P} \
+ -command "$proc_frame_left_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $project_new_xd_spb \
+ -text [mc "Size of external data memory"]
+ pack $project_new_xd_spb -side right -after $project_new_xd_scl
+ pack $proc_frame_left_btm -fill both -expand 1
+
+ # Create components of XCODE labelframe
+ set project_new_xc_chb [checkbutton $proc_frame_middle_right.checkbutton \
+ -variable ::X::project_new_xcode_ena \
+ -text [mc "Enable"] \
+ -command ::X::proj_new_xcode_disena \
+ ]
+ pack $project_new_xc_chb -anchor w
+ DynamicHelp::add $proc_frame_middle_right.checkbutton \
+ -text [mc "Connect external program memory"]
+ set proc_frame_right_btm [frame $proc_frame_middle_right.btm]
+ set project_new_xc_scl [ttk::scale $proc_frame_right_btm.scale \
+ -orient horizontal \
+ -variable ::X::project_new_xcode \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::X::project_new_xcode \[expr {int(\${::X::project_new_xcode})}\]
+ $proc_frame_right_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $project_new_xc_scl \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $project_new_xc_scl -fill x -side left -expand 1 -padx 2
+ set project_new_xc_spb [spinbox $proc_frame_right_btm.spinbox \
+ -textvariable ::X::project_new_xcode \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::X::proj_new_validate_xcode %P} \
+ -command "$proc_frame_right_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $project_new_xc_spb \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $project_new_xc_spb -side right -after $project_new_xc_scl
+ pack $proc_frame_right_btm -fill both -expand 1
+
+ pack $proc_frame_top0 -anchor w -pady 5 -padx 10
+ pack $proc_frame_top1 -anchor w -pady 5 -padx 10
+ pack $proc_frame_middle_left -side left -fill x -expand 1 -padx 7
+ pack $proc_frame_middle_right -side left -fill x -expand 1 -padx 7
+ pack $proc_frame_middle -fill both -expand 1 -pady 5
+ pack $lb_compiler -fill both -expand 1
+
+ # Adjust XDATA & XCODE controls
+ proj_new_mcu_changed
+
+ ## PROJECT DESCRIPTION
+ label $win.lb_desc_label \
+ -compound left \
+ -text [mc "Project description"] \
+ -image ::ICONS::16::edit
+ set lb_desc [ttk::labelframe $bottom_frame.lb_desc \
+ -labelwidget $win.lb_desc_label -padding 7 \
+ ]
+ pack $lb_desc -fill both -expand 1
+ pack [text $lb_desc.text \
+ -width 0 -height 7 \
+ -yscrollcommand "$lb_desc.scrollbar set" \
+ ] -fill both -expand 1 -side left
+ $lb_desc.text insert end $project_edit_description
+ pack [ttk::scrollbar $lb_desc.scrollbar \
+ -orient vertical \
+ -command "$lb_desc.text yview" \
+ ] -side right -fill y
+
+ # Pack main frames
+ pack $top_left_frame -fill both -expand 1 -padx 5 -side left -pady 10
+ pack $top_right_frame -fill both -expand 1 -padx 5 -side right -pady 10
+ pack $top_frame -fill both -expand 1 -pady 5
+ pack $bottom_frame -fill both -expand 1 -pady 5 -padx 5
+
+ # Buttons 'Ok' and 'Cancel'
+ pack [ttk::separator $win.separator -orient horizontal] -pady 5 -fill x
+ set buttons [frame $win.buttons]
+ pack [ttk::button $buttons.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::project_edit_OK} \
+ ] -side left -padx 5
+ pack [ttk::button $buttons.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::project_edit_CANCEL} \
+ ] -side left -padx 5
+ pack $buttons -anchor center -pady 5
+
+ # Setup some nessesary window manager options -- for modal window
+ wm iconphoto $win ::ICONS::16::edit
+ wm title $win [mc "Edit project - MCU 8051 IDE"]
+ wm minsize $win 660 440
+ wm protocol $win WM_DELETE_WINDOW {
+ X::project_edit_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Project main file EntryBox validator
+ # Enables/Disables project main file clear button
+ # @parm String string - EntryBox contents
+ # @return Bool - allways 1
+ proc proj_edit_mf_validator {string} {
+ variable project_edit_main_file_clr_but ;# Widget: Project main file clear button
+ if {[string length $string]} {
+ $project_edit_main_file_clr_but configure -state normal
+ } {
+ $project_edit_main_file_clr_but configure -state disabled
+ }
+ return 1
+ }
+
+ ## Select project main file
+ # -- Auxiliary procedure for __proj_edit
+ # @return void
+ proc project_edit_select_main_file {} {
+ variable project_edit_main_file ;# Project main file
+ variable actualProject ;# Object: Current project
+
+ set ext [file extension $project_edit_main_file]
+ if {$ext == {.asm} || $ext == {.inc}} {
+ set defaultmask 0
+ } elseif {$ext == {.c} || $ext == {.cpp} || $ext == {.cc} || $ext == {.cxx}} {
+ set defaultmask 1
+ } elseif {$ext == {.h}} {
+ set defaultmask 2
+ } {
+ set defaultmask 3
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -initialfile $project_edit_main_file \
+ -directory [$actualProject cget -projectPath] \
+ -title [mc "Select main file - %s - MCU 8051 IDE" $actualProject] \
+ -defaultmask $defaultmask -multiple 0 -filetypes [list \
+ [list [mc "Assembly language"] {*.asm} ] \
+ [list [mc "C source"] {*.c} ] \
+ [list [mc "C header"] {*.h} ] \
+ [list [mc "All files"] {*} ] \
+ ]
+ fsd setokcmd {
+ set ::X::project_edit_main_file [X::fsd get]
+ if {![string first [$::X::actualProject cget -projectPath] $::X::project_edit_main_file]} {
+ set ::X::project_edit_main_file \
+ [string replace $::X::project_edit_main_file \
+ 0 [string length [$::X::actualProject cget -projectPath]]]
+ }
+ }
+ fsd activate
+ }
+
+ ## Validate content of entry wingets in dialog "Edit project"
+ # -- axiliary procedure for '__proj_edit'
+ # @parm String string - String to validate
+ # @return Bool - result
+ proc project_edit_validate {string} {
+ if {[string length $string] > 40} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Set project date to today -- axiliary procedure for '__proj_edit'
+ # @return void
+ proc project_edit_today {} {
+ variable project_edit_date ;# Project date (last update)
+
+ set sec [clock seconds]
+ set project_edit_date [clock format $sec -format {%D}]
+ }
+
+ ## Validate content of clock entry in dialog "Edit project"
+ # -- axiliary procedure for '__proj_edit'
+ # @parm String number - String to validate
+ # @return Bool - result
+ proc project_edit_CLOCK_validate {number} {
+ if {![regexp {^\d*$} $number]} {return 0}
+ if {$number > 99999} {return 0}
+ return 1
+ }
+
+ ## Cancel dialog "Edit project" -- axiliary procedure for '__proj_edit'
+ # @return void
+ proc project_edit_CANCEL {} {
+ grab release .project_edit
+ destroy .project_edit
+ }
+
+ ## Save project values -- axiliary procedure for '__proj_edit'
+ # @return void
+ proc project_edit_OK {} {
+ variable actualProject ;# Object: Current project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_clock ;# Default clock rate
+ variable project_edit_main_file ;# Project main file
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ variable projectdetails_last_project {} ;# Project object of the last project details window
+
+ # Adjust XCODE & XDATA values
+ if {!$project_new_xdata_ena} {
+ set project_new_xdata 0
+ }
+ if {!$project_new_xcode_ena} {
+ set project_new_xcode 0
+ }
+
+ # Adjust values
+ if {$project_edit_clock == {}} {
+ set project_edit_clock [lindex $project_edit_defaults {1 1}]
+ }
+ set project_new_xdata [expr {int($project_new_xdata)}]
+ set project_new_xcode [expr {int($project_new_xcode)}]
+
+ # Determinate original values
+ set xdata_prev [$actualProject cget -P_option_mcu_xdata]
+ set xcode_prev [$actualProject cget -P_option_mcu_xcode]
+ set proc_prev [$actualProject cget -P_option_mcu_type]
+
+ # Change object variables
+ foreach parm {
+ P_option_mcu_xdata P_option_mcu_xcode P_information_version
+ P_information_date G_information_licence G_information_copyright
+ P_option_clock P_option_mcu_type P_option_main_file
+ } \
+ value {
+ project_new_xdata project_new_xcode project_edit_version
+ project_edit_date project_edit_licence project_edit_copyright
+ project_edit_clock project_new_processor project_edit_main_file
+ } {
+ $actualProject configure -$parm [subst "\$$value"]
+ }
+ $actualProject Simulator_set_clock $project_edit_clock
+ $actualProject configure -project_description \
+ [.project_edit.bottom.lb_desc.text get 1.0 end-1c]
+ $actualProject configure -G_information_authors \
+ [.project_edit.top.left.lb_general_info.tframe.frame.text get 1.0 end-1c]
+
+ ## Adjust simulator control panel, register watches and hexeditors
+ # Hex editors
+ close_hexedit eram $actualProject
+ close_hexedit eeprom $actualProject
+ close_hexedit eeprom_wr_bf $actualProject
+ if {$xdata_prev != $project_new_xdata} {
+ close_hexedit xdata $actualProject
+ $actualProject simulator_resize_xdata_memory $project_new_xdata
+ }
+ if {$xcode_prev != $project_new_xcode} {
+ close_hexedit code $actualProject
+ $actualProject simulator_resize_code_memory \
+ [expr {$project_new_xcode + 0xFFFF - [$project_new_xc_spb cget -to]}]
+ }
+ # Simulator control panel and register watches
+ if {$proc_prev != $project_new_processor} {
+ change_processor $project_new_processor
+ }
+ # Adjust register watches
+ if {$xdata_prev != $project_new_xdata && $proc_prev == $project_new_processor} {
+ $actualProject rightPanel_watch_force_enable
+ $actualProject rightPanel_watch_sync_all
+ $actualProject rightPanel_watch_disable
+ }
+ # Menu and toolbar
+ disena_simulator_menu $actualProject
+
+ # Finalize
+ Sbar [mc "New values saved."]
+ project_edit_CANCEL ;# Close the dialog
+ return 1
+ }
+
+ ## Change current MCU even in running simulator
+ # @parm String new_processor - Processor type
+ # @return void
+ proc change_processor {new_processor} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProject ;# Object: Current project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+
+ set intr_mon_opeded [$actualProject interrupt_monitor_is_opened]
+ set was_enabled [lindex $simulator_enabled $actualProjectIdx]
+ if {$was_enabled} {
+ set tmp $critical_procedure_in_progress
+ set critical_procedure_in_progress 0
+ __initiate_sim
+ }
+
+ $actualProject configure -P_option_mcu_type $new_processor
+ $actualProject configure -procData \
+ [SelectMCU::get_processor_details $new_processor]
+ $actualProject refresh_project_avaliable_SFR
+
+ $actualProject stack_monitor_monitor_close
+ $actualProject interrupt_monitor_close
+ $actualProject simulator_initialize_mcu
+ $actualProject SimGUI_clean_up
+ $actualProject simulator_itialize_simulator_control_panel
+ $actualProject graph_itialize_simulator_graph_panel {}
+
+ $actualProject sfrmap_commit_new_sfr_set
+ $actualProject rightPanel_watch_force_enable
+ $actualProject rightPanel_watch_sync_all
+ $actualProject rightPanel_watch_disable
+ $actualProject sfr_watches_commit_new_sfr_set
+ $actualProject pale_MCU_changed
+
+ if {$was_enabled} {
+ __initiate_sim
+ set critical_procedure_in_progress $tmp
+ }
+ if {$intr_mon_opeded} {
+ $actualProject interrupt_monitor_invoke_dialog
+ }
+
+ # Refresh syntax highligh in all editors
+ foreach e [$actualProject cget -editors] {
+ $e parseAll
+ }
+ }
+
+ ## Close the current project
+ # @return void
+ proc __proj_close {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ __proj_save ;# Save project
+ $actualProject editor_close_all 0 1 ;# Close all opened files
+ close_project ;# Close project
+ }
+
+ ## Close the current project without saving
+ # @return Bool - project closed
+ proc __proj_close_imm {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+
+ if {$project_menu_locked} {return}
+
+ set modified 0
+ foreach e [$actualProject cget -editors] {
+ if {[$e cget -modified]} {
+ set modified 1
+ break
+ }
+ }
+
+ set response {yes}
+
+ # Invoke confirmation dialog
+ if {$modified} {
+ set response [tk_messageBox \
+ -icon question \
+ -parent . \
+ -type yesno \
+ -title [mc "Requesting confirmation %s" ${::APPNAME}] \
+ -message [mc "Are you sure want to close the project without saving changes ?"] \
+ ]
+ }
+ # Close project
+ if {$response == {yes}} {
+ close_project
+ return 1
+ } {
+ return 0
+ }
+ }
+
+ ## Close the current project -- auxiliary procedure for '__proj_close_imm' and '__proj_close'
+ # @return void
+ proc close_project {} {
+ variable compilation_mess_project ;# Object: Project related to running compilation
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable openedProjects ;# List of opened projects (Object references)
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Abort running compilation
+ if {$compilation_in_progress && $compilation_mess_project == $actualProject} {
+ __abort_compilation
+ }
+
+ # Abort running simulation
+ if {$actualProjectIdx != -1 && ([lindex $simulator_enabled $actualProjectIdx] == 1)} {
+ set critical_procedure_in_progress 0
+ __initiate_sim
+ set critical_procedure_in_progress 1
+ }
+
+ # Delete project object
+ close_hexedit xdata $actualProject
+ close_hexedit code $actualProject
+ close_hexedit eram $actualProject
+ close_hexedit eeprom $actualProject
+ delete object $actualProject
+ # Adjust list of opened project and simlator started flag
+ set openedProjects [lreplace $openedProjects $actualProjectIdx $actualProjectIdx]
+ set simulator_enabled [lreplace $simulator_enabled $actualProjectIdx $actualProjectIdx]
+
+ # Raise nex tab or disable project menu and procedures
+ if {[llength $openedProjects] > 0} {
+ set actualProject [lindex $openedProjects 0]
+ .mainFrame.mainNB raise [string trimleft $actualProject {:}]
+ } {
+ set project_menu_locked 1
+ Lock_project_menu
+ }
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Compile current file
+ # @parm Bool = 0 - Force compilation -- ignore running critical procedure
+ # @parm Bool = 0 - Start simulator after successful compilation
+ # @parm Bool = 0 - Compile current file only (not the main file)
+ # @return Bool - result or {}
+ proc __compile args {
+ variable compilation_successfull ;# Bool: Compilation successfull
+ variable actualProject ;# Object: Current project
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable compiler_pid ;# Int: PID of external compiler if used
+ variable compilation_start_simulator ;# Bool: Start simulator after successful compilation
+ variable compile_this_file_only ;# Bool: Compile the current file only
+ variable compilation_mess_project ;# Object: Project related to running compilation
+
+ # Parse input arguments
+ if {[lindex $args 0] == 1} {
+ set force 1
+ } {
+ set force 0
+ }
+ if {[lindex $args 1] == 1} {
+ set compilation_start_simulator 1
+ } {
+ set compilation_start_simulator 0
+ }
+ if {[lindex $args 2] == 1} {
+ set compile_this_file_only 1
+ } {
+ set compile_this_file_only 0
+ }
+
+ if {$project_menu_locked} {return}
+ if {!$force && $critical_procedure_in_progress} {return}
+ if {$compilation_in_progress} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to run assembler"] \
+ -message [mc "Something is already running in background."]
+ return 0
+ }
+
+ # Compilation started
+ set compilation_mess_project $actualProject
+ set compilation_successfull 1
+ set result 0
+ set compiler_pid 0
+ set compilation_in_progress 1
+ set Compiler::Settings::ABORT_VARIABLE 0
+ # Save current file
+ if {![$actualProject editor_procedure {} save {}]} {
+ set compilation_in_progress 0
+ return 0
+ }
+ # Raise tab "Messages"
+ $actualProject bottomNB_show_up {Messages}
+ # Determinate name of file to compile
+ if {$compile_this_file_only} {
+ set input_file {}
+ } {
+ set input_file [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ }
+ if {[lindex $input_file 1] == {}} {
+ set input_file [$actualProject editor_procedure {} getFileName {}]
+ set language [$actualProject editor_procedure {} get_language {}]
+ } {
+ set ext [string trimleft [file extension [lindex $input_file 1]] {.}]
+ if {$ext == {c} || $ext == {h} || $ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set language 1
+ } elseif {$ext == {lst}} {
+ set language 2
+ } else {
+ set language 0
+ }
+ }
+ # Adjust filename
+ set cur_dir [lindex $input_file 0]
+ set input_file_name [lindex $input_file 1]
+ if {[regexp {\.[^\.]*$} $input_file_name input_file_extension]} {
+ regsub {\.[^\.]*$} $input_file_name {} input_file_name
+ set input_file_extension [string range $input_file_extension 1 end]
+ } {
+ set input_file_extension {}
+ }
+ # Asjust file extension
+ if {$input_file_extension == {h}} {
+ set input_file_extension {c}
+ } elseif {$input_file_extension == {lst}} {
+ set input_file_extension {asm}
+ }
+
+ # Adjust statusbar
+ Sbar [mc "Compiling ..."]
+ make_progressBar_on_Sbar
+ compilation_progress
+
+ # Determinate memory limits
+ set iram_size [lindex [$actualProject cget -procData] 3]
+ set eram_size [lindex [$actualProject cget -procData] 8]
+ set xram_size [$actualProject cget -P_option_mcu_xdata]
+ if {$eram_size > $xram_size} {
+ set xram_size $eram_size
+ }
+ set code_size [expr {
+ ([lindex [$actualProject cget -procData] 2] * 1024)
+ +
+ [$actualProject cget -P_option_mcu_xcode]
+ }]
+
+ ## C language
+ if {$language == 1} {
+ if {!${::PROGRAM_AVALIABLE(sdcc)} && !${::PROGRAM_AVALIABLE(sdcc-sdcc)}} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Compiler not found"] \
+ -message [mc "Unable to find sdcc, please install sdcc and restart MCU 8051 IDE"]
+ } {
+ # Start compiler
+ set compiler_pid [::ExternalCompiler::compile_C \
+ $cur_dir $input_file_name.$input_file_extension \
+ $iram_size $xram_size $code_size \
+ ]
+ return 2
+ }
+
+ ## Assembly language
+ } else {
+ # Check if the choosen assembler is avaliable in the system
+ set avaliable 0
+ switch -- $::ExternalCompiler::selected_assembler {
+ 0 { ;# Native assembler
+ set avaliable 1
+ set assembler_name [mc "MCU 8051 IDE Native assembler"]
+ set assembler_cmd {mcu8051ide --compile}
+ }
+ 1 { ;# ASEM-51
+ set avaliable ${::PROGRAM_AVALIABLE(asem)}
+ set assembler_name "ASEM-51"
+ set assembler_cmd {asem}
+ }
+ 2 { ;# ASL
+ set avaliable ${::PROGRAM_AVALIABLE(asl)}
+ set assembler_name "ASL"
+ set assembler_cmd {asl}
+ }
+ 3 { ;# AS31
+ set avaliable ${::PROGRAM_AVALIABLE(as31)}
+ set assembler_name "AS31"
+ set assembler_cmd {as31}
+ }
+ default {
+ error "Unknown internal error -- Invalid ID of the selected assembler"
+ }
+ }
+ if {!$avaliable} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon error \
+ -title [mc "%s assembler not found" $assembler_name] \
+ -message [mc "Unable to run program \"%s\". Please check if you have installed this assembler or choose a different one in compiler configuration dialog." $assembler_cmd]
+ finalize_compilation 0
+ return 0
+ }
+
+ # Execute compiler
+ switch -- $::ExternalCompiler::selected_assembler {
+ 0 { ;# Native assembler
+ # Adjust compiler settings
+ set ::Compiler::Settings::TEXT_OUPUT_COMMAND X::messages_text_append
+ set ::Compiler::Settings::UPDATE_COMMAND {update}
+ set ::Compiler::Settings::iram_size $iram_size
+ set ::Compiler::Settings::xram_size $xram_size
+ set ::Compiler::Settings::code_size $code_size
+ set ::PreProcessor::check_sfr_usage 1
+ set ::PreProcessor::avaliable_SFR [string tolower [$actualProject cget -avaliable_SFR]]
+
+ # Perform code compilation
+ if {[catch {
+ set result [Compiler::compile \
+ [$actualProject cget -projectPath] \
+ $cur_dir $input_file_name $input_file_extension \
+ ]
+ }]} then {
+ puts stderr "Compiler crashed: \"${::errorInfo}\""
+ tk_messageBox \
+ -parent . \
+ -icon error \
+ -type ok \
+ -title [mc "Compiler crash - MCU 8051 IDE"] \
+ -message [mc "Compiler crased, we are terribly sorry about that.\n\nPlease report this bug via project web or mail to author and please don't forget to include source code on which this error occured."]
+ }
+ ::Compiler::free_resources
+ set Compiler::Settings::ABORT_VARIABLE 0
+ }
+ 1 { ;# ASEM-51
+ set compiler_pid [::ExternalCompiler::asem51_compile $cur_dir \
+ $input_file_name.$input_file_extension \
+ [$actualProject cget -projectPath] \
+ ]
+ return 2
+ }
+ 2 { ;# ASL
+ set compiler_pid [::ExternalCompiler::asl_compile $cur_dir \
+ $input_file_name.$input_file_extension \
+ [$actualProject cget -projectPath] \
+ ]
+ return 2
+ }
+ 3 { ;# AS31
+ set compiler_pid [::ExternalCompiler::as31_compile $cur_dir \
+ $input_file_name.$input_file_extension \
+ [$actualProject cget -projectPath] \
+ ]
+ return 2
+ }
+ default {
+ error "Unknown internal error -- Invalid ID of the selected assembler"
+ }
+ }
+ }
+
+ finalize_compilation $result
+ return $result
+ }
+
+ ## Compile the current file or the main file if it has not been already compiled
+ # @parm String success_callback - Procedure to call upon successfull compilation
+ # @parm String fail_callback - Procedure to call upon failed compilation
+ # @return void
+ proc compile_if_nessesary_and_callback {success_callback fail_callback} {
+ variable actualProject ;# Object: Current project
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable compilation_success_callback ;# String: Indented for HW plugins
+ variable compilation_fail_callback ;# String: Indented for HW plugins
+
+ set compilation_success_callback $success_callback
+ set compilation_fail_callback $fail_callback
+
+ set full_file_name [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ set relative_name [lindex $full_file_name 1]
+ if {$relative_name == {}} {
+ set full_file_name [$actualProject editor_procedure {} getFileName {}]
+ set language [$actualProject editor_procedure {} get_language {}]
+ set relative_name [lindex $full_file_name 1]
+ } {
+ set ext [string trimleft [file extension $relative_name] {.}]
+ if {$ext == {c} || $ext == {h} || $ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set language 1
+ } elseif {$ext == {lst}} {
+ set language 2
+ } else {
+ set language 0
+ }
+ }
+ set full_file_name [file join [lindex $full_file_name 0] [lindex $full_file_name 1]]
+ set full_file_name [file rootname $full_file_name]
+ if {$language != 1} {
+ append full_file_name {.adf}
+ } {
+ append full_file_name {.hashes}
+ }
+
+
+ if {![catch {
+ # C language
+ if {$language == 1} {
+ set hashes_file [open $full_file_name r]
+ set expected_md5s [read $hashes_file]
+ close $hashes_file
+
+ # Assembly language
+ } elseif {$language == 0} {
+ set expected_md5s {}
+ set simulator_file [open $full_file_name r]
+ while {![eof $simulator_file]} {
+ set line [gets $simulator_file]
+ if {$line == {} || [regexp {^\s*#} $line]} {
+ continue
+ }
+ set expected_md5s $line
+ break
+ }
+ close $simulator_file
+
+ # Invalid request!
+ } else {
+ error "Invalid request!"
+ }
+
+ }]} then {
+ if {[verify_md5_hashes 1 $expected_md5s]} {
+ __compile
+ return
+ }
+ } else {
+ __compile
+ return
+ }
+
+ eval "$compilation_success_callback"
+ }
+
+ ## Finalize compilation process
+ # Auxiliary procedure for procedures: __compile && ext_compilation_complete
+ # @parm Bool result - 1 == Compilation successfull; 0 == Compilation failed
+ # @return void
+ proc finalize_compilation {result} {
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable compilation_success_callback ;# String: Indented for HW plugins
+ variable compilation_fail_callback ;# String: Indented for HW plugins
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ set critical_procedure_in_progress 0
+
+ # Adjust statusbar
+ destroy_progressBar_on_Sbar
+ if {$result} {
+ Sbar [mc "Compilation successful"]
+ if {$compilation_success_callback != {}} {
+ eval "$compilation_success_callback"
+ set compilation_fail_callback {}
+ set compilation_success_callback {}
+ }
+ } {
+ Sbar [mc "Compilation failed"]
+ if {$compilation_fail_callback != {}} {
+ eval "$compilation_fail_callback"
+ set compilation_fail_callback {}
+ set compilation_success_callback {}
+ }
+ }
+
+ # Done ...
+ set compilation_in_progress 0
+ }
+
+ ## Handle text output from external or internal compiler
+ # @parm String text - Output from external compiler
+ # @return void
+ proc compilation_message args {
+ variable compilation_successfull ;# Bool: Compilation successfull
+ variable compilation_mess_project ;# Object: Project related to running compilation
+
+ set args [string replace \
+ [regsub -all "\\\{" \
+ [regsub -all "\\\}" \
+ [lindex $args 0]\
+ "\}"] \
+ "\{"] \
+ 0 0]
+
+ # Backspace charactes
+ set idx 0
+ while 1 {
+ set idx [string first "\b" $args $idx]
+ if {$idx == -1} {
+ break
+ }
+ set args [string replace $args [expr {$idx - 1}] [expr {$idx + 1}]]
+ incr idx -1
+ }
+
+ if {[$compilation_mess_project messages_text_append [string trimright $args]]} {
+ set compilation_successfull 0
+ }
+ }
+
+ ## External compiler finnished its work
+ # @return void
+ proc ext_compilation_complete {} {
+ variable compilation_mess_project ;# Object: Project related to running compilation
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable openedProjects ;# List of opened projects (Object references)
+ variable compilation_start_simulator ;# Bool: Start simulator after successful compilation
+ variable compile_this_file_only ;# Bool: Compile the current file only
+ variable compilation_successfull ;# Bool: Compilation successfull
+
+ finalize_compilation $compilation_successfull
+
+ # Conditionaly start simulator
+ if {$compilation_start_simulator && $compilation_successfull} {
+ set actualProject_org $actualProject
+ set actualProjectIdx_org $actualProjectIdx
+
+ set actualProject $compilation_mess_project
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+
+ __initiate_sim $compile_this_file_only
+
+ set actualProject $actualProject_org
+ set actualProjectIdx $actualProjectIdx_org
+ } elseif {$compilation_start_simulator && !$compilation_successfull} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [mc "Compilation failed"] \
+ -message [mc "Compilation failed, see messages for details."]
+ }
+ }
+
+ ## Abort running compilation -- auxiliary procedure for '__compile'
+ # @return void
+ proc __abort_compilation {} {
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable doxygen_pid ;# Int: Doxygen PID
+ variable compiler_pid ;# Int: PID of external compiler if used
+
+ set Compiler::Settings::ABORT_VARIABLE 1
+ destroy_progressBar_on_Sbar
+
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no kill command on Microsoft Windows
+ # Kill doxygen
+ if {$doxygen_pid} {
+ foreach pid $doxygen_pid {
+ catch {
+ exec -- kill -9 $pid &
+ }
+ }
+
+ # Kill SDCC
+ } elseif {${compiler_pid} != {} && ${compiler_pid} != 0} {
+ foreach pid $compiler_pid {
+ catch {
+ exec -- kill -9 $pid &
+ }
+ }
+ }
+ }
+
+ set compilation_in_progress 0
+ set compiler_pid 0
+ set doxygen_pid 0
+ }
+
+ ## Create progressbar on status bar (showing compilation progress)
+ # -- auxiliary procedure for '__compile'
+ # @return void
+ proc make_progressBar_on_Sbar {} {
+ # Frame
+ pack [frame .statusbarR] -in .statusbarF -side right
+ # Label "Compilation"
+ pack [label .status_sim_label \
+ -text [mc "Compilation: "] \
+ ] -in .statusbarR -side left
+ # Button "Abort"
+ pack [ttk::button .status_sim_button \
+ -text [mc "Abort"] \
+ -image ::ICONS::16::cancel \
+ -compound left \
+ -command {X::__abort_compilation} \
+ ] -in .statusbarR -side left
+ # Progressbar
+ pack [ttk::progressbar .status_sim_prog \
+ -maximum 1000 \
+ -mode indeterminate \
+ -variable X::compilation_progress \
+ -length 100 \
+ ] -in .statusbarR -side left
+ }
+
+ ## Destroy progressbar on status bar (showing compilation progress)
+ # -- auxiliary procedure for '__compile'
+ # @return void
+ proc destroy_progressBar_on_Sbar {} {
+ catch {
+ destroy .statusbarR
+ destroy .status_sim_label
+ destroy .status_sim_button
+ destroy .status_sim_prog
+ }
+ }
+
+ ## Increment progreesbar on statusbar (compilation progress)
+ # -- auxiliary procedure for '__compile'
+ # @return void
+ proc compilation_progress {} {
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable compilation_in_progress ;# Bool: Compiler engaged
+
+ if {!$compilation_in_progress} {return}
+
+ incr compilation_progress
+ if {$compilation_progress > 100} {
+ set compilation_progress 0
+ }
+ after 200 {X::compilation_progress}
+ }
+
+ ## Append text to messages text (bottom panel - tab "Messages")
+ # @parm String text - Text to append
+ # @return Bool - True if error occured
+ proc messages_text_append {text} {
+ variable actualProject ;# Object: Current project
+ variable compilation_mess_project ;# Object: Project related to running compilation
+
+ return [$compilation_mess_project messages_text_append $text]
+ }
+
+ ## Copy selected text in messages text to clipboard (bottom panel - tab "Messages")
+ # @return void
+ proc __copy_messages_text {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Copy
+ $actualProject copy_messages_text
+ }
+
+ ## Select all text in messages text (bottom panel - tab "Messages")
+ # @return void
+ proc __select_all_messages_text {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Select all
+ $actualProject select_all_messages_text
+ }
+
+ ## Clear content of messages text (bottom panel - tab "Messages")
+ # @return void
+ proc __clear_messages_text {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # CLear
+ $actualProject clear_messages_text
+ }
+
+ ## Export content of the current editor as XHTML/LaTeX
+ # -- auxiliary procedure for '__toHTML' and '__toLaTeX'
+ # @parm String - Target type ('-html' or '-latex')
+ # @parm String - Title of the dialog window
+ # @return void
+ proc exportToX args {
+ variable actualProject ;# Object: Current project
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable fsd_result ;# Value returnded by file selection dialog (in some cases)
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Expect 2 arguments
+ if {[llength $args] != 2} {
+ error "expected exactly 2 arguments"
+ }
+
+ # Check if the editor isn't empty
+ if {
+ [$actualProject editor_procedure {} getLinesCount {}] == 1
+ &&
+ [$actualProject editor_procedure {} getLineContent 1] == {}
+ } {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "This editor seems to be empty"]
+ return
+ }
+
+ # Determinate target file type (html/latex)
+ set targetType [lindex $args 0]
+ # Compilation started
+ set compilation_progress 1
+ # Determinate maximum value for progress bar
+ set max [$actualProject editor_procedure {} highlight_all_count_of_iterations {}]
+ incr max
+
+ # Create diwlog window
+ set win [toplevel .exportToX_dialog -class [mc "Export dialog"] -bg {#EEEEEE}]
+ wm withdraw $win
+
+ # Label and progress bar
+ set main_frame [frame $win.main_frame]
+ pack [label $main_frame.header \
+ -text [mc "Finishing highlight ..."] \
+ ] -pady 10 -padx 20 -anchor w
+ pack [ttk::progressbar $main_frame.progress_bar \
+ -maximum $max \
+ -mode determinate \
+ -variable {X::compilation_progress} \
+ -length 430 \
+ ] -fill y
+ pack $main_frame -fill x -expand 1
+
+ # Button abort
+ pack [ttk::button $win.abort_button \
+ -text [mc "Abort"] \
+ -command "X::exportToX_abort $targetType" \
+ -image ::ICONS::16::cancel \
+ -compound left \
+ ]
+
+ # Determinate target file name
+ set file [$actualProject editor_procedure {} getFileName {}]
+ set filename [lindex $file 1]
+ if {[lindex $file 0] != {}} {
+ set dir [lindex $file 0]
+ } {
+ set dir [$actualProject cget -projectPath]
+ }
+ regsub {\.[^\.]*$} $filename {} filename
+ if {$targetType == "-html"} {
+ set suffix {html}
+ } {
+ set suffix {tex}
+ }
+ append filename {.} $suffix
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -initialfile $filename -directory $dir \
+ -title [mc "Export as %s - MCU 8051 IDE" [lindex $args 1]] \
+ -defaultmask 0 -multiple 0 -filetypes [subst "
+ {{[mc {[string toupper $suffix] file}]} {*.$suffix}}
+ {{[mc {All files}]} {*}}"]
+ fsd setokcmd {
+ set ::X::fsd_result [X::fsd get]
+ }
+ set fsd_result {}
+ fsd activate
+
+ set filename $fsd_result
+ if {[file isdirectory $filename] || ![string length $filename]} {
+ exportToX_abort $targetType
+ return
+ }
+ if {![regexp {\.\w+$} $filename]} {
+ append filename {.} $suffix
+ }
+
+ # Create backup file
+ if {[file exists $filename] && [file isfile $filename]} {
+ if {![file writable $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to access file: %s" $filename]
+ exportToX_abort $targetType
+ return
+ }
+ # 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~"
+ }
+ }
+
+ # Open target file
+ if {[catch {
+ set file [open $filename w 420]
+ }]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to write to file: \"%s\"" $filename]
+ exportToX_abort $targetType
+ return
+ }
+
+ # Set window attributes
+ if {![winfo exists $win]} {return}
+ wm iconphoto $win ::ICONS::16::html
+ wm deiconify $win
+ wm title $win [mc "[lindex $args 1] - MCU 8051 IDE"]
+ wm minsize $win 450 70
+ wm protocol $win WM_DELETE_WINDOW {
+ exportToX_abort
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ update
+
+ # Highlight all lines in the editor
+ $actualProject editor_procedure {} highlight_all {}
+ if {![winfo exists $win]} {return}
+
+ # Ajust window (Second stage)
+ set max [$actualProject editor_procedure {} getDataAsXHTML_count_of_iterations {}]
+ incr max
+ $main_frame.header configure -text [mc "Converting ..."]
+ $main_frame.progress_bar configure -maximum $max
+ set compilation_progress 1
+ update
+
+ # Export and write data
+ if {$targetType == "-html"} {
+ puts -nonewline $file [$actualProject editor_procedure {} getDataAsXHTML {}]
+ } elseif {$targetType == "-latex"} {
+ puts -nonewline $file [$actualProject editor_procedure {} getDataAsLaTeX {}]
+ } else {
+ error "Unknown argument: $targetType\n\tpossible vaues are: -html -latex"
+ }
+ close $file
+ exportToX_abort $targetType
+
+ # Show result
+ Sbar [mc "Expoted data saved to %s" $filename]
+ }
+
+ ## Abort export content of the current editor as XHTML/LaTeX
+ # -- auxiliary procedure for '__toHTML' and '__toLaTeX'
+ # @parm String - Target type ('-html' or '-latex')
+ # @return void
+ proc exportToX_abort {targetType} {
+ variable actualProject ;# Object: Current project
+
+ # Abort export
+ if {$targetType == "-html"} {
+ $actualProject editor_procedure {} getDataAsXHTML_abort_now {}
+ } elseif {$targetType == "-latex"} {
+ $actualProject editor_procedure {} getDataAsLaTeX_abort_now {}
+ } else {
+ error "Unknown argument: $targetType\n\tpossible vaues are: -html -latex"
+ }
+
+ # Destroy dialog window
+ destroy .exportToX_dialog
+ grab release .exportToX_dialog
+ }
+
+ ## Export data contained in the current editor as XHTML
+ # @return void
+ proc __toHTML {} {
+ exportToX -html "Export to XHTML"
+ }
+
+ ## Export data contained in the current editor as LaTeX
+ # @return void
+ proc __toLaTeX {} {
+ exportToX -latex "Export to LaTeX"
+ }
+
+ ## Exit program
+ # - Ask for saving unsaved files and projects
+ # - Save all projects
+ # - Save session file
+ # - Exit
+ # @parm Bool = 0 - Print message "Exitong on user request"
+ # @return void
+ proc __exit args {
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProject ;# Object: Current project
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable procedure_exit_in_progress ;# Bool: proc "__exit" in progress
+ variable unsaved_projects ;# List: List of project object marked as "unsaved"
+ variable eightsegment_editors ;# List: All 8-segment LED display editors invoked
+ variable spec_calc_objects ;# List: All special calculator objects
+ variable rs232debugger_objects ;# List: All "RS232 debugger" objects
+
+ # If application is not loaded -> exit immediately
+ if {!${::APPLICATION_LOADED}} {
+ exit
+ }
+
+ # This procedure cannot be recursive
+ if {$procedure_exit_in_progress} {
+ return
+ }
+ set procedure_exit_in_progress 1
+
+ # Parse arguments
+ if {[lindex $args 0] == 1} {
+ set do_not_print_exit_message 1
+ } {
+ set do_not_print_exit_message 0
+ }
+
+ # Ask hardware whether it's ready for exit
+ foreach project $openedProjects {
+ if {![$project hw_manager_comfirm_exit]} {
+ set procedure_exit_in_progress 0
+ return
+ }
+ }
+
+ foreach obj [concat $eightsegment_editors $spec_calc_objects $rs232debugger_objects] {
+ catch {
+ delete object $obj
+ }
+ }
+
+ # Cancel running compilation
+ if {$compilation_in_progress} {
+ __abort_compilation
+ }
+
+ # Determinate list of unsaved projects
+ set unsaved_projects {}
+ foreach project $openedProjects {
+ foreach editor [$project cget -editors] {
+ if {[$editor cget -modified]} {
+ lappend unsaved_projects "{$project} {$editor}"
+ }
+ }
+ }
+
+ # Ask user for saving unsaved files -- use proc 'shutdown_dialog'
+ if {[llength $unsaved_projects] != 0} {
+ switch -- [shutdown_dialog] {
+ 0 { ;# SAVESELECTED
+ set i 0
+ foreach unsaved $unsaved_projects {
+ set bool [subst "\$::unsavedfile$i"]
+ if {$bool == 1} {
+ [lindex [lindex $unsaved_projects $i] 1] save
+ }
+ incr i
+ }
+
+ }
+ 1 { ;# SAVEALL
+ set last_project {}
+ foreach project $unsaved_projects {
+ set project [lindex $project 0]
+ if {$last_project == $project} {continue}
+ set last_project $project
+ $project editor_save_all
+ }
+ }
+ 2 { ;# DISCARD
+ }
+ 3 { ;# CANCEL
+ set procedure_exit_in_progress 0
+ return 0
+ }
+ }
+ }
+
+ if {!$do_not_print_exit_message} {
+ puts [mc "\nExiting program on user request ..."]
+ }
+
+ # Withdraw main window
+ wm withdraw .
+ # Withdraw all PALE windows
+ foreach project $openedProjects {
+ $project pale_withdraw_all_windows
+ }
+ update
+
+ # Save session
+ if {[catch {
+ save_session
+ } result]} then {
+ puts stderr [mc "An error occured when saving the last session"]
+ puts stderr $result
+ }
+
+ # Save all projects
+ foreach project $openedProjects {
+ $project kill_childern
+ set actualProject $project
+ __proj_save
+ }
+
+ puts [mc "Program terminated"]
+
+ exit
+ }
+
+ ## Save the current session
+ # @return void
+ proc save_session {} {
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProject ;# Object: Current project
+ variable session_file ;# Path to file defining the last session
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+
+ variable line2pc_jump ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+
+ variable file_recent_files ;# List: recently opened files
+ variable project_recent_files ;# List: recently opened projects
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ variable base_convertors ;# List: All base convertor objects
+
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ # Create configuration directory if it is not exist already
+ if {![file exists ${::CONFIG_DIR}] || ![file isdirectory ${::CONFIG_DIR}]} {
+ if {[catch {[file mkdir ${::CONFIG_DIR}]}]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to save running config"]
+ return 0
+ }
+ }
+
+ # Get project dependent options
+ if {([llength $openedProjects] > 0) && ($actualProject != {})} {
+ array set ::CONFIG [subst {
+ LINE_NUMBERS [$actualProject cget -lineNumbers]
+ ICON_BORDER [$actualProject cget -iconBorder]
+ LEFT_PANEL [$actualProject isLeftPanelVisible]
+ RIGHT_PANEL [$actualProject isRightPanelVisible]
+ BOTTOM_PANEL [$actualProject isBottomPanelVisible]
+ LEFT_PANEL_SIZE [$actualProject getLeftPanelSize]
+ RIGHT_PANEL_SIZE [$actualProject getRightPanelSize]
+ BOTTOM_PANEL_SIZE [$actualProject getBottomPanelSize]
+ LEFT_PANEL_ACTIVE_PAGE {[$actualProject getLeftPanelActivePage]}
+ RIGHT_PANEL_ACTIVE_PAGE {[$actualProject getRightPanelActivePage]}
+ BOTTOM_PANEL_ACTIVE_PAGE {[$actualProject getBottomPanelActivePage]}
+ SUBP_MON_CONFIG {[$actualProject subprograms_get_config]}
+ FS_BROWSER_MASK {[$actualProject fs_browser_get_current_mask]}
+ FIND_IN_FILES_CONFIG {[$actualProject findinfiles_get_config]}
+ STOPWATCH_CONFIG {[$actualProject stopwatch_get_config]}
+ C_VARS_VIEW_CONF {[$actualProject cvarsview_get_config]}
+ BITMAP_CONFIG {[$actualProject bitmap_get_config]}
+ HW_MANAGER_CONFIG {[$actualProject hw_manager_get_cfg]}
+ REGWATCHES_CONFIG {[$actualProject rightPanel_watch_get_config]}
+ FILE_NOTES {[$actualProject get_file_notes_config]}
+ }]
+ }
+ # Get project independent options
+ array set ::CONFIG [subst {
+ KIFSD_CONFIG {[::KIFSD::FSD::get_config_array]}
+ HEXEDIT_CONFIG {[::HexEditDlg::getConfig]}
+ FIND_OPTIONS {[list $find_option_CS \
+ $find_option_back \
+ $find_option_cur \
+ $find_option_sel \
+ $find_option_reg]}
+ REPLACE_OPTIONS {[list $replace_option_CS \
+ $replace_option_back \
+ $replace_option_cur \
+ $replace_option_reg]}
+ INTR_MON_GEOMETRY {${::InterruptMonitor::geometry}}
+ OPEN_WITH_DLG {${::FileList::open_with}}
+ SYMBOL_VIEWER_CONFIG {${::SymbolViewer::config_list}}
+ LINE2PC_JUMP {$line2pc_jump}
+ FILE_RECENT_FILES {$file_recent_files}
+ PROJECT_RECENT_FILES {$project_recent_files}
+ VHW_RECENT_FILES {$vhw_recent_files}
+ EIGHT_SEG_EDITOR {${::EightSegment::config}}
+ SPEC_CALC {${::SpecCalc::config}}
+ ASK_ON_FILE_OPEN {${::FileList::ask__append_file_to_project}}
+ RS232_DEBUGGER {${::RS232Debugger::config_list}}
+ STACK_MON_GEOMETRY {${::StackMonitor::geometry}}
+ STACK_MON_COLLAPSED {${::StackMonitor::collapsed}}
+ }]
+ set ::CONFIG(LETTER_CASE) {}
+ for {set i 0} {$i < 21} {incr i} {
+ lappend ::CONFIG(LETTER_CASE) $change_letter_case_options($i)
+ }
+ set ::CONFIG(BASE_CONVERTORS) {}
+ foreach obj $base_convertors {
+ lappend ::CONFIG(BASE_CONVERTORS) [$obj get_config]
+ }
+
+ # Open session file
+ if {[catch {
+ set file [open $session_file w 420]
+ }]} then {
+ tk_messageBox -parent . -type ok -icon error \
+ -title [mc "Access denied"] \
+ -message [mc "Unable to write to file: \"%s\"" $session_file]
+ return
+ }
+
+ # Write session file
+ puts $file "# ${::APPNAME} [clock format [clock seconds] -format {%T %D}]"
+ puts $file "# Please do not modify this file manualy.\n"
+
+ puts $file "# booleans"
+ if {$::MICROSOFT_WINDOWS} {
+ # There is no such thing on Windows OS
+ puts $file "WINDOW_ZOOMED = \"0\""
+ } {
+ puts $file "WINDOW_ZOOMED = \"[wm attributes . -zoomed]\""
+ }
+ puts $file "LINE_NUMBERS = $::CONFIG(LINE_NUMBERS)"
+ puts $file "ICON_BORDER = $::CONFIG(ICON_BORDER)"
+ puts $file "LEFT_PANEL = $::CONFIG(LEFT_PANEL)"
+ puts $file "RIGHT_PANEL = $::CONFIG(RIGHT_PANEL)"
+ puts $file "BOTTOM_PANEL = $::CONFIG(BOTTOM_PANEL)"
+ puts $file "TOOLBAR_VISIBLE = $::CONFIG(TOOLBAR_VISIBLE)"
+ puts $file "BREAKPOINTS_ALLOWED = $::CONFIG(BREAKPOINTS_ALLOWED)"
+ puts $file "LINE2PC_JUMP = $::CONFIG(LINE2PC_JUMP)"
+ puts $file "ASK_ON_FILE_OPEN = $::CONFIG(ASK_ON_FILE_OPEN)"
+ puts $file "SHOW_EDITOR_TAB_BAR = $::CONFIG(SHOW_EDITOR_TAB_BAR)"
+ puts $file "STACK_MON_COLLAPSED = $::CONFIG(STACK_MON_COLLAPSED)"
+ puts $file "\n# integers"
+ puts $file "LEFT_PANEL_SIZE = $::CONFIG(LEFT_PANEL_SIZE)"
+ puts $file "RIGHT_PANEL_SIZE = $::CONFIG(RIGHT_PANEL_SIZE)"
+ puts $file "BOTTOM_PANEL_SIZE = $::CONFIG(BOTTOM_PANEL_SIZE)"
+ puts $file "VALIDATION_LEVEL = $::CONFIG(VALIDATION_LEVEL)"
+ puts $file "\n# strings"
+ puts $file "LEFT_PANEL_ACTIVE_PAGE = \"$::CONFIG(LEFT_PANEL_ACTIVE_PAGE)\""
+ puts $file "RIGHT_PANEL_ACTIVE_PAGE = \"$::CONFIG(RIGHT_PANEL_ACTIVE_PAGE)\""
+ puts $file "BOTTOM_PANEL_ACTIVE_PAGE = \"$::CONFIG(BOTTOM_PANEL_ACTIVE_PAGE)\""
+ puts $file "OPEN_WITH_DLG = \"$::CONFIG(OPEN_WITH_DLG)\""
+ puts $file "FS_BROWSER_MASK = \"$::CONFIG(FS_BROWSER_MASK)\""
+ puts $file "FILE_RECENT_FILES = \"$::CONFIG(FILE_RECENT_FILES)\""
+ puts $file "PROJECT_RECENT_FILES = \"$::CONFIG(PROJECT_RECENT_FILES)\""
+ puts $file "VHW_RECENT_FILES = \"$::CONFIG(VHW_RECENT_FILES)\""
+ puts $file "\n# lists"
+ puts $file "CLEANUP_OPTIONS = \"[regsub -all {\s+} $::CONFIG(CLEANUP_OPTIONS) { }]\""
+ puts $file "FIND_OPTIONS = \"$::CONFIG(FIND_OPTIONS)\""
+ puts $file "REPLACE_OPTIONS = \"$::CONFIG(REPLACE_OPTIONS)\""
+ puts $file "LETTER_CASE = \"$::CONFIG(LETTER_CASE)\""
+ puts $file "KIFSD_CONFIG = \"$::CONFIG(KIFSD_CONFIG)\""
+ puts $file "HEXEDIT_CONFIG = \"$::CONFIG(HEXEDIT_CONFIG)\""
+ puts $file "SUBP_MON_CONFIG = \"$::CONFIG(SUBP_MON_CONFIG)\""
+ puts $file "FIND_IN_FILES_CONFIG = \"$::CONFIG(FIND_IN_FILES_CONFIG)\""
+ puts $file "SYMBOL_VIEWER_CONFIG = \"$::CONFIG(SYMBOL_VIEWER_CONFIG)\""
+ puts $file "STOPWATCH_CONFIG = \"$::CONFIG(STOPWATCH_CONFIG)\""
+ puts $file "C_VARS_VIEW_CONF = \"$::CONFIG(C_VARS_VIEW_CONF)\""
+ puts $file "BITMAP_CONFIG = \"$::CONFIG(BITMAP_CONFIG)\""
+ puts $file "HW_MANAGER_CONFIG = \"$::CONFIG(HW_MANAGER_CONFIG)\""
+ puts $file "REGWATCHES_CONFIG = \"$::CONFIG(REGWATCHES_CONFIG)\""
+ puts $file "FILE_NOTES = \"$::CONFIG(FILE_NOTES)\""
+ puts $file "EIGHT_SEG_EDITOR = \"$::CONFIG(EIGHT_SEG_EDITOR)\""
+ puts $file "BASE_CONVERTORS = \"$::CONFIG(BASE_CONVERTORS)\""
+ puts $file "SPEC_CALC = \"$::CONFIG(SPEC_CALC)\""
+ puts $file "RS232_DEBUGGER = \"$::CONFIG(RS232_DEBUGGER)\""
+ puts $file "\n# other"
+ puts $file "WINDOW_GEOMETRY = \"[wm geometry .]\""
+ puts $file "ACTIVE_PROJECT = $actualProjectIdx"
+ puts $file "INTR_MON_GEOMETRY = \"$::CONFIG(INTR_MON_GEOMETRY)\""
+ puts $file "STACK_MON_GEOMETRY = \"$::CONFIG(STACK_MON_GEOMETRY)\""
+
+ set projects {}
+ if {[winfo exists .mainFrame.mainNB]} {
+ set projects_len [llength [.mainFrame.mainNB pages]]
+ for {set i 0} {$i < $projects_len} {incr i} {
+ set prj [.mainFrame.mainNB pages $i]
+ lappend projects [file join \
+ [$prj cget -projectPath]\
+ [$prj cget -projectFile]\
+ ]
+ }
+ }
+
+ puts $file "OPENED_PROJECTS = ($projects)"
+
+ # Finalize
+ close $file
+ return 1
+ }
+
+ ## Restore previous session
+ # @return Bool - session file found
+ proc restore_session {} {
+ variable session_file ;# Path to file defining the last session
+
+ variable line2pc_jump ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+
+ variable file_recent_files ;# List: recently opened files
+ variable project_recent_files ;# List: recently opened projects
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ # Set default values
+ array set ::CONFIG {
+ WINDOW_ZOOMED 0
+ LINE_NUMBERS 1
+ ICON_BORDER 1
+ LEFT_PANEL 1
+ RIGHT_PANEL 1
+ BOTTOM_PANEL 1
+ LEFT_PANEL_SIZE 193
+ RIGHT_PANEL_SIZE 329
+ BOTTOM_PANEL_SIZE 190
+ LEFT_PANEL_ACTIVE_PAGE opened_files
+ RIGHT_PANEL_ACTIVE_PAGE Watches
+ BOTTOM_PANEL_ACTIVE_PAGE Simulator
+ WINDOW_GEOMETRY 800x600
+ ACTIVE_PROJECT {}
+ OPENED_PROJECTS {}
+ VALIDATION_LEVEL 2
+ TOOLBAR_VISIBLE 1
+ BREAKPOINTS_ALLOWED 1
+ CLEANUP_OPTIONS {
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0
+ }
+ FIND_OPTIONS {1 0 1 0 0}
+ REPLACE_OPTIONS {1 0 0 0}
+ LETTER_CASE {- - - - - - - - - - - - - - - - - - - - -}
+ KIFSD_CONFIG {}
+ HEXEDIT_CONFIG {+0+0 hex 0 left}
+ INTR_MON_GEOMETRY {780x250}
+ SUBP_MON_CONFIG {1 1}
+ OPEN_WITH_DLG {}
+ FS_BROWSER_MASK {*.asm}
+ FIND_IN_FILES_CONFIG {1 0 1 ~ {*.asm,*.c,*.h} {}}
+ SYMBOL_VIEWER_CONFIG {1 1 1 1 1 1 1 0 0 0 620x450}
+ LINE2PC_JUMP 1
+ STOPWATCH_CONFIG {{} 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
+ C_VARS_VIEW_CONF {400}
+ BITMAP_CONFIG {}
+ HW_MANAGER_CONFIG {}
+ FILE_RECENT_FILES {}
+ PROJECT_RECENT_FILES {}
+ VHW_RECENT_FILES {}
+ REGWATCHES_CONFIG {1 1}
+ FILE_NOTES {1 200}
+ EIGHT_SEG_EDITOR {
+ {0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7}
+ {0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0}
+ }
+ BASE_CONVERTORS {}
+ SPEC_CALC {}
+ ASK_ON_FILE_OPEN 1
+ SHOW_EDITOR_TAB_BAR 1
+ RS232_DEBUGGER {9600 n 8 1 1 0 {} {} 0 0}
+ STACK_MON_GEOMETRY {}
+ STACK_MON_COLLAPSED 1
+ }
+ if {$::MICROSOFT_WINDOWS} {
+ lset ::CONFIG(FIND_IN_FILES_CONFIG) 3 ${::env(USERPROFILE)}
+ }
+ set default_CLEANUP_OPTIONS {
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0
+ }
+ set default_FIND_OPTIONS {1 0 1 0 0}
+ set default_REPLACE_OPTIONS {1 0 0 0}
+
+ set session_file_exists [file exists $session_file]
+
+ # Parse session file
+ if {!$::CLI_OPTION(defaults) && $session_file_exists} {
+ # List of keys which may appear in the session file
+ set acceptable_keys {
+ LINE_NUMBERS ICON_BORDER LEFT_PANEL
+ BOTTOM_PANEL LEFT_PANEL_SIZE RIGHT_PANEL_SIZE
+ BOTTOM_PANEL_SIZE LEFT_PANEL_ACTIVE_PAGE RIGHT_PANEL_ACTIVE_PAGE
+ BOTTOM_PANEL_ACTIVE_PAGE WINDOW_GEOMETRY ACTIVE_PROJECT
+ OPENED_PROJECTS RIGHT_PANEL KIFSD_CONFIG
+ VALIDATION_LEVEL TOOLBAR_VISIBLE CLEANUP_OPTIONS
+ BREAKPOINTS_ALLOWED FIND_OPTIONS REPLACE_OPTIONS
+ LETTER_CASE HEXEDIT_CONFIG INTR_MON_GEOMETRY
+ SUBP_MON_CONFIG OPEN_WITH_DLG FS_BROWSER_MASK
+ FIND_IN_FILES_CONFIG SYMBOL_VIEWER_CONFIG LINE2PC_JUMP
+ STOPWATCH_CONFIG C_VARS_VIEW_CONF BITMAP_CONFIG
+ HW_MANAGER_CONFIG FILE_RECENT_FILES PROJECT_RECENT_FILES
+ REGWATCHES_CONFIG EIGHT_SEG_EDITOR VHW_RECENT_FILES
+ BASE_CONVERTORS WINDOW_ZOOMED SPEC_CALC
+ ASK_ON_FILE_OPEN SHOW_EDITOR_TAB_BAR RS232_DEBUGGER
+ FILE_NOTES STACK_MON_GEOMETRY STACK_MON_COLLAPSED
+ }
+ # List of datatypes for these keys
+ set datatypes {
+ B B B
+ B I I
+ I S S
+ S G S
+ S B S
+ I B S
+ B S S
+ S S G
+ S S S
+ S S B
+ S S S
+ S S S
+ S S S
+ S B S
+ B B S
+ S S B
+ }
+
+ # Open session file
+ set file [open $session_file r]
+ while 1 {
+ # Break on EOF
+ if {[eof $file]} {
+ close $file
+ break
+ }
+
+ # Get and adjust line
+ set line [gets $file]
+ regsub {\s*#.*$} $line {} line
+ if {$line == {}} {continue}
+
+ # Determinate key and value
+ regexp {^\w+} $line key
+ regexp {\=.*$} $line value
+ set value [string replace $value 0 0]
+ set key [string trim $key]
+ set value [string trim $value "\" \t"]
+
+ # Check for valid key
+ set keyIndex [lsearch -exact -ascii $acceptable_keys $key]
+ if {$keyIndex == -1} {
+ puts stderr "Unrecognized key: '$key'"
+ continue
+ }
+ # Check for valid datatype
+ set dt [lindex $datatypes $keyIndex]
+ switch -- $dt {
+ B { ;# Boolean
+ if {![string is boolean -strict $value]} {
+ puts stderr "Invalid value '$value', expected boolean"
+ continue
+ }
+ }
+ I { ;# unsigned Integer
+ if {![string is integer -strict $value]} {
+ puts stderr "Invalid value '$value', expected integer"
+ continue
+ }
+ }
+ S { ;# String
+ }
+ G { ;# window Geometry
+ if {![regexp {=?\d+x\d+(\+\d+\+\d+)?} $value]} {
+ puts stderr "Invalid value '$value', expected win. geometry (key == $key)"
+ continue
+ }
+ }
+ }
+
+ # Parse key "OPENED_PROJECTS"
+ if {$key == {OPENED_PROJECTS}} {
+ set value [string trim $value {( )}]
+ }
+
+ # Set appropriate value of config array
+ set ::CONFIG($key) $value
+ }
+ }
+
+ # Validate some configuration values
+ if {![regexp {^\s*([01]\s+){45}[01]\s*$} $::CONFIG(CLEANUP_OPTIONS)]} {
+ puts stderr "Invalid record CLEANUP_OPTIONS -- setting to default value"
+ set ::CONFIG(CLEANUP_OPTIONS) $default_CLEANUP_OPTIONS
+ }
+ if {![regexp {^\s*[01]\s[01]\s[01]\s[01]\s[01]\s*$} $::CONFIG(FIND_OPTIONS)]} {
+ puts stderr "Invalid record FIND_OPTIONS -- setting to default value"
+ set ::CONFIG(FIND_OPTIONS) $default_FIND_OPTIONS
+ }
+ if {![regexp {^\s*[01]\s[01]\s[01]\s[01]\s*$} $::CONFIG(REPLACE_OPTIONS)]} {
+ puts stderr "Invalid record REPLACE_OPTIONS -- setting to default value"
+ set ::CONFIG(REPLACE_OPTIONS) $default_REPLACE_OPTIONS
+ }
+ if {![regexp {^\s*[01]\s+[01]\s*$} $::CONFIG(REGWATCHES_CONFIG)]} {
+ puts stderr "Invalid record REGWATCHES_CONFIG -- setting to default value"
+ set ::CONFIG(REGWATCHES_CONFIG) {1 1}
+ }
+
+ # Adjust some configuration values
+ set line2pc_jump $::CONFIG(LINE2PC_JUMP)
+
+ set find_option_CS [lindex $::CONFIG(FIND_OPTIONS) 0]
+ set find_option_back [lindex $::CONFIG(FIND_OPTIONS) 1]
+ set find_option_cur [lindex $::CONFIG(FIND_OPTIONS) 2]
+ set find_option_sel [lindex $::CONFIG(FIND_OPTIONS) 3]
+ set find_option_reg [lindex $::CONFIG(FIND_OPTIONS) 4]
+
+ set replace_option_CS [lindex $::CONFIG(REPLACE_OPTIONS) 0]
+ set replace_option_back [lindex $::CONFIG(REPLACE_OPTIONS) 1]
+ set replace_option_cur [lindex $::CONFIG(REPLACE_OPTIONS) 2]
+ set replace_option_reg [lindex $::CONFIG(REPLACE_OPTIONS) 3]
+
+ set file_recent_files $::CONFIG(FILE_RECENT_FILES)
+ set project_recent_files $::CONFIG(PROJECT_RECENT_FILES)
+ set vhw_recent_files $::CONFIG(VHW_RECENT_FILES)
+
+ for {set i 0} {$i < 21} {incr i} {
+ set val [lindex $::CONFIG(LETTER_CASE) $i]
+ if {$val != {U} && $val != {L} && $val != {-}} {
+ set val {-}
+ }
+ set change_letter_case_options($i) $val
+ }
+
+ if {!$::CLI_OPTION(defaults)} {
+ if {$::CLI_OPTION(ignore_last)} {
+ set ::CONFIG(OPENED_PROJECTS) {}
+ }
+ if {$::CLI_OPTION(open_project) != {}} {
+ set ::CONFIG(OPENED_PROJECTS) [list $::CLI_OPTION(open_project)]
+ }
+ }
+
+ # Return result
+ return $session_file_exists
+ }
+
+ ## Invoke dialog "Exit program"
+ # @return Int - result
+ # '0' == Save selected
+ # '1' == Save all
+ # '2' == Discard
+ # '3' == Cancel
+ proc shutdown_dialog {} {
+ variable unsaved_projects ;# List: List of project object marked as "unsaved"
+
+ catch {unset ::exit_dialog_result}
+
+ # Create dialog window
+ set dialog [toplevel .save_multiple_projects -class {Save multimple} -bg {#EEEEEE}]
+
+ # Create the top part of dialog (Header and some icon)
+ pack [frame $dialog.topframe] -fill x -expand 1
+ pack [label $dialog.topframe.image \
+ -image ::ICONS::32::fileclose \
+ ] -side left -padx 10
+ pack [label $dialog.topframe.message \
+ -text [mc "The following documents have been modified,\ndo you want to save them before closing ?"] \
+ ] -side right -fill x -expand 1
+
+ # Create the middle part of the dialog (list of unsaved files)
+ pack [ttk::labelframe $dialog.lf -text [mc "Unsaved files"] -labelanchor nw -padding 5] -fill both -expand 1 -pady 10 -padx 10
+ set last_project {}
+ set i 0
+ foreach unsaved $unsaved_projects {
+ # Project name
+ if {[lindex $unsaved 0] != $last_project} {
+ set last_project [lindex $unsaved 0]
+ pack [label $dialog.lf.chp$i \
+ -text [mc "Project: \"%s\"" [$last_project cget -projectName]] \
+ -image ::ICONS::16::kcmdevices \
+ -compound left \
+ ] -anchor w -padx 20 -pady 5
+ }
+ # Unsaved files
+ set ::unsavedfile$i 1
+ pack [checkbutton $dialog.lf.chb$i \
+ -text [[lindex $unsaved 1] cget -filename] \
+ -variable ::unsavedfile$i \
+ ] -anchor w -padx 60
+ incr i
+ }
+
+ # Create the bottom part of the dialog (buttons)
+ pack [ttk::separator $dialog.separator -orient horizontal] -fill x -expand 1 -padx 10
+ pack [frame $dialog.f] -pady 5 -padx 5
+ # button SAVESELECTED
+ pack [ttk::button $dialog.f.b_save_selected \
+ -text [mc "Save selected"] \
+ -underline 0 \
+ -compound left \
+ -image ::ICONS::16::filesave \
+ -command {set ::exit_dialog_result 0} \
+ ] -side left -padx 5
+ bind $dialog.f.b_save_selected <Return> {set ::exit_dialog_result 0}
+ bind $dialog.f.b_save_selected <KP_Enter> {set ::exit_dialog_result 0}
+ # button SAVEALL
+ pack [ttk::button $dialog.f.b_save_all \
+ -text [mc "Save all"] \
+ -underline 5 \
+ -compound left \
+ -image ::ICONS::16::save_all \
+ -command {set ::exit_dialog_result 1} \
+ ] -side left -padx 5
+ bind $dialog.f.b_save_all <Return> {set ::exit_dialog_result 1}
+ bind $dialog.f.b_save_all <KP_Enter> {set ::exit_dialog_result 1}
+ # button DESTROY
+ pack [ttk::button $dialog.f.b_discard \
+ -text [mc "Discard"] \
+ -underline 0 \
+ -compound left \
+ -image ::ICONS::16::editdelete \
+ -command {set ::exit_dialog_result 2} \
+ ] -side left -padx 5
+ bind $dialog.f.b_discard <Return> {set ::exit_dialog_result 2}
+ bind $dialog.f.b_discard <KP_Enter> {set ::exit_dialog_result 2}
+ # button CANCEL
+ pack [ttk::button $dialog.f.b_cancel \
+ -text [mc "Cancel"] \
+ -underline 0 \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {set ::exit_dialog_result 3} \
+ ] -side left -padx 5
+ bind $dialog.f.b_cancel <Return> {set ::exit_dialog_result 3}
+ bind $dialog.f.b_cancel <KP_Enter> {set ::exit_dialog_result 3}
+
+ # Set key-events bindings
+ bind $dialog <Alt-Key-s> {set ::exit_dialog_result 0}
+ bind $dialog <Alt-Key-a> {set ::exit_dialog_result 1}
+ bind $dialog <Alt-Key-d> {set ::exit_dialog_result 2}
+ bind $dialog <Alt-Key-c> {set ::exit_dialog_result 3}
+
+ # Window manager options -- modal window
+ wm iconphoto $dialog ::ICONS::16::exit
+ wm title $dialog [mc "Exit program - MCU 8051 IDE"]
+ wm state $dialog normal
+ wm minsize $dialog 350 200
+ grab $dialog
+ focus -force $dialog.f.b_save_all
+ wm transient $dialog .
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ set ::exit_dialog_result 3
+ "
+ vwait ::exit_dialog_result
+ grab release $dialog
+ destroy $dialog
+ return ${::exit_dialog_result}
+ }
+
+ ## Simulator: STEPBACK
+ # @return void
+ proc __stepback {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator is engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check if simulator isn't busy
+ if {[$actualProject sim_is_busy]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Perform program step
+ stepback_button_set_ena [$actualProject stepback]
+ set lineNum [$actualProject simulator_getCurrentLine]
+ if {$lineNum != {}} {
+ $actualProject move_simulator_line $lineNum
+ } {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ }
+ $actualProject Simulator_sync_PC_etc
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Simulator: STEP
+ # @return void
+ proc __step {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator is engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check if simulator isn't busy
+ if {[$actualProject sim_is_busy]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Perform program step
+ set lineNum [$actualProject step]
+ if {$lineNum != {}} {
+ $actualProject move_simulator_line $lineNum
+ } {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ }
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ $actualProject Simulator_sync_PC_etc
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Simulator: STEPOVER
+ # @return void
+ proc __stepover {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator is engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+ # Check if simulator isn't busy
+ if {[$actualProject sim_run_in_progress] || [$actualProject sim_anim_in_progress]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+
+
+ # Change button image (simulator control panel)
+ $actualProject invert_stepover_button
+
+ # Perform program step
+ set lineNum [$actualProject sim_stepover]
+ if {$lineNum != {}} {
+ $actualProject move_simulator_line $lineNum
+ } {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ }
+
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ $actualProject invert_stepover_button ;# Change button image (simulator control panel)
+ $actualProject Simulator_sync_PC_etc ;# Synchronize PC and Time
+ }
+
+ ## Simulator: ANIMATE
+ # @return void
+ proc __animate {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator is engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check if simulator isn't busy
+ if {[$actualProject sim_run_in_progress] || [$actualProject sim_stepover_in_progress]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ $actualProject invert_animate_button ;# Change button image (simulator control panel)
+ $actualProject sim_animate ;# Start simulator in mode "animate"
+ $actualProject invert_animate_button ;# Change button image (simulator control panel)
+ }
+
+ ## Simulator: RUN
+ # @return void
+ proc __run {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator isn't already engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check if simulator isn't busy
+ if {[$actualProject sim_anim_in_progress] || [$actualProject sim_stepover_in_progress]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Change button image (simulator control panel)
+ $actualProject invert_run_button
+ ## Start simulator
+ # Remove simulator cursor from editor
+ $actualProject editor_procedure {} unset_simulator_line {}
+ # Engage mode "run"
+ set line_num [$actualProject sim_run]
+ if {$line_num != {}} {
+ $actualProject move_simulator_line $line_num
+ } {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ }
+ # Adjust simulator control panel
+ $actualProject invert_run_button
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ # Synchronize
+ $actualProject Simulator_sync ;# Simulator GUI (registers)
+ $actualProject Simulator_sync_clock ;# Simulator GUI (time)
+ $actualProject Simulator_sync_PC_etc ;# Simulator GUI (PC, Watchdog, etc.)
+ refresh_xram_mem_window $actualProject ;# XDATA memory hexadecimal editor
+ refresh_eram_mem_window $actualProject ;# EDATA memory hexadecimal editor
+ refresh_eeprom_mem_window $actualProject ;# Data EEPROM hexadecimal editor
+ }
+
+ ## Simulator: RESET
+ # @parm Char arg - reset mode
+ # '-' == no change (IRAM and XRAM)
+ # '0' == all zeroes (IRAM and XRAM)
+ # '1' == all ones (IRAM and XRAM)
+ # 'r' == random values (IRAM and XRAM)
+ # @return void
+ proc __reset {arg} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical + simulator must be on
+ if {$critical_procedure_in_progress} {return}
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ return
+ }
+ set critical_procedure_in_progress 1
+
+ # Clear program time
+ $actualProject simulator_clear_overall_time
+ # Clear graph
+ $actualProject clear_graph
+ # Perform reset
+ $actualProject Simulator_reset $arg
+ $actualProject simulator_setWatchDogTimer 0
+ # Move simulator cursor in editor to the begining of the program
+ foreach editor [$actualProject cget -editors] {
+ $editor unset_simulator_line
+ }
+ $actualProject move_simulator_line [$actualProject simulator_getCurrentLine]
+
+ # Synchronize with Hex editor and Register watches on right panel
+ if {$arg != {-}} {
+ refresh_xram_mem_window $actualProject
+ refresh_eram_mem_window $actualProject
+ refresh_eeprom_mem_window $actualProject
+ $actualProject rightPanel_watch_sync_all
+ }
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Start/Shutdown simulator
+ # @parm Bool = 0 - Load debug file for the current file only (not the main file)
+ # @return void
+ proc __initiate_sim args {
+ variable actualProject ;# Object: Current project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ if {[lindex $args 0] == 1} {
+ set current_file_only 1
+ } {
+ set current_file_only 0
+ }
+
+ # Clear program timer
+ $actualProject simulator_clear_overall_time
+
+ # Shutdown simulator
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ lset simulator_enabled $actualProjectIdx 0 ;# Simlulator disabled (set flag)
+ $actualProject Simulator_shutdown ;# Shutdown simulator engine
+ $actualProject sim_disable ;# Disable widgets of simulator GUI
+ $actualProject sfr_watches_disable ;# Disable SFR watches
+ $actualProject rightPanel_watch_disable ;# Disable widgets of register watches
+ $actualProject sfrmap_setEnabled 0 ;# Disable SFR map
+ $actualProject bitmap_setEnabled 0 ;# Disable map of bit area
+ $actualProject thaw ;# Unlock menus in file lists
+ line2pc_safely_close ;# Safely Close dialog "Line to address"
+ $actualProject subprograms_setEnabled 0 ;# Disable list of subprograms
+ $actualProject cvarsview_setEnabled 0 ;# Disable C vars view
+ $actualProject stack_monitor_set_enabled 0 ;# Disable stack monitor
+ update
+ Lock_simulator_menu ;# Lock simulator menu and toolbar
+ $actualProject interrupt_monitor_disable_buttons;# Disable interrupt monitor
+
+ # Remove simulator pointers
+ foreach editor [$actualProject cget -editors] {
+ $editor unset_simulator_line
+ }
+
+ # Inform code memory hexadecimal editor about that
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $actualProject {:}]]
+ if {$idx != -1} {
+ [lindex $code_mem_window_objects $idx] simulator_stared_stopped 0
+ }
+
+ # Start simulator
+ } else {
+ # Get ID of currently active page on bottom notebook
+ set bottom_page_ID [$actualProject getBottomPanelActivePage]
+
+ # Determinate name of simulator data file
+ set full_file_name [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ set relative_name [lindex $full_file_name 1]
+ if {$current_file_only || $relative_name == {}} {
+ set full_file_name [$actualProject editor_procedure {} getFileName {}]
+ set language [$actualProject editor_procedure {} get_language {}]
+ set relative_name [lindex $full_file_name 1]
+ } {
+ set ext [string trimleft [file extension $relative_name] {.}]
+ if {$ext == {c} || $ext == {h} || $ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set language 1
+ } elseif {$ext == {lst}} {
+ set language 2
+ } else {
+ set language 0
+ }
+ }
+ set full_file_name [file join [lindex $full_file_name 0] [lindex $full_file_name 1]]
+ set full_file_name [file rootname $full_file_name]
+ if {$language == 1} {
+ append full_file_name {.cdb}
+ } {
+ append full_file_name {.adf}
+ }
+
+ # Try to open the file and determinate expected MD5 hash
+ if {![catch {
+ # C language
+ if {$language == 1} {
+ set hashes_file [open "[file rootname $full_file_name].hashes" {r}]
+ set expected_md5s [read $hashes_file]
+ close $hashes_file
+
+ # Assembly language
+ } elseif {$language == 0} {
+ set expected_md5s {}
+ set simulator_file [open $full_file_name r]
+ while {![eof $simulator_file]} {
+ set line [gets $simulator_file]
+ if {$line == {} || [regexp {^\s*#} $line]} {
+ continue
+ }
+ set expected_md5s $line
+ break
+ }
+ close $simulator_file
+
+ # Invalid request!
+ } else {
+ error "Invalid request!"
+ }
+
+ }]} then {
+ # MD5 hash verification failed -> ask for recompilation
+ if {($language == 0 || $language == 1) && [verify_md5_hashes 1 $expected_md5s]} {
+ # Ask for recompilation
+ set response [
+ tk_messageBox \
+ -icon question \
+ -type yesno \
+ -default {yes} \
+ -title [mc "Recompile ?"] \
+ -message [mc "MD5 hashes verification failed. That probably means than some source files have been modified since last compilation.\n\nDo you want to recompile the code ?"] \
+ ]
+ if {$response != {yes}} {
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ ## Compile the source code
+ set compilation_result [__compile 1 1]
+ # (0) Compilation failed
+ if {!$compilation_result} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [mc "Compilation failed"] \
+ -message [mc "Compilation failed, see messages for details."]
+ set critical_procedure_in_progress 0
+ return
+ # (2) External compiler used
+ } elseif {$compilation_result == 2} {
+ return
+ }
+ }
+ # Unable to open the simulator data file -> ask for recompilation
+ } else {
+ # Ask for recompilation
+ set response [
+ tk_messageBox \
+ -icon question \
+ -type yesno \
+ -title [mc "File not found"] \
+ -message [mc "Simulator data file not found.\nDo you want create it ?"]
+ ]
+ if {$response == {no}} {
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ ## Compile the source code
+ set compilation_result [__compile 1 1]
+ # (0) Compilation failed
+ if {!$compilation_result} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [mc "Compilation failed"] \
+ -message [mc "Compilation failed, see messages for details."]
+ set critical_procedure_in_progress 0
+ return
+ # (2) External compiler used
+ } elseif {$compilation_result == 2} {
+ return
+ }
+
+ set full_file_name [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ if {[lindex $full_file_name 1] == {}} {
+ set full_file_name [$actualProject editor_procedure {} getFileName {}]
+ }
+ set full_file_name [file join [lindex $full_file_name 0] [lindex $full_file_name 1]]
+ regsub {\.[^\.]*$} $full_file_name {} full_file_name
+ append full_file_name {.adf}
+ }
+
+ # Open simulator data file
+ if {[catch {
+ set simulator_file [open $full_file_name r]
+ }]} then {
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to start simulator"] \
+ -message [mc "Unable to read simulator file. Possibly you have disabled generation of simulator file in compiler configuration dialog."]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Try to load IHX file if C language is used
+ if {$language == 1} {
+ if {[catch {
+ set hex_file [open "[file rootname $full_file_name].ihx" r]
+ } result]} then {
+ puts stderr $result
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to find hex file"] \
+ -message [mc "Unable to open:\n'%s'" "[file rootname $full_file_name].ihx"]
+ return
+ }
+ }
+
+ $actualProject freeze ;# Switch filelist to "Simulator mode"
+ update
+
+ # Raise tab "Simulator" on the bottom panel
+ if {[lsearch {Graph Simulator CVarsView} $bottom_page_ID] == -1} {
+ $actualProject bottomNB_show_up {Simulator}
+ } {
+ $actualProject bottomNB_show_up $bottom_page_ID
+ }
+
+ ## Engage simulator
+ lset simulator_enabled $actualProjectIdx 1 ;# Set simulator enabled flag to True
+ $actualProject sim_enable ;# Enable simulator GUI
+ $actualProject sfr_watches_enable ;# Enable SFR watches
+ $actualProject sfrmap_setEnabled 1 ;# Enable SFR map
+ $actualProject bitmap_setEnabled 1 ;# Enable map of bit area
+
+ # Load program into simulator engine
+ if {$language == 1} {
+ if {[$actualProject load_program_from_cdb \
+ [file rootname $full_file_name].c \
+ $simulator_file $hex_file \
+ ]} {
+ seek $simulator_file 0
+ $actualProject cvarsview_load_cdb $simulator_file
+ }
+ close $hex_file
+ } {
+ $actualProject load_program_from_adf $simulator_file
+ }
+
+ # Autoload list of defined symbolic name into register watches
+ $actualProject rightPanel_watch_autoload [file rootname $full_file_name].lst
+
+ # Some more initialization
+ close $simulator_file ;# Close simulator data file
+ $actualProject clear_graph ;# Clear graph
+ $actualProject Simulator_sync ;# Synchronize simulator (due to reset)
+ $actualProject rightPanel_watch_enable ;# Enable entry widgets in register watches
+ $actualProject subprograms_setEnabled 1 ;# Enable list of subprograms
+ $actualProject cvarsview_setEnabled 1 ;# Enable C vars view
+ $actualProject stack_monitor_set_enabled 1 ;# Enable stack monitor
+ $actualProject Simulator_initiate ;# Initialize simulator engine
+ $actualProject interrupt_monitor_enable_buttons ;# Enable interrupt monitor
+ __sim_clear_highlight ;# Clear all highlights
+
+ # Reset virtual MCU
+ set critical_procedure_in_progress 0
+ __reset -
+ set critical_procedure_in_progress 1
+
+ # Load breakpoints into simulator engine
+ set found 0
+ set editor {}
+ set editors [$actualProject cget -editors]
+ foreach filename [$actualProject simulator_get_list_of_filenames] {
+ set found 0
+ foreach editor $editors {
+ if {$filename == [$editor cget -fullFileName]} {
+ set found 1
+ break
+ }
+ }
+ if {$found} {
+ $actualProject Simulator_import_breakpoints \
+ $filename [$editor getBreakpoints]
+ } {
+ $actualProject Simulator_import_breakpoints $filename {}
+ }
+ }
+
+ $actualProject now_frozen
+
+ # Set simulator cursor in editor to the first OP code
+ $actualProject move_simulator_line [$actualProject simulator_getCurrentLine]
+ refresh_code_mem_window $actualProject ;# Synchronize CODE memory hex editor
+ update
+ Unlock_simulator_menu ;# Unlock simulator menu and toolbar
+ stepback_button_set_ena 0 ;# Disable StepBack controls
+
+ # Inform code memory hexadecimal editor about that
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $actualProject {:}]]
+ if {$idx != -1} {
+ [lindex $code_mem_window_objects $idx] simulator_stared_stopped 1
+ }
+ }
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Verify MD5 hashes for the given files (only for current project)
+ # @parm Bool save_files - Save modified files mentioned in the given list
+ # @parm List hashes - {hash filename hash filename ...}
+ # @return Int - Final result
+ # 0 == All correct
+ # 1 == Verification failed
+ # 2 == File access error
+ proc verify_md5_hashes {save_files hashes} {
+ variable actualProject ;# Object: Current project
+
+ # Local variables
+ set len [llength $hashes] ;# Length of the given list of hashes and files
+ set filenames {} ;# List of filenames only
+ set md5_hashes {} ;# List of md5 hashes only
+
+ set dir [$actualProject cget -projectPath]
+
+ # Separate filenames and hashes
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ lappend filenames [file join $dir [lindex $hashes $j]]
+ lappend md5_hashes [lindex $hashes $i]
+ }
+ set len [expr {int($len/2)}]
+
+ # Save mentioned files
+ if {$save_files} {
+ set idx 0
+ set e_filenames {}
+ set editors [$actualProject cget -editors]
+
+ # Determinate list of opened files
+ foreach editor $editors {
+ set filename [$editor cget -fullFileName]
+ if {$filename == {}} {
+ continue
+ }
+
+ lappend e_filenames $filename
+ }
+
+ # Save files
+ for {set i 0} {$i < $len} {incr i} {
+ set idx [lsearch $e_filenames [lindex $filenames $i]]
+
+ if {$idx == -1} {continue}
+
+ if {[[lindex $editors $idx] cget -modified]} {
+ [lindex $editors $idx] save
+ }
+ }
+ }
+
+ # Check MD5s
+ for {set i 0} {$i < $len} {incr i} {
+ set recorded_md5 [lindex $md5_hashes $i]
+ if {[catch {
+ set computed_md5 [::md5::md5 -hex -file [lindex $filenames $i]]
+ }]} {
+ return 2
+ }
+ if {$recorded_md5 != $computed_md5} {
+ return 1
+ }
+ }
+
+ return 0
+ }
+
+ ## Invoke file selection dialog to normalize IHEX8 file
+ # @return void
+ proc __normalize_hex {} {
+ variable input_file ;# Input file
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ if {$critical_procedure_in_progress} {return}
+
+ # Invoke dialog to select input file
+ set input_file {}
+ select_input_output 1 {hex} .
+ if {$input_file == {}} {return}
+
+ # File name is not valid -> invoke error message
+ if {
+ $input_file == {} ||
+ ![file exists $input_file] ||
+ ![file isfile $input_file] ||
+ (!$::MICROSOFT_WINDOWS && ![file writable $input_file]) ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $input_file])
+ } {
+ tk_messageBox \
+ -parent . -icon warning \
+ -title [mc "Error - MCU 8051 IDE"] \
+ -message [mc "Unable to gain unlimited access to the given file"]
+ # File name is valid -> normalize its content
+ } else {
+ # Progress dialog
+ create_progress_bar .prgDl \
+ . \
+ {} \
+ "Parsing file: $input_file" \
+ ::IHexTools::progress \
+ 1 \
+ [mc "Parsing file ..."] \
+ ::ICONS::16::bottom1 \
+ [mc "Abort"] \
+ {set ::IHexTools::abort 1}
+
+ # Read file
+ set file [open $input_file r]
+ set data [read $file]
+ close $file
+
+ # Normalize content
+ set ::IHexTools::update 1
+ catch {.prgDl.f.progressbar configure -maximum [::IHexTools::get_number_of_iterations $data]}
+ ::IHexTools::load_hex_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ catch {.prgDl.f.progressbar configure -maximum 16}
+ set data [::IHexTools::get_hex_data]
+ }
+
+ # Destroy progress dialog
+ catch {destroy .prgDl}
+
+ # No errors occured -> rewrite file
+ if {!${::IHexTools::error_count}} {
+ if {[catch {
+ set file [open $input_file w 420]
+ }]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -parent . \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to open file:\n\"%s\"\nfor writing" $input_file]
+ return
+ } else {
+ puts -nonewline $file $data
+ close $file
+ }
+ # Errors occured -> Invoke error message dialog
+ } else {
+ # Create dialog window
+ set dialog [toplevel .error_message_dialog -class {Error dialog} -bg {#EEEEEE}]
+
+ # Create main frame (text widget and scrolbar)
+ set main_frame [frame $dialog.main_frame]
+
+ # Create text widget
+ set text [text $main_frame.text \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ -width 0 -height 0 \
+ ]
+ pack $text -side left -fill both -expand 1
+ # Create scrollbar
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$text yview" \
+ ] -side right -fill y
+
+ # Pack main frame and create button "Close"
+ pack $main_frame -fill both -expand 1
+ pack [ttk::button $dialog.ok_button \
+ -text [mc "Close"] \
+ -command "grab release $dialog; destroy $dialog" \
+ ]
+
+ # Show error string and disable the text widget
+ $text insert end ${::IHexTools::error_string}
+ $text configure -state disabled
+
+ # Set window attributes
+ wm iconphoto $dialog ::ICONS::16::status_unknown
+ wm title $dialog [mc "Error(s) occured while parsing IHEX file - %s" ${::APPNAME}]
+ wm minsize $dialog 500 250
+ wm protocol $dialog WM_DELETE_WINDOW [mc "grab release %s; destroy %s" $dialog $dialog]
+ wm transient $dialog .
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ # Free resources reserved during normalization
+ ::IHexTools::free_resources
+ }
+ }
+
+ ## Invkoke dialog for converting Binary files to Intel® HEX 8 files
+ # @return void
+ proc __bin2hex {} {
+ variable hex__bin ;# Type of conversion
+
+ set hex__bin 0
+ hex2bin2hex
+ }
+
+ ## Invkoke dialog for converting Intel® HEX 8 files to Binary files
+ # @return void
+ proc __hex2bin {} {
+ variable hex__bin ;# Type of conversion
+ set hex__bin 1
+ hex2bin2hex
+ }
+
+ ## Invkoke dialog for converting Simulator data files to Intel® HEX 8 files
+ # @return void
+ proc __sim2hex {} {
+ variable hex__bin ;# Type of conversion
+ set hex__bin 2
+ hex2bin2hex
+ }
+
+ ## Invkoke dialog for converting Simulator data files to Binary files
+ # @return void
+ proc __sim2bin {} {
+ variable hex__bin ;# Type of conversion
+ set hex__bin 3
+ hex2bin2hex
+ }
+
+ ## Invoke conversion dialog -- auxiliary procedure for '__bin2hex', '__hex2bin', '__sim2hex', '__sim2bin'
+ # @return void
+ proc hex2bin2hex {} {
+ variable hex__bin ;# Type of conversion
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ if {$critical_procedure_in_progress} {return}
+
+ # Create dialog window
+ set win [toplevel .hex2bin2hex_dialog -class {Conversion} -bg {#EEEEEE}]
+ set mainframe [frame $win.frame]
+
+ # Label, Entry and Button "Input file"
+ grid [Label $mainframe.lbl_input \
+ -text [mc "Input file"] \
+ -helptext {File to convert} \
+ ] -column 1 -row 1 -sticky w
+ grid [ttk::entry $mainframe.entry_input \
+ -textvariable X::input_file \
+ -width 50 \
+ ] -column 2 -row 1 -sticky we
+ DynamicHelp::add $mainframe.entry_input -text [mc "File to convert"]
+ grid [ttk::button $mainframe.button_select_input_file \
+ -image ::ICONS::16::fileopen \
+ -takefocus 0 \
+ -style Flat.TButton \
+ -command {
+ # Determinate file suffix
+ if {${::X::hex__bin} == 0} {
+ set mask {bin}
+ } elseif {${::X::hex__bin} == 1} {
+ set mask {{hex,ihx}}
+ } else {
+ set mask {adf}
+ }
+ # Invoke file selection dialog
+ X::select_input_output 1 $mask .hex2bin2hex_dialog
+ } \
+ ] -column 3 -row 1 -sticky e
+ DynamicHelp::add $mainframe.button_select_input_file \
+ -text [mc "Invoke dialog to select input file"]
+
+ # Label, Entry and Button "Output file"
+ grid [Label $mainframe.lbl_output \
+ -text [mc "Output file"] \
+ -helptext [mc "File where to save result"] \
+ ] -column 1 -row 2 -sticky w
+ grid [ttk::entry $mainframe.entry_output \
+ -textvariable X::output_file \
+ -width 50 \
+ ] -column 2 -row 2 -sticky we
+ DynamicHelp::add $mainframe.entry_output \
+ -text [mc "File where to save result"]
+ grid [ttk::button $mainframe.button_select_output_file \
+ -image ::ICONS::16::fileopen \
+ -style Flat.TButton \
+ -command {
+ # Determinate file suffix
+ if {${::X::hex__bin} == 0} {
+ set mask {{hex,ihx}}
+ } elseif {${::X::hex__bin} == 1} {
+ set mask {bin}
+ } elseif {${::X::hex__bin} == 2} {
+ set mask {{hex,ihx}}
+ } elseif {${::X::hex__bin} == 3} {
+ set mask {bin}
+ }
+ # Invoke file selection dialog
+ X::select_input_output 0 $mask .hex2bin2hex_dialog
+ } \
+ ] -column 3 -row 2 -sticky e
+ DynamicHelp::add $mainframe.button_select_output_file \
+ -text [mc "Invoke dialog to select output file"]
+
+ # Create separator
+ grid [ttk::separator $mainframe.separator \
+ -orient horizontal \
+ ] -column 1 -columnspan 3 -row 3 -sticky we -pady 10
+
+ # Create buttons "Ok" and "Cancel"
+ set button_frame [frame $mainframe.button_frame]
+ pack [ttk::button $button_frame.button_ok \
+ -text [mc "Ok"] \
+ -command {X::hex2bin2hex_OK} \
+ -compound left \
+ -image ::ICONS::16::ok \
+ ] -side left -padx 5
+ pack [ttk::button $button_frame.button_cancel \
+ -text [mc "Cancel"] \
+ -command {X::hex2bin2hex_CANCEL} \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ ] -side left -padx 5
+ grid $button_frame -column 1 -columnspan 3 -row 4
+
+ # Set window title
+ if {$hex__bin == 0} {
+ wm title $win [mc "Convert Binary file to Intel HEX 8 - MCU 8051 IDE"]
+ } elseif {$hex__bin == 1} {
+ wm title $win [mc "Convert Intel HEX 8 to binary file - MCU 8051 IDE"]
+ } elseif {$hex__bin == 2} {
+ wm title $win [mc "Convert sim file to Intel HEX 8 - MCU 8051 IDE"]
+ }
+
+ pack $mainframe -fill both -expand 1 -padx 5 -pady 5
+
+ # Event bindings (Enter == Ok; Escape == Cancel)
+ bind $win <KeyRelease-Return> {X::hex2bin2hex_OK; break}
+ bind $win <KeyRelease-KP_Enter> {X::hex2bin2hex_OK; break}
+ bind $win <KeyRelease-Escape> {X::hex2bin2hex_CANCEL; break}
+
+ # Set window attributes -- modal window
+ wm iconphoto $win ::ICONS::16::bottom1
+ wm minsize $win 450 100
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW {
+ X::hex2bin2hex_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Increment compilation progress variable and call update command
+ # @return void
+ proc update_progress {} {
+ variable compilation_progress ;# Variable for compilation progressbar
+
+ incr compilation_progress
+ update
+ }
+
+ ## Set maximum for progressbar in file conversion dialog
+ # -- internal auxiliary procedure for 'hex2bin2hex_OK'
+ # @parm Int max - value to set
+ # @return void
+ proc hex2bin2hex_set_progress_max {max} {
+ .hex2bin2hex_dialog.button_frame.progress_bar configure -maximum $max
+ }
+
+ ## Perform file conversion -- auxiliary procedure for 'hex2bin2hex'
+ # @return void
+ proc hex2bin2hex_OK {} {
+ variable input_file ;# Input file
+ variable output_file ;# Output file
+ variable hex__bin ;# Type of conversion
+
+ # Check if input and output file names are not empty strings
+ if {$input_file == {} || $output_file == {}} {
+ tk_messageBox \
+ -parent .hex2bin2hex_dialog \
+ -icon warning -type ok \
+ -title "MCU 8051 IDE" \
+ -message [mc "Both entries must be filled"]
+ return
+ }
+
+ # Normalize name of input file
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $input_file]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$input_file"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $input_file]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $input_file]
+ }
+ }
+ set input_file [file normalize $input_file]
+
+ # Normalize name of output file
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $output_file]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$output_file"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $output_file]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $output_file]
+ }
+ }
+ set output_file [file normalize $output_file]
+
+ set win .hex2bin2hex_dialog
+
+ # Diable entry widgets in file selection dialog
+ foreach wdg [subst {
+ $win.frame.entry_input
+ $win.frame.entry_output
+ $win.frame.button_select_input_file
+ $win.frame.button_select_output_file
+ }] {
+ $wdg configure -state disabled
+ }
+
+ # Destroy buttons "Ok" and "Cancel"
+ destroy $win.frame.button_frame.button_ok
+ destroy $win.frame.button_frame.button_cancel
+
+ # Change window size
+ wm minsize $win 450 170
+
+ # Create staus label, progressbar and Abort button
+ set status_label [label $win.frame.button_frame.status_label -justify left]
+ set progressbar [ttk::progressbar \
+ $win.frame.button_frame.progress_bar \
+ -variable ::IHexTools::progress \
+ -mode determinate \
+ -length 440 \
+ ]
+ pack $status_label -anchor w -padx 10
+ pack $progressbar -pady 15
+ pack [ttk::button $win.frame.button_frame.button_ok \
+ -text [mc "Abort"] \
+ -image ::ICONS::16::cancel \
+ -compound left \
+ -command {X::hex2bin2hex_ABORT} \
+ ] -pady 5
+
+ # Create backup copy for output file
+ if {[file exists $output_file] && [file isfile $output_file]} {
+ if {![file writable $output_file]} {
+ tk_messageBox \
+ -type ok -icon error -parent $win \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to access file: %s" $output_file]
+ hex2bin2hex_CANCEL
+ return
+ }
+ # Ask user for overwrite existing file
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent $win \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $output_file]]
+ ] != {yes}
+ } {
+ hex2bin2hex_CANCEL
+ return
+ }
+ # Create a backup file
+ catch {
+ file rename -force $output_file "$output_file~"
+ }
+ }
+
+ # Read input file
+ if {[catch {
+ set file [open $input_file r]
+ fconfigure $file -translation binary
+ set data [read $file]
+ close $file
+ }]} then {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -title [mc "File not found - MCU 8051 IDE"] \
+ -message [mc "Unable to open file '%s'" $input_file]
+
+ } else {
+ # Update progress variable
+ set ::IHexTools::update 1
+
+ # Perform cnversion
+ switch -- $hex__bin {
+ 0 { ;# Bin -> Hex
+ $status_label configure -text [mc "Loading file ..."]
+ ::IHexTools::load_bin_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ $status_label configure -text [mc "Saving file ..."]
+ $progressbar configure -maximum 16
+ set data [::IHexTools::get_hex_data]
+ }
+ }
+ 1 { ;# Hex -> Bin
+ $status_label configure -text [mc "Loading file ..."]
+ $progressbar configure -maximum [::IHexTools::get_number_of_iterations $data]
+ ::IHexTools::load_hex_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ $status_label configure -text [mc "Saving file ..."]
+ $progressbar configure -maximum 16
+ set data [::IHexTools::get_bin_data]
+ }
+ }
+ 2 { ;# Sim -> Hex
+ $status_label configure -text [mc "Loading file ..."]
+ $progressbar configure -maximum [::IHexTools::get_number_of_iterations $data]
+ ::IHexTools::load_sim_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ $status_label configure -text [mc "Saving file ..."]
+ $progressbar configure -maximum 16
+ set data [::IHexTools::get_hex_data]
+ }
+ }
+ 3 { ;# Sim -> Bin
+ $status_label configure -text [mc "Loading file ..."]
+ $progressbar configure -maximum [::IHexTools::get_number_of_iterations $data]
+ ::IHexTools::load_sim_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ $status_label configure -text [mc "Saving file ..."]
+ $progressbar configure -maximum 16
+ set data [::IHexTools::get_bin_data]
+ }
+ }
+ }
+
+ # Write output file
+ if {$data != {}} {
+ if {[catch {
+ set file [open $output_file w 420]
+ }]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -parent . \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to open file:\n\"%s\"\nfor writing" $output_file]
+ hex2bin2hex_CANCEL
+ return
+ } else {
+ fconfigure $file -translation binary
+ puts -nonewline $file $data
+ close $file
+ }
+ }
+ }
+
+ # If errors occured -> Invoke error message dialog
+ if {${::IHexTools::error_count}} {
+ # Destroy previous dialog
+ hex2bin2hex_CANCEL
+
+ # Create dialog window
+ set dialog [toplevel .error_message_dialog -class {Error dialog} -bg {#EEEEEE}]
+
+ # Create main frame (text and scrollbar)
+ set main_frame [frame $dialog.main_frame]
+ set text [text $main_frame.text \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ -width 0 -height 0 \
+ ]
+ pack $text -side left -fill both -expand 1
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$text yview" \
+ ] -side right -fill y
+ pack $main_frame -fill both -expand 1
+
+ # Create button "Close"
+ pack [ttk::button $dialog.ok_button \
+ -text [mc "Close"] \
+ -command "grab release $dialog; destroy $dialog" \
+ ]
+
+ $text insert end ${::IHexTools::error_string}
+ $text configure -state disabled
+
+ # Set window attributes -- modal window
+ wm iconphoto $dialog ::ICONS::16::no
+ wm title $dialog [mc "Corrupted file - MCU 8051 IDE"]
+ wm minsize $dialog 520 250
+ wm protocol $dialog WM_DELETE_WINDOW "grab release $dialog; destroy $dialog"
+ wm transient $dialog .
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ # Close original dialog
+ hex2bin2hex_CANCEL
+ }
+
+ ## Abort file conversion -- auxiliary procedure for 'hex2bin2hex'
+ # @return void
+ proc hex2bin2hex_ABORT {} {
+ set ::IHexTools::abort 1
+ }
+
+ ## Close file conversion dialog -- auxiliary procedure for 'hex2bin2hex'
+ # @return void
+ proc hex2bin2hex_CANCEL {} {
+ ::IHexTools::free_resources
+ grab release .hex2bin2hex_dialog
+ destroy .hex2bin2hex_dialog
+ }
+
+ ## Invoke file selection dialog to select input or output file
+ # Result is stored in variable '::X::input_file' or '::X::output_file'
+ # @parm Bool io - 1 == Input; 0 == Output
+ # @parm String mask - File suffix
+ # @parm Widget master - GUI parent
+ # @return void
+ proc select_input_output {io mask master} {
+ variable IO ;# Bool: 1 == choose input file; 0 == choose output file
+ variable actualProject ;# Object: Current project
+ set IO $io
+
+ # Invoke the dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Open file - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes [list \
+ [list [mc "Input file"] "*.$mask"] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Ok button
+ fsd setokcmd {
+ set filename [X::fsd get]
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+ if {${X::IO}} {
+ set X::input_file $filename
+ } {
+ set X::output_file $filename
+ }
+ }
+
+ fsd activate ;# Activate the dialog
+ }
+
+ ## Invoke dialog "Disassemble"
+ # @return void
+ proc __disasm {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Invoke the file selection dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Open file - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes [list \
+ [list [mc "IHEX 8"] {*.{hex,ihx}}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ fsd setokcmd {
+ X::fsd deactivate
+
+ set filename [X::fsd get]
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+
+ if {
+ ![file exists $filename] ||
+ ![file isfile $filename] ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $filename])
+ } {
+ tk_messageBox -type ok -icon warning \
+ -parent [X::fsd get_window_name] \
+ -title [mc "File not found - MCU 8051 IDE"] \
+ -message [mc "The selected file %s does not exist." $filename]
+ } else {
+ set data [X::decompile $filename]
+
+ if {$data != {}} {
+ ${X::actualProject} background_open $data
+ if {[lindex ${X::simulator_enabled} ${X::actualProjectIdx}] == 0} {
+ ${X::actualProject} switch_to_last
+ }
+ } {
+ tk_messageBox \
+ -type ok -icon warning \
+ -title [mc "Decompilation failed"] \
+ -message [mc "Decompilation failed -- see messages for details"]
+ }
+ }
+ }
+ # activate the dialog
+ fsd activate
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Disaaemble the given file -- auxiliary procedure for '__disasm'
+ # @parm String filename - name of IHEX8 file to disassemble
+ # @return String - resulting source code
+ proc decompile {filename} {
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable compilation_mess_project ;# Object: Project related to running compilation
+ variable actualProject ;# Object: Current project
+
+ set compilation_in_progress 1
+ set compilation_mess_project $actualProject
+ messages_text_append [mc "\nLoading IHEX file ..."]
+
+ # Open the specified file
+ if {[catch {
+ set file [open $filename r]
+ }]} then {
+ tk_messageBox -parent . \
+ -icon warning -type ok \
+ -title [mc "Unable to open file"] \
+ -message [mc "Unable to read file '%s'" $filename]
+ return {}
+ }
+
+ # Adjust GUI
+ make_progressBar_on_Sbar ;# Create compilation progress bar on status bar
+ compilation_progress ;# Initialize compilation progress bar
+ $actualProject bottomNB_show_up {Messages} ;# Raise tab "Messages" on bottom panel
+
+ # Setup compiler
+ set Compiler::Settings::ABORT_VARIABLE 0
+ set Compiler::Settings::TEXT_OUPUT_COMMAND X::messages_text_append
+ set Compiler::Settings::UPDATE_COMMAND {update}
+
+ # Perform decompilation
+ set data {}
+ set ::IHexTools::update 1
+ ::IHexTools::load_hex_data [read $file]
+ if {!${::IHexTools::error_count} && !${::IHexTools::abort}} {
+ messages_text_append [mc "Successful"]
+ set data [::disassembler::compile [::IHexTools::get_hex_data]]
+ set ::disassembler::asm {}
+ }
+ close $file
+
+ # Finalize
+ set Compiler::Settings::ABORT_VARIABLE 0
+ destroy_progressBar_on_Sbar
+ set compilation_in_progress 0
+
+ # Write error messages
+ if {${::IHexTools::error_count}} {
+ messages_text_append ${::IHexTools::error_string}
+ messages_text_append [mc "FAILED"]
+ }
+
+ # Free resources reserved during decompilation
+ ::IHexTools::free_resources
+
+ return $data
+ }
+
+ ## Show/Hide Line numbers (in Editor)
+ # @return void
+ proc __show_hine_LineN {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Show/Hide line numbers
+ $actualProject show_hide_lineNumbers
+ }
+
+ ## Show/Hide Icon border (in Editor)
+ # @return void
+ proc __show_hine_IconB {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Show/Hide Icon border
+ $actualProject show_hide_IconBorder
+ }
+
+ ## Redraw pane windows -- binding for event <Configure>
+ # @return void
+ proc redraw_panes {} {
+ variable last_WIN_GEOMETRY ;# Last window geometry (main window)
+ variable openedProjects ;# List of opened projects (Object references)
+
+ # Window geometry unchanged -> return
+ if {$last_WIN_GEOMETRY == [wm geometry .]} {
+ return
+ # Refresh last window geometry variable
+ } {
+ set last_WIN_GEOMETRY [wm geometry .]
+ }
+
+ # Gain window height and width
+ evaluate_new_window_geometry
+
+ # Bottom NoteBook
+ if {${::last_WIN_GEOMETRY_width} != ${::WIN_GEOMETRY_width}} {
+ set ::last_WIN_GEOMETRY_width ${::WIN_GEOMETRY_width}
+ foreach project $openedProjects {
+ catch {
+ $project bottomNB_redraw_pane
+ }
+ catch {
+ $project leftpanel_redraw_pane
+ }
+ }
+ }
+ # Right panel & File notes
+ if {${::last_WIN_GEOMETRY_height} != ${::WIN_GEOMETRY_height}} {
+ set ::last_WIN_GEOMETRY_height ${::WIN_GEOMETRY_height}
+ foreach project $openedProjects {
+ catch {
+ $project right_panel_redraw_pane
+ $project todo_panel_redraw_pane
+ }
+ }
+ }
+ }
+
+ ## Invoke dialog "About"
+ # @return void
+ proc __about {} {
+ # Create dialog window
+ set win [toplevel .about -class [mc "About dialog"] -bg {#EEEEEE}]
+
+ # Create dialog header
+ pack [label $win.header \
+ -compound left \
+ -image ::ICONS::32::mcu8051ide \
+ -text " ${::APPNAME}" \
+ -font [font create \
+ -size -20 \
+ -family {helvetica}]
+ ] -side top -pady 5
+
+ # Create notebook
+ set nb [ttk::notebook $win.nb]
+
+ # Create tab "About"
+ set about_tab [frame $nb.about_tab]
+ $nb add $about_tab -text [mc "About"]
+ pack [text $about_tab.text \
+ -width 0 -height 0 -cursor left_ptr \
+ -yscrollcommand "$about_tab.scrollbar set" \
+ -font [font create \
+ -size -12 \
+ -family {helvetica}] \
+ ] -fill both -expand 1 -side left
+ pack [ttk::scrollbar $about_tab.scrollbar \
+ -orient vertical \
+ -command "$about_tab.text yview" \
+ ] -fill y -side right
+ # fill in the about tab
+ $about_tab.text insert end "${::APPNAME}\n"
+ $about_tab.text insert end [mc "\tComplete IDE for MCS-51 based microconrollers.\n"]
+ $about_tab.text insert end [mc "\tThis program is witten for POSIX Systems\n"]
+ if {$::MICROSOFT_WINDOWS} {
+ $about_tab.text insert end [mc "\tYOU ARE CURRENTLY USING VERSION FOR Microsoft® Windows®\n"]
+ }
+ $about_tab.text insert end "\n(c) Martin Ošmera <martin.osmera@gmail.com>\n"
+ $about_tab.text insert end [mc "Web: http://mcu8051ide.sourceforge.net\n"]
+ $about_tab.text insert end [mc "Please post suggestions and comments at http://mcu8051ide.sf.net\n"]
+ $about_tab.text insert end [mc "\n\nThanks to Kostya V. Ivanov for bug fixes.\n"]
+ $about_tab.text insert end [mc "Thanks to SDCC development team for their great work !\n"]
+ $about_tab.text insert end [mc "Thanks to %s for their help during development\n" "Fabricio Alcalde, Shakthi Kannan, Miroslav Hradílek, Kostya V. Ivanov"]
+
+ # Finalize text widget creation
+ $about_tab.text configure -state disabled
+
+ # Create tab "Thanks to"
+ set thanks_tab [frame $nb.thanks_tab]
+ $nb add $thanks_tab -text [mc "Thanks to"]
+ pack [text $thanks_tab.text \
+ -width 0 -height 0 -cursor left_ptr \
+ -yscrollcommand "$thanks_tab.scrollbar set" \
+ ] -fill both -expand 1 -side left
+ pack [ttk::scrollbar $thanks_tab.scrollbar \
+ -orient vertical \
+ -command "$thanks_tab.text yview" \
+ ] -fill y -side right
+
+
+ $thanks_tab.text insert end [mc "Thanks to Fabricio Alcalde for bug reports and suggestions\n"]
+ $thanks_tab.text insert end [mc "Thanks to Miroslav Hradílek for bug reports\n"]
+ $thanks_tab.text insert end [mc "Thanks to Kostya V. Ivanov for significant bug fixes.\n"]
+ $thanks_tab.text insert end [mc "Thanks to Shakthi Kannan for including this IDE in FEL\n\n"]
+ $thanks_tab.text insert end [mc "SDCC developers:\n"]
+ $thanks_tab.text insert end "\tBela Torok\n"
+ $thanks_tab.text insert end "\tBernhard Held\n"
+ $thanks_tab.text insert end "\tBorut Ražem\n"
+ $thanks_tab.text insert end "\tDave Helton\n"
+ $thanks_tab.text insert end "\tDaniel Drotos\n"
+ $thanks_tab.text insert end "\tErik Petrich\n"
+ $thanks_tab.text insert end "\tFrieder Ferlemann\n"
+ $thanks_tab.text insert end "\tHans Dorn\n"
+ $thanks_tab.text insert end "\tJerome Bessiere\n"
+ $thanks_tab.text insert end "\tJesus Calvino-Fraga\n"
+ $thanks_tab.text insert end "\tJohan Knol\n"
+ $thanks_tab.text insert end "\tAlex Karahalios\n"
+ $thanks_tab.text insert end "\tKarl Bongers\n"
+ $thanks_tab.text insert end "\tKlaus Flittner\n"
+ $thanks_tab.text insert end "\tKlaus Martin Hennemann\n"
+ $thanks_tab.text insert end "\tKevin Vigor\n"
+ $thanks_tab.text insert end "\tMaarten Brock\n"
+ $thanks_tab.text insert end "\tMartin Dubuc\n"
+ $thanks_tab.text insert end "\tMartin Helmling\n"
+ $thanks_tab.text insert end "\tMichael Hope\n"
+ $thanks_tab.text insert end "\tMichael Schmitt\n"
+ $thanks_tab.text insert end "\tPaul Stoffregen\n"
+ $thanks_tab.text insert end "\tSandeep Dutta\n"
+ $thanks_tab.text insert end "\tScott Dattalo\n"
+ $thanks_tab.text insert end "\tErik Petrich\n"
+ $thanks_tab.text insert end "\tStephen M. Kenton\n"
+ $thanks_tab.text insert end "\tSlade Rich\n"
+ $thanks_tab.text insert end "\tShawn Masters\n"
+ $thanks_tab.text insert end "\tPhilipp Krause\n"
+ $thanks_tab.text insert end "\tStephen Williams\n"
+ $thanks_tab.text insert end "\tRaphael Neider\n"
+ $thanks_tab.text insert end "\tAnton Voloshin\n"
+ $thanks_tab.text insert end "\tVangelis Rokas\n"
+ $thanks_tab.text insert end "\tWim Lewis\n"
+ $thanks_tab.text insert end [mc "\n(Please post suggestions to %s)\n" "martin.osmera@gmail.com"]
+ $thanks_tab.text configure -state disabled
+
+ # Create tab "Licence"
+ set licence_tab [frame $nb.licence_tab]
+ $nb add $licence_tab -text [mc "Licence"]
+ pack [text $licence_tab.text \
+ -width 0 -height 0 \
+ -yscrollcommand "$licence_tab.scrollbar set" \
+ ] -fill both -expand 1 -side left
+ pack [ttk::scrollbar $licence_tab.scrollbar \
+ -orient vertical \
+ -command "$licence_tab.text yview" \
+ ] -fill y -side right
+ # Fill in the licence tab
+ if {[file exists "${::LIB_DIRNAME}/../data/licence.txt"]} {
+ $licence_tab.text insert end [read [open "${::LIB_DIRNAME}/../data/licence.txt" {r}]]
+ } {
+ $licence_tab.text insert end [mc "FILE \"licence.txt\" WAS NOT FOUND\n\n"]
+ $licence_tab.text insert end [mc "Text of the licence agreement is not availble,\n"]
+ $licence_tab.text insert end [mc "please check your instalation."]
+ }
+ $licence_tab.text configure -state disabled
+
+ # Pack NoteBook
+ pack $nb -fill both -expand 1 -side top -padx 10
+ $nb select $about_tab
+ # Create button "Close"
+ pack [ttk::button $win.close \
+ -text [mc "Close"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::about_CLOSE} \
+ ] -side bottom -pady 5
+
+ # Events binding (Enter, Escape == Close)
+ bind $win <KeyRelease-Return> {X::about_CLOSE; break}
+ bind $win <KeyRelease-KP_Enter> {X::about_CLOSE; break}
+ bind $win <KeyRelease-Escape> {X::about_CLOSE; break}
+
+ # Focus on button "Close"
+ focus $win.close
+
+ # Window manager options -- modal window
+ wm iconphoto $win ::ICONS::16::mcu8051ide
+ wm title $win [mc "About - MCU 8051 IDE"]
+ wm minsize $win 620 320
+ wm protocol $win WM_DELETE_WINDOW {
+ X::about_CLOSE
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Close dialog "About" -- auxiliary procedure for '__about'
+ # @return void
+ proc about_CLOSE {} {
+ grab release .about
+ destroy .about
+ }
+
+ ## Auto indent source code in the current editor
+ # @return void
+ proc __reformat_code {} {
+ variable actualProject ;# Object: Current project
+ variable editor_lines ;# Number of lines in the current editor
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable reformat_code_abort ;# Bool: Abort function 'reformat_code'
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # C language
+ if {[$actualProject editor_procedure {} get_language {}] == 1} {
+ if {$::MICROSOFT_WINDOWS} { ;# Not implemented yet on Microsoft Windows
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Sorry, unable to compile"] \
+ -message [mc "Unable to indent C source without program indent, MCU 8051 IDE is unable to localize this program on Microsoft Windows operating system. So this feature is not available in version for MS Windows. Correction of this limitation is planed but right now it's not available."]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check for program "indent"
+ if {!${::PROGRAM_AVALIABLE(indent)}} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to compile"] \
+ -message [mc "Unable to indent C source without program indent, please install indent and restart MCU 8051 IDE."]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Save file
+ if {![$actualProject editor_procedure {} save {}]} {
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Perform indention and refresh editor
+ set filename [$actualProject editor_procedure {} getFileName {}]
+ set filename [file join [lindex $filename 0] [lindex $filename 1]]
+ if {[catch {exec -- indent -kr -npro $filename} result]} {
+ puts stderr $result
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to compile"] \
+ -message [mc "Unable to indent C source code.\n\n%s" $result]
+ } {
+ $actualProject filelist_reload_file
+ }
+
+ # Assembly language
+ } {
+ # Prepare
+ set reformat_code_abort 0 ;# Reset auto indention abort flag
+ set editor_lines [$actualProject editor_linescount] ;# Number of lines in the editor
+ set compilation_progress 0 ;# Reset compilation progress variable
+ set editor [$actualProject editor_procedure {} cget -editor] ;# Editor widget
+ set lastLine [$actualProject editor_actLineNumber] ;# Current line
+ set new_content {} ;# Initialize new content string
+
+ set max [expr {$editor_lines / 10}]
+ if {!$max} {
+ set max 1
+ }
+
+ # Create progress dialog
+ create_progress_bar .prgDl \
+ . \
+ {} \
+ "Reformating code" \
+ ::X::compilation_progress \
+ $max \
+ [mc "Reformating code"] \
+ ::ICONS::16::filter \
+ [mc "Abort"] \
+ {::X::reformat_code_stop}
+
+ $editor configure -autoseparators 0
+
+ # Perform auto indention
+ set new_content [reformat_code_core [$editor get 1.0 end]]
+ $editor delete 1.0 end
+
+ # Insert new content in the editor
+ $editor insert end [string replace $new_content {end-1} end]
+ $actualProject editor_procedure {} parseAll {}
+ $actualProject editor_procedure {} goto $lastLine
+
+ $editor edit separator
+ $editor configure -autoseparators 1
+
+ # Finalize
+ catch {destroy .prgDl ;# Destroy progress dialog}
+ }
+ set critical_procedure_in_progress 0
+ }
+
+ ## Abort auto indention -- auxiliary procedure for '__reformat_code'
+ # @return void
+ proc reformat_code_stop {} {
+ variable reformat_code_abort ;# Bool: Abort function 'reformat_code'
+ set reformat_code_abort 1
+ }
+
+ ## Perform auto indention -- auxiliary procedure for '__reformat_code'
+ # @parm String data - data to parse
+ # @return String - result
+ proc reformat_code_core {data} {
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable reformat_code_abort ;# Bool: Abort function 'reformat_code'
+
+ set idx 1 ;# Line number
+ set new_content {} ;# Resulting string
+
+ # Parse input data (line by line)
+ foreach line [split $data "\n"] {
+ if {$reformat_code_abort} {break} ;# Conditional abort
+ incr idx ;# Increment line number
+
+ # Replace lines containg only white space with empty lines
+ if {[regexp {^\s*$} $line]} {
+ append new_content "\n"
+ if {![expr {$idx % 10}]} {
+ incr compilation_progress
+ }
+ continue
+ }
+
+ # Line fields
+ set field_0 {} ;# 1st field (labels, constants, etc.)
+ set field_1 {} ;# 2nd field (instructins, directives, macros, etc.)
+ set field_2 {} ;# 3rd field (operands, arguments, etc.)
+ set field_3 {} ;# 4th field (comments only)
+
+ # Determinate line with replaced strings and chars with underscores
+ set line_tmp $line
+ while 1 {
+ if {![regexp {'[^']+'} $line_tmp str]} {break}
+ set len [string length $str]
+ regsub {'[^']+'} $line_tmp [string repeat {_} $len] line_tmp
+ }
+
+ # Determinate comment field (field_3)
+ set commentBegin [string first {;} $line_tmp]
+ if {$commentBegin != -1} {
+ set field_3 [string range $line $commentBegin end]
+ regsub {\s*;.*$} $line_tmp {} line_tmp
+ set line [string range $line 0 [expr {$commentBegin - 1}]]
+ }
+
+ # Determinate fields 0..2
+ set pos 0
+ for {set j 0} {$j < 2} {incr j} {
+ if {![regexp {^\s*[^\s]+} $line_tmp str]} {break}
+ set len [string length $str]
+ set i [expr {$len - 1}]
+ set space [string repeat { } $len]
+ regsub {^\s*[^\s]+} $line_tmp $space line_tmp
+ set field_$j [regsub {^\s+} [string range $line $pos $i] {}]
+ set line [string replace $line $pos $i $space]
+ incr pos $len
+ }
+
+ # Remove leading white space from Field 2
+ set field_2 [regsub {^\s+} $line {}]
+
+ # Field 1 >> Field 2; Field 0 -> Field 1; "" -> Field 0;
+ if {
+ [regexp {^\w+$} $field_0] &&
+ ![regexp {^\d} $field_0] &&
+ [lsearch -exact -ascii ${::ASMsyntaxHighlight::directive_type2} \
+ [string toupper $field_1]] == -1
+ } {
+ append field_1 $field_2
+ set field_2 $field_1
+ set field_1 {}
+ if {[string toupper $field_0] != {ENDM}} {
+ set field_1 $field_0
+ set field_0 {}
+ }
+ }
+
+ # If line contains only comment then Field 3 -> Field 1
+ if {
+ $field_3 != {} &&
+ $field_0 == {} &&
+ $field_1 == {} &&
+ $field_2 == {} &&
+ $commentBegin != 0
+ } {
+ set field_1 $field_3
+ set field_3 {}
+ }
+
+ # Adjust space between operans/arguments
+ set field_2_new {}
+ if {$field_2 != {}} {
+ # Strings/Chars to underscores
+ set field_2_tmp $field_2
+ while 1 {
+ if {![regexp {'[^']+'} $field_2_tmp str]} {break}
+ set len [string length $str]
+ regsub {'[^']+'} $field_2_tmp [string repeat {_} $len] field_2_tmp
+ }
+ # Recomposite Field 2
+ while 1 {
+ set i [string first {,} $field_2_tmp]
+ if {$i == -1} {
+ append field_2_new {, }
+ append field_2_new [string trim $field_2]
+ break
+ }
+ append field_2_new {, }
+ append field_2_new [string trim [string range $field_2 0 [expr {$i - 1}]]]
+ set field_2 [string range $field_2 [expr {$i + 1}] end]
+ set field_2_tmp [string range $field_2_tmp [expr {$i + 1}] end]
+ }
+ set field_2 [string trimleft $field_2_new {, }]
+ }
+
+ # Recomposite line
+ set line $field_0
+ if {$field_1 != {}} {
+ append line "\t"
+ append line $field_1
+ }
+ if {$field_2 != {}} {
+ append line "\t"
+ append line $field_2
+ }
+ if {$field_3 != {}} {
+ # Adjust field 3 (insure appropriate number of leading tabs)
+ if {$line != {}} {
+ set i -1
+ set spaces 0
+ set correction 0
+ set falseLength [string length $line]
+
+ while 1 {
+ set i [string first "\t" $line [expr {$i + 1}]]
+ if {$i == -1} {break}
+
+ set spaces [expr {8 - (($i + $correction) % 8)}]
+ set spaces_1 [expr {$spaces - 1}]
+ incr correction $spaces_1
+ incr falseLength $spaces_1
+ }
+
+ set spaces [expr {4 - ($falseLength / 8)}]
+ if {$spaces < 1} {
+ set spaces 1
+ }
+
+ append line [string repeat "\t" $spaces]
+ }
+ append line $field_3
+ }
+
+ # Append new line to the result
+ append new_content $line
+ append new_content "\n"
+ if {![expr {$idx % 10}]} {
+ incr compilation_progress
+ }
+ }
+
+ # Return result
+ return $new_content
+ }
+
+ ## Invoke dialog "Clean up project folder"
+ # @return void
+ proc __cleanup {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Create dialog window
+ set win [toplevel .cleanup -class [mc "Options dialog"] -bg {#EEEEEE}]
+ set bottom_frame [frame $win.buttonFrame]
+ set status_bar_lbl [label $bottom_frame.status_bar \
+ -justify left -anchor w \
+ ]
+
+ # Create label frames
+ set backup_labelframe [ttk::labelframe $win.backup_labelframe\
+ -text [mc "Backup files"] \
+ ]
+ set other_labelframe [ttk::labelframe $win.other_labelframe \
+ -text [mc "Other files"] \
+ ]
+
+ set i 0 ;# Checkbutton index
+
+ # Fill in top labelframe
+ set row 0 ;# Row in the grid
+ set col 0 ;# Column in the grid
+ foreach text {
+ *.asm~ *.lst~ *.sim~ *.hex~ *.bin~ *.html~
+ *.tex~ *.wtc~ *.mcu8051ide~ *.m5ihib~ *.cdb~
+ *.ihx~ *.adf~ *.omf~ *.map~ *.c~ *.h~
+ *.vhc~ *.vhw~ *.txt~ *~
+ } ID {
+ asm lst sim hex bin html
+ tex wtc mcu8051ide m5ihib cdb
+ ihx adf omf map c h
+ vhc vhw txt all_bc
+ } helptext {
+ {Assembly language sources}
+ {Code listing files}
+ {Assembly debug files (before v1.0.5)}
+ {IHEX object code files}
+ {Binary object code files}
+ {HTML files}
+ {TeX sources}
+ {Register watches definition files}
+ {MCU 8051 IDE Project}
+ {Hibernated programs}
+ {SDCC debug files}
+ {SDCC IHEX8 object files}
+ {MCU 8051 IDE Assembler debug files}
+ {OMF-51 object files}
+ {SDCC: The memory map for the load module}
+ {C sources}
+ {C headers}
+ {Virtual Hardware Component}
+ {Virtual HardWare}
+ {Text files}
+ {All backup files}
+ } \
+ {
+ set helptext [mc $helptext]
+ set button [checkbutton $backup_labelframe.$ID \
+ -text $text -anchor w \
+ -command "::X::cleanup_option $i" \
+ -variable __cleanup_$ID \
+ ]
+ grid $button -row $row -column $col -sticky w -padx 5
+ if {[lindex $::CONFIG(CLEANUP_OPTIONS) $i] != {0}} {$button select} {$button deselect}
+ bind $button <Enter> "$status_bar_lbl configure -text {$helptext}"
+ bind $button <Leave> "$status_bar_lbl configure -text {}"
+
+ incr i
+ incr col
+ if {$col == 4} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Fill in bottom labelframe
+ set row 0 ;# Row in the grid
+ set col 0 ;# Column in the grid
+ foreach text {
+ *.lst *.sim *.hex *.bin *.html *.tex *.m5ihib
+ *.noi *.obj *.map *.p *.mac *.i *.ihx
+ *.adf *.adb *.rel *.cdb *.mem *.lnk *.sym
+ *.omf *.rst *.hashes *.bak
+ } ID {
+ lst sim hex bin html tex m5ihib
+ noi obj map p mac i ihx
+ adf adb rel cdb mem lnk sym
+ omf rst hashes bak
+ } helptext {
+ {Code listing files}
+ {Assembly debug files (before v1.0.5)}
+ {IHEX object code files}
+ {Binary object code files}
+ {HTML files}
+ {TeX sources}
+ {Hibernated programs}
+ {ASL: NoICE-compatible command file}
+ {ASL: Atmel debub file used by the AVR tools}
+ {SDCC: The memory map for the load module}
+ {ASL object files}
+ {Macro definition file}
+ {Macro output files}
+ {SDCC IHEX8 object files}
+ {MCU 8051 IDE Assembler debug files}
+ {SDCC Assembler debug files}
+ {SDCC: Object file created by the assembler}
+ {SDCC debug files}
+ {SDCC: A file with a summary of the memory usage}
+ {SDCC: Linker script}
+ {SDCC: Symbol listing for the sourcefile}
+ {OMF-51 object files}
+ {SDCC: Listing file updated with linkedit information}
+ {MD5 hashes for C source files}
+ {Doxygen backup file}
+ } \
+ {
+ set helptext [mc $helptext]
+ set button [checkbutton $other_labelframe.$ID \
+ -text $text -anchor w \
+ -command "::X::cleanup_option $i" \
+ -variable __cleanup__$ID \
+ ]
+ grid $button -row $row -column $col -sticky w -padx 5
+ if {[lindex $::CONFIG(CLEANUP_OPTIONS) $i] != {0}} {$button select} {$button deselect}
+ bind $button <Enter> "$status_bar_lbl configure -text {$helptext}"
+ bind $button <Leave> "$status_bar_lbl configure -text {}"
+
+ incr i
+ incr col
+ if {$col == 4} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Set column sizes
+ grid columnconfigure $backup_labelframe 0 -minsize 130
+ grid columnconfigure $backup_labelframe 1 -minsize 130
+ grid columnconfigure $backup_labelframe 2 -minsize 130
+ grid columnconfigure $backup_labelframe 3 -minsize 130
+ grid columnconfigure $other_labelframe 0 -minsize 130
+ grid columnconfigure $other_labelframe 1 -minsize 130
+ grid columnconfigure $other_labelframe 2 -minsize 130
+ grid columnconfigure $other_labelframe 3 -minsize 130
+
+ # Pack label frames
+ pack $backup_labelframe -fill both -expand 1 -padx 10 -pady 5
+ pack $other_labelframe -fill both -expand 1 -padx 10 -pady 5
+
+ # Create 'OK' and 'CANCEL' buttons
+ pack $status_bar_lbl -side left -fill x -expand 1
+ pack [ttk::button $win.buttonFrame.ok \
+ -text [mc "Remove files"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::cleanup_OK} \
+ ] -side left
+ pack [ttk::button $win.buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::cleanup_CANCEL} \
+ ] -side left
+ pack $bottom_frame -pady 5 -fill x -padx 5
+
+ # Events binding (Enter == Ok; Esc == Cancel)
+ bind $win <KeyRelease-Return> {X::cleanup_OK; break}
+ bind $win <KeyRelease-KP_Enter> {X::cleanup_OK; break}
+ bind $win <KeyRelease-Escape> {X::cleanup_CANCEL; break}
+
+ # Set window attributes -- modal window
+ wm iconphoto .cleanup ::ICONS::16::emptytrash
+ wm title .cleanup [mc "Cleanup project folder - MCU 8051 IDE"]
+ wm minsize .cleanup 360 310
+ wm resizable .cleanup 0 0
+ wm protocol .cleanup WM_DELETE_WINDOW {
+ X::cleanup_CANCEL
+ }
+ wm transient .cleanup .
+ grab .cleanup
+ raise .cleanup
+ tkwait window .cleanup
+ }
+
+ ## Change cleanup option -- auxiliary procedure for '__cleanup'
+ # @parm Int idx - checkbutton index
+ # @return void
+ proc cleanup_option {idx} {
+ lset ::CONFIG(CLEANUP_OPTIONS) $idx \
+ [expr {[lindex $::CONFIG(CLEANUP_OPTIONS) $idx] == {0}}]
+ }
+
+ ## Start cleanup -- auxiliary procedure for '__cleanup'
+ # @return void
+ proc cleanup_OK {} {
+ variable cleanup_masks ;# GLOB patterns
+ variable actualProject ;# Object: Current project
+
+ # Invoke confirmation dialog
+ if {
+ ![tk_messageBox \
+ -parent . \
+ -icon question \
+ -type yesno \
+ -title [mc "Cleanup project folder"] \
+ -message [mc "Are you sure ?"]
+ ]
+ } {
+ return
+ }
+
+ # Determinate list of GLOB expressions of selected for removal
+ set dir [$actualProject cget -projectPath]
+ set files [list]
+ foreach mask $cleanup_masks bool $::CONFIG(CLEANUP_OPTIONS) {
+ if {$bool} {
+ lappend files $mask
+ }
+ }
+
+ # Determinate list of files selected for removal
+ set files_n [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach f $files {
+ append files_n { } [glob -directory $dir -nocomplain -type f $f]
+ }
+ }
+ set files $files_n
+
+ # Remove the specified files
+ set result {}
+ foreach file $files {
+ if {![catch {
+ file delete -force -- $file
+ }]} {
+ lappend result $file
+ }
+ }
+
+ # Finalize
+ cleanup_CANCEL ;# Close dialog window
+ cleanup_finish $result ;# Invoke results dialog
+ }
+
+ ## Close dialog "Clean up project folder" -- auxiliary procedure for 'cleanup_OK'
+ # @return void
+ proc cleanup_CANCEL {} {
+ destroy .cleanup
+ }
+
+ ## Show results of files removal -- auxiliary procedure for 'cleanup_OK'
+ # @parm List files - list of removed files
+ # @return void
+ proc cleanup_finish {files} {
+ # Create dialog window
+ set win [toplevel .cleanup_finish -class {Results} -bg {#EEEEEE}]
+
+ # Create window header
+ pack [label $win.header_label \
+ -text [mc "These files were removed"] \
+ -font [font create \
+ -size -20 \
+ -family {helvetica}]
+ ] -anchor center
+
+ # Create top frame (text widget and scrollbar)
+ set frame [frame $win.top_frame]
+
+ # Create text widget and its scrollbar
+ set scrollbar [ttk::scrollbar $frame.scrollbar \
+ -command "$frame.text yview" \
+ -orient vertical \
+ ]
+ set text [text $frame.text \
+ -yscrollcommand "$frame.scrollbar set" \
+ -width 1 -height 1 \
+ -cursor left_ptr \
+ ]
+
+ # Fill in the text widget
+ foreach txt $files {
+ $text insert end $txt
+ $text insert end "\n"
+ }
+ $text configure -state disabled
+
+ # Pack scrollbar and the text widget
+ pack $scrollbar -side right -fill y
+ pack $text -side left -fill both -expand 1
+
+ # Pack the top frame and create button "Ok"
+ pack $frame -fill both -expand 1
+ pack [ttk::button $win.ok_button \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "destroy $win" \
+ ] -anchor center -side bottom
+
+ # Events binding (Enter/Escape == Ok)
+ bind $win <KeyRelease-Return> "destroy $win; break"
+ bind $win <KeyRelease-KP_Enter> "destroy $win; break"
+ bind $win <KeyRelease-Escape> "destroy $win; break"
+
+ # Set window attributes -- modal window
+ wm iconphoto $win ::ICONS::16::emptytrash
+ wm title $win [mc "Cleanup project folder - MCU 8051 IDE"]
+ wm minsize $win 520 300
+ wm protocol $win WM_DELETE_WINDOW "grab release $win; destroy $win"
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Execute custom command
+ # @parm Int cmd_num - command number
+ # @return void
+ proc __exec_custom_cmd {cmd_num} {
+ variable custom_command_cmd ;# Array of custom commands (shell scripts)
+ variable custom_command_options ;# Array of Lists of custom command options
+ variable custom_command_PID ;# Array of custom command TIDs (Thread IDentifiers)
+ variable custom_command_NUM ;# Array of custom command numbers
+ variable custom_command_counter ;# Counter of custom command invocations
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if the command is not already running
+ if {$custom_command_PID($cmd_num) != {}} {
+ if {[tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type yesno \
+ -title [mc "Confirm termination - MCU 8051 IDE"] \
+ -message [mc "This process is alredy in progress. Do you want to terminate it ?"]
+ ] == {yes}} {
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no kill command on Microsoft Windows
+ if {$custom_command_PID($cmd_num) != {}} {
+ catch {
+ exec -- kill -9 $custom_command_PID($cmd_num) &
+ }
+ }
+ }
+ custom_cmd_icon_reset $custom_command_NUM($cmd_num)
+ }
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Invoke confiramation dialog (if requested)
+ if {[lindex $custom_command_options($cmd_num) 0]} {
+ if {
+ ![tk_messageBox \
+ -parent . \
+ -icon question \
+ -type yesno \
+ -title [mc "Confirmation required"] \
+ -message [mc "Do you really want to execute\ncustom command %s ?" $cmd_num]]
+ } {
+ set critical_procedure_in_progress 0
+ return
+ }
+ }
+
+ # Adjust button icon on main toolbar
+ if {[winfo exists .mainIconBar.custom$cmd_num]} {
+ .mainIconBar.custom$cmd_num configure \
+ -image ::ICONS::22::gear${cmd_num}_play
+ }
+
+ # Perform variables substitution in the command string
+ set cmd $custom_command_cmd($cmd_num)
+ regsub -all {%%} $cmd "\a" cmd
+ if {[regexp {%} $cmd]} {
+ # Determinate editor object reference
+ set editor [$actualProject get_current_editor_object]
+
+ if {[regexp {%URLS} $cmd]} {
+ set URLS {}
+ foreach e [$actualProject cget -editors] {
+ set url [$e cget -fullFileName]
+ if {[regexp {\s} $url]} {
+ append URLS "\"" $url "\"" { }
+ } {
+ append URLS $url { }
+ }
+ }
+ regsub -all {%URLS} $cmd [string replace $URLS end end] cmd
+ }
+ if {[regexp {%URL} $cmd]} {
+ regsub -all {%URL} $cmd [$editor cget -fullFileName] cmd
+ }
+ if {[regexp {%directory} $cmd]} {
+ regsub -all {%directory} $cmd [$actualProject cget -projectPath] cmd
+ }
+ if {[regexp {%filename} $cmd]} {
+ regsub -all {%filename} $cmd [$editor cget -filename] cmd
+ }
+ if {[regexp {%basename} $cmd]} {
+ regsub -all {%basename} $cmd [file tail [file rootname [$editor cget -filename]]] cmd
+ }
+ if {[regexp {%mainfile} $cmd]} {
+ regsub -all {%mainfile} $cmd [$actualProject cget -P_option_main_file] cmd
+ }
+ if {!${::Editor::editor_to_use}} {
+ if {[regexp {%line} $cmd]} {
+ regsub -all {%line} $cmd [$editor get_current_line_number] cmd
+ }
+ if {[regexp {%column} $cmd]} {
+ regexp {\d+$} [[$editor cget -editor] index insert] col
+ regsub -all {%column} $cmd $col cmd
+ }
+ if {[regexp {%selection} $cmd]} {
+ regsub -all {%selection} $cmd [$editor getselection] cmd
+ }
+ if {[regexp {%text} $cmd]} {
+ regsub -all {%text} $cmd [$editor getdata] cmd
+ }
+ } {
+ if {[regsub -all {%(line|column|selection|text)} $cmd {} cmd]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Warning - Custom command"] \
+ -message [mc "Some variables in user command could not be resolved."]
+ }
+ }
+ }
+ regsub -all "\a" $cmd {%} cmd
+
+ # Execute specified command in a separate thread
+ set custom_command_NUM($cmd_num) $custom_command_counter
+ set custom_command_PID($cmd_num) [exec -- tclsh \
+ ${::LIB_DIRNAME}/custom_command.tcl [tk appname] \
+ $custom_command_NUM($cmd_num) << $cmd & \
+ ]
+ incr custom_command_counter
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Invoke dialog "Custom command finished"
+ # -- auxiliary procedure for '__exec_custom_cmd'
+ # @parm Int num - Command number
+ # @parm String result - Result string
+ # @return void
+ proc custom_cmd_finish {num result} {
+ variable custom_command_options ;# Array of Lists of custom command options
+
+ # Set toolbar button icon to default and determinate command index
+ set i [custom_cmd_icon_reset $num]
+ if {$i == {}} {return}
+
+ # Check if result dialogs are allowed
+ if {![lindex $custom_command_options($i) 1]} {return}
+ # Invoke results dialog
+ invoke_custom_cmd_dialog $i {#00DD00} [mc "Custom command finished"] $result
+ }
+
+ ## Invoke dialog "Custom command failed"
+ # -- auxiliary procedure for '__exec_custom_cmd'
+ # @parm Int num - Command number
+ # @parm String result - Result string
+ # @return void
+ proc custom_cmd_error {num result} {
+ variable custom_command_options ;# Array of Lists of custom command options
+
+ # Set toolbar button icon to default and determinate command index
+ set i [custom_cmd_icon_reset $num]
+ if {$i == {}} {return}
+
+ # Check if error dialogs are allowed
+ if {[lindex $custom_command_options($i) 2]} {return}
+ # Invoke error dialog
+ invoke_custom_cmd_dialog $i {#DD0000} [mc "Custom command failed"] $result
+ }
+
+ ## Invoke dialog window showing results of some custom command
+ # -- auxiliary procedure for 'custom_cmd_error' and 'custom_cmd_finish'
+ # @parm Int i - Index of the custom command (0..2)
+ # @parm RGB color - Color for dialog header (24-bit RGB color code)
+ # @parm String label - Text of the dialog header
+ # @parm String result - Text of the messages area
+ # @return void
+ proc invoke_custom_cmd_dialog {i color label result} {
+ variable custom_cmd_dialog_index ;# Index of results dialog (to keep win IDs unique)
+
+ incr custom_cmd_dialog_index
+
+ # Create dialog window
+ set win [toplevel .custom_cmd_dialog${custom_cmd_dialog_index} -class {Custom command finished} -bg {#EEEEEE}]
+
+ # Create dialog header
+ pack [label $win.header_label \
+ -compound left \
+ -fg $color \
+ -text $label \
+ -image ::ICONS::22::gear$i \
+ -font [font create \
+ -family {helvetica} \
+ -size -20 \
+ -weight bold \
+ ] \
+ ] -pady 5
+
+ # Create main frame (text widget and scrollbar)
+ set main_frame [frame $win.main_frame]
+ set text [text $main_frame.text \
+ -width 1 -height 1 \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ ]
+ pack $text -side left -fill both -expand 1
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -command "$text yview" \
+ -orient vertical \
+ ] -fill y -side right
+ pack $main_frame -fill both -expand 1 -pady 5
+
+ # Create button "Ok"
+ pack [ttk::button $win.ok_button \
+ -text [mc "Ok"] \
+ -command "destroy $win" \
+ -compound left \
+ -image ::ICONS::16::ok \
+ ] -pady 5
+
+ # Fill in the text widget and disable it
+ $text insert end [string replace [regsub -all {\\\{} [regsub -all {\\\}} $result "\}"] "\{"] 0 0]
+ $text configure -state disabled
+
+ # Events binding (Enter/Escape == Ok)
+ bind $win <KeyRelease-Return> "destroy $win; break"
+ bind $win <KeyRelease-KP_Enter> "destroy $win; break"
+ bind $win <KeyRelease-Escape> "destroy $win; break"
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::gear
+ wm title $win [mc "Custom command %s - MCU 8051 IDE" $i]
+ wm minsize $win 550 300
+ wm protocol $win WM_DELETE_WINDOW "destroy $win"
+ wm transient $win .
+ }
+
+ ## Set toolbar button icon to default and determinate index of cutom command
+ # -- auxiliary procedure for 'custom_cmd_error' and 'custom_cmd_finish'
+ # @parm Int num - Command number
+ # @return Int - index of the specified cutom command (by TID) or {} (means 'not found')
+ proc custom_cmd_icon_reset {num} {
+ variable custom_command_NUM ;# Array of custom command numbers
+ variable custom_command_PID ;# Array of custom command TIDs (Thread IDentifiers)
+
+ # Search for command index
+ set found 0 ;# Bool: Coresponding index found
+ for {set i 0} {$i < 3} {incr i} {
+ if {[string equal $custom_command_NUM($i) $num]} {
+ set found 1
+ break
+ }
+ }
+ # If index not found -> return {}
+ if {!$found} {return {}}
+
+ # Reset toolbar button icon
+ if {[winfo exists .mainIconBar.custom$i]} {
+ .mainIconBar.custom$i configure -image ::ICONS::22::gear${i}
+ }
+ # Reset command PID and return result
+ set custom_command_PID($i) {}
+ return $i
+ }
+
+ ## Invoke welcome dialog
+ # @return void
+ proc __welcome_dialog {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ if {$critical_procedure_in_progress} {return}
+ if {[winfo exists .welcome]} {
+ return
+ }
+
+ # Create dialog window
+ set win [toplevel .welcome -class [mc "Welcome dialog"] -bg {#EEEEEE}]
+
+ # Create header label
+ pack [label $win.header_label \
+ -compound left -fg {#0000DD} \
+ -text [mc "Welcome to MCU 8051 IDE !"] \
+ -font [font create \
+ -family {helvetica} \
+ -size -20 \
+ -weight {bold} \
+ -slant {italic} \
+ ] \
+ ] -pady 10
+
+ # Create text widget showing the dialog message
+ set text [text $win.text \
+ -bg {#EEEEEE} -takefocus 0 \
+ -width 0 -heigh 0 -bd 0 \
+ -cursor left_ptr \
+ -wrap word \
+ -font [font create \
+ -family {helvetica} \
+ -size -12 \
+ ] \
+ ]
+ pack $text -fill both -expand 1 -padx 15
+
+ # Create button "Ok"
+ pack [ttk::button $win.ok_button \
+ -text [mc "Ok"] \
+ -command "grab release $win; destroy $win" \
+ ] -pady 5
+
+ # Create label for opening demostration project
+ set open_demo_label [label $text.open_demo_label \
+ -text [mc "Click here to open demonstration project."] \
+ -justify left -fg {#00DD00} -cursor hand1 \
+ ]
+ bind $open_demo_label <Enter> {%W configure -fg {#0000DD}}
+ bind $open_demo_label <Leave> {%W configure -fg {#00DD00}}
+ bind $open_demo_label <Button-1> "
+ grab release $win
+ destroy $win
+ ::X::open_demo_project
+ break
+ "
+
+ # Load images
+ set image_new [image create photo -format png \
+ -file "${::LIB_DIRNAME}/../icons/16x16/filenew.png"]
+ set image_start [image create photo -format png \
+ -file "${::LIB_DIRNAME}/../icons/16x16/launch.png"]
+ set image_step [image create photo -format png \
+ -file "${::LIB_DIRNAME}/../icons/16x16/goto.png"]
+
+ # Create text tags
+ $text tag configure bold -font [font create \
+ -family {times} \
+ -size -12 \
+ -weight bold \
+ ]
+ $text tag configure header -font [font create \
+ -family {times} \
+ -size -12 \
+ -weight bold \
+ -underline 1 \
+ ] -foreground {#0000FF}
+
+ # Fill in the text widget
+ $text insert end [mc "MCU 8051 IDE is fully featured Integrated Development Enviroment"]
+ $text insert end [mc " for MCS-51 based microcontollers. It's written for POSIX Operating Systems (GNU/Linux, etc.) "]
+ if {$::MICROSOFT_WINDOWS} {
+ $text insert end [mc "and since version 1.3.5 it is also available for Microsoft® Windows® operating system."]
+ }
+ $text insert end "\n\n"
+ $text insert end [mc "Main features:"]
+ $text tag add header {insert linestart} insert
+ $text insert end [mc "\n\t- Editor with syntax highlight, validation and popup-based completion"]
+ $text insert end [mc "\n\t- MCS-51 Assembler and Disassembler"]
+ $text insert end [mc "\n\t- MCS-51 Simulator (not all MCUs are fully supported !)"]
+ $text insert end [mc "\n\t- Support for C language (using C compiler SDCC)"]
+ $text insert end [mc "\n\t- Partial support for some HW tools"]
+ $text insert end [mc "\n\t- Project management"]
+ $text insert end [mc "\n\t- Custom editable commands (using shell scripts)"]
+ $text insert end [mc "\n\t- Dynamic help for instruction at the current line"]
+ $text insert end [mc "\n\t- Hexadecimal editor for eXternal RAM, Expanded RAM, Code memory, etc."]
+ $text insert end [mc "\n\t- Scientific calculator"]
+ $text insert end [mc "\n\t- Simple hardware simulation (LED's, etc.)"]
+ $text insert end [mc "\n\t- Graph showing voltage levels on ports\n\n"]
+
+ $text insert end [mc "Where to start:"]
+ $text tag add header {insert linestart} insert
+ $text insert end [mc "\n\t1. Create a new project"]
+ $text image create end -image $image_new -padx 5
+ $text insert end [mc "\n\t\t- Enter project name\n"]
+ $text insert end [mc "\t\t- Choose project directory\n"]
+ $text insert end [mc "\t\t- Choose microcontroller (e.g. AT89S52)\n"]
+ $text insert end [mc "\t2. Write your code in the opened editor and click on "]
+ $text image create end -image $image_start -padx 5
+ $text insert end [mc " to start simulator\n"]
+ $text insert end [mc "\t3. Step your program by clicking on "]
+ $text image create end -image $image_step -padx 5
+ $text insert end "\n\t----\n\t"
+ $text window create end -window $open_demo_label
+ $text insert end ""
+
+ $text insert end "\n\n"
+ $text insert end [mc "Web site:"]
+ $text tag add bold {insert linestart} insert
+ $text insert end "\thttp://mcu8051ide.sourceforge.net\n"
+ $text insert end [mc "Author:"]
+ $text tag add bold {insert linestart} insert
+ $text insert end "\tMartin Ošmera <martin.osmera@gmail.com>\n\n"
+
+ $text insert end [mc "Thank you for using/trying MCU 8051 IDE."]
+ $text tag add bold {insert linestart} insert
+
+ $text configure -state disabled
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::info
+ wm title $win [mc "Welcome to MCU 8051 IDE"]
+ wm minsize $win 580 600
+ wm protocol $win WM_DELETE_WINDOW "grab release $win; destroy $win"
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ }
+
+ ## Open demostration project -- auxiliary procedure for '__welcome_dialog'
+ # @return void
+ proc open_demo_project {} {
+ Project::open_project_file "${::LIB_DIRNAME}/../demo/Demo project.mcu8051ide"
+ }
+
+ ## Invoke dialog "Change letter case"
+ # @return void
+ proc __change_letter_case {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ if {$critical_procedure_in_progress} {return}
+
+ # Create dialog window
+ set win [toplevel .change_letter_case -class [mc "Options dialog"] -bg {#EEEEEE}]
+
+ # Create dialog header
+ pack [label $win.header \
+ -compound left \
+ -image ::ICONS::22::change_case \
+ -text [mc "Change letter case"] \
+ -font [font create \
+ -size -20 \
+ -family {times}]
+ ] -side top -pady 5
+
+ # Create main frame (contains labels and radio buttons)
+ set main_frame [frame $win.main_frame]
+
+ # Create header
+ foreach column {1 2 3 5 6 7 } \
+ image {up0 down0 button_cancel up0 down0 button_cancel } \
+ helptext {
+ {Uppercase} {Lowercase} {Keep case}
+ {Uppercase} {Lowercase} {Keep case}
+ } \
+ {
+ grid [Label $main_frame.header_label$column \
+ -pady 0 -bd 0 -helptext [mc $helptext] \
+ -image ::ICONS::16::$image \
+ ] -row 0 -column $column -sticky w
+ }
+
+ # Create matrix of radiobuttons and labels
+ set i 0
+ set row 1
+ set col 0
+ foreach text {
+ {Hexadecimal number} {Octal number}
+ {Decimal number} {Binary number}
+ {Constant} {Generic number}
+ {Comment} {Control sequentce}
+ {Symbol} {Directive}
+ {Label} {Instruction}
+ {SFR register} {Indirect adress}
+ {Immediate hex} {Immediate oct}
+ {Immediate dec} {Immediate bin}
+ {Immediate const} {Immediate generic}
+ {Macro instruction}
+ } {
+ # Create label
+ grid [label $main_frame.label$i \
+ -text [mc $text] -justify left \
+ -highlightthickness 0 \
+ -pady 0 -bd 0 \
+ ] -row $row -column [expr {$col * 4}] -sticky w
+
+ # Radiobutton "Uppercase"
+ grid [radiobutton $main_frame.upper$i \
+ -value [mc "U"] -highlightthickness 0 -pady 0 \
+ -variable ::X::change_letter_case_options($i) \
+ ] -row $row -column [expr {$col * 4 + 1}] -sticky w
+ # Radiobutton "Lowercase"
+ grid [radiobutton $main_frame.lower$i \
+ -value [mc "L"] -highlightthickness 0 -pady 0 \
+ -variable ::X::change_letter_case_options($i) \
+ ] -row $row -column [expr {$col * 4 + 2}] -sticky w
+ # Radiobutton "Keep"
+ grid [radiobutton $main_frame.keep$i \
+ -value [mc "-"] -highlightthickness 0 -pady 0 \
+ -variable ::X::change_letter_case_options($i) \
+ ] -row $row -column [expr {$col * 4 + 3}] -sticky w
+
+ incr col
+ incr i
+ if {$col > 1} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Set column sizes
+ grid columnconfigure $main_frame 0 -minsize 140
+ grid columnconfigure $main_frame 3 -minsize 50
+ grid columnconfigure $main_frame 4 -minsize 140
+
+ # Create button frame
+ set button_frame [frame $win.button_frame]
+ # Create buttons "All up", "All down" and "All keep"
+ foreach image {up0 down0 button_cancel} \
+ state {U L -} \
+ {
+ pack [ttk::button $button_frame.${image}_but \
+ -compound right \
+ -text [mc "All "] \
+ -image ::ICONS::16::$image \
+ -command "::X::change_letter_case_all_to $state" \
+ ] -side left
+ }
+ # Create and pack buttons "OK" and "CANCEL"
+ pack [ttk::button $button_frame.ok_button \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::change_letter_case_OK} \
+ ] -side right
+ pack [ttk::button $button_frame.cancel_button \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::change_letter_case_CANCEL} \
+ ] -side right
+
+ # Events binding (Enter == Ok; Escape == Cancel)
+ bind $win <KeyRelease-Return> {::X::change_letter_case_OK; break}
+ bind $win <KeyRelease-KP_Enter> {::X::change_letter_case_OK; break}
+ bind $win <KeyRelease-Escape> {::X::change_letter_case_CANCEL; break}
+
+ # Pack frames
+ pack $main_frame -fill both -expand 1 -padx 10 -pady 10
+ pack $button_frame -side bottom -fill x
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::change_case
+ wm title $win [mc "Change letter case - MCU 8051 IDE"]
+ wm minsize $win 450 70
+ wm protocol $win WM_DELETE_WINDOW {
+ ::X::change_letter_case_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Perform letter case change -- auxiliary procedure for '__change_letter_case'
+ # @return void
+ proc change_letter_case_OK {} {
+ change_letter_case_CANCEL ;# Close dialog window
+ change_letter_case_start ;# Perform change
+ }
+
+ ## Close "Change letter case" dialog window
+ # -- auxiliary procedure for '__change_letter_case'
+ # @return void
+ proc change_letter_case_CANCEL {} {
+ grab release .change_letter_case
+ destroy .change_letter_case
+ }
+
+ ## Set all options to the specified state
+ # -- auxiliary procedure for '__change_letter_case'
+ # @parm Char state - new state
+ # 'U' == Uppercase
+ # 'L' == Lowercase
+ # '-' == Keep
+ # @return void
+ proc change_letter_case_all_to {state} {
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ for {set i 0} {$i < 21} {incr i} {
+ set change_letter_case_options($i) $state
+ }
+ }
+
+ ## Perform letter case change -- auxiliary procedure for 'change_letter_case_OK'
+ # @return void
+ proc change_letter_case_start {} {
+ variable actualProject ;# Object: Current project
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ # Check if the current editor is not empty
+ if {
+ [$actualProject editor_procedure {} getLinesCount {}] == 1
+ &&
+ [$actualProject editor_procedure {} getLineContent 1] == {}
+ } {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Unable to compile"] \
+ -message [mc "This editor seems to be empty"]
+ return
+ }
+
+ set compilation_progress 1 ;# Reset compilation progress variable
+
+ # Set maximum for 1st progress bar ("Finishing highlight")
+ set max [$actualProject editor_procedure {} highlight_all_count_of_iterations {}]
+ incr max
+
+ # Create progress dialog window
+ set win [toplevel .change_letter_case_dialog -class {Progress dialog} -bg {#EEEEEE}]
+
+ # Create label and progress bar
+ set main_frame [frame $win.main_frame]
+ pack [label $main_frame.header -text [mc "Finishing highlight ..."]] \
+ -pady 10 -padx 20 -anchor w
+ pack [ttk::progressbar $main_frame.progress_bar \
+ -maximum $max \
+ -mode determinate \
+ -variable {X::compilation_progress} \
+ -length 430 \
+ ] -fill y
+ pack $main_frame -fill x -expand 1
+ pack [ttk::button $win.abort_button \
+ -text [mc "Abort"] \
+ -image ::ICONS::16::cancel \
+ -compound left \
+ -command {X::change_letter_case_abort} \
+ ]
+
+ # Create options list
+ for {set i 0} {$i < 21} {incr i} {
+ lappend options $change_letter_case_options($i)
+ }
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::change_case
+ wm title $win [mc "Change letter case - MCU 8051 IDE"]
+ wm minsize $win 450 70
+ wm protocol $win WM_DELETE_WINDOW {
+ exportToX_abort
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ update
+
+ # Finish highlight
+ $actualProject editor_procedure {} highlight_all {}
+ if {![winfo exists $win]} {return}
+
+ # Determinate maximum value for the 2nd progress bar ("Formating")
+ set max [$actualProject editor_procedure {} change_letter_case_get_count_of_iterations "{$options}"]
+ incr max
+ # Change progress bar header label
+ $main_frame.header configure -text [mc "Formating ..."]
+ $main_frame.progress_bar configure -maximum $max
+
+ set compilation_progress 1 ;# Reset compilation progress variable
+ update
+
+ # Finaly perform letter case change
+ $actualProject editor_procedure {} change_letter_case [list $options]
+
+ # Close the window
+ catch {
+ grab release .change_letter_case_dialog
+ destroy .change_letter_case_dialog
+ }
+ }
+
+ ## Abort letter case change-- auxiliary procedure for 'change_letter_case_start'
+ # @return void
+ proc change_letter_case_abort {} {
+ variable actualProject ;# Object: Current project
+
+ # Abort the procedure in editor
+ $actualProject editor_procedure {} change_letter_case_abort_now {}
+
+ # Close progress dialog
+ grab release .change_letter_case_dialog
+ destroy .change_letter_case_dialog
+ }
+
+ ## Switch to the previous editor in the current project
+ # @return void
+ proc __prev_editor {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Switch editor
+ $actualProject prev_editor
+
+ # Finalize
+ set critical_procedure_in_progress 0
+
+ }
+
+ ## Switch to the next editor in the current project
+ # @return void
+ proc __next_editor {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Switch editor
+ $actualProject next_editor
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Change EOL character in the current editor
+ # @return void
+ proc change_EOL {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Change EOL
+ $actualProject change_EOL
+ }
+
+ ## Change character encoding in the current editor
+ # @return void
+ proc change_encoding {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Change encoding
+ $actualProject change_encoding
+ }
+
+ ## Switch between RO and RW modes in the current editor
+ # @return void
+ proc switch_editor_RO_MODE {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject switch_editor_RO_MODE
+ }
+
+ ## Prepare window "Project details"
+ # @parm Object project - project object descriptor
+ # @return void
+ proc create_project_details {project} {
+ variable openedProjects ;# List of opened projects (Object references)
+ variable PROJECTDETAILSWIN ;# ID of project details window
+ variable projectdetails_last_project ;# Project object of the last project details window
+
+ # Check if the given project is a valid object reference
+ if {[lsearch -ascii -exact $openedProjects $project] == -1} {
+ return
+ }
+
+ if {$projectdetails_last_project == $project} {
+ project_details_move
+ return
+ } {
+ set projectdetails_last_project $project
+ }
+
+ # Destroy previous window
+ catch {destroy $PROJECTDETAILSWIN}
+
+ set authors [$project cget -G_information_authors]
+ set authors [join [split $authors "\n"] {, }]
+ if {[string length $authors] > 40} {
+ set authors [string range $authors 0 36]
+ append authors {...}
+ }
+
+ # Create window
+ set PROJECTDETAILSWIN [frame .project_details_win -bg {#BBBBFF}]
+ set project_details_win [frame $PROJECTDETAILSWIN.frm -bg {#FFFFFF}]
+ bind $PROJECTDETAILSWIN <Button-1> "catch {destroy $PROJECTDETAILSWIN}"
+
+ # Create header
+ pack [label $project_details_win.header \
+ -text [$project cget -projectName] \
+ -justify left -pady 0 -padx 15 \
+ -compound left -anchor w -bg {#BBBBFF} \
+ -image ::ICONS::16::kcmdevices \
+ ] -fill x
+
+ # Create main frame (containing everything except the header)
+ set main_frame [frame $project_details_win.main_frame -bg {#FFFFFF}]
+
+ # File name
+ grid [label $main_frame.filename_label \
+ -text [mc "File name:"] \
+ -fg {#880033} -bg {#FFFFFF} \
+ -anchor w -pady 0 \
+ ] -row 0 -column 0 -sticky w -pady 0
+ grid [label $main_frame.filename_value \
+ -text [$project cget -projectFile] \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 0 -column 1 -sticky w -pady 0
+ # Path
+ grid [label $main_frame.path_label \
+ -text [mc "Path:"] -fg {#880033} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 1 -column 0 -sticky w -pady 0
+ grid [label $main_frame.path_value \
+ -text [$project cget -projectPath] \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 1 -column 1 -sticky w -pady 0
+
+ # Separator
+ grid [ttk::separator $main_frame.sep0 -orient horizontal \
+ ] -row 2 -column 0 -columnspan 2 -sticky we -pady 5
+
+ # MCU:
+ grid [label $main_frame.family_label \
+ -text [mc "MCU:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 3 -column 0 -sticky w -pady 0
+ grid [label $main_frame.family_value \
+ -text [$project cget -P_option_mcu_type]\
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 3 -column 1 -sticky w -pady 0
+ # XDATA:
+ grid [label $main_frame.xdata_label \
+ -text [mc "XDATA:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 4 -column 0 -sticky w -pady 0
+ grid [label $main_frame.xdata_value \
+ -text "[$project cget -P_option_mcu_xdata] B" \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 4 -column 1 -sticky w -pady 0
+ # XCODE:
+ grid [label $main_frame.xcode_label \
+ -text [mc "XCODE:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 5 -column 0 -sticky w -pady 0
+ grid [label $main_frame.xcode_value \
+ -text "[$project cget -P_option_mcu_xcode] B" \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 5 -column 1 -sticky w -pady 0
+ # Clock:
+ grid [label $main_frame.clock_label \
+ -text [mc "Clock:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 6 -column 0 -sticky w -pady 0
+ grid [label $main_frame.clock_value \
+ -text "[$project cget -P_option_clock] kHz" \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 6 -column 1 -sticky w -pady 0
+
+ set more_details_avaliable 0
+ # Version
+ if {[string length [$project cget -P_information_version]]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.ver_label \
+ -text [mc "Version:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 8 -column 0 -sticky w -pady 0
+ grid [label $main_frame.ver_value \
+ -text [$project cget -P_information_version] \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 8 -column 1 -sticky w -pady 0
+ }
+ # Date
+ if {[string length [$project cget -P_information_date]]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.date_label \
+ -text [mc "Date:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 9 -column 0 -sticky w -pady 0
+ grid [label $main_frame.date_value \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ -text [$project cget -P_information_date] \
+ ] -row 9 -column 1 -sticky w -pady 0
+ }
+ # Licence
+ if {[string length [$project cget -G_information_licence]]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.licence_label \
+ -text [mc "Licence:"] \
+ -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 10 -column 0 -sticky w -pady 0
+ grid [label $main_frame.licence_value \
+ -text [$project cget -G_information_licence] \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 10 -column 1 -sticky w -pady 0
+ }
+ # Copyright
+ if {[string length [$project cget -G_information_copyright]]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.copyright_label \
+ -text [mc "Copyright:"] \
+ -fg {#0000AA} -bg {#FFFFFF} \
+ -anchor w -pady 0 \
+ ] -row 11 -column 0 -sticky w -pady 0
+ grid [label $main_frame.copyright_value \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ -text [$project cget -G_information_copyright] \
+ ] -row 11 -column 1 -sticky w -pady 0
+ }
+ # Authors
+ if {[string length $authors]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.authors_label \
+ -text [mc "Authors:"] \
+ -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 12 -column 0 -sticky w -pady 0
+ grid [label $main_frame.authors_value \
+ -text $authors -anchor w \
+ -pady 0 -bg {#FFFFFF} \
+ ] -row 12 -column 1 -sticky w -pady 0
+ }
+ # Separator
+ if {$more_details_avaliable} {
+ grid [ttk::separator $main_frame.sep1 -orient horizontal \
+ ] -row 7 -column 0 -columnspan 2 -sticky we -pady 5
+ }
+
+ # Pack main frame
+ grid columnconfigure $main_frame 0 -minsize 80
+ pack $main_frame -fill both -expand 1 -padx 8 -pady 3
+ pack $project_details_win -fill both -expand 1 -padx 2 -pady 2
+
+ # Show window "Project details"
+ project_details_move
+ }
+
+ ## Move window "Project details"
+ # @return void
+ proc project_details_move args {
+ variable PROJECTDETAILSWIN ;# ID of project details window
+
+ # Show the window
+ catch {
+ place $PROJECTDETAILSWIN -anchor nw \
+ -x [expr {[winfo pointerx .] - [winfo rootx .] + 20}] \
+ -y [expr {[winfo pointery .] - [winfo rooty .] + 20}]
+ update
+ raise $PROJECTDETAILSWIN
+ }
+ }
+
+ ## Hide window "Project details"
+ # @return void
+ proc close_project_details args {
+ variable PROJECTDETAILSWIN ;# ID of project details window
+ variable projectdetails_last_project ;# Project object of the last project details window
+
+ # Hide the window
+ catch {place forget $PROJECTDETAILSWIN}
+ }
+
+ ## Invokes menu for manipulating project tab
+ # @parm Int x - Absolute X coordinate of mouse pointer
+ # @parm Int y - Absolute Y coordinate of mouse pointer
+ # Object project - project object descriptor
+ proc invoke_project_menu {x y project} {
+ variable projectmenu ;# ID of Popup menu for project tabs
+ variable projectmenu_project ;# Object: project selected by project popup menu
+ variable openedProjects ;# List of opened projects (Object references)
+
+ # Check if the given project exists (due to a bug in BWidget-1.7)
+ if {[lsearch -ascii -exact $openedProjects $project] == -1} {
+ puts stderr "Internal error detected: Please install BWidget-1.8 or higher"
+ return
+ }
+
+ # Enable/Disable menu entries
+ set tabindex [.mainFrame.mainNB index $project]
+ if {!$tabindex} {
+ $projectmenu entryconfigure [::mc "Move to beginning"] -state disabled
+ $projectmenu entryconfigure [::mc "Move left"] -state disabled
+ } {
+ $projectmenu entryconfigure [::mc "Move to beginning"] -state normal
+ $projectmenu entryconfigure [::mc "Move left"] -state normal
+ }
+ if {$tabindex == ([llength [.mainFrame.mainNB pages]] - 1)} {
+ $projectmenu entryconfigure [::mc "Move right"] -state disabled
+ $projectmenu entryconfigure [::mc "Move to end"] -state disabled
+ } {
+ $projectmenu entryconfigure [::mc "Move right"] -state normal
+ $projectmenu entryconfigure [::mc "Move to end"] -state normal
+ }
+
+ # Invoke the menu and set project identifier
+ set projectmenu_project $project
+ tk_popup $projectmenu $x $y
+ }
+
+ ## Function for project popup menu
+ # -- Save this project
+ # @return void
+ proc __project_pmenu_save {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set tmp $actualProject
+ set actualProject $projectmenu_project
+ set tmp_idx $actualProjectIdx
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+
+ __proj_save
+
+ set actualProject $tmp
+ set actualProjectIdx $tmp_idx
+ }
+
+ ## Function for project popup menu
+ # -- Edit this project
+ # @return void
+ proc __project_pmenu_edit {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set tmp $actualProject
+ set actualProject $projectmenu_project
+ set tmp_idx $actualProjectIdx
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+
+ __proj_edit
+
+ set actualProject $tmp
+ set ctualProjectIdx $tmp_idx
+ }
+
+ ## Function for project popup menu
+ # -- Close this project
+ # @return void
+ proc __project_pmenu_close {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ # Adjust variables identifing current project
+ set tmp $actualProject
+ set tmp_idx $actualProjectIdx
+ set actualProject $projectmenu_project
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+ if {$actualProjectIdx == $tmp_idx} {
+ set this_closed 1
+ } {
+ set this_closed 0
+ }
+
+ # Close project
+ __proj_close
+ }
+
+ ## Function for project popup menu
+ # -- Close this project without saving
+ # @return void
+ proc __project_pmenu_close_imm {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ # Adjust variables identifing current project
+ set tmp $actualProject
+ set tmp_idx $actualProjectIdx
+ set actualProject $projectmenu_project
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+ if {$actualProjectIdx == $tmp_idx} {
+ set this_closed 1
+ } {
+ set this_closed 0
+ }
+
+ # Close project and restore variables identifing current project
+ if {[__proj_close_imm] && !$this_closed} {
+ if {$tmp_idx > $actualProjectIdx} {
+ incr tmp_idx -1
+ }
+ set actualProjectIdx $tmp_idx
+ set actualProject $tmp
+ }
+ }
+
+ ## Function for project popup menu
+ # -- Move this tab left
+ # @return void
+ proc __project_move_to_left {} {
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set index [.mainFrame.mainNB index $projectmenu_project]
+ if {!$index} {
+ return
+ }
+
+ incr index -1
+ .mainFrame.mainNB move $projectmenu_project $index
+ }
+
+ ## Function for project popup menu
+ # -- Move this tab right
+ # @return void
+ proc __project_move_to_right {} {
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set index [.mainFrame.mainNB index $projectmenu_project]
+ if {$index == ([llength [.mainFrame.mainNB index pages]] - 1)} {
+ return
+ }
+
+ incr index
+ .mainFrame.mainNB move $projectmenu_project $index
+ }
+
+ ## Function for project popup menu
+ # -- Move this tab to the beginning
+ # @return void
+ proc __project_move_to_beginning {} {
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ if {![.mainFrame.mainNB index $projectmenu_project]} {
+ return
+ }
+ .mainFrame.mainNB move $projectmenu_project 0
+ }
+
+ ## Function for project popup menu
+ # -- Move this tab to the end
+ # @return void
+ proc __project_move_to_end {} {
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set end [expr {[llength [.mainFrame.mainNB pages]] - 1}]
+ if {[.mainFrame.mainNB index $projectmenu_project] == $end} {
+ return
+ }
+
+ .mainFrame.mainNB move $projectmenu_project $end
+ }
+
+ ## Invert flag "allow breakpoints"
+ # @return void
+ proc __invert_allow_breakpoints {} {
+ set ::CONFIG(BREAKPOINTS_ALLOWED) [expr {!$::CONFIG(BREAKPOINTS_ALLOWED)}]
+ }
+
+ ## Refresh bookmarks in filesystem browser in all projects
+ # @return void
+ proc refresh_bookmarks_in_fs_browsers {} {
+ variable openedProjects ;# List of opened projects (Object references)
+
+ foreach project $openedProjects {
+ $project filelist_fsb_refresh_bookmarks
+ }
+ }
+
+ ## Invoke dialog "Tip of the day"
+ # @return void
+ proc __tip_of_the_day {} {
+ ::Tips::show_tip_of_the_day_win
+ }
+
+ ## Refresh program pointer in CODE memory hexadecimal editor
+ # @parm Object project - Project object
+ # @parm Int new_PC - New value of PC (-1 after reset)
+ # @return void
+ proc program_counter_changed {project new_PC} {
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ set opcode [$project getCode $new_PC]
+ if {[lsearch ${CompilerConsts::defined_OPCODE} $opcode] == -1} {
+ set ins_length 1
+ } {
+ set ins_length [lindex $CompilerConsts::Opcode($opcode) 2]
+ }
+ [lindex $code_mem_window_objects $idx] move_program_pointer $new_PC $ins_length
+ }
+ }
+
+ ## Refresh program pointer in CODE memory hexadecimal editor
+ # @parm Object project - Project object
+ # @parm Int new_PC - New value of PC (-1 after reset)
+ # @return void
+ proc code_hex_editor_directly_move_program_pointer {project new_PC} {
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ if {$new_PC != -1} {
+ set opcode [$project getCode $new_PC]
+ if {[lsearch ${CompilerConsts::defined_OPCODE} $opcode] == -1} {
+ set ins_length 1
+ } {
+ set ins_length [lindex $CompilerConsts::Opcode($opcode) 2]
+ }
+ } {
+ set ins_length 0
+ }
+ [lindex $code_mem_window_objects $idx] move_program_pointer_directly $new_PC $ins_length
+ }
+ }
+
+ ## Refresh the current page in CODE memory hexadecimal editor
+ # @parm Object project - Project object
+ # @return void
+ proc refresh_code_mem_window {project} {
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $code_mem_window_objects $idx] refresh
+ }
+ }
+
+ ## Refresh the current page in XDATA memory hexadecimal editor
+ # @parm Object project - Project object
+ # @return void
+ proc refresh_xram_mem_window {project} {
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_xdata_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $xdata_mem_window_objects $idx] refresh
+ }
+ }
+
+ ## Refresh the current page in EDATA memory hexadecimal editor
+ # @parm Object project - Project object
+ # @return void
+ proc refresh_eram_mem_window {project} {
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_eram_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $eram_window_objects $idx] refresh
+ }
+ }
+
+ ## Refresh the current page in data EEPROM hexadecimal editor
+ # @parm Object project - Project object
+ # @return void
+ proc refresh_eeprom_mem_window {project} {
+ variable opended_eeprom_mem_windows ;# List of project object with opened ERAM hex editor
+ variable eeprom_mem_window_objects ;# List of ERAM hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $eeprom_mem_window_objects $idx] refresh
+ }
+ }
+
+ ## Clear background highlight for certain cell in hexeditor of data EEPROM
+ # @parm Int addr - Register address (absolute)
+ # @parm Object project - Project object
+ # @return void
+ proc sync_eeprom_clear_bg_hg {addr project} {
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $eeprom_mem_window_objects $idx] set_bg_hg_clr $addr 0
+ }
+ }
+
+ ## Synchronize the specified cell in data EEPROM hexadecimal editor
+ # @parm String addr - Hexadecimal address (0 - FFFF)
+ # @parm Int hg -
+ # 1 == highlight background
+ # 0 == do not affect bg. highlight
+ # @parm Object project - Project object
+ # @return void
+ proc sync_eeprom_mem_window {addr hg project} {
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ set obj [lindex $eeprom_mem_window_objects $idx]
+ $obj reg_sync $addr
+ if {$hg} {
+ $obj set_bg_hg_clr [expr "0x$addr"] 1
+ }
+ }
+ }
+
+ ## Synchronize the specified cell in XDATA/ERAM hexadecimal editor
+ # @parm String addr - Hexadecimal address (0 - FFFF)
+ # @parm Object project - Project object
+ # @return void
+ proc sync_xram_mem_window {addr project} {
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+
+ set project [string trimleft $project {:}]
+
+ # Syncronize XDATA
+ set idx [lsearch -exact -ascii $opended_xdata_mem_windows $project]
+ if {$idx != -1} {
+ [lindex $xdata_mem_window_objects $idx] reg_sync $addr
+ }
+ # Syncronize ERAM
+ set idx [lsearch -exact -ascii $opended_eram_windows $project]
+ if {$idx != -1} {
+ [lindex $eram_window_objects $idx] reg_sync $addr
+ }
+ }
+
+ ## Show/Close CODE memory hexadecimal editor
+ # @return void
+ proc __show_code_mem {} {
+ show_X_memory code
+ }
+
+ ## Show/Close XDATA memory hexadecimal editor
+ # @return void
+ proc __show_ext_mem {} {
+ show_X_memory xdata
+ }
+
+ ## Show/Close ERAM hexadecimal editor
+ # @return void
+ proc __show_exp_mem {} {
+ show_X_memory eram
+ }
+
+ ## Show/Close ERAM hexadecimal editor
+ # @return void
+ proc __show_eeprom {} {
+ show_X_memory eeprom
+ }
+
+ ## Invoke hexeditor dialog
+ # @see __show_exp_mem, __show_ext_mem, __show_code_mem, __show_eeprom
+ # @parm String type - memory type (one of {eeprom xdata code eram})
+ # @return void
+ proc show_X_memory {type} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+
+ if {$project_menu_locked} {return}
+
+ # Determinate index of the currently opened hex editor for the current project
+ switch -- $type {
+ {xdata} {
+ if {![$actualProject cget -P_option_mcu_xdata]} {
+ return
+ }
+ set idx [lsearch -exact -ascii $opended_xdata_mem_windows $actualProject]
+ set list_of_opened {opended_xdata_mem_windows}
+ set window_objects {xdata_mem_window_objects}
+ }
+ {eram} {
+ if {![lindex [$actualProject cget -procData] 8]} {
+ return
+ }
+ set idx [lsearch -exact -ascii $opended_eram_windows $actualProject]
+ set list_of_opened {opended_eram_windows}
+ set window_objects {eram_window_objects}
+ }
+ {code} {
+ set idx [lsearch -exact -ascii $opended_code_mem_windows $actualProject]
+ set list_of_opened {opended_code_mem_windows}
+ set window_objects {code_mem_window_objects}
+ }
+ {eeprom} {
+ if {![lindex [$actualProject cget -procData] 32]} {
+ return
+ }
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows $actualProject]
+ set list_of_opened {opended_eeprom_mem_windows}
+ set window_objects {eeprom_mem_window_objects}
+ }
+ }
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Close
+ if {$idx != -1} {
+ close_hexedit $type $actualProject
+ set critical_procedure_in_progress 0
+ return
+ # Show
+ } {
+ set object "hexedit_${type}_${actualProject}"
+ HexEditDlg ::$object $actualProject $type
+ lappend $list_of_opened $actualProject
+ lappend $window_objects $object
+ }
+
+ # Set filename for code memory and program pointer
+ if {$type == {code}} {
+ set filename [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ if {[lindex $filename 1] == {}} {
+ set filename [$actualProject editor_procedure {} getFileName {}]
+ }
+ set filename [file join [lindex $filename 0] [lindex $filename 1]]
+
+ set ext [file extension $filename]
+ set filename [file rootname $filename]
+ if {$ext == {.c} || $ext == {.h} || $ext == {.cxx} || $ext == {.cpp} || $ext == {.cc}} {
+ append filename {.ihx}
+ } {
+ append filename {.hex}
+ }
+
+ ::$object set_filename $filename
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ program_counter_changed $actualProject [$actualProject getPC]
+ }
+
+ # Highlight cells which are beeing written (EEPROM only)
+ } elseif {$type == {eeprom}} {
+ foreach addr [$actualProject simulator_get_eeprom_beeing_written] {
+ ::$object set_bg_hg_clr $addr 1
+ }
+ }
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Synchronize cell in data EEPROM write buffer with simulator engine
+ # @parm Int addr - Cell address (0..31)
+ # @parm Object project - Project object
+ # @return void
+ proc sync_eeprom_write_buffer {addr project} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+
+ if {$project_menu_locked} {return}
+ set idx [lsearch -exact -ascii $opended_eeprom_wr_bf_windows [string trimleft $project {:}]]
+ if {$idx == -1} {return}
+ [string replace [lindex $eeprom_wr_bf_window_objects $idx] 0 0] \
+ setValue $addr [$project getEepromWrBufDEC $addr]
+ }
+
+ ## Clear data EEPROM write buffer
+ # @parm Object project - Project object
+ # @return void
+ proc clear_eeprom_write_buffer {project} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+
+ if {$project_menu_locked} {return}
+ set idx [lsearch -exact -ascii $opended_eeprom_wr_bf_windows [string trimleft $project {:}]]
+ if {$idx == -1} {return}
+ set hexeditor [string replace [lindex $eeprom_wr_bf_window_objects $idx] 0 0]
+ for {set addr 0} {$addr < 32} {incr addr} {
+ $hexeditor setValue $addr {}
+ }
+ }
+
+ ## Set offset for data EEPROM write buffer window
+ # @parm String offset - New offset (format: 0xXXXX or {})
+ # @parm Object project - Project object
+ # @return void
+ proc eeprom_write_buffer_set_offset {offset project} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+
+ if {$project_menu_locked} {return}
+ set idx [lsearch -exact -ascii $opended_eeprom_wr_bf_windows [string trimleft $project {:}]]
+ if {$idx == -1} {return}
+ if {$offset == {}} {
+ set offset [mc "< Undefined >"]
+ }
+ [lindex $eeprom_wr_bf_window_objects $idx].offset_frame.val configure -text $offset
+ }
+
+ ## Binding for pseudo-events <cell_enter> and <cell_leave> in data EEPROM write buffer hexeditor
+ # Set value of curosor label at the bottom of the window
+ # This function takes list of attributes with any length gerater
+ #+ than one but only first two are significant
+ # @parm Widget - Data EEPROM write buffer window
+ # @parm Int - Cell address
+ # @return void
+ proc eeprom_write_buffer_change_cursor_addr args {
+ variable foo_procedure_in_progress ;# Bool: Disables some non-critical procedures
+
+ if {$foo_procedure_in_progress} {return}
+ set foo_procedure_in_progress 1
+
+ # Parse input arguments
+ set win [lindex $args 0]
+ set addr [lindex $args 1]
+
+ # Increment the given address by offset
+ set offset [$win.offset_frame.val cget -text]
+ if {$addr != {} && [regexp {^0x[0-9a-fA-F]{4}$} $offset]} {
+ incr addr [expr "$offset"]
+ }
+
+ # Modify content of cursor label
+ if {$addr == {}} {
+ $win.bottom_frame.cur_val configure -text { }
+ } {
+ set addr [format %X $addr]
+ set len [string length $addr]
+ if {$len < 4} {
+ set addr "[string repeat {0} [expr {4 - $len}]]$addr"
+ }
+ $win.bottom_frame.cur_val configure -text "0x$addr"
+ }
+
+ set foo_procedure_in_progress 0
+ }
+
+ ## Invoke hexeditor with data EEPROM write buffer
+ # @return void
+ proc __show_eeprom_write_buffer {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+ variable eeprom_wr_buf_counter ;# Counter of EEPROM write buffer hex editor objects
+
+ # Check if this function call is valid
+ if {$project_menu_locked} {return}
+ if {![lindex [$actualProject cget -procData] 32]} {
+ return
+ }
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if the dialog is not already opened
+ if {[lsearch -exact -ascii $opended_eeprom_wr_bf_windows $actualProject] != -1} {
+ close_hexedit eeprom_wr_bf $actualProject
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Create dialog window
+ incr eeprom_wr_buf_counter
+ set win [toplevel .eeprom_write_buffer_${eeprom_wr_buf_counter} -class {EEPROM} -bg {#EEEEEE}]
+
+ # Adjust NS variables
+ lappend eeprom_wr_bf_window_objects $win
+ lappend opended_eeprom_wr_bf_windows $actualProject
+
+ # Create window header
+ pack [label $win.header \
+ -text [mc "%s - EEPROM write buffer" $actualProject] \
+ ] -fill x -pady 10
+
+ # Create offset label
+ set offset_frame [frame $win.offset_frame]
+ pack [label $offset_frame.lbl \
+ -text [mc "OFFSET = "] \
+ -font [font create \
+ -size -17 -weight bold \
+ -family {helvetica}] \
+ ] -side left
+ pack [label $offset_frame.val \
+ -fg {#0000FF} \
+ -font [font create \
+ -size -17 -weight bold \
+ -family {helvetica}] \
+ ] -side left
+ pack $offset_frame -anchor w
+
+ # Create middle frame (hexeditor)
+ set hexeditor [HexEditor ::eeprom_write_buffer_${eeprom_wr_buf_counter} \
+ $win.mainframe 8 4 2 hex 1 0 4 32 \
+ ]
+ $hexeditor showHideScrollbar 0
+ $hexeditor bindCellValueChanged "$actualProject setEepromWrBufDEC"
+ $hexeditor bindCellEnter "::X::eeprom_write_buffer_change_cursor_addr $win"
+ $hexeditor bindCellLeave "::X::eeprom_write_buffer_change_cursor_addr $win {}"
+ for {set i 0} {$i < 32} {incr i} {
+ $hexeditor setValue $i [$actualProject getEepromWrBufDEC $i]
+ }
+ eeprom_write_buffer_set_offset [$actualProject getEepromWrOffsetDEC] $actualProject
+ $hexeditor focus_left_view
+ pack $win.mainframe
+
+ # Create bottom frame
+ set bottom_frame [frame $win.bottom_frame]
+ pack [ttk::button $bottom_frame.close_but \
+ -text [mc "Close"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "X::close_hexedit eeprom_wr_bf $actualProject" \
+ ] -side left -anchor w
+ pack [label $bottom_frame.cur_val \
+ -text { } -fg {#0000FF} \
+ -font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ] \
+ ] -side right -anchor e -padx 5
+ pack [label $bottom_frame.cur_lbl \
+ -text [mc "Cursor: "] \
+ ] -side right -anchor e
+ pack $bottom_frame -side bottom -fill x
+
+ # Configure dialog window
+ wm iconphoto $win ::ICONS::16::kcmmemory
+ wm title $win [mc "EEPROM write buffer - %s - MCU 8051 IDE" $actualProject]
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW \
+ "X::close_hexedit eeprom_wr_bf $actualProject"
+
+ # Finalize
+ set critical_procedure_in_progress 0
+
+ }
+
+ ## Close hexadecimal editor window
+ # -- auxiliary procedure for '__show_ext_mem' and '__show_code_mem'
+ # @parm String type - Editor type ('eeprom', 'eeprom_wr_bf' 'eram', 'code' or 'xdata')
+ # @parm Object project - Project object descriptor
+ # @return void
+ proc close_hexedit {type project} {
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # Close CODE memory editor
+ if {$type == {code}} {
+ set opended_windows_var {opended_code_mem_windows}
+ set window_objects_var {code_mem_window_objects}
+ set opended_windows $opended_code_mem_windows
+ set window_objects $code_mem_window_objects
+
+ # Close ERAM editor
+ } elseif {$type == {eram}} {
+ set opended_windows_var {opended_eram_windows}
+ set window_objects_var {eram_window_objects}
+ set opended_windows $opended_eram_windows
+ set window_objects $eram_window_objects
+
+ # Close XDATA memory editor
+ } elseif {$type == {xdata}} {
+ set opended_windows_var {opended_xdata_mem_windows}
+ set window_objects_var {xdata_mem_window_objects}
+ set opended_windows $opended_xdata_mem_windows
+ set window_objects $xdata_mem_window_objects
+
+ # Close data EEPROM editor
+ } elseif {$type == {eeprom}} {
+ set opended_windows_var {opended_eeprom_mem_windows}
+ set window_objects_var {eeprom_mem_window_objects}
+ set opended_windows $opended_eeprom_mem_windows
+ set window_objects $eeprom_mem_window_objects
+
+ # Close EEPROM write buffer
+ } elseif {$type == {eeprom_wr_bf}} {
+ set opended_windows_var {opended_eeprom_wr_bf_windows}
+ set window_objects_var {eeprom_wr_bf_window_objects}
+ set opended_windows $opended_eeprom_wr_bf_windows
+ set window_objects $eeprom_wr_bf_window_objects
+
+ # Close project independent hexadecimal editor
+ } elseif {$type == {uni}} {
+ return
+
+ # Invalid request
+ } else {
+ return
+ }
+
+
+ # Determinate editor index
+ set idx [lsearch -exact -ascii $opended_windows $project]
+ if {$idx == -1} {return}
+ # Destroy editor object
+ if {$type == {eeprom_wr_bf}} {
+ destroy [lindex $window_objects $idx]
+ } {
+ delete object [lindex $window_objects $idx]
+ }
+ # Delete references
+ set $opended_windows_var [lreplace $opended_windows $idx $idx]
+ set $window_objects_var [lreplace $window_objects $idx $idx]
+ }
+
+ ## Adjust main window title to current project and file
+ # @return void
+ proc adjust_title {} {
+ variable actualProject ;# Object: Current project
+ set title {} ;# New title
+
+ # Project opened
+ if {$actualProject != {}} {
+ # Gain data from the project
+ if {[catch {
+ if {[$actualProject editor_procedure {} cget -modified]} {
+ append title {[modified] }
+ }
+ append title $actualProject
+ append title { : }
+ append title [$actualProject editor_procedure {} cget -filename]
+ append title { - MCU 8051 IDE}
+ wm title . $title
+
+ # Error -- default title
+ }]} {
+ wm title . ${::APPNAME}
+ }
+
+ # No project opened -- default title
+ } {
+ wm title . ${::APPNAME}
+ }
+ }
+
+ ## Clear highlight for changed registers in simulator panels
+ # @return void
+ proc __sim_clear_highlight {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+
+ if {$project_menu_locked} {return}
+ $actualProject simulator_clear_highlight
+ $actualProject rightPanel_watch_clear_highlight
+ $actualProject bitmap_clear_hg
+ $actualProject sfrmap_clear_hg
+
+ set idx [lsearch -exact -ascii $opended_xdata_mem_windows $actualProject]
+ if {$idx != -1} {
+ [lindex $xdata_mem_window_objects $idx] clear_highlight
+ }
+ set idx [lsearch -exact -ascii $opended_eram_windows $actualProject]
+ if {$idx != -1} {
+ [lindex $eram_window_objects $idx] clear_highlight
+ }
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows $actualProject]
+ if {$idx != -1} {
+ [lindex $eeprom_mem_window_objects $idx] clear_highlight
+ }
+ }
+
+ ## Insure than simulator cursor is in editor visible area
+ # @return void
+ proc __see_sim_cursor {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ $actualProject editor_procedure {} see_sim_cursor {}
+ }
+ }
+
+ ## Load value to PC in simulator control panel; line -> address
+ # @return void
+ proc __simulator_set_PC_by_line {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ variable line2pc ;# Int: Selected line in source code
+ variable line2pc_jump ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable line2pc_value_lbl ;# Widget: Label containing PC value
+ variable line2pc_new_value ;# Int: Resolved address or {}
+ variable line2pc_org_line ;# Int: Original line
+ variable line2pc_line_max ;# Int: Number of lines in the source code
+ variable line2pc_ok_button ;# Widget: Button "OK"
+ variable line2pc_file_number ;# Int: File number
+
+ if {$project_menu_locked} {return}
+
+ # Check if simulator is started
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ return
+ }
+ set filename [$actualProject editor_procedure {} cget -fullFileName]
+ if {[lindex $filename 0] == {}} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "This operation cannot be performed on an untitled file"]
+ return
+ }
+ set line2pc_file_number [$actualProject simulator_get_filenumber $filename]
+ if {$line2pc_file_number == -1} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "This file does not contain any part of the running program"]
+ return
+ }
+
+ # Load some NS variables
+ set line2pc_line_max [$actualProject editor_linescount]
+ set line2pc_org_line [lindex [$actualProject simulator_getCurrentLine] 0]
+ set line2pc_new_value [$actualProject simulator_line2address $line2pc_org_line $line2pc_file_number]
+ set line2pc $line2pc_org_line
+
+ # Create dialog window
+ set win [toplevel .goto_line2pc -class [mc "Goto dialog"] -bg {#EEEEEE}]
+
+ # Create window label frame
+ label $win.header \
+ -text [mc "Line to address"] \
+ -image ::ICONS::16::goto \
+ -compound left
+
+ # Create middle frame
+ set middle_frame [frame $win.middle_frame]
+ pack [label $middle_frame.left_lbl \
+ -text [mc "PC = "] \
+ -font [font create \
+ -size -16 -weight bold \
+ -family {helvetica}] \
+ ] -side left
+ set line2pc_value_lbl [label $middle_frame.right_lbl \
+ -font [font create \
+ -size -16 -weight bold \
+ -family {helvetica}] \
+ ]
+ pack $line2pc_value_lbl -side left
+ set middle_right_frame [frame $middle_frame.right_frame]
+ pack [radiobutton $middle_right_frame.jump_rabut \
+ -variable ::X::line2pc_jump \
+ -value 1 -text [mc "Program jump"] \
+ ] -anchor w
+ pack [radiobutton $middle_right_frame.call_rabut \
+ -variable ::X::line2pc_jump \
+ -value 0 -text [mc "Subprogram call"] \
+ ] -anchor w
+ pack $middle_right_frame -side right
+ pack $middle_frame -padx 5 -fill x -pady 5
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ set line2pc_ok_button [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::line2pc_OK} \
+ ]
+ pack $line2pc_ok_button -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::line2pc_CANCEL} \
+ ] -side left
+ pack $buttonFrame -after $middle_frame -pady 5
+
+ ## Create top frame
+ set topFrame [ttk::labelframe $win.topFrame -labelwidget $win.header -relief flat]
+ pack $topFrame -expand 1 -fill x -before $middle_frame -padx 5 -pady 5
+ # Create scale widget
+ pack [ttk::scale $topFrame.scale \
+ -from 1 \
+ -to $line2pc_line_max \
+ -orient horizontal \
+ -variable ::X::line2pc \
+ -command "
+ set ::X::line2pc \[expr {int(\${::X::line2pc})}\]
+ $topFrame.spinbox selection range 0 end
+ #" \
+ ] -side left -expand 1 -fill x -padx 2
+ DynamicHelp::add $topFrame.scale \
+ -text [mc "Graphical representation of the line where to go"]
+ # Create spinbox widget
+ pack [spinbox $topFrame.spinbox \
+ -from 1 -to $line2pc_line_max \
+ -textvariable X::line2pc \
+ -validate all \
+ -vcmd {X::line2pc_validate [expr {int(%P)}] %W} \
+ -width 4 \
+ -command "$topFrame.spinbox selection range 0 end ;#" \
+ ] -side left
+ DynamicHelp::add $topFrame.spinbox -text [mc "Line where to go"]
+
+ # Events binding (Enter == Ok, Esc == CANCEL)
+ bind $win <KeyRelease-Return> {X::line2pc_OK; break}
+ bind $win <KeyRelease-KP_Enter> {X::line2pc_OK; break}
+ bind $win <KeyRelease-Escape> {X::line2pc_CANCEL; break}
+
+ # Focus on the Spinbox
+ focus $topFrame.spinbox
+ $topFrame.spinbox selection range 0 end
+
+ # Nessesary window manager options -- modal window
+ wm iconphoto $win ::ICONS::16::exec
+ wm title $win [mc "Line to address"]
+ wm minsize $win 350 100
+ wm protocol $win WM_DELETE_WINDOW {
+ X::line2pc_CANCEL
+ }
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Validate content od spinbox in dialog "Line to address"
+ # @parm String content - String to validate
+ # @return Bool - result
+ proc line2pc_validate {content line2pc_spinbox} {
+ variable actualProject ;# Object: Current project
+
+ variable line2pc ;# Int: Selected line in source code
+ variable line2pc_value_lbl ;# Widget: Label containing PC value
+ variable line2pc_new_value ;# Int: Resolved address or {}
+ variable line2pc_org_line ;# Int: Original line
+ variable line2pc_line_max ;# Int: Number of lines in the source code
+ variable line2pc_ok_button ;# Widget: Button "OK"
+ variable line2pc_file_number ;# Int: File number
+
+ # Validate the given string
+ if {![string is digit $content] || $content > $line2pc_line_max || $content < 0} {
+ $line2pc_spinbox configure -bg {#FFFFFF}
+ return 0
+ }
+
+ # Try to determinate address in program memory
+ set content [expr $content]
+ set line2pc_new_value [$actualProject simulator_line2address $content $line2pc_file_number]
+
+ # Fail
+ if {$line2pc_new_value == {}} {
+ # Adjust PC value label
+ $line2pc_value_lbl configure \
+ -fg {#DD0000} \
+ -text [mc "Unable to resolve"]
+
+ code_hex_editor_directly_move_program_pointer $actualProject -1
+ $actualProject editor_procedure {} unset_simulator_line {} ;# Adjust editor
+ $line2pc_ok_button configure -state disabled ;# Adjust Ok button
+ $line2pc_spinbox configure -bg {#FFCCCC} ;# Adjust SpinBox
+
+ # Success
+ } {
+ # Translate address to hexadecimal system
+ set addr_in_hex [format %X $line2pc_new_value]
+ set len [string length $addr_in_hex]
+ if {$len < 4} {
+ set addr_in_hex "[string repeat {0} [expr {4 - $len}]]$addr_in_hex"
+ }
+ $line2pc_value_lbl configure \
+ -fg {#00DD00} \
+ -text "0x$addr_in_hex"
+
+ # Adjust editor
+ code_hex_editor_directly_move_program_pointer $actualProject $line2pc_new_value
+ $actualProject move_simulator_line [list $content $line2pc_file_number]
+ $line2pc_ok_button configure -state normal ;# Adjust Ok button
+ $line2pc_spinbox configure -bg {#CCFFCC} ;# Adjust SpinBox
+ }
+ return 1
+ }
+
+ ## Safely close dialog "Line to address"
+ # @return void
+ proc line2pc_safely_close {} {
+ if {[winfo exists .goto_line2pc]} {
+ grab release .goto_line2pc
+ destroy .goto_line2pc
+ }
+ }
+
+ ## Cancel dialog "Line to address"
+ # @return void
+ proc line2pc_CANCEL {} {
+ variable line2pc_org_line ;# Int: Original line
+ variable actualProject ;# Object: Current project
+
+ if {$line2pc_org_line == {}} {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ } {
+ $actualProject move_simulator_line $line2pc_org_line
+ }
+ code_hex_editor_directly_move_program_pointer $actualProject -1
+
+ grab release .goto_line2pc
+ destroy .goto_line2pc
+ }
+
+ ## Confirm dialog "Line to address"
+ # @return void
+ proc line2pc_OK {} {
+ variable line2pc_new_value ;# Int: Resolved address or {}
+ variable actualProject ;# Object: Current project
+ variable line2pc_jump ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable line2pc ;# Int: Selected line in source code
+
+ if {$line2pc_new_value == {}} {
+ line2pc_CANCEL
+ return
+ }
+
+ $actualProject move_simulator_line $line2pc
+ if {$line2pc_jump} {
+ $actualProject setPC $line2pc_new_value
+ } {
+ $actualProject simulator_subprog_call $line2pc_new_value
+ }
+ code_hex_editor_directly_move_program_pointer $actualProject -1
+ $actualProject Simulator_sync_PC_etc
+
+ grab release .goto_line2pc
+ destroy .goto_line2pc
+ }
+
+ ## Switch to the previous editor in the current project (from editor statusbar popup menu)
+ # @return void
+ proc __prev_editor_from_pmenu {} {
+ variable actualProject ;# Object: Current project
+ variable selectedView ;# Int: Selected editor view
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Switch editor
+ $actualProject filelist_editor_selected $selectedView
+ $actualProject prev_editor
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Switch to the next editor in the current project (from editor statusbar popup menu)
+ # @return void
+ proc __next_editor_from_pmenu {} {
+ variable actualProject ;# Object: Current project
+ variable selectedView ;# Int: Selected editor view
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Switch editor
+ $actualProject filelist_editor_selected $selectedView
+ $actualProject next_editor
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Switch to editor command line
+ # @return void
+ proc __switch_to_cmd_line {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject cmd_line_on
+ }
+
+ ## Split editor vertical
+ # @return void
+ proc __split_vertical {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject split_vertical
+ }
+
+ ## Split editor horizontal
+ # @return void
+ proc __split_horizontal {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject split_horizontal
+ }
+
+ ## Close current view (editor) from editor statusbar popup menu
+ # @return void
+ proc __close_current_view_from_pmenu {} {
+ variable selectedView ;# Int: Selected editor view
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject close_current_view $selectedView
+ }
+
+ ## Close current view (editor)
+ # @return void
+ proc __close_current_view {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject close_current_view {}
+ }
+
+ ## Enable / Disable stepback controls
+ # @parm Bool bool - 1 == enable; 0 == disable
+ # @return void
+ proc stepback_button_set_ena {bool} {
+ variable actualProject ;# Object: Current project
+
+ if {$bool != 0} {
+ set boot 1
+ }
+ $actualProject stepback_button_set_ena $bool
+ ena_dis_menu_buttons $bool {{{.mainMenu.simulator} {{Step back}}}}
+ ena_dis_iconBar_buttons $bool .mainIconBar. {stepback}
+ }
+
+ ## Hibernate running program to a file
+ # This function also invokes file selection dialog to select target file.
+ # @return void
+ proc __hibernate {} {
+ hibernate_or_resume 1
+ }
+
+ ## Resume hibernated program
+ # This function also invokes file selection dialog to select source file.
+ # @return void
+ proc __resume {} {
+ hibernate_or_resume 0
+ }
+
+ ## Hibernate running program // Resume hibernated program
+ # @parm Bool hib_res - 1 == Hiberanate; 0 == Resume
+ # @return void
+ proc hibernate_or_resume {hib_res} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # Simulator must be engaged for this function
+ if {$project_menu_locked} {return}
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ return
+ }
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ set sourcefile [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ if {[lindex $sourcefile 1] == {}} {
+ set sourcefile [$actualProject editor_procedure {} getFileName {}]
+ }
+ set sourcefile [file join [lindex $sourcefile 0] [lindex $sourcefile 1]]
+ set initialfile [file rootname [file tail $sourcefile]]
+ if {$hib_res} {
+ set title [mc "Hibernate running program - MCU 8051 IDE"]
+ set cmd {__hibernate_to}
+ } {
+ set title [mc "Resume hibernated program - MCU 8051 IDE"]
+ set cmd {__resume_from}
+ }
+
+ # Invoke file selection dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title $title -initialfile $initialfile \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{MCU 8051 IDE Hibernated program} {*.m5ihib} }
+ {{All files} {*} }
+ }
+
+ # Open file after press of OK button
+ fsd setokcmd "
+ ::X::fsd deactivate
+ ::X::$cmd \[X::fsd get\] {$sourcefile}
+ "
+
+ # Activate FSD
+ fsd activate
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Hibernate running program to the given file
+ # @parm String filename - Target file
+ # @parm String sourcefile - Source file
+ # @return void
+ proc __hibernate_to {filename sourcefile} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ # Simulator must be engaged for this function
+ if {$project_menu_locked} {return}
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ return
+ }
+
+ # Adjust the given name of the target file
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ if {[file extension $filename] == {}} {
+ append filename {.m5ihib}
+ }
+ set filename [file normalize $filename]
+
+ # Create backup copy the target 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~"
+ }
+ }
+
+ # Hibernate running program
+ set sourcefile_md5 {}
+ catch {
+ set sourcefile_md5 [::md5::md5 -hex -file $sourcefile]
+ }
+ if {![$actualProject hibernate_hibernate \
+ $filename [file tail $sourcefile] $sourcefile_md5 0 \
+ ]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Hibernation failed"] \
+ -message [mc "Unable to write to file:\n%s\nCheck your permissions." $filename]
+ }
+ }
+
+ ## Resume hibernated program
+ # @parm String filename - Hibernation file
+ # @parm String sourcefile - Name of file from which the hibernation file was generated
+ # @return void
+ proc __resume_from {filename sourcefile} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ # Simulator must be engaged for this function
+ if {$project_menu_locked} {return}
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ return
+ }
+
+ # Adjust the given name of the target file
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+
+ # Resume hibernated program
+ set result [$actualProject hibernate_resume $filename 0]
+
+ # ERROR: Cannot open the specified file
+ if {$result == 1} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Resumption failed"] \
+ -message [mc "Unable to read file:\n%s\nCheck your permissions." $filename]
+
+ # ERROR: Cannot parse the specified file
+ } elseif {$result == 2} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Resumption failed"] \
+ -message [mc "This hibernation is corrupted or it is not MCU 8051 IDE M5IHIB file."]
+ }
+ }
+
+ ## Invoke interrupt monitor window
+ # @parm Object project_object = actualProject - Project
+ # @return void
+ proc __interrupt_monitor args {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[string length $args]} {
+ $args interrupt_monitor_invoke_dialog
+ } {
+ $actualProject interrupt_monitor_invoke_dialog
+ }
+ }
+
+ ## Invoke stack monitor window
+ # @parm Object project_object = actualProject - Project
+ # @return void
+ proc __stack_monitor args {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[string length $args]} {
+ $args stack_monitor_invoke_dialog
+ } {
+ $actualProject stack_monitor_invoke_dialog
+ }
+ }
+
+ ## Invoke SFR map window
+ # @return void
+ proc __sfr_map {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject sfrmap_invoke_dialog
+ }
+
+ ## Show bit adrea
+ # @return void
+ proc __bitmap {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject bitmap_invoke_dialog
+ }
+
+ ## Adjust application language to variable ::GLOBAL_CONFIG(language)
+ # @return void
+ proc switch_language {} {
+ # ${::GLOBAL_CONFIG(language)}
+ }
+
+ ## Set syntax highlight for current editor
+ # @param Int highlight_num - -1 == None; 0 == Assembler; 1 == ISO C; 2 == Assembler code listing
+ # @return void
+ proc __set_highlight {highlight_num} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject editor_procedure {} force_language $highlight_num
+ }
+
+ ## Highlight parrern for the current editor has been changed
+ # @return void
+ proc highlight_pattern_changed {} {
+ __set_highlight $::editor_SH
+ }
+
+ ## Invoke independent hexadecimal editor
+ # @return Object - Hexeditor object reference
+ proc __hexeditor {} {
+ variable independent_hexeditor_count ;# Counter of intances of independent hexadecimal editor
+ incr independent_hexeditor_count
+
+ return [HexEditDlg ::independent_hexeditor_$independent_hexeditor_count {} uni]
+ }
+
+ ## Document current function in editor
+ # @return void
+ proc __document_current_func {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject editor_procedure {} document_current_func {}
+ }
+
+ ## Create doxygen configguration file if it does not already exist
+ # @return void
+ proc create_doxyfile {} {
+ variable doxygen_pid ;# Int: Doxygen PID
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable actualProject ;# Object: Current project
+
+ if {$compilation_in_progress} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "Something is already running in background."]
+ return
+ }
+
+ set compilation_in_progress 1
+ make_progressBar_on_Sbar
+
+ if {[catch {
+ cd [$actualProject cget -projectPath]
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to change diectory to '%s'." [$actualProject cget -projectPath]]
+ return
+ }
+ if {![file exists Doxyfile]} {
+ $actualProject messages_text_append "\ndoxygen -g Doxyfile\n"
+ set doxygen_pid [exec -- \
+ doxygen -g Doxyfile && doxygen -u Doxyfile |& \
+ tclsh ${::LIB_DIRNAME}/external_command.tcl [tk appname] \
+ ::X::doxygen_finish ::X::doxygen_message & \
+ ]
+ } {
+ $actualProject messages_text_append "\ndoxygen -u Doxyfile\n"
+ set doxygen_pid [exec -- \
+ doxygen -u Doxyfile |& tclsh \
+ ${::LIB_DIRNAME}/external_command.tcl [tk appname] \
+ ::X::doxygen_finish ::X::doxygen_message & \
+ ]
+ }
+ }
+
+ ## Handle end of doxygen text output
+ # @return void
+ proc doxygen_finish {} {
+ variable actualProject ;# Object: Current project
+ variable doxygen_run_doxywizard ;# Bool: Run doxywizard
+ variable doxygen_build_api_doc ;# Bool: Build API documentation
+ variable doxygen_pid ;# Int: Doxygen PID
+ variable compilation_in_progress ;# Bool: Compiler engaged
+
+ if {$doxygen_run_doxywizard} {
+ exec -- doxywizard Doxyfile &
+ } elseif {$doxygen_build_api_doc} {
+ set doxygen_build_api_doc 0
+ if {[catch {
+ cd [$actualProject cget -projectPath]
+ }]} {
+ $actualProject messages_text_append [mc "\nUnable to change diectory to '%s'\n" [$actualProject cget -projectPath]]
+ destroy_progressBar_on_Sbar
+ set compilation_in_progress 0
+ set doxygen_pid 0
+ return
+ }
+
+ $actualProject messages_text_append "\ndoxygen Doxyfile\n"
+ set doxygen_pid [exec -- \
+ doxygen Doxyfile |& tclsh \
+ ${::LIB_DIRNAME}/external_command.tcl [tk appname] \
+ ::X::doxygen_finish ::X::doxygen_message & \
+ ]
+ }
+
+ destroy_progressBar_on_Sbar
+ set compilation_in_progress 0
+ set doxygen_pid 0
+ }
+
+ ## Handle text output doxygen
+ # @parm String text - Output from external compiler
+ # @return void
+ proc doxygen_message args {
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+ $doxygen_mess_project messages_text_append \
+ [string replace [regsub -all "\\\{" [regsub -all "\\\}" [lindex $args 0] "\}"] "\{"] 0 0]
+ }
+
+ ## Build C API documentation
+ # @return void
+ proc __generate_documentation {} {
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+ variable doxygen_build_api_doc ;# Bool: Build API documentation
+ variable doxygen_pid ;# Int: Doxygen PID
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$compilation_in_progress} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "Something is already running in background."]
+ return
+ }
+ set doxygen_mess_project $actualProject
+ set doxygen_build_api_doc 1
+ if {!$::PROGRAM_AVALIABLE(doxygen)} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to find Doxygen"] \
+ -message [mc "Unable to find Doxygen. Please install doxygen and restart MCU 8051 IDE."]
+ return
+ }
+ $actualProject bottomNB_show_up {Messages}
+ create_doxyfile
+ }
+
+ ## Run doxygen graphical frontend
+ # @return void
+ proc __run_doxywizard {} {
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+ variable doxygen_run_doxywizard ;# Bool: Run doxywizard
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {!$::PROGRAM_AVALIABLE(doxywizard)} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to find doxywizard"] \
+ -message [mc "Unable to find doxywizard. Please install doxygen and restart MCU 8051 IDE."]
+ return
+ }
+ set doxygen_run_doxywizard 1
+ set doxygen_mess_project $actualProject
+ create_doxyfile
+ }
+
+ ## Remove doxygen documentation
+ # @return void
+ proc __clear_documentation {} {
+ variable actualProject ;# Object: Current project
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ set doxygen_mess_project $actualProject
+ if {[catch {
+ cd [$actualProject cget -projectPath]
+ }]} {
+ $actualProject messages_text_append [mc "\nError: Unable to change diectory to '%s'\n" [$actualProject cget -projectPath]]
+ return
+ }
+
+ $actualProject bottomNB_show_up {Messages}
+ $actualProject messages_text_append "\nrm -rfv html/* && rm -rfv latex/* && rm -rfv xml/*\n"
+ catch {exec -- /bin/sh << \
+ "rm -rfv html/* && rm -rfv latex/* && rm -rfv xml/*" |& \
+ tclsh ${::LIB_DIRNAME}/external_command.tcl [tk appname] \
+ ::X::doxygen_message ::X::doxygen_message & \
+ }
+ }
+
+ ## Display file statistic for the current file
+ # @return void
+ proc __statistics {} {
+ variable actualProject ;# Object: Current project
+ variable statistics_counter ;# Int: Counter of invocations of this dialog
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ # Check if this procedure can be run
+ if {$project_menu_locked} {return}
+ if {${::Editor::editor_to_use}} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to compile"] \
+ -message [mc "Unable to gain file statistics while external editor is used"]
+ return
+ }
+
+ # Create dialog window (not modal)
+ incr statistics_counter
+ set win [toplevel .statistics$statistics_counter -class {File statistics} -bg {#EEEEEE}]
+
+ # Local variables
+ set bold_font [font create -family {helvetica} -size -12 -weight bold]
+ set normal_font [font create -family {helvetica} -size -12 -weight normal]
+ set header_font [font create -family {helvetica} -size -20 -weight normal]
+ set statistics [$actualProject editor_procedure {} getFileStatistics {}]
+
+ # Create window header
+ set dialog_header [label $win.dialog_header \
+ -width 25 -font $header_font \
+ -text [lindex [$actualProject editor_procedure {} getFileName {}] 1] \
+ ]
+
+ set main_frame [frame $win.main_frame]
+ # Header: "Characters"
+ grid [label $main_frame.characters_lbl -pady 0 \
+ -text [mc "Characters"] -font $bold_font \
+ ] -row 0 -column 0 -columnspan 3 -sticky w
+ # - Words and numbers
+ grid [Label $main_frame.c_words_name_lbl \
+ -text [mc "Words and numbers:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Alphanumeric characters and connector punctuation characters"] \
+ ] -row 1 -column 1 -sticky w
+ grid [label $main_frame.c_words_value_lbl \
+ -text [lindex $statistics 0] \
+ -font $normal_font -pady 0 \
+ ] -row 1 -column 2 -sticky e
+ # - Comments
+ grid [Label $main_frame.c_comments_name_lbl \
+ -text [mc "Comments:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Characters highlighted as comments"] \
+ ] -row 2 -column 1 -sticky w
+ grid [label $main_frame.c_comments_value_lbl \
+ -text [lindex $statistics 1] \
+ -font $normal_font -pady 0 \
+ ] -row 2 -column 2 -sticky e
+ # - Other characters
+ grid [Label $main_frame.c_other_name_lbl \
+ -text [mc "Other characters:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "All other charactes without EOLs (e.g. spaces and brackets)"] \
+ ] -row 3 -column 1 -sticky w
+ grid [label $main_frame.c_other_value_lbl \
+ -text [lindex $statistics 2] \
+ -font $normal_font -pady 0 \
+ ] -row 3 -column 2 -sticky e
+ # Separator
+ grid [ttk::separator $main_frame.sep_0 \
+ -orient horizontal \
+ ] -row 4 -column 2 -sticky we
+ # - Total characters
+ grid [Label $main_frame.c_total_name_lbl \
+ -text [mc "Total characters:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "All charactes in the text without EOLs"] \
+ ] -row 5 -column 1 -sticky w
+ grid [label $main_frame.c_total_value_lbl \
+ -text [lindex $statistics 3] \
+ -font $normal_font -pady 0 \
+ ] -row 5 -column 2 -sticky e
+ # Header: "Strings"
+ grid [label $main_frame.strings_lbl -pady 0 \
+ -text [mc "Strings"] -font $bold_font \
+ ] -row 7 -column 0 -columnspan 3 -sticky w
+ # - Words
+ grid [Label $main_frame.s_words_name_lbl \
+ -text [mc "Words:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Just normal words (not keywords and not comments)"] \
+ ] -row 8 -column 1 -sticky w
+ grid [label $main_frame.s_words_value_lbl \
+ -text [lindex $statistics 4] \
+ -font $normal_font -pady 0 \
+ ] -row 8 -column 2 -sticky e
+ # - Keywords
+ grid [Label $main_frame.s_keywords_name_lbl \
+ -text [mc "Keywords:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Instructions, Assembler directives, C directives, C keywords"] \
+ ] -row 9 -column 1 -sticky w
+ grid [label $main_frame.s_keywords_value_lbl \
+ -text [lindex $statistics 5] \
+ -font $normal_font -pady 0 \
+ ] -row 9 -column 2 -sticky e
+ # - Comments
+ grid [Label $main_frame.s_comments_name_lbl \
+ -text [mc "Comments:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Words in comments"] \
+ ] -row 10 -column 1 -sticky w
+ grid [label $main_frame.s_comments_value_lbl \
+ -text [lindex $statistics 6] \
+ -font $normal_font -pady 0 \
+ ] -row 10 -column 2 -sticky e
+ # Separator
+ grid [ttk::separator $main_frame.sep_1 \
+ -orient horizontal \
+ ] -row 11 -column 2 -sticky we
+ # - Total strings
+ grid [Label $main_frame.s_total_name_lbl \
+ -text [mc "Total strings:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Total number of words in the text"] \
+ ] -row 12 -column 1 -sticky w
+ grid [label $main_frame.s_total_value_lbl \
+ -text [lindex $statistics 7] \
+ -font $normal_font -pady 0 \
+ ] -row 12 -column 2 -sticky e
+ # Header: "Lines"
+ grid [label $main_frame.lines_lbl \
+ -text [mc "Lines"] \
+ -font $bold_font -pady 0 \
+ ] -row 14 -column 0 -columnspan 3 -sticky w
+ # - Empty lines
+ grid [Label $main_frame.l_empty_name_lbl \
+ -text [mc "Empty lines:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Totaly empty lines (without even spaces)"] \
+ ] -row 15 -column 1 -sticky w
+ grid [label $main_frame.l_empty_value_lbl \
+ -text [lindex $statistics 8] \
+ -font $normal_font -pady 0 \
+ ] -row 15 -column 2 -sticky e
+ # - Commented lines
+ grid [Label $main_frame.l_commented_name_lbl \
+ -text [mc "Commented lines:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Lines which are all commented"] \
+ ] -row 16 -column 1 -sticky w
+ grid [label $main_frame.l_commented_value_lbl \
+ -text [lindex $statistics 9] \
+ -font $normal_font -pady 0 \
+ ] -row 16 -column 2 -sticky e
+ # - Normal lines
+ grid [Label $main_frame.l_normal_name_lbl \
+ -text [mc "Normal lines:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Just normal code lines"] \
+ ] -row 17 -column 1 -sticky w
+ grid [label $main_frame.l_normal_value_lbl \
+ -text [lindex $statistics 10] \
+ -font $normal_font -pady 0 \
+ ] -row 17 -column 2 -sticky e
+ # Separator
+ grid [ttk::separator $main_frame.sep_2 \
+ -orient horizontal \
+ ] -row 18 -column 2 -sticky we
+ # - Total lines
+ grid [Label $main_frame.l_total_name_lbl \
+ -text [mc "Total lines:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Total number of lines in the text"] \
+ ] -row 19 -column 1 -sticky w
+ grid [label $main_frame.l_total_value_lbl \
+ -text [lindex $statistics 11] \
+ -font $normal_font -pady 0 \
+ ] -row 19 -column 2 -sticky e
+
+ # Configure main frame
+ grid columnconfigure $main_frame 0 -minsize 25
+ grid columnconfigure $main_frame 1 -weight 1
+ grid rowconfigure $main_frame 6 -minsize 10
+ grid rowconfigure $main_frame 13 -minsize 10
+
+ # Create and pack 'COPY' and 'OK' buttons
+ set button_frame [frame $win.button_frame]
+ pack [ttk::button $button_frame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "X::statistics_close $statistics_counter" \
+ ] -side right
+ pack [ttk::button $button_frame.copy \
+ -text [mc "Copy"] \
+ -compound left \
+ -image ::ICONS::16::editcopy \
+ -command "X::statistics_copy $statistics_counter" \
+ ] -side left
+
+ # Pack dialog frames
+ pack $dialog_header -side top -fill x -pady 5
+ pack $main_frame -side top -anchor nw -fill x -pady 15 -padx 10
+ pack $button_frame -side bottom -anchor se
+
+ # Set window manager options
+ wm iconphoto $win ::ICONS::16::graph
+ wm title $win [mc "File statistics - MCU 8051 IDE"]
+ wm minsize $win 250 400
+ wm transient $win .
+ wm protocol $win WM_DELETE_WINDOW "X::statistics_close $statistics_counter"
+ update
+ focus $button_frame.ok
+ raise $win
+ }
+
+ ## Close dialog "File statistics"
+ # @parm Int dialog_number -
+ # @return void
+ proc statistics_close {dialog_number} {
+ variable statistics_counter ;# Int: Counter of invocations of this dialog
+ if {![winfo exists .statistics$statistics_counter]} {return}
+ destroy .statistics$statistics_counter
+ }
+
+ ## Copy contents of file statistics dialog to the clipboard
+ # @parm Int dialog_number -
+ # @return void
+ proc statistics_copy {dialog_number} {
+ variable statistics_counter ;# Int: Counter of invocations of this dialog
+ if {![winfo exists .statistics$statistics_counter]} {return}
+
+ set win .statistics$statistics_counter
+ set main_frame $win.main_frame
+
+ clipboard clear
+ clipboard append [mc "Statistics for: %s\n\n" [$win.dialog_header cget -text]]
+ clipboard append [mc "Characters:\n"]
+ clipboard append [mc " Words and numbers:\t\t%s\n" [$main_frame.c_words_value_lbl cget -text]]
+ clipboard append [mc " Comments:\t\t\t%s\n" [$main_frame.c_comments_value_lbl cget -text]]
+ clipboard append [mc " Other characters:\t\t%s\n" [$main_frame.c_other_value_lbl cget -text]]
+ clipboard append [mc " ------\n"]
+ clipboard append [mc " Total characters:\t\t%s\n\n" [$main_frame.c_total_value_lbl cget -text]]
+ clipboard append [mc "Strings:\n"]
+ clipboard append [mc " Words:\t\t\t%s\n" [$main_frame.s_words_value_lbl cget -text]]
+ clipboard append [mc " Keywords:\t\t\t%s\n" [$main_frame.s_keywords_value_lbl cget -text]]
+ clipboard append [mc " Comments:\t\t\t%s\n" [$main_frame.s_comments_value_lbl cget -text]]
+ clipboard append [mc " ------\n"]
+ clipboard append [mc " Total strings:\t\t%s\n" [$main_frame.s_total_value_lbl cget -text]]
+ clipboard append [mc "Lines:\n"]
+ clipboard append [mc " Empty lines:\t\t\t%s\n" [$main_frame.l_empty_value_lbl cget -text]]
+ clipboard append [mc " Commented lines:\t\t%s\n" [$main_frame.l_commented_value_lbl cget -text]]
+ clipboard append [mc " Normal lines:\t\t\t%s\n" [$main_frame.l_normal_value_lbl cget -text]]
+ clipboard append [mc " ------\n"]
+ clipboard append [mc " Total lines:\t\t\t%s\n" [$main_frame.l_total_value_lbl cget -text]]
+ }
+
+ ## Modify main menu and main toolbar acording to configuration of the current editor
+ # @parm Bool read_only - 1 == Read only; 0 == Normal mode; {} == Do not change
+ # @parm Bool c_language - 1 == Uses C language; 0 == Uses Assembler; {} == Do not change
+ # @return void
+ proc adjust_mainmenu_and_toolbar_to_editor {read_only c_language} {
+ variable mainmenu_editor_readonly ;# Menu bar items which are not avaliable when editor is in read only mode
+ variable toolbar_editor_readonly ;# Tool bar items which are not avaliable when editor is in read only mode
+ variable mainmenu_editor_c_only ;# Menu bar items which are not avaliable only for C language
+ variable toolbar_editor_c_only ;# Toolbar items which are not avaliable only for C language
+
+ # Read only flag
+ if {$read_only != {}} {
+ set read_only [expr {!$read_only}]
+ ena_dis_menu_buttons $read_only $mainmenu_editor_readonly
+ ena_dis_iconBar_buttons $read_only .mainIconBar. $toolbar_editor_readonly
+ }
+
+ # C language
+ if {$c_language != {}} {
+ ena_dis_menu_buttons $c_language $mainmenu_editor_c_only
+ ena_dis_iconBar_buttons $c_language .mainIconBar. $toolbar_editor_c_only
+ }
+ }
+
+ ## Conditionaly disable menu and toolbar items which
+ #+ are not avaliable when external editor used
+ # @return void
+ proc adjust_mm_and_tb_ext_editor {} {
+ variable mainmenu_editor_external_na ;# Menu bar items which are not avaliable when external embedded editor is used
+ variable toolbar_editor_external_na ;# Toolbar items which are not avaliable when external embedded editor is used
+
+ if {!${::Editor::editor_to_use}} {
+ return
+ }
+
+ ena_dis_menu_buttons 0 $mainmenu_editor_external_na
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_editor_external_na
+ }
+
+ ## Invoke assembly language symbols viewer
+ # @return void
+ proc __symb_view {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+
+ # Open dialog window
+ set obj [SymbolViewer #auto]
+
+ # Try to load some file into the viewer
+ if {!$project_menu_locked} {
+ set file [$actualProject cget -P_option_main_file]
+ if {$file == {}} {
+ set file [$actualProject editor_procedure {} getFileName {}]
+ set file [file join [lindex $file 0] [lindex $file 1]]
+ }
+ if {$file != {}} {
+ $obj open_file 1 [file rootname $file].lst
+ }
+ }
+ }
+
+ ## Invoke 8-segment LED display editor
+ # @return void
+ proc __eightsegment {} {
+ variable eightsegment_editors ;# List: All 8-segment LED display editors invoked
+
+ lappend eightsegment_editors [EightSegment #auto]
+ }
+
+ ## Invoke ASCII chart
+ # @return void
+ proc __ascii_chart {} {
+ variable ascii_chart_win_object ;# Object: ASCII chart window object
+ if {$ascii_chart_win_object != {}} {
+ if {[$ascii_chart_win_object is_visible]} {
+ $ascii_chart_win_object raise_window
+ } {
+ $ascii_chart_win_object restore_window
+ }
+ } {
+ set ascii_chart_win_object [AsciiChart #this]
+ }
+ }
+
+ ## Switch editor to block selection mode
+ # @return void
+ proc __block_selection_mode {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+
+ if {$project_menu_locked} {return}
+ $actualProject editor_procedure {} switch_sel_mode {}
+ }
+
+ ## Invoke stopwatch timer window
+ # @return void
+ proc __stopwatch_timer {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+
+ if {$project_menu_locked} {return}
+ $actualProject stopwatch_invoke_dialog
+ }
+
+ ## Referesh contents of menu "Open recent"
+ # @param Int what
+ # 0 - Recent project files
+ # 1 - Recent source code files
+ # 2 - Recent Virtual HW files
+ # @return void
+ proc refresh_recent_files {what} {
+ variable file_recent_files ;# List: recently opened files
+ variable project_recent_files ;# List: recently opened projects
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ # Refresh "Recent Virtual HW files"
+ if {$what == 2} {
+ # Clean up the menu
+ .mainMenu.virtual_hw.open_recent delete 0 end
+ .mainMenu.virtual_hw.load_recent delete 0 end
+ # Interate over recently opened files and add them to the menu
+ foreach file $vhw_recent_files {
+ .mainMenu.virtual_hw.open_recent add command \
+ -label $file -command [list ::X::open_recent 2 $file]
+ .mainMenu.virtual_hw.load_recent add command \
+ -label $file -command [list ::X::open_recent -2 $file]
+ }
+
+ # Refresh "Recent source code file"
+ } elseif {$what == 1} {
+ # Clean up the menu
+ .mainMenu.file.open_recent delete 0 end
+
+ # Interate over recently opened files and add them to the menu
+ foreach file $file_recent_files {
+
+ # Determinate file type and appropriate icon
+ set ext [string trimleft [file extension $file] {.}]
+ if {$ext == {c}} {
+ set img {source_c}
+ } elseif {$ext == {h}} {
+ set img {source_h}
+ } elseif {$ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set img {source_cpp}
+ } elseif {$ext == {lst}} {
+ set img {ascii}
+ } elseif {$ext == {asm}} {
+ set img {asm}
+ } else {
+ set img {ascii}
+ }
+
+ # Create a new menu entry
+ .mainMenu.file.open_recent add command \
+ -label $file -compound left -image ::ICONS::16::$img \
+ -command [list ::X::open_recent $what $file]
+ }
+
+ # Refresh "Recent project file"
+ } elseif {$what == 0} {
+ # Clean up the menu
+ .mainMenu.project.open_recent delete 0 end
+ # Interate over recently opened files and add them to the menu
+ foreach file $project_recent_files {
+ .mainMenu.project.open_recent add command \
+ -label $file -command [list ::X::open_recent $what $file]
+ }
+ }
+
+
+ }
+
+ ## Open recent file
+ # @param Int what
+ # 0 - Recent project files
+ # 1 - Recent source code files
+ # 2 - Recent Virtual HW files (OPEN)
+ # -2 - Recent Virtual HW files (LOAD)
+ # @param String filename - Name of file to open
+ # @return void
+ proc open_recent {what filename} {
+ variable critical_procedure_in_progress ;# Bool: Disable critical procedures (like compilation, start simulator, etc.)
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Open "Recent Virtual HW file"
+ if {$what == 2} {
+ if {[$actualProject pale_open_scenario $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ }
+
+ # Load "Recent Virtual HW file"
+ } elseif {$what == -2} {
+ if {[$actualProject pale_load_scenarion $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ }
+
+ # Open "Recent source code file"
+ } elseif {$what == 1} {
+ # If there is no project opened -> invalid function call -> abort
+ if {![llength $openedProjects]} {
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Open the specified file
+ if {[$actualProject openfile $filename 1 . def def 0 0 {}] != {}} {
+ $actualProject switch_to_last
+ update
+ $actualProject editor_procedure {} parseAll {}
+
+ # Make LST read only
+ if {[file extension $filename] == {.lst}} {
+ set ::editor_RO_MODE 1
+ $actualProject switch_editor_RO_MODE
+ }
+ }
+
+ # Open "Recent project file"
+ } elseif {$what == 0} {
+ # Try to open he specified project file
+ if {![Project::open_project_file $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent . \
+ -title [mc "Error - MCU 8051 IDE"] \
+ -message [mc "Unable to load file: %s" $filename]
+ } {
+ $actualProject editor_procedure {} highlight_visible_area {}
+ }
+
+ adjust_title
+ disaena_menu_toolbar_for_current_project
+ }
+
+ # Unlock critical procedures
+ set critical_procedure_in_progress 0
+ }
+
+ ## Add item into list of recent files
+ # @param Int what
+ # 0 - Recent project files
+ # 1 - Recent source code files
+ # 2 - Recent Virtual HW files
+ # @param String filename - Name of file to add
+ # @return void
+ proc recent_files_add {what filename} {
+ variable file_recent_files ;# List: recently opened files
+ variable project_recent_files ;# List: recently opened projects
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ # Add "Recent Virtual HW file"
+ if {$what == 2} {
+ # Check wheather the specified file is already in the list
+ set tmp [lsearch -ascii -exact $vhw_recent_files $filename]
+ if {$tmp != -1} {
+ set vhw_recent_files [linsert [lreplace $vhw_recent_files $tmp $tmp] 0 $filename]
+ refresh_recent_files $what
+ return
+ }
+
+ # Trim list length to 10
+ if {[llength $vhw_recent_files] >= 10} {
+ set vhw_recent_files [lreplace $vhw_recent_files end end]
+ }
+
+ # Add new item and refersh menu
+ set vhw_recent_files [linsert $vhw_recent_files 0 $filename]
+ refresh_recent_files $what
+
+ # Add "Recent source code file"
+ } elseif {$what == 1} {
+ # Check wheather the specified file is already in the list
+ set tmp [lsearch -ascii -exact $file_recent_files $filename]
+ if {$tmp != -1} {
+ set file_recent_files [linsert [lreplace $file_recent_files $tmp $tmp] 0 $filename]
+ refresh_recent_files $what
+ return
+ }
+
+ # Trim list length to 10
+ if {[llength $file_recent_files] >= 10} {
+ set file_recent_files [lreplace $file_recent_files end end]
+ }
+
+ # Add new item and refersh menu
+ set file_recent_files [linsert $file_recent_files 0 $filename]
+ refresh_recent_files $what
+
+ # Add "Recent project file"
+ } elseif {$what == 0} {
+ # Check wheather the specified file is already in the list
+ set tmp [lsearch -ascii -exact $project_recent_files $filename]
+ if {$tmp != -1} {
+ set project_recent_files [linsert [lreplace $project_recent_files $tmp $tmp] 0 $filename]
+ refresh_recent_files $what
+ return
+ }
+
+ # Trim list length to 10
+ if {[llength $project_recent_files] >= 10} {
+ set project_recent_files [lreplace $project_recent_files end end]
+ }
+
+ # Add new item and refersh menu
+ set project_recent_files [linsert $project_recent_files 0 $filename]
+ refresh_recent_files $what
+
+ }
+ }
+
+ ## Invoke "scribble notepad"
+ # @return void
+ proc __notes {} {
+ Notes #auto {} {}
+ }
+
+ ## Invoke "Base convertor"
+ # @return void
+ proc __base_convertor {} {
+ variable base_convertors ;# List: All base convertor objects
+
+ set obj [BaseConvertor #auto]
+ lappend base_convertors ::X::$obj
+
+ return $obj
+ }
+
+ ## Close "Base convertor"
+ # @return void
+ proc __base_convertor_close {obj} {
+ variable base_convertors ;# List: All base convertor objects
+
+ set idx [lsearch -ascii -exact $base_convertors $obj]
+ if {$idx != -1} {
+ set base_convertors [lreplace $base_convertors $idx $idx]
+ }
+ }
+
+ ## Invoke "LED panel" (section Virtual Hardware)
+ # @return void
+ proc __vhw_LED_panel {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [LedPanel #auto $actualProject]
+ }
+
+ ## Invoke "LED display" (section Virtual Hardware)
+ # @return void
+ proc __vhw_LED_display {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [LedDisplay #auto $actualProject]
+ }
+
+ ## Invoke "LED matrix" (section Virtual Hardware)
+ # @return void
+ proc __vhw_LED_matrix {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [LedMatrix #auto $actualProject]
+ }
+
+ ## Invoke "Multiplexed LED display" (section Virtual Hardware)
+ # @return void
+ proc __vhw_M_LED_display {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [MultiplexedLedDisplay #auto $actualProject]
+ }
+
+ ## Invoke "Simple keypad" (section Virtual Hardware)
+ # @return void
+ proc __vhw_keys {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [SimpleKeyPad #auto $actualProject]
+ }
+
+ ## Invoke "Matrix keypad" (section Virtual Hardware)
+ # @return void
+ proc __vhw_matrix_keypad {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [MatrixKeyPad #auto $actualProject]
+ }
+
+ ## Open VHW file (section Virtual Hardware)
+ # @return void
+ proc __open_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Ask user for save modified VHW scenario
+ if {[${::X::actualProject} pale_modified]} {
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -title [mc "File modified"] \
+ -message [mc "The current VHW connections have been modified,\ndo you want to save them before closing ?"]
+ ] == {yes}} then {
+ if {![$actualProject pale_save]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to write to file:\n\"%s\"" [$actualProject pale_get_scenario_filename]]
+ }
+ }
+ }
+
+ # Create file selection dialog
+ catch {delete object ::fsd}
+ KIFSD::FSD ::fsd \
+ -title [mc "Open file - Virtual HW - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes [list \
+ [list [mc "Virtual HW"] {*.vhw}] \
+ [list [mc "VH component"] {*.vhc}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ ::fsd setokcmd {
+ set filename [::fsd get]
+ if {[${::X::actualProject} pale_open_scenario $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ } {
+ ::X::recent_files_add 2 $filename
+ }
+ }
+
+ # activate the dialog
+ ::fsd activate
+ }
+
+ ## Import virtual hardware file
+ # @return void
+ proc __load_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Create file selection dialog
+ catch {delete object ::fsd}
+ KIFSD::FSD ::fsd \
+ -title [mc "Load file - Virtual HW - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 1 -filetypes [list \
+ [list [mc "Virtual HW"] {*.vhw}] \
+ [list [mc "VH component"] {*.vhc}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ ::fsd setokcmd {
+ foreach filename [::fsd get] {
+ if {[${::X::actualProject} pale_load_scenarion $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ } {
+ ::X::recent_files_add 2 $filename
+ }
+ }
+ }
+
+ # Activate the dialog
+ ::fsd activate
+ }
+
+ ## Save virtual hardware scenario to a file
+ # @return void
+ proc __save_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ if {![$actualProject pale_save]} {
+ Sbar [mc "Unable to save Virtual HW connections"]
+ }
+ }
+
+ ## Save virtual hardware scenario under a different filename
+ # @return void
+ proc __save_as_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Create file selection dialog
+ catch {delete object ::fsd}
+ KIFSD::FSD ::fsd \
+ -title [mc "Save file - Virtual HW - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -initialfile [$actualProject pale_get_scenario_filename]\
+ -defaultmask 0 -multiple 1 -filetypes [list \
+ [list [mc "Virtual HW"] {*.vhw}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ ::fsd setokcmd {
+ set abort 0
+ set filename [::fsd get]
+
+ # Ask user for overwrite existing file
+ if {[file exists $filename]} {
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Do you want to overwrite it ?" [file tail $filename]]
+ ] != {yes}
+ } {
+ set abort 1
+ }
+ }
+
+ if {!$abort} {
+ if {![${::X::actualProject} pale_save_as $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to save file:\n\"%s\"" $filename]
+ } {
+ ::X::recent_files_add 2 $filename
+ }
+ }
+ }
+
+ # Activate the dialog
+ ::fsd activate
+ }
+
+ ## Remove all virtual hardware and forget VHW filename
+ # @return void
+ proc __remove_all_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Ask user for comfirmation
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Are you sure ?"] \
+ -message [mc "Do you really want to remove all virtual hardware from the current simulation scenario ?"]
+ ] != {yes}
+ } {
+ return
+ }
+
+ $actualProject pale_forget_all
+ }
+
+ ## Toggle fullscreen mode
+ # @return void
+ proc __toggle_fullscreen {} {
+ # Normal window
+ if {[wm attributes . -fullscreen]} {
+ if {[winfo exists .mainIconBar.fullscreen]} {
+ .mainIconBar.fullscreen configure -image ::ICONS::22::window_fullscreen
+ }
+ wm attributes . -fullscreen 0
+ # Fullscreen window
+ } {
+ if {[winfo exists .mainIconBar.fullscreen]} {
+ .mainIconBar.fullscreen configure -image ::ICONS::22::window_nofullscreen
+ }
+ wm attributes . -fullscreen 1
+ }
+
+ # Restore position of bottom pane
+ after 300 {
+ foreach project ${::X::openedProjects} {
+ $project bottomNB_redraw_pane
+ }
+ }
+ }
+
+ ## Invoke the special calculator
+ # @return void
+ proc __spec_calc {} {
+ variable spec_calc_objects ;# List: All special calculator objects
+
+ lappend spec_calc_objects [SpecCalc #auto]
+ }
+
+ ## Invoke RS232/UART debugger
+ # @return void
+ proc __rs232debugger {} {
+ variable rs232debugger_objects ;# List: All RS232 Debugger objects
+
+ lappend rs232debugger_objects [RS232Debugger #auto]
+ }
+
+ ## Invoke a functional diagram of the given type
+ # @parm Int type -
+ # @return void
+ proc __functional_diagram {type} {
+ }
+
+ ## Invoke a virtual terminal of the given type
+ # @parm Int type -
+ # @return void
+ proc __virtual_terminal {type} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ switch -- $type {
+ {u} {
+ $actualProject virtual_uart_termial_invoke_dialog
+ }
+ }
+ }
+}
diff --git a/lib/bottompanel/bottomnotebook.tcl b/lib/bottompanel/bottomnotebook.tcl
new file mode 100755
index 0000000..463f93d
--- /dev/null
+++ b/lib/bottompanel/bottomnotebook.tcl
@@ -0,0 +1,469 @@
+#!/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 bottom panel of the project tab
+# --------------------------------------------------------------------------
+
+# Import nesesary sources
+source "${::LIB_DIRNAME}/bottompanel/calculator.tcl" ;# Calculator
+source "${::LIB_DIRNAME}/bottompanel/todo.tcl" ;# Todo list
+source "${::LIB_DIRNAME}/bottompanel/graph.tcl" ;# Graph
+source "${::LIB_DIRNAME}/bottompanel/messages.tcl" ;# Messages
+source "${::LIB_DIRNAME}/bottompanel/terminal.tcl" ;# Terminal
+source "${::LIB_DIRNAME}/bottompanel/find_in_files.tcl" ;# Find in files
+source "${::LIB_DIRNAME}/bottompanel/cvarsview.tcl" ;# C variables
+
+class BottomNoteBook {
+
+ # Inherit content of some other clases
+ inherit Calculator Todo Simulator Graph Messages Terminal FindInFiles CVarsView
+
+ ## Public
+ public variable simulator_frame ;# Identifier of tab of NoteBook widget for simulator
+ public variable cvarsview_frame ;# Identifier of tab of NoteBook widget for c variables
+ public variable graph_frame ;# Identifier of tab of NoteBook widget for graph
+ public variable messages_frame ;# Identifier of tab of NoteBook widget for messages box
+ public variable todo_frame ;# Identifier of tab of NoteBook widget for todo box
+ public variable calculator_frame ;# Identifier of tab of NoteBook widget for calculator
+ public variable terminal_frame ;# Identifier of tab of NoteBook widget for terminal
+ public variable findinfiles_frame ;# Identifier of tab of NoteBook widget for terminal
+
+ ## Private
+ private variable pri_notebook ;# Identifier of NoteBook widget when panel is visible
+ private variable sec_notebook ;# Identifier of NoteBook widget when panel is hidden
+ private variable main_frame ;# Identifier of frame containing both NoteBooks
+
+ private variable panel_hidding_ena 1 ;# Is panel hidding enabled
+ private variable redraw_pane_in_progress 0 ;# Is panel pane redraw in progress
+ private variable parentPane ;# Identifier of parent pane
+ private variable last_PanelSize ;# Last panel height
+ private variable PanelVisible $CONFIG(BOTTOM_PANEL) ;# Is panel visible
+ private variable active_page $CONFIG(BOTTOM_PANEL_ACTIVE_PAGE) ;# Identifier of active NoteBook page
+ private variable PanelSize $CONFIG(BOTTOM_PANEL_SIZE) ;# Current panel height
+
+ ## object constructor
+ constructor {} {
+ # Validate and set active page
+ if {$active_page == {Terminal}} {
+ set active_page {Simulator}
+ } elseif {
+ [lsearch {Simulator CVarsView Graph Messages Todo Calculator FindInFiles} $active_page] == -1
+ } {
+ puts stderr "Invalid value of active page '$active_page', setting to {Simulator}"
+ set active_page {Simulator}
+ }
+ }
+
+ ## object destructor
+ destructor {
+ # Destroy GUI
+ destroy $main_frame
+ notebook_Sbar_unset {bottomnb}
+ }
+
+ ## Create Bottom NoteBook (This function must be called after contructor)
+ # @parm widget mainframe - Frame for bottom notebook
+ # @parm widget PaneWindow - parent pane window contaier
+ # @parm String todoText - content of todo text
+ # @parm List calculatorList - List of values for calculator (display content, radix, etc.)
+ # @parm List graph_config - Graph configuration list
+ # @return Widget - ID of frame containg both notebooks
+ public method initiate_BottomNoteBook {mainframe PaneWindow todoText calculatorList graph_config} {
+
+ # set parent pane window
+ set parentPane $PaneWindow
+
+ ## Create some widgets
+ # Frame for primary and secondary notebook
+ set main_frame $mainframe
+ # Primary notebook
+ set pri_notebook [NoteBook $main_frame.ntb_bottomNB_pri \
+ -side top -bd 1 \
+ -arcradius 4 -bg {#EEEEEE} \
+ -font [font create -family {helvetica} -size -12 -weight bold] \
+ ]
+ # Secondary notebook
+ set sec_notebook [NoteBook $main_frame.ntb_bottomNB_sec \
+ -side top \
+ -arcradius 4 \
+ -borderwidth 1 -bg {#EEEEEE} \
+ -font [font create -family {helvetica} -size -12 -weight bold] \
+ ]
+
+ # Register notebook status bar tips
+ notebook_Sbar_set {bottomnb} [list \
+ Simulator [mc "Simulator panel"] \
+ CVarsView [mc "List of variables defined in C program"] \
+ Graph [mc "Graph showing voltage levels"] \
+ Messages [mc "Compiler messages"] \
+ Todo [mc "Editable notepad"] \
+ Calculator [mc "Scientific calculator"] \
+ Terminal [mc "Linux terminal emulator"] \
+ FindInFiles [mc "Search string in files"] \
+ Hide [mc "Hide the panel"] \
+ Show [mc "Show the panel"] \
+ ]
+ $pri_notebook bindtabs <Enter> "notebook_Sbar bottomnb"
+ $pri_notebook bindtabs <Leave> "Sbar {} ;#"
+ $sec_notebook bindtabs <Enter> "notebook_Sbar bottomnb"
+ $sec_notebook bindtabs <Leave> "Sbar {} ;#"
+
+ ## create Primary NoteBook tabs
+ # Tab "Simulator"
+ set simulator_frame [$pri_notebook insert end {Simulator} \
+ -text [mc "Simulator"] \
+ -image ::ICONS::16::kcmmemory \
+ -raisecmd "$this bottomNB_set_active_page {Simulator}" \
+ -helptext [mc "Simulator panel %s" "(Ctrl+1)"] \
+ -createcmd [list $this CreateSimulatorGUI] \
+ ]
+ # Tab "C variables"
+ set cvarsview_frame [$pri_notebook insert end {CVarsView} \
+ -text [mc "C variables"] \
+ -image ::ICONS::16::player_playlist \
+ -raisecmd "$this bottomNB_set_active_page {CVarsView}" \
+ -helptext [mc "Variables from C source code %s" ""] \
+ -createcmd [list $this CreateCVarsViewGUI] \
+ ]
+ # Tab "Graph"
+ set graph_frame [$pri_notebook insert end {Graph} \
+ -text [mc "IO Ports"] \
+ -image ::ICONS::16::graph \
+ -raisecmd "$this bottomNB_set_active_page {Graph}" \
+ -helptext [mc "Graph showing state of MCU ports %s" "(Ctrl+2)"] \
+ -createcmd [list $this CreateGraphGUI] \
+ ]
+ # Tab "Messages"
+ set messages_frame [$pri_notebook insert end {Messages} \
+ -text [mc "Messages"] \
+ -image ::ICONS::16::kcmsystem \
+ -raisecmd "$this bottomNB_set_active_page {Messages}" \
+ -helptext [mc "Compiler messages %s" "(Ctrl+3)"] \
+ -createcmd [list $this CreateMessagesGUI] \
+ ]
+ # Tab "Notes"
+ set todo_frame [$pri_notebook insert end {Todo} \
+ -text [mc "Notes"] \
+ -image ::ICONS::16::camera_test \
+ -raisecmd "$this bottomNB_set_active_page {Todo}" \
+ -helptext [mc "Personal todo list & notepad %s" "(Ctrl+4)"]\
+ -createcmd [list $this CreateTodoGUI] \
+ ]
+ # Tab "Calculator"
+ set calculator_frame [$pri_notebook insert end {Calculator} \
+ -text [mc "Calculator"] \
+ -image ::ICONS::16::xcalc \
+ -raisecmd "$this bottomNB_set_active_page {Calculator}" \
+ -helptext [mc "Scientific calculator %s" "(Ctrl+5)"] \
+ -createcmd [list $this CreateCalculatorGUI] \
+ ]
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no terminal emulator
+ # Tab "Terminal"
+ set terminal_frame [$pri_notebook insert end {Terminal} \
+ -text [mc "Terminal"] \
+ -image ::ICONS::16::terminal \
+ -raisecmd "$this bottomNB_set_active_page {Terminal}" \
+ -helptext [mc "Terminal emulator %s" ""] \
+ -createcmd [list $this CreateTerminalEmulGUI] \
+ -state [expr {${::PROGRAM_AVALIABLE(urxvt)} ? "normal" : "disabled"}] \
+ ]
+ }
+ # Tab "Find in files"
+ set findinfiles_frame [$pri_notebook insert end {FindInFiles} \
+ -text [mc "Find in files"] \
+ -image ::ICONS::16::filefind \
+ -raisecmd "$this bottomNB_set_active_page {FindInFiles}"\
+ -helptext [mc "Find in files %s" ""] \
+ -createcmd [list $this CreateFindInFilesGUI] \
+ ]
+
+ # Tab "Hide"
+ $pri_notebook insert end {Hide} \
+ -text [mc "Hide"] \
+ -image ::ICONS::16::2downarrow \
+ -raisecmd "$this bottomNB_show_hide" \
+ -helptext [mc "Hide this panel"] \
+
+ ## Create Secondary NoteBook tabs
+ # tab "Simulator"
+ $sec_notebook insert end {Simulator} \
+ -text [mc "Simulator"] \
+ -image ::ICONS::16::kcmmemory \
+ -raisecmd "$this bottomNB_show_hide Simulator" \
+ -helptext [mc "Simulator panel %s" "(Ctrl+1)"]
+ # tab "C variables"
+ $sec_notebook insert end {CVarsView} \
+ -text [mc "C variables"] \
+ -image ::ICONS::16::player_playlist \
+ -raisecmd "$this bottomNB_show_hide CVarsView" \
+ -helptext [mc "Variables from C source code %s" ""]
+ # tab "Graph"
+ $sec_notebook insert end {Graph} \
+ -text [mc "IO Ports"] \
+ -image ::ICONS::16::graph \
+ -raisecmd "$this bottomNB_show_hide Graph" \
+ -helptext [mc "Graph showing state of MCU ports %s" "(Ctrl+2)"]
+ # tab "Messages"
+ $sec_notebook insert end {Messages} \
+ -text [mc "Messages"] \
+ -image ::ICONS::16::kcmsystem \
+ -raisecmd "$this bottomNB_show_hide Messages" \
+ -helptext [mc "Compiler messages %s" "(Ctrl+3)"]
+ # tab "Notes"
+ $sec_notebook insert end {Todo} \
+ -text [mc "Notes"] \
+ -image ::ICONS::16::camera_test \
+ -raisecmd "$this bottomNB_show_hide Todo" \
+ -helptext [mc "Personal todo list & notepad %s" "(Ctrl+4)"]
+ # tab "Calculator"
+ $sec_notebook insert end {Calculator} \
+ -text [mc "Calculator"] \
+ -image ::ICONS::16::xcalc \
+ -raisecmd "$this bottomNB_show_hide Calculator" \
+ -helptext [mc "Scientific calculator %s" "(Ctrl+5)"]
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no terminal emulator
+ # tab "Terminal"
+ $sec_notebook insert end {Terminal} \
+ -text [mc "Terminal"] \
+ -image ::ICONS::16::terminal \
+ -raisecmd "$this bottomNB_show_hide Terminal" \
+ -helptext [mc "Terminal emulator %s" ""] \
+ -state [expr {${::PROGRAM_AVALIABLE(urxvt)} ? "normal" : "disabled"}]
+ }
+ # tab "Find in files"
+ $sec_notebook insert end {FindInFiles} \
+ -text [mc "Find in files"] \
+ -image ::ICONS::16::filefind \
+ -raisecmd "$this bottomNB_show_hide FindInFiles" \
+ -helptext [mc "Find in files %s" ""] \
+ -createcmd [list $this CreateFindInFilesGUI]
+ # tab "Show"
+ $sec_notebook insert end {Show} \
+ -text [mc "Show"] \
+ -image ::ICONS::16::2uparrow \
+ -raisecmd "$this bottomNB_show_hide" \
+ -helptext [mc "Show this panel"]
+
+ # Prepare panel componenets but do not create GUI elements
+ PrepareCalculator $calculator_frame $calculatorList
+ PrepareGraph $graph_frame $graph_config
+ PrepareMessages $messages_frame
+ PrepareTodo $todo_frame $todoText
+ PrepareSimulator $simulator_frame
+ PrepareCVarsView $cvarsview_frame
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no terminal emulator
+ PrepareTerminal $terminal_frame
+ }
+ PrepareFindInFiles $findinfiles_frame
+
+
+ # take case of proper pane resizing
+ bind $parentPane <ButtonRelease-1> "$this bottomNB_panel_set_size"
+
+ # Show primary notebook if panel is visible or secondary notebook ohterwise
+ if {$PanelVisible != 0} {
+ pack $pri_notebook -expand 1 -fill both
+ $parentPane paneconfigure $main_frame -minsize 190
+ $parentPane configure -sashwidth 2
+
+ # Raise tab
+ catch {$pri_notebook raise $active_page}
+ } {
+ pack $sec_notebook -anchor nw -fill x -expand 1
+ $parentPane paneconfigure $main_frame -minsize 0
+ $parentPane configure -sashwidth 0
+ bind $parentPane <Button> {break}
+ set last_PanelSize $PanelSize
+ set PanelSize 24
+ }
+ }
+
+ ## Return true if the panel is visible
+ # @return bool result
+ public method isBottomPanelVisible {} {return $PanelVisible}
+
+ ## Return panel height
+ # @return int panle height
+ public method getBottomPanelSize {} {
+ if {$PanelVisible} {
+ return $PanelSize
+ } {
+ return $last_PanelSize
+ }
+ }
+
+ ## Return ID of active page of the NoteBook
+ # @return String Active page
+ public method getBottomPanelActivePage {} {return $active_page}
+
+ ## Set active page for both notebooks (primary and secondary)
+ # This function may also inform GUI of new active page about that it has became active
+ # @parm String pageName - ID of page to set
+ # @return void
+ public method bottomNB_set_active_page {pageName} {
+ switch -- $pageName {
+ Simulator {$this SimulatorTabRaised}
+ CVarsView {$this CVarsViewTabRaised}
+ Graph {$this GraphTabRaised}
+ Messages {$this MessagesTabRaised}
+ Todo {$this TodoTabRaised}
+ Calculator {$this CalculatorTabRaised}
+ FindInFiles {$this FindInFilesTabRaised}
+ }
+ set active_page $pageName
+ }
+
+ ## Show or hide the panel
+ # @parm String args = NULL - name of active page (show panel)
+ # @return void
+ public method bottomNB_show_hide args {
+
+ # If panel hidding is disabled -- abort
+ if {!$panel_hidding_ena} {return}
+
+ # Hide the panel
+ if {$PanelVisible} {
+ $parentPane paneconfigure $main_frame -minsize 0
+
+ # Ged rid of primary notebook
+ pack forget $pri_notebook ;# Hide primary notebook
+ set last_PanelSize $PanelSize ;# Save current panel size
+ set PanelSize 24 ;# Set New panel size
+ bottomNB_redraw_pane ;# Perform hidding
+
+ # Create and show secondary notebook
+ pack $sec_notebook -anchor nw -fill x -expand 1
+ $sec_notebook compute_size
+ set panel_hidding_ena 0
+ $sec_notebook raise $active_page
+ set panel_hidding_ena 1
+ $parentPane configure -sashwidth 0
+ bind $parentPane <Button> {break}
+
+ # Panel is now hidden
+ set PanelVisible 0
+
+ # Show the panel
+ } {
+ $parentPane paneconfigure $main_frame -minsize 190
+
+ # Hide secondary notebook
+ pack forget $sec_notebook
+
+ # Create and show primary notebook
+ set PanelSize $last_PanelSize ;# Restore panel size
+ bottomNB_redraw_pane ;# Perform showing
+ # Raise active page
+ if {$args == {}} {
+ $pri_notebook raise $active_page
+ } {
+ $pri_notebook raise $args
+ }
+ # Pack primary notebook
+ pack $pri_notebook -expand 1 -fill both
+ # Restore sash width
+ $parentPane configure -sashwidth 2
+ bind $parentPane <Button> {}
+
+ # Panel is now shown
+ set PanelVisible 1
+ }
+
+ update idle
+ $this editor_procedure {} Configure {}
+ }
+
+ ## Get true panel size and store it into variable PanelSize
+ # @return void
+ public method bottomNB_panel_set_size {} {
+ set PanelSize [lindex [$parentPane sash coord 0] 1]
+ set PanelSize [expr {[winfo height $parentPane] - $PanelSize}]
+
+ update idle
+ $this editor_procedure {} Configure {}
+ $this editor_procedure {} goto \
+ [$this editor_procedure {} get_current_line_number {}]
+ }
+
+ ## Move panel pane up by the given number of pixels
+ # @parm Int by - pixels
+ # @return void
+ public method bottomNB_move_pane_up {by} {
+ update idle
+ $parentPane sash place 0 0 [expr {[winfo height $parentPane] - $PanelSize - $by}]
+ }
+
+ ## Redraw panel pane
+ # @return void
+ public method bottomNB_redraw_pane {} {
+ update idle
+ $parentPane sash place 0 0 [expr {[winfo height $parentPane] - $PanelSize}]
+ }
+
+ ## Redraw panel pane on expose event
+ # @return void
+ public method bottomNB_redraw_pane_on_expose {} {
+ if {$redraw_pane_in_progress} {
+ after 50 "$this bottomNB_redraw_pane_on_expose"
+ return
+ }
+ set redraw_pane_in_progress 1
+
+ update idle
+ $parentPane sash place 0 0 [expr {[winfo height $parentPane] - $PanelSize}]
+ update idle
+
+ set redraw_pane_in_progress 0
+ }
+
+ ## Raise specified page
+ # This function should not be bypased
+ # @parm String page - ID of page to show
+ # @return void
+ public method bottomNB_show_up {page} {
+ if {$PanelVisible} {
+ $pri_notebook raise $page
+ } {
+ bottomNB_show_hide $page
+ }
+ }
+
+ ## Destroy current simulator control panel and create a new one
+ # @return void
+ public method simulator_itialize_simulator_control_panel {} {
+ foreach wdg [winfo children $simulator_frame] {
+ destroy $wdg
+ }
+ $this sumulator_clear_widgets
+ PrepareSimulator $simulator_frame
+ CreateSimulatorGUI
+ }
+
+ ## Destroy current graph panel and create a new one
+ # @return void
+ public method graph_itialize_simulator_graph_panel {graph_config} {
+ $this graph_change_mcu
+ }
+} \ No newline at end of file
diff --git a/lib/bottompanel/calculator.tcl b/lib/bottompanel/calculator.tcl
new file mode 100755
index 0000000..5196b40
--- /dev/null
+++ b/lib/bottompanel/calculator.tcl
@@ -0,0 +1,2071 @@
+#!/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
+#
+# --------------------------------------------------------------------------
+
+class Calculator {
+
+ common count 0 ;# counter of instances
+ # Font for numerical keypad
+ common large_font [font create \
+ -family {helveticat} \
+ -size -12 \
+ -weight {bold} \
+ ]
+
+ common oper_fg_color {#0000FF} ;# Foreground color for operator display
+ common error_bg_color {#FF6666} ;# Background color for display containing too many characters
+ common display_bg_color {#DDFFDD} ;# Background color for main display
+ common buffer_bg_color {#DDDDFF} ;# Background color for buffer display
+
+ # Variables related to object initialization
+ private variable parent ;# Teportary variable -- GUI parent
+ private variable calculatorList ;# Teportary variable -- COnfiguration list
+ private variable gui_initialized 0 ;# Bool: GUI created
+
+ # GUI variables
+ private variable calc_num_keypad ;# Container of left side of calc. (keypad)
+ private variable calc_num_display ;# Container for right side (displays etc.)
+ private variable calc_timers_calc ;# ID of label frame of timer preset calculator
+ private variable calc_display_widget ;# ID of main display widget
+ private variable calc_oper_widget ;# ID of operator display widget
+ private variable calc_buffer_widget ;# ID of buffer display widget
+ private variable timerscalc_THxDec_label ;# ID of THx (dec) label
+ private variable timerscalc_THxHex_label ;# ID of THx (hex) label
+ private variable timerscalc_THxOct_label ;# ID of THx (oct) label
+ private variable timerscalc_TLxDec_label ;# ID of TLx (dec) label
+ private variable timerscalc_TLxHex_label ;# ID of TLx (hex) label
+ private variable timerscalc_TLxOct_label ;# ID of TLx (oct) label
+ private variable timerscalc_RepeatDec_label ;# ID of Repeat (dec) label
+ private variable timerscalc_RepeatHex_label ;# ID of Repeat (hex) label
+ private variable timerscalc_RepeatOct_label ;# ID of Repeat (oct) label
+ private variable timerscalc_CorrectionDec_label ;# ID of Correction (dec) label
+ private variable timerscalc_CorrectionHex_label ;# ID of Correction (hex) label
+ private variable timerscalc_CorrectionOct_label ;# ID of Correction (oct) label
+ private variable timerscalc_freq_entry ;# ID of frequency entry widget
+ private variable timerscalc_mode_spinbox ;# ID of mode spinbox widget
+ private variable timerscalc_time_entry ;# ID of tim entry widget
+ private variable mem_entry_0 ;# ID of memory 0 entry widget
+ private variable mem_entry_1 ;# ID of memory 1 entry widget
+ private variable mem_entry_2 ;# ID of memory 2 entry widget
+
+ # Core variables
+ private variable base ;# Numeric base (Hex, Dec. Oct, Bin)
+ private variable last_base ;# Last numeric base
+ private variable angle ;# Angle unit (rad, deg, grad)
+ private variable last_angle ;# Last angle unit
+ private variable calc_oper {} ;# Chosen mathematical operation
+ private variable calc_oper_h ;# Human readible $calc_oper
+ private variable calc_last_oper ;# Last $calc_oper
+ private variable calc_display ;# Actual display text variable
+ private variable calc_buffer ;# Last display text variable
+ private variable calc_last_display ;# Var. for UNDO/REDO (takes back $calc_display)
+ private variable calc_last_buffer ;# Var. for UNDO/REDO (takes back $calc_buffer)
+ private variable ena_undo 0 ;# Undo enabled
+ private variable ena_redo 0 ;# Redo enabled
+ private variable after_eval 0 ;# Clear display if actual display val. is result of last operation
+ private variable scrollable_frame ;# Widget: Scrollable area (parent for all other widgets)
+ private variable horizontal_scrollbar ;# Widget: Horizontal scrollbar for scrollable area
+
+ # other public variables
+ private variable calc_idx ;# number of current instance
+ private variable timerscalc_validation_dis 1 ;# Disabled validation of timers calc
+
+ # definition of calculator keyboard
+ # {
+ # # row
+ # { # button
+ # {text path_part command_postfix
+ # columnspan rowspan
+ # helptext width
+ # height bgColor
+ # activeBackground bool_large_font
+ # }
+ # {separator}
+ # }
+ # }
+ common calculator_keyboard {
+ {
+ {{AND} {and} {calc_opr and 1} {} {}
+ {Bit-wise AND}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Bit-wise AND. Valid for integer operands only.}}
+ {{Sin} {S} {calc_opr Sin 1} {} {}
+ {Sine}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Sine}}
+ {{Cos} {Cs} {calc_opr Cos 1} {} {}
+ {Cosine}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Cosine}}
+ {{Tan} {T} {calc_opr Tan 1} {} {}
+ {Tangent}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Tangent}}
+ {{A} {A} {calc_val A} {} {} {} {} {} {5} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{F} {F} {calc_val F} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{/} {div} {calc_opr div 1} {} {} {} {} {} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ {{*} {mul} {calc_opr mul 1} {} {} {} {} {} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ {{-} {min} {calc_opr min 1} {} {} {} {} {} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ } {
+ {{OR} {or} {calc_opr or 1} {} {}
+ {Bit-wise OR}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Bit-wise OR. Valid for integer operands only.}}
+ {{ASin} {AS} {calc_opr ASin 1} {} {}
+ {Arc sine}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Arc sine. Argument should be in the range \[-1,1\].}}
+ {{ACos} {AC} {calc_opr ACos 1} {} {}
+ {Arc cosine}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Arc cosine. Argument should be in the range \[-1,1\].}}
+ {{ATan} {AT} {calc_opr ATan 1} {} {}
+ {Arc tangent}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Arc tangent}}
+
+ {{B} {B} {calc_val B} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{7} {7} {calc_val 7} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{8} {8} {calc_val 8} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{9} {9} {calc_val 9} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{+} {add} {calc_opr add 1} {} {2} {} {} {2} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ } {
+ {{NOT} {not} {calc_opr not 1} {} {}
+ {Bit-wise NOT}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Bit-wise NOT. Valid for integer operands only.}}
+ {{e**} {exp} {calc_opr Exp 1} {} {}
+ {Exponential of argument (e**arg)}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Exponential of argument (e**arg)}}
+ {{sqrt} {sqr} {calc_opr Sqr 1} {} {}
+ {Square root}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Square root. Argument must be non-negative.}}
+ {{pow} {power} {calc_opr pow 1} {} {}
+ {Power}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Computes the value of x raised to the power y. If x is negative, y must be an integer value.}}
+
+ {{C} {C} {calc_val C} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{4} {4} {calc_val 4} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{5} {5} {calc_val 5} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{6} {6} {calc_val 6} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ } {
+ {{XOR} {xor} {calc_opr xor 1} {} {}
+ {Bit-wise exclusive OR}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Bit-wise exclusive OR. Valid for integer operands only.}}
+ {{Log} {L} {calc_opr Log 1} {} {}
+ {Base 10 logarithm}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Returns the base 10 logarithm of argument. Argument must be a positive value.}}
+ {{Ln} {Ln} {calc_opr Ln 1} {} {}
+ {Natural logarithm}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Returns the natural logarithm of argument. Argument must be a positive value.}}
+ {{PI} {P} {calc_val PI} {} {}
+ {Constant Pi}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Constant Pi}}
+
+ {{D} {D} {calc_val D} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{1} {1} {calc_val 1} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{2} {2} {calc_val 2} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{3} {3} {calc_val 3} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{=} {=} {calc_Evaluate} {} {2} {} {} {2} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ } {
+ {{>>} {right} {calc_opr right 1} {} {}
+ {Right shift}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Right shift. Valid for integer operands only. A right shift always propagates the sign bit.}}
+ {{Mod} {M} {calc_opr mod 1} {} {}
+ {Modulo}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Computes remainder of integer division}}
+ {{UNDO} {U} {calc_UNDO} {} {}
+ {Undo last operation}
+ {5} {} {} {Calculator_GRAY} {#F8F8F8} 0
+ {Undo last operation. Not all operations are supported.}}
+ {{REDO} {RE} {calc_REDO} {} {}
+ {Take back last undo operation}
+ {5} {} {} {Calculator_GRAY} {#F8F8F8} 0
+ {Take back last undo operation. Not all operations are supported.}}
+
+ {{E} {E} {calc_val E} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{0} {0} {calc_val 0} {2} {} {} {5} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+
+ {{.} {dot} {calc_val .} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ }
+ }
+
+ ## object constructor
+ constructor {} {
+ # Initialize some variables
+ incr count ;# Instance counter
+ set calc_idx $count ;# Index of this object
+ set base Dec ;# Default numeric base
+ set angle rad ;# Default angle unit
+ set last_base $base ;# Last numeric base
+ set last_angle $angle ;# Last angle unit
+
+ # Configure ttk styles
+ ttk::style configure Calculator_Buffer.TEntry \
+ -fieldbackground $buffer_bg_color
+ ttk::style configure Calculator_Oper.TEntry \
+ -fieldbackground {#FFDDDD} \
+ -fieldforeground $oper_fg_color \
+ -justify center
+ ttk::style configure Calculator_OperError.TEntry\
+ -fieldbackground {#FFDDDD} \
+ -foreground {#FF0000} \
+ -justify center
+ ttk::style configure Calculator_Display.TEntry \
+ -fieldbackground $display_bg_color
+ ttk::style configure Calculator_Error.TEntry \
+ -fieldbackground $error_bg_color
+
+ ttk::style configure Calculator_GREEN.TButton -padding 2
+ ttk::style map Calculator_GREEN.TButton \
+ -background [list active {#AAFFAA} {!active !disabled} {#CCFFCC} disabled {#DDEEDD}]
+
+ ttk::style configure Calculator_RED.TButton -padding 2
+ ttk::style map Calculator_RED.TButton \
+ -background [list active {#FFAAAA} {!active !disabled} {#FFDDDD} disabled {#EEDDDD}]
+
+ ttk::style configure Calculator_CYAN.TButton -padding 2
+ ttk::style map Calculator_CYAN.TButton \
+ -background [list active {#88EEEE} {!active !disabled} {#AAFFFF} disabled {#DDEEEE}]
+
+ ttk::style configure Calculator_GRAY.TButton -padding 2
+ ttk::style map Calculator_GRAY.TButton \
+ -background [list active {#DDDDDD} {!active !disabled} {#F8F8F8} disabled {#EEEEEE}]
+
+ ttk::style configure Calculator_PURPLE.TButton -padding 2 -font $large_font
+ ttk::style map Calculator_PURPLE.TButton \
+ -background [list active {#AAAAFF} {!active !disabled} {#DDDDFF} disabled {#DDDDEE}]
+
+ ttk::style configure Calculator_YELLOW.TButton -padding 2 -font $large_font
+ ttk::style map Calculator_YELLOW.TButton \
+ -background [list active {#FFFFAA} {!active !disabled} {#FFFFDD} disabled {#EEEEDD}]
+ }
+
+ ## object destructor
+ destructor {
+ # Unallocate GUI related variables
+ catch {
+ unset ::Calculator::calc_base$calc_idx
+ unset ::Calculator::calc_angle$calc_idx
+ unset ::Calculator::calc_buffer$calc_idx
+ unset ::Calculator::calc_oper$calc_idx
+ unset ::Calculator::calc_displ$calc_idx
+ unset ::Calculator::calc_mem0_$calc_idx
+ unset ::Calculator::calc_mem1_$calc_idx
+ unset ::Calculator::calc_mem2_$calc_idx
+ }
+ }
+
+ ## Append given value to the end of the display
+ # Use carefully, it does not check value validity !
+ # @parm String value - value to append
+ # @return String - new display content
+ public method calc_val {value} {
+ # Read raw content of the main display
+ reread_display 1
+
+ # Insert PI
+ if {$value == {PI}} {
+ # Conver PI to selected numeric base
+ switch -- $base {
+ {Hex} {set value [NumSystem::dec2hex ${Angle::PI}]}
+ {Dec} {set value ${Angle::PI}}
+ {Oct} {set value [NumSystem::dec2oct ${Angle::PI}]}
+ {Bin} {set value [NumSystem::dec2bin ${Angle::PI}]}
+ }
+ # Save current values
+ set calc_last_display [reread_display] ;# Main display
+ set calc_last_buffer [reread_buffer] ;# Buffer
+ # Clear main display
+ set calc_display {}
+ # Save current opetaror
+ set calc_last_oper $calc_oper
+ enable_undo ;# enable UNDO operation
+
+ # Clear main display if current value is result of the last operation
+ } elseif {$after_eval} {
+ set calc_last_display $calc_display ;# Save current content of display
+ set calc_last_buffer {}
+ set calc_last_oper {}
+ set calc_display {}
+ set after_eval 0
+ enable_undo ;# enable UNDO operation
+ }
+
+ # Append given value to the end of main display
+ set tmp "$calc_display$value"
+ if {[calc_validate $calc_display_widget $tmp]} {
+ set ::Calculator::calc_displ$calc_idx $tmp
+
+ catch {
+ $calc_display_widget delete sel.first sel.last
+ }
+ }
+
+ $calc_display_widget icursor end
+ $calc_buffer_widget icursor end
+ return $calc_display
+ }
+
+ ## Choose mathematical operation
+ # @parm String operation - Selected operation
+ # @parm Bool external - Evaluate result
+ # @return void
+ public method calc_opr {operation external} {
+
+ # Save current operator and set the new one
+ set calc_last_oper $calc_oper
+ set calc_oper $operation
+ # Clear displays if external
+ if {$external} {
+ set calc_last_display [reread_display]
+ set calc_last_buffer [reread_buffer]
+ set calc_buffer $calc_display
+ set calc_display {}
+ enable_undo
+ rewrite_buffer
+ rewrite_display
+ }
+
+ # Evaluate specified operation
+ switch -- $operation {
+ {div} { ;# Division
+ set calc_oper_h {/}
+ }
+ {mul} { ;# Multiplication
+ set calc_oper_h {*}
+ }
+ {min} { ;# Subtraction
+ set calc_oper_h {-}
+ }
+ {add} { ;# Addition
+ set calc_oper_h {+}
+ }
+ {pow} { ;# Power
+ set calc_oper_h {**}
+ }
+ {mod} { ;# Modulo
+ set calc_oper_h {mod}
+ }
+ {and} { ;# Bit-wise and
+ set calc_oper_h {&}
+ }
+ {or} { ;# Bit-wise inclusive or
+ set calc_oper_h {|}
+ }
+ {xor} { ;# Bit-wise exclusive or
+ set calc_oper_h {^}
+ }
+ {right} { ;# Right shift
+ set calc_oper_h {>>}
+ }
+
+ {not} { ;# Bit-wise inversion
+ set calc_oper_h {~}
+ if {$external} {calc_Evaluate}
+ }
+ {Exp} { ;# Exponential of argument
+ set calc_oper_h {e**}
+ if {$external} {calc_Evaluate}
+ }
+ {Sqr} { ;# Square root
+ set calc_oper_h {sqrt}
+ if {$external} {calc_Evaluate}
+ }
+ {Log} { ;# Decimal logarithm
+ set calc_oper_h {lg}
+ if {$external} {calc_Evaluate}
+ }
+ {Ln} { ;# Natural logarithm
+ set calc_oper_h {ln}
+ if {$external} {calc_Evaluate}
+ }
+ {Sin} { ;# Sine
+ set calc_oper_h {sin}
+ if {$external} {calc_Evaluate}
+ }
+ {Cos} { ;# Cosine
+ set calc_oper_h {cos}
+ if {$external} {calc_Evaluate}
+ }
+ {Tan} { ;# Tangent
+ set calc_oper_h {tan}
+ if {$external} {calc_Evaluate}
+ }
+ {ASin} { ;# Arc sine
+ set calc_oper_h {asin}
+ if {$external} {calc_Evaluate}
+ }
+ {ACos} { ;# Arc cosine
+ set calc_oper_h {acos}
+ if {$external} {calc_Evaluate}
+ }
+ {ATan} { ;# Acr cotangent
+ set calc_oper_h {atan}
+ if {$external} {calc_Evaluate}
+ }
+ default { ;# No operand
+ set calc_oper_h {}
+ }
+ }
+
+ # Display selected operand
+ set ::Calculator::calc_oper$calc_idx $calc_oper_h
+ }
+
+ ## Perform operation with calulator memory
+ # @parm String action - "Save" (to main display) or "Load" (from main display)
+ # @parm Int cell - Index of memory cell
+ # @return void
+ public method mem {action cell} {
+ if {$action == {Save}} {
+ # Show message on status bar
+ Sbar [mc "Calculator: M%s saved" $cell]
+ # Save content of main display
+ set calc_mem [reread_display]
+ if {[regexp {\.0$} $calc_mem]} {
+ set calc_mem [string range $calc_mem 0 {end-2}]
+ }
+ set ::Calculator::calc_mem${cell}_$calc_idx $calc_mem
+ } {
+ # Load memory content into main display
+ set calc_display [subst "\$::Calculator::calc_mem${cell}_$calc_idx"]
+ rewrite_display
+ }
+ }
+
+ ## Perform evaluation of given mathematical expression
+ # @return void
+ public method calc_Evaluate {} {
+
+ ## Check for presence of nessesary values
+ # * For unary operations
+ set display [reread_display]
+ set buffer [reread_buffer]
+ if {$buffer == {} || $buffer == {-}} {
+ Sbar [mc "Calculator: Unable to evaluate, missing argument"]
+ return 0
+ }
+ if {$calc_oper == {}} {
+ Sbar [mc "Calculator: Unable to evaluate, missing operator"]
+ return 0
+ }
+ # * For binary operations
+ if {
+ $calc_oper == {div} || $calc_oper == {mul} ||
+ $calc_oper == {min} || $calc_oper == {add} ||
+ $calc_oper == {pow} || $calc_oper == {mod} ||
+ $calc_oper == {and} || $calc_oper == {or} ||
+ $calc_oper == {xor} || $calc_oper == {nand}
+ } {
+ # Check display value length
+ if {$display == {}} {
+ Sbar [mc "Calculator: Unable to evaluate, missing argument"]
+ return 0
+ }
+ }
+
+ # Make backup for display, buffer and operator
+ enable_undo ;# enable UNDO operation
+ set calc_last_display $display
+ set calc_last_buffer $buffer
+
+ # Load up content of buffer and display
+ read_buffer_inDec
+ read_display_inDec
+
+ # Perform evaluation in safe environment
+ if {[catch {
+ switch -- $calc_oper {
+ {and} { ;# Bit-wise and
+ set calc_display [expr {wide($calc_buffer) & wide($calc_display)}]
+ }
+ {or} { ;# Bit-wise or
+ set calc_display [expr {wide($calc_buffer) | wide($calc_display)}]
+ }
+ {xor} { ;# Bit-wise xor
+ set calc_display [expr {wide($calc_buffer) ^ wide($calc_display)}]
+ }
+ {right} { ;# Right shift
+ set tmp [expr {wide($calc_display)}]
+ if {$tmp > 0} {
+ set calc_display [expr {wide($calc_buffer) >> $tmp}]
+ } elseif {$tmp < 0} {
+ set calc_display [expr {wide($calc_buffer) << abs($tmp)}]
+ } else {
+ set calc_display [expr {wide($calc_buffer)}]
+ }
+ }
+ {mul} { ;# Multiplication
+ set calc_display [expr {$calc_buffer * $calc_display}]
+ }
+ {min} { ;# Subtraction
+ set calc_display [expr {$calc_buffer - $calc_display}]
+ }
+ {add} { ;# Addtion
+ set calc_display [expr {$calc_buffer + $calc_display}]
+ }
+ {mod} { ;# Modulo
+ set calc_display [expr {int(fmod($calc_buffer,$calc_display))}]
+ }
+ {pow} { ;# Power
+ set calc_display [expr {pow($calc_buffer, $calc_display)}]
+ }
+ {div} { ;# Division
+ if {$calc_display == 0} {
+ Sbar [mc "Calculator: WARNING result is +/- infinity => operation terminated !"]
+ return
+ }
+ if {![regexp {\.} $calc_buffer]} {
+ set calc_buffer "$calc_buffer.0"
+ }
+ set calc_display [expr {$calc_buffer / $calc_display}]
+ }
+ {not} { ;# Bit-wise inversion
+ set len [string length [format {%X} [expr {int($calc_buffer)}]]]
+ if {$len > 8} {
+ Sbar [mc "Calculator: This value is too high to invert (max. 0xFFFFFFFF)"]
+ return
+ }
+ incr len -1
+ set calc_display [expr {0x7FFFFFFF ^ int($calc_buffer)}]
+ set calc_display [format {%X} $calc_display]
+ set calc_display [string range $calc_display end-$len end]
+ set calc_display [expr "0x$calc_display"]
+ }
+ {Exp} { ;# Exponential of argument
+ set calc_display [expr {exp($calc_buffer)}]
+ }
+ {Sqr} { ;# Square root
+ set calc_display [expr {sqrt($calc_buffer)}]
+ }
+ {Log} { ;# Decimal logarithm
+ set calc_display [expr {log10($calc_buffer)}]
+ }
+ {Ln} { ;# Natiral logarithm
+ set calc_display [expr {log($calc_buffer)}]
+ }
+ {ASin} { ;# Arc sine
+ set calc_display [expr {asin($calc_buffer)}]
+ set calc_display [rad_to_Xangle $calc_display]
+ }
+ {ACos} { ;# Arc cosine
+ set calc_display [expr {acos($calc_buffer)}]
+ set calc_display [rad_to_Xangle $calc_display]
+ }
+ {ATan} { ;# Arc Tangent
+ set calc_display [expr {atan($calc_buffer)}]
+ set calc_display [rad_to_Xangle $calc_display]
+ }
+ {Sin} { ;# Sine
+ set calc_buffer [Xangle_to_rad $calc_buffer]
+ set calc_display [expr {sin($calc_buffer)}]
+ }
+ {Cos} { ;# Cosine
+ set calc_buffer [Xangle_to_rad $calc_buffer]
+ set calc_display [expr {cos($calc_buffer)}]
+ }
+ {Tan} { ;# Arc tangent
+ set calc_buffer [Xangle_to_rad $calc_buffer]
+ set calc_display [expr {tan($calc_buffer)}]
+ }
+ }
+ }]} {
+ # If error occured -> show error message
+ Sbar [mc "Calculator: ERROR (result value is out of allowed range)"]
+ return
+ }
+
+ # If result value contain exponent -> show error message
+ if {[regexp {e} $calc_display]} {
+ Sbar[mc "Calculator: Unable to evaluate, result value is too high"]
+ return
+ }
+
+ # Display result
+ set calc_buffer {}
+ set after_eval 1
+ rewrite_buffer
+ calc_opr {} 0
+ write_display_inXbase $calc_display
+ }
+
+ ## Safely clear display
+ # @return void
+ public method calc_ClearActual {} {
+ # enable UNDO operation
+ enable_undo
+ # save actual values
+ set calc_last_display [reread_display]
+ set calc_display {}
+ set calc_last_buffer [reread_buffer]
+ # show new values
+ rewrite_display
+ }
+
+ ## Safely clear display and buffer
+ # @return void
+ public method calc_Clear {} {
+ # enable UNDO operation
+ enable_undo
+ # save actual values
+ set calc_last_display [reread_display]
+ set calc_display {}
+ set calc_last_buffer [reread_buffer]
+ set calc_buffer {}
+ calc_opr {} 0
+ # show new values
+ rewrite_display
+ rewrite_buffer
+ }
+
+ ## Enable execution of UNDO operation and disable REDO
+ # @return void
+ private method enable_undo {} {
+ # set status
+ set ena_undo 1
+ set ena_redo 0
+ # enable/disable UNDO and REDO buttons
+ enable_buttons {U}
+ disable_buttons {RE}
+ }
+
+ ## Enable execution of REDO operation and disable UNDO
+ # @return void
+ private method enable_redo {} {
+ # set status
+ set ena_undo 0
+ set ena_redo 1
+ # enable/disable UNDO and REDO buttons
+ enable_buttons {RE}
+ disable_buttons {U}
+ }
+
+ ## Take back the last operation
+ # @return void
+ public method calc_UNDO {} {
+ # enable REDO operation
+ enable_redo
+ # ....
+ set after_eval 0
+ # save actual status and restore previous
+ calc_opr $calc_last_oper 0
+ set tmp [reread_display]
+ set calc_display $calc_last_display
+ set calc_last_display $tmp
+ set tmp [reread_buffer]
+ set calc_buffer $calc_last_buffer
+ set calc_last_buffer $tmp
+ # show new values
+ rewrite_display
+ rewrite_buffer
+ # inform user by starts bar
+ Sbar [mc "Calculator: UNDO: previous state was: %s %s %s" $calc_last_buffer $calc_last_oper $calc_last_display]
+ }
+
+ ## Take back the UNDO operation
+ # @return void
+ public method calc_REDO {} {
+ # enable UNDO operation
+ enable_undo
+ # save actual status and restore previous
+ calc_opr $calc_last_oper 0
+ set tmp [reread_display]
+ set calc_display $calc_last_display
+ set calc_last_display $tmp
+ set tmp [reread_buffer]
+ set calc_buffer $calc_last_buffer
+ set calc_last_buffer $tmp
+ # show new values
+ rewrite_display
+ rewrite_buffer
+ # inform user by starts bar
+ Sbar [mc "Calculator: REDO: previous state was: %s %s %s" $calc_last_buffer $calc_last_oper $calc_last_display]
+ }
+
+ ## Convert content of both displays and all merory cells using given command
+ # @parm String command - command to use for converion
+ # @return void
+ private method convert_displays {command} {
+
+ # Determinate what displays aren't empty
+ if {[reread_display] == {}} {set dis 0} {set dis 1}
+ if {[reread_buffer] == {}} {set buf 0} {set buf 1}
+
+ # Determinate what memory cells aren't empty
+ for {set i 0} {$i < 3} {incr i} {
+ set mem [[subst "\$mem_entry_$i"] get]
+ if {[string index $mem end] == {.}} {
+ append mem 0
+ }
+ set memory$i $mem
+ if {$mem == {} || $mem == 0} {
+ set mem$i 0
+ } {
+ set mem$i 1
+ }
+ }
+
+ # Convert all non empty displays
+ foreach cnd "$dis $buf $mem0 $mem1 $mem2" \
+ var {calc_display calc_buffer memory0 memory1 memory2} {
+ if {$cnd} {
+ if {[catch {
+ set $var [$command [subst "\$$var"]]
+ }]} {
+ Sbar [mc "Calculator: Value is too high to convert, value deleted !"]
+ set $var 0
+ }
+ }
+ }
+
+ # Display new content of memory cells
+ for {set i 0} {$i < 3} {incr i} {
+ [subst "\$mem_entry_$i"] delete 0 end
+ [subst "\$mem_entry_$i"] insert end [subst "\$memory$i"]
+ }
+ }
+
+ ## Switch numeric base
+ # @return void
+ public method cal_switchBase {} {
+
+ # Get chosen value
+ set base [subst "\$::Calculator::calc_base$calc_idx"]
+
+ # Convert display content to setected numeric system
+ if {$base == $last_base} {
+ set last_base $base
+ return
+ }
+
+ # Adjust value in display and buffer
+ if {[regexp {\.0$} $calc_display]} {
+ set calc_display [string range $calc_display 0 {end-2}]
+ }
+ if {[regexp {\.0$} $calc_buffer]} {
+ set calc_buffer [string range $calc_buffer 0 {end-2}]
+ }
+
+ # Covert content of all displays to new numeric base
+ switch -- $base {
+ {Hex} { ;# to Hexadecimal
+ enable_buttons {0 1 2 3 4 5 6 7 8 9 A B C D E F}
+ switch -- $last_base {
+ {Dec} {convert_displays NumSystem::dec2hex}
+ {Oct} {convert_displays NumSystem::oct2hex}
+ {Bin} {convert_displays NumSystem::bin2hex}
+ }
+ }
+ {Dec} { ;# to Decimal
+ disable_buttons {A B C D E F}
+ enable_buttons {0 1 2 3 4 5 6 7 8 9}
+ switch -- $last_base {
+ {Hex} {convert_displays NumSystem::hex2dec}
+ {Oct} {convert_displays NumSystem::oct2dec}
+ {Bin} {convert_displays NumSystem::bin2dec}
+ }
+ }
+ {Oct} { ;# to Octal
+ disable_buttons {8 9 A B C D E F}
+ enable_buttons {0 1 2 3 4 5 6 7}
+ switch -- $last_base {
+ {Hex} {convert_displays NumSystem::hex2oct}
+ {Dec} {convert_displays NumSystem::dec2oct}
+ {Bin} {convert_displays NumSystem::bin2oct}
+ }
+ }
+ {Bin} { ;# to Binary
+ disable_buttons {2 3 4 5 6 7 8 9 A B C D E F}
+ enable_buttons {0 1}
+ switch -- $last_base {
+ {Hex} {convert_displays NumSystem::hex2bin}
+ {Dec} {convert_displays NumSystem::dec2bin}
+ {Oct} {convert_displays NumSystem::oct2bin}
+ }
+ }
+ }
+
+ # Display new values
+ rewrite_display
+ rewrite_buffer
+
+ # set last value
+ set last_base $base
+ }
+
+ ## Disable buttons specified in the given list
+ # example: disable_buttons {1 2} ;# disable .calc_1_0 and .calc_2_0
+ # @return void
+ private method disable_buttons {buttons_list} {
+ foreach path $buttons_list {
+ $calc_num_keypad.calc_${path} \
+ configure -state disabled
+ }
+ }
+
+ ## Enable buttons specified in the given list
+ # example: enable_buttons {1 2} ;# enable .calc_1_0 and .calc_2_0
+ # @return void
+ private method enable_buttons {buttons_list} {
+ foreach path $buttons_list {
+ $calc_num_keypad.calc_${path} \
+ configure -state normal
+ }
+ }
+
+ ## Switch angle unit
+ # @return void
+ public method cal_switchAngle {} {
+
+ # Get chosen unit
+ set angle [subst "\$::Calculator::calc_angle$calc_idx"]
+
+ # Convert all displays
+ if {$angle != $last_angle} {
+ # Convert display if is not empty
+ if {[read_display_inDec] != {}} {
+ write_display_inXbase [Angle::${last_angle}2${angle} $calc_display]
+ }
+ # Convert buffer if is not empty
+ if {[read_buffer_inDec] != {}} {
+ write_buffer_inXbase [Angle::${last_angle}2${angle} $calc_buffer]
+ }
+ # Conver memory cells
+ for {set i 0} {$i <3} {incr i} {
+ # Get memory cell value
+ set mem [[subst "\$mem_entry_$i"] get]
+ # Adjust that value
+ if {[string index $mem end] == {.}} {
+ append mem 0
+ }
+ # Display new value
+ if {$mem != {}} {
+ set mem [Angle::${last_angle}2${angle} $mem]
+ [subst "\$mem_entry_$i"] delete 0 end
+ [subst "\$mem_entry_$i"] insert end $mem
+ }
+ }
+ }
+
+ # Set last unit
+ set last_angle $angle
+ }
+
+ ## Read content of main display in decimal system
+ # @return Float result
+ private method read_display_inDec {} {
+ # get display content
+ if {[reread_display] != {}} {
+ # convert to decimal value
+ if {$base != {Dec}} {
+ switch -- $base {
+ {Hex} { ;# from Hexadecimal
+ set calc_display [NumSystem::hex2dec $calc_display]
+ }
+ {Oct} { ;# from Octal
+ set calc_display [NumSystem::oct2dec $calc_display]
+ }
+ {Bin} { ;# from Binary
+ set calc_display [NumSystem::bin2dec $calc_display]
+ }
+ }
+ }
+ }
+ # done
+ return $calc_display
+ }
+
+ ## Write the given number (in dec) to main display (in selected base)
+ # @parm Float dec_content - number to display
+ # @return void
+ private method write_display_inXbase {dec_content} {
+
+ # If selected numeric base isn't Dec -> perform conversion
+ if {$base != {Dec}} {
+ switch -- $base {
+ {Hex} { ;# to Hexadecimal
+ if {[catch {
+ set calc_display [NumSystem::dec2hex $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, result is too high (cannot be displayed)"]
+ set calc_display 0
+ }
+ }
+ {Oct} { ;# to Octal
+ if {[catch {
+ set calc_display [NumSystem::dec2oct $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, result is too high (cannot be displayed)"]
+ set calc_display 0
+ }
+ }
+ {Bin} { ;# to Binary
+ if {[catch {
+ set calc_display [NumSystem::dec2bin $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, result is too high (cannot be displayed)"]
+ set calc_display 0
+ }
+ }
+ }
+ # If selected numeric base is Dec -> do nothing
+ } {
+ set calc_display $dec_content
+ }
+
+ # display (new) value
+ rewrite_display
+ }
+
+ ## Read content of buffer in decimal system
+ # @return Float result
+ private method read_buffer_inDec {} {
+ # Get content buffer display
+ if {[reread_buffer] != {}} {
+ # Convert to decimal value
+ if {$base != {Dec}} {
+ switch -- $base {
+ {Hex} { ;# from Hexadecimal
+ set calc_buffer [NumSystem::hex2dec $calc_buffer]
+ }
+ {Oct} { ;# from Octal
+ set calc_buffer [NumSystem::oct2dec $calc_buffer]
+ }
+ {Bin} { ;# from BInary
+ set calc_buffer [NumSystem::bin2dec $calc_buffer]
+ }
+ }
+ }
+ }
+ # done
+ return $calc_buffer
+ }
+
+ ## Write the given number (in dec) to buffer display (in selected base)
+ # @parm Float dec_content - number to display
+ # @return void
+ private method write_buffer_inXbase {dec_content} {
+
+ # If selected numeric base isn't Dec -> perform conversion
+ if {$base != {Dec}} {
+ switch -- $base {
+ {Hex} { ;# to Hexadecimal
+ if {[catch {
+ set calc_buffer [NumSystem::dec2hex $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, value is too high"]
+ set calc_buffer 0
+ }
+ }
+ {Oct} { ;# to Octal
+ if {[catch {
+ set calc_buffer [NumSystem::dec2oct $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, value is too high"]
+ set calc_buffer 0
+ }
+ }
+ {Bin} { ;# to Binary
+ if {[catch {
+ set calc_buffer [NumSystem::dec2bin $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, value is too high"]
+ set calc_buffer 0
+ }
+ }
+ }
+ # If selected numeric base is Dec -> do nothing
+ } {
+ set calc_buffer $dec_content
+ }
+
+ # display (new) value
+ rewrite_buffer
+ }
+
+ ## Write adjusted content of variable calc_display to main display widget
+ # @return void
+ private method rewrite_display {} {
+ # Adust content of source variable
+ if {[regexp {\.0$} $calc_display]} {
+ set calc_display [string range $calc_display 0 {end-2}]
+ }
+ # Show its content
+ set ::Calculator::calc_displ$calc_idx $calc_display
+ }
+
+ ## Write adjusted content of variable calc_buffer to buffer display widget
+ # @return void
+ private method rewrite_buffer {} {
+ # Adust content of source variable
+ if {[regexp {\.0$} $calc_buffer]} {
+ set calc_buffer [string range $calc_buffer 0 {end-2}]
+ }
+ # Show its content
+ set ::Calculator::calc_buffer$calc_idx $calc_buffer
+ }
+
+ ## Read true content of main display widget converted
+ # @parm args = False - adjust to float
+ # @return Float - content of the main display
+ private method reread_display args {
+
+ # Get content of the widget
+ set calc_display [$calc_display_widget get]
+ regsub {\,} $calc_display {.} calc_display
+
+ # Adhust to float (if requested)
+ if {$args != 1} {
+ if {[regexp {^\.} $calc_display]} {
+ set calc_display "0$calc_display"
+ } elseif {[regexp {\.$} $calc_display]} {
+ append calc_display 0
+ }
+ if {[string first {.} $calc_display] == -1} {
+ append calc_display {.0}
+ }
+ }
+
+ # Remove trailing '.0'
+ if {[regexp {^\.0$} $calc_display]} {
+ set calc_display {}
+ }
+
+ # Return result
+ return $calc_display
+ }
+
+ ## Read true content of buffer display widget converted
+ # @return Float - content of the buffer
+ private method reread_buffer {} {
+
+ # Get content of the widget
+ set calc_buffer [$calc_buffer_widget get]
+ regsub {\,} $calc_buffer {.} calc_buffer
+
+ # Adhust to float
+ if {[regexp {^\.} $calc_buffer]} {
+ set calc_buffer "0$calc_buffer"
+ } elseif {[regexp {\.$} $calc_buffer]} {
+ append calc_buffer 0
+ }
+ if {[string first {.} $calc_buffer] == -1} {
+ append calc_buffer {.0}
+ }
+
+ # Remove trailing '.0'
+ if {[regexp {^\.0$} $calc_buffer]} {
+ set calc_buffer {}
+ }
+
+ # Return result
+ return $calc_buffer
+ }
+
+ ## Covert given angle to current angle unit
+ # @parm Float dec_angle - angle to convert in decimal
+ # @return Float - angle in radians
+ private method Xangle_to_rad {dec_angle} {
+ # If current angle unit isn't radians -> perform converison
+ if {$angle != {rad}} {
+ # From grad
+ if {$angle == {grad}} {
+ set dec_angle [Angle::grad2rad $dec_angle]
+ # From degrees
+ } {
+ set dec_angle [Angle::deg2rad $dec_angle]
+ }
+ }
+ # return result
+ return $dec_angle
+ }
+
+ ## Convert given angle in radians to current angle unit
+ # @parm Float dec_angle - angle to conver in radians (decimal)
+ # @return Float - converted angle
+ private method rad_to_Xangle {dec_angle} {
+ # If current angle unit isn't radians -> perform converison
+ if {$angle != {rad}} {
+ # To grad
+ if {$angle == {grad}} {
+ set dec_angle [Angle::rad2grad $dec_angle]
+ # To degrees
+ } {
+ set dec_angle [Angle::rad2deg $dec_angle]
+ }
+ }
+ # return result
+ return $dec_angle
+ }
+
+ ## Validate display content
+ # @parm Widget widget - entry widget
+ # @parm String content - content to validate
+ # @return bool - result
+ public method calc_validate {widget content} {
+
+ # Set default background color for that widget
+ if {$widget == $calc_display_widget} {
+ $widget configure -style Calculator_Display.TEntry
+ } elseif {$widget == $calc_buffer_widget} {
+ $widget configure -style Calculator_Buffer.TEntry
+ } else {
+ $widget configure -style TEntry
+ }
+
+ # Valid if content is empty
+ set len [string length $content]
+ if {$len == 0 || $content == {-}} {
+ return 1
+ }
+
+ # Invalid if content is too wide
+ if {$len > 40} {
+ Sbar [mc "Calculator: ERROR, value is too high"]
+ if {[string length [$widget get]] > 13} {
+ $widget configure -style Calculator_Error.TEntry
+ }
+ return 0
+ }
+
+ # Adjust content
+ regsub {\,} $content {.} content
+ if {[regexp {\.$} $content]} {
+ append content 0
+ }
+
+ # Check for valid numeric base
+ switch -- $base {
+ {Hex} {set content [NumSystem::ishex $content]}
+ {Dec} {set content [NumSystem::isdec $content]}
+ {Oct} {set content [NumSystem::isoct $content]}
+ {Bin} {set content [NumSystem::isbin $content]}
+ default {set content 0}
+ }
+
+ # Evaluate filan result
+ if {$content} {
+ if {$len > 13} {
+ $widget configure -style Calculator_Error.TEntry
+ }
+ return 1
+ } {
+ Sbar [mc "Calculator: Trying to insert invalid value"]
+ return 0
+ }
+ }
+
+ ## Validate content of operator diaplay
+ # @parm String content - string to validate
+ # @return Bool - result of validation
+ public method calc_oper_validate {content} {
+
+ # Check for length
+ if {[string length $content] > 4} {
+ return 0
+ }
+
+ # Check for allowed content
+ switch -- $content {
+ {/} {set calc_oper {div}}
+ {*} {set calc_oper {mul}}
+ {-} {set calc_oper {min}}
+ {+} {set calc_oper {add}}
+ {**} {set calc_oper {pow}}
+ {mod} {set calc_oper {mod}}
+ {&} {set calc_oper {and}}
+ {|} {set calc_oper {or}}
+ {^} {set calc_oper {xor}}
+ {>>} {set calc_oper {right}}
+ {~} {set calc_oper {not}}
+ {e**} {set calc_oper {Exp}}
+ {sqrt} {set calc_oper {Sqr}}
+ {lg} {set calc_oper {Log}}
+ {ln} {set calc_oper {Ln}}
+ {sin} {set calc_oper {Sin}}
+ {cos} {set calc_oper {Cos}}
+ {tan} {set calc_oper {Tan}}
+ {asin} {set calc_oper {ASin}}
+ {acos} {set calc_oper {ACos}}
+ {atan} {set calc_oper {ATan}}
+ default {
+ # Set foteground color to #FF0000 if content is invalid
+ set calc_oper {}
+ $calc_oper_widget configure -style Calculator_OperError.TEntry
+ return 1
+ }
+ }
+
+ # Set foreground color to default and return result (True)
+ $calc_oper_widget configure -style Calculator_Oper.TEntry
+ return 1
+ }
+
+ ## Negate content of the main display
+ # @return void
+ public method calc_NegateDis {} {
+ # Empty display -> abort
+ if {[reread_display] == {}} {
+ return
+
+ # Negate value
+ } {
+ if {[regexp {^\-} $calc_display]} {
+ set calc_display [string range $calc_display 1 end]
+ } {
+ set calc_display "-$calc_display"
+ }
+ }
+
+ # Write result
+ rewrite_display
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - parent widget (some frame)
+ # @parm List _calculatorList - List of initial values (displays,, memory, radix, angle unit)
+ # @return void
+ public method PrepareCalculator {_parent _calculatorList} {
+ set parent $_parent
+ set calculatorList $_calculatorList
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method CalculatorTabRaised {} {
+ $calc_display_widget selection range 0 end
+ $calc_display_widget icursor end
+ focus $calc_display_widget
+ }
+
+ ## Initialize calculator GUI
+ # @return void
+ public method CreateCalculatorGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Create scrollable area
+ set scrollable_frame [ScrollableFrame $parent.scrollable_frame \
+ -xscrollcommand "$this calc_gui_scroll_set" \
+ ]
+ set horizontal_scrollbar [ttk::scrollbar $parent.horizontal_scrollbar \
+ -orient horizontal -command "$scrollable_frame xview" \
+ ]
+ pack $scrollable_frame -fill both -side bottom -expand 1
+ set parent [$scrollable_frame getframe]
+
+ # LEFT HALF
+
+ # create numeric keypad
+ set calc_num_keypad [frame $parent.calc_num_keypad]
+ makeKeypad $calc_num_keypad $calculator_keyboard
+
+
+ # RIGHT HALF
+
+ # create display
+ set calc_num_display [frame $parent.calc_num_display]
+ set frame0 [frame $calc_num_display.calc_num_display0]
+ set frame1 [frame $calc_num_display.calc_num_display1]
+
+ # Buffer display
+ set calc_buffer_widget [ttk::entry $frame0.calc_buffer \
+ -textvariable ::Calculator::calc_buffer$calc_idx \
+ -validate key \
+ -validatecommand "$this calc_validate %W %P" \
+ -width 13 \
+ -style Calculator_Buffer.TEntry \
+ ]
+ DynamicHelp::add $frame0.calc_buffer -text [mc "Buffer display"]
+ setStatusTip -widget $calc_buffer_widget \
+ -text [mc "Calculator buffer"]
+ # Operator display
+ set calc_oper_widget [ttk::entry $frame0.calc_oper \
+ -textvariable ::Calculator::calc_oper$calc_idx \
+ -validate all \
+ -width 3 \
+ -validatecommand "$this calc_oper_validate %P" \
+ -style Calculator_Oper.TEntry \
+ ]
+ DynamicHelp::add $frame0.calc_oper -text [mc "Selected operation"]
+ setStatusTip -widget $calc_oper_widget \
+ -text [mc "Selected operation"]
+ # Main display
+ set calc_display_widget [ttk::entry $frame0.calc_displ \
+ -textvariable ::Calculator::calc_displ$calc_idx \
+ -validate key \
+ -validatecommand "$this calc_validate %W %P" \
+ -width 13 \
+ -style Calculator_Display.TEntry \
+ ]
+ DynamicHelp::add $frame0.calc_displ -text [mc "Main display"]
+ setStatusTip -widget $calc_display_widget \
+ -text [mc "Main display"]
+ # Pack displays
+ pack $calc_buffer_widget -side left
+ pack $calc_oper_widget -side left
+ pack $calc_display_widget -side left
+ # Create binding for displays
+ bind $calc_buffer_widget <KP_Enter> "$this calc_Evaluate"
+ bind $calc_oper_widget <KP_Enter> "$this calc_Evaluate"
+ bind $calc_display_widget <KP_Enter> "$this calc_Evaluate"
+ bind $calc_buffer_widget <Return> "$this calc_Evaluate"
+ bind $calc_oper_widget <Return> "$this calc_Evaluate"
+ bind $calc_display_widget <Return> "$this calc_Evaluate"
+
+
+ ## Create: numeric base and angle unit switch + CA + C
+ frame $frame1.lf
+ # Numeric base switch
+ pack [ttk::combobox $frame1.lf.calc_base_CB \
+ -state readonly \
+ -values {Hex Dec Oct Bin} \
+ -textvariable ::Calculator::calc_base$calc_idx \
+ -width 4 \
+ ] -side left
+ bind $frame1.lf.calc_base_CB <<ComboboxSelected>> "$this cal_switchBase"
+ DynamicHelp::add $frame1.lf.calc_base_CB -text [mc "Numeric base"]
+ setStatusTip -widget $frame1.lf.calc_base_CB \
+ -text [mc "Numeric base"]
+ # Angle unit switch
+ pack [ttk::combobox $frame1.lf.calc_angle_CB \
+ -state readonly \
+ -values {rad deg grad} \
+ -textvariable ::Calculator::calc_angle$calc_idx \
+ -width 4 \
+ ] -side left
+ bind $frame1.lf.calc_angle_CB <<ComboboxSelected>> "$this cal_switchAngle"
+ DynamicHelp::add $frame1.lf.calc_angle_CB -text [mc "Angle unit"]
+ setStatusTip -widget $frame1.lf.calc_angle_CB \
+ -text [mc "Angle unit"]
+ pack $frame1.lf -side left -padx 5
+
+ frame $frame1.rf
+ # Button "Clear"
+ pack [ttk::button $frame1.rf.calc_Clear \
+ -text {C} \
+ -command "$this calc_Clear" \
+ -width 3 \
+ ] -side left
+ DynamicHelp::add $frame1.rf.calc_Clear \
+ -text [mc "Clear both displays"]
+ setStatusTip -widget $frame1.rf.calc_Clear \
+ -text [mc "Clear both displays"]
+ # Button "Clear actual"
+ pack [ttk::button $frame1.rf.calc_Clear_act \
+ -text {CA} \
+ -command "$this calc_ClearActual" \
+ -width 3 \
+ ] -side left
+ DynamicHelp::add $frame1.rf.calc_Clear_act \
+ -text [mc "Clear main display"]
+ setStatusTip -widget $frame1.rf.calc_Clear_act \
+ -text [mc "Clear main display"]
+ # Button "Negate"
+ pack [ttk::button $frame1.rf.calc_Negate_dis \
+ -text {+/-} \
+ -command "$this calc_NegateDis" \
+ -width 3 \
+ ] -side left
+ DynamicHelp::add $frame1.rf.calc_Negate_dis \
+ -text [mc "Negate value in main display"]
+ setStatusTip -widget $frame1.rf.calc_Negate_dis \
+ -text [mc "Negate value in main display"]
+ pack $frame1.rf -side right -padx 5
+
+ # Create calculator memory cells
+ for {set i 0} {$i < 3} {incr i} {
+ # Determinate ID of target frame
+ set frame_id [frame $calc_num_display.calc_num_display[expr $i + 2]]
+ # Label "Mx:"
+ pack [Label $frame_id.calc_mem_label_${i} \
+ -text "M$i: " -helptext [mc "Memory bank %s" $i]\
+ ] -side left
+ setStatusTip -widget $frame_id.calc_mem_label_${i} \
+ -text [mc "Memory bank %s" $i]
+ # Entry widget
+ set entry [ttk::entry $frame_id.calc_mem_entry_${i} \
+ -textvariable ::Calculator::calc_mem${i}_${calc_idx} \
+ -validate all \
+ -validatecommand "$this calc_validate %W %P" \
+ ]
+ DynamicHelp::add $frame_id.calc_mem_entry_${i} -text [mc "Memory bank %s" $i]
+ pack $entry -side left
+ set mem_entry_$i $entry
+ setStatusTip -widget $entry -text [mc "Memory bank %s" $i]
+ # Button "Save"
+ pack [ttk::button $frame_id.calc_mem_save_button_${i} \
+ -text [mc "Save"] \
+ -command "$this mem Save $i" \
+ -width 5 \
+ ] -side left
+ DynamicHelp::add $frame_id.calc_mem_save_button_${i} \
+ -text [mc "Save content of main display to this memory bank %s" $i]
+ setStatusTip -widget $frame_id.calc_mem_save_button_${i} \
+ -text [mc "Save content of main display to this memory bank %s" $i]
+ # Button "Load"
+ pack [ttk::button $frame_id.calc_mem_load_button_${i} \
+ -text [mc "Load"] \
+ -command "$this mem Load $i" \
+ -width 5 \
+ ] -side left
+ DynamicHelp::add $frame_id.calc_mem_load_button_${i} \
+ -text [mc "Load content of this bank into main display"]
+ setStatusTip -widget $frame_id.calc_mem_load_button_${i} \
+ -text [mc "Load content of memory bank %s into calculator main display" $i]
+ }
+
+ bind $mem_entry_0 <Up> "focus $mem_entry_2"
+ bind $mem_entry_0 <Down> "focus $mem_entry_1"
+
+ bind $mem_entry_1 <Up> "focus $mem_entry_0"
+ bind $mem_entry_1 <Down> "focus $mem_entry_2"
+
+ bind $mem_entry_2 <Up> "focus $mem_entry_1"
+ bind $mem_entry_2 <Down> "focus $mem_entry_0"
+
+
+ # TIMERS CALC
+
+ set calc_timers_calc [ttk::labelframe $parent.calc_timers_calc -text [mc "Timers preset"]]
+ makeTimersCalc $calc_timers_calc
+
+
+ # INNER INITIALIZATION
+
+ # pack "left side" of calculator
+ pack $calc_num_keypad -side left
+
+ # pack "right side" of calculator
+ for {set i 0} {$i < 5} {incr i} {
+ if {$i == 1} {
+ pack $calc_num_display.calc_num_display${i} -pady 10
+ } {
+ pack $calc_num_display.calc_num_display${i}
+ }
+ }
+ pack $calc_num_display -side left -padx 10
+
+ # pack timres calc
+ pack $calc_timers_calc -side left -expand 0 -anchor nw
+
+ ## save data given by $calculatorList
+ # "$base $angle $calc_display $calc_oper $calc_buffer $calc_mem0 $calc_mem1 $calc_mem2"
+ set base [lindex $calculatorList 0]
+ set angle [lindex $calculatorList 1]
+ if {
+ $base != {Hex} && $base != {Dec} &&
+ $base != {Oct} && $base != {Bin}
+ } {
+ set base [lindex ${X::project_edit_defaults} {3 1}]
+ puts stderr [mc "Invalid numerical base: '%s'" $base]
+ }
+ if {$angle != {rad} && $angle != {deg} && $angle != {grad}} {
+ puts stderr [mc "Invalid angle unit: '%s'" $angle]
+ set angle [lindex ${X::project_edit_defaults} {4 1}]
+ }
+ set ::Calculator::calc_base$calc_idx $base
+ set ::Calculator::calc_angle$calc_idx $angle
+
+ set last_base $base
+ set last_angle $angle
+
+ # Enable/Disable buttons on numeric keypad
+ switch -- $base {
+ {Hex} {
+ enable_buttons {0 1 2 3 4 5 6 7 8 9 A B C D E F}
+ disable_buttons {U RE}}
+ {Dec} {
+ enable_buttons {0 1 2 3 4 5 6 7 8 9}
+ disable_buttons {A B C D E F U RE}}
+ {Oct} {
+ enable_buttons {0 1 2 3 4 5 6 7}
+ disable_buttons {8 9 A B C D E F U RE}}
+ {Bin} {
+ enable_buttons {0 1}
+ disable_buttons {2 3 4 5 6 7 8 9 A B C D E F U RE}}
+ }
+
+ # Fill displays
+ set calc_display [lindex $calculatorList 2]
+ rewrite_display
+ calc_opr [lindex $calculatorList 3] 0
+ set calc_buffer [lindex $calculatorList 4]
+ rewrite_buffer
+ set ::Calculator::calc_mem0_$calc_idx [lindex $calculatorList 5]
+ set ::Calculator::calc_mem1_$calc_idx [lindex $calculatorList 6]
+ set ::Calculator::calc_mem2_$calc_idx [lindex $calculatorList 7]
+
+ # Set frequenci and mode in timers calculator
+ set freq [lindex $calculatorList 8]
+ set mode [lindex $calculatorList 10]
+ if {$freq == {} || [regexp {^\d\+$} $freq] || $freq < 0 || $freq > 99999} {
+ set freq 12000
+ }
+ if {$mode != 0 && $mode != 1 && $mode != 2} {
+ set mode 0
+ }
+ $timerscalc_freq_entry insert 0 $freq
+ $timerscalc_time_entry insert 0 [lindex $calculatorList 9]
+ $timerscalc_mode_spinbox delete 0 end
+ $timerscalc_mode_spinbox insert 0 $mode
+
+ # Unset teportary variables
+ unset parent
+ unset calculatorList
+ }
+
+ ## Get calculator list for later initialization
+ # @return List - resulting list of values
+ public method get_calculator_list {} {
+ if {!$gui_initialized} {CreateCalculatorGUI}
+ return [list $base $angle \
+ [$calc_display_widget get] \
+ $calc_oper \
+ [$calc_buffer_widget get] \
+ [subst "\$::Calculator::calc_mem0_$calc_idx"] \
+ [subst "\$::Calculator::calc_mem1_$calc_idx"] \
+ [subst "\$::Calculator::calc_mem2_$calc_idx"] \
+ [$timerscalc_freq_entry get] \
+ [$timerscalc_time_entry get] \
+ [$timerscalc_mode_spinbox get]]
+ }
+
+ ## Validate and evaluate content of Frequency entry (timers calculator)
+ # @parm String content - String to validate (and evaluate)
+ # @return Bool - result of validation
+ public method calc_timerscalc_freq_validate {content} {
+ # If validation disabled -> abort
+ if {$timerscalc_validation_dis} {
+ return 1
+ }
+ # If content is decimal number (max 5. digits) -> evaluate and return True
+ if {[regexp {^\d*$} $content] && ([string length $content] < 6)} {
+ calc_timerscalc_evaluate \
+ $content \
+ [$timerscalc_time_entry get] \
+ [$timerscalc_mode_spinbox get] \
+
+ return 1
+ }
+ # Otherwise -> return False
+ Sbar [mc "Calculator - timers preset: you are trying to insert an invalid value"]
+ return 0
+ }
+
+ ## Validate and evaluate content of Mode entry (timers calculator)
+ # @parm String content - String to validate (and evaluate)
+ # @return Bool - result of validation
+ public method calc_timerscalc_mode_validate {content} {
+ # If validation disabled -> abort
+ if {$timerscalc_validation_dis} {
+ return 1
+ }
+ # If the given value is one of {0 1 2} the evaluate and return True
+ if {[regexp {^\d?$} $content]} {
+ if {$content > 2} {
+ return 0
+ }
+ calc_timerscalc_evaluate \
+ [$timerscalc_freq_entry get] \
+ [$timerscalc_time_entry get] \
+ $content
+ return 1
+ }
+ # Otherwise -> return False
+ Sbar [mc "Calculator - timers preset: you are trying to insert an invalid value"]
+ return 0
+ }
+
+ ## Validate and evaluate content of Time entry (timers calculator)
+ # @parm String content - String to validate (and evaluate)
+ # @return Bool - result of validation
+ public method calc_timerscalc_time_validate {content} {
+ # If validation disabled -> abort
+ if {$timerscalc_validation_dis} {
+ return 1
+ }
+ # If content is decimal number (max 9. digits) -> evaluate and return True
+ if {[regexp {^\d*$} $content] && ([string length $content] < 10)} {
+ calc_timerscalc_evaluate \
+ [$timerscalc_freq_entry get] \
+ $content \
+ [$timerscalc_mode_spinbox get]
+ return 1
+ }
+ # Otherwise -> return False
+ Sbar [mc "Calculator - timers preset: you are trying to insert an invalid value"]
+ return 0
+ }
+
+ ## Highlight result of timer preset calculator
+ # @parm Bool valid - highlight for valid results
+ # @return void
+ private method calc_timerscalc_highlight {valid} {
+
+ # List of widgets to highlight
+ set widgets "
+ $timerscalc_THxDec_label
+ $timerscalc_THxHex_label
+ $timerscalc_THxOct_label
+ $timerscalc_TLxDec_label
+ $timerscalc_TLxHex_label
+ $timerscalc_TLxOct_label
+ $timerscalc_RepeatDec_label
+ $timerscalc_RepeatHex_label
+ $timerscalc_RepeatOct_label
+ $timerscalc_CorrectionDec_label
+ $timerscalc_CorrectionHex_label
+ $timerscalc_CorrectionOct_label
+ "
+
+ # Perform highlighting
+ if {$valid} {
+ foreach widget $widgets {
+ $widget configure -state normal
+ }
+ } {
+ foreach widget $widgets {
+ $widget configure -state disabled
+ }
+ }
+ }
+
+ ## Evaluate tmers preset (timers preset calculator)
+ # @parm Int freq - Frequency
+ # @parm Int time - Time in miliseconds
+ # @parm Int mode - Mode {0 1 2}
+ # @return Bool - Resulting status
+ private method calc_timerscalc_evaluate {freq time mode} {
+
+ # Set default results
+ set TLx 0
+ set THx 0
+ set repeat 0
+ set correction 0
+
+ # Check for validity of given values
+ if {$freq == {} || $freq == 0 || $time == {} || $mode == {} } {
+ set mode {invalid}
+ } {
+ # Compute time in machine cycles
+ set time [expr {int($time * (12000.0 / $freq))}]
+ }
+
+ # Perform computation for the given mode
+ switch -- $mode {
+ 0 {
+ # Determinate apparent number of repeats
+ set repeat [expr {($time >> 13) + 1}]
+ # Compute tempotary results
+ if {[expr {!($time & 0x1FFF)}]} {
+ incr repeat -1
+ set stepsPerIter 0x1FFF
+ } {
+ set stepsPerIter [expr {$time / $repeat}]
+ set tmp [expr {0x2000 - $stepsPerIter}]
+ set TLx [expr {$tmp & 0x1F}]
+ set THx [expr {$tmp >> 5}]
+ set correction [expr {$time - ((0x1FFF - $tmp) * $repeat)}]
+ }
+ }
+ 1 {
+ # Determinate apparent number of repeats
+ set repeat [expr {($time >> 16) + 1}]
+ # Compute tempotary results
+ if {[expr {!($time & 0xFFFF)}]} {
+ incr repeat -1
+ set stepsPerIter 0xFFFF
+ } {
+ set stepsPerIter [expr {$time / $repeat}]
+ set tmp [expr {0x10000 - $stepsPerIter}]
+ set TLx [expr {$tmp & 0xFF}]
+ set THx [expr {$tmp >> 8}]
+ set correction [expr {$time - ((0x10000 - $tmp) * $repeat)}]
+ }
+ }
+ 2 {
+ # Determinate apparent number of repeats
+ set repeat [expr {($time >> 8) + 1}]
+ # Compute tempotary results
+ if {[expr {!($time & 0xFF)}]} {
+ incr repeat -1
+ set stepsPerIter 0xFF
+ } {
+ set stepsPerIter [expr {$time / $repeat}]
+ set TLx [expr {0x100 - $stepsPerIter}]
+ set THx $TLx
+ set correction [expr {$time - ((0xFF - $THx) * $repeat)}]
+ }
+ }
+ {invalid} { ;# Invalid input data
+ calc_timerscalc_highlight 0
+ }
+ default { ;# Something went wrong
+ error "Calculator error: Invalid timer mode $mode"
+ return 0
+ }
+ }
+
+ # If pre-computation was performed succesfully -- finish the results
+ if {$mode != {invalid}} {
+ # Highlight results as valid
+ calc_timerscalc_highlight 1
+
+ # Perform correction
+ if {$correction >= $stepsPerIter} {
+ incr repeat [expr {$correction / $stepsPerIter}]
+ set correction [expr {$correction % $stepsPerIter}]
+ }
+ }
+
+ # Check for allowed length of results (string representation)
+ if {
+ [string length [format "%o" $repeat]] > 6
+ ||
+ [string length [format "%o" $correction]] > 6
+ } {
+ set TLx 0
+ set THx 0
+ set repeat 0
+ set correction 0
+ calc_timerscalc_highlight 0
+ Sbar [mc "Calculator: Unable to evaluate, result value is too high"]
+ }
+
+ ## Write results
+ # THx values
+ $timerscalc_THxDec_label configure -text $THx
+ $timerscalc_THxHex_label configure -text [format "%X" $THx]
+ $timerscalc_THxOct_label configure -text [format "%o" $THx]
+ # TLx values
+ $timerscalc_TLxDec_label configure -text $TLx
+ $timerscalc_TLxHex_label configure -text [format "%X" $TLx]
+ $timerscalc_TLxOct_label configure -text [format "%o" $TLx]
+ # Repeat values
+ $timerscalc_RepeatDec_label configure -text $repeat
+ $timerscalc_RepeatHex_label configure -text [format "%X" $repeat]
+ $timerscalc_RepeatOct_label configure -text [format "%o" $repeat]
+ # Correction values
+ $timerscalc_CorrectionDec_label configure -text $correction
+ $timerscalc_CorrectionHex_label configure -text [format "%X" $correction]
+ $timerscalc_CorrectionOct_label configure -text [format "%o" $correction]
+
+ return 1
+ }
+
+ ## Create widgets of timers preset calculator
+ # @parm widget parent - parent contaner (some frame)
+ # @return void
+ private method makeTimersCalc {parent} {
+ # TOP HALF
+ set top_frame [frame $parent.calc_timerscalc_top_frame]
+ # frequency
+ grid [label $top_frame.calc_timerscalc_freq_label \
+ -text [mc "Frequency \[kHz\]"] \
+ ] -row 0 -column 0 -sticky w
+ set timerscalc_freq_entry [ttk::entry \
+ $top_frame.calc_timerscalc_freq_entry \
+ -width 5 \
+ -validate all \
+ -validatecommand "$this calc_timerscalc_freq_validate %P" \
+ ]
+ grid $timerscalc_freq_entry -row 0 -column 1 -sticky we
+ # mode
+ grid [label $top_frame.calc_timerscalc_mode_label \
+ -text [mc "Mode"] \
+ ] -row 0 -column 2 -sticky w
+ set timerscalc_mode_spinbox [spinbox \
+ $top_frame.calc_timerscalc_mode_spinbox \
+ -bg {#FFFFFF} -highlightthickness 0 \
+ -from 0 -to 2 -width 1 -validate key \
+ -vcmd "$this calc_timerscalc_mode_validate %P" \
+ ]
+ grid $timerscalc_mode_spinbox -row 0 -column 3 -sticky we
+ # time
+ grid [label $top_frame.calc_timerscalc_time_label \
+ -text [mc "Time \[us\]"] \
+ ] -row 1 -column 0 -sticky w
+ set timerscalc_time_entry [ttk::entry \
+ $top_frame.calc_timerscalc_time_entry \
+ -width 8 \
+ -validate all \
+ -validatecommand "$this calc_timerscalc_time_validate %P" \
+ ]
+ grid $timerscalc_time_entry -row 1 -column 1 -sticky we -columnspan 3
+
+ # BOTTOM HALF
+ set bottom_frame [frame $parent.calc_timerscalc_bottom_frame]
+
+ # "dec" "hex" "oct"
+ grid [label $bottom_frame.calc_timerscalc_dec_label \
+ -text [mc "DEC"] -font $::smallfont -anchor e \
+ -highlightthickness 0 \
+ ] -row 0 -column 1 -ipadx 12
+ grid [label $bottom_frame.calc_timerscalc_hex_label \
+ -text [mc "HEX"] -font $::smallfont -anchor e \
+ -highlightthickness 0 \
+ ] -row 0 -column 2 -ipadx 12
+ grid [label $bottom_frame.calc_timerscalc_oct_label \
+ -text [mc "OCT"] -font $::smallfont -anchor e \
+ -highlightthickness 0 \
+ ] -row 0 -column 3 -ipadx 12
+
+ # "THx" "TLx" "Repeat" "Correction"
+ grid [label $bottom_frame.calc_timerscalc_thx_label \
+ -text "THx" \
+ ] -row 1 -column 0 -sticky w
+ grid [label $bottom_frame.calc_timerscalc_tlx_label \
+ -text "TLx" \
+ ] -row 2 -column 0 -sticky w
+ grid [label $bottom_frame.calc_timerscalc_repeat_label \
+ -text [mc "Repeats"] \
+ ] -row 3 -column 0 -sticky w
+ grid [label $bottom_frame.calc_timerscalc_correction_label \
+ -text [mc "Correction"] \
+ ] -row 4 -column 0 -sticky w
+
+ # THx values
+ set timerscalc_THxDec_label [label \
+ $bottom_frame.calc_timerscalc_THxDec_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_THxHex_label [label \
+ $bottom_frame.calc_timerscalc_THxHex_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_THxOct_label [label \
+ $bottom_frame.calc_timerscalc_THxOct_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+
+ # TLx values
+ set timerscalc_TLxDec_label [label \
+ $bottom_frame.calc_timerscalc_TLxDec_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_TLxHex_label [label \
+ $bottom_frame.calc_timerscalc_TLxHex_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_TLxOct_label [label \
+ $bottom_frame.calc_timerscalc_TLxOct_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+
+ # Repeat values
+ set timerscalc_RepeatDec_label [label \
+ $bottom_frame.calc_timerscalc_RepeatDec_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_RepeatHex_label [label \
+ $bottom_frame.calc_timerscalc_RepeatHex_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_RepeatOct_label [label \
+ $bottom_frame.calc_timerscalc_RepeatOct_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+
+ # Correction values
+ set timerscalc_CorrectionDec_label [label \
+ $bottom_frame.calc_timerscalc_CorrectionDec_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_CorrectionHex_label [label \
+ $bottom_frame.calc_timerscalc_CorrectionHex_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_CorrectionOct_label [label \
+ $bottom_frame.calc_timerscalc_CorrectionOct_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+
+ # Show widgets
+ grid $timerscalc_THxDec_label -row 1 -column 1 -sticky e
+ grid $timerscalc_THxHex_label -row 1 -column 2 -sticky e
+ grid $timerscalc_THxOct_label -row 1 -column 3 -sticky e
+ grid $timerscalc_TLxDec_label -row 2 -column 1 -sticky e
+ grid $timerscalc_TLxHex_label -row 2 -column 2 -sticky e
+ grid $timerscalc_TLxOct_label -row 2 -column 3 -sticky e
+ grid $timerscalc_RepeatDec_label -row 3 -column 1 -sticky e
+ grid $timerscalc_RepeatHex_label -row 3 -column 2 -sticky e
+ grid $timerscalc_RepeatOct_label -row 3 -column 3 -sticky e
+ grid $timerscalc_CorrectionDec_label -row 4 -column 1 -sticky e
+ grid $timerscalc_CorrectionHex_label -row 4 -column 2 -sticky e
+ grid $timerscalc_CorrectionOct_label -row 4 -column 3 -sticky e
+
+ # Make widgets in table as small as possible
+ foreach widget "
+ $bottom_frame.calc_timerscalc_dec_label
+ $bottom_frame.calc_timerscalc_hex_label
+ $bottom_frame.calc_timerscalc_oct_label
+ $bottom_frame.calc_timerscalc_thx_label
+ $bottom_frame.calc_timerscalc_tlx_label
+ $bottom_frame.calc_timerscalc_repeat_label
+ $bottom_frame.calc_timerscalc_correction_label
+ $timerscalc_THxDec_label
+ $timerscalc_THxHex_label
+ $timerscalc_THxOct_label
+ $timerscalc_TLxDec_label
+ $timerscalc_TLxHex_label
+ $timerscalc_TLxOct_label
+ $timerscalc_RepeatDec_label
+ $timerscalc_RepeatHex_label
+ $timerscalc_RepeatOct_label
+ $timerscalc_CorrectionDec_label
+ $timerscalc_CorrectionHex_label
+ $timerscalc_CorrectionOct_label
+ " {
+ $widget configure -bd 0 -relief raised -pady 0 -highlightthickness 0
+ }
+
+ # Pack frames
+ pack $top_frame -padx 5 -pady 2
+ pack $bottom_frame -padx 5 -pady 2
+
+ # Highlight calculator results as invalid
+ calc_timerscalc_highlight 0
+ set timerscalc_validation_dis 0
+ }
+
+ ## Create calculator keypad
+ # @parm widget parent - target contaner (some frame)
+ # @parm List definition - keypad definition (see class header)
+ # @return void
+ private method makeKeypad {parent definition} {
+ # Local variables
+ set row 0 ;# Current row in the grid
+
+ # Oterate over row definitions in the given keypad definition
+ foreach line $definition {
+ # Local variables
+ set col 0 ;# current column in the grid
+
+ # Iterate over button definitions in the row
+ foreach item $line {
+ if {$item == "separator"} {continue}
+
+ # Inicalize array of button features
+ for {set i 0} {$i < 13} {incr i} {
+ set parm($i) [lindex $item $i]
+ }
+
+ if {[lsearch -ascii -exact {A B C D E} $parm(0)] != -1} {
+ incr col
+ }
+
+ # Initialize default values for some items
+ foreach i {3 4 7} {
+ if {$parm($i) == {}} {set parm($i) 1}
+ }
+ if {$parm(6) == {}} {set parm(6) 2}
+ if {$parm(8) == {}} {set parm(8) 0}
+ if {$parm(9) == {}} {set parm(9) {#FFFFFF}}
+ if {$parm(10) == {}} {set parm(10) {#FFFFFF}}
+
+ if {[string index $parm(9) 0] == {#}} {
+ set parm(9) {Calculator}
+ }
+
+ # Set button ID
+ set path "$parent.calc_$parm(1)"
+ # Create button
+ ttk::button $path \
+ -text $parm(0) \
+ -command "$this $parm(2)" \
+ -width $parm(6) \
+ -style $parm(9).TButton
+# -activebackground $parm(10) \
+# -height $parm(7) \
+ DynamicHelp::add $path -text [mc $parm(5)]
+ # Confugure button
+# if {$parm(11) == 1} {$path configure -font $large_font -pady 2}
+ if {$parm(12) != {}} {
+ setStatusTip -widget $path -text [mc $parm(12)]
+ }
+
+ if {$parm(3) > 1} {
+ set sticky {we}
+ } elseif {$parm(4) > 1} {
+ set sticky {ns}
+ } else {
+ set sticky {}
+ }
+
+ # Show button
+ grid $path \
+ -columnspan $parm(3) \
+ -rowspan $parm(4) \
+ -sticky $sticky \
+ -padx 2 \
+ -pady 2 \
+ -column $col \
+ -row $row
+
+ # Incremet number of current column
+ incr col $parm(3)
+ }
+ # Incremet number of current row
+ incr row
+ }
+
+ grid columnconfigure $parent 4 -minsize 10
+ }
+
+ ## Adjust scrollbar for scrollable area
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method calc_gui_scroll_set {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $horizontal_scrollbar]} {
+ pack forget $horizontal_scrollbar
+ update
+ }
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $horizontal_scrollbar]} {
+ pack $horizontal_scrollbar -fill x -side top -before $scrollable_frame
+ }
+ $horizontal_scrollbar set $frac0 $frac1
+ update
+ }
+ }
+}
diff --git a/lib/bottompanel/cvarsview.tcl b/lib/bottompanel/cvarsview.tcl
new file mode 100755
index 0000000..fbc5dd2
--- /dev/null
+++ b/lib/bottompanel/cvarsview.tcl
@@ -0,0 +1,1303 @@
+#!/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 GUI interface designed for the bottom panel to show and
+# manipulate contents of variables in a running C program on simulated 8051
+# --------------------------------------------------------------------------
+
+class CVarsView {
+ ## COMMON
+ # Normal font fot the text widget
+ common text_wdg_font_n [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight normal \
+ -slant roman \
+ ]
+ # Bold font for the text widget
+ common text_wdg_font_b [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ -slant roman \
+ ]
+ # Italic font for the text widget
+ common text_wdg_font_i [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight normal \
+ -slant italic \
+ ]
+ # Background color for selected lines
+ common color_selected_line {#CCCCFF}
+
+ private variable main_frame ;# Widget: Main frame
+
+ # Variables related to object initialization
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ private variable panedwindow ;# Widget: Paned window for local and global variables
+ # Int: Last paned window sash position
+ private variable panel_sash_position [lindex $::CONFIG(C_VARS_VIEW_CONF) 0]
+
+ private variable local_variables_nlist {} ;# List of Strings: Names of all local variables
+ private variable local_variables {} ;# List of Lists: Detail definition of all local variables
+ private variable local_addresses {} ;# List of Lists: Addresses of all local variables
+ private variable local_addresses_list {} ;# List of Lists: {scope name level block}
+
+ private variable global_variables_nlist {} ;# List of Strings: Names of all global variables
+ private variable global_variables {} ;# List of Lists: Detail definition of all global variables
+ private variable global_addresses {} ;# List of Lists: Addresses of all global variables
+ private variable global_addresses_list {} ;# List of Lists: {scope name level block}
+ private variable global_displayed {} ;# List of Integers: Indexes of displayed variables
+
+ private variable help_window_frame {} ;# Widget: Main frame for the help window
+
+ private variable text_widget_local ;# Widget: Text widget for local variables
+ private variable text_widget_global ;# Widget: Text widget for global variables
+ private variable current_level {} ;# Int: Current code level (determinated by simulator)
+ private variable current_block {} ;# Int: Current code level (determinated by simulator)
+
+ private variable validation_ena 1 ;# Bool: Entries validation and synchronization enabled
+
+ private variable search_entry_Local ;# Widget: Search entry for local variables
+ private variable search_clear_Local ;# Widget: Clear button for search entry box for local variables
+ private variable search_entry_Global ;# Widget: Search entry for global variables
+ private variable search_clear_Global ;# Widget: Clear button for search entry box for global variables
+ private variable search_val_in_progress 0 ;# Bool: Search is in progress
+
+ private variable selected_line_global 0 ;# Int: Number of currently selected line in global variables (0 == nothig selected)
+ private variable selected_line_local 0 ;# Int: Number of currently selected line in local variables (0 == nothig selected)
+
+ constructor {} {
+ }
+
+ destructor {
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @return void
+ public method PrepareCVarsView {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method CVarsViewTabRaised {} {
+ }
+
+ ## Create GUI of this tab
+ # @return void
+ public method CreateCVarsViewGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ ## Create GUI of main frame
+ set main_frame [frame $parent.main_frame]
+ set panedwindow [panedwindow $main_frame.pw \
+ -sashwidth 5 -showhandle 0 \
+ -opaqueresize 1 -orient horizontal \
+ ]
+
+ # Create part containing local variables
+ set pane [create_list_of_variables Local]
+# $panedwindow add $pane
+# $panedwindow paneconfigure $pane -minsize 200
+
+ # Create part containing global variables
+ set pane [create_list_of_variables Global]
+ $panedwindow add $pane
+ $panedwindow paneconfigure $pane -minsize 200
+
+ # Pack main GUI parts of the panel
+ pack $panedwindow -fill both -expand 1
+ pack $main_frame -fill both -expand 1
+
+ # Restore sash position
+ cvarsview_redraw_pane
+
+ # Load CDB file if simulator is engaged and C language is used
+ if {[$this cget -programming_language] && [$this is_frozen]} {
+ set filename [$this simulator_get_cdb_filename]
+ if {[catch {
+ set file [open $filename r]
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to read file\n'%s'"] $filename
+ } {
+ cvarsview_load_cdb $file
+ close $file
+ }
+ }
+ }
+
+ ## Restore paned window sash position
+ # @return void
+ public method cvarsview_redraw_pane {} {
+ if {!$gui_initialized} {return}
+# update idle
+# $panedwindow sash place 0 $panel_sash_position 0
+ }
+
+ ## Get panel configuration list
+ # @return List - Panel config
+ public method cvarsview_get_config {} {
+ if {$gui_initialized} {
+# set panel_sash_position [lindex [$panedwindow sash coord 0] 0]
+ }
+ return [list $panel_sash_position]
+ }
+
+ ## Search for certain variable by its name
+ # @parm String type - Basic variable type specification ("Global" or "Local")
+ # @parm String string - Variable name
+ # @return Bool - allways 1
+ public method cvarsview_search {type string} {
+ # Lock this function
+ if {$search_val_in_progress} {return 0}
+ set search_val_in_progress 1
+
+ # Empty string given
+ if {![string length $string]} {
+ [subst "\$search_entry_$type"] configure -style TEntry
+ [subst "\$search_clear_$type"] configure -state disabled
+ set search_val_in_progress 0
+ return 1
+ }
+ [subst "\$search_clear_$type"] configure -state normal
+
+ ## Perform search
+ set idx 0
+ set found 0
+ # Global variable
+ if {$type == {Global}} {
+ foreach name $global_variables_nlist {
+ if {![string first $string $name] && [lsearch $global_displayed $idx] != -1} {
+ set found 1
+ break
+ }
+ incr idx
+ }
+ # Local variable
+ } {
+ }
+
+
+ # Variable found
+ if {$found} {
+ cvarsview_select_line $type [expr {[lsearch $global_displayed $idx] + 1}] 1
+ [subst "\$search_entry_$type"] configure -style StringFound.TEntry
+ # Variable not found
+ } {
+ [subst "\$search_entry_$type"] configure -style StringNotFound.TEntry
+ }
+
+
+ # Unlock this function
+ set search_val_in_progress 0
+ return 1
+ }
+
+ ## Select line in the text widget
+ # @parm String type - Basic variable type specification ("Global" or "Local")
+ # @parm Int line_number - Number of line to select (1 .. infinity)
+ # @parm Bool nofocus - Do not focus the entrybox
+ # @return void
+ public method cvarsview_select_line {type line_number nofocus} {
+ cvarsview_unselect_line $type
+
+ # Line with a global variable
+ if {$type == {Global}} {
+ set max [llength $global_displayed]
+ if {$line_number > $max} {
+ return
+ }
+
+ set selected_line_global $line_number
+ $text_widget_global tag add tag_current_line $line_number.0 $line_number.0+1l
+ $text_widget_global see $line_number.0
+ incr line_number -1
+ set eid [lindex $global_displayed $line_number]
+ $text_widget_global.e_$eid configure \
+ -bg $color_selected_line \
+ -disabledbackground $color_selected_line
+ if {!$nofocus} {
+ focus $text_widget_global.e_$eid
+ }
+
+ # Line with a local variable
+ } {
+ }
+ }
+
+ ## Unselect line in the text widget
+ # @parm String type - Basic variable type specification ("Global" or "Local")
+ # @return void
+ public method cvarsview_unselect_line {type} {
+ # View with a global variable
+ if {$type == {Global}} {
+ if {$selected_line_global != 0} {
+ incr selected_line_global -1
+ $text_widget_global.e_[lindex $global_displayed $selected_line_global] configure \
+ -bg white -disabledbackground white
+ }
+ $text_widget_global tag remove tag_current_line 0.0 end
+ set selected_line_global 0
+ # View with a local variable
+ } {
+ }
+ }
+
+ ## Select line above the current one
+ # @parm Bool isglobal - Global scope
+ # @parm Int lines - Distance
+ # @return void
+ public method cvarsview_selection_up {isglobal lines} {
+ if {$isglobal} {
+ if {$selected_line_global == 0} {
+ return
+ }
+ set max [llength $global_displayed]
+ set target_line $selected_line_global
+
+ incr target_line -$lines
+ while {$target_line < 1} {
+ incr target_line $max
+ }
+
+ cvarsview_select_line Global $target_line 0
+ }
+ }
+
+ ## Select line below the current one
+ # @parm Bool isglobal - Global scope
+ # @parm Int lines - Distance
+ # @return void
+ public method cvarsview_selection_down {isglobal lines} {
+ if {$isglobal} {
+ if {$selected_line_global == 0} {
+ return
+ }
+ set max [llength $global_displayed]
+ set target_line $selected_line_global
+
+ incr target_line $lines
+ while {$target_line > $max} {
+ incr target_line -$max
+ }
+
+ cvarsview_select_line Global $target_line 0
+ }
+ }
+
+ ## Open the helpwindow for certain variable
+ # @parm Int id - Variable ID
+ # @parm Bool isglobal - Related to global scope variable
+ # @return void
+ public method cvarsview_create_help_window {id isglobal} {
+# set help_window_frame [frame .cvarsview_help_window -bg {#BBBBFF}]
+#
+# if {$isglobal} {
+# set variable_def [lindex $global_variables $id]
+# pack [label $help_window_frame.header \
+# -text [lindex $variable_def 1] \
+# -bg {#BBBBFF} \
+# ] -anchor w
+#
+# set var_det_frame [frame $help_window_frame.details_frame -bg {#FFFFFF}]
+# pack $var_det_frame -fill both -padx 2 -pady 2
+#
+# grid [label $var_det_frame.value_lbl \
+# -text "Value:" \
+# ] -row 0 -column 0 -columnspan 3 -sticky w
+#
+# }
+#
+# # lappend global_variables [list \
+# # $scope $name \
+# # [lindex $type_record 0] [lindex $type_record end] \
+# # [lrange $type_record 1 end-1] $address_space \
+# # $onstack $stack \
+# # $registers 0 \
+# # 0 \
+# # ]
+ }
+
+ ## Move with the help window
+ # @parm Bool isglobal - Related to global scope variable
+ # @parm Int X - Absolute X position
+ # @parm Int Y - Absolute Y position
+ # @return void
+ public method cvarsview_help_window_move {isglobal X Y} {
+ if {[winfo exists $help_window_frame]} {
+ incr X 10
+ incr Y 10
+ place $help_window_frame -x $X -y $Y -anchor sw
+ raise $help_window_frame
+ }
+ }
+
+ ## Hide the help window
+ # @parm Bool isglobal - Related to global scope variable
+ # @return void
+ public method cvarsview_help_window_hide {isglobal} {
+ if {[winfo exists $help_window_frame]} {
+ destroy $help_window_frame
+ }
+ }
+
+ ## Create panel with list of global or local variables
+ # @parm String type - Basic variable type specification ("Global" or "Local")
+ # @return void
+ private method create_list_of_variables {type} {
+ set local_frame [frame $main_frame.var_${type}_frame]
+
+ # Create the top frame
+ set top_frame [frame $local_frame.top_frame]
+ pack [label $top_frame.header \
+ -text "$type static scalar variables" \
+ -anchor w -justify left \
+ ] -side left
+
+ # Create search frame
+ set search_frame [frame $top_frame.search_frame]
+ pack [label $search_frame.search_lbl \
+ -text [mc "Search:"] \
+ ] -side left
+ set search_entry_$type [ttk::entry $search_frame.search_ent \
+ -validate all \
+ -validatecommand "$this cvarsview_search $type %P" \
+ ]
+ pack $search_frame.search_ent -side left
+ set search_clear_$type [ttk::button $search_frame.search_clr_but\
+ -image ::ICONS::16::clear_left \
+ -style Flat.TButton \
+ -command "$search_frame.search_ent delete 0 end" \
+ -state disabled \
+ ]
+ pack $search_frame.search_clr_but -side left
+
+ # Pack top frame
+ pack $search_frame -side right
+ pack $top_frame -fill x -anchor nw
+
+ # Create the text widget
+ set text_frame [frame $local_frame.text_frame]
+ set text_frame_main [frame $text_frame.main_frame -bd 1 -relief sunken]
+ if {$type == {Local}} {
+ set text [mc "Value Level Data type Variable name"]
+ } {
+ set text [mc "Value Data type Variable name"]
+ }
+ pack [label $text_frame_main.header \
+ -font $text_wdg_font_b -justify left \
+ -text $text \
+ -bd 0 -relief flat -bg white -anchor w \
+ ] -fill x -anchor w -padx 0 -pady 0
+ pack [ttk::separator $text_frame_main.sep \
+ -orient horizontal \
+ ] -fill x
+ set text_widget [text $text_frame_main.text \
+ -bg white -exportselection 0 -bd 0 \
+ -width 0 -height 0 -relief flat \
+ -font $text_wdg_font_n \
+ -yscrollcommand "$text_frame.scrollbar set" \
+ -state disabled \
+ -cursor left_ptr \
+ ]
+ bind $text_widget <<Selection>> "false_selection $text_widget; break"
+ bind $text_widget <Button-1> "$this cvarsview_select_line $type \[expr {int(\[%W index @%x,%y\])}\] 0"
+ bind $text_widget <Menu> {break}
+ bind $text_widget <ButtonRelease-3> {break}
+ pack $text_widget -fill both -expand 1
+
+ pack $text_frame_main -fill both -expand 1 -side left
+ pack [ttk::scrollbar $text_frame.scrollbar \
+ -command "$text_widget yview" \
+ -orient vertical \
+ ] -fill y -side right -after $text_frame_main
+ pack $text_frame -fill both -expand 1
+
+ if {$type == {Local}} {
+ set text_widget_local $text_widget
+ } {
+ set text_widget_global $text_widget
+ }
+
+ # Create text tags
+ $text_widget tag configure tag_current_line -background $color_selected_line
+ $text_widget tag configure tag_variable -font $text_wdg_font_b
+ $text_widget tag configure tag_datatype -font $text_wdg_font_i
+
+ return $local_frame
+ }
+
+ ## Load CDB file (debugging file generated by SDCC)
+ # @parm File cdb_file - Opened CDB file
+ # @return Bool - True in success
+ public method cvarsview_load_cdb {cdb_file} {
+ if {!$gui_initialized} {CreateCVarsViewGUI}
+ set result 1
+
+ set local_variables_nlist {}
+ set local_variables_list {}
+ set local_variables {}
+ set local_addresses {}
+ set local_addresses_list {}
+ set global_variables_nlist {}
+ set global_variables {}
+ set global_addresses {}
+ set global_addresses_list {}
+
+ # Parse linker and symbol records
+ while {![eof $cdb_file]} {
+ set line [gets $cdb_file]
+ set subtype [string index $line 2]
+ switch -- [string index $line 0] {
+ {S} { ;# Symbol record
+ if {$subtype != {G} && $subtype != {L} && $subtype != {F}} {
+ continue
+ }
+ if {![symbol_record $subtype [string range $line 3 end]]} {
+ set result 0
+ }
+ }
+ {L} { ;# Linker record
+ if {$subtype != {G} && $subtype != {L} && $subtype != {F}} {
+ continue
+ }
+ if {![link_address_of_symbol $subtype [string range $line 3 end]]} {
+ set result 0
+ }
+ }
+ default {
+ continue
+ }
+ }
+ }
+
+ # Initialize list of displayed global variables
+ set global_displayed {}
+
+ # Clear search entries
+ $search_entry_Global delete 0 end
+
+ # Adjust lists of addresses
+ evaluate_lists_of_addresses
+
+ # Clear the viewers
+ cvarsview_clear_view local
+ cvarsview_clear_view global
+
+ # Load gained informations into the viewers
+ cvarsview_load_global_variables
+
+ return $result
+ }
+
+ ## Adjust lists of addresses
+ # @see cvarsview_load_cdb
+ # Translate each start address to list of address of all registers occupied by the variable
+ # @return void
+ private method evaluate_lists_of_addresses {} {
+
+ # Process global vaiables
+ set global_addresses_new {}
+ set global_variables_new {}
+ set global_variables_nlist_new {}
+ foreach start_address $global_addresses name $global_addresses_list {
+ set name [lindex $name 1]
+ set idx [lsearch $global_variables_nlist $name]
+ set addresses {}
+ set lenght 0
+
+ if {$idx == -1} {
+ puts stderr "CVarsView::evaluate_lists_of_addresses :: Unknown error 0"
+ continue
+ }
+
+ set glob_var_def [lindex $global_variables $idx]
+ set length [lindex $glob_var_def 2]
+ for {set i 0} {$i < $length} {incr i} {
+ lappend addresses $start_address
+ incr start_address
+ }
+ lappend global_addresses_new $addresses
+ lappend global_variables_new $glob_var_def
+ lappend global_variables_nlist_new $name
+ }
+ set global_addresses $global_addresses_new
+ set global_variables $global_variables_new
+ set global_variables_nlist $global_variables_nlist_new
+
+ # Process local vaiables
+ }
+
+ ## Handle symbol record
+ # @see cvarsview_load_cdb
+ # @parm Char subtype - Variable scope ('G' == Global; 'L' == Local; 'F' == File)
+ # @parm String record - Record data
+ # @return Bool - True on success
+ private method symbol_record {subtype record} {
+ set scope {}
+ set name {}
+ set level {}
+ set block {}
+ set type_record {}
+ set address_space {}
+ set onstack {}
+ set stack {}
+ set registers {}
+
+ if {$subtype == {F}} {
+ set subtype {G}
+ }
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set scope [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set name [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set level [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set bracket_idx [string first {(} $record]
+ if {$bracket_idx == -1} {return 0}
+ set block [string range $record 0 [expr {$bracket_idx - 1}]]
+
+ set record [string replace $record 0 $bracket_idx]
+ set bracket_idx [string first {)} $record]
+ if {$bracket_idx == -1} {return 0}
+ set type_record [string range $record 1 [expr {$bracket_idx - 1}]]
+ set type_record [split $type_record {\{\},:}]
+
+ set record [string replace $record 0 [expr {$bracket_idx + 1}]]
+ set comma_idx [string first {,} $record]
+ if {$comma_idx == -1} {return 0}
+ set address_space [string range $record 0 [expr {$comma_idx - 1}]]
+
+ set record [string replace $record 0 $comma_idx]
+ set comma_idx [string first {,} $record]
+ if {$comma_idx == -1} {return 0}
+ set onstack [string range $record 0 [expr {$comma_idx - 1}]]
+
+ set record [string replace $record 0 $comma_idx]
+ set comma_idx [string first {,} $record]
+ if {$comma_idx == -1} {
+ set comma_idx [string length $record]
+ }
+ set stack [string range $record 0 [expr {$comma_idx - 1}]]
+
+ if {$record != {}} {
+ set record [string replace $record 0 $comma_idx]
+ set registers [split [string range $record 1 end-1] {,}]
+ }
+
+ if {$subtype == {G}} {
+ lappend global_variables_nlist $name
+ lappend global_variables [list \
+ $scope $name \
+ [lindex $type_record 0] [lindex $type_record end] \
+ [lrange $type_record 1 end-1] $address_space \
+ $onstack $stack \
+ $registers 0 \
+ 0 \
+ ]
+ } {
+ lappend local_variables_nlist $name
+ lappend local_variables_list [list $level $block]
+ lappend local_variables [list \
+ $scope $name \
+ [lindex $type_record 0] [lindex $type_record end] \
+ [lrange $type_record 1 end-1] $address_space \
+ $onstack $stack \
+ $registers $level \
+ $block \
+ ]
+ }
+
+ return 1
+ }
+
+ ## Handle linker record
+ # @see cvarsview_load_cdb
+ # @parm Char subtype - Variable scope ('G' == Global; 'L' == Local; 'F' == File)
+ # @parm String record - Record data
+ # @return Bool - True on success
+ private method link_address_of_symbol {subtype record} {
+ set scope {}
+ set name {}
+ set level {}
+ set block {}
+ set address {}
+
+ if {$subtype == {F}} {
+ set subtype {G}
+ }
+
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set scope [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set name [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set level [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set colon_idx [string first {:} $record]
+ if {$colon_idx == -1} {return 0}
+ set block [string range $record 0 [expr {$colon_idx - 1}]]
+
+ set address [string replace $record 0 $colon_idx]
+
+ if {$subtype == {G}} {
+ set addresses_lst {global_addresses}
+ set addresses_list_lst {global_addresses_list}
+ } {
+ set addresses_lst {local_addresses}
+ set addresses_list_lst {local_addresses_list}
+ }
+ lappend $addresses_lst [expr "0x$address"]
+ lappend $addresses_list_lst [list $scope $name $level $block]
+
+ return 1
+ }
+
+ ## Clear the specified viewer
+ # @parm String type - "Local" or "Global"
+ # @return void
+ public method cvarsview_clear_view {type} {
+ if {!$gui_initialized} {CreateCVarsViewGUI}
+
+ if {$type == {local}} {
+ set text_widget $text_widget_local
+ set current_level {}
+ set current_block {}
+ } {
+ set text_widget $text_widget_global
+ }
+ $text_widget configure -state normal
+ $text_widget delete 1.0 end
+ $text_widget configure -state disabled
+ }
+
+ ## Create variable record in the viewer
+ # @parm Int id - Variable ID (an unique number)
+ # @parm String name - Variable name
+ # @parm Int level - Block level
+ # @parm Bool isglobal - Is variable in global sope
+ # @parm Int isvector - Is variable a vector
+ # @parm Int start_address - Variable start address
+ # @parm Int end_address - Variable end address
+ # @parm Char memory_type - Type of memory where is the variable stored (see SDCC manual for more)
+ # @parm Bool signed - Is variable signed (has meaning only for integers)
+ # @parm String datatype - List describing data type (e.g. {SI DA2} is an array of two integers)
+ # @return void
+ private method create_variable_record {id name level isglobal isvector start_address end_address memory_type signed datatype} {
+ set data_type {}
+ set dt_func {}
+ set pointer { }
+ if {$isglobal} {
+ set text_widget $text_widget_global
+ } {
+ set text_widget $text_widget_local
+ }
+
+ foreach dt $datatype {
+ switch -glob -- $dt {
+ {DA*} { ;# Array of <n> elements
+ set argument [string replace $dt 0 1]
+ return
+ }
+ {ST*} { ;# Structure of name <name>
+ set argument [string replace $dt 0 1]
+ return
+ }
+ {SB*} { ;# Bit field of <n> bits
+ set argument [string replace $dt 0 1]
+ return
+ }
+ {SX} { ;# Sbit
+ set data_type {sbit}
+ }
+ {DG} { ;# Generic pointer
+ set pointer {*}
+ }
+ {DC} { ;# Code pointer
+ set pointer {*}
+ }
+ {DX} { ;# External ram pointer
+ set pointer {*}
+ }
+ {DD} { ;# Internal ram pointer
+ set pointer {*}
+ }
+ {DP} { ;# Paged pointer
+ set pointer {*}
+ }
+ {DI} { ;# Upper 128 byte pointer
+ set pointer {*}
+ }
+ {DF} { ;# Function
+ set dt_func {>> }
+ }
+ {SL} { ;# Long integer
+ if {$signed == {U}} {
+ set data_type {ulong}
+ } {
+ set data_type {long}
+ }
+ }
+ {SI} { ;# Integer
+ if {$signed == {U}} {
+ set data_type {uint}
+ } {
+ set data_type {int}
+ }
+ }
+ {SC} { ;# Char
+ if {$signed == {U}} {
+ set data_type {uchar}
+ } {
+ set data_type {char}
+ }
+ }
+ {SS} { ;# Short integer
+ if {$signed == {U}} {
+ set data_type {ushort}
+ } {
+ set data_type {short}
+ }
+ }
+ {SV} { ;# Void
+ set data_type {void}
+ }
+ {SF} { ;# Float
+ set data_type {float}
+ }
+ }
+ }
+
+ if {!$isglobal} {
+ set level_str [string repeat { } [expr {7 - [string length $level]}]]
+ append level_str $level { }
+ $text_widget insert insert $level_str
+ }
+
+ $text_widget configure -state normal
+ set entry [create_embedded_entry $text_widget $id $isglobal $start_address]
+ if {$data_type == {float}} {
+ $entry configure -state readonly
+ }
+ $text_widget window create insert -window $entry -pady 0
+
+ set data_type "${dt_func}${data_type}${pointer}"
+ set data_type "[string repeat { } [expr {12 - [string length $data_type]}]]$data_type"
+ set tag_indexes {}
+
+ lappend tag_indexes [$text_widget index insert]
+ $text_widget insert insert $data_type
+ lappend tag_indexes [$text_widget index insert]
+ $text_widget insert insert { }
+ lappend tag_indexes [$text_widget index insert]
+ $text_widget insert insert $name
+ lappend tag_indexes [$text_widget index insert]
+ $text_widget insert insert "\n"
+
+ $text_widget tag add tag_datatype [lindex $tag_indexes 0] [lindex $tag_indexes 1]
+ $text_widget tag add tag_variable [lindex $tag_indexes 2] [lindex $tag_indexes 3]
+
+ $text_widget configure -state disabled
+ }
+
+ ## Create embeddable entry box for representing variable value
+ # @parm Widget target_widget - Target text widget
+ # @parm Int id - Variable ID (an unique number)
+ # @parm Bool isglobal - Is variable in global scope
+ # @parm Int start_address - Variable start address
+ # @return Widget - Created entry box
+ private method create_embedded_entry {target_widget id isglobal start_address} {
+ lappend global_displayed $id
+
+ # Create entry widget
+ set entry [entry $target_widget.e_$id \
+ -width 11 -font $text_wdg_font_b \
+ -bg {#FFFFFF} -validate key \
+ -takefocus 0 -highlightthickness 0 \
+ -bd 0 -justify right \
+ -disabledbackground {#FFFFFF} \
+ -fg ${::Simulator::normal_color} \
+ -validatecommand "$this cvarsview_validate $id $isglobal $start_address %P" \
+ ]
+ $entry insert insert 0
+ if {$isglobal} {
+ set type {Global}
+ } {
+ set type {Local}
+ }
+
+ # Set event bindings
+ bind $entry <Button-1> "$this cvarsview_select_line $type [expr {$id + 1}] 1"
+ bind $entry <Key-Up> "$this cvarsview_selection_up $isglobal 1"
+ bind $entry <Key-Down> "$this cvarsview_selection_down $isglobal 1"
+ bind $entry <Key-Next> "$this cvarsview_selection_down $isglobal 4"
+ bind $entry <Key-Prior> "$this cvarsview_selection_up $isglobal 4"
+ bind $entry <Motion> "$this cvarsview_help_window_move $isglobal %X %Y"
+ bind $entry <Leave> "$this cvarsview_help_window_hide $isglobal"
+ bind $entry <Enter> "$this cvarsview_create_help_window $id $isglobal"
+ bind $entry <FocusIn> "%W configure -fg ${::Simulator::normal_color}"
+ bind $entry <Button-4> "$target_widget yview scroll -5 units"
+ bind $entry <Button-5> "$target_widget yview scroll +5 units"
+
+ # Return entry reference
+ return $entry
+ }
+
+ ## Load definded global variables into the viewer
+ # @return void
+ public method cvarsview_load_global_variables {} {
+ set id 0
+ foreach variable_def $global_variables {
+ set isvector 0
+ set idx [lsearch $global_addresses_list [list \
+ [lindex $variable_def 0] [lindex $variable_def 1] \
+ [lindex $variable_def 9] [lindex $variable_def 10] \
+ ] \
+ ]
+ if {$idx == -1} {
+ continue
+ }
+ set start_address [lindex $global_addresses [list $idx 0]]
+ set end_address [lindex $global_addresses [list $idx end]]
+ create_variable_record \
+ $id [lindex $variable_def 1] {} 1 \
+ $isvector $start_address $end_address \
+ [lindex $variable_def 5] \
+ [lindex $variable_def 3] \
+ [lindex $variable_def 4]
+ incr id
+ }
+ }
+
+ ## Load definded global variables into the viewer
+ # TODO: This function is not implemented yet
+ # @return void
+ # @parm Int level - Variable level
+ # @parm Int block - Program block
+ # @return void
+ public method cvarsview_load_local_variables {level block} {
+ return
+ if {$current_level == $level && $current_block == $block} {
+ return
+ }
+
+ set current_level $level
+ set current_block $block
+
+ set idx [lsearch -ascii -exact $local_variables_list [list $level $block]]
+ if {$idx == -1} {
+ return 0
+ }
+
+ set variable_def [lindex $local_variables $idx]
+
+ return 1
+ }
+
+ ## Validator for entryboxes representing variable values
+ # @parm Int id - Variable ID (an unique number)
+ # @parm Bool isglobal - Variable is in the global scope
+ # @parm Int address - Vaiable start address
+ # @parm String string - String to validate
+ # @return Bool - Validation result
+ public method cvarsview_validate {id isglobal address string} {
+ set value $string
+ set negative 0
+ set min_value 0
+ set max_value 0
+
+ if {!$validation_ena} {return 1}
+ set validation_ena 0
+
+ if {$isglobal} {
+ set definition [lindex $global_variables $id]
+ } {
+ set validation_ena 1
+ return 0 ;# <-- DEBUG
+ }
+ if {$address == {}} {
+ error "Unknown address"
+ }
+
+ set datatype [lindex $definition 4]
+ set mem_type [lindex $definition 5]
+ set len [lindex $definition 2]
+ set signed [lindex $definition 3]
+ if {$signed == {S}} {
+ set signed 1
+ } {
+ set signed 0
+ }
+
+ # Check for valid characters
+ if {$signed} {
+ if {[string index $string 0] == {-}} {
+ set negative 1
+ set value [string replace $string 0 0]
+ }
+ }
+ if {$value == {}} {
+ set validation_ena 1
+ return 1
+ }
+ if {![string is digit -strict $value]} {
+ set validation_ena 1
+ return 0
+ }
+
+ # Determinate valid value range
+ if {$mem_type == {J} || $mem_type == {H}} {
+ set max_value 1
+ } {
+ set max_value [expr {int(pow(2, $len*8))}]
+ if {$signed} {
+ set min_value [expr {$max_value / 2}]
+ set max_value [expr {$max_value / 2 - 1}]
+ } {
+ incr max_value -1
+ }
+ }
+
+ # Check for valid range
+ if {$negative} {
+ if {$value > $min_value} {
+ set validation_ena 1
+ return 0
+ }
+ } {
+ if {$value > $max_value} {
+ set validation_ena 1
+ return 0
+ }
+ }
+
+ ## Convert to list of decimal values
+ # Bit value
+ if {$mem_type == {J} || $mem_type == {H}} {
+ set value_list $value
+ # Other values
+ } {
+ set value_list [list]
+ set value [format %X $string]
+ set value [string range $value end-[expr {$len * 2}] end]
+
+ for {set i 0} {$i < $len} {incr i} {
+ set val [string range $value end-1 end]
+ set value [string replace $value end-1 end]
+
+ if {$val == {}} {
+ lappend value_list 0
+ } {
+ lappend value_list [expr "0x$val"]
+ }
+ }
+ }
+
+ set command {}
+ switch -- $mem_type {
+ {A} { ;# External stack
+ }
+ {B} { ;# Internal stack
+ }
+ {C} { ;# Code
+ set validation_ena 1
+ return 0
+ }
+ {D} { ;# Code / static segment
+ set validation_ena 1
+ return 0
+ }
+ {E} { ;# Internal ram (lower 128) bytes
+ set command {setDataDEC}
+ set mem_type_for_SE D
+ set synccmd {Simulator_sync_reg}
+ }
+ {F} { ;# External ram
+ set command {setXdataDEC}
+ set mem_type_for_SE X
+ set synccmd {Simulator_XDATA_sync}
+ }
+ {G} { ;# Internal ram
+ set command {setDataDEC}
+ set mem_type_for_SE I
+ set synccmd {Simulator_sync_reg}
+ }
+ {H} { ;# Bit addressable
+ set mem_type_for_SE B
+ if {[$this simulator_address_range $mem_type_for_SE $address]} {
+ $this setBit $address $value
+ $this Simulator_sync_reg [$this getRegOfBit $address]
+ }
+ set validation_ena 1
+ return 1
+ }
+ {I} { ;# SFR space
+ set mem_type_for_SE D
+ set command {setSfr_directly}
+ set synccmd {Simulator_sync_sfr}
+ }
+ {J} { ;# SBIT space
+ set mem_type_for_SE B
+ if {[$this simulator_address_range $mem_type_for_SE $address]} {
+ $this setBit $address $value
+ $this Simulator_sync_sfr [$this getRegOfBit $address]
+ }
+ set validation_ena 1
+ return 1
+ }
+ {R} { ;# Register space
+ }
+ {Z} { ;# Used for function records, or any undefined space code
+ }
+ default {
+ set validation_ena 1
+ return 1
+ }
+ }
+
+ if {$command == {}} {
+ set validation_ena 1
+ return 0
+ }
+ foreach val $value_list {
+ if {[$this simulator_address_range $mem_type_for_SE $address]} {
+ $this $command $address $val
+ $this $synccmd $address
+ }
+ incr address
+ }
+
+ set validation_ena 1
+ return 1
+ }
+
+ ## Enable or disable the panel
+ # @parm Bool enabled - 1 == Enable; 0 == Disable
+ # @return void
+ public method cvarsview_setEnabled {enabled} {
+ if {!$gui_initialized} {return}
+
+ if {$enabled} {
+ set state normal
+ } {
+ set state disabled
+ }
+
+ foreach id $global_displayed {
+ if {[$text_widget_global.e_$id cget -state] == {readonly}} {
+ continue
+ }
+ $text_widget_global.e_$id configure -state $state
+ }
+ }
+
+ ## Synchronize with simulator engine (data are obtained from the engine)
+ # @parm Char memtype - Type of memory (e.g. 'E' means IDATA)
+ # @parm Int address - Address of changed register
+ # @return void
+ public method cvarsview_sync {memtype address} {
+ if {!$gui_initialized} {return}
+ if {!$validation_ena} {return}
+ if {$memtype == {I} && !($address % 8)} {
+ set bitaddr $address
+ for {set i 0} {$i < 8} {incr i} {
+ cvarsview_sync J $bitaddr
+ incr bitaddr
+ }
+ } elseif {$memtype == {E} && $address > 31 && $address < 40} {
+ set bitaddr [expr {($address - 32) * 8}]
+ for {set i 0} {$i < 8} {incr i} {
+ cvarsview_sync H $bitaddr
+ incr bitaddr
+ }
+ }
+
+ set idx 0
+ foreach addr $global_addresses {
+ if {[lsearch $addr $address] != -1} {
+ if {[lindex $global_variables [list $idx 5]] != $memtype} {
+ continue
+ }
+ refresh_global_variable $idx
+ break
+ }
+ incr idx
+ }
+ }
+
+ ## Refresh contents of certain global variable (synchronize with simulator engine)
+ # @parm Int idx - Variable ID
+ # @return void
+ private method refresh_global_variable {idx} {
+ if {[lsearch $global_displayed $idx] == -1} {
+ return
+ }
+
+ set validation_ena 0
+ set variable_def [lindex $global_variables $idx]
+ set address_space [lindex $variable_def 5]
+ set datatype [lindex $variable_def 4]
+ set signed [lindex $variable_def 3]
+ set length [lindex $variable_def 2]
+
+ set value 0
+ set byte_num 0
+ foreach addr [lindex $global_addresses $idx] {
+ switch -- $address_space {
+ {G} {
+ if {[$this simulator_address_range I $addr]} {
+ incr value [expr {[$this getDataDEC $addr] << ($byte_num * 8)}]
+ }
+ }
+ {E} {
+ if {[$this simulator_address_range I $addr]} {
+ incr value [expr {[$this getDataDEC $addr] << ($byte_num * 8)}]
+ }
+ }
+ {I} {
+ if {[$this simulator_address_range D $addr]} {
+ incr value [expr {[$this getSfrDEC $addr] << ($byte_num * 8)}]
+ }
+ }
+ {F} {
+ if {[$this simulator_address_range X $addr]} {
+ incr value [expr {[$this getXdataDEC $addr] << ($byte_num * 8)}]
+ }
+ }
+ {J} {
+ if {[$this simulator_address_range B $addr]} {
+ incr value [$this getBit $addr]
+ }
+ }
+ {H} {
+ if {[$this simulator_address_range B $addr]} {
+ incr value [$this getBit $addr]
+ }
+ }
+ }
+ incr byte_num
+ }
+
+ ## Adjust value
+ # IEEE 754-1985 single precision floating-point number
+ if {$datatype == {SF}} {
+ ## Special cases
+ # Zero
+ if {$value == 0} {
+ # One
+ } elseif {$value == 0x3F800000} {
+ set value 1
+ # Minus One
+ } elseif {$value == 0xBF800000} {
+ set value -1
+ # Positive infinity
+ } elseif {$value == 0x7F800000} {
+ set value {+ infinity}
+ # Negative infinity
+ } elseif {$value == 0xFF800000} {
+ set value {- infinity}
+ # Not a number
+ } elseif {(($value & 0x7F800000) == 0x7F800000) && ($value & 0x007FFFFF)} {
+ set value {NaN}
+
+ ## Common cases
+ } else {
+ set sign [expr {($value & 0x80000000) ? 1 : 0}]
+ set exponent [expr {int(($value & 0x7F800000) >> 23)}]
+ set fraction_b [expr {$value & 0x007FFFFF}]
+
+ incr exponent -127
+
+ set fraction 1
+ set val 0.5
+ set mask 0x00400000
+ for {set i 0} {$i < 23} {incr i} {
+ if {$fraction_b & $mask} {
+ set fraction [expr {$fraction + $val}]
+ }
+ set val [expr {$val / 2}]
+ set mask [expr {$mask >> 1}]
+ }
+
+ set value [expr {pow(-1,$sign) * pow(2,$exponent) * $fraction}]
+ }
+
+ # Common signed integer
+ } elseif {$signed == {S}} {
+ set max_positive_value [expr {pow(2,($length * 8 - 1)) - 1}]
+ if {$value > $max_positive_value} {
+ set value [expr {pow(2,($length * 8)) - $value}]
+ }
+ set value [expr {int($value)}]
+
+ # Common unsigned integer
+ } else {
+ set value [expr {int($value)}]
+ }
+
+ # Write value to the entrybox
+ if {$datatype == {SF}} {
+ $text_widget_global.e_$idx configure -state normal
+ }
+ $text_widget_global.e_$idx delete 0 end
+ $text_widget_global.e_$idx insert 0 $value
+ $text_widget_global.e_$idx configure -fg ${::Simulator::highlight_color}
+ if {$datatype == {SF}} {
+ $text_widget_global.e_$idx configure -state readonly
+ }
+
+ # Reeanable synchronization and entryboxes validation
+ set validation_ena 1
+ }
+}
diff --git a/lib/bottompanel/find_in_files.tcl b/lib/bottompanel/find_in_files.tcl
new file mode 100755
index 0000000..d085110
--- /dev/null
+++ b/lib/bottompanel/find_in_files.tcl
@@ -0,0 +1,750 @@
+#!/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 panel "Find in files", GUI and function
+# Inteted for bottom panel
+# --------------------------------------------------------------------------
+
+class FindInFiles {
+
+ common count 0 ;# Counter of class instances
+
+ # Variables related to object initialization
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ private variable obj_idx ;# Int: Object index
+ private variable abort_variable 0 ;# Bool: Abort search
+ private variable iteration 0 ;# Int: Counter of search iterations (lines read)
+ private variable folder ;# String: Choosen folder
+ private variable pattern ;# String: Search pattern
+ private variable reg_expr ;# Bool: Use regular expression
+ private variable case_sen ;# Bool: Perform case sensitive search
+ private variable pattern_length ;# Int: Pettern length
+
+ private variable pattern_entry ;# Windegt: EntryBox "Pattern"
+ private variable main_frame ;# Widget: Main frame
+ private variable menu {} ;# Widget: popup menu for text widge
+ private variable text_widget ;# Widget: Text widget to show results
+ private variable clear_button ;# Widget: Button "Clear"
+ private variable find_stop_button {} ;# Widget: Button "Find / Stop"
+
+ constructor {} {
+ # Increment object counter
+ incr count
+ set obj_idx $count
+
+ # Load configuration
+ set ::FindInFiles::recursive_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 0]
+ set ::FindInFiles::regular_expr_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 1]
+ set ::FindInFiles::case_sensitive_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 2]
+ set ::FindInFiles::folder_$obj_idx [$this cget -projectPath] ;#[lindex $::CONFIG(FIND_IN_FILES_CONFIG) 3]
+ set ::FindInFiles::mask_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 4]
+ set ::FindInFiles::pattern_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 5]
+
+ # Validate loaded configuration
+ if {![string is boolean -strict [subst "\$::FindInFiles::recursive_$obj_idx"]]} {
+ set ::FindInFiles::recursive_$obj_idx 1
+ }
+ if {![string is boolean -strict [subst "\$::FindInFiles::regular_expr_$obj_idx"]]} {
+ set ::FindInFiles::regular_expr_$obj_idx 0
+ }
+ if {![string is boolean -strict [subst "\$::FindInFiles::case_sensitive_$obj_idx"]]} {
+ set ::FindInFiles::case_sensitive_$obj_idx 1
+ }
+ }
+
+ destructor {
+ # Remove status bar help for popup menus
+ if {$menu != {}} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @return void
+ public method PrepareFindInFiles {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method FindInFilesTabRaised {} {
+ $pattern_entry selection range 0 end
+ $pattern_entry icursor end
+ focus $pattern_entry
+ }
+
+ ## Create GUI of messages tab
+ # @return void
+ public method CreateFindInFilesGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ create_findinfilesgui
+ create_tags_and_bindings
+ create_popup_menu
+ }
+
+ ## Create GUI elements
+ # @return void
+ private method create_findinfilesgui {} {
+ set main_frame [frame $parent.main_frame]
+
+ ## Top frame
+ set top_frame [frame $main_frame.top_frame]
+ # Entry "Pattern"
+ set pattern_entry [ttk::entry $top_frame.pattern_entry \
+ -validate all \
+ -width 1 \
+ -textvariable ::FindInFiles::pattern_$obj_idx \
+ -validatecommand "$this findinfiles_validate_crit_ent 0 %P" \
+ ]
+ bind $pattern_entry <Return> "$this findinfiles_search"
+ bind $pattern_entry <KP_Enter> "$this findinfiles_search"
+ setStatusTip -widget $pattern_entry \
+ -text [mc "Search pattern"]
+ # Entry "Mask"
+ set mask_entry [ttk::entry $top_frame.mask_entry \
+ -validate all \
+ -width 1 \
+ -textvariable ::FindInFiles::mask_$obj_idx \
+ -validatecommand "$this findinfiles_validate_crit_ent 1 %P" \
+ ]
+ bind $mask_entry <Return> "$this findinfiles_search"
+ bind $mask_entry <KP_Enter> "$this findinfiles_search"
+ setStatusTip -widget $mask_entry \
+ -text [mc "File mask (e.g. \"*.c,*.asm\")"]
+ # Entry "Folder"
+ set folder_entry_frm [frame $top_frame.folder_entry_frm]
+ set folder_entry [ttk::entry $folder_entry_frm.folder_entry \
+ -textvariable ::FindInFiles::folder_$obj_idx \
+ -validate all \
+ -width 1 \
+ -validatecommand "$this findinfiles_validate_crit_ent 2 %P" \
+ ]
+ set ::FindInFiles::folder_$obj_idx [$this cget -projectPath]
+ bind $folder_entry <Return> "$this findinfiles_search"
+ bind $folder_entry <KP_Enter> "$this findinfiles_search"
+ pack $folder_entry -side left -fill x -expand 1
+ # Button "Select directory"
+ pack [ttk::button $folder_entry_frm.select_dir_but \
+ -image ::ICONS::16::fileopen \
+ -style Flat.TButton \
+ -command "$this findinfiles_select_dir" \
+ ] -side left
+ DynamicHelp::add $folder_entry_frm.select_dir_but \
+ -text [mc "Choose destination location"]
+ setStatusTip -widget $folder_entry_frm.select_dir_but -text [mc "Select folder"]
+ # Checkbutton "Recursive"
+ pack [checkbutton $folder_entry_frm.recursive_chb \
+ -variable ::FindInFiles::recursive_$obj_idx \
+ -text [mc "Recursive"] \
+ ] -side left -padx 10
+ setStatusTip -widget $folder_entry_frm.recursive_chb -text [mc "Search in all subfolders"]
+ # Button "Start / Stop search"
+ set top_bottom_frame [frame $top_frame.bottom_frame]
+ set find_stop_button [ttk::button $top_bottom_frame.find_stop_button \
+ -text [mc "Find"] \
+ -image ::ICONS::16::find \
+ -compound left \
+ -command "$this findinfiles_search" \
+ -width 7 \
+ ]
+ setStatusTip -widget $find_stop_button -text [mc "Start / Stop search"]
+ # Button "Clear"
+ set clear_button [ttk::button $top_bottom_frame.clear_button \
+ -text [mc "Clear"] \
+ -image ::ICONS::16::clear_left \
+ -compound left \
+ -command "$this findinfiles_clear" \
+ -state disabled \
+ -width 7 \
+ ]
+ setStatusTip -widget $clear_button -text [mc "Clear results"]
+ pack $find_stop_button -side left
+ pack $clear_button -side left
+ # Separator
+ pack [ttk::separator $top_bottom_frame.sep \
+ -orient vertical \
+ ] -fill y -side left -padx 10 -pady 2
+ # Checkbutton "Case sensitive"
+ pack [checkbutton $top_bottom_frame.case_sen_chb \
+ -text [mc "Case sensitive"] \
+ -variable ::FindInFiles::case_sensitive_$obj_idx \
+ ] -side left
+ setStatusTip -widget $top_bottom_frame.case_sen_chb \
+ -text [mc "Perform case sensitive search"]
+ # Checkbutton "Regular expression"
+ pack [checkbutton $top_bottom_frame.regular_expr_chb \
+ -text [mc "Regular expression"] \
+ -variable ::FindInFiles::regular_expr_$obj_idx \
+ ] -side left
+ setStatusTip -widget $top_bottom_frame.regular_expr_chb \
+ -text [mc "Pattern is a regular expression"]
+ # Labels ... (Pattern, Folder, Mask)
+ grid [label $top_frame.pattern_lbl \
+ -text [mc "Pattern:"] \
+ ] -row 0 -column 0 -sticky w
+ grid [label $top_frame.folder_lbl \
+ -text [mc "Folder:"] \
+ ] -row 0 -column 4 -sticky w
+ grid [label $top_frame.template_lbl \
+ -text [mc "Mask:"] \
+ ] -row 1 -column 0 -sticky w
+ # Button "Clear pattern entrybox"
+ grid [ttk::button $top_frame.pattern_clr_but \
+ -image ::ICONS::16::clear_left \
+ -style Flat.TButton \
+ -command "set ::FindInFiles::pattern_$obj_idx {}"\
+ ] -row 0 -column 2
+ setStatusTip -widget $top_frame.pattern_clr_but \
+ -text [mc "Clear pattern entrybox"]
+ # Button "Show help for file mask"
+ grid [ttk::button $top_frame.mask_show_help \
+ -image ::ICONS::16::help \
+ -style Flat.TButton \
+ -command "$this findinfiles_hlp" \
+ ] -row 1 -column 2
+ setStatusTip -widget $top_frame.mask_show_help \
+ -text [mc "Show help for file mask"]
+ # Place some widgets into the grid
+ grid $pattern_entry -row 0 -column 1 -sticky we
+ grid $folder_entry_frm -row 0 -column 5 -sticky we
+ grid $mask_entry -row 1 -column 1 -sticky we
+ grid $top_bottom_frame -row 1 -column 4 -columnspan 2 -sticky we
+ grid columnconfigure $top_frame 1 -weight 1
+ grid columnconfigure $top_frame 5 -weight 1
+ grid columnconfigure $top_frame 3 -minsize 20
+
+ ## Bottom frame (text widget and its scrollbar)
+ set bottom_frame [frame $main_frame.bottom_frame]
+ set text_widget [text $bottom_frame.text \
+ -bg white -state disabled -bd 1 -wrap none \
+ -highlightthickness 0 -exportselection 0 \
+ -cursor left_ptr -width 0 -height 0 \
+ -yscrollcommand "$bottom_frame.scrollbar set" \
+ -font [font create -family helvetica -size -12] \
+ -fg {#555555} \
+ ]
+ pack $text_widget -side left -fill both -expand 1
+ pack [ttk::scrollbar $bottom_frame.scrollbar \
+ -orient vertical -command "$text_widget yview" \
+ ] -side right -after $text_widget -fill y
+
+ # Mask panel frames
+ pack $top_frame -fill x -anchor nw
+ pack $bottom_frame -fill both -expand 1
+ pack $main_frame -fill both -expand 1
+
+ # Adjust GUI
+ findinfiles_validate_crit_ent -1 {}
+ }
+
+ ## Create text tags and event binding for the text widget
+ # @return void
+ private method create_tags_and_bindings {} {
+ # Create tags
+ set bold_font [font create -family helvetica -size -12 -weight bold]
+ $text_widget tag configure tag_highlight -foreground {#000000} -font $bold_font
+ $text_widget tag configure tag_filename -foreground {#0000DD}
+ $text_widget tag configure tag_linenumber -foreground {#00DD00}
+ $text_widget tag configure tag_normal -foreground {#000000}
+ $text_widget tag configure tag_cur_line -background {#FFFF88}
+
+ # Create evet bindings
+ bind $text_widget <ButtonRelease-3> "$this findinfiles_popupmenu %X %Y %x %y; break"
+ bind $text_widget <Button-1> "$this findinfiles_click %x %y; break"
+ bind $text_widget <Double-Button-1> "$this findinfiles_doubleclick %x %y; break"
+ bind $text_widget <<Selection>> "false_selection $text_widget; break"
+ }
+
+ ## Create popup menu for the text widget
+ # @return void
+ private method create_popup_menu {} {
+ set menu $text_widget.popup_menu
+ menuFactory {
+ {command "Go to" {} 0 "findinfiles_goto_cur_line"
+ {goto} "Go to this line"}
+ {command "Clear" {} 0 "findinfiles_clear"
+ {editdelete} "Clear this panel"}
+ } $menu 0 "$this " 0 {}
+ $menu entryconfigure [::mc "Clear"] -state disabled
+ }
+
+ ## Invoke file selection dialog to select folder where to search
+ # @return void
+ public method findinfiles_select_dir {} {
+ KIFSD::FSD ::fsd \
+ -title [mc "Choose directory - MCU 8051 IDE"] \
+ -fileson 0 -master . \
+ -directory [subst "\$::FindInFiles::folder_$obj_idx"]
+ fsd setokcmd "set ::FindInFiles::folder_$obj_idx \[::fsd get\]"
+ fsd activate
+ }
+
+ ## Start searching
+ # @return void
+ public method findinfiles_search {} {
+ # Gain search options
+ set folder [file normalize [subst "\$::FindInFiles::folder_$obj_idx"]]
+ set mask [subst "\$::FindInFiles::mask_$obj_idx"]
+ set pattern [subst "\$::FindInFiles::pattern_$obj_idx"]
+ set reg_expr [subst "\$::FindInFiles::regular_expr_$obj_idx"]
+ set case_sen [subst "\$::FindInFiles::case_sensitive_$obj_idx"]
+
+ # Validate search options
+ if {![string length $folder] || ![string length $mask] || ![string length $pattern]} {
+ return
+ }
+ if {![file exists $folder]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Folder not found"] \
+ -message [mc "The specified folder does not exist.\n'%s'" $folder]
+ return
+ }
+ if {![file isdirectory $folder]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Folder not found"] \
+ -message [mc "The string specified as a folder is not a folder.\n'%s'" $folder]
+ return
+ }
+ if {$reg_expr && [catch {regexp -about $pattern}]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Error"] \
+ -message [mc "Invalid regular expression"]
+ return
+ }
+
+ # Adjust GUI (Find button, text widget ...)
+ $find_stop_button configure \
+ -text [mc "Stop"] -image ::ICONS::16::cancel \
+ -command "$this findinfiles_stop"
+ $text_widget configure -state normal
+ $text_widget delete 0.0 end
+ update
+
+ # Determinate list of files
+ set new_mask {}
+ foreach glob [split $mask {,}] {
+ lappend new_mask $glob
+ }
+ set mask $new_mask
+ set files [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach m $mask {
+ eval "append files { } \[glob -directory {$folder} -nocomplain -types {f l} -- $m\]"
+ }
+ }
+ if {[subst "\$::FindInFiles::recursive_$obj_idx"]} {
+ append files { } [regsub -all {[\{\}]} [recursive_search $folder $mask] {\\&}]
+ }
+
+ # Search
+ if {!$reg_expr && !$case_sen} {
+ set pattern [string tolower $pattern]
+ }
+ set pattern_length [string length $pattern]
+ set iteration 0
+ foreach filename $files {
+ if {[search_in_file $filename]} {
+ break
+ }
+ }
+
+ # Adjust GUI (Find button, text widget ...)
+ $text_widget delete end-1l end
+ $text_widget configure -state disabled
+ $find_stop_button configure \
+ -text [mc "Find"] \
+ -image ::ICONS::16::find \
+ -command "$this findinfiles_search"
+
+ # Enable / Disable clear button and clear entry in the popup menu
+ if {[$text_widget index {1.0 lineend}] == {1.0}} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $menu entryconfigure [::mc "Clear"] -state $state
+ $clear_button configure -state $state
+ }
+
+ ## Perform recursive search for ceratin files in certain folder
+ # @parm String folder - Directory to search
+ # @parm String mask - File masks
+ # @return List - Found files
+ private method recursive_search {folder mask} {
+ set files {}
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach dir [glob -directory $folder -nocomplain -types {d} -- *] {
+ foreach m $mask {
+ eval "append files { } \[glob -directory {$dir} -nocomplain -types {f l} -- $m\]"
+ }
+ append files { } [recursive_search $dir $mask]
+ }
+ }
+ if {[llength $files]} {
+ update
+ }
+ return $files
+ }
+
+ ## Search in certain file
+ # @parm String filename - File where to search in
+ # @return Bool - 1 == Search aborted; 0 == Normal
+ private method search_in_file {filename} {
+ # Open file
+ if {[catch {
+ set file [open $filename r]
+ }]} {
+ return 0
+ }
+
+ # Local variables
+ set relative_filename [string replace $filename 0 [string length $folder]]
+ set indexes {}
+ set text_idx {end}
+ set line_number 0
+ set matched_str {}
+
+ # Iterate over lines
+ while {![eof $file]} {
+ incr line_number
+ incr iteration
+ set line [gets $file]
+
+ # Update GUI and evaluate abort variable
+ if {$iteration > 100} {
+ if {[lindex [$text_widget yview] 1] == 1} {
+ $text_widget see end
+ }
+ update
+ if {$abort_variable} {
+ set abort_variable 0
+ return 1
+ }
+ }
+
+ ## Search string
+ if {!$case_sen} {
+ set line [string tolower $line]
+ }
+ set indexes {}
+ set lengths {}
+ set last_idx -1
+ set idx 0
+ set found 1
+ # Regular expression
+ if {$reg_expr} {
+ while $found {
+ set found 0
+ if {$case_sen} {
+ set found [regexp -start $idx -- $pattern $line matched_str]
+ } {
+ set found [regexp -nocase -start $idx -- $pattern $line matched_str]
+ }
+
+ set idx [string first $matched_str $line $idx]
+ if {$last_idx >= $idx} {
+ break
+ }
+
+ lappend indexes $idx
+ lappend lengths [string length $matched_str]
+ incr idx
+ set last_idx $idx
+ }
+ # Pure string pattern
+ } {
+ while {$idx != -1} {
+ set idx [string first $pattern $line $idx]
+ if {$last_idx >= $idx} {
+ break
+ }
+
+ lappend indexes $idx
+ lappend lengths $pattern_length
+ incr idx
+ set last_idx $idx
+ }
+ }
+ if {![llength $indexes]} {
+ continue
+ }
+
+ ## Display result
+ # Filename
+ $text_widget insert insert $relative_filename
+ $text_widget tag add tag_filename [list insert linestart] insert
+ set text_idx [$text_widget index insert]
+ # ":"
+ $text_widget insert insert ": "
+ $text_widget tag add tag_normal $text_idx insert
+ set text_idx [$text_widget index insert]
+ # Line number
+ $text_widget insert insert $line_number
+ $text_widget tag add tag_linenumber $text_idx insert
+ set text_idx [$text_widget index insert]
+ # ":"
+ $text_widget insert insert ": "
+ $text_widget tag add tag_normal $text_idx insert
+ set text_idx [$text_widget index insert]
+ scan $text_idx {%d.%d} row col
+ # Line content and highlight pattern found
+ $text_widget insert insert $line
+ foreach index $indexes length $lengths {
+ $text_widget tag add tag_highlight \
+ $row.[expr {$col + $index}] \
+ $row.[expr {$col + $index + $length}]
+ }
+ $text_widget insert insert "\n"
+ }
+
+ # Close file
+ catch {
+ close $file
+ }
+ return 0
+ }
+
+ ## Abort search
+ # @return void
+ public method findinfiles_stop {} {
+ set abort_variable 1
+ }
+
+ ## Clear results
+ # @return void
+ public method findinfiles_clear {} {
+ # Clear text widget
+ $text_widget configure -state normal
+ $text_widget delete 0.0 end
+ $text_widget configure -state disabled
+
+ # Adjust controls
+ $menu entryconfigure [::mc "Clear"] -state disabled
+ $clear_button configure -state disabled
+ }
+
+ ## Invoke popup menu for the text widget
+ # @parm Int X - Absolute mouse pointer position (X axis)
+ # @parm Int Y - Absolute mouse pointer position (Y axis)
+ # @parm Int x - Relative mouse pointer position (X axis)
+ # @parm Int y - Relative mouse pointer position (Y axis)
+ # @return void
+ public method findinfiles_popupmenu {X Y x y} {
+ findinfiles_click $x $y
+ set index [$text_widget index [list @$x,$y linestart]]
+ if {[$text_widget compare $index == [list $index lineend]]} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $menu entryconfigure [::mc "Go to"] -state $state
+ tk_popup $menu $X $Y
+ }
+
+ ## Select line in the text widget by mouse click
+ # @parm Int x - Relative mouse pointer position (X axis)
+ # @parm Int y - Relative mouse pointer position (Y axis)
+ # @return void
+ public method findinfiles_click {x y} {
+ set index [$text_widget index [list @$x,$y linestart]]
+ $text_widget tag remove tag_cur_line 0.0 end
+ if {[$text_widget compare $index != [list $index lineend]]} {
+ $text_widget tag add tag_cur_line $index $index+1l
+ }
+ }
+
+ ## Handle <DoubleButton-1> event on the text widget
+ # - Switch editor and go to specified line
+ # @parm Int x - Relative mouse pointer position (X axis)
+ # @parm Int y - Relative mouse pointer position (Y axis)
+ # @return void
+ public method findinfiles_doubleclick {x y} {
+ editor_goto_line [$text_widget index [list @$x,$y linestart]]
+ }
+
+ ## Activate hypertext link on the specified index
+ # @parm TextIndex index - Index of linestart
+ # @return void
+ private method editor_goto_line {index} {
+ # Determinate line number and relative name of file
+ set filename [$text_widget tag nextrange tag_filename $index [list $index lineend]]
+ set linenumber [$text_widget tag nextrange tag_linenumber $index [list $index lineend]]
+ set filename [$text_widget get [lindex $filename 0] [lindex $filename 1]]
+ set linenumber [$text_widget get [lindex $linenumber 0] [lindex $linenumber 1]]
+ if {![string length $filename] || ![string length $linenumber]} {
+ return
+ }
+
+ # Switch editor
+ set current_filename [lindex [$this editor_procedure {} getFileName {}] 1]
+ if {$filename != $current_filename} {
+ if {![$this fucus_specific_editor $filename 1]} {
+ set filename [file join $folder $filename]
+ if {[$this openfile $filename 1 . def def 0 0 {}] != {}} {
+ $this switch_to_last
+ update idle
+ $this editor_procedure {} parseAll {}
+ } {
+ return
+ }
+ }
+ }
+
+ # Go to target line
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto $linenumber
+ }
+
+ ## Validator function for all entry widgets
+ # Conditionaly disables button "Find"
+ # @parm Int for_what - Number of entrybox from which this function was invoked
+ # 0 - Pattern
+ # 1 - Folder
+ # 2 - Mask
+ # @parm String content - String to validate
+ # @return Bool - Always 1
+ public method findinfiles_validate_crit_ent {for_what content} {
+ if {![winfo exists $find_stop_button]} {
+ return 1
+ }
+ set state normal
+ set string {}
+ foreach var [list pattern_$obj_idx folder_$obj_idx mask_$obj_idx] \
+ number {0 1 2} \
+ {
+ if {$for_what == $number} {
+ set string $content
+ } {
+ set string [subst "\$::FindInFiles::$var"]
+ }
+ if {![string length $string]} {
+ set state disabled
+ break
+ }
+ }
+ $find_stop_button configure -state $state
+ return 1
+ }
+
+ ## Invoke helwindow for entrybox "Mask"
+ # @return void
+ public method findinfiles_hlp {} {
+ # Destroy legend window
+ if {[winfo exists .findinfiles_help_win]} {
+ grab release .findinfiles_help_win
+ destroy .findinfiles_help_win
+ return
+ }
+ set x [expr {[winfo pointerx .] + 10}]
+ set y [winfo pointery .]
+
+ # Create legend window
+ set win [toplevel .findinfiles_help_win -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 \
+ -font ${::Editor::defaultFont} \
+ ]
+
+ pack $frame -fill both -expand 1
+
+ # Fill the text widget
+ $text insert end "Comma separated list of file masks (e.g \"*.c,*.h,*.asm\")\n"
+ $text insert end "The mask may contain any of the following special characters:\n"
+ $text insert end " ? Matches any single character.\n"
+ $text insert end " * Matches any sequence of zero or more characters.\n"
+ $text insert end " \[chars\] Matches any single character in chars.\n"
+ $text insert end " If chars contains a sequence of the form a-b then any\n"
+ $text insert end " character between a and b (inclusive) will match.\n"
+ $text insert end " \x Matches the character x."
+
+ # Show the text
+ $text configure -state disabled
+ pack $text -side bottom -fill both -expand 1
+
+ # Show the window
+ wm geometry $win "=600x180+$x+$y"
+ update
+ catch {
+ grab -global $win
+ }
+ }
+
+ ## Menu action "Go to"
+ # @return void
+ public method findinfiles_goto_cur_line {} {
+ set index [lindex [$text_widget tag nextrange tag_cur_line 1.0 end] 0]
+ if {$index == {}} {
+ return
+ }
+ editor_goto_line $index
+ }
+
+ ## Get configuration list for this panel
+ # - Intented for session management
+ # @return void
+ public method findinfiles_get_config {} {
+ return [list \
+ [subst "\$::FindInFiles::recursive_$obj_idx"] \
+ [subst "\$::FindInFiles::regular_expr_$obj_idx"] \
+ [subst "\$::FindInFiles::case_sensitive_$obj_idx"] \
+ [subst "\$::FindInFiles::folder_$obj_idx"] \
+ [subst "\$::FindInFiles::mask_$obj_idx"] \
+ [subst "\$::FindInFiles::pattern_$obj_idx"] \
+ ]
+ }
+}
diff --git a/lib/bottompanel/graph.tcl b/lib/bottompanel/graph.tcl
new file mode 100755
index 0000000..e9def9b
--- /dev/null
+++ b/lib/bottompanel/graph.tcl
@@ -0,0 +1,714 @@
+#!/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
+# Graph panel in the bottom panel - shows states of ports
+# --------------------------------------------------------------------------
+
+source "${::LIB_DIRNAME}/bottompanel/graph_wdg.tcl" ;# Graph widget
+
+class Graph {
+ ## COMMON
+
+ # Variables related to object initialization
+ private variable data_list ;# Teportary variable -- Configuration list
+ private variable gui_initialized 0 ;# Bool: GUI created
+ private variable parent ;# Parent widget
+
+ private variable grid_mode {b} ;# Current grid mode (one of {b n x y})
+ private variable drawing_on 0 ;# Bool: Graph enabled
+ private variable magnification 0 ;# Magnification level (0..3)
+ private variable active_page {} ;# String: ID of currently active page
+
+ private variable start_stop_button ;# Widget: Button "ON"/"OFF"
+ private variable zoom_in_button ;# Widget: Button "Zoom in"
+ private variable zoom_out_button ;# Widget: Button "Zoom out"
+ private variable clear_marks_button ;# Widget: Button "Clear marks"
+ private variable grid_button ;# Widget: Button "Change grid"
+
+ private variable pages_manager ;# Widget: Pages manager for graph widgets
+ private variable nb_state_frame ;# Widget: Frame containing graph "True state"
+ private variable nb_latches_frame ;# Widget: Frame containing graph "Latches"
+ private variable nb_output_frame ;# Widget: Frame containing graph "True Output"
+
+ private variable state_but ;# Widget: Button "True state"
+ private variable latches_but ;# Widget: Button "Latches"
+ private variable output_but ;# Widget: Button "True Output"
+
+ private variable graph_state ;# Object: Graph widget representing "True state"
+ private variable graph_latches ;# Object: Graph widget representing "Latches"
+ private variable graph_output ;# Object: Graph widget representing "True Output"
+
+ private variable graph_state_created 0 ;# Bool: GUI of object $graph_state created
+ private variable graph_latches_created 0 ;# Bool: GUI of object $graph_latches created
+ private variable graph_output_created 0 ;# Bool: GUI of object $graph_output created
+
+
+ ## Object constructor
+ constructor {} {
+ # Configure localy used ttk styles
+ ttk::style configure Graph_ActiveTab.TButton \
+ -background {#AAAAFF} \
+ -padding 0 \
+ -borderwidth 1
+ ttk::style map Graph_ActiveTab.TButton \
+ -background [list active {#DDDDFF}] \
+ -foreground [list active {#0000DD} !active {#000000}]
+ }
+
+ ## Object destructor
+ destructor {
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget Parent - GUI parent widget
+ # @parm List _data_list - Configuration data list
+ # @return void
+ public method PrepareGraph {Parent _data_list} {
+ set parent $Parent
+ set data_list $_data_list
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method GraphTabRaised {} {
+ }
+
+ ## Initialize graph
+ # @return void
+ public method CreateGraphGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Create panel frames
+ set top_bar [frame $parent.top_bar -bg {#CCCCCC}] ;# Buttons for switching pages
+ set bottom_frame [frame $parent.bottom_frame] ;# Graphs
+ set left_bar [frame $bottom_frame.left_bar] ;# Button bar on the left
+
+ ## Create button bar
+ # Button "Enable/Disable"
+ set start_stop_button [ttk::button $left_bar.start_stop_button \
+ -command "$this graph_change_status_on" \
+ -width 3 \
+ ]
+ DynamicHelp::add $left_bar.start_stop_button \
+ -text [mc "Turn graph on/off"]
+ setStatusTip -widget $start_stop_button -text [mc "Enable/Disable graph"]
+ bind $start_stop_button <Button-3> "$this graph_change_status_on; break"
+ pack $start_stop_button -anchor n
+ # Separator
+ pack [ttk::separator $left_bar.sep0 -orient horizontal] -fill x -pady 2
+ # Button "Change grid mode"
+ set grid_button [ttk::button $left_bar.grid_button \
+ -style Flat.TButton \
+ -image ::ICONS::16::grid1 \
+ -command "$this graph_switch_grid_mode 1" \
+ ]
+ DynamicHelp::add $grid_button -text [mc "Change grid"]
+ setStatusTip -widget $grid_button -text [mc "Change grid morfology"]
+ pack $grid_button -anchor n
+ bind $grid_button <Button-1> "$this graph_switch_grid_mode 1; break"
+ bind $grid_button <Button-3> "$this graph_switch_grid_mode -1; break"
+ # Separator
+ pack [ttk::separator $left_bar.sep1 -orient horizontal] -fill x -pady 2
+ # Button "Zoom in"
+ set zoom_in_button [ttk::button $left_bar.zoom_in_button \
+ -image ::ICONS::16::viewmag_in \
+ -command "$this graph_zoom_in" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $zoom_in_button -text [mc "Change bit length on X axis to a lower value"]
+ setStatusTip -widget $zoom_in_button -text [mc "Zoom in (X axis)"]
+ pack $zoom_in_button
+ # Button "Zoom out"
+ set zoom_out_button [ttk::button $left_bar.zoom_out_button \
+ -image ::ICONS::16::viewmag_out \
+ -command "$this graph_zoom_out" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $zoom_out_button -text [mc "Change bit length on X axis to a higher value"]
+ setStatusTip -widget $zoom_out_button -text [mc "Zoom out (X axis)"]
+ pack $zoom_out_button
+ # Separator
+ pack [ttk::separator $left_bar.sep2 -orient horizontal] -fill x -pady 2
+ # Button "Clear marks"
+ set clear_marks_button [ttk::button $left_bar.clear_marks_button \
+ -image ::ICONS::16::editdelete \
+ -command "$this graph_clear_marks" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $clear_marks_button -text [mc "Clear user marks"]
+ setStatusTip -widget $clear_marks_button -text [mc "Clear marks"]
+ pack $clear_marks_button
+
+ # Create graphs
+ set pages_manager [PagesManager $bottom_frame.pages_manager -background {#eeeeee}]
+ set nb_state_frame [$pages_manager add {state}]
+ set nb_latches_frame [$pages_manager add {latches}]
+ set nb_output_frame [$pages_manager add {output}]
+
+ ## Create buttons
+ # Button "True state"
+ set state_but [ttk::button $top_bar.state_but \
+ -text [mc "True state"] \
+ -image ::ICONS::16::dot_g \
+ -command "$this Graph_set_active_page {state}" \
+ -compound left \
+ -style Flat.TButton \
+ ]
+ pack $state_but -side left -pady 0 -ipady 0 -padx 1
+ # Button "Port Latches"
+ set latches_but [ttk::button $top_bar.latches_but \
+ -text [mc "Port latches"] \
+ -compound left \
+ -image ::ICONS::16::dot \
+ -command "$this Graph_set_active_page {latches}" \
+ -style Flat.TButton \
+ ]
+ pack $latches_but -side left -pady 0 -ipady 0 -padx 1
+ # Button "True Output"
+ set output_but [ttk::button $top_bar.output_but \
+ -text [mc "True output"] \
+ -compound left \
+ -image ::ICONS::16::dot_r \
+ -command "$this Graph_set_active_page {output}" \
+ -style Flat.TButton \
+ ]
+ pack $output_but -side left -pady 0 -ipady 0 -padx 1
+ # Button "Show legend"
+ set help_but [ttk::button $top_bar.help_but \
+ -text [mc "Legend"] \
+ -command "$this Graph_show_legend" \
+ -style Flat.TButton \
+ ]
+ pack $help_but -side left -pady 0 -ipady 0 -padx 1
+
+ set graph_state [GraphWidget #auto $nb_state_frame $this]
+ set graph_latches [GraphWidget #auto $nb_latches_frame $this]
+ set graph_output [GraphWidget #auto $nb_output_frame $this]
+
+ pack $top_bar -anchor nw -ipady 1
+ pack $left_bar -anchor n -side left
+ pack [ttk::separator $bottom_frame.sep -orient vertical] -fill y -side left -padx 1
+ pack $pages_manager -fill both -expand 1 -side left
+ pack $bottom_frame -fill both -expand 1
+
+ # Adjust configuration to the given datalist
+ set grid_mode [lindex $data_list 0]
+ set magnification [lindex $data_list 1]
+ set drawing_on [lindex $data_list 2]
+ set mark_flags_s [lindex $data_list 3]
+ set mark_flags_l [lindex $data_list 4]
+ set mark_flags_o [lindex $data_list 5]
+ set active_page [lindex $data_list 6]
+
+ # Validate the loaded confiuration
+ foreach mark_flags {mark_flags_s mark_flags_l mark_flags_o} {
+ set mark_flags_data [subst "\$$mark_flags"]
+ if {
+ ![regexp {^[01]+$} $mark_flags_data]
+ ||
+ [string bytelength $mark_flags_data] != 170
+ } then {
+ puts stderr "Invalid graph mark flags -- discarded"
+ set $mark_flags [string repeat {0 } 170]
+ } else {
+ set $mark_flags [split $mark_flags_data {}]
+ }
+ }
+ if {
+ $magnification != {0} && $magnification != {1} &&
+ $magnification != {2} && $magnification != {3}
+ } {
+ puts stderr "Invalid graph magnification level -- setting to default"
+ set magnification 0
+ }
+ if {$drawing_on != {0} && $drawing_on != {1}} {
+ puts stderr "Invalid graph on/off flag -- setting to 'on'"
+ set drawing_on 1
+ }
+ if {
+ $grid_mode != {b} && $grid_mode != {n} &&
+ $grid_mode != {y} && $grid_mode != {x}
+ } {
+ puts stderr "Invalid graph grid mode -- setting to 'y'"
+ set grid_mode {y}
+ }
+ if {[lsearch -ascii -exact {state latches output} $active_page] == -1} {
+ puts stderr "Invalid graph active page -- setting to 'state'"
+ set active_page {state}
+ }
+
+ set mark_flags [list $mark_flags_s $mark_flags_l $mark_flags_o]
+ set i 0
+ foreach obj [list $graph_state $graph_latches $graph_output] {
+ $obj graph_set_data \
+ $grid_mode \
+ $magnification \
+ $drawing_on \
+ [lindex $mark_flags $i]
+ incr i
+ }
+
+ adjust_mag_buttons
+ adjust_on_off_button
+ adjust_grid_button
+
+ # Unset tempotary variables
+ unset data_list
+
+ Graph_set_active_page $active_page
+ }
+
+ ## Show legend for graph
+ # @return void
+ public method Graph_show_legend {} {
+ # Destroy legend window
+ if {[winfo exists .graph_help_win]} {
+ grab release .graph_help_win
+ destroy .graph_help_win
+ return
+ }
+ set win_x [expr {[winfo pointerx .] + 10}]
+ set win_y [winfo pointery .]
+
+ # Create legend window
+ set win [toplevel .graph_help_win -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 canvas widget
+ set canvas [canvas $frame.canvas\
+ -bg {#FFFFFF} \
+ -takefocus 0 \
+ -cursor left_ptr \
+ -bd 0 -relief flat \
+ -width 1 -height 1 \
+ ]
+
+ pack $frame -fill both -expand 1
+
+ # Fill in the canvas widget
+ Graph_create_legend $canvas 0
+
+ # Show the canvas
+ pack $canvas -side bottom -fill both -expand 1
+
+ # Show the window
+ wm geometry $win "=260x135+$win_x+$win_y"
+ update
+ catch {
+ grab -global $win
+ }
+ }
+
+ ## Fill in the specified canvas widget to contain the graph legend
+ # @parm Widget canvas - Target canvas widget
+ # @parm Bool nc_instead_of_X - Show "Not connected" instead of "Access to external memory"
+ # @return void
+ public method Graph_create_legend {canvas nc_instead_of_X} {
+ set x 10
+ # {=} Log. 1 forced to log. 0
+ $canvas create line $x 20 [expr {$x + 20}] 20 -fill {#FF00AA} -width 2
+ incr x 20
+ # {} Not connected
+ if {$nc_instead_of_X} {
+ $canvas create line $x 20 $x 15 -fill {#FF00AA} -width 2
+ $canvas create line $x 15 [expr {$x + 20}] 15 -fill {#000000} -width 2
+
+ # {X} Access to external memory
+ } {
+ $canvas create rectangle $x 20 \
+ [expr {$x + 20}] 15 \
+ -fill {#00FF00} -width 0 -outline {#00FF00}
+ $canvas create rectangle $x 15 \
+ [expr {$x + 20}] 10 \
+ -fill {#FF0000} -width 0 -outline {#FF0000}
+ }
+ incr x 20
+ # {-} Undeterminable state
+ $canvas create line $x 15 \
+ [expr {$x + 5}] 11 \
+ [expr {$x + 10}] 15 \
+ [expr {$x + 15}] 17 \
+ [expr {$x + 20}] 14 -fill {#FF8800} -width 2
+ incr x 20
+ # {?} No voltage
+ $canvas create line $x 15 [expr {$x + 20}] 15 -fill {#888888} -width 2
+ incr x 20
+ # {1} Log. 1
+ $canvas create line $x 15 $x 10 [expr {$x + 20}] 10 [expr {$x + 20}] 15 -fill {#FF0000} -width 2
+ incr x 20
+ # {0} Log. 0
+ $canvas create line $x 15 $x 20 [expr {$x + 20}] 20 -fill {#00FF00} -width 2
+ incr x 20
+
+ ## Descriptions
+ # {=} Log. 1 forced to log. 0
+ $canvas create line 20 23 20 100 30 100 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 30 100 -fill {#000000} -anchor w \
+ -text [mc "Log. 1 forced to log. 0"] \
+ -font $::smallfont
+ # {} Not connected
+ if {$nc_instead_of_X} {
+ set tmp_txt [mc "Not connected"]
+ # {X} Access to external memory
+ } {
+ set tmp_txt [mc "Access to external memory"]
+ }
+ $canvas create line 40 23 40 86 50 86 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 50 86 -fill {#000000} -anchor w \
+ -text $tmp_txt -font $::smallfont
+ # {-} Undeterminable state
+ $canvas create line 60 23 60 72 70 72 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 70 72 -fill {#000000} -anchor w \
+ -text [mc "Undeterminable state"] -font $::smallfont
+ # {?} No voltage
+ $canvas create line 80 23 80 58 90 58 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 90 58 -fill {#000000} -anchor w \
+ -text [mc "No voltage"] -font $::smallfont
+ # {1} Log. 1
+ $canvas create line 100 23 100 44 110 44 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 110 44 -fill {#000000} -anchor w \
+ -text [mc "Log. 1"] -font $::smallfont
+ # {0} Log. 0
+ $canvas create line 120 23 120 30 130 30 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 130 30 -fill {#000000} -anchor w \
+ -text [mc "Log. 0"] -font $::smallfont
+ }
+
+ ## Create GUI for the specified tab
+ # @parm String page - Tab ID
+ # @return void
+ public method Graph_create_tab {page} {
+ switch -- $page {
+ {state} { ;# Tab: True state
+ if {!$graph_state_created} {
+ set graph_state_created 1
+ $graph_state CreateGraphGUI
+ }
+ }
+ {latches} { ;# Tab: Port Latches
+ if {!$graph_latches_created} {
+ set graph_latches_created 1
+ $graph_latches CreateGraphGUI
+ }
+ }
+ {output} { ;# Tab: True Output
+ if {!$graph_output_created} {
+ set graph_output_created 1
+ $graph_output CreateGraphGUI
+ }
+ }
+ }
+ }
+
+ ## Set current active page
+ # @parm String page - Tab ID
+ # @return void
+ public method Graph_set_active_page {page} {
+ set active_page $page
+ Graph_create_tab $page
+ $pages_manager raise $page
+
+ # Adjust buttons on the top
+ foreach w [list $state_but $latches_but $output_but] {
+ $w configure -style Flat.TButton
+ }
+ switch -- $page {
+ {state} { ;# Tab: True state
+ $state_but configure -style Graph_ActiveTab.TButton
+ }
+ {latches} { ;# Tab: Port Latches
+ $latches_but configure -style Graph_ActiveTab.TButton
+ }
+ {output} { ;# Tab: True Output
+ $output_but configure -style Graph_ActiveTab.TButton
+ }
+ }
+ }
+
+ ## Draw interrupt line
+ # @parm String = {} - If "nohistory" the history of interrupt lines will not be modified
+ # @return void
+ public method graph_draw_interrupt_line args {
+ if {!$gui_initialized} {CreateGraphGUI}
+ create_all_graph_widgets
+
+ $graph_state graph_draw_interrupt_line $args
+ $graph_latches graph_draw_interrupt_line $args
+ $graph_output graph_draw_interrupt_line $args
+ }
+
+ ## Draw new port states in the graph
+ # @parm String target - Target Graph, one of {S L O}
+ # @parm List values - Values to display ...
+ # @return void
+ public method graph_new_output_state {target values} {
+ if {!$gui_initialized} {CreateGraphGUI}
+ create_all_graph_widgets
+
+ switch -- $target {
+ {S} { ;# Tab: True state
+ $graph_state graph_new_output_state $values
+ }
+ {L} { ;# Tab: Port Latches
+ $graph_latches graph_new_output_state $values
+ }
+ {O} { ;# Tab: True Output
+ $graph_output graph_new_output_state $values
+ }
+ }
+ }
+
+ ## Adjust magnification buttons to the current magnification level
+ # @return void
+ private method adjust_mag_buttons {} {
+ # The lowest possible magnification level
+ if {!$magnification} {
+ $zoom_in_button configure -state normal
+ $zoom_out_button configure -state disabled
+ # The highest possible magnification level
+ } elseif {$magnification == 3} {
+ $zoom_in_button configure -state disabled
+ $zoom_out_button configure -state normal
+ # Something in the middle
+ } else {
+ $zoom_in_button configure -state normal
+ $zoom_out_button configure -state normal
+ }
+ }
+
+ ## Switch between ON and OFF
+ # @return void
+ public method graph_change_status_on {} {
+ set drawing_on [expr {!$drawing_on}]
+ graph_commit_state_on_off
+ }
+
+ ## Commit new ON/OFF state
+ # @return void
+ public method graph_commit_state_on_off {} {
+ create_all_graph_widgets
+
+ $graph_state commit_state_on_off $drawing_on
+ $graph_latches commit_state_on_off $drawing_on
+ $graph_output commit_state_on_off $drawing_on
+
+ adjust_mag_buttons
+ adjust_on_off_button
+ }
+
+ ## Adjust apparence of all "ON/OFF" buttons in the PALE system
+ # @return void
+ private method adjust_on_off_button {} {
+ $this pale_on_off $drawing_on
+
+ # ON
+ if {$drawing_on} {
+ $start_stop_button configure -style GreenBg.TButton -text "ON"
+ $grid_button configure -state normal
+ $clear_marks_button configure -state normal
+
+ # OFF
+ } else {
+ $start_stop_button configure -style RedBg.TButton -text "OFF"
+
+ $zoom_in_button configure -state disabled
+ $zoom_out_button configure -state disabled
+ $grid_button configure -state disabled
+ $clear_marks_button configure -state disabled
+ }
+ }
+
+ ## Adjust apparence of all "Grid" buttons in the PALE system
+ # @return void
+ private method adjust_grid_button {} {
+ # Adjust button in button bar and canvas popup menu
+ switch -- $grid_mode {
+ {b} {set image {grid0}}
+ {n} {set image {grid1}}
+ {y} {set image {grid2}}
+ {x} {set image {grid3}}
+ }
+ $grid_button configure -image ::ICONS::16::$image
+
+ }
+
+ ## Zoom in/out
+ # @parm Int by - Steps
+ # @return void
+ public method graph_switch_grid_mode {by} {
+ create_all_graph_widgets
+
+ # Determinate number of the current grid mode
+ set i [lsearch {b n y x} $grid_mode]
+ # Increment by '$by'
+ incr i $by
+ while {$i > 3} {
+ incr i -4
+ }
+ while {$i < 0} {
+ incr i 4
+ }
+ # Set new grid mode
+ set grid_mode [lindex {b n y x} $i]
+ adjust_grid_button
+
+ $graph_state graph_switch_grid_mode $grid_mode
+ $graph_latches graph_switch_grid_mode $grid_mode
+ $graph_output graph_switch_grid_mode $grid_mode
+ }
+
+ ## Zoom out
+ # @return void
+ public method graph_zoom_out {} {
+ if {!$magnification} {return}
+ incr magnification -1
+ commit_magnification
+ }
+
+ ## Zoom in
+ # @return void
+ public method graph_zoom_in {} {
+ if {$magnification == 3} {return}
+ incr magnification
+ commit_magnification
+ }
+
+ ## Commit new magnification level
+ # @return void
+ private method commit_magnification {} {
+ create_all_graph_widgets
+
+ $graph_state commit_magnification $magnification
+ $graph_latches commit_magnification $magnification
+ $graph_output commit_magnification $magnification
+
+ # Adjust states of magnification buttons
+ adjust_mag_buttons
+ }
+
+ ## Clear graph marks in the the current graph
+ # @return void
+ public method graph_clear_marks {} {
+ switch -- $active_page {
+ {state} { ;# Tab: True state
+ $graph_state graph_clear_marks
+ }
+ {latches} { ;# Tab: Port Latches
+ $graph_latches graph_clear_marks
+ }
+ {output} { ;# Tab: True Output
+ $graph_output graph_clear_marks
+ }
+ }
+ }
+
+ ## Clear all graphs
+ # @return void
+ public method clear_graph {} {
+ create_all_graph_widgets
+
+ $graph_state clear_graph
+ $graph_latches clear_graph
+ $graph_output clear_graph
+ }
+
+ ## Create GUI of all graphs
+ # @return void
+ private method create_all_graph_widgets {} {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ if {!$graph_state_created} {
+ $graph_state CreateGraphGUI
+ }
+ if {!$graph_latches_created} {
+ $graph_latches CreateGraphGUI
+ }
+ if {!$graph_output_created} {
+ $graph_output CreateGraphGUI
+ }
+ }
+
+ ## Get graph configuration values -- for project save
+ # @return List - Configuration list
+ public method graph_get_config {} {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ create_all_graph_widgets
+
+ return [list $grid_mode $magnification $drawing_on \
+ [$graph_state graph_get_marks] \
+ [$graph_latches graph_get_marks] \
+ [$graph_output graph_get_marks] \
+ $active_page \
+ ]
+ }
+
+ ## Try to restore graph state before the given number of program steps
+ # @parm Int bits - Number of steps to take back
+ # @return void
+ public method graph_stepback {bits} {
+ if {!$gui_initialized} {CreateGraphGUI}
+ if {!$drawing_on} {return}
+
+ create_all_graph_widgets
+
+ $graph_state graph_stepback $bits
+ $graph_latches graph_stepback $bits
+ $graph_output graph_stepback $bits
+ }
+
+ ## React to MCU change
+ # @return void
+ public method graph_change_mcu {} {
+ if {$graph_state_created} {
+ $graph_state change_mcu
+ }
+ if {$graph_latches_created} {
+ $graph_latches change_mcu
+ }
+ if {$graph_output_created} {
+ $graph_output change_mcu
+ }
+ }
+}
diff --git a/lib/bottompanel/graph_wdg.tcl b/lib/bottompanel/graph_wdg.tcl
new file mode 100755
index 0000000..bcb2d62
--- /dev/null
+++ b/lib/bottompanel/graph_wdg.tcl
@@ -0,0 +1,1115 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2008 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
+# Graph widget for showing port states
+# --------------------------------------------------------------------------
+
+class GraphWidget {
+ ## COMMON
+ common step_y 13 ;# Int: Vertical distance between graph rows
+ common half_edge 5 ;# Int: Half length of bit edge
+ common full_edge 10 ;# Int: Full length of bit edge
+
+ # Big font (vertical header)
+ common big_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 -weight bold \
+ ]
+ # Small font (horizontal header)
+ common small_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 -weight bold \
+ ]
+ # Font for booleans values for each port
+ common bool_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 -weight bold \
+ ]
+ # Definition of graph popup menu
+ common GRAPHMENU {
+ {command {ON/OFF} {} 0 "graph_change_status_on"
+ {} "Enable/Disable graph"}
+ {separator}
+ {command {Change grid} {} 1 "graph_switch_grid_mode 1"
+ {} "Change grid morfology"}
+ {separator}
+ {command {Zoom in} {} 1 "graph_zoom_in"
+ {viewmag_in} "Change bit length on X axis to a lower value"}
+ {command {Zoom out} {} 1 "graph_zoom_out"
+ {viewmag_out} "Change bit length on X axis to a higher value"}
+ {separator}
+ {command {Remove marks} {} 1 "graph_clear_marks"
+ {editdelete} "Clear user marks"}
+ }
+
+ # Variables related to object initialization
+ private variable gui_initialized 0 ;# Bool: GUI created
+ private variable _parent ;# Parent widget
+ private variable parent ;# Innert parent widget
+
+ private variable canvasWidget ;# ID of the canvas widget
+ private variable grid_mode {b} ;# Current grid mode (one of {b n x y})
+ private variable drawing_on 1 ;# Bool: Graph enabled
+ private variable magnification 0 ;# Magnification level (0..3)
+ private variable graph_elements ;# Array: IDs of graph elements (green and red lines)
+ private variable intr_lines {} ;# List of IDs of interrupt lines
+ private variable marks {} ;# List of IDs mark rectangulars
+ private variable mark_flags {} ;# List of Boolean mark flags
+ private variable state_history {} ;# History of X bits (for changing magnification level and stepback)
+ private variable intr_history {} ;# History of X interrupt flags
+ private variable previous_state ;# Array: previous state of each bit
+ private variable menu {} ;# ID of canvas popup menu
+ private variable step_x ;# Number of pixels required for draw one bit
+ private variable scrollable_frame ;# Widget: Scrollable area (parent for all other widgets)
+ private variable horizontal_scrollbar ;# Widget: Horizontal scrollbar for scrollable area
+ private variable number_of_ports ;# Int: Number of MCU's ports (see engine proc. get_ports_info)
+ private variable port_numbers ;# List: Numbers of implemented ports (e.g. {0 3})
+ private variable port_length_in_px ;# Length of one port segment in PX
+ private variable port_graph_length ;# Same as port_length_in_px but only visible area
+ private variable history_max_length ;# Maximum history depth
+
+ private variable Super ;# Object: Super
+
+
+ ## Prepare object for creating its GUI
+ # @parm Widget Parent - GUI parent widget
+ # @parm List _data_list - Configuration data list
+ # @return void
+ constructor {Parent super} {
+ set _parent $Parent
+ set Super $super
+ set gui_initialized 0
+ }
+
+ ## Object destructor
+ destructor {
+ if {$gui_initialized} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## React to MCU change
+ # @return void
+ public method change_mcu {} {
+ if {!$gui_initialized} {return}
+
+ foreach wdg [winfo children $_parent] {
+ destroy $wdg
+ }
+ set gui_initialized 0
+ CreateGraphGUI
+ }
+
+ ## Initialize graph
+ # @return void
+ public method CreateGraphGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Determinate number of ports and port indexes
+ set number_of_ports [$Super get_ports_info]
+ set port_numbers [lindex $number_of_ports 1]
+ set number_of_ports [lindex $number_of_ports 0]
+
+ set port_length_in_px [expr {840 / $number_of_ports}]
+ set port_graph_length [expr {$port_length_in_px - 15}]
+ set history_max_length [expr {$port_graph_length / 5}]
+
+ # Create scrollable area
+ set scrollable_frame [ScrollableFrame $_parent.scrollable_frame \
+ -xscrollcommand "$this graph_gui_scroll_set" \
+ ]
+ set horizontal_scrollbar [ttk::scrollbar $_parent.horizontal_scrollbar \
+ -orient horizontal -command "$scrollable_frame xview" \
+ ]
+ pack $scrollable_frame -fill both -side bottom -expand 1
+ set parent [$scrollable_frame getframe]
+
+ # Create canvas widget
+ set canvasWidget [canvas $parent.canvas \
+ -height 120 -width 860 -bd 0 \
+ -highlightthickness 0 \
+ ]
+
+ # Create graph headers
+ for {set i 0; set y 17} {$i < 8} {incr i; incr y $step_y} {
+ $canvasWidget create text 10 $y -text $i -font $small_font -anchor n -fill {#0000FF} -tags background
+ }
+ for {set i 0} {$i < $number_of_ports} {incr i} {
+ set x [expr {$i * $port_length_in_px + $port_length_in_px / 2 + 20}]
+ $canvasWidget create text $x 7 \
+ -text "P[lindex $port_numbers $i]" \
+ -font $big_font -fill {#0000FF} -tags background
+ }
+ # Create separators
+ $canvasWidget create line 20 0 20 120 -fill {#000000} -tags background
+ $canvasWidget create line 0 15 860 15 -fill {#000000} -tags background
+ for {set i 1} {$i <= $number_of_ports} {incr i} {
+ set x [expr {$i * $port_length_in_px + 20}]
+ $canvasWidget create line $x 0 $x 120 -fill {#000000} -tags background
+ incr x -$step_y
+ $canvasWidget create line $x 0 $x 120 -fill {#888888} -tags background
+ }
+
+ # Initialize array of graph elements and previous states
+ for {set i 0} {$i < 40} {incr i} {
+ set graph_elements($i) {}
+ set previous_state($i) 1
+ }
+
+ # Create canvas popup menu
+ set menu $canvasWidget.menu
+ menuFactory $GRAPHMENU $menu 0 "$Super " 0 {}
+
+
+ # Set event bindings for the canvas widget
+ bind $canvasWidget <Motion> "$this graph_highlight %x %y"
+ bind $canvasWidget <Leave> "$this graph_unhighlight"
+ bind $canvasWidget <ButtonRelease-3> "$this graph_popup_menu %X %Y"
+ bind $canvasWidget <Button-1> "$this graph_place_mark %x %y"
+
+ # Pack the canvas widget
+ set marks [string repeat {{} } [expr {$history_max_length + 1}]]
+ pack $canvasWidget -fill none -expand 0 -anchor nw -side left
+
+ # Commit magnification level
+ commit_magnification $magnification
+
+ # Commit ON/OFF state
+ commit_state_on_off $drawing_on
+
+ # Create graph grid
+ graph_switch_grid_mode $grid_mode
+ }
+
+ ## Draw interrupt line
+ # @parm String = {} - If "nohistory" the history of interrupt lines will not be modified
+ # @return void
+ public method graph_draw_interrupt_line args {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ # Check if graph is enabled
+ if {!$drawing_on} {return}
+
+ # Adjust history
+ if {$args != {nohistory}} {
+ if {[llength $intr_history]} {
+ lset intr_history end 1
+ } {
+ lappend intr_history 1
+ }
+ }
+
+ # Create interrupt lines
+ set lines {}
+ for {set col 0} {$col < $number_of_ports} {incr col} {
+ set x [expr {$col * $port_length_in_px + ([llength $graph_elements(0)] * $step_x) + 20}]
+ lappend lines [$canvasWidget create line $x 16 $x 120 \
+ -fill {#DDAA00} -tags graph -width 2 -dash ,]
+ }
+
+ # Adjust list of canvas elements related to this line
+ if {$args != {nohistory}} {
+ if {[llength $intr_lines]} {
+ lset intr_lines end $lines
+ } {
+ lappend intr_lines $lines
+ }
+ }
+ }
+
+ ## Draw new port states in the graph
+ # A) With history enabled:
+ # @parm String - Hexadecimal value of P0
+ # @parm String - Hexadecimal value of P1
+ # @parm String - Hexadecimal value of P2
+ # @parm String - Hexadecimal value of P3
+ # @parm String - Hexadecimal value of P4
+ # B) With disabled:
+ # @parm List - {# {P0_hex P1_hex P2_hex P3_hex P4_hex}}
+ # @return void
+ public method graph_new_output_state args {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ # Check if graph is enabled
+ if {!$drawing_on} {return}
+
+ # Determinate number of bits per block and the current position
+ set treshold [expr {$port_graph_length / $step_x}]
+ set position [llength $graph_elements(0)]
+
+ # If graph is full -> remove last elements and move the graph
+ if {$position == $treshold} {
+ # Remove elemets
+ for {set i 0} {$i < ($number_of_ports * 8)} {incr i} {
+ foreach elm [lindex $graph_elements($i) 0] {
+ $canvasWidget delete $elm
+ }
+ set graph_elements($i) [lreplace $graph_elements($i) 0 0]
+ }
+ foreach elm [lindex $intr_lines 0] {
+ $canvasWidget delete $elm
+ }
+ set intr_lines [lreplace $intr_lines 0 0]
+ # Adjust position index
+ incr position -1
+ # Move graph
+ $canvasWidget move graph -$step_x 0
+ }
+
+ # Adjust history (cannot be longer than 38)
+ if {[llength $intr_history] > $history_max_length} {
+ set intr_history [lreplace $intr_history 0 0]
+ set state_history [lreplace $state_history 0 0]
+ }
+
+ # Adjust history
+ set args [join $args {}]
+ if {[lindex $args 0] != {#}} {
+ lappend state_history [list {#} $args]
+ lappend intr_history 0
+ } {
+ set args [lindex $args 1]
+ }
+ lappend intr_lines {}
+
+ # Adjust arguments
+ set ports {}
+ foreach idx $port_numbers {
+ lappend ports [lindex $args $idx]
+ }
+
+ # Create new elements
+ set p_idx 0 ;# Port index (not port number)
+ set idx 0 ;# Bit index
+ $canvasWidget delete booleans ;# Clear boolean values
+ foreach num_x $ports {
+ set num [list 0 0 0 0 0 0 0 0]
+ for {set i 0; set j 7} {$i < 8} {incr i; incr j -1} {
+ lset num $j [lindex $num_x $i]
+ }
+
+ # Draw bits
+ foreach bit $num {
+ draw_bit $idx $position $bit
+ incr idx
+ }
+ # Draw booleans
+ write_boolean $p_idx $num
+ incr p_idx
+ }
+ }
+
+ ## Write boolean values for the given port
+ # @parm Int port_idx - Port number
+ # @parm Int val - Port value
+ # @return void
+ private method write_boolean {port_idx val} {
+ set x [expr {($port_idx + 1) * $port_length_in_px + 13}]
+
+ for {set i 0; set y 17} {$i < 8} {incr i; incr y $step_y} {
+ switch -- [lindex $val $i] {
+ {1} {
+ set txt {H}
+ set clr {#FF0000}
+ }
+ {0} {
+ set txt {L}
+ set clr {#00FF00}
+ }
+ {|} {
+ set txt {-}
+ set clr {#FF8800}
+ }
+ {?} {
+ set txt {-}
+ set clr {#888888}
+ }
+ {X} {
+ set txt {-}
+ set clr {#8800FF}
+ }
+ {-} {
+ set txt {?}
+ set clr {#AAAA00}
+ }
+ {=} {
+ set txt {L}
+ set clr {#FF00AA}
+ }
+ }
+
+ $canvasWidget create text $x $y \
+ -text $txt \
+ -font $bool_font \
+ -anchor n \
+ -fill $clr \
+ -tags booleans
+ }
+ }
+
+ ## Draw one bit to the graph
+ # @parm Int idx - Bit index (0..39)
+ # @parm Int pos - Target position
+ # @parm Char bool - Bit value
+ # @return void
+ private method draw_bit {idx pos bool} {
+ # Local variables
+ set prev $previous_state($idx) ;# Previous state of the bit
+ set offset_y [expr {($idx % 8) * $step_y + 18}] ;# Y offset
+ set lines {} ;# List of line IDs
+ # X offset
+ set offset_x [expr {
+ ($idx / 8) * $port_length_in_px + ($pos * $step_x) + 20
+ }]
+
+ # Determinate length of line elements acording to the current magnification level
+ switch -- $magnification {
+ {0} {
+ set line_len 3
+ set enge_diff 0
+ set enge_inc0 0
+ set enge_inc1 0
+ }
+ {1} {
+ set line_len 4
+ set enge_diff 1
+ set enge_inc0 1
+ set enge_inc1 1
+ }
+ {2} {
+ set line_len 6
+ set enge_diff 1
+ set enge_inc0 2
+ set enge_inc1 1
+ }
+ {3} {
+ set line_len 8
+ set enge_diff 2
+ set enge_inc0 2
+ set enge_inc1 2
+ }
+ }
+
+ # Logical one forced to zero (e.g. by NPN transistor)
+ if {$bool == {=}} {
+ set bool 0
+ set zero_color {#FF00AA}
+ } {
+ set zero_color {#FF0000}
+ }
+
+ ## Draw graph line(s)
+
+ # High frequency pulse
+ if {$bool == {|}} {
+ # Draw transition from the previous value
+ switch -- $prev {
+ {0} { ;# From logical 0
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+ }
+ {1} { ;# From logical 1
+ }
+ {?} { ;# From no voltage
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+ }
+ {-} { ;# From undeterminable state
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+ }
+ }
+
+ if {$magnification == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + 1}] $offset_y \
+ [expr {$offset_x + 1}] [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+
+ lappend lines [$canvasWidget create line \
+ [expr {$offset_x + 1}] [expr {$offset_y + $half_edge}] \
+ [expr {$offset_x + 1}] [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + 3}] [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + 3}] [expr {$offset_y + $half_edge}] \
+ -fill {#00FF00} -tags graph]
+
+ lappend lines [$canvasWidget create line \
+ [expr {$offset_x + 4}] [expr {$offset_y + $half_edge}] \
+ [expr {$offset_x + 4}] [expr {$offset_y}] \
+ -fill $zero_color -tags graph]
+ } else {
+ switch -- $magnification {
+ {1} {
+ set line_len 3
+ set enge_diff 0
+ set enge_inc0 0
+ set enge_inc1 0
+ }
+ {2} {
+ set line_len 4
+ set enge_diff 1
+ set enge_inc0 1
+ set enge_inc1 1
+ }
+ {3} {
+ set line_len $half_edge
+ set enge_diff 1
+ set enge_inc0 2
+ set enge_inc1 1
+ }
+ }
+
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $line_len}] $offset_y\
+ -fill $zero_color -tags graph]
+ incr offset_x $line_len
+ lappend lines [$canvasWidget create line\
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] \
+ [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph \
+ ]
+ incr offset_x $enge_inc0
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line\
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] \
+ [expr {$offset_y + 5}] \
+ -fill {#00FF00} -tags graph \
+ ]
+ incr offset_x $enge_inc1
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $line_len + 1}] $offset_y \
+ -fill {#00FF00} -tags graph]
+
+ incr offset_x $line_len
+ incr offset_x
+ lappend lines [$canvasWidget create line\
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] \
+ [expr {$offset_y - $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ incr offset_x $enge_inc0
+ incr offset_y -$half_edge
+ lappend lines [$canvasWidget create line\
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] \
+ [expr {$offset_y - $half_edge}] \
+ -fill $zero_color -tags graph]
+ incr offset_x $enge_inc1
+ incr offset_y -$half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $line_len}] $offset_y \
+ -fill $zero_color -tags graph]
+ }
+
+ # Access to external memory
+ } elseif {$bool == {X}} {
+ lappend lines [$canvasWidget create rectangle \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -width 0 -tags graph]
+ lappend lines [$canvasWidget create rectangle \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \
+ -fill {#00FF00} -width 0 -tags graph]
+
+
+ set bool $prev
+
+ # Underminable state
+ } elseif {$bool == {-}} {
+ # Draw transition from the previous value
+ switch -- $prev {
+ {0} { ;# From logical zero
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ }
+ {1} { ;# From logical one
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ }
+ {|} { ;# From high frequency pulse
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ }
+ }
+
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $line_len}] [expr {$offset_y + int(rand() * $half_edge)}] \
+ [expr {$offset_x + $line_len + $enge_inc0}] $offset_y \
+ [expr {$offset_x + $line_len + $enge_inc0 + $enge_inc1}] [expr {$offset_y - int(rand() * $half_edge)}] \
+ [expr {$offset_x + 2*$line_len + $enge_inc0 + $enge_inc1}] $offset_y \
+ -fill {#FF8800} -tags graph]
+
+ # "Undeterminable state" -> "Zero"
+ } elseif {$prev == {-} && $bool == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \
+ -fill {#00FF00} -tags graph]
+
+ # "Undeterminable state" -> "One"
+ } elseif {$prev == {-} && $bool == 1} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+
+ # No voltage
+ } elseif {$bool == {?}} {
+ # Draw transition from the previous value
+ switch -- $prev {
+ {0} { ;# From logical zero
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ }
+ {1} { ;# From logical one
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ }
+ {|} { ;# From high frequency pulse
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ }
+ }
+
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] $offset_y \
+ -fill {#888888} -tags graph -width 2]
+
+ # "No voltage" -> "Zero"
+ } elseif {$prev == {?} && $bool == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \
+ -fill {#00FF00} -tags graph]
+
+ # "No voltage" -> "One"
+ } elseif {$prev == {?} && $bool == 1} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+
+ # "High freq. pulse" -> "Zero"
+ } elseif {$prev == {|} && $bool == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \
+ -fill {#00FF00} -tags graph]
+
+ # "High freq. pulse" -> "One"
+ } elseif {$prev == {|} && $bool == 1} {
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] $offset_y \
+ -fill $zero_color -tags graph]
+
+ # 1 -> 1
+ } elseif {$prev == 1 && $bool == 1} {
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] $offset_y \
+ -fill $zero_color -tags graph]
+
+ # 1 -> 0
+ } elseif {$prev == 1 && $bool == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \
+ -fill $zero_color -tags graph]
+ incr offset_x $line_len
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ incr offset_x $enge_inc0
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] [expr {$offset_y + 5}] \
+ -fill {#00FF00} -tags graph]
+ incr offset_x $enge_inc1
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \
+ -fill {#00FF00} -tags graph]
+
+ # 0 -> 1
+ } elseif {$prev == 0 && $bool == 1} {
+ incr offset_y $full_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \
+ -fill {#00FF00} -tags graph]
+ incr offset_x $line_len
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] [expr {$offset_y - $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ incr offset_x $enge_inc0
+ incr offset_y -$half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] [expr {$offset_y - $half_edge}] \
+ -fill $zero_color -tags graph]
+ incr offset_x $enge_inc1
+ incr offset_y -$half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \
+ -fill $zero_color -tags graph]
+
+ # 0 -> 0
+ } else {
+ incr offset_y $full_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] $offset_y \
+ -fill {#00FF00} -tags graph]
+ }
+
+ # Adjust array of graph elements and previous states
+ lappend graph_elements($idx) $lines
+ set previous_state($idx) $bool
+ }
+
+ ## Iterate over avaliable grid modes
+ # @parm Int by - Iterate by
+ # @return void
+ public method graph_switch_grid_mode {_grid_mode} {
+ set grid_mode $_grid_mode
+
+ # Adjust button in button bar and canvas popup menu
+ switch -- $grid_mode {
+ {b} {set image {grid0}}
+ {n} {set image {grid1}}
+ {y} {set image {grid2}}
+ {x} {set image {grid3}}
+ }
+ $menu entryconfigure [::mc "Change grid"] -image ::ICONS::16::$image
+ # Redraw grid
+ adjust_grid
+ }
+
+ ## Adjust grid morfology to the current grid mode
+ # @return void
+ private method adjust_grid {} {
+ # Remove the current grid
+ catch {
+ $canvasWidget delete grid
+ }
+ # Create new grid
+ switch -- $grid_mode {
+ {b} {
+ draw_y_grid
+ draw_x_grid
+ }
+ {n} {}
+ {y} {draw_y_grid}
+ {x} {draw_x_grid}
+ }
+ }
+
+ ## Draw vertical grid lines
+ # @return void
+ private method draw_y_grid {} {
+ # Iterate over graph blocks
+ for {set i 0} {$i < $number_of_ports} {incr i} {
+ # Determinate horizontal boundaries
+ set xoff [expr {$i * $port_length_in_px + 20 + $step_x}]
+ set xend [expr {($i + 1) * $port_length_in_px + 5}]
+ # Draw vertical lines
+ for {set x $xoff} {$x < $xend} {incr x $step_x} {
+ $canvasWidget create line $x 16 $x 120 -fill {#AAAAAA} -tags grid -dash .
+ }
+ }
+ }
+
+ ## Draw horizontal grid lines
+ # @return void
+ private method draw_x_grid {} {
+ for {set y 30} {$y < 120} {incr y $step_y} {
+ $canvasWidget create line 0 $y 860 $y -fill {#888888} -tags grid
+ }
+ }
+
+ ## Set graph configuration variables
+ # @parm Char _grid_mode - Grid morfology (one of {'n' 'x' 'y' 'b'})
+ # @parm Int _magnification - Magnification mode (one of {0 1 2 3})
+ # @parm Bool _drawing_on - Widget enabled
+ # @parm List _mark_flags - List of mark flags (e.g {0 0 0 1 1 0})
+ # @return void
+ public method graph_set_data {_grid_mode _magnification _drawing_on _mark_flags} {
+ set grid_mode $_grid_mode
+ set magnification $_magnification
+ set drawing_on $_drawing_on
+ set mark_flags $_mark_flags
+ }
+
+ ## Get mark flags
+ # @return String - String of boolean flags
+ public method graph_get_marks {} {
+ return [join $mark_flags {}]
+ }
+
+ ## Adjust graph to the current magnification level
+ # @return void
+ public method commit_magnification {_magnification} {
+ set magnification $_magnification
+
+ # Determinate one bit X axis step
+ set step_x [expr {$magnification * 5 + 5}]
+
+ clear_graph keephistory ;# Clear graph
+ adjust_grid ;# Adjust graph grid
+ # Remove user marks
+ catch {
+ $canvasWidget delete mark
+ }
+
+ # Restore graph content from the history (voltage levels and interrupt lines)
+ set length [expr {$port_graph_length / $step_x - 1}]
+ foreach state [lrange $state_history end-$length end] \
+ intr [lrange $intr_history end-$length end] \
+ {
+ graph_new_output_state $state
+ if {$intr == 1} {
+ graph_draw_interrupt_line nohistory
+ }
+ }
+
+ # Restore user marks
+ set x_off [expr {21 - $step_x}]
+ set i -1
+ foreach mark [lrange $mark_flags 0 $length] {
+ incr i
+ incr x_off $step_x
+ if {!$mark} {continue}
+
+ set x $x_off
+ set lines [list]
+ for {set j 0} {$j < $number_of_ports} {incr j} {
+ lappend lines [$canvasWidget create rectangle \
+ $x 16 [expr {$x + $step_x - 1}] 120 \
+ -fill {#AA88FF} -tags mark -width 0]
+ incr x $port_length_in_px
+ }
+ lset marks $i $lines
+ }
+ }
+
+ ## Remove all graph elements (voltage levels)
+ # @parm String - If "keephistory" then do not clear history
+ # @return void
+ public method clear_graph args {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ catch {
+ $canvasWidget delete graph
+ }
+ catch {
+ $canvasWidget delete highlight
+ }
+ catch {
+ $canvasWidget delete booleans
+ }
+ for {set i 0} {$i < 40} {incr i} {
+ set graph_elements($i) {}
+ }
+ set intr_lines {}
+
+ if {$args != {keephistory}} {
+ set state_history {}
+ set intr_history {}
+ for {set i 0} {$i < 40} {incr i} {
+ set previous_state($i) 1
+ }
+ }
+ }
+
+ ## Turn graph ON/OFF
+ # @return void
+ public method graph_change_status_on {} {
+ $Super graph_commit_state_on_off $drawing_on
+ }
+
+ ## Adjust object to the current value of flag 'drawing_on'
+ # @return void
+ public method commit_state_on_off {_drawing_on} {
+ if {!$gui_initialized} {CreateGraphGUI}
+ set drawing_on $_drawing_on
+
+ # Enable widgets
+ if {$drawing_on} {
+ $menu entryconfigure [::mc "Remove marks"] -state normal
+ $menu entryconfigure [::mc "Change grid"] -state normal
+ $canvasWidget configure -state normal
+
+ # Disable widgets, clear graph and clear history
+ } else {
+ $menu entryconfigure [::mc "Remove marks"] -state disabled
+ $menu entryconfigure [::mc "Change grid"] -state disabled
+ $menu entryconfigure [::mc "Zoom in"] -state disabled
+ $menu entryconfigure [::mc "Zoom out"] -state disabled
+ $canvasWidget configure -state disabled
+ clear_graph
+ }
+ }
+
+ ## Highlight graph segment
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method graph_highlight {x y} {
+ # Remove previous highlight
+ graph_unhighlight
+
+ # Check for allowed coordinate range
+ if {$y < 17 || $x < 21} {return}
+ set x [expr {($x - 20) % $port_length_in_px}]
+ if {$x >= $port_graph_length - ($port_graph_length % $step_x)} {return}
+
+ incr x [expr {-($x % $step_x)}]
+ incr x 21
+
+ # Draw highlight rectangulars
+ for {set i 0} {$i < $number_of_ports} {incr i} {
+ $canvasWidget create rectangle \
+ $x 16 [expr {$x + $step_x - 1}] 120 \
+ -fill {#88FFFF} -tags highlight -width 0
+ incr x $port_length_in_px
+ }
+
+ set y [expr {$y - (($y - 17) % $step_y)}]
+
+ $canvasWidget create rectangle \
+ 0 $y 860 [expr {$y + $step_y}] \
+ -fill {#88FFFF} -tags highlight -width 0
+
+ # Set tag priorities
+ catch {
+ $canvasWidget lower highlight mark
+ }
+ catch {
+ $canvasWidget lower highlight grid
+ }
+ catch {
+ $canvasWidget lower highlight graph
+ }
+ catch {
+ $canvasWidget lower highlight booleans
+ }
+ catch {
+ $canvasWidget lower highlight background
+ }
+ }
+
+ ## Remove highlightion
+ # @return void
+ public method graph_unhighlight {} {
+ catch {
+ $canvasWidget delete highlight
+ }
+ }
+
+ ## Popup canvas menu
+ # @parm Int X - Absolute X coordinate
+ # @parm Int Y - Absolute X coordinate
+ # @return void
+ public method graph_popup_menu {X Y} {
+ tk_popup $menu $X $Y
+ }
+
+ ## Place mark in the graph
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method graph_place_mark {x y} {
+ # Check for allowed coordinate range
+ if {$y < 17 || $x < 21} {return}
+ set x [expr {($x - 20) % $port_length_in_px}]
+ if {$x >= $port_graph_length - ($port_graph_length % $step_x)} {return}
+
+ incr x [expr {-($x % $step_x)}]
+ set idx [expr {$x / $step_x}]
+
+ # Create mark
+ if {[lindex $mark_flags $idx] != 1} {
+ incr x 21
+ set lines {}
+ for {set i 0} {$i < $number_of_ports} {incr i} {
+ lappend lines [$canvasWidget create rectangle \
+ $x 16 [expr {$x + $step_x - 1}] 120 \
+ -fill {#AA88FF} -tags mark -width 0]
+ incr x $port_length_in_px
+ }
+ catch {
+ $canvasWidget raise mark highlight
+ }
+ catch {
+ $canvasWidget lower mark grid
+ }
+ catch {
+ $canvasWidget lower mark graph
+ }
+ lset marks $idx $lines
+ lset mark_flags $idx 1
+
+ # Remove mark
+ } {
+ catch {
+ foreach elm [lindex $marks $idx] {
+ $canvasWidget delete $elm
+ }
+ }
+ lset marks $idx {}
+ lset mark_flags $idx 0
+ }
+ }
+
+ ## Remove all user marks from the graph
+ # @return void
+ public method graph_clear_marks {} {
+ catch {
+ $canvasWidget delete mark
+ }
+ set marks [string repeat {{} } [expr {$history_max_length + 1}]]
+ set mark_flags [string repeat {0 } [expr {$history_max_length + 1}]]
+ }
+
+ ## Adjust scrollbar for scrollable area
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method graph_gui_scroll_set {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $horizontal_scrollbar]} {
+ pack forget $horizontal_scrollbar
+ update
+ }
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $horizontal_scrollbar]} {
+ pack $horizontal_scrollbar -fill x -side top -before $scrollable_frame
+ }
+ $horizontal_scrollbar set $frac0 $frac1
+ update
+ }
+ }
+
+ ## Try to restore graph state before the given number of program steps
+ # @parm Int bits - Number of steps to take back
+ # @return void
+ public method graph_stepback {bits} {
+ if {!$gui_initialized} {CreateGraphGUI}
+ if {!$drawing_on} {return}
+
+ # Remove elemets
+ incr bits -1
+ for {set i 0} {$i < ($number_of_ports * 8)} {incr i} {
+ foreach elm [lrange $graph_elements($i) end-$bits end] {
+ foreach e $elm {
+ $canvasWidget delete $e
+ }
+ }
+ foreach elm [lrange $intr_lines end-$bits end] {
+ foreach e $elm {
+ $canvasWidget delete $e
+ }
+ }
+ set graph_elements($i) [lreplace $graph_elements($i) end-$bits end]
+ }
+ set intr_lines [lreplace $intr_lines end-$bits end]
+
+ # Adjust history
+ set intr_history [lreplace $intr_history end-$bits end]
+ set state_history [lreplace $state_history end-$bits end]
+
+ # Return graph to state before $bits steps
+ set last_state [lindex $state_history {end 1}]
+ if {[llength $last_state]} {
+ set ports {}
+ foreach idx $port_numbers {
+ lappend ports [lindex $last_state $idx]
+ }
+
+ set p_idx 0 ;# Port index (not port number)
+ set idx 0 ;# Bit index
+ $canvasWidget delete booleans ;# Clear boolean values
+ foreach num $ports {
+ foreach bit $num {
+ set previous_state($idx) $bit
+ incr idx
+ }
+ # Draw booleans
+ write_boolean $p_idx $num
+ incr p_idx
+ }
+ } else {
+ clear_graph
+ }
+ }
+}
diff --git a/lib/bottompanel/messages.tcl b/lib/bottompanel/messages.tcl
new file mode 100755
index 0000000..51c96ce
--- /dev/null
+++ b/lib/bottompanel/messages.tcl
@@ -0,0 +1,632 @@
+#!/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 messages text for the bottom panel of the project tab
+# --------------------------------------------------------------------------
+
+class Messages {
+
+ ## COMMON
+ common set_shortcuts {} ;# Currently set shortcut bindigs for messages text
+ common shortcuts_cat {messages} ;# Key shortcut categories related to messages text
+ # Normal font for messages text
+ common messages_normal_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12]
+ # Bold font for messages text
+ common messages_bold_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold]
+ # Definition of popup menu for messages text
+ common MESSAGESMENU {
+ {command {Select all} {Ctrl+A} 0 "select_all_messages_text"
+ {} "Select all text in this TextBox"}
+ {command {Copy} {Ctrl+C} 0 "copy_messages_text"
+ {editcopy} "Copy selected text into clipboard"}
+ {command {Clear} {$messages:clear_mess} 1 "clear_messages_text"
+ {editdelete} "Clear all messages"}
+ {separator}
+ {command {Find} {$messages:mess_find} 0 "messages_text_find_dialog"
+ {find} {}}
+ {command {Find next} {$messages:mess_find_n} 5 "messages_text_find_next"
+ {down0} {}}
+ {command {Find previous} {$messages:mess_find_p} 8 "messages_text_find_prev"
+ {up0} {}}
+ }
+
+ private variable main_frame ;# Widget: Main frame
+ private variable messages_text ;# Widget: text widget
+ private variable menu {} ;# Widget: popup menu
+ private variable hyperlink_line_start ;# TextIndex: Active hyperlink line start index
+
+ # Variables related to object initialization
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ # Variables related to search bar
+ private variable search_frame ;# Widget: Search bar frame
+ private variable last_find_index {} ;# String: Index of last found occurence of the search string
+ private variable search_string ;# String: Search string
+ private variable search_string_length ;# Int: Length of the search string
+ private variable search_entry ;# Widget: Search bar entry box
+ private variable search_find_next ;# Widget: Button "Next"
+ private variable search_find_prev ;# Widget: Button "Prev"
+
+ constructor {} {
+ }
+
+ destructor {
+ # Remove status bar help for popup menus
+ if {$menu != {}} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @return void
+ public method PrepareMessages {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method MessagesTabRaised {} {
+ focus $messages_text
+ }
+
+ ## Create GUI of messages tab
+ # @return void
+ public method CreateMessagesGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ ## Create GUI of main frame
+ set main_frame [frame $parent.main_frame]
+ # Create messages text and its scrollbar
+ set messages_text [text $main_frame.messages_text \
+ -state disabled -cursor xterm \
+ -yscrollcommand "$main_frame.msg_text_scrl set" \
+ -font $messages_normal_font -wrap word \
+ -tabstyle wordprocessor \
+ ]
+ set messages_text_scrl [ttk::scrollbar $main_frame.msg_text_scrl \
+ -command "$messages_text yview" -orient vertical \
+ ]
+ # Text tags for messages text
+ $messages_text tag configure error \
+ -foreground #FF0000 \
+ -underline 1 \
+ -font $messages_bold_font
+ $messages_text tag configure error_nu \
+ -foreground #FF0000 \
+ -underline 0 \
+ -font $messages_bold_font
+ $messages_text tag configure warning \
+ -foreground #FF8800 \
+ -underline 1 \
+ -font $messages_bold_font
+ $messages_text tag configure warning_nu \
+ -foreground #FF8800 \
+ -underline 0 \
+ -font $messages_bold_font
+ $messages_text tag configure successful \
+ -foreground #00DD00 \
+ -font $messages_bold_font
+ $messages_text tag configure hyper_link_over \
+ -foreground #0055FF -underline 0 \
+ -font $messages_bold_font
+ $messages_text tag raise hyper_link_over
+
+ $messages_text tag bind error <ButtonPress-1> "$this messages_text_anchor %x %y"
+ $messages_text tag bind error <Enter> "$this messages_text_hyperlink_enter %x %y"
+ $messages_text tag bind error <Leave> "$this messages_text_hyperlink_leave"
+ $messages_text tag bind error <Motion> "$this messages_text_hyperlink_motion %x %y"
+ $messages_text tag bind warning <ButtonPress-1> "$this messages_text_anchor %x %y"
+ $messages_text tag bind warning <Enter> "$this messages_text_hyperlink_enter %x %y"
+ $messages_text tag bind warning <Leave> "$this messages_text_hyperlink_leave"
+ $messages_text tag bind warning <Motion> "$this messages_text_hyperlink_motion %x %y"
+ # Popup menu for messages text
+ set menu $messages_text.messages_text_menu
+ messages_text_makePopupMenu
+ # Bindings for messages text
+ bind $messages_text <ButtonPress-1> "focus $messages_text"
+ bind $messages_text <Control-a> "$this select_all_messages_text"
+ bind $messages_text <ButtonRelease-3> "tk_popup $menu %X %Y; break"
+ bind $messages_text <Key-Menu> "$this messages_text_key_menu; break"
+ # Pack parts of main frame
+ pack $messages_text -fill both -expand 1 -side left
+ pack $messages_text_scrl -fill y -side right
+ pack $main_frame -fill both -expand 1
+
+ ## Create GUI components in search bar frame
+ set search_frame [frame $parent.search_frame]
+ # Search entry box
+ set search_entry [ttk::entry $search_frame.entry \
+ -width 30 \
+ -validate all \
+ -validatecommand "$this messages_text_search %P" \
+ ]
+ bind $search_entry <Key-Escape> "$this messages_text_hide_find_dialog"
+ # Button: "Next"
+ set search_find_next [ttk::button $search_frame.find_next_but \
+ -image ::ICONS::16::down0 \
+ -style Flat.TButton \
+ -command "$this messages_text_find_next" \
+ -state disabled \
+ ]
+ DynamicHelp::add $search_frame.find_next_but \
+ -text [mc "Find next occurence of search string"]
+ # Button: "Prev"
+ set search_find_prev [ttk::button $search_frame.find_prev_but \
+ -image ::ICONS::16::up0 \
+ -style Flat.TButton \
+ -command "$this messages_text_find_prev" \
+ -state disabled \
+ ]
+ DynamicHelp::add $search_frame.find_prev_but \
+ -text [mc "Find previous occurence of search string"]
+ # Button: "Close"
+ pack [ttk::button $search_frame.close_but \
+ -image ::ICONS::16::button_cancel \
+ -style Flat.TButton \
+ -command "$this messages_text_hide_find_dialog" \
+ ] -side left
+ DynamicHelp::add $search_frame.close_but \
+ -text [mc "Hide search bar"]
+ # Separator
+ pack [ttk::separator $search_frame.sep \
+ -orient vertical \
+ ] -fill y -padx 5 -side left -pady 2
+ # Label: "Find"
+ pack [label $search_frame.find_lbl \
+ -text [mc "Find:"] \
+ ] -side left
+ # Pack entry and buttons next and prev
+ pack $search_entry -side left
+ pack $search_find_next -side left -padx 5
+ pack $search_find_prev -side left
+ # Checkbutton: "Match case"
+ pack [checkbutton $search_frame.match_case_chb \
+ -text [mc "Match case"] \
+ -variable ::Todo::match_case \
+ -command "$this messages_text_perform_search 1 1.0" \
+ ] -side left -padx 5
+
+
+ messages_text_shortcuts_reevaluate
+ unset parent
+ }
+
+ ## Select all text in messages text
+ # @return void
+ public method select_all_messages_text {} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+ $messages_text tag add sel 1.0 end
+ }
+
+ ## Copy selected text in messages text into clipboard
+ # @return void
+ public method copy_messages_text {} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+ clipboard clear
+ if {[llength [$messages_text tag nextrange sel 1.0]]} {
+ clipboard append [$messages_text get sel.first sel.last]
+ } {
+ clipboard append [$messages_text get 1.0 end]
+ }
+ }
+
+ ## Create bindings for defined key shortcuts for messages text
+ # @return void
+ public method messages_text_shortcuts_reevaluate {} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+
+ # Unset previous configuration
+ foreach key $set_shortcuts {
+ bind $messages_text <$key> {}
+ }
+ set set_shortcuts {}
+
+ # Iterate over shortcuts definition
+ foreach block ${::SHORTCUTS_LIST} {
+ # Determinate category
+ set category [lindex $block 0]
+ if {[lsearch $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 set_shortcuts $key
+ set cmd [subst [lindex $block [list $j 1]]]
+ append cmd {;break}
+ bind $messages_text <$key> $cmd
+ bind $search_entry <$key> $cmd
+ }
+ }
+ }
+
+ ## Define popup menu for messages text
+ # @return void
+ public method messages_text_makePopupMenu {} {
+ if {!$gui_initialized} {return}
+ if {[winfo exists $menu]} {
+ destroy $menu
+ }
+ menuFactory $MESSAGESMENU $menu 0 "$this " 0 {}
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ }
+
+ ## Handles event: 'Menu' on messages text -- invoke popup menu
+ # @return void
+ public method messages_text_key_menu {} {
+ $messages_text see insert
+ set bbox [$messages_text bbox [$messages_text index insert]]
+ tk_popup $menu \
+ [expr {[winfo rootx $messages_text] + [lindex $bbox 0] + 10}] \
+ [expr {[winfo rooty $messages_text] + [lindex $bbox 1] + 10}]
+ }
+
+ ## Clear all content of messages text
+ # @return void
+ public method clear_messages_text {} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+
+ $messages_text configure -state normal
+ $messages_text delete 0.0 end
+ $messages_text configure -state disabled
+ }
+
+ ## Goto line (in editor) which is somehow related to some tag in messages text
+ # @parm int x - relative x coordinate in messages text widget
+ # @parm int y - relative y coordinate in messages text widget
+ # @return void
+ public method messages_text_anchor {x y} {
+ # Determinate line number for editor
+ set idx [$messages_text index @$x,$y]
+ set line [$messages_text get "$idx linestart" "$idx lineend"]
+ # Focus on editor and goto that line
+
+ # Message from As31 assembler
+ if {[regexp {^(Error)|(Warning)\, line \d+} $line line]} {
+ if {![regexp {\d+$} $line lineNum]} {
+ set lineNum 0
+ }
+
+ if {$lineNum} {
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto $lineNum
+ }
+
+ # Message from ASEM-51 assembler
+ } elseif {[regexp {^([^\(\)]+\(\d+(\,\d+)?\)\: \w+)} $line line]} {
+ if {![regexp {\(\d+(\,\d+)?\):} $line lineNum]} {
+ set lineNum 0
+ } {
+ set lineNum [string range $lineNum 1 end-2]
+ set lineNum [lindex [split $lineNum {,}] 0]
+ }
+ if {[regexp {^.+\(\d+(\,\d+)?\):} $line target_filename]} {
+ set target_filename [regsub {\(\d+(\,\d+)?\):$} $target_filename {}]
+ set current_filename [lindex [$this editor_procedure {} getFileName {}] 1]
+ if {$target_filename != $current_filename} {
+ if {![$this fucus_specific_editor $target_filename 0]} {
+ return
+ }
+ }
+ }
+ if {$lineNum} {
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto "$lineNum"
+ }
+
+ # GNU error message (from SDCC or ASL)
+ } elseif {[regexp {\:\d+\:} $line linenum]} {
+ if {[regexp {[^\:]+\:} $line target_filename]} {
+ set target_filename [string trim [string range $target_filename 0 {end-1}]]
+ set current_filename [lindex [$this editor_procedure {} getFileName {}] 1]
+ if {$target_filename != $current_filename} {
+ if {![$this fucus_specific_editor $target_filename 0]} {
+ return
+ }
+ }
+ }
+
+ set linenum [string trim $linenum {:}]
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto $linenum
+
+ # Message from MCU8051IDE assembler
+ } elseif {[regexp {at \d+ in [^\:]+\:} $line line]} {
+ if {[regexp { in [^\:]+\:} $line target_filename]} {
+ set target_filename [string trim [string range $target_filename 4 {end-1}] "\""]
+ set current_filename [lindex [$this editor_procedure {} getFileName {}] 1]
+ if {$target_filename != $current_filename} {
+ if {![$this fucus_specific_editor $target_filename 0]} {
+ return
+ }
+ }
+ }
+
+ regexp {\d+} $line lineNum
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto $lineNum
+ }
+ }
+
+ ## Append text at the end of messages text
+ # @parm String txt - Text to append
+ # @return Bool - True if error occured
+ public method messages_text_append {txt} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+
+ # Enable the messages text widget
+ $messages_text configure -state normal
+
+ set ern 0 ;# The text is some error, but text should not be underlined and linked to certain line
+ set err 0 ;# The text is some error
+ set war 0 ;# The text is some warning which points to specific line in source code
+ set warn 0 ;# The text is some warning
+ set suc 0 ;# The text is success message
+
+ foreach text [split $txt "\n"] {
+ set ern 0
+ set err 0
+ set war 0
+ set warn 0
+ set suc 0
+
+ # Determinate number of the last line in the widget
+ set row [expr {int([$messages_text index end]) - 1}]
+
+ ## Determinate what kind of text will be inserted
+
+ # check for error which points to specific line in source code
+ if {[regexp {^(\|EL\|.*)|^(Compilation error at \d+ in [^\:]+\:)|^(Syntax error at \d+ in [^\:]+\:)|^(Error at\s+\d+ in [^\:]+\:)|^(.+:\d+: .*error.*)|^(.+\(\d+(\,\d+)?\): \w+.*)|^(Error\, line \d+)} $text error]} {
+ set len [string length $error]
+ set err 1
+
+ # check for an error
+ } elseif {[regexp {^(\|EN\|.*)|^(File access error:)|^(FAILED)|^(Compilation FAILED)|^(Pre-processing FAILED !)|^(Error:)|(^@@@@@ .+ @@@@@$)|(^.*returned errorcode.*)|^(Cannot open input file)|^(Cannot open file)|^(Errors in pass1, assembly aborted)|^(Errors in pass2, assembly aborted)} $text error]} {
+ set len [string length $error]
+ set ern 1
+
+ # check for warning which points to specific line in source code
+ } elseif {[regexp {^(\|WL\|.*)|^(Notice at \d+ in [^\:]+\:)|^(Warning at \d+ in [^\:]+\:)|^(.+:\d+: warning.*)|^(Warning\, line \d+)} $text warning]} {
+ set len [string length $warning]
+ set war 1
+
+ # check for a warning
+ } elseif {[regexp {^(\|WN\|.*)|^(.*: Warning:.*)|^(Warning:)} $text warning]} {
+ set len [string length $warning]
+ set warn 1
+
+ # check for success
+ } elseif {[regexp {^(\|SN\|.*)|^((Dec|C)ompilation successful)|(Successful)|(Starting compiler ...)} $text success]} {
+ set len [string length $success]
+ set suc 1
+
+ # check for error which points to specific line in source code
+ } elseif {[regexp {^(\|EL\|.*)|^(.+:\d+: .*)} $text error]} {
+ set len [string length $error]
+ set err 1
+ }
+
+ regsub {^(\|[EWS][LN]\|)} $text {} text
+
+ # Insert specified text
+ $messages_text insert end $text
+ $messages_text insert end "\n"
+
+
+ # Insert appropriate text tags
+ if {$err || $ern || $war || $warn || $suc} {
+ # Insert error tag
+ if {$ern} {
+ set tag {error_nu}
+ # Insert error tag
+ } elseif {$err} {
+ set tag {error}
+ # Insert warning tag
+ } elseif {$warn} {
+ set tag {warning_nu}
+ # Insert warning tag
+ } elseif {$war} {
+ set tag {warning}
+ # Insert success tag
+ } elseif {$suc} {
+ set tag successful
+ }
+ $messages_text tag add $tag $row.0 $row.$len
+ }
+ }
+
+ $messages_text see end
+ $messages_text configure -state disabled
+
+ return [expr {$err || $ern}]
+ }
+
+ ## Hide search bar
+ # @return void
+ public method messages_text_hide_find_dialog {} {
+ if {[winfo ismapped $search_frame]} {
+ pack forget $search_frame
+ }
+ }
+
+ ## Show search bar
+ # @return void
+ public method messages_text_find_dialog {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ $search_entry delete 0 end
+ focus -force $search_entry
+ } {
+ focus -force $search_entry
+ }
+ }
+
+ ## Search for the given string within the text
+ # @parm String string - Text to find
+ # @return Bool - Always 1
+ public method messages_text_search {string} {
+ if {$string == {}} {
+ $search_entry configure -style TEntry
+ $search_find_next configure -state disabled
+ $search_find_prev configure -state disabled
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ return 1
+ }
+ set search_string $string
+ messages_text_perform_search 1 1.0
+
+ return 1
+ }
+
+ ## Perform search for $search_string in the text widget
+ # @parm Bool forw__back - 1 == Search forwards; 0 == Search backard
+ # @parm String from - Start index
+ # @return void
+ public method messages_text_perform_search {forw__back from} {
+ if {$search_string == {}} {return}
+
+ if {$forw__back} {
+ set direction {-forwards}
+ } {
+ set direction {-backwards}
+ }
+ if {${::Todo::match_case}} {
+ set last_find_index [$messages_text search $direction -- $search_string $from]
+ } {
+ set last_find_index [$messages_text search $direction -nocase -- $search_string $from]
+ }
+ if {$last_find_index == {}} {
+ $search_entry configure -style StringNotFound.TEntry
+ $search_find_next configure -state disabled
+ $search_find_prev configure -state disabled
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ } {
+ $search_entry configure -style StringFound.TEntry
+ $search_find_next configure -state normal
+ $search_find_prev configure -state normal
+ $menu entryconfigure [::mc "Find next"] -state normal
+ $menu entryconfigure [::mc "Find previous"] -state normal
+
+ set search_string_length [string length $search_string]
+ $messages_text see $last_find_index
+ catch {
+ $messages_text tag remove sel 0.0 end
+ }
+ $messages_text tag add sel $last_find_index $last_find_index+${search_string_length}c
+ }
+ }
+
+ ## Find next occurence of the search string
+ # @return void
+ public method messages_text_find_next {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ }
+ if {$last_find_index == {}} {
+ return
+ }
+ messages_text_perform_search 1 $last_find_index+${search_string_length}c
+ }
+
+ ## Find previous occurence of the search string
+ # @return void
+ public method messages_text_find_prev {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ }
+ if {$last_find_index == {}} {
+ return
+ }
+ messages_text_perform_search 0 $last_find_index
+ }
+
+ ## Enter hyperlink
+ # @parm Int x - Relative pointer position
+ # @parm Int x - Relative pointer position
+ # @return void
+ public method messages_text_hyperlink_enter {x y} {
+ set hyperlink_line_start [$messages_text index [list @$x,$y linestart]]
+ hyperlink_active
+ }
+
+ ## Leave hyperlink
+ # @return void
+ public method messages_text_hyperlink_leave {} {
+ $messages_text config -cursor xterm
+ $messages_text tag remove hyper_link_over 0.0 end
+ }
+
+ ## Enter pointer motion
+ # @parm Int x - Relative pointer position
+ # @parm Int x - Relative pointer position
+ # @return void
+ public method messages_text_hyperlink_motion {x y} {
+ set line_start [$messages_text index [list @$x,$y linestart]]
+ if {$hyperlink_line_start == $line_start} {
+ return
+ }
+ set hyperlink_line_start $line_start
+ $messages_text tag remove hyper_link_over 0.0 end
+ hyperlink_active
+ }
+
+ ## Highlight hyperlink on line $hyperlink_line_start
+ # @return void
+ private method hyperlink_active {} {
+ set range [$messages_text tag nextrange error $hyperlink_line_start [list $hyperlink_line_start lineend]]
+ if {![llength $range]} {
+ set range [$messages_text tag nextrange warning $hyperlink_line_start [list $hyperlink_line_start lineend]]
+ }
+ if {![llength $range]} {
+ return
+ }
+ $messages_text config -cursor hand2
+ $messages_text tag add hyper_link_over [lindex $range 0] [lindex $range 1]
+ }
+}
diff --git a/lib/bottompanel/terminal.tcl b/lib/bottompanel/terminal.tcl
new file mode 100755
index 0000000..6c373f8
--- /dev/null
+++ b/lib/bottompanel/terminal.tcl
@@ -0,0 +1,135 @@
+#!/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 terminal emulator for bottom notebook
+# --------------------------------------------------------------------------
+
+class Terminal {
+ # Terminal emulator configuration
+ common configuration
+ common configuration_def [subst {
+ bg #FFFFFF
+ fg #000000
+ font_size 12
+ font_family {$::DEFAULT_FIXED_FONT}
+ }]
+
+ private variable terminal_counter 0 ;# Int: Counter of terminal emulator instances
+ private variable terminal_frame ;# Widget: ID of terminal container frame
+ private variable wrapper_frame ;# Widget: Wrapper frame for $terminal_frame
+ private variable parent ;# Widget: Parent frame
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+ private variable terminal_pid {} ;# Int: PID of terminal emulator
+
+ destructor {
+ terminal_kill_childern
+ }
+
+ ## Prepare this tab for GUI creation
+ # @parm Widget _parent -
+ # @return void
+ public method PrepareTerminal {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method TerminalTabRaised {} {
+ focus $terminal_frame
+ }
+
+ ## Create GUI
+ # @return void
+ public method CreateTerminalEmulGUI {} {
+ if {$gui_initialized || !${::PROGRAM_AVALIABLE(urxvt)}} {return}
+ set gui_initialized 1
+
+ set wrapper_frame [frame $parent.wrapper_frame -relief sunken -bd 2]
+ pack $wrapper_frame -fill both -expand 1
+ terminal_recreate_terminal
+ unset parent
+ }
+
+ ## Internal procedure -- (re)create frame with terminal emulator
+ # @return void
+ public method terminal_recreate_terminal {} {
+ if {![winfo exists $wrapper_frame]} {return}
+ set terminal_frame [frame $wrapper_frame.terminal_frame_${terminal_counter} -container 1]
+ bind $terminal_frame <Destroy> "$this terminal_recreate_terminal"
+
+ set pwd [