📄 chatwindow.tcl
字号:
########################################## Chat Window code abstraction ## By Alberto D�z ##########################################package require framecpackage require scalable-bgnamespace eval ::ChatWindow { #/////////////////////////////////////////////////////////////////////////////// # Namespace variables, relative to chat windows' data. In the code are accessible # through '::namespace::variable' syntax (to avoid local instances of the variable # and have the scope more clear). # As ::ChatWindow::winid is the index used in the # window widgets for chat windows, we only initialize # it at the first time, to avoid problems with proc # reload_files wich will cause some bugs related to # winid being 0 after some windows have been created. if { $initialize_amsn == 1 } { variable chat_ids variable first_message variable msg_windows variable new_message_on variable recent_message variable titles variable windows [list] variable winid 0 variable containers variable containerwindows variable tab2win variable win2tab variable containercurrent variable containerid 0 variable scrolling } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::Change (chatid, newchatid) # This proc is called from the protocol layer when a private chat changes into a # conference, right after a JOI command comes from the SB. It means that the window # assigned to $chatid should now be related to $newchatid. ::ChatWindow::Change # will return the new chatid if the change is OK (no other window for that name # exists), or the old chatid if the change is not right # Arguments: # - chatid => Is the name of the chat that was a single private before. # - newchatid => Is the new id of the chat for the conference proc Change { chatid newchatid } { set win_name [::ChatWindow::For $chatid] if { $win_name == 0 } { # Old window window does not exists, so just accept the change, no worries status_log "::ChatWindow::Change: Window doesn't exist (probably invited to a conference)\n" return $newchatid } if { [::ChatWindow::For $newchatid] != 0} { #Old window existed, probably a conference, but new one exists too, so we can't #just allow that messages shown in old window now are shown in a different window, #that wouldn't be nice, so don't allow change status_log "conference wants to become private, but there's already a window\n" return $chatid } #So, we had an old window for chatid, but no window for newchatid, so the window will #change it's assigned chat ::ChatWindow::UnsetFor $chatid $win_name ::ChatWindow::SetFor $newchatid $win_name status_log "::ChatWindow::Change: changing $chatid into $newchatid\n" return $newchatid } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::GetTopFrame (window) # Returns the path to the top frame (containing "To: ...") for a given window # Arguments: # - window => Is the chat window widget (.msg_n - Where n is an integer) proc GetTopFrame { window } { return $window.top } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::GetOutText (window) # Returns the path to the output text widget in a given window # Arguments: # - window => Is the chat window widget (.msg_n - Where n is an integer) proc GetOutText { window } { return $window.f.out.scroll.text } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::GetInputText (window) # Returns the path to the input text widget in a given window # Arguments: # - window => Is the chat window widget (.msg_n - Where n is an integer) proc GetInputText { window } { return [$window.f.bottom.left.in getinnerframe].text } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::GetStatusText (window) # Returns the path to the statusbar text widget in a given window # Arguments: # - window => Is the chat window widget (.msg_n - Where n is an integer) proc GetStatusText { window } { return [$window.statusbar getinnerframe].status } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::GetStatusCharsTypedText (window) # Returns the path to the statusbar text widget in a given window # Arguments: # - window => Is the chat window widget (.msg_n - Where n is an integer) proc GetStatusCharsTypedText { window } { return [$window.statusbar getinnerframe].charstyped } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::Clear (window) # Deletes all the text in the chat window's input widget # Arguments: # - window => Is the chat window widget (.msg_n - Where n is an integer) proc Clear { window } { set window [::ChatWindow::getCurrentTab $window] [::ChatWindow::GetOutText $window] configure -state normal [::ChatWindow::GetOutText $window] delete 0.0 end [::ChatWindow::GetOutText $window] configure -state disabled } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::Close (window) # Called when a window is about to be closed, for example when we press ESC. # Arguments: # - window => Is the window widget destroyed (.msg_n - Where n is an integer) proc Close { window } { if { $::ChatWindow::recent_message($window) == 1 && [::config::getKey recentmsg] == 1} { status_log "Recent message exists\n" white set ::ChatWindow::recent_message($window) 0 } else { set idx [lsearch $::ChatWindow::windows $window] if { $idx != -1 } { set ::ChatWindow::windows [lreplace $::ChatWindow::windows $idx $idx] } destroy $window } } proc ContainerClose { window } { variable win2tab set current [GetCurrentWindow $window] set currenttab [set win2tab($current)] #If there is just one tab OR user choosed to always close one tab when clicking the close button if { [::ChatWindow::CountTabs $window] == 1 || [::config::getKey ContainerCloseAction] == 2} { ::ChatWindow::CloseTab $currenttab return } #If user choosed to always close all tabs when clicking the close button if {[::config::getKey ContainerCloseAction] == 1} { ::ChatWindow::CloseAll $window; destroy $window return } set nodot [string map { "." "_"} $window] set w .close$nodot if { [winfo exists $w] } { raise $w return } toplevel $w wm title $w "[trans closeall]" #Create the 2 frames frame $w.top frame $w.buttons #Create the picture of warning (at left) label $w.top.bitmap -image [::skin::loadPixmap warning] pack $w.top.bitmap -side left -pady 5 -padx 10 label $w.top.question -text "[trans closeall]" -font bigfont pack $w.top.question -pady 5 -padx 10 checkbutton $w.top.remember -text [trans remembersetting] -variable [::config::getVar remember] pack $w.top.remember -pady 5 -padx 10 -side left #Create the buttons button $w.buttons.yes -text "[trans yes]" -command "::ChatWindow::ContainerCloseAction yes $window $w" button $w.buttons.no -text "[trans no]" -command "::ChatWindow::ContainerCloseAction no $currenttab $w" -default active button $w.buttons.cancel -text "[trans cancel]" -command "destroy $w" pack $w.buttons.yes -pady 5 -padx 5 -side right pack $w.buttons.cancel -pady 5 -padx 5 -side left pack $w.buttons.no -pady 5 -padx 5 -side right #Pack frames pack $w.top -pady 5 -padx 5 -side top pack $w.buttons -pady 5 -padx 5 -fill x moveinscreen $w 30 bind $w <<Escape>> "destroy $w" } #Action to do when someone chooses yes/or inside ContainerClose proc ContainerCloseAction {action window w} { if {$action == "yes"} { ::ChatWindow::CloseAll $window; destroy $window; destroy $w if {[::config::getKey remember]} { ::config::setKey ContainerCloseAction 1 } } else { ::ChatWindow::CloseTab $window; destroy $w if {[::config::getKey remember]} { ::config::setKey ContainerCloseAction 2 } } } proc DetachAll { w } { variable containerwindows variable containers variable containercurrent if {![info exists containerwindows($w)] || [winfo toplevel $w] != $w} { return } status_log "detaching containerwindows $w\n" red foreach window [set containerwindows($w)] { status_log "destroy $window\n" red DetachTab [set ::ChatWindow::win2tab($window)] } status_log "unsetting containerwindow and containercurrent\n" red unset containerwindows($w) unset containercurrent($w) status_log "unsetting containers array...\n" red foreach { key value } [array get containers] { if { $value == $w } { status_log "found containers $key $value\n" red unset containers($key) } } destroy $w } proc CountTabs { w } { return [llength [set ::ChatWindow::containerwindows($w)]] } proc CloseAll { w } { variable containerwindows variable containers variable containercurrent if {![info exists containerwindows($w)] || [winfo toplevel $w] != $w} { return } status_log "destroying containerwindows $w\n" red foreach window [set containerwindows($w)] { status_log "destroy $window\n" red destroy $window } status_log "unsetting containerwindow and containercurrent\n" red unset containerwindows($w) unset containercurrent($w) status_log "unsetting containers array...\n" red foreach { key value } [array get containers] { if { $value == $w } { status_log "found containers $key $value\n" red unset containers($key) } } } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::Closed (window, path) # Called when a window and its children are destroyed. When the main window is # destroyed ($window == $path) then it tells the protocol layer to leave the # chat related to $window, and unsets variables used for that window. # Arguments: # - window => Is the window widget destroyed (.msg_n - Where n is an integer) # - path => Is the parent widget of the destroyed childrens (the window) proc Closed { window path } { #Only run when the parent window close event comes if { "$window" != "$path" } { return 0 } set chatid [::ChatWindow::Name $window] if { $chatid == 0 } { status_log "VERY BAD ERROR in ::ChatWindow::Closed!!!\n" red return 0 } if {[::config::getKey keep_logs]} { set user_list [::MSN::usersInChat $chatid] foreach user_login $user_list { ::log::StopLog $user_login } } ::ChatWindow::UnsetFor $chatid $window unset ::ChatWindow::titles(${window}) unset ::ChatWindow::first_message(${window}) unset ::ChatWindow::recent_message(${window}) #Delete images if not in use catch {destroy $window.bottom.pic} set user_list [::MSN::usersInChat $chatid] #Could be cleaner, but this works, destroying unused vars, saving mem catch { global ${window}_show_picture ${window}.f.bottom.left.in.inner.text unset ${window}_show_picture unset ${window}.f.bottom.left.in.inner.text } ::MSN::leaveChat $chatid } #/////////////////////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////////////////// # ::ChatWindow::Configured (window) # This proc is called when we resize the window, it stores the new size in config # Arguments: # - window => Is the chat window widget (.msg_n - Where n is an integer) proc Configured { window } { #only run this if the window is the outer window if { ![string equal $window [winfo toplevel $window]]} { return } set chatid [::ChatWindow::Name $window] if { $chatid != 0 } { after cancel "::ChatWindow::TopUpdate $chatid" after 200 "::ChatWindow::TopUpdate $chatid" } if { [::config::getKey savechatwinsize] } { set geometry [wm geometry $window] set pos_start [string first "+" $geometry] ::config::setKey winchatsize [string range $geometry 0 [expr {$pos_start-1}]] } } #///////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -