mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[apps/solver] Display user variables in the solutions
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <poincare/horizontal_layout.h>
|
||||
#include <poincare/preferences.h>
|
||||
#include <poincare/symbol_abstract.h>
|
||||
#include <poincare/symbol.h>
|
||||
#include <poincare/vertical_offset_layout.h>
|
||||
|
||||
using namespace Poincare;
|
||||
@@ -17,19 +18,21 @@ namespace Solver {
|
||||
|
||||
static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
|
||||
|
||||
constexpr KDColor SolutionsController::ContentView::k_backgroundColor;
|
||||
|
||||
SolutionsController::ContentView::ContentView(SolutionsController * controller) :
|
||||
m_warningMessageView0(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, KDColorBlack, Palette::WallScreenDark),
|
||||
m_warningMessageView1(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, KDColorBlack, Palette::WallScreenDark),
|
||||
m_warningMessageView0(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, KDColorBlack, k_backgroundColor),
|
||||
m_warningMessageView1(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, KDColorBlack, k_backgroundColor),
|
||||
m_selectableTableView(controller),
|
||||
m_displayWarningMoreSolutions(false)
|
||||
{
|
||||
m_selectableTableView.setBackgroundColor(Palette::WallScreenDark);
|
||||
m_selectableTableView.setBackgroundColor(k_backgroundColor);
|
||||
m_selectableTableView.setVerticalCellOverlap(0);
|
||||
}
|
||||
|
||||
void SolutionsController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
if (m_displayWarningMoreSolutions) {
|
||||
ctx->fillRect(KDRect(0, 0, bounds().width(), k_topMargin), Palette::WallScreenDark);
|
||||
ctx->fillRect(KDRect(0, 0, bounds().width(), k_topMargin), k_backgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +83,7 @@ SolutionsController::SolutionsController(Responder * parentResponder, EquationSt
|
||||
m_deltaCell(0.5f, 0.5f),
|
||||
m_delta2Layout(),
|
||||
m_contentView(this),
|
||||
m_shouldReplaceFuncionsButNotSymbols(false)
|
||||
m_shouldReplaceFunctionsButNotSymbols(false)
|
||||
{
|
||||
m_delta2Layout = HorizontalLayout::Builder(VerticalOffsetLayout::Builder(CodePointLayout::Builder('2', KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Superscript), LayoutHelper::String("-4ac", 4, KDFont::SmallFont));
|
||||
const char * deltaB = "Δ=b";
|
||||
@@ -93,6 +96,7 @@ SolutionsController::SolutionsController(Responder * parentResponder, EquationSt
|
||||
}
|
||||
for (int i = 0; i < k_numberOfSymbolCells; i++) {
|
||||
m_symbolCells[i].setAlignment(0.5f, 0.5f);
|
||||
m_symbolCells[i].setFont(KDFont::LargeFont);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +113,7 @@ void SolutionsController::viewWillAppear() {
|
||||
bool requireWarning = false;
|
||||
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
m_contentView.setWarningMessages(I18n::Message::OnlyFirstSolutionsDisplayed0, I18n::Message::OnlyFirstSolutionsDisplayed1);
|
||||
requireWarning = m_equationStore->haveMoreApproximationSolutions(App::app()->localContext(), m_shouldReplaceFuncionsButNotSymbols);
|
||||
requireWarning = m_equationStore->haveMoreApproximationSolutions(App::app()->localContext(), m_shouldReplaceFunctionsButNotSymbols);
|
||||
} else if (m_equationStore->type() == EquationStore::Type::PolynomialMonovariable && m_equationStore->numberOfSolutions() == 1) {
|
||||
assert(Preferences::sharedPreferences()->complexFormat() == Preferences::ComplexFormat::Real);
|
||||
m_contentView.setWarningMessages(I18n::Message::PolynomeHasNoRealSolution0, I18n::Message::PolynomeHasNoRealSolution1);
|
||||
@@ -158,52 +162,76 @@ Responder * SolutionsController::defaultController() {
|
||||
/* TableViewDataSource */
|
||||
|
||||
int SolutionsController::numberOfRows() const {
|
||||
return m_equationStore->numberOfSolutions();
|
||||
return m_equationStore->numberOfSolutions() + (m_equationStore->numberOfUserVariables() > 0 ? 1 + m_equationStore->numberOfUserVariables() : 0);
|
||||
}
|
||||
|
||||
void SolutionsController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) {
|
||||
const int rowOfUserVariablesMessage = userVariablesMessageRow();
|
||||
if (j == rowOfUserVariablesMessage) {
|
||||
// Predefined varaible used/ignored message
|
||||
assert(i >= 0);
|
||||
MessageCell * messageCell = static_cast<MessageCell *>(cell);
|
||||
messageCell->setHorizontalAlignment(i == 0 ? 1.0f : 0.0f);
|
||||
if (usedUserVariables()) {
|
||||
messageCell->setMessage(i == 0 ? I18n::Message::PredefinedVariablesUsedLeft : I18n::Message::PredefinedVariablesUsedRight);
|
||||
} else {
|
||||
messageCell->setMessage(i == 0 ? I18n::Message::PredefinedVariablesIgnoredLeft : I18n::Message::PredefinedVariablesIgnoredRight);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (i == 0) {
|
||||
// Name of the variable or discriminant
|
||||
if (m_equationStore->type() == EquationStore::Type::PolynomialMonovariable && j == m_equationStore->numberOfSolutions()-1) {
|
||||
// Discriminant
|
||||
// Formula of the discriminant
|
||||
EvenOddExpressionCell * deltaCell = static_cast<EvenOddExpressionCell *>(cell);
|
||||
deltaCell->setLayout(m_delta2Layout);
|
||||
} else {
|
||||
EvenOddBufferTextCell * symbolCell = static_cast<EvenOddBufferTextCell *>(cell);
|
||||
symbolCell->setFont(KDFont::LargeFont);
|
||||
char bufferSymbol[Poincare::SymbolAbstract::k_maxNameSize+1]; // Hold at maximum Delta = b^2-4ac or the variable name + a digit
|
||||
switch (m_equationStore->type()) {
|
||||
case EquationStore::Type::LinearSystem:
|
||||
char bufferSymbol[Poincare::SymbolAbstract::k_maxNameSize+1]; // Holds at maximum the variable name + a digit
|
||||
if (rowOfUserVariablesMessage < 0 || j < rowOfUserVariablesMessage) {
|
||||
// Solution symbol name
|
||||
if (m_equationStore->type() == EquationStore::Type::LinearSystem) {
|
||||
/* The system has more than one variable: the cell text is the
|
||||
* variable name */
|
||||
strlcpy(bufferSymbol, m_equationStore->variableAtIndex(j), Poincare::SymbolAbstract::k_maxNameSize);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
/* The system has one variable but might have many solutions: the cell
|
||||
* text is variableX, with X the row index + 1 (e.g. x1, x2,...) */
|
||||
int length = strlcpy(bufferSymbol, m_equationStore->variableAtIndex(0), Poincare::SymbolAbstract::k_maxNameSize);
|
||||
bufferSymbol[length++] = j+'1';
|
||||
bufferSymbol[length++] = j+'1'; // TODO LEA change for 10
|
||||
bufferSymbol[length] = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// User variable name
|
||||
assert(rowOfUserVariablesMessage > 0);
|
||||
strlcpy(bufferSymbol, m_equationStore->userVariableAtIndex(j - rowOfUserVariablesMessage - 1), Poincare::SymbolAbstract::k_maxNameSize);
|
||||
}
|
||||
symbolCell->setText(bufferSymbol);
|
||||
}
|
||||
} else {
|
||||
// Value of the variable or discriminant
|
||||
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
EvenOddBufferTextCell * valueCell = static_cast<EvenOddBufferTextCell *>(cell);
|
||||
constexpr int precision = Preferences::LargeNumberOfSignificantDigits;
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
|
||||
char bufferValue[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToText<double>(m_equationStore->approximateSolutionAtIndex(j), bufferValue, bufferSize, precision);
|
||||
valueCell->setText(bufferValue);
|
||||
} else {
|
||||
ScrollableTwoExpressionsCell * valueCell = static_cast<ScrollableTwoExpressionsCell *>(cell);
|
||||
Poincare::Layout exactLayout = m_equationStore->exactSolutionLayoutsAtIndexAreIdentical(j) ? Poincare::Layout() : m_equationStore->exactSolutionLayoutAtIndex(j, true);
|
||||
valueCell->setLayouts(exactLayout, m_equationStore->exactSolutionLayoutAtIndex(j, false));
|
||||
if (!exactLayout.isUninitialized()) {
|
||||
valueCell->setEqualMessage(m_equationStore->exactSolutionLayoutsAtIndexAreEqual(j) ? I18n::Message::Equal : I18n::Message::AlmostEqual);
|
||||
if (rowOfUserVariablesMessage < 0 || j < rowOfUserVariablesMessage) {
|
||||
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
// Values of the solutions
|
||||
EvenOddBufferTextCell * valueCell = static_cast<EvenOddBufferTextCell *>(cell);
|
||||
constexpr int precision = Preferences::LargeNumberOfSignificantDigits;
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
|
||||
char bufferValue[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToText<double>(m_equationStore->approximateSolutionAtIndex(j), bufferValue, bufferSize, precision);
|
||||
valueCell->setText(bufferValue);
|
||||
} else {
|
||||
// Values of the solutions or discriminant
|
||||
ScrollableTwoExpressionsCell * valueCell = static_cast<ScrollableTwoExpressionsCell *>(cell);
|
||||
Poincare::Layout exactLayout = m_equationStore->exactSolutionLayoutsAtIndexAreIdentical(j) ? Poincare::Layout() : m_equationStore->exactSolutionLayoutAtIndex(j, true);
|
||||
valueCell->setLayouts(exactLayout, m_equationStore->exactSolutionLayoutAtIndex(j, false));
|
||||
if (!exactLayout.isUninitialized()) {
|
||||
valueCell->setEqualMessage(m_equationStore->exactSolutionLayoutsAtIndexAreEqual(j) ? I18n::Message::Equal : I18n::Message::AlmostEqual);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Values of the solutions or discriminant
|
||||
ScrollableTwoExpressionsCell * valueCell = static_cast<ScrollableTwoExpressionsCell *>(cell);
|
||||
const char * symbol = m_equationStore->userVariableAtIndex(j - rowOfUserVariablesMessage - 1);
|
||||
Poincare::Layout layout = PoincareHelpers::CreateLayout(App::app()->localContext()->expressionForSymbolAbstract(Poincare::Symbol::Builder(symbol, strlen(symbol)), false));
|
||||
valueCell->setLayouts(Poincare::Layout(), layout);
|
||||
}
|
||||
}
|
||||
EvenOddCell * evenOddCell = static_cast<EvenOddCell *>(cell);
|
||||
@@ -218,12 +246,22 @@ KDCoordinate SolutionsController::rowHeight(int j) {
|
||||
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
return k_defaultCellHeight;
|
||||
}
|
||||
Poincare::Layout exactLayout = m_equationStore->exactSolutionLayoutAtIndex(j, true);
|
||||
Poincare::Layout approximateLayout = m_equationStore->exactSolutionLayoutAtIndex(j, false);
|
||||
KDCoordinate exactLayoutHeight = exactLayout.layoutSize().height();
|
||||
KDCoordinate approximateLayoutHeight = approximateLayout.layoutSize().height();
|
||||
KDCoordinate layoutHeight = maxCoordinate(exactLayout.baseline(), approximateLayout.baseline()) + maxCoordinate(exactLayoutHeight-exactLayout.baseline(), approximateLayoutHeight-approximateLayout.baseline());
|
||||
return layoutHeight + 2 * Metric::CommonSmallMargin;
|
||||
const int rowOfUserVariablesMessage = userVariablesMessageRow();
|
||||
if (rowOfUserVariablesMessage < 0 || j < rowOfUserVariablesMessage) {
|
||||
Poincare::Layout exactLayout = m_equationStore->exactSolutionLayoutAtIndex(j, true);
|
||||
Poincare::Layout approximateLayout = m_equationStore->exactSolutionLayoutAtIndex(j, false);
|
||||
KDCoordinate exactLayoutHeight = exactLayout.layoutSize().height();
|
||||
KDCoordinate approximateLayoutHeight = approximateLayout.layoutSize().height();
|
||||
KDCoordinate layoutHeight = maxCoordinate(exactLayout.baseline(), approximateLayout.baseline()) + maxCoordinate(exactLayoutHeight-exactLayout.baseline(), approximateLayoutHeight-approximateLayout.baseline());
|
||||
return layoutHeight + 2 * Metric::CommonSmallMargin;
|
||||
}
|
||||
if (j == rowOfUserVariablesMessage) {
|
||||
return Metric::CommonTopMargin + k_defaultCellHeight + Metric::CommonBottomMargin;
|
||||
}
|
||||
// TODO: memoize user symbols if too slow
|
||||
const char * symbol = m_equationStore->userVariableAtIndex(j - rowOfUserVariablesMessage - 1);
|
||||
Poincare::Layout layout = PoincareHelpers::CreateLayout(App::app()->localContext()->expressionForSymbolAbstract(Poincare::Symbol::Builder(symbol, strlen(symbol)), false));
|
||||
return layout.layoutSize().height() + 2 * Metric::CommonSmallMargin;
|
||||
}
|
||||
|
||||
KDCoordinate SolutionsController::cumulatedWidthFromIndex(int i) {
|
||||
@@ -232,11 +270,9 @@ KDCoordinate SolutionsController::cumulatedWidthFromIndex(int i) {
|
||||
return 0;
|
||||
case 1:
|
||||
return k_symbolCellWidth;
|
||||
case 2:
|
||||
return k_symbolCellWidth+k_valueCellWidth;
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
assert(i == 2);
|
||||
return k_symbolCellWidth+k_valueCellWidth;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +296,8 @@ HighlightCell * SolutionsController::reusableCell(int index, int type) {
|
||||
return &m_deltaCell;
|
||||
case k_exactValueCellType:
|
||||
return &m_exactValueCells[index];
|
||||
case k_messageCellType:
|
||||
return &m_messageCells[index];
|
||||
default:
|
||||
assert(type == k_approximateValueCellType);
|
||||
return &m_approximateValueCells[index];
|
||||
@@ -269,29 +307,43 @@ HighlightCell * SolutionsController::reusableCell(int index, int type) {
|
||||
int SolutionsController::reusableCellCount(int type) {
|
||||
switch (type) {
|
||||
case k_symbolCellType:
|
||||
return EquationStore::k_maxNumberOfSolutions;
|
||||
return k_numberOfSymbolCells;
|
||||
case k_deltaCellType:
|
||||
return 1;
|
||||
case k_exactValueCellType:
|
||||
return EquationStore::k_maxNumberOfExactSolutions;
|
||||
return k_numberOfExactValueCells;
|
||||
case k_messageCellType:
|
||||
return k_numberOfMessageCells;
|
||||
default:
|
||||
assert(type == k_approximateValueCellType);
|
||||
return EquationStore::k_maxNumberOfApproximateSolutions;
|
||||
return k_numberOfApproximateValueCells;
|
||||
}
|
||||
}
|
||||
|
||||
int SolutionsController::typeAtLocation(int i, int j) {
|
||||
const int rowOfUserVariableMessage = userVariablesMessageRow();
|
||||
if (j == rowOfUserVariableMessage) {
|
||||
return k_messageCellType;
|
||||
}
|
||||
if (i == 0) {
|
||||
if (m_equationStore->type() == EquationStore::Type::PolynomialMonovariable && j == m_equationStore->numberOfSolutions()-1) {
|
||||
return k_deltaCellType;
|
||||
}
|
||||
return k_symbolCellType;
|
||||
}
|
||||
return m_equationStore->type() == EquationStore::Type::Monovariable ? k_approximateValueCellType : k_exactValueCellType;
|
||||
if ((rowOfUserVariableMessage < 0 || j < rowOfUserVariableMessage) && m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
return k_approximateValueCellType;
|
||||
}
|
||||
return k_exactValueCellType;
|
||||
}
|
||||
|
||||
void SolutionsController::didBecomeFirstResponder() {
|
||||
Container::activeApp()->setFirstResponder(m_contentView.selectableTableView());
|
||||
}
|
||||
|
||||
int SolutionsController::userVariablesMessageRow() const {
|
||||
assert(m_equationStore->numberOfUserVariables() >= 0);
|
||||
return m_equationStore->numberOfUserVariables() == 0 ? -1 : m_equationStore->numberOfSolutions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user