Index: xbmc/guilib/GUIControlFactory.cpp
===================================================================
--- xbmc/guilib/GUIControlFactory.cpp	(revision 33046)
+++ xbmc/guilib/GUIControlFactory.cpp	(working copy)
@@ -188,20 +188,122 @@
   return g_SkinInfo.ResolveConstant(pNode->FirstChild()->Value(), value);
 }
 
-bool CGUIControlFactory::GetDimension(const TiXmlNode *pRootNode, const char* strTag, float &value, float &min)
+float CGUIControlFactory::ParsePosition(const char* pos, const float parentSize)
+{
+  char* end = NULL;
+  float value = pos ? (float)strtod(pos, &end) : 0;
+  if (end)
+  {
+    if (*end == 'r')
+      value = parentSize - value;
+    else if (*end == '%')
+      value = value * parentSize / 100.0f;
+  }
+  return value;
+}
+
+bool CGUIControlFactory::GetPosition(const TiXmlNode *node, const char* strTag, const float parentSize, float& value)
+{
+  const TiXmlElement* pNode = node->FirstChildElement(strTag);
+  if (!pNode || !pNode->FirstChild()) return false;
+
+  value = ParsePosition(pNode->FirstChild()->Value(), parentSize);
+  return true;
+}
+
+bool CGUIControlFactory::GetDimension(const TiXmlNode *pRootNode, const char* strTag, const float parentSize, float &value, float &min)
 {
   const TiXmlElement* pNode = pRootNode->FirstChildElement(strTag);
   if (!pNode || !pNode->FirstChild()) return false;
   if (0 == strnicmp("auto", pNode->FirstChild()->Value(), 4))
   { // auto-width - at least min must be set
-    g_SkinInfo.ResolveConstant(pNode->Attribute("max"), value);
-    g_SkinInfo.ResolveConstant(pNode->Attribute("min"), min);
+    value = ParsePosition(pNode->Attribute("max"), parentSize);
+    min = ParsePosition(pNode->Attribute("min"), parentSize);
     if (!min) min = 1;
     return true;
   }
   return g_SkinInfo.ResolveConstant(pNode->FirstChild()->Value(), value);
 }
 
+bool CGUIControlFactory::GetDimensions(const TiXmlNode *node, const char *leftTag, const char *rightTag, const char *centerLeftTag,
+                                       const char *centerRightTag, const char *widthTag, const float parentSize, float &left,
+                                       float &width, float &min_width)
+{
+  float center = 0, right = 0;
+
+  // read from the XML
+  bool hasLeft = GetPosition(node, leftTag, parentSize, left);
+  bool hasCenter = GetPosition(node, centerLeftTag, parentSize, center);
+  if (!hasCenter && GetPosition(node, centerRightTag, parentSize, center))
+  {
+    center = parentSize - center;
+    hasCenter = true;
+  }
+  bool hasRight = false;
+  if (GetPosition(node, rightTag, parentSize, right))
+  {
+    right = parentSize - right;
+    hasRight = true;
+  }
+  bool hasWidth = GetDimension(node, widthTag, parentSize, width, min_width);
+
+  if (!hasLeft)
+  { // figure out position
+    if (hasCenter) // no left specified
+    {
+      if (hasWidth)
+      {
+        left = center - width/2;
+        hasLeft = true;
+      }
+      else
+      {
+        if (hasRight)
+        {
+          width = (right - center) * 2;
+          left = right - width;
+          hasLeft = true;
+        }
+      }
+    }
+    else if (hasRight) // no left or centre
+    {
+      if (hasWidth)
+      {
+        left = right - width;
+        hasLeft = true;
+      }
+    }
+  }
+  if (!hasWidth)
+  {
+    if (hasRight)
+    {
+      width = max(0.0f, right - left); // if left=0, this fills to size of parent
+      hasLeft = true;
+    }
+    else if (hasCenter)
+    {
+      if (hasLeft)
+      {
+        width = max(0.0f, (center - left) * 2);
+        hasWidth = true;
+      }
+      else if (center > 0 && center < parentSize)
+      { // centre given, so fill to edge of parent
+        width = max(0.0f, min(parentSize - center, center) * 2);
+        left = center - width/2;
+        hasLeft = hasWidth = true;
+      }
+    }
+    else if (hasLeft) // neither right nor center specified
+    {
+      width = max(0.0f, parentSize - left); // if left=0, this fills to parent
+    }
+  }
+  return hasLeft && hasWidth;
+}
+
 bool CGUIControlFactory::GetPath(const TiXmlNode* pRootNode, const char* strTag, CStdString& strStringPath)
 {
   const TiXmlNode* pNode = pRootNode->FirstChild(strTag );
@@ -605,7 +707,7 @@
   int id = 0;
   float posX = 0, posY = 0;
   float width = 0, height = 0;
-  float minWidth = 0;
+  float minHeight = 0, minWidth = 0;
 
   CGUIAction leftActions, rightActions, upActions, downActions, backActions, nextActions, prevActions;
 
@@ -728,33 +830,29 @@
   // TODO: Perhaps we should check here whether id is valid for focusable controls
   // such as buttons etc.  For labels/fadelabels/images it does not matter
 
-  GetFloat(pControlNode, "posx", posX);
-  GetFloat(pControlNode, "posy", posY);
-  // Convert these from relative coords
-  CStdString pos;
-  XMLUtils::GetString(pControlNode, "posx", pos);
-  if (pos.Right(1) == "r")
-    posX = (rect.right - rect.left) - posX;
-  XMLUtils::GetString(pControlNode, "posy", pos);
-  if (pos.Right(1) == "r")
-    posY = (rect.bottom - rect.top) - posY;
-
-  GetDimension(pControlNode, "width", width, minWidth);
-  GetFloat(pControlNode, "height", height);
-  GetFloat(pControlNode, "offsetx", offset.x);
+  GetAlignment(pControlNode, "align", labelInfo.align);
+  if (!GetDimensions(pControlNode, "left", "right", "centerleft", "centerright", "width", (rect.right - rect.left), posX, width, minWidth))
+  { // didn't get 2 dimensions, so test for old <posx> as well
+    if (GetPosition(pControlNode, "posx", (rect.right - rect.left), posX))
+    { // <posx> available, so use it along with any hacks we used to support
+      if (!insideContainer &&
+          type == CGUIControl::GUICONTROL_LABEL &&
+          (labelInfo.align & XBFONT_RIGHT))
+        posX -= width;
+    }
+    if (!width)
+      width = max((rect.right - rect.left) - posX, 0.0f);
+  }
+  if (!GetDimensions(pControlNode, "top", "bottom", "centertop", "centerbottom", "height", (rect.bottom - rect.top), posY, height, minHeight))
+  {
+    GetPosition(pControlNode, "posy", (rect.bottom - rect.top), posY);
+    if (!height)
+      height = max((rect.bottom - rect.top) - posY, 0.0f);
+  }
+
+  GetFloat(pControlNode, "offsetx", offset.x);
   GetFloat(pControlNode, "offsety", offset.y);
 
-  // adjust width and height accordingly for groups.  Groups should
-  // take the width/height of the parent (adjusted for positioning)
-  // if none is defined.
-  if (type == CGUIControl::GUICONTROL_GROUP || type == CGUIControl::GUICONTROL_GROUPLIST)
-  {
-    if (!width)
-      width = max(rect.right - posX, 0.0f);
-    if (!height)
-      height = max(rect.bottom - posY, 0.0f);
-  }
-
   hitRect.SetRect(posX, posY, posX + width, posY + height);
   GetHitRect(pControlNode, hitRect);
 
@@ -795,7 +893,6 @@
   CStdString strFont;
   if (XMLUtils::GetString(pControlNode, "font", strFont))
     labelInfo.font = g_fontManager.GetFont(strFont);
-  GetAlignment(pControlNode, "align", labelInfo.align);
   uint32_t alignY = 0;
   if (GetAlignmentY(pControlNode, "aligny", alignY))
     labelInfo.align |= alignY;
Index: xbmc/guilib/GUIControlFactory.h
===================================================================
--- xbmc/guilib/GUIControlFactory.h	(revision 33046)
+++ xbmc/guilib/GUIControlFactory.h	(working copy)
@@ -61,19 +61,6 @@
    */
   static CStdString TranslateControlType(CGUIControl::GUICONTROLTYPES type);
 
-  /*! \brief grab a dimension out of the XML
-   
-   Supports plain reading of a number (or constant) and, in addition allows "auto" as the value
-   for the dimension, whereby value is set to the max attribute (if it exists) and min is set the min
-   attribute (if it exists) or 1.  Auto values are thus detected by min != 0.
-
-   \param pRootNode XML node to read
-   \param strTag tag within pRootNode to read
-   \param value value to set, or maximum value if using auto
-   \param min minimum value - set != 0 if auto is used.
-   \return true if we found and read the tag.
-   */
-  static bool GetDimension(const TiXmlNode* pRootNode, const char* strTag, float &value, float &min);
   static bool GetUnsigned(const TiXmlNode* pRootNode, const char* strTag, unsigned int& value);
   static bool GetAspectRatio(const TiXmlNode* pRootNode, const char* strTag, CAspectRatio &aspectRatio);
   static bool GetInfoTexture(const TiXmlNode* pRootNode, const char* strTag, CTextureInfo &image, CGUIInfoLabel &info, int parentID);
@@ -110,5 +97,61 @@
   bool GetString(const TiXmlNode* pRootNode, const char* strTag, CStdString& strString);
   bool GetFloatRange(const TiXmlNode* pRootNode, const char* strTag, float& iMinValue, float& iMaxValue, float& iIntervalValue);
   bool GetIntRange(const TiXmlNode* pRootNode, const char* strTag, int& iMinValue, int& iMaxValue, int& iIntervalValue);
+
+  /*! \brief Parse a position string
+   Handles strings of the form
+     ###   number of pixels
+     ###r  number of pixels measured from the right
+     ###%  percentage of parent size
+   \param pos the string to parse.
+   \param parentSize the size of the parent.
+   \sa GetPosition
+   */
+  static float ParsePosition(const char* pos, const float parentSize);
+
+  /*! \brief Get the value of a position tag from XML
+   Handles both absolute and relative values.
+   \param node the <control> XML node.
+   \param tag the XML node to parse.
+   \param parentSize the size of the parent, for relative positioning.
+   \param value [out] the returned value.
+   \sa ParsePosition, GetDimension, GetDimensions.
+   */
+  static bool GetPosition(const TiXmlNode *node, const char* tag, const float parentSize, float& value);
+
+  /*! \brief grab a dimension out of the XML
+   Supports plain reading of a number (or constant) and, in addition allows "auto" as the value
+   for the dimension, whereby value is set to the max attribute (if it exists) and min is set the min
+   attribute (if it exists) or 1.  Auto values are thus detected by min != 0.
+   \param node the <control> XML node to read
+   \param strTag tag within node to read
+   \param parentSize the size of the parent for relative sizing.
+   \param value value to set, or maximum value if using auto
+   \param min minimum value - set != 0 if auto is used.
+   \return true if we found and read the tag.
+   \sa GetPosition, GetDimensions, ParsePosition.
+   */
+  static bool GetDimension(const TiXmlNode *node, const char* strTag, const float parentSize, float &value, float &min);
+
+  /*! \brief Retrieve the dimensions for a control.
+
+   Handles positioning based on at least 2 of left/right/center/width.
+
+   \param node the <control> node describing the control.
+   \param leftTag the tag that holds the left field.
+   \param rightTag the tag that holds the right field.
+   \param centerLeftTag the tag that holds the center left field.
+   \param centerRightTag the tag that holds the center right field.
+   \param widthTag the tag holding the width.
+   \param parentSize the size of the parent, for relative sizing.
+   \param pos [out] the discovered position.
+   \param width [out] the discovered width.
+   \param min_width [out] the discovered minimum width.
+   \return true if we can successfully derive the position and size, false otherwise.
+   \sa GetDimension, GetPosition, ParsePosition.
+   */
+  static bool GetDimensions(const TiXmlNode *node, const char *leftTag, const char *rightTag, const char *centerLeftTag,
+                            const char *centerRightTag, const char *widthTag, const float parentSize, float &left,
+                            float &width, float &min_width);
 };
 #endif
Index: xbmc/guilib/GUILabelControl.cpp
===================================================================
--- xbmc/guilib/GUILabelControl.cpp	(revision 33046)
+++ xbmc/guilib/GUILabelControl.cpp	(working copy)
@@ -35,8 +35,6 @@
   ControlType = GUICONTROL_LABEL;
   m_startHighlight = m_endHighlight = 0;
   m_minWidth = 0;
-  if ((labelInfo.align & XBFONT_RIGHT) && m_width)
-    m_posX -= m_width;
 }
 
 CGUILabelControl::~CGUILabelControl(void)
