diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 510cab5e7..255c90133 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -20,29 +20,23 @@ AppsContainer::AppsContainer() : m_batteryTimer(BatteryTimer(this)), m_USBTimer(USBTimer(this)), m_suspendTimer(SuspendTimer(this)), - m_backlightDimmingTimer(BacklightDimmingTimer()) + m_backlightDimmingTimer(BacklightDimmingTimer()), + m_hardwareTestSnapshot(), + m_onBoardingSnapshot(), + m_homeSnapshot(), + m_calculationSnapshot(), + m_graphSnapshot(), + m_sequenceSnapshot(), + m_settingsSnapshot(), + m_statisticsSnapshot(), + m_probabilitySnapshot(), + m_regressionSnapshot() { - m_descriptors[0] = Home::App::buildDescriptor(); - m_descriptors[1] = Calculation::App::buildDescriptor(); - m_descriptors[2] = Graph::App::buildDescriptor(); - m_descriptors[3] = Sequence::App::buildDescriptor(); - m_descriptors[4] = Settings::App::buildDescriptor(); - m_descriptors[5] = Statistics::App::buildDescriptor(); - m_descriptors[6] = Probability::App::buildDescriptor(); - m_descriptors[7] = Regression::App::buildDescriptor(); - m_descriptors[8] = OnBoarding::App::buildDescriptor(); - m_descriptors[9] = HardwareTest::App::buildDescriptor(); refreshPreferences(); m_emptyBatteryWindow.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); Poincare::Expression::setCircuitBreaker(AppsContainer::poincareCircuitBreaker); } -AppsContainer::~AppsContainer() { - for (int i = 0; i < k_totalNumberOfApps; i++) { - delete m_descriptors[i]; - } -} - bool AppsContainer::poincareCircuitBreaker(const Poincare::Expression * e) { Ion::Keyboard::State state = Ion::Keyboard::scan(); return Ion::Keyboard::keyDown(Ion::Keyboard::Key::A6, state); @@ -52,22 +46,38 @@ int AppsContainer::numberOfApps() { return k_numberOfCommonApps; } -App::Descriptor * AppsContainer::appDescriptorAtIndex(int index) { +App::Snapshot * AppsContainer::appSnapshotAtIndex(int index) { + if (index < 0) { + return nullptr; + } + App::Snapshot * snapshots[] = { + &m_homeSnapshot, + &m_calculationSnapshot, + &m_graphSnapshot, + &m_sequenceSnapshot, + &m_settingsSnapshot, + &m_statisticsSnapshot, + &m_probabilitySnapshot, + &m_regressionSnapshot, + }; + assert(sizeof(snapshots)/sizeof(snapshots[0]) == k_numberOfCommonApps); assert(index >= 0 && index < k_numberOfCommonApps); - return m_descriptors[index]; + return snapshots[index]; } -App::Descriptor * AppsContainer::hardwareTestAppDescriptor() { - return m_descriptors[k_totalNumberOfApps-1]; +App::Snapshot * AppsContainer::hardwareTestAppSnapshot() { + return &m_hardwareTestSnapshot; } -App::Descriptor * AppsContainer::onBoardingAppDescriptor() { - return m_descriptors[k_totalNumberOfApps - 2]; +App::Snapshot * AppsContainer::onBoardingAppSnapshot() { + return &m_onBoardingSnapshot; } void AppsContainer::reset() { Clipboard::sharedClipboard()->reset(); - //TODO: persitence->reset() + for (int i = 0; i < k_numberOfCommonApps; i++) { + appSnapshotAtIndex(i)->reset(); + } } Poincare::Context * AppsContainer::globalContext() { @@ -83,7 +93,7 @@ VariableBoxController * AppsContainer::variableBoxController() { } void AppsContainer::suspend(bool checkIfPowerKeyReleased) { - if (activeApp()->descriptor() != onBoardingAppDescriptor() && GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp()) { + if (activeApp()->snapshot()!= onBoardingAppSnapshot() && GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp()) { activeApp()->displayModalViewController(&m_updateController, 0.f, 0.f); } Ion::Power::suspend(checkIfPowerKeyReleased); @@ -103,12 +113,12 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) { bool alphaLockWantsRedraw = m_window.updateAlphaLock(); // Home and Power buttons are not sent to apps. We handle them straight away. - if (event == Ion::Events::Home && activeApp()->descriptor() != onBoardingAppDescriptor() && activeApp()->descriptor() != hardwareTestAppDescriptor() && activeApp()->descriptor() != appDescriptorAtIndex(0)) { - switchTo(appDescriptorAtIndex(0)); + if (event == Ion::Events::Home && activeApp()->snapshot() != onBoardingAppSnapshot() && activeApp()->snapshot() != hardwareTestAppSnapshot()) { + switchTo(appSnapshotAtIndex(0)); return true; } - if (event == Ion::Events::OnOff && activeApp()->descriptor() != hardwareTestAppDescriptor()) { - if (activeApp()->descriptor() == onBoardingAppDescriptor()) { + if (event == Ion::Events::OnOff && activeApp()->snapshot() != hardwareTestAppSnapshot()) { + if (activeApp()->snapshot() == onBoardingAppSnapshot()) { ((OnBoarding::App *)activeApp())->reinitOnBoarding(); } suspend(true); @@ -116,7 +126,7 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) { } bool didProcessEvent = Container::dispatchEvent(event); if (!didProcessEvent && event == Ion::Events::Back) { - switchTo(appDescriptorAtIndex(0)); + switchTo(appSnapshotAtIndex(0)); return true; } if (!didProcessEvent && alphaLockWantsRedraw) { @@ -126,17 +136,17 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) { return didProcessEvent; } -void AppsContainer::switchTo(App::Descriptor * descriptor) { - if (descriptor == hardwareTestAppDescriptor() || descriptor == onBoardingAppDescriptor()) { +void AppsContainer::switchTo(App::Snapshot * snapshot) { + if (snapshot == hardwareTestAppSnapshot() || snapshot == onBoardingAppSnapshot()) { m_window.hideTitleBarView(true); } else { m_window.hideTitleBarView(false); } - if (descriptor) { - m_window.setTitle(descriptor->upperName()); + if (snapshot) { + m_window.setTitle(snapshot->descriptor()->upperName()); } - Container::switchTo(descriptor); - if (activeApp()->descriptor() == onBoardingAppDescriptor()) { + Container::switchTo(snapshot); + if (activeApp() != nullptr && activeApp()->snapshot() == onBoardingAppSnapshot()) { ((OnBoarding::App *)activeApp())->reinitOnBoarding(); } } @@ -178,12 +188,12 @@ Window * AppsContainer::window() { } int AppsContainer::numberOfTimers() { - bool onBoardingTimer = activeApp()->descriptor() == onBoardingAppDescriptor() && ((OnBoarding::App *)activeApp())->hasTimer(); + bool onBoardingTimer = activeApp()->snapshot() == onBoardingAppSnapshot() && ((OnBoarding::App *)activeApp())->hasTimer(); return 4+(GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) + onBoardingTimer; } Timer * AppsContainer::timerAtIndex(int i) { - bool onBoardingTimer = activeApp()->descriptor() == onBoardingAppDescriptor() && ((OnBoarding::App *)activeApp())->hasTimer(); + bool onBoardingTimer = activeApp()->snapshot() == onBoardingAppSnapshot() && ((OnBoarding::App *)activeApp())->hasTimer(); if (onBoardingTimer && i == 4) { return ((OnBoarding::App *)activeApp())->timer(); } diff --git a/apps/apps_container.h b/apps/apps_container.h index 7dd01c73e..6ea3d70b5 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -5,13 +5,13 @@ #include "graph/app.h" #include "probability/app.h" #include "calculation/app.h" -#include "hardware_test/app.h" -#include "on_boarding/app.h" -#include "on_boarding/update_controller.h" #include "regression/app.h" #include "sequence/app.h" #include "settings/app.h" #include "statistics/app.h" +#include "on_boarding/app.h" +#include "hardware_test/app.h" +#include "on_boarding/update_controller.h" #include "apps_window.h" #include "empty_battery_window.h" #include "math_toolbox.h" @@ -31,29 +31,18 @@ class AppsContainer : public Container { public: AppsContainer(); - ~AppsContainer(); - /* Rule of 5: the copy constructor, move constructor, copy assignment - * operator and move assignment operator are deleted as their default - * implementation does not create new apps. The new object thus become - * obsolete as soon as the copy is deleted (because of our - * implementation of deletion). To avoid any use of obsolete object, - * we prevent to copy and assign. */ - AppsContainer(const AppsContainer& other) = delete; - AppsContainer(AppsContainer&& other) = delete; - AppsContainer& operator=(const AppsContainer& other) = delete; - AppsContainer& operator=(AppsContainer&& other) = delete; static bool poincareCircuitBreaker(const Poincare::Expression * e); int numberOfApps(); - App::Descriptor * appDescriptorAtIndex(int index); - App::Descriptor * hardwareTestAppDescriptor(); - App::Descriptor * onBoardingAppDescriptor(); + App::Snapshot * appSnapshotAtIndex(int index); + App::Snapshot * hardwareTestAppSnapshot(); + App::Snapshot * onBoardingAppSnapshot(); void reset(); Poincare::Context * globalContext(); MathToolbox * mathToolbox(); VariableBoxController * variableBoxController(); void suspend(bool checkIfPowerKeyReleased = false); virtual bool dispatchEvent(Ion::Events::Event event) override; - void switchTo(App::Descriptor * descriptor) override; + void switchTo(App::Snapshot * snapshot) override; void updateBatteryState(); void refreshPreferences(); void displayExamModePopUp(bool activate); @@ -81,7 +70,16 @@ private: USBTimer m_USBTimer; SuspendTimer m_suspendTimer; BacklightDimmingTimer m_backlightDimmingTimer; - App::Descriptor * m_descriptors[k_totalNumberOfApps]; + HardwareTest::App::Snapshot m_hardwareTestSnapshot; + OnBoarding::App::Snapshot m_onBoardingSnapshot; + Home::App::Snapshot m_homeSnapshot; + Calculation::App::Snapshot m_calculationSnapshot; + Graph::App::Snapshot m_graphSnapshot; + Sequence::App::Snapshot m_sequenceSnapshot; + Settings::App::Snapshot m_settingsSnapshot; + Statistics::App::Snapshot m_statisticsSnapshot; + Probability::App::Snapshot m_probabilitySnapshot; + Regression::App::Snapshot m_regressionSnapshot; }; #endif diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index 2d3bd0b36..1ad45263a 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -2,16 +2,13 @@ #include "../apps_container.h" #include "calculation_icon.h" #include "../i18n.h" + using namespace Poincare; using namespace Shared; namespace Calculation { -App * App::Descriptor::build(Container * container) { - return new App(container, this); -} - I18n::Message App::Descriptor::name() { return I18n::Message::CalculApp; } @@ -24,17 +21,33 @@ const Image * App::Descriptor::icon() { return ImageStore::CalculationIcon; } -App::App(Container * container, Descriptor * descriptor) : - TextFieldDelegateApp(container, &m_editExpressionController, descriptor), - m_localContext((GlobalContext *)((AppsContainer *)container)->globalContext(), &m_calculationStore), - m_calculationStore(), - m_historyController(&m_editExpressionController, &m_calculationStore), - m_editExpressionController(&m_modalViewController, &m_historyController, &m_calculationStore) -{ +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); } -App::App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); +void App::Snapshot::reset() { + m_calculationStore.deleteAll(); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +CalculationStore * App::Snapshot::calculationStore() { + return &m_calculationStore; +} + +void App::Snapshot::tidy() { + m_calculationStore.tidy(); +} + +App::App(Container * container, Snapshot * snapshot) : + TextFieldDelegateApp(container, snapshot, &m_editExpressionController), + m_localContext((GlobalContext *)((AppsContainer *)container)->globalContext(), snapshot->calculationStore()), + m_historyController(&m_editExpressionController, snapshot->calculationStore()), + m_editExpressionController(&m_modalViewController, &m_historyController, snapshot->calculationStore()) +{ } Context * App::localContext() { diff --git a/apps/calculation/app.h b/apps/calculation/app.h index c5dc6faf5..067c96c68 100644 --- a/apps/calculation/app.h +++ b/apps/calculation/app.h @@ -5,6 +5,7 @@ #include "local_context.h" #include "history_controller.h" #include "../shared/text_field_delegate_app.h" +#include "calculation_store.h" #include namespace Calculation { @@ -13,17 +14,24 @@ class App : public Shared::TextFieldDelegateApp { public: class Descriptor : public ::App::Descriptor { public: - App * build(Container * container) override; I18n::Message name() override; I18n::Message upperName() override; const Image * icon() override; }; - static Descriptor * buildDescriptor(); + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + void reset() override; + Descriptor * descriptor() override; + CalculationStore * calculationStore(); + private: + void tidy() override; + CalculationStore m_calculationStore; + }; Poincare::Context * localContext() override; private: - App(Container * container, Descriptor * descriptor); + App(Container * container, Snapshot * snapshot); LocalContext m_localContext; - CalculationStore m_calculationStore; HistoryController m_historyController; EditExpressionController m_editExpressionController; }; diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index ae3aea970..93eab7d9a 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -34,6 +34,59 @@ Calculation::~Calculation() { void Calculation::reset() { m_inputText[0] = 0; m_outputText[0] = 0; + tidy(); +} + +void Calculation::setContent(const char * c, Context * context) { + reset(); + strlcpy(m_inputText, c, sizeof(m_inputText)); + output(context)->writeTextInBuffer(m_outputText, sizeof(m_outputText)); +} + +const char * Calculation::inputText() { + return m_inputText; +} + +const char * Calculation::outputText() { + return m_outputText; +} + +Expression * Calculation::input() { + if (m_input == nullptr) { + m_input = Expression::parse(m_inputText); + } + return m_input; +} + +ExpressionLayout * Calculation::inputLayout() { + if (m_inputLayout == nullptr && input() != nullptr) { + m_inputLayout = input()->createLayout(Expression::FloatDisplayMode::Decimal, Expression::ComplexFormat::Algebric); + } + return m_inputLayout; +} + +Expression * Calculation::output(Context * context) { + if (m_output == nullptr && input() != nullptr) { + m_output = input()->evaluate(*context); + } + return m_output; +} + +ExpressionLayout * Calculation::outputLayout(Context * context) { + if (m_outputLayout == nullptr && output(context) != nullptr) { + m_outputLayout = output(context)->createLayout(); + } + return m_outputLayout; +} + +bool Calculation::isEmpty() { + if (strlen(m_inputText) == 0) { + return true; + } + return false; +} + +void Calculation::tidy() { if (m_input != nullptr) { delete m_input; } @@ -52,45 +105,4 @@ void Calculation::reset() { m_outputLayout = nullptr; } -void Calculation::setContent(const char * c, Context * context) { - reset(); - strlcpy(m_inputText, c, sizeof(m_inputText)); - m_input = Expression::parse(m_inputText); - m_inputLayout = m_input->createLayout(Expression::FloatDisplayMode::Decimal, Expression::ComplexFormat::Algebric); - m_output = m_input->evaluate(*context); - m_outputLayout = m_output->createLayout(); - m_output->writeTextInBuffer(m_outputText, sizeof(m_outputText)); -} - -const char * Calculation::inputText() { - return m_inputText; -} - -const char * Calculation::outputText() { - return m_outputText; -} - -Expression * Calculation::input() { - return m_input; -} - -ExpressionLayout * Calculation::inputLayout() { - return m_inputLayout; -} - -Expression * Calculation::output() { - return m_output; -} - -ExpressionLayout * Calculation::outputLayout() { - return m_outputLayout; -} - -bool Calculation::isEmpty() { - if (m_output == nullptr) { - return true; - } - return false; -} - } diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h index 8ee6c72e8..571e2300b 100644 --- a/apps/calculation/calculation.h +++ b/apps/calculation/calculation.h @@ -20,10 +20,11 @@ public: const char * outputText(); Poincare::Expression * input(); Poincare::ExpressionLayout * inputLayout(); - Poincare::Expression * output(); - Poincare::ExpressionLayout * outputLayout(); + Poincare::Expression * output(Poincare::Context * context); + Poincare::ExpressionLayout * outputLayout(Poincare::Context * context); void setContent(const char * c, Poincare::Context * context); bool isEmpty(); + void tidy(); private: char m_inputText[::TextField::maxBufferSize()]; char m_outputText[::TextField::maxBufferSize()]; diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index cfe8b2aa1..34ab18c89 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -61,4 +61,10 @@ void CalculationStore::deleteAll() { } } +void CalculationStore::tidy() { + for (int i = 0; i < k_maxNumberOfCalculations; i++) { + m_calculations[i].tidy(); + } +} + } diff --git a/apps/calculation/calculation_store.h b/apps/calculation/calculation_store.h index d8f436fad..0348c1844 100644 --- a/apps/calculation/calculation_store.h +++ b/apps/calculation/calculation_store.h @@ -15,6 +15,7 @@ public: void deleteCalculationAtIndex(int i); void deleteAll(); int numberOfCalculations(); + void tidy(); private: static constexpr int k_maxNumberOfCalculations = 10; Calculation * m_start; diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 5c7f8eaf2..474bea9cd 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -108,7 +108,6 @@ void HistoryController::tableViewDidChangeSelection(SelectableTableView * t, int if (selectedCell == nullptr) { return; } - selectedCell->setParentResponder(t); if (selectedRow() < previousSelectedCellY) { selectedCell->setSelectedSubviewType(HistoryViewCell::SubviewType::Output); } @@ -147,7 +146,8 @@ void HistoryController::willDisplayCellForIndex(HighlightCell * cell, int index) KDCoordinate HistoryController::rowHeight(int j) { Calculation * calculation = m_calculationStore->calculationAtIndex(j); KDCoordinate inputHeight = calculation->inputLayout()->size().height(); - KDCoordinate outputHeight = calculation->outputLayout()->size().height(); + App * calculationApp = (App *)app(); + KDCoordinate outputHeight = calculation->outputLayout(calculationApp->localContext())->size().height(); return inputHeight + outputHeight + 3*HistoryViewCell::k_digitVerticalMargin; } @@ -181,10 +181,11 @@ CalculationSelectableTableView * HistoryController::selectableTableView() { } View * HistoryController::loadView() { - for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { - m_calculationHistory[i] = new HistoryViewCell(); + CalculationSelectableTableView * tableView = new CalculationSelectableTableView(this, this, this); +for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { + m_calculationHistory[i] = new HistoryViewCell(tableView); } - return new CalculationSelectableTableView(this, this, this); + return tableView; } void HistoryController::unloadView(View * view) { diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index c763165ea..671de7047 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -1,4 +1,5 @@ #include "history_view_cell.h" +#include "app.h" #include "../constant.h" #include "selectable_table_view.h" #include @@ -6,8 +7,8 @@ namespace Calculation { -HistoryViewCell::HistoryViewCell() : - Responder(nullptr), +HistoryViewCell::HistoryViewCell(Responder * parentResponder) : + Responder(parentResponder), m_inputView(this), m_outputView(this), m_selectedSubviewType(HistoryViewCell::SubviewType::Output) @@ -48,7 +49,8 @@ void HistoryViewCell::layoutSubviews() { void HistoryViewCell::setCalculation(Calculation * calculation) { m_inputView.setExpression(calculation->inputLayout()); - m_outputView.setExpression(calculation->outputLayout()); + App * calculationApp = (App *)app(); + m_outputView.setExpression(calculation->outputLayout(calculationApp->localContext())); } void HistoryViewCell::reloadCell() { diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index 046e38a2f..048613ec9 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -13,7 +13,7 @@ public: Input, Output }; - HistoryViewCell(); + HistoryViewCell(Responder * parentResponder); void reloadCell() override; KDColor backgroundColor() const override; void setCalculation(Calculation * calculation); diff --git a/apps/calculation/local_context.cpp b/apps/calculation/local_context.cpp index 1b4a363c7..f0352b2e3 100644 --- a/apps/calculation/local_context.cpp +++ b/apps/calculation/local_context.cpp @@ -15,7 +15,7 @@ Expression * LocalContext::ansValue() { return m_parentContext->defaultExpression(); } Calculation * lastCalculation = m_calculationStore->calculationAtIndex(m_calculationStore->numberOfCalculations()-1); - return lastCalculation->output(); + return lastCalculation->output(m_parentContext); } void LocalContext::setExpressionForSymbolName(Expression * expression, const Symbol * symbol) { diff --git a/apps/graph/app.cpp b/apps/graph/app.cpp index a65ad761d..7e3337edb 100644 --- a/apps/graph/app.cpp +++ b/apps/graph/app.cpp @@ -8,10 +8,6 @@ using namespace Shared; namespace Graph { -App * App::Descriptor::build(Container * container) { - return new App(container, this); -} - I18n::Message App::Descriptor::name() { return I18n::Message::FunctionApp; } @@ -24,19 +20,39 @@ const Image * App::Descriptor::icon() { return ImageStore::GraphIcon; } -App::App(Container * container, Descriptor * descriptor) : - FunctionApp(container, &m_inputViewController, descriptor), - m_functionStore(), +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); +} + +void App::Snapshot::reset() { + m_functionStore.removeAll(); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +CartesianFunctionStore * App::Snapshot::functionStore() { + return &m_functionStore; +} + +void App::Snapshot::tidy() { + m_functionStore.tidy(); +} + +App::App(Container * container, Snapshot * snapshot) : + FunctionApp(container, snapshot, &m_inputViewController), m_xContext('x',((AppsContainer *)container)->globalContext()), - m_listController(&m_listFooter, &m_functionStore, &m_listHeader, &m_listFooter), + m_listController(&m_listFooter, snapshot->functionStore(), &m_listHeader, &m_listFooter), m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(&m_listStackViewController, &m_listFooter, &m_listController), m_listStackViewController(&m_tabViewController, &m_listHeader), - m_graphController(&m_graphAlternateEmptyViewController, &m_functionStore, &m_graphHeader), + m_graphController(&m_graphAlternateEmptyViewController, snapshot->functionStore(), &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, &m_functionStore, &m_valuesHeader), + m_valuesController(&m_valuesAlternateEmptyViewController, snapshot->functionStore(), &m_valuesHeader), m_valuesAlternateEmptyViewController(&m_valuesHeader, &m_valuesController, &m_valuesController), m_valuesHeader(&m_valuesStackViewController, &m_valuesAlternateEmptyViewController, &m_valuesController), m_valuesStackViewController(&m_tabViewController, &m_valuesHeader), @@ -45,10 +61,6 @@ App::App(Container * container, Descriptor * descriptor) : { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} - InputViewController * App::inputViewController() { return &m_inputViewController; } diff --git a/apps/graph/app.h b/apps/graph/app.h index 58c8f4bc9..c3cd58129 100644 --- a/apps/graph/app.h +++ b/apps/graph/app.h @@ -15,12 +15,20 @@ class App : public Shared::FunctionApp { public: class Descriptor : public ::App::Descriptor { public: - App * build(Container * container) override; I18n::Message name() override; I18n::Message upperName() override; const Image * icon() override; }; - static Descriptor * buildDescriptor(); + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + void reset() override; + Descriptor * descriptor() override; + CartesianFunctionStore * functionStore(); + private: + void tidy() override; + CartesianFunctionStore m_functionStore; + }; InputViewController * inputViewController() override; /* This local context can parse x. However, it always stores NAN * as x value. When we need to evaluate expression with a specific x value, we @@ -28,8 +36,7 @@ public: * weird x values after drawing curves or displaying the value table. */ Poincare::Context * localContext() override; private: - App(Container * container, Descriptor * descriptor); - CartesianFunctionStore m_functionStore; + App(Container * container, Snapshot * snapshot); Poincare::VariableContext m_xContext; ListController m_listController; ButtonRowController m_listFooter; diff --git a/apps/graph/graph/curve_parameter_controller.cpp b/apps/graph/graph/curve_parameter_controller.cpp index b98686e85..dd10280fb 100644 --- a/apps/graph/graph/curve_parameter_controller.cpp +++ b/apps/graph/graph/curve_parameter_controller.cpp @@ -1,4 +1,5 @@ #include "curve_parameter_controller.h" +#include "../../i18n.h" #include using namespace Shared; diff --git a/apps/hardware_test/app.cpp b/apps/hardware_test/app.cpp index 6ce7b02d5..bb7c6fbb8 100644 --- a/apps/hardware_test/app.cpp +++ b/apps/hardware_test/app.cpp @@ -7,18 +7,19 @@ extern "C" { namespace HardwareTest { -App * App::Descriptor::build(Container * container) { +App * App::Snapshot::unpack(Container * container) { return new App(container, this); } -App::App(Container * container, Descriptor * descriptor) : - ::App(container, &m_keyboardController, descriptor), +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +App::App(Container * container, Snapshot * snapshot) : + ::App(container, snapshot, &m_keyboardController), m_keyboardController(&m_modalViewController) { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} - } diff --git a/apps/hardware_test/app.h b/apps/hardware_test/app.h index 2c67bd694..70f72ca80 100644 --- a/apps/hardware_test/app.h +++ b/apps/hardware_test/app.h @@ -10,13 +10,13 @@ namespace HardwareTest { class App : public ::App { public: - class Descriptor : public ::App::Descriptor { + class Snapshot : public ::App::Snapshot { public: - App * build(Container * container) override; + App * unpack(Container * container) override; + Descriptor * descriptor() override; }; - static Descriptor * buildDescriptor(); private: - App(Container * container, Descriptor * descriptor); + App(Container * container, Snapshot * snapshot); KeyboardController m_keyboardController; }; diff --git a/apps/hardware_test/color_controller.cpp b/apps/hardware_test/color_controller.cpp index a7557ae93..c5c3d38d7 100644 --- a/apps/hardware_test/color_controller.cpp +++ b/apps/hardware_test/color_controller.cpp @@ -20,7 +20,7 @@ bool ColorController::handleEvent(Ion::Events::Event event) { m_view.setColors(nextColor(m_view.fillColor()), nextColor(m_view.outlineColor())); if (m_view.fillColor() == KDColorBlack) { AppsContainer * container = (AppsContainer *)app()->container(); - container->switchTo(container->appDescriptorAtIndex(0)); + container->switchTo(container->appSnapshotAtIndex(0)); } return true; } diff --git a/apps/home/app.cpp b/apps/home/app.cpp index 3117414ff..57b90dc1c 100644 --- a/apps/home/app.cpp +++ b/apps/home/app.cpp @@ -1,6 +1,6 @@ #include "app.h" -#include "../apps_container.h" #include "../i18n.h" +#include "../apps_container.h" extern "C" { #include @@ -8,10 +8,6 @@ extern "C" { namespace Home { -App * App::Descriptor::build(Container * container) { - return new App(container, this); -} - I18n::Message App::Descriptor::name() { return I18n::Message::Apps; } @@ -20,14 +16,19 @@ I18n::Message App::Descriptor::upperName() { return I18n::Message::AppsCapital; } -App::App(Container * container, Descriptor * descriptor) : - ::App(container, &m_controller, descriptor, I18n::Message::Warning), +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +App::App(Container * container, Snapshot * snapshot) : + ::App(container, snapshot, &m_controller, I18n::Message::Warning), m_controller(&m_modalViewController, (AppsContainer *)container) { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} - } diff --git a/apps/home/app.h b/apps/home/app.h index 6af9f4d49..dee11daf7 100644 --- a/apps/home/app.h +++ b/apps/home/app.h @@ -12,13 +12,16 @@ class App : public ::App { public: class Descriptor : public ::App::Descriptor { public: - App * build(Container * container) override; I18n::Message name() override; I18n::Message upperName() override; }; - static Descriptor * buildDescriptor(); + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + Descriptor * descriptor() override; + }; private: - App(Container * container, Descriptor * descriptor); + App(Container * container, Snapshot * snapshot); Controller m_controller; }; diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index 139908950..bff5609d8 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -47,7 +47,7 @@ Controller::Controller(Responder * parentResponder, ::AppsContainer * container) bool Controller::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { - m_container->switchTo(m_container->appDescriptorAtIndex(selectedRow()*k_numberOfColumns+selectedColumn()+1)); + m_container->switchTo(m_container->appSnapshotAtIndex(selectedRow()*k_numberOfColumns+selectedColumn()+1)); return true; } return false; @@ -101,7 +101,7 @@ void Controller::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) { appCell->setVisible(false); } else { appCell->setVisible(true); - ::App::Descriptor * descriptor = m_container->appDescriptorAtIndex((j*k_numberOfColumns+i)+1); + ::App::Descriptor * descriptor = m_container->appSnapshotAtIndex((j*k_numberOfColumns+i)+1)->descriptor(); appCell->setAppDescriptor(descriptor); } } diff --git a/apps/main.cpp b/apps/main.cpp index d32cff3b0..b1a64538d 100644 --- a/apps/main.cpp +++ b/apps/main.cpp @@ -3,7 +3,7 @@ AppsContainer container; void ion_app() { - container.switchTo(container.onBoardingAppDescriptor()); + container.switchTo(container.onBoardingAppSnapshot()); container.run(); container.switchTo(nullptr); } diff --git a/apps/on_boarding/app.cpp b/apps/on_boarding/app.cpp index d7b09f812..fd07c5b7a 100644 --- a/apps/on_boarding/app.cpp +++ b/apps/on_boarding/app.cpp @@ -3,21 +3,22 @@ namespace OnBoarding { -App * App::Descriptor::build(Container * container) { +App * App::Snapshot::unpack(Container * container) { return new App(container, this); } -App::App(Container * container, Descriptor * descriptor) : - ::App(container, &m_languageController, descriptor), +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +App::App(Container * container, Snapshot * snapshot) : + ::App(container, snapshot, &m_languageController), m_languageController(&m_modalViewController, &m_logoController, ((AppsContainer *)container)->updatePopUpController()), m_logoController() { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} - void App::reinitOnBoarding() { m_languageController.reinitOnBoarding(); } diff --git a/apps/on_boarding/app.h b/apps/on_boarding/app.h index 81f57ab64..108f64385 100644 --- a/apps/on_boarding/app.h +++ b/apps/on_boarding/app.h @@ -10,16 +10,16 @@ namespace OnBoarding { class App : public ::App { public: - class Descriptor : public ::App::Descriptor { + class Snapshot : public ::App::Snapshot { public: - App * build(Container * container) override; + App * unpack(Container * container) override; + Descriptor * descriptor() override; }; - static Descriptor * buildDescriptor(); void reinitOnBoarding(); bool hasTimer(); Timer * timer(); private: - App(Container * container, Descriptor * descriptor); + App(Container * container, Snapshot * snapshot); LanguageController m_languageController; LogoController m_logoController; }; diff --git a/apps/on_boarding/update_controller.cpp b/apps/on_boarding/update_controller.cpp index e37b53673..04ec7881c 100644 --- a/apps/on_boarding/update_controller.cpp +++ b/apps/on_boarding/update_controller.cpp @@ -16,8 +16,8 @@ bool UpdateController::handleEvent(Ion::Events::Event event) { if (event != Ion::Events::Back) { app()->dismissModalViewController(); AppsContainer * appsContainer = (AppsContainer *)app()->container(); - if (appsContainer->activeApp()->descriptor() == appsContainer->onBoardingAppDescriptor()) { - appsContainer->switchTo(appsContainer->appDescriptorAtIndex(0)); + if (appsContainer->activeApp()->snapshot() == appsContainer->onBoardingAppSnapshot()) { + appsContainer->switchTo(appsContainer->appSnapshotAtIndex(0)); } return true; } diff --git a/apps/probability/app.cpp b/apps/probability/app.cpp index 7af503ebf..8cb1dcc43 100644 --- a/apps/probability/app.cpp +++ b/apps/probability/app.cpp @@ -1,14 +1,11 @@ #include "app.h" +#include "../i18n.h" #include "probability_icon.h" using namespace Shared; namespace Probability { -App * App::Descriptor::build(Container * container) { - return new App(container, this); -} - I18n::Message App::Descriptor::name() { return I18n::Message::ProbaApp; } @@ -21,15 +18,20 @@ const Image * App::Descriptor::icon() { return ImageStore::ProbabilityIcon; } -App::App(Container * container, Descriptor * descriptor) : - TextFieldDelegateApp(container, &m_stackViewController, descriptor), +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +App::App(Container * container, Snapshot * snapshot) : + TextFieldDelegateApp(container, snapshot, &m_stackViewController), m_lawController(nullptr), m_stackViewController(&m_modalViewController, &m_lawController) { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} - } diff --git a/apps/probability/app.h b/apps/probability/app.h index f27bdcf7a..c0324f1c7 100644 --- a/apps/probability/app.h +++ b/apps/probability/app.h @@ -12,14 +12,17 @@ class App : public Shared::TextFieldDelegateApp { public: class Descriptor : public ::App::Descriptor { public: - App * build(Container * container) override; I18n::Message name() override; I18n::Message upperName() override; const Image * icon() override; }; - static Descriptor * buildDescriptor(); + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + Descriptor * descriptor() override; + }; private: - App(Container * container, Descriptor * descriptor); + App(Container * container, Snapshot * snapshot); LawController m_lawController; StackViewController m_stackViewController; }; diff --git a/apps/probability/calculation_controller.cpp b/apps/probability/calculation_controller.cpp index deffd982b..a3d4292c0 100644 --- a/apps/probability/calculation_controller.cpp +++ b/apps/probability/calculation_controller.cpp @@ -1,6 +1,7 @@ #include "calculation_controller.h" #include "../constant.h" #include "../apps_container.h" +#include "app.h" #include "calculation/left_integral_calculation.h" #include "calculation/right_integral_calculation.h" #include "calculation/finite_integral_calculation.h" diff --git a/apps/regression/app.cpp b/apps/regression/app.cpp index 5df331321..b656e60d5 100644 --- a/apps/regression/app.cpp +++ b/apps/regression/app.cpp @@ -6,10 +6,6 @@ using namespace Shared; namespace Regression { -App * App::Descriptor::build(Container * container) { - return new App(container, this); -} - I18n::Message App::Descriptor::name() { return I18n::Message::RegressionApp; } @@ -22,25 +18,38 @@ const Image * App::Descriptor::icon() { return ImageStore::RegressionIcon; } -App::App(Container * container, Descriptor * descriptor) : - TextFieldDelegateApp(container, &m_tabViewController, descriptor), - m_store(), - m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, &m_store), +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); +} + +void App::Snapshot::reset() { + m_store.deleteAllPairs(); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +Store * App::Snapshot::store() { + return &m_store; +} + +App::App(Container * container, Snapshot * snapshot) : + TextFieldDelegateApp(container, snapshot, &m_tabViewController), + m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, snapshot->store()), m_calculationAlternateEmptyViewController(&m_calculationHeader, &m_calculationController, &m_calculationController), m_calculationHeader(&m_tabViewController, &m_calculationAlternateEmptyViewController, &m_calculationController), - m_graphController(&m_graphAlternateEmptyViewController, &m_graphHeader, &m_store), + m_graphController(&m_graphAlternateEmptyViewController, &m_graphHeader, snapshot->store()), m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController), m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController), m_graphStackViewController(&m_tabViewController, &m_graphHeader), - m_storeController(&m_storeHeader, &m_store, &m_storeHeader), + m_storeController(&m_storeHeader, snapshot->store(), &m_storeHeader), m_storeHeader(&m_storeStackViewController, &m_storeController, &m_storeController), m_storeStackViewController(&m_tabViewController, &m_storeHeader), m_tabViewController(&m_modalViewController, &m_storeStackViewController, &m_graphStackViewController, &m_calculationHeader) { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} } diff --git a/apps/regression/app.h b/apps/regression/app.h index 0a16cf9dc..611658dac 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -14,15 +14,21 @@ class App : public Shared::TextFieldDelegateApp { public: class Descriptor : public ::App::Descriptor { public: - App * build(Container * container) override; I18n::Message name() override; I18n::Message upperName() override; const Image * icon() override; }; - static Descriptor * buildDescriptor(); + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + void reset() override; + Descriptor * descriptor() override; + Store * store(); + private: + Store m_store; + }; private: - App(Container * container, Descriptor * descriptor); - Store m_store; + App(Container * container, Snapshot * snapshot); CalculationController m_calculationController; AlternateEmptyViewController m_calculationAlternateEmptyViewController; ButtonRowController m_calculationHeader; diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index b5c964796..12d01680c 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -6,10 +6,6 @@ using namespace Poincare; namespace Sequence { -App * App::Descriptor::build(Container * container) { - return new App(container, this); -} - I18n::Message App::Descriptor::name() { return I18n::Message::SequenceApp; } @@ -22,19 +18,39 @@ const Image * App::Descriptor::icon() { return ImageStore::SequenceIcon; } -App::App(Container * container, Descriptor * descriptor) : - FunctionApp(container, &m_inputViewController, descriptor), - m_sequenceStore(), +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); +} + +void App::Snapshot::reset() { + m_sequenceStore.removeAll(); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +SequenceStore * App::Snapshot::sequenceStore() { + return &m_sequenceStore; +} + +void App::Snapshot::tidy() { + m_sequenceStore.tidy(); +} + +App::App(Container * container, Snapshot * snapshot) : + FunctionApp(container, snapshot, &m_inputViewController), m_nContext(((AppsContainer *)container)->globalContext()), - m_listController(&m_listFooter, &m_sequenceStore, &m_listHeader, &m_listFooter), + m_listController(&m_listFooter, snapshot->sequenceStore(), &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, &m_sequenceStore, &m_graphHeader), + m_graphController(&m_graphAlternateEmptyViewController, snapshot->sequenceStore(), &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, &m_sequenceStore, &m_valuesHeader), + m_valuesController(&m_valuesAlternateEmptyViewController, snapshot->sequenceStore(), &m_valuesHeader), m_valuesAlternateEmptyViewController(&m_valuesHeader, &m_valuesController, &m_valuesController), m_valuesHeader(nullptr, &m_valuesAlternateEmptyViewController, &m_valuesController), m_valuesStackViewController(&m_tabViewController, &m_valuesHeader), @@ -43,10 +59,6 @@ App::App(Container * container, Descriptor * descriptor) : { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} - InputViewController * App::inputViewController() { return &m_inputViewController; } diff --git a/apps/sequence/app.h b/apps/sequence/app.h index 8ad0d6ca1..b959fd82b 100644 --- a/apps/sequence/app.h +++ b/apps/sequence/app.h @@ -16,18 +16,25 @@ class App : public Shared::FunctionApp { public: class Descriptor : public ::App::Descriptor { public: - App * build(Container * container) override; I18n::Message name() override; I18n::Message upperName() override; const Image * icon() override; }; - static Descriptor * buildDescriptor(); + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + void reset() override; + Descriptor * descriptor() override; + SequenceStore * sequenceStore(); + private: + void tidy() override; + SequenceStore m_sequenceStore; + }; InputViewController * inputViewController() override; Poincare::Context * localContext() override; const char * XNT() override; private: - App(Container * container, Descriptor * descriptor); - SequenceStore m_sequenceStore; + App(Container * container, Snapshot * snapshot); LocalContext m_nContext; ListController m_listController; ButtonRowController m_listFooter; diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index b9951ca58..1a45135de 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -95,56 +95,40 @@ Sequence::Type Sequence::type() { void Sequence::setType(Type type) { m_type = type; - if (m_nameLayout != nullptr) { - delete m_nameLayout; - m_nameLayout = nullptr; - } - if (m_definitionName != nullptr) { - delete m_definitionName; - m_definitionName = nullptr; - } - if (m_firstInitialConditionName != nullptr) { - delete m_firstInitialConditionName; - m_firstInitialConditionName = nullptr; - } - if (m_secondInitialConditionName != nullptr) { - delete m_secondInitialConditionName; - m_secondInitialConditionName = nullptr; - } + tidy(); /* Reset all contents */ setContent(""); setFirstInitialConditionContent(""); setSecondInitialConditionContent(""); - m_nameLayout = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - if (m_type == Type::Explicite) { - m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n ", 2, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - } - if (m_type == Type::SingleRecurrence) { - m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+1 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("0", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - } - if (m_type == Type::DoubleRecurrence) { - m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+2 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("0", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - m_secondInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("1", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - } m_indexBuffer[0] = -1; m_indexBuffer[1] = -1; } Poincare::Expression * Sequence::firstInitialConditionExpression() { + if (m_firstInitialConditionExpression == nullptr) { + m_firstInitialConditionExpression = Poincare::Expression::parse(m_firstInitialConditionText); + } return m_firstInitialConditionExpression; } Poincare::Expression * Sequence::secondInitialConditionExpression() { + if (m_secondInitialConditionExpression == nullptr) { + m_secondInitialConditionExpression = Poincare::Expression::parse(m_secondInitialConditionText); + } return m_secondInitialConditionExpression; } Poincare::ExpressionLayout * Sequence::firstInitialConditionLayout() { + if (m_firstInitialConditionLayout == nullptr && firstInitialConditionExpression() != nullptr) { + m_firstInitialConditionLayout = firstInitialConditionExpression()->createLayout(Expression::FloatDisplayMode::Decimal); + } return m_firstInitialConditionLayout; } Poincare::ExpressionLayout * Sequence::secondInitialConditionLayout() { + if (m_secondInitialConditionLayout == nullptr && secondInitialConditionExpression()) { + m_secondInitialConditionLayout = secondInitialConditionExpression()->createLayout(Expression::FloatDisplayMode::Decimal); + } return m_secondInitialConditionLayout; } @@ -158,14 +142,11 @@ void Sequence::setFirstInitialConditionContent(const char * c) { strlcpy(m_firstInitialConditionText, c, sizeof(m_firstInitialConditionText)); if (m_firstInitialConditionExpression != nullptr) { delete m_firstInitialConditionExpression; + m_firstInitialConditionExpression = nullptr; } - m_firstInitialConditionExpression = Poincare::Expression::parse(m_firstInitialConditionText); if (m_firstInitialConditionLayout != nullptr) { delete m_firstInitialConditionLayout; - } - m_firstInitialConditionLayout = nullptr; - if (m_firstInitialConditionExpression) { - m_firstInitialConditionLayout = m_firstInitialConditionExpression->createLayout(Expression::FloatDisplayMode::Decimal); + m_firstInitialConditionLayout = nullptr; } m_indexBuffer[0] = -1; m_indexBuffer[1] = -1; @@ -175,14 +156,11 @@ void Sequence::setSecondInitialConditionContent(const char * c) { strlcpy(m_secondInitialConditionText, c, sizeof(m_secondInitialConditionText)); if (m_secondInitialConditionExpression != nullptr) { delete m_secondInitialConditionExpression; + m_secondInitialConditionExpression = nullptr; } - m_secondInitialConditionExpression = Poincare::Expression::parse(m_secondInitialConditionText); if (m_secondInitialConditionLayout != nullptr) { delete m_secondInitialConditionLayout; - } - m_secondInitialConditionLayout = nullptr; - if (m_secondInitialConditionExpression) { - m_secondInitialConditionLayout = m_secondInitialConditionExpression->createLayout(Expression::FloatDisplayMode::Decimal); + m_secondInitialConditionLayout = nullptr; } m_indexBuffer[0] = -1; m_indexBuffer[1] = -1; @@ -197,29 +175,57 @@ int Sequence::numberOfElements() { } Poincare::ExpressionLayout * Sequence::nameLayout() { + if (m_nameLayout == nullptr) { + m_nameLayout = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + } return m_nameLayout; } Poincare::ExpressionLayout * Sequence::definitionName() { + if (m_definitionName == nullptr) { + if (m_type == Type::Explicite) { + m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n ", 2, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + } + if (m_type == Type::SingleRecurrence) { + m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+1 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + } + if (m_type == Type::DoubleRecurrence) { + m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+2 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + } + } return m_definitionName; } Poincare::ExpressionLayout * Sequence::firstInitialConditionName() { + if (m_firstInitialConditionName == nullptr) { + if (m_type == Type::SingleRecurrence) { + m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("0", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + } + if (m_type == Type::DoubleRecurrence) { + m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("0", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + } + } return m_firstInitialConditionName; } Poincare::ExpressionLayout * Sequence::secondInitialConditionName() { + if (m_secondInitialConditionName == nullptr) { + if (m_type == Type::DoubleRecurrence) { + m_secondInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("1", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + + } + } return m_secondInitialConditionName; } bool Sequence::isDefined() { switch (m_type) { case Type::Explicite: - return expression() != nullptr; + return strlen(text()) != 0; case Type::SingleRecurrence: - return expression() != nullptr && m_firstInitialConditionExpression != nullptr; + return strlen(text()) != 0 && strlen(firstInitialConditionText()) != 0; default: - return expression() != nullptr && m_firstInitialConditionExpression != nullptr && m_secondInitialConditionExpression != nullptr; + return strlen(text()) != 0 && strlen(firstInitialConditionText()) != 0 && strlen(secondInitialConditionText()) != 0; } } @@ -319,4 +325,40 @@ float Sequence::sumOfTermsBetweenAbscissa(float start, float end, Context * cont return result; } +void Sequence::tidy() { + Function::tidy(); + if (m_firstInitialConditionLayout != nullptr) { + delete m_firstInitialConditionLayout; + m_firstInitialConditionLayout = nullptr; + } + if (m_secondInitialConditionLayout != nullptr) { + delete m_secondInitialConditionLayout; + m_secondInitialConditionLayout = nullptr; + } + if (m_firstInitialConditionExpression != nullptr) { + delete m_firstInitialConditionExpression; + m_firstInitialConditionExpression = nullptr; + } + if (m_secondInitialConditionExpression != nullptr) { + delete m_secondInitialConditionExpression; + m_secondInitialConditionExpression = nullptr; + } + if (m_nameLayout != nullptr) { + delete m_nameLayout; + m_nameLayout = nullptr; + } + if (m_definitionName != nullptr) { + delete m_definitionName; + m_definitionName = nullptr; + } + if (m_firstInitialConditionName != nullptr) { + delete m_firstInitialConditionName; + m_firstInitialConditionName = nullptr; + } + if (m_secondInitialConditionName != nullptr) { + delete m_secondInitialConditionName; + m_secondInitialConditionName = nullptr; + } +} + } diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index 6b39f836c..73a9f0991 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -38,6 +38,7 @@ public: bool isEmpty() override; float evaluateAtAbscissa(float x, Poincare::Context * context) const override; float sumOfTermsBetweenAbscissa(float start, float end, Poincare::Context * context); + void tidy() override; private: constexpr static int k_maxRecurrentRank = 10000; constexpr static float k_maxNumberOfTermsInSum = 100000.0f; diff --git a/apps/settings/app.cpp b/apps/settings/app.cpp index b68f28124..137768557 100644 --- a/apps/settings/app.cpp +++ b/apps/settings/app.cpp @@ -4,10 +4,6 @@ namespace Settings { -App * App::Descriptor::build(Container * container) { - return new App(container, this); -} - I18n::Message App::Descriptor::name() { return I18n::Message::SettingsApp; } @@ -20,15 +16,20 @@ const Image * App::Descriptor::icon() { return ImageStore::SettingsIcon; } -App::App(Container * container, Descriptor * descriptor) : - ::App(container, &m_stackViewController, descriptor, I18n::Message::Warning), +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +App::App(Container * container, Snapshot * snapshot) : + ::App(container, snapshot, &m_stackViewController, I18n::Message::Warning), m_mainController(&m_stackViewController), m_stackViewController(&m_modalViewController, &m_mainController) { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} - } diff --git a/apps/settings/app.h b/apps/settings/app.h index 6661a38e5..ea9170848 100644 --- a/apps/settings/app.h +++ b/apps/settings/app.h @@ -10,14 +10,17 @@ class App : public ::App { public: class Descriptor : public ::App::Descriptor { public: - App * build(Container * container) override; I18n::Message name() override; I18n::Message upperName() override; const Image * icon() override; }; - static Descriptor * buildDescriptor(); + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + Descriptor * descriptor() override; + }; private: - App(Container * container, Descriptor * descriptor); + App(Container * container, Snapshot * snapshot); MainController m_mainController; StackViewController m_stackViewController; }; diff --git a/apps/settings/sub_controller.cpp b/apps/settings/sub_controller.cpp index 9dea636cd..c6ba73d98 100644 --- a/apps/settings/sub_controller.cpp +++ b/apps/settings/sub_controller.cpp @@ -60,7 +60,7 @@ bool SubController::handleEvent(Ion::Events::Event event) { * clicking on '6' on the serial number row. */ if (event == Ion::Events::Six && m_nodeModel->label() == I18n::Message::About && selectedRow() == 1) { AppsContainer * appsContainer = (AppsContainer *)app()->container(); - appsContainer->switchTo(appsContainer->hardwareTestAppDescriptor()); + appsContainer->switchTo(appsContainer->hardwareTestAppSnapshot()); return true; } if (event == Ion::Events::OK || event == Ion::Events::EXE) { diff --git a/apps/shared/function.cpp b/apps/shared/function.cpp index e5251f83d..7cb2bb0fa 100644 --- a/apps/shared/function.cpp +++ b/apps/shared/function.cpp @@ -27,16 +27,13 @@ Function& Function::operator=(const Function& other) { void Function::setContent(const char * c) { strlcpy(m_text, c, sizeof(m_text)); - if (m_expression != nullptr) { - delete m_expression; - } - m_expression = Poincare::Expression::parse(m_text); if (m_layout != nullptr) { delete m_layout; + m_layout = nullptr; } - m_layout = nullptr; - if (m_expression) { - m_layout = expression()->createLayout(Expression::FloatDisplayMode::Decimal); + if (m_expression != nullptr) { + delete m_expression; + m_expression = nullptr; } } @@ -64,15 +61,21 @@ const char * Function::name() const { } Poincare::Expression * Function::expression() { + if (m_expression == nullptr) { + m_expression = Expression::parse(m_text); + } return m_expression; } Poincare::ExpressionLayout * Function::layout() { + if (m_layout == nullptr && expression() != nullptr) { + m_layout = expression()->createLayout(Expression::FloatDisplayMode::Decimal); + } return m_layout; } bool Function::isDefined() { - return m_expression != nullptr; + return strlen(m_text) != 0; } bool Function::isActive() { @@ -95,4 +98,15 @@ float Function::evaluateAtAbscissa(float x, Poincare::Context * context) const { return m_expression->approximate(variableContext); } +void Function::tidy() { + if (m_layout != nullptr) { + delete m_layout; + m_layout = nullptr; + } + if (m_expression != nullptr) { + delete m_expression; + m_expression = nullptr; + } +} + } diff --git a/apps/shared/function.h b/apps/shared/function.h index 67abb12b0..b3e0b05a5 100644 --- a/apps/shared/function.h +++ b/apps/shared/function.h @@ -27,6 +27,7 @@ public: virtual void setContent(const char * c); void setColor(KDColor m_color); virtual float evaluateAtAbscissa(float x, Poincare::Context * context) const; + virtual void tidy(); protected: Poincare::Expression * m_expression; private: diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index d15392b64..3804c4110 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -5,8 +5,8 @@ using namespace Poincare; namespace Shared { -FunctionApp::FunctionApp(Container * container, ViewController * rootViewController, Descriptor * descriptor) : - TextFieldDelegateApp(container, rootViewController, descriptor) +FunctionApp::FunctionApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) : + TextFieldDelegateApp(container, snapshot, rootViewController) { } diff --git a/apps/shared/function_app.h b/apps/shared/function_app.h index 575663b74..5c592e8bc 100644 --- a/apps/shared/function_app.h +++ b/apps/shared/function_app.h @@ -10,7 +10,8 @@ namespace Shared { class FunctionApp : public TextFieldDelegateApp { public: - FunctionApp(Container * container, ViewController * rootViewController, Descriptor * descriptor); + FunctionApp(Container * container, Snapshot * snapshot, ViewController * rootViewController); + virtual ~FunctionApp() = default; virtual InputViewController * inputViewController() = 0; void willBecomeInactive() override; }; diff --git a/apps/shared/function_store.cpp b/apps/shared/function_store.cpp index 0c735f7aa..a5102db74 100644 --- a/apps/shared/function_store.cpp +++ b/apps/shared/function_store.cpp @@ -62,4 +62,10 @@ int FunctionStore::numberOfDefinedFunctions() { return result; } +void FunctionStore::tidy() { + for (int i = 0; i < m_numberOfFunctions; i++) { + functionAtIndex(i)->tidy(); + } +} + } diff --git a/apps/shared/function_store.h b/apps/shared/function_store.h index b8d8272ae..93d1c2397 100644 --- a/apps/shared/function_store.h +++ b/apps/shared/function_store.h @@ -26,6 +26,7 @@ public: int numberOfActiveFunctions(); virtual int maxNumberOfFunctions() = 0; virtual char symbol() const = 0; + void tidy(); protected: int m_numberOfFunctions; private: diff --git a/apps/shared/text_field_delegate_app.cpp b/apps/shared/text_field_delegate_app.cpp index 628419c69..22ae44e3a 100644 --- a/apps/shared/text_field_delegate_app.cpp +++ b/apps/shared/text_field_delegate_app.cpp @@ -7,8 +7,8 @@ using namespace Poincare; namespace Shared { -TextFieldDelegateApp::TextFieldDelegateApp(Container * container, ViewController * rootViewController, Descriptor * descriptor) : - ::App(container, rootViewController, descriptor, I18n::Message::Warning), +TextFieldDelegateApp::TextFieldDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) : + ::App(container, snapshot, rootViewController, I18n::Message::Warning), TextFieldDelegate() { } diff --git a/apps/shared/text_field_delegate_app.h b/apps/shared/text_field_delegate_app.h index 29c41d7d2..9d3d95573 100644 --- a/apps/shared/text_field_delegate_app.h +++ b/apps/shared/text_field_delegate_app.h @@ -11,7 +11,8 @@ namespace Shared { class TextFieldDelegateApp : public ::App, public TextFieldDelegate { public: - TextFieldDelegateApp(Container * container, ViewController * rootViewController, Descriptor * descriptor); + TextFieldDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController); + virtual ~TextFieldDelegateApp() = default; virtual Poincare::Context * localContext(); AppsContainer * container(); virtual const char * XNT(); diff --git a/apps/statistics/app.cpp b/apps/statistics/app.cpp index f65290228..cea063eaf 100644 --- a/apps/statistics/app.cpp +++ b/apps/statistics/app.cpp @@ -1,14 +1,11 @@ #include "app.h" #include "stat_icon.h" +#include "../i18n.h" using namespace Shared; namespace Statistics { -App * App::Descriptor::build(Container * container) { - return new App(container, this); -} - I18n::Message App::Descriptor::name() { return I18n::Message::StatsApp; } @@ -21,28 +18,40 @@ const Image * App::Descriptor::icon() { return ImageStore::StatIcon; } -App::App(Container * container, Descriptor * descriptor) : - TextFieldDelegateApp(container, &m_tabViewController, descriptor), - m_store(), - m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, &m_store), +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); +} + +void App::Snapshot::reset() { + m_store.deleteAllPairs(); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +Store * App::Snapshot::store() { + return &m_store; +} + +App::App(Container * container, Snapshot * snapshot) : + TextFieldDelegateApp(container, snapshot, &m_tabViewController), + m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, snapshot->store()), m_calculationAlternateEmptyViewController(&m_calculationHeader, &m_calculationController, &m_calculationController), m_calculationHeader(&m_tabViewController, &m_calculationAlternateEmptyViewController, &m_calculationController), - m_boxController(&m_boxAlternateEmptyViewController, &m_boxHeader, &m_store), + m_boxController(&m_boxAlternateEmptyViewController, &m_boxHeader, snapshot->store()), m_boxAlternateEmptyViewController(&m_boxHeader, &m_boxController, &m_boxController), m_boxHeader(&m_tabViewController, &m_boxAlternateEmptyViewController, &m_boxController), - m_histogramController(&m_histogramAlternateEmptyViewController, &m_histogramHeader, &m_store), + m_histogramController(&m_histogramAlternateEmptyViewController, &m_histogramHeader, snapshot->store()), m_histogramAlternateEmptyViewController(&m_histogramHeader, &m_histogramController, &m_histogramController), m_histogramHeader(&m_histogramStackViewController, &m_histogramAlternateEmptyViewController, &m_histogramController), m_histogramStackViewController(&m_tabViewController, &m_histogramHeader), - m_storeController(&m_storeHeader, &m_store, &m_storeHeader), + m_storeController(&m_storeHeader, snapshot->store(), &m_storeHeader), m_storeHeader(&m_storeStackViewController, &m_storeController, &m_storeController), m_storeStackViewController(&m_tabViewController, &m_storeHeader), - m_tabViewController(&m_modalViewController, &m_storeStackViewController, &m_histogramStackViewController, &m_boxHeader, &m_calculationHeader) + m_tabViewController(&m_modalViewController, &m_storeStackViewController, &m_histogramStackViewController, &m_boxHeader, &m_calculationHeader) { } -App::Descriptor * App::buildDescriptor() { - return new App::Descriptor(); -} - } diff --git a/apps/statistics/app.h b/apps/statistics/app.h index 56c4699a9..7016887a8 100644 --- a/apps/statistics/app.h +++ b/apps/statistics/app.h @@ -15,15 +15,21 @@ class App : public Shared::TextFieldDelegateApp { public: class Descriptor : public ::App::Descriptor { public: - App * build(Container * container) override; I18n::Message name() override; I18n::Message upperName() override; const Image * icon() override; }; - static Descriptor * buildDescriptor(); + class Snapshot : public ::App::Snapshot { + public: + App * unpack(Container * container) override; + void reset() override; + Descriptor * descriptor() override; + Store * store(); + private: + Store m_store; + }; private: - App(Container * container, Descriptor * descriptor); - Store m_store; + App(Container * container, Snapshot * snapshot); CalculationController m_calculationController; AlternateEmptyViewController m_calculationAlternateEmptyViewController; ButtonRowController m_calculationHeader; diff --git a/escher/include/escher/app.h b/escher/include/escher/app.h index 792ab6ed8..8bbc8b60a 100644 --- a/escher/include/escher/app.h +++ b/escher/include/escher/app.h @@ -23,16 +23,24 @@ class App : public Responder { public: class Descriptor { public: - virtual App * build(Container * container) = 0; virtual I18n::Message name(); virtual I18n::Message upperName(); virtual const Image * icon(); }; - /* Each App subclass must implement - * static Descriptor * builDescriptor(); */ - Descriptor * descriptor(); + class Snapshot { + public: + virtual App * unpack(Container * container) = 0; + void pack(App * app); + /* reset all instances to their initial values */ + virtual void reset(); + virtual Descriptor * descriptor() = 0; + private: + /* tidy clean all dynamically-allocated data */ + virtual void tidy(); + }; virtual ~App() = default; constexpr static uint8_t Magic = 0xA8; + Snapshot * snapshot(); void setFirstResponder(Responder * responder); Responder * firstResponder(); bool processEvent(Ion::Events::Event event); @@ -46,12 +54,12 @@ public: virtual void didBecomeActive(Window * window); virtual void willBecomeInactive(); protected: - App(Container * container, ViewController * rootViewController, Descriptor * descriptor, I18n::Message warningMessage = (I18n::Message)0); + App(Container * container, Snapshot * snapshot, ViewController * rootViewController, I18n::Message warningMessage = (I18n::Message)0); ModalViewController m_modalViewController; private: - Descriptor * m_descriptor; Container * m_container; Responder * m_firstResponder; + Snapshot * m_snapshot; WarningController m_warningController; }; diff --git a/escher/include/escher/container.h b/escher/include/escher/container.h index 78343454c..8412274ff 100644 --- a/escher/include/escher/container.h +++ b/escher/include/escher/container.h @@ -26,7 +26,7 @@ public: void run(); App * activeApp(); virtual bool dispatchEvent(Ion::Events::Event event) override; - virtual void switchTo(App::Descriptor * descriptor); + virtual void switchTo(App::Snapshot * snapshot); protected: virtual Window * window() = 0; void windowRedraw() override; diff --git a/escher/src/app.cpp b/escher/src/app.cpp index b3bf406a7..4893ae0c4 100644 --- a/escher/src/app.cpp +++ b/escher/src/app.cpp @@ -16,19 +16,30 @@ const Image * App::Descriptor::icon() { return nullptr; } -App::App(Container * container, ViewController * rootViewController, Descriptor * descriptor, I18n::Message warningMessage) : +void App::Snapshot::pack(App * app) { + tidy(); + delete app; +} + +void App::Snapshot::reset() { +} + +void App::Snapshot::tidy() { +} + +App::App(Container * container, Snapshot * snapshot, ViewController * rootViewController, I18n::Message warningMessage) : Responder(nullptr), m_magic(Magic), m_modalViewController(this, rootViewController), - m_descriptor(descriptor), m_container(container), m_firstResponder(nullptr), + m_snapshot(snapshot), m_warningController(this, warningMessage) { } -App::Descriptor * App::descriptor() { - return m_descriptor; +App::Snapshot * App::snapshot() { + return m_snapshot; } bool App::processEvent(Ion::Events::Event event) { diff --git a/escher/src/container.cpp b/escher/src/container.cpp index cd7c273c1..2314eda06 100644 --- a/escher/src/container.cpp +++ b/escher/src/container.cpp @@ -13,13 +13,18 @@ Container::~Container() { } } -void Container::switchTo(App::Descriptor * descriptor) { +void Container::switchTo(App::Snapshot * snapshot) { + if (m_activeApp && snapshot == m_activeApp->snapshot()) { + return; + } if (m_activeApp) { m_activeApp->willBecomeInactive(); - delete m_activeApp; + m_activeApp->snapshot()->pack(m_activeApp); } - if (descriptor) { - m_activeApp = descriptor->build(this); + if (snapshot) { + m_activeApp = snapshot->unpack(this); + } else { + m_activeApp = nullptr; } if (m_activeApp) { m_activeApp->didBecomeActive(window());