[escher] TableCell: the subviews are layoutted horizontally or

vertically. We add an option to decide which subviews should overlap on
top of the other if there is not enough space
This commit is contained in:
Émilie Feral
2019-12-27 18:09:17 +01:00
committed by Léa Saviot
parent 5974149162
commit 4bd3dfd542
10 changed files with 137 additions and 79 deletions

View File

@@ -3,6 +3,7 @@
#include <escher/metric.h>
static inline KDCoordinate minCoordinate(KDCoordinate x, KDCoordinate y) { return x < y ? x : y; }
static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
TableCell::TableCell(Layout layout) :
HighlightCell(),
@@ -40,74 +41,125 @@ View * TableCell::subviewAtIndex(int index) {
* margins (like ExpressionView), sometimes the subview has no margins (like
* MessageView) which prevents us to handle margins only here. */
KDCoordinate withMargin(KDCoordinate length, KDCoordinate margin) {
return length == 0 ? 0 : length + margin;
}
void TableCell::layoutSubviews(bool force) {
/* TODO: this code is awful. However, this should handle multiples cases
* (subviews are not defined, margins are overriden...) */
KDCoordinate width = bounds().width();
KDCoordinate height = bounds().height();
View * label = labelView();
KDSize labelSize = label ? label->minimalSizeForOptimalDisplay() : KDSizeZero;
if (label) {
switch (m_layout) {
case Layout::Vertical:
{
KDCoordinate x = k_separatorThickness+labelMargin();
KDCoordinate y = k_separatorThickness+Metric::TableCellVerticalMargin;
label->setFrame(KDRect(
x,
y,
width-2*x,
minCoordinate(labelSize.height(), height-2*y)),
force);
break;
}
default:
{
KDCoordinate x = k_separatorThickness+labelMargin();
KDCoordinate y = k_separatorThickness;
label->setFrame(KDRect(
x,
k_separatorThickness,
minCoordinate(labelSize.width(), width-2*x),
height - 2*y),
force);
break;
}
}
}
View * accessory = accessoryView();
if (accessory) {
KDSize accessorySize = accessory->minimalSizeForOptimalDisplay();
switch (m_layout) {
case Layout::Vertical:
{
KDCoordinate x = k_separatorThickness+k_accessoryMargin;
accessory->setFrame(KDRect(
x,
height-k_separatorThickness-accessorySize.height()-k_accessoryBottomMargin,
width-2*x,
accessorySize.height()),
force);
break;
}
default:
// In some cases, the accessory view cannot take all the size it can
KDCoordinate wantedX = width-accessorySize.width()-k_separatorThickness-k_accessoryMargin;
KDCoordinate minX = label ? label->bounds().x()+labelSize.width()+labelMargin()+k_separatorThickness+k_accessoryMargin : k_accessoryMargin;
KDCoordinate x = minX < wantedX ? wantedX : minX;
accessory->setFrame(KDRect(
x,
k_separatorThickness,
minCoordinate(accessorySize.width(), width - x),
height-2*k_separatorThickness),
force);
break;
}
}
View * subAccessory = subAccessoryView();
if (subAccessory && accessory) {
KDSize accessorySize = accessory->minimalSizeForOptimalDisplay();
KDSize subAccessorySize = subAccessory->minimalSizeForOptimalDisplay();
subAccessory->setFrame(KDRect(width-k_separatorThickness-k_accessoryMargin-accessorySize.width()-subAccessorySize.width(), k_separatorThickness,
subAccessorySize.width(), height-2*k_separatorThickness), force);
KDSize labelSize = label ? label->minimalSizeForOptimalDisplay() : KDSizeZero;
KDSize accessorySize = accessory ? accessory->minimalSizeForOptimalDisplay() : KDSizeZero;
KDSize subAccessorySize = subAccessory ? subAccessory->minimalSizeForOptimalDisplay() : KDSizeZero;
if (m_layout == Layout::Vertical) {
/*
* Vertically:
* ----------------
* ----------------
* Line separator
* ----------------
* k_verticalMargin
* ----------------
* LABEL
* ----------------
* k_verticalMargin
* ----------------
* .
* . [White space if possible, otherwise LABEL overlaps SUBACCESSORY and so on]
* .
* ----------------
* SUBACCESSORY
* ----------------
* ACCESSORY
* ----------------
* k_verticalMargin
* ----------------
* Line separator
* ----------------
* ----------------
*
*
* Horizontally:
* || Line separator | margin* | SUBVIEW | margin* | Line separator ||
*
* * = margin can either be labelMargin() or k_horizontalMargin depending on the subview
*
* */
KDCoordinate horizontalMargin = k_separatorThickness + labelMargin();
KDCoordinate y = k_separatorThickness;
if (label) {
y += k_verticalMargin;
KDCoordinate labelHeight = minCoordinate(labelSize.height(), height - y - k_separatorThickness - k_verticalMargin);
label->setFrame(KDRect(horizontalMargin, y, width-2*horizontalMargin, labelHeight), force);
y += labelHeight + k_verticalMargin;
}
horizontalMargin = k_separatorThickness + k_horizontalMargin;
y = maxCoordinate(y, height - k_separatorThickness - withMargin(accessorySize.height(), Metric::TableCellVerticalMargin) - withMargin(subAccessorySize.height(), 0));
if (subAccessory) {
KDCoordinate subAccessoryHeight = minCoordinate(subAccessorySize.height(), height - y - k_separatorThickness - Metric::TableCellVerticalMargin);
accessory->setFrame(KDRect(horizontalMargin, y, width - 2*horizontalMargin, subAccessoryHeight), force);
y += subAccessoryHeight;
}
y = maxCoordinate(y, height - k_separatorThickness - withMargin(accessorySize.height(), Metric::TableCellVerticalMargin));
if (accessory) {
KDCoordinate accessoryHeight = minCoordinate(accessorySize.height(), height - y - k_separatorThickness - Metric::TableCellVerticalMargin);
accessory->setFrame(KDRect(horizontalMargin, y, width - 2*horizontalMargin, accessoryHeight), force);
}
} else {
/*
* Vertically:
* ----------------
* ----------------
* Line separator
* ----------------
* SUBVIEW
* ----------------
* Line separator
* ----------------
* ----------------
*
* Horizontally:
* || Line separator | Label margin | LABEL | Label margin | ...
* [ White space if possible otherwise the overlap can be from left to
* right subviews or the contrary ]
*
* ... | SUBACCESSORY | ACCESSORY | k_horizontalMargin | Line separator ||
*
* */
KDCoordinate verticalMargin = k_separatorThickness;
KDCoordinate x = 0;
KDCoordinate labelX = k_separatorThickness + labelMargin();
KDCoordinate subAccessoryX = maxCoordinate(k_separatorThickness+k_horizontalMargin, width - k_separatorThickness - withMargin(accessorySize.width(), k_horizontalMargin) - withMargin(subAccessorySize.width(), 0));
KDCoordinate accessoryX = maxCoordinate(k_separatorThickness+k_horizontalMargin, width - k_separatorThickness - withMargin(accessorySize.width(), k_horizontalMargin));
if (label) {
x = labelX;
KDCoordinate labelWidth = minCoordinate(labelSize.width(), width - x - k_separatorThickness - labelMargin());
if (m_layout == Layout::HorizontalRightOverlap) {
labelWidth = minCoordinate(labelWidth, subAccessoryX - x - labelMargin());
}
label->setFrame(KDRect(x, verticalMargin, labelWidth, height-2*verticalMargin), force);
x += labelWidth + labelMargin();
}
if (subAccessory) {
x = maxCoordinate(x, subAccessoryX);
KDCoordinate subAccessoryWidth = minCoordinate(subAccessorySize.width(), width - x - k_separatorThickness - k_horizontalMargin);
if (m_layout == Layout::HorizontalRightOverlap) {
subAccessoryWidth = minCoordinate(subAccessoryWidth, accessoryX - x);
}
subAccessory->setFrame(KDRect(x, verticalMargin, subAccessoryWidth, height-2*verticalMargin), force);
x += subAccessoryWidth;
}
if (accessory) {
x = maxCoordinate(x, accessoryX);
KDCoordinate accessoryWidth = minCoordinate(accessorySize.width(), width - x - k_separatorThickness - k_horizontalMargin);
accessory->setFrame(KDRect(x, verticalMargin, accessoryWidth, height-2*verticalMargin), force);
}
}
}