diff --git a/apps/graph/list/storage_list_controller.cpp b/apps/graph/list/storage_list_controller.cpp index 4824efdb5..adaab3ddb 100644 --- a/apps/graph/list/storage_list_controller.cpp +++ b/apps/graph/list/storage_list_controller.cpp @@ -155,9 +155,11 @@ HighlightCell * StorageListController::expressionCells(int index) { void StorageListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) { TextFieldFunctionTitleCell * titleCell = static_cast(cell); + // Update the corresponding expression cell in order to geet the baseline StorageExpressionModelListController::willDisplayExpressionCellAtIndex(m_selectableTableView.cellAtLocation(1, j), j); titleCell->setBaseline(baseline(j)); if (!titleCell->isEditing()) { + // Set name and color if the name is not being edited ExpiringPointer function = modelStore()->modelForRecord(modelStore()->recordAtIndex(j)); setFunctionNameInTextField(function, titleCell->textField()); KDColor functionNameColor = function->isActive() ? function->color() : Palette::GreyDark; @@ -187,7 +189,6 @@ KDCoordinate StorageListController::privateBaseline(int j) const { return -1; } return 0.5*(const_cast(this)->rowHeight(j)-layout.layoutSize().height())+layout.baseline(); - } } diff --git a/apps/graph/list/text_field_function_title_cell.cpp b/apps/graph/list/text_field_function_title_cell.cpp index d4694df7d..405053675 100644 --- a/apps/graph/list/text_field_function_title_cell.cpp +++ b/apps/graph/list/text_field_function_title_cell.cpp @@ -71,14 +71,10 @@ void TextFieldFunctionTitleCell::didBecomeFirstResponder() { } } -float TextFieldFunctionTitleCell::verticalAlignment() const { +float TextFieldFunctionTitleCell::verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const { + assert(m_orientation == Orientation::VerticalIndicator); KDCoordinate glyphHeight = font()->glyphSize().height(); - return max( - 0.0f, - min( - 1.0f, - m_baseline < 0 ? 0.5f : ((float)(m_baseline - glyphHeight/2))/((float)subviewFrame().height()+1-glyphHeight))); - + return ((float)(expressionBaseline - glyphHeight/2))/((float)rowHeight+1-glyphHeight); } } diff --git a/apps/graph/list/text_field_function_title_cell.h b/apps/graph/list/text_field_function_title_cell.h index 7ee79d2da..3a8771ba2 100644 --- a/apps/graph/list/text_field_function_title_cell.h +++ b/apps/graph/list/text_field_function_title_cell.h @@ -42,7 +42,7 @@ public: private: constexpr static KDCoordinate k_textFieldRightMargin = 4; constexpr static int k_textFieldBufferSize = Shared::StorageFunction::k_maxNameWithArgumentSize; - float verticalAlignment() const; + float verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const override; Shared::TextFieldWithExtension m_textField; char m_textFieldBuffer[k_textFieldBufferSize]; }; diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index 81f7888c7..0348a4c00 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -192,10 +192,15 @@ HighlightCell * ListController::expressionCells(int index) { } void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) { + assert(j>=0 && j < k_maxNumberOfRows); SequenceTitleCell * myCell = (SequenceTitleCell *)cell; + // Update the corresponding expression cell to get its baseline + willDisplayExpressionCellAtIndex(m_selectableTableView.cellAtLocation(1, j), j); + myCell->setBaseline(baseline(j)); + // Set the layout Sequence * sequence = m_sequenceStore->modelAtIndex(modelIndexForRow(j)); if (sequenceDefinitionForRow(j) == 0) { - myCell->setLayout(sequence->definitionNameWithEqual()); + myCell->setLayout(sequence->definitionName()); } if (sequenceDefinitionForRow(j) == 1) { myCell->setLayout(sequence->firstInitialConditionName()); @@ -203,6 +208,7 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) { if (sequenceDefinitionForRow(j) == 2) { myCell->setLayout(sequence->secondInitialConditionName()); } + // Set the color KDColor nameColor = sequence->isActive() ? sequence->color() : Palette::GreyDark; myCell->setColor(nameColor); } @@ -299,4 +305,15 @@ void ListController::reinitExpression(Shared::ExpressionModel * model) { selectableTableView()->reloadData(); } +KDCoordinate ListController::baseline(int j) const { + //TODO copied from Graph::StorageListController, will be refactored when Sequence is a StorageApp + assert(j>=0 && j((const_cast(&m_selectableTableView))->cellAtLocation(1, j)); + Poincare::Layout layout = cell->layout(); + if (layout.isUninitialized()) { + return 0.5*const_cast(this)->rowHeight(j); + } + return 0.5*(const_cast(this)->rowHeight(j)-layout.layoutSize().height())+layout.baseline(); +} + } diff --git a/apps/sequence/list/list_controller.h b/apps/sequence/list/list_controller.h index 316dbc14a..969fa3d7e 100644 --- a/apps/sequence/list/list_controller.h +++ b/apps/sequence/list/list_controller.h @@ -44,6 +44,7 @@ private: void reinitExpression(Shared::ExpressionModel * model) override; void editExpression(Shared::ExpressionModel * model, Ion::Events::Event event) override; bool removeModelRow(Shared::ExpressionModel * model) override; + KDCoordinate baseline(int j) const; constexpr static int k_maxNumberOfRows = 3*MaxNumberOfSequences; SequenceStore * m_sequenceStore; SequenceTitleCell m_sequenceTitleCells[k_maxNumberOfRows]; diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index 6f47aac39..e0fb7f8ab 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -24,7 +24,7 @@ Sequence::Sequence(const char * text, KDColor color) : m_firstInitialConditionLayout(), m_secondInitialConditionLayout(), m_nameLayout(), - m_definitionNameWithEqual(), + m_definitionName(), m_firstInitialConditionName(), m_secondInitialConditionName(), m_initialRank(0) @@ -155,38 +155,23 @@ Poincare::Layout Sequence::nameLayout() { } Poincare::Layout Sequence::definitionName() { - if (m_type == Type::Explicit) { - return HorizontalLayout( - CharLayout(name()[0], k_layoutFont), - VerticalOffsetLayout(LayoutHelper::String("n", 1, k_layoutFont), VerticalOffsetLayoutNode::Type::Subscript)); + if (m_definitionName.isUninitialized()) { + if (m_type == Type::Explicit) { + m_definitionName = HorizontalLayout( + CharLayout(name()[0], k_layoutFont), + VerticalOffsetLayout(LayoutHelper::String("n", 1, k_layoutFont), VerticalOffsetLayoutNode::Type::Subscript)); + } else if (m_type == Type::SingleRecurrence) { + m_definitionName = HorizontalLayout( + CharLayout(name()[0], k_layoutFont), + VerticalOffsetLayout(LayoutHelper::String("n+1", 3, k_layoutFont), VerticalOffsetLayoutNode::Type::Subscript)); + } else { + assert(m_type == Type::DoubleRecurrence); + m_definitionName = HorizontalLayout( + CharLayout(name()[0], k_layoutFont), + VerticalOffsetLayout(LayoutHelper::String("n+2", 3, k_layoutFont), VerticalOffsetLayoutNode::Type::Subscript)); + } } - if (m_type == Type::SingleRecurrence) { - return HorizontalLayout( - CharLayout(name()[0], k_layoutFont), - VerticalOffsetLayout(LayoutHelper::String("n+1", 3, k_layoutFont), VerticalOffsetLayoutNode::Type::Subscript)); - } - assert(m_type == Type::DoubleRecurrence); - return HorizontalLayout( - CharLayout(name()[0], k_layoutFont), - VerticalOffsetLayout(LayoutHelper::String("n+2", 3, k_layoutFont), VerticalOffsetLayoutNode::Type::Subscript)); -} - -Poincare::Layout Sequence::definitionNameWithEqual() { - if (m_definitionNameWithEqual.isUninitialized()) { - m_definitionNameWithEqual = definitionName(); - assert(m_definitionNameWithEqual.isHorizontal()); - static_cast(m_definitionNameWithEqual).addChildAtIndex( - CharLayout(' ', KDFont::SmallFont), // Cheat margin - m_definitionNameWithEqual.numberOfChildren(), - m_definitionNameWithEqual.numberOfChildren(), - nullptr); - static_cast(m_definitionNameWithEqual).addChildAtIndex( - CharLayout('=', k_layoutFont), - m_definitionNameWithEqual.numberOfChildren(), - m_definitionNameWithEqual.numberOfChildren(), - nullptr); - } - return m_definitionNameWithEqual; + return m_definitionName; } Poincare::Layout Sequence::firstInitialConditionName() { @@ -199,10 +184,7 @@ Poincare::Layout Sequence::firstInitialConditionName() { Layout indexLayout = LayoutHelper::String(buffer, strlen(buffer), k_layoutFont); m_firstInitialConditionName = HorizontalLayout( CharLayout(name()[0], k_layoutFont), - VerticalOffsetLayout(indexLayout, VerticalOffsetLayoutNode::Type::Subscript), - CharLayout(' ', KDFont::SmallFont), // Cheat margin - CharLayout('=', k_layoutFont) - ); + VerticalOffsetLayout(indexLayout, VerticalOffsetLayoutNode::Type::Subscript)); } return m_firstInitialConditionName; } @@ -215,10 +197,7 @@ Poincare::Layout Sequence::secondInitialConditionName() { Layout indexLayout = LayoutHelper::String(buffer, strlen(buffer), k_layoutFont); m_secondInitialConditionName = HorizontalLayout( CharLayout(name()[0], k_layoutFont), - VerticalOffsetLayout(indexLayout, VerticalOffsetLayoutNode::Type::Subscript), - CharLayout(' ', KDFont::SmallFont), // Cheat margin - CharLayout('=', k_layoutFont) - ); + VerticalOffsetLayout(indexLayout, VerticalOffsetLayoutNode::Type::Subscript)); } } return m_secondInitialConditionName; @@ -331,7 +310,7 @@ void Sequence::tidy() { m_firstInitialConditionExpression = Expression(); m_secondInitialConditionExpression = Expression(); m_nameLayout = Layout(); - m_definitionNameWithEqual = Layout(); + m_definitionName = Layout(); m_firstInitialConditionName = Layout(); m_secondInitialConditionName = Layout(); } diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index c99072854..bd9deb493 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -36,7 +36,6 @@ public: int numberOfElements(); Poincare::Layout nameLayout(); Poincare::Layout definitionName(); - Poincare::Layout definitionNameWithEqual(); Poincare::Layout firstInitialConditionName(); Poincare::Layout secondInitialConditionName(); bool isDefined() override; @@ -66,7 +65,7 @@ private: Poincare::Layout m_firstInitialConditionLayout; Poincare::Layout m_secondInitialConditionLayout; Poincare::Layout m_nameLayout; - Poincare::Layout m_definitionNameWithEqual; + Poincare::Layout m_definitionName; Poincare::Layout m_firstInitialConditionName; Poincare::Layout m_secondInitialConditionName; int m_initialRank; diff --git a/apps/sequence/sequence_title_cell.cpp b/apps/sequence/sequence_title_cell.cpp index e7e3c6853..7e2f08a90 100644 --- a/apps/sequence/sequence_title_cell.cpp +++ b/apps/sequence/sequence_title_cell.cpp @@ -52,18 +52,16 @@ View * SequenceTitleCell::subviewAtIndex(int index) { } void SequenceTitleCell::layoutSubviews() { - KDRect textFrame(0, k_colorIndicatorThickness, bounds().width(), bounds().height() - k_colorIndicatorThickness); if (m_orientation == Orientation::VerticalIndicator) { - KDCoordinate h = bounds().height()-k_separatorThickness; - textFrame = KDRect(k_colorIndicatorThickness, 0, bounds().width() - k_colorIndicatorThickness, h); - /* We try to align the text so that the equal is vertically centered in the - * cell. This makes the title cell and the definition cell baselines be - * approximately at the same level for basic sequences definitions (un = 1, - * un=1/2, ...). */ - float verticalAlignment = 0.5f + 20.0f/((float)h); // 20.0f is a magic value - m_titleTextView.setAlignment(k_verticalOrientationHorizontalAlignment, verticalAlignment); + m_titleTextView.setAlignment(k_verticalOrientationHorizontalAlignment, verticalAlignment()); } - m_titleTextView.setFrame(textFrame); + m_titleTextView.setFrame(subviewFrame()); +} + +float SequenceTitleCell::verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const { + assert(m_orientation == Orientation::VerticalIndicator); + Layout l = layout(); + return ((float)(expressionBaseline - l.baseline()))/((float)rowHeight-l.layoutSize().height()); } } diff --git a/apps/sequence/sequence_title_cell.h b/apps/sequence/sequence_title_cell.h index db787b793..1f6b92c67 100644 --- a/apps/sequence/sequence_title_cell.h +++ b/apps/sequence/sequence_title_cell.h @@ -26,6 +26,7 @@ private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; void layoutSubviews() override; + float verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const override; EvenOddExpressionCell m_titleTextView; }; diff --git a/apps/shared/expression_model_list_controller.cpp b/apps/shared/expression_model_list_controller.cpp index 327a5ac3b..02a52ec4f 100644 --- a/apps/shared/expression_model_list_controller.cpp +++ b/apps/shared/expression_model_list_controller.cpp @@ -45,6 +45,7 @@ bool ExpressionModelListController::handleEventOnExpression(Ion::Events::Event e if (event == Ion::Events::OK || event == Ion::Events::EXE) { if (isAddEmptyRow(selectedRow())) { addEmptyModel(); + selectableTableView()->reloadCellAtLocation(selectedColumn(), selectedRow()); return true; } ExpressionModel * model = modelStore()->modelAtIndex(modelIndexForRow(selectedRow())); @@ -55,10 +56,12 @@ bool ExpressionModelListController::handleEventOnExpression(Ion::Events::Event e ExpressionModel * model = modelStore()->modelAtIndex(modelIndexForRow(selectedRow())); if (model->shouldBeClearedBeforeRemove()) { reinitExpression(model); + selectableTableView()->reloadCellAtLocation(selectedColumn(), selectedRow()); } else { if (removeModelRow(model)) { int newSelectedRow = selectedRow() >= numberOfExpressionRows() ? numberOfExpressionRows()-1 : selectedRow(); selectCellAtLocation(selectedColumn(), newSelectedRow); + selectableTableView()->reloadCellAtLocation(selectedColumn(), selectedRow()); selectableTableView()->reloadData(); } } @@ -84,7 +87,6 @@ void ExpressionModelListController::reinitExpression(ExpressionModel * model) { selectableTableView()->reloadData(); } - void ExpressionModelListController::editExpression(ExpressionModel * model, Ion::Events::Event event) { char * initialText = nullptr; char initialTextContent[TextField::maxBufferSize()]; diff --git a/apps/shared/function_list_controller.h b/apps/shared/function_list_controller.h index 4e5f659f3..24d1cf760 100644 --- a/apps/shared/function_list_controller.h +++ b/apps/shared/function_list_controller.h @@ -47,6 +47,7 @@ protected: StackViewController * stackController() const; void configureFunction(Function * function); FunctionStore * m_functionStore; + SelectableTableView m_selectableTableView; private: static constexpr KDCoordinate k_functionNameWidth = 65; TabViewController * tabController() const; @@ -60,7 +61,6 @@ private: virtual HighlightCell * titleCells(int index) = 0; virtual HighlightCell * expressionCells(int index) = 0; virtual void willDisplayTitleCellAtIndex(HighlightCell * cell, int j) = 0; - SelectableTableView m_selectableTableView; EvenOddCell m_emptyCell; Button m_plotButton; Button m_valuesButton; diff --git a/apps/shared/function_title_cell.cpp b/apps/shared/function_title_cell.cpp index b6147c7f5..b32a7b4ea 100644 --- a/apps/shared/function_title_cell.cpp +++ b/apps/shared/function_title_cell.cpp @@ -3,6 +3,9 @@ namespace Shared { +static inline float min(float x, float y) { return (xy ? x : y); } + void FunctionTitleCell::setOrientation(Orientation orientation) { m_orientation = orientation; reloadCell(); @@ -44,7 +47,15 @@ KDRect FunctionTitleCell::subviewFrame() const { return KDRect(k_colorIndicatorThickness, 0, bounds().width() - k_colorIndicatorThickness - k_equalWidthWithMargins, bounds().height()-k_separatorThickness); } return KDRect(0, k_colorIndicatorThickness, bounds().width(), bounds().height()-k_colorIndicatorThickness); +} +float FunctionTitleCell::verticalAlignment() const { + assert(m_orientation == Orientation::VerticalIndicator); + return max( + 0.0f, + min( + 1.0f, + m_baseline < 0 ? 0.5f : verticalAlignmentGivenExpressionBaselineAndRowHeight(m_baseline, subviewFrame().height()))); } } diff --git a/apps/shared/function_title_cell.h b/apps/shared/function_title_cell.h index 4a400e67e..45fc820d6 100644 --- a/apps/shared/function_title_cell.h +++ b/apps/shared/function_title_cell.h @@ -26,10 +26,12 @@ protected: constexpr static KDCoordinate k_separatorThickness = 1; constexpr static KDCoordinate k_colorIndicatorThickness = 2; KDRect subviewFrame() const; + float verticalAlignment() const; Orientation m_orientation; KDCoordinate m_baseline; private: constexpr static KDCoordinate k_equalWidthWithMargins = 10; // Ad hoc value + virtual float verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const { assert(false); return 0; } KDColor m_functionColor; };