From 0bd796310c33e006def11c747bdf9592353f9911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 22 Feb 2017 18:05:56 +0100 Subject: [PATCH] [apps/shared] Move partial classes from grpah/graph to shared to be used by sequence Change-Id: I0e18be96cfaa92b6a51836ae8aa072fa6cf0f1af --- apps/graph/Makefile | 2 - .../graph/curve_parameter_controller.cpp | 33 +-- apps/graph/graph/curve_parameter_controller.h | 17 +- apps/graph/graph/goto_parameter_controller.h | 32 --- apps/graph/graph/graph_controller.cpp | 208 ++++-------------- apps/graph/graph/graph_controller.h | 38 +--- apps/graph/graph/graph_view.cpp | 31 +-- apps/graph/graph/graph_view.h | 13 +- apps/shared/Makefile | 5 + apps/shared/curve_view.h | 2 +- .../function_curve_parameter_controller.cpp | 43 ++++ .../function_curve_parameter_controller.h | 30 +++ apps/shared/function_graph_controller.cpp | 169 ++++++++++++++ apps/shared/function_graph_controller.h | 49 +++++ apps/shared/function_graph_view.cpp | 37 ++++ apps/shared/function_graph_view.h | 27 +++ .../go_to_parameter_controller.cpp} | 15 +- apps/shared/go_to_parameter_controller.h | 33 +++ .../initialisation_parameter_controller.cpp | 5 +- .../initialisation_parameter_controller.h | 10 +- escher/include/escher/app.h | 2 +- 21 files changed, 464 insertions(+), 337 deletions(-) delete mode 100644 apps/graph/graph/goto_parameter_controller.h create mode 100644 apps/shared/function_curve_parameter_controller.cpp create mode 100644 apps/shared/function_curve_parameter_controller.h create mode 100644 apps/shared/function_graph_controller.cpp create mode 100644 apps/shared/function_graph_controller.h create mode 100644 apps/shared/function_graph_view.cpp create mode 100644 apps/shared/function_graph_view.h rename apps/{graph/graph/goto_parameter_controller.cpp => shared/go_to_parameter_controller.cpp} (81%) create mode 100644 apps/shared/go_to_parameter_controller.h rename apps/{graph/graph => shared}/initialisation_parameter_controller.cpp (97%) rename apps/{graph/graph => shared}/initialisation_parameter_controller.h (76%) diff --git a/apps/graph/Makefile b/apps/graph/Makefile index 5ee8f67c8..cec09dd90 100644 --- a/apps/graph/Makefile +++ b/apps/graph/Makefile @@ -5,10 +5,8 @@ app_objs += $(addprefix apps/graph/,\ function_title_cell.o\ graph/banner_view.o\ graph/curve_parameter_controller.o\ - graph/goto_parameter_controller.o\ graph/graph_controller.o\ graph/graph_view.o\ - graph/initialisation_parameter_controller.o\ list/list_controller.o\ values/abscissa_parameter_controller.o\ values/derivative_parameter_controller.o\ diff --git a/apps/graph/graph/curve_parameter_controller.cpp b/apps/graph/graph/curve_parameter_controller.cpp index 2abdf672e..bba3c3fd4 100644 --- a/apps/graph/graph/curve_parameter_controller.cpp +++ b/apps/graph/graph/curve_parameter_controller.cpp @@ -6,15 +6,10 @@ using namespace Shared; namespace Graph { CurveParameterController::CurveParameterController(InteractiveCurveViewRange * graphRange, BannerView * bannerView, CurveViewCursor * cursor) : - ViewController(nullptr), + FunctionCurveParameterController(graphRange, cursor), m_bannerView(bannerView), - m_function(nullptr), m_calculationCell(PointerTableCellWithChevron((char*)"Calculer")), - m_goToCell(PointerTableCellWithChevron((char*)"Aller a")), - m_derivativeCell(PointerTableCellWithSwitch((char*)"Nombre derivee")), - m_selectableTableView(SelectableTableView(this, this, Metric::CommonTopMargin, Metric::CommonRightMargin, - Metric::CommonBottomMargin, Metric::CommonLeftMargin)), - m_goToParameterController(GoToParameterController(this, graphRange, cursor)) + m_derivativeCell(PointerTableCellWithSwitch((char*)"Nombre derivee")) { } @@ -22,15 +17,6 @@ const char * CurveParameterController::title() const { return "Options de la courbe"; } -View * CurveParameterController::view() { - return &m_selectableTableView; -} - -void CurveParameterController::didBecomeFirstResponder() { - m_selectableTableView.selectCellAtLocation(0, 0); - app()->setFirstResponder(&m_selectableTableView); -} - void CurveParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) { if (cell == &m_derivativeCell) { SwitchView * switchView = (SwitchView *)m_derivativeCell.accessoryView(); @@ -44,12 +30,7 @@ bool CurveParameterController::handleEvent(Ion::Events::Event event) { case 0: return true; case 1: - { - m_goToParameterController.setFunction(m_function); - StackViewController * stack = (StackViewController *)parentResponder(); - stack->push(&m_goToParameterController); - return true; - } + return handleGotoSelection(); case 2: { m_bannerView->setDisplayDerivative(!m_bannerView->displayDerivative()); @@ -78,12 +59,4 @@ int CurveParameterController::reusableCellCount() { return k_totalNumberOfCells; } -KDCoordinate CurveParameterController::cellHeight() { - return Metric::ParameterCellHeight; -} - -void CurveParameterController::setFunction(CartesianFunction * function) { - m_function = function; -} - } diff --git a/apps/graph/graph/curve_parameter_controller.h b/apps/graph/graph/curve_parameter_controller.h index b7c376fea..919035e3c 100644 --- a/apps/graph/graph/curve_parameter_controller.h +++ b/apps/graph/graph/curve_parameter_controller.h @@ -1,38 +1,25 @@ #ifndef GRAPH_GRAPH_CURVE_PARAMETER_CONTROLLER_H #define GRAPH_GRAPH_CURVE_PARAMETER_CONTROLLER_H -#include -#include "goto_parameter_controller.h" +#include "../../shared/function_curve_parameter_controller.h" #include "banner_view.h" -#include "../cartesian_function.h" -#include "../../shared/curve_view_cursor.h" -#include "../../shared/interactive_curve_view_range.h" namespace Graph { -class CurveParameterController : public ViewController, public SimpleListViewDataSource { +class CurveParameterController : public Shared::FunctionCurveParameterController { public: CurveParameterController(Shared::InteractiveCurveViewRange * graphRange, BannerView * bannerView, Shared::CurveViewCursor * cursor); - - View * view() override; const char * title() const override; bool handleEvent(Ion::Events::Event event) override; - void didBecomeFirstResponder() override; int numberOfRows() override; - KDCoordinate cellHeight() override; HighlightCell * reusableCell(int index) override; int reusableCellCount() override; void willDisplayCellForIndex(HighlightCell * cell, int index) override; - void setFunction(CartesianFunction * function); private: BannerView * m_bannerView; - CartesianFunction * m_function; constexpr static int k_totalNumberOfCells = 3; PointerTableCellWithChevron m_calculationCell; - PointerTableCellWithChevron m_goToCell; PointerTableCellWithSwitch m_derivativeCell; - SelectableTableView m_selectableTableView; - GoToParameterController m_goToParameterController; }; } diff --git a/apps/graph/graph/goto_parameter_controller.h b/apps/graph/graph/goto_parameter_controller.h deleted file mode 100644 index fa3c7651b..000000000 --- a/apps/graph/graph/goto_parameter_controller.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef GRAPH_GRAPH_GOTO_PARAMETER_CONTROLLER_H -#define GRAPH_GRAPH_GOTO_PARAMETER_CONTROLLER_H - -#include -#include "graph_view.h" -#include "../../shared/float_parameter_controller.h" -#include "../../shared/curve_view_cursor.h" -#include "../../shared/interactive_curve_view_range.h" - -namespace Graph { -class GoToParameterController : public Shared::FloatParameterController { -public: - GoToParameterController(Responder * parentResponder, Shared::InteractiveCurveViewRange * graphRange, Shared::CurveViewCursor * cursor); - const char * title() const override; - int numberOfRows() override; - HighlightCell * reusableCell(int index) override; - int reusableCellCount() override; - void setFunction(CartesianFunction * function); - bool textFieldDidFinishEditing(TextField * textField, const char * text) override; -private: - float parameterAtIndex(int index) override; - void setParameterAtIndex(int parameterIndex, float f) override; - char m_draftTextBuffer[PointerTableCellWithEditableText::k_bufferLength]; - PointerTableCellWithEditableText m_abscisseCell; - Shared::InteractiveCurveViewRange * m_graphRange; - Shared::CurveViewCursor * m_cursor; - CartesianFunction * m_function; -}; - -} - -#endif diff --git a/apps/graph/graph/graph_controller.cpp b/apps/graph/graph/graph_controller.cpp index 3419df864..fe087d4a3 100644 --- a/apps/graph/graph/graph_controller.cpp +++ b/apps/graph/graph/graph_controller.cpp @@ -1,172 +1,50 @@ #include "graph_controller.h" -#include "../app.h" -#include "../../apps_container.h" -#include -#include -#include -using namespace Poincare; using namespace Shared; +using namespace Poincare; namespace Graph { GraphController::GraphController(Responder * parentResponder, CartesianFunctionStore * functionStore, HeaderViewController * header) : - InteractiveCurveViewController(parentResponder, header, &m_graphRange, &m_view), + FunctionGraphController(parentResponder, header, &m_graphRange, &m_view), m_bannerView(BannerView()), m_view(GraphView(functionStore, &m_graphRange, &m_cursor, &m_bannerView, &m_cursorView)), m_graphRange(InteractiveCurveViewRange(&m_cursor, this)), - m_initialisationParameterController(InitialisationParameterController(this, &m_graphRange)), m_curveParameterController(CurveParameterController(&m_graphRange, &m_bannerView, &m_cursor)), - m_functionStore(functionStore), - m_indexFunctionSelectedByCursor(0) + m_functionStore(functionStore) { } -bool GraphController::isEmpty() const { - if (m_functionStore->numberOfActiveFunctions() == 0) { - return true; - } - return false; -} - const char * GraphController::emptyMessage() { if (m_functionStore->numberOfDefinedFunctions() == 0) { return "Aucune fonction"; } - return "Aucune fonction selectionnee"; -} - -ViewController * GraphController::initialisationParameterController() { - return &m_initialisationParameterController; -} - -void GraphController::viewWillAppear() { - if (m_view.context() == nullptr) { - App * graphApp = (Graph::App *)app(); - m_view.setContext(graphApp->localContext()); - } - Expression::AngleUnit newAngleUnitVersion = Preferences::sharedPreferences()->angleUnit(); - if (m_angleUnitVersion != newAngleUnitVersion) { - m_angleUnitVersion = newAngleUnitVersion; - initCursorParameters(); - } - InteractiveCurveViewController::viewWillAppear(); -} - -bool GraphController::didChangeRange(InteractiveCurveViewRange * interactiveCurveViewRange) { - if (!m_graphRange.yAuto()) { - return false; - } - App * graphApp = (Graph::App *)app(); - if (m_functionStore->numberOfActiveFunctions() <= 0) { - return false; - } - float min = FLT_MAX; - float max = -FLT_MAX; - float xMin = m_graphRange.xMin(); - float xMax = m_graphRange.xMax(); - float step = (xMax - xMin)/Ion::Display::Width; - for (int i=0; inumberOfActiveFunctions(); i++) { - CartesianFunction * f = m_functionStore->activeFunctionAtIndex(i); - float y = 0.0f; - for (int i = 0; i <= Ion::Display::Width; i++) { - float x = xMin + i*step; - y = f->evaluateAtAbscissa(x, graphApp->localContext()); - if (!isnan(y) && !isinf(y)) { - min = min < y ? min : y; - max = max > y ? max : y; - } - } - } - float range = max - min; - if (m_graphRange.yMin() == min-k_displayBottomMarginRatio*range - && m_graphRange.yMax() == max+k_displayTopMarginRatio*range) { - return false; - } - if (min == max) { - min = min - 1; - max = max + 1; - } - if (min == FLT_MAX && max == -FLT_MAX) { - min = -1.0f; - max = 1.0f; - } - if (min == FLT_MAX) { - min = max-1.0f; - } - if (max == -FLT_MAX) { - max = min+1.0f; - } - m_graphRange.setYMin(min-k_displayBottomMarginRatio*range); - m_graphRange.setYMax(max+k_displayTopMarginRatio*range); - if (isinf(m_graphRange.xMin())) { - m_graphRange.setYMin(-FLT_MAX); - } - if (isinf(m_graphRange.xMax())) { - m_graphRange.setYMax(FLT_MAX); - } - return true; + return "Aucune fonction activee"; } BannerView * GraphController::bannerView() { return &m_bannerView; } -bool GraphController::handleEnter() { - CartesianFunction * f = m_functionStore->activeFunctionAtIndex(m_indexFunctionSelectedByCursor); - m_curveParameterController.setFunction(f); - StackViewController * stack = stackController(); - stack->push(&m_curveParameterController); - return true; -} - void GraphController::reloadBannerView() { + FunctionGraphController::reloadBannerView(); + if (!m_bannerView.displayDerivative()) { + return; + } char buffer[k_maxNumberOfCharacters+Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; - const char * legend = "x = "; + const char * legend = "00(x) = "; int legendLength = strlen(legend); strlcpy(buffer, legend, legendLength+1); - Complex::convertFloatToText(m_cursor.x(), buffer+ legendLength, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - m_bannerView.setLegendAtIndex(buffer, 0); - - legend = "00(x) = "; - legendLength = strlen(legend); - strlcpy(buffer, legend, legendLength+1); if (m_functionStore->numberOfActiveFunctions() == 0) { return; } CartesianFunction * f = m_functionStore->activeFunctionAtIndex(m_indexFunctionSelectedByCursor); - buffer[1] = f->name()[0]; - Complex::convertFloatToText(m_cursor.y(), buffer+legendLength, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - m_bannerView.setLegendAtIndex(buffer+1, 1); - - if (m_bannerView.displayDerivative()) { - buffer[0] = f->name()[0]; - buffer[1] = '\''; - App * graphApp = (Graph::App *)app(); - float y = f->approximateDerivative(m_cursor.x(), graphApp->localContext()); - Complex::convertFloatToText(y, buffer + legendLength, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - m_bannerView.setLegendAtIndex(buffer, 2); - } -} - -void GraphController::initRangeParameters() { - if (didChangeRange(&m_graphRange)) { - initCursorParameters(); - } -} - -void GraphController::initCursorParameters() { - float x = (m_graphRange.xMin()+m_graphRange.xMax())/2.0f; - m_indexFunctionSelectedByCursor = 0; - App * graphApp = (Graph::App *)app(); - int functionIndex = 0; - float y = 0; - do { - CartesianFunction * firstFunction = m_functionStore->activeFunctionAtIndex(functionIndex++); - y = firstFunction->evaluateAtAbscissa(x, graphApp->localContext()); - } while (isnan(y) && functionIndex < m_functionStore->numberOfActiveFunctions()); - m_cursor.moveTo(x, y); - m_graphRange.panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio); + buffer[0] = f->name()[0]; + buffer[1] = '\''; + TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); + float y = f->approximateDerivative(m_cursor.x(), myApp->localContext()); + Complex::convertFloatToText(y, buffer + legendLength, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); + m_bannerView.setLegendAtIndex(buffer, 2); } bool GraphController::moveCursorHorizontally(int direction) { @@ -174,51 +52,41 @@ bool GraphController::moveCursorHorizontally(int direction) { float x = direction > 0 ? xCursorPosition + m_graphRange.xGridUnit()/k_numberOfCursorStepsInGradUnit : xCursorPosition - m_graphRange.xGridUnit()/k_numberOfCursorStepsInGradUnit; CartesianFunction * f = m_functionStore->activeFunctionAtIndex(m_indexFunctionSelectedByCursor); - App * graphApp = (Graph::App *)app(); - float y = f->evaluateAtAbscissa(x, graphApp->localContext()); + TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); + float y = f->evaluateAtAbscissa(x, myApp->localContext()); m_cursor.moveTo(x, y); m_graphRange.panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio); return true; } -bool GraphController::moveCursorVertically(int direction) { - CartesianFunction * actualFunction = m_functionStore->activeFunctionAtIndex(m_indexFunctionSelectedByCursor); - App * graphApp = (Graph::App *)app(); - float y = actualFunction->evaluateAtAbscissa(m_cursor.x(), graphApp->localContext()); - CartesianFunction * nextFunction = actualFunction; - float nextY = direction > 0 ? FLT_MAX : -FLT_MAX; - for (int i = 0; i < m_functionStore->numberOfActiveFunctions(); i++) { - CartesianFunction * f = m_functionStore->activeFunctionAtIndex(i); - float newY = f->evaluateAtAbscissa(m_cursor.x(), graphApp->localContext()); - bool isNextFunction = direction > 0 ? (newY > y && newY < nextY) : (newY < y && newY > nextY); - if (isNextFunction) { - m_indexFunctionSelectedByCursor = i; - nextY = newY; - nextFunction = f; - } - } - if (nextFunction == actualFunction) { - return false; - } - m_cursor.moveTo(m_cursor.x(), nextY); - m_graphRange.panToMakePointVisible(m_cursor.x(), m_cursor.y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio); - return true; -} - -uint32_t GraphController::modelVersion() { - return m_functionStore->storeChecksum(); -} - -uint32_t GraphController::rangeVersion() { - return m_graphRange.rangeChecksum(); +void GraphController::initCursorParameters() { + float x = (interactiveCurveViewRange()->xMin()+interactiveCurveViewRange()->xMax())/2.0f; + m_indexFunctionSelectedByCursor = 0; + TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); + int functionIndex = 0; + float y = 0; + do { + CartesianFunction * firstFunction = functionStore()->activeFunctionAtIndex(functionIndex++); + y = firstFunction->evaluateAtAbscissa(x, myApp->localContext()); + } while (isnan(y) && functionIndex < functionStore()->numberOfActiveFunctions()); + m_cursor.moveTo(x, y); + interactiveCurveViewRange()->panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio); } InteractiveCurveViewRange * GraphController::interactiveCurveViewRange() { return &m_graphRange; } -CurveView * GraphController::curveView() { +CartesianFunctionStore * GraphController::functionStore() const { + return m_functionStore; +} + +GraphView * GraphController::functionGraphView() { return &m_view; } +CurveParameterController * GraphController::curveParameterController() { + return &m_curveParameterController; +} + } diff --git a/apps/graph/graph/graph_controller.h b/apps/graph/graph/graph_controller.h index a37d70e59..dbe7c3d85 100644 --- a/apps/graph/graph/graph_controller.h +++ b/apps/graph/graph/graph_controller.h @@ -1,56 +1,32 @@ #ifndef GRAPH_GRAPH_CONTROLLER_H #define GRAPH_GRAPH_CONTROLLER_H -#include #include "graph_view.h" #include "banner_view.h" #include "curve_parameter_controller.h" -#include "initialisation_parameter_controller.h" -#include "../../shared/interactive_curve_view_controller.h" +#include "../../shared/function_graph_controller.h" #include "../cartesian_function_store.h" namespace Graph { -class GraphController : public Shared::InteractiveCurveViewController, public Shared::InteractiveCurveViewRangeDelegate { + +class GraphController : public Shared::FunctionGraphController { public: GraphController(Responder * parentResponder, CartesianFunctionStore * functionStore, HeaderViewController * header); - void viewWillAppear() override; - ViewController * initialisationParameterController() override; - - bool isEmpty() const override; const char * emptyMessage() override; - - bool didChangeRange(Shared::InteractiveCurveViewRange * interactiveCurveViewRange) override; private: - constexpr static float k_cursorTopMarginRatio = 0.07f; // (cursorHeight/2)/graphViewHeight - constexpr static float k_cursorRightMarginRatio = 0.04f; // (cursorWidth/2)/graphViewWidth - constexpr static float k_cursorBottomMarginRatio = 0.15f; // (cursorHeight/2+bannerHeigh)/graphViewHeight - constexpr static float k_cursorLeftMarginRatio = 0.04f; // (cursorWidth/2)/graphViewWidth - - /* When y auto is ticked, we use a display margin to be ensure that the user - * can move the cursor along the curve without panning the window */ - constexpr static float k_displayTopMarginRatio = 0.09f; - constexpr static float k_displayBottomMarginRatio = 0.2f; - - constexpr static int k_maxNumberOfCharacters = 8; BannerView * bannerView() override; - bool handleEnter() override; void reloadBannerView() override; - void initRangeParameters() override; - void initCursorParameters() override; bool moveCursorHorizontally(int direction) override; - bool moveCursorVertically(int direction) override; - uint32_t modelVersion() override; - uint32_t rangeVersion() override; + void initCursorParameters() override; Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override; - Shared::CurveView * curveView() override; + CartesianFunctionStore * functionStore() const override; + GraphView * functionGraphView() override; + CurveParameterController * curveParameterController() override; BannerView m_bannerView; GraphView m_view; Shared::InteractiveCurveViewRange m_graphRange; - InitialisationParameterController m_initialisationParameterController; CurveParameterController m_curveParameterController; CartesianFunctionStore * m_functionStore; - int m_indexFunctionSelectedByCursor; - Poincare::Expression::AngleUnit m_angleUnitVersion; }; } diff --git a/apps/graph/graph/graph_view.cpp b/apps/graph/graph/graph_view.cpp index ecd1333ba..ec35f887f 100644 --- a/apps/graph/graph/graph_view.cpp +++ b/apps/graph/graph/graph_view.cpp @@ -1,48 +1,27 @@ #include "graph_view.h" -#include -#include -#include -using namespace Poincare; + using namespace Shared; namespace Graph { GraphView::GraphView(CartesianFunctionStore * functionStore, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, BannerView * bannerView, View * cursorView) : - CurveView(graphRange, cursor, bannerView, cursorView), - m_functionStore(functionStore), - m_context(nullptr) + FunctionGraphView(graphRange, cursor, bannerView, cursorView), + m_functionStore(functionStore) { } void GraphView::drawRect(KDContext * ctx, KDRect rect) const { - ctx->fillRect(rect, KDColorWhite); - drawGrid(ctx, rect); - drawAxes(ctx, rect, Axis::Horizontal); - drawAxes(ctx, rect, Axis::Vertical); - drawLabels(ctx, rect, Axis::Horizontal, true); - drawLabels(ctx, rect, Axis::Vertical, true); + FunctionGraphView::drawRect(ctx, rect); for (int i = 0; i < m_functionStore->numberOfActiveFunctions(); i++) { CartesianFunction * f = m_functionStore->activeFunctionAtIndex(i); drawCurve(ctx, rect, f, f->color()); } } -void GraphView::setContext(Context * context) { - m_context = context; -} - -Context * GraphView::context() const { - return m_context; -} - -char * GraphView::label(Axis axis, int index) const { - return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]); -} - float GraphView::evaluateModelWithParameter(Model * curve, float abscissa) const { CartesianFunction * f = (CartesianFunction *)curve; - return f->evaluateAtAbscissa(abscissa, m_context); + return f->evaluateAtAbscissa(abscissa, context()); } } diff --git a/apps/graph/graph/graph_view.h b/apps/graph/graph/graph_view.h index 4fccb1d2f..cd5f30c68 100644 --- a/apps/graph/graph/graph_view.h +++ b/apps/graph/graph/graph_view.h @@ -1,28 +1,19 @@ #ifndef GRAPH_GRAPH_VIEW_H #define GRAPH_GRAPH_VIEW_H -#include -#include "../../shared/curve_view.h" -#include "../../constant.h" +#include "../../shared/function_graph_view.h" #include "../cartesian_function_store.h" -#include "../../shared/interactive_curve_view_range.h" namespace Graph { -class GraphView : public Shared::CurveView { +class GraphView : public Shared::FunctionGraphView { public: GraphView(CartesianFunctionStore * functionStore, Shared::InteractiveCurveViewRange * graphRange, Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, View * cursorView); void drawRect(KDContext * ctx, KDRect rect) const override; - void setContext(Poincare::Context * context); - Poincare::Context * context() const; private: - char * label(Axis axis, int index) const override; float evaluateModelWithParameter(Model * expression, float abscissa) const override; - char m_xLabels[k_maxNumberOfXLabels][Poincare::Complex::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; - char m_yLabels[k_maxNumberOfYLabels][Poincare::Complex::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; CartesianFunctionStore * m_functionStore; - Poincare::Context * m_context; }; } diff --git a/apps/shared/Makefile b/apps/shared/Makefile index 00831079a..91c9bf67a 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -8,9 +8,14 @@ app_objs += $(addprefix apps/shared/,\ float_pair_store.o\ float_parameter_controller.o\ function.o\ + function_curve_parameter_controller.o\ + function_graph_view.o\ + function_graph_controller.o\ function_store.o\ function_expression_cell.o\ function_title_cell.o\ + go_to_parameter_controller.o\ + initialisation_parameter_controller.o\ interactive_curve_view_controller.o\ interactive_curve_view_range.o\ list_controller.o\ diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 8903d0fca..c49f51d11 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -32,6 +32,7 @@ protected: constexpr static int k_maxNumberOfXLabels = CurveViewRange::k_maxNumberOfXGridUnits; constexpr static int k_maxNumberOfYLabels = CurveViewRange::k_maxNumberOfYGridUnits; constexpr static KDCoordinate k_cursorSize = 25; + constexpr static int k_externRectMargin = 1; float pixelToFloat(Axis axis, KDCoordinate p) const; float floatToPixel(Axis axis, float f) const; void drawLine(KDContext * ctx, KDRect rect, Axis axis, @@ -50,7 +51,6 @@ protected: void drawLabels(KDContext * ctx, KDRect rect, Axis axis, bool shiftOrigin) const; private: - constexpr static int k_externRectMargin = 1; /* The window bounds are deduced from the model bounds but also take into account a margin (computed with k_marginFactor) */ float min(Axis axis) const; diff --git a/apps/shared/function_curve_parameter_controller.cpp b/apps/shared/function_curve_parameter_controller.cpp new file mode 100644 index 000000000..f88cdcf5c --- /dev/null +++ b/apps/shared/function_curve_parameter_controller.cpp @@ -0,0 +1,43 @@ +#include "function_curve_parameter_controller.h" +#include + +namespace Shared { + +FunctionCurveParameterController::FunctionCurveParameterController(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor) : + ViewController(nullptr), + m_goToCell(PointerTableCellWithChevron((char*)"Aller a")), + m_selectableTableView(SelectableTableView(this, this, Metric::CommonTopMargin, Metric::CommonRightMargin, + Metric::CommonBottomMargin, Metric::CommonLeftMargin)), + m_goToParameterController(GoToParameterController(this, graphRange, cursor)), + m_function(nullptr) +{ +} + +View * FunctionCurveParameterController::view() { + return &m_selectableTableView; +} + +void FunctionCurveParameterController::didBecomeFirstResponder() { + m_selectableTableView.selectCellAtLocation(0, 0); + app()->setFirstResponder(&m_selectableTableView); +} + +bool FunctionCurveParameterController::handleGotoSelection() { + if (m_function == nullptr) { + return false; + } + m_goToParameterController.setFunction(m_function); + StackViewController * stack = (StackViewController *)parentResponder(); + stack->push(&m_goToParameterController); + return true; +} + +KDCoordinate FunctionCurveParameterController::cellHeight() { + return Metric::ParameterCellHeight; +} + +void FunctionCurveParameterController::setFunction(Function * function) { + m_function = function; +} + +} diff --git a/apps/shared/function_curve_parameter_controller.h b/apps/shared/function_curve_parameter_controller.h new file mode 100644 index 000000000..56e8946c8 --- /dev/null +++ b/apps/shared/function_curve_parameter_controller.h @@ -0,0 +1,30 @@ +#ifndef SHARED_FUNCTION_CURVE_PARAMETER_CONTROLLER_H +#define SHARED_FUNCTION_CURVE_PARAMETER_CONTROLLER_H + +#include +#include "go_to_parameter_controller.h" +#include "function.h" +#include "curve_view_cursor.h" +#include "interactive_curve_view_range.h" + +namespace Shared { + +class FunctionCurveParameterController : public ViewController, public SimpleListViewDataSource { +public: + FunctionCurveParameterController(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor); + View * view() override; + void didBecomeFirstResponder() override; + KDCoordinate cellHeight() override; + void setFunction(Function * function); +protected: + bool handleGotoSelection(); + PointerTableCellWithChevron m_goToCell; + SelectableTableView m_selectableTableView; +private: + GoToParameterController m_goToParameterController; + Function * m_function; +}; + +} + +#endif diff --git a/apps/shared/function_graph_controller.cpp b/apps/shared/function_graph_controller.cpp new file mode 100644 index 000000000..89ed200a0 --- /dev/null +++ b/apps/shared/function_graph_controller.cpp @@ -0,0 +1,169 @@ +#include "function_graph_controller.h" +#include "text_field_delegate_app.h" +#include +#include +#include + +using namespace Poincare; + +namespace Shared { + +FunctionGraphController::FunctionGraphController(Responder * parentResponder, HeaderViewController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView) : + InteractiveCurveViewController(parentResponder, header, interactiveRange, curveView), + m_indexFunctionSelectedByCursor(0), + m_initialisationParameterController(InitialisationParameterController(this, interactiveRange)) +{ +} + +bool FunctionGraphController::isEmpty() const { + if (functionStore()->numberOfActiveFunctions() == 0) { + return true; + } + return false; +} + +ViewController * FunctionGraphController::initialisationParameterController() { + return &m_initialisationParameterController; +} + +void FunctionGraphController::viewWillAppear() { + if (functionGraphView()->context() == nullptr) { + TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); + functionGraphView()->setContext(myApp->localContext()); + } + Expression::AngleUnit newAngleUnitVersion = Preferences::sharedPreferences()->angleUnit(); + if (m_angleUnitVersion != newAngleUnitVersion) { + m_angleUnitVersion = newAngleUnitVersion; + initCursorParameters(); + } + InteractiveCurveViewController::viewWillAppear(); +} + +bool FunctionGraphController::didChangeRange(InteractiveCurveViewRange * interactiveCurveViewRange) { + if (!interactiveCurveViewRange->yAuto()) { + return false; + } + TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); + if (functionStore()->numberOfActiveFunctions() <= 0) { + return false; + } + float min = FLT_MAX; + float max = -FLT_MAX; + float xMin = interactiveCurveViewRange->xMin(); + float xMax = interactiveCurveViewRange->xMax(); + float step = (xMax - xMin)/Ion::Display::Width; + for (int i=0; inumberOfActiveFunctions(); i++) { + Function * f = functionStore()->activeFunctionAtIndex(i); + float y = 0.0f; + for (int i = 0; i <= Ion::Display::Width; i++) { + float x = xMin + i*step; + y = f->evaluateAtAbscissa(x, myApp->localContext()); + if (!isnan(y) && !isinf(y)) { + min = min < y ? min : y; + max = max > y ? max : y; + } + } + } + float range = max - min; + if (interactiveCurveViewRange->yMin() == min-k_displayBottomMarginRatio*range + && interactiveCurveViewRange->yMax() == max+k_displayTopMarginRatio*range) { + return false; + } + if (min == max) { + min = min - 1; + max = max + 1; + } + if (min == FLT_MAX && max == -FLT_MAX) { + min = -1.0f; + max = 1.0f; + } + if (min == FLT_MAX) { + min = max-1.0f; + } + if (max == -FLT_MAX) { + max = min+1.0f; + } + interactiveCurveViewRange->setYMin(min-k_displayBottomMarginRatio*range); + interactiveCurveViewRange->setYMax(max+k_displayTopMarginRatio*range); + if (isinf(interactiveCurveViewRange->xMin())) { + interactiveCurveViewRange->setYMin(-FLT_MAX); + } + if (isinf(interactiveCurveViewRange->xMax())) { + interactiveCurveViewRange->setYMax(FLT_MAX); + } + return true; +} + +bool FunctionGraphController::handleEnter() { + Function * f = functionStore()->activeFunctionAtIndex(m_indexFunctionSelectedByCursor); + curveParameterController()->setFunction(f); + StackViewController * stack = stackController(); + stack->push(curveParameterController()); + return true; +} + +void FunctionGraphController::reloadBannerView() { + char buffer[k_maxNumberOfCharacters+Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; + const char * legend = "0 = "; + int legendLength = strlen(legend); + strlcpy(buffer, legend, legendLength+1); + buffer[0] = functionStore()->symbol(); + Complex::convertFloatToText(m_cursor.x(), buffer+ legendLength, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); + bannerView()->setLegendAtIndex(buffer, 0); + + legend = "0(x) = "; + legendLength = strlen(legend); + strlcpy(buffer, legend, legendLength+1); + buffer[2] = functionStore()->symbol(); + if (functionStore()->numberOfActiveFunctions() == 0) { + return; + } + Function * f = functionStore()->activeFunctionAtIndex(m_indexFunctionSelectedByCursor); + buffer[0] = f->name()[0]; + Complex::convertFloatToText(m_cursor.y(), buffer+legendLength, Complex::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); + bannerView()->setLegendAtIndex(buffer, 1); +} + +void FunctionGraphController::initRangeParameters() { + if (didChangeRange(interactiveCurveViewRange())) { + initCursorParameters(); + } +} + +bool FunctionGraphController::moveCursorVertically(int direction) { + Function * actualFunction = functionStore()->activeFunctionAtIndex(m_indexFunctionSelectedByCursor); + TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); + float y = actualFunction->evaluateAtAbscissa(m_cursor.x(), myApp->localContext()); + Function * nextFunction = actualFunction; + float nextY = direction > 0 ? FLT_MAX : -FLT_MAX; + for (int i = 0; i < functionStore()->numberOfActiveFunctions(); i++) { + Function * f = functionStore()->activeFunctionAtIndex(i); + float newY = f->evaluateAtAbscissa(m_cursor.x(), myApp->localContext()); + bool isNextFunction = direction > 0 ? (newY > y && newY < nextY) : (newY < y && newY > nextY); + if (isNextFunction) { + m_indexFunctionSelectedByCursor = i; + nextY = newY; + nextFunction = f; + } + } + if (nextFunction == actualFunction) { + return false; + } + m_cursor.moveTo(m_cursor.x(), nextY); + interactiveCurveViewRange()->panToMakePointVisible(m_cursor.x(), m_cursor.y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio); + return true; +} + +CurveView * FunctionGraphController::curveView() { + return functionGraphView(); +} + +uint32_t FunctionGraphController::modelVersion() { + return functionStore()->storeChecksum(); +} + +uint32_t FunctionGraphController::rangeVersion() { + return interactiveCurveViewRange()->rangeChecksum(); +} + +} diff --git a/apps/shared/function_graph_controller.h b/apps/shared/function_graph_controller.h new file mode 100644 index 000000000..cffaee7aa --- /dev/null +++ b/apps/shared/function_graph_controller.h @@ -0,0 +1,49 @@ +#ifndef SHARED_FUNCTION_GRAPH_CONTROLLER_H +#define SHARED_FUNCTION_GRAPH_CONTROLLER_H + +#include +#include "initialisation_parameter_controller.h" +#include "interactive_curve_view_controller.h" +#include "function_store.h" +#include "function_graph_view.h" +#include "function_curve_parameter_controller.h" + +namespace Shared { + +class FunctionGraphController : public InteractiveCurveViewController, public InteractiveCurveViewRangeDelegate { +public: + FunctionGraphController(Responder * parentResponder, HeaderViewController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView); + bool isEmpty() const override; + ViewController * initialisationParameterController() override; + void viewWillAppear() override; + bool didChangeRange(Shared::InteractiveCurveViewRange * interactiveCurveViewRange) override; +protected: + constexpr static float k_cursorTopMarginRatio = 0.07f; // (cursorHeight/2)/graphViewHeight + constexpr static float k_cursorRightMarginRatio = 0.04f; // (cursorWidth/2)/graphViewWidth + constexpr static float k_cursorBottomMarginRatio = 0.15f; // (cursorHeight/2+bannerHeigh)/graphViewHeight + constexpr static float k_cursorLeftMarginRatio = 0.04f; // (cursorWidth/2)/graphViewWidth + constexpr static int k_maxNumberOfCharacters = 8; + void reloadBannerView() override; + int m_indexFunctionSelectedByCursor; +private: + /* When y auto is ticked, we use a display margin to be ensure that the user + * can move the cursor along the curve without panning the window */ + 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; + uint32_t modelVersion() override; + uint32_t rangeVersion() override; + virtual FunctionStore * functionStore() const = 0; + virtual FunctionGraphView * functionGraphView() = 0; + virtual FunctionCurveParameterController * curveParameterController() = 0; + InitialisationParameterController m_initialisationParameterController; + Poincare::Expression::AngleUnit m_angleUnitVersion; +}; + +} + +#endif diff --git a/apps/shared/function_graph_view.cpp b/apps/shared/function_graph_view.cpp new file mode 100644 index 000000000..c7b372e23 --- /dev/null +++ b/apps/shared/function_graph_view.cpp @@ -0,0 +1,37 @@ +#include "function_graph_view.h" +#include +#include +#include +using namespace Poincare; + +namespace Shared { + +FunctionGraphView::FunctionGraphView(InteractiveCurveViewRange * graphRange, + CurveViewCursor * cursor, BannerView * bannerView, View * cursorView) : + CurveView(graphRange, cursor, bannerView, cursorView), + m_context(nullptr) +{ +} + +void FunctionGraphView::drawRect(KDContext * ctx, KDRect rect) const { + ctx->fillRect(rect, KDColorWhite); + drawGrid(ctx, rect); + drawAxes(ctx, rect, Axis::Horizontal); + drawAxes(ctx, rect, Axis::Vertical); + drawLabels(ctx, rect, Axis::Horizontal, true); + drawLabels(ctx, rect, Axis::Vertical, true); +} + +void FunctionGraphView::setContext(Context * context) { + m_context = context; +} + +Context * FunctionGraphView::context() const { + return m_context; +} + +char * FunctionGraphView::label(Axis axis, int index) const { + return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]); +} + +} diff --git a/apps/shared/function_graph_view.h b/apps/shared/function_graph_view.h new file mode 100644 index 000000000..d0159ecd2 --- /dev/null +++ b/apps/shared/function_graph_view.h @@ -0,0 +1,27 @@ +#ifndef SHARED_FUNCTION_GRAPH_VIEW_H +#define SHARED_FUNCTION_GRAPH_VIEW_H + +#include +#include "curve_view.h" +#include "../constant.h" +#include "interactive_curve_view_range.h" + +namespace Shared { + +class FunctionGraphView : public CurveView { +public: + FunctionGraphView(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, + BannerView * bannerView, View * cursorView); + void drawRect(KDContext * ctx, KDRect rect) const override; + void setContext(Poincare::Context * context); + Poincare::Context * context() const; +private: + char * label(Axis axis, int index) const override; + char m_xLabels[k_maxNumberOfXLabels][Poincare::Complex::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; + char m_yLabels[k_maxNumberOfYLabels][Poincare::Complex::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; + Poincare::Context * m_context; +}; + +} + +#endif diff --git a/apps/graph/graph/goto_parameter_controller.cpp b/apps/shared/go_to_parameter_controller.cpp similarity index 81% rename from apps/graph/graph/goto_parameter_controller.cpp rename to apps/shared/go_to_parameter_controller.cpp index decdadd2e..ce4f13fae 100644 --- a/apps/graph/graph/goto_parameter_controller.cpp +++ b/apps/shared/go_to_parameter_controller.cpp @@ -1,11 +1,8 @@ -#include "goto_parameter_controller.h" -#include "../app.h" -#include "../../apps_container.h" +#include "go_to_parameter_controller.h" +#include "text_field_delegate_app.h" #include -using namespace Shared; - -namespace Graph { +namespace Shared { GoToParameterController::GoToParameterController(Responder * parentResponder, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor) : FloatParameterController(parentResponder), @@ -27,8 +24,8 @@ float GoToParameterController::parameterAtIndex(int index) { void GoToParameterController::setParameterAtIndex(int parameterIndex, float f) { assert(parameterIndex == 0); - App * graphApp = (Graph::App *)app(); - float y = m_function->evaluateAtAbscissa(f, graphApp->localContext()); + TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); + float y = m_function->evaluateAtAbscissa(f, myApp->localContext()); m_graphRange->centerAxisAround(CurveViewRange::Axis::X, f); m_graphRange->centerAxisAround(CurveViewRange::Axis::Y, y); m_cursor->moveTo(f, y); @@ -47,7 +44,7 @@ int GoToParameterController::reusableCellCount() { return 1; } -void GoToParameterController::setFunction(CartesianFunction * function) { +void GoToParameterController::setFunction(Function * function) { m_function = function; } diff --git a/apps/shared/go_to_parameter_controller.h b/apps/shared/go_to_parameter_controller.h new file mode 100644 index 000000000..20e956d1e --- /dev/null +++ b/apps/shared/go_to_parameter_controller.h @@ -0,0 +1,33 @@ +#ifndef SHARED_GO_TO_PARAMETER_CONTROLLER_H +#define SHARED_GO_TO_PARAMETER_CONTROLLER_H + +#include +#include "float_parameter_controller.h" +#include "curve_view_cursor.h" +#include "interactive_curve_view_range.h" +#include "function.h" + +namespace Shared { + +class GoToParameterController : public FloatParameterController { +public: + GoToParameterController(Responder * parentResponder, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor); + const char * title() const override; + int numberOfRows() override; + HighlightCell * reusableCell(int index) override; + int reusableCellCount() override; + void setFunction(Function * function); + bool textFieldDidFinishEditing(TextField * textField, const char * text) override; +private: + float parameterAtIndex(int index) override; + void setParameterAtIndex(int parameterIndex, float f) override; + char m_draftTextBuffer[PointerTableCellWithEditableText::k_bufferLength]; + PointerTableCellWithEditableText m_abscisseCell; + InteractiveCurveViewRange * m_graphRange; + CurveViewCursor * m_cursor; + Function * m_function; +}; + +} + +#endif diff --git a/apps/graph/graph/initialisation_parameter_controller.cpp b/apps/shared/initialisation_parameter_controller.cpp similarity index 97% rename from apps/graph/graph/initialisation_parameter_controller.cpp rename to apps/shared/initialisation_parameter_controller.cpp index ca681e2f0..afdb5a1e6 100644 --- a/apps/graph/graph/initialisation_parameter_controller.cpp +++ b/apps/shared/initialisation_parameter_controller.cpp @@ -1,11 +1,8 @@ #include "initialisation_parameter_controller.h" -#include "../app.h" #include #include -using namespace Shared; - -namespace Graph { +namespace Shared { InitialisationParameterController::InitialisationParameterController(Responder * parentResponder, InteractiveCurveViewRange * graphRange) : ViewController(parentResponder), diff --git a/apps/graph/graph/initialisation_parameter_controller.h b/apps/shared/initialisation_parameter_controller.h similarity index 76% rename from apps/graph/graph/initialisation_parameter_controller.h rename to apps/shared/initialisation_parameter_controller.h index d33e62dd9..77b119594 100644 --- a/apps/graph/graph/initialisation_parameter_controller.h +++ b/apps/shared/initialisation_parameter_controller.h @@ -1,10 +1,10 @@ -#ifndef GRAPH_GRAPH_INITIALISATION_PARAMETER_CONTROLLER_H -#define GRAPH_GRAPH_INITIALISATION_PARAMETER_CONTROLLER_H +#ifndef SHARED_INITIALISATION_PARAMETER_CONTROLLER_H +#define SHARED_INITIALISATION_PARAMETER_CONTROLLER_H #include -#include "../../shared/interactive_curve_view_range.h" +#include "interactive_curve_view_range.h" -namespace Graph { +namespace Shared { class InitialisationParameterController : public ViewController, public SimpleListViewDataSource { public: @@ -22,7 +22,7 @@ private: constexpr static int k_totalNumberOfCells = 4; PointerTableCell m_cells[k_totalNumberOfCells]; SelectableTableView m_selectableTableView; - Shared::InteractiveCurveViewRange * m_graphRange; + InteractiveCurveViewRange * m_graphRange; }; } diff --git a/escher/include/escher/app.h b/escher/include/escher/app.h index a19d3adb4..d60d98825 100644 --- a/escher/include/escher/app.h +++ b/escher/include/escher/app.h @@ -2,9 +2,9 @@ #define ESCHER_APP_H #include +#include #include #include -#include #include /* An app is fed events and outputs drawing calls.