diff --git a/apps/calculation/additional_outputs/complex_list_controller.cpp b/apps/calculation/additional_outputs/complex_list_controller.cpp index 9bfd3e960..2bbf450c2 100644 --- a/apps/calculation/additional_outputs/complex_list_controller.cpp +++ b/apps/calculation/additional_outputs/complex_list_controller.cpp @@ -26,10 +26,10 @@ void ComplexListController::setExpression(Poincare::Expression e) { } Poincare::Context * context = App::app()->localContext(); // Fill Calculation Store - m_calculationStore.push("im(z)", context); - m_calculationStore.push("re(z)", context); - m_calculationStore.push("arg(z)", context); - m_calculationStore.push("abs(z)", context); + m_calculationStore.push("im(z)", context, CalculationHeight); + m_calculationStore.push("re(z)", context, CalculationHeight); + m_calculationStore.push("arg(z)", context, CalculationHeight); + m_calculationStore.push("abs(z)", context, CalculationHeight); // Set Complex illustration // Compute a and b as in Expression::hasDefinedComplexApproximation to ensure the same defined result diff --git a/apps/calculation/additional_outputs/illustrated_list_controller.cpp b/apps/calculation/additional_outputs/illustrated_list_controller.cpp index 1b78bef20..370729bb2 100644 --- a/apps/calculation/additional_outputs/illustrated_list_controller.cpp +++ b/apps/calculation/additional_outputs/illustrated_list_controller.cpp @@ -80,16 +80,7 @@ KDCoordinate IllustratedListController::rowHeight(int j) { } Shared::ExpiringPointer calculation = m_calculationStore.calculationAtIndex(calculationIndex); constexpr bool expanded = true; - KDCoordinate result = calculation->memoizedHeight(expanded); - if (result < 0) { - result = ScrollableThreeExpressionsCell::Height(calculation.pointer()); - if (result < 0) { - // Raise, because Height modified the calculation and failed. - Poincare::ExceptionCheckpoint::Raise(); - } - calculation->setMemoizedHeight(expanded, result); - } - return result + Metric::CellSeparatorThickness; + return calculation->height(expanded) + Metric::CellSeparatorThickness; } int IllustratedListController::typeAtLocation(int i, int j) { @@ -98,7 +89,6 @@ int IllustratedListController::typeAtLocation(int i, int j) { void IllustratedListController::willDisplayCellForIndex(HighlightCell * cell, int index) { if (index == 0) { - // TODO ? return; } Poincare::Context * context = App::app()->localContext(); @@ -106,7 +96,6 @@ void IllustratedListController::willDisplayCellForIndex(HighlightCell * cell, in Calculation * c = m_calculationStore.calculationAtIndex(index-1).pointer(); myCell->setCalculation(c); myCell->setDisplayCenter(c->displayOutput(context) != Calculation::DisplayOutput::ApproximateOnly); - //myCell->setHighlighted(myCell->isHighlighted()); //TODO?? } void IllustratedListController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { diff --git a/apps/calculation/additional_outputs/illustrated_list_controller.h b/apps/calculation/additional_outputs/illustrated_list_controller.h index 970341821..ea5b484de 100644 --- a/apps/calculation/additional_outputs/illustrated_list_controller.h +++ b/apps/calculation/additional_outputs/illustrated_list_controller.h @@ -10,8 +10,6 @@ namespace Calculation { class IllustratedListController : public ListController, public SelectableTableViewDelegate { -/* TODO There is factorizable code between this and - * Calculation::HistoryController (at least rowHeight). */ public: IllustratedListController(EditExpressionController * editExpressionController); @@ -35,6 +33,7 @@ public: constexpr static KDCoordinate k_illustrationHeight = 120; protected: + static KDCoordinate CalculationHeight(Calculation * c, bool expanded) { return ScrollableThreeExpressionsCell::Height(c); } Poincare::Expression m_savedExpression; CalculationStore m_calculationStore; private: diff --git a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp index 63cf7b17e..563d49e1a 100644 --- a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp +++ b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.cpp @@ -8,8 +8,8 @@ void ScrollableThreeExpressionsView::resetMemoization() { setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout()); } -void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, bool * didForceOutput) { - assert(!didForceOutput || *didForceOutput == false); +// TODO: factorize with HistoryViewCell! +void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, bool canChangeDisplayOutput) { Poincare::Context * context = App::app()->localContext(); // Clean the layouts to make room in the pool @@ -24,13 +24,10 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, b bool couldNotCreateExactLayout = false; exactOutputLayout = calculation->createExactOutputLayout(&couldNotCreateExactLayout); if (couldNotCreateExactLayout) { - if (calculation->displayOutput(context) == ::Calculation::Calculation::DisplayOutput::ExactOnly) { - Poincare::ExceptionCheckpoint::Raise(); - } else { + if (canChangeDisplayOutput && calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) { calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); - if (didForceOutput) { - *didForceOutput = true; - } + } else { + Poincare::ExceptionCheckpoint::Raise(); } } } @@ -44,21 +41,18 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, b bool couldNotCreateApproximateLayout = false; approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout); if (couldNotCreateApproximateLayout) { - if (calculation->displayOutput(context) == ::Calculation::Calculation::DisplayOutput::ApproximateOnly) { - Poincare::ExceptionCheckpoint::Raise(); - } else { + if (canChangeDisplayOutput && calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ApproximateOnly) { /* Set the display output to ApproximateOnly, make room in the pool by * erasing the exact layout, and retry to create the approximate layout */ calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); - if (didForceOutput) { - *didForceOutput = true; - } exactOutputLayout = Poincare::Layout(); couldNotCreateApproximateLayout = false; approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout); if (couldNotCreateApproximateLayout) { Poincare::ExceptionCheckpoint::Raise(); } + } else { + Poincare::ExceptionCheckpoint::Raise(); } } @@ -74,16 +68,7 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, b KDCoordinate ScrollableThreeExpressionsCell::Height(Calculation * calculation) { ScrollableThreeExpressionsCell cell; - bool didForceOutput = false; - cell.setCalculation(calculation, &didForceOutput); - if (didForceOutput) { - /* We could not compute the height of the calculation as it is (the display - * output was forced to another value during the height computation). - * Warning: the display output of calculation was actually changed, so it - * will cause problems if we already did some computations with another - * display value. */ - return -1; - } + cell.setCalculation(calculation, true); KDRect leftFrame = KDRectZero; KDRect centerFrame = KDRectZero; KDRect approximateSignFrame = KDRectZero; @@ -103,8 +88,8 @@ void ScrollableThreeExpressionsCell::reinitSelection() { m_view.reloadScroll(); } -void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation, bool * didForceOutput) { - m_view.setCalculation(calculation, didForceOutput); +void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation, bool canChangeDisplayOutput) { + m_view.setCalculation(calculation, canChangeDisplayOutput); layoutSubviews(); } diff --git a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h index 4a8a015b4..95ad64823 100644 --- a/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h +++ b/apps/calculation/additional_outputs/scrollable_three_expressions_cell.h @@ -20,7 +20,7 @@ public: setBackgroundColor(Palette::BackgroundApps); } void resetMemoization(); - void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr); + void setCalculation(Calculation * calculation, bool canChangeDisplayOutput); void subviewFrames(KDRect * leftFrame, KDRect * centerFrame, KDRect * approximateSignFrame, KDRect * rightFrame) { return m_contentCell.subviewFrames(leftFrame, centerFrame, approximateSignFrame, rightFrame); } @@ -61,7 +61,7 @@ public: void setHighlighted(bool highlight) override { m_view.evenOddCell()->setHighlighted(highlight); } void resetMemoization() { m_view.resetMemoization(); } - void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr); + void setCalculation(Calculation * calculation, bool canChangeDisplayOutput = false); void setDisplayCenter(bool display); ScrollableThreeExpressionsView::SubviewPosition selectedSubviewPosition() { return m_view.selectedSubviewPosition(); } void setSelectedSubviewPosition(ScrollableThreeExpressionsView::SubviewPosition subviewPosition) { m_view.setSelectedSubviewPosition(subviewPosition); } diff --git a/apps/calculation/additional_outputs/trigonometry_list_controller.cpp b/apps/calculation/additional_outputs/trigonometry_list_controller.cpp index a7e0ffa64..b8bdcb076 100644 --- a/apps/calculation/additional_outputs/trigonometry_list_controller.cpp +++ b/apps/calculation/additional_outputs/trigonometry_list_controller.cpp @@ -11,9 +11,9 @@ void TrigonometryListController::setExpression(Poincare::Expression e) { // Fill calculation store Poincare::Context * context = App::app()->localContext(); - m_calculationStore.push("sin(θ)", context); - m_calculationStore.push("cos(θ)", context); - m_calculationStore.push("θ", context); + m_calculationStore.push("sin(θ)", context, CalculationHeight); + m_calculationStore.push("cos(θ)", context, CalculationHeight); + m_calculationStore.push("θ", context, CalculationHeight); // Set trigonometry illustration float angle = Shared::PoincareHelpers::ApproximateToScalar(m_calculationStore.calculationAtIndex(0)->approximateOutput(context, Calculation::NumberOfSignificantDigits::Maximal), context); diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index ebe6e0f9c..31b5cd8ff 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -38,12 +38,6 @@ Calculation * Calculation::next() const { return reinterpret_cast(const_cast(result)); } -void Calculation::tidy() { - /* Reset height memoization (the complex format could have changed when - * re-entering Calculation app which would impact the heights). */ - resetHeightMemoization(); -} - const char * Calculation::approximateOutputText(NumberOfSignificantDigits numberOfSignificantDigits) const { const char * exactOutput = exactOutputText(); const char * approximateOutputTextWithMaxNumberOfDigits = exactOutput + strlen(exactOutput) + 1; @@ -126,12 +120,15 @@ Layout Calculation::createApproximateOutputLayout(Context * context, bool * coul } } -void Calculation::setMemoizedHeight(bool expanded, KDCoordinate height) { - if (expanded) { - m_expandedHeight = height; - } else { - m_height = height; - } +KDCoordinate Calculation::height(bool expanded) { + KDCoordinate h = expanded ? m_expandedHeight : m_height; + assert(h >= 0); + return h; +} + +void Calculation::setHeights(KDCoordinate height, KDCoordinate expandedHeight) { + m_height = height; + m_expandedHeight = expandedHeight; } Calculation::DisplayOutput Calculation::displayOutput(Context * context) { @@ -190,9 +187,9 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) { } void Calculation::forceDisplayOutput(DisplayOutput d) { + // Heights haven't been computed yet + assert(m_height == -1 && m_expandedHeight == -1); m_displayOutput = d; - // Reset heights memoization as it might have changed when we modify the display output - resetHeightMemoization(); } bool Calculation::shouldOnlyDisplayExactOutput() { @@ -219,6 +216,7 @@ Calculation::EqualSign Calculation::exactAndApproximateDisplayedOutputsAreEqual( Poincare::ExceptionCheckpoint ecp; if (ExceptionRun(ecp)) { Preferences * preferences = Preferences::sharedPreferences(); + // TODO: complex format should not be needed here (as it is not used to create layouts) Preferences::ComplexFormat complexFormat = Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), m_inputText); m_equalSign = Expression::ParsedExpressionsAreEqual(exactOutputText(), approximateOutputText(NumberOfSignificantDigits::UserDefined), context, complexFormat, preferences->angleUnit()) ? EqualSign::Equal : EqualSign::Approximation; return m_equalSign; @@ -256,25 +254,32 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co } if (o.hasUnit()) { Expression unit; - PoincareHelpers::Reduce(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User,ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None); + PoincareHelpers::Reduce(&o, + App::app()->localContext(), + ExpressionNode::ReductionTarget::User, + ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, + ExpressionNode::UnitConversion::None); o = o.removeUnit(&unit); - if (Unit::IsSI(unit)) { - if (Unit::IsSISpeed(unit) || Unit::IsSIVolume(unit) || Unit::IsSIEnergy(unit)) { - /* All these units will provide misc. classic representatives in - * addition to the SI unit in additional information. */ - return AdditionalInformationType::Unit; - } - if (Unit::IsSITime(unit)) { - /* If the number of seconds is above 60s, we can write it in the form - * of an addition: 23_min + 12_s for instance. */ - double value = Shared::PoincareHelpers::ApproximateToScalar(o, App::app()->localContext()); - if (value > Unit::SecondsPerMinute) { + // There might be no unit in the end, if the reduction was interrupted. + if (!unit.isUninitialized()) { + if (Unit::IsSI(unit)) { + if (Unit::IsSISpeed(unit) || Unit::IsSIVolume(unit) || Unit::IsSIEnergy(unit)) { + /* All these units will provide misc. classic representatives in + * addition to the SI unit in additional information. */ return AdditionalInformationType::Unit; } + if (Unit::IsSITime(unit)) { + /* If the number of seconds is above 60s, we can write it in the form + * of an addition: 23_min + 12_s for instance. */ + double value = Shared::PoincareHelpers::ApproximateToScalar(o, App::app()->localContext()); + if (value > Unit::SecondsPerMinute) { + return AdditionalInformationType::Unit; + } + } + return AdditionalInformationType::None; } - return AdditionalInformationType::None; + return AdditionalInformationType::Unit; } - return AdditionalInformationType::Unit; } if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) { return AdditionalInformationType::Integer; @@ -289,9 +294,4 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co return AdditionalInformationType::None; } -void Calculation::resetHeightMemoization() { - m_height = -1; - m_expandedHeight = -1; -} - } diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h index f93c99aca..29e82f28d 100644 --- a/apps/calculation/calculation.h +++ b/apps/calculation/calculation.h @@ -61,8 +61,6 @@ public: bool operator==(const Calculation& c); Calculation * next() const; - void tidy(); - // Texts enum class NumberOfSignificantDigits { Maximal, @@ -83,9 +81,8 @@ public: Poincare::Layout createExactOutputLayout(bool * couldNotCreateExactLayout); Poincare::Layout createApproximateOutputLayout(Poincare::Context * context, bool * couldNotCreateApproximateLayout); - // Memoization of height - KDCoordinate memoizedHeight(bool expanded) { return expanded ? m_expandedHeight : m_height; } - void setMemoizedHeight(bool expanded, KDCoordinate height); + // Heights + KDCoordinate height(bool expanded); // Displayed output DisplayOutput displayOutput(Poincare::Context * context); @@ -100,7 +97,9 @@ private: static constexpr int k_numberOfExpressions = 4; static constexpr KDCoordinate k_heightComputationFailureHeight = 50; static constexpr const char * k_maximalIntegerWithAdditionalInformation = "10000000000000000"; - void resetHeightMemoization(); + + void setHeights(KDCoordinate height, KDCoordinate expandedHeight); + /* Buffers holding text expressions have to be longer than the text written * by user (of maximum length TextField::maxBufferSize()) because when we * print an expression we add omitted signs (multiplications, parenthesis...) */ diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index e51ae3043..af83020ec 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -51,7 +51,7 @@ ExpiringPointer CalculationStore::calculationAtIndex(int i) { return calculationAtIndex(i); } -ExpiringPointer CalculationStore::push(const char * text, Context * context) { +ExpiringPointer CalculationStore::push(const char * text, Context * context, HeightComputer heightComputer) { /* Compute ans now, before the buffer is slided and before the calculation * might be deleted */ Expression ans = ansExpression(context); @@ -85,7 +85,7 @@ ExpiringPointer CalculationStore::push(const char * text, Context * /* If the input does not fit in the store (event if the current * calculation is the only calculation), just replace the calculation with * undef. */ - return emptyStoreAndPushUndef(context); + return emptyStoreAndPushUndef(context, heightComputer); } nextSerializationLocation += strlen(nextSerializationLocation) + 1; } @@ -116,7 +116,7 @@ ExpiringPointer CalculationStore::push(const char * text, Context * * undef if it fits, else replace the whole calcualtion with undef. */ Expression undef = Undefined::Builder(); if (!pushSerializeExpression(undef, nextSerializationLocation, &newCalculationsLocation)) { - return emptyStoreAndPushUndef(context); + return emptyStoreAndPushUndef(context, heightComputer); } } nextSerializationLocation += strlen(nextSerializationLocation) + 1; @@ -133,7 +133,15 @@ ExpiringPointer CalculationStore::push(const char * text, Context * // Clean the memoization resetMemoizedModelsAfterCalculationIndex(-1); - return ExpiringPointer(reinterpret_cast(m_buffer)); + ExpiringPointer calculation = ExpiringPointer(reinterpret_cast(m_buffer)); + /* Heights are computed now to make sure that the display output is decided + * accordingly to the remaining size in the Poincare pool. Once it is, it + * can't change anymore: the calculation heights are fixed which ensures that + * scrolling computation is right. */ + calculation->setHeights( + heightComputer(calculation.pointer(), false), + heightComputer(calculation.pointer(), true)); + return calculation; } void CalculationStore::deleteCalculationAtIndex(int i) { @@ -164,9 +172,6 @@ void CalculationStore::tidy() { return; } resetMemoizedModelsAfterCalculationIndex(-1); - for (Calculation * c : *this) { - c->tidy(); - } } Expression CalculationStore::ansExpression(Context * context) { @@ -255,12 +260,12 @@ const char * CalculationStore::lastCalculationPosition(const char * calculations return reinterpret_cast(c); } -Shared::ExpiringPointer CalculationStore::emptyStoreAndPushUndef(Context * context) { +Shared::ExpiringPointer CalculationStore::emptyStoreAndPushUndef(Context * context, HeightComputer heightComputer) { /* We end up here as a result of a failed calculation push. The store * attributes are not necessarily clean, so we need to reset them. */ m_slidedBuffer = false; deleteAll(); - return push(Undefined::Name(), context); + return push(Undefined::Name(), context, heightComputer); } void CalculationStore::resetMemoizedModelsAfterCalculationIndex(int index) { diff --git a/apps/calculation/calculation_store.h b/apps/calculation/calculation_store.h index 9c2185f88..9f69d3edf 100644 --- a/apps/calculation/calculation_store.h +++ b/apps/calculation/calculation_store.h @@ -28,7 +28,8 @@ class CalculationStore { public: CalculationStore(); Shared::ExpiringPointer calculationAtIndex(int i); - Shared::ExpiringPointer push(const char * text, Poincare::Context * context); + typedef KDCoordinate (*HeightComputer)(Calculation * c, bool expanded); + Shared::ExpiringPointer push(const char * text, Poincare::Context * context, HeightComputer heightComputer); void deleteCalculationAtIndex(int i); void deleteAll(); int numberOfCalculations() const { return m_numberOfCalculations; } @@ -60,7 +61,7 @@ private: char * slideCalculationsToEndOfBuffer(); // returns the new position of the calculations size_t deleteLastCalculation(const char * calculationsStart = nullptr); const char * lastCalculationPosition(const char * calculationsStart) const; - Shared::ExpiringPointer emptyStoreAndPushUndef(Poincare::Context * context); + Shared::ExpiringPointer emptyStoreAndPushUndef(Poincare::Context * context, HeightComputer heightComputer); char m_buffer[k_bufferSize]; const char * m_bufferEnd; diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index cd7702e93..2ae7929a9 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -122,7 +122,7 @@ bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event if (!myApp->isAcceptableText(m_cacheBuffer)) { return true; } - m_calculationStore->push(m_cacheBuffer, myApp->localContext()); + m_calculationStore->push(m_cacheBuffer, myApp->localContext(), HistoryViewCell::Height); m_historyController->reload(); return true; } @@ -145,7 +145,7 @@ bool EditExpressionController::inputViewDidFinishEditing(const char * text, Layo } else { layoutR.serializeParsedExpression(m_cacheBuffer, k_cacheBufferSize, context); } - m_calculationStore->push(m_cacheBuffer, context); + m_calculationStore->push(m_cacheBuffer, context, HistoryViewCell::Height); m_historyController->reload(); m_contentView.expressionField()->setEditing(true, true); telemetryReportEvent("Input", m_cacheBuffer); diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index c8c153b6a..16e68704d 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -129,7 +129,9 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { return true; } m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0); - setSelectedSubviewType(subviewType, true, 0, selectedRow()); + /* The parameters 'sameCell' and 'previousSelectedY' are chosen to enforce + * toggling of the output when necessary. */ + setSelectedSubviewType(subviewType, false, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1); return true; } if (event == Ion::Events::Clear) { @@ -204,20 +206,7 @@ KDCoordinate HistoryController::rowHeight(int j) { } Shared::ExpiringPointer calculation = calculationAtIndex(j); bool expanded = j == selectedRow() && selectedSubviewType() == SubviewType::Output; - KDCoordinate result = calculation->memoizedHeight(expanded); - if (result < 0) { - result = HistoryViewCell::Height(calculation.pointer(), expanded); - if (result < 0) { - // Raise, because Height modified the calculation and failed. - Poincare::ExceptionCheckpoint::Raise(); - } - calculation->setMemoizedHeight(expanded, result); - } - /* We might want to put an assertion here to check the memoization: - * assert(result == HistoryViewCell::Height(calculation.pointer(), expanded)); - * However, Height might fail due to pool memory exhaustion, in which case the - * assertion fails even if "result" had the right value. */ - return result; + return calculation->height(expanded); } int HistoryController::typeAtLocation(int i, int j) { diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index 1f47f7e0f..87e84e5fc 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -36,16 +36,7 @@ void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType, KDCoordinate HistoryViewCell::Height(Calculation * calculation, bool expanded) { HistoryViewCell cell(nullptr); - bool didForceOutput = false; - cell.setCalculation(calculation, expanded, &didForceOutput); - if (didForceOutput) { - /* We could not compute the height of the calculation as it is (the display - * output was forced to another value during the height computation). - * Warning: the display output of calculation was actually changed, so it - * will cause problems if we already did some computations with another - * display value. */ - return -1; - } + cell.setCalculation(calculation, expanded, true); KDRect ellipsisFrame = KDRectZero; KDRect inputFrame = KDRectZero; KDRect outputFrame = KDRectZero; @@ -246,8 +237,7 @@ void HistoryViewCell::resetMemoization() { m_calculationCRC32 = 0; } -void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput) { - assert(!didForceOutput || *didForceOutput == false); +void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, bool canChangeDisplayOutput) { uint32_t newCalculationCRC = Ion::crc32Byte((const uint8_t *)calculation, ((char *)calculation->next()) - ((char *) calculation)); if (newCalculationCRC == m_calculationCRC32 && m_calculationExpanded == expanded) { return; @@ -273,11 +263,8 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, b bool couldNotCreateExactLayout = false; exactOutputLayout = calculation->createExactOutputLayout(&couldNotCreateExactLayout); if (couldNotCreateExactLayout) { - if (calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) { + if (canChangeDisplayOutput && calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) { calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); - if (didForceOutput) { - *didForceOutput = true; - } } else { /* We should only display the exact result, but we cannot create it * -> raise an exception. */ @@ -294,21 +281,18 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, b bool couldNotCreateApproximateLayout = false; approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout); if (couldNotCreateApproximateLayout) { - if (calculation->displayOutput(context) == ::Calculation::Calculation::DisplayOutput::ApproximateOnly) { - Poincare::ExceptionCheckpoint::Raise(); - } else { + if (canChangeDisplayOutput && calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ApproximateOnly) { /* Set the display output to ApproximateOnly, make room in the pool by * erasing the exact layout, and retry to create the approximate layout */ calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); - if (didForceOutput) { - *didForceOutput = true; - } exactOutputLayout = Poincare::Layout(); couldNotCreateApproximateLayout = false; approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout); if (couldNotCreateApproximateLayout) { Poincare::ExceptionCheckpoint::Raise(); } + } else { + Poincare::ExceptionCheckpoint::Raise(); } } } diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index 2932ee1a5..38d7e22f1 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -51,7 +51,7 @@ public: Poincare::Layout layout() const override; KDColor backgroundColor() const override { return m_even ? Palette::CalculationBackgroundEven : Palette::CalculationBackgroundOdd; } void resetMemoization(); - void setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput = nullptr); + void setCalculation(Calculation * calculation, bool expanded, bool canChangeDisplayOutput = false); int numberOfSubviews() const override { return 2 + displayedEllipsis(); } View * subviewAtIndex(int index) override; void layoutSubviews(bool force = false) override; diff --git a/apps/calculation/test/calculation_store.cpp b/apps/calculation/test/calculation_store.cpp index 48e1af129..eb2045778 100644 --- a/apps/calculation/test/calculation_store.cpp +++ b/apps/calculation/test/calculation_store.cpp @@ -14,6 +14,7 @@ void assert_store_is(CalculationStore * store, const char * * result) { } } +KDCoordinate dummyHeight(::Calculation::Calculation * c, bool expanded) { return 0; } QUIZ_CASE(calculation_store) { Shared::GlobalContext globalContext; @@ -22,7 +23,7 @@ QUIZ_CASE(calculation_store) { const char * result[] = {"9", "8", "7", "6", "5", "4", "3", "2", "1", "0"}; for (int i = 0; i < 10; i++) { char text[2] = {(char)(i+'0'), 0}; - store.push(text, &globalContext); + store.push(text, &globalContext, dummyHeight); quiz_assert(store.numberOfCalculations() == i+1); } assert_store_is(&store, result); @@ -41,13 +42,13 @@ QUIZ_CASE(calculation_ans) { Shared::GlobalContext globalContext; CalculationStore store; - store.push("1+3/4", &globalContext); - store.push("ans+2/3", &globalContext); + store.push("1+3/4", &globalContext, dummyHeight); + store.push("ans+2/3", &globalContext, dummyHeight); Shared::ExpiringPointer<::Calculation::Calculation> lastCalculation = store.calculationAtIndex(0); quiz_assert(lastCalculation->displayOutput(&globalContext) == ::Calculation::Calculation::DisplayOutput::ExactAndApproximate); quiz_assert(strcmp(lastCalculation->exactOutputText(),"29/12") == 0); - store.push("ans+0.22", &globalContext); + store.push("ans+0.22", &globalContext, dummyHeight); lastCalculation = store.calculationAtIndex(0); quiz_assert(lastCalculation->displayOutput(&globalContext) == ::Calculation::Calculation::DisplayOutput::ExactAndApproximateToggle); quiz_assert(strcmp(lastCalculation->approximateOutputText(::Calculation::Calculation::NumberOfSignificantDigits::Maximal),"2.6366666666667") == 0); @@ -56,7 +57,7 @@ QUIZ_CASE(calculation_ans) { } void assertCalculationIs(const char * input, ::Calculation::Calculation::DisplayOutput display, ::Calculation::Calculation::EqualSign sign, const char * exactOutput, const char * displayedApproximateOutput, const char * storedApproximateOutput, Context * context, CalculationStore * store) { - store->push(input, context); + store->push(input, context, dummyHeight); Shared::ExpiringPointer<::Calculation::Calculation> lastCalculation = store->calculationAtIndex(0); quiz_assert(lastCalculation->displayOutput(context) == display); if (sign != ::Calculation::Calculation::EqualSign::Unknown) { diff --git a/apps/code/base.it.i18n b/apps/code/base.it.i18n index d3778db0a..cd99347a2 100644 --- a/apps/code/base.it.i18n +++ b/apps/code/base.it.i18n @@ -1,7 +1,7 @@ AddScript = "Aggiungere script" AllowedCharactersaz09 = "Caratteri consentiti : a-z, 0-9, _" Autocomplete = "Autocompletamento" -AutoImportScript = "Importazione automatica dello script" +AutoImportScript = "Auto importazione nella console" BuiltinsAndKeywords = "Funzioni native e parole chiave" Console = "Console d'esecuzione" DeleteScript = "Eliminare lo script" diff --git a/apps/graph/graph/preimage_parameter_controller.cpp b/apps/graph/graph/preimage_parameter_controller.cpp index 1c1e519da..cc96183b2 100644 --- a/apps/graph/graph/preimage_parameter_controller.cpp +++ b/apps/graph/graph/preimage_parameter_controller.cpp @@ -21,10 +21,6 @@ PreimageParameterController::PreimageParameterController( { } -const char * PreimageParameterController::title() { - return I18n::translate(I18n::Message::Preimage); -} - void PreimageParameterController::viewWillAppear() { setParameterName(I18n::Message::Y); m_preimageGraphController->setImage(m_cursor->y()); @@ -32,19 +28,17 @@ void PreimageParameterController::viewWillAppear() { } void PreimageParameterController::buttonAction() { - m_preimageGraphController->setRecord(m_record); - StackViewController * stack = static_cast(parentResponder()); - stack->pop(); - stack->pop(); - stack->pop(); - stack->push(m_preimageGraphController); + if (confirmParameterAtIndex(0, m_tempParameter)) { + m_preimageGraphController->setRecord(m_record); + StackViewController * stack = static_cast(parentResponder()); + stack->pop(); + stack->pop(); + stack->pop(); + stack->push(m_preimageGraphController); + } } -double PreimageParameterController::parameterAtIndex(int index) { - assert(index == 0); - return m_preimageGraphController->image(); -} -bool PreimageParameterController::setParameterAtIndex(int parameterIndex, double f) { +bool PreimageParameterController::confirmParameterAtIndex(int parameterIndex, double f) { assert(parameterIndex == 0); m_preimageGraphController->setImage(f); return true; diff --git a/apps/graph/graph/preimage_parameter_controller.h b/apps/graph/graph/preimage_parameter_controller.h index dbe683004..1b8d1a963 100644 --- a/apps/graph/graph/preimage_parameter_controller.h +++ b/apps/graph/graph/preimage_parameter_controller.h @@ -15,13 +15,16 @@ public: Shared::CurveViewCursor * cursor, PreimageGraphController * preimageGraphController ); - const char * title() override; + const char * title() override { return I18n::translate(I18n::Message::Preimage); } void setRecord(Ion::Storage::Record record) { m_record = record; } void viewWillAppear() override; private: void buttonAction() override; - double parameterAtIndex(int index) override; - bool setParameterAtIndex(int parameterIndex, double f) override; + double extractParameterAtIndex(int index) override { + assert(index == 0); + return m_preimageGraphController->image(); + } + bool confirmParameterAtIndex(int parameterIndex, double f) override; Ion::Storage::Record m_record; PreimageGraphController * m_preimageGraphController; }; diff --git a/apps/regression/go_to_parameter_controller.cpp b/apps/regression/go_to_parameter_controller.cpp index d313f8e63..461f98bfa 100644 --- a/apps/regression/go_to_parameter_controller.cpp +++ b/apps/regression/go_to_parameter_controller.cpp @@ -30,7 +30,7 @@ const char * GoToParameterController::title() { return I18n::translate(I18n::Message::YPrediction); } -double GoToParameterController::parameterAtIndex(int index) { +double GoToParameterController::extractParameterAtIndex(int index) { assert(index == 0); if (m_xPrediction) { return m_cursor->x(); @@ -38,7 +38,7 @@ double GoToParameterController::parameterAtIndex(int index) { return m_cursor->y(); } -bool GoToParameterController::setParameterAtIndex(int parameterIndex, double f) { +bool GoToParameterController::confirmParameterAtIndex(int parameterIndex, double f) { assert(parameterIndex == 0); int series = m_graphController->selectedSeriesIndex(); Poincare::Context * globContext = AppsContainer::sharedAppsContainer()->globalContext(); diff --git a/apps/regression/go_to_parameter_controller.h b/apps/regression/go_to_parameter_controller.h index c5d27f6c7..3fa6d6aab 100644 --- a/apps/regression/go_to_parameter_controller.h +++ b/apps/regression/go_to_parameter_controller.h @@ -15,8 +15,8 @@ public: void setXPrediction(bool xPrediction); const char * title() override; private: - double parameterAtIndex(int index) override; - bool setParameterAtIndex(int parameterIndex, double f) override; + double extractParameterAtIndex(int index) override; + bool confirmParameterAtIndex(int parameterIndex, double f) override; Store * m_store; bool m_xPrediction; GraphController * m_graphController; diff --git a/apps/shared/function_go_to_parameter_controller.cpp b/apps/shared/function_go_to_parameter_controller.cpp index 3382815b1..c5b21cb43 100644 --- a/apps/shared/function_go_to_parameter_controller.cpp +++ b/apps/shared/function_go_to_parameter_controller.cpp @@ -11,16 +11,7 @@ FunctionGoToParameterController::FunctionGoToParameterController(Responder * par { } -const char * FunctionGoToParameterController::title() { - return I18n::translate(I18n::Message::Goto); -} - -double FunctionGoToParameterController::parameterAtIndex(int index) { - assert(index == 0); - return m_cursor->t(); -} - -bool FunctionGoToParameterController::setParameterAtIndex(int parameterIndex, double f) { +bool FunctionGoToParameterController::confirmParameterAtIndex(int parameterIndex, double f) { assert(parameterIndex == 0); FunctionApp * myApp = FunctionApp::app(); ExpiringPointer function = myApp->functionStore()->modelForRecord(m_record); diff --git a/apps/shared/function_go_to_parameter_controller.h b/apps/shared/function_go_to_parameter_controller.h index 5af912a31..a5680105f 100644 --- a/apps/shared/function_go_to_parameter_controller.h +++ b/apps/shared/function_go_to_parameter_controller.h @@ -9,13 +9,16 @@ namespace Shared { class FunctionGoToParameterController : public GoToParameterController { public: FunctionGoToParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor); - const char * title() override; + const char * title() override { return I18n::translate(I18n::Message::Goto); } void setRecord(Ion::Storage::Record record); protected: - bool setParameterAtIndex(int parameterIndex, double f) override; + bool confirmParameterAtIndex(int parameterIndex, double f) override; Ion::Storage::Record m_record; private: - double parameterAtIndex(int index) override; + double extractParameterAtIndex(int index) override { + assert(index == 0); + return m_cursor->t(); + } }; } diff --git a/apps/shared/go_to_parameter_controller.cpp b/apps/shared/go_to_parameter_controller.cpp index d72ab64d9..5151af985 100644 --- a/apps/shared/go_to_parameter_controller.cpp +++ b/apps/shared/go_to_parameter_controller.cpp @@ -11,19 +11,11 @@ GoToParameterController::GoToParameterController(Responder * parentResponder, In { } -int GoToParameterController::numberOfRows() const { - return 2; -} - HighlightCell * GoToParameterController::reusableParameterCell(int index, int type) { assert(index == 0); return &m_parameterCell; } -int GoToParameterController::reusableParameterCellCount(int type) { - return 1; -} - bool GoToParameterController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::Left) { stackController()->pop(); @@ -32,10 +24,25 @@ bool GoToParameterController::handleEvent(Ion::Events::Event event) { return false; } +void GoToParameterController::viewWillAppear() { + // Initialize m_tempParameter to the extracted value. + setParameterAtIndex(0, extractParameterAtIndex(0)); + FloatParameterController::viewWillAppear(); +} + +bool GoToParameterController::setParameterAtIndex(int parameterIndex, double f) { + assert(parameterIndex == 0); + m_tempParameter = f; + return true; +} + void GoToParameterController::buttonAction() { - StackViewController * stack = (StackViewController *)parentResponder(); - stack->pop(); - stack->pop(); + // Update parameter value to m_tempParameter, and proceed if value is valid + if (confirmParameterAtIndex(0, m_tempParameter)) { + StackViewController * stack = (StackViewController *)parentResponder(); + stack->pop(); + stack->pop(); + } } } diff --git a/apps/shared/go_to_parameter_controller.h b/apps/shared/go_to_parameter_controller.h index 31516b923..24b39c5ea 100644 --- a/apps/shared/go_to_parameter_controller.h +++ b/apps/shared/go_to_parameter_controller.h @@ -11,16 +11,28 @@ namespace Shared { class GoToParameterController : public FloatParameterController { public: GoToParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor); - int numberOfRows() const override; + int numberOfRows() const override { return 2; } bool handleEvent(Ion::Events::Event event) override; protected: void setParameterName(I18n::Message message) { m_parameterCell.setMessage(message); } + void viewWillAppear() override; + // extractParameterAtIndex extracts the current value of the parameter + virtual double extractParameterAtIndex(int index) = 0; + // confirmParameterAtIndex updates the current value of the parameter + virtual bool confirmParameterAtIndex(int parameterIndex, double f) = 0; + // parameterAtIndex and setParameterAtIndex manipulate m_tempParameter only + double parameterAtIndex(int index) override { + assert(index == 0); + return m_tempParameter; + } + bool setParameterAtIndex(int parameterIndex, double f) override; CurveViewCursor * m_cursor; InteractiveCurveViewRange * m_graphRange; + double m_tempParameter; private: void buttonAction() override; HighlightCell * reusableParameterCell(int index, int type) override; - int reusableParameterCellCount(int type) override; + int reusableParameterCellCount(int type) override { return 1; } MessageTableCellWithEditableText m_parameterCell; }; diff --git a/apps/shared/interactive_curve_view_controller.cpp b/apps/shared/interactive_curve_view_controller.cpp index 6daeacea0..c6b736296 100644 --- a/apps/shared/interactive_curve_view_controller.cpp +++ b/apps/shared/interactive_curve_view_controller.cpp @@ -15,8 +15,10 @@ InteractiveCurveViewController::InteractiveCurveViewController(Responder * paren m_rangeVersion(rangeVersion), m_rangeParameterController(this, inputEventHandlerDelegate, interactiveRange), m_zoomParameterController(this, interactiveRange, curveView), + m_interactiveRange(interactiveRange), m_rangeButton(this, I18n::Message::Axis, Invocation([](void * context, void * sender) { InteractiveCurveViewController * graphController = (InteractiveCurveViewController *) context; + graphController->rangeParameterController()->setRange(graphController->interactiveRange()); StackViewController * stack = graphController->stackController(); stack->push(graphController->rangeParameterController()); return true; @@ -113,7 +115,7 @@ void InteractiveCurveViewController::didBecomeFirstResponder() { } } -ViewController * InteractiveCurveViewController::rangeParameterController() { +RangeParameterController * InteractiveCurveViewController::rangeParameterController() { return &m_rangeParameterController; } diff --git a/apps/shared/interactive_curve_view_controller.h b/apps/shared/interactive_curve_view_controller.h index c732ff524..99927b65a 100644 --- a/apps/shared/interactive_curve_view_controller.h +++ b/apps/shared/interactive_curve_view_controller.h @@ -19,7 +19,7 @@ public: void didBecomeFirstResponder() override; TELEMETRY_ID("Graph"); - ViewController * rangeParameterController(); + RangeParameterController * rangeParameterController(); ViewController * zoomParameterController(); virtual ViewController * initialisationParameterController() = 0; @@ -35,6 +35,7 @@ public: void willExitResponderChain(Responder * nextFirstResponder) override; bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; + protected: Responder * tabController() const; virtual StackViewController * stackController() const; @@ -56,6 +57,8 @@ protected: // SimpleInteractiveCurveViewController float cursorBottomMarginRatio() override; + InteractiveCurveViewRange * interactiveRange() { return m_interactiveRange; } + OkView m_okView; private: /* The value 21 is the actual height of the ButtonRow, that is @@ -75,6 +78,7 @@ private: uint32_t * m_rangeVersion; RangeParameterController m_rangeParameterController; ZoomParameterController m_zoomParameterController; + InteractiveCurveViewRange * m_interactiveRange; Button m_rangeButton; Button m_zoomButton; Button m_defaultInitialisationButton; diff --git a/apps/shared/interval.cpp b/apps/shared/interval.cpp index 4754feb3d..1fccb9e81 100644 --- a/apps/shared/interval.cpp +++ b/apps/shared/interval.cpp @@ -29,21 +29,6 @@ double Interval::element(int i) { return m_intervalBuffer[i]; } -void Interval::setStart(double f) { - m_start = f; - m_needCompute = true; -} - -void Interval::setEnd(double f) { - m_end = f; - m_needCompute = true; -} - -void Interval::setStep(double f) { - m_step = f; - m_needCompute = true; -} - void Interval::setElement(int i, double f) { assert(i <= numberOfElements() && i < k_maxNumberOfElements); computeElements(); @@ -54,16 +39,16 @@ void Interval::setElement(int i, double f) { } void Interval::reset() { - m_start = 0.0; - m_end = 10.0; - m_step = 1.0; + m_parameters.setStart(0.0); + m_parameters.setEnd(10.0); + m_parameters.setStep(1.0); m_needCompute = true; } void Interval::clear() { - m_start = 1.0; - m_end = 0.0; - m_step = 1.0; + m_parameters.setStart(1.0); + m_parameters.setEnd(0.0); + m_parameters.setStep(1.0); m_needCompute = true; } @@ -71,14 +56,14 @@ void Interval::computeElements() { if (!m_needCompute) { return; } - if (m_start > m_end) { + if (m_parameters.start() > m_parameters.end()) { m_numberOfElements = 0; } else { - m_numberOfElements = m_step > 0 ? 1 + (m_end - m_start)/m_step : k_maxNumberOfElements; + m_numberOfElements = m_parameters.step() > 0 ? 1 + (m_parameters.end() - m_parameters.start())/m_parameters.step() : k_maxNumberOfElements; m_numberOfElements = m_numberOfElements > k_maxNumberOfElements || m_numberOfElements < 0 ? k_maxNumberOfElements : m_numberOfElements; } for (int i = 0; i < m_numberOfElements; i += 1) { - m_intervalBuffer[i] = m_start + i * m_step; + m_intervalBuffer[i] = m_parameters.start() + i * m_parameters.step(); } m_needCompute = false; } diff --git a/apps/shared/interval.h b/apps/shared/interval.h index 3be28dc93..95c269d68 100644 --- a/apps/shared/interval.h +++ b/apps/shared/interval.h @@ -10,13 +10,22 @@ public: Interval(const Interval&) = delete; int numberOfElements(); void deleteElementAtIndex(int index); + class IntervalParameters { + public: + void setStart(double f) { m_start = f; } + void setEnd(double f) { m_end = f; } + void setStep(double f) { m_step = f; } + double start() const { return m_start; } + double end() const { return m_end; } + double step() const { return m_step; } + private: + double m_start; + double m_end; + double m_step; + }; double element(int i); - double start() const { return m_start; } - double end() const { return m_end; } - double step() const { return m_step; } - void setStart(double f); - void setEnd(double f); - void setStep(double f); + IntervalParameters * parameters() { return &m_parameters; } + void setParameters(IntervalParameters parameters) { m_parameters = parameters; } void setElement(int i, double f); void forceRecompute(){ m_needCompute = true;} void reset(); @@ -27,14 +36,12 @@ private: void computeElements(); int m_numberOfElements; double m_intervalBuffer[k_maxNumberOfElements]; - double m_start; - double m_end; - double m_step; bool m_needCompute; + IntervalParameters m_parameters; }; -typedef void (Interval::*SetterPointer)(double); -typedef double (Interval::*GetterPointer)() const; +typedef void (Interval::IntervalParameters::*SetterPointer)(double); +typedef double (Interval::IntervalParameters::*GetterPointer)() const; } diff --git a/apps/shared/interval_parameter_controller.cpp b/apps/shared/interval_parameter_controller.cpp index cc8a41bca..2404f4604 100644 --- a/apps/shared/interval_parameter_controller.cpp +++ b/apps/shared/interval_parameter_controller.cpp @@ -2,6 +2,11 @@ namespace Shared { +Interval::IntervalParameters * IntervalParameterController::SharedTempIntervalParameters() { + static Interval::IntervalParameters sTempIntervalParameters; + return &sTempIntervalParameters; +} + IntervalParameterController::IntervalParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate) : FloatParameterController(parentResponder), m_interval(nullptr), @@ -16,6 +21,11 @@ IntervalParameterController::IntervalParameterController(Responder * parentRespo } } +void IntervalParameterController::setInterval(Interval * interval) { + m_interval = interval; + *SharedTempIntervalParameters() = *(interval->parameters()); +} + const char * IntervalParameterController::title() { return I18n::translate(m_title); } @@ -42,8 +52,8 @@ void IntervalParameterController::willDisplayCellForIndex(HighlightCell * cell, } double IntervalParameterController::parameterAtIndex(int index) { - GetterPointer getters[k_totalNumberOfCell] = {&Interval::start, &Interval::end, &Interval::step}; - return (m_interval->*getters[index])(); + GetterPointer getters[k_totalNumberOfCell] = {&Shared::Interval::IntervalParameters::start, &Shared::Interval::IntervalParameters::end, &Shared::Interval::IntervalParameters::step}; + return (SharedTempIntervalParameters()->*getters[index])(); } bool IntervalParameterController::setParameterAtIndex(int parameterIndex, double f) { @@ -51,18 +61,18 @@ bool IntervalParameterController::setParameterAtIndex(int parameterIndex, double Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); return false; } - double start = parameterIndex == 0 ? f : m_interval->start(); - double end = parameterIndex == 1 ? f : m_interval->end(); + double start = parameterIndex == 0 ? f : SharedTempIntervalParameters()->start(); + double end = parameterIndex == 1 ? f : SharedTempIntervalParameters()->end(); if (start > end) { if (parameterIndex == 1) { Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); return false; } double g = f+1.0; - m_interval->setEnd(g); + SharedTempIntervalParameters()->setEnd(g); } - SetterPointer setters[k_totalNumberOfCell] = {&Interval::setStart, &Interval::setEnd, &Interval::setStep}; - (m_interval->*setters[parameterIndex])(f); + SetterPointer setters[k_totalNumberOfCell] = {&Shared::Interval::IntervalParameters::setStart, &Shared::Interval::IntervalParameters::setEnd, &Shared::Interval::IntervalParameters::setStep}; + (SharedTempIntervalParameters()->*setters[parameterIndex])(f); return true; } @@ -85,6 +95,7 @@ int IntervalParameterController::reusableParameterCellCount(int type) { } void IntervalParameterController::buttonAction() { + m_interval->setParameters(*SharedTempIntervalParameters()); m_interval->forceRecompute(); StackViewController * stack = stackController(); stack->pop(); diff --git a/apps/shared/interval_parameter_controller.h b/apps/shared/interval_parameter_controller.h index 9ed10d99b..21c689a3a 100644 --- a/apps/shared/interval_parameter_controller.h +++ b/apps/shared/interval_parameter_controller.h @@ -12,7 +12,7 @@ class IntervalParameterController : public Shared::FloatParameterController(parentResponder), m_interactiveRange(interactiveRange), + m_tempInteractiveRange(*interactiveRange), m_xRangeCells{}, m_yRangeCells{}, m_yAutoCell(I18n::Message::YAuto) @@ -18,7 +19,7 @@ RangeParameterController::RangeParameterController(Responder * parentResponder, } for (int i = 0; i < k_numberOfConvertibleTextCell; i++) { m_yRangeCells[i].setParentResponder(&m_selectableTableView); - m_yRangeCells[i].setInteractiveCurveViewRange(m_interactiveRange); + m_yRangeCells[i].setInteractiveCurveViewRange(&m_tempInteractiveRange); m_yRangeCells[i].textField()->setDelegates(inputEventHandlerDelegate, this); } } @@ -50,13 +51,13 @@ void RangeParameterController::willDisplayCellForIndex(HighlightCell * cell, int } if (index == 2) { SwitchView * switchView = (SwitchView *)m_yAutoCell.accessoryView(); - switchView->setState(m_interactiveRange->yAuto()); + switchView->setState(m_tempInteractiveRange.yAuto()); return; } MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *)cell; I18n::Message labels[k_numberOfTextCell+1] = {I18n::Message::XMin, I18n::Message::XMax, I18n::Message::Default, I18n::Message::YMin, I18n::Message::YMax}; myCell->setMessage(labels[index]); - KDColor yColor = m_interactiveRange->yAuto() ? Palette::SecondaryText : Palette::PrimaryText; + KDColor yColor = m_tempInteractiveRange.yAuto() ? Palette::SecondaryText : Palette::PrimaryText; KDColor colors[k_numberOfTextCell+1] = {Palette::PrimaryText, Palette::PrimaryText, Palette::PrimaryText, yColor, yColor}; myCell->setTextColor(colors[index]); FloatParameterController::willDisplayCellForIndex(cell, index); @@ -70,9 +71,14 @@ bool RangeParameterController::textFieldDidFinishEditing(TextField * textField, return false; } +void RangeParameterController::setRange(InteractiveCurveViewRange * range){ + m_interactiveRange = range; + m_tempInteractiveRange = *range; +} + bool RangeParameterController::handleEvent(Ion::Events::Event event) { if (activeCell() == 2 && (event == Ion::Events::OK || event == Ion::Events::EXE)) { - m_interactiveRange->setYAuto(!m_interactiveRange->yAuto()); + m_tempInteractiveRange.setYAuto(!m_tempInteractiveRange.yAuto()); m_selectableTableView.reloadData(); return true; } @@ -83,14 +89,14 @@ float RangeParameterController::parameterAtIndex(int parameterIndex) { ParameterGetterPointer getters[k_numberOfTextCell] = {&InteractiveCurveViewRange::xMin, &InteractiveCurveViewRange::xMax, &InteractiveCurveViewRange::yMin, &InteractiveCurveViewRange::yMax}; int index = parameterIndex > 2 ? parameterIndex - 1 : parameterIndex; - return (m_interactiveRange->*getters[index])(); + return (m_tempInteractiveRange.*getters[index])(); } bool RangeParameterController::setParameterAtIndex(int parameterIndex, float f) { ParameterSetterPointer setters[k_numberOfTextCell] = {&InteractiveCurveViewRange::setXMin, &InteractiveCurveViewRange::setXMax, &InteractiveCurveViewRange::setYMin, &InteractiveCurveViewRange::setYMax}; int index = parameterIndex > 2 ? parameterIndex - 1 : parameterIndex; - (m_interactiveRange->*setters[index])(f); + (m_tempInteractiveRange.*setters[index])(f); return true; } @@ -119,4 +125,10 @@ int RangeParameterController::reusableParameterCellCount(int type) { return k_numberOfConvertibleTextCell; } +void RangeParameterController::buttonAction() { + *m_interactiveRange = m_tempInteractiveRange; + StackViewController * stack = stackController(); + stack->pop(); +} + } diff --git a/apps/shared/range_parameter_controller.h b/apps/shared/range_parameter_controller.h index 250ba0ce8..a2006f284 100644 --- a/apps/shared/range_parameter_controller.h +++ b/apps/shared/range_parameter_controller.h @@ -16,6 +16,7 @@ public: void willDisplayCellForIndex(HighlightCell * cell, int index) override; bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; bool handleEvent(Ion::Events::Event event) override; + void setRange(InteractiveCurveViewRange * range); TELEMETRY_ID("Range"); private: class MessageTableCellWithConvertibleEditableText : public MessageTableCellWithEditableText { @@ -35,10 +36,12 @@ private: int reusableParameterCellCount(int type) override; float parameterAtIndex(int index) override; bool setParameterAtIndex(int parameterIndex, float f) override; + void buttonAction() override; constexpr static int k_numberOfEditableTextCell = 2; constexpr static int k_numberOfConvertibleTextCell = 2; constexpr static int k_numberOfTextCell = k_numberOfEditableTextCell+k_numberOfConvertibleTextCell; InteractiveCurveViewRange * m_interactiveRange; + InteractiveCurveViewRange m_tempInteractiveRange; MessageTableCellWithEditableText m_xRangeCells[k_numberOfEditableTextCell]; MessageTableCellWithConvertibleEditableText m_yRangeCells[k_numberOfConvertibleTextCell]; MessageTableCellWithSwitch m_yAutoCell; diff --git a/apps/shared/toolbox_helpers.cpp b/apps/shared/toolbox_helpers.cpp index 8758ca763..fc16a0544 100644 --- a/apps/shared/toolbox_helpers.cpp +++ b/apps/shared/toolbox_helpers.cpp @@ -41,7 +41,7 @@ void TextToInsertForCommandText(const char * command, int commandLength, char * UTF8Decoder decoder(command); CodePoint codePoint = decoder.nextCodePoint(); - while (codePoint != UCodePointNull && (commandLength < 0 || (decoder.stringPosition() - command <= commandLength))) { + while (codePoint != UCodePointNull && index < bufferSize - 1 && (commandLength < 0 || (decoder.stringPosition() - command <= commandLength))) { if (codePoint == ')') { numberOfOpenParentheses--; } else if (codePoint == ']') { diff --git a/apps/toolbox.nl.i18n b/apps/toolbox.nl.i18n index d4c4516e8..e4f6713ed 100644 --- a/apps/toolbox.nl.i18n +++ b/apps/toolbox.nl.i18n @@ -116,7 +116,7 @@ BasedLogarithm = "Logaritme met grondtal a" Calculation = "Calculatie" ComplexNumber = "Complexe getallen" Combinatorics = "Combinatoriek" -Arithmetic = "rekenkunde" +Arithmetic = "Rekenkunde" Matrices = "Matrix" NewMatrix = "Nieuwe matrix" Identity = "Eenheidsmatrix van formaat n" diff --git a/ion/src/device/shared/drivers/display.cpp b/ion/src/device/shared/drivers/display.cpp index fdf504847..508242dde 100644 --- a/ion/src/device/shared/drivers/display.cpp +++ b/ion/src/device/shared/drivers/display.cpp @@ -434,8 +434,9 @@ void initPanel() { // Calibration const uint8_t * gammaCalibration = nullptr; uint32_t panelId = panelIdentifier(); - if (panelId == 0x4E4101) { - // Don't forget the "static" qualifier, otherwise this array can be deleted before reaching send_long_command + if (panelId == 0x4E4101 || panelId == 0x4E4801) { + /* Don't forget the "static" qualifier, otherwise this array can be deleted + * before reaching send_long_command. */ static const uint8_t calibration[] = {0xA2, 0xA, 0x11, 0xA, 0xC, 0x1A, 0x34, 0x22, 0x4D, 0x28, 0x15, 0x13, 0x29, 0x2D}; gammaCalibration = calibration; } diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 141cf5a5f..0eaf6aa94 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -156,13 +156,16 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon * the result is not homogeneous. */ { Expression unit; - childAtIndex(0).removeUnit(&unit); + if (childAtIndex(0).removeUnit(&unit).isUndefined()) { + return replaceWithUndefinedInPlace(); + } const bool hasUnit = !unit.isUninitialized(); for (int i = 1; i < childrenCount; i++) { Expression otherUnit; - childAtIndex(i).removeUnit(&otherUnit); - if (hasUnit == otherUnit.isUninitialized() || - (hasUnit && !unit.isIdenticalTo(otherUnit))) + Expression childI = childAtIndex(i).removeUnit(&otherUnit); + if (childI.isUndefined() + || hasUnit == otherUnit.isUninitialized() + || (hasUnit && !unit.isIdenticalTo(otherUnit))) { return replaceWithUndefinedInPlace(); } diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 41b9b04bd..f9b066832 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -366,8 +366,8 @@ Expression Expression::defaultHandleUnitsInChildren() { const int childrenCount = numberOfChildren(); for (int i = 0; i < childrenCount; i++) { Expression unit; - childAtIndex(i).removeUnit(&unit); - if (!unit.isUninitialized()) { + Expression childI = childAtIndex(i).removeUnit(&unit); + if (childI.isUndefined() || !unit.isUninitialized()) { return replaceWithUndefinedInPlace(); } } @@ -817,7 +817,11 @@ Expression Expression::angleUnitToRadian(Preferences::AngleUnit angleUnit) { Expression Expression::reduce(ExpressionNode::ReductionContext reductionContext) { sSimplificationHasBeenInterrupted = false; - return deepReduce(reductionContext); + Expression result = deepReduce(reductionContext); + if (sSimplificationHasBeenInterrupted) { + return replaceWithUndefinedInPlace(); + } + return result; } Expression Expression::deepReduce(ExpressionNode::ReductionContext reductionContext) { diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 45eae68e9..14db22469 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -279,8 +279,16 @@ Expression Multiplication::removeUnit(Expression * unit) { Multiplication unitMult = Multiplication::Builder(); int resultChildrenCount = 0; for (int i = 0; i < numberOfChildren(); i++) { + Expression childI = childAtIndex(i); + assert(!childI.isUndefined()); Expression currentUnit; - childAtIndex(i).removeUnit(¤tUnit); + childI = childI.removeUnit(¤tUnit); + if (childI.isUndefined()) { + /* If the child was a unit convert, it replaced itself with an undefined + * during the removeUnit. */ + *unit = Expression(); + return replaceWithUndefinedInPlace(); + } if (!currentUnit.isUninitialized()) { unitMult.addChildAtIndexInPlace(currentUnit, resultChildrenCount, resultChildrenCount); resultChildrenCount++; @@ -384,7 +392,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu self = deepReduce(reductionContext); // removeUnit has to be called on reduced expression self = removeUnit(&units); - if (units.isUninitialized()) { + if (self.isUndefined() || units.isUninitialized()) { // TODO: handle error "Invalid unit" result = Undefined::Builder(); goto replace_by_result; diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 299221d86..dab4c6707 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -407,8 +407,8 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex { Expression indexUnit; index = index.removeUnit(&indexUnit); - if (!indexUnit.isUninitialized()) { - // There must be no unit in the exponent + if (!indexUnit.isUninitialized() || index.isUndefined()) { + // There must be no unit nor undefined in the exponent return replaceWithUndefinedInPlace(); } assert(index == childAtIndex(1)); diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index 9807c48be..c8c2acf7c 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -59,8 +59,8 @@ Expression UnitConvert::shallowBeautify(ExpressionNode::ReductionContext reducti reductionContext.target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined); Expression unit; - childAtIndex(1).clone().deepReduce(reductionContextWithUnits).removeUnit(&unit); - if (unit.isUninitialized()) { + Expression childWithoutUnit = childAtIndex(1).clone().deepReduce(reductionContextWithUnits).removeUnit(&unit); + if (childWithoutUnit.isUndefined() || unit.isUninitialized()) { // There is no unit on the right return replaceWithUndefinedInPlace(); } diff --git a/poincare/test/context.cpp b/poincare/test/context.cpp index b8b8d64dd..b11f65a0f 100644 --- a/poincare/test/context.cpp +++ b/poincare/test/context.cpp @@ -70,8 +70,8 @@ QUIZ_CASE(poincare_context_user_variable_simple) { } QUIZ_CASE(poincare_context_user_variable_2_circular_variables) { - assert_simplify("a→b"); - assert_simplify("b→a"); + assert_reduce("a→b"); + assert_reduce("b→a"); assert_expression_approximates_to("a", Undefined::Name()); assert_expression_approximates_to("b", Undefined::Name()); @@ -81,9 +81,9 @@ QUIZ_CASE(poincare_context_user_variable_2_circular_variables) { } QUIZ_CASE(poincare_context_user_variable_3_circular_variables) { - assert_simplify("a→b"); - assert_simplify("b→c"); - assert_simplify("c→a"); + assert_reduce("a→b"); + assert_reduce("b→c"); + assert_reduce("c→a"); assert_expression_approximates_to("a", Undefined::Name()); assert_expression_approximates_to("b", Undefined::Name()); assert_expression_approximates_to("c", Undefined::Name()); @@ -96,7 +96,7 @@ QUIZ_CASE(poincare_context_user_variable_3_circular_variables) { QUIZ_CASE(poincare_context_user_variable_1_circular_function) { // h: x → h(x) - assert_simplify("h(x)→h(x)"); + assert_reduce("h(x)→h(x)"); assert_expression_approximates_to("h(1)", Undefined::Name()); // Clean the storage for other tests @@ -104,9 +104,9 @@ QUIZ_CASE(poincare_context_user_variable_1_circular_function) { } QUIZ_CASE(poincare_context_user_variable_2_circular_functions) { - assert_simplify("1→f(x)"); - assert_simplify("f(x)→g(x)"); - assert_simplify("g(x)→f(x)"); + assert_reduce("1→f(x)"); + assert_reduce("f(x)→g(x)"); + assert_reduce("g(x)→f(x)"); assert_expression_approximates_to("f(1)", Undefined::Name()); assert_expression_approximates_to("g(1)", Undefined::Name()); @@ -116,10 +116,10 @@ QUIZ_CASE(poincare_context_user_variable_2_circular_functions) { } QUIZ_CASE(poincare_context_user_variable_3_circular_functions) { - assert_simplify("1→f(x)"); - assert_simplify("f(x)→g(x)"); - assert_simplify("g(x)→h(x)"); - assert_simplify("h(x)→f(x)"); + assert_reduce("1→f(x)"); + assert_reduce("f(x)→g(x)"); + assert_reduce("g(x)→h(x)"); + assert_reduce("h(x)→f(x)"); assert_expression_approximates_to("f(1)", Undefined::Name()); assert_expression_approximates_to("g(1)", Undefined::Name()); assert_expression_approximates_to("h(1)", Undefined::Name()); @@ -131,9 +131,9 @@ QUIZ_CASE(poincare_context_user_variable_3_circular_functions) { } QUIZ_CASE(poincare_context_user_variable_circular_variables_and_functions) { - assert_simplify("a→b"); - assert_simplify("b→a"); - assert_simplify("a→f(x)"); + assert_reduce("a→b"); + assert_reduce("b→a"); + assert_reduce("a→f(x)"); assert_expression_approximates_to("f(1)", Undefined::Name()); assert_expression_approximates_to("a", Undefined::Name()); assert_expression_approximates_to("b", Undefined::Name()); @@ -146,21 +146,21 @@ QUIZ_CASE(poincare_context_user_variable_circular_variables_and_functions) { QUIZ_CASE(poincare_context_user_variable_composed_functions) { // f: x→x^2 - assert_simplify("x^2→f(x)"); + assert_reduce("x^2→f(x)"); // g: x→f(x-2) - assert_simplify("f(x-2)→g(x)"); + assert_reduce("f(x-2)→g(x)"); assert_expression_approximates_to("f(2)", "4"); assert_expression_approximates_to("g(3)", "1"); assert_expression_approximates_to("g(5)", "9"); // g: x→f(x-2)+f(x+1) - assert_simplify("f(x-2)+f(x+1)→g(x)"); + assert_reduce("f(x-2)+f(x+1)→g(x)"); // Add a sum to bypass simplification assert_expression_approximates_to("g(3)+sum(1, n, 2, 4)", "20"); assert_expression_approximates_to("g(5)", "45"); // g: x→x+1 - assert_simplify("x+1→g(x)"); + assert_reduce("x+1→g(x)"); assert_expression_approximates_to("f(g(4))", "25"); // Add a sum to bypass simplification assert_expression_approximates_to("f(g(4))+sum(1, n, 2, 4)", "28"); @@ -172,7 +172,7 @@ QUIZ_CASE(poincare_context_user_variable_composed_functions) { QUIZ_CASE(poincare_context_user_variable_functions_approximation_with_value_for_symbol) { // f : x→ x^2 - assert_simplify("x^2→f(x)"); + assert_reduce("x^2→f(x)"); // Approximate f(?-2) with ? = 5 constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; @@ -187,7 +187,7 @@ QUIZ_CASE(poincare_context_user_variable_functions_approximation_with_value_for_ Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); // f : x → √(-1) - assert_simplify("√(-1)×√(-1)→f(x)"); + assert_reduce("√(-1)×√(-1)→f(x)"); // Approximate f(?) with ? = 5 // Cartesian assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(UCodePointUnknown)), x, 1.0, -1.0); diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index c55748011..145e533af 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -48,7 +48,7 @@ QUIZ_CASE(poincare_properties_is_approximate) { assert_expression_has_property("3.4", &context, Expression::IsApproximate); assert_expression_has_property("2.3+1", &context, Expression::IsApproximate); assert_expression_has_not_property("a", &context, Expression::IsApproximate); - assert_simplify("42.3→a"); + assert_reduce("42.3→a"); assert_expression_has_property("a", &context, Expression::IsApproximate); Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); } @@ -93,7 +93,7 @@ QUIZ_CASE(poincare_properties_is_infinity) { assert_expression_has_property("3.4+inf", &context, Expression::IsInfinity); assert_expression_has_not_property("2.3+1", &context, Expression::IsInfinity); assert_expression_has_not_property("a", &context, Expression::IsInfinity); - assert_simplify("42.3+inf→a"); + assert_reduce("42.3+inf→a"); assert_expression_has_property("a", &context, Expression::IsInfinity); Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); } @@ -155,7 +155,7 @@ QUIZ_CASE(poincare_properties_sign) { assert_reduced_expression_sign("sign(π)", Positive); assert_reduced_expression_sign("sign(-π)", Negative); assert_reduced_expression_sign("a", Unknown); - assert_simplify("42→a"); + assert_reduce("42→a"); assert_reduced_expression_sign("a", Positive); Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); } @@ -232,7 +232,7 @@ QUIZ_CASE(poincare_properties_polynomial_degree) { assert_reduced_expression_polynomial_degree("π×x", 1); assert_reduced_expression_polynomial_degree("√(-1)×x", -1, "x", Real); // f: x→x^2+πx+1 - assert_simplify("1+π×x+x^2→f(x)"); + assert_reduce("1+π×x+x^2→f(x)"); assert_reduced_expression_polynomial_degree("f(x)", 2); Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); } @@ -271,7 +271,7 @@ QUIZ_CASE(poincare_properties_characteristic_range) { // cos(cos(x)), degree assert_reduced_expression_has_characteristic_range(Cosine::Builder((Expression)Cosine::Builder(Symbol::Builder(UCodePointUnknown))), 360.0f); // f(x) with f : x --> cos(x), degree - assert_simplify("cos(x)→f(x)"); + assert_reduce("cos(x)→f(x)"); assert_reduced_expression_has_characteristic_range(Function::Builder("f",1,Symbol::Builder(UCodePointUnknown)), 360.0f); Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); } @@ -309,7 +309,7 @@ QUIZ_CASE(poincare_properties_get_variables) { assert_expression_has_variables("a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+aa+bb+cc+dd+ee+ff+gg+hh+ii+jj+kk+ll+mm+nn+oo", variableBuffer6, -1); assert_expression_has_variables("a+b+c+d+e+f+g", variableBuffer6, -1); // f: x→1+πx+x^2+toto - assert_simplify("1+π×x+x^2+toto→f(x)"); + assert_reduce("1+π×x+x^2+toto→f(x)"); const char * variableBuffer7[] = {"tata","toto", ""}; assert_expression_has_variables("f(tata)", variableBuffer7, 2); Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); @@ -347,7 +347,7 @@ QUIZ_CASE(poincare_properties_get_polynomial_coefficients) { assert_reduced_expression_has_polynomial_coefficient("x^2-π×x+1", "x", coefficient3); // f: x→x^2+Px+1 - assert_simplify("1+π×x+x^2→f(x)"); + assert_reduce("1+π×x+x^2→f(x)"); const char * coefficient4[] = {"1", "π", "1", 0}; //x^2+π×x+1 assert_reduced_expression_has_polynomial_coefficient("f(x)", "x", coefficient4); const char * coefficient5[] = {"0", "𝐢", 0}; //√(-1)x @@ -356,7 +356,7 @@ QUIZ_CASE(poincare_properties_get_polynomial_coefficients) { assert_reduced_expression_has_polynomial_coefficient("√(-1)x", "x", coefficient6, Real); // 3 -> x - assert_simplify("3→x"); + assert_reduce("3→x"); const char * coefficient7[] = {"4", 0}; assert_reduced_expression_has_polynomial_coefficient("x+1", "x", coefficient7 ); const char * coefficient8[] = {"2", "1", 0}; diff --git a/poincare/test/helper.cpp b/poincare/test/helper.cpp index 417fba00c..399cb589f 100644 --- a/poincare/test/helper.cpp +++ b/poincare/test/helper.cpp @@ -76,13 +76,13 @@ Poincare::Expression parse_expression(const char * expression, Context * context return result; } -void assert_simplify(const char * expression, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target) { +void assert_reduce(const char * expression, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target) { Shared::GlobalContext globalContext; Expression e = parse_expression(expression, &globalContext, false); - assert_expression_simplify(e, angleUnit, complexFormat, target, expression); + assert_expression_reduce(e, angleUnit, complexFormat, target, expression); } -void assert_expression_simplify(Expression e, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target, const char * printIfFailure) { +void assert_expression_reduce(Expression e, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target, const char * printIfFailure) { Shared::GlobalContext globalContext; e = e.reduce(ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, target)); quiz_assert_print_if_failure(!(e.isUninitialized()), printIfFailure); diff --git a/poincare/test/helper.h b/poincare/test/helper.h index 335efb1a3..afb122eb1 100644 --- a/poincare/test/helper.h +++ b/poincare/test/helper.h @@ -39,9 +39,9 @@ Poincare::Expression parse_expression(const char * expression, Poincare::Context // Simplification -void assert_simplify(const char * expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User); +void assert_reduce(const char * expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User); -void assert_expression_simplify(Poincare::Expression expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User, const char * printIfFailure = "Error"); +void assert_expression_reduce(Poincare::Expression expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User, const char * printIfFailure = "Error"); void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, Poincare::ExpressionNode::ReductionTarget target = User, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion unitConversion = DefaultUnitConversion); diff --git a/poincare/test/simplification.cpp b/poincare/test/simplification.cpp index 00a246928..64175b73c 100644 --- a/poincare/test/simplification.cpp +++ b/poincare/test/simplification.cpp @@ -898,7 +898,7 @@ QUIZ_CASE(poincare_simplification_matrix) { assert_parsed_expression_simplify_to("transpose(√(4))", "2"); // Expressions with unreduced matrix - assert_simplify("confidence(cos(2)/25,3)→a"); + assert_reduce("confidence(cos(2)/25,3)→a"); // Check that matrices are not permuted in multiplication assert_parsed_expression_simplify_to("cos(3a)*abs(transpose(a))", "cos(3×confidence(cos(2)/25,3))×abs(transpose(confidence(cos(2)/25,3)))"); assert_parsed_expression_simplify_to("abs(transpose(a))*cos(3a)", "abs(transpose(confidence(cos(2)/25,3)))×cos(3×confidence(cos(2)/25,3))"); @@ -1054,13 +1054,13 @@ QUIZ_CASE(poincare_simplification_unit_convert) { assert_parsed_expression_simplify_to("4→_km/_m", Undefined::Name()); assert_parsed_expression_simplify_to("3×_min→_s+1-1", Undefined::Name()); - assert_simplify("_m→a", Radian, Real); - assert_simplify("_m→b", Radian, Real); + assert_reduce("_m→a", Radian, Real); + assert_reduce("_m→b", Radian, Real); assert_parsed_expression_simplify_to("1_km→a×b", Undefined::Name()); - assert_simplify("2→a"); + assert_reduce("2→a"); assert_parsed_expression_simplify_to("3_m→a×_km", Undefined::Name()); - assert_simplify("2→f(x)"); + assert_reduce("2→f(x)"); assert_parsed_expression_simplify_to("3_m→f(2)×_km", Undefined::Name()); // Clean the storage for other tests @@ -1087,13 +1087,13 @@ QUIZ_CASE(poincare_simplification_complex_format) { // User defined variable assert_parsed_expression_simplify_to("a", "a", User, Radian, Real); // a = 2+i - assert_simplify("2+𝐢→a", Radian, Real); + assert_reduce("2+𝐢→a", Radian, Real); assert_parsed_expression_simplify_to("a", "unreal", User, Radian, Real); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); // User defined function // f : x → x+1 - assert_simplify("x+1+𝐢→f(x)", Radian, Real); + assert_reduce("x+1+𝐢→f(x)", Radian, Real); assert_parsed_expression_simplify_to("f(3)", "unreal", User, Radian, Real); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); @@ -1173,13 +1173,13 @@ QUIZ_CASE(poincare_simplification_complex_format) { // User defined variable assert_parsed_expression_simplify_to("a", "a", User, Radian, Cartesian); // a = 2+i - assert_simplify("2+𝐢→a", Radian, Cartesian); + assert_reduce("2+𝐢→a", Radian, Cartesian); assert_parsed_expression_simplify_to("a", "2+𝐢", User, Radian, Cartesian); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); // User defined function // f : x → x+1 - assert_simplify("x+1+𝐢→f(x)", Radian, Cartesian); + assert_reduce("x+1+𝐢→f(x)", Radian, Cartesian); assert_parsed_expression_simplify_to("f(3)", "4+𝐢", User, Radian, Cartesian); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); @@ -1223,13 +1223,13 @@ QUIZ_CASE(poincare_simplification_complex_format) { // User defined variable assert_parsed_expression_simplify_to("a", "a", User, Radian, Polar); // a = 2 + 𝐢 - assert_simplify("2+𝐢→a", Radian, Polar); + assert_reduce("2+𝐢→a", Radian, Polar); assert_parsed_expression_simplify_to("a", "√(5)×ℯ^\u0012\u0012-2×atan(2)+π\u0013/2×𝐢\u0013", User, Radian, Polar); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy(); // User defined function // f: x → x+1 - assert_simplify("x+1+𝐢→f(x)", Radian, Polar); + assert_reduce("x+1+𝐢→f(x)", Radian, Polar); assert_parsed_expression_simplify_to("f(3)", "√(17)×ℯ^\u0012\u0012-2×atan(4)+π\u0013/2×𝐢\u0013", User, Radian, Polar); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); @@ -1295,10 +1295,10 @@ QUIZ_CASE(poincare_simplification_unit_conversion) { QUIZ_CASE(poincare_simplification_user_function) { // User defined function // f: x → x*1 - assert_simplify("x*3→f(x)", Radian, Polar); + assert_reduce("x*3→f(x)", Radian, Polar); assert_parsed_expression_simplify_to("f(1+1)", "6", User, Radian, Polar); // f: x → 3 - assert_simplify("3→f(x)", Radian, Polar); + assert_reduce("3→f(x)", Radian, Polar); assert_parsed_expression_simplify_to("f(1/0)", Undefined::Name(), User, Radian, Polar); // Clean the storage for other tests Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); @@ -1315,8 +1315,19 @@ QUIZ_CASE(poincare_simplification_user_function_with_convert) { Function::Builder( "f", 1, Symbol::Builder('x'))); - assert_expression_simplify(e); - assert_simplify("e^(f(0))", Radian, Polar); + assert_expression_reduce(e); + assert_parsed_expression_simplify_to("e^(f(0))", "undef"); + + e = Store::Builder( + UnitConvert::Builder( + Rational::Builder(0), + Unit::Second()), + Function::Builder( + "f", 1, + Symbol::Builder('x'))); + assert_expression_reduce(e); + assert_parsed_expression_simplify_to("0f(0)", "undef"); + Ion::Storage::sharedStorage()->recordNamed("f.func").destroy(); }