summaryrefslogtreecommitdiff
path: root/lib/dialogues
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialogues')
-rw-r--r--lib/dialogues/errorhandler.tcl189
-rw-r--r--lib/dialogues/fsd.tcl2871
-rw-r--r--lib/dialogues/my_tk_messageBox.tcl303
-rw-r--r--lib/dialogues/selectmcu.tcl1566
-rw-r--r--lib/dialogues/tips.tcl402
5 files changed, 5331 insertions, 0 deletions
diff --git a/lib/dialogues/errorhandler.tcl b/lib/dialogues/errorhandler.tcl
new file mode 100644
index 0000000..93e1cf4
--- /dev/null
+++ b/lib/dialogues/errorhandler.tcl
@@ -0,0 +1,189 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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. #
+############################################################################
+
+# >>> File inclusion guard
+if { ! [ info exists _ERRORHANDLER_TCL ] } {
+set _ERRORHANDLER_TCL _
+# <<< File inclusion guard
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Background error handler
+# --------------------------------------------------------------------------
+
+namespace eval ErrorHandler {
+ variable num_of_opened 0 ;# Int: Number of currently opened dialogues
+ variable count 0 ;# Int: Counter of ivokations
+ variable enabled 1 ;# Bool: Dialog window enabled
+
+ ## Open dialog window
+ # @parm String message - Error message
+ # @return void
+ proc open_dialog {message} {
+ variable count ;# Int: Counter of ivokations
+ variable enabled ;# Bool: Dialog window enabled
+ variable num_of_opened ;# Int: Number of currently opened dialogues
+
+ if {$num_of_opened > 2} {
+ puts stderr "ERROR MESSAGE SUPPRESED (too many error dialogues opened at the time)"
+ return
+ }
+ incr num_of_opened
+
+ # Send error message to standard error output
+ puts stderr [string repeat # 64]
+ puts stderr "# PROGRAM ERROR #"
+ puts stderr [string repeat # 64]
+ puts stderr $::errorInfo
+ puts stderr [string repeat # 64]
+
+ # Save log file
+ if {![catch {set log_file [open [file join ${::X::defaultDirectory} mcu8051ide_errors.log] a]}]} {
+ puts $log_file [string repeat # 64]
+ puts $log_file "Program version:\t${::VERSION}"
+ puts $log_file "Tcl version:\t\t${::tcl_version}"
+ puts $log_file "Tk version:\t\t${::tk_version}"
+ puts $log_file [string repeat - 64]
+ puts $log_file $::errorInfo
+ close $log_file
+ }
+
+ # Create dialog window
+ if {!$enabled} {return}
+ incr count
+ set win [toplevel .error_dialog$count -bg {#EE0000} -class {Error message} -bg ${::COMMON_BG_COLOR}]
+
+ # Create window frames
+ set main_frame [frame $win.main_frame]
+ set top_frame [frame $main_frame.top_frame -bg {#EE0000}]
+ set middle_frame [frame $main_frame.middle_frame]
+ set bottom_frame [frame $main_frame.bottom_frame]
+
+ # Create window header
+ pack [label $top_frame.header_lbl \
+ -text [mc "PROGRAM ERROR "] \
+ -bg {#EE0000} -fg {#FFFFFF} \
+ -font [font create \
+ -family helvetica \
+ -size [expr {int(-24 * $::font_size_factor)}] \
+ -weight bold \
+ ] \
+ ] -side left -fill x -expand 1
+
+ # Create error message text and scrollbar
+ pack [text $middle_frame.text \
+ -bg {white} -bd 0 \
+ -yscrollcommand "$middle_frame.scrollbar set" \
+ -width 0 -height 0 -relief flat -wrap word \
+ ] -side left -fill both -expand 1 -padx 5 -pady 5
+ bind $middle_frame.text <Button-1> {focus %W}
+ pack [ttk::scrollbar $middle_frame.scrollbar \
+ -orient vertical \
+ -command "$middle_frame.text yview" \
+ ] -fill y -side right
+
+ # Create text tags
+ $middle_frame.text tag configure tag_bold \
+ -font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -weight bold \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ ]
+ $middle_frame.text tag configure tag_tt \
+ -font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ ]
+ $middle_frame.text tag configure tag_big_bold \
+ -font [font create \
+ -family {helvetica} \
+ -weight bold \
+ -size [expr {int(-17 * $::font_size_factor)}] \
+ ]
+
+ # Write error message
+ $middle_frame.text insert end [mc "Error log saved in: %s\n" "${::X::defaultDirectory}[file separator]mcu8051ide_errors.log"]
+ $middle_frame.text insert end [mc "Please send this file to %s\nor report this bug at: http://sourceforge.net/tracker/?group_id=185864&atid=914981\n\n\n" {<martin.osmera@gmail.com>}]
+ create_link_tag_in_text_widget $middle_frame.text
+ convert_all_https_to_links $middle_frame.text
+ $middle_frame.text tag add tag_big_bold 1.0 4.0
+ $middle_frame.text insert end [mc "ERROR DETAILS:\n--------------\n"]
+ $middle_frame.text tag add tag_bold 6.0 8.0
+ $middle_frame.text insert end $::errorInfo
+ $middle_frame.text tag add tag_tt 8.0 end
+ $middle_frame.text configure -state disabled
+
+ # Create button frame
+ pack [ttk::button $bottom_frame.skip \
+ -text [mc "Skip errors"] \
+ -compound left \
+ -command "
+ set ::ErrorHandler::enabled 0
+ ::ErrorHandler::close_dialog $count
+ " \
+ ] -side left
+ pack [ttk::button $bottom_frame.ok \
+ -text [mc "Close"] \
+ -style GreenBg.TButton \
+ -command "::ErrorHandler::close_dialog $count" \
+ ] -side right
+ focus -force $bottom_frame.ok
+
+ # Pack window frames
+ pack $top_frame -fill x -anchor n
+ pack $middle_frame -fill both -expand 1
+ pack $bottom_frame -fill x
+ pack $main_frame -fill both -expand 1 -padx 5 -pady 5
+
+ # Configure dialog window
+ set x [expr {[winfo screenwidth $win] / 2 - 225}]
+ set y [expr {[winfo screenheight $win] / 2 - 125}]
+ wm iconphoto $win ::ICONS::16::bug
+ wm title $win [mc "PROGRAM ERROR - MCU 8051 IDE"]
+ wm minsize $win 450 250
+ wm geometry $win =550x250+$x+$y
+ wm protocol $win WM_DELETE_WINDOW "::ErrorHandler::close_dialog $count"
+ update
+ raise $win
+ catch {grab $win}
+ }
+
+ ## Close dialog window
+ # @parm Int number - Dialog unique number
+ # @return void
+ proc close_dialog {number} {
+ variable num_of_opened ;# Int: Number of currently opened dialogues
+
+ incr num_of_opened -1
+ destroy .error_dialog$number
+ }
+}
+
+# Register error handler
+proc bgerror {message} {
+ ::ErrorHandler::open_dialog $message
+}
+
+# >>> File inclusion guard
+}
+# <<< File inclusion guard
diff --git a/lib/dialogues/fsd.tcl b/lib/dialogues/fsd.tcl
new file mode 100644
index 0000000..fce7e24
--- /dev/null
+++ b/lib/dialogues/fsd.tcl
@@ -0,0 +1,2871 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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. #
+############################################################################
+
+# >>> File inclusion guard
+if { ! [ info exists _FSD_TCL ] } {
+set _FSD_TCL _
+# <<< File inclusion guard
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# This class provides file selection dialog
+# Usage:
+# KIFSD::FSD <fsd_object> ;# Create dialog object
+# <fsd_object> setokcmd {set filename [<fsd_object> get]} ;# Set command for Ok button
+# <fsd_object> activate <some_command> ;# Show up the dialog
+#
+# Constructor options:
+# -title String = {} ;# Dialog title
+# -initialfile String = {} ;# Initial file
+# -directory String = {~} ;# Initiali directory
+# -multiple Bool = 0 ;# Allow selection of multiple files (get will return list instead of string)
+# -filetypes List = {{All} {*}} ;# { {{Some string} {GLOB}} ... }
+# -defaultmask Int = 0 ;# Number of detault mask (see -filetypes) (1st is zero)
+# -modal Bool = 1 ;# Create as modal window
+# -doubleclick Bool = 0 ;# Use double click to open folder instead of single click
+# -autoclose Bool = 1 ;# Close dialog after pressure of Ok button
+# -master Widget = . ;# Master window (wm transient $master)
+# -fileson Bool = 1 ;# 1 == Select file(s); 0 == Select directory/ies
+#
+# Other public methods:
+# set_bookmark_change_command Command ;# Set command to invoke when bookmarks changes
+# deactivate ;# Deactivate the dialog
+# close_dialog ;# Close dialog window but keep object alive
+# get_config_array -> List ;# Get dialog configuration array for proc. load_config_array
+# load_config_array List ;# Load dialog configuration array
+# get_window_name -> Widget ;# Get path to dialog window
+# --------------------------------------------------------------------------
+
+itcl::class KIFSD::FSD {
+
+ common bookmark_change_command {} ;# Command to invoke on bokmark change
+ # Font for quick navigation panel
+ common quick_nav_panel_font [font create \
+ -family {helvetica} \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ -weight bold \
+ ]
+ # Font for files listbox in mode (Short view)
+ common listbox_font_short [font create \
+ -family {helvetica} \
+ -size [expr {int(-14 * $::font_size_factor)}] \
+ -weight normal \
+ ]
+ # Font for files listbox in mode (Detailed view) and directories listbox
+ common listbox_font_detailed [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ -weight normal \
+ ]
+ # Font for listbox header
+ common listbox_header_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ -weight bold \
+ ]
+
+ ## Values given by constructor arguments
+ private variable option_title {Select file} ;# Dialog title
+ private variable option_filetypes {{All} {*}} ;# File types
+ if {!$::MICROSOFT_WINDOWS} {
+ variable option_directory ${::env(HOME)} ;# Initial directory
+ } else {
+ variable option_directory ${::env(USERPROFILE)} ;# Initial directory
+ }
+ private variable option_master {.} ;# Window master
+ private variable option_fileson {1} ;# 1 == Files on (select file); 0 == Files off (select directory)
+ private variable option_doubleclick {0} ;# Use doble click instead of single clicks
+ private variable option_modal {1} ;# Open dialog windown as modal window
+ private variable option_initialfile {} ;# Initial file
+ private variable option_multiple {0} ;# Allow mulstiple selection
+ private variable option_defaultmask {0} ;# Index of default mask in $option_filetypes
+ private variable option_autoclose {1} ;# 1 == Close dialog after press of Ok button
+
+ private variable bookmark_edit_listbox {} ;# Widget: ListBox in bookmarks editor
+ private variable bookmark_menu {} ;# Widget: Bookmarks menu
+ private variable config_menu {} ;# Widget: Configuration menu
+ private variable listbox_font {} ;# Font: Current font for files listbox
+ private variable current_directory {} ;# String: Current directory
+ private variable back_history {} ;# List: Backward history
+ private variable forward_history {} ;# List: Forward hitory
+ private variable ok_command {} ;# String: Ok command
+ private variable current_mask {*} ;# GLOB: Current fileter mask
+ private variable item_menu_request 0 ;# Bool: Item popup menu request
+ private variable current_item {} ;# String: ID of currenly selected item
+ private variable current_item_index 0 ;# Int: Index of currently selected item
+ private variable cur_listbox {} ;# String currently selected listbox {dir} or {file}
+
+ private variable dialog_loaded 0 ;# Bool: Dialog is completely loaded
+ private variable win ;# Widget: Dialog window
+ private variable ok_button ;# Widget: Button "Ok"
+ private variable location_cb ;# Widget: Location ComboBox
+ private variable filter_cb ;# Widget: Filter ComboBox
+ private variable dir_combobox ;# Widget: Directory ComboBox
+ private variable toolbar ;# Widget: Frame containing toolbar
+ private variable quick_access_bar ;# Widget: Quick access bar ListBox
+ private variable dir_listbox_scrollbar {} ;# Widget: Directory ListBox scrollbar
+ private variable dir_listbox {} ;# Widget: Directory ListBox
+ private variable main_paned_window ;# Widget: Paned window for quick access bar and other LBs
+ private variable leftframe ;# Widget: Frame contaning quick access bar and its scrollbar
+ private variable rightframe ;# Widget: Frame containing directory & file ListBoxes
+ private variable right_top_right_frame ;# Widget: files ListBox
+ private variable right_top_left_frame ;# Widget: Frame for files ListBox
+ private variable right_top_frame ;# Widget: Frame for $right_paned_window
+ private variable right_paned_window ;# Widget: Paned window for directories ListBox and files ListBox
+ private variable file_listbox ;# Widget: Files ListBox
+ private variable file_listbox_header ;# Widget: Header for files ListBox
+ private variable file_listbox_frame ;# Widget: Frame for $file_listbox_header and $file_listbox
+ private variable file_listbox_vscrollbar {} ;# Widget: Vertical scollbar for files ListBox
+ private variable file_listbox_hscrollbar {} ;# Widget: Hotizontal scollbar for files ListBox
+ private variable right_top_right_top_frame ;# Widget: Frame for $file_listbox_frame and scrollbars
+
+ proc static_reload {object args} {
+ catch [list $object reload]
+ }
+
+ ## Dialog constructor
+ # For complite list of possible arguments see desctiption above
+ constructor args {
+
+ # Configure local ttk styles
+ ttk::style configure FSD_RedBg.TCombobox -fieldbackground {#FFDDDD}
+ ttk::style configure FSD_RedBg.TEntry -fieldbackground {#FFDDDD}
+
+ ## Parse given arguments and set appropriate object variables
+ set arglen [llength $args]
+ set arg {}
+ for {set i 0} {$i < $arglen} {incr i} {
+ set arg [lindex $args $i]
+ switch -- $arg {
+ -modal {
+ incr i
+ set option_modal [lindex $args $i]
+ if {![string is boolean -strict $option_modal]} {
+ error "-modal must have value either 0 or 1"
+ }
+ }
+ -doubleclick {
+ incr i
+ set option_doubleclick [lindex $args $i]
+ if {![string is boolean -strict $option_doubleclick]} {
+ error "-doubleclick must have value either 0 or 1"
+ }
+ }
+ -autoclose {
+ incr i
+ set option_autoclose [lindex $args $i]
+ if {![string is boolean -strict $option_autoclose]} {
+ error "-autoclose must have value either 0 or 1"
+ }
+ }
+ -initialfile {
+ incr i
+ set option_initialfile [lindex $args $i]
+ }
+ -multiple {
+ incr i
+ set option_multiple [lindex $args $i]
+ if {![string is boolean -strict $option_multiple]} {
+ error "-multiple must have value either 0 or 1"
+ }
+ }
+ -defaultmask {
+ incr i
+ set option_defaultmask [lindex $args $i]
+ if {![string is integer -strict $option_defaultmask]} {
+ error "-defaultmask must be an integer"
+ }
+ }
+ -title {
+ incr i
+ set option_title [lindex $args $i]
+ }
+ -filetypes {
+ incr i
+ set option_filetypes [lindex $args $i]
+ }
+ -directory {
+ incr i
+ set option_directory [lindex $args $i]
+ }
+ -master {
+ incr i
+ set option_master [lindex $args $i]
+ }
+ -fileson {
+ incr i
+ set option_fileson [lindex $args $i]
+ if {![string is boolean -strict $option_modal]} {
+ error "-fileson must have value either 0 or 1"
+ }
+ }
+ default {
+ error "Option '$arg' is not valid"
+ }
+ }
+ }
+ set args {}
+ set current_directory [file normalize $option_directory]
+
+ # Cretate dialog window
+ create_dialog
+
+ # Initalize window key shortcuts
+ create_shortcuts
+
+ # Finalize
+ set dialog_loaded 1
+ }
+
+ ## Destrurtor
+ destructor {
+ catch {
+ # Save position of right paned window sash
+ if {[winfo ismapped $right_paned_window]} {
+ set ::KIFSD::FSD::config(right_PW_size) \
+ [lindex [$right_paned_window sash coord 0] 0]
+ }
+ # Save position of main paned window sash
+ if {[winfo ismapped $main_paned_window]} {
+ set ::KIFSD::FSD::config(main_PW_size) \
+ [lindex [$main_paned_window sash coord 0] 0]
+ }
+ # Save window geometry
+ set ::KIFSD::FSD::config(win_geometry) [wm geometry $win]
+ }
+
+ # Destroy dialog window
+ grab release $win
+ destroy $win
+ }
+
+ ## Create dialog GUI elements
+ # @return void
+ private method create_dialog {} {
+ # Determinate window name (path)
+ set win_base {}
+ if {$option_master != {.}} {
+ set win_base $option_master
+ }
+ append win_base .[string tolower [regsub -all {:} $this {}]]
+ set win $win_base
+ set i 0
+ while [winfo exists $win] {
+ set win $win_base
+ append win $i
+ incr i
+ }
+
+ # Create and configure dialog window
+ toplevel $win -bg ${::COMMON_BG_COLOR}
+ wm iconphoto $win ::ICONS::16::fileopen
+ wm withdraw $win
+ wm title $win $option_title
+ wm minsize $win 540 290
+ wm protocol $win WM_DELETE_WINDOW "catch {itcl::delete object $this}"
+ wm transient $win $option_master
+ wm geometry $win ${::KIFSD::FSD::config(win_geometry)}
+ wm resizable $win 0 0
+ raise $win
+ update
+ if {$option_modal} {
+ catch {
+ grab $win
+ }
+ }
+
+
+ create_popup_menus ;# Create popup menus
+ set topframe [frame $win.topframe] ;# Create frame above ListBoxes
+ set toolbar [frame $topframe.toobar] ;# Create toolbar frame
+ create_tool_bar ;# Create toolbar
+
+ # Create directory ComboBox
+ set dir_combobox [ttk::combobox $topframe.dir_cb \
+ -values {} \
+ -exportselection 0 \
+ -validate all \
+ -validatecommand "::KIFSD::FSD::dir_validate $topframe.dir_cb %W %P" \
+ ]
+ bind $dir_combobox <<ComboboxSelected>> [list $this dir_cb_modify]
+ bind $dir_combobox <KP_Enter> [list $this dir_cb_modify]
+ bind $dir_combobox <Return> [list $this dir_cb_modify]
+
+ DynamicHelp::add $dir_combobox -text [mc "Current directory"]
+ pack $dir_combobox -side right -expand 1 -fill x -padx 5
+
+ # Create main paned window and some frames
+ set mainframe [frame $win.mainframe]
+ set main_paned_window [panedwindow $mainframe.main_paned_window \
+ -orient horizontal -opaqueresize 1 -sashwidth 2 \
+ -showhandle 0 -sashrelief flat \
+ ]
+ set leftframe [frame $mainframe.leftframe]
+ set rightframe [frame $mainframe.rightframe]
+
+ # Create quick access bar
+ set quick_access_bar [ListBox $leftframe.quick_access_bar \
+ -selectfill 1 -selectbackground white -bd 1 -padx 30 -width 15 \
+ -selectmode single -highlightthickness 0 -bg white -deltay 30 \
+ -selectforeground black -highlightcolor {#BBBBFF} \
+ ]
+ refresh_quick_access_bar
+ $quick_access_bar bindText <ButtonRelease-3> [list $this quick_access_bar_item_menu %X %Y ]
+ $quick_access_bar bindImage <ButtonRelease-3> [list $this quick_access_bar_item_menu %X %Y ]
+ $quick_access_bar bindText <Double-Button-1> [list $this quick_access_bar_doubleclick ]
+ $quick_access_bar bindImage <Double-Button-1> [list $this quick_access_bar_doubleclick ]
+ bind $quick_access_bar <<ListboxSelect>> [list $this quick_access_bar_select ]
+ if {[winfo exists $quick_access_bar.c]} {
+ bind $quick_access_bar.c <Button-5> {%W yview scroll +5 units; break}
+ bind $quick_access_bar.c <Button-4> {%W yview scroll -5 units; break}
+ bind $quick_access_bar.c <ButtonRelease-3> [list $this quick_access_bar_menu %X %Y ]
+ }
+ pack $quick_access_bar -fill both -expand 1
+
+ # Create right paned window
+ set right_top_frame [frame $rightframe.topframe]
+ set right_bottom_frame [frame $rightframe.bottomframe]
+ set right_paned_window [panedwindow $right_top_frame.right_paned_window \
+ -orient horizontal -opaqueresize 1 -sashwidth 2 \
+ -showhandle 0 -sashrelief flat \
+ ]
+ set right_top_left_frame [frame $win.left_frame]
+ set right_top_right_frame [frame $win.right_frame]
+
+ # Create directories ListBox
+ if {$option_fileson} {
+ set dir_listbox [ListBox $right_top_left_frame.dir_listbox \
+ -bd 1 -padx 19 -selectfill 1 -width 1 -highlightcolor {#BBBBFF} \
+ -selectmode single -highlightthickness 0 -bg white -deltay 18 \
+ -yscrollcommand "$this dir_listbox_scroll" \
+ ]
+ set dir_listbox_scrollbar [ttk::scrollbar \
+ $right_top_left_frame.scrollbar \
+ -orient vertical -command "$dir_listbox yview" \
+ ]
+ $dir_listbox bindText <Double-Button-1> [list $this dir_listbox_doubleclick ]
+ $dir_listbox bindImage <Double-Button-1> [list $this dir_listbox_doubleclick ]
+ $dir_listbox bindText <ButtonRelease-3> [list $this dir_listbox_item_menu %X %Y ]
+ $dir_listbox bindImage <ButtonRelease-3> [list $this dir_listbox_item_menu %X %Y ]
+ bind $dir_listbox <<ListboxSelect>> [list $this dir_listbox_select ]
+ if {[winfo exists $dir_listbox.c]} {
+ bind $dir_listbox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $dir_listbox.c <Button-4> {%W yview scroll -5 units; break}
+ bind $dir_listbox.c <ButtonRelease-3> [list $this dir_listbox_menu %X %Y ]
+ }
+ pack $dir_listbox -side left -fill both -expand 1
+ }
+
+ # Create files ListBox
+ if {$option_multiple} {
+ set selmode {multiple}
+ } else {
+ set selmode {single}
+ }
+ set right_top_right_top_frame [frame $right_top_right_frame.right_top_right_top_frame]
+ set file_listbox_frame [frame $right_top_right_top_frame.file_listbox_frame]
+ set file_listbox_header [text $file_listbox_frame.text \
+ -width 1 -height 1 -takefocus 0 -bg white \
+ -font $listbox_header_font -bd 1 -relief sunken \
+ -cursor left_ptr -wrap none \
+ ]
+ $file_listbox_header delete 1.0 end
+ if {!$::MICROSOFT_WINDOWS} {
+ $file_listbox_header insert end \
+ [mc " Name Size Rights Date "]
+ } else {
+ $file_listbox_header insert end \
+ [mc " Name Size Date "]
+ }
+ bindtags $file_listbox_header $file_listbox_header
+ $file_listbox_header configure -state disabled
+ set file_listbox [ListBox $file_listbox_frame.file_listbox \
+ -bd 1 \
+ -padx 17 \
+ -width 1 \
+ -height 1 \
+ -bg white \
+ -deltay 18 \
+ -selectfill 1 \
+ -selectmode $selmode \
+ -highlightthickness 0 \
+ -selectbackground {#88AAFF} \
+ -highlightcolor {#BBBBFF} \
+ -yscrollcommand "$this file_listbox_vscroll" \
+ -xscrollcommand "$this file_listbox_hscroll" \
+ ]
+ pack $file_listbox -fill both -expand 1
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ $file_listbox configure -multicolumn 0
+ set listbox_font $listbox_font_detailed
+ pack $file_listbox_header -before $file_listbox -fill x -expand 0
+ } else {
+ $file_listbox configure -multicolumn 1
+ set listbox_font $listbox_font_short
+ }
+ set file_listbox_vscrollbar [ttk::scrollbar \
+ $right_top_right_top_frame.vscrollbar \
+ -orient vertical -command "$file_listbox yview" \
+ ]
+ set file_listbox_hscrollbar [ttk::scrollbar \
+ $right_top_right_frame.hscrollbar \
+ -orient horizontal \
+ -command "$this file_listbox_hscrollbar_cmd" \
+ ]
+ $file_listbox bindText <Double-Button-1> [list $this file_listbox_doubleclick]
+ $file_listbox bindImage <Double-Button-1> [list $this file_listbox_doubleclick]
+ $file_listbox bindText <ButtonRelease-3> [list $this file_listbox_item_menu %X %Y]
+ $file_listbox bindImage <ButtonRelease-3> [list $this file_listbox_item_menu %X %Y]
+ bind $file_listbox <<ListboxSelect>> [list $this file_listbox_select]
+ if {[winfo exists $file_listbox.c]} {
+ bind $file_listbox.c <Button-5> [list $this file_listbox_scroll +5 units]
+ bind $file_listbox.c <Button-4> [list $this file_listbox_scroll -5 units]
+ bind $file_listbox.c <ButtonRelease-3> [list $this file_listbox_menu %X %Y]
+ }
+ pack $file_listbox_frame -fill both -expand 1 -side left
+ pack $right_top_right_top_frame -fill both -expand 1 -side top
+ pack $right_top_frame -side top -fill both -expand 1
+
+ # Create Location Label+ComboBox and Filter Label+ComboBox
+ grid [label $right_bottom_frame.location_label \
+ -text [mc "Location:"] \
+ ] -sticky w -column 0 -row 0
+ grid [label $right_bottom_frame.filter_label \
+ -text [mc "Filter:"] \
+ ] -sticky w -column 0 -row 1
+
+ set location_cb [ttk::combobox $right_bottom_frame.location_cb \
+ -values {} \
+ -exportselection 0 \
+ ]
+ bind $location_cb <<ComboboxSelected>> "$file_listbox selection clear"
+ DynamicHelp::add $location_cb -text [mc "Selected file(s)"]
+ bind $location_cb <Key> "$file_listbox selection clear"
+ bind $location_cb <KP_Enter> [list $this ok]
+ bind $location_cb <Return> [list $this ok]
+
+ set tmp_option_filetypes {}
+ foreach type $option_filetypes {
+ set glob_masks [lindex $type 1]
+ if {[regexp {^\*\.\{\w+(,\w+)*\}$} $glob_masks]} {
+ set glob_masks [split $glob_masks {{,}}]
+ set glob_masks [lreplace $glob_masks 0 0]
+ set glob_masks [lreplace $glob_masks end end]
+ set glob_masks_new [list]
+ foreach ext $glob_masks {
+ lappend glob_masks_new [format "*.%s" $ext]
+ }
+ set glob_masks [join $glob_masks_new {, }]
+ }
+ lappend tmp_option_filetypes "[lindex $type 0] ($glob_masks)"
+ }
+ set filter_cb [ttk::combobox $right_bottom_frame.filter_cb \
+ -state readonly \
+ -values $tmp_option_filetypes \
+ -exportselection 0 \
+ ]
+ DynamicHelp::add $right_bottom_frame.filter_cb -text [mc "Filter"]
+ set tmp_option_filetypes {}
+ foreach type $option_filetypes {
+ lappend tmp_option_filetypes [lindex $type 1]
+ }
+ set option_filetypes $tmp_option_filetypes
+ $filter_cb current $option_defaultmask
+ set current_mask [lindex $option_filetypes $option_defaultmask]
+ bind $filter_cb <<ComboboxSelected>> [list $this filter_cb_modify]
+ grid $location_cb -sticky ew -column 1 -row 0
+ grid $filter_cb -sticky ew -column 1 -row 1
+
+ if {!$option_fileson} {
+ $filter_cb configure -state disabled
+ }
+
+ # Create buttons "Ok" and "Cancel"
+ set ok_button [ttk::button $right_bottom_frame.ok_button\
+ -text [mc "Ok"] \
+ -compound left \
+ -width 8 \
+ -image ::ICONS::16::ok \
+ -command [list $this ok] \
+ ]
+ grid $ok_button -sticky w -column 2 -row 0 -padx 7 -pady 2
+ grid [ttk::button $right_bottom_frame.cancel_button \
+ -text [mc "Cancel"] \
+ -compound left \
+ -width 8 \
+ -image ::ICONS::16::button_cancel \
+ -command "itcl::delete object $this" \
+ ] -sticky w -column 2 -row 1 -padx 7 -pady 2
+
+ grid columnconfigure $right_bottom_frame 1 -weight 1
+
+ pack $right_bottom_frame -side bottom -fill x -expand 0 -anchor w
+
+ pack $topframe -side top -fill x -padx 12 -pady 10
+ pack $mainframe -side bottom -fill both -expand 1 -padx 12
+
+ # Adjust paned windows to current configuration
+ quick_access_panel_onoff
+ separate_folders_onoff
+
+ # Finalize
+ $location_cb set $option_initialfile
+ focus -force $location_cb
+ catch {
+ $location_cb.e selection range 0 end
+ }
+ }
+
+ ## Create dialog toolbar
+ # @return void
+ private method create_tool_bar {} {
+ set si 0
+ foreach item {
+ {up "Parent folder" {1uparrow}
+ {up}}
+ {back "Back" {1leftarrow}
+ {back}}
+ {forward "Forward" {1rightarrow}
+ {forward}}
+ {reload "Reload" {reload}
+ {reload}}
+ {separator}
+ {newdir "New folder" {folder_new}
+ {newdir}}
+ {separator}
+ {short "Short view" {view_icon}
+ {short_view}}
+ {detail "Detailed view" {view_detailed}
+ {detail_view}}
+ {separator}
+ {bookmark "Bookmarks" {bookmark}
+ {bookmark_menu}}
+ {configure "Configure" {configure}
+ {config_menu}}
+ } \
+ {
+ # Create separator
+ if {$item == {separator}} {
+ pack [ttk::separator $toolbar.sep$si \
+ -orient vertical \
+ ] -side left -padx 4 -fill both -expand 1
+ incr si
+ continue
+ }
+
+ # Create button
+ if {[lindex $item 0] == {bookmark}} {
+ set buttonWidget [ttk::menubutton $toolbar.[lindex $item 0] \
+ -image ::ICONS::22::[lindex $item 2] \
+ -menu $bookmark_menu \
+ -style Flat.TMenubutton \
+ ]
+ } elseif {[lindex $item 0] == {configure}} {
+ set buttonWidget [ttk::menubutton $toolbar.[lindex $item 0] \
+ -image ::ICONS::22::[lindex $item 2] \
+ -menu $config_menu \
+ -style Flat.TMenubutton \
+ ]
+ } else {
+ set buttonWidget [ttk::button $toolbar.[lindex $item 0] \
+ -command "$this [lindex $item 3]" \
+ -style Flat.TButton \
+ -image ::ICONS::22::[lindex $item 2] \
+ ]
+ }
+ DynamicHelp::add $buttonWidget -text [mc [lindex $item 1]]
+
+ # Pack it
+ pack $buttonWidget -side left -padx 2
+ }
+
+ # Disable button for manipulating history
+ $toolbar.back configure -state disabled
+ $toolbar.forward configure -state disabled
+
+ # Pack toolbar frame
+ pack $toolbar -side left -expand 0 -fill none
+ }
+
+
+ ## Create dialog popup menus
+ # @return void
+ private method create_popup_menus {} {
+ # Create configuration menu
+ set config_menu [menu $win.config_menu -tearoff 0]
+
+ ## Create menu: Configuration -> Sorting
+ set sorting_menu [menu $win.config_menu.sorting_menu -tearoff 0]
+ # Entry: "By name"
+ $sorting_menu add radiobutton -label [mc "By name"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {name} -underline 3 -command [list $this reload]
+ # Entry: "By date"
+ $sorting_menu add radiobutton -label [mc "By date"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {date} -underline 3 -command [list $this reload]
+ # Entry: "By size"
+ $sorting_menu add radiobutton -label [mc "By size"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {size} -underline 3 -command [list $this reload]
+ $sorting_menu add separator
+ # Entry: "Reverse"
+ $sorting_menu add checkbutton -label [mc "Reverse"] \
+ -variable ::KIFSD::FSD::config(reverse_sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+ # Entry: "Folders first"
+ $sorting_menu add checkbutton -label [mc "Folders first"] \
+ -variable ::KIFSD::FSD::config(folders_first) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+ # Entry: "Case insensitive"
+ $sorting_menu add checkbutton -label [mc "Case insensitive"] \
+ -variable ::KIFSD::FSD::config(case_insensitive) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+
+ ## Create entries for configuraion menu (accessable from toolbar)
+ # Entry: "Sorting"
+ $win.config_menu add cascade -label [mc "Sorting"] -underline 1 -menu $sorting_menu -image ::ICONS::16::sort_incr -compound left
+ $win.config_menu add separator
+ # Entry: "Short view"
+ $win.config_menu add command -label [mc "Short view"] -compound left \
+ -accelerator "F6" -command "$this short_view" -underline 0 \
+ -image ::ICONS::16::view_icon
+ # Entry: "Detailed view"
+ $win.config_menu add command -label [mc "Detailed view"] -compound left \
+ -accelerator "F7" -command "$this detail_view" -underline 0 \
+ -image ::ICONS::16::view_detailed
+ $win.config_menu add separator
+ # Entry: "Show hidden files"
+ $win.config_menu add checkbutton -label [mc "Show hidden files"] \
+ -accelerator "F8" -variable ::KIFSD::FSD::config(show_hidden_files) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 5
+ # Entry: "Quick access navigation panel"
+ $win.config_menu add checkbutton -label [mc "Quick access navigation panel"] \
+ -accelerator "F9" -variable ::KIFSD::FSD::config(quick_access_panel) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this quick_access_panel_onoff" -underline 0
+ # Entry: "Separate folders"
+ $win.config_menu add checkbutton -label [mc "Separate folders"] \
+ -accelerator "F12" -variable ::KIFSD::FSD::config(separate_folders) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this separate_folders_onoff" -underline 9
+ if {!$option_fileson} {
+ $win.config_menu entryconfigure [mc "Separate folders"] -state disabled
+ $sorting_menu entryconfigure [mc "Folders first"] -state disabled
+ $sorting_menu entryconfigure [mc "By size"] -state disabled
+ }
+
+ ## Create bookmarks menu (accessable from toolbar)
+ set bookmark_menu [menu $win.bookmark_menu -tearoff 0]
+ # Entry: "Add bookmark"
+ $bookmark_menu add command -label [mc "Add bookmark"] \
+ -command "$this add_bookmark" \
+ -underline 0 -image ::ICONS::16::bookmark_add -compound left
+ # Entry: "Edit bookmarks"
+ $bookmark_menu add command -label [mc "Edit bookmarks"] -compound left \
+ -command "$this edit_bookmarks" -underline 0 -image ::ICONS::16::bookmark
+ $bookmark_menu add separator
+ refresh_bookmarks
+
+ ## Create ListBox item menu
+ menu $win.listbox_menu -tearoff 0
+ # Entry: "Up"
+ $win.listbox_menu add command -label [mc "Up"] -compound left \
+ -underline 0 -command [list $this up] \
+ -image ::ICONS::16::up
+ # Entry: "Back"
+ $win.listbox_menu add command -label [mc "Back"] -compound left \
+ -underline 0 -command [list $this back] \
+ -image ::ICONS::16::left -state disabled
+ # Entry: "Forward"
+ $win.listbox_menu add command -label [mc "Forward"] -compound left \
+ -underline 0 -command [list $this forward] \
+ -image ::ICONS::16::right -state disabled
+ $win.listbox_menu add separator
+ # Entry: "Rename"
+ $win.listbox_menu add command -label [mc "Rename"] \
+ -underline 0 -command [list $this rename_item_command] \
+ -compound left -image ::ICONS::16::edit
+ # Entry: "Delete"
+ $win.listbox_menu add command -label [mc "Delete"] \
+ -underline 0 -command [list $this delete_item_command] \
+ -compound left -image ::ICONS::16::editdelete
+ # Entry: "New folder"
+ $win.listbox_menu add command -label [mc "New folder"] \
+ -accelerator "F10" \
+ -underline 0 -command [list $this newdir] \
+ -compound left -image ::ICONS::16::folder_new
+ # Entry: "Bookmark folder"
+ $win.listbox_menu add command -label [mc "Bookmark folder"] \
+ -underline 0 -command [list $this item_bookmark_add] \
+ -compound left -image ::ICONS::16::bookmark_add
+ $win.listbox_menu add separator
+ # Entry: "Properties"
+ $win.listbox_menu add command -label [mc "Properties"] \
+ -underline 0 -command [list $this properties_item_command]
+
+ ## Create quick access bar popup menu
+ menu $win.quick_access_panel_menu -tearoff 0
+ # Entry: "Add entry"
+ $win.quick_access_panel_menu add command -label [mc "Add entry"] \
+ -underline 0 -image ::ICONS::16::filenew -compound left \
+ -command "$this quick_access_panel_add_entry"
+ $win.quick_access_panel_menu add separator
+ # Entry: "Hide panel"
+ $win.quick_access_panel_menu add command -label [mc "Hide panel"] \
+ -underline 0 -image ::ICONS::16::2leftarrow -compound left \
+ -accelerator "F9" -command "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff"
+
+ ## Create quick access bar ITEM popup menu
+ menu $win.quick_access_panel_item_menu -tearoff 0
+ # Entry: "Move up"
+ $win.quick_access_panel_item_menu add command -label [mc "Move up"] \
+ -underline 0 -image ::ICONS::16::1uparrow -compound left \
+ -command "$this quick_access_panel_up"
+ # Entry: "Move down"
+ $win.quick_access_panel_item_menu add command -label [mc "Move down"] \
+ -underline 0 -image ::ICONS::16::1downarrow -compound left \
+ -command "$this quick_access_panel_down"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Edit entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Edit entry"] \
+ -underline 0 -image ::ICONS::16::edit -compound left \
+ -command "$this quick_access_panel_edit_entry"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Add entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Add entry"] \
+ -underline 0 -image ::ICONS::16::filenew -compound left \
+ -command "$this quick_access_panel_add_entry"
+ # Entry: "Remove entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Remove entry"]\
+ -underline 0 -image ::ICONS::16::editdelete -compound left \
+ -command "$this quick_access_panel_remove_entry"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Hide panel"
+ $win.quick_access_panel_item_menu add command -label [mc "Hide panel"] \
+ -underline 0 -image ::ICONS::16::2leftarrow -compound left \
+ -accelerator "F9" \
+ -command "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff"
+ }
+
+ ## Define key shortcuts for the dialog
+ # @return void
+ private method create_shortcuts {} {
+ bind $win <Key-F5> "$this reload; break"
+ bind $win <Key-F6> "$this short_view; break"
+ bind $win <Key-F7> "$this detail_view; break"
+ bind $win <Key-F8> "
+ set ::KIFSD::FSD::config(show_hidden_files) \
+ \[expr {!\${::KIFSD::FSD::config(show_hidden_files)}}\]
+ $this reload
+ break
+ "
+ bind $win <Key-F9> "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff
+ break
+ "
+ bind $win <Key-F10> "$this newdir; break"
+ if {$option_fileson} {
+ bind $win <Key-F12> "
+ set ::KIFSD::FSD::config(separate_folders) \
+ \[expr {!\${::KIFSD::FSD::config(separate_folders)}}\]
+ $this separate_folders_onoff
+ break
+ "
+ }
+ }
+
+ ## Change current directory
+ # This function checks for directory validity
+ # @parm String dir - New directory
+ # @return void
+ public method change_directory {dir} {
+ if {$::MICROSOFT_WINDOWS} {
+ # Transform for instance "C:" to "C:/"
+ if {[regexp {^\w+:$} $dir]} {
+ append dir {/}
+ }
+ }
+
+ # Check if the specified directory is valid
+ if {![file exists $dir] || ![file isdirectory $dir]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [mc "Invalid folder"] \
+ -message [mc "The specified folder does not exist:\n%s" $dir]
+ return
+ }
+ set dir [file normalize $dir]
+
+ # Adjust history
+ if {$dir != $current_directory} {
+ lappend back_history $current_directory
+ set forward_history {}
+ $win.listbox_menu entryconfigure [mc "Forward"] -state disabled
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ $toolbar.forward configure -state disabled
+ $toolbar.back configure -state normal
+ }
+
+ # Option separate_folders ON
+ FSnotifications::forget $current_directory
+ FSnotifications::watch $dir [list KIFSD::FSD::static_reload $this]
+ set current_directory $dir
+ if {${::KIFSD::FSD::config(separate_folders)} && $option_fileson} {
+ # Fill up directory ListBox with directories
+ $dir_listbox delete [$dir_listbox items]
+ foreach folder [dir_cmd $dir 1] {
+ if {$folder == {..}} {
+ set image {up}
+ } else {
+ set image {fileopen}
+ }
+ $dir_listbox insert end #auto \
+ -text $folder \
+ -image ::ICONS::16::$image \
+ -font $listbox_font_short
+ }
+
+ # Fill up file ListBox with files
+ $file_listbox delete [$file_listbox items]
+ foreach file [file_cmd $dir $current_mask] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set filename [lindex $file 1]
+ set file [lindex $file 0]
+ } else {
+ set filename $file
+ }
+ $file_listbox insert end #auto \
+ -text $file \
+ -image ::ICONS::16::ascii \
+ -font $listbox_font \
+ -data [list $filename {}]
+ }
+ # Option separate_folders OFF
+ } else {
+ # Option folders_first ON or option_fileson OFF
+ $file_listbox delete [$file_listbox items]
+ if {!$option_fileson || ${::KIFSD::FSD::config(folders_first)}} {
+ # Fill up files ListBox with directories
+ foreach folder [dir_cmd $dir] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set fullname [lindex $folder 1]
+ set folder [lindex $folder 0]
+ } else {
+ set fullname $folder
+ }
+
+ if {$folder == {..}} {
+ set image {up}
+ set fullname $folder
+ } else {
+ set image {fileopen}
+ }
+
+ $file_listbox insert end #auto \
+ -text $folder \
+ -image ::ICONS::16::$image \
+ -font $listbox_font \
+ -data [list {} $fullname]
+ }
+ # Option: option_fileson ON
+ if {$option_fileson} {
+ # Fill up files ListBox with files
+ foreach file [file_cmd $dir $current_mask] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set filename [lindex $file 1]
+ set file [lindex $file 0]
+ } else {
+ set filename $file
+ }
+
+ $file_listbox insert end #auto \
+ -text $file \
+ -image ::ICONS::16::ascii \
+ -font $listbox_font \
+ -data [list $filename {}]
+ }
+ }
+ # Option NOT ( folders_first ON or option_fileson OFF )
+ } else {
+ # Fill up files ListBox with files and directories
+ foreach file [dir_file_cmd $dir $current_mask] {
+ set filename {}
+ set folder {}
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set fullname [lindex $file {0 1}]
+ set text [lindex $file {0 0}]
+ } else {
+ set fullname [lindex $file 0]
+ set text $fullname
+ }
+
+ switch -- [lindex $file 1] {
+ u {
+ set image {up}
+ set folder {..}
+ }
+ d {
+ set image {fileopen}
+ set folder $fullname
+ }
+ f {
+ set image {ascii}
+ set filename $fullname
+ }
+ }
+
+ $file_listbox insert end #auto \
+ -text $text \
+ -image ::ICONS::16::$image \
+ -font $listbox_font \
+ -data [list $filename $folder]
+ }
+ }
+ }
+
+ # Fill up location ComboBox with available files or directories
+ if {$option_fileson} {
+ $location_cb configure -values [file_cmd $dir $current_mask 1]
+ } else {
+ $location_cb configure -values [dir_cmd $dir 1]
+ }
+ $location_cb set {}
+
+ # Fill up directory ComboBox
+ set values {}
+ set folder $dir
+ while {1} {
+ lappend values $folder
+ if {$folder == [file separator]} {break}
+ if {$::MICROSOFT_WINDOWS} {
+ if {[regexp {^\w+:[\\\/]?$} $folder]} {break}
+ }
+ set folder [file normalize [file join $folder {..}]]
+ }
+ foreach folder [dir_cmd $dir 1] {
+ if {$folder == {..}} {continue}
+ lappend values [file join $dir $folder]
+ }
+ if {$::MICROSOFT_WINDOWS} { ;# Include drive letters on Microsoft Windows
+ foreach drive_letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
+ if {[file exists "${drive_letter}:/"]} {
+ lappend values "${drive_letter}:/"
+ }
+ }
+ }
+
+ $dir_combobox configure -values $values
+ $dir_combobox current 0
+ $dir_combobox icursor end
+
+ # Enable / Disable button "Up (Parent folder)"
+ if {$dir == {/} || $dir == "\\"} {
+ $toolbar.up configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Up"] -state disabled
+ } else {
+ $toolbar.up configure -state normal
+ $win.listbox_menu entryconfigure [mc "Up"] -state normal
+ }
+ }
+
+ ## This function shoul be called after Filter ComboBox change
+ # @return void
+ public method filter_cb_modify {} {
+ set current_mask [lindex $option_filetypes [$filter_cb current]]
+ reload
+ }
+
+ ## Show / Hide quick access bar according to configuration variable quick_access_panel
+ # @return void
+ public method quick_access_panel_onoff {} {
+ # Show the panel
+ if {${::KIFSD::FSD::config(quick_access_panel)}} {
+ pack $main_paned_window -fill both -expand 1
+ $main_paned_window add $leftframe
+ $main_paned_window add $rightframe
+ $main_paned_window paneconfigure $leftframe -minsize 100
+ $main_paned_window paneconfigure $rightframe -minsize 300
+ if {$dialog_loaded} {update}
+ $main_paned_window sash place 0 ${::KIFSD::FSD::config(main_PW_size)} 0
+ if {$dialog_loaded} {update}
+ # Hide the panel
+ } else {
+ if {[winfo ismapped $main_paned_window]} {
+ set ::KIFSD::FSD::config(main_PW_size) \
+ [lindex [$main_paned_window sash coord 0] {0 0}]
+ $main_paned_window forget $leftframe
+ $main_paned_window forget $rightframe
+ pack forget $main_paned_window
+ }
+ pack $rightframe -fill both -expand 1 -padx 5
+ }
+ }
+
+ ## Show / Hide folders ListBox according to configuration variable separate_folders
+ # This function will show folders ListBox only if option_fileson == 1
+ # @return void
+ public method separate_folders_onoff {} {
+ # Show folders ListBox
+ if {${::KIFSD::FSD::config(separate_folders)} && $option_fileson} {
+ pack $right_paned_window -fill both -expand 1
+ $right_paned_window add $right_top_left_frame
+ $right_paned_window add $right_top_right_frame
+ $right_paned_window paneconfigure $right_top_left_frame -minsize 150
+ $right_paned_window paneconfigure $right_top_right_frame -minsize 200
+ if {$dialog_loaded} {update}
+ $right_paned_window sash place 0 ${::KIFSD::FSD::config(right_PW_size)} 0
+ if {$dialog_loaded} {update}
+
+ # Hide folders ListBox
+ } else {
+ if {[winfo ismapped $right_paned_window]} {
+ set ::KIFSD::FSD::config(right_PW_size) \
+ [lindex [$right_paned_window sash coord 0] {0 0}]
+ $right_paned_window forget $right_top_left_frame
+ $right_paned_window forget $right_top_right_frame
+ pack forget $right_paned_window
+ }
+ pack $right_top_right_frame -expand 1 -fill both -in $right_top_frame
+ }
+
+ # Refresh files and folders ListBoxes
+ change_directory $current_directory
+ }
+
+ ## Invoke bookmark menu
+ # @return void
+ public method bookmark_menu {} {
+ set x [winfo rootx $toolbar.bookmark]
+ set y [winfo rooty $toolbar.bookmark]
+ incr y [winfo height $toolbar.bookmark]
+ tk_popup $win.bookmark_menu $x $y
+ }
+
+ ## Invoke configuration menu
+ # @return void
+ public method config_menu {} {
+ set x [winfo rootx $toolbar.configure]
+ set y [winfo rooty $toolbar.configure]
+ incr y [winfo height $toolbar.configure]
+ tk_popup $win.config_menu $x $y
+ }
+
+ ## Scroll folders ListBox and (Un)Map its scrollbar
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method dir_listbox_scroll {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $dir_listbox_scrollbar]} {
+ pack forget $dir_listbox_scrollbar
+ }
+ # Show scrollbar
+ } else {
+ if {![winfo ismapped $dir_listbox_scrollbar]} {
+ pack $dir_listbox_scrollbar -fill y -expand 1 -after $dir_listbox
+ }
+ $dir_listbox_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Switch to mode "Short View"
+ # @return void
+ public method short_view {} {
+ if {!${::KIFSD::FSD::config(detailed_view)}} {return}
+ set ::KIFSD::FSD::config(detailed_view) 0
+ $file_listbox configure -multicolumn 1
+ set listbox_font $listbox_font_short
+ pack forget $file_listbox_header
+ reload
+ }
+
+ ## Switch to mode "Detailed View"
+ # @return void
+ public method detail_view {} {
+ if {${::KIFSD::FSD::config(detailed_view)}} {return}
+ set ::KIFSD::FSD::config(detailed_view) 1
+ $file_listbox configure -multicolumn 0
+ set listbox_font $listbox_font_detailed
+ pack $file_listbox_header -before $file_listbox -fill x -expand 0
+ reload
+ }
+
+ ## Bookmark current folder
+ # @return void
+ public method add_bookmark {} {
+ lappend ::KIFSD::FSD::config(bookmarks) $current_directory
+ $bookmark_menu add command \
+ -label $current_directory -compound left \
+ -image ::ICONS::16::fileopen \
+ -command "$this change_directory {$current_directory}"
+ uplevel #0 $bookmark_change_command
+ }
+
+ ## Invoke bookmark editor
+ # @return void
+ public method edit_bookmarks {} {
+ # Create dialog window
+ set dialog [toplevel $win.edit_bookmarks -class {Edit bookmarks} -bg ${::COMMON_BG_COLOR}]
+
+ # Create top frame (ListBox containing bookmarks and its scrollbar)
+ set top_frame [frame $dialog.top_frame]
+ set bookmark_edit_listbox [ListBox $top_frame.listbox \
+ -yscrollcommand "$top_frame.scrollbar set" \
+ -bg white -selectfill 1 -selectmode single \
+ -highlightcolor {#BBBBFF} \
+ ]
+ $bookmark_edit_listbox bindText <Double-1> "$this edit_bookmarks_edit"
+ pack $bookmark_edit_listbox -side left -fill both -expand 1
+ pack [ttk::scrollbar $top_frame.scrollbar \
+ -orient vertical \
+ -command "$bookmark_edit_listbox yview" \
+ ] -fill y -expand 1
+
+ # Fill up ListBox with defined bookmarks
+ foreach item ${::KIFSD::FSD::config(bookmarks)} {
+ $bookmark_edit_listbox insert end #auto -text $item
+ }
+
+ ## Create bottom frame (buttons)
+ set bottom_frame [frame $dialog.bottom_frame]
+ # Button: "Remove"
+ pack [ttk::button $bottom_frame.remove \
+ -text [::mc "Remove"] \
+ -compound left \
+ -image ::ICONS::16::editdelete \
+ -command "$this edit_bookmarks_remove" \
+ -width 8 \
+ ] -side left -padx 2
+ # Button: "Edit"
+ pack [ttk::button $bottom_frame.edit \
+ -text [::mc "Edit"] \
+ -compound left \
+ -image ::ICONS::16::edit \
+ -command "$this edit_bookmarks_edit" \
+ -width 8 \
+ ] -side left -padx 2
+ # Button: "Up"
+ pack [ttk::button $bottom_frame.up \
+ -text [::mc "Up"] \
+ -compound left \
+ -image ::ICONS::16::up \
+ -command "$this edit_bookmarks_up" \
+ -width 8 \
+ ] -side left -padx 2
+ # Button: "Down"
+ pack [ttk::button $bottom_frame.down \
+ -text [::mc "Down"] \
+ -compound left \
+ -image ::ICONS::16::down \
+ -command "$this edit_bookmarks_down" \
+ -width 8 \
+ ] -side left -padx 2
+ # Button: "Ok"
+ pack [ttk::button $bottom_frame.ok \
+ -text [::mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -width 8 \
+ -command "
+ $this bookmark_edit_ok
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right -padx 2
+ # Button: "Cancel"
+ pack [ttk::button $bottom_frame.cancel \
+ -text [::mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -width 8 \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right -padx 2
+
+ # Pack dialog frames (top and bottom)
+ pack $top_frame -side top -fill both -expand 1 -pady 5 -padx 5
+ pack $bottom_frame -side top -after $top_frame -fill x -expand 0 -pady 5 -padx 5
+
+ # Configure dialog window
+ wm iconphoto $dialog ::ICONS::16::bookmark
+ wm title $dialog "Edit bookmarks"
+ wm minsize $dialog 550 240
+ wm geometry $dialog 550x340
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ if {[winfo ismapped $win]} {
+ wm transient $dialog $win
+ } else {
+ wm transient $dialog .
+ }
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Remove current bookmark
+ # @return void
+ public method edit_bookmarks_remove {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ $bookmark_edit_listbox delete $item
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Edit current bookmark
+ # @return void
+ public method edit_bookmarks_edit args {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ set text [$bookmark_edit_listbox edit $item \
+ [$bookmark_edit_listbox itemcget $item -text]]
+ if {$text == {}} {return}
+ $bookmark_edit_listbox itemconfigure $item -text $text
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Move current bookmark up
+ # @return void
+ public method edit_bookmarks_up {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ if {
+ ![$bookmark_edit_listbox index $item]
+ ||
+ ([llength [$bookmark_edit_listbox items]] < 2)
+ } then {
+ return
+ }
+ $bookmark_edit_listbox move $item [expr {[$bookmark_edit_listbox index $item] - 1}]
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Move current bookmark down
+ # @return void
+ public method edit_bookmarks_down {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ if {
+ [$bookmark_edit_listbox index $item]
+ >=
+ ([llength [$quick_access_bar items]] - 1)
+ } then {
+ return
+ }
+ $bookmark_edit_listbox move $item [expr {[$bookmark_edit_listbox index $item] + 1}]
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Confirm bookmark edit dialog
+ # @return void
+ public method bookmark_edit_ok {} {
+ set ::KIFSD::FSD::config(bookmarks) {}
+ foreach item [$bookmark_edit_listbox items] {
+ lappend ::KIFSD::FSD::config(bookmarks) \
+ [$bookmark_edit_listbox itemcget $item -text]
+ }
+ refresh_bookmarks
+ uplevel #0 $bookmark_change_command
+ }
+
+ ## Reload items to bookmarks menu
+ # @return void
+ private method refresh_bookmarks {} {
+ if {[$bookmark_menu index end] > 2} {
+ $bookmark_menu delete 3 end
+ }
+ foreach dir ${::KIFSD::FSD::config(bookmarks)} {
+ $bookmark_menu add command \
+ -label $dir -compound left \
+ -image ::ICONS::16::fileopen \
+ -command "$this change_directory {$dir}"
+ }
+ }
+
+ ## Set command to execute when bookmark list changes
+ # @parm String command - Command to invoke from root namespace
+ # @return void
+ proc set_bookmark_change_command {command} {
+ set bookmark_change_command $command
+ }
+
+ ## Unmap dialog window (but keep object alive)
+ # @return void
+ public method deactivate {} {
+ wm withdraw $win
+ }
+
+ ## Activate (map) dialog window
+ # And wait until window is unmapped
+ # @return void
+ public method activate {} {
+ wm resizable $win 1 1
+ wm deiconify $win
+ update idletasks
+ if {[winfo ismapped $right_paned_window]} {
+ $right_paned_window sash place 0 ${::KIFSD::FSD::config(right_PW_size)} 0
+ }
+ if {[winfo ismapped $main_paned_window]} {
+ $main_paned_window sash place 0 ${::KIFSD::FSD::config(main_PW_size)} 0
+ }
+ tkwait window $win
+ }
+
+ ## Get selected item(s)
+ # @return String/List - Full path(s) to selected item(s)
+ public method get {} {
+ # Return List
+ if {$option_multiple} {
+ set result {}
+ foreach item [$file_listbox selection get] {
+ lappend result [file join $current_directory \
+ [lindex [$file_listbox itemcget $item -data] 0]]
+ }
+ if {$result == {}} {
+ lappend result [file join $current_directory [$location_cb get]]
+ }
+ return $result
+ # Return String
+ } else {
+ return [file join $current_directory [$location_cb get]]
+ }
+ }
+
+ ## Destroy dialog object
+ # @return void
+ public method close_dialog {} {
+ catch {
+ itcl::delete object $this
+ }
+ }
+
+ ## Set command to invoke from root namespace on action "Ok"
+ # @parm String command - Command (with arguments)
+ # @return void
+ public method setokcmd {cmd} {
+ set ok_command $cmd
+ }
+
+ ## Ok action - command for button "Ok"
+ # @return void
+ public method ok {} {
+ if {$option_autoclose} {
+ wm withdraw $win
+ set ok_command_tmp $ok_command
+ set ok_command {}
+ uplevel #0 $ok_command_tmp
+ close_dialog
+ } else {
+ uplevel #0 $ok_command
+ }
+ }
+
+ ## Command for files ListBox horizontal scrollbar
+ # Takes any list of arguments (see code)
+ # @return void
+ public method file_listbox_hscrollbar_cmd args {
+ eval "$file_listbox xview $args"
+ eval "$file_listbox_header xview $args"
+ }
+
+ ## Scroll files ListBox vertically
+ # This function manages scrollbar visibility
+ # @parm Float frac0 - 1st fraction (see Tk manual)
+ # @parm Float frac1 - 2nd fraction (see Tk manual)
+ # @return void
+ public method file_listbox_vscroll {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $file_listbox_vscrollbar]} {
+ pack forget $file_listbox_vscrollbar
+ update
+ }
+
+ # Show scrollbar
+ } else {
+ if {![winfo ismapped $file_listbox_vscrollbar]} {
+ pack $file_listbox_vscrollbar \
+ -after $file_listbox_frame \
+ -fill y -expand 1
+ update
+ }
+ $file_listbox_vscrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Scroll files ListBox horizontaly
+ # This function manages scrollbar visibility
+ # @parm Float frac0 - 1st fraction (see Tk manual)
+ # @parm Float frac1 - 2nd fraction (see Tk manual)
+ # @return void
+ public method file_listbox_hscroll {frac0 frac1} {
+
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $file_listbox_hscrollbar]} {
+ pack forget $file_listbox_hscrollbar
+ update
+ }
+
+ # Show scrollbar
+ } else {
+ if {![winfo ismapped $file_listbox_hscrollbar]} {
+ pack $file_listbox_hscrollbar \
+ -after $right_top_right_top_frame \
+ -side bottom -fill x -expand 0
+ update
+ }
+ catch {
+ $file_listbox_hscrollbar set $frac0 $frac1
+ }
+ }
+ }
+
+ ## Event handler for quick access bar ListBox, event <<ListboxSelect>>
+ # @return void
+ public method quick_access_bar_select {} {
+ if {$option_doubleclick} {return}
+ catch {
+ change_directory \
+ [$quick_access_bar itemcget \
+ [$quick_access_bar selection get] -data]
+ }
+ }
+
+ ## Event handler for quick access bar ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method quick_access_bar_doubleclick {item} {
+ if {!$option_doubleclick} {return}
+ catch {
+ change_directory \
+ [$quick_access_bar itemcget \
+ [$quick_access_bar selection get] -data]
+ }
+ }
+
+ ## Event handler for directories ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method dir_listbox_doubleclick {item} {
+ # Abort if dirs ListBox widget is no longer available
+ if {![winfo exists $dir_listbox]} {
+ return
+ }
+ if {!$option_doubleclick} {return}
+ catch {
+ change_directory [file join $current_directory \
+ [$dir_listbox itemcget $item -text]]
+ }
+ }
+
+ ## Event handler for directories ListBox, event <<ListboxSelect>>
+ # @return void
+ public method dir_listbox_select {} {
+ # Abort if dirs ListBox widget is no longer available
+ if {![winfo exists $dir_listbox]} {
+ return
+ }
+ if {$option_doubleclick} {return}
+ catch {
+ change_directory [file normalize [file join $current_directory \
+ [$dir_listbox itemcget [$dir_listbox selection get] -text]]]
+ }
+ }
+
+ ## Event handler for files ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method file_listbox_doubleclick {item} {
+ # Abort if files ListBox widget is no longer available
+ if {![winfo exists $file_listbox]} {
+ return
+ }
+
+ # Item directory or {} if it's a file
+ if {[catch {
+ set folder [lindex [$file_listbox itemcget $item -data] 1]
+ }]} then {
+ return
+ }
+
+ if {!$option_fileson} {
+ if {$folder != {}} {
+ change_directory [file join $current_directory $folder]
+ }
+ return
+ }
+
+ if {$option_doubleclick && !${::KIFSD::FSD::config(separate_folders)}} {
+ if {$folder != {}} {
+ change_directory [file join $current_directory $folder]
+ }
+ }
+
+ if {!$option_doubleclick && ($folder == {})} {
+ ok
+ }
+ }
+
+ ## Scroll files listbox
+ # Arguments are passed to yview or xview command
+ # @return void
+ public method file_listbox_scroll args {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set cmd {yview}
+ } else {
+ set cmd {xview}
+ }
+ eval "$file_listbox.c $cmd scroll $args"
+ }
+
+ ## Event handler for files ListBox, event <<ListboxSelect>>
+ # @return void
+ public method file_listbox_select {} {
+ set selection [$file_listbox selection get]
+
+ # Change directory if the item represents a directory
+ if {$option_fileson && !${::KIFSD::FSD::config(separate_folders)}} {
+ set folder [$file_listbox itemcget [lindex $selection end] -data]
+ set folder [lindex $folder 1]
+ if {$folder != {}} {
+ if {!$option_doubleclick} {
+ change_directory [file join $current_directory $folder]
+ }
+ return
+ }
+ }
+
+ # Change content of location ComboBox if item is a file
+ if {[llength $selection] == 1} {
+ set index [lindex [$file_listbox itemcget $selection -data] [expr {$option_fileson ? 0 : 1}]]
+ if {$index != {..}} {
+ set index [lsearch -ascii [$location_cb cget -values] $index]
+ if {$index != -1} {
+ $location_cb current $index
+ }
+ }
+ } elseif {[llength $selection] > 1} {
+ set text {}
+ foreach item $selection {
+ append text "\""
+ append text [lindex [$file_listbox itemcget $item -data] [expr {$option_fileson ? 0 : 1}]]
+ append text "\" "
+ }
+ $location_cb set $text
+ }
+ }
+
+ ## Reload content of quick access bar ListBox
+ # @return void
+ private method refresh_quick_access_bar {} {
+ # Remove existing items
+ $quick_access_bar delete [$quick_access_bar items]
+
+ # Create new items
+ foreach item ${::KIFSD::FSD::config(quick_access_bar_data)} {
+ # Determinate item icon
+ switch -- [lindex $item 0] {
+ 0 {set image hdd_unmount}
+ 1 {set image folder_home}
+ 2 {set image desktop}
+ 3 {set image bookmark_folder}
+ }
+ # Insert item
+ $quick_access_bar insert end #auto \
+ -font $quick_nav_panel_font \
+ -image ::ICONS::22::$image \
+ -text [lindex $item 1] \
+ -data [lindex $item 2] \
+ }
+ }
+
+ ## Invoke popup menu for ListBox of Quick access bar
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method quick_access_bar_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ catch {
+ tk_popup $win.quick_access_panel_menu $x $y
+ }
+ }
+
+ ## Invoke popup menu for particular item in ListBox of Quick access bar
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method quick_access_bar_item_menu {x y item} {
+ set item_menu_request 1
+ set current_item $item
+ set current_item_index [$quick_access_bar index $item]
+ set len [llength [$quick_access_bar items]]
+
+ # Enable / Disabled entry "Move down"
+ if {$current_item_index >= ($len - 1)} {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move down"] -state disabled
+ } else {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move down"] -state normal
+ }
+
+ # Enable / Disabled entry "Move up"
+ if {!$current_item_index || ($len < 2)} {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move up"] -state disabled
+ } else {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move up"] -state normal
+ }
+
+ # Invoke the menu
+ tk_popup $win.quick_access_panel_item_menu $x $y
+ }
+
+ ## Move current item in quick access bar down
+ # @return void
+ public method quick_access_panel_down {} {
+ # Check if the item is not the topmost one
+ if {$current_item_index >= ([llength [$quick_access_bar items]] - 1)} {
+ return
+ }
+
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index [expr {$current_item_index + 1}] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index + 1}]] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index]
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Move current item in quick access bar up
+ # @return void
+ public method quick_access_panel_up {} {
+ # Check if the item is not the bottommost one
+ if {!$current_item_index || ([llength [$quick_access_bar items]] < 2)} {
+ return
+ }
+
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index - 1}] $current_item_index \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index - 1}]]
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Invoke dialog to add entry to quick access bar
+ # @return void
+ public method quick_access_panel_add_entry {} {
+ set data [qa_panel_dialog "Add entry" {3} [::mc "New entry"] {~}]
+ if {![string length [lindex $data 1]]} {return}
+ if {![string length [lindex $data 2]]} {return}
+ lappend ::KIFSD::FSD::config(quick_access_bar_data) $data
+ refresh_quick_access_bar
+ }
+
+ ## Invoke dialog to edit current entry in quick access bar
+ # @return void
+ public method quick_access_panel_edit_entry {} {
+ set data [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} $current_item_index]
+ set data [qa_panel_dialog "Edit entry" [lindex $data 0] [lindex $data 1] [lindex $data 2]]
+ if {![string length [lindex $data 1]]} {return}
+ if {![string length [lindex $data 2]]} {return}
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index $current_item_index $data \
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Select icon in quick access bar edit dialog
+ # @parm Int index - Icon index [0; 4]
+ # @return void
+ public method qa_panel_dialog_icon {index} {
+ for {set i 0} {$i < 4} {incr i} {
+ ${win}.qa_panel_dialog.labelframe.button_$i configure -style Flat.TButton
+ }
+ ${win}.qa_panel_dialog.labelframe.button_$index configure -style TButton
+ set ::KIFSD::FSD::qa_panel_dialog_icon $index
+ }
+
+ ## EntryBox validator
+ # If the content was an empty string then set entry background color to red
+ # @parm Widget widget - EntryBox widget
+ # @parm String content - EntryBox content
+ # @return Bool - Always 1
+ proc not_empty_entry_validator {widget content} {
+ if {![string length $content]} {
+ $widget configure -style StringNotFound.TEntry
+ } else {
+ $widget configure -style TEntry
+ }
+ return 1
+ }
+
+ ## Invoke dialog for editing entries in the quick access bar
+ # Auxiliary procedure for:
+ # * quick_access_panel_add_entry
+ # * quick_access_panel_edit_entry
+ # @parm String title - Dialog title
+ # @parm Int icon - Icon number [0;3]
+ # @parm String name - Item name
+ # @parm String url - Target URL
+ # @return List - {new_icon_number new_name new_url}
+ private method qa_panel_dialog {title icon name url} {
+ # Create dialog window
+ set dialog [toplevel ${win}.qa_panel_dialog -class {Configuration dialog} -bg ${::COMMON_BG_COLOR}]
+
+ # Set dialog variables
+ set ::KIFSD::FSD::qa_panel_dialog_icon $icon
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry $name
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry $url
+
+ ## Create main frame (Name: and URL:)
+ set mid_frame [frame $dialog.middle]
+ # Label: "Name"
+ grid [label $mid_frame.name_lbl \
+ -text [::mc "Name"] \
+ ] -row 0 -column 0 -sticky w
+ # Label: "URL"
+ grid [label $mid_frame.url_lbl \
+ -text [::mc "URL"] \
+ ] -row 1 -column 0 -sticky w
+ # EntryBox: "Name"
+ grid [ttk::entry $mid_frame.name_entry \
+ -width 1 \
+ -validate all \
+ -validatecommand "::KIFSD::FSD::not_empty_entry_validator %W %P" \
+ -textvariable ::KIFSD::FSD::qa_panel_dialog_name_entry \
+ ] -row 0 -column 1 -sticky we
+ # EntryBox: "URL"
+ grid [ttk::entry $mid_frame.url_entry \
+ -width 1 \
+ -validate all \
+ -textvariable ::KIFSD::FSD::qa_panel_dialog_url_entry \
+ -validatecommand "::KIFSD::FSD::dir_validate {} %W %P" \
+ ] -row 1 -column 1 -sticky we
+ grid columnconfigure $mid_frame 1 -weight 1
+ pack $mid_frame -padx 10 -pady 5 -fill x -expand 1
+
+ # Create frame for selecting icon
+ pack [ttk::labelframe $dialog.labelframe \
+ -text [::mc "Icon"] \
+ ] -fill none -expand 1 -anchor w -padx 10
+ foreach icon {hdd_unmount folder_home desktop bookmark_folder} index {0 1 2 3} {
+ pack [ttk::button $dialog.labelframe.button_$index \
+ -image ::ICONS::22::$icon \
+ -command "$this qa_panel_dialog_icon $index" \
+ -width 6 \
+ -style Flat.TButton \
+ ] -side left -padx 5 -pady 5
+ }
+ $dialog.labelframe.button_${::KIFSD::FSD::qa_panel_dialog_icon} \
+ configure -style TButton
+
+ ## Create bottom frame (Buttons "Ok" and "Cancel")
+ set bot_frame [frame $dialog.bot]
+ # Button: "Ok"
+ pack [ttk::button $bot_frame.ok \
+ -text [::mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "
+ if \[string length \${::KIFSD::FSD::qa_panel_dialog_name_entry}\] {
+ if \[string length \${::KIFSD::FSD::qa_panel_dialog_url_entry}\] {
+ grab release $dialog
+ destroy $dialog
+ }
+ }" \
+ ] -side left -fill none -expand 0 -padx 2
+ # Button: "Cancel"
+ pack [ttk::button $bot_frame.cancel \
+ -text [::mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_icon {}
+ grab release $dialog
+ destroy $dialog" \
+ ] -side left -fill none -expand 0 -padx 2
+ pack $bot_frame -anchor e -padx 10 -pady 5
+
+ # Configure dialog window
+ wm title $dialog $title
+ wm resizable $dialog 0 0
+ wm geometry $dialog 380x160
+ wm protocol $dialog WM_DELETE_WINDOW "
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_icon {}
+ grab release $dialog
+ destroy $dialog
+ "
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ focus -force $mid_frame.name_entry
+ tkwait window $dialog
+
+ # Return results
+ return [list \
+ ${::KIFSD::FSD::qa_panel_dialog_icon} \
+ ${::KIFSD::FSD::qa_panel_dialog_name_entry} \
+ ${::KIFSD::FSD::qa_panel_dialog_url_entry} \
+ ]
+ }
+
+ ## Remove entry from quick access bar (popup menu action)
+ # @return void
+ public method quick_access_panel_remove_entry {} {
+ set ::KIFSD::FSD::config(quick_access_bar_data) \
+ [lreplace ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index $current_item_index]
+ refresh_quick_access_bar
+ }
+
+ ## Invoke popup menu for directories ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method dir_listbox_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state disabled
+ }
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for item in directories ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method dir_listbox_item_menu {x y item} {
+ set item_menu_request 1
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state normal
+ }
+ set cur_listbox {dir}
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for files ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method file_listbox_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ foreach entry {Rename Delete Properties} {
+ $win.listbox_menu entryconfigure [mc $entry] -state disabled
+ }
+ $win.listbox_menu entryconfigure [mc {Bookmark folder}] -state normal
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for item in files ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method file_listbox_item_menu {x y item} {
+ set item_menu_request 1
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state normal
+ }
+ set cur_listbox {file}
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Remove selected file or directory
+ # @return void
+ public method delete_item_command {} {
+ # Determinate URL to delete
+ if {$cur_listbox == {dir}} {
+ set filename [$dir_listbox itemcget $current_item -text]
+ } else {
+ set data [$file_listbox itemcget $current_item -data]
+ if {[lindex $data 0] == {}} {
+ set filename [lindex $data 1]
+ } else {
+ set filename [lindex $data 0]
+ }
+ }
+ if {$filename == {}} {return}
+
+ # Invoke confirmation dialog
+ if {[tk_messageBox \
+ -parent $win \
+ -type yesno \
+ -icon question \
+ -title [::mc "Delete file"] \
+ -message [::mc "Do you really want to delete file:\n%s" $filename]]
+ ==
+ {yes}
+ } then {
+ # Delete file/directory (+ invoke error dialog)
+ if {[catch {file delete -force -- [file join $current_directory $filename]}]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [::mc "Permission denied"] \
+ -message [::mc "Unable to remove file:\n%s" $filename]
+ }
+ }
+ reload
+ }
+
+ ## Bookmark selected folder
+ # @return void
+ public method item_bookmark_add {} {
+ set tmp $current_directory
+ if {$cur_listbox == {dir}} {
+ set current_directory [file join $current_directory \
+ [$dir_listbox itemcget $current_item -text]]
+ }
+ add_bookmark
+ set current_directory $tmp
+ }
+
+ ## Rename selected file or directory
+ # @return void
+ public method rename_item_command {} {
+ if {$cur_listbox == {dir}} {
+ set listbox $dir_listbox
+ } else {
+ set listbox $file_listbox
+ }
+
+ # Determinate old and new name
+ set original [$listbox itemcget $current_item -text]
+ set newname [$listbox edit $current_item \
+ [$listbox itemcget $current_item -text]]
+ if {$newname == {}} {
+ return
+ }
+
+ # Adjust old and new name
+ set original [file join $current_directory $original]
+ set newname [file join $current_directory $newname]
+
+ # Rename file
+ if {[catch {file rename -force $original $newname}]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [::mc "Permission denied"] \
+ -message [::mc "Unable to rename file:\n%s" $original]
+ }
+ reload
+ }
+
+ ## Invoke item properties dialog
+ # @return void
+ public method properties_item_command {} {
+ # Determinate item name, type (File or Directory)
+ if {$cur_listbox == {dir}} {
+ set name [$dir_listbox itemcget $current_item -text]
+ set type "Directory"
+ } else {
+ set name [$file_listbox itemcget $current_item -data]
+ if {[lindex $name 0] == {}} {
+ set name [lindex $name 1]
+ set type "Directory"
+ } else {
+ set name [lindex $name 0]
+ set type "File"
+ }
+ }
+
+ # Determinate full name
+ set fullname [file join $current_directory $name]
+ if {![file exists $fullname]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [::mc "Unknown Error"] \
+ -message [::mc "This file apparently does not exist"]
+ return
+ }
+ # Determinate size
+ set size [file size $fullname]
+ append size { B}
+ # Determinate time of the last mofication
+ set modified [clock format [file mtime $fullname] -format {%D %R}]
+ # Determinate time of the last access
+ set accessed [clock format [file atime $fullname] -format {%D %R}]
+ # Determinate group, owner and permissions
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set perms [file attributes $fullname]
+ set group [lindex $perms 1]
+ set owner [lindex $perms 3]
+ set perms [lindex $perms 5]
+ set perms [string range $perms {end-3} end]
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ mask {0400 0200 0100 040 020 010 04 02 01} \
+ {
+ set ::KIFSD::FSD::item_properties($var) [expr {($perms & $mask) > 0}]
+ }
+ }
+
+ # Create dialog window and Notebook
+ set dialog [toplevel $win.properties_dialog -class {Configuration dialog} -bg ${::COMMON_BG_COLOR}]
+ set nb [NoteBook $dialog.nb -bg ${::COMMON_BG_COLOR}]
+ $nb insert end general -text "General"
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ $nb insert end permission -text "Permissions"
+ }
+ $nb raise general
+
+ ## Create GUI elements for tag "General"
+ set frame [frame [$nb getframe general].frame]
+ pack $frame -side top -anchor n -fill x -expand 1
+ # Name:
+ set row 0
+ grid [label $frame.lbl_$row \
+ -text [::mc "Name:"] -anchor w \
+ -font $listbox_font_short \
+ ] -column 0 -row $row -sticky w -pady 3
+ set ::KIFSD::FSD::item_properties(name) $name
+ grid [ttk::entry $frame.val_lbl_$row \
+ -validate all \
+ -textvariable ::KIFSD::FSD::item_properties(name) \
+ -validatecommand "::KIFSD::FSD::not_empty_entry_validator %W %P" \
+ ] -column 1 -row $row -sticky w -pady 3
+ # Type, Location, Size, Modified, Accessed
+ incr row
+ foreach lbl [list "Type" "Location" "Size" "Modified" "Accessed"] \
+ value [list $type $current_directory $size $modified $accessed] \
+ {
+ grid [label $frame.lbl_$row \
+ -text "[::mc $lbl]:" -anchor w \
+ -font $listbox_font_short \
+ ] -column 0 -row $row -sticky w -pady 3
+ grid [label $frame.val_lbl_$row \
+ -text $value -anchor w \
+ ] -column 1 -row $row -sticky w -pady 3
+ incr row
+ }
+ grid columnconfigure $frame 0 -minsize 100
+
+ ## Create GUI elements for tag "Permissions"
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set frame [$nb getframe permission]
+ set ap_frame [ttk::labelframe $frame.ap_frame \
+ -text [::mc "Access permissions"] \
+ ]
+ set i 0
+ foreach text [list "Class" "Read" "Write" "Exec" "Owner" "Group" "Others"] \
+ row {0 0 0 0 1 2 3} \
+ col {0 1 2 3 0 0 0} \
+ {
+ grid [label $ap_frame.lbl_$i \
+ -text [::mc $text] \
+ -justify center \
+ ] -row $row -column $col -sticky w -padx 4 -pady 4
+ incr i
+ }
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ row {1 1 1 2 2 2 3 3 3} \
+ col {1 2 3 1 2 3 1 2 3} \
+ {
+ grid [checkbutton $ap_frame.check_$i \
+ -variable ::KIFSD::FSD::item_properties($var)
+ ] -row $row -column $col
+ incr i
+ }
+
+ grid columnconfigure $ap_frame 0 -minsize 70
+ grid columnconfigure $ap_frame 0 -weight 1
+ pack $ap_frame -side top -fill x -expand 1 -padx 5 -pady 5 -anchor nw
+
+ set own_frame [ttk::labelframe $frame.own_frame \
+ -text [::mc "Ownership"] \
+ ]
+ grid [label $own_frame.owner_lbl \
+ -text [::mc "Owner"] -font $listbox_font_short \
+ ] -row 0 -column 0 -padx 10 -pady 3 -sticky w
+ grid [label $own_frame.owner_val_lbl \
+ -text $owner -anchor w \
+ ] -row 0 -column 1 -padx 10 -pady 3 -sticky we
+ grid [label $own_frame.group_lbl \
+ -text [::mc "Group"] -font $listbox_font_short \
+ ] -row 1 -column 0 -padx 10 -pady 3 -sticky w
+ grid [label $own_frame.group_val_lbl \
+ -text $group -anchor w \
+ ] -row 1 -column 1 -padx 10 -pady 3 -sticky we
+ grid columnconfigure $own_frame 0 -minsize 70
+ grid columnconfigure $own_frame 1 -weight 1
+ pack $own_frame -side top -fill x -expand 1 -padx 5 -pady 5
+ }
+
+ # Create bottom frame (buttons: "Ok" and "Cancel")
+ set bottom_frame [frame $dialog.bottom_frame]
+ pack [ttk::button $bottom_frame.ok \
+ -text [::mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "$this properties_ok $dialog $fullname" \
+ ] -side left -padx 2
+ pack [ttk::button $bottom_frame.cancel \
+ -text [::mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side left -padx 2
+
+ # Pack notebook and bottom frame
+ pack $nb -fill both -expand 1 -padx 10 -pady 5
+ pack $bottom_frame -anchor e -after $nb -padx 10 -pady 5
+
+ # Configure dialog window
+ wm title $dialog [::mc "Item properties"]
+ wm minsize $dialog 280 320
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog"
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ ## Confirm item properties dialog
+ # @parm Widget dialog - Dialog window
+ # @parm String file - File URL
+ # @return void
+ public method properties_ok {dialog file} {
+ set error 0
+ set perm 0
+
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ val {256 128 64 32 16 8 4 2 1} {
+ if {$::KIFSD::FSD::item_properties($var)} {
+ incr perm $val
+ }
+ }
+ if {[catch {file attributes $file -permissions "0[format {%o} $perm]"}]} {
+ set error 1
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent $dialog \
+ -title [::mc "Permission denied"] \
+ -message [::mc "Unable to change permissions for file:\n%s" [file tail $file]]
+ }
+ }
+ set dir [file dirname $file]
+
+ if {${::KIFSD::FSD::item_properties(name)} != [file tail $file]} {
+ if {[catch {
+ file rename -force -- \
+ $file [file join $dir \
+ ${::KIFSD::FSD::item_properties(name)}]}]
+ } then {
+ set error 1
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent $dialog \
+ -title [::mc "Permission denied"] \
+ -message [::mc "Unable to rename file:%s" "\n[file tail $file]\n\t=>\n${::KIFSD::FSD::item_properties(name)}"]
+ }
+ reload
+ }
+
+ if {!$error} {
+ grab release $dialog
+ destroy $dialog
+ }
+ }
+
+ ## Validate EntryBox containing directory location (set background color: red/white)
+ # @parm widget combobox - ComboBox widget or {}
+ # @parm Widget widget - EntryBox widget
+ # @parm String content - EntryBox content
+ # @return Bool - Always 1
+ proc dir_validate {combobox widget content} {
+ if {![file exists $content] || ![file isdirectory $content]} {
+ if {$combobox != {}} {
+ $combobox configure -style FSD_RedBg.TCombobox
+ } else {
+ $widget configure -style FSD_RedBg.TEntry
+ }
+ } else {
+ if {$combobox != {}} {
+ $combobox configure -style TCombobox
+ } else {
+ $widget configure -style TEntry
+ }
+
+ # Fill directory location combobox
+ if {$combobox != {}} {
+ set folder $content
+ set values {}
+ while {1} {
+ lappend values $folder
+ if {$folder == [file separator]} {break}
+ if {$::MICROSOFT_WINDOWS} {
+ if {[regexp {^\w+:[\\\/]?$} $folder]} {break}
+ }
+ set folder [file normalize [file join $folder {..}]]
+ }
+ foreach folder [::KIFSD::FSD::dir_cmd $content 1] {
+ if {$folder == {..}} {continue}
+ lappend values [file join $content $folder]
+ }
+ if {$::MICROSOFT_WINDOWS} { ;# Include drive letters on Microsoft Windows
+ foreach drive_letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
+ if {[file exists "${drive_letter}:/"]} {
+ lappend values "${drive_letter}:/"
+ }
+ }
+ }
+ $combobox configure -values $values
+ }
+ }
+ return 1
+ }
+
+ ## Reload content of directories ListBox and files ListBox
+ # @param List args - all arguments are ignored
+ # @return void
+ public method reload {args} {
+ update idletasks
+ change_directory $current_directory
+ }
+
+ ## Modify command for directory ComboBox
+ # @return void
+ public method dir_cb_modify {} {
+ change_directory [$dir_combobox get]
+ }
+
+ ## Go to parrent folder
+ # @return void
+ public method up {} {
+ change_directory [file normalize [file join $current_directory {..}]]
+ }
+
+ ## Go back in history
+ # @return void
+ public method back {} {
+ # Determinate new folder
+ set folder [lindex $back_history end]
+ if {$folder == {}} {return}
+
+ # Adjust backward and forward history
+ set back_history [lreplace $back_history end end]
+ lappend forward_history $current_directory
+
+ # Make backup copy of backward and forward history
+ set tmp_forw_hist $forward_history
+ set tmp_back_hist $back_history
+
+ # Change current directory
+ change_directory $folder
+
+ # Restore backward and forward history
+ set forward_history $tmp_forw_hist
+ set back_history $tmp_back_hist
+
+ # Enable / Disable buttons "Back" and "Forward"
+ if {![llength $back_history]} {
+ $toolbar.back configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Back"] -state disabled
+ } else {
+ $toolbar.back configure -state normal
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ }
+ $win.listbox_menu entryconfigure [mc "Forward"] -state normal
+ $toolbar.forward configure -state normal
+ }
+
+ ## Go forward in history
+ # @return void
+ public method forward {} {
+ # Determinate new folder
+ set folder [lindex $forward_history end]
+ if {$folder == {}} {return}
+
+ # Adjust backward and forward history
+ set forward_history [lreplace $forward_history end end]
+ lappend back_history $current_directory
+
+ # Make backup copy of backward and forward history
+ set tmp_forw_hist $forward_history
+ set tmp_back_hist $back_history
+
+ # Change current directory
+ change_directory $folder
+
+ # Restore backward and forward history
+ set forward_history $tmp_forw_hist
+ set back_history $tmp_back_hist
+
+ # Enable / Disable buttons "Back" and "Forward"
+ if {![llength $forward_history]} {
+ $toolbar.forward configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Forward"] -state disabled
+ } else {
+ $toolbar.forward configure -state normal
+ $win.listbox_menu entryconfigure [mc "Forward"] -state normal
+ }
+ $toolbar.back configure -state normal
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ }
+
+ ## Invoke dialog to create a new directory
+ # @return void
+ public method newdir {} {
+ # Create dialog window
+ set dialog [toplevel $win.new_dir -class {New directory} -bg ${::COMMON_BG_COLOR}]
+
+ # Create dialog header and EntryBox
+ pack [label $dialog.header -justify left -text [mc "Create new folder in:\n%s" $current_directory]] \
+ -side top -anchor w -padx 15 -pady 5
+ pack [ttk::entry $dialog.entry \
+ ] -side top -fill x -expand 1 -padx 5 -pady 5
+
+ # Bind button enter to confirmation action
+ bind $dialog.entry <Return> "[list $this create_new_folder]; break"
+ bind $dialog.entry <KP_Enter> "[list $this create_new_folder]; break"
+
+ # Create bottom frame (Buttons: "Clear", "Ok" and "Cancel")
+ set button_frame [frame $dialog.bottom]
+ pack [ttk::button $button_frame.clear \
+ -text [mc "Clear"] \
+ -compound left \
+ -image ::ICONS::16::clear_left \
+ -command "$dialog.entry delete 0 end" \
+ ] -side left -expand 0 -padx 2
+ pack [ttk::button $button_frame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command [list $this create_new_folder] \
+ ] -side left -expand 0 -padx 2
+ pack [ttk::button $button_frame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side left -expand 0 -padx 2
+ pack $button_frame -side bottom -anchor e -expand 0 -padx 5 -pady 5
+
+ # Configure dialog window
+ wm iconphoto $dialog ::ICONS::16::folder_new
+ wm title $dialog [mc "New folder"]
+ wm resizable $dialog 1 0
+ wm minsize $dialog 340 120
+ wm geometry $dialog 340x120
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ focus -force $dialog.entry
+ tkwait window $dialog
+ }
+
+ ## Confirm dialog "Create new folder"
+ # @return void
+ public method create_new_folder {} {
+ set dialog ${win}.new_dir
+ set folder [$dialog.entry get]
+ set error 0
+
+ if {$folder == {}} {
+ set error 1
+ }
+ if {$error || [catch {file mkdir [file join $current_directory $folder]}]} {
+ tk_messageBox \
+ -parent $dialog \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to create folder"] \
+ -message [mc "Unable to create the specified folder"]
+ } else {
+ grab release $dialog
+ destroy $dialog
+ reload
+ }
+ }
+
+ ## Sort the given list of strings
+ # This procedure is closely related to inner logic of this
+ #+ class and it is difficult to properly explain its function
+ # @parm List items - List to sort
+ # @return void
+ proc sort_items {items} {
+ # Determinate sorting order
+ if {${::KIFSD::FSD::config(reverse_sorting)}} {
+ set order "-decreasing"
+ } else {
+ set order "-increasing"
+ }
+
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ if {${::KIFSD::FSD::config(case_insensitive)}} {
+ set method "-dictionary"
+ } else {
+ set method "-ascii"
+ }
+ return [lsort $method $order $items]
+ } else {
+ if {${::KIFSD::FSD::config(sorting)} == {size}} {
+ # Sort by size
+ set index 2
+ } else {
+ # Sort by date
+ set index 1
+ }
+ set items [lsort -index $index $order $items]
+
+ set result {}
+ foreach file $items {
+ lappend result [lindex $file 0]
+ }
+ return $result
+ }
+ }
+
+ ## Get unsorted list of subdirectories in the given directory
+ # @parm String dir - Directory
+ # @return List - List of relative URLs
+ proc get_dirs_simple {dir} {
+ # Search for directories
+ set result [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [glob -nocomplain -tails -directory $dir -types d *]
+ }
+
+ # Include hidden directories
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [concat $result [glob -nocomplain -tails -directory $dir -types {d hidden} *]]
+ }
+
+ # Filter "." and ".."
+ set foo_idx [lsearch $result {..}]
+ if {$foo_idx != -1} {
+ set result [lreplace $result $foo_idx $foo_idx]
+ set foo_idx [lsearch $result {.}]
+ if {$foo_idx != -1} {
+ set result [lreplace $result $foo_idx $foo_idx]
+ }
+ }
+ }
+
+ return $result
+ }
+
+ ## Get unsorted list of subdirectories in the given directory
+ # @parm String dir - Directory
+ # @return List - {{relative_URL mtime size_in_B} ... }
+ proc get_dirs_extended {dir} {
+ set result {}
+
+ # Search for directories
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types d *] {
+ lappend result [list $file [file mtime [file join $dir $file]] 0]
+ }
+ }
+
+ # Include hidden directories
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types {d hidden} *] {
+ # Filter "." and ".."
+ if {$file == {.} || $file == {..}} {
+ continue
+ }
+ # Translate to full URL
+ lappend result [list $file [file mtime [file join $dir $file]] 0]
+ }
+ }
+ }
+
+ return $result
+ }
+
+ ## Get unsorted list of files in the given directory matching the given GLOB
+ # @parm String dir - Directory
+ # @parm GLOB mask - Glob expression
+ # @return List - List of relative URLs
+ proc get_files_simple {dir mask} {
+ set result [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [glob -nocomplain -tails -directory $dir -types f $mask]
+ }
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [concat $result \
+ [glob -nocomplain -tails -directory $dir -types {f hidden} $mask]]
+ }
+ }
+ return $result
+ }
+
+ ## Get unsorted list of files in the given directory matching the given GLOB
+ # @parm String dir - Directory
+ # @parm GLOB mask - Glob expression
+ # @return List - {{relative_URL mtime size_in_B} ... }
+ proc get_files_extended {dir mask} {
+ set result {}
+
+ # Search for files matching the given GLOB
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types f $mask] {
+ if {[catch {
+ lappend result [list \
+ $file \
+ [file mtime [file join $dir $file]] \
+ [file size [file join $dir $file]] \
+ ]
+ }]} then {
+ lappend result [list $file 0 0]
+ }
+ }
+ }
+
+ # Include hidden files
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types {f hidden} $mask] {
+ if {[catch {
+ lappend result [list \
+ $file \
+ [file mtime [file join $dir $file]] \
+ [file size [file join $dir $file]] \
+ ]
+ }]} then {
+ lappend result [list $file 0 0]
+ }
+ }
+ }
+ }
+ return $result
+ }
+
+ ## Get list of items to load to directories ListBox
+ # @parm String dir - Source directory
+ # @parm Bool no_detail=0 - No details
+ # @return List - {text text ...}
+ proc dir_cmd {dir {no_detail 0}} {
+ # Normalize directory and determinate its parent
+ set dir [file normalize $dir]
+ if {$dir != {/}} {
+ set parent {..}
+ } else {
+ set parent {}
+ }
+
+
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [sort_items [get_dirs_simple $dir]]
+ } else {
+ set result [sort_items [get_dirs_extended $dir]]
+ }
+
+ if {!$no_detail && ${::KIFSD::FSD::config(detailed_view)}} {
+ return [concat $parent [add_details $result $dir]]
+ } else {
+ return [concat $parent $result]
+ }
+ }
+
+ ## Get list of items to load to files ListBox
+ # @parm String dir - Source directory
+ # @parm GLOB mask - GLOB expression which must match each returned file
+ # @parm Bool no_detail=0 - Detailed view
+ # @return List - {text text ...}
+ proc file_cmd {dir mask {no_detail 0}} {
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [sort_items [get_files_simple $dir $mask]]
+ } else {
+ set result [sort_items [get_files_extended $dir $mask]]
+ }
+ if {!$no_detail && ${::KIFSD::FSD::config(detailed_view)}} {
+ return [add_details $result $dir]
+ } else {
+ return $result
+ }
+ }
+
+ ## Adjust list of files/directories returned by proc. file_cmd to
+ #+ format required to display in detailed view mode
+ # @parm List filelist - List returned by procedure file_cmd
+ # @parm String dir - Directory
+ # @return List - {{text text text ... } ... }
+ proc add_details {filelist dir} {
+ set result {}
+ foreach filename $filelist {
+ set line $filename
+ set fullfilename [file join $dir $filename]
+ if {[string length $line] > 31} {
+ set line [string range $line 0 27]
+ append line {...}
+ }
+ if {[catch {
+ append line [string repeat { } [expr {35 - [string length $line]}]]
+ set size [file size $fullfilename]
+ if {$size < 1024} {
+ append size { B}
+ } elseif {$size < 1048576} {
+ set size [expr {($size * 10) / 1024}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } else {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { kB}
+ } elseif {$size < 1073741824} {
+ set size [expr {($size * 10) / 1048576}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } else {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { MB}
+ } elseif {$size < 1099511627776} {
+ set size [expr {($size * 10) / 1073741824}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } else {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { GB}
+ } else {
+ set size {>1TB}
+ }
+ }]} then {
+ append line { - ---- -------- -----}
+ } else {
+ if {!$::MICROSOFT_WINDOWS} {
+ append line [string repeat { } [expr {8 - [string length $size]}]] $size " " \
+ [string range [lindex [file attributes $fullfilename] 5] {end-3} end] " " \
+ [clock format [file mtime $fullfilename] -format {%D %R}]
+ } else {
+ append line [string repeat { } [expr {8 - [string length $size]}]] $size " " \
+ [clock format [file mtime $fullfilename] -format {%D %R}]
+ }
+ }
+ lappend result [list $line $filename]
+ }
+ return $result
+ }
+
+ ## Get list of items to load to files ListBox (mode "Separate folders" OFF)
+ # @parm String dir - Source directory
+ # @parm GLOB mask - GLOB expression which must match each returned file
+ # @return List - {text text ...}
+ proc dir_file_cmd {dir mask} {
+ set dir [file normalize $dir]
+ set result {}
+
+ # Determinate list of directories
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [concat [get_dirs_simple $dir] [get_files_simple $dir $mask]]
+ } else {
+ set result [concat [get_dirs_extended $dir] [get_files_extended $dir $mask]]
+ }
+ if {$dir != {/}} {
+ set parent [list [list {..} {u}]]
+ } else {
+ set parent {}
+ }
+ set tmp_result {}
+
+ # Determinate list of files
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ foreach item [sort_items $result] {
+ if {![file exists [file join $dir $item]]} {continue}
+ if {[file isdirectory [file join $dir $item]]} {
+ lappend tmp_result [concat [add_details [list $item] $dir] d]
+ } else {
+ lappend tmp_result [concat [add_details [list $item] $dir] f]
+ }
+ }
+ } else {
+ foreach item [sort_items $result] {
+ if {![file exists [file join $dir $item]]} {continue}
+ if {[file isdirectory [file join $dir $item]]} {
+ lappend tmp_result [list $item d]
+ } else {
+ lappend tmp_result [list $item f]
+ }
+ }
+ }
+ return [concat $parent $tmp_result]
+ }
+
+ ## Get configuration list for procedure load_config_array
+ # @return List - (List which specifies bookmarks, settings and such things)
+ proc get_config_array {} {
+ return [regsub -all "\n" [array get ::KIFSD::FSD::config] { }]
+ }
+
+ ## Load configuration list returned by procedure get_config_array
+ # @parm List config - (List which specifies bookmarks, settings and such things)
+ # @return void
+ proc load_config_array {config} {
+ if {$config == {}} {
+ return
+ }
+
+ if {[catch {
+ array set ::KIFSD::FSD::config $config
+ }]} then {
+ puts stderr "KI File Selection Dialog: Unable to load the given configuration string -- using default"
+ return 0
+ } else {
+ return 1
+ }
+ }
+
+ ## Get descriptor of dialog window
+ # @return Widget - Dialog window
+ public method get_window_name {} {
+ return $win
+ }
+
+ ## Determinate path to the "Desktop" folder.
+ # @return String - The path, e.g. "~/Arbeitsfläche" in case of German Ubuntu.
+ proc get_desktop_dir {} {
+ if {![catch {
+ set f [open "~/.config/user-dirs.dirs" "r"]
+ }]} then {
+ while {![eof $f]} {
+ set l [gets $f]
+ if {[string first "XDG_DESKTOP_DIR=" $l] != -1} {
+ if {[regexp {"[^\"]+"} $l d]} {
+ set d [string range $d 1 end-1]
+ regsub {\$HOME} $d {~} d
+ return $d
+ }
+ }
+ }
+ close $f
+ }
+ return "~/Desktop"
+ }
+}
+
+## Text variables for dialog "Edit entry in Quick access bar"
+set KIFSD::FSD::qa_panel_dialog_url_entry {} ;# Entry URL
+set KIFSD::FSD::qa_panel_dialog_name_entry {} ;# Entry name
+set KIFSD::FSD::qa_panel_dialog_icon {} ;# Icon number [0;3]
+
+## Dialog configuration array (these values are daults)
+ # Invalid configuration list may cause program error !
+array set KIFSD::FSD::config {
+ win_geometry {720x380}
+ detailed_view 0
+ separate_folders 1
+ quick_access_panel 1
+ sorting name
+ reverse_sorting 0
+ folders_first 1
+ case_insensitive 1
+ show_hidden_files 0
+ right_PW_size 200
+ main_PW_size 180
+ bookmarks {}
+}
+
+if {$::MICROSOFT_WINDOWS} {
+ set KIFSD::FSD::config(quick_access_bar_data) [subst {
+ {0 {System Drive ${::env(SystemDrive)}} {${::env(SystemDrive)}}}
+ {1 {Documents and Settings} {${::env(USERPROFILE)}}}
+ }]
+} else {
+ set KIFSD::FSD::config(quick_access_bar_data) [subst {
+ {0 {/} {/}}
+ {0 {Removable media} {/media}}
+ {1 {Home} {~}}
+ {2 {Desktop} {[KIFSD::FSD::get_desktop_dir]}}
+ }]
+}
+
+# >>> File inclusion guard
+}
+# <<< File inclusion guard
diff --git a/lib/dialogues/my_tk_messageBox.tcl b/lib/dialogues/my_tk_messageBox.tcl
new file mode 100644
index 0000000..0698e9e
--- /dev/null
+++ b/lib/dialogues/my_tk_messageBox.tcl
@@ -0,0 +1,303 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2009, 2010, 2011, 2012 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. #
+############################################################################
+
+# >>> File inclusion guard
+if { ! [ info exists _MY_TK_MESSAGEBOX_TCL ] } {
+set _MY_TK_MESSAGEBOX_TCL _
+# <<< File inclusion guard
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Replacement for Tk's tk_messageBox. Usage is the same as tk_messageBox,
+# except for one thing, this one supports also "-icon ok".
+# --------------------------------------------------------------------------
+
+## This namespace implements dialog itself, but does not contain the
+ # "tk_messageBox" function to invoke it. This function is defined onwards, but
+ # still in this file.
+namespace eval my_tk_messageBox {
+ ## Namespace variables
+ variable return_value {} ;# String: Dialog return value (e.g. "abort")
+ variable dialog ;# Widget: Dialog toplevel window
+ variable count 0 ;# Int: Counter of object instances
+ # Buttons available in the dialog
+ variable available_buttons {
+ abort retry ignore
+ ok cancel yes
+ no
+ }
+ # Icons for available buttons
+ variable button_icons {
+ button_cancel reload forward
+ ok cancel ok
+ no
+ }
+
+ ## Invoke the dialog
+ # @parm Int arg_default - Number of default button (0..2)
+ # @parm String arg_icon - Dialog icon (one of values mentioned in variable button_icons)
+ # @parm String arg_message - Message to display to the user
+ # @parm Widget arg_parent - GUI parent
+ # @parm String arg_title - Dialog title
+ # @parm String arg_type - Name of big icon displyed beside the message (one of {error info question warning ok})
+ # @return String - Dialog return value, name of pressed button
+ proc create {arg_default arg_icon arg_message arg_parent arg_title arg_type} {
+ variable return_value {} ;# String: Dialog return value (e.g. "abort")
+ variable button_icons ;# Icons for available buttons
+ variable available_buttons ;# Buttons available in the dialog
+ variable dialog ;# Widget: Dialog toplevel window
+ variable count ;# Int: Counter of object instances
+
+ set dialog [toplevel .my_tk_messageBox_${count}]
+ set buttons [list]
+ incr count
+
+ # Translate icon name
+ switch -- $arg_icon {
+ {error} {
+ set iconphoto {cancel}
+ set arg_icon {messagebox_critical}
+ }
+ {info} {
+ set iconphoto {info}
+ set arg_icon {messagebox_info}
+ }
+ {question} {
+ set iconphoto {help}
+ set arg_icon {help}
+ }
+ {warning} {
+ set iconphoto {status_unknown}
+ set arg_icon {messagebox_warning}
+ }
+ {ok} {
+ set iconphoto {ok}
+ set arg_icon {button_ok}
+ }
+ }
+
+ # Determinate list of buttons
+ switch -- $arg_type {
+ {abortretryignore} {
+ set buttons [list abort retry ignore]
+ }
+ {ok} {
+ set buttons [list ok]
+ }
+ {okcancel} {
+ set buttons [list ok cancel]
+ }
+ {retrycancel} {
+ set buttons [list retry cancel]
+ }
+ {yesno} {
+ set buttons [list yes no]
+ }
+ {yesnocancel} {
+ set buttons [list yes no cancel]
+ }
+ }
+
+ # Adjuts argument "default"
+ if {$arg_default == {}} {
+ set arg_default [lindex $buttons 0]
+ } elseif {[lsearch -ascii -exact $buttons $arg_default] == -1} {
+ error "my_tk_messageBox: Invalid value of agument -default, must be one of: $buttons"
+ }
+
+ # Create top frame (dialog icon and text of the message)
+ set top_frame [frame $dialog.top]
+ pack [label $top_frame.img -image ::ICONS::32::$arg_icon] -side left -padx 5
+ pack [label $top_frame.txt -text $arg_message -wraplength 300 -justify left] -side left -fill both -padx 5
+
+ # Create bottom bar with dialog buttons
+ set bottom_frame [frame $dialog.bottom]
+ foreach button $buttons {
+ set button_icon [lindex $button_icons [ \
+ lsearch $available_buttons $button \
+ ]]
+
+ set text [string toupper [string index $button 0]]
+ append text [string range $button 1 end]
+
+ pack [ttk::button $bottom_frame.button_${button} \
+ -text [mc $text] -compound left \
+ -image ::ICONS::16::$button_icon \
+ -command "::my_tk_messageBox::button_press $button" \
+ ] -side left -padx 2
+ bind $bottom_frame.button_${button} <Return> "::my_tk_messageBox::button_press $button"
+ bind $bottom_frame.button_${button} <KP_Enter> "::my_tk_messageBox::button_press $button"
+ bind $bottom_frame.button_${button} <Escape> "
+ grab release $dialog
+ destroy $dialog
+ set ::my_tk_messageBox::return_value {}
+ "
+ }
+
+ # Pack window frames
+ pack $top_frame -expand 1 -pady 10 -padx 5
+ pack $bottom_frame -padx 5 -pady 10
+
+ # Window manager options -- modal window
+ wm iconphoto $dialog ::ICONS::16::$iconphoto
+ wm title $dialog $arg_title
+ wm state $dialog normal
+ focus -force $bottom_frame.button_${arg_default}
+ if {$arg_parent != {}} {
+ wm transient $dialog $arg_parent
+ }
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ set ::my_tk_messageBox::return_value {}
+ "
+ update
+ catch {
+ grab $dialog
+ }
+
+ # Wait for user response
+ tkwait window $dialog
+
+ # Destroy dialog and return name of pressed button
+ catch {
+ grab release $dialog
+ destroy $dialog
+ }
+ return $return_value
+ }
+
+ ## Handles button press
+ # @parm String value - Name of pressed button
+ # @return void
+ proc button_press {value} {
+ variable return_value ;# String: Dialog return value (e.g. "abort")g
+ variable dialog ;# Widget: Dialog toplevel window
+
+ grab release $dialog
+ destroy $dialog
+ set return_value $value
+ }
+
+ ## Load needed images from the specified directory
+ # @parm String directory - Source directory
+ # @return void
+ proc load_images {directory} {
+ foreach subdir {16x16 32x32} ns {16 32} icons {
+ {cancel info help status_unknown ok button_cancel reload forward no}
+ {messagebox_critical messagebox_info help messagebox_warning button_ok}
+ } \
+ {
+ foreach icon $icons {
+ set filename [file join $directory {../icons} $subdir "${icon}.png"]
+
+ if {[catch {
+ image create photo ::ICONS::${ns}::${icon} -format png -file $filename
+ } result]} then {
+ puts stderr {}
+ puts -nonewline stderr $result
+ image create photo ::ICONS::${ns}::${icon}
+ }
+ }
+ }
+ }
+}
+
+## Replacement for Tk's command "tk_messageBox"
+ # Usage is the same as "tk_messageBox" ...
+proc my_tk_messageBox args {
+ set length [llength $args]
+ if {$length % 2} {
+ error "my_tk_messageBox: Odd number of arguments given"
+ }
+
+ set arg_default {}
+ set arg_icon {info}
+ set arg_message {}
+ set arg_parent {}
+ set arg_title {}
+ set arg_type {}
+
+ for {set i 0; set j 1} {$i < $length} {incr i 2; incr j 2} {
+ set attr [lindex $args $i]
+ set val [lindex $args $j]
+
+ switch -- $attr {
+ {-default} {
+ set arg_default $val
+ }
+ {-icon} {
+ if {[lsearch -ascii -exact {error info question warning ok} $val] == -1} {
+ error "my_tk_messageBox: Invalid message box icon: $val"
+ }
+ set arg_icon $val
+ }
+ {-message} {
+ set arg_message $val
+ }
+ {-parent} {
+ if {![winfo exists $val]} {
+ error "my_tk_messageBox: Window $val does not exist."
+ }
+ set arg_parent $val
+ }
+ {-title} {
+ set arg_title $val
+ }
+ {-type} {
+ if {[lsearch -ascii -exact {abortretryignore ok okcancel retrycancel yesno yesnocancel} $val] == -1} {
+ error "my_tk_messageBox: Invalid message box type: $val"
+ }
+ set arg_type $val
+ }
+ default {
+ error "my_tk_messageBox: Unknown argument: $attr"
+ }
+ }
+ }
+
+ if {![string length $arg_message]} {
+ error "my_tk_messageBox: No message box text specified"
+ }
+ if {![string length $arg_title]} {
+ if {![string length $arg_icon]} {
+ set arg_title {Message}
+ } else {
+ set arg_title [string toupper [string index $arg_icon 0]]
+ append arg_title [string range $arg_icon 1 end]
+ }
+ }
+ if {![string length $arg_type]} {
+ set arg_type {ok}
+ }
+
+ return [my_tk_messageBox::create $arg_default $arg_icon $arg_message $arg_parent $arg_title $arg_type]
+}
+
+# Replace Tk's command "tk_messageBox"
+rename tk_messageBox old_tk_messageBox
+rename my_tk_messageBox tk_messageBox
+
+# >>> File inclusion guard
+}
+# <<< File inclusion guard
diff --git a/lib/dialogues/selectmcu.tcl b/lib/dialogues/selectmcu.tcl
new file mode 100644
index 0000000..584a59f
--- /dev/null
+++ b/lib/dialogues/selectmcu.tcl
@@ -0,0 +1,1566 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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. #
+############################################################################
+
+# >>> File inclusion guard
+if { ! [ info exists _SELECTMCU_TCL ] } {
+set _SELECTMCU_TCL _
+# <<< File inclusion guard
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# This namespace implements "MCU selection" dialog.
+#
+# Usage:
+#
+# Invocation of MCU selection dialog
+# ==================================
+# SelectMCU::activate <parent> <initial_mcu_type xram_cap xcode_cap>
+# -> {mcu_type xdata xcode}
+#
+#
+# Other functions
+# ==================================
+#
+# SelectMCU::get_available_processors
+# -> List of available processors (e.g. {80C51 AT89C52 AT89C4051})
+#
+# SelectMCU::get_processor_details processor_type
+# -> List of MCU definition (see proc. xml_data_parser1)
+# --------------------------------------------------------------------------
+
+namespace eval SelectMCU {
+ # String: Path to MCUs definition file
+ variable definition_file "${::ROOT_DIRNAME}/data/mcus.xml"
+ # List: available MCU vendors
+ variable vendors [list [mc "all"] "Atmel" "Intel"]
+ variable selected_mcu {} ;# List: Dialog return value {mcu_type xdata xcode}
+ variable definition_data {} ;# List: Values gained from $definition_file
+ variable local_definition_data {} ;# List: Basically the same as $definition_data but containing only the shown items
+ variable mcu_names {} ;# List: Available processors (and show in the list)
+ variable maximum_xcode 0x10000 ;# Int: Maximum external program memory (0x10000 - internal)
+ variable vendor [mc "all"] ;# String: Selected vendor
+
+ ## Variables related to GUI
+ variable parent ;# Widget: Dialog parent (another window)
+ variable win ;# Widget: Dialog window
+ variable search_bar ;# Widget: Search bar entry box
+ variable search_bar_clear ;# Widget: Search bar clear button
+ variable listbox_widget ;# Widget: List box containing available MCUs
+ variable value_lbl_uart ;# Widget: Label "UART:" - value
+ variable value_lbl_voltage ;# Widget: Label "Operating voltage:" - value
+ variable value_lbl_interrupts ;# Widget: Label "Interrupts:" - value
+ variable value_lbl_timers ;# Widget: Label "Timers:" - value
+ variable value_lbl_vendor ;# Widget: Label "Vendor" - value
+ variable more_details_text ;# Widget: TextWidget "More details:"
+ variable more_details_scrollbar ;# Widget: Scrollbar for $more_details_text
+ variable details_xdata_aval ;# Widget: Frame containing scale and spinbox for XDATA memory
+ variable details_xdata_note ;# Widget: Frame containing label "NOT available" for XDATA memory
+ variable details_xcode_aval ;# Widget: Frame containing scale and spinbox for XCODE memory
+ variable details_xcode_nota ;# Widget: Frame containing label "NOT available" for XCODE memory
+ variable name_label ;# Widget: Label containing name of selected MCU
+ variable image_label ;# Widget: Label with image for selected MCU
+ variable xdata_scale ;# Widget: Scale for XDATA memory
+ variable xdata_spinbox ;# Widget: SpinBox for XDATA memory
+ variable xcode_scale ;# Widget: Scale for XCODE memory
+ variable xcode_spinbox ;# Widget: SpinBox for XCODE memory
+
+ ## Variables related to XML parser
+ variable current_element ;# String: Current XML element
+ variable expected ;# String: Expected next XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable current_mcu ;# String: Name of MCU currently being parsed
+
+ ## Fonts used in the selection dialog
+ if {$::GUI_AVAILABLE} {
+ # ListBox containing available fonts
+ variable listbox_widget_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size [expr {int(-14 * $::font_size_factor)}] \
+ -weight bold \
+ ]
+ # ListBox header -- label widget above the ListBox
+ variable listbox_header_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size [expr {int(-14 * $::font_size_factor)}] \
+ ]
+ # Label with the MCU name
+ variable name_font [font create \
+ -family {helvetica} \
+ -size [expr {int(-20 * $::font_size_factor)}] \
+ -weight bold \
+ ]
+ # Labels like "Vendor:", "UART:", "Timers:", etc.
+ variable normal_font [font create \
+ -family {helvetica} \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ ]
+ # Labels with values like for "Vendor:", "Timers:", etc.
+ variable bold_font [font create \
+ -family {helvetica} \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ -weight bold \
+ ]
+ }
+
+ ## Invoke MCU selection dialog
+ # @parm Widget Parent - Dialog parent (some window)
+ # @parm String initial - {Initial_MCU Initial_XDATA Initial_XCODE}
+ # @return List - {mcu_type xdata xcode} or {}
+ proc activate {Parent initial} {
+ variable parent ;# Widget: Dialog parent (another window)
+ variable selected_mcu ;# List: Dialog return value {mcu_type xdata xcode}
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable win ;# Widget: Dialog window
+ variable search_bar ;# Widget: Search bar entry box
+
+ # Initialize NS variables
+ set parent $Parent
+ set selected_mcu {}
+ set mcu_definition {}
+
+ # Load MCU definition file
+ if {![load_definition]} {return}
+ set mcu_definition {}
+
+ create_gui ;# Create dialog GUI elements
+ fill_gui ;# Initialize GUI elements
+
+ # Finalize window creation
+ wm iconphoto $win ::ICONS::16::kcmmemory
+ wm title $win [mc "Choose MCU - MCU 8051 IDE"]
+ if {$::font_size_factor > 1.0} {
+ wm minsize $win 870 500
+ } else {
+ wm minsize $win 720 500
+ }
+ wm protocol $win WM_DELETE_WINDOW {
+ ::SelectMCU::cancel
+ }
+ wm transient $win $parent
+ raise $win
+ catch {
+ grab $win
+ }
+
+ # Initialize search bar
+ $search_bar insert end [lindex $initial 0]
+ focus -force $search_bar
+ $search_bar selection range 0 end
+
+ set selected_mcu [lindex $initial 0]
+
+ # Initialize XDATA & XCODE scales
+ if {[lindex $initial 1]} {
+ set ::SelectMCU::xdata_ena 1
+ set ::SelectMCU::xdata_value [lindex $initial 1]
+ } else {
+ set ::SelectMCU::xdata_ena 0
+ set ::SelectMCU::xdata_value 0
+ xdata_disena
+ }
+ if {[lindex $initial 2]} {
+ set ::SelectMCU::xcode_ena 1
+ set ::SelectMCU::xcode_value [lindex $initial 2]
+ } else {
+ set ::SelectMCU::xcode_ena 0
+ set ::SelectMCU::xcode_value 0
+ xcode_disena
+ }
+
+ # Wait until the window is destroyed
+ tkwait window $win
+
+ # Create resulting string
+ if {$selected_mcu == {}} {
+ set result {}
+ } else {
+ if {${::SelectMCU::xdata_ena}} {
+ set xdata ${::SelectMCU::xdata_value}
+ } else {
+ set xdata 0
+ }
+ if {${::SelectMCU::xcode_ena}} {
+ set xcode ${::SelectMCU::xcode_value}
+ } else {
+ set xcode 0
+ }
+
+ if {$xdata == {}} {
+ set xdata 0
+ }
+ if {$xcode == {}} {
+ set xcode 0
+ }
+ set result [list $selected_mcu $xdata $xcode]
+ }
+
+ return $result
+ }
+
+ ## Load MCU definitions into the ListBox
+ # @return void
+ proc fill_gui {} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable local_definition_data ;# List: Basically the same as $definition_data but containing only the shown items
+ variable listbox_widget ;# Widget: List box containing available MCUs
+ variable listbox_widget_font ;# ListBox containing available fonts
+ variable mcu_names ;# List: available processors
+ variable vendor ;# String: Selected vendor
+
+ set mcu_names {}
+ set local_definition_data {}
+
+ # Iterate over defined MCUs
+ foreach mcu $definition_data {
+ # Filter specific vendors
+ if {$vendor != [mc "all"] && [lindex $mcu 11] != $vendor} {
+ continue
+ }
+
+ lappend local_definition_data $mcu
+
+ # MCU type
+ set mcu_type [lindex $mcu 0]
+ lappend mcu_names $mcu_type
+ set text $mcu_type
+ set len [string length $mcu_type]
+ append text [string repeat { } [expr {24 - $len}]]
+
+ # Size of program memory
+ set str [lindex $mcu 3]
+ append str { KB}
+ set len [string length $str]
+ append text [string repeat { } [expr {8 - $len}]] $str
+
+ # Size of internal data memory
+ set str [expr {[lindex $mcu 5] + [lindex $mcu 10]}]
+ append str { B}
+ set len [string length $str]
+ append text [string repeat { } [expr {13 - $len}]] $str
+
+ # Number of IO lines + processor frequency
+ set str [lindex $mcu 6]
+ set len [string length $str]
+ append text [string repeat { } [expr {12 - $len}]] $str { } [lindex $mcu 4]
+
+ # Insert the text into the ListBox
+ $listbox_widget insert end #auto \
+ -text $text -data $mcu_type \
+ -font $listbox_widget_font \
+ -image ::ICONS::16::kcmmemory
+ }
+ }
+
+ ## Create GUI elements of the selection dialog window
+ # @return void
+ proc create_gui {} {
+ variable win ;# Widget: Dialog window
+ variable search_bar ;# Widget: Search bar entry box
+ variable search_bar_clear ;# Widget: Search bar clear button
+ variable listbox_widget ;# Widget: List box containing available MCUs
+ variable value_lbl_uart ;# Widget: Label "UART:" - value
+ variable value_lbl_voltage ;# Widget: Label "Operating voltage:" - value
+ variable value_lbl_interrupts ;# Widget: Label "Interrupts:" - value
+ variable value_lbl_timers ;# Widget: Label "Timers:" - value
+ variable value_lbl_vendor ;# Widget: Label "Vendor" - value
+ variable more_details_text ;# Widget: TextWidget "More details:"
+ variable more_details_scrollbar ;# Widget: Scrollbar for $more_details_text
+ variable details_xdata_aval ;# Widget: Frame containing scale and spinbox for XDATA memory
+ variable details_xdata_note ;# Widget: Frame containing label "NOT available" for XDATA memory
+ variable details_xcode_aval ;# Widget: Frame containing scale and spinbox for XCODE memory
+ variable details_xcode_nota ;# Widget: Frame containing label "NOT available" for XCODE memory
+ variable listbox_widget_font ;# ListBox containing available fonts
+ variable listbox_header_font ;# ListBox header -- label widget above the ListBox
+ variable bold_font ;# Labels with values like for "Vendor:", "Timers:", etc.
+ variable normal_font ;# Labels like "Vendor:", "UART:", "Timers:", etc.
+ variable name_font ;# Label with the MCU name
+ variable name_label ;# Widget: Label containing name of selected MCU
+ variable image_label ;# Widget: Label with image for selected MCU
+ variable xdata_scale ;# Widget: Scale for XDATA memory
+ variable xdata_spinbox ;# Widget: Scale for XDATA memory
+ variable xcode_spinbox ;# Widget: SpinBox for XCODE memory
+ variable xcode_scale ;# Widget: Scale for XCODE memory
+ variable vendors ;# List: available MCU vendors
+
+ # Create toplevel window
+ set win [toplevel .selectmcu_dialog -class {Select MCU} -bg ${::COMMON_BG_COLOR}]
+
+ # Create search bar widgets (but don't pack them)
+ set search_bar_frame [frame $win.search_bar_frame]
+ set search_bar_clear [ttk::button $search_bar_frame.clear_but \
+ -image ::ICONS::16::clear_left \
+ -command ::SelectMCU::clear_search_bar \
+ -state disabled \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $search_bar_frame.clear_but \
+ -text [mc "Clear search bar"]
+ set search_bar [ttk::entry $search_bar_frame.search_bar \
+ -validate all \
+ -validatecommand {::SelectMCU::search %P} \
+ ]
+ DynamicHelp::add $search_bar \
+ -text [mc "Search bar, enter something like \"C4051\""]
+
+ # Create ListBox and its scrollbar
+ set top_frame [frame $win.top_frame]
+ set top_left_frame [frame $top_frame.left -bd 1 -relief sunken]
+ set top_left_top_frame [frame $top_left_frame.top]
+ set listbox_widget [ListBox $top_left_frame.listbox \
+ -selectfill 1 -bg {#FFFFFF} -bd 0 -height 0 \
+ -selectbackground {#CCCCFF} -selectmode single \
+ -selectforeground {#0000AA} \
+ -highlightcolor {#BBBBFF} \
+ -highlightthickness 0 -padx 20 -deltay 20 \
+ -yscrollcommand "$top_frame.scrollbar set" \
+ ]
+ if {[winfo exists $listbox_widget.c]} {
+ bind $listbox_widget.c <Button-5> {%W yview scroll +5 units; break}
+ bind $listbox_widget.c <Button-4> {%W yview scroll -5 units; break}
+ }
+ bind $listbox_widget <<ListboxSelect>> {::SelectMCU::select_item}
+ $listbox_widget bindImage <Double-1> {::SelectMCU::close_window;#}
+ $listbox_widget bindText <Double-1> {::SelectMCU::close_window;#}
+ set tree_scrollbar [ttk::scrollbar $top_frame.scrollbar \
+ -orient vertical \
+ -command [list $listbox_widget yview] \
+ ]
+ # Create ListBox header
+ pack [label $top_left_frame.header \
+ -font $listbox_header_font \
+ -bg {#DDDDDD} -bd 0 -padx 25 \
+ -justify left -anchor w \
+ -text [mc "Processor Type\t\tCODE/PMEM IDATA/IRAM GPIO Frequency"] \
+ ] -fill x
+
+ # Create remaining parts of top frame and pack them
+ pack [label $search_bar_frame.search_label \
+ -text [mc "Search:"] \
+ ] -side left -padx 5
+ pack $search_bar -fill x -expand 1 -side left
+ pack $search_bar_clear -after $search_bar -side left
+ pack [label $search_bar_frame.vendor_label \
+ -text [mc " Vendor:"] \
+ ] -side left -padx 5 -after $search_bar_clear
+ pack [ttk::combobox $search_bar_frame.vendor_cb \
+ -state readonly \
+ -textvariable {::SelectMCU::vendor} \
+ -values $vendors \
+ ] -side left -padx 5 -after $search_bar_frame.vendor_label
+ bind $search_bar_frame.vendor_cb <<ComboboxSelected>> {::SelectMCU::change_vendor}
+ pack $search_bar_frame -fill x -pady 10 -padx 5
+
+ # Pack all frames except the bottom frame and the details frame
+ pack $top_left_top_frame -fill x
+ pack $listbox_widget -fill both -expand 1
+ pack $top_left_frame -fill both -expand 1 -side left
+ pack $tree_scrollbar -fill y -after $top_left_frame -side right
+ pack $top_frame -fill both -expand 1 -padx 5
+
+ # Create parts of details frame
+ set details_frame [frame $win.details_frame]
+ set details_left [frame $details_frame.left]
+ set details_middle [frame $details_frame.middle -width 300]
+ set details_right [frame $details_frame.right]
+ set details_middle_top [frame $details_middle.top]
+ set details_middle_bottom [frame $details_middle.bottom]
+
+ # Left side
+ set name_label [label $details_left.name \
+ -text "" -font $name_font \
+ ]
+ set image_label [label $details_left.image \
+ -image [image create photo] -text { } \
+ -width 200 -height 200 -compound left \
+ ]
+ DynamicHelp::add $image_label -text [mc "One of available packages for selected microcontroller"]
+ pack $name_label -fill x
+ pack $image_label -padx 5
+
+ # General features
+ set i 0
+ foreach text {{Vendor:} {UART:} {Operating voltage:} {Interrupt sources:} {Timers:}} {
+ grid [label $details_middle_top.lbl_$i \
+ -text [mc $text] \
+ -justify left \
+ -font $normal_font \
+ ] -row $i -column 0 -sticky w
+ incr i
+ }
+ set value_lbl_vendor [label $details_middle_top.value_lbl_vendor \
+ -justify left -anchor w -font $bold_font \
+ ]
+ set value_lbl_uart [label $details_middle_top.value_lbl_uart \
+ -justify left -anchor w -font $bold_font \
+ ]
+ set value_lbl_voltage [label $details_middle_top.value_lbl_voltage \
+ -justify left -anchor w -font $bold_font \
+ ]
+ set value_lbl_interrupts [label $details_middle_top.value_lbl_interr \
+ -justify left -anchor w -font $bold_font \
+ ]
+ set value_lbl_timers [label $details_middle_top.value_lbl_timers \
+ -justify left -anchor w -font $bold_font \
+ ]
+ grid $value_lbl_vendor -row 0 -column 1 -sticky we
+ grid $value_lbl_uart -row 1 -column 1 -sticky we
+ grid $value_lbl_voltage -row 2 -column 1 -sticky we
+ grid $value_lbl_interrupts -row 3 -column 1 -sticky we
+ grid $value_lbl_timers -row 4 -column 1 -sticky we
+ grid columnconfigure $details_middle_top 0 -minsize 140
+ grid columnconfigure $details_middle_top 1 -weight 1
+
+ # Details
+ set more_details_text [text $details_middle_bottom.text \
+ -yscrollcommand ::SelectMCU::details_scrollbar_set \
+ -width 0 -heigh 0 -bd 0 -relief flat -font $bold_font \
+ -highlightthickness 0 -state disabled -bg ${::COMMON_BG_COLOR} \
+ -cursor left_ptr -fg {#555555} -wrap word \
+ ]
+ set more_details_scrollbar [ttk::scrollbar \
+ $details_middle_bottom.scrollbar \
+ -command "$more_details_text yview" \
+ -orient vertical \
+ ]
+ pack $more_details_text -side left -fill both -expand 1
+
+ # Pack general & details frames
+ pack $details_middle_top -fill both -pady 10
+ pack $details_middle_bottom -fill both -expand 1
+
+ # Cretate XDATA and XCODE scales and such
+ set details_right_top [ttk::labelframe $details_right.top \
+ -text [mc "External RAM (XDATA)"] \
+ ]
+ set details_right_bottom [ttk::labelframe $details_right.bottom \
+ -text [mc "External ROM/FLASH (XCODE)"] \
+ ]
+
+ set details_xdata_note [label $details_right_top.not_available \
+ -text [mc "NOT available"] -fg {#FF8888} \
+ ]
+ set details_xdata_aval [frame $details_right_top.available]
+ pack [checkbutton $details_xdata_aval.checkbutton \
+ -variable ::SelectMCU::xdata_ena \
+ -text [mc "Enable"] \
+ -command ::SelectMCU::xdata_disena \
+ ] -anchor w
+ DynamicHelp::add $details_xdata_aval.checkbutton \
+ -text [mc "Connect external data memory"]
+ set details_right_top_btm [frame $details_xdata_aval.btm]
+ set xdata_scale [ttk::scale $details_right_top_btm.scale \
+ -orient horizontal \
+ -variable ::SelectMCU::xdata_value \
+ -from 0 -to 0x10000 \
+ -command "
+ set ::SelectMCU::xdata_value \[expr {int(\${::SelectMCU::xdata_value})}\]
+ $details_right_top_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $details_right_top_btm.scale \
+ -text [mc "Amount of external data memory"]
+ pack $xdata_scale -fill x -side left -expand 1 -padx 2
+ set xdata_spinbox [ttk::spinbox $details_right_top_btm.spinbox \
+ -textvariable ::SelectMCU::xdata_value \
+ -width 5 -from 0 -to 0x10000 \
+ -validate all \
+ -validatecommand {::SelectMCU::validate_xdata %P} \
+ ]
+ DynamicHelp::add $details_right_top_btm.spinbox \
+ -text [mc "Amount of external data memory"]
+ pack $xdata_spinbox -side right -after $details_right_top_btm.scale
+ pack $details_right_top_btm -fill both -expand 1
+
+ set details_xcode_nota [label $details_right_bottom.not_available \
+ -text [mc "NOT available"] -fg {#FF8888} \
+ ]
+ set details_xcode_aval [frame $details_right_bottom.available]
+ pack [checkbutton $details_xcode_aval.checkbutton \
+ -variable ::SelectMCU::xcode_ena \
+ -text [mc "Enable"] \
+ -command ::SelectMCU::xcode_disena \
+ ] -anchor w
+ DynamicHelp::add $details_xcode_aval.checkbutton \
+ -text [mc "Connect external program memory"]
+ set details_right_bottom_btm [frame $details_xcode_aval.btm]
+ set xcode_scale [ttk::scale $details_right_bottom_btm.scale \
+ -orient horizontal \
+ -variable ::SelectMCU::xcode_value \
+ -from 0 -to 0x10000 \
+ -command "
+ set ::SelectMCU::xcode_value \[expr {int(\${::SelectMCU::xcode_value})}\]
+ #" \
+ ]
+ DynamicHelp::add $details_right_bottom_btm.scale \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $xcode_scale -fill x -side left -expand 1 -padx 2
+ set xcode_spinbox [ttk::spinbox $details_right_bottom_btm.spinbox \
+ -textvariable ::SelectMCU::xcode_value \
+ -width 5 -from 0 -to 0x10000 \
+ -validate all \
+ -validatecommand {::SelectMCU::validate_xcode %P} \
+ ]
+ DynamicHelp::add $details_right_bottom_btm.spinbox \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $xcode_spinbox -side right -after $details_right_bottom_btm.scale
+ pack $details_right_bottom_btm -fill both -expand 1
+
+ grid $details_right_top -row 0 -column 0 -sticky wens -padx 5 -pady 10
+ grid $details_right_bottom -row 1 -column 0 -sticky wens -padx 5 -pady 10
+ grid rowconfigure $details_right 0 -minsize 100
+ grid rowconfigure $details_right 1 -minsize 100
+ grid columnconfigure $details_right 0 -weight 1 -minsize 180
+
+ # Pack parts of details frame
+ pack $details_left -side left
+ pack $details_middle -side left -fill both -expand 1 -padx 15 -pady 10
+ pack $details_right -side right -fill y -after $details_middle -padx 5
+ pack $details_frame -fill x -padx 5 -pady 10
+
+ # 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 {::SelectMCU::close_window} \
+ ] -side left -padx 2
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::SelectMCU::cancel} \
+ ] -side left -padx 2
+ pack [ttk::separator $win.sep -orient horizontal] -fill x
+ pack $buttonFrame -side bottom -after $details_frame -anchor e -padx 5 -pady 5
+ }
+
+ ## Close MCU selection dialog and force its return value to an empty string
+ # @return void
+ proc close_window {} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable mcu_names ;# List: available processors
+ variable win ;# Widget: Dialog window
+
+ set definition_data {}
+ set mcu_names {}
+ grab release $win
+ destroy $win
+ }
+
+ ## Load MCU database
+ # @return void
+ proc load_definition {} {
+ variable parent ;# Widget: Dialog parent (another window)
+ variable definition_file ;# String: Path to MCUs definition file
+ variable definition_data ;# List: Values gained from $definition_file
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable expected ;# String: Expected next XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+
+ # Initialize NS variables
+ set definition_data {}
+ set mcu_definition {}
+ set expected {mcus}
+ set current_element {}
+ set take_data 0
+
+ # Open definition file
+ if {[catch {
+ set file [open $definition_file {r}]
+ }]} then {
+ tk_messageBox \
+ -parent $parent \
+ -type ok \
+ -icon warning \
+ -title mcus.xml \
+ -message [mc "Unable to open file containing supported MCUs,\nplease check your installation"]
+ return 0
+ }
+
+ # Create XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand {::SelectMCU::xml_data_parser0_element} \
+ -characterdatacommand {::SelectMCU::xml_data_parser0_data} \
+ ]
+
+ # Start XML parser
+ if {[catch {
+ $parser parse [read $file]
+ if {$mcu_definition != {}} {
+ foreach val $mcu_definition {
+ if {$val == {}} {
+ error "Incomplete definition for [lindex $mcu_definition 0]"
+ }
+ }
+ lappend definition_data $mcu_definition
+ }
+ } result]} then {
+ set definition_data {}
+ tk_messageBox \
+ -parent $parent \
+ -icon warning \
+ -type ok \
+ -title [mc "Error"] \
+ -message [mc "MCUs database file is corrupted (code:600),\nplease check your installation"]
+ puts stderr $result
+ close $file
+ return 0
+ }
+
+ # Close file and free parser
+ close $file
+ $parser free
+ return 1
+ }
+
+ ## Get list of MCUs defined in the database
+ # @return List - Defined processors (e.g. {8051 AT89C2051 ...})
+ proc get_available_processors {} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable definition_file ;# String: Path to MCUs definition file
+ variable expected ;# String: Expected next XML element
+
+ # Initialize NS variables
+ set expected {mcus}
+ set definition_data {} ;# <-- Result will be stored here
+
+ # Open database file
+ if {[catch {
+ set file [open $definition_file {r}]
+ }]} then {
+ puts stderr "Unable to open file containing supported MCUs, please check your installation"
+ return {}
+ }
+
+ # Create XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand {::SelectMCU::xml_data_parser2_element} \
+ ]
+
+ # Start XML parser
+ if {[catch {
+ $parser parse [read $file]
+ } result]} then {
+ set definition_data {}
+ puts stderr "MCUs database file is corrupted (code:641),\nplease check your installation"
+ puts stderr $result
+ }
+
+ # Close file and free parser
+ close $file
+ $parser free
+ return $definition_data
+ }
+
+ ## Gain detail description for the given processor
+ # @parm String mcu_name - Processor type (e.g. AT89C51RC)
+ # @return List - (see proc. xml_data_parser1)
+ proc get_processor_details {mcu_name} {
+ variable definition_file ;# String: Path to MCUs definition file
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable current_mcu ;# String: Name of MCU currently being parsed
+
+ # Initialize NS variables
+ set mcu_definition $mcu_name
+ set expected {mcus}
+ set definition_data {} ;# <-- Result will be stored here
+ set take_data 0
+ set current_mcu {}
+
+ # Open database file
+ if {[catch {
+ set file [open $definition_file {r}]
+ }]} then {
+ puts stderr "Unable to open file containing supported MCUs, please check your installation"
+ return {}
+ }
+
+ # Create XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand {::SelectMCU::xml_data_parser1_element} \
+ -characterdatacommand {::SelectMCU::xml_data_parser1_data} \
+ ]
+
+ # Start XML parser
+ if {[catch {
+ $parser parse [read $file]
+ } result]} then {
+ set definition_data {}
+ puts stderr "MCUs database file is corrupted (code:688),\nplease check your installation"
+ puts stderr $result
+ }
+
+ # Close file and free parser
+ close $file
+ $parser free
+ return $definition_data
+ }
+
+ ## XML parser handler for procedure get_available_processors -- Takes XML tags
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc xml_data_parser2_element {arg1 attrs} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+
+ # Check for consistent formatting
+ if {$arg1 != $expected} {
+ error "Bad element `$arg1'"
+ }
+
+ switch -- $arg1 {
+ {mcus} {
+ set expected {mcu}
+ }
+ {mcu} {
+ set expected {timers}
+ set len [llength $attrs]
+
+ # Search for attribute "name"
+ for {set i 0} {$i < $len} {incr i 2} {
+ set val [lindex $attrs $i]
+ if {$val == {name}} {
+ # Append MCU name to result
+ incr i
+ lappend definition_data [lindex $attrs $i]
+ break
+ }
+ }
+ }
+ {timers} {set expected {more}}
+ {more} {set expected {bits}}
+ {bits} {set expected {writeonly}}
+ {writeonly} {set expected {sfr}}
+ {sfr} {set expected {mcu}}
+ }
+ }
+
+
+ ## XML parser handler for procedure get_processor_details -- Takes XML data
+ # @parm String arg1 - content of the element
+ # @return void
+ proc xml_data_parser1_data {arg1} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable current_element ;# String: Current XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+
+ # Take data only if they were expected
+ if {!$take_data} {return}
+ set take_data 0
+
+ # Take data section only for 1 processor
+ if {$mcu_definition == {} || ![llength $definition_data]} {
+ return
+ }
+
+ # Adjust data string
+ set arg1 [string trim $arg1]
+ regsub {\s+} $arg1 { } arg1
+
+ # Validate and store data
+ switch -- $current_element {
+ {bits} { ;# Incomplete registers
+ if {![regexp {([0-9A-Fa-f]{4})?(\s+[0-9A-Fa-f]{4})*} $arg1]} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 18 $arg1
+ }
+ {writeonly} { ;# Write only registers
+ if {![regexp {([0-9A-Fa-f]{2})?(\s+[0-9A-Fa-f]{2})*} $arg1]} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 19 $arg1
+ }
+ {sfr} { ;# available special function registers and bit addressable bits in SFR
+ lset definition_data 43 $arg1
+
+ set mcu_definition {} ;# This is the last tag
+ }
+ }
+ }
+
+ ## XML parser handler for procedure get_processor_details -- Takes XML tags
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc xml_data_parser1_element {arg1 attrs} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable current_mcu ;# String: Name of MCU currently being parsed
+ variable current_element ;# String: Current XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+
+ set take_data 0
+
+ ## Take tag attributes
+ set current_element $arg1
+ if {$arg1 != $expected} {
+ error "Bad element `$arg1'"
+ }
+ switch -- $arg1 {
+ {mcus} {
+ set expected {mcu}
+ }
+ {mcu} {
+ set expected {timers}
+ set len [llength $attrs]
+
+ for {set i 0} {$i < $len} {incr i 2} {
+ set val [lindex $attrs $i]
+ if {$val == {name}} {
+ incr i
+ set current_mcu [lindex $attrs $i]
+ if {$mcu_definition != $current_mcu} {
+ return
+ }
+ }
+ }
+
+ set definition_data [list \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} \
+ ]
+
+ for {set i 0} {$i < $len} {incr i} {
+ switch -- [lindex $attrs $i] {
+ {xdata} {
+ incr i
+ xml_dp1_attr_yes_no 0 [lindex $attrs $i]
+ }
+ {xcode} {
+ incr i
+ xml_dp1_attr_yes_no 1 [lindex $attrs $i]
+ }
+ {code} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 0x10000} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 2 $val
+ }
+ {ram} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 256} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 3 $val
+ }
+ {portbits} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 256} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 4 $val
+ }
+ {uart} {
+ incr i
+ xml_dp1_attr_yes_no 5 [lindex $attrs $i]
+ }
+ {timer2} {
+ incr i
+ xml_dp1_attr_yes_no 6 [lindex $attrs $i]
+ }
+ {watchdog} {
+ incr i
+ xml_dp1_attr_yes_no 7 [lindex $attrs $i]
+ }
+ {eram} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 0x10000} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 8 $val
+ }
+ {dualdtpr} {
+ incr i
+ xml_dp1_attr_yes_no 9 [lindex $attrs $i]
+ }
+ {auxr} {
+ incr i
+ xml_dp1_attr_yes_no 10 [lindex $attrs $i]
+ }
+ {t2mod} {
+ incr i
+ xml_dp1_attr_yes_no 11 [lindex $attrs $i]
+ }
+ {port0} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 12 $val
+ }
+ {port1} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 13 $val
+ }
+ {port2} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 14 $val
+ }
+ {port3} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 15 $val
+ }
+ {port4} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 16 $val
+ }
+ {pof} {
+ incr i
+ xml_dp1_attr_yes_no 17 [lindex $attrs $i]
+ }
+ {gf0} {
+ incr i
+ xml_dp1_attr_yes_no 20 [lindex $attrs $i]
+ }
+ {gf1} {
+ incr i
+ xml_dp1_attr_yes_no 21 [lindex $attrs $i]
+ }
+ {pd} {
+ incr i
+ xml_dp1_attr_yes_no 22 [lindex $attrs $i]
+ }
+ {idl} {
+ incr i
+ xml_dp1_attr_yes_no 23 [lindex $attrs $i]
+ }
+ {smod0} {
+ incr i
+ xml_dp1_attr_yes_no 24 [lindex $attrs $i]
+ }
+ {iph} {
+ incr i
+ xml_dp1_attr_yes_no 25 [lindex $attrs $i]
+ }
+ {acomparator} {
+ incr i
+ xml_dp1_attr_yes_no 26 [lindex $attrs $i]
+ }
+ {euart} {
+ incr i
+ xml_dp1_attr_yes_no 27 [lindex $attrs $i]
+ }
+ {clkreg} {
+ incr i
+ xml_dp1_attr_yes_no 28 [lindex $attrs $i]
+ }
+ {pwdex} {
+ incr i
+ xml_dp1_attr_yes_no 29 [lindex $attrs $i]
+ }
+ {spi} {
+ incr i
+ xml_dp1_attr_yes_no 30 [lindex $attrs $i]
+ }
+ {wdtcon} {
+ incr i
+ xml_dp1_attr_yes_no 31 [lindex $attrs $i]
+ }
+ {eeprom} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val]} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data 32 $val
+ }
+ {intelpe} {
+ incr i
+ xml_dp1_attr_yes_no 33 [lindex $attrs $i]
+ }
+ {pwm} {
+ incr i
+ xml_dp1_attr_yes_no 34 [lindex $attrs $i]
+ }
+ {x2reset} {
+ incr i
+ xml_dp1_attr_yes_no 35 [lindex $attrs $i]
+ }
+ {ckcon} {
+ incr i
+ xml_dp1_attr_yes_no 36 [lindex $attrs $i]
+ }
+ {auxr1gf3} {
+ incr i
+ xml_dp1_attr_yes_no 37 [lindex $attrs $i]
+ }
+ {ao} {
+ incr i
+ xml_dp1_attr_yes_no 38 [lindex $attrs $i]
+ }
+ {wdtprg} {
+ incr i
+ xml_dp1_attr_yes_no 39 [lindex $attrs $i]
+ }
+ {hddptr} {
+ incr i
+ xml_dp1_attr_yes_no 40 [lindex $attrs $i]
+ }
+ {auxrwdidle} {
+ incr i
+ xml_dp1_attr_yes_no 41 [lindex $attrs $i]
+ }
+ {auxrdisrto} {
+ incr i
+ xml_dp1_attr_yes_no 42 [lindex $attrs $i]
+ }
+ default {
+ incr i
+ }
+ }
+ }
+ }
+ {timers} {
+ set expected {more}
+ }
+ {more} {
+ set expected {bits}
+ }
+ {bits} {
+ if {$mcu_definition == $current_mcu} {
+ set take_data 1
+ }
+ set expected {writeonly}
+ }
+ {writeonly} {
+ if {$mcu_definition == $current_mcu} {
+ set take_data 1
+ }
+ set expected {sfr}
+ }
+ {sfr} {
+ if {$mcu_definition == $current_mcu} {
+ set take_data 1
+ }
+ set expected {mcu}
+ }
+ }
+ }
+
+ ## Auxiliary procedure for xml_data_parser1
+ # Invoke error if the given value was neither "yes" nor "no"
+ # @parm Int index - Index in list $definition_data
+ # @parm String value - Value to set in $definition_data
+ # @return void
+ proc xml_dp1_attr_yes_no {index value} {
+ variable definition_data ;# List: Values gained from $definition_file
+
+ if {$value != {yes} && $value != {no}} {
+ error "MCUs database file corrupted"
+ }
+ lset definition_data $index $value
+ }
+
+ ## XML parser handler for procedure load_definition -- takes XML tags
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc xml_data_parser0_element {arg1 attrs} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable current_element ;# String: Current XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable vendors ;# List: available MCU vendors
+
+ if {$arg1 != $expected} {
+ error "Bad element `$arg1'"
+ }
+ set current_element $arg1
+ switch -- $arg1 {
+ {mcus} {
+ set expected {mcu}
+ }
+ {mcu} {
+ if {$mcu_definition != {}} {
+ foreach val $mcu_definition {
+ if {$val == {}} {
+ error "Incomplete definition for [lindex $mcu_definition 0]"
+ }
+ }
+ lappend definition_data $mcu_definition
+ }
+ set expected {timers}
+ set mcu_definition [list {} {} {} {} {} {} {} {} {} {} {} {}]
+ for {set i 0} {$i < [llength $attrs]} {incr i} {
+ switch -- [lindex $attrs $i] {
+ {name} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is alnum -strict $val]} {
+ error "MCU name must match ^\[\w\d\]+$"
+ }
+ lset mcu_definition 0 $val
+ }
+ {xdata} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {yes} && $val != {no}} {
+ error "Attribute XDATA must have value \"yes\" or \"no\""
+ }
+ lset mcu_definition 1 $val
+ }
+ {xcode} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {yes} && $val != {no}} {
+ error "Attribute XCODE must have value \"yes\" or \"no\""
+ }
+ lset mcu_definition 2 $val
+ }
+ {code} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 65536} {
+ error "CODE memory capacity must be an integer value \[0;65536\]"
+ }
+ lset mcu_definition 3 $val
+ }
+ {frequency} {
+ incr i
+ set val [lindex $attrs $i]
+ if {[string length $val] > 16 || ![string is print $val]} {
+ error "Attribute FREQUENCY must be printable string (max. 16 characters)"
+ }
+ lset mcu_definition 4 $val
+ }
+ {ram} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 256} {
+ error "RAM capacity must be an integer value \[0;256\]"
+ }
+ lset mcu_definition 5 $val
+ }
+ {portbits} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 256} {
+ error "Attribute PORTBITS must be an integer value \[0;256\]"
+ }
+ lset mcu_definition 6 $val
+ }
+ {uart} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {yes} && $val != {no}} {
+ error "Attribute UART must be either \"yes\" or \"no\""
+ }
+ lset mcu_definition 7 $val
+ }
+ {interrupts} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 99} {
+ error "Attribute INTERRUPTS must be an integer value \[0;99\]"
+ }
+ lset mcu_definition 8 $val
+ }
+ {voltage} {
+ incr i
+ set val [lindex $attrs $i]
+ if {[string length $val] > 11 || ![string is print $val]} {
+ error "Attribute VOLTAGE must be printable string (max. 11 characters)"
+ }
+ lset mcu_definition 9 $val
+ }
+ {eram} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 65536} {
+ error "ERAM capacity must be an integer value \[0;65536\]"
+ }
+ lset mcu_definition 10 $val
+ }
+ {vendor} {
+ incr i
+ set val [lindex $attrs $i]
+ if {[lsearch $vendors $val] == -1} {
+ error "Undefined vendor \"$val\""
+ }
+ lset mcu_definition 11 $val
+ }
+ default {
+ incr i
+ }
+ }
+ }
+ }
+ {timers} {
+ set expected {more}
+ set take_data 1
+ }
+ {more} {
+ set expected {bits}
+ set take_data 1
+ }
+ {bits} {
+ set expected {writeonly}
+ set take_data 0
+ }
+ {writeonly} {
+ set expected {sfr}
+ set take_data 0
+ }
+ {sfr} {
+ set expected {mcu}
+ set take_data 0
+ }
+ }
+ }
+
+ ## XML parser handler for procedure load_definition -- takes data section
+ # @parm String arg1 - content of the element
+ # @return void
+ proc xml_data_parser0_data {arg1} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable current_element ;# String: Current XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable vendors ;# List: available MCU vendors
+
+ if {!$take_data} {
+ return
+ }
+
+ set take_data 0
+
+ regsub -all {^\s+} $arg1 {} arg1
+ regsub -all {\s+$} $arg1 {} arg1
+ regsub -all -line {^\t+} $arg1 {} arg1
+
+ switch -- $current_element {
+ {timers} {
+ lappend mcu_definition $arg1
+ }
+ {more} {
+ lappend mcu_definition $arg1
+ }
+ }
+ }
+
+ ## Event handler for ListBox with list of processors
+ # Handles <<ListboxSelect>> -- Change contents of details frame
+ # @parm String - "noclear" == do not clear search EntryBox
+ # @return void
+ proc select_item args {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable local_definition_data ;# List: Basically the same as $definition_data but containing only the shown items
+ variable selected_mcu ;# List: Dialog return value {mcu_type xdata xcode}
+ variable listbox_widget ;# Widget: List box containing available MCUs
+ variable value_lbl_uart ;# Widget: Label "UART:" - value
+ variable value_lbl_voltage ;# Widget: Label "Operating voltage:" - value
+ variable value_lbl_interrupts ;# Widget: Label "Interrupts:" - value
+ variable value_lbl_timers ;# Widget: Label "Timers:" - value
+ variable value_lbl_vendor ;# Widget: Label "Vendor" - value
+ variable more_details_text ;# Widget: TextWidget "More details:"
+ variable details_xdata_aval ;# Widget: Frame containing scale and spinbox for XDATA memory
+ variable details_xdata_note ;# Widget: Frame containing label "NOT available" for XDATA memory
+ variable details_xcode_aval ;# Widget: Frame containing scale and spinbox for XCODE memory
+ variable details_xcode_nota ;# Widget: Frame containing label "NOT available" for XCODE memory
+ variable name_label ;# Widget: Label containing name of selected MCU
+ variable image_label ;# Widget: Label with image for selected MCU
+ variable xcode_spinbox ;# Widget: SpinBox for XCODE memory
+ variable xcode_scale ;# Widget: Scale for XCODE memory
+ variable maximum_xcode ;# Int: Maximum external program memory (0x10000 - internal)
+
+ # Get MCU definition for the selected processor
+ set mcu [lindex $local_definition_data \
+ [$listbox_widget index [$listbox_widget selection get]] \
+ ]
+ set mcu_name [lindex $mcu 0]
+ if {$selected_mcu == $mcu_name} {
+ return
+ }
+ set selected_mcu $mcu_name
+ set maximum_xcode [expr {0x10000 - ([lindex $mcu 3] * 1024)}]
+
+ # Configure detail labels
+ $name_label configure -text $mcu_name
+ $value_lbl_vendor configure -text [lindex $mcu 11]
+ $value_lbl_uart configure -text [lindex $mcu 7]
+ $value_lbl_voltage configure -text [lindex $mcu 9]
+ $value_lbl_interrupts configure -text [lindex $mcu 8]
+ $value_lbl_timers configure -text [lindex $mcu 12]
+
+ # Configure details text
+ $more_details_text configure -state normal
+ $more_details_text delete 1.0 end
+ foreach line [split [lindex $mcu 13] "\n"] {
+ $more_details_text image create end -image ::ICONS::16::bookmark -padx 2 -pady 2
+ $more_details_text insert end $line
+ $more_details_text insert end "\n"
+ }
+ $more_details_text configure -state disabled
+
+ # Configure XDATA scale
+ if {[lindex $mcu 1] != {yes}} {
+ if {[winfo ismapped $details_xdata_aval]} {
+ pack forget $details_xdata_aval
+ }
+ pack $details_xdata_note -fill both -expand 1
+ } else {
+ if {[winfo ismapped $details_xdata_note]} {
+ pack forget $details_xdata_note
+ }
+ pack $details_xdata_aval -fill both -expand 1 -padx 2
+ }
+ # Configure XCODE scale
+ if {[lindex $mcu 2] != {yes}} {
+ if {[winfo ismapped $details_xcode_aval]} {
+ pack forget $details_xcode_aval
+ }
+ pack $details_xcode_nota -fill both -expand 1
+ } else {
+ $xcode_spinbox configure -to $maximum_xcode
+ $xcode_scale configure -to $maximum_xcode
+ if {[winfo ismapped $details_xcode_nota]} {
+ pack forget $details_xcode_nota
+ }
+ pack $details_xcode_aval -fill both -expand 1 -padx 2
+ }
+
+ # Clear search bar
+ if {$args != {noclear}} {
+ clear_search_bar
+ }
+
+ # Load image
+ set image [$image_label cget -image]
+ $image_label configure \
+ -fg {#888888} \
+ -text [mc "Loading image ..."] \
+ -image ::ICONS::16::exec
+ if {$image != {} && $image != {::ICONS::16::no} && $image != {::ICONS::16::exec}} {
+ image delete $image
+ }
+ update
+ if {[catch {
+ $image_label configure -text { } -image [image create photo \
+ -format png -file "${::ROOT_DIRNAME}/icons/mcu/$mcu_name.png"
+ ]
+ }]} then {
+ $image_label configure \
+ -fg {#DD0000} \
+ -text [mc " Image not found"] \
+ -image ::ICONS::16::no
+ }
+ }
+
+ ## Set scrollbar for details text
+ # If frac0 == 0 && frac1 == 1 -> hide scrollbar
+ # @parm Float frac0 - Fraction of the topmost visible area
+ # @parm Float frac1 - Fraction of the bottommost visible area
+ # @return void
+ proc details_scrollbar_set {frac0 frac1} {
+ variable more_details_scrollbar ;# Widget: Scrollbar for $more_details_text
+ variable more_details_text ;# Widget: TextWidget "More details:"
+
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $more_details_scrollbar]} {
+ pack forget $more_details_scrollbar
+ }
+ # Show scrollbar
+ } else {
+ if {![winfo ismapped $more_details_scrollbar]} {
+ pack $more_details_scrollbar \
+ -side right -fill y \
+ -after $more_details_text
+ }
+ $more_details_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Clear search entry box
+ # @return void
+ proc clear_search_bar {} {
+ variable search_bar ;# Widget: Search bar entry box
+ $search_bar delete 0 end
+ }
+
+ ## Search for the give string in the listbox of available processors
+ # Primary purpose is validator for search entry box, it also
+ #+ ajusts search entry box background color
+ # @parm String string - Part of MCU name
+ # @return Bool - allways 1
+ proc search {string} {
+ variable search_bar ;# Widget: Search bar entry box
+ variable search_bar_clear ;# Widget: Search bar clear button
+ variable listbox_widget ;# Widget: List box containing available MCUs
+ variable mcu_names ;# List: Available processors (and show in the list)
+
+ # Search for empty string -> abort
+ if {![string length $string]} {
+ $search_bar_clear configure -state disabled
+ $search_bar configure -style TEntry
+ return 1
+ }
+
+ $search_bar_clear configure -state normal
+
+ # Do a case-insensitive search
+ set string [string toupper $string]
+
+ set i 0
+ foreach mcu $mcu_names {
+ if {[string first $string [string toupper $mcu]] != -1} {
+ $search_bar configure -style StringFound.TEntry
+ set item [$listbox_widget items $i]
+ $listbox_widget selection set $item
+ $listbox_widget see $item
+ select_item noclear
+ return 1
+ }
+ incr i
+ }
+
+ $search_bar configure -style StringNotFound.TEntry
+ return 1
+ }
+
+ ## Close MCU selection dialog and discart its result
+ # @return void
+ proc cancel {} {
+ variable selected_mcu ;# List: Dialog return value {mcu_type xdata xcode}
+ set selected_mcu {}
+ close_window
+ }
+
+ ## Disable/Enable XDATA memory
+ # @return void
+ proc xdata_disena {} {
+ variable xdata_scale ;# Widget: Scale for XDATA memory
+ variable xdata_spinbox ;# Widget: Scale for XDATA memory
+
+ if {${::SelectMCU::xdata_ena}} {
+ $xdata_scale state !disabled
+ $xdata_spinbox configure -state normal
+ } else {
+ $xdata_scale state disabled
+ $xdata_spinbox configure -state disabled
+ }
+ }
+
+ ## Disable/Enable XCODE memory
+ # @return void
+ proc xcode_disena {} {
+ variable xcode_spinbox ;# Widget: SpinBox for XCODE memory
+ variable xcode_scale ;# Widget: Scale for XCODE memory
+
+ if {${::SelectMCU::xcode_ena}} {
+ $xcode_scale state !disabled
+ $xcode_spinbox configure -state normal
+ } else {
+ $xcode_scale state disabled
+ $xcode_spinbox configure -state disabled
+ }
+ }
+
+ ## Validate XDATA memory spinbox
+ # @parm String string - String to validate
+ # @return Bool - Validation result
+ proc validate_xdata {string} {
+ if {![string is digit $string]} {
+ return 0
+ }
+ if {$string == {}} {
+ return 1
+ }
+ if {$string < 0 || $string > 0x10000} {
+ return 0
+ }
+
+ return 1
+ }
+
+ ## Validate XCODE memory spinbox
+ # @parm String string - String to validate
+ # @return Bool - Validation result
+ proc validate_xcode {string} {
+ variable maximum_xcode ;# Int: Maximum external program memory (0x10000 - internal)
+
+ if {![string is digit $string]} {
+ return 0
+ }
+ if {$string == {}} {
+ return 1
+ }
+ if {$string < 0 || $string > $maximum_xcode} {
+ return 0
+ }
+
+ return 1
+ }
+
+ ## This functionshould be changecmd for vendor comboBox
+ # @return void
+ proc change_vendor {} {
+ variable listbox_widget ;# Widget: List box containing available MCUs
+
+ clear_search_bar
+ $listbox_widget delete [$listbox_widget items]
+ fill_gui
+ }
+}
+
+# >>> File inclusion guard
+}
+# <<< File inclusion guard
diff --git a/lib/dialogues/tips.tcl b/lib/dialogues/tips.tcl
new file mode 100644
index 0000000..d2df211
--- /dev/null
+++ b/lib/dialogues/tips.tcl
@@ -0,0 +1,402 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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. #
+############################################################################
+
+# >>> File inclusion guard
+if { ! [ info exists _TIPS_TCL ] } {
+set _TIPS_TCL _
+# <<< File inclusion guard
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides facility to show tips on start-up
+# * Tips are readed from file deindef in NS variable "tips_file"
+# * Format of definition file is XML and it supports mutiple languages
+# * Usage is simple: execute procedure "::Tips::show_tip_of_the_day_win"
+# * It requires NS ConfigDialogues (see ${::GLOBAL_CONFIG(tips)})
+# --------------------------------------------------------------------------
+
+namespace eval Tips {
+ variable tip_of_the_day_win ;# ID of window "Tip of the day"
+ variable tip_of_the_day_text ;# ID of text widget in "Tip of the day"
+ variable tip_of_the_day_show_again ;# Bool: Show "Tip of the day"
+
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips available
+ variable current_tip ;# Number of the currently displayed tip
+ variable expected ;# Expeceted element
+ variable take_data ;# Bool: Append data section to $tips_data
+ # File containing tips data
+ variable tips_file "${::INSTALLATION_DIR}/data/tips.xml"
+
+ ## Invoke dialog "Tip on start-up"
+ # @return void
+ proc show_tip_of_the_day_win {} {
+ variable tip_of_the_day_win ;# ID of window "Tip of the day"
+ variable tip_of_the_day_text ;# ID of text widget in "Tip of the day"
+ variable tip_of_the_day_show_again ;# Bool: Show "Tip of the day"
+ variable number_of_tips ;# Number of tips available
+ variable tip_of_the_day_show_again ;# Bool: Show "Tip of the day"
+
+ # Set value of checkbox "Show again"
+ set tip_of_the_day_show_again ${::GLOBAL_CONFIG(tips)}
+ # Load tips definition file
+ load_tips_file
+
+ # Create toplevel window
+ set win [toplevel .tip_of_the_day -class {Tip of the day} -bg ${::COMMON_BG_COLOR}]
+ set tip_of_the_day_win $win
+
+ # Create window header
+ pack [label $win.header \
+ -text [mc "Did you know ... "] \
+ -font [font create \
+ -family {times} \
+ -size [expr {int(-25 * $::font_size_factor)}] \
+ -weight bold \
+ ] \
+ -compound right \
+ -image ::ICONS::32::help \
+ ] -pady 5
+
+ # Create middle frame (text windget and scrollbar)
+ set middle_frame [frame $win.middle_frame]
+ set text [text $middle_frame.text \
+ -width 0 -height 0 -bg white \
+ -wrap word \
+ -yscrollcommand "$middle_frame.scrollbar set" \
+ -font [font create \
+ -family {helvetica} \
+ -size [expr {int(-14 * $::font_size_factor)}] \
+ -weight normal \
+ ] \
+ ]
+ pack $text -side left -fill both -expand 1
+ pack [ttk::scrollbar $middle_frame.scrollbar \
+ -orient vertical \
+ -command [list $text yview] \
+ ] -side left -fill y -after $text
+ set tip_of_the_day_text $text
+
+ ## Create bottom frame
+ set bottom_frame [frame $win.bottom_frame]
+ # - CheckButton "Show tips on start-up"
+ pack [checkbutton $bottom_frame.chbutton \
+ -variable ::Tips::tip_of_the_day_show_again \
+ -command {::Tips::tip_otd_show_again} \
+ -text [mc "Show tips on start-up"] \
+ ] -side left -anchor e
+ # - Button "Close"
+ pack [ttk::button $bottom_frame.close_but \
+ -compound left \
+ -text [mc "Close"] \
+ -image ::ICONS::16::button_cancel \
+ -command {::Tips::tip_otd_CLOSE} \
+ -width 8 \
+ ] -side right -anchor w -padx 2
+ # - Button "Next"
+ pack [ttk::button $bottom_frame.next_but \
+ -compound left \
+ -text [mc "Next"] \
+ -image ::ICONS::16::right \
+ -command {::Tips::tip_otd_NEXT} \
+ -width 8 \
+ ] -side right -anchor w -padx 2
+ # - Button "Previous"
+ pack [ttk::button $bottom_frame.prev_but \
+ -compound left \
+ -text [mc "Previous"] \
+ -image ::ICONS::16::left \
+ -command {::Tips::tip_otd_PREV} \
+ -width 8 \
+ ] -side right -anchor w -padx 2
+
+ # Pack window frames
+ pack $middle_frame -side top -fill both -expand 1 -padx 10 -pady 5
+ pack $bottom_frame -side bottom -fill x -after $middle_frame -padx 10 -pady 5
+
+ # Configure text tags
+ $text tag configure tag_bold -font [font create \
+ -family {helvetica} \
+ -size [expr {int(-14 * $::font_size_factor)}] \
+ -weight bold \
+ ]
+ # Configure text tags
+ $text tag configure tag_code -font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size [expr {int(-14 * $::font_size_factor)}] \
+ -weight normal \
+ ] -foreground {#DD8800}
+
+ # Create tag for external hyperlinks
+ create_link_tag_in_text_widget $text
+
+ # Determinate random number of tip to show
+ expr {srand([clock seconds])}
+ display_tip [expr {int(rand() * $number_of_tips)}]
+
+ # Configure dialog window
+ wm iconphoto $win ::ICONS::16::info
+ wm title $win [mc "Tip of the day - MCU 8051 IDE"]
+ wm minsize $win 520 250
+ wm protocol $win WM_DELETE_WINDOW {
+ ::Tips::tip_otd_CLOSE
+ }
+ wm transient $win .
+ raise $win
+ catch {
+ grab $win
+ }
+ }
+
+ ## Load definition of tips
+ # @return void
+ proc load_tips_file {} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips available
+ variable tips_file ;# File containing tips data
+ variable expected ;# Expeceted element
+ variable take_data ;# Bool: Append data section to $tips_data
+
+ # Initialize NS variables
+ set take_data 0
+ set number_of_tips 0
+ set expected {tips}
+ set tips_data {}
+
+ # Open file
+ if {[catch {
+ set file [open $tips_file {r}]
+ }]} then {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title "tips.xml" \
+ -message [mc "Unable to open file containing tips,\nplease check your installation"]
+ return
+ }
+
+ # Create XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand ::Tips::xml_data_parser_element \
+ -characterdatacommand ::Tips::xml_data_parser_data \
+ ]
+
+ # Start XML parser
+ if {[catch {
+ $parser parse [read $file]
+ } result]} then {
+ set number_of_tips 0
+ set tips_data {}
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to parse tips.xml"] \
+ -message [mc "File tips.xml is corrupted,\nplease check your installation"]
+ puts stderr $result
+ return
+ }
+
+ # Close file and free parser
+ close $file
+ $parser free
+ }
+
+ ## Universal parser handler - handles XML tags and data
+ # @parm String arg1 - content of the element
+ # @return void
+ proc xml_data_parser_data {arg1} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips available
+ variable current_tip ;# Number of the currently displayed tip
+ variable expected ;# Expeceted element
+ variable take_data ;# Bool: Append data section to $tips_data
+
+ if {!$take_data} {
+ return
+ }
+
+ set take_data 0
+ incr number_of_tips
+
+ regsub -all {^\s+} $arg1 {} arg1
+ regsub -all {\s+$} $arg1 {} arg1
+ lappend tips_data [regsub -all -line {^\t+} $arg1 {}]
+ }
+
+ ## XML parser handler - handles XML tags
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc xml_data_parser_element {arg1 attrs} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips available
+ variable current_tip ;# Number of the currently displayed tip
+ variable expected ;# Expeceted element
+ variable take_data ;# Bool: Append data section to $tips_data
+
+ if {$arg1 != $expected} {
+ error "Bad element `$arg1'"
+ }
+ if {$arg1 == {tips}} {
+ set expected {tip}
+ }
+
+ # Iterate over element attributes
+ for {set i 0} {$i < [llength $attrs]} {incr i} {
+ if {[lindex $attrs $i] != {lang}} {
+ incr i
+ continue
+ }
+ incr i
+
+ # Take data only if some translation has been loaded and it conforms with the text
+ if {[string tolower [lindex $attrs $i]] == [string tolower ${::GLOBAL_CONFIG(language)}]} {
+ set take_data 1
+ } else {
+ set take_data 0
+ }
+ }
+ }
+
+ ## Close dialog
+ # @return void
+ proc tip_otd_CLOSE {} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips available
+ variable current_tip ;# Number of the currently displayed tip
+ variable tip_of_the_day_win ;# ID of window "Tip of the day"
+
+ # Remove dialog
+ grab release $tip_of_the_day_win
+ destroy $tip_of_the_day_win
+
+ # Free dialog resources
+ set tips_data {}
+ set number_of_tips {}
+ set current_tip {}
+ }
+
+ ## Display tip with the given number in the window
+ # @parm Int tip_number - number of the tip to show (can overlap allowed range)
+ # @return void
+ proc display_tip {tip_number} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips available
+ variable current_tip ;# Number of the currently displayed tip
+ variable tip_of_the_day_text ;# ID of text widget in "Tip of the day"
+
+ set current_tip $tip_number
+
+ # Clear text widget
+ $tip_of_the_day_text configure -state normal
+ $tip_of_the_day_text delete 1.0 end
+
+ # Validate tip number
+ if {!$number_of_tips} {
+ $tip_of_the_day_text configure -state disabled
+ return
+ }
+ if {$tip_number >= $number_of_tips} {
+ set current_tip $number_of_tips
+ incr current_tip -1
+ }
+
+ # Create map of bold and code font tags
+ set bold_tag_map [list]
+ set code_tag_map [list]
+ set content [lindex $tips_data $current_tip]
+ foreach map {bold_tag_map code_tag_map} \
+ tag {b c} \
+ {
+ while {1} {
+ set tag_pair {}
+
+ set idx [string first "<$tag>" $content]
+ if {$idx == -1} {break}
+ regsub "<$tag>" $content {} content
+ lappend tag_pair $idx
+
+ set idx [string first "</$tag>" $content]
+ if {$idx == -1} {break}
+ regsub "</$tag>" $content {} content
+ lappend tag_pair $idx
+
+ lappend $map $tag_pair
+ }
+ }
+
+ # Fill text widget
+ set start [$tip_of_the_day_text index insert]
+ $tip_of_the_day_text insert end $content
+ foreach pair $bold_tag_map {
+ $tip_of_the_day_text tag add tag_bold $start+[lindex $pair 0]c $start+[lindex $pair 1]c
+ }
+ foreach pair $code_tag_map {
+ $tip_of_the_day_text tag add tag_code $start+[lindex $pair 0]c $start+[lindex $pair 1]c
+ }
+ $tip_of_the_day_text configure -state disabled
+
+ # Detect external hyperlinks and make the functional
+ convert_all_https_to_links $tip_of_the_day_text
+ }
+
+ ## Show next tip
+ # @return void
+ proc tip_otd_NEXT {} {
+ variable number_of_tips ;# Number of tips available
+ variable current_tip ;# Number of the currently displayed tip
+
+ incr current_tip
+ if {$current_tip >= $number_of_tips} {
+ set current_tip 0
+ }
+ display_tip $current_tip
+ }
+
+ ## Show previous tip
+ # @return void
+ proc tip_otd_PREV {} {
+ variable number_of_tips ;# Number of tips available
+ variable current_tip ;# Number of the currently displayed tip
+
+ incr current_tip -1
+ if {$current_tip < 0} {
+ set current_tip [expr {$number_of_tips - 1}]
+ }
+ display_tip $current_tip
+ }
+
+ ## Adjust base configuration file to variable "tip_of_the_day_show_again"
+ # @return void
+ proc tip_otd_show_again {} {
+ variable tip_of_the_day_show_again ;# Bool: Show "Tip of the day"
+
+ ::configDialogues::global::set_variable tips $tip_of_the_day_show_again
+ }
+}
+
+# >>> File inclusion guard
+}
+# <<< File inclusion guard