diff --git a/apps/solver/base.de.i18n b/apps/solver/base.de.i18n index 3b935cb33..ab32b9dce 100644 --- a/apps/solver/base.de.i18n +++ b/apps/solver/base.de.i18n @@ -16,3 +16,5 @@ EnterEquation = "Entrez une équation" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." +OnlyFirstSolutionsDisplayed0 = "Seulement les 10 premières" +OnlyFirstSolutionsDisplayed1 = "solutions sont affichées" diff --git a/apps/solver/base.en.i18n b/apps/solver/base.en.i18n index 3b935cb33..ab32b9dce 100644 --- a/apps/solver/base.en.i18n +++ b/apps/solver/base.en.i18n @@ -16,3 +16,5 @@ EnterEquation = "Entrez une équation" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." +OnlyFirstSolutionsDisplayed0 = "Seulement les 10 premières" +OnlyFirstSolutionsDisplayed1 = "solutions sont affichées" diff --git a/apps/solver/base.es.i18n b/apps/solver/base.es.i18n index 3b935cb33..ab32b9dce 100644 --- a/apps/solver/base.es.i18n +++ b/apps/solver/base.es.i18n @@ -16,3 +16,5 @@ EnterEquation = "Entrez une équation" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." +OnlyFirstSolutionsDisplayed0 = "Seulement les 10 premières" +OnlyFirstSolutionsDisplayed1 = "solutions sont affichées" diff --git a/apps/solver/base.fr.i18n b/apps/solver/base.fr.i18n index 3b935cb33..ab32b9dce 100644 --- a/apps/solver/base.fr.i18n +++ b/apps/solver/base.fr.i18n @@ -16,3 +16,5 @@ EnterEquation = "Entrez une équation" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." +OnlyFirstSolutionsDisplayed0 = "Seulement les 10 premières" +OnlyFirstSolutionsDisplayed1 = "solutions sont affichées" diff --git a/apps/solver/base.pt.i18n b/apps/solver/base.pt.i18n index 3b935cb33..ab32b9dce 100644 --- a/apps/solver/base.pt.i18n +++ b/apps/solver/base.pt.i18n @@ -16,3 +16,5 @@ EnterEquation = "Entrez une équation" InfiniteNumberOfSolutions = "Le systeme admet une infinite de solutions" ApproximateSolutionIntervalInstruction0= "Entrez l'intervalle dans lequel" ApproximateSolutionIntervalInstruction1= "rechercher une solution approchée." +OnlyFirstSolutionsDisplayed0 = "Seulement les 10 premières" +OnlyFirstSolutionsDisplayed1 = "solutions sont affichées" diff --git a/apps/solver/equation_store.cpp b/apps/solver/equation_store.cpp index 50c89d89c..87c3f2dc0 100644 --- a/apps/solver/equation_store.cpp +++ b/apps/solver/equation_store.cpp @@ -55,11 +55,19 @@ double EquationStore::approximateSolutionAtIndex(int i) { return m_approximateSolutions[i]; } -bool EquationStore::approximateSolve(Poincare::Context * context) { +bool EquationStore::haveMoreApproximationSolutions(Context * context) const { + if (m_numberOfSolutions < k_maxNumberOfEquations) { + return false; + } + double step = (m_intervalApproximateSolutions[1]-m_intervalApproximateSolutions[0])*k_precision; + return !std::isnan(m_equations[0].standardForm(context)->nextRoot(m_variables[0], m_approximateSolutions[m_numberOfSolutions-1], step, m_intervalApproximateSolutions[1], *context)); +} + +void EquationStore::approximateSolve(Poincare::Context * context) { assert(m_variables[0] != 0 && m_variables[1] == 0); m_numberOfSolutions = 0; double start = m_intervalApproximateSolutions[0]; - double step = (m_intervalApproximateSolutions[1]-m_intervalApproximateSolutions[0])/100.0; + double step = (m_intervalApproximateSolutions[1]-m_intervalApproximateSolutions[0])*k_precision; for (int i = 0; i < k_maxNumberOfApproximateSolutions; i++) { m_approximateSolutions[i] = m_equations[0].standardForm(context)->nextRoot(m_variables[0], start, step, m_intervalApproximateSolutions[1], *context); if (std::isnan(m_approximateSolutions[i])) { @@ -69,10 +77,6 @@ bool EquationStore::approximateSolve(Poincare::Context * context) { m_numberOfSolutions++; } } - if (m_numberOfSolutions < k_maxNumberOfEquations) { - return true; - } - return std::isnan(m_equations[0].standardForm(context)->nextRoot(m_variables[0], start, step, m_intervalApproximateSolutions[1], *context)); } EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) { diff --git a/apps/solver/equation_store.h b/apps/solver/equation_store.h index 77e10c145..5d2e3f270 100644 --- a/apps/solver/equation_store.h +++ b/apps/solver/equation_store.h @@ -42,12 +42,14 @@ public: void setIntervalBound(int index, double value); double approximateSolutionAtIndex(int i); void tidy() override; + void approximateSolve(Poincare::Context * context); + bool haveMoreApproximationSolutions(Poincare::Context * context) const; Error exactSolve(Poincare::Context * context); - bool approximateSolve(Poincare::Context * context); static constexpr int k_maxNumberOfExactSolutions = Poincare::Expression::k_maxNumberOfVariables > Poincare::Expression::k_maxPolynomialDegree + 1? Poincare::Expression::k_maxNumberOfVariables : Poincare::Expression::k_maxPolynomialDegree + 1; static constexpr int k_maxNumberOfApproximateSolutions = 10; static constexpr int k_maxNumberOfSolutions = k_maxNumberOfExactSolutions > k_maxNumberOfApproximateSolutions ? k_maxNumberOfExactSolutions : k_maxNumberOfApproximateSolutions; private: + static constexpr double k_precision = 0.0001; static constexpr int k_maxNumberOfEquations = Poincare::Expression::k_maxNumberOfVariables; // Enable the same number of equations as the number of unknown variables Equation * emptyModel() override; Equation * nullModel() override { diff --git a/apps/solver/interval_controller.cpp b/apps/solver/interval_controller.cpp index 9b5e4ee7e..1d9196305 100644 --- a/apps/solver/interval_controller.cpp +++ b/apps/solver/interval_controller.cpp @@ -6,7 +6,7 @@ namespace Solver { -IntervalController::ContentView::ContentView(Responder * parentResponder, SelectableTableView * selectableTableView) : +IntervalController::ContentView::ContentView(SelectableTableView * selectableTableView) : m_instructions0(KDText::FontSize::Small, I18n::Message::ApproximateSolutionIntervalInstruction0, 0.5f, 0.5f, KDColorBlack, Palette::WallScreen), m_instructions1(KDText::FontSize::Small, I18n::Message::ApproximateSolutionIntervalInstruction1, 0.5f, 0.5f, KDColorBlack, Palette::WallScreen), m_selectableTableView(selectableTableView) @@ -111,7 +111,7 @@ View * IntervalController::loadView() { for (int i = 0; i < k_maxNumberOfCells; i++) { m_intervalCell[i] = new MessageTableCellWithEditableText(m_selectableTableView, this, m_draftTextBuffer); } - ContentView * contentView = (ContentView *)new ContentView(this, m_selectableTableView); + ContentView * contentView = (ContentView *)new ContentView(m_selectableTableView); return contentView; } diff --git a/apps/solver/interval_controller.h b/apps/solver/interval_controller.h index cb611f98d..7a608cc3a 100644 --- a/apps/solver/interval_controller.h +++ b/apps/solver/interval_controller.h @@ -25,7 +25,7 @@ private: void unloadView(View * view) override; class ContentView : public View { public: - ContentView(Responder * parentResponder, SelectableTableView * selectableTableView); + ContentView(SelectableTableView * selectableTableView); void drawRect(KDContext * ctx, KDRect rect) const override; private: constexpr static KDCoordinate k_topMargin = 50; diff --git a/apps/solver/solutions_controller.cpp b/apps/solver/solutions_controller.cpp index e42f54345..d74d4c431 100644 --- a/apps/solver/solutions_controller.cpp +++ b/apps/solver/solutions_controller.cpp @@ -9,20 +9,66 @@ using namespace Shared; namespace Solver { +SolutionsController::ContentView::ContentView(SolutionsController * controller) : + m_warningMessageView0(KDText::FontSize::Small, I18n::Message::OnlyFirstSolutionsDisplayed0, 0.5f, 0.5f, KDColorBlack, Palette::WallScreenDark), + m_warningMessageView1(KDText::FontSize::Small, I18n::Message::OnlyFirstSolutionsDisplayed1, 0.5f, 0.5f, KDColorBlack, Palette::WallScreenDark), + m_selectableTableView(controller), + m_displayWarningMoreSolutions(false) +{ + m_selectableTableView.setBackgroundColor(Palette::WallScreenDark); + m_selectableTableView.setVerticalCellOverlap(0); +} + +void SolutionsController::ContentView::drawRect(KDContext * ctx, KDRect rect) const { + if (m_displayWarningMoreSolutions) { + ctx->fillRect(KDRect(0, 0, bounds().width(), k_topMargin), Palette::WallScreenDark); + } +} + +void SolutionsController::ContentView::setWarningMoreSolutions(bool warning) { + m_displayWarningMoreSolutions = warning; + m_selectableTableView.setTopMargin(m_displayWarningMoreSolutions ? 0 : Metric::CommonTopMargin); + layoutSubviews(); + markRectAsDirty(bounds()); +} + +int SolutionsController::ContentView::numberOfSubviews() const { + return 1+2*m_displayWarningMoreSolutions; +} + +View * SolutionsController::ContentView::subviewAtIndex(int index) { + assert(index >= 0 && index < 1+2*m_displayWarningMoreSolutions); + if (index == 0 && m_displayWarningMoreSolutions) { + return &m_warningMessageView0; + } + if (index == 1 && m_displayWarningMoreSolutions) { + return &m_warningMessageView1; + } + return &m_selectableTableView; +} + +void SolutionsController::ContentView::layoutSubviews() { + if (m_displayWarningMoreSolutions) { + KDCoordinate textHeight = KDText::charSize(KDText::FontSize::Small).height(); + m_warningMessageView0.setFrame(KDRect(0, k_topMargin/2-textHeight, bounds().width(), textHeight)); + m_warningMessageView1.setFrame(KDRect(0, k_topMargin/2, bounds().width(), textHeight)); + m_selectableTableView.setFrame(KDRect(0, k_topMargin, bounds().width(), bounds().height()-k_topMargin)); + } else { + m_selectableTableView.setFrame(bounds()); + } +} + SolutionsController::SolutionsController(Responder * parentResponder, EquationStore * equationStore) : ViewController(parentResponder), m_equationStore(equationStore), m_deltaCell(0.5f, 0.5f), m_delta2Layout(nullptr), - m_selectableTableView(this) + m_contentView(this) { - m_selectableTableView.setBackgroundColor(Palette::WallScreenDark); - m_selectableTableView.setVerticalCellOverlap(0); - m_delta2Layout = new HorizontalLayout(new VerticalOffsetLayout(new CharLayout('2', KDText::FontSize::Small), VerticalOffsetLayout::Type::Superscript, false), LayoutEngine::createStringLayout("-4ac", 4, KDText::FontSize::Small), false); static_cast(m_delta2Layout)->addOrMergeChildAtIndex(new CharLayout('b', KDText::FontSize::Small), 0, false); for (int i = 0; i < EquationStore::k_maxNumberOfExactSolutions; i++) { - m_exactValueCells[i].setParentResponder(&m_selectableTableView); + m_exactValueCells[i].setParentResponder(m_contentView.selectableTableView()); } for (int i = 0; i < EquationStore::k_maxNumberOfApproximateSolutions; i++) { m_approximateValueCells[i].setFontSize(KDText::FontSize::Large); @@ -48,12 +94,14 @@ const char * SolutionsController::title() { } View * SolutionsController::view() { - return &m_selectableTableView; + return &m_contentView; } void SolutionsController::viewWillAppear() { ViewController::viewWillAppear(); - m_selectableTableView.reloadData(); + App * solverApp = static_cast(app()); + m_contentView.setWarningMoreSolutions(m_equationStore->haveMoreApproximationSolutions(solverApp->localContext())); + m_contentView.selectableTableView()->reloadData(); if (selectedRow() < 0) { selectCellAtLocation(0, 0); } @@ -235,7 +283,7 @@ int SolutionsController::typeAtLocation(int i, int j) { } void SolutionsController::didBecomeFirstResponder() { - app()->setFirstResponder(&m_selectableTableView); + app()->setFirstResponder(m_contentView.selectableTableView()); } } diff --git a/apps/solver/solutions_controller.h b/apps/solver/solutions_controller.h index 1b933aa66..93ebd6c85 100644 --- a/apps/solver/solutions_controller.h +++ b/apps/solver/solutions_controller.h @@ -35,7 +35,26 @@ public: int typeAtLocation(int i, int j) override; /* Responder */ void didBecomeFirstResponder() override; + private: + class ContentView : public View { + public: + ContentView(SolutionsController * controller); + void drawRect(KDContext * ctx, KDRect rect) const override; + void setWarningMoreSolutions(bool warning); + SelectableTableView * selectableTableView() { + return &m_selectableTableView; + } + private: + constexpr static KDCoordinate k_topMargin = 50; + int numberOfSubviews() const override; + View * subviewAtIndex(int index) override; + void layoutSubviews() override; + MessageTextView m_warningMessageView0; + MessageTextView m_warningMessageView1; + SelectableTableView m_selectableTableView; + bool m_displayWarningMoreSolutions; + }; constexpr static int k_symbolCellWidth = 90; constexpr static int k_valueCellWidth = 190; constexpr static KDCoordinate k_defaultCellHeight = 20; @@ -45,7 +64,7 @@ private: Poincare::ExpressionLayout * m_delta2Layout; Shared::ScrollableExactApproximateExpressionsCell m_exactValueCells[EquationStore::k_maxNumberOfExactSolutions]; EvenOddBufferTextCell m_approximateValueCells[EquationStore::k_maxNumberOfApproximateSolutions]; - SelectableTableView m_selectableTableView; + ContentView m_contentView; }; }