From c8937b8c177569606c7e3031347835a6fd7a9801 Mon Sep 17 00:00:00 2001
From: Ivica Ico Bukvic <ico@vt.edu>
Date: Mon, 2 Sep 2013 01:29:34 -0400
Subject: [PATCH] fixed inconsistent scrolling amount when using various
 scrolling methods as well as scrollbar detection logic

---
 pd/src/g_editor.c |  20 +++++--
 pd/src/pd.tk      | 146 +++++++++++++++++++++++++++++++++++++---------
 2 files changed, 133 insertions(+), 33 deletions(-)

diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index 73c6e7d03..a7d82c694 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -142,14 +142,12 @@ void gobj_getrect(t_gobj *x, t_glist *glist, int *x1, int *y1,
 
 void gobj_displace(t_gobj *x, t_glist *glist, int dx, int dy)
 {
-	fprintf(stderr,"gobj_displace\n");
     if (x->g_pd->c_wb && x->g_pd->c_wb->w_displacefn)
         (*x->g_pd->c_wb->w_displacefn)(x, glist, dx, dy);
 }
 
 void gobj_displace_withtag(t_gobj *x, t_glist *glist, int dx, int dy)
 {
-		fprintf(stderr,"gobj_displace_withtag\n");
     if (x->g_pd->c_wb && x->g_pd->c_wb->w_displacefnwtag)
         (*x->g_pd->c_wb->w_displacefnwtag)(x, glist, dx, dy);
 }
@@ -4207,7 +4205,8 @@ void canvas_mouseup(t_canvas *x,
 	    x->gl_editor->e_onmotion = MA_NONE;
 	}
 	//fprintf(stderr,"canvas_mouseup -> canvas_doclick %d\n", which);
-	canvas_doclick(x, xpos, ypos, 0, (glob_shift + glob_ctrl*2 + glob_alt*4), 0);
+	if (canvas_last_glist_mod == -1) //this is to ignore scrollbar clicks from within tcl
+		canvas_doclick(x, xpos, ypos, 0, (glob_shift + glob_ctrl*2 + glob_alt*4), 0);
 }
 
 void canvas_mousedown_middle(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
@@ -4283,7 +4282,7 @@ static void canvas_displaceselection(t_canvas *x, int dx, int dy)
 		sys_vgui(".x%lx.c move selected %d %d\n", x, dx, dy);
 	    if (resortin) canvas_resortinlets(x);
 	    if (resortout) canvas_resortoutlets(x);
-	    sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x);
+	    //sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x);
 	    if (x->gl_editor->e_selection)
 	        canvas_dirty(x, 1);
 	}
@@ -4512,13 +4511,20 @@ extern void graph_checkgop_rect(t_gobj *z, t_glist *glist,
 void canvas_motion(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
     t_floatarg fmod)
 { 
-    //fprintf(stderr,"motion %d %d %d\n", (int)xpos, (int)ypos, (int)fmod);
+    //fprintf(stderr,"motion %d %d %d %d\n", (int)xpos, (int)ypos, (int)fmod, canvas_last_glist_mod);
     int mod = fmod;
     if (!x->gl_editor)
     {
         bug("editor");
         return;
     }
+    if (canvas_last_glist_mod == -1 && mod != -1) {
+    	//fprintf(stderr,"revert the cursor %d\n", x->gl_edit);
+    	if (x->gl_edit)
+	    	canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+	    else
+	    	canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
+    }
     glist_setlastxymod(x, xpos, ypos, mod);
     if (x->gl_editor->e_onmotion == MA_MOVE)
     {
@@ -4613,10 +4619,12 @@ void canvas_motion(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
     }
 	else if (x->gl_editor->e_onmotion == MA_SCROLL || mod == -1) {
 		// we use bogus mod from tcl to let editor know we are scrolling
+		if (mod == -1)
+			canvas_setcursor(x, CURSOR_RUNMODE_CLICKME);
 		//fprintf(stderr,"canvas_motion MA_SCROLL\n");
 	}
     else {
-		//fprintf(stderr,"canvas_motion -> doclick %d\n", x->gl_editor->e_onmotion);
+		//fprintf(stderr,"canvas_motion -> doclick %d %d\n", x->gl_editor->e_onmotion, mod);
 		//sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x);
 		canvas_doclick(x, xpos, ypos, 0, mod, 0);
 		//pd_vmess(&x->gl_pd, gensym("mouse"), "ffff", (double)xpos, (double)ypos, 0, (double)mod);
diff --git a/pd/src/pd.tk b/pd/src/pd.tk
index 5cb8d427e..0319d25c2 100644
--- a/pd/src/pd.tk
+++ b/pd/src/pd.tk
@@ -3269,9 +3269,11 @@ proc pdtk_canvas_new {name width height geometry editable} {
 
 	set ::scroll_on($name) 0
 	set ::hit_scrollbar($name) 0
-	set ::scroll_was_cursor($name) 0
+	#set ::scroll_was_cursor($name) 0
 	set ::last_scroll_x($name) 0
 	set ::last_scroll_y($name) 0
+	set ::canvaswidth($name) 0
+	set ::canvasheight($name) 0
 }
 
 set HSCROLL_PAD_L 6
@@ -3307,13 +3309,14 @@ proc pdtk_canvas_draw_scrollbars {name} {
 			set scrolly1 [expr [$name.c canvasy 0] + [winfo height $name] - $SCROLL_PAD_EDGE]
 			set scrollx2 [expr $scrollx1 + $width]
 			#puts stderr "$vx1 $vx2 $npix $width $loffset $scrollx1 $scrollx2"
-			set hscroll [$name.c create polyline $scrollx1 $scrolly1 $scrollx2 $scrolly1 -stroke $scrollbar_color -strokewidth $SCROLL_THICKNESS -strokeopacity 0.25 -tags noscroll -strokelinecap round]
-			$name.c bind $hscroll <Button-1> {pdtk_canvas_scroll_horizontal_click %W %x %y %b 0}
-			$name.c bind $hscroll <Enter> {pdtk_canvas_enter_scrollbar %W}
-			$name.c bind $hscroll <Leave> {pdtk_canvas_leave_scrollbar %W}
+			set hscroll [$name.c create polyline $scrollx1 $scrolly1 $scrollx2 $scrolly1 -stroke $scrollbar_color -strokewidth $SCROLL_THICKNESS -strokeopacity 0.25 -tags xscroll -strokelinecap round]
+			$name.c addtag noscroll withtag xscroll
+			#$name.c bind $hscroll <Button-1> {pdtk_canvas_scroll_horizontal_click %W %x %y %b 0}
+			$name.c bind $hscroll <Enter> {pdtk_canvas_enter_scrollbar %W %x %y}
+			#$name.c bind $hscroll <Motion> {pdtk_canvas_enter_scrollbar %W}
+			$name.c bind $hscroll <Leave> {pdtk_canvas_leave_scrollbar %W %x %y}
 		}
 	}
-
 	if {$::yscrollable($name)} {
 		set visible [$name.c yview]
 		set vy1 [lindex $visible 0]
@@ -3326,31 +3329,80 @@ proc pdtk_canvas_draw_scrollbars {name} {
 			set scrolly1 [expr [$name.c canvasy 0] + $VSCROLL_PAD_U +$toffset]
 			set scrolly2 [expr $scrolly1 + $height]
 			#puts stderr "$vy1 $vy2 $npix $height $toffset $scrolly1 $scrolly2"
-			set vscroll [$name.c create polyline $scrollx1 $scrolly1 $scrollx1 $scrolly2 -stroke $scrollbar_color -strokewidth $SCROLL_THICKNESS -strokeopacity 0.25 -tags noscroll -strokelinecap round]
-			$name.c bind $vscroll <Button-1> {pdtk_canvas_scroll_vertical_click %W %x %y %b 0}
-			$name.c bind $vscroll <Enter> {pdtk_canvas_enter_scrollbar %W}
-			$name.c bind $vscroll <Leave> {pdtk_canvas_leave_scrollbar %W}
+			set vscroll [$name.c create polyline $scrollx1 $scrolly1 $scrollx1 $scrolly2 -stroke $scrollbar_color -strokewidth $SCROLL_THICKNESS -strokeopacity 0.25 -tags yscroll -strokelinecap round]
+			$name.c addtag noscroll withtag yscroll
+			#$name.c bind $vscroll <Button-1> {pdtk_canvas_scroll_vertical_click %W %x %y %b 0}
+			$name.c bind $vscroll <Enter> {pdtk_canvas_enter_scrollbar %W %x %y}
+			#$name.c bind $vscroll <Motion> {pdtk_canvas_enter_scrollbar %W}
+			$name.c bind $vscroll <Leave> {pdtk_canvas_leave_scrollbar %W %x %y}
 		}
 	}
 	pdtk_canvas_update_sticky_tip $name.c
 }
 
-proc pdtk_canvas_enter_scrollbar {name} {
+proc pdtk_canvas_enter_scrollbar {name x y} {
 	set name [string trimright $name .c]
-	global cursor_runmode_clickme
 	if { $::hit_scrollbar($name) == 0 } {
-		set ::scroll_was_cursor($name) [$name cget -cursor]
-		$name configure -cursor $cursor_runmode_clickme
-		set ::hit_scrollbar($name) 1
+		set x [$name.c canvasx $x]
+		set y [$name.c canvasy $y]
+		set inside 0
+		if { $::yscrollable($name) } {
+			set coords [$name.c bbox yscroll]
+			foreach {xa ya xb yb} $coords {
+				#puts stderr "Y | $x $y | $xa $xb $ya $yb"
+				if { [expr $xa + 3] < $x && [expr $xb - 3] > $x && [expr $ya + 5] < $y && [expr $yb - 5] > $y } {
+					 #puts stderr "inside Y"
+					 set inside 1
+				}
+			}
+		}
+		if { $::xscrollable($name) } {
+			set coords [$name.c bbox xscroll]
+			foreach {xa ya xb yb} $coords {
+				#puts stderr "Y | $x $y | $xa $xb $ya $yb"
+				if { [expr $xa + 5] < $x && [expr $xb - 5] > $x && [expr $ya + 3] < $y && [expr $yb - 3] > $y } {
+					 #puts stderr "inside X"
+					 set inside 1
+				}
+			}
+		}
+		#set ::scroll_was_cursor($name) [$name cget -cursor]
+		#$name configure -cursor $cursor_runmode_clickme
+		if { $inside == 1 } {
+			set ::hit_scrollbar($name) 1
+		}
 		#puts stderr scrollbar_enter
 	}
 }
 
-proc pdtk_canvas_leave_scrollbar {name} {
+proc pdtk_canvas_leave_scrollbar {name x y} {
+	#puts stderr pre_scrollbar_leave
 	set name [string trimright $name .c]
 	if { $::hit_scrollbar($name) != 0 } {
+		set x [$name.c canvasx $x]
+		set y [$name.c canvasy $y]
+		if { $::yscrollable($name) } {
+			set coords [$name.c bbox yscroll]
+			foreach {xa ya xb yb} $coords {
+				#puts stderr "Y | $x $y | $xa $xb $ya $yb"
+				if { [expr $xa + 3] < $x && [expr $xb - 3] > $x && [expr $ya + 5] < $y && [expr $yb - 5] > $y } {
+					 #puts stderr "Y still inside"
+					 return
+				}
+			}
+		}
+		if { $::xscrollable($name) } {
+			set coords [$name.c bbox xscroll]
+			foreach {xa ya xb yb} $coords {
+				#puts stderr "Y | $x $y | $xa $xb $ya $yb"
+				if { [expr $xa + 5] < $x && [expr $xb - 5] > $x && [expr $ya + 3] < $y && [expr $yb - 3] > $y } {
+					 #puts stderr "X still inside"
+					 return
+				}
+			}
+		}
 		set ::hit_scrollbar($name) 0
-		$name configure -cursor $::scroll_was_cursor($name)
+		#$name configure -cursor $::scroll_was_cursor($name)
 		#puts stderr scrollbar_leave
 	}
 }
@@ -3364,6 +3416,30 @@ proc pdtk_canvas_scroll_xy_click {name x y b} {
 	#puts stderr "XY CLICK $name $x $y"
 }
 
+proc pdtk_canvas_detect_scroll_click {name x y b mod} {
+	set xc [$name.c canvasx $x]
+	set yc [$name.c canvasy $y]
+	if { $::yscrollable($name) } {
+		set coords [$name.c bbox yscroll]
+		foreach {xa ya xb yb} $coords {
+			#puts stderr "Y | $x $y | $xa $xb $ya $yb"
+			if { [expr $xa + 3] < $xc && [expr $xb - 3] > $xc && [expr $ya + 5] < $yc && [expr $yb - 5] > $yc } {
+				 pdtk_canvas_scroll_vertical_click $name.c $x $y $b $mod
+				 return
+			}
+		}
+	}
+	if { $::xscrollable($name) } {
+		set coords [$name.c bbox xscroll]
+		foreach {xa ya xb yb} $coords {
+			#puts stderr "Y | $x $y | $xa $xb $ya $yb"
+			if { [expr $xa + 5] < $xc && [expr $xb - 5] > $xc && [expr $ya + 3] < $yc && [expr $yb - 3] > $yc } {
+				 pdtk_canvas_scroll_horizontal_click $name.c $x $y $b $mod
+			}
+		}
+	}
+}
+
 proc pdtk_canvas_scroll_horizontal_click {name x y b mod} {
 	#puts stderr "HORIZONTAL CLICK $name $x $y $b $mod"
 	set name [string trimright $name .c]
@@ -3372,7 +3448,7 @@ proc pdtk_canvas_scroll_horizontal_click {name x y b mod} {
 		#set ::hit_scrollbar($name) 1
 	} else {
 		set ::scroll_on($name) 0
-		pdtk_canvas_leave_scrollbar $name
+		pdtk_canvas_leave_scrollbar $name $x $y
 	}
 	#puts stderr $::scroll_on($name)
 	set ::last_scroll_x($name) $x
@@ -3387,8 +3463,8 @@ proc pdtk_canvas_scroll_horizontal_click {name x y b mod} {
 proc pdtk_canvas_scroll_horizontal_motion {name x y mod} {
 	global HSCROLL_PAD_L
 	global HSCROLL_PAD_R
-	#puts stderr "HORIZONTAL MOTION $name $x $y $mod"
 	set name [string trimright $name .c]
+	#puts stderr "HORIZONTAL MOTION $name $x $y $mod $::last_scroll_x($name)"
 	if {$::xscrollable($name) && ($::scroll_on($name) == 1 || $::scroll_on($name) == 3)} {
 		set deltax [expr $::last_scroll_x($name) - $x]
 		#puts stderr "deltax=$deltax"
@@ -3396,7 +3472,11 @@ proc pdtk_canvas_scroll_horizontal_motion {name x y mod} {
 			set visible [$name.c xview]
 			set vx1 [lindex $visible 0]
 			set vx2 [lindex $visible 1]
-			set perpixdelta [expr (1.0)/([winfo width $name]-$HSCROLL_PAD_L-$HSCROLL_PAD_R)]
+			if {$::scroll_on($name) == 1} {
+				set perpixdelta [expr (1.0)/([winfo width $name]-$HSCROLL_PAD_L-$HSCROLL_PAD_R)]
+			} else {
+				set perpixdelta [expr 1.0/$::canvasheight($name)]
+			}
 			#puts stderr "scrolling... $vx1 $vx2 $perpixdelta"
 			#$name xview scroll [expr -$deltax] units
 			set displace [expr $perpixdelta * $deltax]
@@ -3418,7 +3498,7 @@ proc pdtk_canvas_scroll_vertical_click {name x y b mod} {
 		#set ::hit_scrollbar($name) 1
 	} else {
 		set ::scroll_on($name) 0
-		pdtk_canvas_leave_scrollbar $name
+		pdtk_canvas_leave_scrollbar $name $x $y
 	}
 	#puts stderr $::scroll_on($name)
 	set ::last_scroll_y($name) $y
@@ -3427,8 +3507,8 @@ proc pdtk_canvas_scroll_vertical_click {name x y b mod} {
 proc pdtk_canvas_scroll_vertical_motion {name x y mod} {
 	global VSCROLL_PAD_U
 	global VSCROLL_PAD_D
-	#puts stderr "VERTICAL MOTION $name $x $y $mod"
 	set name [string trimright $name .c]
+	#puts stderr "VERTICAL MOTION $name $x $y $mod $::last_scroll_y($name)"
 	if {$::yscrollable($name) && $::scroll_on($name) >= 2} {
 		set deltay [expr $::last_scroll_y($name) - $y]
 		#puts stderr "deltay=$deltay"
@@ -3436,7 +3516,11 @@ proc pdtk_canvas_scroll_vertical_motion {name x y mod} {
 			set visible [$name.c yview]
 			set vy1 [lindex $visible 0]
 			set vy2 [lindex $visible 1]
-			set perpixdelta [expr (1.0)/([winfo height $name.c]-$VSCROLL_PAD_U-$VSCROLL_PAD_D)]
+			if {$::scroll_on($name) == 2} {
+				set perpixdelta [expr (1.0)/([winfo height $name.c]-$VSCROLL_PAD_U-$VSCROLL_PAD_D)]
+			} else {
+				set perpixdelta [expr 1.0/$::canvasheight($name)]
+			}
 			#puts stderr "scrolling... $vy1 $vy2 $perpixdelta $deltay"
 			#$name xview scroll [expr -$deltax] units
 			set displace [expr $perpixdelta * $deltay]
@@ -3809,6 +3893,7 @@ proc pdtk_canvas_sendmiddleclick {name x y b f} {
 proc pdtk_canvas_click {name x y b f} {
     focus $name
     set scroll_name [string trimright $name .c]
+    pdtk_canvas_detect_scroll_click $scroll_name $x $y $b $f
 	if { $::hit_scrollbar($scroll_name) == 0 } {
     	pdtk_canvas_sendclick $name $x $y $b $f
 	}
@@ -3846,10 +3931,13 @@ set pdtk_canvas_mouseup_yminval 0
 set pdtk_canvas_mouseup_ymaxval 0
 
 proc pdtk_canvas_mouseup {name x y b} {
-    pd [concat [canvastosym $name] mouseup [$name canvasx $x] \
-            [$name canvasy $y] $b \;]
 	pdtk_canvas_scroll_horizontal_click $name $x $y 0 0
 	pdtk_canvas_scroll_vertical_click $name $x $y 0 0
+	set scroll_name [string trimright $name .c]
+	if { $::hit_scrollbar($scroll_name) == 0 } {
+    	pd [concat [canvastosym $name] mouseup [$name canvasx $x] \
+            [$name canvasy $y] $b \;]
+    }
 }
 
 #proc pdtk_canvas_getscroll_ping {name} {
@@ -4125,6 +4213,9 @@ proc pdtk_canvas_getscroll {name} {
 		set canvaswidth [ expr {abs($xmaxval-$xminval)} ]
 		set canvasheight [ expr {abs($ymaxval-$yminval)} ]
 
+		set ::canvaswidth($parentname) $canvaswidth
+		set ::canvasheight($parentname) $canvasheight
+
 		#puts stderr "BEFORE W: $winwidth ? $canvaswidth -- H: $winheight ? $canvasheight -- SC: $::xscrollable($parentname) $::yscrollable($parentname)"
 
 		if {$::scroll($parentname) == 1} {
@@ -4519,6 +4610,7 @@ proc pdtk_check_scroll_on_motion {w threshold} {
 }
 
 proc pdtk_canvas_motion {name x y mods} {
+	#puts stderr "motion [$name canvasx $x] [$name canvasy $y]"
 	global pointer_x_local pointer_y_local pointer_x_global pointer_y_global tooltip_visible
 	set pointer_x_local $x
 	set pointer_y_local $y
@@ -4529,9 +4621,9 @@ proc pdtk_canvas_motion {name x y mods} {
 	if { $::hit_scrollbar($scroll_name) != 0 } { set mods -1 }
  	#puts stderr [concat $pointer_x_local $pointer_y_local $pointer_x_global $pointer_y_global]
     #puts stderr [concat [canvastosym $name] $name $x $y]
-    pd [canvastosym $name] motion [$name canvasx $x] [$name canvasy $y] $mods \;
-	pdtk_canvas_scroll_horizontal_motion $name $x $y 0
+    pdtk_canvas_scroll_horizontal_motion $name $x $y 0
 	pdtk_canvas_scroll_vertical_motion $name $x $y 0
+    pd [canvastosym $name] motion [$name canvasx $x] [$name canvasy $y] $mods \;
 }
 
 # "map" event tells us when the canvas becomes visible (arg is "0") or
-- 
GitLab