mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[shared] Clean unused classes
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "graph_controller_helper.h"
|
||||
#include "../../shared/storage_function_banner_delegate.h"
|
||||
#include "../app.h"
|
||||
#include "../../constant.h"
|
||||
#include "../../shared/poincare_helpers.h"
|
||||
@@ -20,7 +21,7 @@ bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCurso
|
||||
|
||||
void GraphControllerHelper::reloadDerivativeInBannerViewForCursorOnFunction(Shared::CurveViewCursor * cursor, Ion::Storage::Record record, App * app) {
|
||||
ExpiringPointer<StorageCartesianFunction> function = app->functionStore()->modelForRecord(record);
|
||||
constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
|
||||
constexpr size_t bufferSize = StorageFunctionBannerDelegate::k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
|
||||
char buffer[bufferSize];
|
||||
const char * space = " ";
|
||||
int numberOfChar = function->derivativeNameWithArgument(buffer, bufferSize, StorageCartesianFunction::Symbol());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef GRAPH_GRAPH_CONTROLLER_HELPER_H
|
||||
#define GRAPH_GRAPH_CONTROLLER_HELPER_H
|
||||
|
||||
#include "../../shared/function_banner_delegate.h"
|
||||
#include "../../shared/banner_view.h"
|
||||
#include "../../shared/text_field_delegate_app.h"
|
||||
#include "../../shared/interactive_curve_view_range.h"
|
||||
#include "../storage_cartesian_function_store.h"
|
||||
|
||||
@@ -19,7 +19,7 @@ const char * IntersectionGraphController::title() {
|
||||
void IntersectionGraphController::reloadBannerView() {
|
||||
m_bannerView->setNumberOfSubviews(2);
|
||||
reloadBannerViewForCursorOnFunction(m_cursor, m_record, functionStore(), StorageCartesianFunction::Symbol());
|
||||
constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
|
||||
constexpr size_t bufferSize = StorageFunctionBannerDelegate::k_maxNumberOfCharacters+Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
|
||||
char buffer[bufferSize];
|
||||
const char * space = " ";
|
||||
const char * legend = "=";
|
||||
|
||||
@@ -42,7 +42,7 @@ void TangentGraphController::reloadBannerView() {
|
||||
App * myApp = static_cast<App *>(app());
|
||||
StorageFunctionBannerDelegate::reloadBannerViewForCursorOnFunction(m_cursor, m_record, myApp->functionStore(), StorageCartesianFunction::Symbol());
|
||||
GraphControllerHelper::reloadDerivativeInBannerViewForCursorOnFunction(m_cursor, m_record, myApp);
|
||||
constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
|
||||
constexpr size_t bufferSize = StorageFunctionBannerDelegate::k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
|
||||
char buffer[bufferSize];
|
||||
const char * legend = "a=";
|
||||
int legendLength = strlcpy(buffer, legend, bufferSize);
|
||||
|
||||
@@ -10,21 +10,9 @@ app_src += $(addprefix apps/shared/,\
|
||||
double_pair_store.cpp \
|
||||
editable_cell_table_view_controller.cpp \
|
||||
expression_field_delegate_app.cpp \
|
||||
expression_model.cpp \
|
||||
expression_model_handle.cpp \
|
||||
expression_model_list_controller.cpp \
|
||||
expression_model_store.cpp \
|
||||
float_parameter_controller.cpp \
|
||||
function.cpp \
|
||||
function_app.cpp \
|
||||
function_banner_delegate.cpp \
|
||||
function_curve_parameter_controller.cpp \
|
||||
function_expression_cell.cpp \
|
||||
function_go_to_parameter_controller.cpp \
|
||||
function_graph_controller.cpp \
|
||||
function_graph_view.cpp \
|
||||
function_list_controller.cpp \
|
||||
function_store.cpp \
|
||||
function_title_cell.cpp \
|
||||
global_context.cpp \
|
||||
go_to_parameter_controller.cpp \
|
||||
@@ -39,7 +27,6 @@ app_src += $(addprefix apps/shared/,\
|
||||
interval_parameter_controller.cpp \
|
||||
language_controller.cpp \
|
||||
layout_field_delegate.cpp \
|
||||
list_parameter_controller.cpp \
|
||||
margin_even_odd_message_text_cell.cpp \
|
||||
memoized_curve_view_range.cpp \
|
||||
message_view.cpp \
|
||||
@@ -75,14 +62,11 @@ app_src += $(addprefix apps/shared/,\
|
||||
store_parameter_controller.cpp \
|
||||
store_selectable_table_view.cpp \
|
||||
store_title_cell.cpp \
|
||||
sum_graph_controller.cpp \
|
||||
tab_table_controller.cpp \
|
||||
text_field_delegate.cpp \
|
||||
text_field_delegate_app.cpp \
|
||||
text_field_with_extension.cpp \
|
||||
toolbox_helpers.cpp \
|
||||
values_controller.cpp \
|
||||
values_function_parameter_controller.cpp \
|
||||
values_parameter_controller.cpp \
|
||||
vertical_cursor_view.cpp \
|
||||
zoom_parameter_controller.cpp \
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
#include "function.h"
|
||||
#include "poincare_helpers.h"
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
ExpressionModel::ExpressionModel() :
|
||||
m_text{0},
|
||||
m_expression(),
|
||||
m_layout()
|
||||
{
|
||||
}
|
||||
|
||||
const char * ExpressionModel::text() const {
|
||||
return m_text;
|
||||
}
|
||||
|
||||
Poincare::Expression ExpressionModel::expression(Poincare::Context * context) const {
|
||||
if (m_expression.isUninitialized()) {
|
||||
m_expression = PoincareHelpers::ParseAndSimplify(m_text, *context);
|
||||
}
|
||||
return m_expression;
|
||||
}
|
||||
|
||||
Layout ExpressionModel::layout() {
|
||||
if (m_layout.isUninitialized()) {
|
||||
Expression nonSimplifiedExpression = Expression::Parse(m_text);
|
||||
m_layout = PoincareHelpers::CreateLayout(nonSimplifiedExpression);
|
||||
}
|
||||
return m_layout;
|
||||
}
|
||||
|
||||
bool ExpressionModel::isDefined() {
|
||||
return m_text[0] != 0;
|
||||
}
|
||||
|
||||
bool ExpressionModel::isEmpty() {
|
||||
return m_text[0] == 0;
|
||||
}
|
||||
|
||||
void ExpressionModel::setContent(const char * c) {
|
||||
strlcpy(m_text, c, sizeof(m_text));
|
||||
/* We cannot call tidy here because tidy is a virtual function and does not
|
||||
* do the same thing for all children class. And here we want to delete only
|
||||
* the m_layout and m_expression. */
|
||||
m_layout = Layout();
|
||||
m_expression = Expression();
|
||||
}
|
||||
|
||||
void ExpressionModel::tidy() {
|
||||
m_layout = Layout();
|
||||
m_expression = Expression();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef SHARED_EXPRESSION_MODEL_H
|
||||
#define SHARED_EXPRESSION_MODEL_H
|
||||
|
||||
#include <apps/constant.h>
|
||||
#include <poincare/expression.h>
|
||||
#include <poincare/context.h>
|
||||
#include <poincare/layout.h>
|
||||
#include <kandinsky.h>
|
||||
#include <escher.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ExpressionModel {
|
||||
public:
|
||||
ExpressionModel();
|
||||
const char * text() const;
|
||||
Poincare::Expression expression(Poincare::Context * context) const;
|
||||
Poincare::Layout layout();
|
||||
/* Here, isDefined is the exact contrary of isEmpty. However, for Sequence
|
||||
* inheriting from ExpressionModel, isEmpty and isDefined have not exactly
|
||||
* opposite meaning. For instance, u(n+1)=u(n) & u(0) = ... is not empty and
|
||||
* not defined. We thus have to keep both methods. */
|
||||
virtual bool isDefined();
|
||||
virtual bool isEmpty();
|
||||
virtual bool shouldBeClearedBeforeRemove() {
|
||||
return !isEmpty();
|
||||
}
|
||||
virtual void setContent(const char * c);
|
||||
virtual void tidy();
|
||||
constexpr static int k_expressionBufferSize = Constant::MaxSerializedExpressionSize;
|
||||
private:
|
||||
constexpr static size_t k_dataLengthInBytes = k_expressionBufferSize*sizeof(char);
|
||||
static_assert((k_dataLengthInBytes & 0x3) == 0, "The expression model data size is not a multiple of 4 bytes (cannot compute crc)"); // Assert that dataLengthInBytes is a multiple of 4
|
||||
char m_text[k_expressionBufferSize];
|
||||
mutable Poincare::Expression m_expression;
|
||||
mutable Poincare::Layout m_layout;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,123 +0,0 @@
|
||||
#include "expression_model_list_controller.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
ExpressionModelListController::ExpressionModelListController(Responder * parentResponder, I18n::Message text) :
|
||||
ViewController(parentResponder),
|
||||
m_addNewModel()
|
||||
{
|
||||
m_addNewModel.setMessage(text);
|
||||
}
|
||||
|
||||
/* Table Data Source */
|
||||
int ExpressionModelListController::numberOfExpressionRows() {
|
||||
if (modelStore()->numberOfModels() == modelStore()->maxNumberOfModels()) {
|
||||
return modelStore()->numberOfModels();
|
||||
}
|
||||
return 1 + modelStore()->numberOfModels();
|
||||
}
|
||||
|
||||
KDCoordinate ExpressionModelListController::expressionRowHeight(int j) {
|
||||
if (isAddEmptyRow(j)) {
|
||||
return Metric::StoreRowHeight;
|
||||
}
|
||||
ExpressionModel * m = modelStore()->modelAtIndex(j);
|
||||
if (m->layout().isUninitialized()) {
|
||||
return Metric::StoreRowHeight;
|
||||
}
|
||||
KDCoordinate modelSize = m->layout().layoutSize().height();
|
||||
return modelSize + Metric::StoreRowHeight - KDFont::LargeFont->glyphSize().height();
|
||||
}
|
||||
|
||||
void ExpressionModelListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) {
|
||||
EvenOddExpressionCell * myCell = (EvenOddExpressionCell *)cell;
|
||||
ExpressionModel * m = modelStore()->modelAtIndex(j);
|
||||
myCell->setLayout(m->layout());
|
||||
}
|
||||
|
||||
/* Responder */
|
||||
|
||||
bool ExpressionModelListController::handleEventOnExpression(Ion::Events::Event event) {
|
||||
if (selectedRow() < 0) {
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
if (isAddEmptyRow(selectedRow())) {
|
||||
addEmptyModel();
|
||||
selectableTableView()->reloadCellAtLocation(selectedColumn(), selectedRow());
|
||||
return true;
|
||||
}
|
||||
ExpressionModel * model = modelStore()->modelAtIndex(modelIndexForRow(selectedRow()));
|
||||
editExpression(model, event);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Backspace && !isAddEmptyRow(selectedRow())) {
|
||||
ExpressionModel * model = modelStore()->modelAtIndex(modelIndexForRow(selectedRow()));
|
||||
if (model->shouldBeClearedBeforeRemove()) {
|
||||
reinitExpression(model);
|
||||
selectableTableView()->reloadCellAtLocation(selectedColumn(), selectedRow());
|
||||
} else {
|
||||
if (removeModelRow(model)) {
|
||||
int newSelectedRow = selectedRow() >= numberOfExpressionRows() ? numberOfExpressionRows()-1 : selectedRow();
|
||||
selectCellAtLocation(selectedColumn(), newSelectedRow);
|
||||
selectableTableView()->reloadCellAtLocation(selectedColumn(), selectedRow());
|
||||
selectableTableView()->reloadData();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ((event.hasText() || event == Ion::Events::XNT || event == Ion::Events::Paste || event == Ion::Events::Toolbox || event == Ion::Events::Var)
|
||||
&& !isAddEmptyRow(selectedRow())) {
|
||||
ExpressionModel * model = modelStore()->modelAtIndex(modelIndexForRow(selectedRow()));
|
||||
editExpression(model, event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ExpressionModelListController::addEmptyModel() {
|
||||
ExpressionModel * e = modelStore()->addEmptyModel();
|
||||
selectableTableView()->reloadData();
|
||||
editExpression(e, Ion::Events::OK);
|
||||
}
|
||||
|
||||
void ExpressionModelListController::reinitExpression(ExpressionModel * model) {
|
||||
model->setContent("");
|
||||
selectableTableView()->reloadData();
|
||||
}
|
||||
|
||||
void ExpressionModelListController::editExpression(ExpressionModel * model, Ion::Events::Event event) {
|
||||
char * initialText = nullptr;
|
||||
char initialTextContent[TextField::maxBufferSize()];
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
strlcpy(initialTextContent, model->text(), sizeof(initialTextContent));
|
||||
initialText = initialTextContent;
|
||||
}
|
||||
inputController()->edit(this, event, model, initialText,
|
||||
[](void * context, void * sender){
|
||||
ExpressionModel * myModel = static_cast<ExpressionModel *>(context);
|
||||
InputViewController * myInputViewController = (InputViewController *)sender;
|
||||
const char * textBody = myInputViewController->textBody();
|
||||
myModel->setContent(textBody);
|
||||
return true; // TODO we should return a result from myModel->setContent, but we will remove ExpressionModelListController soon anyway
|
||||
},
|
||||
[](void * context, void * sender){
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool ExpressionModelListController::removeModelRow(ExpressionModel * model) {
|
||||
modelStore()->removeModel(model);
|
||||
return true;
|
||||
}
|
||||
|
||||
int ExpressionModelListController::modelIndexForRow(int j) {
|
||||
return j;
|
||||
}
|
||||
|
||||
bool ExpressionModelListController::isAddEmptyRow(int j) {
|
||||
return j == modelStore()->numberOfModels();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef SHARED_EXPRESSION_MODEL_LIST_CONTROLLER_H
|
||||
#define SHARED_EXPRESSION_MODEL_LIST_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "expression_model_store.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ExpressionModelListController : public ViewController, public SelectableTableViewDataSource {
|
||||
public:
|
||||
ExpressionModelListController(Responder * parentResponder, I18n::Message text);
|
||||
protected:
|
||||
static constexpr KDCoordinate k_expressionMargin = 5;
|
||||
/* Table Data Source */
|
||||
virtual int numberOfExpressionRows();
|
||||
virtual KDCoordinate expressionRowHeight(int j);
|
||||
virtual void willDisplayExpressionCellAtIndex(HighlightCell * cell, int j);
|
||||
/* Responder */
|
||||
bool handleEventOnExpression(Ion::Events::Event event);
|
||||
virtual void addEmptyModel();
|
||||
virtual void reinitExpression(ExpressionModel * model);
|
||||
virtual void editExpression(ExpressionModel * model, Ion::Events::Event event);
|
||||
virtual bool removeModelRow(ExpressionModel * function);
|
||||
virtual int modelIndexForRow(int j);
|
||||
virtual bool isAddEmptyRow(int j);
|
||||
/* View Controller */
|
||||
virtual SelectableTableView * selectableTableView() = 0;
|
||||
virtual ExpressionModelStore * modelStore() = 0;
|
||||
virtual InputViewController * inputController() = 0;
|
||||
EvenOddMessageTextCell m_addNewModel;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "expression_model_store.h"
|
||||
#include "function.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
ExpressionModelStore::ExpressionModelStore() :
|
||||
m_numberOfModels(0)
|
||||
{
|
||||
}
|
||||
|
||||
ExpressionModel * ExpressionModelStore::addEmptyModel() {
|
||||
assert(m_numberOfModels < maxNumberOfModels());
|
||||
setModelAtIndex(emptyModel(), m_numberOfModels++);
|
||||
return modelAtIndex(m_numberOfModels-1);
|
||||
}
|
||||
|
||||
void ExpressionModelStore::removeModel(ExpressionModel * f) {
|
||||
int i = 0;
|
||||
while (modelAtIndex(i) != f && i < m_numberOfModels) {
|
||||
i++;
|
||||
}
|
||||
assert(i>=0 && i<m_numberOfModels);
|
||||
for (int j = i; j<m_numberOfModels-1; j++) {
|
||||
setModelAtIndex(modelAtIndex(j+1), j);
|
||||
}
|
||||
setModelAtIndex(nullModel(), m_numberOfModels-1);
|
||||
m_numberOfModels--;
|
||||
}
|
||||
|
||||
void ExpressionModelStore::removeAll() {
|
||||
for (int i = 0; i < m_numberOfModels; i++) {
|
||||
setModelAtIndex(nullModel(), i);
|
||||
}
|
||||
m_numberOfModels = 0;
|
||||
}
|
||||
|
||||
ExpressionModel * ExpressionModelStore::definedModelAtIndex(int i) {
|
||||
assert(i>=0 && i<m_numberOfModels);
|
||||
int index = 0;
|
||||
for (int k = 0; k < m_numberOfModels; k++) {
|
||||
if (modelAtIndex(k)->isDefined()) {
|
||||
if (i == index) {
|
||||
return modelAtIndex(k);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ExpressionModelStore::numberOfDefinedModels() {
|
||||
int result = 0;
|
||||
for (int i = 0; i < m_numberOfModels; i++) {
|
||||
if (modelAtIndex(i)->isDefined()) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ExpressionModelStore::tidy() {
|
||||
for (int i = 0; i < m_numberOfModels; i++) {
|
||||
modelAtIndex(i)->tidy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef SHARED_EXPRESSION_MODEL_STORE_H
|
||||
#define SHARED_EXPRESSION_MODEL_STORE_H
|
||||
|
||||
#include "expression_model.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
/* ExpressionModelStore is a dumb class.
|
||||
* Its only job is to store model */
|
||||
|
||||
class ExpressionModelStore {
|
||||
public:
|
||||
ExpressionModelStore();
|
||||
virtual ExpressionModel * modelAtIndex(int i) = 0;
|
||||
ExpressionModel * addEmptyModel();
|
||||
void removeModel(ExpressionModel * f);
|
||||
virtual void removeAll();
|
||||
int numberOfModels() const { return m_numberOfModels; };
|
||||
virtual ExpressionModel * definedModelAtIndex(int i);
|
||||
int numberOfDefinedModels();
|
||||
virtual int maxNumberOfModels() const = 0;
|
||||
virtual void tidy();
|
||||
protected:
|
||||
virtual ExpressionModel * emptyModel() = 0;
|
||||
virtual ExpressionModel * nullModel() = 0;
|
||||
virtual void setModelAtIndex(ExpressionModel * f, int i) = 0;
|
||||
int m_numberOfModels;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,51 +0,0 @@
|
||||
#include "function.h"
|
||||
#include "poincare_helpers.h"
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
Function::Function(const char * name, KDColor color) :
|
||||
ExpressionModel(),
|
||||
m_name(name),
|
||||
m_color(color),
|
||||
m_active(true)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t Function::checksum() {
|
||||
char data[k_dataLengthInBytes/sizeof(char)] = {};
|
||||
strlcpy(data, text(), TextField::maxBufferSize());
|
||||
data[k_dataLengthInBytes-2] = m_name != nullptr ? m_name[0] : 0;
|
||||
data[k_dataLengthInBytes-1] = m_active ? 1 : 0;
|
||||
return Ion::crc32((uint32_t *)data, k_dataLengthInBytes/sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void Function::setColor(KDColor color) {
|
||||
m_color = color;
|
||||
}
|
||||
|
||||
const char * Function::name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
bool Function::isActive() {
|
||||
return m_active;
|
||||
}
|
||||
|
||||
void Function::setActive(bool active) {
|
||||
m_active = active;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Function::templatedApproximateAtAbscissa(T x, Poincare::Context * context) const {
|
||||
return PoincareHelpers::ApproximateWithValueForSymbol(expression(context), symbol(), x, *context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template float Shared::Function::templatedApproximateAtAbscissa<float>(float, Poincare::Context*) const;
|
||||
template double Shared::Function::templatedApproximateAtAbscissa<double>(double, Poincare::Context*) const;
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_H
|
||||
#define SHARED_FUNCTION_H
|
||||
|
||||
#include "expression_model.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class Function : public ExpressionModel {
|
||||
public:
|
||||
Function(const char * name = nullptr, KDColor color = KDColorBlack);
|
||||
virtual uint32_t checksum();
|
||||
const char * name() const;
|
||||
KDColor color() const { return m_color; }
|
||||
bool isActive();
|
||||
void setActive(bool active);
|
||||
void setColor(KDColor m_color);
|
||||
virtual float evaluateAtAbscissa(float x, Poincare::Context * context) const {
|
||||
return templatedApproximateAtAbscissa(x, context);
|
||||
}
|
||||
virtual double evaluateAtAbscissa(double x, Poincare::Context * context) const {
|
||||
return templatedApproximateAtAbscissa(x, context);
|
||||
}
|
||||
virtual double sumBetweenBounds(double start, double end, Poincare::Context * context) const = 0;
|
||||
private:
|
||||
constexpr static size_t k_dataLengthInBytes = (TextField::maxBufferSize()+2)*sizeof(char)+2;
|
||||
static_assert((k_dataLengthInBytes & 0x3) == 0, "The function data size is not a multiple of 4 bytes (cannot compute crc)"); // Assert that dataLengthInBytes is a multiple of 4
|
||||
template<typename T> T templatedApproximateAtAbscissa(T x, Poincare::Context * context) const;
|
||||
virtual const char * symbol() const = 0;
|
||||
const char * m_name;
|
||||
KDColor m_color;
|
||||
bool m_active;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,70 +0,0 @@
|
||||
#include "function_app.h"
|
||||
#include "../apps_container.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
FunctionApp::Snapshot::Snapshot() :
|
||||
m_cursor(),
|
||||
m_interval(),
|
||||
m_indexFunctionSelectedByCursor(0),
|
||||
m_modelVersion(0),
|
||||
m_rangeVersion(0),
|
||||
m_angleUnitVersion(Preferences::AngleUnit::Radian)
|
||||
{
|
||||
m_interval.setStart(0);
|
||||
m_interval.setEnd(10);
|
||||
m_interval.setStep(1);
|
||||
}
|
||||
|
||||
CurveViewCursor * FunctionApp::Snapshot::cursor() {
|
||||
return &m_cursor;
|
||||
}
|
||||
|
||||
uint32_t * FunctionApp::Snapshot::modelVersion() {
|
||||
return &m_modelVersion;
|
||||
}
|
||||
|
||||
uint32_t * FunctionApp::Snapshot::rangeVersion() {
|
||||
return &m_rangeVersion;
|
||||
}
|
||||
|
||||
Preferences::AngleUnit * FunctionApp::Snapshot::angleUnitVersion() {
|
||||
return &m_angleUnitVersion;
|
||||
}
|
||||
|
||||
Interval * FunctionApp::Snapshot::interval() {
|
||||
return &m_interval;
|
||||
}
|
||||
|
||||
int * FunctionApp::Snapshot::indexFunctionSelectedByCursor() {
|
||||
return &m_indexFunctionSelectedByCursor;
|
||||
}
|
||||
|
||||
void FunctionApp::Snapshot::reset() {
|
||||
m_interval.setStart(0);
|
||||
m_interval.setEnd(10);
|
||||
m_interval.setStep(1);
|
||||
m_indexFunctionSelectedByCursor = 0;
|
||||
m_modelVersion = 0;
|
||||
m_rangeVersion = 0;
|
||||
setActiveTab(0);
|
||||
}
|
||||
|
||||
FunctionApp::FunctionApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) :
|
||||
ExpressionFieldDelegateApp(container, snapshot, rootViewController)
|
||||
{
|
||||
}
|
||||
|
||||
void FunctionApp::willBecomeInactive() {
|
||||
if (m_modalViewController.isDisplayingModal()) {
|
||||
m_modalViewController.dismissModalViewController();
|
||||
}
|
||||
if (inputViewController()->isDisplayingModal()) {
|
||||
inputViewController()->abortEditionAndDismiss();
|
||||
}
|
||||
::App::willBecomeInactive();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_APP_H
|
||||
#define SHARED_FUNCTION_APP_H
|
||||
|
||||
#include <poincare/preferences.h>
|
||||
#include "expression_field_delegate_app.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "interval.h"
|
||||
|
||||
class AppsContainer;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class FunctionApp : public ExpressionFieldDelegateApp {
|
||||
public:
|
||||
class Snapshot : public ::App::Snapshot, public TabViewDataSource {
|
||||
public:
|
||||
Snapshot();
|
||||
CurveViewCursor * cursor();
|
||||
uint32_t * modelVersion();
|
||||
uint32_t * rangeVersion();
|
||||
Poincare::Preferences::AngleUnit * angleUnitVersion();
|
||||
Interval * interval();
|
||||
int * indexFunctionSelectedByCursor();
|
||||
void reset() override;
|
||||
protected:
|
||||
CurveViewCursor m_cursor;
|
||||
Interval m_interval;
|
||||
private:
|
||||
int m_indexFunctionSelectedByCursor;
|
||||
uint32_t m_modelVersion;
|
||||
uint32_t m_rangeVersion;
|
||||
Poincare::Preferences::AngleUnit m_angleUnitVersion;
|
||||
};
|
||||
virtual ~FunctionApp() = default;
|
||||
virtual InputViewController * inputViewController() = 0;
|
||||
void willBecomeInactive() override;
|
||||
protected:
|
||||
FunctionApp(Container * container, Snapshot * snapshot, ViewController * rootViewController);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
#include "function_banner_delegate.h"
|
||||
#include "poincare_helpers.h"
|
||||
#include "../constant.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
void FunctionBannerDelegate::reloadBannerViewForCursorOnFunction(CurveViewCursor * cursor, Function * function, char symbol) {
|
||||
constexpr size_t bufferSize = k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
|
||||
char buffer[bufferSize];
|
||||
const char * space = " ";
|
||||
const char * legend = "0=";
|
||||
int legendLength = strlen(legend);
|
||||
int numberOfChar = 0;
|
||||
strlcpy(buffer, legend, bufferSize);
|
||||
numberOfChar += legendLength;
|
||||
buffer[0] = symbol;
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(cursor->x(), buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits);
|
||||
strlcpy(buffer+numberOfChar, space, bufferSize - numberOfChar);
|
||||
buffer[k_maxDigitLegendLength+2] = 0;
|
||||
bannerView()->setLegendAtIndex(buffer, 0);
|
||||
|
||||
numberOfChar = 0;
|
||||
legend = "0(x)=";
|
||||
legendLength = strlen(legend);
|
||||
numberOfChar += legendLength;
|
||||
strlcpy(buffer, legend, bufferSize);
|
||||
buffer[2] = symbol;
|
||||
buffer[0] = function->name()[0];
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(cursor->y(), buffer+legendLength, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits);
|
||||
strlcpy(buffer+numberOfChar, space, bufferSize - numberOfChar);
|
||||
buffer[k_maxDigitLegendLength+5] = 0;
|
||||
bannerView()->setLegendAtIndex(buffer, 1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_BANNER_DELEGATE_H
|
||||
#define SHARED_FUNCTION_BANNER_DELEGATE_H
|
||||
|
||||
#include "function_store.h"
|
||||
#include "banner_view.h"
|
||||
#include "curve_view_cursor.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class FunctionBannerDelegate {
|
||||
public:
|
||||
constexpr static int k_maxNumberOfCharacters = 50;
|
||||
constexpr static int k_maxDigitLegendLength = 11;
|
||||
protected:
|
||||
void reloadBannerViewForCursorOnFunction(CurveViewCursor * cursor, Function * function, char symbol);
|
||||
virtual BannerView * bannerView() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,43 +0,0 @@
|
||||
#include "function_curve_parameter_controller.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
FunctionCurveParameterController::FunctionCurveParameterController(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor) :
|
||||
ViewController(nullptr),
|
||||
m_goToCell(I18n::Message::Goto),
|
||||
m_selectableTableView(this, this, this),
|
||||
m_function(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
View * FunctionCurveParameterController::view() {
|
||||
return &m_selectableTableView;
|
||||
}
|
||||
|
||||
void FunctionCurveParameterController::didBecomeFirstResponder() {
|
||||
if (selectedRow() < 0) {
|
||||
selectCellAtLocation(0, 0);
|
||||
}
|
||||
app()->setFirstResponder(&m_selectableTableView);
|
||||
}
|
||||
|
||||
bool FunctionCurveParameterController::handleGotoSelection() {
|
||||
if (m_function == nullptr) {
|
||||
return false;
|
||||
}
|
||||
goToParameterController()->setFunction(m_function);
|
||||
StackViewController * stack = (StackViewController *)parentResponder();
|
||||
stack->push(goToParameterController());
|
||||
return true;
|
||||
}
|
||||
|
||||
KDCoordinate FunctionCurveParameterController::cellHeight() {
|
||||
return Metric::ParameterCellHeight;
|
||||
}
|
||||
|
||||
void FunctionCurveParameterController::setFunction(Function * function) {
|
||||
m_function = function;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_CURVE_PARAMETER_CONTROLLER_H
|
||||
#define SHARED_FUNCTION_CURVE_PARAMETER_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "function_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 SelectableTableViewDataSource {
|
||||
public:
|
||||
FunctionCurveParameterController(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor);
|
||||
View * view() override;
|
||||
void didBecomeFirstResponder() override;
|
||||
KDCoordinate cellHeight() override;
|
||||
void setFunction(Function * function);
|
||||
protected:
|
||||
bool handleGotoSelection();
|
||||
MessageTableCellWithChevron m_goToCell;
|
||||
SelectableTableView m_selectableTableView;
|
||||
Function * m_function;
|
||||
private:
|
||||
virtual FunctionGoToParameterController * goToParameterController() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "function_go_to_parameter_controller.h"
|
||||
#include "text_field_delegate_app.h"
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
FunctionGoToParameterController::FunctionGoToParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, I18n::Message symbol) :
|
||||
GoToParameterController(parentResponder, inputEventHandlerDelegate, graphRange, cursor, symbol),
|
||||
m_function(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
const char * FunctionGoToParameterController::title() {
|
||||
return I18n::translate(I18n::Message::Goto);
|
||||
}
|
||||
|
||||
double FunctionGoToParameterController::parameterAtIndex(int index) {
|
||||
assert(index == 0);
|
||||
return m_cursor->x();
|
||||
}
|
||||
|
||||
bool FunctionGoToParameterController::setParameterAtIndex(int parameterIndex, double f) {
|
||||
assert(parameterIndex == 0);
|
||||
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
|
||||
float y = m_function->evaluateAtAbscissa(f, myApp->localContext());
|
||||
if (std::fabs(f) > k_maxDisplayableFloat || std::fabs(y) > k_maxDisplayableFloat) {
|
||||
app()->displayWarning(I18n::Message::ForbiddenValue);
|
||||
return false;
|
||||
}
|
||||
if (std::isnan(y) || std::isinf(y)) {
|
||||
app()->displayWarning(I18n::Message::ValueNotReachedByFunction);
|
||||
return false;
|
||||
}
|
||||
m_cursor->moveTo(f, y);
|
||||
m_graphRange->centerAxisAround(CurveViewRange::Axis::X, m_cursor->x());
|
||||
m_graphRange->centerAxisAround(CurveViewRange::Axis::Y, m_cursor->y());
|
||||
return true;
|
||||
}
|
||||
|
||||
void FunctionGoToParameterController::setFunction(Function * function) {
|
||||
m_function = function;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_GO_TO_PARAMETER_CONTROLLER_H
|
||||
#define SHARED_FUNCTION_GO_TO_PARAMETER_CONTROLLER_H
|
||||
|
||||
#include "go_to_parameter_controller.h"
|
||||
#include "function.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class FunctionGoToParameterController : public GoToParameterController {
|
||||
public:
|
||||
FunctionGoToParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor, I18n::Message symbol);
|
||||
const char * title() override;
|
||||
void setFunction(Function * function);
|
||||
protected:
|
||||
bool setParameterAtIndex(int parameterIndex, double f) override;
|
||||
Function * m_function;
|
||||
private:
|
||||
double parameterAtIndex(int index) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,167 +0,0 @@
|
||||
#include "function_graph_controller.h"
|
||||
#include "text_field_delegate_app.h"
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) :
|
||||
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, rangeVersion),
|
||||
m_initialisationParameterController(this, interactiveRange),
|
||||
m_angleUnitVersion(angleUnitVersion),
|
||||
m_indexFunctionSelectedByCursor(indexFunctionSelectedByCursor)
|
||||
{
|
||||
}
|
||||
|
||||
bool FunctionGraphController::isEmpty() const {
|
||||
if (functionStore()->numberOfActiveFunctions() == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ViewController * FunctionGraphController::initialisationParameterController() {
|
||||
return &m_initialisationParameterController;
|
||||
}
|
||||
|
||||
void FunctionGraphController::viewWillAppear() {
|
||||
functionGraphView()->setCursorView(cursorView());
|
||||
functionGraphView()->setBannerView(bannerView());
|
||||
functionGraphView()->setAreaHighlight(NAN,NAN);
|
||||
|
||||
if (functionGraphView()->context() == nullptr) {
|
||||
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
|
||||
functionGraphView()->setContext(myApp->localContext());
|
||||
}
|
||||
Preferences::AngleUnit newAngleUnitVersion = Preferences::sharedPreferences()->angleUnit();
|
||||
if (*m_angleUnitVersion != newAngleUnitVersion) {
|
||||
*m_angleUnitVersion = newAngleUnitVersion;
|
||||
initCursorParameters();
|
||||
}
|
||||
InteractiveCurveViewController::viewWillAppear();
|
||||
}
|
||||
|
||||
bool FunctionGraphController::handleEnter() {
|
||||
Function * f = functionStore()->activeFunctionAtIndex(indexFunctionSelectedByCursor());
|
||||
curveParameterController()->setFunction(f);
|
||||
StackViewController * stack = stackController();
|
||||
stack->push(curveParameterController());
|
||||
return true;
|
||||
}
|
||||
|
||||
void FunctionGraphController::selectFunctionWithCursor(int functionIndex) {
|
||||
*m_indexFunctionSelectedByCursor = functionIndex;
|
||||
}
|
||||
|
||||
void FunctionGraphController::reloadBannerView() {
|
||||
if (functionStore()->numberOfActiveFunctions() == 0) {
|
||||
return;
|
||||
}
|
||||
Function * f = functionStore()->activeFunctionAtIndex(indexFunctionSelectedByCursor());
|
||||
reloadBannerViewForCursorOnFunction(m_cursor, f, functionStore()->symbol());
|
||||
}
|
||||
|
||||
InteractiveCurveViewRangeDelegate::Range FunctionGraphController::computeYRange(InteractiveCurveViewRange * interactiveCurveViewRange) {
|
||||
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
|
||||
float min = FLT_MAX;
|
||||
float max = -FLT_MAX;
|
||||
float xMin = interactiveCurveViewRange->xMin();
|
||||
float xMax = interactiveCurveViewRange->xMax();
|
||||
if (functionStore()->numberOfActiveFunctions() <= 0) {
|
||||
InteractiveCurveViewRangeDelegate::Range range;
|
||||
range.min = xMin;
|
||||
range.max = xMax;
|
||||
return range;
|
||||
}
|
||||
for (int i=0; i<functionStore()->numberOfActiveFunctions(); i++) {
|
||||
Function * f = functionStore()->activeFunctionAtIndex(i);
|
||||
float y = 0.0f;
|
||||
float res = curveView()->resolution();
|
||||
/* Scan x-range from the middle to the extrema in order to get balanced
|
||||
* y-range for even functions (y = 1/x). */
|
||||
for (int j = -res/2; j <= res/2; j++) {
|
||||
float x = (xMin+xMax)/2.0+(xMax-xMin)*j/res;
|
||||
y = f->evaluateAtAbscissa(x, myApp->localContext());
|
||||
if (!std::isnan(y) && !std::isinf(y)) {
|
||||
min = min < y ? min : y;
|
||||
max = max > y ? max : y;
|
||||
}
|
||||
}
|
||||
}
|
||||
InteractiveCurveViewRangeDelegate::Range range;
|
||||
range.min = min;
|
||||
range.max = max;
|
||||
return range;
|
||||
}
|
||||
|
||||
void FunctionGraphController::initRangeParameters() {
|
||||
interactiveCurveViewRange()->setDefault();
|
||||
initCursorParameters();
|
||||
selectFunctionWithCursor(0);
|
||||
}
|
||||
|
||||
double FunctionGraphController::defaultCursorAbscissa() {
|
||||
return (interactiveCurveViewRange()->xMin()+interactiveCurveViewRange()->xMax())/2.0f;
|
||||
}
|
||||
|
||||
void FunctionGraphController::initCursorParameters() {
|
||||
double x = defaultCursorAbscissa();
|
||||
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
|
||||
int functionIndex = 0;
|
||||
double y = 0;
|
||||
do {
|
||||
Function * firstFunction = functionStore()->activeFunctionAtIndex(functionIndex++);
|
||||
y = firstFunction->evaluateAtAbscissa(x, myApp->localContext());
|
||||
} while ((std::isnan(y) || std::isinf(y)) && functionIndex < functionStore()->numberOfActiveFunctions());
|
||||
m_cursor->moveTo(x, y);
|
||||
functionIndex = (std::isnan(y) || std::isinf(y)) ? 0 : functionIndex - 1;
|
||||
selectFunctionWithCursor(functionIndex);
|
||||
if (interactiveCurveViewRange()->yAuto()) {
|
||||
interactiveCurveViewRange()->panToMakePointVisible(x, y, k_displayTopMarginRatio, k_cursorRightMarginRatio, k_displayBottomMarginRatio, k_cursorLeftMarginRatio);
|
||||
}
|
||||
}
|
||||
|
||||
bool FunctionGraphController::moveCursorVertically(int direction) {
|
||||
Function * actualFunction = functionStore()->activeFunctionAtIndex(indexFunctionSelectedByCursor());
|
||||
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
|
||||
double y = actualFunction->evaluateAtAbscissa(m_cursor->x(), myApp->localContext());
|
||||
Function * nextFunction = actualFunction;
|
||||
double nextY = direction > 0 ? DBL_MAX : -DBL_MAX;
|
||||
for (int i = 0; i < functionStore()->numberOfActiveFunctions(); i++) {
|
||||
Function * f = functionStore()->activeFunctionAtIndex(i);
|
||||
double newY = f->evaluateAtAbscissa(m_cursor->x(), myApp->localContext());
|
||||
bool isNextFunction = direction > 0 ? (newY > y && newY < nextY) : (newY < y && newY > nextY);
|
||||
if (isNextFunction) {
|
||||
selectFunctionWithCursor(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();
|
||||
}
|
||||
|
||||
bool FunctionGraphController::isCursorVisible() {
|
||||
return interactiveCurveViewRange()->isCursorVisible(k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_GRAPH_CONTROLLER_H
|
||||
#define SHARED_FUNCTION_GRAPH_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "initialisation_parameter_controller.h"
|
||||
#include "function_banner_delegate.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 FunctionBannerDelegate {
|
||||
public:
|
||||
FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion);
|
||||
bool isEmpty() const override;
|
||||
ViewController * initialisationParameterController() override;
|
||||
void viewWillAppear() override;
|
||||
|
||||
protected:
|
||||
constexpr static float k_cursorTopMarginRatio = 0.068f; // (cursorHeight/2)/graphViewHeight
|
||||
constexpr static float k_cursorBottomMarginRatio = 0.15f; // (cursorHeight/2+bannerHeigh)/graphViewHeight
|
||||
void reloadBannerView() override;
|
||||
bool handleEnter() override;
|
||||
int indexFunctionSelectedByCursor() const {
|
||||
return *m_indexFunctionSelectedByCursor;
|
||||
}
|
||||
virtual void selectFunctionWithCursor(int functionIndex);
|
||||
virtual double defaultCursorAbscissa();
|
||||
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;
|
||||
|
||||
// InteractiveCurveViewController
|
||||
float displayTopMarginRatio() override { return k_displayTopMarginRatio; }
|
||||
float displayBottomMarginRatio() override { return k_displayBottomMarginRatio; }
|
||||
// InteractiveCurveViewRangeDelegate
|
||||
InteractiveCurveViewRangeDelegate::Range computeYRange(InteractiveCurveViewRange * interactiveCurveViewRange) override;
|
||||
|
||||
void initRangeParameters() override;
|
||||
void initCursorParameters() override;
|
||||
bool moveCursorVertically(int direction) override;
|
||||
CurveView * curveView() override;
|
||||
uint32_t modelVersion() override;
|
||||
uint32_t rangeVersion() override;
|
||||
bool isCursorVisible() override;
|
||||
virtual FunctionGraphView * functionGraphView() = 0;
|
||||
virtual View * cursorView() = 0;
|
||||
virtual FunctionStore * functionStore() const = 0;
|
||||
virtual FunctionCurveParameterController * curveParameterController() = 0;
|
||||
InitialisationParameterController m_initialisationParameterController;
|
||||
Poincare::Preferences::AngleUnit * m_angleUnitVersion;
|
||||
int * m_indexFunctionSelectedByCursor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,88 +0,0 @@
|
||||
#include "function_graph_view.h"
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
FunctionGraphView::FunctionGraphView(InteractiveCurveViewRange * graphRange,
|
||||
CurveViewCursor * cursor, BannerView * bannerView, View * cursorView) :
|
||||
CurveView(graphRange, cursor, bannerView, cursorView),
|
||||
m_selectedFunction(nullptr),
|
||||
m_highlightedStart(NAN),
|
||||
m_highlightedEnd(NAN),
|
||||
m_shouldColorHighlighted(false),
|
||||
m_xLabels{},
|
||||
m_yLabels{},
|
||||
m_context(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void FunctionGraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(rect, KDColorWhite);
|
||||
drawGrid(ctx, rect);
|
||||
drawAxes(ctx, rect);
|
||||
simpleDrawBothAxesLabels(ctx, rect);
|
||||
}
|
||||
|
||||
void FunctionGraphView::setContext(Context * context) {
|
||||
m_context = context;
|
||||
}
|
||||
|
||||
Context * FunctionGraphView::context() const {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
void FunctionGraphView::selectFunction(Function * function) {
|
||||
if (m_selectedFunction != function) {
|
||||
m_selectedFunction = function;
|
||||
reloadBetweenBounds(m_highlightedStart, m_highlightedEnd);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionGraphView::setAreaHighlight(float start, float end) {
|
||||
if (m_highlightedStart != start || m_highlightedEnd != end) {
|
||||
float dirtyStart = start > m_highlightedStart ? m_highlightedStart : start;
|
||||
float dirtyEnd = start > m_highlightedStart ? start : m_highlightedStart;
|
||||
reloadBetweenBounds(dirtyStart, dirtyEnd);
|
||||
dirtyStart = end > m_highlightedEnd ? m_highlightedEnd : end;
|
||||
dirtyEnd = end > m_highlightedEnd ? end : m_highlightedEnd;
|
||||
reloadBetweenBounds(dirtyStart, dirtyEnd);
|
||||
if (std::isnan(start) || std::isnan(end)) {
|
||||
reloadBetweenBounds(m_highlightedStart, m_highlightedEnd);
|
||||
}
|
||||
if (std::isnan(m_highlightedStart) || std::isnan(m_highlightedEnd)) {
|
||||
reloadBetweenBounds(start, end);
|
||||
}
|
||||
m_highlightedStart = start;
|
||||
m_highlightedEnd = end;
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionGraphView::setAreaHighlightColor(bool highlightColor) {
|
||||
if (m_shouldColorHighlighted != highlightColor) {
|
||||
reloadBetweenBounds(m_highlightedStart, m_highlightedEnd);
|
||||
m_shouldColorHighlighted = highlightColor;
|
||||
}
|
||||
}
|
||||
|
||||
char * FunctionGraphView::label(Axis axis, int index) const {
|
||||
return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]);
|
||||
}
|
||||
|
||||
void FunctionGraphView::reloadBetweenBounds(float start, float end) {
|
||||
if (start == end) {
|
||||
return;
|
||||
}
|
||||
float pixelLowerBound = floatToPixel(Axis::Horizontal, start)-2.0;
|
||||
float pixelUpperBound = floatToPixel(Axis::Horizontal, end)+4.0;
|
||||
/* We exclude the banner frame from the dirty zone to avoid unnecessary
|
||||
* redrawing */
|
||||
KDRect dirtyZone(KDRect(pixelLowerBound, 0, pixelUpperBound-pixelLowerBound,
|
||||
bounds().height()-m_bannerView->bounds().height()));
|
||||
markRectAsDirty(dirtyZone);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_GRAPH_VIEW_H
|
||||
#define SHARED_FUNCTION_GRAPH_VIEW_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "curve_view.h"
|
||||
#include "function.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;
|
||||
void selectFunction(Function * function);
|
||||
void setAreaHighlight(float start, float end);
|
||||
virtual void setAreaHighlightColor(bool highlightColor);
|
||||
protected:
|
||||
void reloadBetweenBounds(float start, float end);
|
||||
Function * m_selectedFunction;
|
||||
float m_highlightedStart;
|
||||
float m_highlightedEnd;
|
||||
bool m_shouldColorHighlighted;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override;
|
||||
char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
|
||||
Poincare::Context * m_context;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,220 +0,0 @@
|
||||
#include "function_list_controller.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
FunctionListController::FunctionListController(Responder * parentResponder, FunctionStore * functionStore, ButtonRowController * header, ButtonRowController * footer, I18n::Message text) :
|
||||
ExpressionModelListController(parentResponder, text),
|
||||
ButtonRowDelegate(header, footer),
|
||||
m_functionStore(functionStore),
|
||||
m_selectableTableView(this, this, this, this),
|
||||
m_emptyCell(),
|
||||
m_plotButton(this, I18n::Message::Plot, Invocation([](void * context, void * sender) {
|
||||
FunctionListController * list = (FunctionListController *)context;
|
||||
TabViewController * tabController = list->tabController();
|
||||
tabController->setActiveTab(1);
|
||||
return true;
|
||||
}, this), KDFont::SmallFont, Palette::PurpleBright),
|
||||
m_valuesButton(this, I18n::Message::DisplayValues, Invocation([](void * context, void * sender) {
|
||||
FunctionListController * list = (FunctionListController *)context;
|
||||
TabViewController * tabController = list->tabController();
|
||||
tabController->setActiveTab(2);
|
||||
return true;
|
||||
}, this), KDFont::SmallFont, Palette::PurpleBright)
|
||||
{
|
||||
m_selectableTableView.setMargins(0);
|
||||
m_selectableTableView.setVerticalCellOverlap(0);
|
||||
}
|
||||
|
||||
int FunctionListController::numberOfColumns() {
|
||||
return 2;
|
||||
};
|
||||
|
||||
KDCoordinate FunctionListController::columnWidth(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return k_functionNameWidth;
|
||||
case 1:
|
||||
return selectableTableView()->bounds().width() - k_functionNameWidth;
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
KDCoordinate FunctionListController::cumulatedWidthFromIndex(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return k_functionNameWidth;
|
||||
case 2:
|
||||
return selectableTableView()->bounds().width();
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int FunctionListController::indexFromCumulatedWidth(KDCoordinate offsetX) {
|
||||
if (offsetX <= k_functionNameWidth) {
|
||||
return 0;
|
||||
} else {
|
||||
if (offsetX <= selectableTableView()->bounds().width())
|
||||
return 1;
|
||||
else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FunctionListController::typeAtLocation(int i, int j) {
|
||||
if (isAddEmptyRow(j)){
|
||||
return i + 2;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
HighlightCell * FunctionListController::reusableCell(int index, int type) {
|
||||
assert(index >= 0);
|
||||
assert(index < maxNumberOfRows());
|
||||
switch (type) {
|
||||
case 0:
|
||||
return titleCells(index);
|
||||
case 1:
|
||||
return expressionCells(index);
|
||||
case 2:
|
||||
return &m_emptyCell;
|
||||
case 3:
|
||||
return &m_addNewModel;
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int FunctionListController::reusableCellCount(int type) {
|
||||
if (type > 1) {
|
||||
return 1;
|
||||
}
|
||||
return maxNumberOfRows();
|
||||
}
|
||||
|
||||
void FunctionListController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) {
|
||||
if (!isAddEmptyRow(j)) {
|
||||
if (i == 0) {
|
||||
willDisplayTitleCellAtIndex(cell, j);
|
||||
} else {
|
||||
willDisplayExpressionCellAtIndex(cell, j);
|
||||
}
|
||||
}
|
||||
EvenOddCell * myCell = (EvenOddCell *)cell;
|
||||
myCell->setEven(j%2 == 0);
|
||||
myCell->setHighlighted(i == selectedColumn() && j == selectedRow());
|
||||
myCell->reloadCell();
|
||||
}
|
||||
|
||||
int FunctionListController::numberOfButtons(ButtonRowController::Position position) const {
|
||||
if (position == ButtonRowController::Position::Bottom) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Button * FunctionListController::buttonAtIndex(int index, ButtonRowController::Position position) const {
|
||||
if (position == ButtonRowController::Position::Top) {
|
||||
return nullptr;
|
||||
}
|
||||
const Button * buttons[2] = {&m_plotButton, &m_valuesButton};
|
||||
return (Button *)buttons[index];
|
||||
}
|
||||
|
||||
void FunctionListController::didBecomeFirstResponder() {
|
||||
if (selectedRow() == -1) {
|
||||
selectCellAtLocation(1, 0);
|
||||
} else {
|
||||
selectCellAtLocation(selectedColumn(), selectedRow());
|
||||
}
|
||||
if (selectedRow() >= numberOfRows()) {
|
||||
selectCellAtLocation(selectedColumn(), numberOfRows()-1);
|
||||
}
|
||||
footer()->setSelectedButton(-1);
|
||||
app()->setFirstResponder(selectableTableView());
|
||||
}
|
||||
|
||||
bool FunctionListController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Up) {
|
||||
if (selectedRow() == -1) {
|
||||
footer()->setSelectedButton(-1);
|
||||
selectableTableView()->selectCellAtLocation(1, numberOfRows()-1);
|
||||
app()->setFirstResponder(selectableTableView());
|
||||
return true;
|
||||
}
|
||||
selectableTableView()->deselectTable();
|
||||
assert(selectedRow() == -1);
|
||||
app()->setFirstResponder(tabController());
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Down) {
|
||||
if (selectedRow() == -1) {
|
||||
return false;
|
||||
}
|
||||
selectableTableView()->deselectTable();
|
||||
footer()->setSelectedButton(0);
|
||||
return true;
|
||||
}
|
||||
if (selectedRow() < 0) {
|
||||
return false;
|
||||
}
|
||||
if (selectedColumn() == 1) {
|
||||
return handleEventOnExpression(event);
|
||||
}
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
assert(selectedColumn() == 0);
|
||||
configureFunction(m_functionStore->modelAtIndex(modelIndexForRow(selectedRow())));
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Backspace) {
|
||||
Shared::Function * function = m_functionStore->modelAtIndex(modelIndexForRow(selectedRow()));
|
||||
if (removeModelRow(function)) {
|
||||
int newSelectedRow = selectedRow() >= numberOfRows() ? numberOfRows()-1 : selectedRow();
|
||||
selectCellAtLocation(selectedColumn(), newSelectedRow);
|
||||
selectableTableView()->reloadData();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FunctionListController::didEnterResponderChain(Responder * previousFirstResponder) {
|
||||
selectableTableView()->reloadData();
|
||||
}
|
||||
|
||||
void FunctionListController::willExitResponderChain(Responder * nextFirstResponder) {
|
||||
if (nextFirstResponder == tabController()) {
|
||||
selectableTableView()->deselectTable();
|
||||
footer()->setSelectedButton(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionListController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) {
|
||||
if (isAddEmptyRow(selectedRow()) && selectedColumn() == 0) {
|
||||
t->selectCellAtLocation(1, numberOfRows()-1);
|
||||
}
|
||||
}
|
||||
|
||||
StackViewController * FunctionListController::stackController() const{
|
||||
return (StackViewController *)(parentResponder()->parentResponder()->parentResponder());
|
||||
}
|
||||
|
||||
void FunctionListController::configureFunction(Shared::Function * function) {
|
||||
StackViewController * stack = stackController();
|
||||
parameterController()->setFunction(function);
|
||||
stack->push(parameterController());
|
||||
}
|
||||
|
||||
TabViewController * FunctionListController::tabController() const{
|
||||
return (TabViewController *)(parentResponder()->parentResponder()->parentResponder()->parentResponder());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_LIST_CONTROLLER_H
|
||||
#define SHARED_FUNCTION_LIST_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "function_store.h"
|
||||
#include "function_app.h"
|
||||
#include "list_parameter_controller.h"
|
||||
#include "expression_model_list_controller.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class FunctionListController : public ExpressionModelListController, public ButtonRowDelegate, public TableViewDataSource, public SelectableTableViewDelegate {
|
||||
public:
|
||||
FunctionListController(Responder * parentResponder, FunctionStore * functionStore, ButtonRowController * header, ButtonRowController * footer, I18n::Message text);
|
||||
|
||||
/* TableViewDataSource */
|
||||
int numberOfRows() override {
|
||||
return numberOfExpressionRows();
|
||||
}
|
||||
int numberOfColumns() override;
|
||||
KDCoordinate rowHeight(int j) override {
|
||||
return expressionRowHeight(j);
|
||||
}
|
||||
KDCoordinate columnWidth(int i) override;
|
||||
KDCoordinate cumulatedWidthFromIndex(int i) override;
|
||||
int indexFromCumulatedWidth(KDCoordinate offsetX) override;
|
||||
int typeAtLocation(int i, int j) override;
|
||||
HighlightCell * reusableCell(int index, int type) override;
|
||||
int reusableCellCount(int type) override;
|
||||
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
|
||||
/* ButtonRowDelegate */
|
||||
int numberOfButtons(ButtonRowController::Position position) const override;
|
||||
Button * buttonAtIndex(int index, ButtonRowController::Position position) const override;
|
||||
/* Responder */
|
||||
void didBecomeFirstResponder() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void didEnterResponderChain(Responder * previousFirstResponder) override;
|
||||
void willExitResponderChain(Responder * nextFirstResponder) override;
|
||||
/* ViewController */
|
||||
View * view() override { return &m_selectableTableView; }
|
||||
/* SelectableTableViewDelegate*/
|
||||
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) override;
|
||||
/* ExpressionModelListController */
|
||||
SelectableTableView * selectableTableView() override { return &m_selectableTableView; }
|
||||
protected:
|
||||
StackViewController * stackController() const;
|
||||
void configureFunction(Function * function);
|
||||
FunctionStore * m_functionStore;
|
||||
SelectableTableView m_selectableTableView;
|
||||
private:
|
||||
static constexpr KDCoordinate k_functionNameWidth = 65;
|
||||
TabViewController * tabController() const;
|
||||
ExpressionModelStore * modelStore() override { return m_functionStore; }
|
||||
InputViewController * inputController() override {
|
||||
FunctionApp * myApp = static_cast<FunctionApp *>(app());
|
||||
return myApp->inputViewController();
|
||||
}
|
||||
virtual ListParameterController * parameterController() = 0;
|
||||
virtual int maxNumberOfRows() = 0;
|
||||
virtual HighlightCell * titleCells(int index) = 0;
|
||||
virtual HighlightCell * expressionCells(int index) = 0;
|
||||
virtual void willDisplayTitleCellAtIndex(HighlightCell * cell, int j) = 0;
|
||||
EvenOddCell m_emptyCell;
|
||||
Button m_plotButton;
|
||||
Button m_valuesButton;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
#include "function_store.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
FunctionStore::FunctionStore() :
|
||||
ExpressionModelStore()
|
||||
{
|
||||
}
|
||||
|
||||
Function * FunctionStore::activeFunctionAtIndex(int i) {
|
||||
assert(i >= 0 && i < numberOfActiveFunctions());
|
||||
int index = 0;
|
||||
for (int k = 0; k < m_numberOfModels; k++) {
|
||||
Function * function = modelAtIndex(k);
|
||||
if (function->isActive() && function->isDefined()) {
|
||||
if (i == index) {
|
||||
return function;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int FunctionStore::numberOfActiveFunctions() {
|
||||
int result = 0;
|
||||
for (int i = 0; i < m_numberOfModels; i++) {
|
||||
Function * function = modelAtIndex(i);
|
||||
if (function->isDefined() && function->isActive()) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FunctionStore::firstAvailableAttribute(T attributes[], AttributeGetter<T> attribute) {
|
||||
for (int k = 0; k < maxNumberOfModels(); k++) {
|
||||
int j = 0;
|
||||
while (j < m_numberOfModels) {
|
||||
if (attribute(modelAtIndex(j)) == attributes[k]) {
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if (j == m_numberOfModels) {
|
||||
return attributes[k];
|
||||
}
|
||||
}
|
||||
return attributes[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template char const* const Shared::FunctionStore::firstAvailableAttribute<char const* const>(char const* const*, char const* const (*)(Shared::Function*));
|
||||
template KDColor const Shared::FunctionStore::firstAvailableAttribute<KDColor const>(KDColor const*, KDColor const (*)(Shared::Function*));
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef SHARED_FUNCTION_STORE_H
|
||||
#define SHARED_FUNCTION_STORE_H
|
||||
|
||||
#include "function.h"
|
||||
#include "expression_model_store.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
/* FunctionStore is a dumb class.
|
||||
* Its only job is to store functions and to give them a color. */
|
||||
|
||||
class FunctionStore : public ExpressionModelStore {
|
||||
public:
|
||||
FunctionStore();
|
||||
virtual uint32_t storeChecksum() = 0;
|
||||
virtual Function * modelAtIndex(int i) override = 0;
|
||||
virtual Function * activeFunctionAtIndex(int i);
|
||||
virtual Function * definedFunctionAtIndex(int i) { return static_cast<Function *>(definedModelAtIndex(i)); }
|
||||
// An active function must be defined to be counted
|
||||
int numberOfActiveFunctions();
|
||||
virtual char symbol() const = 0;
|
||||
protected:
|
||||
static const char * const name(Shared::Function * f) { return f->name(); }
|
||||
static KDColor const color(Shared::Function * f) { return f->color(); }
|
||||
template<typename T> using AttributeGetter = T (*)(Function * f);
|
||||
template<typename T> T firstAvailableAttribute(T attributes[], AttributeGetter<T> attribute);
|
||||
const KDColor firstAvailableColor() {
|
||||
return firstAvailableAttribute(Palette::DataColor, FunctionStore::color);
|
||||
}
|
||||
private:
|
||||
virtual const char * firstAvailableName() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,124 +0,0 @@
|
||||
#include "list_parameter_controller.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
ListParameterController::ListParameterController(Responder * parentResponder, FunctionStore * functionStore, I18n::Message functionColorMessage, I18n::Message deleteFunctionMessage, SelectableTableViewDelegate * tableDelegate) :
|
||||
ViewController(parentResponder),
|
||||
m_selectableTableView(this, this, this, tableDelegate),
|
||||
m_functionStore(functionStore),
|
||||
m_function(nullptr),
|
||||
#if FUNCTION_COLOR_CHOICE
|
||||
m_colorCell(functionColorMessage),
|
||||
#endif
|
||||
m_enableCell(I18n::Message::ActivateDeactivate),
|
||||
m_deleteCell(deleteFunctionMessage)
|
||||
{
|
||||
}
|
||||
|
||||
const char * ListParameterController::title() {
|
||||
return I18n::translate(I18n::Message::FunctionOptions);
|
||||
}
|
||||
|
||||
View * ListParameterController::view() {
|
||||
return &m_selectableTableView;
|
||||
}
|
||||
|
||||
void ListParameterController::didBecomeFirstResponder() {
|
||||
app()->setFirstResponder(&m_selectableTableView);
|
||||
}
|
||||
|
||||
void ListParameterController::viewWillAppear() {
|
||||
ViewController::viewWillAppear();
|
||||
if (selectedRow() == -1) {
|
||||
selectCellAtLocation(0, 0);
|
||||
} else {
|
||||
selectCellAtLocation(selectedColumn(), selectedRow());
|
||||
}
|
||||
m_selectableTableView.reloadData();
|
||||
}
|
||||
|
||||
void ListParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
if (cell == &m_enableCell) {
|
||||
SwitchView * switchView = (SwitchView *)m_enableCell.accessoryView();
|
||||
switchView->setState(m_function->isActive());
|
||||
}
|
||||
}
|
||||
|
||||
void ListParameterController::setFunction(Function * function) {
|
||||
m_function = function;
|
||||
selectCellAtLocation(0, 0);
|
||||
}
|
||||
|
||||
bool ListParameterController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
return handleEnterOnRow(selectedRow());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int ListParameterController::numberOfRows() {
|
||||
return k_totalNumberOfCell;
|
||||
};
|
||||
|
||||
HighlightCell * ListParameterController::reusableCell(int index) {
|
||||
assert(index >= 0);
|
||||
assert(index < k_totalNumberOfCell);
|
||||
#if FUNCTION_COLOR_CHOICE
|
||||
HighlightCell * cells[] = {&m_colorCell, &m_enableCell, &m_deleteCell};
|
||||
#else
|
||||
HighlightCell * cells[] = {&m_enableCell, &m_deleteCell};
|
||||
#endif
|
||||
return cells[index];
|
||||
}
|
||||
|
||||
int ListParameterController::reusableCellCount() {
|
||||
return k_totalNumberOfCell;
|
||||
}
|
||||
|
||||
KDCoordinate ListParameterController::cellHeight() {
|
||||
return Metric::ParameterCellHeight;
|
||||
}
|
||||
|
||||
bool ListParameterController::handleEnterOnRow(int rowIndex) {
|
||||
switch (rowIndex) {
|
||||
#if FUNCTION_COLOR_CHOICE
|
||||
case 0:
|
||||
/* TODO: implement function color choice */
|
||||
return true;
|
||||
case 1:
|
||||
#else
|
||||
case 0:
|
||||
#endif
|
||||
m_function->setActive(!m_function->isActive());
|
||||
m_selectableTableView.reloadData();
|
||||
return true;
|
||||
#if FUNCTION_COLOR_CHOICE
|
||||
case 2:
|
||||
#else
|
||||
case 1:
|
||||
#endif
|
||||
{
|
||||
if (m_functionStore->numberOfModels() > 1) {
|
||||
m_functionStore->removeModel(m_function);
|
||||
StackViewController * stack = (StackViewController *)(parentResponder());
|
||||
stack->pop();
|
||||
return true;
|
||||
} else {
|
||||
if (m_functionStore->numberOfDefinedModels() == 1) {
|
||||
Function * f = m_functionStore->definedFunctionAtIndex(0);
|
||||
f->setContent("");
|
||||
StackViewController * stack = (StackViewController *)(parentResponder());
|
||||
stack->pop();
|
||||
return true;
|
||||
}
|
||||
app()->displayWarning(I18n::Message::NoFunctionToDelete);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#ifndef SHARED_LIST_PARAM_CONTROLLER_H
|
||||
#define SHARED_LIST_PARAM_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "function.h"
|
||||
#include "function_store.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ListParameterController : public ViewController, public SimpleListViewDataSource, public SelectableTableViewDataSource {
|
||||
public:
|
||||
ListParameterController(Responder * parentResponder, FunctionStore * functionStore, I18n::Message functionColorMessage, I18n::Message deleteFunctionMessage, SelectableTableViewDelegate * tableDelegate = nullptr);
|
||||
|
||||
View * view() override;
|
||||
const char * title() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
virtual void setFunction(Function * function);
|
||||
void didBecomeFirstResponder() override;
|
||||
void viewWillAppear() override;
|
||||
int numberOfRows() override;
|
||||
KDCoordinate cellHeight() override;
|
||||
HighlightCell * reusableCell(int index) override;
|
||||
int reusableCellCount() override;
|
||||
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
|
||||
protected:
|
||||
bool handleEnterOnRow(int rowIndex);
|
||||
SelectableTableView m_selectableTableView;
|
||||
FunctionStore * m_functionStore;
|
||||
Function * m_function;
|
||||
private:
|
||||
#if FUNCTION_COLOR_CHOICE
|
||||
constexpr static int k_totalNumberOfCell = 3;
|
||||
MessageTableCellWithChevron m_colorCell;
|
||||
#else
|
||||
constexpr static int k_totalNumberOfCell = 2;
|
||||
#endif
|
||||
MessageTableCellWithSwitch m_enableCell;
|
||||
MessageTableCell m_deleteCell;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <escher.h>
|
||||
#include "storage_function_go_to_parameter_controller.h"
|
||||
#include "function.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "interactive_curve_view_range.h"
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <escher.h>
|
||||
#include "storage_function_store.h"
|
||||
#include "function_app.h"
|
||||
#include "function_title_cell.h"
|
||||
#include "storage_list_parameter_controller.h"
|
||||
#include "storage_expression_model_list_controller.h"
|
||||
|
||||
@@ -1,332 +0,0 @@
|
||||
#include "sum_graph_controller.h"
|
||||
#include "../apps_container.h"
|
||||
#include <poincare/layout_helper.h>
|
||||
#include "poincare_helpers.h"
|
||||
#include <poincare/empty_layout.h>
|
||||
#include <poincare/condensed_sum_layout.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
SumGraphController::SumGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, FunctionGraphView * graphView, InteractiveCurveViewRange * range, CurveViewCursor * cursor, CodePoint sumSymbol) :
|
||||
SimpleInteractiveCurveViewController(parentResponder, range, graphView, cursor),
|
||||
m_step(Step::FirstParameter),
|
||||
m_startSum(NAN),
|
||||
m_endSum(NAN),
|
||||
m_function(nullptr),
|
||||
m_graphRange(range),
|
||||
m_graphView(graphView),
|
||||
m_legendView(this, inputEventHandlerDelegate, sumSymbol),
|
||||
m_cursorView()
|
||||
{
|
||||
}
|
||||
|
||||
void SumGraphController::viewWillAppear() {
|
||||
m_graphRange->panToMakePointVisible(m_cursor->x(), m_cursor->y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
|
||||
m_graphView->setBannerView(&m_legendView);
|
||||
m_graphView->setCursorView(&m_cursorView);
|
||||
m_graphView->setOkView(nullptr);
|
||||
m_graphView->selectMainView(true);
|
||||
m_graphView->setAreaHighlightColor(false);
|
||||
m_graphView->setAreaHighlight(NAN, NAN);
|
||||
m_graphView->reload();
|
||||
|
||||
m_startSum = m_cursor->x();
|
||||
m_endSum = NAN;
|
||||
m_step = Step::FirstParameter;
|
||||
m_legendView.setLegendMessage(legendMessageAtStep(Step::FirstParameter), Step::FirstParameter);
|
||||
m_legendView.setEditableZone(m_startSum);
|
||||
m_legendView.setSumSymbol(m_step);
|
||||
}
|
||||
|
||||
|
||||
void SumGraphController::didEnterResponderChain(Responder * previousFirstResponder) {
|
||||
app()->setFirstResponder(m_legendView.textField());
|
||||
}
|
||||
|
||||
bool SumGraphController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Plus || event == Ion::Events::Minus) {
|
||||
return handleZoom(event);
|
||||
}
|
||||
if ((int)m_step > 1 && event != Ion::Events::OK && event != Ion::Events::EXE && event != Ion::Events::Back) {
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::Left) {
|
||||
if ((int)m_step > 0 && m_startSum >= m_cursor->x()) {
|
||||
return false;
|
||||
}
|
||||
if (moveCursorHorizontallyToPosition(cursorNextStep(m_cursor->x(), -1))) {
|
||||
m_graphView->reload();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::Right) {
|
||||
if (moveCursorHorizontallyToPosition(cursorNextStep(m_cursor->x(), 1))) {
|
||||
m_graphView->reload();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
return handleEnter();
|
||||
}
|
||||
if (event == Ion::Events::Back && (int)m_step > 0) {
|
||||
m_step = (Step)((int)m_step-1);
|
||||
m_legendView.setLegendMessage(legendMessageAtStep(m_step), m_step);
|
||||
if (m_step == Step::SecondParameter) {
|
||||
app()->setFirstResponder(m_legendView.textField());
|
||||
m_graphView->setAreaHighlightColor(false);
|
||||
m_graphView->setCursorView(&m_cursorView);
|
||||
m_endSum = m_cursor->x();
|
||||
m_legendView.setEditableZone(m_endSum);
|
||||
m_legendView.setSumSymbol(m_step, m_startSum);
|
||||
}
|
||||
if (m_step == Step::FirstParameter) {
|
||||
m_graphView->setAreaHighlight(NAN,NAN);
|
||||
moveCursorHorizontallyToPosition(m_startSum);
|
||||
m_legendView.setLegendMessage(legendMessageAtStep(m_step), m_step);
|
||||
m_legendView.setEditableZone(m_startSum);
|
||||
m_legendView.setSumSymbol(m_step);
|
||||
m_graphView->reload();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SumGraphController::moveCursorHorizontallyToPosition(double x) {
|
||||
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
|
||||
if (m_function == nullptr) {
|
||||
return false;
|
||||
}
|
||||
double y = m_function->evaluateAtAbscissa(x, myApp->localContext());
|
||||
m_cursor->moveTo(x, y);
|
||||
if (m_step == Step::FirstParameter) {
|
||||
m_startSum = m_cursor->x();
|
||||
m_legendView.setEditableZone(m_startSum);
|
||||
}
|
||||
if (m_step == Step::SecondParameter) {
|
||||
m_graphView->setAreaHighlight(m_startSum, m_cursor->x());
|
||||
m_endSum = m_cursor->x();
|
||||
m_legendView.setEditableZone(m_endSum);
|
||||
}
|
||||
m_graphRange->panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SumGraphController::setFunction(Function * function) {
|
||||
m_graphView->selectFunction(function);
|
||||
m_function = function;
|
||||
}
|
||||
|
||||
bool SumGraphController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
|
||||
AppsContainer * appsContainer = ((TextFieldDelegateApp *)app())->container();
|
||||
Context * globalContext = appsContainer->globalContext();
|
||||
double floatBody = PoincareHelpers::ApproximateToScalar<double>(text, *globalContext);
|
||||
if (std::isnan(floatBody) || std::isinf(floatBody)) {
|
||||
app()->displayWarning(I18n::Message::UndefinedValue);
|
||||
return false;
|
||||
}
|
||||
if (m_step == Step::SecondParameter && floatBody < m_startSum) {
|
||||
app()->displayWarning(I18n::Message::ForbiddenValue);
|
||||
return false;
|
||||
}
|
||||
if (moveCursorHorizontallyToPosition(floatBody)) {
|
||||
handleEnter();
|
||||
m_graphView->reload();
|
||||
return true;
|
||||
}
|
||||
app()->displayWarning(I18n::Message::ForbiddenValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SumGraphController::textFieldDidAbortEditing(TextField * textField) {
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
|
||||
double parameter = NAN;
|
||||
switch(m_step) {
|
||||
case Step::FirstParameter:
|
||||
parameter = m_startSum;
|
||||
break;
|
||||
case Step::SecondParameter:
|
||||
parameter = m_endSum;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
PrintFloat::convertFloatToText<double>(parameter, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal);
|
||||
textField->setText(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SumGraphController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
|
||||
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && !textField->isEditing()) {
|
||||
return handleEnter();
|
||||
}
|
||||
if (m_step == Step::Result) {
|
||||
return handleEvent(event);
|
||||
}
|
||||
return TextFieldDelegate::textFieldDidReceiveEvent(textField, event);
|
||||
}
|
||||
|
||||
bool SumGraphController::handleEnter() {
|
||||
if (m_step == Step::Result) {
|
||||
StackViewController * stack = (StackViewController *)parentResponder();
|
||||
stack->pop();
|
||||
return true;
|
||||
}
|
||||
if (m_step == Step::FirstParameter) {
|
||||
m_step = Step::SecondParameter;
|
||||
m_graphView->setAreaHighlight(m_startSum,m_startSum);
|
||||
m_endSum = m_cursor->x();
|
||||
m_legendView.setEditableZone(m_endSum);
|
||||
m_legendView.setSumSymbol(m_step, m_startSum);
|
||||
m_legendView.setLegendMessage(legendMessageAtStep(m_step), m_step);
|
||||
return true;
|
||||
}
|
||||
m_step = (Step)((int)m_step+1);
|
||||
TextFieldDelegateApp * myApp = static_cast<TextFieldDelegateApp *>(app());
|
||||
double sum = m_function->sumBetweenBounds(m_startSum, m_endSum, myApp->localContext());
|
||||
m_legendView.setSumSymbol(m_step, m_startSum, m_endSum, sum, createFunctionLayout(m_function->name()));
|
||||
m_legendView.setLegendMessage(I18n::Message::Default, m_step);
|
||||
m_graphView->setAreaHighlightColor(true);
|
||||
m_graphView->setCursorView(nullptr);
|
||||
myApp->setFirstResponder(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Legend View */
|
||||
|
||||
SumGraphController::LegendView::LegendView(SumGraphController * controller, InputEventHandlerDelegate * inputEventHandlerDelegate, CodePoint sumSymbol) :
|
||||
m_sum(0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
|
||||
m_sumLayout(),
|
||||
m_legend(KDFont::SmallFont, I18n::Message::Default, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
|
||||
m_editableZone(controller, m_draftText, m_draftText, TextField::maxBufferSize(), inputEventHandlerDelegate, controller, false, KDFont::SmallFont, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
|
||||
m_sumSymbol(sumSymbol)
|
||||
{
|
||||
m_draftText[0] = 0;
|
||||
}
|
||||
|
||||
void SumGraphController::LegendView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(bounds(), Palette::GreyMiddle);
|
||||
}
|
||||
|
||||
KDSize SumGraphController::LegendView::minimalSizeForOptimalDisplay() const {
|
||||
return KDSize(0, k_legendHeight);
|
||||
}
|
||||
|
||||
void SumGraphController::LegendView::setLegendMessage(I18n::Message message, Step step) {
|
||||
m_legend.setMessage(message);
|
||||
layoutSubviews(step);
|
||||
}
|
||||
|
||||
void SumGraphController::LegendView::setEditableZone(double d) {
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
|
||||
PrintFloat::convertFloatToText<double>(d, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal);
|
||||
m_editableZone.setText(buffer);
|
||||
}
|
||||
|
||||
void SumGraphController::LegendView::setSumSymbol(Step step, double start, double end, double result, Layout functionLayout) {
|
||||
assert(step == Step::Result || functionLayout.isUninitialized());
|
||||
constexpr int sigmaSize = 2;
|
||||
const CodePoint sigma[sigmaSize] = {UCodePointSpace, m_sumSymbol};
|
||||
if (step == Step::FirstParameter) {
|
||||
m_sumLayout = LayoutHelper::CodePointString(sigma, sigmaSize);
|
||||
} else if (step == Step::SecondParameter) {
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
|
||||
PrintFloat::convertFloatToText<double>(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal);
|
||||
m_sumLayout = CondensedSumLayout::Builder(
|
||||
LayoutHelper::CodePointString(sigma, sigmaSize),
|
||||
LayoutHelper::String(buffer, strlen(buffer), KDFont::SmallFont),
|
||||
EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, KDFont::SmallFont, false));
|
||||
} else {
|
||||
constexpr size_t bufferSize = 2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
|
||||
char buffer[bufferSize];
|
||||
PrintFloat::convertFloatToText<double>(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal);
|
||||
Layout start = LayoutHelper::String(buffer, strlen(buffer), KDFont::SmallFont);
|
||||
PrintFloat::convertFloatToText<double>(end, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal);
|
||||
Layout end = LayoutHelper::String(buffer, strlen(buffer), KDFont::SmallFont);
|
||||
m_sumLayout = CondensedSumLayout::Builder(
|
||||
LayoutHelper::CodePointString(sigma, sigmaSize),
|
||||
start,
|
||||
end);
|
||||
strlcpy(buffer, "= ", bufferSize);
|
||||
PoincareHelpers::ConvertFloatToText<double>(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
m_sumLayout = HorizontalLayout::Builder(
|
||||
m_sumLayout,
|
||||
functionLayout,
|
||||
LayoutHelper::String(buffer, strlen(buffer), KDFont::SmallFont));
|
||||
}
|
||||
m_sum.setLayout(m_sumLayout);
|
||||
if (step == Step::Result) {
|
||||
m_sum.setAlignment(0.5f, 0.5f);
|
||||
} else {
|
||||
m_sum.setAlignment(0.0f, 0.5f);
|
||||
}
|
||||
layoutSubviews(step);
|
||||
}
|
||||
|
||||
int SumGraphController::LegendView::numberOfSubviews() const {
|
||||
return 3;
|
||||
}
|
||||
|
||||
View * SumGraphController::LegendView::subviewAtIndex(int index) {
|
||||
assert(index >= 0 && index < 3);
|
||||
if (index == 0) {
|
||||
return &m_sum;
|
||||
}
|
||||
if (index == 1) {
|
||||
return &m_editableZone;
|
||||
}
|
||||
return &m_legend;
|
||||
}
|
||||
|
||||
void SumGraphController::LegendView::layoutSubviews() {
|
||||
layoutSubviews(Step::FirstParameter);
|
||||
}
|
||||
|
||||
void SumGraphController::LegendView::layoutSubviews(Step step) {
|
||||
KDCoordinate width = bounds().width();
|
||||
KDCoordinate heigth = bounds().height();
|
||||
KDSize legendSize = m_legend.minimalSizeForOptimalDisplay();
|
||||
|
||||
if (legendSize.width() > 0) {
|
||||
m_sum.setFrame(KDRect(0, k_symbolHeightMargin, width-legendSize.width(), m_sum.minimalSizeForOptimalDisplay().height()));
|
||||
m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth));
|
||||
} else {
|
||||
m_sum.setFrame(bounds());
|
||||
m_legend.setFrame(KDRectZero);
|
||||
}
|
||||
|
||||
KDCoordinate largeGlyphWidth = KDFont::LargeFont->glyphSize().width();
|
||||
KDCoordinate editableZoneWidth = 12 * KDFont::SmallFont->glyphSize().width();
|
||||
KDCoordinate editableZoneHeight = KDFont::SmallFont->glyphSize().height();
|
||||
|
||||
switch(step) {
|
||||
case Step::FirstParameter:
|
||||
m_editableZone.setFrame(KDRect(
|
||||
2 * largeGlyphWidth,
|
||||
k_symbolHeightMargin + k_sigmaHeight/2,
|
||||
editableZoneWidth,
|
||||
editableZoneHeight
|
||||
));
|
||||
return;
|
||||
case Step::SecondParameter:
|
||||
m_editableZone.setFrame(KDRect(
|
||||
2 * largeGlyphWidth,
|
||||
k_symbolHeightMargin + k_sigmaHeight/2 - editableZoneHeight,
|
||||
editableZoneWidth,
|
||||
editableZoneHeight
|
||||
));
|
||||
return;
|
||||
default:
|
||||
m_editableZone.setFrame(KDRectZero);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
#ifndef SHARED_SUM_GRAPH_CONTROLLER_H
|
||||
#define SHARED_SUM_GRAPH_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "function_graph_view.h"
|
||||
#include "interactive_curve_view_range.h"
|
||||
#include "vertical_cursor_view.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "simple_interactive_curve_view_controller.h"
|
||||
#include "function.h"
|
||||
#include "text_field_delegate.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class SumGraphController : public SimpleInteractiveCurveViewController, public TextFieldDelegate {
|
||||
public:
|
||||
SumGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, FunctionGraphView * curveView, InteractiveCurveViewRange * range, CurveViewCursor * cursor, CodePoint sumSymbol);
|
||||
void viewWillAppear() override;
|
||||
void didEnterResponderChain(Responder * previousFirstResponder) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void setFunction(Function * function);
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
protected:
|
||||
virtual bool moveCursorHorizontallyToPosition(double position);
|
||||
enum class Step {
|
||||
FirstParameter = 0,
|
||||
SecondParameter = 1,
|
||||
Result = 2
|
||||
};
|
||||
Step m_step;
|
||||
double m_startSum;
|
||||
double m_endSum;
|
||||
Function * m_function;
|
||||
InteractiveCurveViewRange * m_graphRange;
|
||||
private:
|
||||
constexpr static float k_cursorTopMarginRatio = 0.06f; // (cursorHeight/2)/graphViewHeight
|
||||
constexpr static float k_cursorBottomMarginRatio = 0.28f; // (cursorHeight/2+bannerHeigh)/graphViewHeight
|
||||
virtual I18n::Message legendMessageAtStep(Step step) = 0;
|
||||
virtual double cursorNextStep(double position, int direction) = 0;
|
||||
virtual Poincare::Layout createFunctionLayout(const char * functionName) = 0;
|
||||
Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_graphRange; }
|
||||
Shared::CurveView * curveView() override { return m_graphView; }
|
||||
TextFieldDelegateApp * textFieldDelegateApp() override {
|
||||
return static_cast<TextFieldDelegateApp *>(app());
|
||||
}
|
||||
bool handleEnter() override;
|
||||
class LegendView : public View {
|
||||
public:
|
||||
LegendView(SumGraphController * controller, InputEventHandlerDelegate * inputEventHandlerDelegate, CodePoint sumSymbol);
|
||||
LegendView(const LegendView& other) = delete;
|
||||
LegendView(LegendView&& other) = delete;
|
||||
LegendView& operator=(const LegendView& other) = delete;
|
||||
LegendView& operator=(LegendView&& other) = delete;
|
||||
TextField * textField() { return &m_editableZone; }
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setLegendMessage(I18n::Message message, Step step);
|
||||
void setEditableZone(double d);
|
||||
void setSumSymbol(Step step, double start = NAN, double end = NAN, double result = NAN, Poincare::Layout sequenceName = Poincare::Layout());
|
||||
private:
|
||||
constexpr static KDCoordinate k_legendHeight = 35;
|
||||
constexpr static KDCoordinate k_symbolHeightMargin = 8;
|
||||
constexpr static KDCoordinate k_sigmaHeight = 18;
|
||||
int numberOfSubviews() const override;
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
void layoutSubviews(Step step);
|
||||
ExpressionView m_sum;
|
||||
Poincare::Layout m_sumLayout;
|
||||
MessageTextView m_legend;
|
||||
TextField m_editableZone;
|
||||
char m_draftText[TextField::maxBufferSize()];
|
||||
CodePoint m_sumSymbol;
|
||||
};
|
||||
FunctionGraphView * m_graphView;
|
||||
LegendView m_legendView;
|
||||
VerticalCursorView m_cursorView;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,322 +0,0 @@
|
||||
#include "values_controller.h"
|
||||
#include "text_field_delegate_app.h"
|
||||
#include "../constant.h"
|
||||
#include "../apps_container.h"
|
||||
#include "poincare_helpers.h"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
ValuesController::ValuesController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, I18n::Message parameterTitle, IntervalParameterController * intervalParameterController, Interval * interval) :
|
||||
EditableCellTableViewController(parentResponder),
|
||||
ButtonRowDelegate(header, nullptr),
|
||||
m_interval(interval),
|
||||
m_numberOfColumns(0),
|
||||
m_numberOfColumnsNeedUpdate(true),
|
||||
m_selectableTableView(this),
|
||||
m_abscissaTitleCell(),
|
||||
m_abscissaCells{},
|
||||
m_abscissaParameterController(this, intervalParameterController, parameterTitle),
|
||||
m_setIntervalButton(this, I18n::Message::IntervalSet, Invocation([](void * context, void * sender) {
|
||||
ValuesController * valuesController = (ValuesController *) context;
|
||||
StackViewController * stack = ((StackViewController *)valuesController->stackController());
|
||||
stack->push(valuesController->intervalParameterController());
|
||||
return true;
|
||||
}, this), KDFont::SmallFont)
|
||||
{
|
||||
m_selectableTableView.setVerticalCellOverlap(0);
|
||||
m_selectableTableView.setTopMargin(k_topMargin);
|
||||
m_selectableTableView.setRightMargin(k_rightMargin);
|
||||
m_selectableTableView.setBottomMargin(k_bottomMargin);
|
||||
m_selectableTableView.setLeftMargin(k_leftMargin);
|
||||
m_selectableTableView.setBackgroundColor(Palette::WallScreenDark);
|
||||
m_abscissaTitleCell.setMessageFont(KDFont::SmallFont);
|
||||
for (int i = 0; i < k_maxNumberOfAbscissaCells; i++) {
|
||||
m_abscissaCells[i].setParentResponder(&m_selectableTableView);
|
||||
m_abscissaCells[i].editableTextCell()->textField()->setDelegates(inputEventHandlerDelegate, this);
|
||||
m_abscissaCells[i].editableTextCell()->textField()->setDraftTextBuffer(m_draftTextBuffer);
|
||||
m_abscissaCells[i].editableTextCell()->textField()->setFont(KDFont::SmallFont);
|
||||
}
|
||||
}
|
||||
|
||||
const char * ValuesController::title() {
|
||||
return I18n::translate(I18n::Message::ValuesTab);
|
||||
}
|
||||
|
||||
int ValuesController::numberOfColumns() {
|
||||
if (m_numberOfColumnsNeedUpdate) {
|
||||
updateNumberOfColumns();
|
||||
m_numberOfColumnsNeedUpdate = false;
|
||||
}
|
||||
return m_numberOfColumns;
|
||||
}
|
||||
|
||||
Interval * ValuesController::interval() {
|
||||
return m_interval;
|
||||
}
|
||||
|
||||
bool ValuesController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Down) {
|
||||
if (selectedRow() == -1) {
|
||||
header()->setSelectedButton(-1);
|
||||
selectableTableView()->selectCellAtLocation(0,0);
|
||||
app()->setFirstResponder(selectableTableView());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event == Ion::Events::Up) {
|
||||
if (selectedRow() == -1) {
|
||||
header()->setSelectedButton(-1);
|
||||
app()->setFirstResponder(tabController());
|
||||
return true;
|
||||
}
|
||||
selectableTableView()->deselectTable();
|
||||
header()->setSelectedButton(0);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Backspace && selectedRow() > 0 &&
|
||||
(selectedRow() < numberOfRows()-1 || m_interval->numberOfElements() == Interval::k_maxNumberOfElements)) {
|
||||
m_interval->deleteElementAtIndex(selectedRow()-1);
|
||||
selectableTableView()->reloadData();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
if (selectedRow() == -1) {
|
||||
return header()->handleEvent(event);
|
||||
}
|
||||
if (selectedRow() == 0) {
|
||||
if (selectedColumn() == 0) {
|
||||
configureAbscissa();
|
||||
return true;
|
||||
}
|
||||
configureFunction();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (selectedRow() == -1) {
|
||||
return header()->handleEvent(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ValuesController::didBecomeFirstResponder() {
|
||||
EditableCellTableViewController::didBecomeFirstResponder();
|
||||
if (selectedRow() == -1) {
|
||||
selectableTableView()->deselectTable();
|
||||
header()->setSelectedButton(0);
|
||||
} else {
|
||||
header()->setSelectedButton(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void ValuesController::willExitResponderChain(Responder * nextFirstResponder) {
|
||||
if (nextFirstResponder == tabController()) {
|
||||
selectableTableView()->deselectTable();
|
||||
selectableTableView()->scrollToCell(0,0);
|
||||
header()->setSelectedButton(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int ValuesController::numberOfButtons(ButtonRowController::Position) const {
|
||||
if (isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
Button * ValuesController::buttonAtIndex(int index, ButtonRowController::Position position) const {
|
||||
return (Button *)&m_setIntervalButton;
|
||||
}
|
||||
|
||||
void ValuesController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) {
|
||||
willDisplayCellAtLocationWithDisplayMode(cell, i, j, Preferences::sharedPreferences()->displayMode());
|
||||
if (cellAtLocationIsEditable(i, j)) {
|
||||
return;
|
||||
}
|
||||
// The cell is not a title cell and not editable
|
||||
if (j > 0 && i > 0) {
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
// Special case: last row
|
||||
if (j == numberOfRows() - 1) {
|
||||
int numberOfIntervalElements = m_interval->numberOfElements();
|
||||
if (numberOfIntervalElements < Interval::k_maxNumberOfElements) {
|
||||
buffer[0] = 0;
|
||||
EvenOddBufferTextCell * myValueCell = (EvenOddBufferTextCell *)cell;
|
||||
myValueCell->setText(buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// The cell is a value cell
|
||||
EvenOddBufferTextCell * myValueCell = (EvenOddBufferTextCell *)cell;
|
||||
double x = m_interval->element(j-1);
|
||||
PoincareHelpers::ConvertFloatToText<double>(evaluationOfAbscissaAtColumn(x, i), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
myValueCell->setText(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
KDCoordinate ValuesController::columnWidth(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return k_abscissaCellWidth;
|
||||
default:
|
||||
return k_ordinateCellWidth;
|
||||
}
|
||||
}
|
||||
|
||||
KDCoordinate ValuesController::cumulatedWidthFromIndex(int i) {
|
||||
if (i == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return k_abscissaCellWidth + (i-1)*k_ordinateCellWidth;
|
||||
}
|
||||
}
|
||||
|
||||
int ValuesController::indexFromCumulatedWidth(KDCoordinate offsetX) {
|
||||
if (offsetX <= k_abscissaCellWidth) {
|
||||
return 0;
|
||||
}
|
||||
return (offsetX - k_abscissaCellWidth)/k_ordinateCellWidth+1;
|
||||
}
|
||||
|
||||
HighlightCell * ValuesController::reusableCell(int index, int type) {
|
||||
assert(index >= 0);
|
||||
switch (type) {
|
||||
case 0:
|
||||
assert(index == 0);
|
||||
return &m_abscissaTitleCell;
|
||||
case 1:
|
||||
return functionTitleCells(index);
|
||||
case 2:
|
||||
assert(index < k_maxNumberOfAbscissaCells);
|
||||
return &m_abscissaCells[index];
|
||||
case 3:
|
||||
return floatCells(index);
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int ValuesController::reusableCellCount(int type) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
return maxNumberOfFunctions();
|
||||
case 2:
|
||||
return k_maxNumberOfAbscissaCells;
|
||||
case 3:
|
||||
return maxNumberOfCells();
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ValuesController::typeAtLocation(int i, int j) {
|
||||
if (j == 0) {
|
||||
if (i == 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (i == 0) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool ValuesController::isEmpty() const {
|
||||
if (functionStore()->numberOfActiveFunctions() == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Responder * ValuesController::defaultController() {
|
||||
return tabController();
|
||||
}
|
||||
|
||||
void ValuesController::viewWillAppear() {
|
||||
EditableCellTableViewController::viewWillAppear();
|
||||
header()->setSelectedButton(-1);
|
||||
}
|
||||
|
||||
void ValuesController::viewDidDisappear() {
|
||||
m_numberOfColumnsNeedUpdate = true;
|
||||
EditableCellTableViewController::viewDidDisappear();
|
||||
}
|
||||
|
||||
Function * ValuesController::functionAtColumn(int i) {
|
||||
assert(i > 0);
|
||||
return functionStore()->activeFunctionAtIndex(i-1);
|
||||
}
|
||||
|
||||
Responder * ValuesController::tabController() const {
|
||||
return (parentResponder()->parentResponder()->parentResponder()->parentResponder());
|
||||
}
|
||||
|
||||
StackViewController * ValuesController::stackController() const {
|
||||
return (StackViewController *)(parentResponder()->parentResponder()->parentResponder());
|
||||
}
|
||||
|
||||
void ValuesController::configureAbscissa() {
|
||||
StackViewController * stack = stackController();
|
||||
stack->push(&m_abscissaParameterController);
|
||||
}
|
||||
|
||||
void ValuesController::configureFunction() {
|
||||
#if COPY_COLUMN
|
||||
#else
|
||||
/* Temporary: the sequence value controller does not have a function parameter
|
||||
* controller yet but it shoult come soon. */
|
||||
if (functionParameterController() == nullptr) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
functionParameterController()->setFunction(functionAtColumn(selectedColumn()));
|
||||
StackViewController * stack = stackController();
|
||||
stack->push(functionParameterController());
|
||||
}
|
||||
|
||||
bool ValuesController::cellAtLocationIsEditable(int columnIndex, int rowIndex) {
|
||||
if (rowIndex > 0 && columnIndex == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValuesController::setDataAtLocation(double floatBody, int columnIndex, int rowIndex) {
|
||||
m_interval->setElement(rowIndex-1, floatBody);
|
||||
return true;
|
||||
}
|
||||
|
||||
double ValuesController::dataAtLocation(int columnIndex, int rowIndex) {
|
||||
return m_interval->element(rowIndex-1);
|
||||
}
|
||||
|
||||
int ValuesController::numberOfElements() {
|
||||
return m_interval->numberOfElements();
|
||||
}
|
||||
|
||||
int ValuesController::maxNumberOfElements() const {
|
||||
return Interval::k_maxNumberOfElements;
|
||||
}
|
||||
|
||||
double ValuesController::evaluationOfAbscissaAtColumn(double abscissa, int columnIndex) {
|
||||
Function * function = functionAtColumn(columnIndex);
|
||||
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
|
||||
return function->evaluateAtAbscissa(abscissa, myApp->localContext());
|
||||
}
|
||||
|
||||
void ValuesController::updateNumberOfColumns() {
|
||||
m_numberOfColumns = 1+functionStore()->numberOfActiveFunctions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
#ifndef SHARED_VALUES_CONTROLLER_H
|
||||
#define SHARED_VALUES_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "function_store.h"
|
||||
#include "function_title_cell.h"
|
||||
#include "editable_cell_table_view_controller.h"
|
||||
#include "interval.h"
|
||||
#include "values_parameter_controller.h"
|
||||
#include "values_function_parameter_controller.h"
|
||||
#include "interval_parameter_controller.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ValuesController : public EditableCellTableViewController, public ButtonRowDelegate, public AlternateEmptyViewDefaultDelegate {
|
||||
public:
|
||||
ValuesController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, I18n::Message parameterTitle, IntervalParameterController * intervalParameterController, Interval * interval);
|
||||
const char * title() override;
|
||||
Interval * interval();
|
||||
int numberOfColumns() override;
|
||||
virtual bool handleEvent(Ion::Events::Event event) override;
|
||||
void didBecomeFirstResponder() override;
|
||||
void willExitResponderChain(Responder * nextFirstResponder) override;
|
||||
virtual IntervalParameterController * intervalParameterController() = 0;
|
||||
int numberOfButtons(ButtonRowController::Position) const override;
|
||||
Button * buttonAtIndex(int index, ButtonRowController::Position position) const override;
|
||||
virtual void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
|
||||
KDCoordinate columnWidth(int i) override;
|
||||
KDCoordinate cumulatedWidthFromIndex(int i) override;
|
||||
int indexFromCumulatedWidth(KDCoordinate offsetX) override;
|
||||
HighlightCell * reusableCell(int index, int type) override;
|
||||
int reusableCellCount(int type) override;
|
||||
int typeAtLocation(int i, int j) override;
|
||||
bool isEmpty() const override;
|
||||
Responder * defaultController() override;
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
static constexpr KDCoordinate k_topMargin = 10;
|
||||
static constexpr KDCoordinate k_bottomMargin = 15;
|
||||
static constexpr KDCoordinate k_leftMargin = 1;
|
||||
static constexpr KDCoordinate k_rightMargin = 15;
|
||||
static constexpr KDCoordinate k_abscissaCellWidth = 100;
|
||||
static constexpr KDCoordinate k_ordinateCellWidth = 100;
|
||||
protected:
|
||||
StackViewController * stackController() const;
|
||||
bool setDataAtLocation(double floatBody, int columnIndex, int rowIndex) override;
|
||||
virtual void updateNumberOfColumns();
|
||||
Interval * m_interval;
|
||||
int m_numberOfColumns;
|
||||
bool m_numberOfColumnsNeedUpdate;
|
||||
private:
|
||||
virtual Function * functionAtColumn(int i);
|
||||
Responder * tabController() const override;
|
||||
SelectableTableView * selectableTableView() override { return &m_selectableTableView; }
|
||||
void configureAbscissa();
|
||||
void configureFunction();
|
||||
bool cellAtLocationIsEditable(int columnIndex, int rowIndex) override;
|
||||
double dataAtLocation(int columnIndex, int rowIndex) override;
|
||||
int numberOfElements() override;
|
||||
int maxNumberOfElements() const override;
|
||||
virtual double evaluationOfAbscissaAtColumn(double abscissa, int columnIndex);
|
||||
constexpr static int k_maxNumberOfAbscissaCells = 10;
|
||||
virtual int maxNumberOfCells() = 0;
|
||||
virtual int maxNumberOfFunctions() = 0;
|
||||
SelectableTableView m_selectableTableView;
|
||||
EvenOddMessageTextCell m_abscissaTitleCell;
|
||||
virtual FunctionTitleCell * functionTitleCells(int j) = 0;
|
||||
virtual EvenOddBufferTextCell * floatCells(int j) = 0;
|
||||
char m_draftTextBuffer[TextField::maxBufferSize()];
|
||||
EvenOddEditableTextCell m_abscissaCells[k_maxNumberOfAbscissaCells];
|
||||
virtual FunctionStore * functionStore() const = 0;
|
||||
virtual ValuesFunctionParameterController * functionParameterController() = 0;
|
||||
ValuesParameterController m_abscissaParameterController;
|
||||
Button m_setIntervalButton;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
#include "values_function_parameter_controller.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
ValuesFunctionParameterController::ValuesFunctionParameterController(char symbol) :
|
||||
ViewController(nullptr),
|
||||
m_copyColumn(I18n::Message::CopyColumnInList),
|
||||
m_selectableTableView(this, this, this),
|
||||
m_function(nullptr),
|
||||
m_symbol(symbol)
|
||||
{
|
||||
}
|
||||
|
||||
const char * ValuesFunctionParameterController::title() {
|
||||
strlcpy(m_pageTitle, I18n::translate(I18n::Message::FunctionColumn), k_maxNumberOfCharsInTitle);
|
||||
char * parenthesis = const_cast<char *>(UTF8Helper::CodePointSearch(m_pageTitle, '('));
|
||||
if (UTF8Helper::CodePointIs(parenthesis, '(') && parenthesis > m_pageTitle && parenthesis < m_pageTitle + k_maxNumberOfCharsInTitle) {
|
||||
*(m_pageTitle - 1) = *m_function->name();
|
||||
*(m_pageTitle + 1) = m_symbol;
|
||||
}
|
||||
return m_pageTitle;
|
||||
}
|
||||
|
||||
View * ValuesFunctionParameterController::view() {
|
||||
return &m_selectableTableView;
|
||||
}
|
||||
|
||||
void ValuesFunctionParameterController::setFunction(Function * function) {
|
||||
m_function = function;
|
||||
}
|
||||
|
||||
void ValuesFunctionParameterController::didBecomeFirstResponder() {
|
||||
m_selectableTableView.reloadData();
|
||||
selectCellAtLocation(0, 0);
|
||||
app()->setFirstResponder(&m_selectableTableView);
|
||||
}
|
||||
|
||||
int ValuesFunctionParameterController::numberOfRows() {
|
||||
return 1;
|
||||
};
|
||||
|
||||
HighlightCell * ValuesFunctionParameterController::reusableCell(int index) {
|
||||
assert(index == 0);
|
||||
return &m_copyColumn;
|
||||
}
|
||||
|
||||
int ValuesFunctionParameterController::reusableCellCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
KDCoordinate ValuesFunctionParameterController::cellHeight() {
|
||||
return Metric::ParameterCellHeight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef SHARED_VALUES_FUNCTION_PARAM_CONTROLLER_H
|
||||
#define SHARED_VALUES_FUNCTION_PARAM_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "function.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ValuesFunctionParameterController : public ViewController, public SimpleListViewDataSource, public SelectableTableViewDataSource {
|
||||
public:
|
||||
ValuesFunctionParameterController(char symbol);
|
||||
|
||||
View * view() override;
|
||||
const char * title() override;
|
||||
void didBecomeFirstResponder() override;
|
||||
virtual int numberOfRows() override;
|
||||
KDCoordinate cellHeight() override;
|
||||
virtual HighlightCell * reusableCell(int index) override;
|
||||
virtual int reusableCellCount() override;
|
||||
virtual void setFunction(Function * function);
|
||||
protected:
|
||||
MessageTableCellWithChevron m_copyColumn;
|
||||
SelectableTableView m_selectableTableView;
|
||||
private:
|
||||
constexpr static int k_maxNumberOfCharsInTitle = 16;
|
||||
char m_pageTitle[k_maxNumberOfCharsInTitle];
|
||||
Function * m_function;
|
||||
char m_symbol;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user