1# nick_colors.tcl - Copyright (C) 2004 Pat Thoyts <patthoyts@users.sourceforge.net> 2# 3# Do full text coloring based upon nicks. Includes a color editor and 4# persistence for modified color selection. 5# 6# $Id$ 7 8package require sum 9 10namespace eval nickcolors { 11 12 custom::defvar options(use_colored_nicks) 0 \ 13 [::msgcat::mc "Use colored nicks in chat windows."] \ 14 -group Chat -type boolean \ 15 -command [namespace current]::change_options 16 17 custom::defvar options(use_colored_roster_nicks) 0 \ 18 [::msgcat::mc "Use colored nicks in groupchat rosters."] \ 19 -group Chat -type boolean \ 20 -command [namespace current]::change_options 21 22 custom::defvar options(use_colored_messages) 0 \ 23 [::msgcat::mc "Color message bodies in chat windows."] \ 24 -group Chat -type boolean \ 25 -command [namespace current]::change_options 26 27 hook::add open_chat_post_hook [namespace current]::chat_add_nick_colors 28 hook::add close_chat_post_hook [namespace current]::chat_delete_nick_colors 29 hook::add quit_hook [namespace current]::save_nick_colors 30 hook::add draw_message_hook [namespace current]::check_nick 60 31 hook::add finload_hook [namespace current]::init_nick_colors 32 hook::add chat_win_popup_menu_hook [namespace current]::add_chat_win_popup_menu 10 33 hook::add roster_create_groupchat_user_menu_hook \ 34 [namespace current]::add_groupchat_user_menu_items 35 36 variable NickColorPool 37 if {![info exists NickColorPool]} { 38 set NickColorPool [list blue4 green4 red brown4 orange3 purple3 \ 39 tomato chocolate pink3] 40 } 41 42 variable NickColors 43 if {![info exists NickColors]} { 44 array set NickColors {} 45 } 46} 47 48proc nickcolors::init_nick_colors {} { 49 load_nick_colors 50 add_nick_colors_menu 51} 52 53proc nickcolors::add_nick_colors_menu {} { 54 set m [.mainframe getmenu chats] 55 56 $m insert end checkbutton \ 57 -label [::msgcat::mc "Use colored nicks"] \ 58 -variable [namespace current]::options(use_colored_nicks) \ 59 -command [namespace current]::change_options 60 $m insert end checkbutton \ 61 -label [::msgcat::mc "Use colored roster nicks"] \ 62 -variable [namespace current]::options(use_colored_roster_nicks) \ 63 -command [namespace current]::change_options 64 $m insert end checkbutton \ 65 -label [::msgcat::mc "Use colored messages"] \ 66 -variable [namespace current]::options(use_colored_messages) \ 67 -command [namespace current]::change_options 68 $m insert end command \ 69 -label [::msgcat::mc "Edit nick colors..."] \ 70 -command [namespace current]::edit_nick_colors 71} 72 73# Called upon startup, this will merge the user's stored set of nick-colors 74# into the current array. New chat windows will pick these up. 75# 76proc nickcolors::load_nick_colors {} { 77 variable NickColors 78 set filename [file join $::configdir nickcolors.tcl] 79 if {[file exists $filename]} { 80 set f [open $filename r] 81 fconfigure $f -encoding utf-8 82 while {![eof $f]} { 83 set line [string trim [gets $f]] 84 if {[string length $line] > 0 85 && ![string match \#* $line]} { 86 catch { 87 set NickColors([lindex $line 0]) [lindex $line 1] 88 } 89 } 90 } 91 close $f 92 } 93} 94 95# Called at shutdown to save the current set of nick-colors to file. 96proc nickcolors::save_nick_colors {} { 97 variable NickColors 98 set filename [file join $::configdir nickcolors.tcl] 99 set f [open $filename w] 100 fconfigure $f -encoding utf-8 101 puts $f "# This is an automatically generated file. Do not edit." 102 foreach {nick clr} [array get NickColors] { 103 puts $f [list $nick $clr] 104 } 105 close $f 106} 107 108proc nickcolors::get_color {nick} { 109 variable NickColors 110 variable NickColorPool 111 112 if {[info exists NickColors($nick)]} { 113 return $NickColors($nick) 114 } else { 115 set index [expr {[crc::sum -- $nick] % [llength $NickColorPool]}] 116 return [lindex $NickColorPool $index] 117 } 118} 119 120proc nickcolors::set_color {chatid nick color} { 121 variable options 122 123 if {[catch {set w [chat::chat_win $chatid]}] || \ 124 ![winfo exists $w]} { 125 return 126 } 127 128 if {$options(use_colored_nicks)} { 129 $w tag configure NICK-$nick -foreground $color 130 $w tag configure NICKMSG-$nick -foreground $color 131 } 132 if {$options(use_colored_messages)} { 133 $w tag configure MSG-$nick -foreground $color 134 $w tag lower MSG-$nick 135 } 136} 137 138# Called upon opening a new chat window. This added all the currently defined 139# nick-colors as tags into the text widget. 140# 141proc nickcolors::chat_add_nick_colors {chatid type} { 142 variable NicksInChat 143 144 debugmsg chat "on_open_chat $chatid $type" 145 set NicksInChat($chatid) {} 146} 147 148proc nickcolors::chat_delete_nick_colors {chatid} { 149 variable NicksInChat 150 151 debugmsg chat "on_close_chat $chatid" 152 catch {unset NicksInChat($chatid)} 153} 154 155# draw_message hook used to check that the nick exists as a color and tag. 156proc nickcolors::check_nick {chatid from type body x} { 157 variable NicksInChat 158 159 set xlib [chat::get_xlib $chatid] 160 set nick [chat::get_nick $xlib $from $type] 161 if {[lsearch -exact $NicksInChat($chatid) $nick] < 0} { 162 lappend NicksInChat($chatid) $nick 163 set_color $chatid $nick [get_color $nick] 164 } 165} 166 167proc nickcolors::edit_nick_colors {} { 168 variable NickColors 169 variable NickColorEdits 170 171 array set NickColorEdits [array get NickColors] 172 173 set w .edit_nicks 174 175 Dialog $w -title [::msgcat::mc "Edit chat user colors"] \ 176 -modal none -separator 1 -anchor e \ 177 -default 0 -cancel 1 178 179 $w add -text [::msgcat::mc "OK"] \ 180 -command [list [namespace current]::end_dialog $w ok] 181 $w add -text [::msgcat::mc "Cancel"] \ 182 -command [list [namespace current]::end_dialog $w cancel] 183 184 set f [$w getframe] 185 186 bind $f <Destroy> [list [namespace current]::end_dialog [double% $w] cancel] 187 188 set tools [frame $f.tools] 189 pack $tools -side bottom -fill x 190 191 set sw [ScrolledWindow $w.sw] 192 193 set lf [text $w.nicks -width 32 -height 14 -cursor left_ptr] 194 pack $sw -side top -expand yes -fill both -in $f -pady 1m -padx 1m 195 $sw setwidget $lf 196 197 foreach nick [lsort -dictionary [array names NickColors]] { 198 set clr $NickColors($nick) 199 $lf tag configure NICK-$nick -foreground $clr 200 $lf tag bind NICK-$nick <Enter> \ 201 [double% [list [namespace current]::on_nick_hover $lf $nick Enter]] 202 $lf tag bind NICK-$nick <Leave> \ 203 [double% [list [namespace current]::on_nick_hover $lf $nick Leave]] 204 $lf tag bind NICK-$nick <ButtonPress-1> \ 205 [double% [list [namespace current]::on_nick_click $lf $nick]] 206 $lf insert end $nick [list NICK-$nick] 207 $lf insert end "\n" 208 } 209 210 $lf configure -state disabled 211 212 $w draw 213} 214 215proc nickcolors::end_dialog {w res} { 216 variable options 217 variable NickColors 218 variable NickColorEdits 219 220 bind [$w getframe] <Destroy> { } 221 destroy $w 222 223 if {$res == "ok"} { 224 array set NickColors [array get NickColorEdits] 225 change_options 226 } 227 catch {unset NickColorEdits} 228} 229 230proc nickcolors::on_nick_hover {w nick event} { 231 if {$event == "Enter"} { 232 $w tag configure NICK-$nick -underline 1 233 $w configure -cursor hand2 234 } else { 235 $w tag configure NICK-$nick -underline 0 236 $w configure -cursor left_ptr 237 } 238} 239 240proc nickcolors::on_nick_click {w nick} { 241 variable NickColorEdits 242 243 if {[info exists NickColorEdits($nick)]} { 244 set clr $NickColorEdits($nick) 245 } else { 246 set clr black 247 } 248 set new [tk_chooseColor -initialcolor $clr \ 249 -title [::msgcat::mc "Edit %s color" $nick]] 250 if {$new != ""} { 251 $w tag configure NICK-$nick -foreground $new 252 set NickColorEdits($nick) $new 253 [namespace current]::save_nick_colors 254 } 255} 256 257proc nickcolors::change_options {args} { 258 variable options 259 variable NicksInChat 260 261 foreach chatid [chat::opened] { 262 set wn [chat::chat_win $chatid] 263 if {[winfo exists $wn]} { 264 if {[chat::is_groupchat $chatid]} { 265 chat::redraw_roster_after_idle $chatid 266 } 267 foreach nick $NicksInChat($chatid) { 268 set clr [get_color $nick] 269 $wn tag configure NICK-$nick \ 270 -foreground [expr {$options(use_colored_nicks) ? $clr : ""}] 271 $wn tag configure NICKMSG-$nick \ 272 -foreground [expr {$options(use_colored_nicks) ? $clr : ""}] 273 $wn tag configure MSG-$nick \ 274 -foreground [expr {$options(use_colored_messages) ? $clr : ""}] 275 } 276 } 277 } 278} 279 280proc nickcolors::add_chat_win_popup_menu {m chatwin X Y x y} { 281 variable options 282 283 set tags [$chatwin tag names "@$x,$y"] 284 set nick "" 285 if {$options(use_colored_messages)} { 286 if {[set idx [lsearch -glob $tags MSG-*]] >= 0} { 287 set nick [string range [lindex $tags $idx] 4 end] 288 } 289 } 290 if {$options(use_colored_nicks)} { 291 if {[set idx [lsearch -glob $tags NICK-*]] >= 0} { 292 set nick [string range [lindex $tags $idx] 5 end] 293 } 294 if {[set idx [lsearch -glob $tags NICKMSG-*]] >= 0} { 295 set nick [string range [lindex $tags $idx] 5 end] 296 } 297 } 298 299 if {$nick == ""} return 300 301 $m add command -label [::msgcat::mc "Edit nick color..."] \ 302 -command [list [namespace current]::edit_nick_color $chatwin $nick] 303} 304 305proc nickcolors::add_groupchat_user_menu_items {m xlib jid} { 306 variable options 307 308 if {$options(use_colored_roster_nicks)} { 309 set chatid [chat::chatid $xlib [::xmpp::jid::stripResource $jid]] 310 set chatwin [chat::chat_win $chatid] 311 set nick [chat::get_nick $xlib $jid groupchat] 312 $m add command -label [::msgcat::mc "Edit nick color..."] \ 313 -command [list [namespace current]::edit_nick_color $chatwin $nick] 314 } 315} 316 317proc nickcolors::edit_nick_color {chatwin nick} { 318 variable NickColors 319 320 set new [tk_chooseColor -initialcolor [get_color $nick] \ 321 -title [::msgcat::mc "Edit %s color" $nick]] 322 if {$new == ""} return 323 324 if {$new != [get_color $nick]} { 325 set NickColors($nick) $new 326 change_options 327 [namespace current]::save_nick_colors 328 } 329} 330 331