mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
AbstractScrollableExactApproximateExpressionsView children classes reload scroll after reloading the subview selection when entering the responder chain and when cell becomes first responder. We don't reload scroll when setting content of cells as this is done every time we relayout - when scrolling in the table for instance.
232 lines
11 KiB
C++
232 lines
11 KiB
C++
#include "scrollable_exact_approximate_expressions_view.h"
|
|
#include <apps/i18n.h>
|
|
#include <assert.h>
|
|
using namespace Poincare;
|
|
|
|
namespace Shared {
|
|
|
|
static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
|
|
|
|
AbstractScrollableExactApproximateExpressionsView::ContentCell::ContentCell() :
|
|
m_rightExpressionView(),
|
|
m_approximateSign(KDFont::LargeFont, I18n::Message::AlmostEqual, 0.5f, 0.5f, Palette::GreyVeryDark),
|
|
m_centeredExpressionView(),
|
|
m_selectedSubviewPosition(SubviewPosition::Center),
|
|
m_displayCenter(true)
|
|
{
|
|
}
|
|
|
|
KDColor AbstractScrollableExactApproximateExpressionsView::ContentCell::backgroundColor() const {
|
|
KDColor background = m_even ? KDColorWhite : Palette::WallScreen;
|
|
return background;
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::ContentCell::setHighlighted(bool highlight) {
|
|
// Do not call HighlightCell::setHighlighted to avoid marking all cell as dirty
|
|
m_highlighted = highlight;
|
|
KDColor defaultColor = backgroundColor();
|
|
KDColor color = highlight && m_selectedSubviewPosition == SubviewPosition::Center ? Palette::Select : defaultColor;
|
|
m_centeredExpressionView.setBackgroundColor(color);
|
|
color = highlight && m_selectedSubviewPosition == SubviewPosition::Right ? Palette::Select : defaultColor;
|
|
m_rightExpressionView.setBackgroundColor(color);
|
|
m_approximateSign.setBackgroundColor(defaultColor);
|
|
if (leftExpressionView()) {
|
|
color = highlight && m_selectedSubviewPosition == SubviewPosition::Left ? Palette::Select : defaultColor;
|
|
leftExpressionView()->setBackgroundColor(color);
|
|
}
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::ContentCell::setEven(bool even) {
|
|
EvenOddCell::setEven(even);
|
|
KDColor defaultColor = backgroundColor();
|
|
m_centeredExpressionView.setBackgroundColor(defaultColor);
|
|
m_rightExpressionView.setBackgroundColor(defaultColor);
|
|
m_approximateSign.setBackgroundColor(defaultColor);
|
|
if (leftExpressionView()) {
|
|
leftExpressionView()->setBackgroundColor(defaultColor);
|
|
}
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::ContentCell::reloadTextColor() {
|
|
if (displayCenter()) {
|
|
m_rightExpressionView.setTextColor(Palette::GreyVeryDark);
|
|
} else {
|
|
m_rightExpressionView.setTextColor(KDColorBlack);
|
|
}
|
|
}
|
|
|
|
KDSize AbstractScrollableExactApproximateExpressionsView::ContentCell::minimalSizeForOptimalDisplay() const {
|
|
KDSize leftSize = KDSizeZero;
|
|
KDCoordinate leftViewBaseline = 0;
|
|
KDCoordinate width = 0;
|
|
if (leftExpressionView() && !leftExpressionView()->layout().isUninitialized()) {
|
|
leftSize = leftExpressionView()->minimalSizeForOptimalDisplay();
|
|
leftViewBaseline = leftExpressionView()->layout().baseline();
|
|
width += leftSize.width() + Metric::CommonLargeMargin;
|
|
}
|
|
KDSize rightExpressionSize = m_rightExpressionView.minimalSizeForOptimalDisplay();
|
|
width += rightExpressionSize.width();
|
|
Layout l = m_rightExpressionView.layout();
|
|
KDCoordinate rightBaseline = l.isUninitialized() ? 0 : l.baseline();
|
|
KDSize centeredExpressionSize = KDSizeZero;
|
|
KDCoordinate centeredBaseline = 0;
|
|
if (displayCenter()) {
|
|
centeredBaseline = m_centeredExpressionView.layout().baseline();
|
|
centeredExpressionSize = m_centeredExpressionView.minimalSizeForOptimalDisplay();
|
|
width += centeredExpressionSize.width() + 2*Metric::CommonLargeMargin + m_approximateSign.minimalSizeForOptimalDisplay().width();
|
|
}
|
|
KDCoordinate height = maxCoordinate(maxCoordinate(centeredBaseline, rightBaseline), leftViewBaseline) + maxCoordinate(maxCoordinate(centeredExpressionSize.height()-centeredBaseline, rightExpressionSize.height()-rightBaseline), leftSize.height()-leftViewBaseline);
|
|
return KDSize(width, height);
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::ContentCell::setSelectedSubviewPosition(AbstractScrollableExactApproximateExpressionsView::SubviewPosition subviewPosition) {
|
|
m_selectedSubviewPosition = subviewPosition;
|
|
setHighlighted(isHighlighted());
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::ContentCell::setDisplayCenter(bool display) {
|
|
m_displayCenter = display;
|
|
reloadTextColor();
|
|
layoutSubviews();
|
|
}
|
|
|
|
Poincare::Layout AbstractScrollableExactApproximateExpressionsView::ContentCell::layout() const {
|
|
if (m_selectedSubviewPosition == SubviewPosition::Center) {
|
|
return m_centeredExpressionView.layout();
|
|
} else if (m_selectedSubviewPosition == SubviewPosition::Right) {
|
|
return m_rightExpressionView.layout();
|
|
}
|
|
assert(m_selectedSubviewPosition == SubviewPosition::Left);
|
|
assert(leftExpressionView());
|
|
return leftExpressionView()->layout();
|
|
}
|
|
|
|
int AbstractScrollableExactApproximateExpressionsView::ContentCell::numberOfSubviews() const {
|
|
int nbOfSubviews = 1;
|
|
if (displayCenter()) {
|
|
nbOfSubviews += 2;
|
|
}
|
|
if (leftExpressionView()) {
|
|
nbOfSubviews += 1;
|
|
}
|
|
return nbOfSubviews;
|
|
}
|
|
|
|
View * AbstractScrollableExactApproximateExpressionsView::ContentCell::subviewAtIndex(int index) {
|
|
bool leftIsVisible = leftExpressionView() != nullptr;
|
|
if (leftIsVisible && index == 0) {
|
|
return leftExpressionView();
|
|
}
|
|
View * views[3] = {&m_rightExpressionView, &m_approximateSign, &m_centeredExpressionView};
|
|
return views[index - leftIsVisible];
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::ContentCell::layoutSubviews(bool force) {
|
|
// Subviews sizes
|
|
KDSize leftSize = leftExpressionView() ? leftExpressionView()->minimalSizeForOptimalDisplay() : KDSizeZero;
|
|
KDCoordinate leftViewBaseline = leftExpressionView() && !leftExpressionView()->layout().isUninitialized() ? leftExpressionView()->layout().baseline() : 0;
|
|
KDSize centeredExpressionSize = KDSizeZero;
|
|
KDCoordinate centeredBaseline = 0;
|
|
if (displayCenter()) {
|
|
centeredBaseline = m_centeredExpressionView.layout().baseline();
|
|
centeredExpressionSize = m_centeredExpressionView.minimalSizeForOptimalDisplay();
|
|
}
|
|
KDSize rightExpressionSize = m_rightExpressionView.minimalSizeForOptimalDisplay();
|
|
KDCoordinate rightBaseline = m_rightExpressionView.layout().isUninitialized() ? 0 : m_rightExpressionView.layout().baseline();
|
|
// Compute baseline
|
|
KDCoordinate baseline = maxCoordinate(maxCoordinate(leftViewBaseline, rightBaseline), centeredBaseline);
|
|
// Layout left view
|
|
KDCoordinate currentWidth = 0;
|
|
if (leftExpressionView()) {
|
|
leftExpressionView()->setFrame(KDRect(currentWidth, baseline-leftViewBaseline, leftSize), force);
|
|
currentWidth += leftSize.width() + Metric::CommonLargeMargin;
|
|
}
|
|
// Layout centered expression
|
|
if (displayCenter()) {
|
|
KDSize approximateSignSize = m_approximateSign.minimalSizeForOptimalDisplay();
|
|
m_centeredExpressionView.setFrame(KDRect(currentWidth, baseline-centeredBaseline, centeredExpressionSize), force);
|
|
currentWidth += Metric::CommonLargeMargin+centeredExpressionSize.width();
|
|
m_approximateSign.setFrame(KDRect(currentWidth, baseline-approximateSignSize.height()/2, approximateSignSize), force);
|
|
currentWidth += Metric::CommonLargeMargin + approximateSignSize.width();
|
|
}
|
|
// Layout right expression
|
|
m_rightExpressionView.setFrame(KDRect(currentWidth, baseline-rightBaseline, rightExpressionSize), force);
|
|
}
|
|
|
|
AbstractScrollableExactApproximateExpressionsView::AbstractScrollableExactApproximateExpressionsView(Responder * parentResponder, View * contentCell) :
|
|
ScrollableView(parentResponder, contentCell, this)
|
|
{
|
|
setDecoratorType(ScrollView::Decorator::Type::Arrows);
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::setLayouts(Poincare::Layout leftLayout, Poincare::Layout centerLayout, Poincare::Layout rightLayout) {
|
|
bool updateRightLayout = contentCell()->rightExpressionView()->setLayout(rightLayout);
|
|
bool updateCenterLayout = contentCell()->centeredExpressionView()->setLayout(centerLayout);
|
|
bool updateLeftLayout = false;
|
|
if (contentCell()->leftExpressionView()) {
|
|
updateLeftLayout = contentCell()->leftExpressionView()->setLayout(leftLayout);
|
|
}
|
|
if (updateLeftLayout || updateCenterLayout || updateRightLayout) {
|
|
contentCell()->reloadTextColor();
|
|
contentCell()->layoutSubviews();
|
|
// Do no reload scroll here as 'setLayouts' is called every time the table is re-layout (when scrolling for instance)
|
|
}
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::setEqualMessage(I18n::Message equalSignMessage) {
|
|
contentCell()->approximateSign()->setMessage(equalSignMessage);
|
|
}
|
|
|
|
void AbstractScrollableExactApproximateExpressionsView::reloadScroll() {
|
|
if (selectedSubviewPosition() == SubviewPosition::Right) {
|
|
// Scroll to the right extremity
|
|
scrollToContentPoint(KDPoint(contentCell()->bounds().width(), 0), true);
|
|
} else {
|
|
// Scroll to the left extremity
|
|
ScrollableView::reloadScroll();
|
|
}
|
|
}
|
|
void AbstractScrollableExactApproximateExpressionsView::setDisplayCenter(bool display) {
|
|
contentCell()->setDisplayCenter(display);
|
|
layoutSubviews();
|
|
}
|
|
|
|
bool AbstractScrollableExactApproximateExpressionsView::handleEvent(Ion::Events::Event event) {
|
|
bool leftIsVisible = false;
|
|
KDCoordinate leftWidth = 0;
|
|
if (contentCell()->leftExpressionView()) {
|
|
leftWidth = contentCell()->leftExpressionView()->minimalSizeForOptimalDisplay().width();
|
|
leftIsVisible = leftWidth - contentOffset().x() > 0;
|
|
}
|
|
KDCoordinate rightExpressionWidth = contentCell()->rightExpressionView()->minimalSizeForOptimalDisplay().width();
|
|
bool rightExpressionIsVisible = minimalSizeForOptimalDisplay().width() - rightExpressionWidth - contentOffset().x() < bounds().width();
|
|
bool centeredExpressionIsVisibleOnTheLeft = false;
|
|
bool centeredExpressionIsVisibleOnTheRight = false;
|
|
if (contentCell()->displayCenter()) {
|
|
KDCoordinate centerExpressionWidth = contentCell()->centeredExpressionView()->minimalSizeForOptimalDisplay().width();
|
|
KDCoordinate signWidth = contentCell()->approximateSign()->minimalSizeForOptimalDisplay().width();
|
|
centeredExpressionIsVisibleOnTheLeft = leftWidth + Metric::CommonLargeMargin + centerExpressionWidth - contentOffset().x() > 0;
|
|
centeredExpressionIsVisibleOnTheRight = minimalSizeForOptimalDisplay().width() - rightExpressionWidth - signWidth - centerExpressionWidth - 2*Metric::CommonLargeMargin - contentOffset().x() < bounds().width();
|
|
}
|
|
// Select center
|
|
if ((event == Ion::Events::Left && selectedSubviewPosition() == SubviewPosition::Right && centeredExpressionIsVisibleOnTheLeft) ||
|
|
(event == Ion::Events::Right && selectedSubviewPosition() == SubviewPosition::Left && centeredExpressionIsVisibleOnTheRight)) {
|
|
setSelectedSubviewPosition(SubviewPosition::Center);
|
|
return true;
|
|
}
|
|
// Select left
|
|
if ((event == Ion::Events::Left && selectedSubviewPosition() == SubviewPosition::Right && leftIsVisible) ||
|
|
(event == Ion::Events::Left && selectedSubviewPosition() == SubviewPosition::Center && leftIsVisible)) {
|
|
setSelectedSubviewPosition(SubviewPosition::Left);
|
|
return true;
|
|
}
|
|
if ((event == Ion::Events::Right && selectedSubviewPosition() == SubviewPosition::Center && rightExpressionIsVisible) ||
|
|
(event == Ion::Events::Right && selectedSubviewPosition() == SubviewPosition::Left && rightExpressionIsVisible)) {
|
|
setSelectedSubviewPosition(SubviewPosition::Right);
|
|
return true;
|
|
}
|
|
return ScrollableView::handleEvent(event);
|
|
}
|
|
|
|
}
|