diff --git a/apps/sequence/graph/curve_parameter_controller.cpp b/apps/sequence/graph/curve_parameter_controller.cpp index 6ab052623..4a9173ebb 100644 --- a/apps/sequence/graph/curve_parameter_controller.cpp +++ b/apps/sequence/graph/curve_parameter_controller.cpp @@ -24,7 +24,7 @@ bool CurveParameterController::handleEvent(Ion::Events::Event event) { { StackViewController * stack = (StackViewController *)parentResponder(); stack->pop(); - m_graphController->displayTermSumController(); + stack->push(m_graphController->termSumController()); return true; } case 1: diff --git a/apps/sequence/graph/graph_controller.cpp b/apps/sequence/graph/graph_controller.cpp index aeea2feb9..0b86a9602 100644 --- a/apps/sequence/graph/graph_controller.cpp +++ b/apps/sequence/graph/graph_controller.cpp @@ -29,15 +29,19 @@ const char * GraphController::emptyMessage() { return "Aucune suite activee"; } -void GraphController::displayTermSumController() { - m_termSumController.setSequence(m_sequenceStore->activeFunctionAtIndex(m_indexFunctionSelectedByCursor)); - stackController()->push(&m_termSumController); +TermSumController * GraphController::termSumController() { + return &m_termSumController; } BannerView * GraphController::bannerView() { return &m_bannerView; } +bool GraphController::handleEnter() { + m_termSumController.setSequence(m_sequenceStore->activeFunctionAtIndex(m_indexFunctionSelectedByCursor)); + return FunctionGraphController::handleEnter(); +} + bool GraphController::moveCursorHorizontally(int direction) { float xCursorPosition = roundf(m_cursor.x()); if (direction < 0 && xCursorPosition <= 0) { diff --git a/apps/sequence/graph/graph_controller.h b/apps/sequence/graph/graph_controller.h index 2e9216aba..a795d9f8e 100644 --- a/apps/sequence/graph/graph_controller.h +++ b/apps/sequence/graph/graph_controller.h @@ -16,9 +16,10 @@ public: GraphController(Responder * parentResponder, SequenceStore * sequenceStore, HeaderViewController * header); void viewWillAppear() override; const char * emptyMessage() override; - void displayTermSumController(); + TermSumController * termSumController(); private: BannerView * bannerView() override; + bool handleEnter() override; bool moveCursorHorizontally(int direction) override; void initCursorParameters() override; CurveViewRange * interactiveCurveViewRange() override; diff --git a/apps/sequence/graph/term_sum_controller.cpp b/apps/sequence/graph/term_sum_controller.cpp index 2a95ebb04..84720a1a4 100644 --- a/apps/sequence/graph/term_sum_controller.cpp +++ b/apps/sequence/graph/term_sum_controller.cpp @@ -1,9 +1,15 @@ #include "term_sum_controller.h" #include "../../shared/text_field_delegate.h" +#include "../../../poincare/src/layout/baseline_relative_layout.h" +#include "../../../poincare/src/layout/string_layout.h" +#include "../../../poincare/src/layout/horizontal_layout.h" + #include #include +#include using namespace Shared; +using namespace Poincare; namespace Sequence { @@ -13,7 +19,10 @@ TermSumController::TermSumController(Responder * parentResponder, GraphView * gr m_graphRange(graphRange), m_sequence(nullptr), m_cursor(cursor), - m_cursorView(VerticalCursorView()) + m_cursorView(VerticalCursorView()), + m_step(0), + m_startSum(-1), + m_endSum(-1) { } @@ -32,11 +41,20 @@ void TermSumController::viewWillAppear() { m_contentView.graphView()->selectMainView(true); m_contentView.graphView()->reload(); m_contentView.layoutSubviews(); + + m_startSum = -1; + m_endSum = -1; + m_step = 0; + m_contentView.legendView()->setLegendText("SELECTIONNER LE PREMIER TERME"); + m_contentView.legendView()->setSumSubscript(m_cursor->x()); } bool TermSumController::handleEvent(Ion::Events::Event event) { + if (m_step > 1 && event != Ion::Events::OK) { + return false; + } if (event == Ion::Events::Left) { - if (step > 0) { + if (m_step > 0 && m_startSum >= m_cursor->x()) { return false; } if (moveCursorHorizontallyToPosition(roundf(m_cursor->x()-1.0f))) { @@ -53,7 +71,7 @@ bool TermSumController::handleEvent(Ion::Events::Event event) { return false; } if (event.hasText() && event.text()[0] >= '0' && event.text()[0] <= '9') { - if (step > 0 && event.text()[0]-'0' < m_cursor->x()) { + if (m_step > 0 && event.text()[0]-'0' < m_cursor->x()) { return false; } if (moveCursorHorizontallyToPosition(event.text()[0]-'0')) { @@ -62,7 +80,29 @@ bool TermSumController::handleEvent(Ion::Events::Event event) { } return false; } - + if (event == Ion::Events::OK) { + if (m_step == 2) { + StackViewController * stack = (StackViewController *)parentResponder(); + stack->pop(); + return true; + } + if (m_step == 0) { + m_step++; + m_startSum = m_cursor->x(); + m_contentView.legendView()->setSumSuperscript(m_startSum, m_cursor->x()); + m_contentView.legendView()->setLegendText("SELECTIONNER LE DERNIER TERME"); + return true; + } + m_step++; + m_endSum = m_cursor->x(); + m_contentView.legendView()->setSequenceName(m_sequence->name()); + char buffer[2+Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; + strlcpy(buffer, "= ", 3); + TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); + float sum = m_sequence->sumOfTermsBetweenAbscissa(m_startSum, m_endSum, myApp->localContext()); + Complex::convertFloatToText(sum, buffer+2, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); + m_contentView.legendView()->setLegendText(buffer); + } return false; } @@ -77,6 +117,12 @@ bool TermSumController::moveCursorHorizontallyToPosition(int position) { } float y = m_sequence->evaluateAtAbscissa(x, myApp->localContext()); m_cursor->moveTo(x, y); + if (m_step == 0) { + m_contentView.legendView()->setSumSubscript(m_cursor->x()); + } + if (m_step == 1) { + m_contentView.legendView()->setSumSuperscript(m_startSum, m_cursor->x()); + } m_graphRange->panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio); return true; } @@ -92,6 +138,19 @@ TermSumController::ContentView::ContentView(GraphView * graphView) : { } +void TermSumController::ContentView::layoutSubviews() { + m_graphView->setFrame(bounds()); + m_legendView.setFrame(KDRect(0, bounds().height() - k_legendHeight, bounds().width(), k_legendHeight)); +} + +GraphView * TermSumController::ContentView::graphView() { + return m_graphView; +} + +TermSumController::ContentView::LegendView * TermSumController::ContentView::legendView() { + return &m_legendView; +} + int TermSumController::ContentView::numberOfSubviews() const { return 2; } @@ -104,27 +163,71 @@ View * TermSumController::ContentView::subviewAtIndex(int index) { return &m_legendView; } -void TermSumController::ContentView::layoutSubviews() { - m_graphView->setFrame(bounds()); - m_legendView.setFrame(KDRect(0, bounds().height() - k_legendHeight, bounds().width(), k_legendHeight)); -} - -GraphView * TermSumController::ContentView::graphView() { - return m_graphView; -} - /* Legend View */ TermSumController::ContentView::LegendView::LegendView() : m_sum(ExpressionView(0.0f, 0.5f, KDColorBlack, Palette::GreyBright)), - m_legend(PointerTextView(KDText::FontSize::Small, "SELECTIONNER LE PREMIER TERME", 0.0f, 0.5f, KDColorBlack, Palette::GreyBright)) + m_sumLayout(nullptr), + m_legend(BufferTextView(KDText::FontSize::Small, 0.0f, 0.5f, KDColorBlack, Palette::GreyBright)) { } +TermSumController::ContentView::LegendView::~LegendView() { + if (m_sumLayout != nullptr) { + delete m_sumLayout; + m_sumLayout = nullptr; + } +} + void TermSumController::ContentView::LegendView::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(KDRect(0, bounds().height() - k_legendHeight, bounds().width(), k_legendHeight), Palette::GreyBright); } +void TermSumController::ContentView::LegendView::setLegendText(const char * text) { + m_legend.setText(text); + layoutSubviews(); +} + +void TermSumController::ContentView::LegendView::setSumSubscript(float start) { + if (m_sumLayout) { + delete m_sumLayout; + m_sumLayout = nullptr; + } + const char sigma[2] = {Ion::Charset::CapitalSigma, 0}; + char buffer[Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; + Complex::convertFloatToText(start, buffer, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); + m_sumLayout = new BaselineRelativeLayout(new StringLayout(sigma, 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_sum.setExpression(m_sumLayout); + m_sum.setAlignment(0.0f, 0.5f); + layoutSubviews(); +} + +void TermSumController::ContentView::LegendView::setSumSuperscript(float start, float end) { + if (m_sumLayout) { + delete m_sumLayout; + m_sumLayout = nullptr; + } + const char sigma[2] = {Ion::Charset::CapitalSigma, 0}; + char bufferStart[Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; + Complex::convertFloatToText(start, bufferStart, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); + char bufferEnd[Complex::bufferSizeForFloatsWithPrecision(1)]; + Complex::convertFloatToText(end, bufferEnd, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); + ExpressionLayout * sigmaLayout = new BaselineRelativeLayout(new StringLayout(sigma, 1), new StringLayout(bufferStart, strlen(bufferStart), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_sumLayout = new BaselineRelativeLayout(sigmaLayout, new StringLayout(bufferEnd, strlen(bufferEnd), KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript); + m_sum.setExpression(m_sumLayout); + layoutSubviews(); +} + +void TermSumController::ContentView::LegendView::setSequenceName(const char * sequenceName) { + ExpressionLayout ** childrenLayouts = (ExpressionLayout **)malloc(2*sizeof(ExpressionLayout *)); + childrenLayouts[1] = new BaselineRelativeLayout(new StringLayout(sequenceName, 1, KDText::FontSize::Small), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + childrenLayouts[0] = m_sumLayout; + m_sumLayout = new HorizontalLayout(childrenLayouts, 2); + m_sum.setExpression(m_sumLayout); + m_sum.setAlignment(1.0f, 0.5f); + layoutSubviews(); +} + int TermSumController::ContentView::LegendView::numberOfSubviews() const { return 2; } @@ -140,6 +243,12 @@ View * TermSumController::ContentView::LegendView::subviewAtIndex(int index) { void TermSumController::ContentView::LegendView::layoutSubviews() { KDCoordinate width = bounds().width(); KDCoordinate heigth = bounds().height(); + KDSize legendSize = m_legend.minimalSizeForOptimalDisplay(); + if (legendSize.width() > width/2) { + m_sum.setFrame(KDRect(0, 0, width-legendSize.width(), heigth)); + m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth)); + return; + } m_sum.setFrame(KDRect(0, 0, width/2, heigth)); m_legend.setFrame(KDRect(width/2, 0, width/2, heigth)); } diff --git a/apps/sequence/graph/term_sum_controller.h b/apps/sequence/graph/term_sum_controller.h index 0acba1a81..31721c793 100644 --- a/apps/sequence/graph/term_sum_controller.h +++ b/apps/sequence/graph/term_sum_controller.h @@ -25,33 +25,42 @@ private: constexpr static float k_cursorLeftMarginRatio = 0.04f; // (cursorWidth/2)/graphViewWidth class ContentView : public View { public: - ContentView(GraphView * graphView); - void layoutSubviews() override; - GraphView * graphView(); - private: class LegendView : public View { public: LegendView(); + ~LegendView(); void drawRect(KDContext * ctx, KDRect rect) const override; + void setLegendText(const char * text); + void setSumSubscript(float start); + void setSumSuperscript(float start, float end); + void setSequenceName(const char * sequenceName); private: void layoutSubviews() override; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; ExpressionView m_sum; - PointerTextView m_legend; + Poincare::ExpressionLayout * m_sumLayout; + BufferTextView m_legend; }; + ContentView(GraphView * graphView); + void layoutSubviews() override; + GraphView * graphView(); + LegendView * legendView(); + private: int numberOfSubviews() const override; View * subviewAtIndex(int index) override; GraphView * m_graphView; LegendView m_legendView; - constexpr static KDCoordinate k_legendHeight = 28; + constexpr static KDCoordinate k_legendHeight = 35; }; ContentView m_contentView; CurveViewRange * m_graphRange; Sequence * m_sequence; Shared::CurveViewCursor * m_cursor; VerticalCursorView m_cursorView; - int step; + int m_step; + int m_startSum; + int m_endSum; }; } diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index f88adc4a3..2c2cc51fa 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -173,7 +173,6 @@ bool Sequence::isDefined() { } } - float Sequence::evaluateAtAbscissa(float x, Poincare::Context * context) const { float n = roundf(x); switch (m_type) { @@ -229,4 +228,12 @@ float Sequence::evaluateAtAbscissa(float x, Poincare::Context * context) const { } } +float Sequence::sumOfTermsBetweenAbscissa(float start, float end, Context * context) { + float result = 0.0f; + for (float i = roundf(start); i <= roundf(end); i = i + 1.0f) { + result += evaluateAtAbscissa(i, context); + } + return result; +} + } diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index 785809aa3..95caa4ca1 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -30,6 +30,7 @@ public: Poincare::ExpressionLayout * secondInitialConditionName(); bool isDefined() override; float evaluateAtAbscissa(float x, Poincare::Context * context) const override; + float sumOfTermsBetweenAbscissa(float start, float end, Poincare::Context * context); private: char symbol() const override; Type m_type; diff --git a/apps/shared/function_graph_controller.h b/apps/shared/function_graph_controller.h index cffaee7aa..f13e4ea7b 100644 --- a/apps/shared/function_graph_controller.h +++ b/apps/shared/function_graph_controller.h @@ -24,6 +24,7 @@ protected: constexpr static float k_cursorLeftMarginRatio = 0.04f; // (cursorWidth/2)/graphViewWidth constexpr static int k_maxNumberOfCharacters = 8; void reloadBannerView() override; + bool handleEnter() override; int m_indexFunctionSelectedByCursor; private: /* When y auto is ticked, we use a display margin to be ensure that the user @@ -31,7 +32,6 @@ private: constexpr static float k_displayTopMarginRatio = 0.09f; constexpr static float k_displayBottomMarginRatio = 0.2f; - bool handleEnter() override; void initRangeParameters() override; bool moveCursorVertically(int direction) override; CurveView * curveView() override;