[apps/sequence] Make controllers inherit from StorageFunction controllers when required

This commit is contained in:
Émilie Feral
2019-02-28 14:51:22 +01:00
parent 184d2f0802
commit 2bc2506b60
29 changed files with 270 additions and 285 deletions

View File

@@ -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),

View File

@@ -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<SequenceStore *>(Shared::StorageFunctionApp::functionStore()); }
private:
App(Container * container, Snapshot * snapshot);
SequenceContext m_sequenceContext;

View File

@@ -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)

View File

@@ -2,14 +2,14 @@
#define SEQUENCE_CURVE_PARAMETER_CONTROLLER_H
#include <escher.h>
#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;

View File

@@ -1,5 +1,4 @@
#include "go_to_parameter_controller.h"
#include "../app.h"
#include <assert.h>
#include <cmath>
@@ -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));
}
}

View File

@@ -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;
};

View File

@@ -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<Sequence> 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<Sequence> 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<Sequence> 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());
}
}

View File

@@ -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<SequenceStore *>(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;
};

View File

@@ -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<Sequence> 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);

View File

@@ -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);

View File

@@ -1,6 +1,5 @@
#include "term_sum_controller.h"
#include "../../shared/text_field_delegate.h"
#include "../app.h"
#include <poincare/code_point_layout.h>
#include <poincare/horizontal_layout.h>
#include <poincare/vertical_offset_layout.h>
@@ -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<Shared::StorageFunction> function) {
Shared::ExpiringPointer<Sequence> sequence = static_cast<Shared::ExpiringPointer<Sequence>>(function);
return sequence->nameLayout();
}
}

View File

@@ -5,11 +5,11 @@
#include <poincare/layout.h>
#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<Shared::StorageFunction> function) override;
};
}

View File

@@ -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> 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> 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> 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> 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 *>(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<ListController *>(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<ListController *>(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<ListController *>(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 *>(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> 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> 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> 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> 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> 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<Sequence *>(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<SingleExpressionModelHandle> model) {
// Invalidate the sequences context cache
static_cast<App *>(app())->localContext()->resetCache();
Sequence * sequence = static_cast<Sequence *>(model);
ExpiringPointer<Sequence> sequence = static_cast<ExpiringPointer<Sequence>>(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<k_maxNumberOfRows);
Shared::FunctionExpressionCell * cell = static_cast<Shared::FunctionExpressionCell *>((const_cast<SelectableTableView *>(&m_selectableTableView))->cellAtLocation(1, j));
Poincare::Layout layout = cell->layout();
if (layout.isUninitialized()) {
return 0.5*const_cast<ListController *>(this)->rowHeight(j);
}
return 0.5*(const_cast<ListController *>(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 *>(app())->localContext()->resetCache();
return true;
}
}

View File

@@ -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<Shared::SingleExpressionModelHandle> model) override;
void editExpression(Ion::Events::Event event) override;
bool removeModelRow(Ion::Storage::Record record) override;
SequenceStore * modelStore() override { return static_cast<SequenceStore *>(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;

View File

@@ -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<ExpressionView *>(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 *>(app())->localContext()->resetCache();
StackViewController * stack = (StackViewController *)(parentResponder());
stack->pop();
return true;
}
static_cast<App *>(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 *>(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<ListParameterController *>(this)->sequence()->type() != Sequence::Type::Explicit;
}
}

View File

@@ -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> sequence() { return static_cast<Shared::ExpiringPointer<Sequence>>(function()); }
bool hasInitialRankRow() const;
MessageTableCellWithChevronAndExpression m_typeCell;
MessageTableCellWithEditableText m_initialRankCell;
char m_draftTextBuffer[MessageTableCellWithEditableText::k_bufferLength];
TypeParameterController m_typeParameterController;
Sequence * m_sequence;
};
}

View File

@@ -7,10 +7,11 @@
#include <poincare/vertical_offset_layout.h>
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 *>(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<Sequence *>(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<Sequence> 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 *>(app());
return a->functionStore();
}
StackViewController * TypeParameterController::stackController() const {

View File

@@ -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> 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;
};

View File

@@ -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,

View File

@@ -3,6 +3,7 @@
#include <cmath>
using namespace Poincare;
using namespace Shared;
namespace Sequence {
@@ -49,22 +50,22 @@ void TemplatedSequenceContext<T>::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<Sequence> u = sequenceStore->numberOfModels() > 0 ? sequenceStore->modelForRecord(sequenceStore->recordAtIndex(0)) : nullptr;
u = u.isNull() && u->isDefined() ? u : nullptr;
ExpiringPointer<Sequence> 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<Sequence> 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<T>(m_rank, sqctx) : NAN;
m_values[1][0] = v ? v->approximateToNextRank<T>(m_rank, sqctx) : NAN;
m_values[0][0] = u ? u->approximateToNextRank<T>(m_rank, sqctx) : NAN;
m_values[0][0] = !u.isNull() ? u->approximateToNextRank<T>(m_rank, sqctx) : NAN;
m_values[1][0] = !v.isNull() ? v->approximateToNextRank<T>(m_rank, sqctx) : NAN;
m_values[0][0] = !u.isNull() ? u->approximateToNextRank<T>(m_rank, sqctx) : NAN;
}
template class TemplatedSequenceContext<float>;

View File

@@ -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 {

View File

@@ -2,6 +2,7 @@
#define SEQUENCE_SEQUENCE_STORE_H
#include "../shared/storage_function_store.h"
#include "../shared/global_context.h"
#include "sequence.h"
#include <stdint.h>
#include <escher.h>
@@ -13,18 +14,19 @@ public:
using Shared::StorageFunctionStore::StorageFunctionStore;
char symbol() const override { return Sequence::Symbol(); }
Shared::ExpiringPointer<Sequence> modelForRecord(Ion::Storage::Record record) const { return Shared::ExpiringPointer<Sequence>(static_cast<Sequence *>(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;

View File

@@ -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> 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

View File

@@ -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<SequenceStore *>(Shared::StorageValuesController::functionStore()); }
#if COPY_COLUMN
Shared::ValuesFunctionParameterController m_sequenceParameterController;
#endif
Shared::ValuesFunctionParameterController * functionParameterController() override;
Shared::StorageValuesFunctionParameterController * functionParameterController() override;
IntervalParameterController m_intervalParameterController;
};

View File

@@ -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) {

View File

@@ -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);

View File

@@ -318,7 +318,7 @@ KDCoordinate StorageFunctionListController::nameWidth(int nameLength) const {
}
KDCoordinate StorageFunctionListController::privateBaseline(int j) const {
assert(j >= 0 && j < const_cast<StorageFunctionListController *>(this)->modelStore()->numberOfModels());
assert(j >= 0 && j < const_cast<StorageFunctionListController *>(this)->numberOfExpressionRows());
FunctionExpressionCell * cell = static_cast<Shared::FunctionExpressionCell *>((const_cast<SelectableTableView *>(&m_selectableTableView))->cellAtLocation(1, j));
Poincare::Layout layout = cell->layout();
if (layout.isUninitialized()) {

View File

@@ -31,11 +31,11 @@ protected:
return 2;
#endif
}
StorageFunctionStore * functionStore();
ExpiringPointer<StorageFunction> function();
SelectableTableView m_selectableTableView;
Ion::Storage::Record m_record;
private:
ExpiringPointer<StorageFunction> function();
StorageFunctionStore * functionStore();
#if FUNCTION_COLOR_CHOICE
MessageTableCellWithChevron m_colorCell;
#endif

View File

@@ -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();