diff --git a/apps/calculation/Makefile b/apps/calculation/Makefile index 22457b7c3..3186025b8 100644 --- a/apps/calculation/Makefile +++ b/apps/calculation/Makefile @@ -6,7 +6,9 @@ app_objs += $(addprefix apps/calculation/,\ history_view_cell.o\ history_controller.o\ local_context.o\ + output_expressions_view.o\ scrollable_expression_view.o\ + scrollable_output_expressions_view.o\ selectable_table_view.o\ text_field.o\ ) diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index a1cc677e2..22e0daca1 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -84,6 +84,14 @@ const char * Calculation::outputText() { return m_exactOutputText; } +const char * Calculation::exactOutputText() { + return m_exactOutputText; +} + +const char * Calculation::approximateOutputText() { + return m_approximateOutputText; +} + Expression * Calculation::input() { if (m_input == nullptr) { m_input = Expression::parse(m_inputText); @@ -197,6 +205,9 @@ ExpressionLayout * Calculation::approximateOutputLayout(Context * context) { } bool Calculation::shouldApproximateOutput() { + if (strcmp(m_exactOutputText, m_approximateOutputText) == 0) { + return true; + } return input()->recursivelyMatches([](const Expression * e) { return e->type() == Expression::Type::Decimal || Expression::IsMatrix(e); }); diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h index 25e8bcabf..e85e4dc2b 100644 --- a/apps/calculation/calculation.h +++ b/apps/calculation/calculation.h @@ -19,18 +19,20 @@ public: void setContent(const char * c, Poincare::Context * context); const char * inputText(); const char * outputText(); + const char * exactOutputText(); + const char * approximateOutputText(); Poincare::Expression * input(); Poincare::ExpressionLayout * inputLayout(); Poincare::Expression * output(Poincare::Context * context); Poincare::Expression * approximateOutput(Poincare::Context * context); Poincare::ExpressionLayout * outputLayout(Poincare::Context * context); - bool isEmpty(); - void tidy(); -private: - Poincare::Expression * exactOutput(Poincare::Context * context); Poincare::ExpressionLayout * exactOutputLayout(Poincare::Context * context); Poincare::ExpressionLayout * approximateOutputLayout(Poincare::Context * context); + bool isEmpty(); + void tidy(); bool shouldApproximateOutput(); +private: + Poincare::Expression * exactOutput(Poincare::Context * context); char m_inputText[::TextField::maxBufferSize()]; char m_exactOutputText[2*::TextField::maxBufferSize()]; char m_approximateOutputText[2*::TextField::maxBufferSize()]; diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 5bf9a5a95..9b32a937d 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -47,7 +47,12 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { if (subviewType == HistoryViewCell::SubviewType::Input) { editController->insertTextBody(calculation->inputText()); } else { - editController->insertTextBody(calculation->outputText()); + OutputExpressionsView::SubviewType outputSubviewType = selectedCell->outputView()->selectedSubviewType(); + if (outputSubviewType == OutputExpressionsView::SubviewType::ExactOutput) { + editController->insertTextBody(calculation->exactOutputText()); + } else { + editController->insertTextBody(calculation->approximateOutputText()); + } } return true; } @@ -97,7 +102,12 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { if (subviewType == HistoryViewCell::SubviewType::Input) { Clipboard::sharedClipboard()->store(calculation->inputText()); } else { - Clipboard::sharedClipboard()->store(calculation->outputText()); + OutputExpressionsView::SubviewType outputSubviewType = selectedCell->outputView()->selectedSubviewType(); + if (outputSubviewType == OutputExpressionsView::SubviewType::ExactOutput) { + Clipboard::sharedClipboard()->store(calculation->exactOutputText()); + } else { + Clipboard::sharedClipboard()->store(calculation->approximateOutputText()); + } } return true; } diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index 671de7047..9b61c03eb 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -10,11 +10,25 @@ namespace Calculation { HistoryViewCell::HistoryViewCell(Responder * parentResponder) : Responder(parentResponder), m_inputView(this), - m_outputView(this), + m_scrollableOutputView(this), m_selectedSubviewType(HistoryViewCell::SubviewType::Output) { } +OutputExpressionsView * HistoryViewCell::outputView() { + return m_scrollableOutputView.outputView(); + +} +void HistoryViewCell::setEven(bool even) { + EvenOddCell::setEven(even); + m_scrollableOutputView.outputView()->setEven(even); +} + +void HistoryViewCell::setHighlighted(bool highlight) { + EvenOddCell::setHighlighted(highlight); + m_scrollableOutputView.outputView()->setHighlighted(highlight); +} + KDColor HistoryViewCell::backgroundColor() const { KDColor background = m_even ? Palette::WallScreen : KDColorWhite; return background; @@ -26,7 +40,7 @@ int HistoryViewCell::numberOfSubviews() const { } View * HistoryViewCell::subviewAtIndex(int index) { - View * views[2] = {&m_inputView, &m_outputView}; + View * views[2] = {&m_inputView, &m_scrollableOutputView}; return views[index]; } @@ -39,41 +53,44 @@ void HistoryViewCell::layoutSubviews() { } else { m_inputView.setFrame(KDRect(k_digitHorizontalMargin, k_digitVerticalMargin, inputSize.width(), inputSize.height())); } - KDSize outputSize = m_outputView.minimalSizeForOptimalDisplay(); + KDSize outputSize = m_scrollableOutputView.minimalSizeForOptimalDisplay(); if (outputSize.width() + k_digitHorizontalMargin > width) { - m_outputView.setFrame(KDRect(k_digitHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, width - k_digitHorizontalMargin, height - inputSize.height() - 3*k_digitVerticalMargin)); + m_scrollableOutputView.setFrame(KDRect(k_digitHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, width - k_digitHorizontalMargin, height - inputSize.height() - 3*k_digitVerticalMargin)); } else { - m_outputView.setFrame(KDRect(width - outputSize.width() - k_digitHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, outputSize.width(), height - inputSize.height() - 3*k_digitVerticalMargin)); + m_scrollableOutputView.setFrame(KDRect(width - outputSize.width() - k_digitHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, outputSize.width(), height - inputSize.height() - 3*k_digitVerticalMargin)); } } void HistoryViewCell::setCalculation(Calculation * calculation) { m_inputView.setExpression(calculation->inputLayout()); App * calculationApp = (App *)app(); - m_outputView.setExpression(calculation->outputLayout(calculationApp->localContext())); + m_scrollableOutputView.outputView()->setExpressionAtIndex(calculation->approximateOutputLayout(calculationApp->localContext()), 0); + if (calculation->shouldApproximateOutput()) { + m_scrollableOutputView.outputView()->setExpressionAtIndex(nullptr, 1); + } else { + m_scrollableOutputView.outputView()->setExpressionAtIndex(calculation->exactOutputLayout(calculationApp->localContext()), 1); + } } void HistoryViewCell::reloadCell() { - m_outputView.setBackgroundColor(backgroundColor()); + m_scrollableOutputView.outputView()->reloadCell(); m_inputView.setBackgroundColor(backgroundColor()); if (isHighlighted()) { - if (m_selectedSubviewType == SubviewType::Output) { - m_outputView.setBackgroundColor(Palette::Select); - } else { + if (m_selectedSubviewType == SubviewType::Input) { m_inputView.setBackgroundColor(Palette::Select); } } layoutSubviews(); EvenOddCell::reloadCell(); m_inputView.reloadScroll(); - m_outputView.reloadScroll(); + m_scrollableOutputView.reloadScroll(); } void HistoryViewCell::didBecomeFirstResponder() { if (m_selectedSubviewType == SubviewType::Input) { app()->setFirstResponder(&m_inputView); } else { - app()->setFirstResponder(&m_outputView); + app()->setFirstResponder(&m_scrollableOutputView); } } @@ -83,6 +100,7 @@ HistoryViewCell::SubviewType HistoryViewCell::selectedSubviewType() { void HistoryViewCell::setSelectedSubviewType(HistoryViewCell::SubviewType subviewType) { m_selectedSubviewType = subviewType; + m_scrollableOutputView.outputView()->setHighlighted(m_selectedSubviewType == SubviewType::Output); } bool HistoryViewCell::handleEvent(Ion::Events::Event event) { diff --git a/apps/calculation/history_view_cell.h b/apps/calculation/history_view_cell.h index 048613ec9..877e14d1a 100644 --- a/apps/calculation/history_view_cell.h +++ b/apps/calculation/history_view_cell.h @@ -4,6 +4,7 @@ #include #include "calculation.h" #include "scrollable_expression_view.h" +#include "scrollable_output_expressions_view.h" namespace Calculation { @@ -15,6 +16,8 @@ public: }; HistoryViewCell(Responder * parentResponder); void reloadCell() override; + void setEven(bool even) override; + void setHighlighted(bool highlight) override; KDColor backgroundColor() const override; void setCalculation(Calculation * calculation); int numberOfSubviews() const override; @@ -26,10 +29,11 @@ public: constexpr static KDCoordinate k_digitVerticalMargin = 5; SubviewType selectedSubviewType(); void setSelectedSubviewType(HistoryViewCell::SubviewType subviewType); + OutputExpressionsView * outputView(); private: constexpr static KDCoordinate k_resultWidth = 80; ScrollableExpressionView m_inputView; - ScrollableExpressionView m_outputView; + ScrollableOutputExpressionsView m_scrollableOutputView; SubviewType m_selectedSubviewType; }; diff --git a/apps/calculation/output_expressions_view.cpp b/apps/calculation/output_expressions_view.cpp new file mode 100644 index 000000000..7017c939f --- /dev/null +++ b/apps/calculation/output_expressions_view.cpp @@ -0,0 +1,113 @@ +#include "output_expressions_view.h" +#include "../i18n.h" +#include +using namespace Poincare; + +namespace Calculation { + +OutputExpressionsView::OutputExpressionsView(Responder * parentResponder) : + Responder(parentResponder), + m_approximateExpressionView(), + m_approximateSign(KDText::FontSize::Large, I18n::Message::ApproximateEqual, 0.5f, 0.5f), + m_exactExpressionView(), + m_selectedSubviewType(OutputExpressionsView::SubviewType::ExactOutput) +{ +} + +void OutputExpressionsView::setExpressionAtIndex(ExpressionLayout * expressionLayout, int index) { + if (index == 0) { + m_approximateExpressionView.setExpression(expressionLayout); + } else { + assert(index == 1); + m_exactExpressionView.setExpression(expressionLayout); + } + layoutSubviews(); +} + +KDColor OutputExpressionsView::backgroundColor() const { + KDColor background = m_even ? Palette::WallScreen : KDColorWhite; + return background; +} + +void OutputExpressionsView::reloadCell() { + m_exactExpressionView.setBackgroundColor(backgroundColor()); + m_approximateSign.setBackgroundColor(backgroundColor()); + m_approximateExpressionView.setBackgroundColor(backgroundColor()); + if (isHighlighted()) { + if (m_selectedSubviewType == SubviewType::ExactOutput) { + m_exactExpressionView.setBackgroundColor(Palette::Select); + } else { + m_approximateExpressionView.setBackgroundColor(Palette::Select); + } + } + layoutSubviews(); + EvenOddCell::reloadCell(); +} + +KDSize OutputExpressionsView::minimalSizeForOptimalDisplay() const { + KDSize approximateExpressionSize = m_approximateExpressionView.minimalSizeForOptimalDisplay(); + if (numberOfSubviews() == 1) { + return KDSize(approximateExpressionSize.width() + 2*k_digitHorizontalMargin, approximateExpressionSize.height()); + } + KDSize exactExpressionSize = m_exactExpressionView.minimalSizeForOptimalDisplay(); + KDSize approximateSignSize = m_approximateSign.minimalSizeForOptimalDisplay(); + return KDSize(exactExpressionSize.width()+approximateSignSize.width()+approximateExpressionSize.width()+4*k_digitHorizontalMargin, exactExpressionSize.height() > approximateExpressionSize.height() ? exactExpressionSize.height() : approximateExpressionSize.height()); +} + +void OutputExpressionsView::didBecomeFirstResponder() { + if (numberOfSubviews() == 1) { + setSelectedSubviewType(SubviewType::ApproximativeOutput); + } else { + setSelectedSubviewType(SubviewType::ExactOutput); + } +} + +bool OutputExpressionsView::handleEvent(Ion::Events::Event event) { + if (numberOfSubviews() == 1) { + return false; + } + if ((event == Ion::Events::Left && m_selectedSubviewType == SubviewType::ExactOutput) || + (event == Ion::Events::Right && m_selectedSubviewType == SubviewType::ApproximativeOutput)) { + SubviewType otherSubviewType = m_selectedSubviewType == SubviewType::ExactOutput ? SubviewType::ApproximativeOutput : SubviewType::ExactOutput; + setSelectedSubviewType(otherSubviewType); + reloadCell(); + // TODO: something with scrolling parent() == Scrolling ! + return true; + } + return false; +} + +OutputExpressionsView::SubviewType OutputExpressionsView::selectedSubviewType() { + return m_selectedSubviewType; +} + +void OutputExpressionsView::setSelectedSubviewType(OutputExpressionsView::SubviewType subviewType) { + m_selectedSubviewType = subviewType; +} + +int OutputExpressionsView::numberOfSubviews() const { + if (m_exactExpressionView.expressionLayout() != nullptr) { + return 3; + } + return 1; +} + +View * OutputExpressionsView::subviewAtIndex(int index) { + View * views[3] = {&m_approximateExpressionView, &m_approximateSign, &m_exactExpressionView}; + return views[index]; +} + +void OutputExpressionsView::layoutSubviews() { + KDCoordinate height = bounds().height(); + KDSize approximateExpressionSize = m_approximateExpressionView.minimalSizeForOptimalDisplay(); + m_approximateExpressionView.setFrame(KDRect(k_digitHorizontalMargin, 0, approximateExpressionSize.width(), height)); + if (numberOfSubviews() == 1) { + return; + } + KDSize approximateSignSize = m_approximateSign.minimalSizeForOptimalDisplay(); + KDSize exactExpressionSize = m_exactExpressionView.minimalSizeForOptimalDisplay(); + m_approximateSign.setFrame(KDRect(2*k_digitHorizontalMargin+approximateExpressionSize.width(), 0, approximateSignSize.width(), height)); + m_exactExpressionView.setFrame(KDRect(3*k_digitHorizontalMargin+approximateExpressionSize.width()+approximateSignSize.width(), 0, exactExpressionSize.width(), height)); +} + +} diff --git a/apps/calculation/output_expressions_view.h b/apps/calculation/output_expressions_view.h new file mode 100644 index 000000000..6c9c35b65 --- /dev/null +++ b/apps/calculation/output_expressions_view.h @@ -0,0 +1,36 @@ +#ifndef CALCULATION_OUTPUT_EXPRESSIONS_VIEW_H +#define CALCULATION_OUTPUT_EXPRESSIONS_VIEW_H + +#include + +namespace Calculation { + +class OutputExpressionsView : public EvenOddCell, public Responder { +public: + enum class SubviewType { + ExactOutput, + ApproximativeOutput + }; + OutputExpressionsView(Responder * parentResponder); + void setExpressionAtIndex(Poincare::ExpressionLayout * expressionLayout, int index); + KDColor backgroundColor() const override; + void reloadCell() override; + KDSize minimalSizeForOptimalDisplay() const override; + void didBecomeFirstResponder() override; + bool handleEvent(Ion::Events::Event event) override; + SubviewType selectedSubviewType(); + void setSelectedSubviewType(SubviewType subviewType); +private: + int numberOfSubviews() const override; + View * subviewAtIndex(int index) override; + void layoutSubviews() override; + constexpr static KDCoordinate k_digitHorizontalMargin = 10; + ExpressionView m_approximateExpressionView; + MessageTextView m_approximateSign; + ExpressionView m_exactExpressionView; + SubviewType m_selectedSubviewType; +}; + +} + +#endif diff --git a/apps/calculation/scrollable_output_expressions_view.cpp b/apps/calculation/scrollable_output_expressions_view.cpp new file mode 100644 index 000000000..5648740df --- /dev/null +++ b/apps/calculation/scrollable_output_expressions_view.cpp @@ -0,0 +1,24 @@ +#include "scrollable_output_expressions_view.h" +#include +using namespace Poincare; + +namespace Calculation { + +ScrollableOutputExpressionsView::ScrollableOutputExpressionsView(Responder * parentResponder) : + ScrollableView(parentResponder, &m_outputView, this), + m_outputView(this) +{ +} + +OutputExpressionsView * ScrollableOutputExpressionsView::outputView() { + return &m_outputView; +} + +void ScrollableOutputExpressionsView::didBecomeFirstResponder() { + app()->setFirstResponder(&m_outputView); +} + +KDSize ScrollableOutputExpressionsView::minimalSizeForOptimalDisplay() const { + return m_outputView.minimalSizeForOptimalDisplay(); +} +} diff --git a/apps/calculation/scrollable_output_expressions_view.h b/apps/calculation/scrollable_output_expressions_view.h new file mode 100644 index 000000000..ba561c14c --- /dev/null +++ b/apps/calculation/scrollable_output_expressions_view.h @@ -0,0 +1,21 @@ +#ifndef CALCULATION_SCROLLABLE_OUTPUT_EXPRESSIONS_VIEW_H +#define CALCULATION_SCROLLABLE_OUTPUT_EXPRESSIONS_VIEW_H + +#include +#include "output_expressions_view.h" + +namespace Calculation { + +class ScrollableOutputExpressionsView : public ScrollableView, public ScrollViewDataSource { +public: + ScrollableOutputExpressionsView(Responder * parentResponder); + OutputExpressionsView * outputView(); + void didBecomeFirstResponder() override; + KDSize minimalSizeForOptimalDisplay() const override; +private: + OutputExpressionsView m_outputView; +}; + +} + +#endif diff --git a/apps/i18n.cpp b/apps/i18n.cpp index df6e012d8..83f033229 100644 --- a/apps/i18n.cpp +++ b/apps/i18n.cpp @@ -24,6 +24,8 @@ constexpr static char deviationEnglishDefinition[] = {Ion::Charset::SmallSigma, constexpr static char deviationSpanishDefinition[] = {Ion::Charset::SmallSigma, ' ', ':', ' ', 'D', 'e','s','v','i','a','c','i','o','n',' ','t','i','p','i','c','a',0}; constexpr static char deviationGermanDefinition[] = {Ion::Charset::SmallSigma, ' ', ':', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', 'a', 'b', 'w', 'e', 'i', 'c', 'h', 'u', 'n', 'g', 0}; constexpr static char deviationPortugueseDefinition[] = {Ion::Charset::SmallSigma, ' ', ':', ' ', 'D', 'e','s','v','i','o',' ','p','a','d','r','a','o', 0}; +constexpr static char approximateEqual[] = {Ion::Charset::ApproximateEqual, 0}; + const char * messages[240][5] { {"Warning", "Attention", "Cuidado", "Achtung", "Atencao"}, @@ -317,8 +319,9 @@ constexpr static char leftIntegralFirstLegend[] = {'P', '(', 'X', Ion::Charset:: constexpr static char finiteIntegralLegend[] = {Ion::Charset::LessEqual, 'X', Ion::Charset::LessEqual, 0}; -const char * universalMessages[242] { +const char * universalMessages[243] { "", + approximateEqual, "Python", "PYTHON (BETA)", "alpha", diff --git a/apps/i18n.h b/apps/i18n.h index 13d28447a..4f9701c07 100644 --- a/apps/i18n.h +++ b/apps/i18n.h @@ -273,6 +273,7 @@ namespace I18n { /* UNIVERSAL MESSAGES */ Default = 0x8000, + ApproximateEqual, CodeApp, CodeAppCapital, Alpha, diff --git a/escher/include/escher/expression_view.h b/escher/include/escher/expression_view.h index 660b4a441..f5632a453 100644 --- a/escher/include/escher/expression_view.h +++ b/escher/include/escher/expression_view.h @@ -15,6 +15,7 @@ class ExpressionView : public View { public: ExpressionView(float horizontalAlignment = 0.0f, float verticalAlignment = 0.5f, KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite); + Poincare::ExpressionLayout * expressionLayout() const; void setExpression(Poincare::ExpressionLayout * expressionLayout); void drawRect(KDContext * ctx, KDRect rect) const override; void setBackgroundColor(KDColor backgroundColor); diff --git a/escher/src/expression_view.cpp b/escher/src/expression_view.cpp index 26e282e5e..17a44d3f7 100644 --- a/escher/src/expression_view.cpp +++ b/escher/src/expression_view.cpp @@ -11,6 +11,10 @@ ExpressionView::ExpressionView(float horizontalAlignment, float verticalAlignmen { } +ExpressionLayout * ExpressionView::expressionLayout() const { + return m_expressionLayout; +} + void ExpressionView::setExpression(ExpressionLayout * expressionLayout) { m_expressionLayout = expressionLayout; markRectAsDirty(bounds()); diff --git a/ion/include/ion/charset.h b/ion/include/ion/charset.h index 980c14431..cfdd2548f 100644 --- a/ion/include/ion/charset.h +++ b/ion/include/ion/charset.h @@ -24,6 +24,7 @@ enum Charset : char { GreaterEqual = (char)146, MultiplicationSign = (char)147, MiddleDot = (char)148, + ApproximateEqual = (char)149 }; } diff --git a/kandinsky/fonts/unicode_for_symbol.c b/kandinsky/fonts/unicode_for_symbol.c index 1b27552af..150ba9f04 100644 --- a/kandinsky/fonts/unicode_for_symbol.c +++ b/kandinsky/fonts/unicode_for_symbol.c @@ -2,4 +2,4 @@ wchar_t codePointForSymbol[NUMBER_OF_SYMBOLS] = {0x222b, 0x0078, 0x0305, 0x0079, 0x0305, 0x0393, 0x03a3, 0x03b8, 0x03bb, 0x03bc, 0x03c0, 0x03c3, 0x0456, - 0x1D07, 0x2032, 0x212e, 0x2192, 0x221A, 0x2264, 0x2265, 0x00D7, 0x00B7}; + 0x1D07, 0x2032, 0x212e, 0x2192, 0x221A, 0x2264, 0x2265, 0x00D7, 0x00B7, 0x2248}; diff --git a/kandinsky/fonts/unicode_for_symbol.h b/kandinsky/fonts/unicode_for_symbol.h index 0944e32df..4a76c5da2 100644 --- a/kandinsky/fonts/unicode_for_symbol.h +++ b/kandinsky/fonts/unicode_for_symbol.h @@ -3,7 +3,7 @@ #include -#define NUMBER_OF_SYMBOLS 22 +#define NUMBER_OF_SYMBOLS 23 extern wchar_t codePointForSymbol[NUMBER_OF_SYMBOLS];