[solver] Create a class SolutionsController

This commit is contained in:
Émilie Feral
2018-05-30 18:06:16 +02:00
parent ddfcbfebbf
commit 3434202b48
3 changed files with 265 additions and 0 deletions

View File

@@ -7,6 +7,7 @@ app_objs += $(addprefix apps/solver/,\
equation.o\
equation_store.o\
list_controller.o\
solutions_controller.o\
)
i18n_files += $(addprefix apps/solver/,\

View File

@@ -0,0 +1,213 @@
#include "solutions_controller.h"
#include "app.h"
#include "../constant.h"
#include <assert.h>
#include <limits.h>
using namespace Poincare;
using namespace Shared;
namespace Solver {
SolutionsController::SolutionsController(Responder * parentResponder, EquationStore * equationStore) :
ViewController(parentResponder),
m_equationStore(equationStore),
m_selectableTableView(this)
{
m_selectableTableView.setBackgroundColor(Palette::WallScreenDark);
m_selectableTableView.setVerticalCellOverlap(0);
for (int i = 0; i < EquationStore::k_maxNumberOfExactSolutions; i++) {
m_exactValueCells[i].setParentResponder(&m_selectableTableView);
}
for (int i = 0; i < EquationStore::k_maxNumberOfSolutions; i++) {
m_symbolCells[i].setAlignment(0.5f, 0.5f);
}
}
/* ViewController */
const char * SolutionsController::title() {
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
return I18n::translate(I18n::Message::ApproximateSolution);
}
return I18n::translate(I18n::Message::Solution);
}
View * SolutionsController::view() {
return &m_selectableTableView;
}
void SolutionsController::viewWillAppear() {
ViewController::viewWillAppear();
m_selectableTableView.reloadData();
if (selectedRow() < 0) {
selectCellAtLocation(0, 0);
}
}
/* AlternateEmptyRowDelegate */
bool SolutionsController::isEmpty() const {
if (m_equationStore->numberOfSolutions() == 0 || m_equationStore->numberOfSolutions() == INT_MAX) {
return true;
}
return false;
}
I18n::Message SolutionsController::emptyMessage() {
if (m_equationStore->numberOfSolutions() == INT_MAX) {
return I18n::Message::InfiniteNumberOfSolutions;
}
return I18n::Message::NoSolution;
}
Responder * SolutionsController::defaultController() {
return parentResponder();
}
/* TableViewDataSource */
int SolutionsController::numberOfRows() {
if (m_equationStore->type() == EquationStore::Type::PolynomialMonovariable) {
return m_equationStore->numberOfSolutions() + 1; // add the delta row
}
return m_equationStore->numberOfSolutions();
}
int SolutionsController::numberOfColumns() {
return 2;
}
void SolutionsController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) {
EvenOddCell * evenOddCell = static_cast<EvenOddCell *>(cell);
evenOddCell->setEven(j%2 == 0);
if (i == 0) {
EvenOddBufferTextCell * symbolCell = static_cast<EvenOddBufferTextCell *>(cell);
symbolCell->setFontSize(KDText::FontSize::Large);
char bufferSymbol[10]; // hold at maximum Delta = b^2-4ac
switch (m_equationStore->type()) {
case EquationStore::Type::LinearSystem:
bufferSymbol[0] = m_equationStore->variableAtIndex(j);
bufferSymbol[1] = 0;
break;
case EquationStore::Type::PolynomialMonovariable:
if (j == m_equationStore->numberOfSolutions()) {
symbolCell->setFontSize(KDText::FontSize::Small);
strlcpy(bufferSymbol, I18n::translate(I18n::Message::DiscriminantFormulaDegree2), 10);
break;
}
default:
bufferSymbol[0] = m_equationStore->variableAtIndex(0);
bufferSymbol[1] = j+'0';
bufferSymbol[2] = 0;
break;
}
symbolCell->setText(bufferSymbol);
return;
}
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
EvenOddBufferTextCell * valueCell = static_cast<EvenOddBufferTextCell *>(cell);
char bufferValue[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
PrintFloat::convertFloatToText<double>(m_equationStore->approximateSolutionAtIndex(j), bufferValue, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
valueCell->setText(bufferValue);
} else {
Shared::ScrollableExactApproximateExpressionsCell * valueCell = static_cast<ScrollableExactApproximateExpressionsCell *>(cell);
Poincare::ExpressionLayout * exactSolutionLayouts[2] = {m_equationStore->exactSolutionLayoutAtIndex(j, false), m_equationStore->exactSolutionLayoutAtIndex(j, true)};
valueCell->setExpressions(exactSolutionLayouts);
valueCell->setEqualMessage(I18n::Message::AlmostEqual);// TODO: true equal when possible?
}
}
KDCoordinate SolutionsController::columnWidth(int i) {
if (i == 0) {
return k_symbolCellWidth;
}
return k_valueCellWidth;
}
KDCoordinate SolutionsController::rowHeight(int j) {
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
return k_defaultCellHeight;
}
Poincare::ExpressionLayout * exactLayout = m_equationStore->exactSolutionLayoutAtIndex(j, true);
Poincare::ExpressionLayout * approximateLayout = m_equationStore->exactSolutionLayoutAtIndex(j, false);
KDCoordinate exactLayoutHeight = exactLayout->size().height();
KDCoordinate approximateLayoutHeight = approximateLayout->size().height();
KDCoordinate layoutHeight = max(exactLayout->baseline(), approximateLayout->baseline()) + max(exactLayoutHeight-exactLayout->baseline(), approximateLayoutHeight-approximateLayout->baseline());
return layoutHeight+k_defaultCellHeight;
}
KDCoordinate SolutionsController::cumulatedHeightFromIndex(int j) {
int result = 0;
for (int k = 0; k < j; k++) {
result += rowHeight(k);
}
return result;
}
int SolutionsController::indexFromCumulatedHeight(KDCoordinate offsetY) {
int result = 0;
int j = 0;
while (result < offsetY && j < numberOfRows()) {
result += rowHeight(j++);
}
return (result < offsetY || offsetY == 0) ? j : j - 1;
}
KDCoordinate SolutionsController::cumulatedWidthFromIndex(int i) {
switch (i) {
case 0:
return 0;
case 1:
return k_symbolCellWidth;
case 2:
return k_symbolCellWidth+k_valueCellWidth;
default:
assert(false);
return 0;
}
}
int SolutionsController::indexFromCumulatedWidth(KDCoordinate offsetX) {
if (offsetX <= k_symbolCellWidth) {
return 0;
} else {
if (offsetX <= k_symbolCellWidth+k_valueCellWidth)
return 1;
else {
return 2;
}
}
}
HighlightCell * SolutionsController::reusableCell(int index, int type) {
if (type == 0) {
return &m_symbolCells[index];
} else if (type == 1) {
return &m_exactValueCells[index];
}
return &m_approximateValueCells[index];
}
int SolutionsController::reusableCellCount(int type) {
switch (type) {
case 0:
return EquationStore::k_maxNumberOfSolutions;
case 1:
return EquationStore::k_maxNumberOfExactSolutions;
default:
return EquationStore::k_maxNumberOfApproximateSolutions;
}
}
int SolutionsController::typeAtLocation(int i, int j) {
if (i == 0) {
return 0;
}
return m_equationStore->type() == EquationStore::Type::Monovariable ? 2 : 1;
}
void SolutionsController::didBecomeFirstResponder() {
app()->setFirstResponder(&m_selectableTableView);
}
}

View File

@@ -0,0 +1,51 @@
#ifndef SOLVER_SOLUTIONS_CONTROLLER_H
#define SOLVER_SOLUTIONS_CONTROLLER_H
#include <escher.h>
#include "equation_store.h"
#include "../shared/scrollable_exact_approximate_expressions_cell.h"
#include "../i18n.h"
namespace Solver {
class SolutionsController : public ViewController, public AlternateEmptyViewDelegate, public SelectableTableViewDataSource, public TableViewDataSource {
public:
SolutionsController(Responder * parentResponder, EquationStore * equationStore);
/* ViewController */
const char * title() override;
View * view() override;
void viewWillAppear() override;
/* AlternateEmptyViewDelegate */
bool isEmpty() const override;
virtual I18n::Message emptyMessage() override;
virtual Responder * defaultController() override;
/* TableViewDataSource */
int numberOfRows() override;
int numberOfColumns() override;
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
KDCoordinate columnWidth(int i) override;
KDCoordinate rowHeight(int j) override;
KDCoordinate cumulatedWidthFromIndex(int i) override;
KDCoordinate cumulatedHeightFromIndex(int j) override;
int indexFromCumulatedWidth(KDCoordinate offsetX) override;
int indexFromCumulatedHeight(KDCoordinate offsetY) override;
HighlightCell * reusableCell(int index, int type) override;
int reusableCellCount(int type) override;
int typeAtLocation(int i, int j) override;
/* Responder */
void didBecomeFirstResponder() override;
private:
constexpr static int k_symbolCellWidth = 100;
constexpr static int k_valueCellWidth = 180;
constexpr static KDCoordinate k_defaultCellHeight = 20;
EquationStore * m_equationStore;
EvenOddBufferTextCell m_symbolCells[EquationStore::k_maxNumberOfSolutions];
Shared::ScrollableExactApproximateExpressionsCell m_exactValueCells[EquationStore::k_maxNumberOfExactSolutions];
EvenOddBufferTextCell m_approximateValueCells[EquationStore::k_maxNumberOfApproximateSolutions];
SelectableTableView m_selectableTableView;
};
}
#endif