Hey,

While trying to fox bug #324513, I notice that trying to scroll a control,
which has bigger bounds than any of its Parents controls, shows some drawing
issues.

Example: you have a VScrollBar with Height > than its contaning form:

  __________
  |        |          | <- This is the form (Parent)
  |____|_____|
           | <- This is the scrollbar

This is because when we try to scroll a windows, we copy some area of it and
invalidate the 'new visible' one.
But we assume that the entire control is visible (that all its Bounds are
painted and available to scroll). But it's not the case in this case, where
the VScrollBar is not entirely visible,
because it's parents Bounds don't contain it.

The attached patch tries to detect all the non-visible regions of a control
(top, bottom, right, left) and then check if whe are trying to scroll part
of the non visible area,
which then is invalidated.

Carlos.
Index: System.Windows.Forms/XplatUIX11.cs
===================================================================
--- System.Windows.Forms/XplatUIX11.cs	(revisión: 86279)
+++ System.Windows.Forms/XplatUIX11.cs	(copia de trabajo)
@@ -4743,29 +4743,9 @@
 
 			hwnd = Hwnd.ObjectFromHandle(handle);
 
-			Rectangle r = Rectangle.Intersect (hwnd.Invalid, area);
-			if (!r.IsEmpty) {
-				/* We have an invalid area in the window we're scrolling. 
-				   Adjust our stored invalid rectangle to to match the scrolled amount */
+			ScrollInvalidArea (hwnd, hwnd.Invalid, area, XAmount, YAmount);
+			ScrollInvalidArea (hwnd, GetNonVisibleArea (handle), area, XAmount, YAmount);
 
-				r.X += XAmount;
-				r.Y += YAmount;
-
-				if (r.X < 0) {
-					r.Width += r.X;
-					r.X =0;
-				}
-
-				if (r.Y < 0) {
-					r.Height += r.Y;
-					r.Y =0;
-				}
-
-				if (area.Contains (hwnd.Invalid))
-					hwnd.ClearInvalidArea ();
-				hwnd.AddInvalidArea(r);
-			}
-
 			gc_values = new XGCValues();
 
 			if (with_children) {
@@ -4819,6 +4799,82 @@
 			XFreeGC(DisplayHandle, gc);
 		}
 
+		void ScrollInvalidArea (Hwnd hwnd, Rectangle invalid_area, Rectangle area, int XAmount, int YAmount)
+		{			
+			Rectangle r = Rectangle.Intersect (invalid_area, area);
+			if (!r.IsEmpty) {
+				/* We have an invalid area in the window we're scrolling. 
+				   Adjust our stored invalid rectangle to to match the scrolled amount */
+
+				r.X += XAmount;
+				r.Y += YAmount;
+
+				if (r.X < 0) {
+					r.Width += r.X;
+					r.X =0;
+				}
+
+				if (r.Y < 0) {
+					r.Height += r.Y;
+					r.Y =0;
+				}
+
+				if (area.Contains (hwnd.Invalid))
+					hwnd.ClearInvalidArea ();
+				hwnd.AddInvalidArea(r);
+			}
+		}
+
+		Rectangle GetNonVisibleArea (IntPtr handle)
+		{
+			bool is_area_empty = true;
+			Rectangle non_visible_area = Rectangle.Empty;
+
+			Control c = Control.FromHandle (handle);
+			Control parent;
+			Size ctrl_size = c.ClientSize;
+			Size parent_size;
+
+			for (parent = c.Parent; parent != null; parent = parent.Parent) {
+				Point origin = parent.PointToClient (c.PointToScreen (new Point (0, 0)));
+				parent_size = parent.ClientSize;
+
+				int left = origin.X < 0 ? - (origin.X) : 0;
+				int right = origin.X + ctrl_size.Width - parent_size.Width;
+				int top = origin.Y < 0 ? - (origin.Y) : 0;
+				int bottom = origin.Y + ctrl_size.Height - parent_size.Height;
+
+				if (left <= 0 && right <= 0 && top <= 0 && bottom <= 0)
+					continue;
+
+				Rectangle bottom_rect = new Rectangle (0, ctrl_size.Height - bottom, ctrl_size.Width, bottom);
+				Rectangle top_rect = new Rectangle (0, 0, ctrl_size.Width, top);
+				Rectangle left_rect = new Rectangle (0, 0, left, ctrl_size.Height);
+				Rectangle right_rect = new Rectangle (ctrl_size.Width - right, 0, ctrl_size.Height, right);
+				Rectangle [] areas = new Rectangle [] {bottom_rect, top_rect, left_rect, right_rect};
+
+				for (int i = 0; i < areas.Length; i++) {
+					Rectangle area = areas [i];
+					if (area.Width <= 0 || area.Height <= 0)
+						continue;
+
+					if (is_area_empty) {
+						non_visible_area = area;
+						is_area_empty = false;
+						continue;
+					}
+
+					non_visible_area = Rectangle.Union (area, non_visible_area);
+				}
+
+				// Already need to invalidate entire area
+				if (non_visible_area.Width >= ctrl_size.Width && non_visible_area.Height >= ctrl_size.Height)
+					break;
+			}
+
+			return non_visible_area;
+		}
+
 		internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) {
 			Hwnd		hwnd;
 			Rectangle	rect;
_______________________________________________
Mono-winforms-list maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-winforms-list

Reply via email to