00001 # TKE - Advanced Programmer's Editor
00002 # Copyright (C) 2014-2019 Trevor Williams (phase1geo@gmail.com)
00003 #
00004 # This program is free software; you can redistribute it and/or modify
00005 # it under the terms of the GNU General Public License as published by
00006 # the Free Software Foundation; either version 2 of the License, or
00007 # (at your option) any later version.
00008 #
00009 # This program is distributed in the hope that it will be useful,
00010 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00012 # GNU General Public License for more details.
00013 #
00014 # You should have received a copy of the GNU General Public License along
00015 # with this program; if not, write to the Free Software Foundation, Inc.,
00016 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00017
00018 ######################################################################
00019 # Name: gui.tcl
00020 # Author: Trevor Williams (phase1geo@gmail.com)
00021 # Date: 5/11/2013
00022 # Brief: Contains all of the main GUI elements for the editor and
00023 # their behavior.
00024 ######################################################################
00025
00026 namespace eval gui {
00027
00028 variable curr_id 0
00029 variable pw_index 0
00030 variable pw_current 0
00031 variable nb_index 0
00032 variable nb_move ""
00033 variable file_move 0
00034 variable lengths {}
00035 variable user_exit_status ""
00036 variable file_locked 0
00037 variable file_favorited 0
00038 variable last_opened [list]
00039 variable fif_files [list]
00040 variable info_clear ""
00041 variable trailing_ws_re {[\ ]+$}
00042 variable case_sensitive 1
00043 variable saved 0
00044 variable highlightcolor ""
00045 variable auto_cwd 0
00046 variable numberwidth 4
00047 variable browse_dir "last"
00048 variable synced_key ""
00049 variable synced_txt ""
00050 variable show_match_chars 0
00051 variable search_method "regexp"
00052 variable fif_method "regexp"
00053 variable panel_focus ""
00054
00055 array set widgets {}
00056 array set tab_tip {}
00057 array set line_sel_anchor {}
00058 array set txt_current {}
00059 array set cursor_hist {}
00060 array set synced {}
00061 array set be_after_id {}
00062 array set be_ignore {}
00063 array set undo_count {}
00064
00065 #######################
00066 # PUBLIC PROCEDURES #
00067 #######################
00068
00069 ######################################################################
00070 # Sets the title of the window to match the current file.
00071 proc set_title {} {
00072
00073 # Get the current tab
00074 if {![catch { get_info {} current tabbar }] && ([llength [$tabbar tabs]] > 0)} {
00075 set tab_name [$tabbar tab current -text]
00076 } else {
00077 set tab_name ""
00078 }
00079
00080 # Get the host name
00081 if {($::tcl_platform(os) eq "Darwin") && ([lindex [split $::tcl_platform(osVersion) .] 0] >= 16)} {
00082 set host ""
00083 } else {
00084 set host "[lindex [split [info hostname] .] 0]:"
00085 }
00086
00087 if {[set session [sessions::current]] ne ""} {
00088 wm title . "$tab_name ($session) \[${host}[pwd]\]"
00089 } else {
00090 wm title . "$tab_name \[${host}[pwd]\]"
00091 }
00092
00093 }
00094
00095 ######################################################################
00096 # Sets the default file browser directory pathname.
00097 proc set_browse_directory {bsdir} {
00098
00099 variable browse_dir
00100
00101 set browse_dir $bsdir
00102
00103 }
00104
00105 ######################################################################
00106 # Returns the file browser directory path.
00107 proc get_browse_directory {} {
00108
00109 variable browse_dir
00110
00111 switch $browse_dir {
00112 last { return "" }
00113 buffer { return [file dirname [get_info {} current fname]] }
00114 current { return [pwd] }
00115 default { return $browse_dir }
00116 }
00117
00118 }
00119
00120 ######################################################################
00121 # Creates all images.
00122 proc create_images {} {
00123
00124 # Create tab images
00125 theme::register_image tab_lock bitmap tabs -background \
00126 {msgcat::mc "Image used in tab to indicate that the tab’s file is locked."} \
00127 -file [file join $::tke_dir lib images lock.bmp] \
00128 -maskfile [file join $::tke_dir lib images lock.bmp] \
00129 -foreground 2
00130 theme::register_image tab_readonly bitmap tabs -background \
00131 {msgcat::mc "Image used in tab to indicate that the tab's file is readonly."} \
00132 -file [file join $::tke_dir lib images lock.bmp] \
00133 -maskfile [file join $::tke_dir lib images lock.bmp] \
00134 -foreground 2
00135 theme::register_image tab_diff bitmap tabs -background \
00136 {msgcat::mc "Image used in tab to indicate that the tab contains a difference view."} \
00137 -file [file join $::tke_dir lib images diff.bmp] \
00138 -maskfile [file join $::tke_dir lib images diff.bmp] \
00139 -foreground 2
00140 theme::register_image tab_close bitmap tabs -background \
00141 {msgcat::mc "Image used in tab which, when clicked, closes the tab."} \
00142 -file [file join $::tke_dir lib images close.bmp] \
00143 -maskfile [file join $::tke_dir lib images close.bmp] \
00144 -foreground 2
00145 theme::register_image tab_activeclose bitmap tabs -background \
00146 {msgcat::mc "Images used in tab which will be displayed when the mouse enters the close button area"} \
00147 -file [file join $::tke_dir lib images active_close.bmp] \
00148 -maskfile [file join $::tke_dir lib images active_close.bmp] \
00149 -foreground 2
00150
00151 # Create close button for forms
00152 theme::register_image form_close bitmap ttk_style background \
00153 {msgcat::mc "Image displayed in fill-in forms which closes the form UI. Used in forms such as search, search/replace, and find in files."} \
00154 -file [file join $::tke_dir lib images close.bmp] \
00155 -maskfile [file join $::tke_dir lib images close.bmp] \
00156 -foreground 2
00157
00158 # Create next/previous button for search
00159 theme::register_image search_next bitmap ttk_style background \
00160 {msgcat::mc "Image displayed in find field to search for next match."} \
00161 -file [file join $::tke_dir lib images right.bmp] \
00162 -maskfile [file join $::tke_dir lib images right.bmp] \
00163 -foreground 2
00164 theme::register_image search_prev bitmap ttk_style background \
00165 {msgcat::mc "Image displayed in find field to search for previous match."} \
00166 -file [file join $::tke_dir lib images left.bmp] \
00167 -maskfile [file join $::tke_dir lib images left.bmp] \
00168 -foreground 2
00169
00170 # Create main logo image
00171 image create photo logo -file [file join $::tke_dir lib images tke_logo_64.gif]
00172
00173 # Create menu images
00174 theme::register_image menu_lock bitmap menus -background \
00175 {msgcat::mc "Image used in tab menus to indicate that the file is locked."} \
00176 -file [file join $::tke_dir lib images lock.bmp] \
00177 -maskfile [file join $::tke_dir lib images lock.bmp] \
00178 -foreground black
00179 theme::register_image menu_readonly bitmap menus -background \
00180 {msgcat::mc "Image used in tab menus to indicate that the file is readonly."} \
00181 -file [file join $::tke_dir lib images lock.bmp] \
00182 -maskfile [file join $::tke_dir lib images lock.bmp] \
00183 -foreground black
00184 theme::register_image menu_diff bitmap menus -background \
00185 {msgcat::mc "Image used in tab menus to indicate that the file is associated with a difference view."} \
00186 -file [file join $::tke_dir lib images diff.bmp] \
00187 -maskfile [file join $::tke_dir lib images diff.bmp] \
00188 -foreground black
00189 theme::register_image menu_check bitmap menus -background \
00190 {msgcat::mc "Image used in the menus to indicate that a menu item is selected."} \
00191 -file [file join $::tke_dir lib images menu_check.bmp] \
00192 -maskfile [file join $::tke_dir lib images menu_check.bmp] \
00193 -foreground black
00194 theme::register_image menu_nocheck bitmap menus -background \
00195 {msgcat::mc "Image used in the menus to indicate that a menu item is not selected."} \
00196 -file [file join $::tke_dir lib images menu_nocheck.bmp] \
00197 -maskfile [file join $::tke_dir lib images menu_nocheck.bmp] \
00198 -foreground black
00199
00200 # Create preference images
00201 theme::register_image pref_checked photo ttk_style background \
00202 {msgcat::mc "Image used in the preferences window to indicate that a table item is selected."} \
00203 -file [file join $::tke_dir lib images checked.gif]
00204 theme::register_image pref_unchecked photo ttk_style background \
00205 {msgcat::mc "Image used in the preferences window to indicate that a table item is deselected."} \
00206 -file [file join $::tke_dir lib images unchecked.gif]
00207 theme::register_image pref_check photo ttk_style background \
00208 {msgcat::mc "Image used in the preferences window to indicate that something is true."} \
00209 -file [file join $::tke_dir lib images check.gif]
00210 theme::register_image pref_general photo ttk_style background \
00211 {msgcat::mc "Image used in the preferences window in the General tab."} \
00212 -file [file join $::tke_dir lib images general.gif]
00213 theme::register_image pref_appearance photo ttk_style background \
00214 {msgcat::mc "Image used in the preferences window in the Appearance tab."} \
00215 -file [file join $::tke_dir lib images appearance.gif]
00216 theme::register_image pref_editor photo ttk_style background \
00217 {msgcat::mc "Image used in the preferences window in the Editor tab."} \
00218 -file [file join $::tke_dir lib images editor.gif]
00219 theme::register_image pref_emmet photo ttk_style background \
00220 {msgcat::mc "Image used in the preferences window in the Emmet tab."} \
00221 -file [file join $::tke_dir lib images emmet.gif]
00222 theme::register_image pref_find photo ttk_style background \
00223 {msgcat::mc "Image used in the preferences window in the Find tab."} \
00224 -file [file join $::tke_dir lib images find.gif]
00225 theme::register_image pref_sidebar photo ttk_style background \
00226 {msgcat::mc "Image used in the preferences window in the Sidebar tab."} \
00227 -file [file join $::tke_dir lib images sidebar.gif]
00228 theme::register_image pref_view photo ttk_style background \
00229 {msgcat::mc "Image used in the preferences window in the View tab."} \
00230 -file [file join $::tke_dir lib images view.gif]
00231 theme::register_image pref_snippets photo ttk_style background \
00232 {msgcat::mc "Image used in the preferences window in the Snippets tab."} \
00233 -file [file join $::tke_dir lib images snippets.gif]
00234 theme::register_image pref_shortcuts photo ttk_style background \
00235 {msgcat::mc "Image used in the preferences window in the Shortcuts tab."} \
00236 -file [file join $::tke_dir lib images shortcut.gif]
00237 theme::register_image pref_plugins photo ttk_style background \
00238 {msgcat::mc "Image used in the preferences window in the Plugins tab."} \
00239 -file [file join $::tke_dir lib images plugins.gif]
00240 theme::register_image pref_documentation photo ttk_style background \
00241 {msgcat::mc "Image used in the preferences window in the Documentation tab."} \
00242 -file [file join $::tke_dir lib images documentation.gif]
00243 theme::register_image pref_advanced photo ttk_style background \
00244 {msgcat::mc "Image used in the preferences window in the Advanced tab."} \
00245 -file [file join $::tke_dir lib images advanced.gif]
00246
00247 }
00248
00249 ######################################################################
00250 # Create the main GUI interface.
00251 proc create {} {
00252
00253 variable widgets
00254 variable search_method
00255 variable fif_method
00256
00257 # Set the application icon photo
00258 wm iconphoto . [image create photo -file [file join $::tke_dir lib images tke_logo_128.gif]]
00259 wm geometry . 800x600
00260
00261 # Create images
00262 create_images
00263
00264 # Create the panedwindow
00265 set widgets(pw) [ttk::panedwindow .pw -orient horizontal]
00266
00267 # Add the sidebar
00268 set widgets(sb) [sidebar::create $widgets(pw).sb]
00269
00270 # Create panedwindow (to support split pane view)
00271 $widgets(pw) add [ttk::frame $widgets(pw).tf]
00272
00273 # Create the notebook panedwindow
00274 set widgets(nb_pw) [ttk::panedwindow $widgets(pw).tf.nbpw -orient horizontal]
00275
00276 # Add notebook
00277 add_notebook
00278
00279 # Pack the notebook panedwindow
00280 pack $widgets(nb_pw) -fill both -expand yes
00281
00282 # Create the find_in_files widget
00283 set max_width [expr [msgcat::mcmax "Regexp" "Glob" "Exact"] + 1]
00284 set widgets(fif) [ttk::frame .fif]
00285 ttk::label $widgets(fif).lf -text [format "%s: " [msgcat::mc "Find"]]
00286 set widgets(fif_find) [ttk::entry $widgets(fif).ef]
00287 set widgets(fif_type) [ttk::button $widgets(fif).type -style BButton -width $max_width -command [list gui::handle_menu_popup $widgets(fif).type .fif.typeMenu]]
00288 set widgets(fif_case) [ttk::checkbutton $widgets(fif).case -text "Aa" -variable gui::case_sensitive]
00289 ttk::label $widgets(fif).li -text [format "%s: " [msgcat::mc "In"]]
00290 set widgets(fif_in) [tokenentry::tokenentry $widgets(fif).ti -font [$widgets(fif_find) cget -font] \
00291 -tokenshape square -highlightthickness 2 -highlightbackground white -highlightcolor white]
00292 set widgets(fif_save) [ttk::checkbutton $widgets(fif).save -text [msgcat::mc "Save"] \
00293 -variable gui::saved -command [list search::update_save fif]]
00294 set widgets(fif_close) [ttk::label $widgets(fif).close -image form_close]
00295
00296 # Create the search type menu
00297 set type_menu [menu $widgets(fif).typeMenu -tearoff 0]
00298 $type_menu add radiobutton -label [msgcat::mc "Regexp"] -variable gui::fif_method -value "regexp" -command [list $widgets(fif_type) configure -text [msgcat::mc "Regexp"]]
00299 $type_menu add radiobutton -label [msgcat::mc "Glob"] -variable gui::fif_method -value "glob" -command [list $widgets(fif_type) configure -text [msgcat::mc "Glob"]]
00300 $type_menu add radiobutton -label [msgcat::mc "Exact"] -variable gui::fif_method -value "exact" -command [list $widgets(fif_type) configure -text [msgcat::mc "Exact"]]
00301
00302 tooltip::tooltip $widgets(fif_case) [msgcat::mc "Case sensitivity"]
00303
00304 bind $widgets(fif_find) <Return> [list gui::check_fif_for_return]
00305 bind [$widgets(fif_in) entrytag] <Return> { if {[gui::check_fif_for_return]} break }
00306 bind $widgets(fif_case) <Return> [list gui::check_fif_for_return]
00307 bind $widgets(fif_save) <Return> [list gui::check_fif_for_return]
00308 bind $widgets(fif_find) <Escape> [list set gui::user_exit_status 0]
00309 bind [$widgets(fif_in) entrytag] <Escape> [list set gui::user_exit_status 0]
00310 bind $widgets(fif_case) <Escape> [list set gui::user_exit_status 0]
00311 bind $widgets(fif_save) <Escape> [list set gui::user_exit_status 0]
00312 bind $widgets(fif_close) <Button-1> [list set gui::user_exit_status 0]
00313 bind $widgets(fif_find) <Up> "search::traverse_history fif 1; break"
00314 bind $widgets(fif_find) <Down> "search::traverse_history fif -1; break"
00315 bind $widgets(fif_close) <Key-space> [list set gui::user_exit_status 0]
00316
00317 # Make the fif_in field a drop target
00318 make_drop_target $widgets(fif_in) tokenentry -types {files dirs}
00319
00320 grid columnconfigure $widgets(fif) 1 -weight 1
00321 grid $widgets(fif).lf -row 0 -column 0 -sticky ew -pady 2
00322 grid $widgets(fif).ef -row 0 -column 1 -sticky ew -pady 2
00323 grid $widgets(fif).type -row 0 -column 2 -sticky news -padx 2 -pady 2
00324 grid $widgets(fif).case -row 0 -column 3 -sticky news -padx 2 -pady 2
00325 grid $widgets(fif).close -row 0 -column 4 -sticky news -padx 2 -pady 2
00326 grid $widgets(fif).li -row 1 -column 0 -sticky ew -pady 2
00327 grid $widgets(fif).ti -row 1 -column 1 -sticky ew -pady 2
00328 grid $widgets(fif).save -row 1 -column 3 -sticky news -padx 2 -pady 2 -columnspan 2
00329
00330 # Create the documentation search bar
00331 set widgets(doc) [ttk::frame .doc]
00332 ttk::label $widgets(doc).l1f -text [format "%s: " [msgcat::mc "Search"]]
00333 ttk::menubutton $widgets(doc).mb -menu [menu .doc.docPopup -tearoff 0]
00334 ttk::label $widgets(doc).l2f -text [format "%s: " [msgcat::mc "for"]]
00335 ttk::entry $widgets(doc).e
00336 ttk::checkbutton $widgets(doc).save -text [msgcat::mc "Save"] -variable gui::saved \
00337 -command [list search::update_save docsearch]
00338 ttk::label $widgets(doc).close -image form_close
00339
00340 bind $widgets(doc).e <Return> [list set gui::user_exit_status 1]
00341 bind $widgets(doc).e <Escape> [list set gui::user_exit_status 0]
00342 bind $widgets(doc).e <Up> "search::traverse_history docsearch 1; break"
00343 bind $widgets(doc).e <Down> "search::traverse_history docsearch -1; break"
00344 bind $widgets(doc).mb <Return> [list set gui::user_exit_status 1]
00345 bind $widgets(doc).mb <Escape> [list set gui::user_exit_status 0]
00346 bind $widgets(doc).save <Return> [list set gui::user_exit_status 1]
00347 bind $widgets(doc).save <Escape> [list set gui::user_exit_status 0]
00348 bind $widgets(doc).close <Button-1> [list set gui::user_exit_status 0]
00349 bind $widgets(doc).close <Key-space> [list set gui::user_exit_status 0]
00350
00351 pack $widgets(doc).l1f -side left -padx 2 -pady 2
00352 pack $widgets(doc).mb -side left -padx 2 -pady 2
00353 pack $widgets(doc).l2f -side left -padx 2 -pady 2
00354 pack $widgets(doc).e -side left -padx 2 -pady 2 -fill x -expand yes
00355 pack $widgets(doc).save -side left -padx 2 -pady 2
00356 pack $widgets(doc).close -side left -padx 2 -pady 2
00357
00358 # Create the information bar
00359 set widgets(info) [ttk::frame .if]
00360 set widgets(info_state) [ttk::label .if.l1]
00361 ttk::separator .if.s1 -orient vertical
00362 set widgets(info_msg) [ttk::label .if.l2]
00363 ttk::separator .if.s2 -orient vertical
00364 set widgets(info_encode) [ttk::button .if.enc -style BButton -command [list gui::handle_menu_popup .if.enc [gui::create_encoding_menu .if.enc]]]
00365 ttk::separator .if.s3 -orient vertical
00366 set widgets(info_indent) [ttk::button .if.ind -style BButton -command [list gui::handle_menu_popup .if.ind [indent::create_menu .if.ind]]]
00367 ttk::separator .if.s4 -orient vertical
00368 set widgets(info_syntax) [ttk::button .if.syn -style BButton -command [list gui::handle_menu_popup .if.syn [syntax::create_menu .if.syn]]]
00369 ttk::label .if.sp -text " "
00370
00371 $widgets(info_encode) configure -state disabled
00372 $widgets(info_indent) configure -state disabled
00373 $widgets(info_syntax) configure -state disabled
00374
00375 pack .if.l1 -side left -padx 2 -pady 2
00376 pack .if.s1 -side left -padx 2 -pady 10 -fill y
00377 pack .if.l2 -side left -padx 2 -pady 2
00378 pack .if.sp -side right -padx 2 -pady 2
00379 pack .if.syn -side right -padx 2 -pady 2
00380 pack .if.s3 -side right -padx 2 -pady 10 -fill y
00381 pack .if.ind -side right -padx 2 -pady 2
00382 pack .if.s2 -side right -padx 2 -pady 10 -fill y
00383 pack .if.enc -side right -padx 2 -pady 2
00384 pack .if.s4 -side right -padx 2 -pady 10 -fill y
00385
00386 # Create the configurable response widget
00387 set widgets(ursp) [ttk::frame .rf]
00388 set widgets(ursp_label) [ttk::label .rf.l]
00389 set widgets(ursp_entry) [ttk::entry .rf.e]
00390 ttk::label .rf.close -image form_close
00391
00392 bind $widgets(ursp_entry) <Return> [list set gui::user_exit_status 1]
00393 bind $widgets(ursp_entry) <Escape> [list set gui::user_exit_status 0]
00394 bind .rf.close <Button-1> [list set gui::user_exit_status 0]
00395 bind .rf.close <Key-space> [list set gui::user_exit_status 0]
00396
00397 # Make the user field a drag and drop target
00398 make_drop_target $widgets(ursp_entry) entry
00399
00400 grid rowconfigure .rf 0 -weight 1
00401 grid columnconfigure .rf 1 -weight 1
00402 grid $widgets(ursp_label) -row 0 -column 0 -sticky news -padx 2 -pady 2
00403 grid $widgets(ursp_entry) -row 0 -column 1 -sticky news -padx 2 -pady 2
00404 grid .rf.close -row 0 -column 2 -sticky news -padx 2 -pady 2
00405
00406 # Pack the notebook
00407 grid rowconfigure . 0 -weight 1
00408 grid columnconfigure . 0 -weight 1
00409 grid $widgets(pw) -row 0 -column 0 -sticky news
00410 grid $widgets(info) -row 1 -column 0 -sticky ew
00411
00412 ttk::separator .sep -orient horizontal
00413
00414 # Create tab popup
00415 set widgets(menu) [menu $widgets(nb_pw).popupMenu -tearoff 0 -postcommand gui::setup_tab_popup_menu]
00416 $widgets(menu) add command -label [msgcat::mc "Close Tab"] -command [list gui::close_current]
00417 $widgets(menu) add command -label [msgcat::mc "Close All Other Tabs"] -command gui::close_others
00418 $widgets(menu) add command -label [msgcat::mc "Close All Tabs"] -command gui::close_all
00419 $widgets(menu) add separator
00420 $widgets(menu) add command -label [msgcat::mc "Close Other Tabs In Pane"] -command gui::close_others_current_pane
00421 $widgets(menu) add command -label [msgcat::mc "Close All Tabs In Pane"] -command gui::close_current_pane
00422 $widgets(menu) add separator
00423 $widgets(menu) add command -label [msgcat::mc "Hide Tab"] -command [list gui::hide_current]
00424 $widgets(menu) add separator
00425 $widgets(menu) add checkbutton -label [msgcat::mc "Split View"] -onvalue 1 -offvalue 0 \
00426 -variable menus::show_split_pane -command [list gui::toggle_split_pane]
00427 $widgets(menu) add checkbutton -label [msgcat::mc "Bird's Eye View"] -onvalue 1 -offvalue 0 \
00428 -variable menus::show_birdseye -command [list gui::toggle_birdseye]
00429 $widgets(menu) add separator
00430 $widgets(menu) add checkbutton -label [msgcat::mc "Locked"] -onvalue 1 -offvalue 0 \
00431 -variable gui::file_locked -command [list gui::set_current_file_lock_with_current]
00432 $widgets(menu) add checkbutton -label [msgcat::mc "Favorited"] -onvalue 1 -offvalue 0 \
00433 -variable gui::file_favorited -command [list gui::set_current_file_favorite_with_current]
00434 $widgets(menu) add separator
00435 $widgets(menu) add command -label [msgcat::mc "Show in Sidebar"] -command gui::show_current_in_sidebar
00436 $widgets(menu) add separator
00437 $widgets(menu) add command -label [msgcat::mc "Move to Other Pane"] -command gui::move_to_pane
00438
00439 # Add the menu to the themable widgets
00440 theme::register_widget $widgets(menu) menus
00441 theme::register_widget .doc.docPopup menus
00442
00443 # Add plugins to tab popup
00444 plugins::handle_tab_popup $widgets(menu)
00445
00446 # Add the menu bar
00447 menus::create
00448
00449 # Show the sidebar (if necessary)
00450 if {[preferences::get View/ShowSidebar]} {
00451 show_sidebar_view
00452 } else {
00453 hide_sidebar_view
00454 }
00455
00456 # Show the console (if necessary)
00457 if {[preferences::get View/ShowConsole]} {
00458 show_console_view
00459 } else {
00460 # hide_console_view
00461 }
00462
00463 # Show the tabbar (if necessary)
00464 if {[preferences::get View/ShowTabBar]} {
00465 show_tab_view
00466 } else {
00467 hide_tab_view
00468 }
00469
00470 # Show the status bar (if necessary)
00471 if {[preferences::get View/ShowStatusBar]} {
00472 show_status_view
00473 } else {
00474 hide_status_view
00475 }
00476
00477 # Save the initial state since this value can be modified from Vim
00478 set_matching_char [preferences::get Editor/HighlightMatchingChar]
00479
00480 # Make sure that the browse directory is updated
00481 handle_browse_directory
00482
00483 # Set the default search method
00484 if {![preferences::get Editor/VimMode]} {
00485 set search_method [preferences::get Find/DefaultMethod]
00486 }
00487
00488 # Set the default Find in Files search method
00489 set fif_method [preferences::get Find/DefaultFIFMethod]
00490
00491 # Add the available encodings to the command launcher
00492 foreach encname [encoding names] {
00493 launcher::register [format "%s: %s" [msgcat::mc "Encoding"] [string toupper $encname]] [list gui::set_current_encoding $encname]
00494 }
00495
00496 # If the user attempts to close the window via the window manager, treat
00497 # it as an exit request from the menu system.
00498 wm protocol . WM_DELETE_WINDOW [list menus::exit_command]
00499
00500 # Trace changes to the Appearance/Theme preference variable
00501 trace variable preferences::prefs(Editor/WarningWidth) w gui::handle_warning_width_change
00502 trace variable preferences::prefs(Editor/MaxUndo) w gui::handle_max_undo
00503 trace variable preferences::prefs(Editor/HighlightMatchingChar) w gui::handle_matching_char
00504 trace variable preferences::prefs(Editor/HighlightMismatchingChar) w gui::handle_bracket_audit
00505 trace variable preferences::prefs(Editor/RelativeLineNumbers) w gui::handle_relative_line_numbers
00506 trace variable preferences::prefs(Editor/LineNumberAlignment) w gui::handle_line_number_alignment
00507 trace variable preferences::prefs(View/AllowTabScrolling) w gui::handle_allow_tab_scrolling
00508 trace variable preferences::prefs(Editor/VimMode) w gui::handle_vim_mode
00509 trace variable preferences::prefs(Appearance/EditorFont) w gui::handle_editor_font
00510 trace variable preferences::prefs(General/AutoChangeWorkingDirectory) w gui::handle_auto_cwd
00511 trace variable preferences::prefs(General/DefaultFileBrowserDirectory) w gui::handle_browse_directory
00512 trace variable preferences::prefs(View/ShowBirdsEyeView) w gui::handle_show_birdseye
00513 trace variable preferences::prefs(View/BirdsEyeViewFontSize) w gui::handle_birdseye_font_size
00514 trace variable preferences::prefs(View/BirdsEyeViewWidth) w gui::handle_birdseye_width
00515 trace variable preferences::prefs(View/EnableCodeFolding) w gui::handle_code_folding
00516 trace variable preferences::prefs(Appearance/CursorWidth) w gui::handle_cursor_width
00517 trace variable preferences::prefs(Appearance/ExtraLineSpacing) w gui::handle_extra_line_spacing
00518
00519 # Create general UI bindings
00520 bind all <Control-plus> [list gui::handle_font_change 1]
00521 bind all <Control-minus> [list gui::handle_font_change -1]
00522
00523 }
00524
00525 ######################################################################
00526 # Handles any menu popups that are needed in the information bar
00527 proc handle_menu_popup {w mnu} {
00528
00529 set menu_width [winfo reqwidth $mnu]
00530 set menu_height [winfo reqheight $mnu]
00531 set w_width [winfo width $w]
00532 set w_x [winfo rootx $w]
00533 set w_y [winfo rooty $w]
00534
00535 set x [expr ($w_x + $w_width) - $menu_width]
00536 set y [expr $w_y - ($menu_height + 4)]
00537
00538 tk_popup $mnu $x $y
00539
00540 }
00541
00542 ######################################################################
00543 # Returns 1 if a return key event should cause the find in files search
00544 # to begin.
00545 proc check_fif_for_return {} {
00546
00547 variable widgets
00548 variable user_exit_status
00549
00550 if {([llength [$widgets(fif_in) tokenget]] > 0) && \
00551 ([$widgets(fif_in) entryget] eq "") && \
00552 ([$widgets(fif_find) get] ne "")} {
00553 set user_exit_status 1
00554 return 1
00555 }
00556
00557 return 0
00558
00559 }
00560
00561 ######################################################################
00562 # Handles any preference changes to the Editor/WarningWidth setting.
00563 proc handle_warning_width_change {name1 name2 op} {
00564
00565 # Set the warning width to the specified value
00566 foreach txt [get_all_texts] {
00567 $txt configure -warnwidth [preferences::get Editor/WarningWidth]
00568 }
00569
00570 }
00571
00572 ######################################################################
00573 # Handles any preference changes to the Editor/MaxUndo setting.
00574 proc handle_max_undo {name1 name2 op} {
00575
00576 # Set the max_undo to the specified value
00577 foreach txt [get_all_texts] {
00578 $txt configure -maxundo [preferences::get Editor/MaxUndo]
00579 }
00580
00581 }
00582
00583 ######################################################################
00584 # Handles any preference changes to the Editor/HighlightMatchingChar setting.
00585 proc handle_matching_char {name1 name2 op} {
00586
00587 set_matching_char [preferences::get Editor/HighlightMatchingChar]
00588
00589 }
00590
00591 ######################################################################
00592 # Sets the -matchchar value on all displayed text widgets.
00593 proc set_matching_char {value} {
00594
00595 variable show_match_chars
00596
00597 # Save this value because it can be changed from Vim
00598 set show_match_chars $value
00599
00600 # Update all existing text widgets to the new value
00601 foreach txt [get_all_texts] {
00602 $txt configure -matchchar $value
00603 }
00604
00605 }
00606
00607 ######################################################################
00608 # Handles any preference changes to the Editor/HighlightMismatchingChar setting.
00609 proc handle_bracket_audit {name1 name2 op} {
00610
00611 # Get the preference value
00612 set value [preferences::get Editor/HighlightMismatchingChar]
00613
00614 # Set the -matchaudit option in each opened text widget to the given value
00615 foreach txt [get_all_texts] {
00616 $txt configure -matchaudit $value
00617 }
00618
00619 }
00620
00621 ######################################################################
00622 # Handles any changes to the Editor/RelativeLineNumbers preference
00623 # value. Updates all text widgets to the given value.
00624 proc handle_relative_line_numbers {name1 name2 op} {
00625
00626 set linemap_type [expr {[preferences::get Editor/RelativeLineNumbers] ? "relative" : "absolute"}]
00627
00628 foreach txt [get_all_texts] {
00629 $txt configure -linemap_type $linemap_type
00630 }
00631
00632 }
00633
00634 ######################################################################
00635 # Handles any changes to the Editor/LineNumberAlignment preference value.
00636 # Updates all text widgets to the given value.
00637 proc handle_line_number_alignment {name1 name2 op} {
00638
00639 set value [preferences::get Editor/LineNumberAlignment]
00640
00641 foreach txt [get_all_texts] {
00642 $txt configure -linemap_align $value
00643 }
00644
00645 }
00646
00647 ######################################################################
00648 # Handles any changes to the View/AllowTabScrolling preference variable.
00649 proc handle_allow_tab_scrolling {name1 name2 op} {
00650
00651 variable widgets
00652
00653 foreach pane [$widgets(nb_pw) panes] {
00654 $pane.tbf.tb configure -mintabwidth [expr {[preferences::get View/AllowTabScrolling] ? [lindex [$pane.tbf.tb configure -mintabwidth] 3] : 1}]
00655 }
00656
00657 }
00658
00659 ######################################################################
00660 # Handles any changes to the Editor/VimMode preference variable.
00661 proc handle_vim_mode {name1 name2 op} {
00662
00663 vim::set_vim_mode_all
00664
00665 }
00666
00667 ######################################################################
00668 # Updates all of the fonts in the text window to the given.
00669 proc handle_editor_font {name1 name2 op} {
00670
00671 # Update the size of the editor_font
00672 font configure editor_font {*}[font configure TkFixedFont] {*}[preferences::get Appearance/EditorFont]
00673
00674 }
00675
00676 ######################################################################
00677 # Changes the value of the automatic change working directory variable
00678 # and updates the current working directory with the current file
00679 # information.
00680 proc handle_auto_cwd {name1 name2 op} {
00681
00682 set_auto_cwd [preferences::get General/AutoChangeWorkingDirectory]
00683
00684 }
00685
00686 ######################################################################
00687 # Changes the value of the browse directory variable to match the value
00688 # specified in the preference file.
00689 proc handle_browse_directory {{name1 ""} {name2 ""} {op ""}} {
00690
00691 variable browse_dir
00692
00693 # Set the browse directory to the value
00694 set browse_dir [preferences::get General/DefaultFileBrowserDirectory]
00695
00696 # Adjust browse_dir to be last if the browse directory type was an actual pathname and it
00697 # does not exist.
00698 if {([lsearch [list last buffer current] $browse_dir] == -1) && ![file isdirectory $browse_dir]} {
00699 set browse_dir "last"
00700 }
00701
00702 }
00703
00704 ######################################################################
00705 # Handle any preference changes to the birdseye view status.
00706 proc handle_show_birdseye {name1 name2 op} {
00707
00708 if {[preferences::get View/ShowBirdsEyeView]} {
00709 foreach tab [files::get_tabs] {
00710 if {![winfo exists [get_info $tab tab txt2]]} {
00711 show_birdseye $tab
00712 }
00713 }
00714 } else {
00715 foreach tab [files::get_tabs] {
00716 if {![winfo exists [get_info $tab tab txt2]]} {
00717 hide_birdseye $tab
00718 }
00719 }
00720 }
00721
00722 }
00723
00724 ######################################################################
00725 # Handle any preference changes to the birdseye font size.
00726 proc handle_birdseye_font_size {name1 name2 op} {
00727
00728 set font_size [preferences::get View/BirdsEyeViewFontSize]
00729
00730 foreach txt [get_all_texts] {
00731 if {[string first "tf2" $txt] == -1} {
00732 if {[winfo exists [get_info $txt txt beye]]} {
00733 $beye configure -font "-size $font_size"
00734 }
00735 }
00736 }
00737
00738 }
00739
00740 ######################################################################
00741 # Handle any preference changes to the birdseye width.
00742 proc handle_birdseye_width {name1 name2 op} {
00743
00744 set width [preferences::get View/BirdsEyeViewWidth]
00745
00746 foreach txt [get_all_texts] {
00747 if {[string first "tf2" $txt] == -1} {
00748 if {[winfo exists [get_info $txt txt beye]]} {
00749 $beye configure -width $width
00750 }
00751 }
00752 }
00753
00754 }
00755
00756 ######################################################################
00757 # Handle any changes to the View/EnableCodeFolding preference value.
00758 proc handle_code_folding {name1 name2 op} {
00759
00760 set enable [preferences::get View/EnableCodeFolding]
00761
00762 foreach txt [get_all_texts] {
00763 folding::set_fold_enable $txt $enable
00764 }
00765
00766 }
00767
00768 ######################################################################
00769 # Handles any changes to the Appearance/CursorWidth preference value.
00770 proc handle_cursor_width {name1 name2 op} {
00771
00772 set width [preferences::get Appearance/CursorWidth]
00773
00774 foreach txt [get_all_texts] {
00775 if {![$txt cget -blockcursor]} {
00776 $txt configure -insertwidth $width
00777 }
00778 }
00779
00780 }
00781
00782 ######################################################################
00783 # Handles any changes to the Appearance/ExtraLineSpacing preference
00784 # value.
00785 proc handle_extra_line_spacing {name1 name2 op} {
00786
00787 set spacing [preferences::get Appearance/ExtraLineSpacing]
00788
00789 foreach txt [get_all_texts] {
00790 $txt configure -spacing2 $spacing -spacing3 $spacing
00791 }
00792
00793 }
00794
00795 ######################################################################
00796 # Sets the auto_cwd variable to the given boolean value.
00797 proc set_auto_cwd {value} {
00798
00799 variable auto_cwd
00800
00801 # Update the auto_cwd variable and if a file exists, update the current
00802 # working directory if auto_cwd is true.
00803 if {[set auto_cwd $value] && [files::get_file_num]} {
00804
00805 # Get the current file information
00806 get_info {} current fname buffer diff
00807
00808 # If the current file is neither a buffer nor a difference view, update
00809 # the current working directory and title bar.
00810 if {!$buffer && !$diff} {
00811 cd [file dirname $fname]
00812 set_title
00813 }
00814
00815 }
00816
00817 }
00818
00819 ######################################################################
00820 # Toggles the specified labelbutton.
00821 proc toggle_labelbutton {w} {
00822
00823 if {[$w cget -relief] eq "raised"} {
00824 $w configure -relief sunken
00825 } else {
00826 $w configure -relief raised
00827 }
00828
00829 }
00830
00831 ######################################################################
00832 # Returns 1 if the current buffer can be moved to the other pane.
00833 proc movable_to_other_pane {} {
00834
00835 variable widgets
00836
00837 return [expr {([llength [[get_info {} current tabbar] tabs]] > 1) || ([llength [$widgets(nb_pw) panes]] > 1)}]
00838
00839 }
00840
00841 ######################################################################
00842 # Sets up the tab popup menu.
00843 proc setup_tab_popup_menu {} {
00844
00845 variable widgets
00846 variable file_locked
00847 variable file_favorited
00848 variable pw_current
00849
00850 # Get the current information
00851 get_info {} current txt fname readonly lock diff tabbar remote buffer txt2 beye
00852
00853 # Set the file_locked and file_favorited variable
00854 set file_locked $lock
00855 set file_favorited [favorites::is_favorite $fname]
00856
00857 # Set the state of the menu items
00858 if {[files::get_file_num] > 1} {
00859 $widgets(menu) entryconfigure [msgcat::mc "Close All Other Tabs"] -state normal
00860 } else {
00861 $widgets(menu) entryconfigure [msgcat::mc "Close All Other Tabs"] -state disabled
00862 }
00863 if {[llength [$widgets(nb_pw) panes]] == 2} {
00864 if {[llength [$tabbar tabs]] > 1} {
00865 $widgets(menu) entryconfigure [msgcat::mc "Close Other Tabs In Pane"] -state normal
00866 } else {
00867 $widgets(menu) entryconfigure [msgcat::mc "Close Other Tabs In Pane"] -state disabled
00868 }
00869 $widgets(menu) entryconfigure [msgcat::mc "Close All Tabs In Pane"] -state normal
00870 } else {
00871 $widgets(menu) entryconfigure [msgcat::mc "Close Other Tabs In Pane"] -state disabled
00872 $widgets(menu) entryconfigure [msgcat::mc "Close All Tabs In Pane"] -state disabled
00873 }
00874 if {$diff} {
00875 $widgets(menu) entryconfigure [msgcat::mc "Hide Tab"] -state disabled
00876 } else {
00877 $widgets(menu) entryconfigure [msgcat::mc "Hide Tab"] -state normal
00878 }
00879 if {([llength [$tabbar tabs]] > 1) || ([llength [$widgets(nb_pw) panes]] > 1)} {
00880 $widgets(menu) entryconfigure [format "%s*" [msgcat::mc "Move"]] -state normal
00881 } else {
00882 $widgets(menu) entryconfigure [format "%s*" [msgcat::mc "Move"]] -state disabled
00883 }
00884 if {$readonly || $diff} {
00885 $widgets(menu) entryconfigure [msgcat::mc "Locked"] -state disabled
00886 } else {
00887 $widgets(menu) entryconfigure [msgcat::mc "Locked"] -state normal
00888 }
00889 if {![file exists $fname]} {
00890 $widgets(menu) entryconfigure [msgcat::mc "Favorited"] -state disabled
00891 $widgets(menu) entryconfigure [msgcat::mc "Show in Sidebar"] -state disabled
00892 } else {
00893 $widgets(menu) entryconfigure [msgcat::mc "Show in Sidebar"] -state normal
00894 $widgets(menu) entryconfigure [msgcat::mc "Favorited"] -state [expr {($diff || $buffer || ($remote ne "")) ? "disabled" : "normal"}]
00895 }
00896
00897 # Make the split pane and bird's eye indicators look correct
00898 set menus::show_split_pane [winfo exists $txt2]
00899 set menus::show_birdseye [winfo exists $beye]
00900
00901 # Handle plugin states
00902 plugins::menu_state $widgets(menu) tab_popup
00903
00904 }
00905
00906 ######################################################################
00907 # Shows the sidebar viewer.
00908 proc show_sidebar_view {} {
00909
00910 variable widgets
00911
00912 $widgets(pw) insert 0 $widgets(sb)
00913
00914 }
00915
00916 ######################################################################
00917 # Hides the sidebar viewer.
00918 proc hide_sidebar_view {} {
00919
00920 variable widgets
00921
00922 catch { $widgets(pw) forget $widgets(sb) }
00923
00924 }
00925
00926 ######################################################################
00927 # Shows the console.
00928 proc show_console_view {} {
00929
00930 if {[catch { tkcon show }]} {
00931 catch { console show }
00932 }
00933
00934 }
00935
00936 ######################################################################
00937 # Hides the console.
00938 proc hide_console_view {} {
00939
00940 if {[catch { tkcon hide }]} {
00941 catch { console hide }
00942 }
00943
00944 }
00945
00946 ######################################################################
00947 # Shows the tab bar.
00948 proc show_tab_view {} {
00949
00950 variable widgets
00951
00952 foreach nb [$widgets(nb_pw) panes] {
00953 if {[lsearch [pack slaves $nb] $nb.tbf] == -1} {
00954 pack $nb.tbf -before $nb.tf -fill x
00955 }
00956 }
00957
00958 }
00959
00960 ######################################################################
00961 # Hides the tab bar.
00962 proc hide_tab_view {} {
00963
00964 variable widgets
00965
00966 foreach nb [$widgets(nb_pw) panes] {
00967 if {[lsearch [pack slaves $nb] $nb.tbf] != -1} {
00968 pack forget $nb.tbf
00969 }
00970 }
00971
00972 }
00973
00974 ######################################################################
00975 # Shows the status bar.
00976 proc show_status_view {} {
00977
00978 variable widgets
00979
00980 catch { grid $widgets(info) }
00981
00982 update idletasks
00983
00984 }
00985
00986 ######################################################################
00987 # Hides the status view
00988 proc hide_status_view {} {
00989
00990 variable widgets
00991
00992 catch { grid remove $widgets(info) }
00993
00994 update idletasks
00995
00996 }
00997
00998 ######################################################################
00999 # Shows the line numbers.
01000 proc set_line_number_view {value} {
01001
01002 # Show the line numbers in the current editor
01003 [current_txt] configure -linemap $value
01004
01005 }
01006
01007 ######################################################################
01008 # Sets the minimum line number width of the line gutter to the given
01009 # value.
01010 proc set_line_number_width {val} {
01011
01012 variable numberwidth
01013
01014 set numberwidth $val
01015
01016 for {set i 0} {$i < [files::get_file_num]} {incr i} {
01017 [get_info $i fileindex txt] configure -linemap_minwidth $val
01018 }
01019
01020 }
01021
01022 ######################################################################
01023 # Updates the contents of the text within the tab as well as the
01024 # title bar information to match the given tab.
01025 proc update_tab {tab} {
01026
01027 get_info $tab tab tabbar fname
01028
01029 # Update the tab name
01030 $tabbar tab $tab -text " [file tail $fname]"
01031
01032 # Update the title if necessary
01033 set_title
01034
01035 }
01036
01037 ######################################################################
01038 # Save the window geometry to the geometry.dat file.
01039 proc save_session {} {
01040
01041 variable widgets
01042 variable last_opened
01043
01044 # Gather content to save
01045 set content(Geometry) [::window_geometry .]
01046 set content(Fullscreen) [wm attributes . -fullscreen]
01047 set content(CurrentWorkingDirectory) [pwd]
01048 set content(Sidebar) [sidebar::save_session]
01049 set content(Launcher) [launcher::save_session]
01050
01051 # Calculate the zoomed state
01052 switch [tk windowingsystem] {
01053 x11 {
01054 set content(Zoomed) [wm attributes . -zoomed]
01055 }
01056 default {
01057 set content(Zoomed) [expr {[wm state .] eq "zoomed"}]
01058 }
01059 }
01060
01061 foreach nb [$widgets(nb_pw) panes] {
01062
01063 set tabindex 0
01064 set current_tab ""
01065 set current_set 0
01066
01067 foreach tab [$nb.tbf.tb tabs] {
01068
01069 # Get the file tab information
01070 get_info $tab tab paneindex txt fname save_cmd lock readonly diff sidebar buffer remember remote txt2 beye encode
01071
01072 # If we need to forget this file, don't save it to the session
01073 if {!$remember || ($remote ne "")} {
01074 continue
01075 }
01076
01077 set finfo(pane) $paneindex
01078 set finfo(fname) $fname
01079 set finfo(savecommand) $save_cmd
01080 set finfo(lock) $lock
01081 set finfo(readonly) $readonly
01082 set finfo(diff) $diff
01083 set finfo(sidebar) $sidebar
01084 set finfo(buffer) $buffer
01085 set finfo(remember) $remember
01086 set finfo(encode) $encode
01087
01088 # Save the tab as a current tab if it's not a buffer
01089 if {!$finfo(buffer) && !$current_set} {
01090 set current_tab $tabindex
01091 if {[$nb.tbf.tb select] eq $tab} {
01092 set current_set 1
01093 }
01094 }
01095
01096 set finfo(tab) $tabindex
01097 set finfo(language) [syntax::get_language $txt]
01098 set finfo(indent) [indent::get_indent_mode $txt]
01099 set finfo(modified) 0
01100 set finfo(cursor) [$txt index insert]
01101 set finfo(xview) [lindex [$txt xview] 0]
01102 set finfo(yview) [lindex [$txt yview] 0]
01103 set finfo(beye) [winfo exists $beye]
01104 set finfo(split) [winfo exists $txt2]
01105
01106 # Add markers
01107 set finfo(markers) [list]
01108 foreach {mname mtxt pos} [markers::get_markers $tab] {
01109 lappend finfo(markers) $mname [lindex [split $pos .] 0]
01110 }
01111
01112 # Add diff data, if applicable
01113 if {$finfo(diff)} {
01114 set finfo(diffdata) [diff::get_session_data $txt]
01115 }
01116 lappend content(FileInfo) [array get finfo]
01117
01118 incr tabindex
01119
01120 }
01121
01122 # Set the current tab for the pane (if one exists)
01123 if {$current_tab ne ""} {
01124 lappend content(CurrentTabs) $current_tab
01125 }
01126
01127 }
01128
01129 # Get the last_opened list
01130 set content(LastOpened) $last_opened
01131
01132 # Return the content array
01133 return [array get content]
01134
01135 }
01136
01137 ######################################################################
01138 # Loads the geometry information (if it exists) and changes the current
01139 # window geometry to match the read value.
01140 proc load_session {info new} {
01141
01142 variable widgets
01143 variable last_opened
01144 variable pw_current
01145
01146 array set content [list \
01147 Geometry [wm geometry .] \
01148 CurrentWorkingDirectory [pwd] \
01149 Sidebar [list] \
01150 Launcher [list] \
01151 FileInfo [list] \
01152 CurrentTabs [list] \
01153 LastOpened "" \
01154 ]
01155
01156 array set content $info
01157
01158 array set finfo {
01159 xview 0
01160 yview 0
01161 cursor ""
01162 beye 0
01163 split 0
01164 }
01165
01166 # Put the state information into the rest of the GUI
01167 if {[info exists content(Fullscreen)] && $content(Fullscreen)} {
01168 wm attributes . -fullscreen 1
01169 } else {
01170 wm geometry . $content(Geometry)
01171 if {[info exists content(Zoomed)] && $content(Zoomed)} {
01172 switch [tk windowingsystem] {
01173 x11 { wm attributes . -zoomed 1 }
01174 default { wm state . zoomed }
01175 }
01176 }
01177 }
01178
01179 # Restore the "last_opened" list
01180 set last_opened $content(LastOpened)
01181
01182 # Load the session information into the launcher
01183 launcher::load_session $content(Launcher)
01184
01185 # If we are loading a new TKE session, exit now since we don't want to load the rest
01186 if {$new} return
01187
01188 # Load the session information into the sidebar
01189 sidebar::load_session $content(Sidebar)
01190
01191 # Set the current working directory to the saved value
01192 if {[file exists $content(CurrentWorkingDirectory)]} {
01193 cd $content(CurrentWorkingDirectory)
01194 }
01195
01196 # Put the list in order
01197 if {[llength $content(FileInfo)] > 0} {
01198 set ordered [lrepeat 2 [lrepeat [llength $content(FileInfo)] ""]]
01199 set i 0
01200 foreach finfo_list $content(FileInfo) {
01201 array set finfo $finfo_list
01202 lset ordered $finfo(pane) $finfo(tab) $i
01203 incr i
01204 }
01205 } else {
01206 set ordered [list "" ""]
01207 }
01208
01209 # If the second pane is necessary, create it now
01210 if {[llength $content(CurrentTabs)] == 2} {
01211 add_notebook
01212 }
01213
01214 # Add the tabs (in order) to each of the panes and set the current tab in each pane
01215 for {set pane 0} {$pane < [llength $content(CurrentTabs)]} {incr pane} {
01216 set pw_current $pane
01217 set tab ""
01218 foreach index [lindex $ordered $pane] {
01219 if {$index ne ""} {
01220 array set finfo [lindex $content(FileInfo) $index]
01221 if {[file exists $finfo(fname)]} {
01222 set tab [add_file $finfo(tab) $finfo(fname) \
01223 -savecommand $finfo(savecommand) -lock $finfo(lock) -readonly $finfo(readonly) \
01224 -diff $finfo(diff) -sidebar $finfo(sidebar) -lazy 1 \
01225 -xview $finfo(xview) -yview $finfo(yview) -cursor $finfo(cursor) -lang $finfo(language)]
01226 get_info $tab tab txt
01227 if {[info exists finfo(indent)]} {
01228 indent::set_indent_mode $txt $finfo(indent)
01229 }
01230 if {[info exists finfo(encode)]} {
01231 set_encoding $tab $finfo(encode)
01232 }
01233 if {$finfo(diff) && [info exists finfo(diffdata)]} {
01234 diff::set_session_data $txt $finfo(diffdata)
01235 }
01236 if {$finfo(split)} {
01237 show_split_pane $tab
01238 }
01239 if {$finfo(beye)} {
01240 show_birdseye $tab
01241 }
01242 if {[info exists finfo(markers)]} {
01243 foreach {mname line} $finfo(markers) {
01244 markers::add $tab line $line $mname
01245 }
01246 }
01247 }
01248 }
01249 }
01250 if {$tab ne ""} {
01251 if {[catch { get_info [lindex $content(CurrentTabs) $pane] tabindex tabbar tab }]} {
01252 set_current_tab [get_info $pane paneindex tabbar] $tab
01253 } else {
01254 set_current_tab $tabbar $tab
01255 }
01256 }
01257 }
01258
01259 }
01260
01261 ######################################################################
01262 # Makes the next tab in the notebook viewable.
01263 proc next_tab {} {
01264
01265 # Get the location information for the current tab in the current pane
01266 get_info {} current tabbar tabindex
01267
01268 # If the new tab index is at the end, circle to the first tab
01269 if {[incr tabindex] == [$tabbar index end]} {
01270 set tabindex 0
01271 }
01272
01273 # Select the next tab
01274 set_current_tab $tabbar [lindex [$tabbar tabs -shown] $tabindex]
01275
01276 }
01277
01278 ######################################################################
01279 # Makes the previous tab in the notebook viewable.
01280 proc previous_tab {} {
01281
01282 # Get the location information for the current tab in the current pane
01283 get_info {} current tabbar tabindex
01284
01285 # If the new tab index is at the less than 0, circle to the last tab
01286 if {[incr tabindex -1] == -1} {
01287 set tabindex [expr [$tabbar index end] - 1]
01288 }
01289
01290 # Select the previous tab
01291 set_current_tab $tabbar [lindex [$tabbar tabs -shown] $tabindex]
01292
01293 }
01294
01295 ######################################################################
01296 # Makes the last viewed tab in the notebook viewable.
01297 proc last_tab {} {
01298
01299 # Get the current tabbar
01300 get_info {} current tabbar
01301
01302 # Select the last tab
01303 set_current_tab $tabbar [lindex [$tabbar tabs -shown] [$tabbar index last]]
01304
01305 }
01306
01307 ######################################################################
01308 # If more than one pane is displayed, sets the current pane to the other
01309 # pane.
01310 proc next_pane {} {
01311
01312 variable widgets
01313 variable pw_current
01314
01315 # If we have more than one pane, go to it
01316 if {[llength [$widgets(nb_pw) panes]] > 1} {
01317 set pw_current [expr $pw_current ^ 1]
01318 get_info {} current tabbar tab
01319 set_current_tab $tabbar $tab
01320 }
01321
01322 }
01323
01324 ######################################################################
01325 # Returns the number of panes.
01326 proc panes {} {
01327
01328 variable widgets
01329
01330 return [llength [$widgets(nb_pw) panes]]
01331
01332 }
01333
01334 ######################################################################
01335 # Returns the number of tabs in the current pane.
01336 proc tabs_in_pane {} {
01337
01338 return [llength [[get_info {} current tabbar] tabs]]
01339
01340 }
01341
01342 ######################################################################
01343 # Aligns the current insertion cursors in both panes to the same Y
01344 # pixel value.
01345 proc align_panes {} {
01346
01347 align_lines [get_info 0 paneindex txt] [get_info 1 paneindex txt] insert insert 1
01348
01349 }
01350
01351 ######################################################################
01352 # This is called by set_current_tab to update the pane sync state.
01353 proc pane_sync_tab_change {} {
01354
01355 variable synced
01356 variable synced_key
01357
01358 # Unselect the current key
01359 if {$synced_key ne ""} {
01360 catch {
01361 [winfo parent [lindex $synced_key 0]].vb configure -usealt 0
01362 [winfo parent [lindex $synced_key 1]].vb configure -usealt 0
01363 }
01364 menus::set_pane_sync_indicator 0
01365 set synced_key ""
01366 }
01367
01368 # Set the new pair
01369 catch {
01370
01371 # Get the current text widgets
01372 set txt1 [get_info 0 paneindex txt]
01373 set txt2 [get_info 1 paneindex txt]
01374
01375 # Create the synced key
01376 set key "$txt1 $txt2"
01377
01378 if {[info exists synced($key)]} {
01379
01380 menus::set_pane_sync_indicator 1
01381
01382 set synced_key $key
01383
01384 [winfo parent $txt1].vb configure -usealt 1
01385 [winfo parent $txt2].vb configure -usealt 1
01386
01387 }
01388
01389 }
01390
01391 }
01392
01393 ######################################################################
01394 # Tracks the two displayed text widgets, keeping their views in line
01395 # sync with each other. If initialize is set, we will capture the
01396 # top lines.
01397 proc set_pane_sync {value} {
01398
01399 variable synced
01400 variable synced_key
01401
01402 # Get the displayed text widgets
01403 set txt1 [get_info 0 paneindex txt]
01404 set txt2 [get_info 1 paneindex txt]
01405
01406 # Set the menu indicator to the given value
01407 menus::set_pane_sync_indicator $value
01408
01409 if {$value} {
01410
01411 # Record the synced_key (if this value is the empty string, we are not currently synced)
01412 set synced_key "$txt1 $txt2"
01413
01414 # Record the text widgets that we are sync'ing
01415 set synced($synced_key) [list [$txt1 index @0,0] [$txt2 index @0,0]]
01416
01417 # Set the scrollbar colors to indicate that we are synced
01418 [winfo parent $txt1].vb configure -usealt 1
01419 [winfo parent $txt2].vb configure -usealt 1
01420
01421 } else {
01422
01423 # Return the scrollbar colors to their normal colors
01424 [winfo parent [lindex $synced_key 0]].vb configure -usealt 0
01425 [winfo parent [lindex $synced_key 1]].vb configure -usealt 0
01426
01427 # Delete the synced recording
01428 unset synced($synced_key)
01429
01430 # Clear the synced key
01431 set synced_key ""
01432
01433 }
01434
01435 }
01436
01437 ######################################################################
01438 # Called whenever one of the synced text widgets yview changes. Causes
01439 # the other text widget to stay in sync.
01440 proc sync_scroll {txt yscroll} {
01441
01442 variable synced
01443 variable synced_key
01444 variable synced_count
01445 variable synced_txt
01446
01447 # If we are not currently synced, return now
01448 if {($synced_key eq "") || (($synced_txt ne $txt) && ($synced_txt ne ""))} {
01449 set synced_txt ""
01450 return
01451 }
01452
01453 set top [$txt index @0,0]
01454 lassign $synced_key txt0 txt1
01455 lassign $synced($synced_key) top0 top1
01456
01457 if {$txt eq $txt0} {
01458 set line_diff [$txt count -lines $top0 $top]
01459 align_lines $txt0 $txt1 $top [$txt1 index "$top1+${line_diff}l"] 0
01460 } else {
01461 set line_diff [$txt count -lines $top1 $top]
01462 align_lines $txt1 $txt0 $top [$txt0 index "$top0+${line_diff}l"] 0
01463 }
01464
01465 set synced_txt $txt
01466
01467 }
01468
01469 ######################################################################
01470 # Sync the birdseye text widget.
01471 proc sync_birdseye_helper {tab top} {
01472
01473 variable be_after_id
01474
01475 # Get the current tab
01476 if {[winfo exists [get_info $tab tab beye]]} {
01477 $beye yview moveto $top
01478 }
01479
01480 set be_after_id($tab) ""
01481
01482 }
01483
01484 ######################################################################
01485 # Sync the birdseye text widget.
01486 proc sync_birdseye {tab top} {
01487
01488 variable be_after_id
01489 variable be_ignore
01490
01491 # If bird's eye view is not enabled, exit immediately
01492 if {![info exists be_after_id($tab)]} {
01493 return
01494 }
01495
01496 if {$be_after_id($tab) ne ""} {
01497 after cancel $be_after_id($tab)
01498 }
01499
01500 if {$be_ignore($tab) == 0} {
01501 set be_after_id($tab) [after 50 [list gui::sync_birdseye_helper $tab $top]]
01502 }
01503
01504 set be_ignore($tab) 0
01505
01506 }
01507
01508 ######################################################################
01509 # Sets the yview of the given text widget (called by the yscrollbar)
01510 # and adjusts the scroll of the other pane if sync scrolling is enabled.
01511 proc yview {tab txt args} {
01512
01513 # Return the yview information
01514 if {[llength $args] == 0} {
01515 return [$txt yview]
01516
01517 # Otherwise, set the yview given the arguments
01518 } else {
01519 $txt yview {*}$args
01520 sync_birdseye $tab [lindex $args 1]
01521 sync_scroll $txt 0
01522 }
01523
01524 }
01525
01526 ######################################################################
01527 # Implements yscrollcommand for an editing buffer. Adjusts the scrollbar
01528 # position and performs synchronized scrolling, if enabled.
01529 proc yscrollcommand {tab txt vb args} {
01530
01531 # Set the vertical scrollbar position
01532 $vb set {*}$args
01533
01534 # Set birdseye view
01535 sync_birdseye $tab [lindex $args 0]
01536
01537 # Perform sync scrolling, if necessary
01538 sync_scroll $txt 1
01539
01540 }
01541
01542 ######################################################################
01543 # Aligns the given lines.
01544 proc align_lines {txt1 txt2 line1 line2 adjust_txt1} {
01545
01546 if {[set bbox1 [$txt1 bbox $line1]] eq ""} {
01547 $txt1 see $line1
01548 set bbox1 [$txt1 bbox $line1]
01549 }
01550 if {[set bbox2 [$txt2 bbox $line2]] eq ""} {
01551 $txt2 see $line2
01552 set bbox2 [$txt2 bbox $line2]
01553 }
01554
01555 # Attempt to line up the right pane to the left pane
01556 $txt2 yview scroll [expr [lindex $bbox2 1] - [lindex $bbox1 1]] pixels
01557
01558 # Check to see if the two are aligned, if not then attempt to align the left line to the right
01559 if {$adjust_txt1} {
01560 if {[lindex $bbox1 1] != [lindex [$txt2 bbox $line2] 1]} {
01561 $txt1 yview scroll [expr [lindex $bbox1 1] - [lindex $bbox2 1]] pixels
01562 }
01563 }
01564
01565 }
01566
01567 ######################################################################
01568 # Adds the given filename to the list of most recently opened files.
01569 proc add_to_recently_opened {fname} {
01570
01571 variable last_opened
01572
01573 if {[set index [lsearch $last_opened $fname]] != -1} {
01574 set last_opened [lreplace $last_opened $index $index]
01575 }
01576
01577 set last_opened [lrange [list $fname {*}$last_opened] 0 20]
01578
01579 }
01580
01581 ######################################################################
01582 # Returns the last_opened list contents.
01583 proc get_last_opened {} {
01584
01585 variable last_opened
01586
01587 return $last_opened
01588
01589 }
01590
01591 ######################################################################
01592 # Clears the last_opened list contents.
01593 proc clear_last_opened {} {
01594
01595 variable last_opened
01596
01597 set last_opened [list]
01598
01599 }
01600
01601 ######################################################################
01602 # Selects all of the text in the current text widget.
01603 proc select_all {} {
01604
01605 # Get the current text widget
01606 set txt [current_txt]
01607
01608 # Set the selection to include everything
01609 $txt tag add sel 1.0 end
01610
01611 }
01612
01613 ######################################################################
01614 # Returns true if we have only a single tab that has not been modified
01615 # or named.
01616 proc untitled_check {} {
01617
01618 variable widgets
01619
01620 if {[files::get_file_num] == 1} {
01621 get_info {} current fname buffer txt
01622 if {($fname eq "Untitled") && $buffer && ([vim::get_cleaned_content $txt] eq "")} {
01623 return 1
01624 }
01625 }
01626
01627 return 0
01628
01629 }
01630
01631 ######################################################################
01632 # Adds a new buffer to the editor pane. Buffers require a save command
01633 # (executed when the buffer is saved). Buffers do not save to nor read
01634 # from files. Returns the path to the inserted tab.
01635 #
01636 # Several options are available:
01637 # -lock <bool> Initial lock setting.
01638 # -readonly <bool> Set if file should not be saveable.
01639 # -gutters <list> Creates a gutter in the editor. The contents of list are as follows:
01640 # {name {{symbol_name {symbol_tag_options+}}+}}+
01641 # For a list of valid symbol_tag_options, see the options available for
01642 # tags in a text widget.
01643 # -other <bool> If true, adds the file to the other pane.
01644 # -tags <list> List of plugin btags that will only get applied to this text widget.
01645 # -lang <language> Specifies the language to use for syntax highlighting.
01646 # -background <bool> If true, keeps the current tab displayed.
01647 # -remote <name> If specified, specifies that the buffer should be saved to the given
01648 # remote server name.
01649 proc add_buffer {index name save_command args} {
01650
01651 variable widgets
01652 variable pw_current
01653 variable undo_count
01654
01655 # Handle options
01656 array set opts [list \
01657 -lock 0 \
01658 -readonly 0 \
01659 -sidebar 0 \
01660 -gutters [list] \
01661 -other 0 \
01662 -tags [list] \
01663 -lang "" \
01664 -background 0 \
01665 -remote ""
01666 ]
01667 array set opts $args
01668
01669 # Perform untitled tab check
01670 if {[untitled_check]} {
01671 if {($name ne "Untitled") && !$opts(-other)} {
01672 close_tab [get_info {} current tab] -keeptab 0
01673 }
01674 }
01675
01676 # If the file is already loaded, display the tab
01677 if {($name ne "Untitled") && ([set file_index [files::get_index $name $opts(-remote) -buffer 1]] != -1)} {
01678
01679 if {!$opts(-background)} {
01680 get_info $file_index fileindex tabbar tab
01681 set_current_tab $tabbar $tab
01682 }
01683
01684 } else {
01685
01686 if {$opts(-other)} {
01687
01688 # If the other pane does not exist, add it
01689 if {[llength [$widgets(nb_pw) panes]] == 1} {
01690 add_notebook
01691 }
01692
01693 # Set the current pane to the other one
01694 set pw_current [expr $pw_current ^ 1]
01695
01696 }
01697
01698 # Adjust the index (if necessary)
01699 set index [adjust_insert_tab_index $index $name]
01700
01701 # Get the tabbar
01702 get_info $pw_current paneindex tabbar
01703
01704 # Get the current index
01705 set tab [insert_tab $tabbar $index $name -gutters $opts(-gutters) -tags $opts(-tags) -lang $opts(-lang)]
01706
01707 # Create the file info structure
01708 files::add $name $tab \
01709 -save_cmd $save_command \
01710 -lock $opts(-lock) \
01711 -readonly $opts(-readonly) \
01712 -sidebar $opts(-sidebar) \
01713 -buffer 1 \
01714 -gutters $opts(-gutters) \
01715 -tags $opts(-tags) \
01716 -remote $opts(-remote)
01717
01718 # Get the current text widget
01719 get_info $tab tab txt tabbar
01720
01721 # Perform an insertion adjust, if necessary
01722 if {[vim::in_vim_mode $txt.t]} {
01723 vim::adjust_insert $txt.t
01724 }
01725
01726 # Change the tab text
01727 $tabbar tab $tab -text " [file tail $name]"
01728
01729 # Add the file's directory to the sidebar and highlight it
01730 if {$opts(-sidebar)} {
01731 sidebar::add_directory [file normalize [file dirname $name]] -remote $opts(-remote)
01732 # sidebar::highlight_filename $name 0
01733 }
01734
01735 # Make this tab the currently displayed tab
01736 if {!$opts(-background)} {
01737 set_current_tab $tabbar $tab
01738 }
01739
01740 set undo_count($tab) 0
01741
01742 }
01743
01744 # Set the tab image for the current file
01745 set_tab_image $tab
01746
01747 return $tab
01748
01749 }
01750
01751 ######################################################################
01752 # Adds a new file to the editor pane.
01753 #
01754 # Several options are available:
01755 # -lock <bool> Initial lock setting.
01756 # -readonly <bool> Set if file should not be saveable.
01757 # -sidebar <bool> Specifies if file/directory should be added to the sidebar.
01758 # -gutters <list> Creates a gutter in the editor. The contents of list are as follows:
01759 # {name {{symbol_name {symbol_tag_options+}}+}}+
01760 # For a list of valid symbol_tag_options, see the options available for
01761 # tags in a text widget.
01762 # -other <bool> If true, adds the file to the other pane.
01763 # -tags <list> List of plugin btags that will only get applied to this text widget.
01764 # -name <path> Starting name of file (the file doesn't currently exist).
01765 proc add_new_file {index args} {
01766
01767 array set opts {
01768 -name "Untitled"
01769 -save_as ""
01770 }
01771 array set opts $args
01772
01773 # Add the buffer
01774 return [add_buffer $index $opts(-name) {eval files::save_new_file $opts(-save_as)} {*}$args]
01775
01776 }
01777
01778 ######################################################################
01779 # Creates a new tab for the given filename specified at the given index
01780 # tab position. Returns the path to the inserted tab.
01781 #
01782 # Several options are available:
01783 # -savecommand <command> Optional command that is run when the file is saved.
01784 # -lock <bool> Initial lock setting.
01785 # -readonly <bool> Set if file should not be saveable.
01786 # -sidebar <bool> Specifies if file/directory should be added to the sidebar.
01787 # -gutters <list> Creates a gutter in the editor. The contents of list are as follows:
01788 # {name {{symbol_name {symbol_tag_options+}}+}}+
01789 # For a list of valid symbol_tag_options, see the options available for
01790 # tags in a text widget.
01791 # -diff <bool> Specifies if we need to do a diff of the file.
01792 # -other <bool> If true, adds the file to the other editing pane.
01793 # -tags <list> List of plugin btags that will only attach to this text widget.
01794 # -remote <name> Name of remote connection associated with the file.
01795 proc add_file {index fname args} {
01796
01797 variable widgets
01798 variable pw_current
01799 variable last_opened
01800
01801 # Handle arguments
01802 array set opts {
01803 -savecommand ""
01804 -lock 0
01805 -readonly 0
01806 -sidebar 1
01807 -gutters {}
01808 -diff 0
01809 -other 0
01810 -tags {}
01811 -lazy 0
01812 -remember 1
01813 -remote ""
01814 -cursor 1.0
01815 -xview 0
01816 -yview 0
01817 -lang ""
01818 }
01819 array set opts $args
01820
01821 # If have a single untitled tab in view, close it before adding the file
01822 if {[untitled_check] && !$opts(-other)} {
01823 close_tab [get_info {} current tab] -keeptab 0
01824 }
01825
01826 # If the file is already loaded, display the tab
01827 if {[set file_index [files::get_index $fname $opts(-remote) -diff $opts(-diff)]] != -1} {
01828
01829 # Get the tab associated with the given file index
01830 get_info $file_index fileindex tabbar tab
01831
01832 # Otherwise, load the file in a new tab
01833 } else {
01834
01835 if {$opts(-other)} {
01836
01837 # If the other pane does not exist, add it
01838 if {[llength [$widgets(nb_pw) panes]] == 1} {
01839 add_notebook
01840 }
01841
01842 # Set the current pane to the other one
01843 set pw_current [expr $pw_current ^ 1]
01844
01845 }
01846
01847 # Adjust the index (if necessary)
01848 set index [adjust_insert_tab_index $index [file tail $fname]]
01849
01850 # Get the tabbar
01851 get_info $pw_current paneindex tabbar
01852
01853 # Add the tab to the editor frame
01854 set tab [insert_tab $tabbar $index $fname -diff $opts(-diff) -gutters $opts(-gutters) -tags $opts(-tags) -lang $opts(-lang)]
01855
01856 # Create the file information
01857 files::add $fname $tab \
01858 -save_cmd $opts(-savecommand) \
01859 -lock $opts(-lock) \
01860 -readonly $opts(-readonly) \
01861 -sidebar $opts(-sidebar) \
01862 -buffer 0 \
01863 -gutters $opts(-gutters) \
01864 -diff $opts(-diff) \
01865 -tags $opts(-tags) \
01866 -loaded 0 \
01867 -remember $opts(-remember) \
01868 -remote $opts(-remote) \
01869 -xview $opts(-xview) \
01870 -yview $opts(-yview) \
01871 -cursor $opts(-cursor)
01872
01873 # Run any plugins that should run when a file is opened
01874 plugins::handle_on_open [expr [files::get_file_num] - 1]
01875
01876 }
01877
01878 # Add the file's directory to the sidebar and highlight it
01879 if {$opts(-sidebar)} {
01880 sidebar::add_directory [file dirname $fname] -remote $opts(-remote)
01881 sidebar::highlight_filename $fname [expr ($opts(-diff) * 2) + 1]
01882 }
01883
01884 # Make this tab the currently displayed tab
01885 if {!$opts(-lazy)} {
01886 set_current_tab $tabbar $tab
01887 }
01888
01889 # Set the tab image for the current file
01890 set_tab_image $tab
01891
01892 return $tab
01893
01894 }
01895
01896 ######################################################################
01897 # Inserts the file information and sets the
01898 proc add_tab_content {tab} {
01899
01900 variable undo_count
01901
01902 # Get some of the file information
01903 get_info $tab tab tabbar txt fname diff loaded lock readonly xview yview cursor remember
01904
01905 # Indicate that we are loading the tab
01906 $tabbar tab $tab -busy 1
01907
01908 if {!$loaded && [files::get_file $tab contents]} {
01909
01910 # If we are locked, make sure that we enable the text widget for insertion
01911 if {$lock || $readonly} {
01912 $txt configure -state normal
01913 }
01914
01915 # Delete any dspace characters
01916 vim::remove_dspace $txt
01917
01918 # Initialize the undo count
01919 set undo_count($tab) 0
01920
01921 # Check the highlightable value
01922 check_highlightable $txt $contents
01923
01924 # Insert the file contents
01925 $txt fastinsert end $contents
01926
01927 # Highlight text and add update code folds
01928 $txt syntax highlight 1.0 end
01929 $txt see 1.0
01930
01931 # Add any previous markers saved for this text widget
01932 markers::tagify $tab
01933
01934 # Check brackets
01935 ctext::checkAllBrackets $txt
01936
01937 # Change the text to unmodified
01938 $txt edit reset
01939 files::set_info $tab tab modified 0
01940
01941 # Set the insertion mark to the first position
01942 ::tk::TextSetCursor $txt.t $cursor
01943
01944 # Set the yview
01945 $txt xview moveto $xview
01946 $txt yview moveto $yview
01947
01948 # Perform an insertion adjust, if necessary
01949 if {[vim::in_vim_mode $txt.t]} {
01950 vim::adjust_insert $txt.t
01951 }
01952
01953 # Add the file to the list of recently opened files
01954 if {$remember} {
01955 add_to_recently_opened $fname
01956 }
01957
01958 # Parse Vim modeline information, if needed
01959 vim::parse_modeline $txt
01960
01961 # If a diff command was specified, run and parse it now
01962 if {$diff} {
01963 diff::show $txt
01964 }
01965
01966 # If we are locked, make sure that we disable the text widget
01967 if {$lock || $readonly} {
01968 $txt configure -state disabled
01969 }
01970
01971 # Update tab
01972 update_tab $tab
01973
01974 }
01975
01976 # Specify that we have completed loading the tab
01977 $tabbar tab $tab -busy 0
01978
01979 }
01980
01981 ######################################################################
01982 # Returns true if the given file contents should be highlighted. We
01983 # make this decision by examining the length of each line. If a line
01984 # exceeds a given length, we know this will cause problems with the
01985 # Tk text widget.
01986 proc check_highlightable {txt contents} {
01987
01988 variable widgets
01989
01990 set highlightable 1
01991
01992 foreach line [split $contents \n] {
01993 if {[string length $line] > 8192} {
01994 set highlightable 0
01995 break;
01996 }
01997 }
01998
01999 # Set the highlight value
02000 $txt configure -highlight $highlightable
02001
02002 # Update the auto-indentation value
02003 indent::update_auto_indent $txt.t $widgets(info_indent)
02004
02005 }
02006
02007 ######################################################################
02008 # Add a list of files to the editor panel and raise the window to
02009 # make it visible.
02010 proc add_files_and_raise {host index args} {
02011
02012 # Add the list of files to the editor panel.
02013 foreach fname [lreverse $args] {
02014 if {[file isdirectory $fname]} {
02015 sidebar::add_directory [files::normalize $host $fname]
02016 } elseif {![::check_file_for_import $fname]} {
02017 add_file $index [files::normalize $host $fname]
02018 }
02019 }
02020
02021 # Raise ourselves
02022 raise_window
02023
02024 }
02025
02026 ######################################################################
02027 # Raise ourself to the top.
02028 proc raise_window {} {
02029
02030 variable widgets
02031
02032 # If the notebook widget doesn't exist this will cause an error to occur.
02033 if {$widgets(nb_pw) ne ""} {
02034
02035 wm withdraw .
02036 wm deiconify .
02037
02038 }
02039
02040 }
02041
02042 ######################################################################
02043 # Update the file located at the given notebook index.
02044 proc update_file {file_index} {
02045
02046 variable undo_count
02047
02048 # Get the file information
02049 get_info $file_index fileindex tabbar tab txt fname diff lock remote
02050
02051 # If the editor is a difference view and is not updateable, stop now
02052 if {$diff && ![diff::updateable $txt]} {
02053 return
02054 }
02055
02056 # Get the current insertion index
02057 set insert_index [$txt index insert]
02058
02059 # Delete the text widget
02060 $txt configure -state normal
02061 $txt delete 1.0 end
02062
02063 if {[files::get_file $tab contents]} {
02064
02065 # Updat the highlightability attribute of the text widget
02066 check_highlightable $txt $contents
02067
02068 # Read the file contents and insert them
02069 $txt insert end $contents
02070
02071 # Change the tab text
02072 $tabbar tab $tab -text " [file tail $fname]"
02073
02074 # Update the title bar (if necessary)
02075 set_title
02076
02077 # Change the text to unmodified
02078 $txt edit reset
02079 set undo_count($txt) 0
02080 files::set_info $file_index fileindex modified 0
02081
02082 # Set the insertion mark to the first position
02083 ::tk::TextSetCursor $txt.t $insert_index
02084 if {[vim::in_vim_mode $txt.t]} {
02085 vim::adjust_insert $txt.t
02086 }
02087
02088 # If a diff command was specified, run and parse it now
02089 if {$diff} {
02090 diff::show $txt
02091 }
02092
02093 # Allow plugins to be run on update
02094 plugins::handle_on_update $file_index
02095
02096 }
02097
02098 # If we are locked, set our state back to disabled
02099 if {$lock} {
02100 $txt configure -state disabled
02101 }
02102
02103 }
02104
02105 ######################################################################
02106 # Updates the currently displayed file.
02107 proc update_current {} {
02108
02109 get_info {} current fileindex tab
02110
02111 # Update the file
02112 update_file $fileindex
02113
02114
02115
02116 }
02117
02118 ######################################################################
02119 # Prompts the user for a file save name. Returns the name of the selected
02120 # filename; otherwise, returns the empty string to indicate that no
02121 # filename was selected.
02122 proc prompt_for_save {} {
02123
02124 # Get the directory of the current file
02125 set dirname [gui::get_browse_directory]
02126
02127 # Get the list of save options
02128 set save_opts [list]
02129 if {[llength [set extensions [syntax::get_extensions]]] > 0} {
02130 lappend save_opts -defaultextension [lindex $extensions 0]
02131 }
02132
02133 # Get the save file from the user
02134 return [tk_getSaveFile {*}$save_opts -parent . -title [msgcat::mc "Save As"] -initialdir $dirname]
02135
02136 }
02137
02138 ######################################################################
02139 # Performs a forced pre-save operation for the given filename.
02140 proc save_prehandle {fname save_as force pperms} {
02141
02142 upvar $pperms perms
02143
02144 set perms ""
02145
02146 if {[file exists $fname]} {
02147 if {$save_as eq ""} {
02148 if {![file writable $fname]} {
02149 if {$force} {
02150 set perms [file attributes $fname -permissions]
02151 if {[catch { file attributes $fname -permissions 700 } rc]} {
02152 set_info_message [msgcat::mc "No write permissions. Use '!' to force write."]
02153 return 0
02154 }
02155 } else {
02156 set_info_message [msgcat::mc "No write permissions. Use '!' to force write."]
02157 return 0
02158 }
02159 }
02160 } elseif {!$force} {
02161 set_info_message [msgcat::mc "File already exists. Use '!' to force an overwrite"]
02162 return 0
02163 }
02164 }
02165
02166 return 1
02167
02168 }
02169
02170 ######################################################################
02171 # Performs a forced post-save operation for the given filename.
02172 proc save_posthandle {fname perms} {
02173
02174 if {$perms ne ""} {
02175 catch { file attributes $fname -permissions $perms }
02176 }
02177
02178 return 1
02179
02180 }
02181
02182 ######################################################################
02183 # Sets the EOL translation setting for the current file to the given value.
02184 proc set_current_eol_translation {value} {
02185
02186 # Get the file index of the current file
02187 files::set_info [get_info {} current fileindex] fileindex eol $value
02188
02189 }
02190
02191 ######################################################################
02192 # Sets the current text status modification value to the specified value
02193 # and updates the titlebar and tabbar
02194 proc set_current_modified {value} {
02195
02196 # Get the current file information
02197 get_info {} current tabbar tab txt fname
02198
02199 # Set the file modified status to the given value
02200 files::set_info $tab tab modified $value
02201
02202 # Set the text widget status
02203 if {$value == 0} {
02204 $txt edit modified $value
02205 }
02206
02207 # Update the current tab text
02208 $tabbar tab $tab -text [format "%s %s" [expr {$value ? " *" : ""}] [file tail $fname]]
02209
02210 # Update the title
02211 set_title
02212
02213 }
02214
02215 ######################################################################
02216 # This is called whenever we undo/redo. Checks to see if the current
02217 # buffer should be indicated as being not modified.
02218 proc check_for_modified {txtt} {
02219
02220 variable undo_count
02221
02222 get_info [winfo parent $txtt] txt tabbar tab fname
02223
02224 if {$undo_count($tab) == [$txtt edit undocount]} {
02225 files::set_info $tab tab modified 0
02226 $txtt edit modified 0
02227 $tabbar tab $tab -text [format " %s" [file tail $fname]]
02228 set_title
02229 }
02230
02231 }
02232
02233 ######################################################################
02234 # Saves the current tab contents. Returns 1 if the save was successful;
02235 # otherwise, returns a value of 0.
02236 proc save_current {args} {
02237
02238 variable undo_count
02239
02240 array set opts {
02241 -force 0
02242 -save_as ""
02243 -remote ""
02244 }
02245 array set opts $args
02246
02247 # Get current information
02248 get_info {} current tabbar tab txt fileindex fname buffer save_cmd diff buffer mtime sidebar lang
02249
02250 # If the current file is a buffer and it has a save command, run the save command
02251 if {$buffer && ($save_cmd ne "")} {
02252
02253 # Execute the save command. If it errors or returns a value of 0, return immediately
02254 if {[catch { {*}$save_cmd $fileindex } rc]} {
02255 return 0
02256 } elseif {$rc == 0} {
02257 set_current_modified 0
02258 return 1
02259 }
02260
02261 # Retrieve some values in case they changed in the save command
02262 get_info {} current fname buffer save_cmd
02263
02264 }
02265
02266 # Get the difference mode of the current file
02267 set matching_index -1
02268
02269 # If a save_as name is specified, change the filename
02270 if {$opts(-save_as) ne ""} {
02271
02272 # Add the file to the sidebar and indicate that it is opened
02273 sidebar::highlight_filename $fname [expr $diff * 2]
02274 set matching_index [files::get_index $opts(-save_as) $opts(-remote)]
02275
02276 # Set the filename, remote tag indicator and set the tab attributes to match
02277 # the same as a file
02278 files::set_info $fileindex fileindex \
02279 fname [set fname [file normalize $opts(-save_as)]] \
02280 remote [set remote $opts(-remote)] \
02281 readonly 0 buffer 0 remember 1
02282
02283 # Update the tab image to reflect that fact that we not readonly
02284 set_tab_image $tab
02285
02286 # If the current file doesn't have a filename, allow the user to set it
02287 } elseif {$buffer || $diff} {
02288
02289 if {[set sfile [prompt_for_save]] eq ""} {
02290 return 0
02291 } else {
02292 set matching_index [files::get_index $sfile ""]
02293 files::set_info $fileindex fileindex fname [set fname $sfile]
02294 }
02295
02296 }
02297
02298 # Run the on_save plugins
02299 plugins::handle_on_save $fileindex
02300
02301 # If we need to do a force write, do it now
02302 set perms ""
02303 if {![save_prehandle $fname $opts(-save_as) $opts(-force) perms]} {
02304 return 0
02305 }
02306
02307 # If the file already exists in one of the open tabs, close it now
02308 if {$matching_index != -1} {
02309 close_tab [files::get_info $matching_index fileindex tab] -keeptab 0 -check 0
02310 }
02311
02312 # Save the file contents
02313 if {![files::set_file $tab [scrub_text $txt]]} {
02314 return 0
02315 }
02316
02317 # If we need to do a force write, do it now
02318 if {![save_posthandle $fname $perms]} {
02319 return 0
02320 }
02321
02322 # If the file doesn't have a timestamp, it's a new file so add and highlight it in the sidebar
02323 if {($mtime eq "") || ($opts(-save_as) ne "")} {
02324
02325 # Add the filename to the most recently opened list
02326 add_to_recently_opened $fname
02327
02328 # If it is okay to add the file to the sidebar, do it now
02329 if {$sidebar} {
02330 sidebar::insert_file [sidebar::add_directory [file dirname $fname] -remote $opts(-remote)] $fname $opts(-remote)
02331 sidebar::highlight_filename $fname [expr ($diff * 2) + 1]
02332 }
02333
02334 # Syntax highlight the file
02335 syntax::set_language $txt [syntax::get_default_language $fname]
02336
02337 }
02338
02339 # If the information panel needs to be updated for this file, do it now
02340 sidebar::update_info_panel_for_file $fname $opts(-remote)
02341
02342 # Set the modified state to 0
02343 set_current_modified 0
02344 set undo_count($tab) [$txt edit undocount]
02345
02346 # If there is a save command, run it now
02347 if {$save_cmd ne ""} {
02348 eval {*}$save_cmd $fileindex
02349
02350 # Otherwise, if the file type is TclPlugin, automatically reload the plugin
02351 } elseif {[lsearch [list PluginTcl PluginHeader] $lang] != -1} {
02352 plugins::reload
02353 }
02354
02355 return 1
02356
02357 }
02358
02359 ######################################################################
02360 # Saves all of the opened tab contents (if necessary). If a tab has
02361 # not been previously saved (a new file), that tab is made the current
02362 # tab and the save_current procedure is called.
02363 proc save_all {} {
02364
02365 variable undo_count
02366
02367 for {set i 0} {$i < [files::get_file_num]} {incr i} {
02368
02369 # Get file information
02370 get_info $i fileindex tabbar tab txt fname modified diff save_cmd buffer
02371
02372 # If the file needs to be saved, do it
02373 if {$modified && !$diff} {
02374
02375 # If the file needs to be saved as a new filename, call the save_current
02376 # procedure
02377 if {$buffer && ($save_cmd ne "")} {
02378
02379 # Run the save command and if it ran successfully,
02380 if {[catch { {*}$save_cmd $i } rc]} {
02381
02382 continue
02383
02384 } elseif {$rc == 0} {
02385
02386 # Change the tab text
02387 $tabbar tab $tab -text " [file tail $fname]"
02388
02389 # Change the text to unmodified
02390 $txt edit modified false
02391 set undo_count($tab) [$txt edit undocount]
02392 files::set_info $i fileindex modified 0
02393
02394 # Save the current
02395 } else {
02396
02397 set_current_tab $tabbar $tab
02398 save_current -force 1
02399
02400 }
02401
02402 # Perform a tab-only save
02403 } else {
02404
02405 # Run the on_save plugins
02406 plugins::handle_on_save $i
02407
02408 # Save the file contents
02409 if {![files::set_file $tab [scrub_text $txt]]} {
02410 continue
02411 }
02412
02413 # Change the tab text
02414 $tabbar tab $tab -text " [file tail $fname]"
02415
02416 # Change the text to unmodified
02417 $txt edit modified false
02418 set undo_count($tab) [$txt edit undocount]
02419 files::set_info $i fileindex modified 0
02420
02421 # If there is a save command, run it now
02422 if {$save_cmd ne ""} {
02423 eval {*}$save_cmd $i
02424 }
02425
02426 }
02427
02428 }
02429
02430 }
02431
02432 # Make sure that the title is consistent
02433 set_title
02434
02435 }
02436
02437 ######################################################################
02438 # Returns 1 if the tab is closable; otherwise, returns a value of 0.
02439 # Saves the tab if it needs to be saved.
02440 proc close_check {tab force exiting} {
02441
02442 # Get the tab information
02443 get_info $tab tab tabbar fname modified diff
02444
02445 # If the file needs to be saved, do it now
02446 if {$modified && !$diff && !$force} {
02447 set fname [file tail $fname]
02448 set msg [format "%s %s?" [msgcat::mc "Save"] $fname]
02449 set_current_tab $tabbar $tab
02450 if {[set answer [tk_messageBox -default yes -type [expr {$exiting ? {yesno} : {yesnocancel}}] -message $msg -title [msgcat::mc "Save request"]]] eq "yes"} {
02451 return [save_current -force $force]
02452 } elseif {$answer eq "cancel"} {
02453 return 0
02454 }
02455 }
02456
02457 return 1
02458
02459 }
02460
02461 ######################################################################
02462 # Returns 1 if the tab is closable; otherwise, returns a value of 0.
02463 # Saves the tab if it needs to be saved.
02464 proc close_check_by_tabbar {w tab} {
02465
02466 return [close_check $tab 0 0]
02467
02468 }
02469
02470 ######################################################################
02471 # Close the current tab. If -force is set to 1, closes regardless of
02472 # modified state of text widget. If -force is set to 0 and the text
02473 # widget is modified, the user will be questioned if they want to save
02474 # the contents of the file prior to closing the tab.
02475 proc close_current {args} {
02476
02477 array set opts {
02478 -force 0
02479 -exiting 0
02480 }
02481 array set opts $args
02482
02483 close_tab [get_info {} current tab] -force $opts(-force) -exiting $opts(-exiting)
02484
02485 }
02486
02487
02488 ######################################################################
02489 # Closes the tab specified by "tab". This is called by the tabbar when
02490 # the user clicks on the close button of a tab.
02491 proc close_tab_by_tabbar {w tab} {
02492
02493 variable pw_current
02494
02495 # Close the tab specified by tab (we don't need to check because the check
02496 # will have already been performed with the -checkcommand passed to the
02497 # tabbar.
02498 close_tab $tab -tabbar $w -check 0
02499
02500 return 1
02501
02502 }
02503
02504 ######################################################################
02505 # Close the specified tab (do not ask the user about closing the tab).
02506 proc close_tab {tab args} {
02507
02508 variable widgets
02509 variable pw_current
02510
02511 array set opts {
02512 -exiting 0
02513 -keeptab 1
02514 -lazy 0
02515 -force 0
02516 -check 1
02517 -tabbar ""
02518 }
02519 array set opts $args
02520
02521 # Get information
02522 get_info $tab tab pane tabbar tabindex txt txt2 fileindex fname diff
02523
02524 # Figure out if the tab has txt2 opened
02525 set txt2_exists [winfo exists $txt2]
02526
02527 # Perform save check on close
02528 if {$opts(-check)} {
02529 if {![close_check $tab $opts(-force) $opts(-exiting)]} {
02530 return
02531 }
02532 }
02533
02534 # Unhighlight the file in the file browser (if the file was not a difference view)
02535 sidebar::highlight_filename $fname [expr $diff * 2]
02536
02537 # Run the close event for this file
02538 plugins::handle_on_close $fileindex
02539
02540 # Delete the file from files
02541 files::remove $tab
02542
02543 # Remove the tab from the tabbar (unless this has already been done by the tabbar)
02544 if {$opts(-tabbar) eq ""} {
02545 $tabbar delete $tabindex
02546 } else {
02547 set tabbar $opts(-tabbar)
02548 set pane [winfo parent [winfo parent $tabbar]]
02549 set pw_current [lsearch [$widgets(nb_pw) panes] $pane]
02550 }
02551
02552 # Delete the text frame
02553 catch { pack forget $tab }
02554
02555 # Destroy the text frame
02556 destroy $tab
02557
02558 # Clean up any code that is reliant on the text widget (if we are not exiting
02559 # the application) to avoid memory leaks
02560 if {!$opts(-exiting)} {
02561 cleanup_txt $txt
02562 if {$txt2_exists} {
02563 cleanup_txt $txt2
02564 }
02565 }
02566
02567 # Display the current pane (if one exists)
02568 if {!$opts(-lazy) && ([set tab [$tabbar select]] ne "")} {
02569 set_current_tab $tabbar $tab
02570 }
02571
02572 # If we have no more tabs and there is another pane, remove this pane
02573 if {([llength [$tabbar tabs]] == 0) && ([llength [$widgets(nb_pw) panes]] > 1)} {
02574 $widgets(nb_pw) forget $pane
02575 set pw_current 0
02576 set tabbar [get_info 0 paneindex tabbar]
02577 }
02578
02579 # Add a new file if we have no more tabs, we are the only pane, and the preference
02580 # setting is to not close after the last tab is closed.
02581 if {([llength [$tabbar tabs]] == 0) && ([llength [$widgets(nb_pw) panes]] == 1) && !$opts(-exiting)} {
02582 if {[preferences::get General/ExitOnLastClose] || $::cl_exit_on_close} {
02583 menus::exit_command
02584 } elseif {$opts(-keeptab)} {
02585 add_new_file end
02586 }
02587 }
02588
02589 }
02590
02591 ######################################################################
02592 # Close all tabs but the current tab.
02593 proc close_others {} {
02594
02595 variable widgets
02596 variable pw_current
02597
02598 set current_nb [lindex [$widgets(nb_pw) panes] $pw_current]
02599 set current_tab [$current_nb.tbf.tb select]
02600
02601 foreach nb [lreverse [$widgets(nb_pw) panes]] {
02602 foreach tab [lreverse [$nb.tbf.tb tabs]] {
02603 if {$tab ne $current_tab} {
02604 close_tab $tab -lazy 1
02605 }
02606 }
02607 }
02608
02609 # Set the current tab
02610 get_info {} current tabbar tab
02611 set_current_tab $tabbar $tab
02612
02613 }
02614
02615 ######################################################################
02616 # Close all of the tabs.
02617 proc close_all {args} {
02618
02619 variable widgets
02620
02621 array set opts {
02622 -force 0
02623 -exiting 0
02624 }
02625 array set opts $args
02626
02627 foreach nb [lreverse [$widgets(nb_pw) panes]] {
02628 foreach tab [lreverse [$nb.tbf.tb tabs]] {
02629 close_tab $tab -lazy 1 {*}$args
02630 }
02631 }
02632
02633 }
02634
02635 ######################################################################
02636 # Closes all other tabs within the current pane.
02637 proc close_others_current_pane {} {
02638
02639 variable widgets
02640 variable pw_current
02641
02642 set nb [lindex [$widgets(nb_pw) panes] $pw_current]
02643 set current_tab [$nb.tbf.tb select]
02644
02645 foreach tab [lreverse [$nb.tbf.tb tabs]] {
02646 if {$tab ne $current_tab} {
02647 close_tab $tab -lazy 1
02648 }
02649 }
02650
02651 # Set the current tab
02652 get_info {} current tabbar tab
02653 set_current_tab $tabbar $tab
02654
02655 }
02656
02657 ######################################################################
02658 # Closes all tabs within the current pane.
02659 proc close_current_pane {} {
02660
02661 variable widgets
02662 variable pw_current
02663
02664 set nb [lindex [$widgets(nb_pw) panes] $pw_current]
02665
02666 foreach tab [lreverse [$nb.tbf.tb tabs]] {
02667 close_tab $tab -lazy 1
02668 }
02669
02670 }
02671
02672 ######################################################################
02673 # Closes the tabs with the given file indices.
02674 proc close_files {indices} {
02675
02676 if {[llength $indices] > 0} {
02677
02678 # Perform a lazy close
02679 foreach index [lsort -decreasing $indices] {
02680 catch { close_tab [get_info $index fileindex tab] -lazy 1 }
02681 }
02682
02683 # Set the current tab
02684 get_info {} current tabbar tab
02685 set_current_tab $tabbar $tab
02686
02687 }
02688
02689 }
02690
02691 ######################################################################
02692 # Closes all of the opened files that exist within the given directories
02693 proc close_dir_files {dirs} {
02694
02695 set set_current 0
02696
02697 foreach dir $dirs {
02698 foreach index [lreverse [files::get_indices fname $dir*]] {
02699 close_tab [get_info $index fileindex tab] -lazy 1
02700 set set_current 1
02701 }
02702 }
02703
02704 # Set the current tab if we have lost it
02705 if {$set_current} {
02706 get_info {} current tabbar tab
02707 set_current_tab $tabbar $tab
02708 }
02709
02710 }
02711
02712 ######################################################################
02713 # Hides the given tab.
02714 proc hide_tab {tab} {
02715
02716 variable widgets
02717
02718 # Get the current tabbar
02719 get_info $tab tab tabbar fname remote
02720
02721 # Hide the tab
02722 $tabbar tab $tab -state hidden
02723
02724 # Make sure the sidebar is updated properly
02725 sidebar::set_hide_state $fname $remote 1
02726
02727 # Update ourselves to reflect the current tab show in the tabbar
02728 show_current_tab $tabbar
02729
02730 }
02731
02732 ######################################################################
02733 # Makes the given tab visible in the tabbar.
02734 proc show_tab {tab} {
02735
02736 variable widgets
02737
02738 # Get the current tabbar
02739 get_info $tab tab tabbar fname remote
02740
02741 # Show the tab
02742 $tabbar tab $tab -state normal
02743
02744 # Make sure the sidebar is updated properly
02745 sidebar::set_hide_state $fname $remote 0
02746
02747 # Update ourselves to reflect the current tab show in the tabbar
02748 show_current_tab $tabbar
02749
02750 }
02751
02752 ######################################################################
02753 # Hides the current tab.
02754 proc hide_current {} {
02755
02756 # Get the current tabbar and tab
02757 hide_tab [get_info {} current tab]
02758
02759 }
02760
02761 ######################################################################
02762 # Hides all of the files with the given filenames. The parameter must
02763 # be a list with the following format:
02764 # {filename remote}+
02765 proc hide_files {indices} {
02766
02767 # Perform a lazy close
02768 foreach index [lsort -decreasing $indices] {
02769 hide_tab [get_info $index fileindex tab]
02770 }
02771
02772 }
02773
02774 ######################################################################
02775 # Hides all of the opened files.
02776 proc hide_all {} {
02777
02778 foreach tab [files::get_tabs] {
02779 hide_tab $tab
02780 }
02781
02782 }
02783
02784 ######################################################################
02785 # Shows all of the files with the given filenames. The parameter must
02786 # be a list with the following format:
02787 # {filename remote}+
02788 proc show_files {indices} {
02789
02790 # Make sure that all specified files are shown
02791 foreach index [lsort -decreasing $indices] {
02792 show_tab [get_info $index fileindex tab]
02793 }
02794
02795 }
02796
02797 ######################################################################
02798 # Shows all of the files.
02799 proc show_all {} {
02800
02801 foreach tab [files::get_tabs] {
02802 show_tab $tab
02803 }
02804
02805 }
02806
02807 ######################################################################
02808 # Sorts all of the open tabs (in both panes, if both panes are visible)
02809 # by alphabetical order.
02810 proc sort_tabs {} {
02811
02812 variable widgets
02813
02814 foreach nb [$widgets(nb_pw) panes] {
02815
02816 get_info $nb pane tabbar tab
02817
02818 # Get the list of opened tabs
02819 set tabs [list]
02820 foreach atab [$tabbar tabs] {
02821 set fullname [$tabbar tab $atab -text]
02822 regexp {(\S+)$} $fullname -> name
02823 lappend tabs [list $name $fullname $atab]
02824 $tabbar delete $atab
02825 }
02826
02827 # Sort the tabs by alphabetical order and move them
02828 foreach atab [lsort -index 0 $tabs] {
02829 lassign $atab name fullname tabid
02830 $tabbar insert end $tabid -text $fullname -emboss 0
02831 }
02832
02833 # Reset the current tab
02834 $tabbar select $tab
02835
02836 }
02837
02838 }
02839
02840 ######################################################################
02841 # Moves the current notebook tab to the other notebook pane. If the
02842 # other notebook pane is not displayed, create it and display it.
02843 proc move_to_pane {} {
02844
02845 variable widgets
02846 variable pw_current
02847
02848 # Get the list of panes
02849 set panes [$widgets(nb_pw) panes]
02850
02851 # If the other pane does not exist, add it
02852 if {[llength $panes] == 1} {
02853 add_notebook
02854 set panes [$widgets(nb_pw) panes]
02855 }
02856
02857 # Get information
02858 get_info {} current pane tabbar tab tabindex
02859
02860 # Get the current title
02861 set title [$tabbar tab $tabindex -text]
02862
02863 # Remove the tab from the tabbar
02864 $tabbar delete $tabindex
02865
02866 # Remove the tab from the current pane
02867 catch { pack forget $tab }
02868
02869 # Display the current pane (if one exists)
02870 if {[set ctab [$tabbar select]] ne ""} {
02871 set_current_tab $tabbar $ctab
02872 set pw_current [expr $pw_current ^ 1]
02873 } else {
02874 $widgets(nb_pw) forget $pane
02875 set pw_current 0
02876 }
02877
02878 # Get the other tabbar
02879 get_info {} current tabbar
02880
02881 # Make sure that tabbar is visible
02882 grid $tabbar
02883
02884 # Add the new tab to the notebook in alphabetical order (if specified)
02885 if {[preferences::get View/OpenTabsAlphabetically]} {
02886 set added 0
02887 foreach t [$tabbar tabs] {
02888 if {[string compare $title [$tabbar tab $t -text]] == -1} {
02889 $tabbar insert $t $tab -text $title -emboss 0
02890 set added 1
02891 break
02892 }
02893 }
02894 if {$added == 0} {
02895 $tabbar insert end $tab -text $title -emboss 0
02896 }
02897
02898 # Otherwise, add the tab in the specified location
02899 } else {
02900 $tabbar insert end $tab -text $title -emboss 0
02901 }
02902
02903 # Now move the current tab from the previous current pane to the new current pane
02904 set_current_tab $tabbar $tab
02905
02906 # Set the tab image for the moved file
02907 set_tab_image $tab
02908
02909 }
02910
02911 ######################################################################
02912 # Merges both panes into one.
02913 proc merge_panes {} {
02914
02915 variable widgets
02916 variable pw_current
02917
02918 while {[llength [$widgets(nb_pw) panes]] == 2} {
02919
02920 # Make the second pane the current pane
02921 set pw_current 1
02922
02923 # Move the pane
02924 move_to_pane
02925
02926 }
02927
02928 }
02929
02930 ######################################################################
02931 # Performs an undo of the current tab.
02932 proc undo {} {
02933
02934 # Get the current textbox
02935 set txt [current_txt]
02936
02937 # Perform the undo operation from Vim perspective
02938 vim::undo $txt.t
02939
02940 }
02941
02942 ######################################################################
02943 # Returns true if there is something in the undo buffer.
02944 proc undoable {} {
02945
02946 # Get the current textbox
02947 set txt [current_txt]
02948
02949 return [$txt edit undoable]
02950
02951 }
02952
02953 ######################################################################
02954 # This procedure performs an redo operation.
02955 proc redo {} {
02956
02957 # Get the current textbox
02958 set txt [current_txt]
02959
02960 # Perform the redo operation from Vim perspective
02961 vim::redo $txt.t
02962
02963 }
02964
02965 ######################################################################
02966 # Returns true if there is something in the redo buffer.
02967 proc redoable {} {
02968
02969 # Get the current textbox
02970 set txt [current_txt]
02971
02972 return [$txt edit redoable]
02973
02974 }
02975
02976 ######################################################################
02977 # Cuts the currently selected text.
02978 proc cut {} {
02979
02980 # Perform the cut
02981 [current_txt] cut
02982
02983 # Add the clipboard contents to history
02984 cliphist::add_from_clipboard
02985
02986 }
02987
02988 ##############################################################################
02989 # This procedure performs a text selection copy operation.
02990 proc copy {} {
02991
02992 # Perform the copy
02993 [current_txt] copy
02994
02995 # Add the clipboard contents to history
02996 cliphist::add_from_clipboard
02997
02998 }
02999
03000 ######################################################################
03001 # Returns true if text is currently selected in the current buffer.
03002 proc selected {} {
03003
03004 if {([set txt [current_txt]] ne "") && \
03005 ([llength [$txt tag ranges sel]] > 0)} {
03006 return 1
03007 } else {
03008 return 0
03009 }
03010
03011 }
03012
03013 ##############################################################################
03014 # This procedure performs a text selection paste operation. Returns 1 if the
03015 # paste operation was performed on the current text widget; otherwise, returns 0.
03016 proc paste {} {
03017
03018 # Get the current text widget
03019 set txt [current_txt]
03020
03021 # If the current txt widget has the focus, paste clipboard contents to it and record the
03022 # paste with the Vim namespace.
03023 if {[focus] eq "$txt.t"} {
03024
03025 # Perform the paste
03026 $txt paste
03027
03028 # Handle the Vim paste
03029 vim::handle_paste $txt
03030
03031 return 1
03032
03033 }
03034
03035 return 0
03036
03037 }
03038
03039 ######################################################################
03040 # This procedure performs a paste operation, formatting the pasted text
03041 # to match the code that it is being pasted into.
03042 proc paste_and_format {} {
03043
03044 if {![catch {clipboard get}]} {
03045
03046 # Get the length of the clipboard text
03047 set cliplen [string length [clipboard get]]
03048
03049 # Get the position of the insertion cursor
03050 set insertpos [[current_txt] index insert]
03051
03052 # Perform the paste operation
03053 if {[paste]} {
03054
03055 # Have the indent namespace format the clipboard contents
03056 indent::format_text [current_txt].t $insertpos "$insertpos+${cliplen}c"
03057
03058 }
03059
03060 }
03061
03062 }
03063
03064 ######################################################################
03065 # Returns true if there is something in the paste buffer and the current
03066 # editor is editable.
03067 proc pastable {} {
03068
03069 return [expr {![catch {clipboard get} contents] && ($contents ne "") && [editable]}]
03070
03071 }
03072
03073 ######################################################################
03074 # Returns true if the current editor is editable.
03075 proc editable {} {
03076
03077 return [expr {[[current_txt] cget -state] eq "normal"}]
03078
03079 }
03080
03081 ######################################################################
03082 # Formats either the selected text (if type is "selected") or the entire
03083 # file contents (if type is "all").
03084 proc format_text {} {
03085
03086 # Get the file information
03087 get_info {} current txt fname lock readonly
03088
03089 # Get the locked/readonly status
03090 set readonly [expr $lock || $readonly]
03091
03092 # If the file is locked or readonly, set the state so that it can be modified
03093 if {$readonly} {
03094 $txt configure -state normal
03095 }
03096
03097 # If any text is selected, format it
03098 if {[llength [set selected [$txt tag ranges sel]]] > 0} {
03099 foreach {endpos startpos} [lreverse [$txt tag ranges sel]] {
03100 indent::format_text $txt.t $startpos $endpos
03101 }
03102
03103 # Otherwise, select the full file
03104 } else {
03105 indent::format_text $txt.t 1.0 end
03106 }
03107
03108 # If the file is locked or readonly, clear the modified state and reset the text state
03109 # back to disabled
03110 if {$readonly} {
03111
03112 # Clear the modified state
03113 set_current_modified 0
03114
03115 # Reset the state
03116 $txt configure -state disabled
03117
03118 }
03119
03120 }
03121
03122 ######################################################################
03123 # Updates the menubutton label for the given widget with the current
03124 # value of search_method.
03125 proc update_search_method {tab} {
03126
03127 variable search_method
03128
03129 switch $search_method {
03130 glob { set lbl [msgcat::mc "Glob"] }
03131 exact { set lbl [msgcat::mc "Exact"] }
03132 default { set lbl [msgcat::mc "Regexp"] }
03133 }
03134
03135 # Update the labels
03136 $tab.sf.type configure -text $lbl
03137 $tab.rf.opts.type configure -text $lbl
03138
03139 # If the find field for the given search type is not an empty string, perform the
03140 # search with the new search method
03141 if {[winfo ismapped $tab.sf]} {
03142 search::find_resilient "next" "find"
03143 } elseif {[winfo ismapped $tab.rf]} {
03144 search::find_resilient "next" "replace"
03145 }
03146
03147 }
03148
03149 ######################################################################
03150 # Called whenever the user changes the search text.
03151 proc handle_search_change {tab value} {
03152
03153 set state [expr {($value eq "") ? "disabled" : "normal"}]
03154
03155 $tab.sf.prev configure -state $state
03156 $tab.sf.next configure -state $state
03157
03158 return 1
03159
03160 }
03161
03162 ######################################################################
03163 # Called whenever the user changes the search text.
03164 proc handle_replace_change {tab value} {
03165
03166 set state [expr {($value eq "") ? "disabled" : "normal"}]
03167
03168 $tab.rf.act.prev configure -state $state
03169 $tab.rf.act.next configure -state $state
03170 $tab.rf.act.rep configure -state $state
03171 $tab.rf.act.repa configure -state $state
03172
03173 return 1
03174
03175 }
03176
03177 ######################################################################
03178 # Clears the search UI for find and find/replace.
03179 proc search_clear {} {
03180
03181 # Get the current tab
03182 get_info {} current tab
03183
03184 # Clear the find UI
03185 $tab.sf.e delete 0 end
03186 handle_search_change $tab ""
03187
03188 # Clear the find/replace UI
03189 $tab.rf.fe delete 0 end
03190 $tab.rf.re delete 0 end
03191 handle_replace_change $tab ""
03192
03193 }
03194
03195 ######################################################################
03196 # Displays the search bar.
03197 proc search {{dir "next"}} {
03198
03199 variable saved
03200
03201 # Get the tab information
03202 get_info {} current tab txt
03203
03204 # Update the search method menubutton label
03205 update_search_method $tab
03206
03207 # Display the search bar and separator
03208 panel_forget $tab.rf
03209 panel_place $tab.sf
03210
03211 # Add bindings
03212 bind $tab.sf.e <Return> [list search::find_start $dir]
03213 bind $tab.sf.case <Return> [list search::find_start $dir]
03214 bind $tab.sf.save <Return> [list search::find_start $dir]
03215
03216 # Reset the saved indicator
03217 set saved 0
03218
03219 # If a line or less is selected, populate the search bar with it
03220 if {([llength [set ranges [$txt tag ranges sel]]] == 2) && ([$txt count -lines {*}$ranges] == 0)} {
03221 $tab.sf.e delete 0 end
03222 $tab.sf.e insert end [$txt get {*}$ranges]
03223 } else {
03224 $tab.sf.e selection range 0 end
03225 }
03226
03227 # Place the focus on the search bar
03228 focus $tab.sf.e
03229
03230 # Set the unfocussed insertion cursor to hollow
03231 catch { $txt configure -insertunfocussed hollow }
03232
03233 }
03234
03235 ######################################################################
03236 # Performs the search operation.
03237 proc find_resilient {dir {type find}} {
03238
03239 get_info {} current tab
03240
03241 # Clear the selection of the search entry
03242 $tab.sf.e selection clear
03243 $tab.rf.fe selection clear
03244
03245 # Perform the search
03246 search::find_resilient $dir $type
03247
03248 }
03249
03250 ######################################################################
03251 # Closes the search widget.
03252 proc close_search {} {
03253
03254 # Get the current text frame
03255 get_info {} current tab txt
03256
03257 # Hide the search frame
03258 panel_forget $tab.sf
03259
03260 # Put the focus on the text widget
03261 set_txt_focus [last_txt_focus]
03262
03263 # Set the unfocussed insertion cursor to none
03264 catch { $txt configure -insertunfocussed none }
03265
03266 }
03267
03268 ######################################################################
03269 # Displays the search and replace bar.
03270 proc search_and_replace {} {
03271
03272 variable saved
03273
03274 # Get the tab information
03275 get_info {} current tab txt
03276
03277 # Update the search method menubutton label
03278 update_search_method $tab
03279
03280 # Display the search bar and separator
03281 panel_forget $tab.sf
03282 panel_place $tab.rf
03283
03284 # Reset the saved indicator
03285 set saved 0
03286
03287 # If a line or less is selected, populate the find entry with it
03288 if {([llength [set ranges [$txt tag ranges sel]]] == 2) && ([$txt count -lines {*}$ranges] == 0)} {
03289 $tab.rf.fe delete 0 end
03290 $tab.rf.fe insert end [$txt get {*}$ranges]
03291 } else {
03292 $tab.rf.fe selection range 0 end
03293 }
03294
03295 # Place the focus on the find entry field
03296 focus $tab.rf.fe
03297
03298 }
03299
03300 ######################################################################
03301 # Closes the search and replace bar.
03302 proc close_search_and_replace {} {
03303
03304 # Get the current tab
03305 get_info {} current tab
03306
03307 # Hide the search and replace bar
03308 panel_forget $tab.rf
03309
03310 # Put the focus on the text widget
03311 set_txt_focus [last_txt_focus]
03312
03313 }
03314
03315 ######################################################################
03316 # Retrieves the current search information for the specified type.
03317 proc get_search_data {type} {
03318
03319 variable widgets
03320 variable case_sensitive
03321 variable saved
03322 variable search_method
03323
03324 # Get the current tab
03325 get_info {} current tab
03326
03327 switch $type {
03328 "find" { return [list find [$tab.sf.e get] method $search_method case $case_sensitive save $saved] }
03329 "replace" { return [list find [$tab.rf.fe get] replace [$tab.rf.re get] method $search_method case $case_sensitive save $saved] }
03330 "fif" { return [list find [$widgets(fif_find) get] in [$widgets(fif_in) tokenget] method $search_method case $case_sensitive save $saved] }
03331 "docsearch" { return [list find [$widgets(doc).e get] name [$widgets(doc).mb cget -text] save $saved] }
03332 }
03333
03334 }
03335
03336 ######################################################################
03337 # Sets the given search information in the current search widget based
03338 # on type.
03339 proc set_search_data {type data} {
03340
03341 variable widgets
03342 variable case_sensitive
03343 variable saved
03344 variable search_method
03345
03346 # Get the current tab
03347 get_info {} current tab
03348
03349 array set data_array $data
03350
03351 switch $type {
03352 "find" {
03353 set search_method $data_array(method)
03354 set case_sensitive $data_array(case)
03355 set saved $data_array(save)
03356 $tab.sf.e delete 0 end
03357 $tab.sf.e insert end $data_array(find)
03358 handle_search_change $tab $data_array(find)
03359 }
03360 "replace" {
03361 set search_method $data_array(method)
03362 set case_sensitive $data_array(case)
03363 set saved $data_array(save)
03364 $tab.rf.fe delete 0 end
03365 $tab.rf.re delete 0 end
03366 $tab.rf.fe insert end $data_array(find)
03367 $tab.rf.re insert end $data_array(replace)
03368 handle_replace_change $tab $data_array(find)
03369 }
03370 "fif" {
03371 set search_method $data_array(method)
03372 set case_sensitive $data_array(case)
03373 set saved $data_array(save)
03374 $widgets(fif_find) delete 0 end
03375 $widgets(fif_find) insert end $data_array(find)
03376 $widgets(fif_in) tokendelete 0 end
03377 $widgets(fif_in) tokeninsert end $data_array(in)
03378 }
03379 "docsearch" {
03380 set saved $data_array(save)
03381 $widgets(doc).mb configure -text [expr {($data_array(name) eq "") ? [[$widgets(doc).mb cget -menu] entrycget 0 -label] : $data_array(name)}]
03382 $widgets(doc).e delete 0 end
03383 $widgets(doc).e insert end $data_array(find)
03384 }
03385 }
03386
03387 }
03388
03389 ######################################################################
03390 # Sets the file lock to the specified value for the current file.
03391 proc set_tab_image {tab} {
03392
03393 # Get the tab information
03394 get_info $tab tab tabbar txt diff readonly lock
03395
03396 # Change the state of the text widget to match the lock value
03397 if {$diff} {
03398 $tabbar tab $tab -compound left -image tab_diff
03399 $txt configure -state disabled
03400 } elseif {$readonly} {
03401 $tabbar tab $tab -compound left -image tab_readonly
03402 $txt configure -state disabled
03403 } elseif {$lock} {
03404 $tabbar tab $tab -compound left -image tab_lock
03405 $txt configure -state disabled
03406 } else {
03407 $tabbar tab $tab -image ""
03408 $txt configure -state normal
03409 }
03410
03411 return 1
03412
03413 }
03414
03415 ######################################################################
03416 # Sets the file lock to the specified value for the current file.
03417 proc set_current_file_lock {lock} {
03418
03419 # Get the current tab information
03420 get_info {} current tab
03421
03422 # Set the current lock status
03423 files::set_info $tab tab lock $lock
03424
03425 # Set the tab image to match
03426 set_tab_image $tab
03427
03428 }
03429
03430 ######################################################################
03431 # Sets the file lock of the current editor with the value of the file_locked
03432 # local variable.
03433 proc set_current_file_lock_with_current {} {
03434
03435 variable file_locked
03436
03437 set_current_file_lock $file_locked
03438
03439 }
03440
03441 ######################################################################
03442 # Set or clear the favorite status of the current file.
03443 proc set_current_file_favorite {favorite} {
03444
03445 # Get the current file name
03446 get_info {} current fname
03447
03448 # Add or remove the file from the favorites list
03449 if {$favorite} {
03450 favorites::add $fname
03451 } else {
03452 favorites::remove $fname
03453 }
03454
03455 }
03456
03457 ######################################################################
03458 # Sets the file favorite of the current editor with the value of the
03459 # file_favorited local variable.
03460 proc set_current_file_favorite_with_current {} {
03461
03462 variable file_favorited
03463
03464 set_current_file_favorite $file_favorited
03465
03466 }
03467
03468 ######################################################################
03469 # Shows the current file in the sidebar.
03470 proc show_current_in_sidebar {} {
03471
03472 get_info {} current fname remote
03473
03474 # Display the file in the sidebar
03475 sidebar::view_file $fname $remote
03476
03477 }
03478
03479 ######################################################################
03480 # Sets the current information message to the given string.
03481 proc set_info_message {msg args} {
03482
03483 variable widgets
03484 variable info_clear
03485 variable info_msgs
03486
03487 array set opts {
03488 -clear_delay 3000
03489 -win ""
03490 }
03491 array set opts $args
03492
03493 if {[info exists widgets(info_msg)]} {
03494
03495 if {$info_clear ne ""} {
03496 after cancel $info_clear
03497 }
03498
03499 lassign [winfo rgb . [set foreground [utils::get_default_foreground]]] fr fg fb
03500 lassign [winfo rgb . [utils::get_default_background]] br bg bb
03501 $widgets(info_msg) configure -text $msg -foreground $foreground
03502
03503 # Remember or clear the message for the window, if necessary
03504 if {$opts(-win) ne ""} {
03505 if {$msg eq ""} {
03506 unset -nocomplain info_msgs($opts(-win))
03507 } else {
03508 set info_msgs($opts(-win)) [list $msg $opts(-clear_delay)]
03509 }
03510 }
03511
03512 # If the status bar is supposed to be hidden, show it now
03513 if {![winfo ismapped $widgets(info)]} {
03514 show_status_view
03515 set hide_info 1
03516 } else {
03517 set hide_info 0
03518 }
03519
03520 # Call ourselves
03521 if {($opts(-clear_delay) > 0) && ([string trim $msg] ne "")} {
03522 set info_clear [after $opts(-clear_delay) \
03523 [list gui::clear_info_message $hide_info \
03524 [expr $fr >> 8] [expr $fg >> 8] [expr $fb >> 8] \
03525 [expr $br >> 8] [expr $bg >> 8] [expr $bb >> 8] -win $opts(-win)]]
03526 }
03527
03528 } else {
03529
03530 puts $msg
03531
03532 }
03533
03534 }
03535
03536 ######################################################################
03537 # Clears the info message.
03538 proc clear_info_message {hide_info fr fg fb br bg bb args} {
03539
03540 variable widgets
03541 variable info_clear
03542 variable info_msgs
03543
03544 array set opts {
03545 -fade_count 0
03546 -win ""
03547 }
03548 array set opts $args
03549
03550 if {$opts(-fade_count) == 10} {
03551
03552 # Clear the text
03553 $widgets(info_msg) configure -text ""
03554
03555 # Clear the message memory
03556 unset -nocomplain info_msgs($opts(-win))
03557
03558 # Clear the info_clear variable
03559 set info_clear ""
03560
03561 # If the status bar is supposed to be hidden, hide it now
03562 if {$hide_info} {
03563 hide_status_view
03564 }
03565
03566 } else {
03567
03568 # Calculate the color
03569 set color [format {#%02x%02x%02x} \
03570 [expr $fr - ((($fr - $br) / 10) * $opts(-fade_count))] \
03571 [expr $fg - ((($fg - $bg) / 10) * $opts(-fade_count))] \
03572 [expr $fb - ((($fb - $bb) / 10) * $opts(-fade_count))]]
03573
03574 # Set the foreground color to simulate the fade effect
03575 $widgets(info_msg) configure -foreground $color
03576
03577 set info_clear [after 100 [list gui::clear_info_message $hide_info $fr $fg $fb $br $bg $bb -fade_count [incr opts(-fade_count)] -win $opts(-win)]]
03578
03579 }
03580
03581 }
03582
03583 ######################################################################
03584 # Generates an error message parented by the main window. Used to
03585 # unify the error message experience.
03586 proc set_error_message {msg {detail ""}} {
03587
03588 tk_messageBox -parent . -icon error -title [msgcat::mc "Error"] -type ok -default ok -message $msg -detail $detail
03589
03590 }
03591
03592 ######################################################################
03593 # Sets the entire application UI state to either the normal or disabled
03594 # state which will allow the user to drag/drop information into the panel
03595 # without allowing the editor state to change. This procedure is automatically
03596 # called by the panel_place and panel_forget procedures so it should
03597 # not need to be called directly by any other code.
03598 proc panel_set_ui_state {state} {
03599
03600 variable widgets
03601
03602 set markable [expr {($state eq "normal")}]
03603
03604 # Disable the tabbars
03605 foreach pane [$widgets(nb_pw) panes] {
03606 get_info $pane pane tabbar txt txt2
03607 $tabbar configure -state $state
03608 $txt configure -state $state -linemap_markable $markable
03609 if {[winfo exists $txt2]} {
03610 $txt2 configure -state $state -linemap_markable $markable
03611 }
03612 }
03613
03614 # For good measure, we'll even disable the information bar items
03615 $widgets(info_encode) configure -state $state
03616 $widgets(info_indent) configure -state $state
03617 $widgets(info_syntax) configure -state $state
03618
03619 # Disable the menubar
03620 menus::set_state $state
03621
03622 # Disable the sidebar from executing
03623 sidebar::set_state [expr {($state eq "normal") ? "normal" : "viewonly"}]
03624
03625 }
03626
03627 ######################################################################
03628 # Places the panel in the window.
03629 proc panel_place {w} {
03630
03631 variable widgets
03632 variable panel_focus
03633
03634 if {[winfo parent $w] eq "."} {
03635 set top [winfo height $widgets(info)]
03636 set sep .sep
03637 } else {
03638 set top 0
03639 set sep [winfo parent $w].sep
03640 }
03641
03642 set stop [winfo reqheight $sep]
03643 set wtop [winfo reqheight $w]
03644
03645 # Place the separator
03646 place $sep -relwidth 1.0 -rely 1.0 -y [expr 0 - ($top + $stop)]
03647 raise $sep
03648
03649 # Place the window and make sure that the window is raised above all others
03650 place $w -relwidth 1.0 -rely 1.0 -y [expr 0 - ($top + $stop + $wtop)]
03651 raise $w
03652
03653 # Disable the UI
03654 # panel_set_ui_state disabled
03655
03656 # Remember who has the focus
03657 set panel_focus [focus]
03658
03659 }
03660
03661 ######################################################################
03662 # Forget the pnael.
03663 proc panel_forget {w} {
03664
03665 variable panel_focus
03666
03667 if {[winfo parent $w] eq "."} {
03668 set sep .sep
03669 } else {
03670 set sep [winfo parent $w].sep
03671 }
03672
03673 # Remove the given panels from display
03674 place forget $w
03675 place forget $sep
03676
03677 # Enable the UI
03678 # panel_set_ui_state normal
03679
03680 # Return the focus
03681 if {$panel_focus ne ""} {
03682 focus $panel_focus
03683 set panel_focus ""
03684 }
03685
03686 }
03687
03688 ######################################################################
03689 # Gets user input from the interface in a generic way.
03690 proc get_user_response {msg pvar args} {
03691
03692 variable widgets
03693
03694 array set opts {
03695 -allow_vars 0
03696 -selrange {}
03697 }
03698 array set opts $args
03699
03700 upvar $pvar var
03701
03702 # Initialize the widget
03703 $widgets(ursp_label) configure -text $msg
03704 $widgets(ursp_entry) delete 0 end
03705
03706 # If var contains a value, display it and select it
03707 if {$var ne ""} {
03708 $widgets(ursp_entry) insert end $var
03709 if {$opts(-selrange) ne ""} {
03710 $widgets(ursp_entry) selection range {*}$opts(-selrange)
03711 }
03712 }
03713
03714 # Display the user input widget
03715 panel_place $widgets(ursp)
03716
03717 # Wait for the ursp_entry widget to be closed
03718 focus $widgets(ursp_entry)
03719 tkwait variable gui::user_exit_status
03720
03721 # Hide the user input widget
03722 panel_forget $widgets(ursp)
03723
03724 # Get the user response value
03725 set var [$widgets(ursp_entry) get]
03726
03727 # If variable substitutions are allowed, perform any substitutions
03728 if {$opts(-allow_vars)} {
03729 set var [utils::perform_substitutions $var]
03730 }
03731
03732 return [set gui::user_exit_status]
03733
03734 }
03735
03736 ######################################################################
03737 # Returns file information for the given file index and attribute.
03738 # This is called by the get_file_info API command.
03739 proc get_file_info {index attr} {
03740
03741 # Perform error detections
03742 if {($index < 0) || ($index >= [files::get_file_num])} {
03743 return -code error [msgcat::mc "File index is out of range"]
03744 }
03745
03746 # Get the current text widget
03747 get_info $index fileindex txt remote
03748
03749 switch $attr {
03750 "sb_index" {
03751 return [sidebar::get_index $index $remote]
03752 }
03753 "txt" {
03754 return $txt.t
03755 }
03756 "current" {
03757 return [expr {$txt eq [current_txt]}]
03758 }
03759 "vimmode" {
03760 return [vim::in_vim_mode $txt.t]
03761 }
03762 "lang" {
03763 return [syntax::get_language $txt]
03764 }
03765 default {
03766 return [files::get_info $index fileindex $attr]
03767 }
03768 }
03769
03770 }
03771
03772 ######################################################################
03773 # Retrieves the "find in file" inputs from the user.
03774 proc fif_get_input {prsp_list} {
03775
03776 variable widgets
03777 variable fif_files
03778 variable fif_method
03779 variable case_sensitive
03780 variable saved
03781
03782 upvar $prsp_list rsp_list
03783
03784 # Initialize variables
03785 set case_sensitive 1
03786 set saved 0
03787
03788 # Reset the input widgets
03789 $widgets(fif_find) delete 0 end
03790 $widgets(fif_in) delete 0 end
03791
03792 # Populate the fif_in tokenentry menu
03793 set fif_files [sidebar::get_fif_files]
03794 $widgets(fif_in) configure -listvar gui::fif_files -matchmode regexp -matchindex 0 -matchdisplayindex 0
03795
03796 switch $fif_method {
03797 "regexp" { $widgets(fif_type) configure -text [msgcat::mc "Regexp"] }
03798 "glob" { $widgets(fif_type) configure -text [msgcat::mc "Glob"] }
03799 "exact" { $widgets(fif_type) configure -text [msgcat::mc "Exact"] }
03800 }
03801
03802 # Display the FIF widget
03803 panel_place $widgets(fif)
03804
03805 # Wait for the panel to be exited
03806 focus $widgets(fif_find)
03807 tkwait variable gui::user_exit_status
03808
03809 # Hide the widget
03810 panel_forget $widgets(fif)
03811
03812 # Get the list of files/directories from the list of tokens
03813 set ins [list]
03814 foreach token [$widgets(fif_in) tokenget] {
03815 if {[set index [lsearch -index 0 $fif_files $token]] != -1} {
03816 lappend ins {*}[lindex $fif_files $index 1]
03817 } else {
03818 lappend ins [utils::perform_substitutions $token]
03819 }
03820 }
03821
03822 # Gather the input to return
03823 set rsp_list [list find [$widgets(fif_find) get] in $ins method $fif_method case $case_sensitive save $saved]
03824
03825 return [set gui::user_exit_status]
03826
03827 }
03828
03829 ######################################################################
03830 # Displays the help menu "About" window.
03831 proc show_about {} {
03832
03833 # Generate the version string
03834 if {$::version_point == 0} {
03835 set version_str "$::version_major.$::version_minor ($::version_hgid)"
03836 } else {
03837 set version_str "$::version_major.$::version_minor.$::version_point ($::version_hgid)"
03838 }
03839
03840 if {[preferences::get General/UpdateReleaseType] eq "devel"} {
03841 set release_type "Development"
03842 } else {
03843 set release_type "Stable"
03844 }
03845
03846 toplevel .aboutwin
03847 wm title .aboutwin ""
03848 wm transient .aboutwin .
03849 wm resizable .aboutwin 0 0
03850
03851 ttk::frame .aboutwin.f
03852 ttk::label .aboutwin.f.logo -compound left -image logo -text " TKE" \
03853 -font [font create -family Helvetica -size 30 -weight bold]
03854
03855 ttk::frame .aboutwin.f.if
03856 ttk::label .aboutwin.f.if.l0 -text [format "%s:" [msgcat::mc "Version"]]
03857 ttk::label .aboutwin.f.if.v0 -text $version_str
03858 ttk::label .aboutwin.f.if.l1 -text [format "%s:" [msgcat::mc "Release Type"]]
03859 ttk::label .aboutwin.f.if.v1 -text $release_type
03860 ttk::label .aboutwin.f.if.l2 -text [format "%s:" [msgcat::mc "License"]]
03861 ttk::label .aboutwin.f.if.v2 -text "GPL 2.0"
03862 ttk::label .aboutwin.f.if.l3 -text [format "%s:" [msgcat::mc "Tcl/Tk Version"]]
03863 ttk::label .aboutwin.f.if.v3 -text [info patchlevel]
03864 ttk::label .aboutwin.f.if.l4 -text [format "\n%s:" [msgcat::mc "Developer"]]
03865 ttk::label .aboutwin.f.if.v4 -text "\nTrevor Williams"
03866 ttk::label .aboutwin.f.if.l5 -text [format "%s:" [msgcat::mc "Email"]]
03867 ttk::label .aboutwin.f.if.v5 -text "phase1geo@gmail.com"
03868 ttk::label .aboutwin.f.if.l6 -text "Twitter:"
03869 ttk::label .aboutwin.f.if.v6 -text "@TkeTextEditor"
03870 ttk::label .aboutwin.f.if.l7 -text "Website:"
03871 ttk::label .aboutwin.f.if.v7 -text "http://tke.sourceforge.net"
03872
03873 bind .aboutwin.f.if.v2 <Enter> [list %W configure -cursor [ttk::cursor link]]
03874 bind .aboutwin.f.if.v2 <Leave> [list %W configure -cursor [ttk::cursor standard]]
03875 bind .aboutwin.f.if.v2 <Button-1> {
03876 destroy .aboutwin
03877 gui::add_file end [file join $::tke_dir LICENSE] -sidebar 0 -readonly 1
03878 }
03879 bind .aboutwin.f.if.v5 <Enter> [list %W configure -cursor [ttk::cursor link]]
03880 bind .aboutwin.f.if.v5 <Leave> [list %W configure -cursor [ttk::cursor standard]]
03881 bind .aboutwin.f.if.v5 <Button-1> [list utils::open_file_externally {mailto:phase1geo@gmail.com} 1]
03882 bind .aboutwin.f.if.v6 <Enter> [list %W configure -cursor [ttk::cursor link]]
03883 bind .aboutwin.f.if.v6 <Leave> [list %W configure -cursor [ttk::cursor standard]]
03884 bind .aboutwin.f.if.v6 <Button-1> [list utils::open_file_externally {https:
03885 bind .aboutwin.f.if.v7 <Enter> [list %W configure -cursor [ttk::cursor link]]
03886 bind .aboutwin.f.if.v7 <Leave> [list %W configure -cursor [ttk::cursor standard]]
03887 bind .aboutwin.f.if.v7 <Button-1> [list utils::open_file_externally {http:
03888
03889 grid .aboutwin.f.if.l0 -row 0 -column 0 -sticky news -padx 2 -pady 2
03890 grid .aboutwin.f.if.v0 -row 0 -column 1 -sticky news -padx 2 -pady 2
03891 grid .aboutwin.f.if.l1 -row 1 -column 0 -sticky news -padx 2 -pady 2
03892 grid .aboutwin.f.if.v1 -row 1 -column 1 -sticky news -padx 2 -pady 2
03893 grid .aboutwin.f.if.l2 -row 2 -column 0 -sticky news -padx 2 -pady 2
03894 grid .aboutwin.f.if.v2 -row 2 -column 1 -sticky news -padx 2 -pady 2
03895 grid .aboutwin.f.if.l3 -row 3 -column 0 -sticky news -padx 2 -pady 2
03896 grid .aboutwin.f.if.v3 -row 3 -column 1 -sticky news -padx 2 -pady 2
03897 grid .aboutwin.f.if.l4 -row 4 -column 0 -sticky news -padx 2 -pady 2
03898 grid .aboutwin.f.if.v4 -row 4 -column 1 -sticky news -padx 2 -pady 2
03899 grid .aboutwin.f.if.l5 -row 5 -column 0 -sticky news -padx 2 -pady 2
03900 grid .aboutwin.f.if.v5 -row 5 -column 1 -sticky news -padx 2 -pady 2
03901 grid .aboutwin.f.if.l6 -row 6 -column 0 -sticky news -padx 2 -pady 2
03902 grid .aboutwin.f.if.v6 -row 6 -column 1 -sticky news -padx 2 -pady 2
03903 grid .aboutwin.f.if.l7 -row 7 -column 0 -sticky news -padx 2 -pady 2
03904 grid .aboutwin.f.if.v7 -row 7 -column 1 -sticky news -padx 2 -pady 2
03905
03906 ttk::frame .aboutwin.f.cf
03907 ttk::label .aboutwin.f.cf.l -text [msgcat::mc "Credits"] -anchor center
03908 ttk::separator .aboutwin.f.cf.sep1 -orient horizontal
03909 # ttk::labelframe .aboutwin.f.cf -text [msgcat::mc "Credits"] -labelanchor n
03910 set txt [text .aboutwin.f.cf.t -wrap word -height 5 -relief flat -highlightthickness 0 \
03911 -font "TkDefaultFont" -width 80 \
03912 -background [utils::get_default_background] \
03913 -foreground [utils::get_default_foreground] \
03914 -yscrollcommand { utils::set_yscrollbar .aboutwin.f.cf.vb }]
03915 scroller::scroller .aboutwin.f.cf.vb -orient vertical -command { .aboutwin.f.cf.t yview }
03916 ttk::separator .aboutwin.f.cf.sep2 -orient horizontal
03917
03918 # Register the widget for theming
03919 theme::register_widget .aboutwin.f.cf.vb misc_scrollbar
03920
03921 grid rowconfigure .aboutwin.f.cf 2 -weight 1
03922 grid columnconfigure .aboutwin.f.cf 0 -weight 1
03923 grid .aboutwin.f.cf.l -row 0 -column 0 -sticky ew -columnspan 2 -padx 2 -pady 4
03924 grid .aboutwin.f.cf.sep1 -row 1 -column 0 -sticky ew -columnspan 2
03925 grid .aboutwin.f.cf.t -row 2 -column 0 -sticky news
03926 grid .aboutwin.f.cf.vb -row 2 -column 1 -sticky ns
03927 grid .aboutwin.f.cf.sep2 -row 3 -column 0 -sticky ew -columnspan 2
03928
03929 ttk::button .aboutwin.f.credits -style BButton -text [msgcat::mc "Credits"] -command {
03930 if {[.aboutwin.f.credits cget -text] eq [msgcat::mc "Credits"]} {
03931 pack forget .aboutwin.f.if
03932 pack .aboutwin.f.cf -after .aboutwin.f.logo -padx 2 -pady 2 -fill both -expand yes
03933 .aboutwin.f.credits configure -text [msgcat::mc "Back"]
03934 } else {
03935 pack forget .aboutwin.f.cf
03936 pack .aboutwin.f.if -after .aboutwin.f.logo -padx 2 -pady 2
03937 .aboutwin.f.credits configure -text [msgcat::mc "Credits"]
03938 }
03939 }
03940 ttk::label .aboutwin.f.copyright -text [format "%s %d-%d" [msgcat::mc "Copyright"] 2013 18]
03941
03942 pack .aboutwin.f.logo -padx 2 -pady 8 -anchor w
03943 pack .aboutwin.f.if -padx 2 -pady 2
03944 pack .aboutwin.f.credits -padx 2 -pady 2
03945 pack .aboutwin.f.copyright -padx 2 -pady 8
03946
03947 pack .aboutwin.f -fill both -expand yes
03948
03949 # Center the window in the editor window
03950 ::tk::PlaceWindow .aboutwin widget .
03951
03952 # Add credit information
03953 $txt insert end "Special thanks to the following:\n\n"
03954 $txt insert end "\uff65 The " {} "filerunner" frlink " project for creating and sharing their FTP and SFTP codebase to make built-in remote file editing possible.\n\n" {}
03955 $txt insert end "\uff65 Dr. Casaba Nemethi for his full-featured " {} "tablelist" tllink " project.\n\n" {}
03956 $txt insert end "\uff65 Jean-Claude Wippler for his excellent webdav package.\n\n" {}
03957
03958 $txt tag configure frlink -underline 1
03959 $txt tag bind frlink <Enter> [list $txt configure -cursor [ttk::cursor link]]
03960 $txt tag bind frlink <Leave> [list $txt configure -cursor [ttk::cursor standard]]
03961 $txt tag bind frlink <Button-1> [list utils::open_file_externally "http://filerunner.sourceforge.net"]
03962
03963 $txt tag configure tllink -underline 1
03964 $txt tag bind tllink <Enter> [list $txt configure -cursor [ttk::cursor link]]
03965 $txt tag bind tllink <Leave> [list $txt configure -cursor [ttk::cursor standard]]
03966 $txt tag bind tllink <Button-1> [list utils::open_file_externally "http://www.nemethi.de"]
03967
03968 # Make sure that the user cannot change the text.
03969 $txt configure -state disabled
03970
03971 wm withdraw .aboutwin
03972 update
03973
03974 set x [expr [winfo reqwidth .aboutwin.f.cf] + 4]
03975 # set x [expr max( [winfo reqwidth .aboutwin.f.logo], [winfo reqwidth .aboutwin.f.if], [winfo reqwidth .aboutwin.f.cf] ) + 4]
03976 set y [expr [winfo reqheight .aboutwin.f.logo] + [winfo reqheight .aboutwin.f.credits] + [winfo reqheight .aboutwin.f.copyright] + 40]
03977 incr y [winfo reqheight .aboutwin.f.if]
03978 wm geometry .aboutwin ${x}x${y}
03979 wm deiconify .aboutwin
03980
03981 }
03982
03983 ######################################################################
03984 # Displays the number insertion dialog box if we are currently in
03985 # multicursor mode.
03986 proc insert_numbers {txt} {
03987
03988 if {[multicursor::enabled $txt]} {
03989
03990 set var1 ""
03991
03992 # Get the number string from the user
03993 if {[get_user_response [msgcat::mc "Starting number:"] var1]} {
03994
03995 # Insert the numbers (if not successful, output an error to the user)
03996 if {![multicursor::insert_numbers $txt $var1]} {
03997 set_info_message [msgcat::mc "Unable to successfully parse number string"]
03998 }
03999
04000 }
04001
04002 # Otherwise, display an error message to the user
04003 } else {
04004 set_info_message [msgcat::mc "Must be in multicursor mode to insert numbers"]
04005 }
04006
04007 }
04008
04009 ######################################################################
04010 # Toggles the split pane for the current tab.
04011 proc toggle_split_pane {} {
04012
04013 get_info {} current tab txt2
04014
04015 if {[winfo exists $txt2]} {
04016 hide_split_pane $tab
04017 } else {
04018 show_split_pane $tab
04019 }
04020
04021 }
04022
04023 ######################################################################
04024 # Toggles the bird's eye view panel for the current tab.
04025 proc toggle_birdseye {} {
04026
04027 get_info {} current tab beye
04028
04029 if {[winfo exists $beye]} {
04030 hide_birdseye $tab
04031 } else {
04032 show_birdseye $tab
04033 }
04034
04035 }
04036
04037 ######################################################################
04038 # Returns a list of all of the text widgets in the tool.
04039 proc get_all_texts {} {
04040
04041 set txts [list]
04042
04043 foreach tab [files::get_tabs] {
04044 get_info $tab tab txt txt2
04045 lappend txts $txt
04046 if {[winfo exists $txt2]} {
04047 lappend txts $txt2
04048 }
04049 }
04050
04051 return $txts
04052
04053 }
04054
04055 ########################
04056 # PRIVATE PROCEDURES #
04057 ########################
04058
04059 ######################################################################
04060 # Gets the various pieces of tos information from the given from.
04061 # The valid values for from and tos (list) is the following:
04062 #
04063 # - current (from_type only)
04064 # - pane (using in from implies the current pane)
04065 # - paneindex (using in from implies the current pane index)
04066 # - tabbar (using in from implies the current tabbar)
04067 # - tab
04068 # - tabindex (using in from implies the index of the tab in the current pane)
04069 # - fileindex
04070 # - txt
04071 # - txt2
04072 # - focus
04073 # - beye
04074 # - fname
04075 # - lang
04076 # - any key from file information (for to_types only)
04077 #
04078 # Throws an error if there were conversion issues.
04079 proc get_info {from from_type args} {
04080
04081 variable widgets
04082 variable pw_current
04083 variable txt_current
04084
04085 # Convert from to a tab
04086 switch $from_type {
04087 current {
04088 set tab [[lindex [$widgets(nb_pw) panes] $pw_current].tbf.tb select]
04089 }
04090 pane {
04091 set tab [$from.tbf.tb select]
04092 }
04093 paneindex {
04094 set tab [[lindex [$widgets(nb_pw) panes] $from].tbf.tb select]
04095 }
04096 tabbar {
04097 set tab [$from select]
04098 }
04099 tab {
04100 set tab $from
04101 }
04102 tabindex {
04103 set tab [lindex [[lindex [$widgets(nb_pw) panes] $pw_current].tbf.tb tabs] $from]
04104 }
04105 fileindex {
04106 files::get_info $from fileindex tab
04107 }
04108 txt -
04109 txt2 {
04110 set tab [winfo parent [winfo parent [winfo parent $from]]]
04111 }
04112 beye {
04113 set tab [winfo parent $from]
04114 }
04115 fname {
04116 files::get_info $from fname tab
04117 }
04118 }
04119
04120 if {$tab eq ""} {
04121 set paneindex $pw_current
04122 } else {
04123 set panes [$widgets(nb_pw) panes]
04124 set paneindex [expr {(([llength $panes] == 1) || ([lsearch [[lindex $panes 0].tbf.tb tabs] $tab] != -1)) ? 0 : 1}]
04125 }
04126
04127 set i 0
04128 foreach to_type $args {
04129 upvar $to_type type$i
04130 switch $to_type {
04131 pane {
04132 set type$i [lindex [$widgets(nb_pw) panes] $paneindex]
04133 }
04134 paneindex {
04135 set type$i $paneindex
04136 }
04137 tabbar {
04138 set type$i [lindex [$widgets(nb_pw) panes] $paneindex].tbf.tb
04139 }
04140 tab {
04141 if {$tab eq ""} {
04142 return -code error "Unable to get tab information"
04143 }
04144 set type$i $tab
04145 }
04146 tabindex {
04147 if {$tab eq ""} {
04148 return -code error "Unable to get tab index information"
04149 }
04150 set type$i [lsearch [[lindex [$widgets(nb_pw) panes] $paneindex].tbf.tb tabs] $tab]
04151 }
04152 txt {
04153 if {$tab eq ""} {
04154 return -code error "Unable to get txt information"
04155 }
04156 set type$i "$tab.pw.tf.txt"
04157 }
04158 txt2 {
04159 if {$tab eq ""} {
04160 return -code error "Unable to get txt2 information"
04161 }
04162 set type$i "$tab.pw.tf2.txt"
04163 }
04164 focus {
04165 if {($tab eq "") || ![info exists txt_current($tab)]} {
04166 return -code error "Unable to get focus information"
04167 }
04168 set type$i $txt_current($tab)
04169 }
04170 beye {
04171 if {$tab eq ""} {
04172 return -code error "Unable to get beye information"
04173 }
04174 set type$i "$tab.be"
04175 }
04176 lang {
04177 if {$tab eq ""} {
04178 return -code error "Unable to get lang information"
04179 }
04180 set type$i [syntax::get_language "$tab.pw.tf.txt"]
04181 }
04182 default {
04183 if {$tab eq ""} {
04184 return -code error "Unable to get $to_type information"
04185 }
04186 set type$i [files::get_info $tab tab $to_type]
04187 }
04188 }
04189 set retval [set type$i]
04190 incr i
04191 }
04192
04193 return $retval
04194
04195 }
04196
04197 ######################################################################
04198 # Add notebook widget.
04199 proc add_notebook {} {
04200
04201 variable widgets
04202 variable curr_notebook
04203
04204 # Create editor notebook
04205 $widgets(nb_pw) add [set nb [ttk::frame $widgets(nb_pw).nb[incr curr_notebook]]] -weight 1
04206
04207 # Add the tabbar frame
04208 ttk::frame $nb.tbf
04209 tabbar::tabbar $nb.tbf.tb -closeimage tab_close -activecloseimage tab_activeclose \
04210 -command [list gui::handle_tabbar_select] \
04211 -checkcommand [list gui::close_check_by_tabbar] \
04212 -closecommand [list gui::close_tab_by_tabbar]
04213
04214 # Configure the tabbar
04215 $nb.tbf.tb configure {*}[theme::get_category_options tabs 1]
04216
04217 grid rowconfigure $nb.tbf 0 -weight 1
04218 grid columnconfigure $nb.tbf 0 -weight 1
04219 grid $nb.tbf.tb -row 0 -column 0 -sticky news
04220 grid remove $nb.tbf.tb
04221
04222 bind [$nb.tbf.tb scrollpath left] <Button-$::right_click> [list gui::show_tabs $nb.tbf.tb left]
04223 bind [$nb.tbf.tb scrollpath right] <Button-$::right_click> [list gui::show_tabs $nb.tbf.tb right]
04224
04225 # Create popup menu for extra tabs
04226 menu $nb.tbf.tb.mnu -tearoff 0
04227
04228 ttk::frame $nb.tf
04229
04230 pack $nb.tbf -fill x
04231 pack $nb.tf -fill both -expand yes
04232
04233 bind [$nb.tbf.tb btag] <ButtonPress-$::right_click> {
04234 if {[%W cget -state] eq "disabled"} {
04235 return
04236 }
04237 if {[info exists gui::tab_tip(%W)]} {
04238 unset gui::tab_tip(%W)
04239 tooltip::tooltip clear %W
04240 tooltip::hide
04241 }
04242 set pane [winfo parent [winfo parent [winfo parent %W]]]
04243 set gui::pw_current [lsearch [$gui::widgets(nb_pw) panes] [winfo parent [winfo parent [winfo parent %W]]]]
04244 if {![catch { [winfo parent %W] select @%x,%y }]} {
04245 gui::set_current_tab [winfo parent %W] [[winfo parent %W] select]
04246 tk_popup $gui::widgets(menu) %X %Y
04247 }
04248 }
04249
04250 # Handle tooltips
04251 bind [$nb.tbf.tb btag] <Motion> [list gui::handle_notebook_motion %W %x %y]
04252
04253 # Register the tabbar and menu for theming
04254 theme::register_widget $nb.tbf.tb tabs
04255 theme::register_widget $nb.tbf.tb.mnu menus
04256
04257 }
04258
04259 ######################################################################
04260 # Called when the user places the cursor over a notebook tab.
04261 proc handle_notebook_motion {W x y} {
04262
04263 variable tab_tip
04264 variable tab_close
04265
04266 # Adjust W
04267 set W [winfo parent $W]
04268
04269 # If the tab is one of the left or right shift tabs, exit now
04270 if {[set tab_index [$W index @$x,$y]] == -1} {
04271 return
04272 }
04273
04274 set tab [lindex [$W tabs] $tab_index]
04275
04276 # Handle tooltip
04277 if {![info exists tab_tip($W)]} {
04278 set_tab_tooltip $W $tab
04279 } elseif {$tab_tip($W) ne $tab} {
04280 clear_tab_tooltip $W
04281 set_tab_tooltip $W $tab
04282 } else {
04283 clear_tab_tooltip $W
04284 }
04285
04286 }
04287
04288 ######################################################################
04289 # Sets a tooltip for the specified tab.
04290 proc set_tab_tooltip {W tab} {
04291
04292 variable tab_tip
04293
04294 # Get the full pathname to the current file
04295 get_info $tab tab fname remote
04296
04297 # Figure out what to display
04298 if {$remote eq ""} {
04299 set tip $fname
04300 } else {
04301 set remote [join [lassign [split $remote ,] group] ,]
04302 set tip "$fname ($remote)"
04303 }
04304
04305 # Create the tooltip
04306 set tab_tip($W) $tab
04307 tooltip::tooltip $W $tip
04308 event generate $W <Enter>
04309
04310 }
04311
04312 ######################################################################
04313 # Clears the tooltip for the specified tab.
04314 proc clear_tab_tooltip {W} {
04315
04316 variable tab_tip
04317
04318 unset -nocomplain tab_tip($W)
04319 tooltip::tooltip clear $W
04320 tooltip::hide
04321
04322 }
04323
04324 ######################################################################
04325 # Adjusts the given index (if necessary) such that the tab will be
04326 # inserted into the current notebook in alphabetical order.
04327 proc adjust_insert_tab_index {index title} {
04328
04329 if {[preferences::get View/OpenTabsAlphabetically] && ($index eq "end")} {
04330
04331 set sorted_index 0
04332
04333 if {![catch { get_info {} current tabbar }]} {
04334 foreach tab [$tabbar tabs] {
04335 regexp {(\S+)$} [$tabbar tab $tab -text] -> curr_title
04336 if {[string compare $title $curr_title] == -1} {
04337 return $sorted_index
04338 }
04339 incr sorted_index
04340 }
04341 }
04342
04343 }
04344
04345 return $index
04346
04347 }
04348
04349 ######################################################################
04350 # Inserts a new tab into the editor tab notebook.
04351 # Options:
04352 # -diff (0 | 1) Specifies if this tab is a difference view. Default is 0.
04353 # -gutters list Specifies a list of gutters to add to the ctext gutter area
04354 # -tags list Specifies a list of text binding tags
04355 # -lang language Specifies initial language parsing of buffer. Default is to determine based on title.
04356 proc insert_tab {tb index fname args} {
04357
04358 variable widgets
04359 variable curr_id
04360 variable language
04361 variable case_sensitive
04362 variable numberwidth
04363 variable show_match_chars
04364
04365 array set opts {
04366 -diff 0
04367 -gutters [list]
04368 -tags [list]
04369 -lang ""
04370 }
04371 array set opts $args
04372
04373 # Get the scrollbar coloring information
04374 array set sb_opts [theme::get_category_options text_scrollbar 1]
04375
04376 # Get the unique tab ID
04377 set id [incr curr_id]
04378
04379 # Calculate the title name
04380 set title [file tail $fname]
04381
04382 # Make the tabbar visible and the syntax menubutton enabled
04383 grid $tb
04384 $widgets(info_encode) configure -state normal
04385 $widgets(info_indent) configure -state normal
04386 $widgets(info_syntax) configure -state normal
04387
04388 # Create the tab frame
04389 set tab [ttk::frame .tab$id]
04390
04391 # Create the editor pane
04392 ttk::panedwindow $tab.pw
04393
04394 # Create tab frame name
04395 set txt $tab.pw.tf.txt
04396
04397 # Create the editor frame
04398 $tab.pw add [frame $tab.pw.tf -background $sb_opts(-background)]
04399 ctext $txt -wrap none -undo 1 -autoseparators 1 -insertofftime 0 \
04400 -highlightcolor orange -warnwidth [preferences::get Editor/WarningWidth] \
04401 -maxundo [preferences::get Editor/MaxUndo] \
04402 -insertwidth [preferences::get Appearance/CursorWidth] \
04403 -spacing2 [preferences::get Appearance/ExtraLineSpacing] \
04404 -spacing3 [preferences::get Appearance/ExtraLineSpacing] \
04405 -diff_mode $opts(-diff) -matchchar $show_match_chars \
04406 -matchaudit [preferences::get Editor/HighlightMismatchingChar] \
04407 -linemap_mark_command [list gui::mark_command $tab] -linemap_mark_color orange \
04408 -linemap_relief flat -linemap_minwidth $numberwidth -linemap_separator 1 \
04409 -linemap_type [expr {[preferences::get Editor/RelativeLineNumbers] ? "relative" : "absolute"}] \
04410 -linemap_align [preferences::get Editor/LineNumberAlignment] \
04411 -xscrollcommand [list $tab.pw.tf.hb set] -yscrollcommand [list gui::yscrollcommand $tab $txt $tab.pw.tf.vb]
04412 scroller::scroller $tab.pw.tf.hb {*}[array get sb_opts] -orient horizontal -autohide 0 -command [list $txt xview]
04413 scroller::scroller $tab.pw.tf.vb {*}[array get sb_opts] -orient vertical -autohide 1 -command [list gui::yview $tab $txt] \
04414 -markcommand1 [list markers::get_positions $tab] -markhide1 [expr [preferences::get View/ShowMarkerMap] ^ 1] \
04415 -markcommand2 [expr {$opts(-diff) ? [list diff::get_marks $txt] : ""}]
04416
04417 # Update the widgets to match the current theme
04418 update_theme $txt
04419
04420 # Register the widgets
04421 theme::register_widget $txt syntax
04422 theme::register_widget $tab.pw.tf.vb text_scrollbar
04423 theme::register_widget $tab.pw.tf.hb text_scrollbar
04424
04425 # Create the editor font if it does not currently exist
04426 if {[lsearch [font names] editor_font] == -1} {
04427 font create editor_font {*}[font configure TkFixedFont] {*}[preferences::get Appearance/EditorFont]
04428 }
04429
04430 $txt configure -font editor_font
04431
04432 bind Ctext <<Modified>> [list gui::text_changed %W %d]
04433 bind $txt.t <FocusIn> [list +gui::handle_txt_focus %W]
04434 bind $txt.t <<CursorChanged>> [list +gui::update_position $txt]
04435 bind $txt.l <ButtonPress-1> [list gui::select_line %W %x %y]
04436 bind $txt.l <B1-Motion> [list gui::select_lines %W %x %y]
04437 bind $txt.l <Shift-ButtonPress-1> [list gui::select_lines %W %x %y]
04438 bind $txt <<Selection>> [list gui::selection_changed $txt]
04439 bind $txt <Motion> [list gui::clear_tab_tooltip $tb]
04440 bind Text <<Cut>> ""
04441 bind Text <<Copy>> ""
04442 bind Text <<Paste>> ""
04443 bind Text <Control-d> ""
04444 bind Text <Control-i> ""
04445
04446 # Move the all bindtag ahead of the Text bindtag
04447 set text_index [lsearch [bindtags $txt.t] Text]
04448 set all_index [lsearch [bindtags $txt.t] all]
04449 bindtags $txt.t [lreplace [bindtags $txt.t] $all_index $all_index]
04450 bindtags $txt.t [linsert [bindtags $txt.t] $text_index all]
04451
04452 grid rowconfigure $tab.pw.tf 0 -weight 1
04453 grid columnconfigure $tab.pw.tf 0 -weight 1
04454 grid $tab.pw.tf.txt -row 0 -column 0 -sticky news
04455 grid $tab.pw.tf.vb -row 0 -column 1 -sticky ns
04456 grid $tab.pw.tf.hb -row 1 -column 0 -sticky ew
04457
04458 # Create the Vim command bar
04459 vim::bind_command_entry $txt [entry $tab.ve]
04460
04461 # Create the search type menu
04462 set type_menu [menu $tab.typeMenu -tearoff 0]
04463 set max_width [expr [msgcat::mcmax "Regexp" "Glob" "Exact"] + 1]
04464 $type_menu add radiobutton -label [msgcat::mc "Regexp"] -variable gui::search_method -value "regexp" -command [list gui::update_search_method $tab]
04465 $type_menu add radiobutton -label [msgcat::mc "Glob"] -variable gui::search_method -value "glob" -command [list gui::update_search_method $tab]
04466 $type_menu add radiobutton -label [msgcat::mc "Exact"] -variable gui::search_method -value "exact" -command [list gui::update_search_method $tab]
04467
04468 # Create the search bar
04469 ttk::frame $tab.sf
04470 ttk::label $tab.sf.l1 -text [format "%s:" [msgcat::mc "Find"]]
04471 ttk::entry $tab.sf.e -validate key -validatecommand [list gui::handle_search_change $tab %P]
04472 ttk::button $tab.sf.prev -style BButton -image search_prev -command [list gui::find_resilient prev] -state disabled
04473 ttk::button $tab.sf.next -style BButton -image search_next -command [list gui::find_resilient next] -state disabled
04474 ttk::button $tab.sf.type -style BButton -width $max_width -command [list gui::handle_menu_popup $tab.sf.type $type_menu]
04475 ttk::checkbutton $tab.sf.case -text " Aa" -variable gui::case_sensitive
04476 ttk::checkbutton $tab.sf.save -text [format " %s" [msgcat::mc "Save"]] -variable gui::saved -command [list search::update_save find]
04477 ttk::label $tab.sf.close -image form_close
04478
04479 tooltip::tooltip $tab.sf.next [msgcat::mc "Find next occurrence"]
04480 tooltip::tooltip $tab.sf.prev [msgcat::mc "Find previous occurrence"]
04481 tooltip::tooltip $tab.sf.case [msgcat::mc "Case sensitivity"]
04482 tooltip::tooltip $tab.sf.save [msgcat::mc "Save this search"]
04483
04484 pack $tab.sf.l1 -side left -padx 4 -pady 2
04485 pack $tab.sf.e -side left -padx 4 -pady 2 -fill x -expand yes
04486 pack $tab.sf.close -side right -padx 4 -pady 2
04487 pack $tab.sf.save -side right -padx 4 -pady 2
04488 pack $tab.sf.case -side right -padx 4 -pady 2
04489 pack $tab.sf.type -side right -padx 4 -pady 2
04490 pack $tab.sf.next -side right -padx 4 -pady 2
04491 pack $tab.sf.prev -side right -padx 4 -pady 2
04492
04493 bind $tab.sf.e <Escape> [list gui::close_search]
04494 bind $tab.sf.case <Escape> [list gui::close_search]
04495 bind $tab.sf.save <Escape> [list gui::close_search]
04496 bind $tab.sf.type <Escape> [list gui::close_search]
04497 bind $tab.sf.next <Escape> [list gui::close_search]
04498 bind $tab.sf.prev <Escape> [list gui::close_search]
04499 bind $tab.sf.e <Up> "search::traverse_history find 1; break"
04500 bind $tab.sf.e <Down> "search::traverse_history find -1; break"
04501 bind $tab.sf.close <Button-1> [list gui::close_search]
04502 bind $tab.sf.close <Key-space> [list gui::close_search]
04503
04504 # Create the search/replace bar
04505 ttk::frame $tab.rf
04506 ttk::label $tab.rf.fl -text [format "%s:" [msgcat::mc "Find"]]
04507 ttk::entry $tab.rf.fe -validate key -validatecommand [list gui::handle_replace_change $tab %P]
04508 ttk::label $tab.rf.rl -text [format "%s:" [msgcat::mc "Replace"]]
04509 ttk::entry $tab.rf.re
04510 ttk::frame $tab.rf.act
04511 ttk::button $tab.rf.act.prev -style BButton -image search_prev -command [list gui::find_resilient prev replace] -state disabled
04512 ttk::button $tab.rf.act.next -style BButton -image search_next -command [list gui::find_resilient next replace] -state disabled
04513 ttk::button $tab.rf.act.rep -style BButton -text [msgcat::mc "Replace"] -command [list search::replace_one] -state disabled
04514 ttk::button $tab.rf.act.repa -style BButton -text [msgcat::mc "Replace All"] -command [list search::replace_start 1] -state disabled
04515 ttk::frame $tab.rf.opts
04516 ttk::button $tab.rf.opts.type -style BButton -width $max_width -command [list gui::handle_menu_popup $tab.rf.opts.type $type_menu]
04517 ttk::checkbutton $tab.rf.opts.case -text " Aa" -variable gui::case_sensitive
04518 ttk::checkbutton $tab.rf.opts.save -text [format " %s" [msgcat::mc "Save"]] -variable gui::saved \
04519 -command [list search::update_save replace]
04520 ttk::label $tab.rf.close -image form_close
04521 ttk::separator $tab.rf.sep -orient horizontal
04522
04523 tooltip::tooltip $tab.rf.act.next [msgcat::mc "Find next occurrence"]
04524 tooltip::tooltip $tab.rf.act.prev [msgcat::mc "Find previous occurrence"]
04525 tooltip::tooltip $tab.rf.opts.case [msgcat::mc "Case sensitivity"]
04526 tooltip::tooltip $tab.rf.opts.save [msgcat::mc "Save this search"]
04527
04528 pack $tab.rf.act.prev -side left -padx 4
04529 pack $tab.rf.act.next -side left -padx 4
04530 pack $tab.rf.act.rep -side left -padx 4
04531 pack $tab.rf.act.repa -side left -padx 4
04532
04533 pack $tab.rf.opts.type -side left -padx 4
04534 pack $tab.rf.opts.case -side left -padx 4
04535 pack $tab.rf.opts.save -side right -padx 4
04536
04537 grid columnconfigure $tab.rf 1 -weight 1
04538 grid $tab.rf.fl -row 0 -column 0 -sticky news -padx 4 -pady 2
04539 grid $tab.rf.fe -row 0 -column 1 -sticky news -padx 4 -pady 2
04540 grid $tab.rf.act -row 0 -column 2 -sticky news -padx 4 -pady 2
04541 grid $tab.rf.close -row 0 -column 3 -sticky news -padx 4 -pady 2
04542 grid $tab.rf.rl -row 1 -column 0 -sticky news -padx 4 -pady 2
04543 grid $tab.rf.re -row 1 -column 1 -sticky news -padx 4 -pady 2
04544 grid $tab.rf.opts -row 1 -column 2 -sticky news -padx 4 -pady 2
04545 grid $tab.rf.sep -row 2 -column 0 -sticky news -column 4
04546
04547 bind $tab.rf.fe <Return> [list search::replace_start]
04548 bind $tab.rf.re <Return> [list search::replace_start]
04549 bind $tab.rf.opts.type <Return> [list search::replace_start]
04550 bind $tab.rf.opts.case <Return> [list search::replace_start]
04551 bind $tab.rf.opts.save <Return> [list search::replace_start]
04552 bind $tab.rf.fe <Escape> [list gui::close_search_and_replace]
04553 bind $tab.rf.re <Escape> [list gui::close_search_and_replace]
04554 bind $tab.rf.opts.type <Escape> [list gui::close_search_and_replace]
04555 bind $tab.rf.opts.case <Escape> [list gui::close_search_and_replace]
04556 bind $tab.rf.opts.save <Escape> [list gui::close_search_and_replace]
04557 bind $tab.rf.act.prev <Escape> [list gui::close_search_and_replace]
04558 bind $tab.rf.act.next <Escape> [list gui::close_search_and_replace]
04559 bind $tab.rf.act.rep <Escape> [list gui::close_search_and_replace]
04560 bind $tab.rf.act.repa <Escape> [list gui::close_search_and_replace]
04561 bind $tab.rf.close <Button-1> [list gui::close_search_and_replace]
04562 bind $tab.rf.close <Key-space> [list gui::close_search_and_replace]
04563 bind $tab.rf.fe <Up> "search::traverse_history replace 1; break"
04564 bind $tab.rf.fe <Down> "search::traverse_history replace -1; break"
04565
04566 # Create the diff bar
04567 if {$opts(-diff)} {
04568 ttk::frame $tab.df
04569 pack [diff::create_diff_bar $txt $tab.df.df] -fill x
04570 pack [ttk::separator $tab.df.sep -orient horizontal] -fill x
04571 }
04572
04573 grid rowconfigure $tab 0 -weight 1
04574 grid columnconfigure $tab 0 -weight 1
04575 grid $tab.pw -row 0 -column 0 -sticky news
04576 # grid $tab.sb -row 0 -column 2 -sticky news
04577 if {$opts(-diff)} {
04578 grid $tab.df -row 1 -column 0 -sticky ew -columnspan 2
04579 }
04580
04581 # grid remove $tab.sb
04582
04583 # Separator
04584 ttk::separator $tab.sep -orient horizontal
04585
04586 # Get the adjusted index
04587 set adjusted_index [$tb index $index]
04588
04589 # Add the text bindings
04590 if {!$opts(-diff)} {
04591 indent::add_bindings $txt
04592 vim::set_vim_mode $txt
04593 multicursor::add_bindings $txt
04594 completer::add_bindings $txt
04595 }
04596 select::add $txt $tab.sb
04597 plugins::handle_text_bindings $txt $opts(-tags)
04598 make_drop_target $txt text
04599
04600 # Apply the appropriate syntax highlighting for the given extension
04601 syntax::set_language $txt [expr {($opts(-lang) eq "") ? [syntax::get_default_language $fname] : $opts(-lang)}]
04602
04603 # Snippet bindings must go after syntax language setting
04604 if {!$opts(-diff)} {
04605 snippets::add_bindings $txt
04606 folding::initialize $txt
04607 }
04608
04609 # Add any gutters
04610 foreach gutter $opts(-gutters) {
04611 $txt gutter create {*}$gutter
04612 }
04613
04614 # Add the new tab to the notebook in alphabetical order (if specified) and if
04615 # the given index is "end"
04616 if {[preferences::get View/OpenTabsAlphabetically] && ($index eq "end")} {
04617 set added 0
04618 foreach t [$tb tabs] {
04619 if {[string compare " $title" [$tb tab $t -text]] == -1} {
04620 $tb insert $t $tab -text " $title" -emboss 0
04621 set added 1
04622 break
04623 }
04624 }
04625 if {$added == 0} {
04626 $tb insert end $tab -text " $title" -emboss 0
04627 }
04628
04629 # Otherwise, add the tab in the specified location
04630 } else {
04631 $tb insert $index $tab -text " $title" -emboss 0
04632 }
04633
04634 # Display the bird's eye viewer
04635 if {[preferences::get View/ShowBirdsEyeView]} {
04636 show_birdseye $tab
04637 }
04638
04639 return $tab
04640
04641 }
04642
04643 ######################################################################
04644 # Adds a peer ctext widget to the current widget in the pane just below
04645 # the current pane.
04646 #
04647 # TBD - This is missing support for applied gutters!
04648 proc show_split_pane {tab} {
04649
04650 variable show_match_chars
04651
04652 # Get the current paned window
04653 get_info $tab tab tabbar txt txt2 diff
04654
04655 # Get the paned window of the text widget
04656 set pw [winfo parent [winfo parent $txt]]
04657
04658 # Get the scrollbar coloring information
04659 array set sb_opts [set scrollbar_opts [theme::get_category_options text_scrollbar 1]]
04660
04661 # Create the editor frame
04662 $pw insert 0 [frame $pw.tf2 -background $sb_opts(-background)]
04663 ctext $txt2 -wrap none -undo 1 -autoseparators 1 -insertofftime 0 -font editor_font \
04664 -insertwidth [preferences::get Appearance/CursorWidth] \
04665 -spacing2 [preferences::get Appearance/ExtraLineSpacing] \
04666 -spacing3 [preferences::get Appearance/ExtraLineSpacing] \
04667 -highlightcolor orange -warnwidth [preferences::get Editor/WarningWidth] \
04668 -maxundo [preferences::get Editor/MaxUndo] -matchchar $show_match_chars \
04669 -matchaudit [preferences::get Editor/HighlightMismatchingChar] \
04670 -linemap [preferences::get View/ShowLineNumbers] -linemap_separator 1 \
04671 -linemap_mark_command [list gui::mark_command $tab] -linemap_mark_color orange -peer $txt \
04672 -linemap_align [preferences::get Editor/LineNumberAlignment] \
04673 -xscrollcommand "$pw.tf2.hb set" \
04674 -yscrollcommand "$pw.tf2.vb set"
04675 scroller::scroller $pw.tf2.hb {*}$scrollbar_opts -orient horizontal -autohide 0 -command "$txt2 xview"
04676 scroller::scroller $pw.tf2.vb {*}$scrollbar_opts -orient vertical -autohide 1 -command "$txt2 yview" \
04677 -markcommand1 [list markers::get_positions $tab] -markhide1 [expr [preferences::get View/ShowMarkerMap] ^ 1] \
04678 -markcommand2 [expr {$diff ? [list diff::get_marks $txt] : ""}]
04679
04680 # Update the widgets to match the current theme
04681 update_theme $txt2
04682
04683 # Register the widgets
04684 theme::register_widget $txt2 syntax_split
04685 theme::register_widget $pw.tf2.vb text_scrollbar
04686 theme::register_widget $pw.tf2.hb text_scrollbar
04687
04688 bind $txt2.t <FocusIn> [list +gui::handle_txt_focus %W]
04689 bind $txt2.t <<CursorChanged>> [list +gui::update_position $txt2]
04690 bind $txt2.l <ButtonPress-1> [list gui::select_line %W %x %y]
04691 bind $txt2.l <B1-Motion> [list gui::select_lines %W %x %y]
04692 bind $txt2.l <Shift-ButtonPress-1> [list gui::select_lines %W %x %y]
04693 bind $txt2 <<Selection>> [list gui::selection_changed $txt2]
04694 bind $txt2 <Motion> [list gui::clear_tab_tooltip $tabbar]
04695
04696 # Move the all bindtag ahead of the Text bindtag
04697 set text_index [lsearch [bindtags $txt2.t] Text]
04698 set all_index [lsearch [bindtags $txt2.t] all]
04699 bindtags $txt2.t [lreplace [bindtags $txt2.t] $all_index $all_index]
04700 bindtags $txt2.t [linsert [bindtags $txt2.t] $text_index all]
04701
04702 grid rowconfigure $pw.tf2 0 -weight 1
04703 grid columnconfigure $pw.tf2 0 -weight 1
04704 grid $pw.tf2.txt -row 0 -column 0 -sticky news
04705 grid $pw.tf2.vb -row 0 -column 1 -sticky ns
04706 grid $pw.tf2.hb -row 1 -column 0 -sticky ew
04707
04708 # Associate the existing command entry field with this text widget
04709 vim::bind_command_entry $txt2 $tab.ve
04710
04711 # Add the text bindings
04712 indent::add_bindings $txt2
04713 vim::set_vim_mode $txt2
04714 multicursor::add_bindings $txt2
04715 completer::add_bindings $txt2
04716 plugins::handle_text_bindings $txt2 {}
04717 make_drop_target $txt2 text
04718
04719 # Apply the appropriate syntax highlighting for the given extension
04720 syntax::set_language $txt2 [syntax::get_language $txt]
04721
04722 # Snippet bindings must go after syntax language is set
04723 snippets::add_bindings $txt2
04724
04725 # Apply code foldings
04726 folding::initialize $txt2
04727
04728 # Give the text widget the focus
04729 set_txt_focus $txt2
04730
04731 }
04732
04733 ######################################################################
04734 # Called when the given text widget is destroyed.
04735 proc handle_destroy_txt {txt} {
04736
04737 variable line_sel_anchor
04738 variable txt_current
04739 variable cursor_hist
04740 variable be_after_id
04741 variable be_ignore
04742 variable undo_count
04743
04744 set tab [join [lrange [split $txt .] 0 end-3] .]
04745
04746 catch { unset line_sel_anchor($txt.l) }
04747 catch { unset txt_current($tab) }
04748 catch { unset undo_count($tab) }
04749 catch { array unset cursor_hist $txt,* }
04750
04751 # Only unset the bird's eye variables if we are destroying txt
04752 if {[lindex [split $txt .] end-1] eq "tf"} {
04753 catch { unset be_after_id($tab) }
04754 catch { unset be_ignore($tab) }
04755 }
04756
04757 }
04758
04759 ######################################################################
04760 # Removes the split pane
04761 proc hide_split_pane {tab} {
04762
04763 # Get the current paned window
04764 get_info $tab tab txt
04765 set pw [winfo parent [winfo parent $txt]]
04766
04767 # Delete the extra text widget
04768 $pw forget $pw.tf2
04769
04770 # Destroy the extra text widget frame
04771 destroy $pw.tf2
04772
04773 # Cleanup the text widget
04774 cleanup_txt $pw.tf2.txt
04775
04776 # Set the focus back on the tf text widget
04777 set_txt_focus $pw.tf.txt
04778
04779 }
04780
04781 ######################################################################
04782 # Creates and displays the bird's eye viewer in the same editing buffer
04783 # as the specified text widget.
04784 proc show_birdseye {tab} {
04785
04786 variable be_after_id
04787 variable be_ignore
04788
04789 # Get the tab that contains the text widget
04790 get_info $tab tab txt beye
04791
04792 if {![winfo exists $beye]} {
04793
04794 # Calculate the background color
04795 set background [utils::auto_adjust_color [$txt cget -background] 25]
04796
04797 # Create the bird's eye viewer
04798 $txt._t peer create $beye -width [preferences::get View/BirdsEyeViewWidth] -bd 0 \
04799 -highlightthickness 0 -font "-size [preferences::get View/BirdsEyeViewFontSize]" \
04800 -wrap none -cursor [ttk::cursor standard] \
04801 -background [$txt cget -background] -foreground [$txt cget -foreground] \
04802 -inactiveselectbackground $background -selectbackground $background
04803
04804 # Add the bird's eye viewer to the tab's grid manager
04805 grid $beye -row 0 -column 1 -sticky ns
04806
04807 # Setup bindings
04808 bind $beye <Enter> [list gui::handle_birdseye_enter %W $txt %m]
04809 bind $beye <Leave> [list gui::handle_birdseye_leave %W %m]
04810 bind $beye <ButtonPress-1> [list gui::handle_birdseye_left_press %W %x %y $tab $txt]
04811 bind $beye <B1-Motion> [list gui::handle_birdseye_motion %W %x %y $tab $txt]
04812 bind $beye <Control-Button-1> [list gui::handle_birdseye_control_left %W]
04813 bind $beye <Control-Button-$::right_click> [list gui::handle_birdseye_control_right %W]
04814 bind $beye <MouseWheel> [bind Text <MouseWheel>]
04815 bind $beye <Button-4> [bind Text <Button-4>]
04816 bind $beye <Button-5> [bind Text <Button-5>]
04817
04818 set index [lsearch [bindtags $beye] "Text"]
04819 bindtags $beye [lreplace [bindtags $beye] $index $index]
04820
04821 set be_after_id($tab) ""
04822 set be_ignore($tab) 0
04823
04824 # Make sure that the bird's eye viewer is below any lower panel
04825 lower $beye
04826
04827 }
04828
04829 }
04830
04831 ######################################################################
04832 # Highlights the currently displayed area in the text widget.
04833 proc highlight_birdseye {be txt} {
04834
04835 # Get the start and end shown lines of the given text widget
04836 set startline [$txt index @0,0]
04837 set endline [$txt index @0,[winfo height $txt]]
04838
04839 # Set the selection
04840 $be tag remove sel 1.0 end
04841 $be tag add sel $startline $endline
04842
04843 }
04844
04845 ######################################################################
04846 # Handles the mouse entering the bird's eye view. This will cause the
04847 # currently displayed text region to be selected in the bird's eye viewer.
04848 proc handle_birdseye_enter {be txt m} {
04849
04850 variable be_show_after_id
04851
04852 if {$m eq "NotifyNormal"} {
04853
04854 # Highlight the shown text
04855 set be_show_after_id [after 300 [list gui::highlight_birdseye $be $txt]]
04856
04857 }
04858
04859 }
04860
04861 ######################################################################
04862 # Handles the mouse leaving the bird's eye viewer.
04863 proc handle_birdseye_leave {be m} {
04864
04865 variable be_show_after_id
04866
04867 if {$m eq "NotifyNormal"} {
04868
04869 # Cancel the bird's eye show activity if it is valid
04870 after cancel $be_show_after_id
04871
04872 # Clear the selection
04873 $be tag remove sel 1.0 end
04874
04875 }
04876
04877 }
04878
04879 ######################################################################
04880 # Handles a left button press event inside the bird's eye viewer.
04881 proc handle_birdseye_left_press {W x y tab txt} {
04882
04883 variable be_last_y
04884 variable be_ignore
04885
04886 set cursor [$W index @$x,$y]
04887
04888 lassign [$W tag ranges sel] selstart selend
04889
04890 # If we clicked on the selection, start a motion event
04891 if {[$W compare $selstart <= $cursor] && [$W compare $selend >= $cursor]} {
04892 set be_last_y $y
04893
04894 # Otherwise, jump the view to the given location
04895 } else {
04896
04897 set be_last_y ""
04898 set height [winfo height $txt]
04899 set be_ignore($tab) 1
04900
04901 # TBD - We will want to make sure that the cursor line is centered vertically
04902 $txt see $cursor
04903 $txt yview scroll [expr [lindex [$txt bbox $cursor] 1] - ($height / 2)] pixels
04904
04905 # Highlight the bird's eye viewer
04906 highlight_birdseye $W $txt
04907
04908 }
04909
04910 return 1
04911
04912 }
04913
04914 ######################################################################
04915 # Handles a left button motion event inside the bird's eye viewer.
04916 proc handle_birdseye_motion {W x y tab txt} {
04917
04918 variable be_last_y
04919 variable be_ignore
04920
04921 if {($be_last_y ne "") && ($y != $be_last_y)} {
04922
04923 # Get the current cursor
04924 set cursor [$W index @$x,$y]
04925 set height [winfo height $txt]
04926 set be_ignore($tab) 1
04927
04928 # TBD - We will want to make sure that the cursor line is centered vertically
04929 $txt see $cursor
04930 $txt yview scroll [expr [lindex [$txt bbox $cursor] 1] - ($height / 2)] pixels
04931
04932 # Highlight the bird's eye viewer to match the text widget
04933 highlight_birdseye $W $txt
04934
04935 }
04936
04937 return 1
04938
04939 }
04940
04941 ######################################################################
04942 # Handles a control left-click event in the birdseye.
04943 proc handle_birdseye_control_left {W} {
04944
04945 $W yview scroll -1 pages
04946
04947 }
04948
04949 ######################################################################
04950 # Handles a control right-click event in the birdseye.
04951 proc handle_birdseye_control_right {W} {
04952
04953 $W yview scroll 1 pages
04954
04955 }
04956
04957 ######################################################################
04958 # Hides the bird's eye viewer associated with the given text widget.
04959 proc hide_birdseye {tab} {
04960
04961 variable be_after_id
04962 variable be_ignore
04963
04964 # Get the tab that contains the bird's eye viewer
04965 get_info $tab tab beye
04966
04967 if {[winfo exists $beye]} {
04968
04969 # Cancel the scroll event if one is still set
04970 if {$be_after_id($tab) ne ""} {
04971 after cancel $be_after_id($tab)
04972 }
04973
04974 # Remove the be_after_id
04975 unset be_after_id($tab)
04976 unset be_ignore($tab)
04977
04978 # Remove the widget from the grid
04979 grid forget $beye
04980
04981 # Destroy the bird's eye viewer
04982 destroy $beye
04983
04984 }
04985
04986 }
04987
04988 ######################################################################
04989 # Adds the necessary bindings to make the given text/entry widget a drop
04990 # target for TkDND. Type should be set to text or entry.
04991 proc make_drop_target {win type args} {
04992
04993 array set opts {
04994 -types {files dirs text}
04995 -force 0
04996 }
04997 array set opts $args
04998
04999 set types [list]
05000 if {[lsearch $opts(-types) *s] != -1} { lappend types DND_Files }
05001 if {[lsearch $opts(-types) text] != -1} { lappend types DND_Text }
05002
05003 # Make ourselves a drop target (if Tkdnd is available)
05004 catch {
05005
05006 tkdnd::drop_target register $win $types
05007
05008 bind $win <<DropEnter>> [list gui::handle_drop_enter %W $type %a %b $opts(-force)]
05009 bind $win <<DropLeave>> [list gui::handle_drop_leave %W $type]
05010 bind $win <<Drop:DND_Files>> [list gui::handle_drop %W $type %A %m 0 %D $opts(-types)]
05011 bind $win <<Drop:DND_Text>> [list gui::handle_drop %W $type %A %m 1 %D $opts(-types)]
05012
05013 }
05014
05015 }
05016
05017 ######################################################################
05018 # Front-end handler for the drop_enter method.
05019 proc handle_drop_enter {win type actions buttons force} {
05020
05021 if {!$force && ([$win cget -state] ne "normal")} {
05022 return "refuse_drop"
05023 }
05024
05025 if {[catch { handle_${type}_drop_enter $win $actions $buttons } rc] || ($rc == 0)} {
05026 return "refuse_drop"
05027 }
05028
05029 return "link"
05030
05031 }
05032
05033 ######################################################################
05034 # Front-end handler for the drop method.
05035 proc handle_drop {win type actions modifiers dtype data types} {
05036
05037 # If we are attempting to drop a file, check to see if it is the proper type
05038 if {$dtype == 0} {
05039 set tdata [list]
05040 set files [expr {[lsearch $types files] != -1}]
05041 set dirs [expr {[lsearch $types dirs] != -1}]
05042 foreach item $data {
05043 if {($files && [file isfile $item]) || ($dirs && [file isdirectory $item])} {
05044 lappend tdata $item
05045 }
05046 }
05047 set data $tdata
05048 }
05049
05050 if {$data ne ""} {
05051 catch { handle_${type}_drop $win $actions $modifiers $dtype $data {*}[array get opts] }
05052 }
05053
05054 catch { handle_${type}_drop_leave $win }
05055
05056 return "link"
05057
05058 }
05059
05060 ######################################################################
05061 # Front-end handler for the drop leave method.
05062 proc handle_drop_leave {win type} {
05063
05064 catch { handle_${type}_drop_leave $win }
05065
05066 }
05067
05068 ######################################################################
05069 # Handles a drag-and-drop enter/position event. Draws UI to show that
05070 # the file drop request would be excepted or rejected.
05071 proc handle_text_drop_enter {txt actions buttons args} {
05072
05073 get_info $txt txt readonly lock diff
05074
05075 # If the file is readonly, refuse the drop
05076 if {$readonly || $lock || $diff} {
05077 return 0
05078 }
05079
05080 # Make sure the text widget has the focus
05081 focus -force $txt.t
05082
05083 # Set the highlight color to green
05084 ctext::set_border_color $txt green
05085
05086 return 1
05087
05088 }
05089
05090 ######################################################################
05091 # Called when the user drags a droppable item over the given entry widget.
05092 proc handle_entry_drop_enter {win actions buttons args} {
05093
05094 # Make sure that the text window has the focus
05095 focus -force $win
05096
05097 # Cause the entry field to display that it can accept the data
05098 $win state alternate
05099
05100 return 1
05101
05102 }
05103
05104 ######################################################################
05105 # Indicates that an item can be dropped in the tokentry.
05106 proc handle_tokenentry_drop_enter {win actions buttons args} {
05107
05108 # Display the highlight color
05109 $win configure -highlightbackground green -highlightcolor green
05110
05111 # Make sure the entry received focus
05112 focus -force $win
05113
05114 return 1
05115
05116 }
05117
05118 ######################################################################
05119 # Handles a drop leave event.
05120 proc handle_text_drop_leave {txt} {
05121
05122 # Set the highlight color to green
05123 ctext::set_border_color $txt white
05124
05125 }
05126
05127 ######################################################################
05128 # Handles a drag leave event.
05129 proc handle_entry_drop_leave {win} {
05130
05131 $win state focus
05132
05133 }
05134
05135 ######################################################################
05136 # Handles a drag leave event.
05137 proc handle_tokenentry_drop_leave {win} {
05138
05139 $win configure -highlightbackground white -highlightcolor white
05140
05141 }
05142
05143 ######################################################################
05144 # If the editing buffer has formatting support for links/images, adjusts
05145 # the supplied data to be formatted.
05146 proc format_dropped_data {txt pdata pcursor} {
05147
05148 upvar $pdata data
05149 upvar $pcursor cursor
05150
05151 # Get the formatting information for the current editing buffer
05152 array set formatting [syntax::get_formatting $txt]
05153
05154 # If the data is an image, adjust for an image if we can
05155 if {[lsearch [list .png .jpg .jpeg .gif .bmp .tiff .svg] [string tolower [file extension $data]]] != -1} {
05156 if {[info exists formatting(image)]} {
05157 set pattern [lindex $formatting(image) 1]
05158 set cursor [string first \{TEXT\} $pattern]
05159 set data [string map [list \{REF\} $data \{TEXT\} {}] $pattern]
05160 }
05161
05162 # Otherwise, if the data looks like a URL reference, change the data to a
05163 # link if we can
05164 } elseif {[utils::is_url $data]} {
05165 if {[info exists formatting(link)]} {
05166 set pattern [lindex $formatting(link) 1]
05167 set cursor [string first \{TEXT\} $pattern]
05168 set data [string map [list \{REF\} $data \{TEXT\} {}] $pattern]
05169 }
05170 }
05171
05172 }
05173
05174 ######################################################################
05175 # Handles a drop event. Adds the given files/directories to the sidebar.
05176 proc handle_text_drop {txt action modifier dtype data args} {
05177
05178 gui::get_info $txt txt fileindex
05179
05180 # If the data is text or the Alt key modifier is held during the drop, insert the data at the
05181 # current insertion point
05182 if {[plugins::handle_on_drop $fileindex $dtype $data]} {
05183 # Do nothing
05184
05185 # If we are inserting text or the file name, do that now
05186 } elseif {$dtype} {
05187
05188 set cursor 0
05189
05190 # Attempt to format the data
05191 format_dropped_data $txt data cursor
05192
05193 # Insert the data
05194 if {[multicursor::enabled $txt.t]} {
05195 multicursor::insert $txt.t $data
05196 } else {
05197 $txt insert insert $data
05198 }
05199
05200 # If we need to adjust the cursor(s) do it now.
05201 if {$cursor != 0} {
05202 # TBD
05203 }
05204
05205 # Otherwise, insert the content of the file(s) after the insertion line
05206 } elseif {![::check_file_for_import $data] && ![utils::is_binary $data]} {
05207 set str "\n"
05208 foreach ifile $data {
05209 if {[file isfile $ifile]} {
05210 if {![catch { open $ifile r } rc]} {
05211 append str [read $rc]
05212 close $rc
05213 }
05214 }
05215 }
05216 if {[multicursor::enabled $txt.t]} {
05217 multicursor::insert $txt.t $str
05218 } else {
05219 $txt insert "insert lineend" $str
05220 }
05221 }
05222
05223 }
05224
05225 ######################################################################
05226 # Called if the user drops the given data into the entry field. If the
05227 # data is text, insert the text at the current insertion point. If the
05228 # data is a file, insert the filename at the current insertion point.
05229 proc handle_entry_drop {win action modifier dtype data args} {
05230
05231 # We are not going to allow
05232 if {($dtype == 0) && ([llength $data] > 1)} {
05233 return
05234 }
05235
05236 # Get the state before the drop
05237 set state [$win cget -state]
05238
05239 # Allow the entry field to be modified and clear the field
05240 $win configure -state normal
05241 $win delete 0 end
05242
05243 # Insert the information
05244 $win insert insert {*}$data
05245
05246 # Return the state of the entry field
05247 $win configure -state $state
05248
05249 }
05250
05251 ######################################################################
05252 # Called if the user drops the given data into the tokenentry field.
05253 proc handle_tokenentry_drop {win action modifier dtype data args} {
05254
05255 # Insert the information
05256 $win tokeninsert end $data
05257
05258 }
05259
05260 ######################################################################
05261 # Handles a change to the current text widget.
05262 proc text_changed {txt data} {
05263
05264 variable cursor_hist
05265
05266 if {[$txt edit modified]} {
05267
05268 # Get file information
05269 get_info $txt txt tabbar tab fileindex readonly
05270
05271 if {!$readonly && ([lindex $data 2] ne "ignore")} {
05272 set_current_modified 1
05273 }
05274
05275 # Clear the cursor history
05276 array unset cursor_hist $txt,*
05277
05278 }
05279
05280 # Update the folding gutter
05281 if {[lindex $data 2] ne "ignore"} {
05282 foreach {startpos endpos} [lindex $data 1] {
05283 folding::add_folds $txt $startpos $endpos
05284 }
05285 }
05286
05287 }
05288
05289 ######################################################################
05290 # Handles a change to the current text widget selection.
05291 proc selection_changed {txt} {
05292
05293 # Get the first range of selected text
05294 if {[set range [$txt tag nextrange sel 1.0]] ne ""} {
05295
05296 # Get the current search entry field
05297 set sentry [current_search]
05298
05299 # Set the search frame
05300 $sentry delete 0 end
05301 $sentry insert end [$txt get {*}$range]
05302
05303 }
05304
05305 }
05306
05307 ######################################################################
05308 # Selects the given line in the text widget.
05309 proc select_line {w x y} {
05310
05311 variable line_sel_anchor
05312
05313 # Get the parent window
05314 set txt [winfo parent $w]
05315
05316 # Get the last line
05317 set fontwidth [font measure [$txt cget -font] -displayof . "0"]
05318 set last_line [lindex [split [$txt index end-1c] .] 0]
05319 set line_chars [expr ([$txt cget -linemap] ? max( [$txt cget -linemap_minwidth], [string length $last_line] ) : 1) + 1]
05320
05321 # We will only select the line if we clicked in the line number area
05322 if {$x > ($fontwidth * $line_chars)} {
05323 return
05324 }
05325
05326 # Get the current line from the line sidebar
05327 set index [$txt index @0,$y]
05328
05329 # Select the corresponding line in the text widget
05330 $txt tag remove sel 1.0 end
05331 $txt tag add sel "$index linestart" "$index lineend"
05332
05333 $txt mark set insert "$index lineend"
05334 vim::adjust_insert $txt.t
05335
05336 # Save the selected line to the anchor
05337 set line_sel_anchor($w) $index
05338
05339 }
05340
05341 ######################################################################
05342 # Selects all lines between the anchored line and the current line,
05343 # inclusive.
05344 proc select_lines {w x y} {
05345
05346 variable line_sel_anchor
05347
05348 # Get the parent window
05349 set txt [winfo parent $w]
05350
05351 # Get the last line
05352 set fontwidth [font measure [$txt cget -font] -displayof . "0"]
05353 set last_line [lindex [split [$txt index end-1c] .] 0]
05354 set line_chars [expr ([$txt cget -linemap] ? max( [$txt cget -linemap_minwidth], [string length $last_line] ) : 1) + 1]
05355
05356 # We will only select the line if we clicked in the line number area
05357 if {$x > ($fontwidth * $line_chars)} {
05358 return
05359 }
05360
05361 # Get the current line from the line sidebar
05362 set index [$txt index @$x,$y]
05363
05364 # Remove the current selection
05365 $txt tag remove sel 1.0 end
05366
05367 # If the anchor has not been set, set it now
05368 if {![info exists line_sel_anchor($w)]} {
05369 set line_sel_anchor($w) $index
05370 }
05371
05372 # Add the selection between the anchor and this line, inclusive
05373 if {[$txt compare $index < $line_sel_anchor($w)]} {
05374 $txt tag add sel "$index linestart" "$line_sel_anchor($w) lineend"
05375 $txt mark set insert "$line_sel_anchor($w) lineend"
05376 } else {
05377 $txt tag add sel "$line_sel_anchor($w) linestart" "$index lineend"
05378 $txt mark set insert "$index lineend"
05379 }
05380
05381 # Make sure that the insertion cursor is handled properly when in Vim mode
05382 vim::adjust_insert $txt.t
05383
05384 }
05385
05386 ######################################################################
05387 # Make the specified tab the current tab.
05388 proc set_current_tab {tabbar tab} {
05389
05390 variable widgets
05391 variable pw_current
05392
05393 # Get the frame containing the text widget
05394 set tf [winfo parent [winfo parent $tabbar]].tf
05395
05396 # If there is no tab being set, just delete the packed slave
05397 if {$tab eq ""} {
05398 if {[set slave [pack slaves $tf]] ne ""} {
05399 pack forget $slave
05400 }
05401 return
05402 }
05403
05404 # Get the tab's file information
05405 get_info $tab tab fname remote
05406
05407 # Make sure that the tab state is shown
05408 $tabbar tab $tab -state normal
05409
05410 # Make sure the sidebar is updated properly
05411 sidebar::set_hide_state $fname $remote 0
05412
05413 # Make the tab the selected tab in the tabbar
05414 $tabbar select $tab
05415
05416 # Make sure that the tab's content is displayed
05417 show_current_tab $tabbar
05418
05419 }
05420
05421 ######################################################################
05422 # Causes the currently selected tab contents to be displayed to the
05423 # screen. This procedure is called by the tabbar when the user releases
05424 # the mouse button so it is assumed that the tabbar and tab parameters
05425 # are always valid.
05426 proc show_current_tab {tabbar} {
05427
05428 variable widgets
05429 variable pw_current
05430 variable auto_cwd
05431
05432 # Get the frame containing the text widget
05433 set tf [winfo parent [winfo parent $tabbar]].tf
05434
05435 # If the current tabbar contains no visible tabs, remove the editing frame
05436 if {[$tabbar select] eq ""} {
05437 if {[set slave [pack slaves $tf]] ne ""} {
05438 pack forget $slave
05439 }
05440 return
05441 }
05442
05443 # Get the current information
05444 get_info $tabbar tabbar tab paneindex fname buffer diff
05445
05446 # If nothing is changing, stop now
05447 if {($pw_current eq $paneindex) && ([pack slaves $tf] eq $tab)} {
05448 return
05449 }
05450
05451 # Update the current panedwindow indicator
05452 set pw_current $paneindex
05453
05454 # Add the tab content, if necessary
05455 add_tab_content $tab
05456
05457 # Remove the current tab frame (if it exists)
05458 if {[set slave [pack slaves $tf]] ne ""} {
05459 pack forget $slave
05460 }
05461
05462 # Display the tab frame
05463 pack [$tabbar select] -in $tf -fill both -expand yes
05464
05465 # Update the pane synchronization status
05466 pane_sync_tab_change
05467
05468 # Update the preferences
05469 preferences::update_prefs [sessions::current]
05470
05471 # Reload the snippets to correspond to the current file
05472 snippets::reload_snippets
05473
05474 # Update the encoding indicator
05475 update_encode_button
05476
05477 # Update the indentation indicator
05478 indent::update_button $widgets(info_indent)
05479
05480 # Set the syntax menubutton to the current language
05481 syntax::update_button $widgets(info_syntax)
05482
05483 # If we are supposed to automatically change the working directory, do it now
05484 if {$auto_cwd && !$buffer && !$diff} {
05485 cd [file dirname $fname]
05486 }
05487
05488 # Make sure that the title bar is updated
05489 set_title
05490
05491 # Set the text focus
05492 set_txt_focus [last_txt_focus $tab]
05493
05494 }
05495
05496 ######################################################################
05497 # Handles a selection made by the user from the tabbar.
05498 proc handle_tabbar_select {tabbar args} {
05499
05500 show_current_tab $tabbar
05501
05502 }
05503
05504 ######################################################################
05505 # Returns the current text widget pathname (or the empty string if
05506 # there is no current text widget).
05507 proc current_txt {} {
05508
05509 if {[catch { get_info {} current focus } focus]} {
05510 return [expr {[catch { get_info {} current txt } txt] ? "" : $txt}]
05511 }
05512
05513 return $focus
05514
05515 }
05516
05517 ######################################################################
05518 # Returns the current search entry pathname.
05519 proc current_search {} {
05520
05521 get_info {} current tab
05522
05523 return $tab.sf.e
05524
05525 }
05526
05527 ######################################################################
05528 # Updates the current position information in the information bar based
05529 # on the current location of the insertion cursor.
05530 proc update_position {txt} {
05531
05532 variable widgets
05533
05534 # Get the current position of the insertion cursor
05535 lassign [split [$txt index insert] .] line column
05536
05537 # Update the information widgets
05538 if {[set vim_mode [expr {[select::in_select_mode $txt.t stype] ? "[string toupper $stype] SELECT MODE" : [vim::get_mode $txt]}]] ne ""} {
05539 if {$vim_mode eq "MULTIMOVE MODE"} {
05540 $widgets(info_state) configure -text [format "%s" $vim_mode]
05541 } else {
05542 $widgets(info_state) configure -text [format "%s, %s: %d, %s: %d" $vim_mode [msgcat::mc "Line"] $line [msgcat::mc "Column"] [expr $column + 1]]
05543 }
05544 } else {
05545 $widgets(info_state) configure -text [format "%s: %d, %s: %d" [msgcat::mc "Line"] $line [msgcat::mc "Column"] [expr $column + 1]]
05546 }
05547
05548 }
05549
05550 ######################################################################
05551 # Display the file count information in the status bar.
05552 proc display_file_counts {txt} {
05553
05554 variable widgets
05555
05556 # Get the current position of the insertion cursor
05557 lassign [split [$txt index insert] .] line column
05558
05559 # Get the total line count
05560 set lines [$txt count -lines 1.0 end]
05561
05562 # Get the total character count
05563 set chars [$txt count -chars 1.0 end]
05564
05565 # Update the information widget
05566 set_info_message [format "%s: %d, %s: %d" [msgcat::mc "Total Lines"] $lines [msgcat::mc "Total Characters"] $chars]
05567
05568 }
05569
05570 ######################################################################
05571 # Returns the list of procs in the current text widget. Uses the _procs
05572 # highlighting to tag to quickly find procs in the widget.
05573 proc get_symbol_list {} {
05574
05575 variable lengths
05576
05577 # Get current text widget
05578 set txt [current_txt]
05579
05580 set proclist [list]
05581 foreach tag [$txt tag names] {
05582 if {[string range $tag 0 9] eq "__symbols:"} {
05583 if {[set type [string range $tag 10 end]] ne ""} {
05584 append type ": "
05585 }
05586 foreach {startpos endpos} [$txt tag ranges $tag] {
05587 lappend proclist "$type[$txt get $startpos $endpos]" $startpos
05588 }
05589 }
05590 }
05591
05592 return $proclist
05593
05594 }
05595
05596 ######################################################################
05597 # Create a marker at the current insertion cursor line of the current
05598 # editor.
05599 proc create_current_marker {} {
05600
05601 # Get the current text widget
05602 get_info {} current tab txt
05603
05604 # Get the current line
05605 set line [lindex [split [$txt index insert] .] 0]
05606
05607 # Add the marker at the current line
05608 if {[set tag [ctext::linemapSetMark $txt $line]] ne ""} {
05609 if {[markers::add $tab tag $tag]} {
05610 update_tab_markers $tab
05611 } else {
05612 ctext::linemapClearMark $txt $line
05613 }
05614 }
05615
05616 }
05617
05618 ######################################################################
05619 # Removes all markers placed at the current line.
05620 proc remove_current_marker {} {
05621
05622 # Get the current text widget
05623 get_info {} current tab txt
05624
05625 # Get the current line number
05626 set line [lindex [split [$txt index insert] .] 0]
05627
05628 # Remove all markers at the current line
05629 markers::delete_by_line $tab $line
05630 ctext::linemapClearMark $txt $line
05631
05632 # Update the tab's marker view
05633 update_tab_markers $tab
05634
05635 }
05636
05637 ######################################################################
05638 # Remove all of the text markers for the given text widget.
05639 proc remove_txt_markers {txt} {
05640
05641 get_info $txt txt tab
05642
05643 foreach {name t line} [markers::get_markers $tab] {
05644 set line [lindex [split $line .] 0]
05645 markers::delete_by_name $tab $name
05646 ctext::linemapClearMark $txt $line
05647 }
05648
05649 # Update the marker display
05650 update_tab_markers $tab
05651
05652 }
05653
05654 ######################################################################
05655 # Removes all of the markers associated with the current text widget.
05656 proc remove_current_markers {} {
05657
05658 remove_txt_markers [current_txt]
05659
05660 }
05661
05662 ######################################################################
05663 # Removes all of the markers from the current editor.
05664 proc remove_all_markers {} {
05665
05666 foreach txt [get_all_texts] {
05667 remove_txt_markers $txt
05668 }
05669
05670 }
05671
05672 ######################################################################
05673 # Returns the list of markers in the all text widgets, sorted in
05674 # alphabetical order..
05675 proc get_marker_list {} {
05676
05677 # Create a list of marker names and index
05678 set markers [list]
05679 foreach {name tab pos} [markers::get_markers] {
05680 get_info $tab tab txt fname
05681 lappend markers [list "[file tail $fname] - $name" $txt $name]
05682 }
05683
05684 return [lsort -index 0 -dictionary $markers]
05685
05686 }
05687
05688 ######################################################################
05689 # Jump to the given position in the current text widget.
05690 proc jump_to {pos} {
05691
05692 jump_to_txt [current_txt] $pos
05693
05694 }
05695
05696 ######################################################################
05697 # Jump to the given position in the given text widget.
05698 proc jump_to_txt {txt pos} {
05699
05700 # Change the current tab, if necessary
05701 get_info $txt txt tabbar tab
05702 set_current_tab $tabbar $tab
05703
05704 # Make sure that the cursor is visible
05705 folding::show_line $txt.t [lindex [split $pos .] 0]
05706
05707 # Make the line viewable
05708 ::tk::TextSetCursor $txt.t $pos
05709
05710 # Adjust the insert
05711 vim::adjust_insert $txt.t
05712
05713 }
05714
05715 ######################################################################
05716 # Jumps to the specified text name.
05717 proc jump_to_marker {txt name} {
05718
05719 # Change the current tab, if necessary
05720 get_info $txt txt tabbar tab
05721 set_current_tab $tabbar $tab
05722
05723 # Get the marker position
05724 set pos [markers::get_index $tab $name]
05725
05726 # Make sure that the cursor is visible
05727 folding::show_line $txt.t [lindex [split $pos .] 0]
05728
05729 # Make the line viewable
05730 ::tk::TextSetCursor $txt.t $pos
05731
05732 # Adjust the insert
05733 vim::adjust_insert $txt.t
05734
05735 }
05736
05737 ######################################################################
05738 # Finds the matching character for the one at the current insertion
05739 # marker.
05740 proc show_match_pair {} {
05741
05742 # Get the current widget
05743 set txt [current_txt]
05744
05745 # If we are escaped or in a comment/string, we should not match
05746 if {[$txt is escaped insert] || [$txt is incommentstring insert]} {
05747 return
05748 }
05749
05750 # If the current character is a matchable character, change the
05751 # insertion cursor to the matching character.
05752 switch -- [$txt get insert] {
05753 "\{" { set index [ctext::getMatchBracket $txt curlyR] }
05754 "\}" { set index [ctext::getMatchBracket $txt curlyL] }
05755 "\[" { set index [ctext::getMatchBracket $txt squareR] }
05756 "\]" { set index [ctext::getMatchBracket $txt squareL] }
05757 "\(" { set index [ctext::getMatchBracket $txt parenR] }
05758 "\)" { set index [ctext::getMatchBracket $txt parenL] }
05759 "<" { set index [ctext::getMatchBracket $txt angledR] }
05760 ">" { set index [ctext::getMatchBracket $txt angledL] }
05761 "\"" { set index [find_match_char $txt "\"" [expr {([lsearch [$txt tag names insert-1c] __dQuote*] == -1) ? "-forwards" : "-backwards"}]] }
05762 "'" { set index [find_match_char $txt "'" [expr {([lsearch [$txt tag names insert-1c] __sQuote*] == -1) ? "-forwards" : "-backwards"}]] }
05763 "`" { set index [find_match_char $txt "`" [expr {([lsearch [$txt tag names insert-1c] __bQuote*] == -1) ? "-forwards" : "-backwards"}]]}
05764 default { set index [find_match_pair $txt {*}[lrange [syntax::get_indentation_expressions $txt] 0 1] -backwards] }
05765 }
05766
05767 # Change the insertion cursor to the matching character
05768 if {($index ne "") && ($index != -1)} {
05769 ::tk::TextSetCursor $txt.t $index
05770 }
05771
05772 }
05773
05774 ######################################################################
05775 # Finds the matching bracket type and returns it's index if found;
05776 # otherwise, returns -1.
05777 proc find_match_pair {txt str1 str2 dir {startpos insert}} {
05778
05779 if {[$txt is escaped $startpos] || [$txt is incommentstring $startpos]} {
05780 return -1
05781 }
05782
05783 set search_re "[set str1]|[set str2]"
05784 set count 1
05785 set pos [$txt index [expr {($dir eq "-forwards") ? "$startpos+1c" : $startpos}]]
05786
05787 # Calculate the endpos
05788 if {[set incomstr [$txt is incommentstring $pos srange]]} {
05789 if {$dir eq "-forwards"} {
05790 set endpos [lindex $srange 1]
05791 } else {
05792 set endpos [lindex $srange 0]
05793 }
05794 } else {
05795 if {$dir eq "-forwards"} {
05796 set endpos "end"
05797 } else {
05798 set endpos "1.0"
05799 }
05800 }
05801
05802 while {1} {
05803
05804 if {[set found [$txt search $dir -regexp -- $search_re $pos $endpos]] eq ""} {
05805 return -1
05806 }
05807
05808 set char [$txt get $found]
05809 if {$dir eq "-forwards"} {
05810 set pos "$found+1c"
05811 } else {
05812 set pos $found
05813 }
05814
05815 if {[$txt is escaped $found] || (!$incomstr && [$txt is incommentstring $found])} {
05816 continue
05817 } elseif {[string equal $char [subst $str2]]} {
05818 incr count
05819 } elseif {[string equal $char [subst $str1]]} {
05820 incr count -1
05821 if {$count == 0} {
05822 return $found
05823 }
05824 }
05825
05826 }
05827
05828 }
05829
05830 ######################################################################
05831 # Returns the index of the matching character; otherwise, if one
05832 # is not found, returns -1.
05833 proc find_match_char {txt char dir {startpos insert}} {
05834
05835 set last_found ""
05836
05837 if {[$txt is escaped $startpos]} {
05838 return -1
05839 }
05840
05841 if {$dir eq "-forwards"} {
05842 set startpos [$txt index "$startpos+1c"]
05843 set endpos "end"
05844 } else {
05845 set endpos "1.0"
05846 }
05847
05848 while {1} {
05849
05850 if {[set found [$txt search $dir $char $startpos $endpos]] eq ""} {
05851 return -1
05852 }
05853
05854 set last_found $found
05855 set startpos [expr {($dir eq "-backwards") ? $found : [$txt index "$found+1c"]}]
05856
05857 if {[$txt is escaped $last_found]} {
05858 continue
05859 }
05860
05861 return $last_found
05862
05863 }
05864
05865 }
05866
05867 ######################################################################
05868 # Jumps the insertion cursor to the next/previous mismatching bracket
05869 # within the current text widget.
05870 proc goto_mismatch {dir args} {
05871
05872 return [ctext::gotoBracketMismatch [current_txt] $dir {*}$args]
05873
05874 }
05875
05876 ######################################################################
05877 # Updates the scroller markers for the given tab.
05878 proc update_tab_markers {tab} {
05879
05880 # Get the pathname of txt and txt2 from the given tab
05881 get_info $tab tab txt txt2
05882
05883 # The txt widget will always exist, so update it now
05884 ctext::linemapUpdate $txt
05885 scroller::update_markers [winfo parent $txt].vb
05886
05887 # If the split view widget exists, update it as well
05888 if {[winfo exists $txt2]} {
05889 ctext::linemapUpdate $txt2
05890 scroller::update_markers [winfo parent $txt2].vb
05891 }
05892
05893 }
05894
05895 ######################################################################
05896 # Handles a mark request when the line is clicked.
05897 proc mark_command {tab win type tag} {
05898
05899 if {$type eq "marked"} {
05900 if {![markers::add $tab tag $tag]} {
05901 return 0
05902 }
05903 } else {
05904 markers::delete_by_tag $tab $tag
05905 }
05906
05907 # Update the markers in the scrollbar
05908 update_tab_markers $tab
05909
05910 return 1
05911
05912 }
05913
05914 ######################################################################
05915 # Displays all of the unhidden tabs.
05916 proc show_tabs {tb side} {
05917
05918 # If the tabbar is disabled, don't show the tab menu
05919 if {[$tb cget -state] eq "disabled"} {
05920 return
05921 }
05922
05923 set mnu $tb.mnu
05924
05925 # Get the shown tabs
05926 set shown [$tb xview shown]
05927 lset shown 1 [expr [lindex $shown 1] + 1]
05928
05929 # Clear the menu
05930 $mnu delete 0 end
05931
05932 set i 0
05933 foreach tab [$tb tabs] {
05934 if {[lindex $shown 0] == $i} {
05935 if {$i > 0} {
05936 $mnu add separator
05937 }
05938 set shown [lassign $shown tmp]
05939 }
05940 set tab_image [$tb tab $tab -image]
05941 set img [expr {($tab_image ne "") ? "menu_[string range $tab_image 4 end]" : ""}]
05942 $mnu add command -compound left -image $img -label [$tb tab $tab -text] \
05943 -command [list gui::set_current_tab $tb $tab]
05944 incr i
05945 }
05946
05947 # Figure out where to display the menu
05948 if {$side eq "right"} {
05949 set x [expr ([winfo rootx $tb] + [winfo width $tb]) - [winfo reqwidth $mnu]]
05950 } else {
05951 set x [winfo rootx $tb]
05952 }
05953 set y [expr [winfo rooty $tb] + [winfo height $tb]]
05954
05955 # Display the menu
05956 tk_popup $mnu $x $y
05957
05958 }
05959
05960 ######################################################################
05961 # This is called by the indent namespace to update the indentation
05962 # widget when the indent value changes internally (due to changing
05963 # the current language.
05964 proc update_indent_button {} {
05965
05966 variable widgets
05967
05968 indent::update_button $widgets(info_indent)
05969
05970 }
05971
05972 ######################################################################
05973 # Creates the encoding menu.
05974 proc create_encoding_menu {w} {
05975
05976 variable widgets
05977
05978 # Create the menubutton menu
05979 set mnu [menu ${w}Menu -tearoff 0]
05980
05981 # If we are running in Aqua, don't perform the column break
05982 set dobreak [expr {[tk windowingsystem] ne "aqua"}]
05983
05984 # Populate the menu with the available languages
05985 set i 0
05986 foreach enc [lsort -dictionary [encoding names]] {
05987 $mnu add radiobutton -label [string toupper $enc] -variable gui::current_encoding \
05988 -value $enc -command [list gui::set_current_encoding $enc] -columnbreak [expr (($i % 20) == 0) && $dobreak]
05989 incr i
05990 }
05991
05992 # Register the menu
05993 theme::register_widget $mnu menus
05994
05995 return $mnu
05996
05997 }
05998
05999 ######################################################################
06000 # Sets the encoding of the current buffer to the given value.
06001 proc set_current_encoding {value} {
06002
06003 gui::get_info {} current tab fileindex
06004
06005 # Set the encoding
06006 if {![set_encoding $tab $value]} {
06007 return
06008 }
06009
06010 # Update the encode button
06011 update_encode_button
06012
06013 # Update the file with the new encoding
06014 update_file $fileindex
06015
06016 # Set the focus back to the text editor
06017 set_txt_focus [last_txt_focus]
06018
06019 }
06020
06021 ######################################################################
06022 # Sets the encoding of the given tab to the given value.
06023 proc set_encoding {tab value {setfocus 1}} {
06024
06025 variable widgets
06026
06027 # Get the current tab info
06028 get_info $tab tab fileindex encode
06029
06030 # If the value did not change, do nothing
06031 if {$value eq $encode} {
06032 return 0
06033 }
06034
06035 # Save the file encoding
06036 files::set_info $fileindex fileindex encode $value
06037
06038 return 1
06039
06040 }
06041
06042 ######################################################################
06043 # This is called when the tab changes. Our job is to update the label
06044 # on the encoding button to match the value for the file.
06045 proc update_encode_button {} {
06046
06047 variable widgets
06048 variable current_encoding
06049
06050 # Get the current encoding
06051 get_info {} current encode
06052
06053 set current_encoding $encode
06054
06055 # Update the encode button
06056 $widgets(info_encode) configure -text [string toupper $encode]
06057
06058 }
06059
06060 ######################################################################
06061 # Handles a text FocusIn event from the widget.
06062 proc handle_txt_focus {txtt} {
06063
06064 variable widgets
06065 variable pw_current
06066 variable txt_current
06067 variable info_msgs
06068
06069 # It is possible that getting the parent of txtt could cause errors, so just
06070 # silently catch them and move on
06071 catch {
06072
06073 # Get the text information
06074 get_info [winfo parent $txtt] txt paneindex tab txt fileindex fname buffer diff
06075 set pw_current $paneindex
06076
06077 # Set the line and row information
06078 update_position $txt
06079
06080 # Check to see if the file has changed
06081 catch { files::check_file $fileindex }
06082
06083 # Save the text widget
06084 set txt_current($tab) [winfo parent $txtt]
06085
06086 # Update the informational message if one exists for the text widget
06087 if {[info exists info_msgs($txt)]} {
06088 set_info_message [lindex $info_msgs($txt) 0] -clear_delay [lindex $info_msgs($txt) 1] -win [winfo parent $txtt]
06089 } else {
06090 set_info_message "" -win [winfo parent $txtt]
06091 }
06092
06093 # Remove the find or find/replace panels if we are told to do so
06094 if {[preferences::get Find/ClosePanelsOnTextFocus]} {
06095 panel_forget $tab.sf
06096 panel_forget $tab.rf
06097 }
06098
06099 # Let the plugins know about the FocusIn event
06100 plugins::handle_on_focusin $tab
06101
06102 }
06103
06104 }
06105
06106 ######################################################################
06107 # Sets the focus to the given ctext widget.
06108 proc set_txt_focus {txt} {
06109
06110 variable txt_current
06111
06112 # Set the focus
06113 focus $txt.t
06114
06115 # Save the last text widget in focus
06116 set txt_current([get_info $txt txt tab]) $txt
06117
06118 }
06119
06120 ######################################################################
06121 # Returns the path to the ctext widget that last received focus.
06122 proc last_txt_focus {{tab ""}} {
06123
06124 variable txt_current
06125
06126 if {$tab eq ""} {
06127 return $txt_current([get_info {} current tab])
06128 } elseif {[info exists txt_current($tab)]} {
06129 return $txt_current($tab)
06130 } else {
06131 return [get_info $tab tab txt]
06132 }
06133
06134 }
06135
06136 ######################################################################
06137 # Scrubs the given text widget, returning the scrubbed text as a string
06138 # to be used for saving to a file.
06139 proc scrub_text {txt} {
06140
06141 variable trailing_ws_re
06142
06143 # Clear any snippet tabstops embedded in the text widget
06144 snippets::clear_tabstops $txt.t
06145
06146 # Clean up the text from Vim
06147 set str [vim::get_cleaned_content $txt]
06148
06149 if {[preferences::get Editor/RemoveTrailingWhitespace]} {
06150 regsub -all -lineanchor -- $trailing_ws_re $str {} str
06151 }
06152
06153 return $str
06154
06155 }
06156
06157 ######################################################################
06158 # Jumps to the next cursor as specified by direction. Returns a boolean
06159 # value of true if a jump occurs (or can occur).
06160 proc jump_to_cursor {dir jump} {
06161
06162 variable cursor_hist
06163
06164 # Get the current text widget
06165 set txt [current_txt]
06166
06167 # Get the index of the cursor in the cursor hist to use
06168 if {![info exists cursor_hist($txt,hist)]} {
06169 set cursor_hist($txt,hist) [$txt edit cursorhist]
06170 set cursor_hist($txt,index) [llength $cursor_hist($txt,hist)]
06171 }
06172
06173 set index $cursor_hist($txt,index)
06174 set length [llength $cursor_hist($txt,hist)]
06175 set diff [preferences::get Find/JumpDistance]
06176
06177 if {$index == $length} {
06178 set last_line [lindex [split [$txt index insert] .] 0]
06179 } else {
06180 set last_line [lindex [split [lindex $cursor_hist($txt,hist) $index] .] 0]
06181 }
06182
06183 # Get the cursor index
06184 while {([incr index $dir] >= 0) && ($index < $length)} {
06185 set cursor [lindex $cursor_hist($txt,hist) $index]
06186 set index_line [lindex [split $cursor .] 0]
06187 if {[expr abs( $index_line - $last_line ) >= $diff]} {
06188 if {$jump} {
06189 set cursor_hist($txt,index) $index
06190 ::tk::TextSetCursor $txt.t "$cursor linestart"
06191 if {[vim::in_vim_mode $txt.t]} {
06192 vim::adjust_insert $txt.t
06193 }
06194 }
06195 return 1
06196 }
06197 }
06198
06199 return 0
06200
06201 }
06202
06203 ######################################################################
06204 # Jumps to the next difference in the specified direction. Returns
06205 # a boolean value of true if a jump occurs (or can occur).
06206 proc jump_to_difference {dir jump} {
06207
06208 # Get the current text widget
06209 set txt [current_txt]
06210
06211 # Get the list of ranges
06212 if {[$txt cget -diff_mode] && ([llength [set ranges [$txt diff ranges both]]] > 0)} {
06213
06214 if {$jump} {
06215
06216 # Get the list of difference ranges
06217 if {$dir == 1} {
06218 set index [$txt index @0,[winfo height $txt]]
06219 foreach {start end} $ranges {
06220 if {[$txt compare $start > $index]} {
06221 $txt see $start
06222 return 1
06223 }
06224 }
06225 $txt see [lindex $ranges 0]
06226 } else {
06227 set index [$txt index @0,0]
06228 foreach {end start} [lreverse $ranges] {
06229 if {[$txt compare $start < $index]} {
06230 $txt see $start
06231 return 1
06232 }
06233 }
06234 $txt see [lindex $ranges end-1]
06235 }
06236
06237 }
06238
06239 return 1
06240
06241 }
06242
06243 return 0
06244
06245 }
06246
06247 ######################################################################
06248 # Finds the last version that caused the currently selected line to be
06249 # changed. Returns true if this can be accomplished; otherwise, returns
06250 # false.
06251 proc show_difference_line_change {show} {
06252
06253 # Get the current information
06254 get_info {} current txt fname
06255
06256 if {[$txt cget -diff_mode] && ![catch { $txt index sel.first } rc]} {
06257 if {$show} {
06258 diff::find_current_version $txt $fname [lindex [split $rc .] 0]
06259 }
06260 return 1
06261 }
06262
06263 return 0
06264
06265 }
06266
06267 ######################################################################
06268 # Handles a font size change event on the widget that the mouse cursor
06269 # is currently hovering over.
06270 proc handle_font_change {dir} {
06271
06272 # Get the current cursor position
06273 lassign [winfo pointerxy .] x y
06274
06275 # Get the window containing x and y
06276 set win [winfo containing $x $y]
06277
06278 # Get the class of the given window
06279 switch [winfo class $win] {
06280 "Text" -
06281 "Listbox" {
06282 array set f [font actual [$win cget -font]]
06283 set f(-size) [expr ($f(-size) < 0) ? ($f(-size) - $dir) : ($f(-size) + $dir)]
06284 $win configure -font [array get f]
06285 }
06286 }
06287
06288 }
06289
06290 ######################################################################
06291 # Change the current working directory to the specified direction and
06292 # update the title bar.
06293 proc change_working_directory {dir} {
06294
06295 # Change the current working directory to dir
06296 cd $dir
06297
06298 # Update the title
06299 set_title
06300
06301 }
06302
06303 ######################################################################
06304 # Check all of the namespaces for a procedure called "handle_destroy_txt".
06305 # When a namespace is found the the procedure, call it with the given
06306 # text widget. This allows namespaces to clean up any state that is
06307 # dependent on the given text widget.
06308 proc cleanup_txt {txt} {
06309
06310 foreach ns [namespace children ::] {
06311 if {[info procs ${ns}::handle_destroy_txt] ne ""} {
06312 eval ${ns}::handle_destroy_txt $txt
06313 }
06314 }
06315
06316 }
06317
06318 ######################################################################
06319 # Gets the documentation search URL and string.
06320 proc docsearch_get_input {docs prsplist args} {
06321
06322 variable widgets
06323 variable saved
06324
06325 upvar $prsplist rsplist
06326
06327 array set opts {
06328 -str ""
06329 -url ""
06330 }
06331 array set opts $args
06332
06333 # Clear the saved indicator
06334 set saved 0
06335
06336 # Clear the entry field
06337 $widgets(doc).e delete 0 end
06338
06339 # Initialize the text in the menubutton
06340 $widgets(doc).mb configure -text [lindex $docs 0 0]
06341
06342 # Populate the documentation list
06343 [$widgets(doc).mb cget -menu] delete 0 end
06344 foreach item $docs {
06345 [$widgets(doc).mb cget -menu] add command -label [lindex $item 0] -command [list $widgets(doc).mb configure -text [lindex $item 0]]
06346 }
06347
06348 # Initialize the widget
06349 if {$opts(-str) ne ""} {
06350 $widgets(doc).e insert end $opts(-str)
06351 }
06352 if {($opts(-url) ne "") && ([set name [lsearch -exact -inline -index 1 $docs $opts(-url)]] ne "")} {
06353 $widgets(doc).mb configure -text $name
06354 }
06355
06356 # Display the user input widget
06357 panel_place $widgets(doc)
06358
06359 # Wait for the panel to be done
06360 focus $widgets(doc).mb
06361 tkwait variable gui::user_exit_status
06362
06363 # Hide the user input widget
06364 panel_forget $widgets(doc)
06365
06366 set name [$widgets(doc).mb cget -text]
06367 set url [lindex [lsearch -exact -index 0 -inline $docs $name] 1]
06368 set rsplist [list str [$widgets(doc).e get] name $name url $url save $saved]
06369
06370 return [set gui::user_exit_status]
06371
06372 }
06373
06374 ######################################################################
06375 # This procedure should be called whenever the theme changes. Updates
06376 # the given text widget.
06377 proc update_theme {txt} {
06378
06379 # Get the current syntax theme
06380 array set theme [theme::get_syntax_colors]
06381 array set stheme [theme::get_category_options text_scrollbar 1]
06382
06383 [winfo parent $txt] configure -background $stheme(-background)
06384
06385 # Set the text background color to the current theme
06386 $txt configure -background $theme(background) -foreground $theme(foreground) \
06387 -selectbackground $theme(select_background) -selectforeground $theme(select_foreground) \
06388 -insertbackground $theme(cursor) -highlightcolor $theme(border_highlight) \
06389 -linemapbg $theme(linemap) -linemapfg $theme(line_number) \
06390 -linemap_mark_color $theme(marker) -linemap_separator_color $theme(linemap_separator) \
06391 -warnwidth_bg $theme(warning_width) -relief flat \
06392 -diffaddbg $theme(difference_add) -diffsubbg $theme(difference_sub) \
06393 -matchchar_fg $theme(background) -matchchar_bg $theme(foreground) \
06394 -matchaudit_bg $theme(attention) -theme [array get theme]
06395
06396 catch {
06397
06398 # If the bird's eye view exists, update it
06399 get_info $txt txt beye
06400
06401 if {[winfo exists $beye]} {
06402
06403 # Calculate the background color
06404 set background [utils::auto_adjust_color [$txt cget -background] 25]
06405
06406 # Create the bird's eye viewer
06407 $beye configure -background $theme(background) -foreground $theme(foreground) \
06408 -inactiveselectbackground $background -selectbackground $background
06409
06410 }
06411
06412 }
06413
06414 }
06415
06416 }