From 09a892525cfca8d7326e33a4b183bd780941692e Mon Sep 17 00:00:00 2001
From: Brownard <brownard>
Date: Sun, 21 Sep 2014 18:25:09 +0100
Subject: [PATCH] Modify focus handling

Modified the focus handling so that an element more in line with the direction of movement is selected over an element that is closer
---
 .../Controls/Visuals/FrameworkElement.cs           | 54 ++++++++++++++++++----
 1 file changed, 46 insertions(+), 8 deletions(-)

diff --git a/MediaPortal/Source/UI/SkinEngine/Controls/Visuals/FrameworkElement.cs b/MediaPortal/Source/UI/SkinEngine/Controls/Visuals/FrameworkElement.cs
index 7257e20..e967964 100644
--- a/MediaPortal/Source/UI/SkinEngine/Controls/Visuals/FrameworkElement.cs
+++ b/MediaPortal/Source/UI/SkinEngine/Controls/Visuals/FrameworkElement.cs
@@ -1018,9 +1018,9 @@ namespace MediaPortal.UI.SkinEngine.Controls.Visuals
             // it won't be used as next focus element
             continue;
           float distance = BorderDistance(child.ActualBounds, currentFocusRect.Value);
-          if (bestMatch == null || distance < bestDistance ||
-            distance == bestDistance && topOrLeftDifference < bestTopOrLeftDifference
-            /* || topOrLeftDifference == bestTopOrLeftDifference && centerDistance < bestCenterDistance*/)
+          if (bestMatch == null || (distance < bestDistance && topOrLeftDifference < 0)
+            || (topOrLeftDifference < bestTopOrLeftDifference && (distance == bestDistance || bestTopOrLeftDifference >= 0))
+            /*|| topOrLeftDifference == bestTopOrLeftDifference && centerDistance < bestCenterDistance*/)
           {
             bestMatch = child;
             bestDistance = distance;
@@ -1058,6 +1058,44 @@ namespace MediaPortal.UI.SkinEngine.Controls.Visuals
       return (float) Math.Sqrt(distX * distX + distY * distY);
     }
 
+    /// <summary>
+    /// Calculates the horizontal distance from <paramref name="r1"/> to <paramref name="r2"/>.
+    /// </summary>
+    /// <param name="r1"></param>
+    /// <param name="r2"></param>
+    /// <returns>Horizontal distance, negative if there is an overlap.</returns>
+    protected static float HorizontalDistance(RectangleF r1, RectangleF r2)
+    {
+      if (r1.Right <= r2.Left)
+        return r2.Left - r1.Right;
+      if (r1.Left >= r2.Right)
+        return r1.Left - r2.Right;
+      if (r1.Left < r2.Left && r1.Right < r2.Right)
+        return r2.Left - r1.Right;
+      if (r1.Right > r2.Right && r1.Left > r2.Left)
+        return r1.Left - r2.Right;
+      return -r1.Width;
+    }
+
+    /// <summary>
+    /// Calculates the vertical distance from <paramref name="r1"/> to <paramref name="r2"/>.
+    /// </summary>
+    /// <param name="r1"></param>
+    /// <param name="r2"></param>
+    /// <returns>Vertical distance, negative if there is an overlap.</returns>
+    protected static float VerticalDistance(RectangleF r1, RectangleF r2)
+    {
+      if (r1.Bottom <= r2.Top)
+        return r2.Top - r1.Bottom;
+      if (r1.Top >= r2.Bottom)
+        return r1.Top - r2.Bottom;
+      if (r1.Top < r2.Top && r1.Bottom < r2.Bottom)
+        return r2.Top - r1.Bottom;
+      if (r1.Bottom > r2.Bottom && r1.Top > r2.Top)
+        return r1.Top - r2.Bottom;
+      return -r1.Height;
+    }
+
     protected PointF GetCenterPosition(RectangleF rect)
     {
       return new PointF((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
@@ -1100,7 +1138,7 @@ namespace MediaPortal.UI.SkinEngine.Controls.Visuals
       PointF start = new PointF((actualBounds.Right + actualBounds.Left) / 2, actualBounds.Top);
       PointF end = new PointF((otherRect.Right + otherRect.Left) / 2, otherRect.Bottom);
       float alpha = CalcDirection(start, end);
-      topOrLeftDifference = Math.Abs(actualBounds.Left - otherRect.Left);
+      topOrLeftDifference = HorizontalDistance(actualBounds, otherRect); //Math.Abs(actualBounds.Left - otherRect.Left);
       return isNear || alpha > DELTA_DOUBLE && alpha < Math.PI - DELTA_DOUBLE;
     }
 
@@ -1111,8 +1149,8 @@ namespace MediaPortal.UI.SkinEngine.Controls.Visuals
       PointF start = new PointF((actualBounds.Right + actualBounds.Left) / 2, actualBounds.Bottom);
       PointF end = new PointF((otherRect.Right + otherRect.Left) / 2, otherRect.Top);
       float alpha = CalcDirection(start, end);
-      topOrLeftDifference = Math.Abs(actualBounds.Left - otherRect.Left);
-      return isNear|| alpha > Math.PI + DELTA_DOUBLE && alpha < 2 * Math.PI - DELTA_DOUBLE;
+      topOrLeftDifference = HorizontalDistance(actualBounds, otherRect); //Math.Abs(actualBounds.Left - otherRect.Left);
+      return isNear || alpha > Math.PI + DELTA_DOUBLE && alpha < 2 * Math.PI - DELTA_DOUBLE;
     }
 
     protected bool LocatedLeftOf(RectangleF otherRect, out float topOrLeftDifference)
@@ -1122,7 +1160,7 @@ namespace MediaPortal.UI.SkinEngine.Controls.Visuals
       PointF start = new PointF(actualBounds.Right, (actualBounds.Top + actualBounds.Bottom) / 2);
       PointF end = new PointF(otherRect.Left, (otherRect.Top + otherRect.Bottom) / 2);
       float alpha = CalcDirection(start, end);
-      topOrLeftDifference = Math.Abs(actualBounds.Top - otherRect.Top);
+      topOrLeftDifference = VerticalDistance(actualBounds, otherRect); //Math.Abs(actualBounds.Top - otherRect.Top);
       return isNear || alpha < Math.PI / 2 - DELTA_DOUBLE || alpha > 3 * Math.PI / 2 + DELTA_DOUBLE;
     }
 
@@ -1133,7 +1171,7 @@ namespace MediaPortal.UI.SkinEngine.Controls.Visuals
       PointF start = new PointF(actualBounds.Left, (actualBounds.Top + actualBounds.Bottom) / 2);
       PointF end = new PointF(otherRect.Right, (otherRect.Top + otherRect.Bottom) / 2);
       float alpha = CalcDirection(start, end);
-      topOrLeftDifference = Math.Abs(actualBounds.Top - otherRect.Top);
+      topOrLeftDifference = VerticalDistance(actualBounds, otherRect); //Math.Abs(actualBounds.Top - otherRect.Top);
       return isNear || alpha > Math.PI / 2 + DELTA_DOUBLE && alpha < 3 * Math.PI / 2 - DELTA_DOUBLE;
     }
 
-- 
1.8.1.msysgit.1

