Files
Upsilon/escher/src/table_cell.cpp
Romain Goyet 84768472bd Explicit std::min/max template usage
This is unfortunately required in several cases:
 - Sometimes when we use either float and double (this should be changed)
 - Because KDCoordinate is not an int, so any arithmemtic promotes it to
an int
 - Because we mix pointer differences and ints
2020-04-14 09:31:02 -04:00

171 lines
6.6 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <escher/table_cell.h>
#include <escher/palette.h>
#include <escher/metric.h>
#include <algorithm>
TableCell::TableCell(Layout layout) :
Bordered(),
HighlightCell(),
m_layout(layout)
{
}
View * TableCell::labelView() const {
return nullptr;
}
View * TableCell::accessoryView() const {
return nullptr;
}
View * TableCell::subAccessoryView() const {
return nullptr;
}
int TableCell::numberOfSubviews() const {
return (labelView() != nullptr) + (accessoryView()!= nullptr) + (subAccessoryView()!= nullptr);
}
View * TableCell::subviewAtIndex(int index) {
if (index == 0) {
return labelView();
}
if (index == 1) {
return accessoryView();
}
return subAccessoryView();
}
/*TODO: uniformize where margins are added. Sometimes the subview has included
* 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();
View * accessory = accessoryView();
View * subAccessory = subAccessoryView();
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(), accessoryMargin() or k_horizontalMargin depending on the subview
*
* */
KDCoordinate horizontalMargin = k_separatorThickness + labelMargin();
KDCoordinate y = k_separatorThickness;
if (label) {
y += k_verticalMargin;
KDCoordinate labelHeight = std::min<KDCoordinate>(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 = std::max<KDCoordinate>(y, height - k_separatorThickness - withMargin(accessorySize.height(), Metric::TableCellVerticalMargin) - withMargin(subAccessorySize.height(), 0));
if (subAccessory) {
KDCoordinate subAccessoryHeight = std::min<KDCoordinate>(subAccessorySize.height(), height - y - k_separatorThickness - Metric::TableCellVerticalMargin);
accessory->setFrame(KDRect(horizontalMargin, y, width - 2*horizontalMargin, subAccessoryHeight), force);
y += subAccessoryHeight;
}
horizontalMargin = k_separatorThickness + accessoryMargin();
y = std::max<KDCoordinate>(y, height - k_separatorThickness - withMargin(accessorySize.height(), Metric::TableCellVerticalMargin));
if (accessory) {
KDCoordinate accessoryHeight = std::min<KDCoordinate>(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 | Accessory margin | Line separator ||
*
* */
KDCoordinate verticalMargin = k_separatorThickness;
KDCoordinate x = 0;
KDCoordinate labelX = k_separatorThickness + labelMargin();
KDCoordinate subAccessoryX = std::max(k_separatorThickness + k_horizontalMargin, width - k_separatorThickness - withMargin(accessorySize.width(), accessoryMargin()) - withMargin(subAccessorySize.width(), 0));
KDCoordinate accessoryX = std::max(k_separatorThickness + accessoryMargin(), width - k_separatorThickness - withMargin(accessorySize.width(), accessoryMargin()));
if (label) {
x = labelX;
KDCoordinate labelWidth = std::min<KDCoordinate>(labelSize.width(), width - x - k_separatorThickness - labelMargin());
if (m_layout == Layout::HorizontalRightOverlap) {
labelWidth = std::min<KDCoordinate>(labelWidth, subAccessoryX - x - labelMargin());
}
label->setFrame(KDRect(x, verticalMargin, labelWidth, height-2*verticalMargin), force);
x += labelWidth + labelMargin();
}
if (subAccessory) {
x = std::max(x, subAccessoryX);
KDCoordinate subAccessoryWidth = std::min<KDCoordinate>(subAccessorySize.width(), width - x - k_separatorThickness - k_horizontalMargin);
if (m_layout == Layout::HorizontalRightOverlap) {
subAccessoryWidth = std::min<KDCoordinate>(subAccessoryWidth, accessoryX - x);
}
subAccessory->setFrame(KDRect(x, verticalMargin, subAccessoryWidth, height-2*verticalMargin), force);
x += subAccessoryWidth;
}
if (accessory) {
x = std::max(x, accessoryX);
KDCoordinate accessoryWidth = std::min<KDCoordinate>(accessorySize.width(), width - x - k_separatorThickness - accessoryMargin());
accessory->setFrame(KDRect(x, verticalMargin, accessoryWidth, height-2*verticalMargin), force);
}
}
}
void TableCell::drawRect(KDContext * ctx, KDRect rect) const {
KDColor backgroundColor = isHighlighted() ? Palette::Select : KDColorWhite;
drawInnerRect(ctx, bounds(), backgroundColor);
drawBorderOfRect(ctx, bounds(), Palette::GreyBright);
}