mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[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:
@@ -12,7 +12,7 @@ ListParameterController::ListParameterController(::InputEventHandlerDelegate * i
|
||||
Shared::ListParameterController(listController, I18n::Message::SequenceColor, I18n::Message::DeleteSequence, this),
|
||||
m_typeCell(I18n::Message::SequenceType),
|
||||
m_initialRankCell(&m_selectableTableView, inputEventHandlerDelegate, this, I18n::Message::FirstTermIndex),
|
||||
m_typeParameterController(this, listController, TableCell::Layout::Horizontal, Metric::CommonTopMargin, Metric::CommonRightMargin,
|
||||
m_typeParameterController(this, listController, TableCell::Layout::HorizontalLeftOverlap, Metric::CommonTopMargin, Metric::CommonRightMargin,
|
||||
Metric::CommonBottomMargin, Metric::CommonLeftMargin)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
class ExpressionTableCell : public Responder, public TableCell {
|
||||
public:
|
||||
ExpressionTableCell(Responder * responder = nullptr, Layout layout = Layout::Horizontal);
|
||||
ExpressionTableCell(Responder * responder = nullptr, Layout layout = Layout::HorizontalRightOverlap);
|
||||
View * labelView() const override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setLayout(Poincare::Layout layout);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
class ExpressionTableCellWithPointer : public ExpressionTableCell {
|
||||
public:
|
||||
ExpressionTableCellWithPointer(Responder * responder = nullptr, I18n::Message accessoryMessage = (I18n::Message)0, Layout layout = Layout::Horizontal);
|
||||
ExpressionTableCellWithPointer(Responder * responder = nullptr, I18n::Message accessoryMessage = (I18n::Message)0, Layout layout = Layout::HorizontalRightOverlap);
|
||||
View * accessoryView() const override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setAccessoryMessage(I18n::Message messageBody);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
class MessageTableCell : public TableCell {
|
||||
public:
|
||||
MessageTableCell(I18n::Message label = (I18n::Message)0, const KDFont * font = KDFont::SmallFont, Layout layout = Layout::Horizontal);
|
||||
MessageTableCell(I18n::Message label = (I18n::Message)0, const KDFont * font = KDFont::SmallFont, Layout layout = Layout::HorizontalLeftOverlap);
|
||||
View * labelView() const override;
|
||||
virtual void setHighlighted(bool highlight) override;
|
||||
void setMessage(I18n::Message message);
|
||||
|
||||
@@ -6,25 +6,31 @@
|
||||
|
||||
class TableCell : public HighlightCell {
|
||||
public:
|
||||
/* Layout enum class determines the way subviews are layouted.
|
||||
* We can split the cell vertically or horizontally.
|
||||
* We can choose which subviews frames are optimized (if there is not enough
|
||||
* space for all subviews, which one is cropped). This case happens so far only
|
||||
* for horizontally splitted cell, so we distinguish only these sub cases.
|
||||
* TODO: implement VerticalTopOverlap, VerticalBottomlap? */
|
||||
enum class Layout {
|
||||
Vertical,
|
||||
Horizontal
|
||||
HorizontalLeftOverlap, // Label overlaps on SubAccessory which overlaps on Accessory
|
||||
HorizontalRightOverlap, // Reverse
|
||||
};
|
||||
TableCell(Layout layout = Layout::Horizontal);
|
||||
TableCell(Layout layout = Layout::HorizontalLeftOverlap);
|
||||
virtual View * labelView() const;
|
||||
virtual View * accessoryView() const;
|
||||
virtual View * subAccessoryView() const;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
constexpr static KDCoordinate k_labelMargin = 10;
|
||||
constexpr static KDCoordinate k_accessoryMargin = 10;
|
||||
protected:
|
||||
virtual KDCoordinate labelMargin() const { return k_labelMargin; }
|
||||
virtual KDCoordinate labelMargin() const { return Metric::TableCellHorizontalMargin; }
|
||||
int numberOfSubviews() const override;
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews(bool force = false) override;
|
||||
constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness;
|
||||
constexpr static KDCoordinate k_verticalMargin = Metric::TableCellVerticalMargin;
|
||||
constexpr static KDCoordinate k_horizontalMargin = Metric::TableCellHorizontalMargin;
|
||||
private:
|
||||
constexpr static KDCoordinate k_accessoryBottomMargin = 3;
|
||||
Layout m_layout;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
ExpressionTableCell::ExpressionTableCell(Responder * parentResponder, Layout layout) :
|
||||
Responder(parentResponder),
|
||||
TableCell(layout),
|
||||
m_labelExpressionView(this, k_labelMargin, 0, 0.0f, 0.5f, KDColorBlack, KDColorWhite)
|
||||
m_labelExpressionView(this, k_horizontalMargin, 0, 0.0f, 0.5f, KDColorBlack, KDColorWhite)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
ExpressionTableCellWithExpression::ExpressionTableCellWithExpression(Responder * parentResponder) :
|
||||
ExpressionTableCell(parentResponder, Layout::Horizontal),
|
||||
ExpressionTableCell(parentResponder, Layout::HorizontalLeftOverlap),
|
||||
m_accessoryExpressionView(1.0f, 0.5f, Palette::GreyDark, KDColorWhite)
|
||||
{}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ ExpressionTableCellWithPointer::ExpressionTableCellWithPointer(Responder * paren
|
||||
ExpressionTableCell(parentResponder, layout),
|
||||
m_accessoryView(KDFont::SmallFont, accessoryMessage, 0.0f, 0.5f, Palette::GreyDark, KDColorWhite)
|
||||
{
|
||||
if (layout == Layout::Horizontal) {
|
||||
if (layout != Layout::Vertical) {
|
||||
m_accessoryView.setAlignment(1.0f, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +52,11 @@ void MessageTableCellWithEditableText::layoutSubviews(bool force) {
|
||||
KDSize labelSize = labelView()->minimalSizeForOptimalDisplay();
|
||||
/* Handle textfield that has no defined width (as their width evolves with
|
||||
* the length of edited text */
|
||||
textFieldSize = KDSize(bounds().width() - 2*k_separatorThickness - labelSize.width()-2*labelMargin()-k_accessoryMargin, textFieldSize.height());
|
||||
textFieldSize = KDSize(bounds().width() - 2*k_separatorThickness - labelSize.width()-2*labelMargin()-k_horizontalMargin, textFieldSize.height());
|
||||
m_textField.setFrame(KDRect(
|
||||
bounds().width() - textFieldSize.width() - k_separatorThickness-k_accessoryMargin,
|
||||
(bounds().height()-textFieldSize.height()-k_accessoryMargin)/2,
|
||||
bounds().width() - textFieldSize.width() - k_separatorThickness-k_horizontalMargin,
|
||||
(bounds().height()-textFieldSize.height()-k_horizontalMargin)/2,
|
||||
textFieldSize.width(),
|
||||
textFieldSize.height()+k_accessoryMargin),
|
||||
textFieldSize.height()+k_horizontalMargin),
|
||||
force);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user