git-gui: Display tooltips in blame viewer
[gitweb.git] / lib / blame.tcl
index f48624a99eba8820230c7f30e6e9f802af1890ad..fef28a347e84752f0357d061c95db307ad3caf8b 100644 (file)
@@ -31,6 +31,11 @@ field r_orig_line   ; # original line number
 field r_final_line  ; # final line number
 field r_line_count  ; # lines in this region
 
+field tooltip_wm     {} ; # Current tooltip toplevel, if open
+field tooltip_timer  {} ; # Current timer event for our tooltip
+field tooltip_commit {} ; # Commit in tooltip
+field tooltip_text   {} ; # Text in current tooltip
+
 variable active_color #98e1a0
 variable group_colors {
        #cbcbcb
@@ -38,6 +43,8 @@ variable group_colors {
 }
 
 constructor new {i_commit i_path} {
+       global cursor_ptr
+
        set commit $i_commit
        set path   $i_path
 
@@ -149,6 +156,7 @@ constructor new {i_commit i_path} {
                $w_load \
                $w_line \
                $w_file] {
+               $i conf -cursor $cursor_ptr
                $i conf -yscrollcommand \
                        [list many2scrollbar [list \
                        $w_cgrp \
@@ -156,8 +164,16 @@ constructor new {i_commit i_path} {
                        $w_line \
                        $w_file \
                        ] yview $w.out.sby]
-               bind $i <Button-1> "[cb _click $i @%x,%y]; focus $i"
+               bind $i <Button-1>   "
+                       [cb _hide_tooltip]
+                       [cb _click $i @%x,%y]
+                       focus $i
+               "
+               bind $i <Any-Motion>  [cb _show_tooltip $i @%x,%y]
+               bind $i <Any-Enter>   [cb _hide_tooltip]
+               bind $i <Any-Leave>   [cb _hide_tooltip]
                bind_button3 $i "
+                       [cb _hide_tooltip]
                        set cursorX %x
                        set cursorY %y
                        set cursorW %W
@@ -267,7 +283,18 @@ method _read_blame {fd} {
                        set n    $r_line_count
                        set lno  $r_final_line
                        set cmit $r_commit
-                       set abbr [string range $cmit 0 4]
+
+                       if {[regexp {^0{40}$} $cmit]} {
+                               set abbr work
+                       } else {
+                               set abbr [string range $cmit 0 4]
+                       }
+
+                       if {![catch {set ncmit $line_commit([expr {$lno - 1}])}]} {
+                               if {$ncmit eq $cmit} {
+                                       set abbr |
+                               }
+                       }
 
                        while {$n > 0} {
                                set lno_e "$lno.0 lineend + 1c"
@@ -286,8 +313,9 @@ method _read_blame {fd} {
                                set line_commit($lno) $cmit
                                set line_file($lno)   $file
 
-                               $w_cgrp delete $lno.0 $lno_e
-                               $w_cgrp insert $lno.0 "$abbr\n"
+                               $w_cgrp delete $lno.0 "$lno.0 lineend"
+                               $w_cgrp insert $lno.0 $abbr
+                               set abbr |
 
                                $w_cgrp tag add g$cmit $lno.0 $lno_e
                                $w_line tag add g$cmit $lno.0 $lno_e
@@ -311,6 +339,13 @@ method _read_blame {fd} {
                                incr blame_lines
                        }
 
+                       if {![catch {set ncmit $line_commit($lno)}]} {
+                               if {$ncmit eq $cmit} {
+                                       $w_cgrp delete $lno.0 "$lno.0 lineend + 1c"
+                                       $w_cgrp insert $lno.0 "|\n"
+                               }
+                       }
+
                        set hc $highlight_commit
                        if {$hc ne {}
                                && [expr {$order($hc) + 1}] == $order($cmit)} {
@@ -425,6 +460,10 @@ $msg"
 
        set highlight_line $lno
        set highlight_commit $cmit
+
+       if {$highlight_commit eq $tooltip_commit} {
+               _hide_tooltip $this
+       }
 }
 
 method _copycommit {} {
@@ -439,4 +478,111 @@ method _copycommit {} {
        }
 }
 
+method _show_tooltip {cur_w pos} {
+       set lno [lindex [split [$cur_w index $pos] .] 0]
+       if {[catch {set cmit $line_commit($lno)}]} {
+               _hide_tooltip $this
+               return
+       }
+
+       if {$cmit eq $highlight_commit} {
+               _hide_tooltip $this
+               return
+       }
+
+       if {$cmit eq $tooltip_commit} {
+               _position_tooltip $this
+       } elseif {$tooltip_wm ne {}} {
+               _open_tooltip $this $cur_w
+       } elseif {$tooltip_timer eq {}} {
+               set tooltip_timer [after 1000 [cb _open_tooltip $cur_w]]
+       }
+}
+
+method _open_tooltip {cur_w} {
+       set tooltip_timer {}
+       set pos_x [winfo pointerx $cur_w]
+       set pos_y [winfo pointery $cur_w]
+       if {[winfo containing $pos_x $pos_y] ne $cur_w} {
+               _hide_tooltip $this
+               return
+       }
+
+       set pos @[join [list \
+               [expr {$pos_x - [winfo rootx $cur_w]}] \
+               [expr {$pos_y - [winfo rooty $cur_w]}]] ,]
+       set lno [lindex [split [$cur_w index $pos] .] 0]
+       set cmit $line_commit($lno)
+
+       set author_name {}
+       set author_email {}
+       set author_time {}
+       catch {set author_name $header($cmit,author)}
+       catch {set author_email $header($cmit,author-mail)}
+       catch {set author_time [clock format \
+               $header($cmit,author-time) \
+               -format {%Y-%m-%d %H:%M:%S}
+       ]}
+
+       set committer_name {}
+       set committer_email {}
+       set committer_time {}
+       catch {set committer_name $header($cmit,committer)}
+       catch {set committer_email $header($cmit,committer-mail)}
+       catch {set committer_time [clock format \
+               $header($cmit,committer-time) \
+               -format {%Y-%m-%d %H:%M:%S}
+       ]}
+
+       set summary {}
+       catch {set summary $header($cmit,summary)}
+
+       set tooltip_commit $cmit
+       set tooltip_text "commit $cmit
+$author_name $author_email  $author_time
+$summary"
+
+       if {$tooltip_wm ne "$cur_w.tooltip"} {
+               _hide_tooltip $this
+
+               set tooltip_wm [toplevel $cur_w.tooltip -borderwidth 1]
+               wm overrideredirect $tooltip_wm 1
+               wm transient $tooltip_wm [winfo toplevel $cur_w]
+               pack [label $tooltip_wm.label \
+                       -background lightyellow \
+                       -foreground black \
+                       -textvariable @tooltip_text \
+                       -justify left]
+       }
+       _position_tooltip $this
+}
+
+method _position_tooltip {} {
+       set req_w [winfo reqwidth  $tooltip_wm.label]
+       set req_h [winfo reqheight $tooltip_wm.label]
+       set pos_x [expr {[winfo pointerx .] +  5}]
+       set pos_y [expr {[winfo pointery .] + 10}]
+
+       set g "${req_w}x${req_h}"
+       if {$pos_x >= 0} {append g +}
+       append g $pos_x
+       if {$pos_y >= 0} {append g +}
+       append g $pos_y
+
+       wm geometry $tooltip_wm $g
+       raise $tooltip_wm
+}
+
+method _hide_tooltip {} {
+       if {$tooltip_wm ne {}} {
+               destroy $tooltip_wm
+               set tooltip_wm {}
+               set tooltip_commit {}
+       }
+       if {$tooltip_timer ne {}} {
+               after cancel $tooltip_timer
+               set tooltip_timer {}
+       }
+}
+
 }