[apps/shared] Move partial classes from grpah/graph to shared to be used

by sequence

Change-Id: I0e18be96cfaa92b6a51836ae8aa072fa6cf0f1af
This commit is contained in:
Émilie Feral
2017-02-22 18:05:56 +01:00
parent a0b4cc3485
commit 0bd796310c
21 changed files with 464 additions and 337 deletions

View File

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

View File

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

View File

@@ -1,38 +1,25 @@
#ifndef GRAPH_GRAPH_CURVE_PARAMETER_CONTROLLER_H
#define GRAPH_GRAPH_CURVE_PARAMETER_CONTROLLER_H
#include <escher.h>
#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;
};
}

View File

@@ -1,32 +0,0 @@
#ifndef GRAPH_GRAPH_GOTO_PARAMETER_CONTROLLER_H
#define GRAPH_GRAPH_GOTO_PARAMETER_CONTROLLER_H
#include <escher.h>
#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

View File

@@ -1,172 +1,50 @@
#include "graph_controller.h"
#include "../app.h"
#include "../../apps_container.h"
#include <assert.h>
#include <math.h>
#include <float.h>
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; i<m_functionStore->numberOfActiveFunctions(); 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;
}
}

View File

@@ -1,56 +1,32 @@
#ifndef GRAPH_GRAPH_CONTROLLER_H
#define GRAPH_GRAPH_CONTROLLER_H
#include <escher.h>
#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;
};
}

View File

@@ -1,48 +1,27 @@
#include "graph_view.h"
#include <assert.h>
#include <math.h>
#include <float.h>
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());
}
}

View File

@@ -1,28 +1,19 @@
#ifndef GRAPH_GRAPH_VIEW_H
#define GRAPH_GRAPH_VIEW_H
#include <escher.h>
#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;
};
}

View File

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

View File

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

View File

@@ -0,0 +1,43 @@
#include "function_curve_parameter_controller.h"
#include <assert.h>
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;
}
}

View File

@@ -0,0 +1,30 @@
#ifndef SHARED_FUNCTION_CURVE_PARAMETER_CONTROLLER_H
#define SHARED_FUNCTION_CURVE_PARAMETER_CONTROLLER_H
#include <escher.h>
#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

View File

@@ -0,0 +1,169 @@
#include "function_graph_controller.h"
#include "text_field_delegate_app.h"
#include <assert.h>
#include <math.h>
#include <float.h>
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; i<functionStore()->numberOfActiveFunctions(); 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();
}
}

View File

@@ -0,0 +1,49 @@
#ifndef SHARED_FUNCTION_GRAPH_CONTROLLER_H
#define SHARED_FUNCTION_GRAPH_CONTROLLER_H
#include <escher.h>
#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

View File

@@ -0,0 +1,37 @@
#include "function_graph_view.h"
#include <assert.h>
#include <math.h>
#include <float.h>
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]);
}
}

View File

@@ -0,0 +1,27 @@
#ifndef SHARED_FUNCTION_GRAPH_VIEW_H
#define SHARED_FUNCTION_GRAPH_VIEW_H
#include <escher.h>
#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

View File

@@ -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 <assert.h>
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;
}

View File

@@ -0,0 +1,33 @@
#ifndef SHARED_GO_TO_PARAMETER_CONTROLLER_H
#define SHARED_GO_TO_PARAMETER_CONTROLLER_H
#include <escher.h>
#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

View File

@@ -1,11 +1,8 @@
#include "initialisation_parameter_controller.h"
#include "../app.h"
#include <assert.h>
#include <math.h>
using namespace Shared;
namespace Graph {
namespace Shared {
InitialisationParameterController::InitialisationParameterController(Responder * parentResponder, InteractiveCurveViewRange * graphRange) :
ViewController(parentResponder),

View File

@@ -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 <escher.h>
#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;
};
}

View File

@@ -2,9 +2,9 @@
#define ESCHER_APP_H
#include <escher/modal_view_controller.h>
#include <escher/image.h>
#include <escher/responder.h>
#include <escher/view_controller.h>
#include <escher/image.h>
#include <escher/warning_controller.h>
/* An app is fed events and outputs drawing calls.