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: themes.tcl
00020 # Author: Trevor Williams (phase1geo@gmail.com)
00021 # Date: 07/09/2014
00022 # Brief: Creates and sets the main UI theme to the given value.
00023 ######################################################################
00024
00025 namespace eval themes {
00026
00027 variable curr_theme ""
00028
00029 array set files {}
00030
00031 set themes_dir [file join $::tke_home themes]
00032
00033 ######################################################################
00034 # Updates the user's home themes directory
00035 proc update_themes_dir {} {
00036
00037 variable themes_dir
00038
00039 foreach fname [glob -nocomplain -directory $themes_dir *.tketheme] {
00040 file mkdir [file rootname $fname]
00041 file rename $fname [file rootname $fname]
00042 }
00043
00044 }
00045
00046 ######################################################################
00047 # Loads the theme information.
00048 proc load {} {
00049
00050 variable files
00051 variable themes_dir
00052
00053 # Update the user's themes directory
00054 update_themes_dir
00055
00056 # Trace changes to syntax preference values
00057 if {[array size files] == 0} {
00058 trace variable preferences::prefs(Appearance/Theme) w themes::handle_theme_change
00059 trace variable preferences::prefs(Appearance/Colorize) w themes::handle_colorize_change
00060 trace variable preferences::prefs(Appearance/HiddenThemes) w themes::handle_hidden_change
00061 }
00062
00063 # Reset the files/themes arrays and unregister launcher items
00064 array unset files
00065 launcher::unregister [msgcat::mc "Theme:*"]
00066
00067 # Load the tke_dir theme files
00068 set tfiles [utils::glob_install [file join $::tke_dir data themes] *.tketheme]
00069
00070 # Load the theme files
00071 foreach item [glob -nocomplain -directory $themes_dir -types d *] {
00072 if {[file exists [file join $item [file tail $item].tketheme]]} {
00073 lappend tfiles [file join $item [file tail $item].tketheme]
00074 }
00075 }
00076
00077 # Get the theme information
00078 foreach tfile $tfiles {
00079 set name [file rootname [file tail $tfile]]
00080 set files($name) $tfile
00081 }
00082
00083 # Create the launcher items (only display the visible themes)
00084 foreach name [get_visible_themes] {
00085 launcher::register [format "%s: %s" [msgcat::mc "Theme"] $name] [list theme::load_theme $files($name)] "" [list themes::theme_okay]
00086 }
00087
00088 # Allow the preferences UI to be updated, if it exists
00089 pref_ui::themes_populate_table
00090
00091 }
00092
00093 ######################################################################
00094 # Deletes the given theme from the file system.
00095 proc delete_theme {name} {
00096
00097 variable files
00098
00099 # If the theme file exists, delete the file
00100 if {[info exists files($name)] && [file exists $files($name)]} {
00101 file delete -force $files($name)
00102 }
00103
00104 # Reload the theme information
00105 load
00106
00107 }
00108
00109 ######################################################################
00110 # Returns true if it is okay to change the theme.
00111 proc theme_okay {} {
00112
00113 return [expr [themer::window_exists] ^ 1]
00114
00115 }
00116
00117 ######################################################################
00118 # Returns the filename associated with the given theme name. If the
00119 # theme name does not exist, returns an error.
00120 proc get_file {theme_name} {
00121
00122 variable files
00123
00124 if {[info exists files($theme_name)]} {
00125 return $files($theme_name)
00126 }
00127
00128 return -code error "Filename for theme $theme_name does not exist"
00129
00130 }
00131
00132 ######################################################################
00133 # Returns a sorted list of all the themes.
00134 proc get_all_themes {} {
00135
00136 variable files
00137
00138 return [lsort [array names files]]
00139
00140 }
00141
00142 ######################################################################
00143 # Returns the list of themes that will be visible from the theme menu.
00144 proc get_visible_themes {} {
00145
00146 variable files
00147
00148 # Create list of files to
00149 return [lsort [::struct::set difference [array names files] [preferences::get Appearance/HiddenThemes]]]
00150
00151 }
00152
00153 ######################################################################
00154 # Called whenever the Appearance/Theme preference value is changed.
00155 proc handle_theme_change {{name1 ""} {name2 ""} {op ""}} {
00156
00157 variable files
00158
00159 set user_theme [preferences::get Appearance/Theme]
00160
00161 if {[info exists files($user_theme)]} {
00162 theme::load_theme $files($user_theme)
00163 } else {
00164 theme::load_theme $files(Default)
00165 }
00166
00167 }
00168
00169 ######################################################################
00170 # Called whenever the Appearance/Colorize preference value is changed.
00171 proc handle_colorize_change {name1 name2 op} {
00172
00173 theme::update_syntax
00174
00175 }
00176
00177 ######################################################################
00178 # Handle a change to the Appearance/HiddenThemes preference value.
00179 proc handle_hidden_change {name1 name2 op} {
00180
00181 # Reload the themes
00182 load
00183
00184 }
00185
00186 ######################################################################
00187 # Imports the contents of the given theme file (which must have either
00188 # the .tketheme or .tkethemz file extensions). Imports the theme into
00189 # the user directory. Returns the name of the installed .tketheme file
00190 # if successful; otherwise, returns the empty string.
00191 proc import {parent_win fname} {
00192
00193 variable files
00194 variable themes_dir
00195
00196 # If the directory exists, move it out of the way
00197 set odir [file join $themes_dir [file rootname [file tail $fname]]]
00198 if {[file exists $odir]} {
00199 file rename $odir $odir.old
00200 }
00201
00202 # Unzip the file contents
00203 if {[catch { zipper::unzip $fname $themes_dir } rc]} {
00204 if {[catch { exec -ignorestderr unzip -u $fname -d $themes_dir } rc]} {
00205 catch { file rename $odir.old $odir }
00206 tk_messageBox -parent $parent_win -icon error -type ok -default ok \
00207 -message "Unable to unzip theme file" -detail $rc
00208 return ""
00209 }
00210 }
00211
00212 # Remove the old file if it exists
00213 catch { file delete [file exists $odir.old] }
00214
00215 # Reload the available themes
00216 load
00217
00218 # Return the pathname of the installed .tketheme file
00219 return $files([file rootname [file tail $fname]])
00220
00221 }
00222
00223 ######################################################################
00224 # Exports the contents of the given theme to the given .tkethemz
00225 # directory.
00226 proc export {parent_win theme odir creator website license} {
00227
00228 # Create the theme directory
00229 file mkdir [set theme_dir [file join $odir $theme]]
00230
00231 # Populate the theme directory with the given contents
00232 if {![theme::export $theme $theme_dir $creator $website $license]} {
00233 tk_messageBox -parent $parent_win -icon error -type ok -default ok \
00234 -message "Unable to export theme contents"
00235 return
00236 }
00237
00238 # Get the current working directory
00239 set pwd [pwd]
00240
00241 # Set the current working directory to the user themes directory
00242 cd $odir
00243
00244 # Perform the archive
00245 if {[catch { zipper::list2zip [pwd] [glob -directory $theme *] $theme.tkethemz } rc]} {
00246 if {[catch { exec -ignorestderr zip -r [file join .. $theme.tkethemz] $theme } rc]} {
00247 tk_messageBox -parent $parent_win -icon error -type ok -default ok \
00248 -message "Unable to zip theme file"
00249 return
00250 }
00251 }
00252
00253 # Restore the current working directory
00254 cd $pwd
00255
00256 # Delete the theme directory and its contents
00257 catch { file delete -force $theme_dir }
00258
00259 }
00260
00261 ######################################################################
00262 # Batch exports all custom themes to a directory on the Desktop.
00263 proc export_custom {{parent_win .}} {
00264
00265 variable files
00266 variable themes_dir
00267
00268 # Create the themes directory
00269 set output_dir [file join ~ Desktop UpdatedThemes]
00270 set current [theme::get_current_theme]
00271
00272 # If the output directory exists, delete it
00273 if {[file exists $output_dir]} {
00274 file delete -force $output_dir
00275 }
00276
00277 # Make the output directory
00278 file mkdir $output_dir
00279
00280 # Load each theme and then export it
00281 foreach {name theme_file} [array get files] {
00282
00283 # Only consider themes from the themes_dir
00284 if {[string compare -length [string length $themes_dir] $theme_file $themes_dir] != 0} {
00285 continue
00286 }
00287
00288 # Initialize some variables
00289 set license [file join [file dirname $theme_file] LICENSE]
00290
00291 # Load the theme
00292 theme::read_tketheme $theme_file
00293
00294 # Export the theme to the output directory
00295 array set attrs [list creator "" website "" date ""]
00296 array set attrs [theme::get_attributions]
00297
00298 # Export the loaded theme
00299 export $parent_win $name $output_dir $attrs(creator) $attrs(website) $license
00300
00301 }
00302
00303 # Restore the theme namespace with the current theme contents
00304 theme::load_theme $files($current)
00305
00306 # Tell the user that the export was successful
00307 gui::set_info_message [msgcat::mc "Batch custom theme export completed successfully"]
00308
00309 }
00310
00311 ######################################################################
00312 # Repopulates the specified theme selection menu.
00313 proc populate_theme_menu {mnu} {
00314
00315 variable files
00316 variable curr_theme
00317
00318 # Get the current theme
00319 set curr_theme [theme::get_current_theme]
00320
00321 # Figure out the state for the items
00322 set state [expr {[themer::window_exists] ? "disabled" : "normal"}]
00323
00324 # Clear the menu
00325 $mnu delete 0 end
00326
00327 # Populate the menu with the available themes
00328 foreach name [get_visible_themes] {
00329 $mnu add radiobutton -label $name -variable themes::curr_theme -value $name -command [list theme::load_theme $files($name)] -state $state
00330 }
00331
00332 return $mnu
00333
00334 }
00335
00336 ######################################################################
00337 # Returns the name of the currently displayed theme.
00338 proc get_current_theme {} {
00339
00340 variable curr_theme
00341
00342 return $curr_theme
00343
00344 }
00345
00346 ######################################################################
00347 # Returns 1 if the given file is imported; otherwise, returns 0.
00348 proc get_imported {name} {
00349
00350 variable files
00351 variable themes_dir
00352
00353 if {[info exists files($name)]} {
00354 return [expr [string compare -length [string length $themes_dir] $themes_dir $files($name)] == 0]
00355 }
00356
00357 return 0
00358
00359 }
00360
00361 ######################################################################
00362 # Returns the creator, website and/or date information from the file in array format.
00363 proc get_attributions {name} {
00364
00365 variable files
00366
00367 array set attrs [list creator "" website "" date ""]
00368
00369 if {[info exists files($name)]} {
00370 array set attrs [theme::get_file_attributions $files($name)]
00371 }
00372
00373 return [array get attrs]
00374
00375 }
00376
00377 ######################################################################
00378 # Returns the location of the user themes directory.
00379 proc get_user_directory {} {
00380
00381 variable themes_dir
00382
00383 return $themes_dir
00384
00385 }
00386
00387 ######################################################################
00388 # Returns the list of files in the TKE home directory to copy.
00389 proc get_share_items {dir} {
00390
00391 return [list themes]
00392
00393 }
00394
00395 ######################################################################
00396 # Called whenever the share directory changes.
00397 proc share_changed {dir} {
00398
00399 variable themes_dir
00400
00401 set themes_dir [file join $dir themes]
00402
00403 }
00404
00405 }