diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index c3da93582..93fea6e6e 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -19,7 +19,7 @@ const Image * App::Descriptor::icon() { } App::Snapshot::Snapshot() : - Shared::FunctionApp::Snapshot::Snapshot(), + Shared::StorageFunctionApp::Snapshot::Snapshot(), m_sequenceStore(), m_graphRange(&m_cursor) { @@ -30,19 +30,17 @@ App * App::Snapshot::unpack(Container * container) { } void App::Snapshot::reset() { - FunctionApp::Snapshot::reset(); + StorageFunctionApp::Snapshot::reset(); /* reset might be called when activating the exam mode from the settings or * when a memory exception occurs. In both cases, we do not want to * computeYAuto in GraphRange::setDefault, so we need to set its delegate to * nullptr. */ m_graphRange.setDelegate(nullptr); - m_graphRange.setDefault(); /* We do not need to invalidate the sequence context cache here: * - The context is not allocated yet when reset is call from the application * settings. * - The cache will be destroyed if the reset call comes from a memory * exception. */ - m_sequenceStore.removeAll(); } App::Descriptor * App::Snapshot::descriptor() { @@ -56,17 +54,17 @@ void App::Snapshot::tidy() { } App::App(Container * container, Snapshot * snapshot) : - FunctionApp(container, snapshot, &m_inputViewController), - m_sequenceContext(((AppsContainer *)container)->globalContext(), snapshot->sequenceStore()), - m_listController(&m_listFooter, this, snapshot->sequenceStore(), &m_listHeader, &m_listFooter), + StorageFunctionApp(container, snapshot, &m_inputViewController), + m_sequenceContext(((AppsContainer *)container)->globalContext(), snapshot->functionStore()), + m_listController(&m_listFooter, this, &m_listHeader, &m_listFooter), m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(nullptr, &m_listFooter, &m_listController), m_listStackViewController(&m_tabViewController, &m_listHeader), - m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->sequenceStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), + m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader), m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController), m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController), m_graphStackViewController(&m_tabViewController, &m_graphHeader), - m_valuesController(&m_valuesAlternateEmptyViewController, this, snapshot->sequenceStore(), snapshot->interval(), &m_valuesHeader), + m_valuesController(&m_valuesAlternateEmptyViewController, this, snapshot->interval(), &m_valuesHeader), m_valuesAlternateEmptyViewController(&m_valuesHeader, &m_valuesController, &m_valuesController), m_valuesHeader(nullptr, &m_valuesAlternateEmptyViewController, &m_valuesController), m_valuesStackViewController(&m_tabViewController, &m_valuesHeader), diff --git a/apps/sequence/app.h b/apps/sequence/app.h index c3f71836c..c63f24f30 100644 --- a/apps/sequence/app.h +++ b/apps/sequence/app.h @@ -8,11 +8,11 @@ #include "graph/curve_view_range.h" #include "list/list_controller.h" #include "values/values_controller.h" -#include "../shared/function_app.h" +#include "../shared/storage_function_app.h" namespace Sequence { -class App : public Shared::FunctionApp { +class App : public Shared::StorageFunctionApp { public: class Descriptor : public ::App::Descriptor { public: @@ -20,13 +20,13 @@ public: I18n::Message upperName() override; const Image * icon() override; }; - class Snapshot : public Shared::FunctionApp::Snapshot { + class Snapshot : public Shared::StorageFunctionApp::Snapshot { public: Snapshot(); App * unpack(Container * container) override; void reset() override; Descriptor * descriptor() override; - SequenceStore * sequenceStore() { return &m_sequenceStore; } + SequenceStore * functionStore() override { return &m_sequenceStore; } CurveViewRange * graphRange() { return &m_graphRange; } private: void tidy() override; @@ -34,8 +34,11 @@ public: CurveViewRange m_graphRange; }; InputViewController * inputViewController() override; - SequenceContext * localContext() override; + // TODO: override variableBoxForInputEventHandler to lock sequence in the variable box once they appear there + // NestedMenuController * variableBoxForInputEventHandler(InputEventHandler * textInput) override; char XNT() override; + SequenceContext * localContext() override; + SequenceStore * functionStore() override { return static_cast(Shared::StorageFunctionApp::functionStore()); } private: App(Container * container, Snapshot * snapshot); SequenceContext m_sequenceContext; diff --git a/apps/sequence/graph/curve_parameter_controller.cpp b/apps/sequence/graph/curve_parameter_controller.cpp index 6521148ec..9ba0be189 100644 --- a/apps/sequence/graph/curve_parameter_controller.cpp +++ b/apps/sequence/graph/curve_parameter_controller.cpp @@ -7,7 +7,7 @@ using namespace Shared; namespace Sequence { CurveParameterController::CurveParameterController(InputEventHandlerDelegate * inputEventHandlerDelegate, GraphController * graphController, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor) : - FunctionCurveParameterController(graphRange, cursor), + StorageFunctionCurveParameterController(graphRange, cursor), m_goToParameterController(this, inputEventHandlerDelegate, graphRange, cursor, I18n::Message::N), m_sumCell(I18n::Message::TermSum), m_graphController(graphController) diff --git a/apps/sequence/graph/curve_parameter_controller.h b/apps/sequence/graph/curve_parameter_controller.h index 37e0eb54f..7a5bf923a 100644 --- a/apps/sequence/graph/curve_parameter_controller.h +++ b/apps/sequence/graph/curve_parameter_controller.h @@ -2,14 +2,14 @@ #define SEQUENCE_CURVE_PARAMETER_CONTROLLER_H #include -#include "../../shared/function_curve_parameter_controller.h" +#include "../../shared/storage_function_curve_parameter_controller.h" #include "go_to_parameter_controller.h" namespace Sequence { class GraphController; -class CurveParameterController : public Shared::FunctionCurveParameterController { +class CurveParameterController : public Shared::StorageFunctionCurveParameterController { public: CurveParameterController(InputEventHandlerDelegate * inputEventHandlerDelegate, GraphController * graphController, Shared::InteractiveCurveViewRange * graphRange, Shared::CurveViewCursor * cursor); const char * title() override; diff --git a/apps/sequence/graph/go_to_parameter_controller.cpp b/apps/sequence/graph/go_to_parameter_controller.cpp index 25aa8307c..e373e15fb 100644 --- a/apps/sequence/graph/go_to_parameter_controller.cpp +++ b/apps/sequence/graph/go_to_parameter_controller.cpp @@ -1,5 +1,4 @@ #include "go_to_parameter_controller.h" -#include "../app.h" #include #include @@ -7,7 +6,7 @@ namespace Sequence { bool GoToParameterController::setParameterAtIndex(int parameterIndex, double f) { assert(parameterIndex == 0); - return Shared::FunctionGoToParameterController::setParameterAtIndex(parameterIndex, std::round(f)); + return Shared::StorageFunctionGoToParameterController::setParameterAtIndex(parameterIndex, std::round(f)); } } diff --git a/apps/sequence/graph/go_to_parameter_controller.h b/apps/sequence/graph/go_to_parameter_controller.h index adf6dd31b..d7424d184 100644 --- a/apps/sequence/graph/go_to_parameter_controller.h +++ b/apps/sequence/graph/go_to_parameter_controller.h @@ -1,13 +1,13 @@ #ifndef SEQUENCE_GO_TO_PARAMETER_CONTROLLER_H #define SEQUENCE_GO_TO_PARAMETER_CONTROLLER_H -#include "../../shared/function_go_to_parameter_controller.h" +#include "../../shared/storage_function_go_to_parameter_controller.h" namespace Sequence { -class GoToParameterController : public Shared::FunctionGoToParameterController { +class GoToParameterController : public Shared::StorageFunctionGoToParameterController { public: - using Shared::FunctionGoToParameterController::FunctionGoToParameterController; + using Shared::StorageFunctionGoToParameterController::StorageFunctionGoToParameterController; private: bool setParameterAtIndex(int parameterIndex, double f) override; }; diff --git a/apps/sequence/graph/graph_controller.cpp b/apps/sequence/graph/graph_controller.cpp index 92db25c1a..1ba55c2b7 100644 --- a/apps/sequence/graph/graph_controller.cpp +++ b/apps/sequence/graph/graph_controller.cpp @@ -11,19 +11,18 @@ static inline int minInt(int x, int y) { return (x < y ? x : y); } static inline int maxInt(int x, int y) { return (x > y ? x : y); } GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : - FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion), + StorageFunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion), m_bannerView(), m_view(sequenceStore, graphRange, m_cursor, &m_bannerView, &m_cursorView), m_graphRange(graphRange), m_curveParameterController(inputEventHandlerDelegate, this, graphRange, m_cursor), - m_termSumController(this, inputEventHandlerDelegate, &m_view, graphRange, m_cursor), - m_sequenceStore(sequenceStore) + m_termSumController(this, inputEventHandlerDelegate, &m_view, graphRange, m_cursor) { m_graphRange->setDelegate(this); } I18n::Message GraphController::emptyMessage() { - if (m_sequenceStore->numberOfDefinedModels() == 0) { + if (functionStore()->numberOfDefinedModels() == 0) { return I18n::Message::NoSequence; } return I18n::Message::NoActivatedSequence; @@ -31,35 +30,34 @@ I18n::Message GraphController::emptyMessage() { float GraphController::interestingXMin() const { int nmin = INT_MAX; - for (int i = 0; i < m_sequenceStore->numberOfModels(); i++) { - Sequence * s = m_sequenceStore->modelAtIndex(i); - if (s->isDefined() && s->isActive()) { - nmin = minInt(nmin, s->initialRank()); - } + int nbOfActiveModels = functionStore()->numberOfActiveFunctions(); + for (int i = 0; i < nbOfActiveModels; i++) { + ExpiringPointer s = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i)); + nmin = minInt(nmin, s->initialRank()); } assert(nmin < INT_MAX); return nmin; } float GraphController::interestingXHalfRange() const { - float standardRange = Shared::FunctionGraphController::interestingXHalfRange(); + float standardRange = Shared::StorageFunctionGraphController::interestingXHalfRange(); int nmin = INT_MAX; int nmax = 0; - for (int i = 0; i < m_sequenceStore->numberOfModels(); i++) { - Sequence * s = m_sequenceStore->modelAtIndex(i); - if (s->isDefined() && s->isActive()) { - int firstInterestingIndex = s->initialRank(); - nmin = minInt(nmin, firstInterestingIndex); - nmax = maxInt(nmax, firstInterestingIndex + standardRange); - } + int nbOfActiveModels = functionStore()->numberOfActiveFunctions(); + for (int i = 0; i < nbOfActiveModels; i++) { + ExpiringPointer s = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i)); + int firstInterestingIndex = s->initialRank(); + nmin = minInt(nmin, firstInterestingIndex); + nmax = maxInt(nmax, firstInterestingIndex + standardRange); } assert(nmax - nmin >= standardRange); return nmax - nmin; } bool GraphController::handleEnter() { - m_termSumController.setFunction(m_sequenceStore->activeFunctionAtIndex(indexFunctionSelectedByCursor())); - return FunctionGraphController::handleEnter(); + Ion::Storage::Record record = functionStore()->activeRecordAtIndex(indexFunctionSelectedByCursor()); + m_termSumController.setRecord(record); + return StorageFunctionGraphController::handleEnter(); } bool GraphController::moveCursorHorizontally(int direction) { @@ -77,16 +75,16 @@ bool GraphController::moveCursorHorizontally(int direction) { if (x < 0.0) { return false; } - Sequence * s = m_sequenceStore->activeFunctionAtIndex(indexFunctionSelectedByCursor()); + ExpiringPointer s = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(indexFunctionSelectedByCursor())); TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); double y = s->evaluateAtAbscissa(x, myApp->localContext()); m_cursor->moveTo(x, y); - m_graphRange->panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio); + m_graphRange->panToMakePointVisible(x, y, cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); return true; } double GraphController::defaultCursorAbscissa() { - return std::round(Shared::FunctionGraphController::defaultCursorAbscissa()); + return std::round(Shared::StorageFunctionGraphController::defaultCursorAbscissa()); } } diff --git a/apps/sequence/graph/graph_controller.h b/apps/sequence/graph/graph_controller.h index b8579a776..1cdc56c46 100644 --- a/apps/sequence/graph/graph_controller.h +++ b/apps/sequence/graph/graph_controller.h @@ -6,13 +6,13 @@ #include "curve_parameter_controller.h" #include "curve_view_range.h" #include "term_sum_controller.h" -#include "../../shared/function_graph_controller.h" +#include "../../shared/storage_function_graph_controller.h" #include "../../shared/cursor_view.h" #include "../sequence_store.h" namespace Sequence { -class GraphController final : public Shared::FunctionGraphController { +class GraphController final : public Shared::StorageFunctionGraphController { public: GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header); I18n::Message emptyMessage() override; @@ -21,14 +21,14 @@ public: float interestingXMin() const override; float interestingXHalfRange() const override; protected: - int numberOfCurves() const override { return m_sequenceStore->numberOfModels(); } + int numberOfCurves() const override { return functionStore()->numberOfModels(); } private: BannerView * bannerView() override { return &m_bannerView; } bool handleEnter() override; bool moveCursorHorizontally(int direction) override; double defaultCursorAbscissa() override; CurveViewRange * interactiveCurveViewRange() override { return m_graphRange; } - SequenceStore * functionStore() const override { return m_sequenceStore; } + SequenceStore * functionStore() const override { return static_cast(Shared::StorageFunctionGraphController::functionStore()); } GraphView * functionGraphView() override { return &m_view; } View * cursorView() override { return &m_cursorView; @@ -40,7 +40,6 @@ private: CurveViewRange * m_graphRange; CurveParameterController m_curveParameterController; TermSumController m_termSumController; - SequenceStore * m_sequenceStore; }; diff --git a/apps/sequence/graph/graph_view.cpp b/apps/sequence/graph/graph_view.cpp index c973b5715..7611adfae 100644 --- a/apps/sequence/graph/graph_view.cpp +++ b/apps/sequence/graph/graph_view.cpp @@ -7,15 +7,16 @@ namespace Sequence { GraphView::GraphView(SequenceStore * sequenceStore, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, BannerView * bannerView, View * cursorView) : - FunctionGraphView(graphRange, cursor, bannerView, cursorView), + StorageFunctionGraphView(graphRange, cursor, bannerView, cursorView), m_sequenceStore(sequenceStore) { } void GraphView::drawRect(KDContext * ctx, KDRect rect) const { - FunctionGraphView::drawRect(ctx, rect); + StorageFunctionGraphView::drawRect(ctx, rect); for (int i = 0; i < m_sequenceStore->numberOfActiveFunctions(); i++) { - Sequence * s = m_sequenceStore->activeFunctionAtIndex(i); + Ion::Storage::Record record = m_sequenceStore->activeRecordAtIndex(i); + ExpiringPointer s = m_sequenceStore->modelForRecord(record);; float rectXMin = pixelToFloat(Axis::Horizontal, rect.left() - k_externRectMargin); rectXMin = rectXMin < 0 ? 0 : rectXMin; float rectXMax = pixelToFloat(Axis::Horizontal, rect.right() + k_externRectMargin); @@ -29,7 +30,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { continue; } drawDot(ctx, rect, x, y, s->color()); - if (x >= m_highlightedStart && x <= m_highlightedEnd && s == m_selectedFunction) { + if (x >= m_highlightedStart && x <= m_highlightedEnd && record == m_selectedRecord) { KDColor color = m_shouldColorHighlighted ? s->color() : KDColorBlack; if (y >= 0.0f) { drawSegment(ctx, rect, Axis::Vertical, x, 0.0f, y, color, 1); diff --git a/apps/sequence/graph/graph_view.h b/apps/sequence/graph/graph_view.h index 97d35ea99..291ddf8fe 100644 --- a/apps/sequence/graph/graph_view.h +++ b/apps/sequence/graph/graph_view.h @@ -1,12 +1,12 @@ #ifndef SEQUENCE_GRAPH_VIEW_H #define SEQUENCE_GRAPH_VIEW_H -#include "../../shared/function_graph_view.h" +#include "../../shared/storage_function_graph_view.h" #include "../sequence_store.h" namespace Sequence { -class GraphView : public Shared::FunctionGraphView { +class GraphView : public Shared::StorageFunctionGraphView { public: GraphView(SequenceStore * sequenceStore, Shared::InteractiveCurveViewRange * graphRange, Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, View * cursorView); diff --git a/apps/sequence/graph/term_sum_controller.cpp b/apps/sequence/graph/term_sum_controller.cpp index 8f7a99e5f..15a018a93 100644 --- a/apps/sequence/graph/term_sum_controller.cpp +++ b/apps/sequence/graph/term_sum_controller.cpp @@ -1,6 +1,5 @@ #include "term_sum_controller.h" #include "../../shared/text_field_delegate.h" -#include "../app.h" #include #include #include @@ -18,7 +17,7 @@ using namespace Poincare; namespace Sequence { TermSumController::TermSumController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, GraphView * graphView, CurveViewRange * graphRange, CurveViewCursor * cursor) : - SumGraphController(parentResponder, inputEventHandlerDelegate, graphView, graphRange, cursor, UCodePointNArySummation) + StorageSumGraphController(parentResponder, inputEventHandlerDelegate, graphView, graphRange, cursor, UCodePointNArySummation) { } @@ -30,7 +29,7 @@ bool TermSumController::moveCursorHorizontallyToPosition(double position) { if (position < 0.0) { return false; } - return SumGraphController::moveCursorHorizontallyToPosition(std::round(position)); + return StorageSumGraphController::moveCursorHorizontallyToPosition(std::round(position)); } I18n::Message TermSumController::legendMessageAtStep(Step step) { @@ -49,14 +48,9 @@ double TermSumController::cursorNextStep(double x, int direction) { return std::round(m_cursor->x()+delta); } -Layout TermSumController::createFunctionLayout(const char * functionName) { - return HorizontalLayout::Builder( - CodePointLayout::Builder(functionName[0], KDFont::SmallFont), - VerticalOffsetLayout::Builder( - CodePointLayout::Builder('n', KDFont::SmallFont), - VerticalOffsetLayoutNode::Type::Subscript - ) - ); +Layout TermSumController::createFunctionLayout(Shared::ExpiringPointer function) { + Shared::ExpiringPointer sequence = static_cast>(function); + return sequence->nameLayout(); } } diff --git a/apps/sequence/graph/term_sum_controller.h b/apps/sequence/graph/term_sum_controller.h index df3acf423..5d7e4b31b 100644 --- a/apps/sequence/graph/term_sum_controller.h +++ b/apps/sequence/graph/term_sum_controller.h @@ -5,11 +5,11 @@ #include #include "graph_view.h" #include "curve_view_range.h" -#include "../../shared/sum_graph_controller.h" +#include "../../shared/storage_sum_graph_controller.h" namespace Sequence { -class TermSumController : public Shared::SumGraphController { +class TermSumController : public Shared::StorageSumGraphController { public: TermSumController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, GraphView * graphView, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor); const char * title() override; @@ -17,7 +17,7 @@ private: bool moveCursorHorizontallyToPosition(double position) override; I18n::Message legendMessageAtStep(Step step) override; double cursorNextStep(double position, int direction) override; - Poincare::Layout createFunctionLayout(const char * functionName) override; + Poincare::Layout createFunctionLayout(Shared::ExpiringPointer function) override; }; } diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index 86c73fba8..c5eec2f96 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -9,13 +9,12 @@ static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { retur namespace Sequence { -ListController::ListController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, ButtonRowController * header, ButtonRowController * footer) : - Shared::FunctionListController(parentResponder, sequenceStore, header, footer, I18n::Message::AddSequence), - m_sequenceStore(sequenceStore), +ListController::ListController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, ButtonRowController * footer) : + Shared::StorageFunctionListController(parentResponder, header, footer, I18n::Message::AddSequence), m_sequenceTitleCells{}, m_expressionCells{}, - m_parameterController(inputEventHandlerDelegate, this, sequenceStore), - m_typeParameterController(this, sequenceStore, this, TableCell::Layout::Vertical), + m_parameterController(inputEventHandlerDelegate, this), + m_typeParameterController(this, this, TableCell::Layout::Vertical), m_typeStackController(nullptr, &m_typeParameterController, KDColorWhite, Palette::PurpleDark, Palette::PurpleDark), m_sequenceToolbox() { @@ -28,29 +27,13 @@ const char * ListController::title() { return I18n::translate(I18n::Message::SequenceTab); } -Toolbox * ListController::toolboxForInputEventHandler(InputEventHandler * textInput) { - return toolboxForSender(textInput); -} - -TextFieldDelegateApp * ListController::textFieldDelegateApp() { - return (App *)app(); -} - -ExpressionFieldDelegateApp * ListController::expressionFieldDelegateApp() { - return (App *)app(); -} - -InputEventHandlerDelegateApp * ListController::inputEventHandlerDelegateApp() { - return (App *)app(); -} - int ListController::numberOfExpressionRows() { int numberOfRows = 0; - for (int i = 0; i < m_sequenceStore->numberOfModels(); i++) { - Sequence * sequence = m_sequenceStore->modelAtIndex(i); + for (int i = 0; i < modelStore()->numberOfModels(); i++) { + ExpiringPointer sequence = modelStore()->modelForRecord(modelStore()->recordAtIndex(i)); numberOfRows += sequence->numberOfElements(); } - if (m_sequenceStore->numberOfModels() == m_sequenceStore->maxNumberOfModels()) { + if (modelStore()->numberOfModels() == modelStore()->maxNumberOfModels()) { return numberOfRows; } return 1 + numberOfRows; @@ -58,11 +41,11 @@ int ListController::numberOfExpressionRows() { KDCoordinate ListController::expressionRowHeight(int j) { KDCoordinate defaultHeight = Metric::StoreRowHeight; - if (m_sequenceStore->numberOfModels() < m_sequenceStore->maxNumberOfModels() && j == numberOfRows() - 1) { + if (modelStore()->numberOfModels() < modelStore()->maxNumberOfModels() && j == numberOfRows() - 1) { // Add sequence row return defaultHeight; } - Sequence * sequence = m_sequenceStore->modelAtIndex(modelIndexForRow(j)); + ExpiringPointer sequence = modelStore()->modelForRecord(modelStore()->recordAtIndex(modelIndexForRow(j))); Layout layout = sequence->layout(); if (sequenceDefinitionForRow(j) == 1) { layout = sequence->firstInitialConditionLayout(); @@ -78,44 +61,46 @@ KDCoordinate ListController::expressionRowHeight(int j) { } void ListController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) { - Shared::FunctionListController::willDisplayCellAtLocation(cell, i, j); + Shared::StorageFunctionListController::willDisplayCellAtLocation(cell, i, j); EvenOddCell * myCell = (EvenOddCell *)cell; myCell->setEven(modelIndexForRow(j)%2 == 0); } +Toolbox * ListController::toolboxForInputEventHandler(InputEventHandler * textInput) { + // Set extra cells + int recurrenceDepth = -1; + int sequenceDefinition = sequenceDefinitionForRow(selectedRow()); + ExpiringPointer sequence = modelStore()->modelForRecord(modelStore()->recordAtIndex(modelIndexForRow(selectedRow()))); + if (sequenceDefinition == 0) { + recurrenceDepth = sequence->numberOfElements()-1; + } + m_sequenceToolbox.buildExtraCellsLayouts(sequence->fullName(), recurrenceDepth); + // Set sender + m_sequenceToolbox.setSender(textInput); + return &m_sequenceToolbox; +} + void ListController::selectPreviousNewSequenceCell() { if (sequenceDefinitionForRow(selectedRow()) >= 0) { selectCellAtLocation(selectedColumn(), selectedRow()-sequenceDefinitionForRow(selectedRow())); } } -Toolbox * ListController::toolboxForSender(InputEventHandler * sender) { - // Set extra cells - int recurrenceDepth = -1; - int sequenceDefinition = sequenceDefinitionForRow(selectedRow()); - Sequence * sequence = m_sequenceStore->modelAtIndex(modelIndexForRow(selectedRow())); - if (sequenceDefinition == 0) { - recurrenceDepth = sequence->numberOfElements()-1; - } - m_sequenceToolbox.buildExtraCellsLayouts(sequence->name(), recurrenceDepth); - // Set sender - m_sequenceToolbox.setSender(sender); - return &m_sequenceToolbox; -} - -void ListController::editExpression(Sequence * sequence, int sequenceDefinition, Ion::Events::Event event) { +void ListController::editExpression(int sequenceDefinition, Ion::Events::Event event) { + Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(selectedRow())); + ExpiringPointer sequence = modelStore()->modelForRecord(record); char * initialText = nullptr; char initialTextContent[TextField::maxBufferSize()]; if (event == Ion::Events::OK || event == Ion::Events::EXE) { switch (sequenceDefinition) { case 0: - strlcpy(initialTextContent, sequence->text(), sizeof(initialTextContent)); + sequence->text(initialTextContent, sizeof(initialTextContent)); break; case 1: - strlcpy(initialTextContent, sequence->firstInitialConditionText(), sizeof(initialTextContent)); + sequence->firstInitialConditionText(initialTextContent, sizeof(initialTextContent)); break; default: - strlcpy(initialTextContent, sequence->secondInitialConditionText(), sizeof(initialTextContent)); + sequence->secondInitialConditionText(initialTextContent, sizeof(initialTextContent)); break; } initialText = initialTextContent; @@ -126,39 +111,36 @@ void ListController::editExpression(Sequence * sequence, int sequenceDefinition, static_cast(app())->localContext()->resetCache(); switch (sequenceDefinition) { case 0: - inputController->edit(this, event, sequence, initialText, + inputController->edit(this, event, this, initialText, [](void * context, void * sender){ - Sequence * mySequence = (Sequence *)context; + ListController * myController = static_cast(context); InputViewController * myInputViewController = (InputViewController *)sender; const char * textBody = myInputViewController->textBody(); - mySequence->setContent(textBody); - return true; //TODO should return result of mySequence->setContent + return myController->editSelectedRecordWithText(textBody); }, [](void * context, void * sender){ return true; }); break; case 1: - inputController->edit(this, event, sequence, initialText, + inputController->edit(this, event, this, initialText, [](void * context, void * sender){ - Sequence * mySequence = (Sequence *)context; + ListController * myController = static_cast(context); InputViewController * myInputViewController = (InputViewController *)sender; const char * textBody = myInputViewController->textBody(); - mySequence->setFirstInitialConditionContent(textBody); - return true; //TODO should return result of mySequence->setFirstInitialConditionContent + return myController->editInitialConditionOfSelectedRecordWithText(textBody, true); }, [](void * context, void * sender){ return true; }); break; default: - inputController->edit(this, event, sequence, initialText, + inputController->edit(this, event, this, initialText, [](void * context, void * sender){ - Sequence * mySequence = (Sequence *)context; + ListController * myController = static_cast(context); InputViewController * myInputViewController = (InputViewController *)sender; const char * textBody = myInputViewController->textBody(); - mySequence->setSecondInitialConditionContent(textBody); - return true; //TODO should return the result of mySequence->setSecondInitialConditionContent + return myController->editInitialConditionOfSelectedRecordWithText(textBody, false); }, [](void * context, void * sender){ return true; @@ -166,18 +148,32 @@ void ListController::editExpression(Sequence * sequence, int sequenceDefinition, } } -bool ListController::removeModelRow(ExpressionModel * model) { - Shared::FunctionListController::removeModelRow(model); - // Invalidate the sequences context cache - static_cast(app())->localContext()->resetCache(); - return true; +bool ListController::editInitialConditionOfSelectedRecordWithText(const char * text, bool firstInitialCondition) { + // Reset memoization of the selected cell which always corresponds to the k_memoizedCellsCount/2 memoized cell + resetMemoizationForIndex(k_memoizedCellsCount/2); + Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(selectedRow())); + ExpiringPointer sequence = modelStore()->modelForRecord(record); + Ion::Storage::Record::ErrorStatus error = firstInitialCondition? sequence->setFirstInitialConditionContent(text) : sequence->setSecondInitialConditionContent(text); + return (error == Ion::Storage::Record::ErrorStatus::None); +} + +TextFieldDelegateApp * ListController::textFieldDelegateApp() { + return (App *)app(); +} + +ExpressionFieldDelegateApp * ListController::expressionFieldDelegateApp() { + return (App *)app(); +} + +InputEventHandlerDelegateApp * ListController::inputEventHandlerDelegateApp() { + return (App *)app(); } ListParameterController * ListController::parameterController() { return &m_parameterController; } -int ListController::maxNumberOfRows() { +int ListController::maxNumberOfDisplayableRows() { return k_maxNumberOfRows; } @@ -198,7 +194,8 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) { willDisplayExpressionCellAtIndex(m_selectableTableView.cellAtLocation(1, j), j); myCell->setBaseline(baseline(j)); // Set the layout - Sequence * sequence = m_sequenceStore->modelAtIndex(modelIndexForRow(j)); + Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(j)); + ExpiringPointer sequence = modelStore()->modelForRecord(record); if (sequenceDefinitionForRow(j) == 0) { myCell->setLayout(sequence->definitionName()); } @@ -215,7 +212,8 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) { void ListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) { FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell; - Sequence * sequence = m_sequenceStore->modelAtIndex(modelIndexForRow(j)); + Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(j)); + ExpiringPointer sequence = modelStore()->modelForRecord(record); if (sequenceDefinitionForRow(j) == 0) { myCell->setLayout(sequence->layout()); } @@ -241,14 +239,14 @@ int ListController::modelIndexForRow(int j) { int sequenceIndex = -1; do { sequenceIndex++; - Sequence * sequence = m_sequenceStore->modelAtIndex(sequenceIndex); + ExpiringPointer sequence = modelStore()->modelForRecord(modelStore()->recordAtIndex(sequenceIndex)); rowIndex += sequence->numberOfElements(); } while (rowIndex <= j); return sequenceIndex; } bool ListController::isAddEmptyRow(int j) { - return m_sequenceStore->numberOfModels() < m_sequenceStore->maxNumberOfModels() && j == numberOfRows() - 1; + return modelStore()->numberOfModels() < modelStore()->maxNumberOfModels() && j == numberOfRows() - 1; } int ListController::sequenceDefinitionForRow(int j) { @@ -260,12 +258,13 @@ int ListController::sequenceDefinitionForRow(int j) { } int rowIndex = 0; int sequenceIndex = -1; - Sequence * sequence = nullptr; + ExpiringPointer sequence(nullptr); do { sequenceIndex++; - sequence = m_sequenceStore->modelAtIndex(sequenceIndex); + sequence = modelStore()->modelForRecord(modelStore()->recordAtIndex(sequenceIndex)); rowIndex += sequence->numberOfElements(); } while (rowIndex <= j); + assert(!sequence.isNull()); return sequence->numberOfElements()-rowIndex+j; } @@ -273,30 +272,29 @@ void ListController::addEmptyModel() { app()->displayModalViewController(&m_typeStackController, 0.f, 0.f, Metric::TabHeight+Metric::ModalTopMargin, Metric::CommonRightMargin, Metric::ModalBottomMargin, Metric::CommonLeftMargin); } -void ListController::editExpression(Shared::ExpressionModel * model, Ion::Events::Event event) { - Sequence * sequence = static_cast(model); - editExpression(sequence, sequenceDefinitionForRow(selectedRow()), event); +void ListController::editExpression(Ion::Events::Event event) { + editExpression(sequenceDefinitionForRow(selectedRow()), event); } -void ListController::reinitExpression(Shared::ExpressionModel * model) { +void ListController::reinitSelectedExpression(ExpiringPointer model) { // Invalidate the sequences context cache static_cast(app())->localContext()->resetCache(); - Sequence * sequence = static_cast(model); + ExpiringPointer sequence = static_cast>(model); switch (sequenceDefinitionForRow(selectedRow())) { case 1: - if (strlen(sequence->firstInitialConditionText()) == 0) { + if (sequence->firstInitialConditionExpressionClone().isUninitialized()) { return; } sequence->setFirstInitialConditionContent(""); break; case 2: - if (strlen(sequence->secondInitialConditionText()) == 0) { + if (sequence->secondInitialConditionExpressionClone().isUninitialized()) { return; } sequence->setSecondInitialConditionContent(""); break; default: - if (strlen(sequence->text()) == 0) { + if (sequence->expressionClone().isUninitialized()) { return; } sequence->setContent(""); @@ -305,15 +303,11 @@ 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(); +bool ListController::removeModelRow(Ion::Storage::Record record) { + Shared::StorageFunctionListController::removeModelRow(record); + // Invalidate the sequences context cache + static_cast(app())->localContext()->resetCache(); + return true; } } diff --git a/apps/sequence/list/list_controller.h b/apps/sequence/list/list_controller.h index 969fa3d7e..0bd1deb71 100644 --- a/apps/sequence/list/list_controller.h +++ b/apps/sequence/list/list_controller.h @@ -5,7 +5,7 @@ #include "../sequence_title_cell.h" #include "../sequence_store.h" #include "../../shared/function_expression_cell.h" -#include "../../shared/function_list_controller.h" +#include "../../shared/storage_function_list_controller.h" #include "../../shared/input_event_handler_delegate.h" #include "../../shared/layout_field_delegate.h" #include "../../shared/text_field_delegate.h" @@ -15,24 +15,24 @@ namespace Sequence { -class ListController : public Shared::FunctionListController, public Shared::InputEventHandlerDelegate, public Shared::TextFieldDelegate, public Shared::LayoutFieldDelegate { +class ListController : public Shared::StorageFunctionListController, public Shared::InputEventHandlerDelegate, public Shared::TextFieldDelegate, public Shared::LayoutFieldDelegate { public: - ListController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, ButtonRowController * header, ButtonRowController * footer); + ListController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, ButtonRowController * footer); const char * title() override; int numberOfExpressionRows() override; KDCoordinate expressionRowHeight(int j) override; void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; Toolbox * toolboxForInputEventHandler(InputEventHandler * handler) override; void selectPreviousNewSequenceCell(); - void editExpression(Sequence * sequence, int sequenceDefinitionIndex, Ion::Events::Event event); + void editExpression(int sequenceDefinitionIndex, Ion::Events::Event event); private: static constexpr KDCoordinate k_expressionCellVerticalMargin = 3; - Toolbox * toolboxForSender(InputEventHandler * sender); + bool editInitialConditionOfSelectedRecordWithText(const char * text, bool firstInitialCondition); Shared::TextFieldDelegateApp * textFieldDelegateApp() override; Shared::ExpressionFieldDelegateApp * expressionFieldDelegateApp() override; Shared::InputEventHandlerDelegateApp * inputEventHandlerDelegateApp() override; ListParameterController * parameterController() override; - int maxNumberOfRows() override; + int maxNumberOfDisplayableRows() override; Shared::FunctionTitleCell * titleCells(int index) override; HighlightCell * expressionCells(int index) override; void willDisplayTitleCellAtIndex(HighlightCell * cell, int j) override; @@ -41,12 +41,11 @@ private: bool isAddEmptyRow(int j) override; int sequenceDefinitionForRow(int j); void addEmptyModel() override; - 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; + void reinitSelectedExpression(Shared::ExpiringPointer model) override; + void editExpression(Ion::Events::Event event) override; + bool removeModelRow(Ion::Storage::Record record) override; + SequenceStore * modelStore() override { return static_cast(Shared::StorageFunctionListController::modelStore()); } constexpr static int k_maxNumberOfRows = 3*MaxNumberOfSequences; - SequenceStore * m_sequenceStore; SequenceTitleCell m_sequenceTitleCells[k_maxNumberOfRows]; Shared::FunctionExpressionCell m_expressionCells[k_maxNumberOfRows]; ListParameterController m_parameterController; diff --git a/apps/sequence/list/list_parameter_controller.cpp b/apps/sequence/list/list_parameter_controller.cpp index 6b5ac513b..122bc5492 100644 --- a/apps/sequence/list/list_parameter_controller.cpp +++ b/apps/sequence/list/list_parameter_controller.cpp @@ -9,13 +9,12 @@ using namespace Shared; namespace Sequence { -ListParameterController::ListParameterController(::InputEventHandlerDelegate * inputEventHandlerDelegate, ListController * listController, SequenceStore * sequenceStore) : - Shared::ListParameterController(listController, sequenceStore, I18n::Message::SequenceColor, I18n::Message::DeleteSequence, this), +ListParameterController::ListParameterController(::InputEventHandlerDelegate * inputEventHandlerDelegate, ListController * listController) : + Shared::StorageListParameterController(listController, I18n::Message::SequenceColor, I18n::Message::DeleteSequence, this), m_typeCell(I18n::Message::SequenceType), m_initialRankCell(&m_selectableTableView, inputEventHandlerDelegate, this, m_draftTextBuffer, I18n::Message::FirstTermIndex), - m_typeParameterController(this, sequenceStore, listController, TableCell::Layout::Horizontal, Metric::CommonTopMargin, Metric::CommonRightMargin, - Metric::CommonBottomMargin, Metric::CommonLeftMargin), - m_sequence(nullptr) + m_typeParameterController(this, listController, TableCell::Layout::Horizontal, Metric::CommonTopMargin, Metric::CommonRightMargin, + Metric::CommonBottomMargin, Metric::CommonLeftMargin) { static_cast(m_typeCell.subAccessoryView())->setHorizontalMargin(Metric::ExpressionViewHorizontalMargin); } @@ -24,11 +23,6 @@ const char * ListParameterController::title() { return I18n::translate(I18n::Message::SequenceOptions); } -void ListParameterController::setFunction(Shared::Function * function) { - Shared::ListParameterController::setFunction(function); - m_sequence = (Sequence *)function; -} - bool ListParameterController::handleEvent(Ion::Events::Event event) { bool hasAdditionalRow = hasInitialRankRow(); #if FUNCTION_COLOR_CHOICE @@ -46,7 +40,7 @@ bool ListParameterController::handleEvent(Ion::Events::Event event) { if (selectedRowIndex == 0) { #endif StackViewController * stack = (StackViewController *)(parentResponder()); - m_typeParameterController.setSequence(m_sequence); + m_typeParameterController.setRecord(m_record); stack->push(&m_typeParameterController); return true; } @@ -63,25 +57,13 @@ bool ListParameterController::handleEvent(Ion::Events::Event event) { #else if (selectedRowIndex == 2+hasAdditionalRow) { #endif - if (m_functionStore->numberOfModels() > 0) { - m_functionStore->removeModel(m_function); - static_cast(app())->localContext()->resetCache(); - StackViewController * stack = (StackViewController *)(parentResponder()); - stack->pop(); - return true; - } + static_cast(app())->localContext()->resetCache(); + return handleEnterOnRow(selectedRowIndex-hasAdditionalRow-1); } } return false; } -int ListParameterController::numberOfRows() { - if (hasInitialRankRow()) { - return k_totalNumberOfCell; - } - return k_totalNumberOfCell-1; -}; - HighlightCell * ListParameterController::reusableCell(int index) { switch (index) { /*case 0: @@ -93,27 +75,23 @@ HighlightCell * ListParameterController::reusableCell(int index) { return &m_initialRankCell; } default: - return Shared::ListParameterController::reusableCell(index-1-hasInitialRankRow()); + return Shared::StorageListParameterController::reusableCell(index-1-hasInitialRankRow()); } } -int ListParameterController::reusableCellCount() { - return k_totalNumberOfCell; -} - void ListParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) { cell->setHighlighted(index == selectedRow()); // See FIXME in SelectableTableView::reloadData() - Shared::ListParameterController::willDisplayCellForIndex(cell, index); - if (cell == &m_typeCell && m_sequence != nullptr) { - m_typeCell.setLayout(m_sequence->definitionName()); + Shared::StorageListParameterController::willDisplayCellForIndex(cell, index); + if (cell == &m_typeCell && !m_record.isNull()) { + m_typeCell.setLayout(sequence()->definitionName()); } - if (cell == &m_initialRankCell && m_sequence != nullptr) { + if (cell == &m_initialRankCell && !m_record.isNull()) { MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *) cell; if (myCell->isEditing()) { return; } char buffer[Sequence::k_initialRankNumberOfDigits+1]; - Poincare::Integer(m_sequence->initialRank()).serialize(buffer, Sequence::k_initialRankNumberOfDigits+1); + Poincare::Integer(sequence()->initialRank()).serialize(buffer, Sequence::k_initialRankNumberOfDigits+1); myCell->setAccessoryText(buffer); } } @@ -138,7 +116,7 @@ bool ListParameterController::textFieldDidFinishEditing(TextField * textField, c app()->displayWarning(I18n::Message::ForbiddenValue); return false; } - m_sequence->setInitialRank(index); + sequence()->setInitialRank(index); // Invalidate sequence context cache when changing sequence type static_cast(app())->localContext()->resetCache(); m_selectableTableView.reloadCellAtLocation(0, selectedRow()); @@ -178,8 +156,15 @@ TextFieldDelegateApp * ListParameterController::textFieldDelegateApp() { return (TextFieldDelegateApp *)app(); } -bool ListParameterController::hasInitialRankRow() { - return m_sequence && m_sequence->type() != Sequence::Type::Explicit; +int ListParameterController::totalNumberOfCells() const { + if (hasInitialRankRow()) { + return k_totalNumberOfCell; + } + return k_totalNumberOfCell-1; +}; + +bool ListParameterController::hasInitialRankRow() const { + return !m_record.isNull() && const_cast(this)->sequence()->type() != Sequence::Type::Explicit; } } diff --git a/apps/sequence/list/list_parameter_controller.h b/apps/sequence/list/list_parameter_controller.h index 85e2b510c..803c12b8c 100644 --- a/apps/sequence/list/list_parameter_controller.h +++ b/apps/sequence/list/list_parameter_controller.h @@ -1,7 +1,7 @@ #ifndef SEQUENCE_LIST_PARAM_CONTROLLER_H #define SEQUENCE_LIST_PARAM_CONTROLLER_H -#include "../../shared/list_parameter_controller.h" +#include "../../shared/storage_list_parameter_controller.h" #include "../../shared/parameter_text_field_delegate.h" #include "../sequence.h" #include "../sequence_store.h" @@ -11,15 +11,12 @@ namespace Sequence { class ListController; -class ListParameterController : public Shared::ListParameterController, public SelectableTableViewDelegate, public Shared::ParameterTextFieldDelegate { +class ListParameterController : public Shared::StorageListParameterController, public SelectableTableViewDelegate, public Shared::ParameterTextFieldDelegate { public: - ListParameterController(::InputEventHandlerDelegate * inputEventHandlerDelegate, ListController * list, SequenceStore * sequenceStore); + ListParameterController(::InputEventHandlerDelegate * inputEventHandlerDelegate, ListController * list); const char * title() override; bool handleEvent(Ion::Events::Event event) override; - void setFunction(Shared::Function * function) override; - int numberOfRows() override; HighlightCell * reusableCell(int index) override; - int reusableCellCount() override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; @@ -32,12 +29,13 @@ private: #else constexpr static int k_totalNumberOfCell = 4; #endif - bool hasInitialRankRow(); + int totalNumberOfCells() const override; + Shared::ExpiringPointer sequence() { return static_cast>(function()); } + bool hasInitialRankRow() const; MessageTableCellWithChevronAndExpression m_typeCell; MessageTableCellWithEditableText m_initialRankCell; char m_draftTextBuffer[MessageTableCellWithEditableText::k_bufferLength]; TypeParameterController m_typeParameterController; - Sequence * m_sequence; }; } diff --git a/apps/sequence/list/type_parameter_controller.cpp b/apps/sequence/list/type_parameter_controller.cpp index 75bbd12e0..3fe2e46c8 100644 --- a/apps/sequence/list/type_parameter_controller.cpp +++ b/apps/sequence/list/type_parameter_controller.cpp @@ -7,10 +7,11 @@ #include using namespace Poincare; +using namespace Shared; namespace Sequence { -TypeParameterController::TypeParameterController(Responder * parentResponder, SequenceStore * sequenceStore, ListController * list, TableCell::Layout cellLayout, +TypeParameterController::TypeParameterController(Responder * parentResponder, ListController * list, TableCell::Layout cellLayout, KDCoordinate topMargin, KDCoordinate rightMargin, KDCoordinate bottomMargin, KDCoordinate leftMargin) : ViewController(parentResponder), m_expliciteCell(I18n::Message::Explicit, cellLayout), @@ -18,8 +19,7 @@ TypeParameterController::TypeParameterController(Responder * parentResponder, Se m_doubleRecurenceCell(I18n::Message::DoubleRecurrence, cellLayout), m_layouts{}, m_selectableTableView(this), - m_sequenceStore(sequenceStore), - m_sequence(nullptr), + m_record(), m_listController(list) { m_selectableTableView.setMargins(topMargin, rightMargin, bottomMargin, leftMargin); @@ -27,10 +27,10 @@ TypeParameterController::TypeParameterController(Responder * parentResponder, Se } const char * TypeParameterController::title() { - if (m_sequence) { - return I18n::translate(I18n::Message::SequenceType); + if (m_record.isNull()) { + return I18n::translate(I18n::Message::ChooseSequenceType); } - return I18n::translate(I18n::Message::ChooseSequenceType); + return I18n::translate(I18n::Message::SequenceType); } View * TypeParameterController::view() { @@ -54,16 +54,16 @@ void TypeParameterController::didBecomeFirstResponder() { bool TypeParameterController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { - if (m_sequence) { + if (!m_record.isNull()) { Sequence::Type sequenceType = (Sequence::Type)selectedRow(); - if (m_sequence->type() != sequenceType) { + if (sequence()->type() != sequenceType) { m_listController->selectPreviousNewSequenceCell(); - m_sequence->setType(sequenceType); + sequence()->setType(sequenceType); // Invalidate sequence context cache when changing sequence type static_cast(app())->localContext()->resetCache(); // Reset the first index if the new type is "Explicit" if (sequenceType == Sequence::Type::Explicit) { - m_sequence->setInitialRank(0); + sequence()->setInitialRank(0); } } StackViewController * stack = stackController(); @@ -72,13 +72,20 @@ bool TypeParameterController::handleEvent(Ion::Events::Event event) { stack->pop(); return true; } - Sequence * newSequence = static_cast(m_sequenceStore->addEmptyModel()); + + Ion::Storage::Record::ErrorStatus error = sequenceStore()->addEmptyModel(); + if (error == Ion::Storage::Record::ErrorStatus::NotEnoughSpaceAvailable) { + return false; + } + assert(error == Ion::Storage::Record::ErrorStatus::None); + Ion::Storage::Record record = sequenceStore()->recordAtIndex(sequenceStore()->numberOfModels()-1); + ExpiringPointer newSequence = sequenceStore()->modelForRecord(record); newSequence->setType((Sequence::Type)selectedRow()); app()->dismissModalViewController(); - m_listController->editExpression(newSequence, 0, Ion::Events::OK); + m_listController->editExpression(0, Ion::Events::OK); return true; } - if (event == Ion::Events::Left && m_sequence) { + if (event == Ion::Events::Left && !m_record.isNull()) { stackController()->pop(); return true; } @@ -101,17 +108,17 @@ int TypeParameterController::reusableCellCount() { } KDCoordinate TypeParameterController::cellHeight() { - if (m_sequence) { - return Metric::ParameterCellHeight; + if (m_record.isNull()) { + return 50; } - return 50; + return Metric::ParameterCellHeight; } void TypeParameterController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) { - const char * nextName = m_sequenceStore->firstAvailableName(); + const char * nextName = sequenceStore()->firstAvailableName(); const KDFont * font = KDFont::LargeFont; - if (m_sequence) { - nextName = m_sequence->name(); + if (!m_record.isNull()) { + nextName = sequence()->fullName(); font = KDFont::SmallFont; } const char * subscripts[3] = {"n", "n+1", "n+2"}; @@ -123,8 +130,13 @@ void TypeParameterController::willDisplayCellAtLocation(HighlightCell * cell, in myCell->setLayout(m_layouts[j]); } -void TypeParameterController::setSequence(Sequence * sequence) { - m_sequence = sequence; +void TypeParameterController::setRecord(Ion::Storage::Record record) { + m_record = record; +} + +SequenceStore * TypeParameterController::sequenceStore() { + App * a = static_cast(app()); + return a->functionStore(); } StackViewController * TypeParameterController::stackController() const { diff --git a/apps/sequence/list/type_parameter_controller.h b/apps/sequence/list/type_parameter_controller.h index c2eef8b91..2dbd318e0 100644 --- a/apps/sequence/list/type_parameter_controller.h +++ b/apps/sequence/list/type_parameter_controller.h @@ -11,7 +11,7 @@ class ListController; class TypeParameterController : public ViewController, public SimpleListViewDataSource, public SelectableTableViewDataSource { public: - TypeParameterController(Responder * parentResponder, SequenceStore * sequenceStore, ListController * list, + TypeParameterController(Responder * parentResponder, ListController * list, TableCell::Layout cellLayout, KDCoordinate topMargin = 0, KDCoordinate rightMargin = 0, KDCoordinate bottomMargin = 0, KDCoordinate leftMargin = 0); const char * title() override; @@ -25,17 +25,21 @@ public: HighlightCell * reusableCell(int index) override; int reusableCellCount() override; void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; - void setSequence(Sequence * sequence); + void setRecord(Ion::Storage::Record record); private: StackViewController * stackController() const; + Shared::ExpiringPointer sequence() { + assert(!m_record.isNull()); + return sequenceStore()->modelForRecord(m_record); + } + SequenceStore * sequenceStore(); constexpr static int k_totalNumberOfCell = 3; ExpressionTableCellWithPointer m_expliciteCell; ExpressionTableCellWithPointer m_singleRecurrenceCell; ExpressionTableCellWithPointer m_doubleRecurenceCell; Poincare::Layout m_layouts[k_totalNumberOfCell]; SelectableTableView m_selectableTableView; - SequenceStore * m_sequenceStore; - Sequence * m_sequence; + Ion::Storage::Record m_record; ListController * m_listController; }; diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index e195b2fae..4192ca9f9 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -14,9 +14,6 @@ namespace Sequence { class Sequence : public Shared::StorageFunction { friend class SequenceStore; public: - static constexpr char extension[] = "seq"; // TODO: store this elsewhere? - - enum class Type { Explicit = 0, SingleRecurrence = 1, diff --git a/apps/sequence/sequence_context.cpp b/apps/sequence/sequence_context.cpp index 193dc9b98..76d20b3a5 100644 --- a/apps/sequence/sequence_context.cpp +++ b/apps/sequence/sequence_context.cpp @@ -3,6 +3,7 @@ #include using namespace Poincare; +using namespace Shared; namespace Sequence { @@ -49,22 +50,22 @@ void TemplatedSequenceContext::step(SequenceStore * sequenceStore, SequenceCo } /* Evaluate new u(n) and v(n) */ - Sequence * u = sequenceStore->numberOfModels() > 0 ? sequenceStore->modelAtIndex(0) : nullptr; - u = u && u->isDefined() ? u : nullptr; - Sequence * v = sequenceStore->numberOfModels() > 1 ? sequenceStore->modelAtIndex(1) : nullptr; - v = v && v->isDefined() ? v : nullptr; + ExpiringPointer u = sequenceStore->numberOfModels() > 0 ? sequenceStore->modelForRecord(sequenceStore->recordAtIndex(0)) : nullptr; + u = u.isNull() && u->isDefined() ? u : nullptr; + ExpiringPointer v = sequenceStore->numberOfModels() > 1 ? sequenceStore->modelForRecord(sequenceStore->recordAtIndex(1)) : nullptr; + v = v.isNull() && v->isDefined() ? v : nullptr; /* Switch u & v if the name of u is v */ - if (u != nullptr && u->name()[0] == SequenceStore::k_sequenceNames[1][0]) { - Sequence * temp = u; + if (!u.isNull() && u->fullName()[0] == SequenceStore::k_sequenceNames[1][0]) { + ExpiringPointer temp = u; u = v; v = temp; } /* Approximate u & v at the new rank. We evaluate u twice in case its * expression depends on v. */ - m_values[0][0] = u ? u->approximateToNextRank(m_rank, sqctx) : NAN; - m_values[1][0] = v ? v->approximateToNextRank(m_rank, sqctx) : NAN; - m_values[0][0] = u ? u->approximateToNextRank(m_rank, sqctx) : NAN; + m_values[0][0] = !u.isNull() ? u->approximateToNextRank(m_rank, sqctx) : NAN; + m_values[1][0] = !v.isNull() ? v->approximateToNextRank(m_rank, sqctx) : NAN; + m_values[0][0] = !u.isNull() ? u->approximateToNextRank(m_rank, sqctx) : NAN; } template class TemplatedSequenceContext; diff --git a/apps/sequence/sequence_store.cpp b/apps/sequence/sequence_store.cpp index 157d9cf19..718a3e3d3 100644 --- a/apps/sequence/sequence_store.cpp +++ b/apps/sequence/sequence_store.cpp @@ -9,23 +9,32 @@ namespace Sequence { constexpr const char * SequenceStore::k_sequenceNames[MaxNumberOfSequences]; -Ion::Storage::Record::ErrorStatus SequenceStore::addEmptyModel() { +const char * SequenceStore::firstAvailableName(int * nameIndex) { // Choose available name - const char * name; int currentNameIndex = 0; while (currentNameIndex < MaxNumberOfSequences) { - name = k_sequenceNames[currentNameIndex]; - if (Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(name, Sequence::extension).isNull()) { - break; + const char * name = k_sequenceNames[currentNameIndex]; + if (Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(name, Shared::GlobalContext::seqExtension).isNull()) { + if (nameIndex) { + *nameIndex = currentNameIndex; + } + return name; } currentNameIndex++; } - assert(currentNameIndex < MaxNumberOfSequences); + return nullptr; +} + +Ion::Storage::Record::ErrorStatus SequenceStore::addEmptyModel() { + // Choose available name + int nameIndex; + const char * name = firstAvailableName(&nameIndex); + assert(name); // Choose the corresponding color - KDColor color = Palette::DataColor[currentNameIndex]; + KDColor color = Palette::DataColor[nameIndex]; Sequence::SequenceRecordData data(color); // m_sequences - return Ion::Storage::sharedStorage()->createRecordWithExtension(name, Sequence::extension, &data, sizeof(data)); + return Ion::Storage::sharedStorage()->createRecordWithExtension(name, modelExtension(), &data, sizeof(data)); } void SequenceStore::setMemoizedModelAtIndex(int cacheIndex, Ion::Storage::Record record) const { diff --git a/apps/sequence/sequence_store.h b/apps/sequence/sequence_store.h index ce952f4fe..4082de393 100644 --- a/apps/sequence/sequence_store.h +++ b/apps/sequence/sequence_store.h @@ -2,6 +2,7 @@ #define SEQUENCE_SEQUENCE_STORE_H #include "../shared/storage_function_store.h" +#include "../shared/global_context.h" #include "sequence.h" #include #include @@ -13,18 +14,19 @@ public: using Shared::StorageFunctionStore::StorageFunctionStore; char symbol() const override { return Sequence::Symbol(); } Shared::ExpiringPointer modelForRecord(Ion::Storage::Record record) const { return Shared::ExpiringPointer(static_cast(privateModelForRecord(record))); } + Ion::Storage::Record::ErrorStatus addEmptyModel() override; /* WARNING: after calling removeModel or removeAll, the sequence context * need to invalidate its cache as the sequences evaluations might have * changed */ int maxNumberOfModels() const override { return MaxNumberOfSequences; } + static const char * firstAvailableName(int * nameIndex = nullptr); static constexpr const char * k_sequenceNames[MaxNumberOfSequences] = { "u", "v"//, "w" }; private: - const char * modelExtension() const override { return Sequence::extension; } - Ion::Storage::Record::ErrorStatus addEmptyModel() override; + const char * modelExtension() const override { return Shared::GlobalContext::seqExtension; } /* We don't really use model memoization as the number of Sequence is limited * and we keep enough Sequences to store them all. */ void setMemoizedModelAtIndex(int cacheIndex, Ion::Storage::Record record) const override; diff --git a/apps/sequence/values/values_controller.cpp b/apps/sequence/values/values_controller.cpp index a71f3406e..653444660 100644 --- a/apps/sequence/values/values_controller.cpp +++ b/apps/sequence/values/values_controller.cpp @@ -6,11 +6,10 @@ using namespace Shared; namespace Sequence { -ValuesController::ValuesController(Responder * parentResponder,InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, Interval * interval, ButtonRowController * header) : - Shared::ValuesController(parentResponder, inputEventHandlerDelegate, header, I18n::Message::NColumn, &m_intervalParameterController, interval), +ValuesController::ValuesController(Responder * parentResponder,InputEventHandlerDelegate * inputEventHandlerDelegate, Interval * interval, ButtonRowController * header) : + Shared::StorageValuesController(parentResponder, inputEventHandlerDelegate, header, I18n::Message::NColumn, &m_intervalParameterController, interval), m_sequenceTitleCells{}, m_floatCells{}, - m_sequenceStore(sequenceStore), #if COPY_COLUMN m_sequenceParameterController('n'), #endif @@ -22,7 +21,7 @@ ValuesController::ValuesController(Responder * parentResponder,InputEventHandler } void ValuesController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) { - Shared::ValuesController::willDisplayCellAtLocation(cell, i, j); + Shared::StorageValuesController::willDisplayCellAtLocation(cell, i, j); // The cell is the abscissa title cell: if (j == 0 && i == 0) { EvenOddMessageTextCell * mytitleCell = (EvenOddMessageTextCell *)cell; @@ -32,14 +31,14 @@ void ValuesController::willDisplayCellAtLocation(HighlightCell * cell, int i, in // The cell is a function title cell: if (j == 0 && i > 0) { SequenceTitleCell * myCell = (SequenceTitleCell *)cell; - Sequence * sequence = m_sequenceStore->activeFunctionAtIndex(i-1); + Shared::ExpiringPointer sequence = functionStore()->modelForRecord(recordAtColumn(i)); myCell->setLayout(sequence->nameLayout()); myCell->setColor(sequence->color()); } } I18n::Message ValuesController::emptyMessage() { - if (m_sequenceStore->numberOfDefinedModels() == 0) { + if (functionStore()->numberOfDefinedModels() == 0) { return I18n::Message::NoSequence; } return I18n::Message::NoActivatedSequence; @@ -53,7 +52,7 @@ bool ValuesController::setDataAtLocation(double floatBody, int columnIndex, int if (floatBody < 0) { return false; } - return Shared::ValuesController::setDataAtLocation(std::round(floatBody), columnIndex, rowIndex); + return Shared::StorageValuesController::setDataAtLocation(std::round(floatBody), columnIndex, rowIndex); } int ValuesController::maxNumberOfCells() { @@ -74,11 +73,7 @@ EvenOddBufferTextCell * ValuesController::floatCells(int j) { return &m_floatCells[j]; } -SequenceStore * ValuesController::functionStore() const { - return m_sequenceStore; -} - -Shared::ValuesFunctionParameterController * ValuesController::functionParameterController() { +Shared::StorageValuesFunctionParameterController * ValuesController::functionParameterController() { #if COPY_COLUMN return &m_sequenceParameterController; #else diff --git a/apps/sequence/values/values_controller.h b/apps/sequence/values/values_controller.h index 583aac8bb..3f4902f07 100644 --- a/apps/sequence/values/values_controller.h +++ b/apps/sequence/values/values_controller.h @@ -3,14 +3,14 @@ #include "../sequence_store.h" #include "../sequence_title_cell.h" -#include "../../shared/values_controller.h" +#include "../../shared/storage_values_controller.h" #include "interval_parameter_controller.h" namespace Sequence { -class ValuesController : public Shared::ValuesController { +class ValuesController : public Shared::StorageValuesController { public: - ValuesController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, Shared::Interval * interval, ButtonRowController * header); + ValuesController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::Interval * interval, ButtonRowController * header); void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; I18n::Message emptyMessage() override; IntervalParameterController * intervalParameterController() override; @@ -24,12 +24,11 @@ private: SequenceTitleCell * functionTitleCells(int j) override; EvenOddBufferTextCell m_floatCells[k_maxNumberOfCells]; EvenOddBufferTextCell * floatCells(int j) override; - SequenceStore * m_sequenceStore; - SequenceStore * functionStore() const override; + SequenceStore * functionStore() const override { return static_cast(Shared::StorageValuesController::functionStore()); } #if COPY_COLUMN Shared::ValuesFunctionParameterController m_sequenceParameterController; #endif - Shared::ValuesFunctionParameterController * functionParameterController() override; + Shared::StorageValuesFunctionParameterController * functionParameterController() override; IntervalParameterController m_intervalParameterController; }; diff --git a/apps/shared/global_context.cpp b/apps/shared/global_context.cpp index 336945f11..48386b2a5 100644 --- a/apps/shared/global_context.cpp +++ b/apps/shared/global_context.cpp @@ -12,7 +12,7 @@ namespace Shared { constexpr char GlobalContext::expExtension[]; constexpr char GlobalContext::funcExtension[]; -//constexpr char GlobalContext::seqExtension[]; +constexpr char GlobalContext::seqExtension[]; constexpr const char * GlobalContext::k_extensions[]; bool GlobalContext::SymbolAbstractNameIsFree(const char * baseName) { diff --git a/apps/shared/global_context.h b/apps/shared/global_context.h index d94ac7d0a..10a0c8d09 100644 --- a/apps/shared/global_context.h +++ b/apps/shared/global_context.h @@ -11,15 +11,13 @@ namespace Shared { -class Integer; - class GlobalContext final : public Poincare::Context { public: static constexpr int k_numberOfExtensions = 2; static constexpr char expExtension[] = "exp"; // TODO: store this elsewhere? static constexpr char funcExtension[] = "func"; // TODO: store this elsewhere? static constexpr const char * k_extensions[] = {expExtension, funcExtension}; - //static constexpr char seqExtension[] = "seq"; + static constexpr char seqExtension[] = "seq"; // Storage information static bool SymbolAbstractNameIsFree(const char * baseName); diff --git a/apps/shared/storage_function_list_controller.cpp b/apps/shared/storage_function_list_controller.cpp index d989de397..e2f379e4e 100644 --- a/apps/shared/storage_function_list_controller.cpp +++ b/apps/shared/storage_function_list_controller.cpp @@ -318,7 +318,7 @@ KDCoordinate StorageFunctionListController::nameWidth(int nameLength) const { } KDCoordinate StorageFunctionListController::privateBaseline(int j) const { - assert(j >= 0 && j < const_cast(this)->modelStore()->numberOfModels()); + assert(j >= 0 && j < const_cast(this)->numberOfExpressionRows()); FunctionExpressionCell * cell = static_cast((const_cast(&m_selectableTableView))->cellAtLocation(1, j)); Poincare::Layout layout = cell->layout(); if (layout.isUninitialized()) { diff --git a/apps/shared/storage_list_parameter_controller.h b/apps/shared/storage_list_parameter_controller.h index 35b56ffdd..88e61fb73 100644 --- a/apps/shared/storage_list_parameter_controller.h +++ b/apps/shared/storage_list_parameter_controller.h @@ -31,11 +31,11 @@ protected: return 2; #endif } + StorageFunctionStore * functionStore(); + ExpiringPointer function(); SelectableTableView m_selectableTableView; Ion::Storage::Record m_record; private: - ExpiringPointer function(); - StorageFunctionStore * functionStore(); #if FUNCTION_COLOR_CHOICE MessageTableCellWithChevron m_colorCell; #endif diff --git a/apps/shared/storage_values_controller.h b/apps/shared/storage_values_controller.h index fa345d8e6..0e5219a86 100644 --- a/apps/shared/storage_values_controller.h +++ b/apps/shared/storage_values_controller.h @@ -47,12 +47,12 @@ protected: bool setDataAtLocation(double floatBody, int columnIndex, int rowIndex) override; virtual void updateNumberOfColumns(); virtual StorageFunctionStore * functionStore() const; + virtual Ion::Storage::Record recordAtColumn(int i); Interval * m_interval; int m_numberOfColumns; bool m_numberOfColumnsNeedUpdate; private: static constexpr const KDFont * k_font = KDFont::SmallFont; - virtual Ion::Storage::Record recordAtColumn(int i); Responder * tabController() const override; SelectableTableView * selectableTableView() override { return &m_selectableTableView; } void configureAbscissa();