Permalink
Browse files

MythUI: enhance <minsize> functionality.

Allow <minsize> areas to be siblings of each other, with each contributing
to the resulting area.

Allow <minsize> areas to be nested, with the child areas impacting the
resulting area.

Add a <initiator> element so a theme can control when <minsize> areas
instigate a resize, and which <minsize> areas just react to the resize.  By
default <textarea> elements are initiators, and all others are not.  A patch
to allow <imagetype> elements to be initators is forthcoming.
  • Loading branch information...
1 parent 9a646eb commit 8b7ac1e58653c426cc7388f1c0e181d7ad08f753 @jpoet jpoet committed May 29, 2011
View
5 mythtv/libs/libmythui/mythrect.cpp
@@ -263,6 +263,7 @@ MythPoint::MythPoint(const QString &sX, const QString &sY)
Init();
setX(sX);
setY(sY);
+ valid = true;
}
MythPoint::MythPoint(QPoint point)
@@ -275,6 +276,7 @@ void MythPoint::Init()
{
m_needsUpdate = true;
m_percentX = m_percentY = 0.0;
+ valid = false;
}
void MythPoint::CalculatePoint(MythRect parentArea)
@@ -297,6 +299,7 @@ void MythPoint::CalculatePoint(MythRect parentArea)
QPoint::setY(Y);
m_needsUpdate = false;
+ valid = true;
}
void MythPoint::NormPoint(void)
@@ -319,6 +322,7 @@ void MythPoint::setX(const QString &sX)
}
else
QPoint::setX(X.toInt());
+ valid = true;
}
void MythPoint::setY(const QString &sY)
@@ -332,6 +336,7 @@ void MythPoint::setY(const QString &sY)
}
else
QPoint::setY(Y.toInt());
+ valid = true;
}
QString MythPoint::getX(void) const
View
3 mythtv/libs/libmythui/mythrect.h
@@ -82,6 +82,7 @@ class MUI_PUBLIC MythPoint : public QPoint
MythPoint(QPoint point);
void Init(void);
+ bool isValid(void) const { return valid; }
void CalculatePoint(MythRect parentArea);
void NormPoint(void);
@@ -103,6 +104,8 @@ class MUI_PUBLIC MythPoint : public QPoint
bool m_needsUpdate;
QRect m_parentArea;
+
+ bool valid;
};
#endif
View
132 mythtv/libs/libmythui/mythuitext.cpp
@@ -31,6 +31,9 @@ MythUIText::MythUIText(MythUIType *parent, const QString &name)
curR(0.0), curG(0.0), curB(0.0),
incR(0.0), incG(0.0), incB(0.0)
{
+ m_Initiator = true;
+ m_usingAltArea = false;
+ m_ShrinkNarrow = true;
m_MultiLine = false;
m_scrolling = false;
m_scrollDirection = ScrollLeft;
@@ -55,6 +58,9 @@ MythUIText::MythUIText(const QString &text, const MythFontProperties &font,
curR(0.0), curG(0.0), curB(0.0),
incR(0.0), incG(0.0), incB(0.0)
{
+ m_Initiator = true;
+ m_usingAltArea = false;
+ m_ShrinkNarrow = true;
m_MultiLine = false;
m_scrolling = false;
m_scrollDirection = ScrollLeft;
@@ -96,7 +102,7 @@ void MythUIText::SetText(const QString &text)
m_Message = newtext;
m_CutMessage.clear();
- FillCutMessage();
+ FillCutMessage(true);
if (m_scrolling)
{
@@ -163,7 +169,7 @@ void MythUIText::SetFontProperties(const MythFontProperties &fontProps)
{
m_FontStates.insert("default", fontProps);
*m_Font = m_FontStates["default"];
- FillCutMessage();
+ FillCutMessage(false);
SetRedraw();
}
@@ -174,17 +180,24 @@ void MythUIText::SetFontState(const QString &state)
else
*m_Font = m_FontStates["default"];
- FillCutMessage();
+ FillCutMessage(false);
SetRedraw();
}
void MythUIText::UseAlternateArea(bool useAlt)
{
if (useAlt && m_AltDisplayRect.width() > 1)
+ {
MythUIType::SetArea(m_AltDisplayRect);
+ m_usingAltArea = true;
+ }
else
+ {
MythUIType::SetArea(m_OrigDisplayRect);
- FillCutMessage();
+ m_usingAltArea = false;
+ }
+
+ FillCutMessage(false);
}
void MythUIText::SetJustification(int just)
@@ -194,7 +207,7 @@ void MythUIText::SetJustification(int just)
// preserve the wordbreak attribute, drop everything else
m_Justification = m_Justification & Qt::TextWordWrap;
m_Justification |= just;
- FillCutMessage();
+ FillCutMessage(false);
SetRedraw();
}
}
@@ -207,7 +220,7 @@ int MythUIText::GetJustification(void)
void MythUIText::SetCutDown(bool cut)
{
m_Cutdown = cut;
- FillCutMessage();
+ FillCutMessage(false);
SetRedraw();
}
@@ -218,7 +231,7 @@ void MythUIText::SetMultiLine(bool multiline)
m_Justification |= Qt::TextWordWrap;
else
m_Justification &= ~Qt::TextWordWrap;
- FillCutMessage();
+ FillCutMessage(false);
SetRedraw();
}
@@ -234,7 +247,7 @@ void MythUIText::SetArea(const MythRect &rect)
QSize stringSize = fm.size(Qt::TextSingleLine, m_Message);
SetDrawRectSize(stringSize.width(), m_Area.height());
}
- FillCutMessage();
+ FillCutMessage(false);
}
void MythUIText::SetPosition(const MythPoint &pos)
@@ -363,7 +376,7 @@ bool MythUIText::MakeNarrow(QRect &min_rect)
if (min_width == INT_MAX)
{
- // won't fit, even when the ara is the maxium size
+ // won't fit, even when the area is the maxium size
min_rect = fm.boundingRect(m_Area, m_Justification, m_CutMessage);
return false;
}
@@ -380,7 +393,21 @@ bool MythUIText::MakeNarrow(QRect &min_rect)
}
}
-void MythUIText::FillCutMessage()
+/*
+ * If minsize and multiline are defined, minimize the height by using
+ * as many columns as possible.
+ */
+bool MythUIText::MakeShort(QRect &min_rect)
+{
+ QFontMetrics fm(GetFontProperties()->face());
+
+ min_rect = fm.boundingRect(m_Area, m_Justification, m_CutMessage);
+ min_rect.setWidth(m_Area.width());
+
+ return true;
+}
+
+void MythUIText::FillCutMessage(bool reset_size)
{
m_CutMessage.clear();
@@ -405,47 +432,60 @@ void MythUIText::FillCutMessage()
if (m_CutMessage.isEmpty())
m_CutMessage = m_Message;
- if (m_CutMessage.isEmpty())
+
+ if (!reset_size && m_CutMessage.isEmpty())
return;
- QStringList templist;
- QStringList::iterator it;
- switch (m_textCase)
- {
- case CaseUpper :
- m_CutMessage = m_CutMessage.toUpper();
- break;
- case CaseLower :
- m_CutMessage = m_CutMessage.toLower();
- break;
- case CaseCapitaliseFirst :
- //m_CutMessage = m_CutMessage.toLower();
- templist = m_CutMessage.split(". ");
- for (it = templist.begin(); it != templist.end(); ++it)
- (*it).replace(0,1,(*it).left(1).toUpper());
- m_CutMessage = templist.join(". ");
- break;
- case CaseCapitaliseAll :
- //m_CutMessage = m_CutMessage.toLower();
- templist = m_CutMessage.split(" ");
- for (it = templist.begin(); it != templist.end(); ++it)
- (*it).replace(0,1,(*it).left(1).toUpper());
- m_CutMessage = templist.join(" ");
- break;
- }
-
- if (m_MinSize.x() > 0)
+ if (!m_CutMessage.isEmpty())
+ {
+
+ QStringList templist;
+ QStringList::iterator it;
+ switch (m_textCase)
+ {
+ case CaseUpper :
+ m_CutMessage = m_CutMessage.toUpper();
+ break;
+ case CaseLower :
+ m_CutMessage = m_CutMessage.toLower();
+ break;
+ case CaseCapitaliseFirst :
+ //m_CutMessage = m_CutMessage.toLower();
+ templist = m_CutMessage.split(". ");
+ for (it = templist.begin(); it != templist.end(); ++it)
+ (*it).replace(0,1,(*it).left(1).toUpper());
+ m_CutMessage = templist.join(". ");
+ break;
+ case CaseCapitaliseAll :
+ //m_CutMessage = m_CutMessage.toLower();
+ templist = m_CutMessage.split(" ");
+ for (it = templist.begin(); it != templist.end(); ++it)
+ (*it).replace(0,1,(*it).left(1).toUpper());
+ m_CutMessage = templist.join(" ");
+ break;
+ }
+ }
+
+ if (m_MinSize.isValid())
{
QRect rect;
- MakeNarrow(rect);
+
+ if (!m_CutMessage.isEmpty())
+ {
+ if (m_ShrinkNarrow)
+ MakeNarrow(rect);
+ else
+ MakeShort(rect);
+ }
// Record the minimal area needed for the message.
SetMinArea(rect.size());
- if (m_MinArea.width() > 0)
+
+ if (m_MinArea.isValid())
SetDrawRectSize(m_MinArea.width(), m_MinArea.height());
}
- if (m_Cutdown)
+ if (m_Cutdown && !m_CutMessage.isEmpty())
m_CutMessage = cutDown(m_CutMessage, m_Font, m_MultiLine);
}
@@ -648,6 +688,11 @@ bool MythUIText::ParseElement(
{
m_TemplateText = parseText(element);
}
+ else if (element.tagName() == "shrink")
+ {
+ // When minsize is used, select if are should be made narrow or short
+ m_ShrinkNarrow = (parseText(element).toLower() != "short");
+ }
else if (element.tagName() == "cutdown")
{
SetCutDown(parseBool(element));
@@ -719,7 +764,7 @@ bool MythUIText::ParseElement(
m_textCase = CaseCapitaliseAll;
else
m_textCase = CaseNormal;
- FillCutMessage();
+ FillCutMessage(true);
}
else
{
@@ -748,6 +793,7 @@ void MythUIText::CopyFrom(MythUIType *base)
m_CutMessage = text->m_CutMessage;
m_TemplateText = text->m_TemplateText;
+ m_ShrinkNarrow = text->m_ShrinkNarrow;
m_Cutdown = text->m_Cutdown;
m_MultiLine = text->m_MultiLine;
@@ -788,6 +834,6 @@ void MythUIText::CreateCopy(MythUIType *parent)
void MythUIText::Finalize(void)
{
- FillCutMessage();
+ FillCutMessage(true);
}
View
5 mythtv/libs/libmythui/mythuitext.h
@@ -84,7 +84,8 @@ class MUI_PUBLIC MythUIText : public MythUIType, public StorageUser
void MoveDrawRect(const int x, const int y);
bool MakeNarrow(QRect &min_rect);
- void FillCutMessage(void);
+ bool MakeShort(QRect &min_rect);
+ void FillCutMessage(bool reset_size = false);
QString cutDown(const QString &data, MythFontProperties *font,
bool multiline = false);
@@ -98,6 +99,8 @@ class MUI_PUBLIC MythUIText : public MythUIType, public StorageUser
QString m_DefaultMessage;
QString m_TemplateText;
+ bool m_usingAltArea;
+ bool m_ShrinkNarrow;
bool m_Cutdown;
bool m_MultiLine;
View
137 mythtv/libs/libmythui/mythuitype.cpp
@@ -33,6 +33,7 @@ MythUIType::MythUIType(QObject *parent, const QString &name)
m_Visible = true;
m_Enabled = true;
+ m_Initiator = false;
m_CanHaveFocus = m_HasFocus = false;
m_Area = MythRect(0, 0, 0, 0);
m_MinArea = MythRect(0, 0, 0, 0);
@@ -106,6 +107,7 @@ static QObject *qChildHelper(const char *objName, const char *inheritsClass,
for (int i = 0; i < children.size(); ++i)
{
QObject *obj = children.at(i);
+
if (onlyWidgets)
{
if (obj->isWidgetType() && (!objName || obj->objectName() == oName))
@@ -521,19 +523,17 @@ void MythUIType::SetMinSize(const MythPoint &minsize)
MythPoint point(minsize);
if (m_Parent)
- {
point.CalculatePoint(m_Parent->GetArea());
- m_Parent->m_MinSize = point;
- }
+
m_MinSize = point;
}
QSize MythUIType::GetMinSize(void) const
{
- if (m_MinSize.x() > 0)
- return QSize(m_MinSize.x(), m_MinSize.y());
+ if (!m_MinSize.isValid())
+ return m_Area.size();
- return m_Area.size();
+ return QSize(m_MinSize.x(), m_MinSize.y());
}
void MythUIType::SetArea(const MythRect &rect)
@@ -544,6 +544,12 @@ void MythUIType::SetArea(const MythRect &rect)
m_DirtyRegion = QRegion(m_Area.toQRect());
m_Area = rect;
+
+ if (m_Area.width() > m_NormalSize.width())
+ m_NormalSize.setWidth(m_Area.width());
+ if (m_Area.height() > m_NormalSize.height())
+ m_NormalSize.setHeight(m_Area.height());
+
RecalculateArea();
if (m_Parent)
@@ -558,37 +564,108 @@ void MythUIType::SetArea(const MythRect &rect)
void MythUIType::AdjustMinArea(int delta_x, int delta_y)
{
// If a minsize is not set, don't use MinArea
- if (m_MinSize.x() < 1)
+ if (!m_MinSize.isValid())
return;
+ if (m_Area.width() < m_NormalSize.width())
+ m_Area.setWidth(m_NormalSize.width());
+ if (m_Area.height() < m_NormalSize.height())
+ m_Area.setHeight(m_NormalSize.height());
+
QSize size(m_Area.size());
size.setWidth( size.width() + delta_x);
size.setHeight(size.height() + delta_y);
m_MinArea.setSize(size);
m_MinArea.setX(m_Area.x());
m_MinArea.setY(m_Area.y());
+
+ QSize minsize = QSize(m_MinSize.x(), m_MinSize.y());
+ QSize bound(m_MinArea.width(), m_MinArea.height());
+ bound = bound.expandedTo(minsize);
+
+ m_MinArea.setWidth(bound.width());
+ m_MinArea.setHeight(bound.height());
}
/**
* Adjust the size of sibling objects within the button.
*/
-void MythUIType::SetMinAreaSiblings(const QSize &size,
- int delta_x, int delta_y)
+void MythUIType::SetMinAreaParent(MythRect actual_area, MythRect allowed_area,
+ const MythUIType *calling_child)
{
+ int delta_x, delta_y;
+ MythRect area;
+
// If a minsize is not set, don't use MinArea
- if (m_MinSize.x() > 0)
+ if (!m_MinSize.isValid())
+ return;
+
+ m_MinArea.setWidth(0);
+
+ if (m_Area.width() < m_NormalSize.width())
+ m_Area.setWidth(m_NormalSize.width());
+ if (m_Area.height() < m_NormalSize.height())
+ m_Area.setHeight(m_NormalSize.height());
+
+ actual_area.translate(m_Area.topLeft());
+ allowed_area.translate(m_Area.topLeft());
+
+ QList<MythUIType*>::iterator it;
+
+ for (it = m_ChildrenList.begin(); it != m_ChildrenList.end(); ++it)
{
- m_MinArea.setSize(size);
- m_MinArea.setX(m_Area.x());
- m_MinArea.setY(m_Area.y());
+ if (*it == calling_child || !(*it)->m_Initiator)
+ continue;
+
+ // Find union of area(s)
+ area = (*it)->GetArea();
+ area.translate(m_Area.topLeft());
+ actual_area = actual_area.united(area);
+ area = (*it)->m_Area;
+ area.translate(m_Area.topLeft());
+ allowed_area = allowed_area.united(area);
}
- QList<MythUIType*>::iterator it;
+ // Make sure it is not larger than the area allowed
+ actual_area = actual_area.intersected(m_Area);
+ allowed_area = allowed_area.intersected(m_Area);
+
+ if (!actual_area.isValid() || actual_area == m_MinArea)
+ return;
+
+ delta_x = (actual_area.x() + actual_area.width()) -
+ (allowed_area.x() + allowed_area.width());
+ delta_y = (actual_area.y() + actual_area.height()) -
+ (allowed_area.y() + allowed_area.height());
+
for (it = m_ChildrenList.begin(); it != m_ChildrenList.end(); ++it)
{
- (*it)->AdjustMinArea(delta_x, delta_y);
+ if (*it == calling_child)
+ continue;
+
+ if (!(*it)->m_Initiator)
+ {
+ (*it)->AdjustMinArea(delta_x, delta_y);
+ }
+
+ area = (*it)->GetArea();
+ area.translate(m_Area.topLeft());
+ actual_area = actual_area.united(area);
+ area = (*it)->m_Area;
+ area.translate(m_Area.topLeft());
+ allowed_area = allowed_area.united(area);
}
+
+ QSize minsize = QSize(m_MinSize.x(), m_MinSize.y());
+ QSize bound(actual_area.width(), actual_area.height());
+ bound = bound.expandedTo(minsize);
+
+ m_MinArea.setWidth(bound.width());
+ m_MinArea.setHeight(bound.height());
+
+ if (m_Parent)
+ m_Parent->SetMinAreaParent(actual_area, allowed_area, this);
}
/**
@@ -597,14 +674,21 @@ void MythUIType::SetMinAreaSiblings(const QSize &size,
void MythUIType::SetMinArea(const QSize &size)
{
// If a minsize is not set, don't use MinArea
- if (m_MinSize.x() < 1)
+ if (!m_MinSize.isValid())
return;
+ m_MinArea.setWidth(0);
+ if (m_Area.width() < m_NormalSize.width())
+ m_Area.setWidth(m_NormalSize.width());
+ if (m_Area.height() < m_NormalSize.height())
+ m_Area.setHeight(m_NormalSize.height());
+
/**
* The MinArea will have the same origin as the normal Area,
* but can have a smaller size.
*/
QSize minsize = QSize(m_MinSize.x(), m_MinSize.y());
+
QSize bounded(size);
bounded = bounded.expandedTo(minsize);
@@ -613,14 +697,13 @@ void MythUIType::SetMinArea(const QSize &size)
if (bounded == m_MinArea.size())
return;
- m_MinArea.setSize(bounded);
m_MinArea.setX(m_Area.x());
m_MinArea.setY(m_Area.y());
+ m_MinArea.setWidth(bounded.width());
+ m_MinArea.setHeight(bounded.height());
if (m_Parent)
- m_Parent->SetMinAreaSiblings(bounded,
- bounded.width() - m_Area.width(),
- bounded.height() - m_Area.height());
+ m_Parent->SetMinAreaParent(m_MinArea, m_Area, this);
}
void MythUIType::ExpandArea(const MythRect &rect)
@@ -641,7 +724,7 @@ void MythUIType::ExpandArea(const MythRect &rect)
*/
MythRect MythUIType::GetArea(void) const
{
- if (m_MinArea.width() > 0)
+ if (m_MinArea.isValid())
return m_MinArea;
return m_Area;
}
@@ -838,6 +921,7 @@ void MythUIType::CopyFrom(MythUIType *base)
SetArea(base->m_Area);
m_MinArea = base->m_MinArea;
m_MinSize = base->m_MinSize;
+ m_NormalSize = base->m_NormalSize;
m_Alpha = base->m_Alpha;
m_AlphaChangeMode = base->m_AlphaChangeMode;
m_AlphaChange = base->m_AlphaChange;
@@ -882,12 +966,18 @@ bool MythUIType::ParseElement(
if (element.tagName() == "position")
SetPosition(parsePoint(element));
else if (element.tagName() == "area")
+ {
SetArea(parseRect(element));
+ }
else if (element.tagName() == "minsize")
{
// Use parsePoint so percentages can be used
SetMinSize(parsePoint(element));
}
+ else if (element.tagName() == "initiator")
+ {
+ m_Initiator = parseBool(element);
+ }
else if (element.tagName() == "alpha")
{
m_Alpha = getFirstText(element).toInt();
@@ -955,6 +1045,11 @@ void MythUIType::RecalculateArea(bool recurse)
else
m_Area.CalculateArea(GetMythMainWindow()->GetUIScreenRect());
+ if (m_Area.width() > m_NormalSize.width())
+ m_NormalSize.setWidth(m_Area.width());
+ if (m_Area.height() > m_NormalSize.height())
+ m_NormalSize.setHeight(m_Area.height());
+
if (recurse)
{
QList<MythUIType *>::iterator it;
View
6 mythtv/libs/libmythui/mythuitype.h
@@ -112,8 +112,8 @@ class MUI_PUBLIC MythUIType : public QObject, public XMLParseBase
virtual QSize GetMinSize(void) const;
virtual void SetArea(const MythRect &rect);
virtual void AdjustMinArea(int delta_x, int delta_y);
- virtual void SetMinAreaSiblings(const QSize &size,
- int delta_x, int delta_y);
+ virtual void SetMinAreaParent(MythRect actual_area, MythRect full_area,
+ const MythUIType *child);
virtual void SetMinArea(const QSize &size);
virtual MythRect GetArea(void) const;
virtual void RecalculateArea(bool recurse = true);
@@ -199,12 +199,14 @@ class MUI_PUBLIC MythUIType : public QObject, public XMLParseBase
bool m_HasFocus;
bool m_CanHaveFocus;
bool m_Enabled;
+ bool m_Initiator;
int m_focusOrder;
MythRect m_Area;
MythRect m_MinArea;
MythPoint m_MinSize;
+ QSize m_NormalSize;
QRegion m_DirtyRegion;
bool m_NeedsRedraw;

0 comments on commit 8b7ac1e

Please sign in to comment.