From be9cde8ca47259aa67ece9d469595dfd4f61a11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 5 Dec 2017 15:32:25 +0100 Subject: [PATCH 001/257] [expression_editor] Base app for development, to remove later. Change-Id: I1d5b59f67fd146d2e2917546a7d8b9419a0a7036 --- apps/Makefile | 2 +- apps/expression_editor/Makefile | 18 +++++++ apps/expression_editor/app.cpp | 29 +++++++++++ apps/expression_editor/app.h | 35 +++++++++++++ apps/expression_editor/base.universal.i18n | 2 + apps/expression_editor/controller.cpp | 34 +++++++++++++ apps/expression_editor/controller.h | 39 ++++++++++++++ .../expression_and_layout.cpp | 51 +++++++++++++++++++ .../expression_editor/expression_and_layout.h | 26 ++++++++++ apps/expression_editor/test/dummy_test.cpp | 6 +++ 10 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 apps/expression_editor/Makefile create mode 100644 apps/expression_editor/app.cpp create mode 100644 apps/expression_editor/app.h create mode 100644 apps/expression_editor/base.universal.i18n create mode 100644 apps/expression_editor/controller.cpp create mode 100644 apps/expression_editor/controller.h create mode 100644 apps/expression_editor/expression_and_layout.cpp create mode 100644 apps/expression_editor/expression_and_layout.h create mode 100644 apps/expression_editor/test/dummy_test.cpp diff --git a/apps/Makefile b/apps/Makefile index 7e5d367ab..9c3ecf405 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,5 +1,5 @@ EPSILON_I18N_LANGUAGES ?= en fr es de pt -EPSILON_APPS ?= calculation graph sequence settings statistics probability regression code +EPSILON_APPS ?= expression_editor include apps/shared/Makefile include apps/home/Makefile diff --git a/apps/expression_editor/Makefile b/apps/expression_editor/Makefile new file mode 100644 index 000000000..4fa2fd2f5 --- /dev/null +++ b/apps/expression_editor/Makefile @@ -0,0 +1,18 @@ +snapshots += ExpressionEditor::App::Snapshot +snapshot_headers += apps/expression_editor/app.h + +app_objs += $(addprefix apps/expression_editor/,\ + app.o\ + controller.o\ + expression_and_layout.o\ +) + +i18n_files += $(addprefix apps/expression_editor/,\ + base.universal.i18n\ +) + +tests += $(addprefix apps/expression_editor/test/,\ + dummy_test.cpp\ +) + +test_objs += $(addprefix apps/expression_editor/, controller.o) diff --git a/apps/expression_editor/app.cpp b/apps/expression_editor/app.cpp new file mode 100644 index 000000000..9c7111f02 --- /dev/null +++ b/apps/expression_editor/app.cpp @@ -0,0 +1,29 @@ +#include "app.h" +#include "../i18n.h" + +namespace ExpressionEditor { + +I18n::Message App::Descriptor::name() { + return I18n::Message::ExpressionEditorApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::ExpressionEditorAppCapital; +} + +App * App::Snapshot::unpack(Container * container) { + return new App(container, this); +} + +App::Descriptor * App::Snapshot::descriptor() { + static Descriptor descriptor; + return &descriptor; +} + +App::App(Container * container, Snapshot * snapshot) : + ::App(container, snapshot, &m_controller), + m_controller(&m_modalViewController, snapshot->expressionAndLayout()) +{ +} + +} diff --git a/apps/expression_editor/app.h b/apps/expression_editor/app.h new file mode 100644 index 000000000..f90805121 --- /dev/null +++ b/apps/expression_editor/app.h @@ -0,0 +1,35 @@ +#ifndef EXPRESSION_EDITOR_APP_H +#define EXPRESSION_EDITOR_APP_H + +#include +#include "controller.h" +#include "expression_and_layout.h" + +namespace ExpressionEditor { + +/* TODO This app is used for creating ExpressionLayout edition. It should be + * removed when the development is finished. */ + +class App : public ::App { +public: + class Descriptor : public ::App::Descriptor { + public: + I18n::Message name() override; + I18n::Message upperName() override; + }; + class Snapshot : public ::App::Snapshot, public SelectableTableViewDataSource { + public: + App * unpack(Container * container) override; + Descriptor * descriptor() override; + ExpressionAndLayout * expressionAndLayout() { return &m_expressionAndLayout; } + private: + ExpressionAndLayout m_expressionAndLayout; + }; +private: + App(Container * container, Snapshot * snapshot); + Controller m_controller; +}; + +} + +#endif diff --git a/apps/expression_editor/base.universal.i18n b/apps/expression_editor/base.universal.i18n new file mode 100644 index 000000000..01a156f37 --- /dev/null +++ b/apps/expression_editor/base.universal.i18n @@ -0,0 +1,2 @@ +ExpressionEditorApp = "ExpressionEdit" +ExpressionEditorAppCapital = "EXPRESSION EDITOR" diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp new file mode 100644 index 000000000..8c51c5d4d --- /dev/null +++ b/apps/expression_editor/controller.cpp @@ -0,0 +1,34 @@ +#include "controller.h" + +namespace ExpressionEditor { + +Controller::ContentView::ContentView(ExpressionAndLayout * expressionAndLayout) : + SolidColorView(KDColorWhite), + m_expressionView() +{ + m_expressionView.setExpression(expressionAndLayout->expressionLayout()); +} + +void Controller::ContentView::layoutSubviews() { + m_expressionView.setFrame(KDRect( + k_margin, + k_margin, + bounds().width() - 2 * k_margin, + bounds().height() - 2 * k_margin)); +} + +KDSize Controller::ContentView::minimalSizeForOptimalDisplay() const { + return m_expressionView.minimalSizeForOptimalDisplay(); +} + +Controller::Controller(Responder * parentResponder, ExpressionAndLayout * expressionAndLayout) : + ViewController(parentResponder), + m_view(expressionAndLayout) +{ +} + +bool Controller::handleEvent(Ion::Events::Event event) { + return false; +} + +} diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h new file mode 100644 index 000000000..c74e0d076 --- /dev/null +++ b/apps/expression_editor/controller.h @@ -0,0 +1,39 @@ +#ifndef EXPRESSION_EDITOR_CONTROLLER_H +#define EXPRESSION_EDITOR_CONTROLLER_H + +#include +#include +#include "expression_and_layout.h" +extern "C" { +#include +} + +namespace ExpressionEditor { + +class Controller : public ViewController { +public: + Controller(Responder * parentResponder, ExpressionAndLayout * expressionAndLayout); + View * view() override { return &m_view; } + bool handleEvent(Ion::Events::Event event) override; + +private: + class ContentView : public SolidColorView { + public: + ContentView(ExpressionAndLayout * expressionAndLayout); + int numberOfSubviews() const override { return 1; } + View * subviewAtIndex(int index) override { + assert(index == 0); + return &m_expressionView; + } + void layoutSubviews() override; + KDSize minimalSizeForOptimalDisplay() const override; + private: + constexpr static KDCoordinate k_margin = 10; + ExpressionView m_expressionView; + }; + ContentView m_view; +}; + +} + +#endif diff --git a/apps/expression_editor/expression_and_layout.cpp b/apps/expression_editor/expression_and_layout.cpp new file mode 100644 index 000000000..89a0f310e --- /dev/null +++ b/apps/expression_editor/expression_and_layout.cpp @@ -0,0 +1,51 @@ +#include "expression_and_layout.h" + +namespace ExpressionEditor { + +ExpressionAndLayout::ExpressionAndLayout() { + //const char * expression = "2/3"; + //const char * expression = "1+2/(3+4)"; + //const char * expression = "1+2/3+5+8"; + //const char * expression = "[[1+5,2,3][4,5,6]]"; + //const char * expression = "1+2/(7+5/3/467777777)/3+8"; + //const char * expression = "1+2/7467777777"; + //const char * expression = "2385658/(7+5/46)"; + //const char * expression = "1+conj(100)+2"; + //const char * expression = "1+abs(100)+2"; + //const char * expression = "1+root(100,41)+2"; + //const char * expression = "ln(36)"; + //const char * expression = "1+floor(36)+2"; + //const char * expression = "ln(36)+root(542,52)+sum(12,3,4)+int(22,3,4)+conj(988)"; + //const char * expression = "2385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+(1111111)/(2/3+4/5)"; + //const char * expression = "2385658/(int(5/46*7/8,3,45))"; + //const char * expression = "1+binomial(6,88)+1"; + //const char * expression = "[[1+5,2,3][4,5,int(5/46+1,3,4)]]"; + //const char * expression = "2385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]"; + //const char * expression = "1/2+[[1,2,3][4,5,6]]+1"; + //const char * expression = "1+(3+4)+1"; + //const char * expression = "1+product(23,46,123)+[[2,3][5,6]]+1/4"; + //const char * expression = "2385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]"; + //const char * expression = "7/78+int(5/46*7/8,3,45)+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]"; + //const char * expression = "1+conj(39)+abs(3)+root(6000,23)"; + //const char * expression = "1.5+3.4"; + //const char * expression = "abs(5)+int(5/46*7/8,3,4544444)+conj(4)+int(333,4,5)"; + //const char * expression = "conj(int(5/46*7/8,3,45))+conj(4)"; + //const char * expression = "abs(1+conj(conj(4))+(23)+conj(42))+abs(1+2)"; + const char * expression = "13+(23)"; + //const char * expression = "1+sum(12,3,4)+product(12,3,4)+2"; + + m_expression = Poincare::Expression::parse(expression); + m_expressionLayout = m_expression->createLayout(); +} +ExpressionAndLayout::~ExpressionAndLayout() { + if (m_expressionLayout) { + delete m_expressionLayout; + m_expressionLayout = nullptr; + } + if (m_expression) { + delete m_expression; + m_expression = nullptr; + } +} + +} diff --git a/apps/expression_editor/expression_and_layout.h b/apps/expression_editor/expression_and_layout.h new file mode 100644 index 000000000..a1ef237fc --- /dev/null +++ b/apps/expression_editor/expression_and_layout.h @@ -0,0 +1,26 @@ +#ifndef EXPRESSION_EDITOR_EXPRESSION_AND_LAYOUT_H +#define EXPRESSION_EDITOR_EXPRESSION_AND_LAYOUT_H + +#include + +namespace ExpressionEditor { + +class ExpressionAndLayout { +public: + ExpressionAndLayout(); + ~ExpressionAndLayout(); + ExpressionAndLayout(const ExpressionAndLayout& other) = delete; + ExpressionAndLayout(ExpressionAndLayout&& other) = delete; + ExpressionAndLayout operator=(const ExpressionAndLayout& other) = delete; + ExpressionAndLayout& operator=(ExpressionAndLayout&& other) = delete; + + Poincare::Expression * expression() { return m_expression; } + Poincare::ExpressionLayout * expressionLayout() { return m_expressionLayout; } +private: + Poincare::Expression * m_expression; + Poincare::ExpressionLayout * m_expressionLayout; +}; + +} + +#endif diff --git a/apps/expression_editor/test/dummy_test.cpp b/apps/expression_editor/test/dummy_test.cpp new file mode 100644 index 000000000..18e40f6c0 --- /dev/null +++ b/apps/expression_editor/test/dummy_test.cpp @@ -0,0 +1,6 @@ +#include +#include + +QUIZ_CASE() { + assert(true); +} From 4ad3adaab2ac8d75a27e2bb720a46affef2db667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 5 Dec 2017 17:45:54 +0100 Subject: [PATCH 002/257] [apps/escher] Changed setExpression to setExpressionLayout. Change-Id: I095a12868fd7eaf8d4eb2408617941a86f43e1ee --- apps/calculation/history_view_cell.cpp | 2 +- apps/calculation/output_expressions_view.cpp | 4 ++-- apps/calculation/scrollable_expression_view.cpp | 4 ++-- apps/calculation/scrollable_expression_view.h | 2 +- apps/expression_editor/controller.cpp | 2 +- apps/graph/list/list_controller.cpp | 2 +- apps/regression/calculation_controller.cpp | 2 +- apps/regression/store_controller.cpp | 2 +- apps/sequence/graph/term_sum_controller.cpp | 6 +++--- apps/sequence/list/list_controller.cpp | 12 ++++++------ apps/sequence/list/list_parameter_controller.cpp | 2 +- apps/sequence/list/sequence_toolbox.cpp | 2 +- apps/sequence/list/type_parameter_controller.cpp | 2 +- apps/sequence/sequence_title_cell.cpp | 4 ++-- apps/sequence/sequence_title_cell.h | 2 +- apps/sequence/values/values_controller.cpp | 2 +- apps/settings/main_controller.cpp | 2 +- apps/settings/sub_controller.cpp | 2 +- apps/shared/function_expression_cell.cpp | 4 ++-- apps/shared/function_expression_cell.h | 2 +- apps/variable_box_leaf_cell.cpp | 2 +- escher/include/escher/even_odd_expression_cell.h | 2 +- escher/include/escher/expression_table_cell.h | 2 +- escher/include/escher/expression_view.h | 2 +- .../message_table_cell_with_chevron_and_expression.h | 2 +- escher/src/even_odd_expression_cell.cpp | 4 ++-- escher/src/expression_table_cell.cpp | 4 ++-- escher/src/expression_view.cpp | 2 +- ...essage_table_cell_with_chevron_and_expression.cpp | 4 ++-- 29 files changed, 43 insertions(+), 43 deletions(-) diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp index 02c1ec198..5518bcdca 100644 --- a/apps/calculation/history_view_cell.cpp +++ b/apps/calculation/history_view_cell.cpp @@ -83,7 +83,7 @@ void HistoryViewCell::layoutSubviews() { } void HistoryViewCell::setCalculation(Calculation * calculation) { - m_inputView.setExpression(calculation->inputLayout()); + m_inputView.setExpressionLayout(calculation->inputLayout()); App * calculationApp = (App *)app(); /* Both output expressions have to be updated at the same time. The * outputView points to deleted layouts and a call to diff --git a/apps/calculation/output_expressions_view.cpp b/apps/calculation/output_expressions_view.cpp index 43caefc23..7deeddb64 100644 --- a/apps/calculation/output_expressions_view.cpp +++ b/apps/calculation/output_expressions_view.cpp @@ -16,8 +16,8 @@ OutputExpressionsView::OutputExpressionsView(Responder * parentResponder) : } void OutputExpressionsView::setExpressions(ExpressionLayout ** expressionsLayout) { - m_approximateExpressionView.setExpression(expressionsLayout[0]); - m_exactExpressionView.setExpression(expressionsLayout[1]); + m_approximateExpressionView.setExpressionLayout(expressionsLayout[0]); + m_exactExpressionView.setExpressionLayout(expressionsLayout[1]); layoutSubviews(); } diff --git a/apps/calculation/scrollable_expression_view.cpp b/apps/calculation/scrollable_expression_view.cpp index def347a0f..4fd7572df 100644 --- a/apps/calculation/scrollable_expression_view.cpp +++ b/apps/calculation/scrollable_expression_view.cpp @@ -10,8 +10,8 @@ ScrollableExpressionView::ScrollableExpressionView(Responder * parentResponder) { } -void ScrollableExpressionView::setExpression(ExpressionLayout * expressionLayout) { - m_expressionView.setExpression(expressionLayout); +void ScrollableExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) { + m_expressionView.setExpressionLayout(expressionLayout); layoutSubviews(); } diff --git a/apps/calculation/scrollable_expression_view.h b/apps/calculation/scrollable_expression_view.h index a613600f1..fb156fbc9 100644 --- a/apps/calculation/scrollable_expression_view.h +++ b/apps/calculation/scrollable_expression_view.h @@ -8,7 +8,7 @@ namespace Calculation { class ScrollableExpressionView : public ScrollableView, public ScrollViewDataSource { public: ScrollableExpressionView(Responder * parentResponder); - void setExpression(Poincare::ExpressionLayout * expressionLayout); + void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout); void setBackgroundColor(KDColor backgroundColor); KDSize minimalSizeForOptimalDisplay() const override; private: diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 8c51c5d4d..a62313cdc 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -6,7 +6,7 @@ Controller::ContentView::ContentView(ExpressionAndLayout * expressionAndLayout) SolidColorView(KDColorWhite), m_expressionView() { - m_expressionView.setExpression(expressionAndLayout->expressionLayout()); + m_expressionView.setExpressionLayout(expressionAndLayout->expressionLayout()); } void Controller::ContentView::layoutSubviews() { diff --git a/apps/graph/list/list_controller.cpp b/apps/graph/list/list_controller.cpp index 1eb2f4a0d..9c84175d6 100644 --- a/apps/graph/list/list_controller.cpp +++ b/apps/graph/list/list_controller.cpp @@ -90,7 +90,7 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) { void ListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) { FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell; Function * f = m_functionStore->functionAtIndex(j); - myCell->setExpression(f->layout()); + myCell->setExpressionLayout(f->layout()); bool active = f->isActive(); KDColor textColor = active ? KDColorBlack : Palette::GreyDark; myCell->setTextColor(textColor); diff --git a/apps/regression/calculation_controller.cpp b/apps/regression/calculation_controller.cpp index 4b231acc6..1a937c6ea 100644 --- a/apps/regression/calculation_controller.cpp +++ b/apps/regression/calculation_controller.cpp @@ -129,7 +129,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int if (i == 0) { if (j == numberOfRows()-1) { EvenOddExpressionCell * myCell = (EvenOddExpressionCell *)cell; - myCell->setExpression(m_r2Layout); + myCell->setExpressionLayout(m_r2Layout); return; } EvenOddMessageTextCell * myCell = (EvenOddMessageTextCell *)cell; diff --git a/apps/regression/store_controller.cpp b/apps/regression/store_controller.cpp index 62e2e4400..59617a330 100644 --- a/apps/regression/store_controller.cpp +++ b/apps/regression/store_controller.cpp @@ -34,7 +34,7 @@ void StoreController::willDisplayCellAtLocation(HighlightCell * cell, int i, int return; } EvenOddExpressionCell * mytitleCell = (EvenOddExpressionCell *)cell; - mytitleCell->setExpression(m_titleLayout[i]); + mytitleCell->setExpressionLayout(m_titleLayout[i]); } HighlightCell * StoreController::titleCells(int index) { diff --git a/apps/sequence/graph/term_sum_controller.cpp b/apps/sequence/graph/term_sum_controller.cpp index a22e729e0..cc136bd87 100644 --- a/apps/sequence/graph/term_sum_controller.cpp +++ b/apps/sequence/graph/term_sum_controller.cpp @@ -201,7 +201,7 @@ void TermSumController::LegendView::setSumSubscript(float start) { char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; Complex::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr); - m_sum.setExpression(m_sumLayout); + m_sum.setExpressionLayout(m_sumLayout); m_sum.setAlignment(0.0f, 0.5f); } @@ -216,7 +216,7 @@ void TermSumController::LegendView::setSumSuperscript(float start, float end) { char bufferEnd[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; Complex::convertFloatToText(end, bufferEnd, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), new StringLayout(bufferStart, strlen(bufferStart), KDText::FontSize::Small), new StringLayout(bufferEnd, strlen(bufferEnd), KDText::FontSize::Small)); - m_sum.setExpression(m_sumLayout); + m_sum.setExpressionLayout(m_sumLayout); m_sum.setAlignment(0.0f, 0.5f); } @@ -229,7 +229,7 @@ void TermSumController::LegendView::setSumResult(const char * sequenceName, doub childrenLayouts[1] = new BaselineRelativeLayout(new StringLayout(sequenceName, 1, KDText::FontSize::Small), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); childrenLayouts[0] = m_sumLayout; m_sumLayout = new HorizontalLayout(childrenLayouts, 3); - m_sum.setExpression(m_sumLayout); + m_sum.setExpressionLayout(m_sumLayout); m_sum.setAlignment(0.5f, 0.5f); } diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index 29eefaf32..c3a8e6031 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -169,13 +169,13 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) { SequenceTitleCell * myCell = (SequenceTitleCell *)cell; Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(j)); if (sequenceDefinitionForRow(j) == 0) { - myCell->setExpression(sequence->definitionName()); + myCell->setExpressionLayout(sequence->definitionName()); } if (sequenceDefinitionForRow(j) == 1) { - myCell->setExpression(sequence->firstInitialConditionName()); + myCell->setExpressionLayout(sequence->firstInitialConditionName()); } if (sequenceDefinitionForRow(j) == 2) { - myCell->setExpression(sequence->secondInitialConditionName()); + myCell->setExpressionLayout(sequence->secondInitialConditionName()); } KDColor nameColor = sequence->isActive() ? sequence->color() : Palette::GreyDark; myCell->setColor(nameColor); @@ -185,13 +185,13 @@ void ListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell; Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(j)); if (sequenceDefinitionForRow(j) == 0) { - myCell->setExpression(sequence->layout()); + myCell->setExpressionLayout(sequence->layout()); } if (sequenceDefinitionForRow(j) == 1) { - myCell->setExpression(sequence->firstInitialConditionLayout()); + myCell->setExpressionLayout(sequence->firstInitialConditionLayout()); } if (sequenceDefinitionForRow(j) == 2) { - myCell->setExpression(sequence->secondInitialConditionLayout()); + myCell->setExpressionLayout(sequence->secondInitialConditionLayout()); } bool active = sequence->isActive(); KDColor textColor = active ? KDColorBlack : Palette::GreyDark; diff --git a/apps/sequence/list/list_parameter_controller.cpp b/apps/sequence/list/list_parameter_controller.cpp index 075d96581..d466fa330 100644 --- a/apps/sequence/list/list_parameter_controller.cpp +++ b/apps/sequence/list/list_parameter_controller.cpp @@ -103,7 +103,7 @@ void ListParameterController::willDisplayCellForIndex(HighlightCell * cell, int cell->setHighlighted(index == selectedRow()); // See FIXME in SelectableTableView::reloadData() Shared::ListParameterController::willDisplayCellForIndex(cell, index); if (cell == &m_typeCell && m_sequence != nullptr) { - m_typeCell.setExpression(m_sequence->definitionName()); + m_typeCell.setExpressionLayout(m_sequence->definitionName()); } if (cell == &m_initialRankCell && m_sequence != nullptr) { MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *) cell; diff --git a/apps/sequence/list/sequence_toolbox.cpp b/apps/sequence/list/sequence_toolbox.cpp index 708e670d6..ed5a3f49b 100644 --- a/apps/sequence/list/sequence_toolbox.cpp +++ b/apps/sequence/list/sequence_toolbox.cpp @@ -54,7 +54,7 @@ HighlightCell * SequenceToolbox::reusableCell(int index, int type) { void SequenceToolbox::willDisplayCellForIndex(HighlightCell * cell, int index) { if (typeAtLocation(0, index) == 2) { ExpressionTableCell * myCell = (ExpressionTableCell *)cell; - myCell->setExpression(m_addedCellLayout[index]); + myCell->setExpressionLayout(m_addedCellLayout[index]); return; } else { MathToolbox::willDisplayCellForIndex(cell, mathToolboxIndex(index)); diff --git a/apps/sequence/list/type_parameter_controller.cpp b/apps/sequence/list/type_parameter_controller.cpp index 29e3ec3d6..037aaa98f 100644 --- a/apps/sequence/list/type_parameter_controller.cpp +++ b/apps/sequence/list/type_parameter_controller.cpp @@ -122,7 +122,7 @@ void TypeParameterController::willDisplayCellAtLocation(HighlightCell * cell, in } m_expressionLayouts[j] = new BaselineRelativeLayout(new StringLayout(nextName, 1, size), new StringLayout(subscripts[j], strlen(subscripts[j]), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); ExpressionTableCellWithPointer * myCell = (ExpressionTableCellWithPointer *)cell; - myCell->setExpression(m_expressionLayouts[j]); + myCell->setExpressionLayout(m_expressionLayouts[j]); } void TypeParameterController::setSequence(Sequence * sequence) { diff --git a/apps/sequence/sequence_title_cell.cpp b/apps/sequence/sequence_title_cell.cpp index 3f86911d0..7138d103f 100644 --- a/apps/sequence/sequence_title_cell.cpp +++ b/apps/sequence/sequence_title_cell.cpp @@ -12,8 +12,8 @@ SequenceTitleCell::SequenceTitleCell(Orientation orientation) : { } -void SequenceTitleCell::setExpression(Poincare::ExpressionLayout * expressionLayout) { - m_titleTextView.setExpression(expressionLayout); +void SequenceTitleCell::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) { + m_titleTextView.setExpressionLayout(expressionLayout); } void SequenceTitleCell::setHighlighted(bool highlight) { diff --git a/apps/sequence/sequence_title_cell.h b/apps/sequence/sequence_title_cell.h index 253c43902..1fe659c07 100644 --- a/apps/sequence/sequence_title_cell.h +++ b/apps/sequence/sequence_title_cell.h @@ -8,7 +8,7 @@ namespace Sequence { class SequenceTitleCell : public Shared::FunctionTitleCell { public: SequenceTitleCell(Orientation orientation); - void setExpression(Poincare::ExpressionLayout * expressionLayout); + void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout); void setEven(bool even) override; void setHighlighted(bool highlight) override; void setColor(KDColor color) override; diff --git a/apps/sequence/values/values_controller.cpp b/apps/sequence/values/values_controller.cpp index 184685a91..0a1bc8f94 100644 --- a/apps/sequence/values/values_controller.cpp +++ b/apps/sequence/values/values_controller.cpp @@ -30,7 +30,7 @@ void ValuesController::willDisplayCellAtLocation(HighlightCell * cell, int i, in if (j == 0 && i > 0) { SequenceTitleCell * myCell = (SequenceTitleCell *)cell; Sequence * sequence = m_sequenceStore->activeFunctionAtIndex(i-1); - myCell->setExpression(sequence->nameLayout()); + myCell->setExpressionLayout(sequence->nameLayout()); myCell->setColor(sequence->color()); } } diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 4b7dc6768..32a0f7c80 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -183,7 +183,7 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { m_complexFormatLayout = new BaselineRelativeLayout(new StringLayout(base, sizeof(base), KDText::FontSize::Small), new StringLayout(superscript, sizeof(superscript), KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript); } MessageTableCellWithChevronAndExpression * myExpCell = (MessageTableCellWithChevronAndExpression *)cell; - myExpCell->setExpression(m_complexFormatLayout); + myExpCell->setExpressionLayout(m_complexFormatLayout); return; } if (index == 3) { diff --git a/apps/settings/sub_controller.cpp b/apps/settings/sub_controller.cpp index 9ea464dfb..6d5b8ec4e 100644 --- a/apps/settings/sub_controller.cpp +++ b/apps/settings/sub_controller.cpp @@ -28,7 +28,7 @@ SubController::SubController(Responder * parentResponder) : const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '}; m_complexFormatLayout[1] = new BaselineRelativeLayout(new StringLayout(base, sizeof(base)), new StringLayout(superscript, sizeof(superscript)), BaselineRelativeLayout::Type::Superscript); for (int i = 0; i < 2; i++) { - m_complexFormatCells[i].setExpression(m_complexFormatLayout[i]); + m_complexFormatCells[i].setExpressionLayout(m_complexFormatLayout[i]); } m_editableCell.setMessage(I18n::Message::SignificantFigures); m_editableCell.setMessageFontSize(KDText::FontSize::Large); diff --git a/apps/shared/function_expression_cell.cpp b/apps/shared/function_expression_cell.cpp index fee970761..c9345ee71 100644 --- a/apps/shared/function_expression_cell.cpp +++ b/apps/shared/function_expression_cell.cpp @@ -11,8 +11,8 @@ FunctionExpressionCell::FunctionExpressionCell() : { } -void FunctionExpressionCell::setExpression(ExpressionLayout * expressionLayout) { - m_expressionView.setExpression(expressionLayout); +void FunctionExpressionCell::setExpressionLayout(ExpressionLayout * expressionLayout) { + m_expressionView.setExpressionLayout(expressionLayout); } void FunctionExpressionCell::setTextColor(KDColor textColor) { diff --git a/apps/shared/function_expression_cell.h b/apps/shared/function_expression_cell.h index 0b2288f56..351bbe360 100644 --- a/apps/shared/function_expression_cell.h +++ b/apps/shared/function_expression_cell.h @@ -9,7 +9,7 @@ namespace Shared { class FunctionExpressionCell : public EvenOddCell { public: FunctionExpressionCell(); - void setExpression(Poincare::ExpressionLayout * expressionLayout); + void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout); void setTextColor(KDColor color); void setEven(bool even) override; void setHighlighted(bool highlight) override; diff --git a/apps/variable_box_leaf_cell.cpp b/apps/variable_box_leaf_cell.cpp index 6806d64fc..cc7a60983 100644 --- a/apps/variable_box_leaf_cell.cpp +++ b/apps/variable_box_leaf_cell.cpp @@ -91,7 +91,7 @@ void VariableBoxLeafCell::setExpression(const Expression * expression) { if (expression) { m_expressionLayout = expression->createLayout(); } - m_expressionView.setExpression(m_expressionLayout); + m_expressionView.setExpressionLayout(m_expressionLayout); } void VariableBoxLeafCell::drawRect(KDContext * ctx, KDRect rect) const { diff --git a/escher/include/escher/even_odd_expression_cell.h b/escher/include/escher/even_odd_expression_cell.h index 05daf3818..157981777 100644 --- a/escher/include/escher/even_odd_expression_cell.h +++ b/escher/include/escher/even_odd_expression_cell.h @@ -10,7 +10,7 @@ public: KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite); void setEven(bool even) override; void setHighlighted(bool highlight) override; - void setExpression(Poincare::ExpressionLayout * expressionLayout); + void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout); void setBackgroundColor(KDColor backgroundColor); void setTextColor(KDColor textColor); KDSize minimalSizeForOptimalDisplay() const override; diff --git a/escher/include/escher/expression_table_cell.h b/escher/include/escher/expression_table_cell.h index 0bd233a33..4318dc603 100644 --- a/escher/include/escher/expression_table_cell.h +++ b/escher/include/escher/expression_table_cell.h @@ -9,7 +9,7 @@ public: ExpressionTableCell(Layout layout = Layout::Horizontal); View * labelView() const override; void setHighlighted(bool highlight) override; - void setExpression(Poincare::ExpressionLayout * expressionLayout); + void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout); private: ExpressionView m_labelExpressionView; }; diff --git a/escher/include/escher/expression_view.h b/escher/include/escher/expression_view.h index f5632a453..0b3888d9e 100644 --- a/escher/include/escher/expression_view.h +++ b/escher/include/escher/expression_view.h @@ -16,7 +16,7 @@ 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 setExpressionLayout(Poincare::ExpressionLayout * expressionLayout); void drawRect(KDContext * ctx, KDRect rect) const override; void setBackgroundColor(KDColor backgroundColor); void setTextColor(KDColor textColor); diff --git a/escher/include/escher/message_table_cell_with_chevron_and_expression.h b/escher/include/escher/message_table_cell_with_chevron_and_expression.h index e1423629a..ae8b45c7d 100644 --- a/escher/include/escher/message_table_cell_with_chevron_and_expression.h +++ b/escher/include/escher/message_table_cell_with_chevron_and_expression.h @@ -9,7 +9,7 @@ public: MessageTableCellWithChevronAndExpression(I18n::Message message = (I18n::Message)0, KDText::FontSize size = KDText::FontSize::Small); View * subAccessoryView() const override; void setHighlighted(bool highlight) override; - void setExpression(Poincare::ExpressionLayout * expressionLayout); + void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout); private: ExpressionView m_subtitleView; }; diff --git a/escher/src/even_odd_expression_cell.cpp b/escher/src/even_odd_expression_cell.cpp index 75e076768..4fb2e8739 100644 --- a/escher/src/even_odd_expression_cell.cpp +++ b/escher/src/even_odd_expression_cell.cpp @@ -19,8 +19,8 @@ void EvenOddExpressionCell::setEven(bool even) { m_expressionView.setBackgroundColor(backgroundColor()); } -void EvenOddExpressionCell::setExpression(ExpressionLayout * expressionLayout) { - m_expressionView.setExpression(expressionLayout); +void EvenOddExpressionCell::setExpressionLayout(ExpressionLayout * expressionLayout) { + m_expressionView.setExpressionLayout(expressionLayout); } void EvenOddExpressionCell::setBackgroundColor(KDColor backgroundColor) { diff --git a/escher/src/expression_table_cell.cpp b/escher/src/expression_table_cell.cpp index 136fddb41..2d27687ec 100644 --- a/escher/src/expression_table_cell.cpp +++ b/escher/src/expression_table_cell.cpp @@ -18,7 +18,7 @@ void ExpressionTableCell::setHighlighted(bool highlight) { m_labelExpressionView.setBackgroundColor(backgroundColor); } -void ExpressionTableCell::setExpression(Poincare::ExpressionLayout * expressionLayout) { - m_labelExpressionView.setExpression(expressionLayout); +void ExpressionTableCell::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) { + m_labelExpressionView.setExpressionLayout(expressionLayout); layoutSubviews(); } diff --git a/escher/src/expression_view.cpp b/escher/src/expression_view.cpp index cc5c27a3a..2686d7688 100644 --- a/escher/src/expression_view.cpp +++ b/escher/src/expression_view.cpp @@ -15,7 +15,7 @@ ExpressionLayout * ExpressionView::expressionLayout() const { return m_expressionLayout; } -void ExpressionView::setExpression(ExpressionLayout * expressionLayout) { +void ExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) { m_expressionLayout = expressionLayout; markRectAsDirty(bounds()); } diff --git a/escher/src/message_table_cell_with_chevron_and_expression.cpp b/escher/src/message_table_cell_with_chevron_and_expression.cpp index d3e46ee75..9d8dc1cb0 100644 --- a/escher/src/message_table_cell_with_chevron_and_expression.cpp +++ b/escher/src/message_table_cell_with_chevron_and_expression.cpp @@ -17,8 +17,8 @@ void MessageTableCellWithChevronAndExpression::setHighlighted(bool highlight) { m_subtitleView.setBackgroundColor(backgroundColor); } -void MessageTableCellWithChevronAndExpression::setExpression(Poincare::ExpressionLayout * expressionLayout) { - m_subtitleView.setExpression(expressionLayout); +void MessageTableCellWithChevronAndExpression::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) { + m_subtitleView.setExpressionLayout(expressionLayout); reloadCell(); layoutSubviews(); } From 73810bbd9a84f7e0a3bd13e5addaf5637597f4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 12:08:42 +0100 Subject: [PATCH 003/257] [poincare] ExpressionLayout cursor. Change-Id: I2367d20754189608a7925f0d8e8dfe361fed0fd0 --- poincare/Makefile | 1 + poincare/include/poincare.h | 1 + .../poincare/expression_layout_cursor.h | 44 +++++++++++++++++++ poincare/src/expression_layout_cursor.cpp | 22 ++++++++++ 4 files changed, 68 insertions(+) create mode 100644 poincare/include/poincare/expression_layout_cursor.h create mode 100644 poincare/src/expression_layout_cursor.cpp diff --git a/poincare/Makefile b/poincare/Makefile index b681b27aa..08473fef5 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -26,6 +26,7 @@ objs += $(addprefix poincare/src/,\ division_remainder.o\ division.o\ dynamic_hierarchy.o\ + expression_layout_cursor.o\ expression_lexer.o\ expression_parser.o\ expression.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index 2a0a4a801..3bd0a9a9b 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h new file mode 100644 index 000000000..b1b14c180 --- /dev/null +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -0,0 +1,44 @@ +#ifndef POINCARE_EXPRESSION_LAYOUT_CURSOR_H +#define POINCARE_EXPRESSION_LAYOUT_CURSOR_H + +#include + +namespace Poincare { + +class ExpressionLayoutCursor { +public: + enum class Position { + Left, + Inside, + Right + }; + + ExpressionLayoutCursor() : + m_pointedExpressionLayout(nullptr), + m_position(Position::Left), + m_positionInside(0) + {}; + + /* Getters and setters */ + ExpressionLayout * pointedExpressionLayout() { return m_pointedExpressionLayout; } + void setPointedExpressionLayout(ExpressionLayout * expressionLayout) { m_pointedExpressionLayout = expressionLayout; } + Position position() const { return m_position; } + void setPosition(Position position) { m_position = position; } + int positionInside() const { return m_positionInside; } + void setPositionInside(int positionInside) { m_positionInside = positionInside; } + + /* Move */ + bool moveLeft(); + bool moveRight(); + bool moveUp(); + bool moveDown(); + +private: + ExpressionLayout * m_pointedExpressionLayout; + Position m_position; + int m_positionInside; +}; + +} + +#endif diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp new file mode 100644 index 000000000..14ea1aae1 --- /dev/null +++ b/poincare/src/expression_layout_cursor.cpp @@ -0,0 +1,22 @@ +#include + +namespace Poincare { + +bool ExpressionLayoutCursor::moveLeft() { + return false; //TODO +} + +bool ExpressionLayoutCursor::moveRight() { + return false; //TODO +} + +bool ExpressionLayoutCursor::moveUp() { + return false; //TODO +} + +bool ExpressionLayoutCursor::moveDown() { + return false; //TODO +} + +} + From 62c8db97997d44752da15a505031e1aab8852fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 12:09:42 +0100 Subject: [PATCH 004/257] [expression_editor] The controller has a ExpressionLayoutCursor. Change-Id: I8a7e35670eeecca5b633bd784b84df7de1e64626 --- apps/expression_editor/controller.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index c74e0d076..56b268c99 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -2,7 +2,7 @@ #define EXPRESSION_EDITOR_CONTROLLER_H #include -#include +#include #include "expression_and_layout.h" extern "C" { #include @@ -32,6 +32,7 @@ private: ExpressionView m_expressionView; }; ContentView m_view; + Poincare::ExpressionLayoutCursor m_cursor; }; } From 53e7f6ea4477b1ccb83d3eb08b15d8186d8ca1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 13:38:07 +0100 Subject: [PATCH 005/257] [escher] Get a View's frame. Change-Id: I9fbcf2fb8db5f735df5c852762dc8645c0358683 --- escher/include/escher/view.h | 1 + escher/src/view.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/escher/include/escher/view.h b/escher/include/escher/view.h index c1f6bdde8..80d2d3714 100644 --- a/escher/include/escher/view.h +++ b/escher/include/escher/view.h @@ -41,6 +41,7 @@ public: KDPoint pointFromPointInView(View * view, KDPoint point); KDRect bounds() const; + KDRect frame() const; View * subview(int index); virtual KDSize minimalSizeForOptimalDisplay() const; diff --git a/escher/src/view.cpp b/escher/src/view.cpp index 46d3d9212..a2092490a 100644 --- a/escher/src/view.cpp +++ b/escher/src/view.cpp @@ -158,6 +158,10 @@ KDRect View::bounds() const { return m_frame.movedTo(KDPointZero); } +KDRect View::frame() const { + return KDRect(m_frame); +} + KDPoint View::absoluteOrigin() const { if (m_superview == nullptr) { assert(this == (View *)window()); From 589926284c81fd4c7549f61e986a8dfb81b1cceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 13:41:00 +0100 Subject: [PATCH 006/257] [poincare] absoluteOrigin() is public in ExpressionLayout. Change-Id: I7e381887e3c62c36c72536ed7ef280bcc637ead4 --- poincare/include/poincare/expression_layout.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 3d0e65d37..7e27b892a 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -12,6 +12,7 @@ public: void draw(KDContext * ctx, KDPoint p, KDColor expressionColor = KDColorBlack, KDColor backgroundColor = KDColorWhite); KDPoint origin(); + KDPoint absoluteOrigin(); KDSize size(); KDCoordinate baseline(); void setParent(ExpressionLayout* parent); @@ -22,9 +23,7 @@ protected: virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; KDCoordinate m_baseline; private: - KDPoint absoluteOrigin(); - //void computeLayout();//ExpressionLayout * parent, uint16_t childIndex); - ExpressionLayout* m_parent; + ExpressionLayout * m_parent; bool m_sized, m_positioned; KDRect m_frame; }; From 8828eaf79fd7d2bc532181b0bb3d4f8c28455bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 13:51:40 +0100 Subject: [PATCH 007/257] [escher] ExpressionView drawingOrigin(). Change-Id: I737f17f857edb6e9971feeeb196f2698cc92ad9e --- escher/include/escher/expression_view.h | 1 + escher/src/expression_view.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/escher/include/escher/expression_view.h b/escher/include/escher/expression_view.h index 0b3888d9e..25861e61f 100644 --- a/escher/include/escher/expression_view.h +++ b/escher/include/escher/expression_view.h @@ -22,6 +22,7 @@ public: void setTextColor(KDColor textColor); void setAlignment(float horizontalAlignment, float verticalAlignment); KDSize minimalSizeForOptimalDisplay() const override; + KDPoint drawingOrigin() const; private: /* Warning: we do not need to delete the previous expression layout when * deleting object or setting a new expression layout. Indeed, the expression diff --git a/escher/src/expression_view.cpp b/escher/src/expression_view.cpp index 2686d7688..0fa196d63 100644 --- a/escher/src/expression_view.cpp +++ b/escher/src/expression_view.cpp @@ -47,13 +47,15 @@ KDSize ExpressionView::minimalSizeForOptimalDisplay() const { return m_expressionLayout->size(); } +KDPoint ExpressionView::drawingOrigin() const { + KDSize expressionSize = m_expressionLayout->size(); + return KDPoint(m_horizontalAlignment*(m_frame.width() - expressionSize.width()), + 0.5f*(m_frame.height() - expressionSize.height())); +} + void ExpressionView::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(rect, m_backgroundColor); if (m_expressionLayout != nullptr) { - //Position the origin of expression - KDSize expressionSize = m_expressionLayout->size(); - KDPoint origin(m_horizontalAlignment*(m_frame.width() - expressionSize.width()), - 0.5f*(m_frame.height() - expressionSize.height())); - m_expressionLayout->draw(ctx, origin, m_textColor, m_backgroundColor); + m_expressionLayout->draw(ctx, drawingOrigin(), m_textColor, m_backgroundColor); } } From 1c6d18afd98988de4f6a10d94692e3f46c72f9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 12:25:51 +0100 Subject: [PATCH 008/257] [expression_editor] Scrollable ExpressionView with cursor. Change-Id: I8f75bcb0be78d8c8901cdad0e85e8463c2ea717c --- apps/expression_editor/Makefile | 3 ++ .../expression_editor_view.cpp | 31 ++++++++++++ .../expression_editor_view.h | 29 +++++++++++ .../expression_view_with_cursor.cpp | 50 +++++++++++++++++++ .../expression_view_with_cursor.h | 36 +++++++++++++ ...scrollable_expression_view_with_cursor.cpp | 21 ++++++++ .../scrollable_expression_view_with_cursor.h | 25 ++++++++++ 7 files changed, 195 insertions(+) create mode 100644 apps/expression_editor/expression_editor_view.cpp create mode 100644 apps/expression_editor/expression_editor_view.h create mode 100644 apps/expression_editor/expression_view_with_cursor.cpp create mode 100644 apps/expression_editor/expression_view_with_cursor.h create mode 100644 apps/expression_editor/scrollable_expression_view_with_cursor.cpp create mode 100644 apps/expression_editor/scrollable_expression_view_with_cursor.h diff --git a/apps/expression_editor/Makefile b/apps/expression_editor/Makefile index 4fa2fd2f5..bdee10973 100644 --- a/apps/expression_editor/Makefile +++ b/apps/expression_editor/Makefile @@ -5,6 +5,9 @@ app_objs += $(addprefix apps/expression_editor/,\ app.o\ controller.o\ expression_and_layout.o\ + expression_editor_view.o\ + expression_view_with_cursor.o\ + scrollable_expression_view_with_cursor.o\ ) i18n_files += $(addprefix apps/expression_editor/,\ diff --git a/apps/expression_editor/expression_editor_view.cpp b/apps/expression_editor/expression_editor_view.cpp new file mode 100644 index 000000000..fc13a7f78 --- /dev/null +++ b/apps/expression_editor/expression_editor_view.cpp @@ -0,0 +1,31 @@ +#include "expression_editor_view.h" +#include + +namespace ExpressionEditor { + +ExpressionEditorView::ExpressionEditorView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor) : + SolidColorView(KDColorWhite), + m_scrollableExpressionViewWithCursor(parentResponder, expressionLayout, cursor) +{ +} + +void ExpressionEditorView::cursorPositionChanged() { + m_scrollableExpressionViewWithCursor.expressionViewWithCursor()->cursorPositionChanged(); + m_scrollableExpressionViewWithCursor.scrollToCursor(); +} + +void ExpressionEditorView::layoutSubviews() { + m_scrollableExpressionViewWithCursor.setFrame(KDRect( + k_margin, + k_margin, + bounds().width() - 2 * k_margin, + bounds().height() - 2 * k_margin)); +} + +KDSize ExpressionEditorView::minimalSizeForOptimalDisplay() const { + return m_scrollableExpressionViewWithCursor.minimalSizeForOptimalDisplay(); +} + + +} + diff --git a/apps/expression_editor/expression_editor_view.h b/apps/expression_editor/expression_editor_view.h new file mode 100644 index 000000000..49116463e --- /dev/null +++ b/apps/expression_editor/expression_editor_view.h @@ -0,0 +1,29 @@ +#ifndef EXPRESSION_EDITOR_EXPRESSION_EDITOR_VIEW_H +#define EXPRESSION_EDITOR_EXPRESSION_EDITOR_VIEW_H + +#include +#include "expression_and_layout.h" +#include "scrollable_expression_view_with_cursor.h" + +namespace ExpressionEditor { + +class ExpressionEditorView : public SolidColorView { +public: + ExpressionEditorView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor); + void cursorPositionChanged(); + int numberOfSubviews() const override { return 1; } + ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor() { return &m_scrollableExpressionViewWithCursor; } + View * subviewAtIndex(int index) override { + assert(index == 0); + return &m_scrollableExpressionViewWithCursor; + } + void layoutSubviews() override; + KDSize minimalSizeForOptimalDisplay() const override; +private: + constexpr static KDCoordinate k_margin = 10; + ScrollableExpressionViewWithCursor m_scrollableExpressionViewWithCursor; +}; + +} + +#endif diff --git a/apps/expression_editor/expression_view_with_cursor.cpp b/apps/expression_editor/expression_view_with_cursor.cpp new file mode 100644 index 000000000..66f1b8d6e --- /dev/null +++ b/apps/expression_editor/expression_view_with_cursor.cpp @@ -0,0 +1,50 @@ +#include "expression_view_with_cursor.h" +#include + +using namespace Poincare; + +namespace ExpressionEditor { + +ExpressionViewWithCursor::ExpressionViewWithCursor(ExpressionLayout * expressionLayout, ExpressionLayoutCursor * cursor) : + m_cursor(cursor) +{ + m_expressionView.setExpressionLayout(expressionLayout); +} + +void ExpressionViewWithCursor::cursorPositionChanged() { + layoutCursorSubview(); +} + +KDRect ExpressionViewWithCursor::cursorRect() { + return m_cursorView.frame(); +} + +KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { + return m_expressionView.minimalSizeForOptimalDisplay(); +} + +View * ExpressionViewWithCursor::subviewAtIndex(int index) { + assert(index >= 0 && index < 2); + View * m_views[] = {&m_expressionView, &m_cursorView}; + return m_views[index]; +} + +void ExpressionViewWithCursor::layoutSubviews() { + m_expressionView.setFrame(bounds()); + layoutCursorSubview(); +} + +void ExpressionViewWithCursor::layoutCursorSubview() { + KDPoint expressionViewOrigin = m_expressionView.drawingOrigin(); + KDPoint cursoredExpressionViewOrigin = m_cursor->pointedExpressionLayout()->absoluteOrigin(); + KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x(); + if (m_cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursorX += m_cursor->pointedExpressionLayout()->size().width(); + } else if (m_cursor->position() == ExpressionLayoutCursor::Position::Inside) { + cursorX += m_cursor->positionInside() * KDText::charSize().width(); + } + KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + m_cursor->pointedExpressionLayout()->baseline()-k_cursorHeight/2); + m_cursorView.setFrame(KDRect(cursorTopLeftPosition, 1, k_cursorHeight)); +} + +} diff --git a/apps/expression_editor/expression_view_with_cursor.h b/apps/expression_editor/expression_view_with_cursor.h new file mode 100644 index 000000000..991bc4ba1 --- /dev/null +++ b/apps/expression_editor/expression_view_with_cursor.h @@ -0,0 +1,36 @@ +#ifndef EXPRESSION_EDITOR_EXPRESSION_VIEW_WITH_CURSOR_H +#define EXPRESSION_EDITOR_EXPRESSION_VIEW_WITH_CURSOR_H + +#include +#include +#include +#include + +namespace ExpressionEditor { + +class ExpressionViewWithCursor : public View { +public: + ExpressionViewWithCursor(Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor); + void cursorPositionChanged(); + KDRect cursorRect(); + const ExpressionView * expressionView() const { return &m_expressionView; } + /* View */ + KDSize minimalSizeForOptimalDisplay() const override; +private: + enum class Position { + Top, + Bottom + }; + constexpr static KDCoordinate k_cursorHeight = 18; + int numberOfSubviews() const override { return 2; } + View * subviewAtIndex(int index) override; + void layoutSubviews() override; + void layoutCursorSubview(); + Poincare::ExpressionLayoutCursor * m_cursor; + ExpressionView m_expressionView; + TextCursorView m_cursorView; +}; + +} + +#endif diff --git a/apps/expression_editor/scrollable_expression_view_with_cursor.cpp b/apps/expression_editor/scrollable_expression_view_with_cursor.cpp new file mode 100644 index 000000000..b7beb0baf --- /dev/null +++ b/apps/expression_editor/scrollable_expression_view_with_cursor.cpp @@ -0,0 +1,21 @@ +#include "scrollable_expression_view_with_cursor.h" +#include + +namespace ExpressionEditor { + +ScrollableExpressionViewWithCursor::ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor) : + ScrollableView(parentResponder, &m_expressionViewWithCursor, this), + m_expressionViewWithCursor(expressionLayout, cursor) +{ +} + +KDSize ScrollableExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { + return m_expressionViewWithCursor.minimalSizeForOptimalDisplay(); +} + +void ScrollableExpressionViewWithCursor::scrollToCursor() { + scrollToContentRect(m_expressionViewWithCursor.cursorRect()); +} + +} + diff --git a/apps/expression_editor/scrollable_expression_view_with_cursor.h b/apps/expression_editor/scrollable_expression_view_with_cursor.h new file mode 100644 index 000000000..7083f1153 --- /dev/null +++ b/apps/expression_editor/scrollable_expression_view_with_cursor.h @@ -0,0 +1,25 @@ +#ifndef EXPRESSION_EDITOR_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H +#define EXPRESSION_EDITOR_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H + +#include +#include +#include +#include "expression_view_with_cursor.h" + +namespace ExpressionEditor { + +class ScrollableExpressionViewWithCursor : public ScrollableView, public ScrollViewDataSource { +public: + ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor); + KDSize minimalSizeForOptimalDisplay() const override; + ExpressionViewWithCursor * expressionViewWithCursor() { return &m_expressionViewWithCursor; } + void scrollToCursor(); + /* ScrollableView */ + bool handleEvent(Ion::Events::Event event) override { return false; } +private: + ExpressionViewWithCursor m_expressionViewWithCursor; +}; + +} + +#endif From 23d49f768f742cabd49f2fd2a25f22cea1a23d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 15:23:21 +0100 Subject: [PATCH 009/257] [expression_editor] Use ExpressionEditorView. Change-Id: Ib4080fd76f7040be6ad8ebfda10d2e2070c7381c --- apps/expression_editor/Makefile | 7 +++- apps/expression_editor/app.cpp | 2 +- apps/expression_editor/controller.cpp | 39 +++++++++---------- apps/expression_editor/controller.h | 21 ++-------- .../expression_view_with_cursor.cpp | 3 +- 5 files changed, 31 insertions(+), 41 deletions(-) diff --git a/apps/expression_editor/Makefile b/apps/expression_editor/Makefile index bdee10973..7edd46555 100644 --- a/apps/expression_editor/Makefile +++ b/apps/expression_editor/Makefile @@ -18,4 +18,9 @@ tests += $(addprefix apps/expression_editor/test/,\ dummy_test.cpp\ ) -test_objs += $(addprefix apps/expression_editor/, controller.o) +test_objs += $(addprefix apps/expression_editor/,\ + controller.o\ + expression_editor_view.o\ + expression_view_with_cursor.o\ + scrollable_expression_view_with_cursor.o\ +) diff --git a/apps/expression_editor/app.cpp b/apps/expression_editor/app.cpp index 9c7111f02..5ef392b9c 100644 --- a/apps/expression_editor/app.cpp +++ b/apps/expression_editor/app.cpp @@ -22,7 +22,7 @@ App::Descriptor * App::Snapshot::descriptor() { App::App(Container * container, Snapshot * snapshot) : ::App(container, snapshot, &m_controller), - m_controller(&m_modalViewController, snapshot->expressionAndLayout()) + m_controller(&m_modalViewController, snapshot->expressionAndLayout()->expressionLayout()) { } diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index a62313cdc..bbf0ee478 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -2,29 +2,26 @@ namespace ExpressionEditor { -Controller::ContentView::ContentView(ExpressionAndLayout * expressionAndLayout) : - SolidColorView(KDColorWhite), - m_expressionView() -{ - m_expressionView.setExpressionLayout(expressionAndLayout->expressionLayout()); -} - -void Controller::ContentView::layoutSubviews() { - m_expressionView.setFrame(KDRect( - k_margin, - k_margin, - bounds().width() - 2 * k_margin, - bounds().height() - 2 * k_margin)); -} - -KDSize Controller::ContentView::minimalSizeForOptimalDisplay() const { - return m_expressionView.minimalSizeForOptimalDisplay(); -} - -Controller::Controller(Responder * parentResponder, ExpressionAndLayout * expressionAndLayout) : +Controller::Controller(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout) : ViewController(parentResponder), - m_view(expressionAndLayout) + m_view(parentResponder, expressionLayout, &m_cursor) { + m_cursor.setPointedExpressionLayout(expressionLayout); +} + +void Controller::didBecomeFirstResponder() { + m_view.layoutSubviews(); + /* TODO We need the layout to be done in order to scroll to the cursor. We + * thus made ExpressionViewWithCursor's layoutSubviews() public, which is the + * solution used in ModalViewController for instance. A cleaner solution would + * be to split viewWillAppear into loadViewIfNeeded() and viewWillAppear(), in + * order to change App::didBecomeActive to: + * m_modalViewController.loadViewIfNeeded(); + * window->setContentView(view); + * m_modalViewController.viewWillAppear(); + * The scrolling could then be done in viewWillAppear(), without calling + * layoutSubviews() manually. */ + m_view.scrollableExpressionViewWithCursor()->scrollToCursor(); } bool Controller::handleEvent(Ion::Events::Event event) { diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index 56b268c99..f09630034 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -4,6 +4,7 @@ #include #include #include "expression_and_layout.h" +#include "expression_editor_view.h" extern "C" { #include } @@ -12,26 +13,12 @@ namespace ExpressionEditor { class Controller : public ViewController { public: - Controller(Responder * parentResponder, ExpressionAndLayout * expressionAndLayout); + Controller(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout); View * view() override { return &m_view; } + void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; - private: - class ContentView : public SolidColorView { - public: - ContentView(ExpressionAndLayout * expressionAndLayout); - int numberOfSubviews() const override { return 1; } - View * subviewAtIndex(int index) override { - assert(index == 0); - return &m_expressionView; - } - void layoutSubviews() override; - KDSize minimalSizeForOptimalDisplay() const override; - private: - constexpr static KDCoordinate k_margin = 10; - ExpressionView m_expressionView; - }; - ContentView m_view; + ExpressionEditorView m_view; Poincare::ExpressionLayoutCursor m_cursor; }; diff --git a/apps/expression_editor/expression_view_with_cursor.cpp b/apps/expression_editor/expression_view_with_cursor.cpp index 66f1b8d6e..0c83c41ce 100644 --- a/apps/expression_editor/expression_view_with_cursor.cpp +++ b/apps/expression_editor/expression_view_with_cursor.cpp @@ -20,7 +20,8 @@ KDRect ExpressionViewWithCursor::cursorRect() { } KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { - return m_expressionView.minimalSizeForOptimalDisplay(); + KDSize expressionViewSize = m_expressionView.minimalSizeForOptimalDisplay(); + return KDSize(expressionViewSize.width()+1, m_expressionView.minimalSizeForOptimalDisplay().height()); // +1 for the cursor } View * ExpressionViewWithCursor::subviewAtIndex(int index) { From 8f6a27bee8e97be2b8c037b2b5f731fe9ac2caca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 15:23:53 +0100 Subject: [PATCH 010/257] [TO REMOVE] Bigger test case. Change-Id: I72c0474000aab5eec5ebada2e09c0f7f555c8e2b --- apps/expression_editor/expression_and_layout.cpp | 3 ++- poincare/include/poincare/expression_layout_cursor.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/expression_editor/expression_and_layout.cpp b/apps/expression_editor/expression_and_layout.cpp index 89a0f310e..1f36461be 100644 --- a/apps/expression_editor/expression_and_layout.cpp +++ b/apps/expression_editor/expression_and_layout.cpp @@ -31,8 +31,9 @@ ExpressionAndLayout::ExpressionAndLayout() { //const char * expression = "abs(5)+int(5/46*7/8,3,4544444)+conj(4)+int(333,4,5)"; //const char * expression = "conj(int(5/46*7/8,3,45))+conj(4)"; //const char * expression = "abs(1+conj(conj(4))+(23)+conj(42))+abs(1+2)"; - const char * expression = "13+(23)"; + //const char * expression = "13+(23)"; //const char * expression = "1+sum(12,3,4)+product(12,3,4)+2"; + const char * expression = "(1+2^3)-385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]/123+ln(36)+root(542,52)+sum(12,3,4)+int(22,3,4)+conj(988+2)+abs(conj(345))+conj(conj(conj(3)))+floor(48)+binomial(6,88)+product(23,46,123)"; m_expression = Poincare::Expression::parse(expression); m_expressionLayout = m_expression->createLayout(); diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index b1b14c180..89b2a0462 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -15,7 +15,7 @@ public: ExpressionLayoutCursor() : m_pointedExpressionLayout(nullptr), - m_position(Position::Left), + m_position(Position::Right), m_positionInside(0) {}; From 5aa1946796e6e559e28e8d915a20fc3aa84eb325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 15:28:35 +0100 Subject: [PATCH 011/257] [expression_editor] Handle navigation events in the controller. Change-Id: I7f8f2846f7b7ac141e854215edd30e0c078a992c --- apps/expression_editor/controller.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index bbf0ee478..632310443 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -25,7 +25,16 @@ void Controller::didBecomeFirstResponder() { } bool Controller::handleEvent(Ion::Events::Event event) { - return false; + bool returnValue = false; + if ((event == Ion::Events::Left && m_cursor.moveLeft()) + || (event == Ion::Events::Right && m_cursor.moveRight()) + || (event == Ion::Events::Up && m_cursor.moveUp()) + || (event == Ion::Events::Down && m_cursor.moveDown())) + { + returnValue = true; + } + m_view.cursorPositionChanged(); + return returnValue; } } From 78c02e68712c8750395daace86656c365b77503c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 14 Dec 2017 18:12:06 +0100 Subject: [PATCH 012/257] [expression_editor/poincare] Move Left in an ExpressionLayout. Change-Id: Id69def65e0976bfb045c1da6e8786a2f5797120c --- poincare/include/poincare/expression_layout.h | 12 +++- poincare/src/expression_layout_cursor.cpp | 2 +- .../src/layout/baseline_relative_layout.cpp | 42 +++++++++++ .../src/layout/baseline_relative_layout.h | 1 + poincare/src/layout/bracket_layout.cpp | 28 ++++++++ poincare/src/layout/bracket_layout.h | 1 + poincare/src/layout/condensed_sum_layout.cpp | 39 +++++++++++ poincare/src/layout/condensed_sum_layout.h | 1 + poincare/src/layout/conjugate_layout.cpp | 31 ++++++++ poincare/src/layout/conjugate_layout.h | 1 + poincare/src/layout/fraction_layout.cpp | 30 +++++++- poincare/src/layout/fraction_layout.h | 1 + poincare/src/layout/grid_layout.cpp | 52 +++++++++++++- poincare/src/layout/grid_layout.h | 4 ++ poincare/src/layout/horizontal_layout.cpp | 70 ++++++++++++++++--- poincare/src/layout/horizontal_layout.h | 2 + poincare/src/layout/integral_layout.cpp | 41 +++++++++++ poincare/src/layout/integral_layout.h | 1 + poincare/src/layout/nth_root_layout.cpp | 44 +++++++++++- poincare/src/layout/nth_root_layout.h | 1 + poincare/src/layout/parenthesis_layout.cpp | 28 ++++++++ poincare/src/layout/parenthesis_layout.h | 1 + poincare/src/layout/sequence_layout.cpp | 42 +++++++++++ poincare/src/layout/sequence_layout.h | 1 + poincare/src/layout/string_layout.cpp | 45 +++++++++++- poincare/src/layout/string_layout.h | 1 + 26 files changed, 506 insertions(+), 16 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 7e27b892a..9bafc81ac 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -5,25 +5,33 @@ namespace Poincare { +class ExpressionLayoutCursor; + class ExpressionLayout { public: ExpressionLayout(); virtual ~ExpressionLayout() = default; + /* Rendering */ void draw(KDContext * ctx, KDPoint p, KDColor expressionColor = KDColorBlack, KDColor backgroundColor = KDColorWhite); KDPoint origin(); KDPoint absoluteOrigin(); KDSize size(); KDCoordinate baseline(); + + /* Hierarchy */ void setParent(ExpressionLayout* parent); + virtual ExpressionLayout * child(uint16_t index) = 0; + + /* Tree navigation */ + virtual bool moveLeft(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; - virtual ExpressionLayout * child(uint16_t index) = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; KDCoordinate m_baseline; -private: ExpressionLayout * m_parent; +private: bool m_sized, m_positioned; KDRect m_frame; }; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 14ea1aae1..ce5468741 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -3,7 +3,7 @@ namespace Poincare { bool ExpressionLayoutCursor::moveLeft() { - return false; //TODO + return m_pointedExpressionLayout->moveLeft(this); } bool ExpressionLayoutCursor::moveRight() { diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index da55937a9..11cc237ee 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -1,4 +1,5 @@ #include "baseline_relative_layout.h" +#include #include #include @@ -29,6 +30,47 @@ ExpressionLayout * BaselineRelativeLayout::indiceLayout() { return m_indiceLayout; } +bool BaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the indice. + // Go from the indice to the base. + if (m_indiceLayout + && cursor->pointedExpressionLayout() == m_indiceLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + assert(m_baseLayout != nullptr); + cursor->setPointedExpressionLayout(m_baseLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Left of the base. + // Ask the parent. + if (m_baseLayout + && cursor->pointedExpressionLayout() == m_baseLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the indice. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(m_indiceLayout); + return true; + } + // Case: Left. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + void BaselineRelativeLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // There is nothing to draw for a subscript/superscript, only the position of the children matters } diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index f313d9212..029ed653f 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -20,6 +20,7 @@ public: BaselineRelativeLayout& operator=(BaselineRelativeLayout&& other) = delete; ExpressionLayout * baseLayout(); ExpressionLayout * indiceLayout(); + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index dddd78aa9..32cdb10b0 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -1,4 +1,5 @@ #include "bracket_layout.h" +#include extern "C" { #include #include @@ -18,6 +19,33 @@ BracketLayout::~BracketLayout() { delete m_operandLayout; } +bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the operand. + // Go Left of the brackets. + if (m_operandLayout + && cursor->pointedExpressionLayout() == m_operandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right of the brackets. + // Go Right of the operand. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_operandLayout != nullptr); + cursor->setPointedExpressionLayout(m_operandLayout); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left of the brackets. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + void BracketLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize operandSize = m_operandLayout->size(); ctx->fillRect(KDRect(p.x(), p.y(), k_lineThickness, m_operandLayout->size().height()), expressionColor); diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index 4fca30e92..9016cb803 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -14,6 +14,7 @@ public: BracketLayout(BracketLayout&& other) = delete; BracketLayout& operator=(const BracketLayout& other) = delete; BracketLayout& operator=(BracketLayout&& other) = delete; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: virtual KDCoordinate widthMargin() const { return 5; } virtual bool renderTopBar() const { return true; } diff --git a/poincare/src/layout/condensed_sum_layout.cpp b/poincare/src/layout/condensed_sum_layout.cpp index e2c20e853..0a74eece4 100644 --- a/poincare/src/layout/condensed_sum_layout.cpp +++ b/poincare/src/layout/condensed_sum_layout.cpp @@ -1,4 +1,5 @@ #include "condensed_sum_layout.h" +#include #include #include @@ -27,6 +28,44 @@ CondensedSumLayout::~CondensedSumLayout() { } } +bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the bounds. + // Go Left of the sum. + if (((m_subscriptLayout && cursor->pointedExpressionLayout() == m_subscriptLayout) + || (m_superscriptLayout && cursor->pointedExpressionLayout() == m_superscriptLayout)) + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Left of the base. + // Go Right of the lower bound. + if (m_baseLayout + && cursor->pointedExpressionLayout() == m_baseLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(m_subscriptLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the base and move Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_baseLayout); + cursor->setPointedExpressionLayout(m_baseLayout); + return m_baseLayout->moveLeft(cursor); + } + // Case: Left. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + void CondensedSumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // Nothing to draw } diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index dc52f4e5f..fce1333c3 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -14,6 +14,7 @@ public: CondensedSumLayout(CondensedSumLayout&& other) = delete; CondensedSumLayout& operator=(const CondensedSumLayout& other) = delete; CondensedSumLayout& operator=(CondensedSumLayout&& other) = delete; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index ca0aa4cef..fc83bc45b 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -1,4 +1,5 @@ #include "conjugate_layout.h" +#include extern "C" { #include #include @@ -18,6 +19,36 @@ ConjugateLayout::~ConjugateLayout() { delete m_operandLayout; } +bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the operand. + // Ask the parent. + if (m_operandLayout + && cursor->pointedExpressionLayout() == m_operandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the operand and move Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_operandLayout != nullptr); + cursor->setPointedExpressionLayout(m_operandLayout); + return m_operandLayout->moveLeft(cursor); + } + // Case: Left. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + void ConjugateLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { ctx->fillRect(KDRect(p.x(), p.y(), m_operandLayout->size().width(), k_overlineWidth), expressionColor); } diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 29ebdfaa3..4d6eacf8c 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -14,6 +14,7 @@ public: ConjugateLayout(ConjugateLayout&& other) = delete; ConjugateLayout& operator=(const ConjugateLayout& other) = delete; ConjugateLayout& operator=(ConjugateLayout&& other) = delete; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index e71a263db..01ce02e87 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -1,6 +1,7 @@ +#include "fraction_layout.h" +#include #include #include -#include "fraction_layout.h" namespace Poincare { @@ -17,6 +18,33 @@ FractionLayout::~FractionLayout() { delete m_numerator_layout; } +bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the numerator or the denominator. + // Go Left of the fraction. + if (((m_numerator_layout && cursor->pointedExpressionLayout() == m_numerator_layout) + || (m_denominator_layout && cursor->pointedExpressionLayout() == m_denominator_layout)) + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the denominator. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_denominator_layout != nullptr); + cursor->setPointedExpressionLayout(m_denominator_layout); + return true; + } + // Case: Left. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + void FractionLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDCoordinate fractionLineY = p.y() + m_numerator_layout->size().height() + k_fractionLineMargin; ctx->fillRect(KDRect(p.x()+k_fractionBorderMargin, fractionLineY, size().width()-2*k_fractionBorderMargin, 1), expressionColor); diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 4a01a60ae..355f5c44b 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -14,6 +14,7 @@ public: FractionLayout(FractionLayout&& other) = delete; FractionLayout& operator=(const FractionLayout& other) = delete; FractionLayout& operator=(FractionLayout&& other) = delete; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 92dae7a72..79e91f4e9 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -1,4 +1,5 @@ #include "grid_layout.h" +#include extern "C" { #include #include @@ -26,6 +27,42 @@ GridLayout::~GridLayout() { delete[] m_entryLayouts; } +bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Right. + // Go to the last entry. + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + ExpressionLayout * lastChild = m_entryLayouts[m_numberOfColumns*m_numberOfRows-1]; + assert(lastChild != nullptr); + cursor->setPointedExpressionLayout(lastChild); + return true; + } + // Case: The cursor points to a grid's child. + int childIndex = indexOfChild(cursor->pointedExpressionLayout()); + if (childIndex >- 1 && cursor->position() == ExpressionLayoutCursor::Position::Left) { + if (childIsLeftOfGrid(childIndex)) { + // Case: Left of a child on the left of the grid. + // Go Left of the grid + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Left of another child. + // Go Right of its brother on the left. + cursor->setPointedExpressionLayout(m_entryLayouts[childIndex-1]); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + KDCoordinate GridLayout::rowBaseline(int i) { KDCoordinate rowBaseline = 0; for (int j = 0; j < m_numberOfColumns; j++) { @@ -34,7 +71,6 @@ KDCoordinate GridLayout::rowBaseline(int i) { return rowBaseline; } - KDCoordinate GridLayout::rowHeight(int i) { KDCoordinate rowHeight = 0; KDCoordinate baseline = rowBaseline(i); @@ -110,4 +146,18 @@ KDPoint GridLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x, y); } +int GridLayout::indexOfChild(ExpressionLayout * eL) const { + for (int i = 0; i < m_numberOfRows*m_numberOfColumns; i++) { + if (eL == m_entryLayouts[i]) { + return i; + } + } + return -1; +} + +bool GridLayout::childIsLeftOfGrid(int index) const { + assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); + return (index - m_numberOfColumns * (int)(index / m_numberOfColumns)) == 0; +} + } diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index f252f28df..7e5de435e 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class GridLayout : public ExpressionLayout { + //TODO Split it in MatrixLayout and BinomialCoefficientayout. public: GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int numberOfColumns); ~GridLayout(); @@ -14,6 +15,7 @@ public: GridLayout(GridLayout&& other) = delete; GridLayout& operator=(const GridLayout& other) = delete; GridLayout& operator=(GridLayout&& other) = delete; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; @@ -26,6 +28,8 @@ private: KDCoordinate height(); KDCoordinate columnWidth(int j); KDCoordinate width(); + int indexOfChild(ExpressionLayout * eL) const; + bool childIsLeftOfGrid(int index) const; ExpressionLayout ** m_entryLayouts; int m_numberOfRows; int m_numberOfColumns; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 804ef7bd6..63d1e1a9e 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -1,10 +1,12 @@ +#include "horizontal_layout.h" +#include "string_layout.h" +#include + extern "C" { #include #include #include } -#include "horizontal_layout.h" -#include "string_layout.h" namespace Poincare { @@ -28,6 +30,53 @@ HorizontalLayout::~HorizontalLayout() { delete[] m_children_layouts; } +bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left. + // Ask the parent. + if (cursor->pointedExpressionLayout() == this) { + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Go to the last child if there is one, and move Left. + // Else go Left and ask the parent. + if (m_number_of_children < 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + ExpressionLayout * lastChild = m_children_layouts[m_number_of_children-1]; + assert(lastChild != nullptr); + cursor->setPointedExpressionLayout(lastChild); + return lastChild->moveLeft(cursor); + } + + // Case: The cursor is Left of a child. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + int childIndex = indexOfChild(cursor->pointedExpressionLayout()); + assert(childIndex >= 0); + if (childIndex == 0) { + // Case: the child is the leftmost. + // Ask the parent. + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + // Case: the child is not the leftmost. + // Go to its left brother and move Left. + cursor->setPointedExpressionLayout(m_children_layouts[childIndex-1]); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return m_children_layouts[childIndex-1]->moveLeft(cursor); +} + void HorizontalLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { } @@ -61,13 +110,7 @@ ExpressionLayout * HorizontalLayout::child(uint16_t index) { KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; - uint16_t index = 0; - for (int i=0;i 0) { ExpressionLayout * previousChild = m_children_layouts[index-1]; assert(previousChild != nullptr); @@ -77,4 +120,13 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x, y); } +int HorizontalLayout::indexOfChild(ExpressionLayout * eL) const { + for (int i = 0; i < m_number_of_children; i++) { + if (m_children_layouts[i] == eL) { + return i; + } + } + return -1; +} + } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 1770eee1f..55f8dd279 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -14,12 +14,14 @@ public: HorizontalLayout(HorizontalLayout&& other) = delete; HorizontalLayout& operator=(const HorizontalLayout& other) = delete; HorizontalLayout& operator=(HorizontalLayout&& other) = delete; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: + int indexOfChild(ExpressionLayout * eL) const; int m_number_of_children; ExpressionLayout ** m_children_layouts; }; diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 6b91dc738..23470cd74 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -1,4 +1,5 @@ #include "integral_layout.h" +#include #include #include @@ -36,6 +37,46 @@ IntegralLayout::~IntegralLayout() { delete m_integrandLayout; } +bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left the upper or lower bound. + // Go Left of the integral. + if (((m_upperBoundLayout + && cursor->pointedExpressionLayout() == m_upperBoundLayout) + || (m_lowerBoundLayout + && cursor->pointedExpressionLayout() == m_lowerBoundLayout)) + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + return true; + } + // Case: Left the integrand. + // Go Right of the lower bound. + if (m_integrandLayout + && cursor->pointedExpressionLayout() == m_integrandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + assert(m_lowerBoundLayout != nullptr); + cursor->setPointedExpressionLayout(m_lowerBoundLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right of the integral. + // Go Right of the integrand, Left of "dx". + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_integrandLayout != nullptr); + cursor->setPointedExpressionLayout(m_integrandLayout->child(0)); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left of the brackets. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize integrandSize = m_integrandLayout->size(); KDSize upperBoundSize = m_upperBoundLayout->size(); diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 2e7059acd..abf47ff33 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -16,6 +16,7 @@ public: IntegralLayout& operator=(IntegralLayout&& other) = delete; constexpr static KDCoordinate k_symbolHeight = 4; constexpr static KDCoordinate k_symbolWidth = 4; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index c9b75fbae..9fda611b8 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -1,6 +1,7 @@ +#include "nth_root_layout.h" +#include #include #include -#include "nth_root_layout.h" namespace Poincare { @@ -37,6 +38,47 @@ NthRootLayout::~NthRootLayout() { } } +bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the radicand. + // Go the index if there is one, else go Left of the root. + if (m_radicandLayout + && cursor->pointedExpressionLayout() == m_radicandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + if (m_indexLayout) { + cursor->setPointedExpressionLayout(m_indexLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + cursor->setPointedExpressionLayout(this); + return true; + } + // Case: Left of the index. + // Go Left of the root. + if (m_indexLayout + && cursor->pointedExpressionLayout() == m_indexLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go Right of the radicand. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_radicandLayout != nullptr); + cursor->setPointedExpressionLayout(m_radicandLayout); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize radicandSize = m_radicandLayout->size(); KDSize indexSize = m_indexLayout != nullptr ? m_indexLayout->size() : KDSize(k_leftRadixWidth,0); diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index b75cebdb0..ade120681 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -16,6 +16,7 @@ public: NthRootLayout& operator=(NthRootLayout&& other) = delete; constexpr static KDCoordinate k_leftRadixHeight = 8; constexpr static KDCoordinate k_leftRadixWidth = 5; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index 133e6c3af..d71ef1e22 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -1,4 +1,5 @@ #include "parenthesis_layout.h" +#include extern "C" { #include #include @@ -61,6 +62,33 @@ ParenthesisLayout::~ParenthesisLayout() { delete m_operandLayout; } +bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the operand. + // Go Left of the brackets. + if (m_operandLayout + && cursor->pointedExpressionLayout() == m_operandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right of the parentheses. + // Go Right of the operand. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_operandLayout != nullptr); + cursor->setPointedExpressionLayout(m_operandLayout); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left of the parentheses. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + KDColor s_parenthesisWorkingBuffer[ParenthesisLayout::k_parenthesisCurveHeight*ParenthesisLayout::k_parenthesisCurveWidth]; void ParenthesisLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { diff --git a/poincare/src/layout/parenthesis_layout.h b/poincare/src/layout/parenthesis_layout.h index 7ed17ca4a..92f4892ed 100644 --- a/poincare/src/layout/parenthesis_layout.h +++ b/poincare/src/layout/parenthesis_layout.h @@ -16,6 +16,7 @@ public: ParenthesisLayout& operator=(ParenthesisLayout&& other) = delete; constexpr static KDCoordinate k_parenthesisCurveWidth = 5; constexpr static KDCoordinate k_parenthesisCurveHeight = 7; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 52ed5dc95..1bf01e536 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -1,4 +1,6 @@ #include "sequence_layout.h" +#include "string_layout.h" +#include #include #include @@ -22,6 +24,46 @@ SequenceLayout::~SequenceLayout() { delete m_argumentLayout; } +bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the bounds. + // Go Left of the sequence. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && ((m_lowerBoundLayout + && cursor->pointedExpressionLayout() == m_lowerBoundLayout) + || (m_upperBoundLayout + && cursor->pointedExpressionLayout() == m_upperBoundLayout))) + { + cursor->setPointedExpressionLayout(this); + return true; + } + // Case: Left of the argument. + // Go Right of the lower bound. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && m_argumentLayout + && cursor->pointedExpressionLayout() == m_argumentLayout) + { + assert(m_lowerBoundLayout != nullptr); + cursor->setPointedExpressionLayout(m_lowerBoundLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the argument and move Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_argumentLayout != nullptr); + cursor->setPointedExpressionLayout(m_argumentLayout); + return m_argumentLayout->moveLeft(cursor); + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + KDSize SequenceLayout::computeSize() { KDSize argumentSize = m_argumentLayout->size(); KDSize lowerBoundSize = m_lowerBoundLayout->size(); diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 41f3b17bb..03e289454 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -16,6 +16,7 @@ public: SequenceLayout& operator=(SequenceLayout&& other) = delete; constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: constexpr static KDCoordinate k_boundHeightMargin = 2; ExpressionLayout * m_lowerBoundLayout; diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index 62bbbb68c..ab0b2818d 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -1,6 +1,7 @@ +#include "string_layout.h" +#include #include #include -#include "string_layout.h" namespace Poincare { @@ -23,6 +24,48 @@ char * StringLayout::text() { return m_string; } +bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go before the last char. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + size_t stringLength = strlen(m_string); + if (stringLength > 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Inside); + cursor->setPositionInside(stringLength - 1); + return true; + } + if (stringLength == 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + assert(stringLength == 0); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + // Case: Inside. + // Go one char left. + if (cursor->position() == ExpressionLayoutCursor::Position::Inside) { + int cursorIndex = cursor->positionInside(); + assert(cursorIndex > 0 && cursorIndex < strlen(m_string)); + if (cursorIndex == 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + cursor->setPositionInside(cursorIndex - 1); + return true; + } + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + ExpressionLayout * StringLayout::child(uint16_t index) { return nullptr; } diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index 4aa4b584e..bb86c4dc6 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -18,6 +18,7 @@ public: StringLayout& operator=(const StringLayout& other) = delete; StringLayout& operator=(StringLayout&& other) = delete; char * text(); + bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; From 3af2f88da72943fbb38e5d80d6f6af04ca94cd78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 7 Dec 2017 16:01:41 +0100 Subject: [PATCH 013/257] [poincare] Added extern margins on BracketLayout to see the cursor. Change-Id: I32f6d54c2121b4de1d7ae2552239a1e8ac557913 --- poincare/src/layout/bracket_layout.cpp | 22 ++++++++++++++-------- poincare/src/layout/bracket_layout.h | 1 + 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 32cdb10b0..c185fff75 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -47,22 +47,26 @@ bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { } void BracketLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + const KDCoordinate k_widthMargin = widthMargin(); + const KDCoordinate k_externWidthMargin = externWidthMargin(); KDSize operandSize = m_operandLayout->size(); - ctx->fillRect(KDRect(p.x(), p.y(), k_lineThickness, m_operandLayout->size().height()), expressionColor); - ctx->fillRect(KDRect(p.x()+operandSize.width()+2*widthMargin()+k_lineThickness, p.y(), k_lineThickness, m_operandLayout->size().height()), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_lineThickness, m_operandLayout->size().height()), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin+operandSize.width()+2*k_widthMargin+k_lineThickness, p.y(), k_lineThickness, m_operandLayout->size().height()), expressionColor); if (renderTopBar()) { - ctx->fillRect(KDRect(p.x(), p.y(), k_bracketWidth, k_lineThickness), expressionColor); - ctx->fillRect(KDRect(p.x()+2*k_lineThickness+operandSize.width()+2*widthMargin()-k_bracketWidth, p.y(), k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin+2*k_lineThickness+operandSize.width()+2*k_widthMargin-k_bracketWidth, p.y(), k_bracketWidth, k_lineThickness), expressionColor); } if (renderBottomBar()) { - ctx->fillRect(KDRect(p.x(), p.y()+operandSize.height()-k_lineThickness, k_bracketWidth, k_lineThickness), expressionColor); - ctx->fillRect(KDRect(p.x()+2*k_lineThickness+operandSize.width()+2*widthMargin()-k_bracketWidth, p.y()+operandSize.height()-k_lineThickness, k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y()+operandSize.height()-k_lineThickness, k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin+2*k_lineThickness+operandSize.width()+2*k_widthMargin-k_bracketWidth, p.y()+operandSize.height()-k_lineThickness, k_bracketWidth, k_lineThickness), expressionColor); } } KDSize BracketLayout::computeSize() { + const KDCoordinate k_widthMargin = widthMargin(); + const KDCoordinate k_externWidthMargin = externWidthMargin(); KDSize operandSize = m_operandLayout->size(); - return KDSize(operandSize.width() + 2*widthMargin() + 2*k_lineThickness, operandSize.height()); + return KDSize(operandSize.width() + 2*k_externWidthMargin + 2*k_widthMargin + 2*k_lineThickness, operandSize.height()); } ExpressionLayout * BracketLayout::child(uint16_t index) { @@ -73,7 +77,9 @@ ExpressionLayout * BracketLayout::child(uint16_t index) { } KDPoint BracketLayout::positionOfChild(ExpressionLayout * child) { - return KDPoint(widthMargin()+k_lineThickness, 0); + const KDCoordinate k_widthMargin = widthMargin(); + const KDCoordinate k_externWidthMargin = externWidthMargin(); + return KDPoint(k_widthMargin+k_externWidthMargin+k_lineThickness, 0); } } diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index 9016cb803..f110789aa 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -16,6 +16,7 @@ public: BracketLayout& operator=(BracketLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: + KDCoordinate externWidthMargin() const { return 2; } virtual KDCoordinate widthMargin() const { return 5; } virtual bool renderTopBar() const { return true; } virtual bool renderBottomBar() const { return true; } From 074f8c533797f190beb543be1682d84e93cefc88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 7 Dec 2017 16:03:59 +0100 Subject: [PATCH 014/257] [TO REMOVE] Colored the cursor in Red for visibility. Change-Id: Ia93ebbac1f4b7e15e7de7a3d8546a19797929d72 --- escher/src/text_cursor_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/text_cursor_view.cpp b/escher/src/text_cursor_view.cpp index 6ef9a6ebe..fd2ea48f1 100644 --- a/escher/src/text_cursor_view.cpp +++ b/escher/src/text_cursor_view.cpp @@ -2,7 +2,7 @@ void TextCursorView::drawRect(KDContext * ctx, KDRect rect) const { KDCoordinate height = bounds().height(); - ctx->fillRect(KDRect(0, 0, 1, height), KDColorBlack); + ctx->fillRect(KDRect(0, 0, 1, height), KDColorRed); } KDSize TextCursorView::minimalSizeForOptimalDisplay() const { From d5316e06f7a6b77df074f59d7b49a143cabd8a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 15 Dec 2017 10:26:59 +0100 Subject: [PATCH 015/257] [poincare] EditableStringLayout. Change-Id: Ie985874c216881a722d9c6807c007bc17b25d4f0 --- poincare/Makefile | 1 + .../src/layout/editable_string_layout.cpp | 50 +++++++++++++++++++ poincare/src/layout/editable_string_layout.h | 17 +++++++ poincare/src/layout/string_layout.cpp | 30 ++--------- poincare/src/layout/string_layout.h | 2 +- 5 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 poincare/src/layout/editable_string_layout.cpp create mode 100644 poincare/src/layout/editable_string_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index 08473fef5..a33606ae2 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -87,6 +87,7 @@ objs += $(addprefix poincare/src/layout/,\ bracket_layout.o\ condensed_sum_layout.o\ conjugate_layout.o\ + editable_string_layout.o\ expression_layout.o\ fraction_layout.o\ grid_layout.o\ diff --git a/poincare/src/layout/editable_string_layout.cpp b/poincare/src/layout/editable_string_layout.cpp new file mode 100644 index 000000000..e06ab544a --- /dev/null +++ b/poincare/src/layout/editable_string_layout.cpp @@ -0,0 +1,50 @@ +#include "editable_string_layout.h" +#include +#include +#include + +namespace Poincare { + +bool EditableStringLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go before the last char. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + size_t stringLength = strlen(m_string); + if (stringLength > 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Inside); + cursor->setPositionInside(stringLength - 1); + return true; + } + if (stringLength == 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + assert(stringLength == 0); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + // Case: Inside. + // Go one char left. + if (cursor->position() == ExpressionLayoutCursor::Position::Inside) { + int cursorIndex = cursor->positionInside(); + assert(cursorIndex > 0 && cursorIndex < strlen(m_string)); + if (cursorIndex == 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + cursor->setPositionInside(cursorIndex - 1); + return true; + } + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +} diff --git a/poincare/src/layout/editable_string_layout.h b/poincare/src/layout/editable_string_layout.h new file mode 100644 index 000000000..23e92bc65 --- /dev/null +++ b/poincare/src/layout/editable_string_layout.h @@ -0,0 +1,17 @@ +#ifndef POINCARE_EDITABLE_STRING_LAYOUT_H +#define POINCARE_EDITABLE_STRING_LAYOUT_H + +#include "string_layout.h" +#include + +namespace Poincare { + +class EditableStringLayout : public StringLayout { +public: + using StringLayout::StringLayout; + bool moveLeft(ExpressionLayoutCursor * cursor) override; +}; + +} + +#endif diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index ab0b2818d..84a8a35fe 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -25,37 +25,13 @@ char * StringLayout::text() { } bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // A StringLayout is not editable, and the cursor cannot go inside it. assert(cursor->pointedExpressionLayout() == this); // Case: Right. - // Go before the last char. + // Go Left. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - size_t stringLength = strlen(m_string); - if (stringLength > 1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Inside); - cursor->setPositionInside(stringLength - 1); - return true; - } - if (stringLength == 1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - assert(stringLength == 0); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; - } - // Case: Inside. - // Go one char left. - if (cursor->position() == ExpressionLayoutCursor::Position::Inside) { - int cursorIndex = cursor->positionInside(); - assert(cursorIndex > 0 && cursorIndex < strlen(m_string)); - if (cursorIndex == 1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - cursor->setPositionInside(cursorIndex - 1); return true; } // Case: Left. diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index bb86c4dc6..236bfaa8b 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -24,8 +24,8 @@ protected: KDSize computeSize() override; ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; -private: char * m_string; +private: KDText::FontSize m_fontSize; }; From ee77ab972318e3aa7287bd6942ba84a6d2ade229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 15 Dec 2017 10:27:56 +0100 Subject: [PATCH 016/257] [poincare] EditableBaselineRelativeLayout. Change-Id: I8fa6ed2b255d20eb815055987871881b3b5bbf09 --- poincare/Makefile | 1 + .../src/layout/baseline_relative_layout.cpp | 28 +---------- .../src/layout/baseline_relative_layout.h | 4 +- .../editable_baseline_relative_layout.cpp | 50 +++++++++++++++++++ .../editable_baseline_relative_layout.h | 16 ++++++ 5 files changed, 71 insertions(+), 28 deletions(-) create mode 100644 poincare/src/layout/editable_baseline_relative_layout.cpp create mode 100644 poincare/src/layout/editable_baseline_relative_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index a33606ae2..747065f8a 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -87,6 +87,7 @@ objs += $(addprefix poincare/src/layout/,\ bracket_layout.o\ condensed_sum_layout.o\ conjugate_layout.o\ + editable_baseline_relative_layout.o\ editable_string_layout.o\ expression_layout.o\ fraction_layout.o\ diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index 11cc237ee..80cf27596 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -31,35 +31,11 @@ ExpressionLayout * BaselineRelativeLayout::indiceLayout() { } bool BaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { - // Case: Left of the indice. - // Go from the indice to the base. - if (m_indiceLayout - && cursor->pointedExpressionLayout() == m_indiceLayout - && cursor->position() == ExpressionLayoutCursor::Position::Left) - { - assert(m_baseLayout != nullptr); - cursor->setPointedExpressionLayout(m_baseLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - // Case: Left of the base. - // Ask the parent. - if (m_baseLayout - && cursor->pointedExpressionLayout() == m_baseLayout - && cursor->position() == ExpressionLayoutCursor::Position::Left) - { - cursor->setPointedExpressionLayout(this); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; - } assert(cursor->pointedExpressionLayout() == this); // Case: Right. - // Go to the indice. + // Go Left. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_indiceLayout != nullptr); - cursor->setPointedExpressionLayout(m_indiceLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } // Case: Left. diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index 029ed653f..ac3146b86 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -26,10 +26,10 @@ protected: KDSize computeSize() override; ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; -private: - constexpr static KDCoordinate k_indiceHeight = 5; ExpressionLayout * m_baseLayout; ExpressionLayout * m_indiceLayout; +private: + constexpr static KDCoordinate k_indiceHeight = 5; Type m_type; }; diff --git a/poincare/src/layout/editable_baseline_relative_layout.cpp b/poincare/src/layout/editable_baseline_relative_layout.cpp new file mode 100644 index 000000000..27c3988da --- /dev/null +++ b/poincare/src/layout/editable_baseline_relative_layout.cpp @@ -0,0 +1,50 @@ +#include "editable_baseline_relative_layout.h" +#include +#include +#include + +namespace Poincare { + +bool EditableBaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the indice. + // Go from the indice to the base. + if (m_indiceLayout + && cursor->pointedExpressionLayout() == m_indiceLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + assert(m_baseLayout != nullptr); + cursor->setPointedExpressionLayout(m_baseLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Left of the base. + // Ask the parent. + if (m_baseLayout + && cursor->pointedExpressionLayout() == m_baseLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the indice. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(m_indiceLayout); + return true; + } + // Case: Left. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +} + diff --git a/poincare/src/layout/editable_baseline_relative_layout.h b/poincare/src/layout/editable_baseline_relative_layout.h new file mode 100644 index 000000000..f390e1c77 --- /dev/null +++ b/poincare/src/layout/editable_baseline_relative_layout.h @@ -0,0 +1,16 @@ +#ifndef POINCARE_EDITABLE_BASELINE_RELATIVE_LAYOUT_H +#define POINCARE_EDITABLE_BASELINE_RELATIVE_LAYOUT_H + +#include "baseline_relative_layout.h" + +namespace Poincare { + +class EditableBaselineRelativeLayout : public BaselineRelativeLayout { +public: + using BaselineRelativeLayout::BaselineRelativeLayout; + bool moveLeft(ExpressionLayoutCursor * cursor) override; +}; + +} + +#endif From f49168d77910f4c3317c81efcd50613b0759c49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 15 Dec 2017 10:28:50 +0100 Subject: [PATCH 017/257] [poincare] Use editable String and BaselineRelative layouts. Change-Id: I978c4aa43772b294251b948fc20bb0d8b8b05a08 --- poincare/include/poincare/expression_layout.h | 2 +- poincare/src/complex.cpp | 12 ++++++------ poincare/src/decimal.cpp | 4 ++-- poincare/src/factorial.cpp | 4 ++-- poincare/src/integer.cpp | 4 ++-- poincare/src/layout/integral_layout.cpp | 4 ++-- poincare/src/layout_engine.cpp | 8 ++++---- poincare/src/logarithm.cpp | 6 +++--- poincare/src/opposite.cpp | 4 ++-- poincare/src/power.cpp | 4 ++-- poincare/src/store.cpp | 4 ++-- poincare/src/symbol.cpp | 7 ++++--- poincare/src/undefined.cpp | 4 ++-- 13 files changed, 34 insertions(+), 33 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 9bafc81ac..d2df7e271 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -21,13 +21,13 @@ public: /* Hierarchy */ void setParent(ExpressionLayout* parent); - virtual ExpressionLayout * child(uint16_t index) = 0; /* Tree navigation */ virtual bool moveLeft(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; + virtual ExpressionLayout * child(uint16_t index) = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; KDCoordinate m_baseline; ExpressionLayout * m_parent; diff --git a/poincare/src/complex.cpp b/poincare/src/complex.cpp index b11787250..af44cb656 100644 --- a/poincare/src/complex.cpp +++ b/poincare/src/complex.cpp @@ -6,8 +6,8 @@ extern "C" { #include } #include -#include "layout/string_layout.h" -#include "layout/baseline_relative_layout.h" +#include "layout/editable_string_layout.h" +#include "layout/editable_baseline_relative_layout.h" #include namespace Poincare { @@ -443,7 +443,7 @@ ExpressionLayout * Complex::createPolarLayout(Expression::FloatDisplayMode fl if (std::isnan(r()) || (std::isnan(th()) && r() != 0)) { numberOfCharInBase = convertFloatToText(NAN, bufferBase, PrintFloat::k_maxComplexBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode); - return new StringLayout(bufferBase, numberOfCharInBase); + return new EditableStringLayout(bufferBase, numberOfCharInBase); } if (r() != 1 || th() == 0) { numberOfCharInBase = convertFloatToText(r(), bufferBase, PrintFloat::k_maxFloatBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode); @@ -463,16 +463,16 @@ ExpressionLayout * Complex::createPolarLayout(Expression::FloatDisplayMode fl bufferSuperscript[numberOfCharInSuperscript] = 0; } if (numberOfCharInSuperscript == 0) { - return new StringLayout(bufferBase, numberOfCharInBase); + return new EditableStringLayout(bufferBase, numberOfCharInBase); } - return new BaselineRelativeLayout(new StringLayout(bufferBase, numberOfCharInBase), new StringLayout(bufferSuperscript, numberOfCharInSuperscript), BaselineRelativeLayout::Type::Superscript); + return new EditableBaselineRelativeLayout(new EditableStringLayout(bufferBase, numberOfCharInBase), new EditableStringLayout(bufferSuperscript, numberOfCharInSuperscript), BaselineRelativeLayout::Type::Superscript); } template ExpressionLayout * Complex::createCartesianLayout(Expression::FloatDisplayMode floatDisplayMode) const { char buffer[PrintFloat::k_maxComplexBufferLength]; int numberOfChars = convertComplexToText(buffer, PrintFloat::k_maxComplexBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode, Expression::ComplexFormat::Cartesian, Ion::Charset::MiddleDot); - return new StringLayout(buffer, numberOfChars); + return new EditableStringLayout(buffer, numberOfChars); } template class Complex; diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index d502e1d4e..400866c16 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -9,7 +9,7 @@ extern "C" { #include } -#include "layout/string_layout.h" +#include "layout/editable_string_layout.h" namespace Poincare { @@ -204,7 +204,7 @@ int Decimal::writeTextInBuffer(char * buffer, int bufferSize) const { ExpressionLayout * Decimal::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { char buffer[255]; int numberOfChars = writeTextInBuffer(buffer, 255); - return new StringLayout(buffer, numberOfChars); + return new EditableStringLayout(buffer, numberOfChars); } Expression * Decimal::shallowReduce(Context& context, AngleUnit angleUnit) { diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp index 097802b33..3f57bf154 100644 --- a/poincare/src/factorial.cpp +++ b/poincare/src/factorial.cpp @@ -1,5 +1,5 @@ #include -#include "layout/string_layout.h" +#include "layout/editable_string_layout.h" #include "layout/horizontal_layout.h" #include #include @@ -78,7 +78,7 @@ ExpressionLayout * Factorial::privateCreateLayout(FloatDisplayMode floatDisplayM assert(complexFormat != ComplexFormat::Default); ExpressionLayout * childrenLayouts[2]; childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat); - childrenLayouts[1] = new StringLayout("!", 1); + childrenLayouts[1] = new EditableStringLayout("!", 1); return new HorizontalLayout(childrenLayouts, 2); } diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index c8f713516..cb27eb6ef 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -6,7 +6,7 @@ extern "C" { } #include #include -#include "layout/string_layout.h" +#include "layout/editable_string_layout.h" #include namespace Poincare { @@ -618,7 +618,7 @@ int Integer::writeTextInBuffer(char * buffer, int bufferSize) const { ExpressionLayout * Integer::createLayout() const { char buffer[255]; int numberOfChars = writeTextInBuffer(buffer, 255); - return new StringLayout(buffer, numberOfChars); + return new EditableStringLayout(buffer, numberOfChars); } template float Poincare::Integer::approximate() const; diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 23470cd74..f4a594e85 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -65,8 +65,8 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go Right of the integrand, Left of "dx". if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(m_integrandLayout != nullptr); - cursor->setPointedExpressionLayout(m_integrandLayout->child(0)); - return true; + cursor->setPointedExpressionLayout(m_integrandLayout); + return m_integrandLayout->moveLeft(cursor); } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); // Case: Left of the brackets. diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index f5d6896b8..d35d010dc 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -1,5 +1,5 @@ #include -#include "layout/string_layout.h" +#include "layout/editable_string_layout.h" #include "layout/parenthesis_layout.h" #include "layout/horizontal_layout.h" extern "C" { @@ -16,7 +16,7 @@ ExpressionLayout * LayoutEngine::createInfixLayout(const Expression * expression ExpressionLayout** children_layouts = new ExpressionLayout * [2*numberOfOperands-1]; children_layouts[0] = expression->operand(0)->createLayout(); for (int i=1; ioperand(i)->type() == Expression::Type::Opposite ? new ParenthesisLayout(expression->operand(i)->createLayout(floatDisplayMode, complexFormat)) : expression->operand(i)->createLayout(floatDisplayMode, complexFormat); } /* HorizontalLayout holds the children layouts so they do not need to be @@ -34,7 +34,7 @@ ExpressionLayout * LayoutEngine::createPrefixLayout(const Expression * expressio int layoutIndex = 0; grandChildrenLayouts[layoutIndex++] = expression->operand(0)->createLayout(floatDisplayMode, complexFormat); for (int i = 1; i < numberOfOperands; i++) { - grandChildrenLayouts[layoutIndex++] = new StringLayout(",", 1); + grandChildrenLayouts[layoutIndex++] = new EditableStringLayout(",", 1); grandChildrenLayouts[layoutIndex++] = expression->operand(i)->createLayout(floatDisplayMode, complexFormat); } /* HorizontalLayout holds the grand children layouts so they do not need to @@ -42,7 +42,7 @@ ExpressionLayout * LayoutEngine::createPrefixLayout(const Expression * expressio ExpressionLayout * argumentLayouts = new HorizontalLayout(grandChildrenLayouts, 2*numberOfOperands-1); delete [] grandChildrenLayouts; ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = new StringLayout(operatorName, strlen(operatorName)); + childrenLayouts[0] = new EditableStringLayout(operatorName, strlen(operatorName)); childrenLayouts[1] = new ParenthesisLayout(argumentLayouts); /* Same comment as above */ return new HorizontalLayout(childrenLayouts, 2); diff --git a/poincare/src/logarithm.cpp b/poincare/src/logarithm.cpp index 5e6a19549..2b20d2e33 100644 --- a/poincare/src/logarithm.cpp +++ b/poincare/src/logarithm.cpp @@ -16,10 +16,10 @@ extern "C" { #include #include } -#include "layout/baseline_relative_layout.h" +#include "layout/editable_baseline_relative_layout.h" +#include "layout/editable_string_layout.h" #include "layout/horizontal_layout.h" #include "layout/parenthesis_layout.h" -#include "layout/string_layout.h" namespace Poincare { @@ -237,7 +237,7 @@ ExpressionLayout * Logarithm::privateCreateLayout(FloatDisplayMode floatDisplayM return LayoutEngine::createPrefixLayout(this, floatDisplayMode, complexFormat, "log"); } ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = new BaselineRelativeLayout(new StringLayout("log", strlen("log")), operand(1)->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Subscript); + childrenLayouts[0] = new EditableBaselineRelativeLayout(new EditableStringLayout("log", strlen("log")), operand(1)->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Subscript); childrenLayouts[1] = new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat)); return new HorizontalLayout(childrenLayouts, 2); } diff --git a/poincare/src/opposite.cpp b/poincare/src/opposite.cpp index aad66e0cf..08956ca2e 100644 --- a/poincare/src/opposite.cpp +++ b/poincare/src/opposite.cpp @@ -10,7 +10,7 @@ extern "C" { #include #include "layout/horizontal_layout.h" #include "layout/parenthesis_layout.h" -#include "layout/string_layout.h" +#include "layout/editable_string_layout.h" namespace Poincare { @@ -50,7 +50,7 @@ ExpressionLayout * Opposite::privateCreateLayout(FloatDisplayMode floatDisplayMo assert(complexFormat != ComplexFormat::Default); ExpressionLayout * children_layouts[2]; char string[2] = {'-', '\0'}; - children_layouts[0] = new StringLayout(string, 1); + children_layouts[0] = new EditableStringLayout(string, 1); children_layouts[1] = operand(0)->type() == Type::Opposite ? new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat)) : operand(0)->createLayout(floatDisplayMode, complexFormat); return new HorizontalLayout(children_layouts, 2); } diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 64b029aec..be426900f 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -21,7 +21,7 @@ extern "C" { #include #include #include -#include "layout/baseline_relative_layout.h" +#include "layout/editable_baseline_relative_layout.h" namespace Poincare { @@ -121,7 +121,7 @@ ExpressionLayout * Power::privateCreateLayout(FloatDisplayMode floatDisplayMode, if (m_operands[1]->type() == Type::Parenthesis) { indiceOperand = m_operands[1]->operand(0); } - return new BaselineRelativeLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat),indiceOperand->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Superscript); + return new EditableBaselineRelativeLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat),indiceOperand->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Superscript); } int Power::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const { diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index 34296a405..a3598228c 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -8,7 +8,7 @@ extern "C" { #include #include #include "layout/horizontal_layout.h" -#include "layout/string_layout.h" +#include "layout/editable_string_layout.h" namespace Poincare { @@ -31,7 +31,7 @@ ExpressionLayout * Store::privateCreateLayout(FloatDisplayMode floatDisplayMode, ExpressionLayout * childrenLayouts[3]; childrenLayouts[0] = value()->createLayout(floatDisplayMode, complexFormat); const char stoSymbol[2] = {Ion::Charset::Sto, 0}; - childrenLayouts[1] = new StringLayout(stoSymbol, 1); + childrenLayouts[1] = new EditableStringLayout(stoSymbol, 1); childrenLayouts[2] = symbol()->createLayout(floatDisplayMode, complexFormat); return new HorizontalLayout(childrenLayouts, 3); } diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 5d091721b..b3dc142cd 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -3,6 +3,7 @@ #include #include "layout/baseline_relative_layout.h" #include "layout/string_layout.h" +#include "layout/editable_string_layout.h" #include extern "C" { #include @@ -131,7 +132,7 @@ ExpressionLayout * Symbol::privateCreateLayout(FloatDisplayMode floatDisplayMode assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); if (m_name == SpecialSymbols::Ans) { - return new StringLayout("ans", 3); + return new EditableStringLayout("ans", 3); } if (m_name == SpecialSymbols::un) { return new BaselineRelativeLayout(new StringLayout("u", 1), new StringLayout("n",1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); @@ -147,9 +148,9 @@ ExpressionLayout * Symbol::privateCreateLayout(FloatDisplayMode floatDisplayMode } if (isMatrixSymbol()) { const char mi[] = { 'M', (char)(m_name-(char)SpecialSymbols::M0+'0') }; - return new StringLayout(mi, sizeof(mi)); + return new EditableStringLayout(mi, sizeof(mi)); } - return new StringLayout(&m_name, 1); + return new EditableStringLayout(&m_name, 1); } int Symbol::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/undefined.cpp b/poincare/src/undefined.cpp index 1fc6f27ad..36b55ff15 100644 --- a/poincare/src/undefined.cpp +++ b/poincare/src/undefined.cpp @@ -2,7 +2,7 @@ extern "C" { #include } -#include "layout/string_layout.h" +#include "layout/editable_string_layout.h" namespace Poincare { @@ -21,7 +21,7 @@ template Complex * Undefined::templatedApproximate(Context& conte ExpressionLayout * Undefined::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { char buffer[16]; int numberOfChars = Complex::convertFloatToText(NAN, buffer, 16, 1, floatDisplayMode); - return new StringLayout(buffer, numberOfChars); + return new EditableStringLayout(buffer, numberOfChars); } int Undefined::writeTextInBuffer(char * buffer, int bufferSize) const { From 8237bab64ff68a9899241853f31017f4e1efef23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 7 Dec 2017 11:50:19 +0100 Subject: [PATCH 018/257] [poincare] ParenthesisLeft and Right layouts. Change-Id: I13cdb59c8b0d7ec1cf773688edff37babb15f893 --- poincare/Makefile | 3 + poincare/src/layout/parenthesis_layout.cpp | 117 ++++++++---------- poincare/src/layout/parenthesis_layout.h | 5 +- .../src/layout/parenthesis_left_layout.cpp | 52 ++++++++ poincare/src/layout/parenthesis_left_layout.h | 19 +++ .../layout/parenthesis_left_right_layout.cpp | 43 +++++++ .../layout/parenthesis_left_right_layout.h | 33 +++++ .../src/layout/parenthesis_right_layout.cpp | 59 +++++++++ .../src/layout/parenthesis_right_layout.h | 19 +++ 9 files changed, 283 insertions(+), 67 deletions(-) create mode 100644 poincare/src/layout/parenthesis_left_layout.cpp create mode 100644 poincare/src/layout/parenthesis_left_layout.h create mode 100644 poincare/src/layout/parenthesis_left_right_layout.cpp create mode 100644 poincare/src/layout/parenthesis_left_right_layout.h create mode 100644 poincare/src/layout/parenthesis_right_layout.cpp create mode 100644 poincare/src/layout/parenthesis_right_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index 747065f8a..a5a5f5548 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -96,6 +96,9 @@ objs += $(addprefix poincare/src/layout/,\ integral_layout.o\ nth_root_layout.o\ parenthesis_layout.o\ + parenthesis_left_layout.o\ + parenthesis_left_right_layout.o\ + parenthesis_right_layout.o\ product_layout.o\ sequence_layout.o\ string_layout.o\ diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index d71ef1e22..ecd6d7cdd 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -1,5 +1,7 @@ #include "parenthesis_layout.h" #include +#include "parenthesis_left_layout.h" +#include "parenthesis_right_layout.h" extern "C" { #include #include @@ -7,64 +9,38 @@ extern "C" { namespace Poincare { -const uint8_t topLeftCurve[ParenthesisLayout::k_parenthesisCurveHeight][ParenthesisLayout::k_parenthesisCurveWidth] = { - {0xFF, 0xFF, 0xFF, 0xF9, 0x66}, - {0xFF, 0xFF, 0xEB, 0x40, 0x9A}, - {0xFF, 0xF2, 0x40, 0xBF, 0xFF}, - {0xFF, 0x49, 0xB6, 0xFF, 0xFF}, - {0xA9, 0x5A, 0xFF, 0xFF, 0xFF}, - {0x45, 0xBE, 0xFF, 0xFF, 0xFF}, - {0x11, 0xEE, 0xFF, 0xFF, 0xFF}, - -}; - -const uint8_t bottomLeftCurve[ParenthesisLayout::k_parenthesisCurveHeight][ParenthesisLayout::k_parenthesisCurveWidth] = { - {0x11, 0xEE, 0xFF, 0xFF, 0xFF}, - {0x45, 0xBE, 0xFF, 0xFF, 0xFF}, - {0xA9, 0x5A, 0xFF, 0xFF, 0xFF}, - {0xFF, 0x49, 0xB6, 0xFF, 0xFF}, - {0xFF, 0xF2, 0x40, 0xBF, 0xFF}, - {0xFF, 0xFF, 0xEB, 0x40, 0x9A}, - {0xFF, 0xFF, 0xFF, 0xF9, 0x66}, - -}; - -const uint8_t topRightCurve[ParenthesisLayout::k_parenthesisCurveHeight][ParenthesisLayout::k_parenthesisCurveWidth] = { - {0x66, 0xF9, 0xFF, 0xFF, 0xFF}, - {0x9A, 0x40, 0xEB, 0xFF, 0xFF}, - {0xFF, 0xBF, 0x40, 0xF2, 0xFF}, - {0xFF, 0xFF, 0xB6, 0x49, 0xFF}, - {0xFF, 0xFF, 0xFF, 0x5A, 0xA9}, - {0xFF, 0xFF, 0xFF, 0xBE, 0x45}, - {0xFF, 0xFF, 0xFF, 0xEE, 0x11}, -}; - -const uint8_t bottomRightCurve[ParenthesisLayout::k_parenthesisCurveHeight][ParenthesisLayout::k_parenthesisCurveWidth] = { - {0xFF, 0xFF, 0xFF, 0xEE, 0x11}, - {0xFF, 0xFF, 0xFF, 0xBE, 0x45}, - {0xFF, 0xFF, 0xFF, 0x5A, 0xA9}, - {0xFF, 0xFF, 0xB6, 0x49, 0xFF}, - {0xFF, 0xBF, 0x40, 0xF2, 0xFF}, - {0x9A, 0x40, 0xEB, 0xFF, 0xFF}, - {0x66, 0xF9, 0xFF, 0xFF, 0xFF}, - -}; - ParenthesisLayout::ParenthesisLayout(ExpressionLayout * operandLayout) : ExpressionLayout(), m_operandLayout(operandLayout) { + m_leftParenthesisLayout = new ParenthesisLeftLayout(); + m_rightParenthesisLayout = new ParenthesisRightLayout(); m_operandLayout->setParent(this); + m_leftParenthesisLayout->setParent(this); + m_rightParenthesisLayout->setParent(this); m_baseline = m_operandLayout->baseline(); } ParenthesisLayout::~ParenthesisLayout() { delete m_operandLayout; + delete m_rightParenthesisLayout; + delete m_leftParenthesisLayout; } bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the Right parenthesis. + // Go to the operand and move left. + if (m_rightParenthesisLayout + && cursor->pointedExpressionLayout() == m_rightParenthesisLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + assert(m_operandLayout != nullptr); + cursor->setPointedExpressionLayout(m_operandLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } // Case: Left of the operand. - // Go Left of the brackets. + // Go Left. if (m_operandLayout && cursor->pointedExpressionLayout() == m_operandLayout && cursor->position() == ExpressionLayoutCursor::Position::Left) @@ -72,6 +48,19 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { cursor->setPointedExpressionLayout(this); return true; } + // Case: Left of the Left parenthesis. + // Aske the parent. + if (m_leftParenthesisLayout + && cursor->pointedExpressionLayout() == m_leftParenthesisLayout + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } assert(cursor->pointedExpressionLayout() == this); // Case: Right of the parentheses. // Go Right of the operand. @@ -89,40 +78,36 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } -KDColor s_parenthesisWorkingBuffer[ParenthesisLayout::k_parenthesisCurveHeight*ParenthesisLayout::k_parenthesisCurveWidth]; - -void ParenthesisLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - KDSize operandSize = m_operandLayout->size(); - KDRect frame(p.x()+k_externWidthMargin, p.y()+k_externHeightMargin, k_parenthesisCurveWidth, k_parenthesisCurveHeight); - ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)topLeftCurve, (KDColor *)s_parenthesisWorkingBuffer); - frame = KDRect(p.x()+k_externWidthMargin, p.y() + operandSize.height() - k_parenthesisCurveHeight - k_externHeightMargin, - k_parenthesisCurveWidth, k_parenthesisCurveHeight); - ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)bottomLeftCurve, (KDColor *)s_parenthesisWorkingBuffer); - frame = KDRect(p.x()+k_externWidthMargin + operandSize.width() + 2*k_widthMargin + 2*k_lineThickness - k_parenthesisCurveWidth, p.y() + k_externHeightMargin, - k_parenthesisCurveWidth, k_parenthesisCurveHeight); - ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)topRightCurve, (KDColor *)s_parenthesisWorkingBuffer); - frame = KDRect(p.x() +k_externWidthMargin + operandSize.width() + 2*k_widthMargin + 2*k_lineThickness - k_parenthesisCurveWidth, p.y() + operandSize.height() - k_parenthesisCurveHeight - k_externHeightMargin, - k_parenthesisCurveWidth, k_parenthesisCurveHeight); - ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)bottomRightCurve, (KDColor *)s_parenthesisWorkingBuffer); - - ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y()+k_parenthesisCurveHeight+k_externHeightMargin, k_lineThickness, m_operandLayout->size().height() - 2*(k_parenthesisCurveHeight+k_externHeightMargin)), expressionColor); - ctx->fillRect(KDRect(p.x()+k_externWidthMargin+operandSize.width()+2*k_widthMargin+k_lineThickness, p.y()+k_parenthesisCurveHeight+2, k_lineThickness, m_operandLayout->size().height()- 2*(k_parenthesisCurveHeight+k_externHeightMargin)), expressionColor); -} - KDSize ParenthesisLayout::computeSize() { KDSize operandSize = m_operandLayout->size(); - return KDSize(operandSize.width() + 2*k_widthMargin + 2*k_lineThickness+2*k_externWidthMargin, operandSize.height()); + return KDSize(operandSize.width() + 2*m_leftParenthesisLayout->size().width(), operandSize.height()); } ExpressionLayout * ParenthesisLayout::child(uint16_t index) { if (index == 0) { + return m_leftParenthesisLayout; + } + if (index == 1) { return m_operandLayout; } + if (index == 2) { + return m_rightParenthesisLayout; + } return nullptr; } KDPoint ParenthesisLayout::positionOfChild(ExpressionLayout * child) { - return KDPoint(k_widthMargin+k_lineThickness+k_externWidthMargin, 0); + if (child == m_leftParenthesisLayout) { + return KDPoint(0, 0); + } + if (child == m_operandLayout) { + return KDPoint(m_leftParenthesisLayout->size().width(), 0); + } + if (child == m_rightParenthesisLayout) { + return KDPoint(m_operandLayout->origin().x() + m_operandLayout->size().width(), 0); + } + assert(false); + return KDPointZero; } } diff --git a/poincare/src/layout/parenthesis_layout.h b/poincare/src/layout/parenthesis_layout.h index 92f4892ed..e6fcab76a 100644 --- a/poincare/src/layout/parenthesis_layout.h +++ b/poincare/src/layout/parenthesis_layout.h @@ -18,7 +18,8 @@ public: constexpr static KDCoordinate k_parenthesisCurveHeight = 7; bool moveLeft(ExpressionLayoutCursor * cursor) override; protected: - void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { + }; KDSize computeSize() override; ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; @@ -28,6 +29,8 @@ private: constexpr static KDCoordinate k_widthMargin = 5; constexpr static KDCoordinate k_lineThickness = 1; ExpressionLayout * m_operandLayout; + ExpressionLayout * m_leftParenthesisLayout; + ExpressionLayout * m_rightParenthesisLayout; }; } diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp new file mode 100644 index 000000000..807927588 --- /dev/null +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -0,0 +1,52 @@ +#include "parenthesis_left_layout.h" +extern "C" { +#include +#include +} + +namespace Poincare { + +const uint8_t topLeftCurve[ParenthesisLeftRightLayout::k_parenthesisCurveHeight][ParenthesisLeftRightLayout::k_parenthesisCurveWidth] = { + {0xFF, 0xFF, 0xFF, 0xF9, 0x66}, + {0xFF, 0xFF, 0xEB, 0x40, 0x9A}, + {0xFF, 0xF2, 0x40, 0xBF, 0xFF}, + {0xFF, 0x49, 0xB6, 0xFF, 0xFF}, + {0xA9, 0x5A, 0xFF, 0xFF, 0xFF}, + {0x45, 0xBE, 0xFF, 0xFF, 0xFF}, + {0x11, 0xEE, 0xFF, 0xFF, 0xFF}, +}; + +const uint8_t bottomLeftCurve[ParenthesisLeftRightLayout::k_parenthesisCurveHeight][ParenthesisLeftRightLayout::k_parenthesisCurveWidth] = { + {0x11, 0xEE, 0xFF, 0xFF, 0xFF}, + {0x45, 0xBE, 0xFF, 0xFF, 0xFF}, + {0xA9, 0x5A, 0xFF, 0xFF, 0xFF}, + {0xFF, 0x49, 0xB6, 0xFF, 0xFF}, + {0xFF, 0xF2, 0x40, 0xBF, 0xFF}, + {0xFF, 0xFF, 0xEB, 0x40, 0x9A}, + {0xFF, 0xFF, 0xFF, 0xF9, 0x66}, +}; + +void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + //TODO Make sure m_operandHeight is up-to-date. + KDRect frame(p.x()+ParenthesisLeftRightLayout::k_externWidthMargin, + p.y()+ParenthesisLeftRightLayout::k_externHeightMargin, + ParenthesisLeftRightLayout::k_parenthesisCurveWidth, + ParenthesisLeftRightLayout::k_parenthesisCurveHeight); + + ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)topLeftCurve, (KDColor *)(ParenthesisLeftRightLayout::s_parenthesisWorkingBuffer)); + + frame = KDRect(p.x()+ParenthesisLeftRightLayout::k_externWidthMargin, + p.y() + m_operandHeight - ParenthesisLeftRightLayout::k_parenthesisCurveHeight - ParenthesisLeftRightLayout::k_externHeightMargin, + ParenthesisLeftRightLayout::k_parenthesisCurveWidth, + ParenthesisLeftRightLayout::k_parenthesisCurveHeight); + + ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)bottomLeftCurve, (KDColor *)(ParenthesisLeftRightLayout::s_parenthesisWorkingBuffer)); + + ctx->fillRect(KDRect(p.x()+ParenthesisLeftRightLayout::k_externWidthMargin, + p.y()+ParenthesisLeftRightLayout::k_parenthesisCurveHeight+ParenthesisLeftRightLayout::k_externHeightMargin, + ParenthesisLeftRightLayout::k_lineThickness, + m_operandHeight - 2*(ParenthesisLeftRightLayout::k_parenthesisCurveHeight+ParenthesisLeftRightLayout::k_externHeightMargin)), + expressionColor); +} + +} diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h new file mode 100644 index 000000000..32796d8c3 --- /dev/null +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -0,0 +1,19 @@ +#ifndef POINCARE_PARENTHESIS_LEFT_LAYOUT_H +#define POINCARE_PARENTHESIS_LEFT_LAYOUT_H + +#include +#include +#include + +namespace Poincare { + +class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { +public: + using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; +}; + +} + +#endif diff --git a/poincare/src/layout/parenthesis_left_right_layout.cpp b/poincare/src/layout/parenthesis_left_right_layout.cpp new file mode 100644 index 000000000..7b7ae1e88 --- /dev/null +++ b/poincare/src/layout/parenthesis_left_right_layout.cpp @@ -0,0 +1,43 @@ +#include "parenthesis_left_right_layout.h" +#include +extern "C" { +#include +#include +} + +namespace Poincare { + +ParenthesisLeftRightLayout::ParenthesisLeftRightLayout() : + ExpressionLayout(), + m_operandHeight(36) //TODO +{ +} + +bool ParenthesisLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +KDSize ParenthesisLeftRightLayout::computeSize() { + //TODO: compute the operandHeight according to the brothers + return KDSize(k_widthMargin + k_lineThickness + k_externWidthMargin, m_operandHeight); +} + +KDPoint ParenthesisLeftRightLayout::positionOfChild(ExpressionLayout * child) { + assert(false); + return KDPointZero; +} + +} diff --git a/poincare/src/layout/parenthesis_left_right_layout.h b/poincare/src/layout/parenthesis_left_right_layout.h new file mode 100644 index 000000000..a2496e22c --- /dev/null +++ b/poincare/src/layout/parenthesis_left_right_layout.h @@ -0,0 +1,33 @@ +#ifndef POINCARE_PARENTHESIS_LEFT_RIGHT_LAYOUT_H +#define POINCARE_PARENTHESIS_LEFT_RIGHT_LAYOUT_H + +#include +#include + +namespace Poincare { + +class ParenthesisLeftRightLayout : public ExpressionLayout { +public: + ParenthesisLeftRightLayout(); + ~ParenthesisLeftRightLayout() {} + ParenthesisLeftRightLayout(const ParenthesisLeftRightLayout& other) = delete; + ParenthesisLeftRightLayout(ParenthesisLeftRightLayout&& other) = delete; + ParenthesisLeftRightLayout& operator=(const ParenthesisLeftRightLayout& other) = delete; + ParenthesisLeftRightLayout& operator=(ParenthesisLeftRightLayout&& other) = delete; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + constexpr static KDCoordinate k_parenthesisCurveWidth = 5; + constexpr static KDCoordinate k_parenthesisCurveHeight = 7; + constexpr static KDCoordinate k_externWidthMargin = 1; + constexpr static KDCoordinate k_externHeightMargin = 2; + constexpr static KDCoordinate k_widthMargin = 5; + constexpr static KDCoordinate k_lineThickness = 1; +protected: + KDColor s_parenthesisWorkingBuffer[k_parenthesisCurveHeight*k_parenthesisCurveWidth]; + KDSize computeSize() override; + ExpressionLayout * child(uint16_t index) override { return nullptr; } + KDPoint positionOfChild(ExpressionLayout * child) override; + uint16_t m_operandHeight; +}; +} + +#endif diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp new file mode 100644 index 000000000..0a9a3af60 --- /dev/null +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -0,0 +1,59 @@ +#include "parenthesis_right_layout.h" +extern "C" { +#include +#include +} + +namespace Poincare { + +const uint8_t topRightCurve[ParenthesisLeftRightLayout::k_parenthesisCurveHeight][ParenthesisLeftRightLayout::k_parenthesisCurveWidth] = { + {0x66, 0xF9, 0xFF, 0xFF, 0xFF}, + {0x9A, 0x40, 0xEB, 0xFF, 0xFF}, + {0xFF, 0xBF, 0x40, 0xF2, 0xFF}, + {0xFF, 0xFF, 0xB6, 0x49, 0xFF}, + {0xFF, 0xFF, 0xFF, 0x5A, 0xA9}, + {0xFF, 0xFF, 0xFF, 0xBE, 0x45}, + {0xFF, 0xFF, 0xFF, 0xEE, 0x11}, +}; + +const uint8_t bottomRightCurve[ParenthesisLeftRightLayout::k_parenthesisCurveHeight][ParenthesisLeftRightLayout::k_parenthesisCurveWidth] = { + {0xFF, 0xFF, 0xFF, 0xEE, 0x11}, + {0xFF, 0xFF, 0xFF, 0xBE, 0x45}, + {0xFF, 0xFF, 0xFF, 0x5A, 0xA9}, + {0xFF, 0xFF, 0xB6, 0x49, 0xFF}, + {0xFF, 0xBF, 0x40, 0xF2, 0xFF}, + {0x9A, 0x40, 0xEB, 0xFF, 0xFF}, + {0x66, 0xF9, 0xFF, 0xFF, 0xFF}, +}; + +void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + //TODO Make sure m_operandHeight is up-to-date. + KDRect frame = KDRect(p.x() + ParenthesisLeftRightLayout::k_widthMargin + ParenthesisLeftRightLayout::k_lineThickness - ParenthesisLeftRightLayout::k_parenthesisCurveWidth, + p.y() + ParenthesisLeftRightLayout::k_externHeightMargin, + ParenthesisLeftRightLayout::k_parenthesisCurveWidth, + ParenthesisLeftRightLayout::k_parenthesisCurveHeight); + + ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)topRightCurve, (KDColor *)(ParenthesisLeftRightLayout::s_parenthesisWorkingBuffer)); + + frame = KDRect(p.x() + ParenthesisLeftRightLayout::k_widthMargin + ParenthesisLeftRightLayout::k_lineThickness - ParenthesisLeftRightLayout::k_parenthesisCurveWidth, + p.y() + m_operandHeight - ParenthesisLeftRightLayout::k_parenthesisCurveHeight - ParenthesisLeftRightLayout::k_externHeightMargin, + ParenthesisLeftRightLayout::k_parenthesisCurveWidth, + ParenthesisLeftRightLayout::k_parenthesisCurveHeight); + + ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)bottomRightCurve, (KDColor *)(ParenthesisLeftRightLayout::s_parenthesisWorkingBuffer)); + + ctx->fillRect(KDRect(p.x()+ParenthesisLeftRightLayout::k_widthMargin, + p.y()+ParenthesisLeftRightLayout::k_parenthesisCurveHeight+2, + ParenthesisLeftRightLayout::k_lineThickness, + m_operandHeight - 2*(ParenthesisLeftRightLayout::k_parenthesisCurveHeight+ParenthesisLeftRightLayout::k_externHeightMargin)), + expressionColor); +} + +} + + + + + + + diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h new file mode 100644 index 000000000..efb98763b --- /dev/null +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -0,0 +1,19 @@ +#ifndef POINCARE_PARENTHESIS_RIGHT_LAYOUT_H +#define POINCARE_PARENTHESIS_RIGHT_LAYOUT_H + +#include +#include +#include + +namespace Poincare { + +class ParenthesisRightLayout : public ParenthesisLeftRightLayout { +public: + using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; +}; + +} + +#endif From ab81f74bbf12da53d1e36620f9affaa3d2a88a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 15 Dec 2017 12:04:19 +0100 Subject: [PATCH 019/257] [poincare] Bracket Left and Right layouts. Change-Id: I05987e837324628b5141b31d01f59c88ae5ff3ce --- poincare/Makefile | 3 ++ poincare/src/layout/bracket_left_layout.cpp | 12 ++++++ poincare/src/layout/bracket_left_layout.h | 17 ++++++++ .../src/layout/bracket_left_right_layout.cpp | 43 +++++++++++++++++++ .../src/layout/bracket_left_right_layout.h | 30 +++++++++++++ poincare/src/layout/bracket_right_layout.cpp | 19 ++++++++ poincare/src/layout/bracket_right_layout.h | 17 ++++++++ 7 files changed, 141 insertions(+) create mode 100644 poincare/src/layout/bracket_left_layout.cpp create mode 100644 poincare/src/layout/bracket_left_layout.h create mode 100644 poincare/src/layout/bracket_left_right_layout.cpp create mode 100644 poincare/src/layout/bracket_left_right_layout.h create mode 100644 poincare/src/layout/bracket_right_layout.cpp create mode 100644 poincare/src/layout/bracket_right_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index a5a5f5548..c778125ba 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -85,6 +85,9 @@ objs += $(addprefix poincare/src/,\ objs += $(addprefix poincare/src/layout/,\ baseline_relative_layout.o\ bracket_layout.o\ + bracket_left_layout.o\ + bracket_left_right_layout.o\ + bracket_right_layout.o\ condensed_sum_layout.o\ conjugate_layout.o\ editable_baseline_relative_layout.o\ diff --git a/poincare/src/layout/bracket_left_layout.cpp b/poincare/src/layout/bracket_left_layout.cpp new file mode 100644 index 000000000..f9024923e --- /dev/null +++ b/poincare/src/layout/bracket_left_layout.cpp @@ -0,0 +1,12 @@ +#include "bracket_left_layout.h" + +namespace Poincare { + +void BracketLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + //TODO Make sure m_operandHeight is up-to-date. + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_lineThickness, m_operandHeight), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y() + m_operandHeight, k_bracketWidth, k_lineThickness), expressionColor); +} + +} diff --git a/poincare/src/layout/bracket_left_layout.h b/poincare/src/layout/bracket_left_layout.h new file mode 100644 index 000000000..ce025ec99 --- /dev/null +++ b/poincare/src/layout/bracket_left_layout.h @@ -0,0 +1,17 @@ +#ifndef POINCARE_BRACKET_LEFT_LAYOUT_H +#define POINCARE_BRACKET_LEFT_LAYOUT_H + +#include + +namespace Poincare { + +class BracketLeftLayout : public BracketLeftRightLayout { +public: + using BracketLeftRightLayout::BracketLeftRightLayout; +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; +}; + +} + +#endif diff --git a/poincare/src/layout/bracket_left_right_layout.cpp b/poincare/src/layout/bracket_left_right_layout.cpp new file mode 100644 index 000000000..44c6eaa79 --- /dev/null +++ b/poincare/src/layout/bracket_left_right_layout.cpp @@ -0,0 +1,43 @@ +#include "bracket_left_right_layout.h" +#include +extern "C" { +#include +#include +} + +namespace Poincare { + +BracketLeftRightLayout::BracketLeftRightLayout() : + ExpressionLayout(), + m_operandHeight(36) //TODO +{ +} + +bool BracketLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +KDSize BracketLeftRightLayout::computeSize() { + //TODO: compute the operandHeight according to the brothers + return KDSize(k_externWidthMargin + k_lineThickness + k_bracketWidth + k_widthMargin, m_operandHeight); +} + +KDPoint BracketLeftRightLayout::positionOfChild(ExpressionLayout * child) { + assert(false); + return KDPointZero; +} + +} diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h new file mode 100644 index 000000000..e65a4d446 --- /dev/null +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -0,0 +1,30 @@ +#ifndef POINCARE_BRACKET_LEFT_RIGHT_LAYOUT_H +#define POINCARE_BRACKET_LEFT_RIGHT_LAYOUT_H + +#include +#include + +namespace Poincare { + +class BracketLeftRightLayout : public ExpressionLayout { +public: + BracketLeftRightLayout(); + ~BracketLeftRightLayout() {} + BracketLeftRightLayout(const BracketLeftRightLayout& other) = delete; + BracketLeftRightLayout(BracketLeftRightLayout&& other) = delete; + BracketLeftRightLayout& operator=(const BracketLeftRightLayout& other) = delete; + BracketLeftRightLayout& operator=(BracketLeftRightLayout&& other) = delete; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + constexpr static KDCoordinate k_bracketWidth = 5; + constexpr static KDCoordinate k_lineThickness = 1; + constexpr static KDCoordinate k_widthMargin = 5; + constexpr static KDCoordinate k_externWidthMargin = 2; +protected: + KDSize computeSize() override; + ExpressionLayout * child(uint16_t index) override { return nullptr; } + KDPoint positionOfChild(ExpressionLayout * child) override; + uint16_t m_operandHeight; +}; +} + +#endif diff --git a/poincare/src/layout/bracket_right_layout.cpp b/poincare/src/layout/bracket_right_layout.cpp new file mode 100644 index 000000000..3eac6ba5e --- /dev/null +++ b/poincare/src/layout/bracket_right_layout.cpp @@ -0,0 +1,19 @@ +#include "bracket_right_layout.h" + +namespace Poincare { + +void BracketRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + //TODO Make sure m_operandHeight is up-to-date. + ctx->fillRect(KDRect(p.x()+k_widthMargin, p.y(), k_lineThickness, m_operandHeight), expressionColor); + ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth, p.y(), k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth, p.y() + m_operandHeight, k_bracketWidth, k_lineThickness), expressionColor); +} + +} + + + + + + + diff --git a/poincare/src/layout/bracket_right_layout.h b/poincare/src/layout/bracket_right_layout.h new file mode 100644 index 000000000..a9d9c7c79 --- /dev/null +++ b/poincare/src/layout/bracket_right_layout.h @@ -0,0 +1,17 @@ +#ifndef POINCARE_BRACKET_RIGHT_LAYOUT_H +#define POINCARE_BRACKET_RIGHT_LAYOUT_H + +#include + +namespace Poincare { + +class BracketRightLayout : public BracketLeftRightLayout { +public: + using BracketLeftRightLayout::BracketLeftRightLayout; +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; +}; + +} + +#endif From 29e549d475abef85cac9b3f9991f34a4616e3234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 15 Dec 2017 14:49:37 +0100 Subject: [PATCH 020/257] [expression_editor/poincare] Move Right in an ExpressionLayout. Change-Id: Ib5f018666350d6bb061272ae7b04b6f721d50e84 --- poincare/include/poincare/expression_layout.h | 1 + poincare/src/expression_layout_cursor.cpp | 2 +- .../src/layout/baseline_relative_layout.cpp | 17 +++++++ .../src/layout/baseline_relative_layout.h | 1 + poincare/src/layout/bracket_layout.cpp | 28 ++++++++++ poincare/src/layout/bracket_layout.h | 1 + .../src/layout/bracket_left_right_layout.cpp | 18 +++++++ .../src/layout/bracket_left_right_layout.h | 1 + poincare/src/layout/condensed_sum_layout.cpp | 42 +++++++++++++++ poincare/src/layout/condensed_sum_layout.h | 1 + poincare/src/layout/conjugate_layout.cpp | 30 +++++++++++ poincare/src/layout/conjugate_layout.h | 1 + .../editable_baseline_relative_layout.cpp | 40 +++++++++++++++ .../editable_baseline_relative_layout.h | 1 + .../src/layout/editable_string_layout.cpp | 42 +++++++++++++++ poincare/src/layout/editable_string_layout.h | 1 + poincare/src/layout/fraction_layout.cpp | 27 ++++++++++ poincare/src/layout/fraction_layout.h | 1 + poincare/src/layout/grid_layout.cpp | 42 +++++++++++++++ poincare/src/layout/grid_layout.h | 2 + poincare/src/layout/horizontal_layout.cpp | 47 +++++++++++++++++ poincare/src/layout/horizontal_layout.h | 1 + poincare/src/layout/integral_layout.cpp | 40 +++++++++++++++ poincare/src/layout/integral_layout.h | 1 + poincare/src/layout/nth_root_layout.cpp | 42 +++++++++++++++ poincare/src/layout/nth_root_layout.h | 1 + poincare/src/layout/parenthesis_layout.cpp | 51 +++++++++++++++++++ poincare/src/layout/parenthesis_layout.h | 1 + .../layout/parenthesis_left_right_layout.cpp | 17 +++++++ .../layout/parenthesis_left_right_layout.h | 1 + poincare/src/layout/sequence_layout.cpp | 43 ++++++++++++++++ poincare/src/layout/sequence_layout.h | 1 + poincare/src/layout/string_layout.cpp | 17 +++++++ poincare/src/layout/string_layout.h | 1 + 34 files changed, 562 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index d2df7e271..2f49c2b8e 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -24,6 +24,7 @@ public: /* Tree navigation */ virtual bool moveLeft(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? + virtual bool moveRight(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index ce5468741..17c38ae12 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -7,7 +7,7 @@ bool ExpressionLayoutCursor::moveLeft() { } bool ExpressionLayoutCursor::moveRight() { - return false; //TODO + return m_pointedExpressionLayout->moveRight(this); } bool ExpressionLayoutCursor::moveUp() { diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index 80cf27596..4b553d116 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -47,6 +47,23 @@ bool BaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool BaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Right. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + void BaselineRelativeLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // There is nothing to draw for a subscript/superscript, only the position of the children matters } diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index ac3146b86..d88e26708 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -21,6 +21,7 @@ public: ExpressionLayout * baseLayout(); ExpressionLayout * indiceLayout(); bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index c185fff75..1b369ec5a 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -46,6 +46,34 @@ bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the operand. + // Go Right of the brackets. + if (m_operandLayout + && cursor->pointedExpressionLayout() == m_operandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left of the brackets. + // Go Left of the operand. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(m_operandLayout != nullptr); + cursor->setPointedExpressionLayout(m_operandLayout); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right of the brackets. + // Ask the parent. + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + void BracketLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { const KDCoordinate k_widthMargin = widthMargin(); const KDCoordinate k_externWidthMargin = externWidthMargin(); diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index f110789aa..e2f6c926b 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -15,6 +15,7 @@ public: BracketLayout& operator=(const BracketLayout& other) = delete; BracketLayout& operator=(BracketLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: KDCoordinate externWidthMargin() const { return 2; } virtual KDCoordinate widthMargin() const { return 5; } diff --git a/poincare/src/layout/bracket_left_right_layout.cpp b/poincare/src/layout/bracket_left_right_layout.cpp index 44c6eaa79..95c26bade 100644 --- a/poincare/src/layout/bracket_left_right_layout.cpp +++ b/poincare/src/layout/bracket_left_right_layout.cpp @@ -30,6 +30,24 @@ bool BracketLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool BracketLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + + KDSize BracketLeftRightLayout::computeSize() { //TODO: compute the operandHeight according to the brothers return KDSize(k_externWidthMargin + k_lineThickness + k_bracketWidth + k_widthMargin, m_operandHeight); diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h index e65a4d446..6cc309184 100644 --- a/poincare/src/layout/bracket_left_right_layout.h +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -15,6 +15,7 @@ public: BracketLeftRightLayout& operator=(const BracketLeftRightLayout& other) = delete; BracketLeftRightLayout& operator=(BracketLeftRightLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; constexpr static KDCoordinate k_bracketWidth = 5; constexpr static KDCoordinate k_lineThickness = 1; constexpr static KDCoordinate k_widthMargin = 5; diff --git a/poincare/src/layout/condensed_sum_layout.cpp b/poincare/src/layout/condensed_sum_layout.cpp index 0a74eece4..401c684af 100644 --- a/poincare/src/layout/condensed_sum_layout.cpp +++ b/poincare/src/layout/condensed_sum_layout.cpp @@ -66,6 +66,48 @@ bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the bounds. + // Go Left of the operand. + if (((m_subscriptLayout && cursor->pointedExpressionLayout() == m_subscriptLayout) + || (m_superscriptLayout && cursor->pointedExpressionLayout() == m_superscriptLayout)) + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + assert(m_baseLayout != nullptr); + cursor->setPointedExpressionLayout(m_baseLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Right of the base. + // Ask the parent. + if (m_baseLayout + && cursor->pointedExpressionLayout() == m_baseLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go to the upper bound. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(m_superscriptLayout); + cursor->setPointedExpressionLayout(m_superscriptLayout); + return true; + } + // Case: Right. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + void CondensedSumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // Nothing to draw } diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index fce1333c3..6e9ae9dd2 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -15,6 +15,7 @@ public: CondensedSumLayout& operator=(const CondensedSumLayout& other) = delete; CondensedSumLayout& operator=(CondensedSumLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index fc83bc45b..18844c96f 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -49,6 +49,36 @@ bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the operand. + // Ask the parent. + if (m_operandLayout + && cursor->pointedExpressionLayout() == m_operandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go to the operand and move Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(m_operandLayout != nullptr); + cursor->setPointedExpressionLayout(m_operandLayout); + return m_operandLayout->moveRight(cursor); + } + // Case: Right. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + void ConjugateLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { ctx->fillRect(KDRect(p.x(), p.y(), m_operandLayout->size().width(), k_overlineWidth), expressionColor); } diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 4d6eacf8c..6e1030c88 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -15,6 +15,7 @@ public: ConjugateLayout& operator=(const ConjugateLayout& other) = delete; ConjugateLayout& operator=(ConjugateLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/editable_baseline_relative_layout.cpp b/poincare/src/layout/editable_baseline_relative_layout.cpp index 27c3988da..f217e8a33 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.cpp +++ b/poincare/src/layout/editable_baseline_relative_layout.cpp @@ -46,5 +46,45 @@ bool EditableBaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool EditableBaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the base. + // Go from the base to the indice. + if (m_baseLayout + && cursor->pointedExpressionLayout() == m_baseLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(m_indiceLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Right of the indice. + // Go Right. + if (m_indiceLayout + && cursor->pointedExpressionLayout() == m_indiceLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go to the base and move Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(m_baseLayout != nullptr); + cursor->setPointedExpressionLayout(m_baseLayout); + return m_baseLayout->moveRight(cursor); + } + // Case: Right. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + + } diff --git a/poincare/src/layout/editable_baseline_relative_layout.h b/poincare/src/layout/editable_baseline_relative_layout.h index f390e1c77..9839e8628 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.h +++ b/poincare/src/layout/editable_baseline_relative_layout.h @@ -9,6 +9,7 @@ class EditableBaselineRelativeLayout : public BaselineRelativeLayout { public: using BaselineRelativeLayout::BaselineRelativeLayout; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; }; } diff --git a/poincare/src/layout/editable_string_layout.cpp b/poincare/src/layout/editable_string_layout.cpp index e06ab544a..98f085fff 100644 --- a/poincare/src/layout/editable_string_layout.cpp +++ b/poincare/src/layout/editable_string_layout.cpp @@ -47,4 +47,46 @@ bool EditableStringLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool EditableStringLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go after the first char. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + size_t stringLength = strlen(m_string); + if (stringLength > 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Inside); + cursor->setPositionInside(1); + return true; + } + if (stringLength == 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(stringLength == 0); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; + } + // Case: Inside. + // Go one char right. + if (cursor->position() == ExpressionLayoutCursor::Position::Inside) { + int cursorIndex = cursor->positionInside(); + assert(cursorIndex > 0 && cursorIndex < strlen(m_string)); + if (cursorIndex == strlen(m_string)-1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + cursor->setPositionInside(cursorIndex + 1); + return true; + } + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + } diff --git a/poincare/src/layout/editable_string_layout.h b/poincare/src/layout/editable_string_layout.h index 23e92bc65..92e0e9730 100644 --- a/poincare/src/layout/editable_string_layout.h +++ b/poincare/src/layout/editable_string_layout.h @@ -10,6 +10,7 @@ class EditableStringLayout : public StringLayout { public: using StringLayout::StringLayout; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; }; } diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 01ce02e87..5f7a0043a 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -45,6 +45,33 @@ bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool FractionLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the numerator or the denominator. + // Go Right of the fraction. + if (((m_numerator_layout && cursor->pointedExpressionLayout() == m_numerator_layout) + || (m_denominator_layout && cursor->pointedExpressionLayout() == m_denominator_layout)) + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go to the numerator. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(m_numerator_layout != nullptr); + cursor->setPointedExpressionLayout(m_numerator_layout); + return true; + } + // Case: Right. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + void FractionLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDCoordinate fractionLineY = p.y() + m_numerator_layout->size().height() + k_fractionLineMargin; ctx->fillRect(KDRect(p.x()+k_fractionBorderMargin, fractionLineY, size().width()-2*k_fractionBorderMargin, 1), expressionColor); diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 355f5c44b..8f777040e 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -15,6 +15,7 @@ public: FractionLayout& operator=(const FractionLayout& other) = delete; FractionLayout& operator=(FractionLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 79e91f4e9..6df7a62b3 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -63,6 +63,43 @@ bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool GridLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Left. + // Go to the first entry. + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + assert(m_numberOfColumns*m_numberOfRows >= 1); + ExpressionLayout * firstChild = m_entryLayouts[0]; + assert(firstChild != nullptr); + cursor->setPointedExpressionLayout(firstChild); + return true; + } + // Case: The cursor points to a grid's child. + int childIndex = indexOfChild(cursor->pointedExpressionLayout()); + if (childIndex >- 1 && cursor->position() == ExpressionLayoutCursor::Position::Right) { + if (childIsRightOfGrid(childIndex)) { + // Case: Right of a child on the right of the grid. + // Go Right of the grid. + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Right of another child. + // Go Left of its brother on the right. + cursor->setPointedExpressionLayout(m_entryLayouts[childIndex+1]); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + KDCoordinate GridLayout::rowBaseline(int i) { KDCoordinate rowBaseline = 0; for (int j = 0; j < m_numberOfColumns; j++) { @@ -159,5 +196,10 @@ bool GridLayout::childIsLeftOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); return (index - m_numberOfColumns * (int)(index / m_numberOfColumns)) == 0; } +bool GridLayout::childIsRightOfGrid(int index) const { + assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); + return (index - m_numberOfColumns * (int)(index / m_numberOfColumns)) == m_numberOfColumns - 1; +} + } diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 7e5de435e..0cab38840 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -16,6 +16,7 @@ public: GridLayout& operator=(const GridLayout& other) = delete; GridLayout& operator=(GridLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; @@ -30,6 +31,7 @@ private: KDCoordinate width(); int indexOfChild(ExpressionLayout * eL) const; bool childIsLeftOfGrid(int index) const; + bool childIsRightOfGrid(int index) const; ExpressionLayout ** m_entryLayouts; int m_numberOfRows; int m_numberOfColumns; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 63d1e1a9e..429931df8 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -77,6 +77,53 @@ bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { return m_children_layouts[childIndex-1]->moveLeft(cursor); } +bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right. + // Ask the parent. + if (cursor->pointedExpressionLayout() == this) { + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left. + // Go to the first child if there is one, and move Right. + // Else go Right and ask the parent. + if (m_number_of_children < 1) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; + } + ExpressionLayout * firstChild = m_children_layouts[0]; + assert(firstChild != nullptr); + cursor->setPointedExpressionLayout(firstChild); + return firstChild->moveRight(cursor); + } + + // Case: The cursor is Right of a child. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + int childIndex = indexOfChild(cursor->pointedExpressionLayout()); + assert(childIndex >= 0); + if (childIndex == m_number_of_children - 1) { + // Case: the child is the rightmost. + // Ask the parent. + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; + } + // Case: the child is not the rightmost. + // Go to its right brother and move Right. + cursor->setPointedExpressionLayout(m_children_layouts[childIndex+1]); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return m_children_layouts[childIndex+1]->moveRight(cursor); +} + void HorizontalLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 55f8dd279..c081589fb 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -15,6 +15,7 @@ public: HorizontalLayout& operator=(const HorizontalLayout& other) = delete; HorizontalLayout& operator=(HorizontalLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index f4a594e85..1ce316836 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -77,6 +77,46 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right the upper or lower bound. + // Go Left of the integrand. + if (((m_upperBoundLayout + && cursor->pointedExpressionLayout() == m_upperBoundLayout) + || (m_lowerBoundLayout + && cursor->pointedExpressionLayout() == m_lowerBoundLayout)) + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + assert(m_integrandLayout != nullptr); + cursor->setPointedExpressionLayout(m_integrandLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Right the integrand. + // Go Right and move Right. + if (m_integrandLayout + && cursor->pointedExpressionLayout() == m_integrandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + return m_parent->moveRight(cursor); + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left of the integral. + // Go ti the upper bound. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(m_upperBoundLayout != nullptr); + cursor->setPointedExpressionLayout(m_upperBoundLayout); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize integrandSize = m_integrandLayout->size(); KDSize upperBoundSize = m_upperBoundLayout->size(); diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index abf47ff33..0a3ad388d 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -17,6 +17,7 @@ public: constexpr static KDCoordinate k_symbolHeight = 4; constexpr static KDCoordinate k_symbolWidth = 4; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 9fda611b8..0e8727fba 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -79,6 +79,48 @@ bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the radicand. + // Go the Right of the root. + if (m_radicandLayout + && cursor->pointedExpressionLayout() == m_radicandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + return true; + } + // Case: Right of the index. + // Go Left of the integrand. + if (m_indexLayout + && cursor->pointedExpressionLayout() == m_indexLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + assert(m_radicandLayout != nullptr); + cursor->setPointedExpressionLayout(m_radicandLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go index if there is one, else go to the radicand. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + if (m_indexLayout) { + cursor->setPointedExpressionLayout(m_indexLayout); + return true; + } + assert(m_radicandLayout != nullptr); + cursor->setPointedExpressionLayout(m_radicandLayout); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize radicandSize = m_radicandLayout->size(); KDSize indexSize = m_indexLayout != nullptr ? m_indexLayout->size() : KDSize(k_leftRadixWidth,0); diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index ade120681..b4727b531 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -17,6 +17,7 @@ public: constexpr static KDCoordinate k_leftRadixHeight = 8; constexpr static KDCoordinate k_leftRadixWidth = 5; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index ecd6d7cdd..56a50ed51 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -78,6 +78,57 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the Left parenthesis. + // Go to the operand and move Right. + if (m_leftParenthesisLayout + && cursor->pointedExpressionLayout() == m_leftParenthesisLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + assert(m_operandLayout != nullptr); + cursor->setPointedExpressionLayout(m_operandLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return m_operandLayout->moveRight(cursor); + } + // Case: Right of the operand. + // Go Right. + if (m_operandLayout + && cursor->pointedExpressionLayout() == m_operandLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + return true; + } + // Case: Right of the Right parenthesis. + // Ask the parent. + if (m_rightParenthesisLayout + && cursor->pointedExpressionLayout() == m_rightParenthesisLayout + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left of the parentheses. + // Go Left of the operand. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(m_operandLayout != nullptr); + cursor->setPointedExpressionLayout(m_operandLayout); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right of the parentheses. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + KDSize ParenthesisLayout::computeSize() { KDSize operandSize = m_operandLayout->size(); return KDSize(operandSize.width() + 2*m_leftParenthesisLayout->size().width(), operandSize.height()); diff --git a/poincare/src/layout/parenthesis_layout.h b/poincare/src/layout/parenthesis_layout.h index e6fcab76a..84c765893 100644 --- a/poincare/src/layout/parenthesis_layout.h +++ b/poincare/src/layout/parenthesis_layout.h @@ -17,6 +17,7 @@ public: constexpr static KDCoordinate k_parenthesisCurveWidth = 5; constexpr static KDCoordinate k_parenthesisCurveHeight = 7; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { }; diff --git a/poincare/src/layout/parenthesis_left_right_layout.cpp b/poincare/src/layout/parenthesis_left_right_layout.cpp index 7b7ae1e88..bbf204a79 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.cpp +++ b/poincare/src/layout/parenthesis_left_right_layout.cpp @@ -30,6 +30,23 @@ bool ParenthesisLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool ParenthesisLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + KDSize ParenthesisLeftRightLayout::computeSize() { //TODO: compute the operandHeight according to the brothers return KDSize(k_widthMargin + k_lineThickness + k_externWidthMargin, m_operandHeight); diff --git a/poincare/src/layout/parenthesis_left_right_layout.h b/poincare/src/layout/parenthesis_left_right_layout.h index a2496e22c..d032fa1af 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.h +++ b/poincare/src/layout/parenthesis_left_right_layout.h @@ -15,6 +15,7 @@ public: ParenthesisLeftRightLayout& operator=(const ParenthesisLeftRightLayout& other) = delete; ParenthesisLeftRightLayout& operator=(ParenthesisLeftRightLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; constexpr static KDCoordinate k_parenthesisCurveWidth = 5; constexpr static KDCoordinate k_parenthesisCurveHeight = 7; constexpr static KDCoordinate k_externWidthMargin = 1; diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 1bf01e536..2ec7658c9 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -64,6 +64,49 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the bounds. + // Go Left of the argument. + if (cursor->position() == ExpressionLayoutCursor::Position::Right + && ((m_lowerBoundLayout + && cursor->pointedExpressionLayout() == m_lowerBoundLayout) + || (m_upperBoundLayout + && cursor->pointedExpressionLayout() == m_upperBoundLayout))) + { + assert(m_argumentLayout != nullptr); + cursor->setPointedExpressionLayout(m_argumentLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Right of the argument. + // Ask the parent. + if (cursor->position() == ExpressionLayoutCursor::Position::Right + && m_argumentLayout + && cursor->pointedExpressionLayout() == m_argumentLayout) + { + cursor->setPointedExpressionLayout(this); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go to the upper bound. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(m_upperBoundLayout != nullptr); + cursor->setPointedExpressionLayout(m_upperBoundLayout); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + KDSize SequenceLayout::computeSize() { KDSize argumentSize = m_argumentLayout->size(); KDSize lowerBoundSize = m_lowerBoundLayout->size(); diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 03e289454..bcef26d56 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -17,6 +17,7 @@ public: constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: constexpr static KDCoordinate k_boundHeightMargin = 2; ExpressionLayout * m_lowerBoundLayout; diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index 84a8a35fe..c4df91684 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -42,6 +42,23 @@ bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { return false; } +bool StringLayout::moveRight(ExpressionLayoutCursor * cursor) { + // A StringLayout is not editable, and the cursor cannot go inside it. + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + ExpressionLayout * StringLayout::child(uint16_t index) { return nullptr; } diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index 236bfaa8b..60600f022 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -19,6 +19,7 @@ public: StringLayout& operator=(StringLayout&& other) = delete; char * text(); bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; From 96c2f9aebad36a039547139fa6ca7f0987df4681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 15 Dec 2017 14:50:29 +0100 Subject: [PATCH 021/257] [poincare] Fixed some layout moveLeft() problems. Change-Id: Id7b9f9a1cc823589e1abd8a69800331649393126 --- poincare/src/layout/parenthesis_layout.cpp | 4 ++-- poincare/src/layout/string_layout.cpp | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index 56a50ed51..6c9fa5ed4 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -37,7 +37,7 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { assert(m_operandLayout != nullptr); cursor->setPointedExpressionLayout(m_operandLayout); cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; + return m_operandLayout->moveLeft(cursor); } // Case: Left of the operand. // Go Left. @@ -49,7 +49,7 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { return true; } // Case: Left of the Left parenthesis. - // Aske the parent. + // Ask the parent. if (m_leftParenthesisLayout && cursor->pointedExpressionLayout() == m_leftParenthesisLayout && cursor->position() == ExpressionLayoutCursor::Position::Left) diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index c4df91684..4a053c80d 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -25,7 +25,6 @@ char * StringLayout::text() { } bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); // A StringLayout is not editable, and the cursor cannot go inside it. assert(cursor->pointedExpressionLayout() == this); // Case: Right. From fc8cd6c06ea579934b29489dec1883bdb3e53cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 15 Dec 2017 18:10:14 +0100 Subject: [PATCH 022/257] [expression_editor/poincare] Move Up in an ExpressionLayout. Change-Id: I75fd91233729afd4eb77d8e9d53c102a632643ea --- .../expression_view_with_cursor.cpp | 4 +- .../expression_view_with_cursor.h | 1 - kandinsky/include/kandinsky/point.h | 1 + kandinsky/include/kandinsky/rect.h | 4 + kandinsky/src/point.cpp | 4 + kandinsky/src/rect.cpp | 8 ++ poincare/include/poincare/expression_layout.h | 15 ++++ .../poincare/expression_layout_cursor.h | 9 +++ poincare/src/expression_layout_cursor.cpp | 26 ++++++- .../src/layout/baseline_relative_layout.h | 2 +- poincare/src/layout/condensed_sum_layout.cpp | 17 +++++ poincare/src/layout/condensed_sum_layout.h | 1 + .../editable_baseline_relative_layout.cpp | 46 ++++++++++++ .../editable_baseline_relative_layout.h | 1 + .../src/layout/editable_string_layout.cpp | 25 +++++++ poincare/src/layout/editable_string_layout.h | 8 ++ poincare/src/layout/expression_layout.cpp | 74 +++++++++++++++++++ poincare/src/layout/fraction_layout.cpp | 14 ++++ poincare/src/layout/fraction_layout.h | 1 + poincare/src/layout/grid_layout.cpp | 15 ++++ poincare/src/layout/grid_layout.h | 2 + poincare/src/layout/horizontal_layout.cpp | 36 +++++++++ poincare/src/layout/horizontal_layout.h | 1 + poincare/src/layout/integral_layout.cpp | 17 +++++ poincare/src/layout/integral_layout.h | 1 + poincare/src/layout/nth_root_layout.cpp | 25 +++++++ poincare/src/layout/nth_root_layout.h | 1 + poincare/src/layout/sequence_layout.cpp | 17 +++++ poincare/src/layout/sequence_layout.h | 1 + 29 files changed, 372 insertions(+), 5 deletions(-) diff --git a/apps/expression_editor/expression_view_with_cursor.cpp b/apps/expression_editor/expression_view_with_cursor.cpp index 0c83c41ce..3f501434a 100644 --- a/apps/expression_editor/expression_view_with_cursor.cpp +++ b/apps/expression_editor/expression_view_with_cursor.cpp @@ -44,8 +44,8 @@ void ExpressionViewWithCursor::layoutCursorSubview() { } else if (m_cursor->position() == ExpressionLayoutCursor::Position::Inside) { cursorX += m_cursor->positionInside() * KDText::charSize().width(); } - KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + m_cursor->pointedExpressionLayout()->baseline()-k_cursorHeight/2); - m_cursorView.setFrame(KDRect(cursorTopLeftPosition, 1, k_cursorHeight)); + KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + m_cursor->pointedExpressionLayout()->baseline()-m_cursor->cursorHeight()/2); + m_cursorView.setFrame(KDRect(cursorTopLeftPosition, 1, m_cursor->cursorHeight())); } } diff --git a/apps/expression_editor/expression_view_with_cursor.h b/apps/expression_editor/expression_view_with_cursor.h index 991bc4ba1..79353173c 100644 --- a/apps/expression_editor/expression_view_with_cursor.h +++ b/apps/expression_editor/expression_view_with_cursor.h @@ -21,7 +21,6 @@ private: Top, Bottom }; - constexpr static KDCoordinate k_cursorHeight = 18; int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override; void layoutSubviews() override; diff --git a/kandinsky/include/kandinsky/point.h b/kandinsky/include/kandinsky/point.h index 67003b8e7..892aa92c7 100644 --- a/kandinsky/include/kandinsky/point.h +++ b/kandinsky/include/kandinsky/point.h @@ -17,6 +17,7 @@ public: bool operator !=(const KDPoint &other) const { return !(operator ==(other)); } + uint16_t squareDistanceTo(KDPoint other) const; private: KDCoordinate m_x; KDCoordinate m_y; diff --git a/kandinsky/include/kandinsky/rect.h b/kandinsky/include/kandinsky/rect.h index b149a35cf..d5c93ae82 100644 --- a/kandinsky/include/kandinsky/rect.h +++ b/kandinsky/include/kandinsky/rect.h @@ -45,6 +45,8 @@ public: KDCoordinate left() const { return m_x; } KDPoint topLeft() const { return KDPoint(left(), top()); } + KDPoint topRight() const { return KDPoint(right(), top()); } + KDPoint bottomLeft() const { return KDPoint(left(), bottom()); } KDPoint bottomRight() const { return KDPoint(right(), bottom()); } bool operator ==(const KDRect &other) const { @@ -61,6 +63,8 @@ public: KDRect intersectedWith(const KDRect & other) const; KDRect unionedWith(const KDRect & other) const; // Returns the smallest rectangle containing r1 and r2 bool contains(KDPoint p) const; + bool isAbove(KDPoint p) const; + bool isUnder(KDPoint p) const; bool isEmpty() const; private: diff --git a/kandinsky/src/point.cpp b/kandinsky/src/point.cpp index 4fe0a7afb..796232558 100644 --- a/kandinsky/src/point.cpp +++ b/kandinsky/src/point.cpp @@ -7,3 +7,7 @@ KDPoint KDPoint::translatedBy(KDPoint other) const { KDPoint KDPoint::opposite() const { return KDPoint(-m_x, -m_y); } + +uint16_t KDPoint::squareDistanceTo(KDPoint other) const { + return (m_x-other.x()) * (m_x-other.x()) + (m_y-other.y()) * (m_y-other.y()); +} diff --git a/kandinsky/src/rect.cpp b/kandinsky/src/rect.cpp index a9702ce45..9cf0df654 100644 --- a/kandinsky/src/rect.cpp +++ b/kandinsky/src/rect.cpp @@ -105,6 +105,14 @@ bool KDRect::contains(KDPoint p) const { return (p.x() >= x() && p.x() <= right() && p.y() >= y() && p.y() <= bottom()); } +bool KDRect::isAbove(KDPoint p) const { + return (p.y() >= y()); +} + +bool KDRect::isUnder(KDPoint p) const { + return (p.y() <= bottom()); +} + KDRect KDRect::translatedBy(KDPoint p) const { return KDRect(x() + p.x(), y() + p.y(), width(), height()); } diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 2f49c2b8e..b54e8d058 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -9,6 +9,11 @@ class ExpressionLayoutCursor; class ExpressionLayout { public: + enum class VerticalDirection { + Up, + Down + }; + ExpressionLayout(); virtual ~ExpressionLayout() = default; @@ -25,6 +30,8 @@ public: /* Tree navigation */ virtual bool moveLeft(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? virtual bool moveRight(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? + virtual bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); + bool moveUpInside(ExpressionLayoutCursor * cursor); protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; @@ -32,7 +39,15 @@ protected: virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; KDCoordinate m_baseline; ExpressionLayout * m_parent; + virtual void moveCursorInsideAtDirection ( + VerticalDirection direction, + ExpressionLayoutCursor * cursor, + ExpressionLayout ** childResult, + void * resultPosition, + int * resultPositionInside, + int * resultScore); private: + bool moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor); bool m_sized, m_positioned; KDRect m_frame; }; diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 89b2a0462..0fe1f689e 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -2,6 +2,7 @@ #define POINCARE_EXPRESSION_LAYOUT_CURSOR_H #include +#include namespace Poincare { @@ -26,6 +27,7 @@ public: void setPosition(Position position) { m_position = position; } int positionInside() const { return m_positionInside; } void setPositionInside(int positionInside) { m_positionInside = positionInside; } + KDCoordinate cursorHeight() const { return k_cursorHeight; } /* Move */ bool moveLeft(); @@ -33,7 +35,14 @@ public: bool moveUp(); bool moveDown(); + /* Comparison */ + bool positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position, int positionIndex = 0); + + /* Position */ + KDPoint middleLeftPoint(); + KDPoint middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position, int positionInside = 0); private: + constexpr static KDCoordinate k_cursorHeight = 18; ExpressionLayout * m_pointedExpressionLayout; Position m_position; int m_positionInside; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 17c38ae12..1b45f7d32 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -1,4 +1,6 @@ #include +#include +#include namespace Poincare { @@ -11,12 +13,34 @@ bool ExpressionLayoutCursor::moveRight() { } bool ExpressionLayoutCursor::moveUp() { - return false; //TODO + return m_pointedExpressionLayout->moveUp(this); } bool ExpressionLayoutCursor::moveDown() { return false; //TODO } +bool ExpressionLayoutCursor::positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position, int positionIndex) { + assert(expressionLayout != nullptr); + return middleLeftPoint() == middleLeftPointOfCursor(expressionLayout, position, positionIndex); +} + +KDPoint ExpressionLayoutCursor::middleLeftPoint() { + return middleLeftPointOfCursor(m_pointedExpressionLayout, m_position, m_positionInside); +} + +KDPoint ExpressionLayoutCursor::middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position, int positionInside) { + KDPoint layoutOrigin = expressionLayout->absoluteOrigin(); + KDCoordinate y = layoutOrigin.y() + expressionLayout->baseline() - k_cursorHeight/2; + if (position == Position::Left) { + return KDPoint(layoutOrigin.x(), y); + } + if (position == Position::Right) { + return KDPoint(layoutOrigin.x() + expressionLayout->size().width(), y); + } + assert(position == Position::Inside); + return KDPoint(layoutOrigin.x() + positionInside * KDText::charSize().width(), y); +} + } diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index d88e26708..1b75f6822 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -29,9 +29,9 @@ protected: KDPoint positionOfChild(ExpressionLayout * child) override; ExpressionLayout * m_baseLayout; ExpressionLayout * m_indiceLayout; + Type m_type; private: constexpr static KDCoordinate k_indiceHeight = 5; - Type m_type; }; } diff --git a/poincare/src/layout/condensed_sum_layout.cpp b/poincare/src/layout/condensed_sum_layout.cpp index 401c684af..1a4169024 100644 --- a/poincare/src/layout/condensed_sum_layout.cpp +++ b/poincare/src/layout/condensed_sum_layout.cpp @@ -108,6 +108,23 @@ bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +bool CondensedSumLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is inside the subscript layout, move it to the superscript. + if (m_subscriptLayout && previousLayout == m_subscriptLayout) { + assert(m_superscriptLayout != nullptr); + return m_superscriptLayout->moveUpInside(cursor); + } + // If the cursor is Left of the base layout, move it to the superscript. + if (m_baseLayout + && previousLayout == m_baseLayout + && cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Left)) + { + assert(m_superscriptLayout != nullptr); + return m_superscriptLayout->moveUpInside(cursor); + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + void CondensedSumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // Nothing to draw } diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index 6e9ae9dd2..f2aa85bc9 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -16,6 +16,7 @@ public: CondensedSumLayout& operator=(CondensedSumLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/editable_baseline_relative_layout.cpp b/poincare/src/layout/editable_baseline_relative_layout.cpp index f217e8a33..7078f9b8f 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.cpp +++ b/poincare/src/layout/editable_baseline_relative_layout.cpp @@ -85,6 +85,52 @@ bool EditableBaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) return false; } +bool EditableBaselineRelativeLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the baseline is a superscript: + if (m_type == BaselineRelativeLayout::Type::Superscript) { + // If the cursor is Right of the base layout, move it to the indice. + if (m_baseLayout + && previousLayout == m_baseLayout + && cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Right)) + { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(m_indiceLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + cursor->setPositionInside(0); + return true; + } + // If the cursor is Right, move it to the indice. + if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(m_indiceLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPositionInside(0); + return true; + } + } + // If the baseline is a subscript: + if (m_type == BaselineRelativeLayout::Type::Subscript + && m_indiceLayout + && previousLayout == m_indiceLayout) + { + // If the cursor is Left of the indice layout, move it to the base. + if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Left)) { + assert(m_baseLayout != nullptr); + cursor->setPointedExpressionLayout(m_baseLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPositionInside(0); + return true; + } + // If the cursor is Right of the indice layout, move it Right. + if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Right)) { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPositionInside(0); + return true; + } + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} } diff --git a/poincare/src/layout/editable_baseline_relative_layout.h b/poincare/src/layout/editable_baseline_relative_layout.h index 9839e8628..e9bddbffd 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.h +++ b/poincare/src/layout/editable_baseline_relative_layout.h @@ -10,6 +10,7 @@ public: using BaselineRelativeLayout::BaselineRelativeLayout; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; }; } diff --git a/poincare/src/layout/editable_string_layout.cpp b/poincare/src/layout/editable_string_layout.cpp index 98f085fff..1dfd613b8 100644 --- a/poincare/src/layout/editable_string_layout.cpp +++ b/poincare/src/layout/editable_string_layout.cpp @@ -89,4 +89,29 @@ bool EditableStringLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +void EditableStringLayout::moveCursorInsideAtDirection ( + VerticalDirection direction, + ExpressionLayoutCursor * cursor, + ExpressionLayout ** childResult, + void * resultPosition, + int * resultPositionInside, + int * resultScore) +{ + ExpressionLayout::moveCursorInsideAtDirection(direction, cursor, childResult, resultPosition, resultPositionInside, resultScore); + ExpressionLayoutCursor::Position * castedResultPosition = static_cast(resultPosition); + // Check the distance to Inside cursors. + size_t stringLength = strlen(m_string); + int currentDistance = 0; + KDPoint cursorMiddleLeft = cursor->middleLeftPoint(); + for (int i = 1; i < stringLength; i++) { + currentDistance = cursor->middleLeftPointOfCursor(this, ExpressionLayoutCursor::Position::Inside, i).squareDistanceTo(cursorMiddleLeft); + if (currentDistance < *resultScore) { + *childResult = this; + *castedResultPosition = ExpressionLayoutCursor::Position::Inside; + *resultPositionInside = i; + *resultScore = currentDistance; + } + } +} + } diff --git a/poincare/src/layout/editable_string_layout.h b/poincare/src/layout/editable_string_layout.h index 92e0e9730..75e8b77d9 100644 --- a/poincare/src/layout/editable_string_layout.h +++ b/poincare/src/layout/editable_string_layout.h @@ -11,6 +11,14 @@ public: using StringLayout::StringLayout; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; +private: + void moveCursorInsideAtDirection ( + VerticalDirection direction, + ExpressionLayoutCursor * cursor, + ExpressionLayout ** childResult, + void * resultPosition, + int * resultPositionInside, + int * resultScore) override; }; } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 560eed6f8..f3f8a4dfb 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -1,6 +1,8 @@ #include #include #include "string_layout.h" +#include +#include namespace Poincare { @@ -57,4 +59,76 @@ void ExpressionLayout::setParent(ExpressionLayout* parent) { m_parent = parent; } +bool ExpressionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + if (m_parent) { + return m_parent->moveUp(cursor, this, previousLayout); + } + return false; +} + +bool ExpressionLayout::moveUpInside(ExpressionLayoutCursor * cursor) { + return moveInside(VerticalDirection::Up, cursor); +} + +bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor) { + ExpressionLayout * chilResult = nullptr; + ExpressionLayout ** childResultPtr = &chilResult; + ExpressionLayoutCursor::Position resultPosition = ExpressionLayoutCursor::Position::Left; + int resultPositionInside = 0; + // The distance between the cursor and its next position cannot be greater + // than this initial value of score. + int resultScore = Ion::Display::Width*Ion::Display::Width + Ion::Display::Height*Ion::Display::Height; + + moveCursorInsideAtDirection(direction, cursor, childResultPtr, &resultPosition, &resultPositionInside, &resultScore); + + // If there is a valid result + if (*childResultPtr == nullptr) { + return false; + } + cursor->setPointedExpressionLayout(*childResultPtr); + cursor->setPosition(resultPosition); + cursor->setPositionInside(resultPositionInside); + return true; +} + +void ExpressionLayout::moveCursorInsideAtDirection ( + VerticalDirection direction, + ExpressionLayoutCursor * cursor, + ExpressionLayout ** childResult, + void * resultPosition, + int * resultPositionInside, + int * resultScore) +{ + ExpressionLayoutCursor::Position * castedResultPosition = static_cast(resultPosition); + KDPoint cursorMiddleLeft = cursor->middleLeftPoint(); + bool layoutIsUnderOrAbove = direction == VerticalDirection::Up ? m_frame.isAbove(cursorMiddleLeft) : m_frame.isUnder(cursorMiddleLeft); + bool layoutContains = m_frame.contains(cursorMiddleLeft); + + if (layoutIsUnderOrAbove) { + // Check the distance to a Left cursor. + int currentDistance = cursor->middleLeftPointOfCursor(this, ExpressionLayoutCursor::Position::Left, 0).squareDistanceTo(cursorMiddleLeft); + if (currentDistance <= *resultScore ){ + *childResult = this; + *castedResultPosition = ExpressionLayoutCursor::Position::Left; + *resultPositionInside = 0; + *resultScore = currentDistance; + } + + // Check the distance to a Right cursor. + currentDistance = cursor->middleLeftPointOfCursor(this, ExpressionLayoutCursor::Position::Right, 0).squareDistanceTo(cursorMiddleLeft); + if (currentDistance < *resultScore) { + *childResult = this; + *castedResultPosition = ExpressionLayoutCursor::Position::Right; + *resultPositionInside = 0; + *resultScore = currentDistance; + } + } + if (layoutIsUnderOrAbove || layoutContains) { + int childIndex = 0; + while (child(childIndex++)) { + child(childIndex-1)->moveCursorInsideAtDirection(direction, cursor, childResult, castedResultPosition, resultPositionInside, resultScore); + } + } +} + } diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 5f7a0043a..48b0e8778 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -72,6 +72,20 @@ bool FractionLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +bool FractionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is inside denominator, move it to the numerator. + if (m_denominator_layout && previousLayout == m_denominator_layout) { + assert(m_numerator_layout != nullptr); + return m_numerator_layout->moveUpInside(cursor); + } + // If the cursor is Left or Right, move it to the numerator. + if (cursor->pointedExpressionLayout() == this){ + assert(m_numerator_layout != nullptr); + return m_numerator_layout->moveUpInside(cursor); + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + void FractionLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDCoordinate fractionLineY = p.y() + m_numerator_layout->size().height() + k_fractionLineMargin; ctx->fillRect(KDRect(p.x()+k_fractionBorderMargin, fractionLineY, size().width()-2*k_fractionBorderMargin, 1), expressionColor); diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 8f777040e..d5a69c9cd 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -16,6 +16,7 @@ public: FractionLayout& operator=(FractionLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 6df7a62b3..c6110f2ba 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -100,6 +100,16 @@ bool GridLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +bool GridLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is child that is not on the top row, move it inside the upper + // neighbourg. + int childIndex = indexOfChild(previousLayout); + if (childIndex >- 1 && !childIsTopOfGrid(childIndex)) { + return m_entryLayouts[childIndex - m_numberOfColumns]->moveUpInside(cursor); + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + KDCoordinate GridLayout::rowBaseline(int i) { KDCoordinate rowBaseline = 0; for (int j = 0; j < m_numberOfColumns; j++) { @@ -196,10 +206,15 @@ bool GridLayout::childIsLeftOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); return (index - m_numberOfColumns * (int)(index / m_numberOfColumns)) == 0; } + bool GridLayout::childIsRightOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); return (index - m_numberOfColumns * (int)(index / m_numberOfColumns)) == m_numberOfColumns - 1; } +bool GridLayout::childIsTopOfGrid(int index) const { + assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); + return index < m_numberOfColumns; +} } diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 0cab38840..e3b6d25f2 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -17,6 +17,7 @@ public: GridLayout& operator=(GridLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; @@ -32,6 +33,7 @@ private: int indexOfChild(ExpressionLayout * eL) const; bool childIsLeftOfGrid(int index) const; bool childIsRightOfGrid(int index) const; + bool childIsTopOfGrid(int index) const; ExpressionLayout ** m_entryLayouts; int m_numberOfRows; int m_numberOfColumns; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 429931df8..2635e7648 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -124,6 +124,39 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { return m_children_layouts[childIndex+1]->moveRight(cursor); } +bool HorizontalLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // Prevent looping fom child to parent + if (previousPreviousLayout == this) { + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + } + // If the cursor Left or Right of a child, try moving it up from its brother. + int previousLayoutIndex = indexOfChild(previousLayout); + if (previousLayoutIndex > -1) { + ExpressionLayout * brother = nullptr; + ExpressionLayoutCursor::Position newPosition = ExpressionLayoutCursor::Position::Right; + if (cursor->position() == ExpressionLayoutCursor::Position::Left && previousLayoutIndex > 0) { + brother = m_children_layouts[previousLayoutIndex - 1]; + newPosition = ExpressionLayoutCursor::Position::Right; + } + if (cursor->position() == ExpressionLayoutCursor::Position::Right && previousLayoutIndex < m_number_of_children - 1) { + brother = m_children_layouts[previousLayoutIndex + 1]; + newPosition = ExpressionLayoutCursor::Position::Left; + } + if (brother && cursor->positionIsEquivalentTo(brother, newPosition)) { + ExpressionLayout * previousPointedLayout = cursor->pointedExpressionLayout(); + ExpressionLayoutCursor::Position previousPosition = cursor->position(); + cursor->setPointedExpressionLayout(brother); + cursor->setPosition(newPosition); + if (brother->moveUp(cursor, this, previousLayout)) { + return true; + } + cursor->setPointedExpressionLayout(previousPointedLayout); + cursor->setPosition(previousPosition); + } + } + return ExpressionLayout::moveUp(cursor, previousLayout); +} + void HorizontalLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { } @@ -168,6 +201,9 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { } int HorizontalLayout::indexOfChild(ExpressionLayout * eL) const { + if (eL == nullptr) { + return -1; + } for (int i = 0; i < m_number_of_children; i++) { if (m_children_layouts[i] == eL) { return i; diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index c081589fb..33f0ba434 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -16,6 +16,7 @@ public: HorizontalLayout& operator=(HorizontalLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 1ce316836..c1e755fc8 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -117,6 +117,23 @@ bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +bool IntegralLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is inside the lower bound, move it to the upper bound. + if (m_lowerBoundLayout && previousLayout == m_lowerBoundLayout) { + assert(m_upperBoundLayout != nullptr); + return m_upperBoundLayout->moveUpInside(cursor); + } + // If the cursor is Left of the integrand, move it to the upper bound. + if (m_integrandLayout + && previousLayout == m_integrandLayout + && cursor->positionIsEquivalentTo(m_integrandLayout, ExpressionLayoutCursor::Position::Left)) + { + assert(m_upperBoundLayout != nullptr); + return m_upperBoundLayout->moveUpInside(cursor); + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize integrandSize = m_integrandLayout->size(); KDSize upperBoundSize = m_upperBoundLayout->size(); diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 0a3ad388d..d28d98347 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -18,6 +18,7 @@ public: constexpr static KDCoordinate k_symbolWidth = 4; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 0e8727fba..238f504b6 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -121,6 +121,31 @@ bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is Left of the radicand, move it to the index. + if (m_radicandLayout + && previousLayout == m_radicandLayout + && cursor->positionIsEquivalentTo(m_radicandLayout, ExpressionLayoutCursor::Position::Left)) + { + assert(m_indexLayout != nullptr); + cursor->setPointedExpressionLayout(m_indexLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPositionInside(0); + return true; + } + // If the cursor is Left, move it to the index. + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + assert(m_indexLayout != nullptr); + cursor->setPointedExpressionLayout(m_indexLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + cursor->setPositionInside(0); + return true; + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize radicandSize = m_radicandLayout->size(); KDSize indexSize = m_indexLayout != nullptr ? m_indexLayout->size() : KDSize(k_leftRadixWidth,0); diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index b4727b531..14ed3f2f2 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -18,6 +18,7 @@ public: constexpr static KDCoordinate k_leftRadixWidth = 5; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 2ec7658c9..535182d6e 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -107,6 +107,23 @@ bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +bool SequenceLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is inside the lower bound, move it to the upper bound. + if (m_lowerBoundLayout && previousLayout == m_lowerBoundLayout) { + assert(m_upperBoundLayout != nullptr); + return m_upperBoundLayout->moveUpInside(cursor); + } + // If the cursor is Left of the argument, move it to the upper bound. + if (m_argumentLayout + && previousLayout == m_argumentLayout + && cursor->positionIsEquivalentTo(m_argumentLayout, ExpressionLayoutCursor::Position::Left)) + { + assert(m_upperBoundLayout != nullptr); + return m_upperBoundLayout->moveUpInside(cursor); + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + KDSize SequenceLayout::computeSize() { KDSize argumentSize = m_argumentLayout->size(); KDSize lowerBoundSize = m_lowerBoundLayout->size(); diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index bcef26d56..aaf9f9bb2 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -18,6 +18,7 @@ public: constexpr static KDCoordinate k_symbolWidth = 9; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: constexpr static KDCoordinate k_boundHeightMargin = 2; ExpressionLayout * m_lowerBoundLayout; From a4c014c75e36ae02a0191c549901ef217ea4eafa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 18 Dec 2017 11:14:05 +0100 Subject: [PATCH 023/257] [expression_editor/poincare] Move Down in an ExpressionLayout. Change-Id: I87f3394cce5eb4936ab926d5e92fdf44d4473cf7 --- poincare/include/poincare/expression_layout.h | 2 + poincare/src/expression_layout_cursor.cpp | 2 +- poincare/src/layout/condensed_sum_layout.cpp | 17 ++++ poincare/src/layout/condensed_sum_layout.h | 1 + .../editable_baseline_relative_layout.cpp | 48 +++++++++++ .../editable_baseline_relative_layout.h | 1 + poincare/src/layout/expression_layout.cpp | 11 +++ poincare/src/layout/fraction_layout.cpp | 14 ++++ poincare/src/layout/fraction_layout.h | 1 + poincare/src/layout/grid_layout.cpp | 15 ++++ poincare/src/layout/grid_layout.h | 2 + poincare/src/layout/horizontal_layout.cpp | 79 ++++++++++++------- poincare/src/layout/horizontal_layout.h | 2 + poincare/src/layout/integral_layout.cpp | 17 ++++ poincare/src/layout/integral_layout.h | 1 + poincare/src/layout/nth_root_layout.cpp | 21 +++++ poincare/src/layout/nth_root_layout.h | 1 + poincare/src/layout/sequence_layout.cpp | 16 ++++ poincare/src/layout/sequence_layout.h | 1 + 19 files changed, 221 insertions(+), 31 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index b54e8d058..1381aecf5 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -32,6 +32,8 @@ public: virtual bool moveRight(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? virtual bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); bool moveUpInside(ExpressionLayoutCursor * cursor); + virtual bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); + bool moveDownInside(ExpressionLayoutCursor * cursor); protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 1b45f7d32..5fd6c0887 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -17,7 +17,7 @@ bool ExpressionLayoutCursor::moveUp() { } bool ExpressionLayoutCursor::moveDown() { - return false; //TODO + return m_pointedExpressionLayout->moveDown(this); } bool ExpressionLayoutCursor::positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position, int positionIndex) { diff --git a/poincare/src/layout/condensed_sum_layout.cpp b/poincare/src/layout/condensed_sum_layout.cpp index 1a4169024..e1a73f1c2 100644 --- a/poincare/src/layout/condensed_sum_layout.cpp +++ b/poincare/src/layout/condensed_sum_layout.cpp @@ -125,6 +125,23 @@ bool CondensedSumLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayou return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } +bool CondensedSumLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is inside the superscript layout, move it to the subscript. + if (m_superscriptLayout && previousLayout == m_superscriptLayout) { + assert(m_subscriptLayout != nullptr); + return m_subscriptLayout->moveUpInside(cursor); + } + // If the cursor is Left of the base layout, move it to the subscript. + if (m_baseLayout + && previousLayout == m_baseLayout + && cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Left)) + { + assert(m_subscriptLayout != nullptr); + return m_subscriptLayout->moveUpInside(cursor); + } + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} + void CondensedSumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // Nothing to draw } diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index f2aa85bc9..1d15dc1c3 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -17,6 +17,7 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/editable_baseline_relative_layout.cpp b/poincare/src/layout/editable_baseline_relative_layout.cpp index 7078f9b8f..b06e27449 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.cpp +++ b/poincare/src/layout/editable_baseline_relative_layout.cpp @@ -132,5 +132,53 @@ bool EditableBaselineRelativeLayout::moveUp(ExpressionLayoutCursor * cursor, Exp return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } +bool EditableBaselineRelativeLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the baseline is a subscript: + if (m_type == BaselineRelativeLayout::Type::Subscript) { + // If the cursor is Right of the base layout, move it to the indice. + if (m_baseLayout + && previousLayout == m_baseLayout + && cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Right)) + { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(m_indiceLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + cursor->setPositionInside(0); + return true; + } + // If the cursor is Right, move it to the indice. + if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(m_indiceLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPositionInside(0); + return true; + } + } + // If the baseline is a superscript: + if (m_type == BaselineRelativeLayout::Type::Superscript + && m_indiceLayout + && previousLayout == m_indiceLayout) + { + // If the cursor is Left of the indice layout, move it to the base. + if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Left)) { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(m_baseLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPositionInside(0); + return true; + } + // If the cursor is Right of the indice layout, move it Right. + if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Right)) { + assert(m_indiceLayout != nullptr); + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPositionInside(0); + return true; + } + } + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} + } diff --git a/poincare/src/layout/editable_baseline_relative_layout.h b/poincare/src/layout/editable_baseline_relative_layout.h index e9bddbffd..72ef5aa4a 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.h +++ b/poincare/src/layout/editable_baseline_relative_layout.h @@ -11,6 +11,7 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; }; } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index f3f8a4dfb..630b1c61e 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -70,6 +70,17 @@ bool ExpressionLayout::moveUpInside(ExpressionLayoutCursor * cursor) { return moveInside(VerticalDirection::Up, cursor); } +bool ExpressionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + if (m_parent) { + return m_parent->moveDown(cursor, this, previousLayout); + } + return false; +} + +bool ExpressionLayout::moveDownInside(ExpressionLayoutCursor * cursor) { + return moveInside(VerticalDirection::Down, cursor); +} + bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor) { ExpressionLayout * chilResult = nullptr; ExpressionLayout ** childResultPtr = &chilResult; diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 48b0e8778..4191504ab 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -86,6 +86,20 @@ bool FractionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } +bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is inside numerator, move it to the denominator. + if (m_numerator_layout && previousLayout == m_numerator_layout) { + assert(m_denominator_layout != nullptr); + return m_denominator_layout->moveDownInside(cursor); + } + // If the cursor is Left or Right, move it to the denominator. + if (cursor->pointedExpressionLayout() == this){ + assert(m_denominator_layout != nullptr); + return m_denominator_layout->moveDownInside(cursor); + } + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} + void FractionLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDCoordinate fractionLineY = p.y() + m_numerator_layout->size().height() + k_fractionLineMargin; ctx->fillRect(KDRect(p.x()+k_fractionBorderMargin, fractionLineY, size().width()-2*k_fractionBorderMargin, 1), expressionColor); diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index d5a69c9cd..97dd6043a 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -17,6 +17,7 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index c6110f2ba..075854b95 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -110,6 +110,16 @@ bool GridLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * prev return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } +bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is child that is not on the bottom row, move it inside the + // lower neighbourg. + int childIndex = indexOfChild(previousLayout); + if (childIndex >- 1 && !childIsBottomOfGrid(childIndex)) { + return m_entryLayouts[childIndex + m_numberOfColumns]->moveDownInside(cursor); + } + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} + KDCoordinate GridLayout::rowBaseline(int i) { KDCoordinate rowBaseline = 0; for (int j = 0; j < m_numberOfColumns; j++) { @@ -217,4 +227,9 @@ bool GridLayout::childIsTopOfGrid(int index) const { return index < m_numberOfColumns; } +bool GridLayout::childIsBottomOfGrid(int index) const { + assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); + return index > (m_numberOfRows - 1) * m_numberOfColumns - 1; +} + } diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index e3b6d25f2..40cec0ef4 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -18,6 +18,7 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; @@ -34,6 +35,7 @@ private: bool childIsLeftOfGrid(int index) const; bool childIsRightOfGrid(int index) const; bool childIsTopOfGrid(int index) const; + bool childIsBottomOfGrid(int index) const; ExpressionLayout ** m_entryLayouts; int m_numberOfRows; int m_numberOfColumns; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 2635e7648..ddd7b81ea 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -125,36 +125,11 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { } bool HorizontalLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { - // Prevent looping fom child to parent - if (previousPreviousLayout == this) { - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); - } - // If the cursor Left or Right of a child, try moving it up from its brother. - int previousLayoutIndex = indexOfChild(previousLayout); - if (previousLayoutIndex > -1) { - ExpressionLayout * brother = nullptr; - ExpressionLayoutCursor::Position newPosition = ExpressionLayoutCursor::Position::Right; - if (cursor->position() == ExpressionLayoutCursor::Position::Left && previousLayoutIndex > 0) { - brother = m_children_layouts[previousLayoutIndex - 1]; - newPosition = ExpressionLayoutCursor::Position::Right; - } - if (cursor->position() == ExpressionLayoutCursor::Position::Right && previousLayoutIndex < m_number_of_children - 1) { - brother = m_children_layouts[previousLayoutIndex + 1]; - newPosition = ExpressionLayoutCursor::Position::Left; - } - if (brother && cursor->positionIsEquivalentTo(brother, newPosition)) { - ExpressionLayout * previousPointedLayout = cursor->pointedExpressionLayout(); - ExpressionLayoutCursor::Position previousPosition = cursor->position(); - cursor->setPointedExpressionLayout(brother); - cursor->setPosition(newPosition); - if (brother->moveUp(cursor, this, previousLayout)) { - return true; - } - cursor->setPointedExpressionLayout(previousPointedLayout); - cursor->setPosition(previousPosition); - } - } - return ExpressionLayout::moveUp(cursor, previousLayout); + return moveVertically(ExpressionLayout::VerticalDirection::Up, cursor, previousLayout, previousPreviousLayout); +} + +bool HorizontalLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + return moveVertically(ExpressionLayout::VerticalDirection::Down, cursor, previousLayout, previousPreviousLayout); } void HorizontalLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { @@ -200,6 +175,50 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x, y); } +bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // Prevent looping fom child to parent + if (previousPreviousLayout == this) { + if (direction == ExpressionLayout::VerticalDirection::Up) { + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + } + assert(direction == ExpressionLayout::VerticalDirection::Down); + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + } + // If the cursor Left or Right of a child, try moving it up from its brother. + int previousLayoutIndex = indexOfChild(previousLayout); + if (previousLayoutIndex > -1) { + ExpressionLayout * brother = nullptr; + ExpressionLayoutCursor::Position newPosition = ExpressionLayoutCursor::Position::Right; + if (cursor->position() == ExpressionLayoutCursor::Position::Left && previousLayoutIndex > 0) { + brother = m_children_layouts[previousLayoutIndex - 1]; + newPosition = ExpressionLayoutCursor::Position::Right; + } + if (cursor->position() == ExpressionLayoutCursor::Position::Right && previousLayoutIndex < m_number_of_children - 1) { + brother = m_children_layouts[previousLayoutIndex + 1]; + newPosition = ExpressionLayoutCursor::Position::Left; + } + if (brother && cursor->positionIsEquivalentTo(brother, newPosition)) { + ExpressionLayout * previousPointedLayout = cursor->pointedExpressionLayout(); + ExpressionLayoutCursor::Position previousPosition = cursor->position(); + cursor->setPointedExpressionLayout(brother); + cursor->setPosition(newPosition); + if (direction == ExpressionLayout::VerticalDirection::Up && brother->moveUp(cursor, this, previousLayout)) { + return true; + } + if (direction == ExpressionLayout::VerticalDirection::Down && brother->moveDown(cursor, this, previousLayout)) { + return true; + } + cursor->setPointedExpressionLayout(previousPointedLayout); + cursor->setPosition(previousPosition); + } + } + if (direction == ExpressionLayout::VerticalDirection::Up) { + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + } + assert(direction == ExpressionLayout::VerticalDirection::Down); + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} + int HorizontalLayout::indexOfChild(ExpressionLayout * eL) const { if (eL == nullptr) { return -1; diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 33f0ba434..8e8eb3750 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -17,12 +17,14 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: + bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); int indexOfChild(ExpressionLayout * eL) const; int m_number_of_children; ExpressionLayout ** m_children_layouts; diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index c1e755fc8..82f923ec6 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -134,6 +134,23 @@ bool IntegralLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } +bool IntegralLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is inside the upper bound, move it to the lower bound. + if (m_upperBoundLayout && previousLayout == m_upperBoundLayout) { + assert(m_lowerBoundLayout != nullptr); + return m_lowerBoundLayout->moveDownInside(cursor); + } + // If the cursor is Left of the integrand, move it to the lower bound. + if (m_integrandLayout + && previousLayout == m_integrandLayout + && cursor->positionIsEquivalentTo(m_integrandLayout, ExpressionLayoutCursor::Position::Left)) + { + assert(m_lowerBoundLayout != nullptr); + return m_lowerBoundLayout->moveDownInside(cursor); + } + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} + void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize integrandSize = m_integrandLayout->size(); KDSize upperBoundSize = m_upperBoundLayout->size(); diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index d28d98347..f1beceee0 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -19,6 +19,7 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 238f504b6..47ff1725c 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -146,6 +146,27 @@ bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * p return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } +bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + if (m_indexLayout && previousLayout == m_indexLayout) { + // If the cursor is Right of the index, move it to the radicand. + if (cursor->positionIsEquivalentTo(m_indexLayout, ExpressionLayoutCursor::Position::Right)) { + assert(m_radicandLayout != nullptr); + cursor->setPointedExpressionLayout(m_radicandLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + cursor->setPositionInside(0); + return true; + } + // If the cursor is Left of the index, move it Left . + if (cursor->positionIsEquivalentTo(m_indexLayout, ExpressionLayoutCursor::Position::Left)) { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + cursor->setPositionInside(0); + return true; + } + } + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} + void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize radicandSize = m_radicandLayout->size(); KDSize indexSize = m_indexLayout != nullptr ? m_indexLayout->size() : KDSize(k_leftRadixWidth,0); diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index 14ed3f2f2..7a4432c31 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -19,6 +19,7 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 535182d6e..8bb66e969 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -123,6 +123,22 @@ bool SequenceLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * } return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } +bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // If the cursor is inside the upper bound, move it to the lower bound. + if (m_upperBoundLayout && previousLayout == m_upperBoundLayout) { + assert(m_lowerBoundLayout != nullptr); + return m_lowerBoundLayout->moveDownInside(cursor); + } + // If the cursor is Left of the argument, move it to the lower bound. + if (m_argumentLayout + && previousLayout == m_argumentLayout + && cursor->positionIsEquivalentTo(m_argumentLayout, ExpressionLayoutCursor::Position::Left)) + { + assert(m_lowerBoundLayout != nullptr); + return m_lowerBoundLayout->moveDownInside(cursor); + } + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} KDSize SequenceLayout::computeSize() { KDSize argumentSize = m_argumentLayout->size(); diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index aaf9f9bb2..95cf67f5d 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -19,6 +19,7 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: constexpr static KDCoordinate k_boundHeightMargin = 2; ExpressionLayout * m_lowerBoundLayout; From 0cc1d99a5442569afb686edb94376983eba66a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 12:10:37 +0100 Subject: [PATCH 024/257] [poincare] Static and Dynamic Layout hierarchies. Change-Id: I3b47dbd76552b77db762482932518a74c1996cc0 --- poincare/Makefile | 5 + .../poincare/dynamic_layout_hierarchy.h | 31 ++++ poincare/include/poincare/expression_layout.h | 25 +++- .../poincare/static_layout_hierarchy.h | 31 ++++ poincare/src/absolute_value.cpp | 2 +- poincare/src/binomial_coefficient.cpp | 2 +- poincare/src/ceiling.cpp | 2 +- poincare/src/complex.cpp | 2 +- poincare/src/conjugate.cpp | 2 +- poincare/src/division.cpp | 2 +- poincare/src/factorial.cpp | 2 +- poincare/src/floor.cpp | 2 +- poincare/src/integral.cpp | 2 +- poincare/src/layout/absolute_value_layout.cpp | 10 ++ poincare/src/layout/absolute_value_layout.h | 14 +- .../src/layout/baseline_relative_layout.cpp | 59 +++----- .../src/layout/baseline_relative_layout.h | 20 +-- poincare/src/layout/bracket_layout.cpp | 48 +++--- poincare/src/layout/bracket_layout.h | 16 +- poincare/src/layout/bracket_left_layout.cpp | 5 + poincare/src/layout/bracket_left_layout.h | 1 + .../src/layout/bracket_left_right_layout.cpp | 2 +- .../src/layout/bracket_left_right_layout.h | 11 +- poincare/src/layout/bracket_right_layout.cpp | 5 + poincare/src/layout/bracket_right_layout.h | 1 + poincare/src/layout/ceiling_layout.cpp | 10 ++ poincare/src/layout/ceiling_layout.h | 8 +- poincare/src/layout/condensed_sum_layout.cpp | 130 ++++++++-------- poincare/src/layout/condensed_sum_layout.h | 20 +-- poincare/src/layout/conjugate_layout.cpp | 48 +++--- poincare/src/layout/conjugate_layout.h | 16 +- .../src/layout/dynamic_layout_hierarchy.cpp | 62 ++++++++ .../editable_baseline_relative_layout.cpp | 93 ++++++------ .../editable_baseline_relative_layout.h | 1 + .../src/layout/editable_string_layout.cpp | 5 + poincare/src/layout/editable_string_layout.h | 1 + poincare/src/layout/expression_layout.cpp | 48 +++++- poincare/src/layout/floor_layout.cpp | 10 ++ poincare/src/layout/floor_layout.h | 8 +- poincare/src/layout/fraction_layout.cpp | 88 ++++++----- poincare/src/layout/fraction_layout.h | 18 +-- poincare/src/layout/grid_layout.cpp | 46 ++---- poincare/src/layout/grid_layout.h | 19 +-- poincare/src/layout/horizontal_layout.cpp | 64 ++++---- poincare/src/layout/horizontal_layout.h | 18 +-- poincare/src/layout/integral_layout.cpp | 140 +++++++++--------- poincare/src/layout/integral_layout.h | 20 +-- poincare/src/layout/nth_root_layout.cpp | 130 ++++++++-------- poincare/src/layout/nth_root_layout.h | 18 +-- poincare/src/layout/parenthesis_layout.cpp | 105 +++++++------ poincare/src/layout/parenthesis_layout.h | 20 +-- .../src/layout/parenthesis_left_layout.cpp | 5 + poincare/src/layout/parenthesis_left_layout.h | 3 +- .../layout/parenthesis_left_right_layout.cpp | 2 +- .../layout/parenthesis_left_right_layout.h | 11 +- .../src/layout/parenthesis_right_layout.cpp | 5 + .../src/layout/parenthesis_right_layout.h | 3 +- poincare/src/layout/product_layout.cpp | 15 +- poincare/src/layout/product_layout.h | 1 + poincare/src/layout/sequence_layout.cpp | 137 ++++++++--------- poincare/src/layout/sequence_layout.h | 19 +-- .../src/layout/static_layout_hierarchy.cpp | 70 +++++++++ poincare/src/layout/string_layout.cpp | 11 +- poincare/src/layout/string_layout.h | 12 +- poincare/src/layout/sum_layout.cpp | 11 +- poincare/src/layout/sum_layout.h | 1 + poincare/src/layout_engine.cpp | 10 +- poincare/src/logarithm.cpp | 6 +- poincare/src/matrix.cpp | 2 +- poincare/src/nth_root.cpp | 2 +- poincare/src/opposite.cpp | 4 +- poincare/src/parenthesis.cpp | 2 +- poincare/src/power.cpp | 2 +- poincare/src/product.cpp | 2 +- poincare/src/rational.cpp | 2 +- poincare/src/sequence.cpp | 2 +- poincare/src/square_root.cpp | 2 +- poincare/src/store.cpp | 2 +- poincare/src/sum.cpp | 2 +- poincare/src/symbol.cpp | 8 +- 80 files changed, 966 insertions(+), 836 deletions(-) create mode 100644 poincare/include/poincare/dynamic_layout_hierarchy.h create mode 100644 poincare/include/poincare/static_layout_hierarchy.h create mode 100644 poincare/src/layout/absolute_value_layout.cpp create mode 100644 poincare/src/layout/ceiling_layout.cpp create mode 100644 poincare/src/layout/dynamic_layout_hierarchy.cpp create mode 100644 poincare/src/layout/floor_layout.cpp create mode 100644 poincare/src/layout/static_layout_hierarchy.cpp diff --git a/poincare/Makefile b/poincare/Makefile index c778125ba..ba3d233bf 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -83,16 +83,20 @@ objs += $(addprefix poincare/src/,\ ) objs += $(addprefix poincare/src/layout/,\ + absolute_value_layout.o\ baseline_relative_layout.o\ bracket_layout.o\ bracket_left_layout.o\ bracket_left_right_layout.o\ bracket_right_layout.o\ + ceiling_layout.o\ condensed_sum_layout.o\ conjugate_layout.o\ + dynamic_layout_hierarchy.o\ editable_baseline_relative_layout.o\ editable_string_layout.o\ expression_layout.o\ + floor_layout.o\ fraction_layout.o\ grid_layout.o\ horizontal_layout.o\ @@ -104,6 +108,7 @@ objs += $(addprefix poincare/src/layout/,\ parenthesis_right_layout.o\ product_layout.o\ sequence_layout.o\ + static_layout_hierarchy.o\ string_layout.o\ sum_layout.o\ ) diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h new file mode 100644 index 000000000..ef8053f76 --- /dev/null +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -0,0 +1,31 @@ +#ifndef POINCARE_DYNAMIC_LAYOUT_HIERARCHY_H +#define POINCARE_DYNAMIC_LAYOUT_HIERARCHY_H + +#include + +namespace Poincare { + +class DynamicLayoutHierarchy : public ExpressionLayout { +public: + DynamicLayoutHierarchy(); + DynamicLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands = true); + DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, bool cloneOperands = true) : + DynamicLayoutHierarchy(ExpressionLayoutArray2(operand1, operand2), 2, cloneOperands) {} + ~DynamicLayoutHierarchy(); + DynamicLayoutHierarchy(const DynamicLayoutHierarchy & other) = delete; + DynamicLayoutHierarchy(DynamicLayoutHierarchy && other) = delete; + DynamicLayoutHierarchy& operator=(const DynamicLayoutHierarchy & other) = delete; + DynamicLayoutHierarchy& operator=(DynamicLayoutHierarchy && other) = delete; + + int numberOfChildren() const override { return m_numberOfChildren; } + const ExpressionLayout * const * children() const override { return m_children; }; + + //bool addChildAtIndex(ExpressionLayout * operand, int index) override; TODO +protected: + const ExpressionLayout ** m_children; + int m_numberOfChildren; +}; + +} + +#endif diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 1381aecf5..141f0f58c 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -13,19 +13,39 @@ public: Up, Down }; + enum class HorizontalDirection { + Left, + Right + }; + /* Constructor & Destructor */ ExpressionLayout(); virtual ~ExpressionLayout() = default; + static const ExpressionLayout * const * ExpressionLayoutArray2(const ExpressionLayout * e1, const ExpressionLayout * e2); + static const ExpressionLayout * const * ExpressionLayoutArray3(const ExpressionLayout * e1, const ExpressionLayout * e2, const ExpressionLayout * e3); + virtual ExpressionLayout * clone() const = 0; /* Rendering */ void draw(KDContext * ctx, KDPoint p, KDColor expressionColor = KDColorBlack, KDColor backgroundColor = KDColorWhite); KDPoint origin(); KDPoint absoluteOrigin(); KDSize size(); - KDCoordinate baseline(); + KDCoordinate baseline() const { return m_baseline; } /* Hierarchy */ - void setParent(ExpressionLayout* parent); + virtual const ExpressionLayout * const * children() const = 0; + const ExpressionLayout * child(int i) const; + ExpressionLayout * editableChild(int i) { return const_cast(child(i)); } + virtual int numberOfChildren() const = 0; + int indexOfChild(ExpressionLayout * child) const; + + void setParent(ExpressionLayout * parent); + const ExpressionLayout * parent() const { return m_parent; } + ExpressionLayout * editableParent() { return m_parent; } + bool hasAncestor(const ExpressionLayout * e) const; + + /* Dynamic Layout*/ + virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } /* Tree navigation */ virtual bool moveLeft(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? @@ -37,7 +57,6 @@ public: protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; - virtual ExpressionLayout * child(uint16_t index) = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; KDCoordinate m_baseline; ExpressionLayout * m_parent; diff --git a/poincare/include/poincare/static_layout_hierarchy.h b/poincare/include/poincare/static_layout_hierarchy.h new file mode 100644 index 000000000..daf4bbc2c --- /dev/null +++ b/poincare/include/poincare/static_layout_hierarchy.h @@ -0,0 +1,31 @@ +#ifndef POINCARE_STATIC_LAYOUT_HIERARCHY_H +#define POINCARE_STATIC_LAYOUT_HIERARCHY_H + +#include + +namespace Poincare { + +template +class StaticLayoutHierarchy : public ExpressionLayout { +public: + StaticLayoutHierarchy(); + StaticLayoutHierarchy(const ExpressionLayout * const * operands, bool cloneOperands = true); + StaticLayoutHierarchy(const ExpressionLayout * expression, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<1> + StaticLayoutHierarchy(const ExpressionLayout * expression1, const ExpressionLayout * expression2, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<2> + StaticLayoutHierarchy(const ExpressionLayout * expression1, const ExpressionLayout * expression2, const ExpressionLayout * expression3, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<3> + ~StaticLayoutHierarchy(); + StaticLayoutHierarchy(const StaticLayoutHierarchy & other) = delete; + StaticLayoutHierarchy(StaticLayoutHierarchy && other) = delete; + StaticLayoutHierarchy& operator=(const StaticLayoutHierarchy & other) = delete; + StaticLayoutHierarchy& operator=(StaticLayoutHierarchy && other) = delete; + + int numberOfChildren() const override { return T; } + const ExpressionLayout * const * children() const override { return m_children; } +protected: + void build(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands); + const ExpressionLayout * m_children[T]; +}; + +} + +#endif diff --git a/poincare/src/absolute_value.cpp b/poincare/src/absolute_value.cpp index 62bbe0000..42a523c9c 100644 --- a/poincare/src/absolute_value.cpp +++ b/poincare/src/absolute_value.cpp @@ -27,7 +27,7 @@ Expression * AbsoluteValue::setSign(Sign s, Context & context, AngleUnit angleUn ExpressionLayout * AbsoluteValue::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new AbsoluteValueLayout(operand(0)->createLayout(floatDisplayMode, complexFormat)); + return new AbsoluteValueLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false); } Expression * AbsoluteValue::shallowReduce(Context& context, AngleUnit angleUnit) { diff --git a/poincare/src/binomial_coefficient.cpp b/poincare/src/binomial_coefficient.cpp index dfabebd51..d770e25bf 100644 --- a/poincare/src/binomial_coefficient.cpp +++ b/poincare/src/binomial_coefficient.cpp @@ -79,7 +79,7 @@ ExpressionLayout * BinomialCoefficient::privateCreateLayout(FloatDisplayMode flo ExpressionLayout * childrenLayouts[2]; childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat); childrenLayouts[1] = operand(1)->createLayout(floatDisplayMode, complexFormat); - return new ParenthesisLayout(new GridLayout(childrenLayouts, 2, 1)); + return new ParenthesisLayout(new GridLayout(childrenLayouts, 2, 1, false), false); } template diff --git a/poincare/src/ceiling.cpp b/poincare/src/ceiling.cpp index 3fd5205e4..3e1b551da 100644 --- a/poincare/src/ceiling.cpp +++ b/poincare/src/ceiling.cpp @@ -62,7 +62,7 @@ Complex Ceiling::computeOnComplex(const Complex c, AngleUnit angleUnit) { ExpressionLayout * Ceiling::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new CeilingLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat)); + return new CeilingLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat), false); } } diff --git a/poincare/src/complex.cpp b/poincare/src/complex.cpp index af44cb656..d4cb71a93 100644 --- a/poincare/src/complex.cpp +++ b/poincare/src/complex.cpp @@ -465,7 +465,7 @@ ExpressionLayout * Complex::createPolarLayout(Expression::FloatDisplayMode fl if (numberOfCharInSuperscript == 0) { return new EditableStringLayout(bufferBase, numberOfCharInBase); } - return new EditableBaselineRelativeLayout(new EditableStringLayout(bufferBase, numberOfCharInBase), new EditableStringLayout(bufferSuperscript, numberOfCharInSuperscript), BaselineRelativeLayout::Type::Superscript); + return new EditableBaselineRelativeLayout(new EditableStringLayout(bufferBase, numberOfCharInBase), new EditableStringLayout(bufferSuperscript, numberOfCharInSuperscript), BaselineRelativeLayout::Type::Superscript, false); } template diff --git a/poincare/src/conjugate.cpp b/poincare/src/conjugate.cpp index 0944df809..33f1fe30b 100644 --- a/poincare/src/conjugate.cpp +++ b/poincare/src/conjugate.cpp @@ -22,7 +22,7 @@ Expression * Conjugate::clone() const { ExpressionLayout * Conjugate::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new ConjugateLayout(operand(0)->createLayout(floatDisplayMode, complexFormat)); + return new ConjugateLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false); } Expression * Conjugate::shallowReduce(Context& context, AngleUnit angleUnit) { diff --git a/poincare/src/division.cpp b/poincare/src/division.cpp index 032e58feb..d2a4edac4 100644 --- a/poincare/src/division.cpp +++ b/poincare/src/division.cpp @@ -90,7 +90,7 @@ ExpressionLayout * Division::privateCreateLayout(FloatDisplayMode floatDisplayMo assert(complexFormat != ComplexFormat::Default); const Expression * numerator = operand(0)->type() == Type::Parenthesis ? operand(0)->operand(0) : operand(0); const Expression * denominator = operand(1)->type() == Type::Parenthesis ? operand(1)->operand(0) : operand(1); - return new FractionLayout(numerator->createLayout(floatDisplayMode, complexFormat), denominator->createLayout(floatDisplayMode, complexFormat)); + return new FractionLayout(numerator->createLayout(floatDisplayMode, complexFormat), denominator->createLayout(floatDisplayMode, complexFormat), false); } template Matrix * Division::computeOnComplexAndMatrix(const Complex * c, const Matrix * n) { diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp index 3f57bf154..da49dabf0 100644 --- a/poincare/src/factorial.cpp +++ b/poincare/src/factorial.cpp @@ -79,7 +79,7 @@ ExpressionLayout * Factorial::privateCreateLayout(FloatDisplayMode floatDisplayM ExpressionLayout * childrenLayouts[2]; childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat); childrenLayouts[1] = new EditableStringLayout("!", 1); - return new HorizontalLayout(childrenLayouts, 2); + return new HorizontalLayout(childrenLayouts, 2, false); } int Factorial::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/floor.cpp b/poincare/src/floor.cpp index 48892fe5d..987306e77 100644 --- a/poincare/src/floor.cpp +++ b/poincare/src/floor.cpp @@ -59,7 +59,7 @@ Complex Floor::computeOnComplex(const Complex c, AngleUnit angleUnit) { ExpressionLayout * Floor::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new FloorLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat)); + return new FloorLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat), false); } } diff --git a/poincare/src/integral.cpp b/poincare/src/integral.cpp index 8fb5ad914..596c838e2 100644 --- a/poincare/src/integral.cpp +++ b/poincare/src/integral.cpp @@ -62,7 +62,7 @@ ExpressionLayout * Integral::privateCreateLayout(FloatDisplayMode floatDisplayMo ExpressionLayout * childrenLayouts[2]; childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat); childrenLayouts[1] = new StringLayout("dx", 2); - return new IntegralLayout(operand(1)->createLayout(floatDisplayMode, complexFormat), operand(2)->createLayout(floatDisplayMode, complexFormat), new HorizontalLayout(childrenLayouts, 2)); + return new IntegralLayout(operand(1)->createLayout(floatDisplayMode, complexFormat), operand(2)->createLayout(floatDisplayMode, complexFormat), new HorizontalLayout(childrenLayouts, 2, false), false); } template diff --git a/poincare/src/layout/absolute_value_layout.cpp b/poincare/src/layout/absolute_value_layout.cpp new file mode 100644 index 000000000..32fbf72f2 --- /dev/null +++ b/poincare/src/layout/absolute_value_layout.cpp @@ -0,0 +1,10 @@ +#include "absolute_value_layout.h" + +namespace Poincare { + +ExpressionLayout * AbsoluteValueLayout::clone() const { + AbsoluteValueLayout * layout = new AbsoluteValueLayout(const_cast(this)->operandLayout(), true); + return layout; +} + +} diff --git a/poincare/src/layout/absolute_value_layout.h b/poincare/src/layout/absolute_value_layout.h index 8f31b387c..55691659c 100644 --- a/poincare/src/layout/absolute_value_layout.h +++ b/poincare/src/layout/absolute_value_layout.h @@ -7,16 +7,12 @@ namespace Poincare { class AbsoluteValueLayout : public BracketLayout { public: - AbsoluteValueLayout(ExpressionLayout * operandLayout) : BracketLayout(operandLayout) {} - ~AbsoluteValueLayout() {} - AbsoluteValueLayout(const AbsoluteValueLayout& other) = delete; - AbsoluteValueLayout(AbsoluteValueLayout&& other) = delete; - AbsoluteValueLayout& operator=(const AbsoluteValueLayout& other) = delete; - AbsoluteValueLayout& operator=(AbsoluteValueLayout&& other) = delete; + using BracketLayout::BracketLayout; + ExpressionLayout * clone() const override; protected: - KDCoordinate widthMargin() const { return 2; } - bool renderTopBar() const { return false; } - bool renderBottomBar() const { return false; } + KDCoordinate widthMargin() const override { return 2; } + bool renderTopBar() const override { return false; } + bool renderBottomBar() const override { return false; } }; } diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index 4b553d116..0e5b23439 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -5,29 +5,17 @@ namespace Poincare { -BaselineRelativeLayout::BaselineRelativeLayout(ExpressionLayout * baseLayout, ExpressionLayout * indiceLayout, Type type) : - ExpressionLayout(), - m_baseLayout(baseLayout), - m_indiceLayout(indiceLayout), +BaselineRelativeLayout::BaselineRelativeLayout(ExpressionLayout * base, ExpressionLayout * indice, Type type, bool cloneOperands) : + StaticLayoutHierarchy(base, indice, cloneOperands), m_type(type) { - m_baseLayout->setParent(this); - m_indiceLayout->setParent(this); - m_baseline = type == Type::Subscript ? m_baseLayout->baseline() : - m_indiceLayout->size().height() + m_baseLayout->baseline() - k_indiceHeight; + m_baseline = type == Type::Subscript ? baseLayout()->baseline() : + indiceLayout()->size().height() + baseLayout()->baseline() - k_indiceHeight; } -BaselineRelativeLayout::~BaselineRelativeLayout() { - delete m_baseLayout; - delete m_indiceLayout; -} - -ExpressionLayout * BaselineRelativeLayout::baseLayout() { - return m_baseLayout; -} - -ExpressionLayout * BaselineRelativeLayout::indiceLayout() { - return m_indiceLayout; +ExpressionLayout * BaselineRelativeLayout::clone() const { + BaselineRelativeLayout * layout = new BaselineRelativeLayout(const_cast(this)->baseLayout(), const_cast(this)->indiceLayout(), m_type, true); + return layout; } bool BaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -64,37 +52,34 @@ bool BaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +ExpressionLayout * BaselineRelativeLayout::baseLayout() { + return editableChild(0); +} + +ExpressionLayout * BaselineRelativeLayout::indiceLayout() { + return editableChild(1); +} + void BaselineRelativeLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // There is nothing to draw for a subscript/superscript, only the position of the children matters } KDSize BaselineRelativeLayout::computeSize() { - KDSize baseSize = m_baseLayout->size(); - KDSize indiceSize = m_indiceLayout->size(); + KDSize baseSize = baseLayout()->size(); + KDSize indiceSize = indiceLayout()->size(); return KDSize(baseSize.width() + indiceSize.width(), baseSize.height() + indiceSize.height() - k_indiceHeight); } -ExpressionLayout * BaselineRelativeLayout::child(uint16_t index) { - switch (index) { - case 0: - return m_baseLayout; - case 1: - return m_indiceLayout; - default: - return nullptr; - } -} - KDPoint BaselineRelativeLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; - if (child == m_baseLayout && m_type == Type::Superscript) { + if (child == baseLayout() && m_type == Type::Superscript) { x = 0; - y = m_indiceLayout->size().height() - k_indiceHeight; + y = indiceLayout()->size().height() - k_indiceHeight; } - if (child == m_indiceLayout) { - x = m_baseLayout->size().width(); - y = m_type == Type::Superscript ? 0 : m_baseLayout->size().height() - k_indiceHeight; + if (child == indiceLayout()) { + x = baseLayout()->size().width(); + y = m_type == Type::Superscript ? 0 : baseLayout()->size().height() - k_indiceHeight; } return KDPoint(x,y); } diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index 1b75f6822..8ef335015 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -1,34 +1,26 @@ #ifndef POINCARE_BASELINE_RELATIVE_LAYOUT_H #define POINCARE_BASELINE_RELATIVE_LAYOUT_H -#include -#include +#include namespace Poincare { -class BaselineRelativeLayout : public ExpressionLayout { +class BaselineRelativeLayout : public StaticLayoutHierarchy<2> { public: enum class Type { Subscript, Superscript }; - BaselineRelativeLayout(ExpressionLayout * baseLayout, ExpressionLayout * indiceLayout, Type type); - ~BaselineRelativeLayout(); - BaselineRelativeLayout(const BaselineRelativeLayout& other) = delete; - BaselineRelativeLayout(BaselineRelativeLayout&& other) = delete; - BaselineRelativeLayout& operator=(const BaselineRelativeLayout& other) = delete; - BaselineRelativeLayout& operator=(BaselineRelativeLayout&& other) = delete; - ExpressionLayout * baseLayout(); - ExpressionLayout * indiceLayout(); + BaselineRelativeLayout(ExpressionLayout * base, ExpressionLayout * indice, Type type, bool cloneOperands); + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: + ExpressionLayout * baseLayout(); + ExpressionLayout * indiceLayout(); void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; - ExpressionLayout * m_baseLayout; - ExpressionLayout * m_indiceLayout; Type m_type; private: constexpr static KDCoordinate k_indiceHeight = 5; diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 1b369ec5a..487d1e2b0 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -7,23 +7,22 @@ extern "C" { namespace Poincare { -BracketLayout::BracketLayout(ExpressionLayout * operandLayout) : - ExpressionLayout(), - m_operandLayout(operandLayout) +BracketLayout::BracketLayout(ExpressionLayout * operandLayout, bool cloneOperands) : + StaticLayoutHierarchy<1>(operandLayout, cloneOperands) { - m_operandLayout->setParent(this); - m_baseline = m_operandLayout->baseline(); + m_baseline = operandLayout->baseline(); } -BracketLayout::~BracketLayout() { - delete m_operandLayout; +ExpressionLayout * BracketLayout::clone() const { + BracketLayout * layout = new BracketLayout(const_cast(this)->operandLayout(), true); + return layout; } bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the operand. // Go Left of the brackets. - if (m_operandLayout - && cursor->pointedExpressionLayout() == m_operandLayout + if (operandLayout() + && cursor->pointedExpressionLayout() == operandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -33,8 +32,8 @@ bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right of the brackets. // Go Right of the operand. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_operandLayout != nullptr); - cursor->setPointedExpressionLayout(m_operandLayout); + assert(operandLayout() != nullptr); + cursor->setPointedExpressionLayout(operandLayout()); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); @@ -49,8 +48,8 @@ bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the operand. // Go Right of the brackets. - if (m_operandLayout - && cursor->pointedExpressionLayout() == m_operandLayout + if (operandLayout() + && cursor->pointedExpressionLayout() == operandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -60,8 +59,8 @@ bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left of the brackets. // Go Left of the operand. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_operandLayout != nullptr); - cursor->setPointedExpressionLayout(m_operandLayout); + assert(operandLayout() != nullptr); + cursor->setPointedExpressionLayout(operandLayout()); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); @@ -74,12 +73,16 @@ bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +ExpressionLayout * BracketLayout::operandLayout() { + return editableChild(0); +} + void BracketLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { const KDCoordinate k_widthMargin = widthMargin(); const KDCoordinate k_externWidthMargin = externWidthMargin(); - KDSize operandSize = m_operandLayout->size(); - ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_lineThickness, m_operandLayout->size().height()), expressionColor); - ctx->fillRect(KDRect(p.x()+k_externWidthMargin+operandSize.width()+2*k_widthMargin+k_lineThickness, p.y(), k_lineThickness, m_operandLayout->size().height()), expressionColor); + KDSize operandSize = operandLayout()->size(); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_lineThickness, operandLayout()->size().height()), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin+operandSize.width()+2*k_widthMargin+k_lineThickness, p.y(), k_lineThickness, operandLayout()->size().height()), expressionColor); if (renderTopBar()) { ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_bracketWidth, k_lineThickness), expressionColor); ctx->fillRect(KDRect(p.x()+k_externWidthMargin+2*k_lineThickness+operandSize.width()+2*k_widthMargin-k_bracketWidth, p.y(), k_bracketWidth, k_lineThickness), expressionColor); @@ -93,17 +96,10 @@ void BracketLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDSize BracketLayout::computeSize() { const KDCoordinate k_widthMargin = widthMargin(); const KDCoordinate k_externWidthMargin = externWidthMargin(); - KDSize operandSize = m_operandLayout->size(); + KDSize operandSize = operandLayout()->size(); return KDSize(operandSize.width() + 2*k_externWidthMargin + 2*k_widthMargin + 2*k_lineThickness, operandSize.height()); } -ExpressionLayout * BracketLayout::child(uint16_t index) { - if (index == 0) { - return m_operandLayout; - } - return nullptr; -} - KDPoint BracketLayout::positionOfChild(ExpressionLayout * child) { const KDCoordinate k_widthMargin = widthMargin(); const KDCoordinate k_externWidthMargin = externWidthMargin(); diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index e2f6c926b..977095632 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -1,34 +1,28 @@ #ifndef POINCARE_BRACKET_LAYOUT_H #define POINCARE_BRACKET_LAYOUT_H -#include -#include +#include namespace Poincare { -class BracketLayout : public ExpressionLayout { +class BracketLayout : public StaticLayoutHierarchy<1> { public: - BracketLayout(ExpressionLayout * operandLayout); - ~BracketLayout(); - BracketLayout(const BracketLayout& other) = delete; - BracketLayout(BracketLayout&& other) = delete; - BracketLayout& operator=(const BracketLayout& other) = delete; - BracketLayout& operator=(BracketLayout&& other) = delete; + BracketLayout(ExpressionLayout * operandLayout, bool cloneOperands); + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: + ExpressionLayout * operandLayout(); KDCoordinate externWidthMargin() const { return 2; } virtual KDCoordinate widthMargin() const { return 5; } virtual bool renderTopBar() const { return true; } virtual bool renderBottomBar() const { return true; } void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_bracketWidth = 5; constexpr static KDCoordinate k_lineThickness = 1; - ExpressionLayout * m_operandLayout; }; } diff --git a/poincare/src/layout/bracket_left_layout.cpp b/poincare/src/layout/bracket_left_layout.cpp index f9024923e..07d4cb95e 100644 --- a/poincare/src/layout/bracket_left_layout.cpp +++ b/poincare/src/layout/bracket_left_layout.cpp @@ -2,6 +2,11 @@ namespace Poincare { +ExpressionLayout * BracketLeftLayout::clone() const { + BracketLeftLayout * layout = new BracketLeftLayout(); + return layout; +} + void BracketLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { //TODO Make sure m_operandHeight is up-to-date. ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_lineThickness, m_operandHeight), expressionColor); diff --git a/poincare/src/layout/bracket_left_layout.h b/poincare/src/layout/bracket_left_layout.h index ce025ec99..8f46d06d9 100644 --- a/poincare/src/layout/bracket_left_layout.h +++ b/poincare/src/layout/bracket_left_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class BracketLeftLayout : public BracketLeftRightLayout { public: using BracketLeftRightLayout::BracketLeftRightLayout; + ExpressionLayout * clone() const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; }; diff --git a/poincare/src/layout/bracket_left_right_layout.cpp b/poincare/src/layout/bracket_left_right_layout.cpp index 95c26bade..70701274d 100644 --- a/poincare/src/layout/bracket_left_right_layout.cpp +++ b/poincare/src/layout/bracket_left_right_layout.cpp @@ -8,7 +8,7 @@ extern "C" { namespace Poincare { BracketLeftRightLayout::BracketLeftRightLayout() : - ExpressionLayout(), + StaticLayoutHierarchy<0>(), m_operandHeight(36) //TODO { } diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h index 6cc309184..1c9527e1b 100644 --- a/poincare/src/layout/bracket_left_right_layout.h +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -1,19 +1,13 @@ #ifndef POINCARE_BRACKET_LEFT_RIGHT_LAYOUT_H #define POINCARE_BRACKET_LEFT_RIGHT_LAYOUT_H -#include -#include +#include namespace Poincare { -class BracketLeftRightLayout : public ExpressionLayout { +class BracketLeftRightLayout : public StaticLayoutHierarchy<0> { public: BracketLeftRightLayout(); - ~BracketLeftRightLayout() {} - BracketLeftRightLayout(const BracketLeftRightLayout& other) = delete; - BracketLeftRightLayout(BracketLeftRightLayout&& other) = delete; - BracketLeftRightLayout& operator=(const BracketLeftRightLayout& other) = delete; - BracketLeftRightLayout& operator=(BracketLeftRightLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; constexpr static KDCoordinate k_bracketWidth = 5; @@ -22,7 +16,6 @@ public: constexpr static KDCoordinate k_externWidthMargin = 2; protected: KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override { return nullptr; } KDPoint positionOfChild(ExpressionLayout * child) override; uint16_t m_operandHeight; }; diff --git a/poincare/src/layout/bracket_right_layout.cpp b/poincare/src/layout/bracket_right_layout.cpp index 3eac6ba5e..86c43e66f 100644 --- a/poincare/src/layout/bracket_right_layout.cpp +++ b/poincare/src/layout/bracket_right_layout.cpp @@ -2,6 +2,11 @@ namespace Poincare { +ExpressionLayout * BracketRightLayout::clone() const { + BracketRightLayout * layout = new BracketRightLayout(); + return layout; +} + void BracketRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { //TODO Make sure m_operandHeight is up-to-date. ctx->fillRect(KDRect(p.x()+k_widthMargin, p.y(), k_lineThickness, m_operandHeight), expressionColor); diff --git a/poincare/src/layout/bracket_right_layout.h b/poincare/src/layout/bracket_right_layout.h index a9d9c7c79..f2c25186a 100644 --- a/poincare/src/layout/bracket_right_layout.h +++ b/poincare/src/layout/bracket_right_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class BracketRightLayout : public BracketLeftRightLayout { public: using BracketLeftRightLayout::BracketLeftRightLayout; + ExpressionLayout * clone() const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; }; diff --git a/poincare/src/layout/ceiling_layout.cpp b/poincare/src/layout/ceiling_layout.cpp new file mode 100644 index 000000000..0e04baf2b --- /dev/null +++ b/poincare/src/layout/ceiling_layout.cpp @@ -0,0 +1,10 @@ +#include "ceiling_layout.h" + +namespace Poincare { + +ExpressionLayout * CeilingLayout::clone() const { + CeilingLayout * layout = new CeilingLayout(const_cast(this)->operandLayout(), true); + return layout; +} + +} diff --git a/poincare/src/layout/ceiling_layout.h b/poincare/src/layout/ceiling_layout.h index 6fe8d60a8..1dd170093 100644 --- a/poincare/src/layout/ceiling_layout.h +++ b/poincare/src/layout/ceiling_layout.h @@ -7,12 +7,8 @@ namespace Poincare { class CeilingLayout : public BracketLayout { public: - CeilingLayout(ExpressionLayout * operandLayout) : BracketLayout(operandLayout) {} - ~CeilingLayout() {} - CeilingLayout(const CeilingLayout& other) = delete; - CeilingLayout(CeilingLayout&& other) = delete; - CeilingLayout& operator=(const CeilingLayout& other) = delete; - CeilingLayout& operator=(CeilingLayout&& other) = delete; + using BracketLayout::BracketLayout; + ExpressionLayout * clone() const override; protected: bool renderBottomBar() const override { return false; } }; diff --git a/poincare/src/layout/condensed_sum_layout.cpp b/poincare/src/layout/condensed_sum_layout.cpp index e1a73f1c2..d696cb170 100644 --- a/poincare/src/layout/condensed_sum_layout.cpp +++ b/poincare/src/layout/condensed_sum_layout.cpp @@ -5,34 +5,23 @@ namespace Poincare { -CondensedSumLayout::CondensedSumLayout(ExpressionLayout * baseLayout, ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout) : - ExpressionLayout(), - m_baseLayout(baseLayout), - m_subscriptLayout(subscriptLayout), - m_superscriptLayout(superscriptLayout) +CondensedSumLayout::CondensedSumLayout(ExpressionLayout * base, ExpressionLayout * subscript, ExpressionLayout * superscript, bool cloneOperands) : + StaticLayoutHierarchy<3>(base, subscript, superscript, cloneOperands) { - m_baseLayout->setParent(this); - m_subscriptLayout->setParent(this); - if (m_superscriptLayout) { - m_superscriptLayout->setParent(this); - } - KDSize superscriptSize = m_superscriptLayout == nullptr ? KDSizeZero : m_superscriptLayout->size(); - m_baseline = m_baseLayout->baseline() + max(0, superscriptSize.height() - m_baseLayout->size().height()/2); + KDSize superscriptSize = superscriptLayout() == nullptr ? KDSizeZero : superscriptLayout()->size(); + m_baseline = baseLayout()->baseline() + max(0, superscriptSize.height() - baseLayout()->size().height()/2); } -CondensedSumLayout::~CondensedSumLayout() { - delete m_baseLayout; - delete m_subscriptLayout; - if (m_superscriptLayout) { - delete m_superscriptLayout; - } +ExpressionLayout * CondensedSumLayout::clone() const { + CondensedSumLayout * layout = new CondensedSumLayout(const_cast(this)->baseLayout(), const_cast(this)->subscriptLayout(), const_cast(this)->superscriptLayout(), true); + return layout; } bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the bounds. // Go Left of the sum. - if (((m_subscriptLayout && cursor->pointedExpressionLayout() == m_subscriptLayout) - || (m_superscriptLayout && cursor->pointedExpressionLayout() == m_superscriptLayout)) + if (((subscriptLayout() && cursor->pointedExpressionLayout() == subscriptLayout()) + || (superscriptLayout() && cursor->pointedExpressionLayout() == superscriptLayout())) && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -41,11 +30,11 @@ bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor) { } // Case: Left of the base. // Go Right of the lower bound. - if (m_baseLayout - && cursor->pointedExpressionLayout() == m_baseLayout + if (baseLayout() + && cursor->pointedExpressionLayout() == baseLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { - cursor->setPointedExpressionLayout(m_subscriptLayout); + cursor->setPointedExpressionLayout(subscriptLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } @@ -53,9 +42,9 @@ bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go to the base and move Left. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_baseLayout); - cursor->setPointedExpressionLayout(m_baseLayout); - return m_baseLayout->moveLeft(cursor); + assert(baseLayout()); + cursor->setPointedExpressionLayout(baseLayout()); + return baseLayout()->moveLeft(cursor); } // Case: Left. // Ask the parent. @@ -69,19 +58,19 @@ bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the bounds. // Go Left of the operand. - if (((m_subscriptLayout && cursor->pointedExpressionLayout() == m_subscriptLayout) - || (m_superscriptLayout && cursor->pointedExpressionLayout() == m_superscriptLayout)) + if (((subscriptLayout() && cursor->pointedExpressionLayout() == subscriptLayout()) + || (superscriptLayout() && cursor->pointedExpressionLayout() == superscriptLayout())) && cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_baseLayout != nullptr); - cursor->setPointedExpressionLayout(m_baseLayout); + assert(baseLayout() != nullptr); + cursor->setPointedExpressionLayout(baseLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } // Case: Right of the base. // Ask the parent. - if (m_baseLayout - && cursor->pointedExpressionLayout() == m_baseLayout + if (baseLayout() + && cursor->pointedExpressionLayout() == baseLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -95,8 +84,8 @@ bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left. // Go to the upper bound. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_superscriptLayout); - cursor->setPointedExpressionLayout(m_superscriptLayout); + assert(superscriptLayout()); + cursor->setPointedExpressionLayout(superscriptLayout()); return true; } // Case: Right. @@ -110,34 +99,34 @@ bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor) { bool CondensedSumLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the subscript layout, move it to the superscript. - if (m_subscriptLayout && previousLayout == m_subscriptLayout) { - assert(m_superscriptLayout != nullptr); - return m_superscriptLayout->moveUpInside(cursor); + if (subscriptLayout() && previousLayout == subscriptLayout()) { + assert(superscriptLayout() != nullptr); + return superscriptLayout()->moveUpInside(cursor); } // If the cursor is Left of the base layout, move it to the superscript. - if (m_baseLayout - && previousLayout == m_baseLayout - && cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Left)) + if (baseLayout() + && previousLayout == baseLayout() + && cursor->positionIsEquivalentTo(baseLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(m_superscriptLayout != nullptr); - return m_superscriptLayout->moveUpInside(cursor); + assert(superscriptLayout() != nullptr); + return superscriptLayout()->moveUpInside(cursor); } return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } bool CondensedSumLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the superscript layout, move it to the subscript. - if (m_superscriptLayout && previousLayout == m_superscriptLayout) { - assert(m_subscriptLayout != nullptr); - return m_subscriptLayout->moveUpInside(cursor); + if (superscriptLayout() && previousLayout == superscriptLayout()) { + assert(subscriptLayout() != nullptr); + return subscriptLayout()->moveUpInside(cursor); } // If the cursor is Left of the base layout, move it to the subscript. - if (m_baseLayout - && previousLayout == m_baseLayout - && cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Left)) + if (baseLayout() + && previousLayout == baseLayout() + && cursor->positionIsEquivalentTo(baseLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(m_subscriptLayout != nullptr); - return m_subscriptLayout->moveUpInside(cursor); + assert(subscriptLayout() != nullptr); + return subscriptLayout()->moveUpInside(cursor); } return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } @@ -147,42 +136,41 @@ void CondensedSumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionCo } KDSize CondensedSumLayout::computeSize() { - KDSize baseSize = m_baseLayout->size(); - KDSize subscriptSize = m_subscriptLayout->size(); - KDSize superscriptSize = m_superscriptLayout == nullptr ? KDSizeZero : m_superscriptLayout->size(); + KDSize baseSize = baseLayout()->size(); + KDSize subscriptSize = subscriptLayout()->size(); + KDSize superscriptSize = superscriptLayout() == nullptr ? KDSizeZero : superscriptLayout()->size(); return KDSize(baseSize.width() + max(subscriptSize.width(), superscriptSize.width()), max(baseSize.height()/2, subscriptSize.height()) + max(baseSize.height()/2, superscriptSize.height())); } -ExpressionLayout * CondensedSumLayout::child(uint16_t index) { - switch (index) { - case 0: - return m_baseLayout; - case 1: - return m_subscriptLayout; - case 2: - return m_superscriptLayout; - default: - return nullptr; - } -} - KDPoint CondensedSumLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; - KDSize baseSize = m_baseLayout->size(); - KDSize superscriptSize = m_superscriptLayout == nullptr ? KDSizeZero : m_superscriptLayout->size(); - if (child == m_baseLayout) { + KDSize baseSize = baseLayout()->size(); + KDSize superscriptSize = superscriptLayout() == nullptr ? KDSizeZero : superscriptLayout()->size(); + if (child == baseLayout()) { y = max(0, superscriptSize.height() - baseSize.height()/2); } - if (child == m_subscriptLayout) { + if (child == subscriptLayout()) { x = baseSize.width(); y = max(baseSize.height()/2, superscriptSize.height()); } - if (child == m_superscriptLayout) { + if (child == superscriptLayout()) { x = baseSize.width(); } return KDPoint(x,y); } +ExpressionLayout * CondensedSumLayout::baseLayout() { + return editableChild(0); +} + +ExpressionLayout * CondensedSumLayout::subscriptLayout() { + return editableChild(1); +} + +ExpressionLayout * CondensedSumLayout::superscriptLayout() { + return editableChild(2); +} + } diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index 1d15dc1c3..16528e6c7 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -1,19 +1,14 @@ #ifndef POINCARE_CONDENSED_SUM_LAYOUT_H #define POINCARE_CONDENSED_SUM_LAYOUT_H -#include -#include +#include namespace Poincare { -class CondensedSumLayout : public ExpressionLayout { +class CondensedSumLayout : public StaticLayoutHierarchy<3> { public: - CondensedSumLayout(ExpressionLayout * baseLayout, ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout = nullptr); - ~CondensedSumLayout(); - CondensedSumLayout(const CondensedSumLayout& other) = delete; - CondensedSumLayout(CondensedSumLayout&& other) = delete; - CondensedSumLayout& operator=(const CondensedSumLayout& other) = delete; - CondensedSumLayout& operator=(CondensedSumLayout&& other) = delete; + CondensedSumLayout(ExpressionLayout * base, ExpressionLayout * subscript, ExpressionLayout * superscript, bool cloneOperands); + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; @@ -21,12 +16,11 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: - ExpressionLayout * m_baseLayout; - ExpressionLayout * m_subscriptLayout; - ExpressionLayout * m_superscriptLayout; + ExpressionLayout * baseLayout(); + ExpressionLayout * subscriptLayout(); + ExpressionLayout * superscriptLayout(); }; } diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index 18844c96f..db289ce45 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -7,23 +7,22 @@ extern "C" { namespace Poincare { -ConjugateLayout::ConjugateLayout(ExpressionLayout * operandLayout) : - ExpressionLayout(), - m_operandLayout(operandLayout) +ConjugateLayout::ConjugateLayout(ExpressionLayout * operand, bool cloneOperands) : + StaticLayoutHierarchy<1>(operand, cloneOperands) { - m_operandLayout->setParent(this); - m_baseline = m_operandLayout->baseline()+k_overlineWidth+k_overlineMargin; + m_baseline = operandLayout()->baseline()+k_overlineWidth+k_overlineMargin; } -ConjugateLayout::~ConjugateLayout() { - delete m_operandLayout; +ExpressionLayout * ConjugateLayout::clone() const { + ConjugateLayout * layout = new ConjugateLayout(const_cast(this)->operandLayout(), true); + return layout; } bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the operand. // Ask the parent. - if (m_operandLayout - && cursor->pointedExpressionLayout() == m_operandLayout + if (operandLayout() + && cursor->pointedExpressionLayout() == operandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -36,9 +35,9 @@ bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go to the operand and move Left. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_operandLayout != nullptr); - cursor->setPointedExpressionLayout(m_operandLayout); - return m_operandLayout->moveLeft(cursor); + assert(operandLayout() != nullptr); + cursor->setPointedExpressionLayout(operandLayout()); + return operandLayout()->moveLeft(cursor); } // Case: Left. // Ask the parent. @@ -52,8 +51,8 @@ bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the operand. // Ask the parent. - if (m_operandLayout - && cursor->pointedExpressionLayout() == m_operandLayout + if (operandLayout() + && cursor->pointedExpressionLayout() == operandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -66,9 +65,9 @@ bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left. // Go to the operand and move Right. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_operandLayout != nullptr); - cursor->setPointedExpressionLayout(m_operandLayout); - return m_operandLayout->moveRight(cursor); + assert(operandLayout() != nullptr); + cursor->setPointedExpressionLayout(operandLayout()); + return operandLayout()->moveRight(cursor); } // Case: Right. // Ask the parent. @@ -80,24 +79,21 @@ bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { } void ConjugateLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - ctx->fillRect(KDRect(p.x(), p.y(), m_operandLayout->size().width(), k_overlineWidth), expressionColor); + ctx->fillRect(KDRect(p.x(), p.y(), operandLayout()->size().width(), k_overlineWidth), expressionColor); } KDSize ConjugateLayout::computeSize() { - KDSize operandSize = m_operandLayout->size(); + KDSize operandSize = operandLayout()->size(); return KDSize(operandSize.width(), operandSize.height()+k_overlineWidth+k_overlineMargin); } -ExpressionLayout * ConjugateLayout::child(uint16_t index) { - if (index == 0) { - return m_operandLayout; - } - return nullptr; -} - KDPoint ConjugateLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(0, k_overlineWidth+k_overlineMargin); } +ExpressionLayout * ConjugateLayout::operandLayout() { + return editableChild(0); +} + } diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 6e1030c88..15834cce4 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -1,30 +1,24 @@ #ifndef POINCARE_CONJUGATE_LAYOUT_H #define POINCARE_CONJUGATE_LAYOUT_H -#include -#include +#include namespace Poincare { -class ConjugateLayout : public ExpressionLayout { +class ConjugateLayout : public StaticLayoutHierarchy<1> { public: - ConjugateLayout(ExpressionLayout * operandLayout); - ~ConjugateLayout(); - ConjugateLayout(const ConjugateLayout& other) = delete; - ConjugateLayout(ConjugateLayout&& other) = delete; - ConjugateLayout& operator=(const ConjugateLayout& other) = delete; - ConjugateLayout& operator=(ConjugateLayout&& other) = delete; + ConjugateLayout(ExpressionLayout * operand, bool cloneOperands); + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_overlineWidth = 1; constexpr static KDCoordinate k_overlineMargin = 3; - ExpressionLayout * m_operandLayout; + ExpressionLayout * operandLayout(); }; } diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp new file mode 100644 index 000000000..09106b617 --- /dev/null +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -0,0 +1,62 @@ +#include +extern "C" { +#include +#include +} + +namespace Poincare { + +DynamicLayoutHierarchy::DynamicLayoutHierarchy() : + ExpressionLayout(), + m_children(nullptr), + m_numberOfChildren(0) +{ +} + +DynamicLayoutHierarchy::DynamicLayoutHierarchy(const ExpressionLayout * const * children, int numberOfChildren, bool cloneChildren) : + ExpressionLayout(), + m_numberOfChildren(numberOfChildren) +{ + assert(children != nullptr); + m_children = new const ExpressionLayout * [numberOfChildren]; + for (int i=0; iclone(); + } else { + m_children[i] = children[i]; + } + const_cast(m_children[i])->setParent(this); + } +} + +DynamicLayoutHierarchy::~DynamicLayoutHierarchy() { + if (m_children != nullptr) { + for (int i = 0; i < m_numberOfChildren; i++) { + if (m_children[i] != nullptr) { + delete m_children[i]; + } + } + } + delete[] m_children; +} + +/*bool DynamicLayoutHierarchy::addChildAtIndex(ExpressionLayout * child, int index) { + assert(index >= 0 && index <= m_numberOfChildren); + const ExpressionLayout ** newChildren = new const ExpressionLayout * [m_numberOfChildren+1]; + int j = 0; + for (int i=0; i<=m_numberOfChildren; i++) { + if (i == index) { + child->setParent(this); + newChildren[i] = child; + } else { + newChildren[i] = m_children[j++]; + } + } + delete[] m_children; + m_children = newChildren; + m_numberOfChildren += 1; + return true; +}*/ //TODO + +} diff --git a/poincare/src/layout/editable_baseline_relative_layout.cpp b/poincare/src/layout/editable_baseline_relative_layout.cpp index b06e27449..e5b0d29c1 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.cpp +++ b/poincare/src/layout/editable_baseline_relative_layout.cpp @@ -5,22 +5,27 @@ namespace Poincare { +ExpressionLayout * EditableBaselineRelativeLayout::clone() const { + EditableBaselineRelativeLayout * layout = new EditableBaselineRelativeLayout(const_cast(this)->baseLayout(), const_cast(this)->indiceLayout(), m_type, true); + return layout; +} + bool EditableBaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the indice. // Go from the indice to the base. - if (m_indiceLayout - && cursor->pointedExpressionLayout() == m_indiceLayout + if (indiceLayout() + && cursor->pointedExpressionLayout() == indiceLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_baseLayout != nullptr); - cursor->setPointedExpressionLayout(m_baseLayout); + assert(baseLayout() != nullptr); + cursor->setPointedExpressionLayout(baseLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } // Case: Left of the base. // Ask the parent. - if (m_baseLayout - && cursor->pointedExpressionLayout() == m_baseLayout + if (baseLayout() + && cursor->pointedExpressionLayout() == baseLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -33,8 +38,8 @@ bool EditableBaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go to the indice. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_indiceLayout != nullptr); - cursor->setPointedExpressionLayout(m_indiceLayout); + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); return true; } // Case: Left. @@ -49,19 +54,19 @@ bool EditableBaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool EditableBaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the base. // Go from the base to the indice. - if (m_baseLayout - && cursor->pointedExpressionLayout() == m_baseLayout + if (baseLayout() + && cursor->pointedExpressionLayout() == baseLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_indiceLayout != nullptr); - cursor->setPointedExpressionLayout(m_indiceLayout); + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } // Case: Right of the indice. // Go Right. - if (m_indiceLayout - && cursor->pointedExpressionLayout() == m_indiceLayout + if (indiceLayout() + && cursor->pointedExpressionLayout() == indiceLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -71,9 +76,9 @@ bool EditableBaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) // Case: Left. // Go to the base and move Right. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_baseLayout != nullptr); - cursor->setPointedExpressionLayout(m_baseLayout); - return m_baseLayout->moveRight(cursor); + assert(baseLayout() != nullptr); + cursor->setPointedExpressionLayout(baseLayout()); + return baseLayout()->moveRight(cursor); } // Case: Right. // Ask the parent. @@ -89,20 +94,20 @@ bool EditableBaselineRelativeLayout::moveUp(ExpressionLayoutCursor * cursor, Exp // If the baseline is a superscript: if (m_type == BaselineRelativeLayout::Type::Superscript) { // If the cursor is Right of the base layout, move it to the indice. - if (m_baseLayout - && previousLayout == m_baseLayout - && cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Right)) + if (baseLayout() + && previousLayout == baseLayout() + && cursor->positionIsEquivalentTo(baseLayout(), ExpressionLayoutCursor::Position::Right)) { - assert(m_indiceLayout != nullptr); - cursor->setPointedExpressionLayout(m_indiceLayout); + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); cursor->setPositionInside(0); return true; } // If the cursor is Right, move it to the indice. if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) { - assert(m_indiceLayout != nullptr); - cursor->setPointedExpressionLayout(m_indiceLayout); + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); cursor->setPositionInside(0); return true; @@ -110,19 +115,19 @@ bool EditableBaselineRelativeLayout::moveUp(ExpressionLayoutCursor * cursor, Exp } // If the baseline is a subscript: if (m_type == BaselineRelativeLayout::Type::Subscript - && m_indiceLayout - && previousLayout == m_indiceLayout) + && indiceLayout() + && previousLayout == indiceLayout()) { // If the cursor is Left of the indice layout, move it to the base. - if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Left)) { - assert(m_baseLayout != nullptr); - cursor->setPointedExpressionLayout(m_baseLayout); + if (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Left)) { + assert(baseLayout() != nullptr); + cursor->setPointedExpressionLayout(baseLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); cursor->setPositionInside(0); return true; } // If the cursor is Right of the indice layout, move it Right. - if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Right)) { + if (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Right)) { cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); cursor->setPositionInside(0); @@ -136,20 +141,20 @@ bool EditableBaselineRelativeLayout::moveDown(ExpressionLayoutCursor * cursor, E // If the baseline is a subscript: if (m_type == BaselineRelativeLayout::Type::Subscript) { // If the cursor is Right of the base layout, move it to the indice. - if (m_baseLayout - && previousLayout == m_baseLayout - && cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Right)) + if (baseLayout() + && previousLayout == baseLayout() + && cursor->positionIsEquivalentTo(baseLayout(), ExpressionLayoutCursor::Position::Right)) { - assert(m_indiceLayout != nullptr); - cursor->setPointedExpressionLayout(m_indiceLayout); + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); cursor->setPositionInside(0); return true; } // If the cursor is Right, move it to the indice. if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) { - assert(m_indiceLayout != nullptr); - cursor->setPointedExpressionLayout(m_indiceLayout); + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); cursor->setPositionInside(0); return true; @@ -157,20 +162,20 @@ bool EditableBaselineRelativeLayout::moveDown(ExpressionLayoutCursor * cursor, E } // If the baseline is a superscript: if (m_type == BaselineRelativeLayout::Type::Superscript - && m_indiceLayout - && previousLayout == m_indiceLayout) + && indiceLayout() + && previousLayout == indiceLayout()) { // If the cursor is Left of the indice layout, move it to the base. - if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Left)) { - assert(m_indiceLayout != nullptr); - cursor->setPointedExpressionLayout(m_baseLayout); + if (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Left)) { + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(baseLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); cursor->setPositionInside(0); return true; } // If the cursor is Right of the indice layout, move it Right. - if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Right)) { - assert(m_indiceLayout != nullptr); + if (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Right)) { + assert(indiceLayout() != nullptr); cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); cursor->setPositionInside(0); diff --git a/poincare/src/layout/editable_baseline_relative_layout.h b/poincare/src/layout/editable_baseline_relative_layout.h index 72ef5aa4a..22c5c968f 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.h +++ b/poincare/src/layout/editable_baseline_relative_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class EditableBaselineRelativeLayout : public BaselineRelativeLayout { public: using BaselineRelativeLayout::BaselineRelativeLayout; + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; diff --git a/poincare/src/layout/editable_string_layout.cpp b/poincare/src/layout/editable_string_layout.cpp index 1dfd613b8..951989192 100644 --- a/poincare/src/layout/editable_string_layout.cpp +++ b/poincare/src/layout/editable_string_layout.cpp @@ -5,6 +5,11 @@ namespace Poincare { +ExpressionLayout * EditableStringLayout::clone() const { + EditableStringLayout * layout = new EditableStringLayout(m_string, strlen(m_string), m_fontSize); + return layout; +} + bool EditableStringLayout::moveLeft(ExpressionLayoutCursor * cursor) { assert(cursor->pointedExpressionLayout() == this); // Case: Right. diff --git a/poincare/src/layout/editable_string_layout.h b/poincare/src/layout/editable_string_layout.h index 75e8b77d9..147cb1622 100644 --- a/poincare/src/layout/editable_string_layout.h +++ b/poincare/src/layout/editable_string_layout.h @@ -9,6 +9,7 @@ namespace Poincare { class EditableStringLayout : public StringLayout { public: using StringLayout::StringLayout; + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; private: diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 630b1c61e..6defb6e39 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -1,6 +1,6 @@ #include #include -#include "string_layout.h" +#include #include #include @@ -14,8 +14,19 @@ ExpressionLayout::ExpressionLayout() : m_frame(KDRectZero) { } -KDCoordinate ExpressionLayout::baseline() { - return m_baseline; +const ExpressionLayout * const * ExpressionLayout::ExpressionLayoutArray2(const ExpressionLayout * e1, const ExpressionLayout * e2) { + static const ExpressionLayout * result[2] = {nullptr, nullptr}; + result[0] = e1; + result[1] = e2; + return result; +} + +const ExpressionLayout * const * ExpressionLayout::ExpressionLayoutArray3(const ExpressionLayout * e1, const ExpressionLayout * e2, const ExpressionLayout * e3) { + static const ExpressionLayout * result[3] = {nullptr, nullptr, nullptr}; + result[0] = e1; + result[1] = e2; + result[2] = e3; + return result; } KDPoint ExpressionLayout::origin() { @@ -29,7 +40,7 @@ KDPoint ExpressionLayout::origin() { void ExpressionLayout::draw(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { int i = 0; - while (ExpressionLayout * c = child(i++)) { + while (ExpressionLayout * c = editableChild(i++)) { c->draw(ctx, p, expressionColor, backgroundColor); } render(ctx, absoluteOrigin().translatedBy(p), expressionColor, backgroundColor); @@ -55,10 +66,37 @@ KDSize ExpressionLayout::size() { return m_frame.size(); } +const ExpressionLayout * ExpressionLayout::child(int i) const { + assert(i >= 0); + assert(i < numberOfChildren()); + assert(children()[i]->parent() == nullptr || children()[i]->parent() == this); + return children()[i]; +} + +int ExpressionLayout::indexOfChild(ExpressionLayout * child) const { + for (int i = 0; i < numberOfChildren(); i++) { + if (children()[i] == child) { + return i; + } + } + return -1; +} + void ExpressionLayout::setParent(ExpressionLayout* parent) { m_parent = parent; } +bool ExpressionLayout::hasAncestor(const ExpressionLayout * e) const { + assert(m_parent != this); + if (m_parent == e) { + return true; + } + if (m_parent == nullptr) { + return false; + } + return m_parent->hasAncestor(e); +} + bool ExpressionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { if (m_parent) { return m_parent->moveUp(cursor, this, previousLayout); @@ -137,7 +175,7 @@ void ExpressionLayout::moveCursorInsideAtDirection ( if (layoutIsUnderOrAbove || layoutContains) { int childIndex = 0; while (child(childIndex++)) { - child(childIndex-1)->moveCursorInsideAtDirection(direction, cursor, childResult, castedResultPosition, resultPositionInside, resultScore); + editableChild(childIndex-1)->moveCursorInsideAtDirection(direction, cursor, childResult, castedResultPosition, resultPositionInside, resultScore); } } } diff --git a/poincare/src/layout/floor_layout.cpp b/poincare/src/layout/floor_layout.cpp new file mode 100644 index 000000000..598cfea39 --- /dev/null +++ b/poincare/src/layout/floor_layout.cpp @@ -0,0 +1,10 @@ +#include "floor_layout.h" + +namespace Poincare { + +ExpressionLayout * FloorLayout::clone() const { + FloorLayout * layout = new FloorLayout(const_cast(this)->operandLayout(), true); + return layout; +} + +} diff --git a/poincare/src/layout/floor_layout.h b/poincare/src/layout/floor_layout.h index 17c994eb5..1bfb7e8f3 100644 --- a/poincare/src/layout/floor_layout.h +++ b/poincare/src/layout/floor_layout.h @@ -7,12 +7,8 @@ namespace Poincare { class FloorLayout : public BracketLayout { public: - FloorLayout(ExpressionLayout * operandLayout) : BracketLayout(operandLayout) {} - ~FloorLayout() {} - FloorLayout(const FloorLayout& other) = delete; - FloorLayout(FloorLayout&& other) = delete; - FloorLayout& operator=(const FloorLayout& other) = delete; - FloorLayout& operator=(FloorLayout&& other) = delete; + using BracketLayout::BracketLayout; + ExpressionLayout * clone() const override; protected: bool renderTopBar() const override { return false; } }; diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 4191504ab..41d4ec315 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -5,24 +5,23 @@ namespace Poincare { -FractionLayout::FractionLayout(ExpressionLayout * numerator_layout, ExpressionLayout * denominator_layout) : -ExpressionLayout(), m_numerator_layout(numerator_layout), m_denominator_layout(denominator_layout) { - m_numerator_layout->setParent(this); - m_denominator_layout->setParent(this); - m_baseline = m_numerator_layout->size().height() +FractionLayout::FractionLayout(ExpressionLayout * numerator, ExpressionLayout * denominator, bool cloneOperands) : + StaticLayoutHierarchy<2>(numerator, denominator, cloneOperands) +{ + m_baseline = numeratorLayout()->size().height() + k_fractionLineMargin + k_fractionLineHeight; } -FractionLayout::~FractionLayout() { - delete m_denominator_layout; - delete m_numerator_layout; +ExpressionLayout * FractionLayout::clone() const { + FractionLayout * layout = new FractionLayout(const_cast(this)->numeratorLayout(), const_cast(this)->denominatorLayout(), true); + return layout; } bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the numerator or the denominator. // Go Left of the fraction. - if (((m_numerator_layout && cursor->pointedExpressionLayout() == m_numerator_layout) - || (m_denominator_layout && cursor->pointedExpressionLayout() == m_denominator_layout)) + if (((numeratorLayout() && cursor->pointedExpressionLayout() == numeratorLayout()) + || (denominatorLayout() && cursor->pointedExpressionLayout() == denominatorLayout())) && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -32,8 +31,8 @@ bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go to the denominator. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_denominator_layout != nullptr); - cursor->setPointedExpressionLayout(m_denominator_layout); + assert(denominatorLayout() != nullptr); + cursor->setPointedExpressionLayout(denominatorLayout()); return true; } // Case: Left. @@ -48,8 +47,8 @@ bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool FractionLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the numerator or the denominator. // Go Right of the fraction. - if (((m_numerator_layout && cursor->pointedExpressionLayout() == m_numerator_layout) - || (m_denominator_layout && cursor->pointedExpressionLayout() == m_denominator_layout)) + if (((numeratorLayout() && cursor->pointedExpressionLayout() == numeratorLayout()) + || (denominatorLayout() && cursor->pointedExpressionLayout() == denominatorLayout())) && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -59,8 +58,8 @@ bool FractionLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left. // Go to the numerator. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_numerator_layout != nullptr); - cursor->setPointedExpressionLayout(m_numerator_layout); + assert(numeratorLayout() != nullptr); + cursor->setPointedExpressionLayout(numeratorLayout()); return true; } // Case: Right. @@ -74,69 +73,66 @@ bool FractionLayout::moveRight(ExpressionLayoutCursor * cursor) { bool FractionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside denominator, move it to the numerator. - if (m_denominator_layout && previousLayout == m_denominator_layout) { - assert(m_numerator_layout != nullptr); - return m_numerator_layout->moveUpInside(cursor); + if (denominatorLayout() && previousLayout == denominatorLayout()) { + assert(numeratorLayout() != nullptr); + return numeratorLayout()->moveUpInside(cursor); } // If the cursor is Left or Right, move it to the numerator. if (cursor->pointedExpressionLayout() == this){ - assert(m_numerator_layout != nullptr); - return m_numerator_layout->moveUpInside(cursor); + assert(numeratorLayout() != nullptr); + return numeratorLayout()->moveUpInside(cursor); } return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside numerator, move it to the denominator. - if (m_numerator_layout && previousLayout == m_numerator_layout) { - assert(m_denominator_layout != nullptr); - return m_denominator_layout->moveDownInside(cursor); + if (numeratorLayout() && previousLayout == numeratorLayout()) { + assert(denominatorLayout() != nullptr); + return denominatorLayout()->moveDownInside(cursor); } // If the cursor is Left or Right, move it to the denominator. if (cursor->pointedExpressionLayout() == this){ - assert(m_denominator_layout != nullptr); - return m_denominator_layout->moveDownInside(cursor); + assert(denominatorLayout() != nullptr); + return denominatorLayout()->moveDownInside(cursor); } return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } void FractionLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - KDCoordinate fractionLineY = p.y() + m_numerator_layout->size().height() + k_fractionLineMargin; + KDCoordinate fractionLineY = p.y() + numeratorLayout()->size().height() + k_fractionLineMargin; ctx->fillRect(KDRect(p.x()+k_fractionBorderMargin, fractionLineY, size().width()-2*k_fractionBorderMargin, 1), expressionColor); } KDSize FractionLayout::computeSize() { - KDCoordinate width = max(m_numerator_layout->size().width(), m_denominator_layout->size().width()) + KDCoordinate width = max(numeratorLayout()->size().width(), denominatorLayout()->size().width()) + 2*k_fractionBorderLength+2*k_fractionBorderMargin; - KDCoordinate height = m_numerator_layout->size().height() + KDCoordinate height = numeratorLayout()->size().height() + k_fractionLineMargin + k_fractionLineHeight + k_fractionLineMargin - + m_denominator_layout->size().height(); + + denominatorLayout()->size().height(); return KDSize(width, height); } -ExpressionLayout * FractionLayout::child(uint16_t index) { - switch (index) { - case 0: - return m_numerator_layout; - case 1: - return m_denominator_layout; - default: - return nullptr; - } -} - KDPoint FractionLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; - if (child == m_numerator_layout) { - x = (KDCoordinate)((size().width() - m_numerator_layout->size().width())/2); - } else if (child == m_denominator_layout) { - x = (KDCoordinate)((size().width() - m_denominator_layout->size().width())/2); - y = (KDCoordinate)(m_numerator_layout->size().height() + 2*k_fractionLineMargin + k_fractionLineHeight); + if (child == numeratorLayout()) { + x = (KDCoordinate)((size().width() - numeratorLayout()->size().width())/2); + } else if (child == denominatorLayout()) { + x = (KDCoordinate)((size().width() - denominatorLayout()->size().width())/2); + y = (KDCoordinate)(numeratorLayout()->size().height() + 2*k_fractionLineMargin + k_fractionLineHeight); } else { assert(false); // Should not happen } return KDPoint(x, y); } +ExpressionLayout * FractionLayout::numeratorLayout() { + return editableChild(0); +} + +ExpressionLayout * FractionLayout::denominatorLayout() { + return editableChild(1); +} + } diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 97dd6043a..13154045b 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -1,19 +1,14 @@ #ifndef POINCARE_FRACTION_LAYOUT_H #define POINCARE_FRACTION_LAYOUT_H -#include -#include +#include namespace Poincare { -class FractionLayout : public ExpressionLayout { +class FractionLayout : public StaticLayoutHierarchy<2> { public: - FractionLayout(ExpressionLayout * numerator, ExpressionLayout * denominator); - ~FractionLayout(); - FractionLayout(const FractionLayout& other) = delete; - FractionLayout(FractionLayout&& other) = delete; - FractionLayout& operator=(const FractionLayout& other) = delete; - FractionLayout& operator=(FractionLayout&& other) = delete; + FractionLayout(ExpressionLayout * numerator, ExpressionLayout * denominator, bool cloneOperands); + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; @@ -21,15 +16,14 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_fractionBorderLength = 2; constexpr static KDCoordinate k_fractionBorderMargin = 2; constexpr static KDCoordinate k_fractionLineMargin = 2; constexpr static KDCoordinate k_fractionLineHeight = 2; - ExpressionLayout * m_numerator_layout; - ExpressionLayout * m_denominator_layout; + ExpressionLayout * numeratorLayout(); + ExpressionLayout * denominatorLayout(); }; } diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 075854b95..c379c5883 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -7,24 +7,17 @@ extern "C" { namespace Poincare { -GridLayout::GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int numberOfColumns) : - ExpressionLayout(), +GridLayout::GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands) : + DynamicLayoutHierarchy(entryLayouts, numberOfRows*numberOfColumns, cloneOperands), m_numberOfRows(numberOfRows), m_numberOfColumns(numberOfColumns) { - m_entryLayouts = new ExpressionLayout *[numberOfColumns*numberOfRows]; - for (int i = 0; i < m_numberOfRows*m_numberOfColumns; i++) { - m_entryLayouts[i] = entryLayouts[i]; - m_entryLayouts[i]->setParent(this); - } m_baseline = (height()+1)/2; } -GridLayout::~GridLayout() { - for (int i=0; i(children()), m_numberOfRows, m_numberOfColumns, true); + return layout; } bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -33,7 +26,7 @@ bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { if (cursor->pointedExpressionLayout() == this && cursor->position() == ExpressionLayoutCursor::Position::Right) { - ExpressionLayout * lastChild = m_entryLayouts[m_numberOfColumns*m_numberOfRows-1]; + ExpressionLayout * lastChild = editableChild(m_numberOfColumns*m_numberOfRows-1); assert(lastChild != nullptr); cursor->setPointedExpressionLayout(lastChild); return true; @@ -50,7 +43,7 @@ bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { } // Case: Left of another child. // Go Right of its brother on the left. - cursor->setPointedExpressionLayout(m_entryLayouts[childIndex-1]); + cursor->setPointedExpressionLayout(editableChild(childIndex-1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } @@ -70,7 +63,7 @@ bool GridLayout::moveRight(ExpressionLayoutCursor * cursor) { && cursor->position() == ExpressionLayoutCursor::Position::Left) { assert(m_numberOfColumns*m_numberOfRows >= 1); - ExpressionLayout * firstChild = m_entryLayouts[0]; + ExpressionLayout * firstChild = editableChild(0); assert(firstChild != nullptr); cursor->setPointedExpressionLayout(firstChild); return true; @@ -87,7 +80,7 @@ bool GridLayout::moveRight(ExpressionLayoutCursor * cursor) { } // Case: Right of another child. // Go Left of its brother on the right. - cursor->setPointedExpressionLayout(m_entryLayouts[childIndex+1]); + cursor->setPointedExpressionLayout(editableChild(childIndex+1)); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } @@ -105,7 +98,7 @@ bool GridLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * prev // neighbourg. int childIndex = indexOfChild(previousLayout); if (childIndex >- 1 && !childIsTopOfGrid(childIndex)) { - return m_entryLayouts[childIndex - m_numberOfColumns]->moveUpInside(cursor); + return editableChild(childIndex - m_numberOfColumns)->moveUpInside(cursor); } return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } @@ -115,7 +108,7 @@ bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * pr // lower neighbourg. int childIndex = indexOfChild(previousLayout); if (childIndex >- 1 && !childIsBottomOfGrid(childIndex)) { - return m_entryLayouts[childIndex + m_numberOfColumns]->moveDownInside(cursor); + return editableChild(childIndex + m_numberOfColumns)->moveDownInside(cursor); } return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } @@ -123,7 +116,7 @@ bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * pr KDCoordinate GridLayout::rowBaseline(int i) { KDCoordinate rowBaseline = 0; for (int j = 0; j < m_numberOfColumns; j++) { - rowBaseline = max(rowBaseline, m_entryLayouts[i*m_numberOfColumns+j]->baseline()); + rowBaseline = max(rowBaseline, child(i*m_numberOfColumns+j)->baseline()); } return rowBaseline; } @@ -132,7 +125,7 @@ KDCoordinate GridLayout::rowHeight(int i) { KDCoordinate rowHeight = 0; KDCoordinate baseline = rowBaseline(i); for (int j = 0; j < m_numberOfColumns; j++) { - rowHeight = max(rowHeight, m_entryLayouts[i*m_numberOfColumns+j]->size().height() - m_entryLayouts[i*m_numberOfColumns+j]->baseline()); + rowHeight = max(rowHeight, editableChild(i*m_numberOfColumns+j)->size().height() - child(i*m_numberOfColumns+j)->baseline()); } return baseline+rowHeight; } @@ -149,7 +142,7 @@ KDCoordinate GridLayout::height() { KDCoordinate GridLayout::columnWidth(int j) { KDCoordinate columnWidth = 0; for (int i = 0; i < m_numberOfRows; i++) { - columnWidth = max(columnWidth, m_entryLayouts[i*m_numberOfColumns+j]->size().width()); + columnWidth = max(columnWidth, editableChild(i*m_numberOfColumns+j)->size().width()); } return columnWidth; } @@ -171,19 +164,12 @@ KDSize GridLayout::computeSize() { return KDSize(width(), height()); } -ExpressionLayout * GridLayout::child(uint16_t index) { - if (index < m_numberOfColumns*m_numberOfRows) { - return m_entryLayouts[index]; - } - return nullptr; -} - KDPoint GridLayout::positionOfChild(ExpressionLayout * child) { int rowIndex = 0; int columnIndex = 0; for (int i = 0; i < m_numberOfRows; i++) { for (int j = 0; j < m_numberOfColumns; j++) { - if (child == m_entryLayouts[i*m_numberOfColumns+j]) { + if (child == editableChild(i*m_numberOfColumns+j)) { rowIndex = i; columnIndex = j; break; @@ -205,7 +191,7 @@ KDPoint GridLayout::positionOfChild(ExpressionLayout * child) { int GridLayout::indexOfChild(ExpressionLayout * eL) const { for (int i = 0; i < m_numberOfRows*m_numberOfColumns; i++) { - if (eL == m_entryLayouts[i]) { + if (eL == child(i)) { return i; } } diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 40cec0ef4..ce48b66e6 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -1,28 +1,24 @@ #ifndef POINCARE_GRID_LAYOUT_H #define POINCARE_GRID_LAYOUT_H -#include -#include +#include namespace Poincare { -class GridLayout : public ExpressionLayout { - //TODO Split it in MatrixLayout and BinomialCoefficientayout. +class GridLayout : public DynamicLayoutHierarchy { public: - GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int numberOfColumns); - ~GridLayout(); - GridLayout(const GridLayout& other) = delete; - GridLayout(GridLayout&& other) = delete; - GridLayout& operator=(const GridLayout& other) = delete; - GridLayout& operator=(GridLayout&& other) = delete; + GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands); + ExpressionLayout * clone() const override; + + /* Navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_gridEntryMargin = 6; @@ -36,7 +32,6 @@ private: bool childIsRightOfGrid(int index) const; bool childIsTopOfGrid(int index) const; bool childIsBottomOfGrid(int index) const; - ExpressionLayout ** m_entryLayouts; int m_numberOfRows; int m_numberOfColumns; }; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index ddd7b81ea..8f6ac75ba 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -10,24 +10,19 @@ extern "C" { namespace Poincare { -HorizontalLayout::HorizontalLayout(ExpressionLayout ** children_layouts, int number_of_children) : - ExpressionLayout(), m_number_of_children(number_of_children) { - assert(number_of_children > 0); - m_children_layouts = new ExpressionLayout *[number_of_children]; - for (int i=0; isetParent(this); - if (m_children_layouts[i]->baseline() > m_baseline) { - m_baseline = m_children_layouts[i]->baseline(); +HorizontalLayout::HorizontalLayout(ExpressionLayout ** childrenLayouts, int childrenCount, bool cloneOperands) : + DynamicLayoutHierarchy(childrenLayouts, childrenCount, cloneOperands) +{ + for (int i = 0; i < numberOfChildren(); i++) { + if (child(i)->baseline() > m_baseline) { + m_baseline = child(i)->baseline(); } } } -HorizontalLayout::~HorizontalLayout() { - for (int i=0; i(children()), numberOfChildren(), true); + return layout; } bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -44,14 +39,14 @@ bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go to the last child if there is one, and move Left. // Else go Left and ask the parent. - if (m_number_of_children < 1) { + if (numberOfChildren() < 1) { cursor->setPosition(ExpressionLayoutCursor::Position::Left); if (m_parent) { return m_parent->moveLeft(cursor); } return false; } - ExpressionLayout * lastChild = m_children_layouts[m_number_of_children-1]; + ExpressionLayout * lastChild = editableChild(numberOfChildren()-1); assert(lastChild != nullptr); cursor->setPointedExpressionLayout(lastChild); return lastChild->moveLeft(cursor); @@ -72,9 +67,9 @@ bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { } // Case: the child is not the leftmost. // Go to its left brother and move Left. - cursor->setPointedExpressionLayout(m_children_layouts[childIndex-1]); + cursor->setPointedExpressionLayout(editableChild(childIndex-1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return m_children_layouts[childIndex-1]->moveLeft(cursor); + return editableChild(childIndex-1)->moveLeft(cursor); } bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { @@ -91,14 +86,14 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left. // Go to the first child if there is one, and move Right. // Else go Right and ask the parent. - if (m_number_of_children < 1) { + if (numberOfChildren() < 1) { cursor->setPosition(ExpressionLayoutCursor::Position::Right); if (m_parent) { return m_parent->moveRight(cursor); } return false; } - ExpressionLayout * firstChild = m_children_layouts[0]; + ExpressionLayout * firstChild = editableChild(0); assert(firstChild != nullptr); cursor->setPointedExpressionLayout(firstChild); return firstChild->moveRight(cursor); @@ -108,7 +103,7 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { assert(cursor->position() == ExpressionLayoutCursor::Position::Right); int childIndex = indexOfChild(cursor->pointedExpressionLayout()); assert(childIndex >= 0); - if (childIndex == m_number_of_children - 1) { + if (childIndex == numberOfChildren() - 1) { // Case: the child is the rightmost. // Ask the parent. cursor->setPointedExpressionLayout(this); @@ -119,9 +114,9 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { } // Case: the child is not the rightmost. // Go to its right brother and move Right. - cursor->setPointedExpressionLayout(m_children_layouts[childIndex+1]); + cursor->setPointedExpressionLayout(editableChild(childIndex+1)); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return m_children_layouts[childIndex+1]->moveRight(cursor); + return editableChild(childIndex+1)->moveRight(cursor); } bool HorizontalLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { @@ -140,7 +135,7 @@ KDSize HorizontalLayout::computeSize() { int i = 0; KDCoordinate max_under_baseline = 0; KDCoordinate max_above_baseline = 0; - while (ExpressionLayout * c = child(i++)) { + while (ExpressionLayout * c = editableChild(i++)) { KDSize childSize = c->size(); totalWidth += childSize.width(); if (childSize.height() - c->baseline() > max_under_baseline) { @@ -153,21 +148,12 @@ KDSize HorizontalLayout::computeSize() { return KDSize(totalWidth, max_under_baseline + max_above_baseline); } -ExpressionLayout * HorizontalLayout::child(uint16_t index) { - assert(index <= (unsigned int) m_number_of_children); - if (index < (unsigned int) m_number_of_children) { - return m_children_layouts[index]; - } else { - return nullptr; - } -} - KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; int index = indexOfChild(child); if (index > 0) { - ExpressionLayout * previousChild = m_children_layouts[index-1]; + ExpressionLayout * previousChild = editableChild(index-1); assert(previousChild != nullptr); x = previousChild->origin().x() + previousChild->size().width(); } @@ -190,11 +176,11 @@ bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direct ExpressionLayout * brother = nullptr; ExpressionLayoutCursor::Position newPosition = ExpressionLayoutCursor::Position::Right; if (cursor->position() == ExpressionLayoutCursor::Position::Left && previousLayoutIndex > 0) { - brother = m_children_layouts[previousLayoutIndex - 1]; + brother = editableChild(previousLayoutIndex - 1); newPosition = ExpressionLayoutCursor::Position::Right; } - if (cursor->position() == ExpressionLayoutCursor::Position::Right && previousLayoutIndex < m_number_of_children - 1) { - brother = m_children_layouts[previousLayoutIndex + 1]; + if (cursor->position() == ExpressionLayoutCursor::Position::Right && previousLayoutIndex < numberOfChildren() - 1) { + brother = editableChild(previousLayoutIndex + 1); newPosition = ExpressionLayoutCursor::Position::Left; } if (brother && cursor->positionIsEquivalentTo(brother, newPosition)) { @@ -223,8 +209,8 @@ int HorizontalLayout::indexOfChild(ExpressionLayout * eL) const { if (eL == nullptr) { return -1; } - for (int i = 0; i < m_number_of_children; i++) { - if (m_children_layouts[i] == eL) { + for (int i = 0; i < numberOfChildren(); i++) { + if (child(i) == eL) { return i; } } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 8e8eb3750..561d8a9ea 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -1,19 +1,16 @@ #ifndef POINCARE_HORIZONTAL_LAYOUT_H #define POINCARE_HORIZONTAL_LAYOUT_H -#include -#include +#include namespace Poincare { -class HorizontalLayout : public ExpressionLayout { +class HorizontalLayout : public DynamicLayoutHierarchy { public: - HorizontalLayout(ExpressionLayout ** layouts, int number_of_children); - ~HorizontalLayout(); - HorizontalLayout(const HorizontalLayout& other) = delete; - HorizontalLayout(HorizontalLayout&& other) = delete; - HorizontalLayout& operator=(const HorizontalLayout& other) = delete; - HorizontalLayout& operator=(HorizontalLayout&& other) = delete; + HorizontalLayout(ExpressionLayout ** layouts, int childrenCount, bool cloneOperands); + ExpressionLayout * clone() const override; + + /* Navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; @@ -21,13 +18,10 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); int indexOfChild(ExpressionLayout * eL) const; - int m_number_of_children; - ExpressionLayout ** m_children_layouts; }; } diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 82f923ec6..727e477f0 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -19,31 +19,24 @@ const uint8_t bottomSymbolPixel[IntegralLayout::k_symbolHeight][IntegralLayout:: {0xFF, 0xFF, 0x00, 0x00}, }; -IntegralLayout::IntegralLayout(ExpressionLayout * lowerBoundLayout, ExpressionLayout * upperBoundLayout, ExpressionLayout * integrandLayout) : - ExpressionLayout(), - m_lowerBoundLayout(lowerBoundLayout), - m_upperBoundLayout(upperBoundLayout), - m_integrandLayout(integrandLayout) +IntegralLayout::IntegralLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * integrand, bool cloneOperands) : + StaticLayoutHierarchy<3>(upperBound, lowerBound, integrand, cloneOperands) { - m_lowerBoundLayout->setParent(this); - m_upperBoundLayout->setParent(this); - m_integrandLayout->setParent(this); - m_baseline = m_upperBoundLayout->size().height() + k_integrandHeigthMargin + m_integrandLayout->baseline(); + m_baseline = upperBoundLayout()->size().height() + k_integrandHeigthMargin + integrandLayout()->baseline(); } -IntegralLayout::~IntegralLayout() { - delete m_lowerBoundLayout; - delete m_upperBoundLayout; - delete m_integrandLayout; +ExpressionLayout * IntegralLayout::clone() const { + IntegralLayout * layout = new IntegralLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->integrandLayout(), true); + return layout; } bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left the upper or lower bound. // Go Left of the integral. - if (((m_upperBoundLayout - && cursor->pointedExpressionLayout() == m_upperBoundLayout) - || (m_lowerBoundLayout - && cursor->pointedExpressionLayout() == m_lowerBoundLayout)) + if (((upperBoundLayout() + && cursor->pointedExpressionLayout() == upperBoundLayout()) + || (lowerBoundLayout() + && cursor->pointedExpressionLayout() == lowerBoundLayout())) && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -51,12 +44,12 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { } // Case: Left the integrand. // Go Right of the lower bound. - if (m_integrandLayout - && cursor->pointedExpressionLayout() == m_integrandLayout + if (integrandLayout() + && cursor->pointedExpressionLayout() == integrandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_lowerBoundLayout != nullptr); - cursor->setPointedExpressionLayout(m_lowerBoundLayout); + assert(lowerBoundLayout() != nullptr); + cursor->setPointedExpressionLayout(lowerBoundLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } @@ -64,9 +57,9 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right of the integral. // Go Right of the integrand, Left of "dx". if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_integrandLayout != nullptr); - cursor->setPointedExpressionLayout(m_integrandLayout); - return m_integrandLayout->moveLeft(cursor); + assert(integrandLayout() != nullptr); + cursor->setPointedExpressionLayout(integrandLayout()); + return integrandLayout()->moveLeft(cursor); } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); // Case: Left of the brackets. @@ -80,21 +73,21 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right the upper or lower bound. // Go Left of the integrand. - if (((m_upperBoundLayout - && cursor->pointedExpressionLayout() == m_upperBoundLayout) - || (m_lowerBoundLayout - && cursor->pointedExpressionLayout() == m_lowerBoundLayout)) + if (((upperBoundLayout() + && cursor->pointedExpressionLayout() == upperBoundLayout()) + || (lowerBoundLayout() + && cursor->pointedExpressionLayout() == lowerBoundLayout())) && cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_integrandLayout != nullptr); - cursor->setPointedExpressionLayout(m_integrandLayout); + assert(integrandLayout() != nullptr); + cursor->setPointedExpressionLayout(integrandLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } // Case: Right the integrand. // Go Right and move Right. - if (m_integrandLayout - && cursor->pointedExpressionLayout() == m_integrandLayout + if (integrandLayout() + && cursor->pointedExpressionLayout() == integrandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -104,8 +97,8 @@ bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left of the integral. // Go ti the upper bound. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_upperBoundLayout != nullptr); - cursor->setPointedExpressionLayout(m_upperBoundLayout); + assert(upperBoundLayout() != nullptr); + cursor->setPointedExpressionLayout(upperBoundLayout()); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); @@ -119,41 +112,41 @@ bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { bool IntegralLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the lower bound, move it to the upper bound. - if (m_lowerBoundLayout && previousLayout == m_lowerBoundLayout) { - assert(m_upperBoundLayout != nullptr); - return m_upperBoundLayout->moveUpInside(cursor); + if (lowerBoundLayout() && previousLayout == lowerBoundLayout()) { + assert(upperBoundLayout() != nullptr); + return upperBoundLayout()->moveUpInside(cursor); } // If the cursor is Left of the integrand, move it to the upper bound. - if (m_integrandLayout - && previousLayout == m_integrandLayout - && cursor->positionIsEquivalentTo(m_integrandLayout, ExpressionLayoutCursor::Position::Left)) + if (integrandLayout() + && previousLayout == integrandLayout() + && cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(m_upperBoundLayout != nullptr); - return m_upperBoundLayout->moveUpInside(cursor); + assert(upperBoundLayout() != nullptr); + return upperBoundLayout()->moveUpInside(cursor); } return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } bool IntegralLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the upper bound, move it to the lower bound. - if (m_upperBoundLayout && previousLayout == m_upperBoundLayout) { - assert(m_lowerBoundLayout != nullptr); - return m_lowerBoundLayout->moveDownInside(cursor); + if (upperBoundLayout() && previousLayout == upperBoundLayout()) { + assert(lowerBoundLayout() != nullptr); + return lowerBoundLayout()->moveDownInside(cursor); } // If the cursor is Left of the integrand, move it to the lower bound. - if (m_integrandLayout - && previousLayout == m_integrandLayout - && cursor->positionIsEquivalentTo(m_integrandLayout, ExpressionLayoutCursor::Position::Left)) + if (integrandLayout() + && previousLayout == integrandLayout() + && cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(m_lowerBoundLayout != nullptr); - return m_lowerBoundLayout->moveDownInside(cursor); + assert(lowerBoundLayout() != nullptr); + return lowerBoundLayout()->moveDownInside(cursor); } return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - KDSize integrandSize = m_integrandLayout->size(); - KDSize upperBoundSize = m_upperBoundLayout->size(); + KDSize integrandSize = integrandLayout()->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); KDColor workingBuffer[k_symbolWidth*k_symbolHeight]; KDRect topSymbolFrame(p.x() + k_symbolWidth + k_lineThickness, p.y() + upperBoundSize.height() - k_boundHeightMargin, k_symbolWidth, k_symbolHeight); @@ -167,40 +160,27 @@ void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, } KDSize IntegralLayout::computeSize() { - KDSize integrandSize = m_integrandLayout->size(); - KDSize lowerBoundSize = m_lowerBoundLayout->size(); - KDSize upperBoundSize = m_upperBoundLayout->size(); + KDSize integrandSize = integrandLayout()->size(); + KDSize lowerBoundSize = lowerBoundLayout()->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( k_symbolWidth+k_lineThickness+k_boundWidthMargin+max(lowerBoundSize.width(), upperBoundSize.width())+k_integrandWidthMargin+integrandSize.width(), upperBoundSize.height()+ 2*k_integrandHeigthMargin+integrandSize.height()+lowerBoundSize.height()); } -ExpressionLayout * IntegralLayout::child(uint16_t index) { - switch (index) { - case 0: - return m_upperBoundLayout; - case 1: - return m_lowerBoundLayout; - case 2: - return m_integrandLayout; - default: - return nullptr; - } -} - KDPoint IntegralLayout::positionOfChild(ExpressionLayout * child) { - KDSize integrandSize = m_integrandLayout->size(); - KDSize lowerBoundSize = m_lowerBoundLayout->size(); - KDSize upperBoundSize = m_upperBoundLayout->size(); + KDSize integrandSize = integrandLayout()->size(); + KDSize lowerBoundSize = lowerBoundLayout()->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); KDCoordinate x = 0; KDCoordinate y = 0; - if (child == m_lowerBoundLayout) { + if (child == lowerBoundLayout()) { x = k_symbolWidth+k_lineThickness+k_boundWidthMargin; y = upperBoundSize.height()+2*k_integrandHeigthMargin+integrandSize.height(); - } else if (child == m_upperBoundLayout) { + } else if (child == upperBoundLayout()) { x = k_symbolWidth+k_lineThickness+k_boundWidthMargin;; y = 0; - } else if (child == m_integrandLayout) { + } else if (child == integrandLayout()) { x = k_symbolWidth +k_lineThickness+ k_boundWidthMargin+max(lowerBoundSize.width(), upperBoundSize.width())+k_integrandWidthMargin; y = upperBoundSize.height()+k_integrandHeigthMargin; } else { @@ -209,4 +189,16 @@ KDPoint IntegralLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x,y); } +ExpressionLayout * IntegralLayout::upperBoundLayout() { + return editableChild(0); +} + +ExpressionLayout * IntegralLayout::lowerBoundLayout() { + return editableChild(1); +} + +ExpressionLayout * IntegralLayout::integrandLayout() { + return editableChild(2); +} + } diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index f1beceee0..067cc7cea 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -1,21 +1,16 @@ #ifndef POINCARE_INTEGRAL_LAYOUT_H #define POINCARE_INTEGRAL_LAYOUT_H -#include -#include +#include namespace Poincare { -class IntegralLayout : public ExpressionLayout { +class IntegralLayout : public StaticLayoutHierarchy<3> { public: - IntegralLayout(ExpressionLayout * lowerBoundLayout, ExpressionLayout * upperBoundLayout, ExpressionLayout * integrandLayout); - ~IntegralLayout(); - IntegralLayout(const IntegralLayout& other) = delete; - IntegralLayout(IntegralLayout&& other) = delete; - IntegralLayout& operator=(const IntegralLayout& other) = delete; - IntegralLayout& operator=(IntegralLayout&& other) = delete; constexpr static KDCoordinate k_symbolHeight = 4; constexpr static KDCoordinate k_symbolWidth = 4; + IntegralLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * integrand, bool cloneOperands); + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; @@ -23,7 +18,6 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_boundHeightMargin = 8; @@ -31,9 +25,9 @@ private: constexpr static KDCoordinate k_integrandWidthMargin = 2; constexpr static KDCoordinate k_integrandHeigthMargin = 2; constexpr static KDCoordinate k_lineThickness = 1; - ExpressionLayout * m_lowerBoundLayout; - ExpressionLayout * m_upperBoundLayout; - ExpressionLayout * m_integrandLayout; + ExpressionLayout * lowerBoundLayout(); + ExpressionLayout * upperBoundLayout(); + ExpressionLayout * integrandLayout(); }; } diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 47ff1725c..89a3c59a4 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -16,37 +16,31 @@ const uint8_t radixPixel[NthRootLayout::k_leftRadixHeight][NthRootLayout::k_left {0xFF, 0xFF, 0xFF, 0xFF, 0x00}, }; -NthRootLayout::NthRootLayout(ExpressionLayout * radicandLayout, ExpressionLayout * indexLayout) : - ExpressionLayout(), - m_radicandLayout(radicandLayout), - m_indexLayout(indexLayout) +NthRootLayout::NthRootLayout(ExpressionLayout * radicand, ExpressionLayout * index, bool cloneOperands) : + StaticLayoutHierarchy<2>(radicand, index, cloneOperands) { - m_radicandLayout->setParent(this); - if (m_indexLayout != nullptr) { - m_indexLayout->setParent(this); - m_baseline = max(m_radicandLayout->baseline() + k_radixLineThickness + k_heightMargin, - m_indexLayout->size().height() + k_indexHeight); + if (indexLayout() != nullptr) { + m_baseline = max(radicandLayout()->baseline() + k_radixLineThickness + k_heightMargin, + indexLayout()->size().height() + k_indexHeight); } else { - m_baseline = m_radicandLayout->baseline() + k_radixLineThickness + k_heightMargin; + m_baseline = radicandLayout()->baseline() + k_radixLineThickness + k_heightMargin; } } -NthRootLayout::~NthRootLayout() { - delete m_radicandLayout; - if (m_indexLayout != nullptr) { - delete m_indexLayout; - } +ExpressionLayout * NthRootLayout::clone() const { + NthRootLayout * layout = new NthRootLayout(const_cast(this)->radicandLayout(), const_cast(this)->indexLayout(), true); + return layout; } bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the radicand. // Go the index if there is one, else go Left of the root. - if (m_radicandLayout - && cursor->pointedExpressionLayout() == m_radicandLayout + if (radicandLayout() + && cursor->pointedExpressionLayout() == radicandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { - if (m_indexLayout) { - cursor->setPointedExpressionLayout(m_indexLayout); + if (indexLayout()) { + cursor->setPointedExpressionLayout(indexLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } @@ -55,8 +49,8 @@ bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { } // Case: Left of the index. // Go Left of the root. - if (m_indexLayout - && cursor->pointedExpressionLayout() == m_indexLayout + if (indexLayout() + && cursor->pointedExpressionLayout() == indexLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -66,8 +60,8 @@ bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go Right of the radicand. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_radicandLayout != nullptr); - cursor->setPointedExpressionLayout(m_radicandLayout); + assert(radicandLayout() != nullptr); + cursor->setPointedExpressionLayout(radicandLayout()); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); @@ -82,8 +76,8 @@ bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the radicand. // Go the Right of the root. - if (m_radicandLayout - && cursor->pointedExpressionLayout() == m_radicandLayout + if (radicandLayout() + && cursor->pointedExpressionLayout() == radicandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -91,12 +85,12 @@ bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { } // Case: Right of the index. // Go Left of the integrand. - if (m_indexLayout - && cursor->pointedExpressionLayout() == m_indexLayout + if (indexLayout() + && cursor->pointedExpressionLayout() == indexLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_radicandLayout != nullptr); - cursor->setPointedExpressionLayout(m_radicandLayout); + assert(radicandLayout() != nullptr); + cursor->setPointedExpressionLayout(radicandLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } @@ -104,12 +98,12 @@ bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left. // Go index if there is one, else go to the radicand. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - if (m_indexLayout) { - cursor->setPointedExpressionLayout(m_indexLayout); + if (indexLayout()) { + cursor->setPointedExpressionLayout(indexLayout()); return true; } - assert(m_radicandLayout != nullptr); - cursor->setPointedExpressionLayout(m_radicandLayout); + assert(radicandLayout() != nullptr); + cursor->setPointedExpressionLayout(radicandLayout()); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); @@ -123,12 +117,12 @@ bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is Left of the radicand, move it to the index. - if (m_radicandLayout - && previousLayout == m_radicandLayout - && cursor->positionIsEquivalentTo(m_radicandLayout, ExpressionLayoutCursor::Position::Left)) + if (radicandLayout() + && previousLayout == radicandLayout() + && cursor->positionIsEquivalentTo(radicandLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(m_indexLayout != nullptr); - cursor->setPointedExpressionLayout(m_indexLayout); + assert(indexLayout() != nullptr); + cursor->setPointedExpressionLayout(indexLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); cursor->setPositionInside(0); return true; @@ -137,8 +131,8 @@ bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * p if (cursor->pointedExpressionLayout() == this && cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_indexLayout != nullptr); - cursor->setPointedExpressionLayout(m_indexLayout); + assert(indexLayout() != nullptr); + cursor->setPointedExpressionLayout(indexLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); cursor->setPositionInside(0); return true; @@ -147,17 +141,17 @@ bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * p } bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { - if (m_indexLayout && previousLayout == m_indexLayout) { + if (indexLayout() && previousLayout == indexLayout()) { // If the cursor is Right of the index, move it to the radicand. - if (cursor->positionIsEquivalentTo(m_indexLayout, ExpressionLayoutCursor::Position::Right)) { - assert(m_radicandLayout != nullptr); - cursor->setPointedExpressionLayout(m_radicandLayout); + if (cursor->positionIsEquivalentTo(indexLayout(), ExpressionLayoutCursor::Position::Right)) { + assert(radicandLayout() != nullptr); + cursor->setPointedExpressionLayout(radicandLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); cursor->setPositionInside(0); return true; } // If the cursor is Left of the index, move it Left . - if (cursor->positionIsEquivalentTo(m_indexLayout, ExpressionLayoutCursor::Position::Left)) { + if (cursor->positionIsEquivalentTo(indexLayout(), ExpressionLayoutCursor::Position::Left)) { cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Left); cursor->setPositionInside(0); @@ -168,24 +162,24 @@ bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * } void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - KDSize radicandSize = m_radicandLayout->size(); - KDSize indexSize = m_indexLayout != nullptr ? m_indexLayout->size() : KDSize(k_leftRadixWidth,0); + KDSize radicandSize = radicandLayout()->size(); + KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); KDColor workingBuffer[k_leftRadixWidth*k_leftRadixHeight]; KDRect leftRadixFrame(p.x() + indexSize.width() + k_widthMargin - k_leftRadixWidth, - p.y() + m_baseline + radicandSize.height() - m_radicandLayout->baseline() + k_heightMargin - k_leftRadixHeight, + p.y() + m_baseline + radicandSize.height() - radicandLayout()->baseline() + k_heightMargin - k_leftRadixHeight, k_leftRadixWidth, k_leftRadixHeight); ctx->blendRectWithMask(leftRadixFrame, expressionColor, (const uint8_t *)radixPixel, (KDColor *)workingBuffer); - if (indexSize.height() + k_indexHeight > m_radicandLayout->baseline() + k_radixLineThickness + k_heightMargin) { + if (indexSize.height() + k_indexHeight > radicandLayout()->baseline() + k_radixLineThickness + k_heightMargin) { ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin, - p.y() + indexSize.height() + k_indexHeight - m_radicandLayout->baseline() - k_radixLineThickness - k_heightMargin, + p.y() + indexSize.height() + k_indexHeight - radicandLayout()->baseline() - k_radixLineThickness - k_heightMargin, k_radixLineThickness, radicandSize.height() + 2*k_heightMargin + k_radixLineThickness), expressionColor); ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin, - p.y() + indexSize.height() + k_indexHeight - m_radicandLayout->baseline() - k_radixLineThickness - k_heightMargin, + p.y() + indexSize.height() + k_indexHeight - radicandLayout()->baseline() - k_radixLineThickness - k_heightMargin, radicandSize.width() + 2*k_widthMargin, k_radixLineThickness), expressionColor); ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin + radicandSize.width() + 2*k_widthMargin, - p.y() + indexSize.height() + k_indexHeight - m_radicandLayout->baseline() - k_radixLineThickness - k_heightMargin, + p.y() + indexSize.height() + k_indexHeight - radicandLayout()->baseline() - k_radixLineThickness - k_heightMargin, k_radixLineThickness, k_rightRadixHeight + k_radixLineThickness), expressionColor); } else { @@ -206,40 +200,36 @@ void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, } KDSize NthRootLayout::computeSize() { - KDSize radicandSize = m_radicandLayout->size(); - KDSize indexSize = m_indexLayout != nullptr ? m_indexLayout->size() : KDSize(k_leftRadixWidth,0); + KDSize radicandSize = radicandLayout()->size(); + KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); return KDSize( indexSize.width() + 3*k_widthMargin + 2*k_radixLineThickness + radicandSize.width(), - m_baseline + radicandSize.height() - m_radicandLayout->baseline() + k_heightMargin + m_baseline + radicandSize.height() - radicandLayout()->baseline() + k_heightMargin ); } -ExpressionLayout * NthRootLayout::child(uint16_t index) { - switch (index) { - case 0: - return m_radicandLayout; - case 1: - return m_indexLayout; - default: - return nullptr; - } -} - KDPoint NthRootLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; - KDSize indexSize = m_indexLayout != nullptr ? m_indexLayout->size() : KDSize(k_leftRadixWidth,0); - if (child == m_indexLayout) { + KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); + if (child == indexLayout()) { x = 0; y = m_baseline - indexSize.height() - k_indexHeight; - } else if (child == m_radicandLayout) { + } else if (child == radicandLayout()) { x = indexSize.width() + 2*k_widthMargin + k_radixLineThickness; - y = m_baseline - m_radicandLayout->baseline(); + y = m_baseline - radicandLayout()->baseline(); } else { assert(false); } return KDPoint(x,y); } +ExpressionLayout * NthRootLayout::radicandLayout() { + return editableChild(0); } +ExpressionLayout * NthRootLayout::indexLayout() { + return editableChild(1); +} + +} diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index 7a4432c31..d942b3863 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -1,21 +1,16 @@ #ifndef POINCARE_NTH_ROOT_LAYOUT_H #define POINCARE_NTH_ROOT_LAYOUT_H -#include -#include +#include namespace Poincare { -class NthRootLayout : public ExpressionLayout { +class NthRootLayout : public StaticLayoutHierarchy<2> { public: - NthRootLayout(ExpressionLayout * radicandLayout, ExpressionLayout * indexLayout); - ~NthRootLayout(); - NthRootLayout(const NthRootLayout& other) = delete; - NthRootLayout(NthRootLayout&& other) = delete; - NthRootLayout& operator=(const NthRootLayout& other) = delete; - NthRootLayout& operator=(NthRootLayout&& other) = delete; constexpr static KDCoordinate k_leftRadixHeight = 8; constexpr static KDCoordinate k_leftRadixWidth = 5; + NthRootLayout(ExpressionLayout * radicand, ExpressionLayout * index, bool cloneOperands); + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; @@ -23,7 +18,6 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_rightRadixHeight = 2; @@ -31,8 +25,8 @@ private: constexpr static KDCoordinate k_heightMargin = 2; constexpr static KDCoordinate k_widthMargin = 1; constexpr static KDCoordinate k_radixLineThickness = 1; - ExpressionLayout * m_radicandLayout; - ExpressionLayout * m_indexLayout; + ExpressionLayout * radicandLayout(); + ExpressionLayout * indexLayout(); }; } diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index 6c9fa5ed4..eccab7030 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -9,40 +9,36 @@ extern "C" { namespace Poincare { -ParenthesisLayout::ParenthesisLayout(ExpressionLayout * operandLayout) : - ExpressionLayout(), - m_operandLayout(operandLayout) +ParenthesisLayout::ParenthesisLayout(ExpressionLayout * operand, bool cloneOperands) : + StaticLayoutHierarchy<3>() { - m_leftParenthesisLayout = new ParenthesisLeftLayout(); - m_rightParenthesisLayout = new ParenthesisRightLayout(); - m_operandLayout->setParent(this); - m_leftParenthesisLayout->setParent(this); - m_rightParenthesisLayout->setParent(this); - m_baseline = m_operandLayout->baseline(); + ExpressionLayout * leftParenthesis = new ParenthesisLeftLayout(); + ExpressionLayout * rightParenthesis = new ParenthesisRightLayout(); + build(ExpressionLayout::ExpressionLayoutArray3(leftParenthesis, operand, rightParenthesis), 3, cloneOperands); + m_baseline = operandLayout()->baseline(); } -ParenthesisLayout::~ParenthesisLayout() { - delete m_operandLayout; - delete m_rightParenthesisLayout; - delete m_leftParenthesisLayout; +ExpressionLayout * ParenthesisLayout::clone() const { + ParenthesisLayout * layout = new ParenthesisLayout(const_cast(this)->operandLayout(), true); + return layout; } bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the Right parenthesis. // Go to the operand and move left. - if (m_rightParenthesisLayout - && cursor->pointedExpressionLayout() == m_rightParenthesisLayout + if (rightParenthesisLayout() + && cursor->pointedExpressionLayout() == rightParenthesisLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_operandLayout != nullptr); - cursor->setPointedExpressionLayout(m_operandLayout); + assert(operandLayout() != nullptr); + cursor->setPointedExpressionLayout(operandLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return m_operandLayout->moveLeft(cursor); + return operandLayout()->moveLeft(cursor); } // Case: Left of the operand. // Go Left. - if (m_operandLayout - && cursor->pointedExpressionLayout() == m_operandLayout + if (operandLayout() + && cursor->pointedExpressionLayout() == operandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -50,8 +46,8 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { } // Case: Left of the Left parenthesis. // Ask the parent. - if (m_leftParenthesisLayout - && cursor->pointedExpressionLayout() == m_leftParenthesisLayout + if (leftParenthesisLayout() + && cursor->pointedExpressionLayout() == leftParenthesisLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); @@ -65,8 +61,8 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right of the parentheses. // Go Right of the operand. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_operandLayout != nullptr); - cursor->setPointedExpressionLayout(m_operandLayout); + assert(operandLayout() != nullptr); + cursor->setPointedExpressionLayout(operandLayout()); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); @@ -81,19 +77,19 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the Left parenthesis. // Go to the operand and move Right. - if (m_leftParenthesisLayout - && cursor->pointedExpressionLayout() == m_leftParenthesisLayout + if (leftParenthesisLayout() + && cursor->pointedExpressionLayout() == leftParenthesisLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_operandLayout != nullptr); - cursor->setPointedExpressionLayout(m_operandLayout); + assert(operandLayout() != nullptr); + cursor->setPointedExpressionLayout(operandLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return m_operandLayout->moveRight(cursor); + return operandLayout()->moveRight(cursor); } // Case: Right of the operand. // Go Right. - if (m_operandLayout - && cursor->pointedExpressionLayout() == m_operandLayout + if (operandLayout() + && cursor->pointedExpressionLayout() == operandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -101,8 +97,8 @@ bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { } // Case: Right of the Right parenthesis. // Ask the parent. - if (m_rightParenthesisLayout - && cursor->pointedExpressionLayout() == m_rightParenthesisLayout + if (rightParenthesisLayout() + && cursor->pointedExpressionLayout() == rightParenthesisLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); @@ -116,8 +112,8 @@ bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left of the parentheses. // Go Left of the operand. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_operandLayout != nullptr); - cursor->setPointedExpressionLayout(m_operandLayout); + assert(operandLayout() != nullptr); + cursor->setPointedExpressionLayout(operandLayout()); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); @@ -130,35 +126,34 @@ bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { } KDSize ParenthesisLayout::computeSize() { - KDSize operandSize = m_operandLayout->size(); - return KDSize(operandSize.width() + 2*m_leftParenthesisLayout->size().width(), operandSize.height()); -} - -ExpressionLayout * ParenthesisLayout::child(uint16_t index) { - if (index == 0) { - return m_leftParenthesisLayout; - } - if (index == 1) { - return m_operandLayout; - } - if (index == 2) { - return m_rightParenthesisLayout; - } - return nullptr; + KDSize operandSize = operandLayout()->size(); + return KDSize(operandSize.width() + 2*leftParenthesisLayout()->size().width(), operandSize.height()); } KDPoint ParenthesisLayout::positionOfChild(ExpressionLayout * child) { - if (child == m_leftParenthesisLayout) { + if (child == leftParenthesisLayout()) { return KDPoint(0, 0); } - if (child == m_operandLayout) { - return KDPoint(m_leftParenthesisLayout->size().width(), 0); + if (child == operandLayout()) { + return KDPoint(leftParenthesisLayout()->size().width(), 0); } - if (child == m_rightParenthesisLayout) { - return KDPoint(m_operandLayout->origin().x() + m_operandLayout->size().width(), 0); + if (child == rightParenthesisLayout()) { + return KDPoint(operandLayout()->origin().x() + operandLayout()->size().width(), 0); } assert(false); return KDPointZero; } +ExpressionLayout * ParenthesisLayout::operandLayout() { + return editableChild(1); +} + +ExpressionLayout * ParenthesisLayout::leftParenthesisLayout() { + return editableChild(0); +} + +ExpressionLayout * ParenthesisLayout::rightParenthesisLayout() { + return editableChild(2); +} + } diff --git a/poincare/src/layout/parenthesis_layout.h b/poincare/src/layout/parenthesis_layout.h index 84c765893..594d81a34 100644 --- a/poincare/src/layout/parenthesis_layout.h +++ b/poincare/src/layout/parenthesis_layout.h @@ -1,37 +1,31 @@ #ifndef POINCARE_PARENTHESIS_LAYOUT_H #define POINCARE_PARENTHESIS_LAYOUT_H -#include -#include +#include namespace Poincare { -class ParenthesisLayout : public ExpressionLayout { +class ParenthesisLayout : public StaticLayoutHierarchy<3> { public: - ParenthesisLayout(ExpressionLayout * operandLayout); - ~ParenthesisLayout(); - ParenthesisLayout(const ParenthesisLayout& other) = delete; - ParenthesisLayout(ParenthesisLayout&& other) = delete; - ParenthesisLayout& operator=(const ParenthesisLayout& other) = delete; - ParenthesisLayout& operator=(ParenthesisLayout&& other) = delete; constexpr static KDCoordinate k_parenthesisCurveWidth = 5; constexpr static KDCoordinate k_parenthesisCurveHeight = 7; + ParenthesisLayout(ExpressionLayout * operand, bool cloneOperands); + ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { }; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_externWidthMargin = 1; constexpr static KDCoordinate k_externHeightMargin = 2; constexpr static KDCoordinate k_widthMargin = 5; constexpr static KDCoordinate k_lineThickness = 1; - ExpressionLayout * m_operandLayout; - ExpressionLayout * m_leftParenthesisLayout; - ExpressionLayout * m_rightParenthesisLayout; + ExpressionLayout * operandLayout(); + ExpressionLayout * leftParenthesisLayout(); + ExpressionLayout * rightParenthesisLayout(); }; } diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index 807927588..43e3939db 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -26,6 +26,11 @@ const uint8_t bottomLeftCurve[ParenthesisLeftRightLayout::k_parenthesisCurveHeig {0xFF, 0xFF, 0xFF, 0xF9, 0x66}, }; +ExpressionLayout * ParenthesisLeftLayout::clone() const { + ParenthesisLeftLayout * layout = new ParenthesisLeftLayout(); + return layout; +} + void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { //TODO Make sure m_operandHeight is up-to-date. KDRect frame(p.x()+ParenthesisLeftRightLayout::k_externWidthMargin, diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index 32796d8c3..ad0b60906 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -1,8 +1,6 @@ #ifndef POINCARE_PARENTHESIS_LEFT_LAYOUT_H #define POINCARE_PARENTHESIS_LEFT_LAYOUT_H -#include -#include #include namespace Poincare { @@ -10,6 +8,7 @@ namespace Poincare { class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; + ExpressionLayout * clone() const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; }; diff --git a/poincare/src/layout/parenthesis_left_right_layout.cpp b/poincare/src/layout/parenthesis_left_right_layout.cpp index bbf204a79..4f7e51e89 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.cpp +++ b/poincare/src/layout/parenthesis_left_right_layout.cpp @@ -8,7 +8,7 @@ extern "C" { namespace Poincare { ParenthesisLeftRightLayout::ParenthesisLeftRightLayout() : - ExpressionLayout(), + StaticLayoutHierarchy<0>(), m_operandHeight(36) //TODO { } diff --git a/poincare/src/layout/parenthesis_left_right_layout.h b/poincare/src/layout/parenthesis_left_right_layout.h index d032fa1af..92d63ef3c 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.h +++ b/poincare/src/layout/parenthesis_left_right_layout.h @@ -1,19 +1,13 @@ #ifndef POINCARE_PARENTHESIS_LEFT_RIGHT_LAYOUT_H #define POINCARE_PARENTHESIS_LEFT_RIGHT_LAYOUT_H -#include -#include +#include namespace Poincare { -class ParenthesisLeftRightLayout : public ExpressionLayout { +class ParenthesisLeftRightLayout : public StaticLayoutHierarchy<0> { public: ParenthesisLeftRightLayout(); - ~ParenthesisLeftRightLayout() {} - ParenthesisLeftRightLayout(const ParenthesisLeftRightLayout& other) = delete; - ParenthesisLeftRightLayout(ParenthesisLeftRightLayout&& other) = delete; - ParenthesisLeftRightLayout& operator=(const ParenthesisLeftRightLayout& other) = delete; - ParenthesisLeftRightLayout& operator=(ParenthesisLeftRightLayout&& other) = delete; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; constexpr static KDCoordinate k_parenthesisCurveWidth = 5; @@ -25,7 +19,6 @@ public: protected: KDColor s_parenthesisWorkingBuffer[k_parenthesisCurveHeight*k_parenthesisCurveWidth]; KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override { return nullptr; } KDPoint positionOfChild(ExpressionLayout * child) override; uint16_t m_operandHeight; }; diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index 0a9a3af60..d9a8d4c6c 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -26,6 +26,11 @@ const uint8_t bottomRightCurve[ParenthesisLeftRightLayout::k_parenthesisCurveHei {0x66, 0xF9, 0xFF, 0xFF, 0xFF}, }; +ExpressionLayout * ParenthesisRightLayout::clone() const { + ParenthesisRightLayout * layout = new ParenthesisRightLayout(); + return layout; +} + void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { //TODO Make sure m_operandHeight is up-to-date. KDRect frame = KDRect(p.x() + ParenthesisLeftRightLayout::k_widthMargin + ParenthesisLeftRightLayout::k_lineThickness - ParenthesisLeftRightLayout::k_parenthesisCurveWidth, diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index efb98763b..7daba2368 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -1,8 +1,6 @@ #ifndef POINCARE_PARENTHESIS_RIGHT_LAYOUT_H #define POINCARE_PARENTHESIS_RIGHT_LAYOUT_H -#include -#include #include namespace Poincare { @@ -10,6 +8,7 @@ namespace Poincare { class ParenthesisRightLayout : public ParenthesisLeftRightLayout { public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; + ExpressionLayout * clone() const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; }; diff --git a/poincare/src/layout/product_layout.cpp b/poincare/src/layout/product_layout.cpp index cb573cf4b..b344736dd 100644 --- a/poincare/src/layout/product_layout.cpp +++ b/poincare/src/layout/product_layout.cpp @@ -4,17 +4,22 @@ namespace Poincare { +ExpressionLayout * ProductLayout::clone() const { + ProductLayout * layout = new ProductLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->argumentLayout(), true); + return layout; +} + void ProductLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - KDSize upperBoundSize = m_upperBoundLayout->size(); - KDSize lowerBoundSize = m_lowerBoundLayout->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); + KDSize lowerBoundSize = lowerBoundLayout()->size(); ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-(k_symbolHeight+1)/2), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_lineThickness, k_symbolHeight), expressionColor); ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-(k_symbolHeight+1)/2), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_symbolWidth, k_lineThickness), expressionColor); ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2)+k_symbolWidth, - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-(k_symbolHeight+1)/2), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_lineThickness, k_symbolHeight), expressionColor); } diff --git a/poincare/src/layout/product_layout.h b/poincare/src/layout/product_layout.h index 4aca54737..ae68723be 100644 --- a/poincare/src/layout/product_layout.h +++ b/poincare/src/layout/product_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class ProductLayout : public SequenceLayout { public: using SequenceLayout::SequenceLayout; + ExpressionLayout * clone() const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; private: diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 8bb66e969..c810a91b6 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -6,32 +6,20 @@ namespace Poincare { -SequenceLayout::SequenceLayout(ExpressionLayout * lowerBoundLayout, ExpressionLayout * upperBoundLayout, ExpressionLayout * argumentLayout) : - ExpressionLayout(), - m_lowerBoundLayout(lowerBoundLayout), - m_upperBoundLayout(upperBoundLayout), - m_argumentLayout(argumentLayout) +SequenceLayout::SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands) : + StaticLayoutHierarchy<3>(upperBound, lowerBound, argument, cloneOperands) { - m_lowerBoundLayout->setParent(this); - m_upperBoundLayout->setParent(this); - m_argumentLayout->setParent(this); - m_baseline = max(m_upperBoundLayout->size().height()+k_boundHeightMargin+(k_symbolHeight+1)/2, m_argumentLayout->baseline()); -} - -SequenceLayout::~SequenceLayout() { - delete m_lowerBoundLayout; - delete m_upperBoundLayout; - delete m_argumentLayout; + m_baseline = max(upperBoundLayout()->size().height()+k_boundHeightMargin+(k_symbolHeight+1)/2, argumentLayout()->baseline()); } bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the bounds. // Go Left of the sequence. if (cursor->position() == ExpressionLayoutCursor::Position::Left - && ((m_lowerBoundLayout - && cursor->pointedExpressionLayout() == m_lowerBoundLayout) - || (m_upperBoundLayout - && cursor->pointedExpressionLayout() == m_upperBoundLayout))) + && ((lowerBoundLayout() + && cursor->pointedExpressionLayout() == lowerBoundLayout()) + || (upperBoundLayout() + && cursor->pointedExpressionLayout() == upperBoundLayout()))) { cursor->setPointedExpressionLayout(this); return true; @@ -39,11 +27,11 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the argument. // Go Right of the lower bound. if (cursor->position() == ExpressionLayoutCursor::Position::Left - && m_argumentLayout - && cursor->pointedExpressionLayout() == m_argumentLayout) + && argumentLayout() + && cursor->pointedExpressionLayout() == argumentLayout()) { - assert(m_lowerBoundLayout != nullptr); - cursor->setPointedExpressionLayout(m_lowerBoundLayout); + assert(lowerBoundLayout() != nullptr); + cursor->setPointedExpressionLayout(lowerBoundLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } @@ -51,9 +39,9 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go to the argument and move Left. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(m_argumentLayout != nullptr); - cursor->setPointedExpressionLayout(m_argumentLayout); - return m_argumentLayout->moveLeft(cursor); + assert(argumentLayout() != nullptr); + cursor->setPointedExpressionLayout(argumentLayout()); + return argumentLayout()->moveLeft(cursor); } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); // Case: Left. @@ -68,21 +56,21 @@ bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the bounds. // Go Left of the argument. if (cursor->position() == ExpressionLayoutCursor::Position::Right - && ((m_lowerBoundLayout - && cursor->pointedExpressionLayout() == m_lowerBoundLayout) - || (m_upperBoundLayout - && cursor->pointedExpressionLayout() == m_upperBoundLayout))) + && ((lowerBoundLayout() + && cursor->pointedExpressionLayout() == lowerBoundLayout()) + || (upperBoundLayout() + && cursor->pointedExpressionLayout() == upperBoundLayout()))) { - assert(m_argumentLayout != nullptr); - cursor->setPointedExpressionLayout(m_argumentLayout); + assert(argumentLayout() != nullptr); + cursor->setPointedExpressionLayout(argumentLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } // Case: Right of the argument. // Ask the parent. if (cursor->position() == ExpressionLayoutCursor::Position::Right - && m_argumentLayout - && cursor->pointedExpressionLayout() == m_argumentLayout) + && argumentLayout() + && cursor->pointedExpressionLayout() == argumentLayout()) { cursor->setPointedExpressionLayout(this); if (m_parent) { @@ -94,8 +82,8 @@ bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Left. // Go to the upper bound. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(m_upperBoundLayout != nullptr); - cursor->setPointedExpressionLayout(m_upperBoundLayout); + assert(upperBoundLayout() != nullptr); + cursor->setPointedExpressionLayout(upperBoundLayout()); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); @@ -109,74 +97,73 @@ bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { bool SequenceLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the lower bound, move it to the upper bound. - if (m_lowerBoundLayout && previousLayout == m_lowerBoundLayout) { - assert(m_upperBoundLayout != nullptr); - return m_upperBoundLayout->moveUpInside(cursor); + if (lowerBoundLayout() && previousLayout == lowerBoundLayout()) { + assert(upperBoundLayout() != nullptr); + return upperBoundLayout()->moveUpInside(cursor); } // If the cursor is Left of the argument, move it to the upper bound. - if (m_argumentLayout - && previousLayout == m_argumentLayout - && cursor->positionIsEquivalentTo(m_argumentLayout, ExpressionLayoutCursor::Position::Left)) + if (argumentLayout() + && previousLayout == argumentLayout() + && cursor->positionIsEquivalentTo(argumentLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(m_upperBoundLayout != nullptr); - return m_upperBoundLayout->moveUpInside(cursor); + assert(upperBoundLayout() != nullptr); + return upperBoundLayout()->moveUpInside(cursor); } return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); } bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the upper bound, move it to the lower bound. - if (m_upperBoundLayout && previousLayout == m_upperBoundLayout) { - assert(m_lowerBoundLayout != nullptr); - return m_lowerBoundLayout->moveDownInside(cursor); + if (upperBoundLayout() && previousLayout == upperBoundLayout()) { + assert(lowerBoundLayout() != nullptr); + return lowerBoundLayout()->moveDownInside(cursor); } // If the cursor is Left of the argument, move it to the lower bound. - if (m_argumentLayout - && previousLayout == m_argumentLayout - && cursor->positionIsEquivalentTo(m_argumentLayout, ExpressionLayoutCursor::Position::Left)) + if (argumentLayout() + && previousLayout == argumentLayout() + && cursor->positionIsEquivalentTo(argumentLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(m_lowerBoundLayout != nullptr); - return m_lowerBoundLayout->moveDownInside(cursor); + assert(lowerBoundLayout() != nullptr); + return lowerBoundLayout()->moveDownInside(cursor); } return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } +ExpressionLayout * SequenceLayout::upperBoundLayout() { + return editableChild(0); +} + +ExpressionLayout * SequenceLayout::lowerBoundLayout() { + return editableChild(1); +} + +ExpressionLayout * SequenceLayout::argumentLayout() { + return editableChild(2); +} + KDSize SequenceLayout::computeSize() { - KDSize argumentSize = m_argumentLayout->size(); - KDSize lowerBoundSize = m_lowerBoundLayout->size(); - KDSize upperBoundSize = m_upperBoundLayout->size(); + KDSize argumentSize = argumentLayout()->size(); + KDSize lowerBoundSize = lowerBoundLayout()->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSize.width(), - m_baseline + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - m_argumentLayout->baseline()) + m_baseline + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - argumentLayout()->baseline()) ); } -ExpressionLayout * SequenceLayout::child(uint16_t index) { - switch (index) { - case 0: - return m_upperBoundLayout; - case 1: - return m_lowerBoundLayout; - case 2: - return m_argumentLayout; - default: - return nullptr; - } -} - KDPoint SequenceLayout::positionOfChild(ExpressionLayout * child) { - KDSize lowerBoundSize = m_lowerBoundLayout->size(); - KDSize upperBoundSize = m_upperBoundLayout->size(); + KDSize lowerBoundSize = lowerBoundLayout()->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); KDCoordinate x = 0; KDCoordinate y = 0; - if (child == m_lowerBoundLayout) { + if (child == lowerBoundLayout()) { x = max(max(0, (k_symbolWidth-lowerBoundSize.width())/2), (upperBoundSize.width()-lowerBoundSize.width())/2); y = m_baseline + k_symbolHeight/2 + k_boundHeightMargin; - } else if (child == m_upperBoundLayout) { + } else if (child == upperBoundLayout()) { x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSize.width()-upperBoundSize.width())/2); y = m_baseline - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); - } else if (child == m_argumentLayout) { + } else if (child == argumentLayout()) { x = max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin; - y = m_baseline - m_argumentLayout->baseline(); + y = m_baseline - argumentLayout()->baseline(); } else { assert(false); } diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 95cf67f5d..b9e4735d3 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -1,33 +1,26 @@ #ifndef POINCARE_SEQUENCE_LAYOUT_H #define POINCARE_SEQUENCE_LAYOUT_H -#include -#include +#include namespace Poincare { -class SequenceLayout : public ExpressionLayout { +class SequenceLayout : public StaticLayoutHierarchy<3> { public: - SequenceLayout(ExpressionLayout * lowerBoundLayout, ExpressionLayout * upperBoundLayout, ExpressionLayout * argumentLayout); - ~SequenceLayout(); - SequenceLayout(const SequenceLayout& other) = delete; - SequenceLayout(SequenceLayout&& other) = delete; - SequenceLayout& operator=(const SequenceLayout& other) = delete; - SequenceLayout& operator=(SequenceLayout&& other) = delete; constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; + SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands); bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; protected: constexpr static KDCoordinate k_boundHeightMargin = 2; - ExpressionLayout * m_lowerBoundLayout; - ExpressionLayout * m_upperBoundLayout; - ExpressionLayout * m_argumentLayout; + ExpressionLayout * lowerBoundLayout(); + ExpressionLayout * upperBoundLayout(); + ExpressionLayout * argumentLayout(); private: KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; constexpr static KDCoordinate k_argumentWidthMargin = 2; }; diff --git a/poincare/src/layout/static_layout_hierarchy.cpp b/poincare/src/layout/static_layout_hierarchy.cpp new file mode 100644 index 000000000..27d6c68bb --- /dev/null +++ b/poincare/src/layout/static_layout_hierarchy.cpp @@ -0,0 +1,70 @@ +#include +extern "C" { +#include +} + +namespace Poincare { + +template +StaticLayoutHierarchy::StaticLayoutHierarchy() : + ExpressionLayout(), + m_children{} +{ +} + +template +StaticLayoutHierarchy::StaticLayoutHierarchy(const ExpressionLayout * const * children, bool cloneChildren) : + ExpressionLayout() +{ + build(children, T, cloneChildren); +} + +template<> +StaticLayoutHierarchy<1>::StaticLayoutHierarchy(const ExpressionLayout * e, bool cloneChildren) : + StaticLayoutHierarchy((ExpressionLayout **)&e, cloneChildren) +{ +} + +template<> +StaticLayoutHierarchy<2>::StaticLayoutHierarchy(const ExpressionLayout * e1, const ExpressionLayout * e2, bool cloneChildren) : + StaticLayoutHierarchy(ExpressionLayoutArray2(e1, e2), cloneChildren) +{ +} + +template<> +StaticLayoutHierarchy<3>::StaticLayoutHierarchy(const ExpressionLayout * e1, const ExpressionLayout * e2, const ExpressionLayout * e3, bool cloneChildren) : + StaticLayoutHierarchy(ExpressionLayoutArray3(e1, e2, e3), cloneChildren) +{ +} + +template +StaticLayoutHierarchy::~StaticLayoutHierarchy() { + for (int i = 0; i < T; i++) { + if (m_children[i] != nullptr) { + delete m_children[i]; + } + } +} + +template +void StaticLayoutHierarchy::build(const ExpressionLayout * const * children, int numberOfChildren, bool cloneChildren) { + assert(children != nullptr); + assert(numberOfChildren <= T); + for (int i=0; i < numberOfChildren; i++) { + assert(children[i] != nullptr); + if (cloneChildren) { + m_children[i] = children[i]->clone(); + } else { + m_children[i] = children[i]; + } + const_cast(m_children[i])->setParent(this); + } +} + +template class Poincare::StaticLayoutHierarchy<0>; +template class Poincare::StaticLayoutHierarchy<1>; +template class Poincare::StaticLayoutHierarchy<2>; +template class Poincare::StaticLayoutHierarchy<3>; + +} + diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index 4a053c80d..e9e93970d 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -6,7 +6,7 @@ namespace Poincare { StringLayout::StringLayout(const char * string, size_t length, KDText::FontSize fontSize) : - ExpressionLayout(), + StaticLayoutHierarchy<0>(), m_fontSize(fontSize) { m_string = new char[length+1]; @@ -20,8 +20,9 @@ StringLayout::~StringLayout() { delete[] m_string; } -char * StringLayout::text() { - return m_string; +ExpressionLayout * StringLayout::clone() const { + StringLayout * layout = new StringLayout(m_string, strlen(m_string), m_fontSize); + return layout; } bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -58,10 +59,6 @@ bool StringLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } -ExpressionLayout * StringLayout::child(uint16_t index) { - return nullptr; -} - void StringLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { ctx->drawString(m_string, p, m_fontSize, expressionColor, backgroundColor); } diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index 60600f022..5a70b44fd 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -1,12 +1,12 @@ #ifndef POINCARE_STRING_LAYOUT_H #define POINCARE_STRING_LAYOUT_H -#include +#include #include namespace Poincare { -class StringLayout : public ExpressionLayout { +class StringLayout : public StaticLayoutHierarchy<0> { public: // Here the inverse is a uint8_t instead of a bool, because the size of a bool is // not standardized, thus since we call a foreign C function with this value we want to be @@ -17,16 +17,16 @@ public: StringLayout(StringLayout&& other) = delete; StringLayout& operator=(const StringLayout& other) = delete; StringLayout& operator=(StringLayout&& other) = delete; - char * text(); + ExpressionLayout * clone() const override; + + char * text() { return m_string; } bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; - KDSize computeSize() override; - ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; + KDSize computeSize() override; char * m_string; -private: KDText::FontSize m_fontSize; }; diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index 95c376bee..4515eedef 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -22,12 +22,17 @@ const uint8_t symbolPixel[SumLayout::k_symbolHeight][SumLayout::k_symbolWidth] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, }; +ExpressionLayout * SumLayout::clone() const { + SumLayout * layout = new SumLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->argumentLayout(), true); + return layout; +} + void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - KDSize upperBoundSize = m_upperBoundLayout->size(); - KDSize lowerBoundSize = m_lowerBoundLayout->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); + KDSize lowerBoundSize = lowerBoundLayout()->size(); KDColor workingBuffer[k_symbolWidth*k_symbolHeight]; KDRect symbolFrame(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, m_argumentLayout->baseline()-(k_symbolHeight+1)/2), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_symbolWidth, k_symbolHeight); ctx->blendRectWithMask(symbolFrame, expressionColor, (const uint8_t *)symbolPixel, (KDColor *)workingBuffer); } diff --git a/poincare/src/layout/sum_layout.h b/poincare/src/layout/sum_layout.h index e09e447cf..7218e866f 100644 --- a/poincare/src/layout/sum_layout.h +++ b/poincare/src/layout/sum_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class SumLayout : public SequenceLayout { public: using SequenceLayout::SequenceLayout; + ExpressionLayout * clone() const override; private: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; }; diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index d35d010dc..2690be522 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -17,11 +17,11 @@ ExpressionLayout * LayoutEngine::createInfixLayout(const Expression * expression children_layouts[0] = expression->operand(0)->createLayout(); for (int i=1; ioperand(i)->type() == Expression::Type::Opposite ? new ParenthesisLayout(expression->operand(i)->createLayout(floatDisplayMode, complexFormat)) : expression->operand(i)->createLayout(floatDisplayMode, complexFormat); + children_layouts[2*i] = expression->operand(i)->type() == Expression::Type::Opposite ? new ParenthesisLayout(expression->operand(i)->createLayout(floatDisplayMode, complexFormat), false) : expression->operand(i)->createLayout(floatDisplayMode, complexFormat); } /* HorizontalLayout holds the children layouts so they do not need to be * deleted here. */ - ExpressionLayout * layout = new HorizontalLayout(children_layouts, 2*numberOfOperands-1); + ExpressionLayout * layout = new HorizontalLayout(children_layouts, 2*numberOfOperands-1, false); delete[] children_layouts; return layout; } @@ -39,13 +39,13 @@ ExpressionLayout * LayoutEngine::createPrefixLayout(const Expression * expressio } /* HorizontalLayout holds the grand children layouts so they do not need to * be deleted */ - ExpressionLayout * argumentLayouts = new HorizontalLayout(grandChildrenLayouts, 2*numberOfOperands-1); + ExpressionLayout * argumentLayouts = new HorizontalLayout(grandChildrenLayouts, 2*numberOfOperands-1, false); delete [] grandChildrenLayouts; ExpressionLayout * childrenLayouts[2]; childrenLayouts[0] = new EditableStringLayout(operatorName, strlen(operatorName)); - childrenLayouts[1] = new ParenthesisLayout(argumentLayouts); + childrenLayouts[1] = new ParenthesisLayout(argumentLayouts, false); /* Same comment as above */ - return new HorizontalLayout(childrenLayouts, 2); + return new HorizontalLayout(childrenLayouts, 2, false); } int LayoutEngine::writeInfixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName, OperandNeedParenthesis operandNeedParenthesis) { diff --git a/poincare/src/logarithm.cpp b/poincare/src/logarithm.cpp index 2b20d2e33..e55a830c5 100644 --- a/poincare/src/logarithm.cpp +++ b/poincare/src/logarithm.cpp @@ -237,9 +237,9 @@ ExpressionLayout * Logarithm::privateCreateLayout(FloatDisplayMode floatDisplayM return LayoutEngine::createPrefixLayout(this, floatDisplayMode, complexFormat, "log"); } ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = new EditableBaselineRelativeLayout(new EditableStringLayout("log", strlen("log")), operand(1)->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Subscript); - childrenLayouts[1] = new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat)); - return new HorizontalLayout(childrenLayouts, 2); + childrenLayouts[0] = new EditableBaselineRelativeLayout(new EditableStringLayout("log", strlen("log")), operand(1)->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Subscript, false); + childrenLayouts[1] = new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false); + return new HorizontalLayout(childrenLayouts, 2, false); } } diff --git a/poincare/src/matrix.cpp b/poincare/src/matrix.cpp index 10bd0d6a1..09bcb7908 100644 --- a/poincare/src/matrix.cpp +++ b/poincare/src/matrix.cpp @@ -102,7 +102,7 @@ ExpressionLayout * Matrix::privateCreateLayout(FloatDisplayMode floatDisplayMode for (int i = 0; i < numberOfOperands(); i++) { childrenLayouts[i] = operand(i)->createLayout(floatDisplayMode, complexFormat); } - ExpressionLayout * layout = new BracketLayout(new GridLayout(childrenLayouts, numberOfRows(), numberOfColumns())); + ExpressionLayout * layout = new BracketLayout(new GridLayout(childrenLayouts, numberOfRows(), numberOfColumns(), false), false); delete [] childrenLayouts; return layout; } diff --git a/poincare/src/nth_root.cpp b/poincare/src/nth_root.cpp index e648818c0..b9a5d6480 100644 --- a/poincare/src/nth_root.cpp +++ b/poincare/src/nth_root.cpp @@ -41,7 +41,7 @@ Expression * NthRoot::shallowReduce(Context& context, AngleUnit angleUnit) { ExpressionLayout * NthRoot::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new NthRootLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), operand(1)->createLayout(floatDisplayMode, complexFormat)); + return new NthRootLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), operand(1)->createLayout(floatDisplayMode, complexFormat), false); } template diff --git a/poincare/src/opposite.cpp b/poincare/src/opposite.cpp index 08956ca2e..cda885309 100644 --- a/poincare/src/opposite.cpp +++ b/poincare/src/opposite.cpp @@ -51,8 +51,8 @@ ExpressionLayout * Opposite::privateCreateLayout(FloatDisplayMode floatDisplayMo ExpressionLayout * children_layouts[2]; char string[2] = {'-', '\0'}; children_layouts[0] = new EditableStringLayout(string, 1); - children_layouts[1] = operand(0)->type() == Type::Opposite ? new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat)) : operand(0)->createLayout(floatDisplayMode, complexFormat); - return new HorizontalLayout(children_layouts, 2); + children_layouts[1] = operand(0)->type() == Type::Opposite ? new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false) : operand(0)->createLayout(floatDisplayMode, complexFormat); + return new HorizontalLayout(children_layouts, 2, false); } int Opposite::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/parenthesis.cpp b/poincare/src/parenthesis.cpp index e8a7985b6..214f7ba08 100644 --- a/poincare/src/parenthesis.cpp +++ b/poincare/src/parenthesis.cpp @@ -20,7 +20,7 @@ Expression * Parenthesis::clone() const { ExpressionLayout * Parenthesis::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat)); + return new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false); } Expression * Parenthesis::shallowReduce(Context& context, AngleUnit angleUnit) { diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index be426900f..3ae0c3b42 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -121,7 +121,7 @@ ExpressionLayout * Power::privateCreateLayout(FloatDisplayMode floatDisplayMode, if (m_operands[1]->type() == Type::Parenthesis) { indiceOperand = m_operands[1]->operand(0); } - return new EditableBaselineRelativeLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat),indiceOperand->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Superscript); + return new EditableBaselineRelativeLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat),indiceOperand->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Superscript, false); } int Power::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const { diff --git a/poincare/src/product.cpp b/poincare/src/product.cpp index d202cd807..ee896bd98 100644 --- a/poincare/src/product.cpp +++ b/poincare/src/product.cpp @@ -27,7 +27,7 @@ int Product::emptySequenceValue() const { } ExpressionLayout * Product::createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const { - return new ProductLayout(subscriptLayout, superscriptLayout, argumentLayout); + return new ProductLayout(subscriptLayout, superscriptLayout, argumentLayout, false); } template diff --git a/poincare/src/rational.cpp b/poincare/src/rational.cpp index 58fbf8d77..0929172f5 100644 --- a/poincare/src/rational.cpp +++ b/poincare/src/rational.cpp @@ -150,7 +150,7 @@ ExpressionLayout * Rational::privateCreateLayout(FloatDisplayMode floatDisplayMo return numeratorLayout; } ExpressionLayout * denominatorLayout = m_denominator.createLayout(); - return new FractionLayout(numeratorLayout, denominatorLayout); + return new FractionLayout(numeratorLayout, denominatorLayout, false); } int Rational::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index 87386e816..2aa201dad 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -19,7 +19,7 @@ ExpressionLayout * Sequence::privateCreateLayout(FloatDisplayMode floatDisplayMo ExpressionLayout * childrenLayouts[2]; childrenLayouts[0] = new StringLayout("n=", 2); childrenLayouts[1] = operand(1)->createLayout(floatDisplayMode, complexFormat); - return createSequenceLayoutWithArgumentLayouts(new HorizontalLayout(childrenLayouts, 2), operand(2)->createLayout(floatDisplayMode, complexFormat), operand(0)->createLayout(floatDisplayMode, complexFormat)); + return createSequenceLayoutWithArgumentLayouts(new HorizontalLayout(childrenLayouts, 2, false), operand(2)->createLayout(floatDisplayMode, complexFormat), operand(0)->createLayout(floatDisplayMode, complexFormat)); } template diff --git a/poincare/src/square_root.cpp b/poincare/src/square_root.cpp index 5d67ad83a..ccb695d2d 100644 --- a/poincare/src/square_root.cpp +++ b/poincare/src/square_root.cpp @@ -52,7 +52,7 @@ Expression * SquareRoot::shallowReduce(Context& context, AngleUnit angleUnit) { ExpressionLayout * SquareRoot::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new NthRootLayout(operand(0)->createLayout(floatDisplayMode, complexFormat),nullptr); + return new NthRootLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), nullptr, false); } } diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index a3598228c..03d1c90bb 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -33,7 +33,7 @@ ExpressionLayout * Store::privateCreateLayout(FloatDisplayMode floatDisplayMode, const char stoSymbol[2] = {Ion::Charset::Sto, 0}; childrenLayouts[1] = new EditableStringLayout(stoSymbol, 1); childrenLayouts[2] = symbol()->createLayout(floatDisplayMode, complexFormat); - return new HorizontalLayout(childrenLayouts, 3); + return new HorizontalLayout(childrenLayouts, 3, false); } template diff --git a/poincare/src/sum.cpp b/poincare/src/sum.cpp index 70a5168b7..0578083e9 100644 --- a/poincare/src/sum.cpp +++ b/poincare/src/sum.cpp @@ -27,7 +27,7 @@ int Sum::emptySequenceValue() const { } ExpressionLayout * Sum::createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const { - return new SumLayout(subscriptLayout, superscriptLayout, argumentLayout); + return new SumLayout(subscriptLayout, superscriptLayout, argumentLayout, false); } template diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index b3dc142cd..5b55e8ffa 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -135,16 +135,16 @@ ExpressionLayout * Symbol::privateCreateLayout(FloatDisplayMode floatDisplayMode return new EditableStringLayout("ans", 3); } if (m_name == SpecialSymbols::un) { - return new BaselineRelativeLayout(new StringLayout("u", 1), new StringLayout("n",1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + return new BaselineRelativeLayout(new StringLayout("u", 1), new StringLayout("n",1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript, false); } if (m_name == SpecialSymbols::un1) { - return new BaselineRelativeLayout(new StringLayout("u", 1), new StringLayout("n+1",3, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + return new BaselineRelativeLayout(new StringLayout("u", 1), new StringLayout("n+1",3, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript, false); } if (m_name == SpecialSymbols::vn) { - return new BaselineRelativeLayout(new StringLayout("v", 1), new StringLayout("n",1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + return new BaselineRelativeLayout(new StringLayout("v", 1), new StringLayout("n",1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript, false); } if (m_name == SpecialSymbols::vn1) { - return new BaselineRelativeLayout(new StringLayout("v", 1), new StringLayout("n+1",3, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + return new BaselineRelativeLayout(new StringLayout("v", 1), new StringLayout("n+1",3, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript, false); } if (isMatrixSymbol()) { const char mi[] = { 'M', (char)(m_name-(char)SpecialSymbols::M0+'0') }; From d72de7c484c26f4b6efc64483909da5cadfea561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 14:48:54 +0100 Subject: [PATCH 025/257] [poincare] ExpressionLayout edition. Change-Id: I505320c32fcc3ffb516f345091a89afad90ebf56 --- .../poincare/dynamic_layout_hierarchy.h | 2 +- poincare/include/poincare/expression_layout.h | 20 +++- .../src/layout/dynamic_layout_hierarchy.cpp | 5 +- poincare/src/layout/expression_layout.cpp | 98 ++++++++++++++++++- poincare/src/layout/horizontal_layout.cpp | 5 + poincare/src/layout/horizontal_layout.h | 1 + 6 files changed, 121 insertions(+), 10 deletions(-) diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index ef8053f76..54da3dfa9 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -20,7 +20,7 @@ public: int numberOfChildren() const override { return m_numberOfChildren; } const ExpressionLayout * const * children() const override { return m_children; }; - //bool addChildAtIndex(ExpressionLayout * operand, int index) override; TODO + bool addChildAtIndex(ExpressionLayout * operand, int index) override; protected: const ExpressionLayout ** m_children; int m_numberOfChildren; diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 141f0f58c..91a04f8cc 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -31,6 +31,7 @@ public: KDPoint absoluteOrigin(); KDSize size(); KDCoordinate baseline() const { return m_baseline; } + void invalidAllSizesAndPositions(); /* Hierarchy */ virtual const ExpressionLayout * const * children() const = 0; @@ -44,6 +45,14 @@ public: ExpressionLayout * editableParent() { return m_parent; } bool hasAncestor(const ExpressionLayout * e) const; + bool insertLayoutForTextAtCursor(const char * text, ExpressionLayoutCursor * cursor); + + void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); + ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace = true); + ExpressionLayout * replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace); + void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true); + void detachChild(const ExpressionLayout * e); // Removes a child WITHOUT deleting it + /* Dynamic Layout*/ virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } @@ -58,18 +67,21 @@ protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; - KDCoordinate m_baseline; - ExpressionLayout * m_parent; - virtual void moveCursorInsideAtDirection ( + void detachChildAtIndex(int i); + virtual void moveCursorInsideAtDirection ( VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout ** childResult, void * resultPosition, int * resultPositionInside, int * resultScore); + KDCoordinate m_baseline; + ExpressionLayout * m_parent; + bool m_sized; private: bool moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor); - bool m_sized, m_positioned; + void replaceWithJuxtapositionOf(ExpressionLayout * firstLayout, ExpressionLayout * secondLayout); + bool m_positioned; KDRect m_frame; }; diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index 09106b617..667347d46 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -41,7 +41,7 @@ DynamicLayoutHierarchy::~DynamicLayoutHierarchy() { delete[] m_children; } -/*bool DynamicLayoutHierarchy::addChildAtIndex(ExpressionLayout * child, int index) { +bool DynamicLayoutHierarchy::addChildAtIndex(ExpressionLayout * child, int index) { assert(index >= 0 && index <= m_numberOfChildren); const ExpressionLayout ** newChildren = new const ExpressionLayout * [m_numberOfChildren+1]; int j = 0; @@ -56,7 +56,8 @@ DynamicLayoutHierarchy::~DynamicLayoutHierarchy() { delete[] m_children; m_children = newChildren; m_numberOfChildren += 1; + m_sized = false; return true; -}*/ //TODO +} } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 6defb6e39..438726b2f 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -66,11 +67,21 @@ KDSize ExpressionLayout::size() { return m_frame.size(); } +void ExpressionLayout::invalidAllSizesAndPositions() { + m_sized = false; + m_positioned = false; + for (int i = 0; i < numberOfChildren(); i++) { + editableChild(i)->invalidAllSizesAndPositions(); + } +} + const ExpressionLayout * ExpressionLayout::child(int i) const { assert(i >= 0); - assert(i < numberOfChildren()); - assert(children()[i]->parent() == nullptr || children()[i]->parent() == this); - return children()[i]; + if (i < numberOfChildren()) { + assert(children()[i]->parent() == nullptr || children()[i]->parent() == this); + return children()[i]; + } + return nullptr; } int ExpressionLayout::indexOfChild(ExpressionLayout * child) const { @@ -97,6 +108,87 @@ bool ExpressionLayout::hasAncestor(const ExpressionLayout * e) const { return m_parent->hasAncestor(e); } +void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { + if (m_parent) { + int brotherIndex = cursor->position() == ExpressionLayoutCursor::Position::Left ? m_parent->indexOfChild(this) : m_parent->indexOfChild(this) + 1; + if (m_parent->addChildAtIndex(brother, brotherIndex)) { + return; + } + } + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + replaceWithJuxtapositionOf(brother, this, false); + return; + } + replaceWithJuxtapositionOf(this, brother, false); + //TODO Inside position +} + +bool ExpressionLayout::insertLayoutForTextAtCursor(const char * text, ExpressionLayoutCursor * cursor) { + EditableStringLayout * newChild = new EditableStringLayout(text, strlen(text)); + cursor->pointedExpressionLayout()->addBrother(cursor, newChild); + return true; +} + +ExpressionLayout * ExpressionLayout::replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace) { + assert(m_parent != nullptr); + m_parent->replaceChild(this, newChild, deleteAfterReplace); + return newChild; +} + +ExpressionLayout * ExpressionLayout::replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace) { + assert(m_parent != nullptr); + /* One of the children to juxtapose might be "this", so we first have to + * replace "this" with an horizontal layout, then add "this" to the layout. */ + ExpressionLayout * layout = new HorizontalLayout(); + m_parent->replaceChild(this, layout, deleteAfterReplace); + layout->addChildAtIndex(leftChild, 0); + layout->addChildAtIndex(rightChild, 1); + return layout; +} + +void ExpressionLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { + assert(newChild != nullptr); + // Caution: handle the case where we replace an operand with a descendant of ours. + if (newChild->hasAncestor(this)) { + newChild->editableParent()->detachChild(newChild); + } + ExpressionLayout ** op = const_cast(children()); + for (int i = 0; i < numberOfChildren(); i++) { + if (op[i] == oldChild) { + if (oldChild != nullptr && oldChild->parent() == this) { + const_cast(oldChild)->setParent(nullptr); + } + if (deleteOldChild) { + delete oldChild; + } + if (newChild != nullptr) { + const_cast(newChild)->setParent(this); + } + op[i] = newChild; + break; + } + } + m_sized = false; +} + +void ExpressionLayout::detachChild(const ExpressionLayout * e) { + ExpressionLayout ** op = const_cast(children()); + for (int i = 0; i < numberOfChildren(); i++) { + if (op[i] == e) { + detachChildAtIndex(i); + } + } +} + +void ExpressionLayout::detachChildAtIndex(int i) { + ExpressionLayout ** op = const_cast(children()); + if (op[i] != nullptr && op[i]->parent() == this) { + const_cast(op[i])->setParent(nullptr); + } + op[i] = nullptr; + m_sized = false; +} + bool ExpressionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { if (m_parent) { return m_parent->moveUp(cursor, this, previousLayout); diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 8f6ac75ba..4df2322aa 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -10,6 +10,11 @@ extern "C" { namespace Poincare { +HorizontalLayout::HorizontalLayout() : + DynamicLayoutHierarchy() +{ +} + HorizontalLayout::HorizontalLayout(ExpressionLayout ** childrenLayouts, int childrenCount, bool cloneOperands) : DynamicLayoutHierarchy(childrenLayouts, childrenCount, cloneOperands) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 561d8a9ea..dfcd71a63 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class HorizontalLayout : public DynamicLayoutHierarchy { public: + HorizontalLayout(); HorizontalLayout(ExpressionLayout ** layouts, int childrenCount, bool cloneOperands); ExpressionLayout * clone() const override; From 7a5547e3085d53d9726c6d7a11833ecad308feea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 14:46:52 +0100 Subject: [PATCH 026/257] [expression_editor] Changed example. TO REMOVE? Change-Id: Ibf1eb52eeeb9e4386c8c608115ac1ea88fbd715a --- apps/expression_editor/controller.cpp | 2 +- apps/expression_editor/expression_and_layout.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 632310443..5337e432c 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -6,7 +6,7 @@ Controller::Controller(Responder * parentResponder, Poincare::ExpressionLayout * ViewController(parentResponder), m_view(parentResponder, expressionLayout, &m_cursor) { - m_cursor.setPointedExpressionLayout(expressionLayout); + m_cursor.setPointedExpressionLayout(expressionLayout->editableChild(0)); } void Controller::didBecomeFirstResponder() { diff --git a/apps/expression_editor/expression_and_layout.cpp b/apps/expression_editor/expression_and_layout.cpp index 1f36461be..0f777e586 100644 --- a/apps/expression_editor/expression_and_layout.cpp +++ b/apps/expression_editor/expression_and_layout.cpp @@ -1,9 +1,11 @@ #include "expression_and_layout.h" +#include +#include namespace ExpressionEditor { ExpressionAndLayout::ExpressionAndLayout() { - //const char * expression = "2/3"; + const char * expression = "1"; //const char * expression = "1+2/(3+4)"; //const char * expression = "1+2/3+5+8"; //const char * expression = "[[1+5,2,3][4,5,6]]"; @@ -33,10 +35,11 @@ ExpressionAndLayout::ExpressionAndLayout() { //const char * expression = "abs(1+conj(conj(4))+(23)+conj(42))+abs(1+2)"; //const char * expression = "13+(23)"; //const char * expression = "1+sum(12,3,4)+product(12,3,4)+2"; - const char * expression = "(1+2^3)-385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]/123+ln(36)+root(542,52)+sum(12,3,4)+int(22,3,4)+conj(988+2)+abs(conj(345))+conj(conj(conj(3)))+floor(48)+binomial(6,88)+product(23,46,123)"; + //const char * expression = "(1+2^3)-385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]/123+ln(36)+root(542,52)+sum(12,3,4)+int(22,3,4)+conj(988+2)+abs(conj(345))+conj(conj(conj(3)))+floor(48)+binomial(6,88)+product(23,46,123)+log(10,565)-0.03"; m_expression = Poincare::Expression::parse(expression); - m_expressionLayout = m_expression->createLayout(); + m_expressionLayout = new Poincare::HorizontalLayout(); + m_expressionLayout->addChildAtIndex(new Poincare::EditableStringLayout("1", 1), 0); } ExpressionAndLayout::~ExpressionAndLayout() { if (m_expressionLayout) { From c78efeeb5913fa7ed44abaf36982c4f97f487d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 14:49:17 +0100 Subject: [PATCH 027/257] [expression_editor] The user can input text. Change-Id: I6456ee23e3caf3a42899d0734e1bef1f53f68b8d --- apps/expression_editor/controller.cpp | 8 +++++++- apps/expression_editor/controller.h | 1 + apps/expression_editor/expression_editor_view.cpp | 1 + .../scrollable_expression_view_with_cursor.cpp | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 5337e432c..4053ad77c 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -4,7 +4,8 @@ namespace ExpressionEditor { Controller::Controller(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout) : ViewController(parentResponder), - m_view(parentResponder, expressionLayout, &m_cursor) + m_view(parentResponder, expressionLayout, &m_cursor), + m_expressionLayout(expressionLayout) { m_cursor.setPointedExpressionLayout(expressionLayout->editableChild(0)); } @@ -33,6 +34,11 @@ bool Controller::handleEvent(Ion::Events::Event event) { { returnValue = true; } + else if (event.hasText() && m_expressionLayout->insertLayoutForTextAtCursor(event.text(), &m_cursor)) { + returnValue = true; + m_expressionLayout->invalidAllSizesAndPositions(); + m_view.layoutSubviews(); + } m_view.cursorPositionChanged(); return returnValue; } diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index f09630034..d827c35d0 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -19,6 +19,7 @@ public: bool handleEvent(Ion::Events::Event event) override; private: ExpressionEditorView m_view; + Poincare::ExpressionLayout * m_expressionLayout; Poincare::ExpressionLayoutCursor m_cursor; }; diff --git a/apps/expression_editor/expression_editor_view.cpp b/apps/expression_editor/expression_editor_view.cpp index fc13a7f78..5d1047e53 100644 --- a/apps/expression_editor/expression_editor_view.cpp +++ b/apps/expression_editor/expression_editor_view.cpp @@ -20,6 +20,7 @@ void ExpressionEditorView::layoutSubviews() { k_margin, bounds().width() - 2 * k_margin, bounds().height() - 2 * k_margin)); + markRectAsDirty(bounds()); } KDSize ExpressionEditorView::minimalSizeForOptimalDisplay() const { diff --git a/apps/expression_editor/scrollable_expression_view_with_cursor.cpp b/apps/expression_editor/scrollable_expression_view_with_cursor.cpp index b7beb0baf..60b5c1733 100644 --- a/apps/expression_editor/scrollable_expression_view_with_cursor.cpp +++ b/apps/expression_editor/scrollable_expression_view_with_cursor.cpp @@ -14,7 +14,7 @@ KDSize ScrollableExpressionViewWithCursor::minimalSizeForOptimalDisplay() const } void ScrollableExpressionViewWithCursor::scrollToCursor() { - scrollToContentRect(m_expressionViewWithCursor.cursorRect()); + scrollToContentRect(m_expressionViewWithCursor.cursorRect(), true); } } From 001c174a914ec5d9635374061d9fbfecfb86bed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 14:58:55 +0100 Subject: [PATCH 028/257] [poincare] Fixed problem when the cursor is on a layout extremum. Before, if the cursor pointed at the main Horizontal layout, the user could not add text because this layout has no parent. Now the cursor cannot go to the main HorizontalLayout extrema. Change-Id: I360e5da8b250b73945888e88bc1adcdf67ce1ae3 --- poincare/src/layout/horizontal_layout.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 4df2322aa..d025e9f8a 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -64,8 +64,11 @@ bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { if (childIndex == 0) { // Case: the child is the leftmost. // Ask the parent. - cursor->setPointedExpressionLayout(this); if (m_parent) { + // Only move the cursor if the layout has a parent: If not, the cursor + // would go on the extrema of the main HorizontalLayout, which prevents + // the user from adding more text. + cursor->setPointedExpressionLayout(this); return m_parent->moveLeft(cursor); } return false; @@ -111,8 +114,11 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { if (childIndex == numberOfChildren() - 1) { // Case: the child is the rightmost. // Ask the parent. - cursor->setPointedExpressionLayout(this); if (m_parent) { + // Only move the cursor if the layout has a parent: If not, the cursor + // would go on the extrema of the main HorizontalLayout, which prevents + // the user from adding more text. + cursor->setPointedExpressionLayout(this); return m_parent->moveRight(cursor); } return false; From aa8621f7622b756a4d1f6f87663f0a9b46790f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 15:09:00 +0100 Subject: [PATCH 029/257] [expression_editor] Move the cursor right of the text input. Change-Id: I4c78280a880a9d96e629b26c3d0ad77a1392eb2d --- poincare/src/layout/expression_layout.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 438726b2f..5868bce26 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -126,6 +126,9 @@ void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLay bool ExpressionLayout::insertLayoutForTextAtCursor(const char * text, ExpressionLayoutCursor * cursor) { EditableStringLayout * newChild = new EditableStringLayout(text, strlen(text)); cursor->pointedExpressionLayout()->addBrother(cursor, newChild); + cursor->setPointedExpressionLayout(newChild); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPositionInside(0); return true; } From 1c54da21c4038deebd9f58e0381a20ed207baa53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 15:23:22 +0100 Subject: [PATCH 030/257] [poincare] Char layout. Change-Id: I1fc7180b724b7a9faee0bc0e6e7762a1e883f925 --- poincare/Makefile | 1 + poincare/src/layout/char_layout.cpp | 68 +++++++++++++++++++++++++++++ poincare/src/layout/char_layout.h | 27 ++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 poincare/src/layout/char_layout.cpp create mode 100644 poincare/src/layout/char_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index ba3d233bf..e14e404b0 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -90,6 +90,7 @@ objs += $(addprefix poincare/src/layout/,\ bracket_left_right_layout.o\ bracket_right_layout.o\ ceiling_layout.o\ + char_layout.o\ condensed_sum_layout.o\ conjugate_layout.o\ dynamic_layout_hierarchy.o\ diff --git a/poincare/src/layout/char_layout.cpp b/poincare/src/layout/char_layout.cpp new file mode 100644 index 000000000..b81762916 --- /dev/null +++ b/poincare/src/layout/char_layout.cpp @@ -0,0 +1,68 @@ +#include "char_layout.h" +#include +#include +#include + +namespace Poincare { + +CharLayout::CharLayout(char c, KDText::FontSize fontSize) : + StaticLayoutHierarchy<0>(), + m_char(c), + m_fontSize(fontSize) +{ + // Half height of the font. + m_baseline = (KDText::charSize(m_fontSize).height()+1)/2; +} + +ExpressionLayout * CharLayout::clone() const { + CharLayout * layout = new CharLayout(m_char, m_fontSize); + return layout; +} + +bool CharLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +bool CharLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + +void CharLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + char string[2] = {m_char, 0}; + ctx->drawString(string, p, m_fontSize, expressionColor, backgroundColor); +} + +KDPoint CharLayout::positionOfChild(ExpressionLayout * child) { + assert(false); + return KDPointZero; +} + +KDSize CharLayout::computeSize() { + return KDText::charSize(m_fontSize); +} + +} diff --git a/poincare/src/layout/char_layout.h b/poincare/src/layout/char_layout.h new file mode 100644 index 000000000..37cedfb90 --- /dev/null +++ b/poincare/src/layout/char_layout.h @@ -0,0 +1,27 @@ +#ifndef POINCARE_CHAR_LAYOUT_H +#define POINCARE_CHAR_LAYOUT_H + +#include +#include + +namespace Poincare { + +class CharLayout : public StaticLayoutHierarchy<0> { +public: + CharLayout(char c, KDText::FontSize fontSize = KDText::FontSize::Large); + ExpressionLayout * clone() const override; + + char character() { return m_char; } + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + KDPoint positionOfChild(ExpressionLayout * child) override; + KDSize computeSize() override; + char m_char; + KDText::FontSize m_fontSize; +}; + +} + +#endif From b3598e17134df04f3d21f16676c6bf55ed19f5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 15:36:47 +0100 Subject: [PATCH 031/257] [expression_editor] Insert text char by char, using CharLayout. Change-Id: Id5b146bf875c1cf1d9ac949258d43a5ed415a334 --- apps/expression_editor/controller.cpp | 20 ++++++++++++++++++- apps/expression_editor/controller.h | 1 + poincare/include/poincare/expression_layout.h | 2 +- poincare/src/layout/expression_layout.cpp | 7 +------ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 4053ad77c..f82229f4e 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -1,4 +1,5 @@ #include "controller.h" +#include //TODO move from there. namespace ExpressionEditor { @@ -34,7 +35,8 @@ bool Controller::handleEvent(Ion::Events::Event event) { { returnValue = true; } - else if (event.hasText() && m_expressionLayout->insertLayoutForTextAtCursor(event.text(), &m_cursor)) { + else if (event.hasText()) { + insertTextAtCursor(event.text()); returnValue = true; m_expressionLayout->invalidAllSizesAndPositions(); m_view.layoutSubviews(); @@ -43,4 +45,20 @@ bool Controller::handleEvent(Ion::Events::Event event) { return returnValue; } +void Controller::insertTextAtCursor(const char * text) { + int textLength = strlen(text); + if (textLength <= 0) { + return; + } + Poincare::CharLayout * newChild = nullptr; + for (int i = 0; i < textLength; i++) { + newChild = new Poincare::CharLayout(text[i]); + m_cursor.pointedExpressionLayout()->addBrother(&m_cursor, newChild); + } + assert(newChild != nullptr); + m_cursor.setPointedExpressionLayout(newChild); + m_cursor.setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + m_cursor.setPositionInside(0); +} + } diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index d827c35d0..f95e5513b 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -18,6 +18,7 @@ public: void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; private: + void insertTextAtCursor(const char * text); ExpressionEditorView m_view; Poincare::ExpressionLayout * m_expressionLayout; Poincare::ExpressionLayoutCursor m_cursor; diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 91a04f8cc..a9c824f1d 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -45,7 +45,7 @@ public: ExpressionLayout * editableParent() { return m_parent; } bool hasAncestor(const ExpressionLayout * e) const; - bool insertLayoutForTextAtCursor(const char * text, ExpressionLayoutCursor * cursor); + bool insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor); void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace = true); diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 5868bce26..f7b52bcf9 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -120,15 +120,10 @@ void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLay return; } replaceWithJuxtapositionOf(this, brother, false); - //TODO Inside position } -bool ExpressionLayout::insertLayoutForTextAtCursor(const char * text, ExpressionLayoutCursor * cursor) { - EditableStringLayout * newChild = new EditableStringLayout(text, strlen(text)); +bool ExpressionLayout::insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor) { cursor->pointedExpressionLayout()->addBrother(cursor, newChild); - cursor->setPointedExpressionLayout(newChild); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - cursor->setPositionInside(0); return true; } From ed7614c925ef7194fe71e928358a76ab7ae1c5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 15:40:02 +0100 Subject: [PATCH 032/257] [poincare] Removed outdated comment. Change-Id: I80cbfa3a3f643e18ca263ed772c2f4da95ca68a5 --- poincare/src/layout/string_layout.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index 5a70b44fd..60060efb3 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -8,9 +8,6 @@ namespace Poincare { class StringLayout : public StaticLayoutHierarchy<0> { public: - // Here the inverse is a uint8_t instead of a bool, because the size of a bool is - // not standardized, thus since we call a foreign C function with this value we want to be - // sure about compatibility. StringLayout(const char * string, size_t length, KDText::FontSize fontSize = KDText::FontSize::Large); ~StringLayout(); StringLayout(const StringLayout& other) = delete; From 82469ca96eb32903be07cbb5937093c6116f6bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 16:31:15 +0100 Subject: [PATCH 033/257] [poincare] Added margins to ConjugateLayout. Change-Id: I27b3788c87d36390fcea63c6a70b89aa36a2e9f3 --- escher/include/escher/metric.h | 2 ++ poincare/src/layout/conjugate_layout.cpp | 9 +++++---- poincare/src/layout/conjugate_layout.h | 2 +- poincare/src/layout/fraction_layout.cpp | 5 +++-- poincare/src/layout/fraction_layout.h | 2 -- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/escher/include/escher/metric.h b/escher/include/escher/metric.h index cb62d2724..06c060a1c 100644 --- a/escher/include/escher/metric.h +++ b/escher/include/escher/metric.h @@ -25,6 +25,8 @@ public: constexpr static KDCoordinate ExamPopUpBottomMargin = 55; constexpr static KDCoordinate StoreRowHeight = 50; constexpr static KDCoordinate ToolboxRowHeight = 40; + constexpr static KDCoordinate FractionAndConjugateHorizontalOverflow = 2; + constexpr static KDCoordinate FractionAndConjugateHorizontalMargin = 2; }; #endif diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index db289ce45..45b9f7991 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -1,4 +1,5 @@ #include "conjugate_layout.h" +#include #include extern "C" { #include @@ -10,7 +11,7 @@ namespace Poincare { ConjugateLayout::ConjugateLayout(ExpressionLayout * operand, bool cloneOperands) : StaticLayoutHierarchy<1>(operand, cloneOperands) { - m_baseline = operandLayout()->baseline()+k_overlineWidth+k_overlineMargin; + m_baseline = operandLayout()->baseline()+k_overlineWidth+k_overlineVerticalMargin; } ExpressionLayout * ConjugateLayout::clone() const { @@ -79,16 +80,16 @@ bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { } void ConjugateLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - ctx->fillRect(KDRect(p.x(), p.y(), operandLayout()->size().width(), k_overlineWidth), expressionColor); + ctx->fillRect(KDRect(p.x()+Metric::FractionAndConjugateHorizontalMargin, p.y(), operandLayout()->size().width()+2*Metric::FractionAndConjugateHorizontalOverflow, k_overlineWidth), expressionColor); } KDSize ConjugateLayout::computeSize() { KDSize operandSize = operandLayout()->size(); - return KDSize(operandSize.width(), operandSize.height()+k_overlineWidth+k_overlineMargin); + return KDSize(Metric::FractionAndConjugateHorizontalMargin+Metric::FractionAndConjugateHorizontalOverflow+operandSize.width()+Metric::FractionAndConjugateHorizontalOverflow+Metric::FractionAndConjugateHorizontalMargin, operandSize.height()+k_overlineWidth+k_overlineVerticalMargin); } KDPoint ConjugateLayout::positionOfChild(ExpressionLayout * child) { - return KDPoint(0, k_overlineWidth+k_overlineMargin); + return KDPoint(Metric::FractionAndConjugateHorizontalMargin+Metric::FractionAndConjugateHorizontalOverflow, k_overlineWidth+k_overlineVerticalMargin); } ExpressionLayout * ConjugateLayout::operandLayout() { diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 15834cce4..5bb16be5b 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -17,7 +17,7 @@ protected: KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_overlineWidth = 1; - constexpr static KDCoordinate k_overlineMargin = 3; + constexpr static KDCoordinate k_overlineVerticalMargin = 1; ExpressionLayout * operandLayout(); }; diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 41d4ec315..5d183530e 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -1,4 +1,5 @@ #include "fraction_layout.h" +#include #include #include #include @@ -101,12 +102,12 @@ bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout void FractionLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDCoordinate fractionLineY = p.y() + numeratorLayout()->size().height() + k_fractionLineMargin; - ctx->fillRect(KDRect(p.x()+k_fractionBorderMargin, fractionLineY, size().width()-2*k_fractionBorderMargin, 1), expressionColor); + ctx->fillRect(KDRect(p.x()+Metric::FractionAndConjugateHorizontalMargin, fractionLineY, size().width()-2*Metric::FractionAndConjugateHorizontalMargin, 1), expressionColor); } KDSize FractionLayout::computeSize() { KDCoordinate width = max(numeratorLayout()->size().width(), denominatorLayout()->size().width()) - + 2*k_fractionBorderLength+2*k_fractionBorderMargin; + + 2*Metric::FractionAndConjugateHorizontalOverflow+2*Metric::FractionAndConjugateHorizontalMargin; KDCoordinate height = numeratorLayout()->size().height() + k_fractionLineMargin + k_fractionLineHeight + k_fractionLineMargin + denominatorLayout()->size().height(); diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 13154045b..c2c93d275 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -18,8 +18,6 @@ protected: KDSize computeSize() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: - constexpr static KDCoordinate k_fractionBorderLength = 2; - constexpr static KDCoordinate k_fractionBorderMargin = 2; constexpr static KDCoordinate k_fractionLineMargin = 2; constexpr static KDCoordinate k_fractionLineHeight = 2; ExpressionLayout * numeratorLayout(); From 04323e82843097a132caa81cd5c9138c2e096658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 19 Dec 2017 16:35:20 +0100 Subject: [PATCH 034/257] [poincare] Changed the navigation in ConjugateLayout. The cursor can now be Right of the conjugate and Right of the operand, not just Right of the operand. Change-Id: I409ca5595c8e19ad29995bbdcc4309a99bf21c73 --- poincare/src/layout/conjugate_layout.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index 45b9f7991..cfe653ab0 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -21,24 +21,21 @@ ExpressionLayout * ConjugateLayout::clone() const { bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the operand. - // Ask the parent. + // Move Left. if (operandLayout() && cursor->pointedExpressionLayout() == operandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Left) { cursor->setPointedExpressionLayout(this); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; + return true; } assert(cursor->pointedExpressionLayout() == this); // Case: Right. - // Go to the operand and move Left. + // Go to the operand. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(operandLayout() != nullptr); cursor->setPointedExpressionLayout(operandLayout()); - return operandLayout()->moveLeft(cursor); + return true; } // Case: Left. // Ask the parent. @@ -51,24 +48,21 @@ bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right of the operand. - // Ask the parent. + // Move Right. if (operandLayout() && cursor->pointedExpressionLayout() == operandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; + return true; } assert(cursor->pointedExpressionLayout() == this); // Case: Left. - // Go to the operand and move Right. + // Go to the operand. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { assert(operandLayout() != nullptr); cursor->setPointedExpressionLayout(operandLayout()); - return operandLayout()->moveRight(cursor); + return true; } // Case: Right. // Ask the parent. From 62322da1ee3ed25e3e3d061c6258ebec81afacbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 09:55:37 +0100 Subject: [PATCH 035/257] [poincare] Empty and EmptyVisible layouts. Change-Id: Id3234f406e1bfe7addb704c873bde357546ddf67 --- poincare/Makefile | 2 + poincare/src/layout/empty_layout.cpp | 38 +++++++++++++ poincare/src/layout/empty_layout.h | 26 +++++++++ poincare/src/layout/empty_visible_layout.cpp | 60 ++++++++++++++++++++ poincare/src/layout/empty_visible_layout.h | 30 ++++++++++ 5 files changed, 156 insertions(+) create mode 100644 poincare/src/layout/empty_layout.cpp create mode 100644 poincare/src/layout/empty_layout.h create mode 100644 poincare/src/layout/empty_visible_layout.cpp create mode 100644 poincare/src/layout/empty_visible_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index e14e404b0..d5e88b035 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -96,6 +96,8 @@ objs += $(addprefix poincare/src/layout/,\ dynamic_layout_hierarchy.o\ editable_baseline_relative_layout.o\ editable_string_layout.o\ + empty_layout.o\ + empty_visible_layout.o\ expression_layout.o\ floor_layout.o\ fraction_layout.o\ diff --git a/poincare/src/layout/empty_layout.cpp b/poincare/src/layout/empty_layout.cpp new file mode 100644 index 000000000..3823553e5 --- /dev/null +++ b/poincare/src/layout/empty_layout.cpp @@ -0,0 +1,38 @@ +#include "empty_layout.h" +#include +#include + +namespace Poincare { + +EmptyLayout::EmptyLayout() : + StaticLayoutHierarchy<0>() +{ + m_baseline = 0; +} + +ExpressionLayout * EmptyLayout::clone() const { + EmptyLayout * layout = new EmptyLayout(); + return layout; +} + +bool EmptyLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Ask the parent. + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +bool EmptyLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Ask the parent. + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + +} diff --git a/poincare/src/layout/empty_layout.h b/poincare/src/layout/empty_layout.h new file mode 100644 index 000000000..9f1a61da7 --- /dev/null +++ b/poincare/src/layout/empty_layout.h @@ -0,0 +1,26 @@ +#ifndef POINCARE_EMPTY_LAYOUT_H +#define POINCARE_EMPTY_LAYOUT_H + +#include +#include + +namespace Poincare { + +class EmptyLayout : public StaticLayoutHierarchy<0> { +public: + EmptyLayout(); + ExpressionLayout * clone() const override; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; +protected: + virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { return; } + virtual KDSize computeSize() override { return KDSizeZero; } + KDPoint positionOfChild(ExpressionLayout * child) override { + assert(false); + return KDPointZero; + } +}; + +} + +#endif diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp new file mode 100644 index 000000000..3d8910572 --- /dev/null +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -0,0 +1,60 @@ +#include "empty_visible_layout.h" +#include +#include + +namespace Poincare { + +EmptyVisibleLayout::EmptyVisibleLayout() : + EmptyLayout(), + m_fillRectColor(KDColor::RGB24(0xffd370)) //TODO make static or in Palette? +{ + m_baseline = k_height + 2*k_marginHeight; +} + +ExpressionLayout * EmptyVisibleLayout::clone() const { + EmptyVisibleLayout * layout = new EmptyVisibleLayout(); + return layout; +} + +bool EmptyVisibleLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +bool EmptyVisibleLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + +void EmptyVisibleLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + ctx->fillRect(KDRect(p.x()+k_marginWidth, p.y()+k_marginHeight, k_width, k_height), m_fillRectColor); + ctx->fillRect(KDRect(p.x()+k_marginWidth, p.y()+k_marginHeight, k_width, k_height), m_fillRectColor); +} + +KDSize EmptyVisibleLayout::computeSize() { + return KDSize(k_width + 2*k_marginWidth, k_height + 2*k_marginHeight); +} + +} diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h new file mode 100644 index 000000000..c595e9b02 --- /dev/null +++ b/poincare/src/layout/empty_visible_layout.h @@ -0,0 +1,30 @@ +#ifndef POINCARE_EMPTY_VISIBLE_LAYOUT_H +#define POINCARE_EMPTY_VISIBLE_LAYOUT_H + +#include "empty_layout.h" +#include + +namespace Poincare { + +class EmptyVisibleLayout : public EmptyLayout { +public: + EmptyVisibleLayout(); + ExpressionLayout * clone() const override; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; +protected: + virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + virtual KDSize computeSize() override; +private: + constexpr static KDCoordinate k_width = 7; + constexpr static KDCoordinate k_height = 13; + constexpr static KDCoordinate k_marginWidth = 1; + constexpr static KDCoordinate k_marginHeight = 3; + constexpr static KDCoordinate k_lineThickness = 1; + + KDColor m_fillRectColor; +}; + +} + +#endif From 241d37afa59bb0af3f3a7505dc0a78c2922e22a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 10:27:14 +0100 Subject: [PATCH 036/257] [poincare] Recompute baselines when needed. Change-Id: I4ec717402a4dfd287aa95f45189e1734e4f5e3ed --- apps/expression_editor/controller.cpp | 2 +- poincare/include/poincare/expression_layout.h | 6 ++++-- .../src/layout/baseline_relative_layout.cpp | 9 +++++++-- poincare/src/layout/baseline_relative_layout.h | 1 + poincare/src/layout/bracket_layout.cpp | 7 ++++++- poincare/src/layout/bracket_layout.h | 1 + .../src/layout/bracket_left_right_layout.cpp | 6 ++++++ .../src/layout/bracket_left_right_layout.h | 1 + poincare/src/layout/char_layout.cpp | 9 +++++++-- poincare/src/layout/char_layout.h | 1 + poincare/src/layout/condensed_sum_layout.cpp | 9 +++++++-- poincare/src/layout/condensed_sum_layout.h | 1 + poincare/src/layout/conjugate_layout.cpp | 7 ++++++- poincare/src/layout/conjugate_layout.h | 1 + poincare/src/layout/empty_layout.cpp | 5 +++++ poincare/src/layout/empty_layout.h | 1 + poincare/src/layout/empty_visible_layout.cpp | 7 ++++++- poincare/src/layout/empty_visible_layout.h | 1 + poincare/src/layout/expression_layout.cpp | 15 +++++++++++++-- poincare/src/layout/fraction_layout.cpp | 9 +++++++-- poincare/src/layout/fraction_layout.h | 1 + poincare/src/layout/grid_layout.cpp | 11 ++++++++--- poincare/src/layout/grid_layout.h | 1 + poincare/src/layout/horizontal_layout.cpp | 18 ++++++++++++------ poincare/src/layout/horizontal_layout.h | 1 + poincare/src/layout/integral_layout.cpp | 7 ++++++- poincare/src/layout/integral_layout.h | 1 + poincare/src/layout/nth_root_layout.cpp | 17 +++++++++++------ poincare/src/layout/nth_root_layout.h | 1 + poincare/src/layout/parenthesis_layout.cpp | 7 ++++++- poincare/src/layout/parenthesis_layout.h | 1 + .../layout/parenthesis_left_right_layout.cpp | 6 ++++++ .../src/layout/parenthesis_left_right_layout.h | 1 + poincare/src/layout/sequence_layout.cpp | 7 ++++++- poincare/src/layout/sequence_layout.h | 1 + poincare/src/layout/string_layout.cpp | 8 ++++++-- poincare/src/layout/string_layout.h | 1 + 37 files changed, 153 insertions(+), 36 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index f82229f4e..0a83b28c7 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -38,7 +38,7 @@ bool Controller::handleEvent(Ion::Events::Event event) { else if (event.hasText()) { insertTextAtCursor(event.text()); returnValue = true; - m_expressionLayout->invalidAllSizesAndPositions(); + m_expressionLayout->invalidAllSizesPositionsAndBaselines(); m_view.layoutSubviews(); } m_view.cursorPositionChanged(); diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index a9c824f1d..1e48236df 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -30,8 +30,8 @@ public: KDPoint origin(); KDPoint absoluteOrigin(); KDSize size(); - KDCoordinate baseline() const { return m_baseline; } - void invalidAllSizesAndPositions(); + KDCoordinate baseline(); + void invalidAllSizesPositionsAndBaselines(); /* Hierarchy */ virtual const ExpressionLayout * const * children() const = 0; @@ -66,6 +66,7 @@ public: protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; + virtual void computeBaseline() = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; void detachChildAtIndex(int i); virtual void moveCursorInsideAtDirection ( @@ -78,6 +79,7 @@ protected: KDCoordinate m_baseline; ExpressionLayout * m_parent; bool m_sized; + bool m_baselined; private: bool moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor); void replaceWithJuxtapositionOf(ExpressionLayout * firstLayout, ExpressionLayout * secondLayout); diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index 0e5b23439..39b0bac48 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -9,8 +9,7 @@ BaselineRelativeLayout::BaselineRelativeLayout(ExpressionLayout * base, Expressi StaticLayoutHierarchy(base, indice, cloneOperands), m_type(type) { - m_baseline = type == Type::Subscript ? baseLayout()->baseline() : - indiceLayout()->size().height() + baseLayout()->baseline() - k_indiceHeight; + computeBaseline(); } ExpressionLayout * BaselineRelativeLayout::clone() const { @@ -70,6 +69,12 @@ KDSize BaselineRelativeLayout::computeSize() { return KDSize(baseSize.width() + indiceSize.width(), baseSize.height() + indiceSize.height() - k_indiceHeight); } +void BaselineRelativeLayout::computeBaseline() { + m_baseline = m_type == Type::Subscript ? baseLayout()->baseline() : + indiceLayout()->size().height() + baseLayout()->baseline() - k_indiceHeight; + m_baselined = true; +} + KDPoint BaselineRelativeLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index 8ef335015..1e72783a8 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -20,6 +20,7 @@ protected: ExpressionLayout * indiceLayout(); void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; Type m_type; private: diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 487d1e2b0..1ad946b87 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -10,7 +10,7 @@ namespace Poincare { BracketLayout::BracketLayout(ExpressionLayout * operandLayout, bool cloneOperands) : StaticLayoutHierarchy<1>(operandLayout, cloneOperands) { - m_baseline = operandLayout->baseline(); + computeBaseline(); } ExpressionLayout * BracketLayout::clone() const { @@ -100,6 +100,11 @@ KDSize BracketLayout::computeSize() { return KDSize(operandSize.width() + 2*k_externWidthMargin + 2*k_widthMargin + 2*k_lineThickness, operandSize.height()); } +void BracketLayout::computeBaseline() { + m_baseline = operandLayout()->baseline(); + m_baselined = true; +} + KDPoint BracketLayout::positionOfChild(ExpressionLayout * child) { const KDCoordinate k_widthMargin = widthMargin(); const KDCoordinate k_externWidthMargin = externWidthMargin(); diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index 977095632..b9beeb4c7 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -19,6 +19,7 @@ protected: virtual bool renderBottomBar() const { return true; } void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_bracketWidth = 5; diff --git a/poincare/src/layout/bracket_left_right_layout.cpp b/poincare/src/layout/bracket_left_right_layout.cpp index 70701274d..98d01121e 100644 --- a/poincare/src/layout/bracket_left_right_layout.cpp +++ b/poincare/src/layout/bracket_left_right_layout.cpp @@ -53,6 +53,12 @@ KDSize BracketLeftRightLayout::computeSize() { return KDSize(k_externWidthMargin + k_lineThickness + k_bracketWidth + k_widthMargin, m_operandHeight); } +void BracketLeftRightLayout::computeBaseline() { + //TODO: compute the operandHeight according to the brothers + m_baseline = m_operandHeight; + m_baselined = true; +} + KDPoint BracketLeftRightLayout::positionOfChild(ExpressionLayout * child) { assert(false); return KDPointZero; diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h index 1c9527e1b..838b9e00e 100644 --- a/poincare/src/layout/bracket_left_right_layout.h +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -16,6 +16,7 @@ public: constexpr static KDCoordinate k_externWidthMargin = 2; protected: KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; uint16_t m_operandHeight; }; diff --git a/poincare/src/layout/char_layout.cpp b/poincare/src/layout/char_layout.cpp index b81762916..22357ddfc 100644 --- a/poincare/src/layout/char_layout.cpp +++ b/poincare/src/layout/char_layout.cpp @@ -10,8 +10,7 @@ CharLayout::CharLayout(char c, KDText::FontSize fontSize) : m_char(c), m_fontSize(fontSize) { - // Half height of the font. - m_baseline = (KDText::charSize(m_fontSize).height()+1)/2; + computeBaseline(); } ExpressionLayout * CharLayout::clone() const { @@ -65,4 +64,10 @@ KDSize CharLayout::computeSize() { return KDText::charSize(m_fontSize); } +void CharLayout::computeBaseline() { + // Half height of the font. + m_baseline = (KDText::charSize(m_fontSize).height()+1)/2; + m_baselined = true; +} + } diff --git a/poincare/src/layout/char_layout.h b/poincare/src/layout/char_layout.h index 37cedfb90..d00625c09 100644 --- a/poincare/src/layout/char_layout.h +++ b/poincare/src/layout/char_layout.h @@ -18,6 +18,7 @@ protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDPoint positionOfChild(ExpressionLayout * child) override; KDSize computeSize() override; + void computeBaseline() override; char m_char; KDText::FontSize m_fontSize; }; diff --git a/poincare/src/layout/condensed_sum_layout.cpp b/poincare/src/layout/condensed_sum_layout.cpp index d696cb170..04babee19 100644 --- a/poincare/src/layout/condensed_sum_layout.cpp +++ b/poincare/src/layout/condensed_sum_layout.cpp @@ -8,8 +8,7 @@ namespace Poincare { CondensedSumLayout::CondensedSumLayout(ExpressionLayout * base, ExpressionLayout * subscript, ExpressionLayout * superscript, bool cloneOperands) : StaticLayoutHierarchy<3>(base, subscript, superscript, cloneOperands) { - KDSize superscriptSize = superscriptLayout() == nullptr ? KDSizeZero : superscriptLayout()->size(); - m_baseline = baseLayout()->baseline() + max(0, superscriptSize.height() - baseLayout()->size().height()/2); + computeBaseline(); } ExpressionLayout * CondensedSumLayout::clone() const { @@ -142,6 +141,12 @@ KDSize CondensedSumLayout::computeSize() { return KDSize(baseSize.width() + max(subscriptSize.width(), superscriptSize.width()), max(baseSize.height()/2, subscriptSize.height()) + max(baseSize.height()/2, superscriptSize.height())); } +void CondensedSumLayout::computeBaseline() { + KDSize superscriptSize = superscriptLayout() == nullptr ? KDSizeZero : superscriptLayout()->size(); + m_baseline = baseLayout()->baseline() + max(0, superscriptSize.height() - baseLayout()->size().height()/2); + m_baselined = true; +} + KDPoint CondensedSumLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index 16528e6c7..fa9179acd 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -16,6 +16,7 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: ExpressionLayout * baseLayout(); diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index cfe653ab0..97317f5dc 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -11,7 +11,7 @@ namespace Poincare { ConjugateLayout::ConjugateLayout(ExpressionLayout * operand, bool cloneOperands) : StaticLayoutHierarchy<1>(operand, cloneOperands) { - m_baseline = operandLayout()->baseline()+k_overlineWidth+k_overlineVerticalMargin; + computeBaseline(); } ExpressionLayout * ConjugateLayout::clone() const { @@ -82,6 +82,11 @@ KDSize ConjugateLayout::computeSize() { return KDSize(Metric::FractionAndConjugateHorizontalMargin+Metric::FractionAndConjugateHorizontalOverflow+operandSize.width()+Metric::FractionAndConjugateHorizontalOverflow+Metric::FractionAndConjugateHorizontalMargin, operandSize.height()+k_overlineWidth+k_overlineVerticalMargin); } +void ConjugateLayout::computeBaseline() { + m_baseline = operandLayout()->baseline()+k_overlineWidth+k_overlineVerticalMargin; + m_baselined = true; +} + KDPoint ConjugateLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(Metric::FractionAndConjugateHorizontalMargin+Metric::FractionAndConjugateHorizontalOverflow, k_overlineWidth+k_overlineVerticalMargin); } diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 5bb16be5b..732e89e49 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -14,6 +14,7 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_overlineWidth = 1; diff --git a/poincare/src/layout/empty_layout.cpp b/poincare/src/layout/empty_layout.cpp index 3823553e5..fe9a28222 100644 --- a/poincare/src/layout/empty_layout.cpp +++ b/poincare/src/layout/empty_layout.cpp @@ -35,4 +35,9 @@ bool EmptyLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +void EmptyLayout::computeBaseline() { + m_baseline = 0; + m_baselined = true; +} + } diff --git a/poincare/src/layout/empty_layout.h b/poincare/src/layout/empty_layout.h index 9f1a61da7..5573b0207 100644 --- a/poincare/src/layout/empty_layout.h +++ b/poincare/src/layout/empty_layout.h @@ -15,6 +15,7 @@ public: protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { return; } virtual KDSize computeSize() override { return KDSizeZero; } + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override { assert(false); return KDPointZero; diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index 3d8910572..f6cdaf7b4 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -8,7 +8,7 @@ EmptyVisibleLayout::EmptyVisibleLayout() : EmptyLayout(), m_fillRectColor(KDColor::RGB24(0xffd370)) //TODO make static or in Palette? { - m_baseline = k_height + 2*k_marginHeight; + computeBaseline(); } ExpressionLayout * EmptyVisibleLayout::clone() const { @@ -57,4 +57,9 @@ KDSize EmptyVisibleLayout::computeSize() { return KDSize(k_width + 2*k_marginWidth, k_height + 2*k_marginHeight); } +void EmptyVisibleLayout::computeBaseline() { + m_baseline = k_marginHeight + k_height/2; + m_baselined = true; +} + } diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index c595e9b02..7a88565b9 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -15,6 +15,7 @@ public: protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; virtual KDSize computeSize() override; + void computeBaseline() override; private: constexpr static KDCoordinate k_width = 7; constexpr static KDCoordinate k_height = 13; diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index f7b52bcf9..3a92820d7 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -11,6 +11,7 @@ ExpressionLayout::ExpressionLayout() : m_baseline(0), m_parent(nullptr), m_sized(false), + m_baselined(false), m_positioned(false), m_frame(KDRectZero) { } @@ -67,11 +68,21 @@ KDSize ExpressionLayout::size() { return m_frame.size(); } -void ExpressionLayout::invalidAllSizesAndPositions() { +KDCoordinate ExpressionLayout::baseline() { + if (!m_baselined) { + computeBaseline(); + m_baselined = true; + } + return m_baseline; +} + + +void ExpressionLayout::invalidAllSizesPositionsAndBaselines() { m_sized = false; m_positioned = false; + m_baselined = false; for (int i = 0; i < numberOfChildren(); i++) { - editableChild(i)->invalidAllSizesAndPositions(); + editableChild(i)->invalidAllSizesPositionsAndBaselines(); } } diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 5d183530e..6fd6651b3 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -9,8 +9,7 @@ namespace Poincare { FractionLayout::FractionLayout(ExpressionLayout * numerator, ExpressionLayout * denominator, bool cloneOperands) : StaticLayoutHierarchy<2>(numerator, denominator, cloneOperands) { - m_baseline = numeratorLayout()->size().height() - + k_fractionLineMargin + k_fractionLineHeight; + computeBaseline(); } ExpressionLayout * FractionLayout::clone() const { @@ -114,6 +113,12 @@ KDSize FractionLayout::computeSize() { return KDSize(width, height); } +void FractionLayout::computeBaseline() { + m_baseline = numeratorLayout()->size().height() + + k_fractionLineMargin + k_fractionLineHeight; + m_baselined = true; +} + KDPoint FractionLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index c2c93d275..670718879 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -16,6 +16,7 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_fractionLineMargin = 2; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index c379c5883..504a9c65d 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -12,7 +12,7 @@ GridLayout::GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int n m_numberOfRows(numberOfRows), m_numberOfColumns(numberOfColumns) { - m_baseline = (height()+1)/2; + computeBaseline(); } ExpressionLayout * GridLayout::clone() const { @@ -116,7 +116,7 @@ bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * pr KDCoordinate GridLayout::rowBaseline(int i) { KDCoordinate rowBaseline = 0; for (int j = 0; j < m_numberOfColumns; j++) { - rowBaseline = max(rowBaseline, child(i*m_numberOfColumns+j)->baseline()); + rowBaseline = max(rowBaseline, editableChild(i*m_numberOfColumns+j)->baseline()); } return rowBaseline; } @@ -125,7 +125,7 @@ KDCoordinate GridLayout::rowHeight(int i) { KDCoordinate rowHeight = 0; KDCoordinate baseline = rowBaseline(i); for (int j = 0; j < m_numberOfColumns; j++) { - rowHeight = max(rowHeight, editableChild(i*m_numberOfColumns+j)->size().height() - child(i*m_numberOfColumns+j)->baseline()); + rowHeight = max(rowHeight, editableChild(i*m_numberOfColumns+j)->size().height() - editableChild(i*m_numberOfColumns+j)->baseline()); } return baseline+rowHeight; } @@ -164,6 +164,11 @@ KDSize GridLayout::computeSize() { return KDSize(width(), height()); } +void GridLayout::computeBaseline() { + m_baseline = (height()+1)/2; + m_baselined = true; +} + KDPoint GridLayout::positionOfChild(ExpressionLayout * child) { int rowIndex = 0; int columnIndex = 0; diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index ce48b66e6..379fd642f 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -19,6 +19,7 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_gridEntryMargin = 6; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index d025e9f8a..dc627bee9 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -18,11 +18,7 @@ HorizontalLayout::HorizontalLayout() : HorizontalLayout::HorizontalLayout(ExpressionLayout ** childrenLayouts, int childrenCount, bool cloneOperands) : DynamicLayoutHierarchy(childrenLayouts, childrenCount, cloneOperands) { - for (int i = 0; i < numberOfChildren(); i++) { - if (child(i)->baseline() > m_baseline) { - m_baseline = child(i)->baseline(); - } - } + computeBaseline(); } ExpressionLayout * HorizontalLayout::clone() const { @@ -159,6 +155,16 @@ KDSize HorizontalLayout::computeSize() { return KDSize(totalWidth, max_under_baseline + max_above_baseline); } +void HorizontalLayout::computeBaseline() { + m_baseline = 0; + for (int i = 0; i < numberOfChildren(); i++) { + if (editableChild(i)->baseline() > m_baseline) { + m_baseline = editableChild(i)->baseline(); + } + } + m_baselined = true; +} + KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; @@ -168,7 +174,7 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { assert(previousChild != nullptr); x = previousChild->origin().x() + previousChild->size().width(); } - y = m_baseline - child->baseline(); + y = baseline() - child->baseline(); return KDPoint(x, y); } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index dfcd71a63..d6f8bba01 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -19,6 +19,7 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 727e477f0..4e912dd91 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -22,7 +22,7 @@ const uint8_t bottomSymbolPixel[IntegralLayout::k_symbolHeight][IntegralLayout:: IntegralLayout::IntegralLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * integrand, bool cloneOperands) : StaticLayoutHierarchy<3>(upperBound, lowerBound, integrand, cloneOperands) { - m_baseline = upperBoundLayout()->size().height() + k_integrandHeigthMargin + integrandLayout()->baseline(); + computeBaseline(); } ExpressionLayout * IntegralLayout::clone() const { @@ -168,6 +168,11 @@ KDSize IntegralLayout::computeSize() { upperBoundSize.height()+ 2*k_integrandHeigthMargin+integrandSize.height()+lowerBoundSize.height()); } +void IntegralLayout::computeBaseline() { + m_baseline = upperBoundLayout()->size().height() + k_integrandHeigthMargin + integrandLayout()->baseline(); + m_baselined = true; +} + KDPoint IntegralLayout::positionOfChild(ExpressionLayout * child) { KDSize integrandSize = integrandLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 067cc7cea..7390f644a 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -18,6 +18,7 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_boundHeightMargin = 8; diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 89a3c59a4..a52194a0f 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -19,12 +19,7 @@ const uint8_t radixPixel[NthRootLayout::k_leftRadixHeight][NthRootLayout::k_left NthRootLayout::NthRootLayout(ExpressionLayout * radicand, ExpressionLayout * index, bool cloneOperands) : StaticLayoutHierarchy<2>(radicand, index, cloneOperands) { - if (indexLayout() != nullptr) { - m_baseline = max(radicandLayout()->baseline() + k_radixLineThickness + k_heightMargin, - indexLayout()->size().height() + k_indexHeight); - } else { - m_baseline = radicandLayout()->baseline() + k_radixLineThickness + k_heightMargin; - } + computeBaseline(); } ExpressionLayout * NthRootLayout::clone() const { @@ -208,6 +203,16 @@ KDSize NthRootLayout::computeSize() { ); } +void NthRootLayout::computeBaseline() { + if (indexLayout() != nullptr) { + m_baseline = max(radicandLayout()->baseline() + k_radixLineThickness + k_heightMargin, + indexLayout()->size().height() + k_indexHeight); + } else { + m_baseline = radicandLayout()->baseline() + k_radixLineThickness + k_heightMargin; + } + m_baselined = true; +} + KDPoint NthRootLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index d942b3863..aa7d81814 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -18,6 +18,7 @@ public: protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_rightRadixHeight = 2; diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index eccab7030..b5b48641f 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -15,7 +15,7 @@ ParenthesisLayout::ParenthesisLayout(ExpressionLayout * operand, bool cloneOpera ExpressionLayout * leftParenthesis = new ParenthesisLeftLayout(); ExpressionLayout * rightParenthesis = new ParenthesisRightLayout(); build(ExpressionLayout::ExpressionLayoutArray3(leftParenthesis, operand, rightParenthesis), 3, cloneOperands); - m_baseline = operandLayout()->baseline(); + computeBaseline(); } ExpressionLayout * ParenthesisLayout::clone() const { @@ -130,6 +130,11 @@ KDSize ParenthesisLayout::computeSize() { return KDSize(operandSize.width() + 2*leftParenthesisLayout()->size().width(), operandSize.height()); } +void ParenthesisLayout::computeBaseline() { + m_baseline = operandLayout()->baseline(); + m_baselined = true; +} + KDPoint ParenthesisLayout::positionOfChild(ExpressionLayout * child) { if (child == leftParenthesisLayout()) { return KDPoint(0, 0); diff --git a/poincare/src/layout/parenthesis_layout.h b/poincare/src/layout/parenthesis_layout.h index 594d81a34..0757c6f5f 100644 --- a/poincare/src/layout/parenthesis_layout.h +++ b/poincare/src/layout/parenthesis_layout.h @@ -17,6 +17,7 @@ protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { }; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_externWidthMargin = 1; diff --git a/poincare/src/layout/parenthesis_left_right_layout.cpp b/poincare/src/layout/parenthesis_left_right_layout.cpp index 4f7e51e89..1baceff6b 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.cpp +++ b/poincare/src/layout/parenthesis_left_right_layout.cpp @@ -11,6 +11,7 @@ ParenthesisLeftRightLayout::ParenthesisLeftRightLayout() : StaticLayoutHierarchy<0>(), m_operandHeight(36) //TODO { + computeBaseline(); } bool ParenthesisLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -52,6 +53,11 @@ KDSize ParenthesisLeftRightLayout::computeSize() { return KDSize(k_widthMargin + k_lineThickness + k_externWidthMargin, m_operandHeight); } +void ParenthesisLeftRightLayout::computeBaseline() { + m_baseline = m_operandHeight/2; //TODO + m_baselined = true; +} + KDPoint ParenthesisLeftRightLayout::positionOfChild(ExpressionLayout * child) { assert(false); return KDPointZero; diff --git a/poincare/src/layout/parenthesis_left_right_layout.h b/poincare/src/layout/parenthesis_left_right_layout.h index 92d63ef3c..67381f10a 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.h +++ b/poincare/src/layout/parenthesis_left_right_layout.h @@ -19,6 +19,7 @@ public: protected: KDColor s_parenthesisWorkingBuffer[k_parenthesisCurveHeight*k_parenthesisCurveWidth]; KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; uint16_t m_operandHeight; }; diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index c810a91b6..3955f77b3 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -9,7 +9,7 @@ namespace Poincare { SequenceLayout::SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands) : StaticLayoutHierarchy<3>(upperBound, lowerBound, argument, cloneOperands) { - m_baseline = max(upperBoundLayout()->size().height()+k_boundHeightMargin+(k_symbolHeight+1)/2, argumentLayout()->baseline()); + computeBaseline(); } bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -150,6 +150,11 @@ KDSize SequenceLayout::computeSize() { ); } +void SequenceLayout::computeBaseline() { + m_baseline = max(upperBoundLayout()->size().height()+k_boundHeightMargin+(k_symbolHeight+1)/2, argumentLayout()->baseline()); + m_baselined = true; +} + KDPoint SequenceLayout::positionOfChild(ExpressionLayout * child) { KDSize lowerBoundSize = lowerBoundLayout()->size(); KDSize upperBoundSize = upperBoundLayout()->size(); diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index b9e4735d3..6e186982d 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -21,6 +21,7 @@ protected: ExpressionLayout * argumentLayout(); private: KDSize computeSize() override; + void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; constexpr static KDCoordinate k_argumentWidthMargin = 2; }; diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index e9e93970d..43996cd7d 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -12,8 +12,6 @@ StringLayout::StringLayout(const char * string, size_t length, KDText::FontSize m_string = new char[length+1]; memcpy(m_string, string, length); m_string[length] = 0; - // Half height of the font. - m_baseline = (KDText::charSize(m_fontSize).height()+1)/2; } StringLayout::~StringLayout() { @@ -72,4 +70,10 @@ KDSize StringLayout::computeSize() { return KDText::stringSize(m_string, m_fontSize); } +void StringLayout::computeBaseline() { + // Half height of the font. + m_baseline = (KDText::charSize(m_fontSize).height()+1)/2; + m_baselined = true; +} + } diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index 60060efb3..0a3763811 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -23,6 +23,7 @@ protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDPoint positionOfChild(ExpressionLayout * child) override; KDSize computeSize() override; + void computeBaseline() override; char * m_string; KDText::FontSize m_fontSize; }; From 3c45358296218ab93dbb43d07fb7b47f137bbdc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 10:37:40 +0100 Subject: [PATCH 037/257] [expression_editor] Add fraction layouts (simple version). Pressing the divide button adds an empty fraction layout without "absorbing" the neighbouring layouts. Change-Id: I46bdeadfcd80ec3c51c676ae62747e0823718645 --- apps/expression_editor/controller.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 0a83b28c7..4a4c2f842 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -1,9 +1,13 @@ #include "controller.h" #include //TODO move from there. +#include //TODO move from there. +#include //TODO move from there. + +using namespace Poincare; namespace ExpressionEditor { -Controller::Controller(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout) : +Controller::Controller(Responder * parentResponder, ExpressionLayout * expressionLayout) : ViewController(parentResponder), m_view(parentResponder, expressionLayout, &m_cursor), m_expressionLayout(expressionLayout) @@ -34,8 +38,19 @@ bool Controller::handleEvent(Ion::Events::Event event) { || (event == Ion::Events::Down && m_cursor.moveDown())) { returnValue = true; - } - else if (event.hasText()) { + } else if (event == Ion::Events::Division) { + EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); + EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); + + FractionLayout * newChild = new FractionLayout(child1, child2, false); + m_cursor.pointedExpressionLayout()->addBrother(&m_cursor, newChild); + m_cursor.setPointedExpressionLayout(newChild); + m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); + m_cursor.setPositionInside(0); + returnValue = true; + m_expressionLayout->invalidAllSizesPositionsAndBaselines(); + m_view.layoutSubviews(); + } else if (event.hasText()) { insertTextAtCursor(event.text()); returnValue = true; m_expressionLayout->invalidAllSizesPositionsAndBaselines(); @@ -50,14 +65,14 @@ void Controller::insertTextAtCursor(const char * text) { if (textLength <= 0) { return; } - Poincare::CharLayout * newChild = nullptr; + CharLayout * newChild = nullptr; for (int i = 0; i < textLength; i++) { - newChild = new Poincare::CharLayout(text[i]); + newChild = new CharLayout(text[i]); m_cursor.pointedExpressionLayout()->addBrother(&m_cursor, newChild); } assert(newChild != nullptr); m_cursor.setPointedExpressionLayout(newChild); - m_cursor.setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); m_cursor.setPositionInside(0); } From 4d94764c36e3918e31c760fdb355ee72249f5a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 11:23:58 +0100 Subject: [PATCH 038/257] [expression_editor] Controller code cleaning. Change-Id: Ifb31ad712ce9c59e21fc3d670d05f60a15669d60 --- apps/expression_editor/controller.cpp | 73 ++++++++++--------- apps/expression_editor/controller.h | 4 +- .../poincare/expression_layout_cursor.h | 17 +++-- poincare/src/expression_layout_cursor.cpp | 57 +++++++++++---- 4 files changed, 92 insertions(+), 59 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 4a4c2f842..7e747e03d 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -1,7 +1,4 @@ #include "controller.h" -#include //TODO move from there. -#include //TODO move from there. -#include //TODO move from there. using namespace Poincare; @@ -31,49 +28,53 @@ void Controller::didBecomeFirstResponder() { } bool Controller::handleEvent(Ion::Events::Event event) { - bool returnValue = false; - if ((event == Ion::Events::Left && m_cursor.moveLeft()) - || (event == Ion::Events::Right && m_cursor.moveRight()) - || (event == Ion::Events::Up && m_cursor.moveUp()) - || (event == Ion::Events::Down && m_cursor.moveDown())) - { - returnValue = true; - } else if (event == Ion::Events::Division) { - EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); - EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); + if (privateHandleEvent(event)) { + m_view.cursorPositionChanged(); + return true; + } + return false; +} - FractionLayout * newChild = new FractionLayout(child1, child2, false); - m_cursor.pointedExpressionLayout()->addBrother(&m_cursor, newChild); - m_cursor.setPointedExpressionLayout(newChild); +bool Controller::privateHandleEvent(Ion::Events::Event event) { + if (handleMoveEvent(event)) { + return true; + } + ExpressionLayout * newPointedLayout = handleAddEvent(event); + if (newPointedLayout != nullptr) { + m_cursor.setPointedExpressionLayout(newPointedLayout); m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); m_cursor.setPositionInside(0); - returnValue = true; - m_expressionLayout->invalidAllSizesPositionsAndBaselines(); - m_view.layoutSubviews(); - } else if (event.hasText()) { - insertTextAtCursor(event.text()); - returnValue = true; m_expressionLayout->invalidAllSizesPositionsAndBaselines(); m_view.layoutSubviews(); + return true; } - m_view.cursorPositionChanged(); - return returnValue; + return false; } -void Controller::insertTextAtCursor(const char * text) { - int textLength = strlen(text); - if (textLength <= 0) { - return; +bool Controller::handleMoveEvent(Ion::Events::Event event) { + if (event == Ion::Events::Left) { + return m_cursor.moveLeft(); } - CharLayout * newChild = nullptr; - for (int i = 0; i < textLength; i++) { - newChild = new CharLayout(text[i]); - m_cursor.pointedExpressionLayout()->addBrother(&m_cursor, newChild); + if (event == Ion::Events::Right) { + return m_cursor.moveRight(); } - assert(newChild != nullptr); - m_cursor.setPointedExpressionLayout(newChild); - m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); - m_cursor.setPositionInside(0); + if (event == Ion::Events::Up) { + return m_cursor.moveUp(); + } + if (event == Ion::Events::Down) { + return m_cursor.moveDown(); + } + return false; +} + +ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { + if (event == Ion::Events::Division) { + return m_cursor.addEmptyFractionLayout(); + } + if (event.hasText()) { + return m_cursor.insertText(event.text()); + } + return nullptr; } } diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index f95e5513b..e285ff8a8 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -18,7 +18,9 @@ public: void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; private: - void insertTextAtCursor(const char * text); + bool privateHandleEvent(Ion::Events::Event event); + bool handleMoveEvent(Ion::Events::Event event); + Poincare::ExpressionLayout * handleAddEvent(Ion::Events::Event event); ExpressionEditorView m_view; Poincare::ExpressionLayout * m_expressionLayout; Poincare::ExpressionLayoutCursor m_cursor; diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 0fe1f689e..88b29d81f 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -29,18 +29,23 @@ public: void setPositionInside(int positionInside) { m_positionInside = positionInside; } KDCoordinate cursorHeight() const { return k_cursorHeight; } - /* Move */ - bool moveLeft(); - bool moveRight(); - bool moveUp(); - bool moveDown(); - /* Comparison */ bool positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position, int positionIndex = 0); /* Position */ KDPoint middleLeftPoint(); KDPoint middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position, int positionInside = 0); + + /* Move */ + bool moveLeft(); + bool moveRight(); + bool moveUp(); + bool moveDown(); + + /* Edition */ + ExpressionLayout * addEmptyFractionLayout(); + ExpressionLayout * insertText(const char * text); + private: constexpr static KDCoordinate k_cursorHeight = 18; ExpressionLayout * m_pointedExpressionLayout; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 5fd6c0887..1fc9935bc 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -1,25 +1,12 @@ #include #include +#include //TODO move from there. +#include //TODO move from there. +#include //TODO move from there. #include namespace Poincare { -bool ExpressionLayoutCursor::moveLeft() { - return m_pointedExpressionLayout->moveLeft(this); -} - -bool ExpressionLayoutCursor::moveRight() { - return m_pointedExpressionLayout->moveRight(this); -} - -bool ExpressionLayoutCursor::moveUp() { - return m_pointedExpressionLayout->moveUp(this); -} - -bool ExpressionLayoutCursor::moveDown() { - return m_pointedExpressionLayout->moveDown(this); -} - bool ExpressionLayoutCursor::positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position, int positionIndex) { assert(expressionLayout != nullptr); return middleLeftPoint() == middleLeftPointOfCursor(expressionLayout, position, positionIndex); @@ -42,5 +29,43 @@ KDPoint ExpressionLayoutCursor::middleLeftPointOfCursor(ExpressionLayout * expre return KDPoint(layoutOrigin.x() + positionInside * KDText::charSize().width(), y); } +bool ExpressionLayoutCursor::moveLeft() { + return m_pointedExpressionLayout->moveLeft(this); +} + +bool ExpressionLayoutCursor::moveRight() { + return m_pointedExpressionLayout->moveRight(this); +} + +bool ExpressionLayoutCursor::moveUp() { + return m_pointedExpressionLayout->moveUp(this); +} + +bool ExpressionLayoutCursor::moveDown() { + return m_pointedExpressionLayout->moveDown(this); +} + +ExpressionLayout * ExpressionLayoutCursor::addEmptyFractionLayout() { + EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); + EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); + FractionLayout * newChild = new FractionLayout(child1, child2, false); + pointedExpressionLayout()->addBrother(this, newChild); + return child1; +} + +ExpressionLayout * ExpressionLayoutCursor::insertText(const char * text) { + int textLength = strlen(text); + if (textLength <= 0) { + return nullptr; + } + CharLayout * newChild = nullptr; + for (int i = 0; i < textLength; i++) { + newChild = new CharLayout(text[i]); + pointedExpressionLayout()->addBrother(this, newChild); + } + assert(newChild != nullptr); + return newChild; +} + } From 940f2cf38746c42e5542d4984ecbf13f1685e430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 11:25:33 +0100 Subject: [PATCH 039/257] [poincare] Delete empty layouts when adding something next to them. Change-Id: Ie89fa84edb0bdd57ead42fac68cbb564c5327556 --- poincare/include/poincare/expression_layout.h | 2 +- poincare/src/layout/empty_layout.cpp | 4 ++++ poincare/src/layout/empty_layout.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 1e48236df..5398dee72 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -47,7 +47,7 @@ public: bool insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor); - void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); + virtual void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace = true); ExpressionLayout * replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace); void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true); diff --git a/poincare/src/layout/empty_layout.cpp b/poincare/src/layout/empty_layout.cpp index fe9a28222..5d8919441 100644 --- a/poincare/src/layout/empty_layout.cpp +++ b/poincare/src/layout/empty_layout.cpp @@ -15,6 +15,10 @@ ExpressionLayout * EmptyLayout::clone() const { return layout; } +void EmptyLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { + replaceWith(brother, true); +} + bool EmptyLayout::moveLeft(ExpressionLayoutCursor * cursor) { assert(cursor->pointedExpressionLayout() == this); // Ask the parent. diff --git a/poincare/src/layout/empty_layout.h b/poincare/src/layout/empty_layout.h index 5573b0207..2c746faba 100644 --- a/poincare/src/layout/empty_layout.h +++ b/poincare/src/layout/empty_layout.h @@ -10,6 +10,7 @@ class EmptyLayout : public StaticLayoutHierarchy<0> { public: EmptyLayout(); ExpressionLayout * clone() const override; + void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: From 7b2c48465e17a7f92389b979fbc564d1b82b37e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 13:29:23 +0100 Subject: [PATCH 040/257] [expression_editor] Handle Exp, Log, Power, Sqrt and Square events. Change-Id: I96ab58d6f66fcb6aa95ba849d927236cfb5fcc28 --- apps/expression_editor/controller.cpp | 27 ++++++++ .../poincare/expression_layout_cursor.h | 5 ++ poincare/src/expression_layout_cursor.cpp | 69 +++++++++++++++++-- .../src/layout/bracket_left_right_layout.cpp | 6 +- poincare/src/layout/bracket_right_layout.cpp | 11 +-- poincare/src/layout/empty_visible_layout.h | 2 +- .../layout/parenthesis_left_right_layout.cpp | 2 +- 7 files changed, 104 insertions(+), 18 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 7e747e03d..1ed4f7d7e 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -64,6 +64,14 @@ bool Controller::handleMoveEvent(Ion::Events::Event event) { if (event == Ion::Events::Down) { return m_cursor.moveDown(); } + if (event == Ion::Events::ShiftLeft) { + //TODO + return false; + } + if (event == Ion::Events::ShiftRight) { + //TODO + return false; + } return false; } @@ -71,6 +79,25 @@ ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { if (event == Ion::Events::Division) { return m_cursor.addEmptyFractionLayout(); } + if (event == Ion::Events::XNT) { + //TODO + return nullptr; + } + if (event == Ion::Events::Exp) { + return m_cursor.addEmptyExponentialLayout(); + } + if (event == Ion::Events::Log) { + return m_cursor.addEmptyLogarithmLayout(); + } + if (event == Ion::Events::Power) { + return m_cursor.addEmptyPowerLayout(); + } + if (event == Ion::Events::Sqrt) { + return m_cursor.addEmptyRootLayout(); + } + if (event == Ion::Events::Square) { + return m_cursor.addEmptySquarePowerLayout(); + } if (event.hasText()) { return m_cursor.insertText(event.text()); } diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 88b29d81f..d7bb195ff 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -43,7 +43,12 @@ public: bool moveDown(); /* Edition */ + ExpressionLayout * addEmptyExponentialLayout(); ExpressionLayout * addEmptyFractionLayout(); + ExpressionLayout * addEmptyLogarithmLayout(); + ExpressionLayout * addEmptyPowerLayout(); + ExpressionLayout * addEmptyRootLayout(); + ExpressionLayout * addEmptySquarePowerLayout(); ExpressionLayout * insertText(const char * text); private: diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 1fc9935bc..8db913a3f 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -1,8 +1,15 @@ #include #include #include //TODO move from there. -#include //TODO move from there. +#include //TODO move from there. #include //TODO move from there. +#include //TODO move from there. +#include //TODO move from there. +#include //TODO move from there. +#include //TODO move from there. +#include //TODO move from there. +#include //TODO move from there. +#include #include namespace Poincare { @@ -45,6 +52,14 @@ bool ExpressionLayoutCursor::moveDown() { return m_pointedExpressionLayout->moveDown(this); } +ExpressionLayout * ExpressionLayoutCursor::addEmptyExponentialLayout() { + CharLayout * child1 = new CharLayout(Ion::Charset::Exponential); + EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); + EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); + pointedExpressionLayout()->addBrother(this, newChild); + return child2; +} + ExpressionLayout * ExpressionLayoutCursor::addEmptyFractionLayout() { EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); @@ -53,15 +68,61 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyFractionLayout() { return child1; } +ExpressionLayout * ExpressionLayoutCursor::addEmptyLogarithmLayout() { + StringLayout * child1 = new StringLayout("log", 3); + EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); + EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Subscript, false); + m_pointedExpressionLayout->addBrother(this, newChild); + m_pointedExpressionLayout = newChild; + m_position = Position::Right; + return insertText("()"); +} + +ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { + EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); + EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); + EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); + m_pointedExpressionLayout->addBrother(this, newChild); + return child1; +} + +ExpressionLayout * ExpressionLayoutCursor::addEmptyRootLayout() { + EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); + EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); + NthRootLayout * newChild = new NthRootLayout(child1, child2, false); + m_pointedExpressionLayout->addBrother(this, newChild); + return child1; +} + +ExpressionLayout * ExpressionLayoutCursor::addEmptySquarePowerLayout() { + EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); + CharLayout * child2 = new CharLayout('2'); + EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); + m_pointedExpressionLayout->addBrother(this, newChild); + return child1; +} + ExpressionLayout * ExpressionLayoutCursor::insertText(const char * text) { int textLength = strlen(text); if (textLength <= 0) { return nullptr; } - CharLayout * newChild = nullptr; + ExpressionLayout * newChild = nullptr; for (int i = 0; i < textLength; i++) { - newChild = new CharLayout(text[i]); - pointedExpressionLayout()->addBrother(this, newChild); + if (text[i] == '(') { + newChild = new ParenthesisLeftLayout(); + } else if (text[i] == ')') { + newChild = new ParenthesisRightLayout(); + } else if (text[i] == '[') { + newChild = new BracketLeftLayout(); + } else if (text[i] == ']') { + newChild = new BracketRightLayout(); + } else { + newChild = new CharLayout(text[i]); + } + m_pointedExpressionLayout->addBrother(this, newChild); + m_pointedExpressionLayout = newChild; + m_position = Position::Right; } assert(newChild != nullptr); return newChild; diff --git a/poincare/src/layout/bracket_left_right_layout.cpp b/poincare/src/layout/bracket_left_right_layout.cpp index 98d01121e..3a43c0536 100644 --- a/poincare/src/layout/bracket_left_right_layout.cpp +++ b/poincare/src/layout/bracket_left_right_layout.cpp @@ -9,7 +9,7 @@ namespace Poincare { BracketLeftRightLayout::BracketLeftRightLayout() : StaticLayoutHierarchy<0>(), - m_operandHeight(36) //TODO + m_operandHeight(18) //TODO { } @@ -50,12 +50,12 @@ bool BracketLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { KDSize BracketLeftRightLayout::computeSize() { //TODO: compute the operandHeight according to the brothers - return KDSize(k_externWidthMargin + k_lineThickness + k_bracketWidth + k_widthMargin, m_operandHeight); + return KDSize(k_externWidthMargin + k_lineThickness + k_widthMargin, m_operandHeight); } void BracketLeftRightLayout::computeBaseline() { //TODO: compute the operandHeight according to the brothers - m_baseline = m_operandHeight; + m_baseline = m_operandHeight/2; m_baselined = true; } diff --git a/poincare/src/layout/bracket_right_layout.cpp b/poincare/src/layout/bracket_right_layout.cpp index 86c43e66f..c6f8bbb14 100644 --- a/poincare/src/layout/bracket_right_layout.cpp +++ b/poincare/src/layout/bracket_right_layout.cpp @@ -10,15 +10,8 @@ ExpressionLayout * BracketRightLayout::clone() const { void BracketRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { //TODO Make sure m_operandHeight is up-to-date. ctx->fillRect(KDRect(p.x()+k_widthMargin, p.y(), k_lineThickness, m_operandHeight), expressionColor); - ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth, p.y(), k_bracketWidth, k_lineThickness), expressionColor); - ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth, p.y() + m_operandHeight, k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth+1, p.y(), k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth+1, p.y() + m_operandHeight, k_bracketWidth, k_lineThickness), expressionColor); } } - - - - - - - diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index 7a88565b9..1a549d9ce 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -20,7 +20,7 @@ private: constexpr static KDCoordinate k_width = 7; constexpr static KDCoordinate k_height = 13; constexpr static KDCoordinate k_marginWidth = 1; - constexpr static KDCoordinate k_marginHeight = 3; + constexpr static KDCoordinate k_marginHeight = 2; constexpr static KDCoordinate k_lineThickness = 1; KDColor m_fillRectColor; diff --git a/poincare/src/layout/parenthesis_left_right_layout.cpp b/poincare/src/layout/parenthesis_left_right_layout.cpp index 1baceff6b..0764efa73 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.cpp +++ b/poincare/src/layout/parenthesis_left_right_layout.cpp @@ -9,7 +9,7 @@ namespace Poincare { ParenthesisLeftRightLayout::ParenthesisLeftRightLayout() : StaticLayoutHierarchy<0>(), - m_operandHeight(36) //TODO + m_operandHeight(18) //TODO { computeBaseline(); } From 8289e24cfec9579e151e7718b420d8fdd90226c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 13:43:31 +0100 Subject: [PATCH 041/257] [expression_editor] Handle XNT event. Change-Id: I0af832ec0f693c445e424d21795b14cfb4e54622 --- apps/expression_editor/controller.cpp | 3 +-- poincare/include/poincare/expression_layout.h | 6 +++++- poincare/include/poincare/expression_layout_cursor.h | 1 + poincare/src/expression_layout_cursor.cpp | 6 ++++++ poincare/src/layout/expression_layout.cpp | 7 +++++++ poincare/src/layout/sequence_layout.cpp | 4 ++++ poincare/src/layout/sequence_layout.h | 1 + 7 files changed, 25 insertions(+), 3 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 1ed4f7d7e..40563a736 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -80,8 +80,7 @@ ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { return m_cursor.addEmptyFractionLayout(); } if (event == Ion::Events::XNT) { - //TODO - return nullptr; + return m_cursor.addXNTCharLayout(); } if (event == Ion::Events::Exp) { return m_cursor.addEmptyExponentialLayout(); diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 5398dee72..021f891da 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -63,13 +63,17 @@ public: bool moveUpInside(ExpressionLayoutCursor * cursor); virtual bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); bool moveDownInside(ExpressionLayoutCursor * cursor); + + /* Other */ + virtual char XNTChar() const; + protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0; virtual KDSize computeSize() = 0; virtual void computeBaseline() = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; void detachChildAtIndex(int i); - virtual void moveCursorInsideAtDirection ( + virtual void moveCursorInsideAtDirection ( VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout ** childResult, diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index d7bb195ff..5b9dfae37 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -49,6 +49,7 @@ public: ExpressionLayout * addEmptyPowerLayout(); ExpressionLayout * addEmptyRootLayout(); ExpressionLayout * addEmptySquarePowerLayout(); + ExpressionLayout * addXNTCharLayout(); ExpressionLayout * insertText(const char * text); private: diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 8db913a3f..19016af2c 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -102,6 +102,12 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptySquarePowerLayout() { return child1; } +ExpressionLayout * ExpressionLayoutCursor::addXNTCharLayout() { + CharLayout * newChild = new CharLayout(m_pointedExpressionLayout->XNTChar()); + m_pointedExpressionLayout->addBrother(this, newChild); + return newChild; +} + ExpressionLayout * ExpressionLayoutCursor::insertText(const char * text) { int textLength = strlen(text); if (textLength <= 0) { diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 3a92820d7..cb2bdb2a0 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -189,6 +189,13 @@ void ExpressionLayout::detachChild(const ExpressionLayout * e) { } } +char ExpressionLayout::XNTChar() const { + if (m_parent == nullptr) { + return 'x'; + } + return m_parent->XNTChar(); +} + void ExpressionLayout::detachChildAtIndex(int i) { ExpressionLayout ** op = const_cast(children()); if (op[i] != nullptr && op[i]->parent() == this) { diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 3955f77b3..691a9a29c 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -128,6 +128,10 @@ bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } +char SequenceLayout::XNTChar() const { + return 'n'; +} + ExpressionLayout * SequenceLayout::upperBoundLayout() { return editableChild(0); } diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 6e186982d..98e100420 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -14,6 +14,7 @@ public: bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + char XNTChar() const override; protected: constexpr static KDCoordinate k_boundHeightMargin = 2; ExpressionLayout * lowerBoundLayout(); From 37af76512441009f5c793c3df628745937bda0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 13:55:50 +0100 Subject: [PATCH 042/257] [expression_editor] Edit when the cursor points to the main layout. Change-Id: Idc11cfca8aa318803ba243f6649cad6f8662f7f6 --- poincare/src/layout/expression_layout.cpp | 19 +++++++++++++++---- poincare/src/layout/horizontal_layout.cpp | 6 ------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index cb2bdb2a0..06321efe7 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -125,12 +125,23 @@ void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLay if (m_parent->addChildAtIndex(brother, brotherIndex)) { return; } - } - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - replaceWithJuxtapositionOf(brother, this, false); + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + replaceWithJuxtapositionOf(brother, this, false); + return; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + replaceWithJuxtapositionOf(this, brother, false); return; } - replaceWithJuxtapositionOf(this, brother, false); + // If there is no parent, the pointed layout is the main horizontal layout. + // Add the "brother" as a child. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + addChildAtIndex(brother, 0); + return; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + addChildAtIndex(brother, numberOfChildren()); + return; } bool ExpressionLayout::insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor) { diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index dc627bee9..0be29923c 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -61,9 +61,6 @@ bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: the child is the leftmost. // Ask the parent. if (m_parent) { - // Only move the cursor if the layout has a parent: If not, the cursor - // would go on the extrema of the main HorizontalLayout, which prevents - // the user from adding more text. cursor->setPointedExpressionLayout(this); return m_parent->moveLeft(cursor); } @@ -111,9 +108,6 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: the child is the rightmost. // Ask the parent. if (m_parent) { - // Only move the cursor if the layout has a parent: If not, the cursor - // would go on the extrema of the main HorizontalLayout, which prevents - // the user from adding more text. cursor->setPointedExpressionLayout(this); return m_parent->moveRight(cursor); } From c24de3c06915659ce6fcef5ff8a36d46268cfbf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 13:58:31 +0100 Subject: [PATCH 043/257] [expression_editor] Handle ShiftLeft and ShiftRight events. Change-Id: Id416d1c95d023b8a0a4348a2570dd332615aa2b8 --- apps/expression_editor/controller.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 40563a736..3be04567e 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -65,12 +65,17 @@ bool Controller::handleMoveEvent(Ion::Events::Event event) { return m_cursor.moveDown(); } if (event == Ion::Events::ShiftLeft) { - //TODO - return false; + // The cursor should never point to the main HorizontalLayout. + m_cursor.setPointedExpressionLayout(m_expressionLayout); + m_cursor.setPosition(ExpressionLayoutCursor::Position::Left); + m_cursor.setPositionInside(0); + return true; } if (event == Ion::Events::ShiftRight) { - //TODO - return false; + m_cursor.setPointedExpressionLayout(m_expressionLayout); + m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); + m_cursor.setPositionInside(0); + return true; } return false; } From 0d8b6d5ace517d50c007299a06cae14cebaaeb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 15:24:50 +0100 Subject: [PATCH 044/257] [escher/poincare] Handle toolbox input (VERY DIRTY). Change-Id: I01de0ddd6f6500df278e3b4104110f6335289be1 --- apps/expression_editor/app.h | 3 ++ apps/expression_editor/controller.cpp | 19 ++++++++- apps/expression_editor/controller.h | 7 ++++ apps/math_toolbox.cpp | 40 ++++++++++++------- apps/math_toolbox.h | 4 +- escher/include/escher/toolbox_message_tree.h | 8 +++- .../poincare/expression_layout_cursor.h | 1 + poincare/include/poincare_layouts.h | 32 +++++++++++++++ poincare/src/expression_layout_cursor.cpp | 4 ++ 9 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 poincare/include/poincare_layouts.h diff --git a/apps/expression_editor/app.h b/apps/expression_editor/app.h index f90805121..84b537833 100644 --- a/apps/expression_editor/app.h +++ b/apps/expression_editor/app.h @@ -2,6 +2,7 @@ #define EXPRESSION_EDITOR_APP_H #include +#include #include "controller.h" #include "expression_and_layout.h" @@ -25,9 +26,11 @@ public: private: ExpressionAndLayout m_expressionAndLayout; }; + MathToolbox * mathToolbox() { return &m_toolbox; } private: App(Container * container, Snapshot * snapshot); Controller m_controller; + MathToolbox m_toolbox; }; } diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 3be04567e..f29c14c61 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -1,4 +1,5 @@ #include "controller.h" +#include using namespace Poincare; @@ -32,7 +33,23 @@ bool Controller::handleEvent(Ion::Events::Event event) { m_view.cursorPositionChanged(); return true; } - return false; + return Responder::handleEvent(event); +} + +Toolbox * Controller::toolbox() { + ExpressionEditor::App * expressionEditorApp = static_cast(app()); + return expressionEditorApp->mathToolbox(); +} + +void Controller::insertLayoutAtCursor(ExpressionLayout * layout, ExpressionLayout * pointedLayout) { + if (layout == nullptr) { + return; + } + m_cursor.addLayout(layout); + m_cursor.setPointedExpressionLayout(pointedLayout); + m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); + m_cursor.setPositionInside(0); + m_view.cursorPositionChanged(); } bool Controller::privateHandleEvent(Ion::Events::Event event) { diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index e285ff8a8..f34518ff5 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -17,6 +17,13 @@ public: View * view() override { return &m_view; } void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; + + /* Responder */ + Toolbox * toolbox() override; + + /* Callback for Toolbox */ + void insertLayoutAtCursor(ExpressionLayout * layout, ExpressionLayout * pointedLayout); + private: bool privateHandleEvent(Ion::Events::Event event); bool handleMoveEvent(Ion::Events::Event event); diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index caa25e6dc..b0e319531 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -9,8 +9,8 @@ * subtree, the edited text is set at I18n::Message::Default. */ const ToolboxMessageTree calculChildren[4] = { - ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg), - ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg), + ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg, nullptr, 0), + ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, new IntegralLayout(new EmptyVisibleLayout(), new EmptyVisibleLayout, new HorizontalLayout(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2(new EmptyVisibleLayout(), new StringLayout("dx",2))), 2, false), false)), ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg), ToolboxMessageTree(I18n::Message::ProductCommandWithArg, I18n::Message::Product, I18n::Message::ProductCommandWithArg)}; @@ -102,22 +102,34 @@ MathToolbox::MathToolbox() : Toolbox(nullptr, I18n::translate(rootModel()->label { } -TextField * MathToolbox::sender() { - return (TextField *)Toolbox::sender(); +TextField * MathToolbox::textFieldSender() { + return static_cast(Toolbox::sender()); +} + +ExpressionEditor::Controller * MathToolbox::expressionEditorControllerSender() { + return static_cast(Toolbox::sender()); } bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) { - m_selectableTableView.deselectTable(); - ToolboxMessageTree * messageTree = selectedMessageTree; - const char * editedText = I18n::translate(messageTree->insertedText()); - if (!sender()->isEditing()) { - sender()->setEditing(true); + if (0) { + m_selectableTableView.deselectTable(); + ToolboxMessageTree * messageTree = selectedMessageTree; + const char * editedText = I18n::translate(messageTree->insertedText()); + if (!textFieldSender()->isEditing()) { + textFieldSender()->setEditing(true); + } + char strippedEditedText[strlen(editedText)]; + Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedEditedText); + textFieldSender()->insertTextAtLocation(strippedEditedText, textFieldSender()->cursorLocation()); + int newCursorLocation = textFieldSender()->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(strippedEditedText); + textFieldSender()->setCursorLocation(newCursorLocation); + app()->dismissModalViewController(); + return true; } - char strippedEditedText[strlen(editedText)]; - Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedEditedText); - sender()->insertTextAtLocation(strippedEditedText, sender()->cursorLocation()); - int newCursorLocation = sender()->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(strippedEditedText); - sender()->setCursorLocation(newCursorLocation); + // Deal with ExpressionEditor::Controller for now. + m_selectableTableView.deselectTable(); + ExpressionLayout * newLayout = selectedMessageTree->layout()->clone(); + expressionEditorControllerSender()->insertLayoutAtCursor(newLayout, newLayout->editableChild(2)->editableChild(0)); app()->dismissModalViewController(); return true; } diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index 0579969de..9da44865b 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -4,12 +4,14 @@ #define MATRICES_ARE_DEFINED 1 #include #include +#include class MathToolbox : public Toolbox { public: MathToolbox(); protected: - TextField * sender() override; + TextField * textFieldSender(); + ExpressionEditor::Controller * expressionEditorControllerSender(); bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override; const ToolboxMessageTree * rootModel() override; MessageTableCellWithMessage * leafCellAtIndex(int index) override; diff --git a/escher/include/escher/toolbox_message_tree.h b/escher/include/escher/toolbox_message_tree.h index 10e5cb336..aebf25db4 100644 --- a/escher/include/escher/toolbox_message_tree.h +++ b/escher/include/escher/toolbox_message_tree.h @@ -2,23 +2,27 @@ #define ESCHER_TOOLBOX_MESSAGE_TREE_H #include +#include class ToolboxMessageTree : public MessageTree { public: - constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0) : + constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0, Poincare::ExpressionLayout * layout = nullptr) : MessageTree(label, numberOfChildren), m_children(children), m_text(text), - m_insertedText(insertedText) + m_insertedText(insertedText), + m_layout(layout) { }; const MessageTree * children(int index) const override; I18n::Message text() const; I18n::Message insertedText() const; + Poincare::ExpressionLayout * layout() const { return m_layout; } private: const ToolboxMessageTree * m_children; I18n::Message m_text; I18n::Message m_insertedText; + Poincare::ExpressionLayout * m_layout; }; #endif diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 5b9dfae37..5813fee8c 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -43,6 +43,7 @@ public: bool moveDown(); /* Edition */ + void addLayout(ExpressionLayout * layout); ExpressionLayout * addEmptyExponentialLayout(); ExpressionLayout * addEmptyFractionLayout(); ExpressionLayout * addEmptyLogarithmLayout(); diff --git a/poincare/include/poincare_layouts.h b/poincare/include/poincare_layouts.h new file mode 100644 index 000000000..f3d71feae --- /dev/null +++ b/poincare/include/poincare_layouts.h @@ -0,0 +1,32 @@ +#ifndef POINCARE_LAYOUTS_H +#define POINCARE_LAYOUTS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 19016af2c..d10c759e6 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -52,6 +52,10 @@ bool ExpressionLayoutCursor::moveDown() { return m_pointedExpressionLayout->moveDown(this); } +void ExpressionLayoutCursor::addLayout(ExpressionLayout * layout) { + pointedExpressionLayout()->addBrother(this, layout); +} + ExpressionLayout * ExpressionLayoutCursor::addEmptyExponentialLayout() { CharLayout * child1 = new CharLayout(Ion::Charset::Exponential); EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); From 14f2e08872160198b245bb1e523cffa0780b0305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 18:01:24 +0100 Subject: [PATCH 045/257] [poincare/escher] Tell which layout is pointed when adding from toolbox. Change-Id: I84c82ea887e3e7759da7d407532dc7d63174f1ac --- apps/math_toolbox.cpp | 29 ++++++++++++++++++-- escher/include/escher/toolbox_message_tree.h | 10 +++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index b0e319531..c9e4ae3ec 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -8,10 +8,29 @@ * and the text which would be edited by clicking on the row. When the node is a * subtree, the edited text is set at I18n::Message::Default. */ +const int pointedLayoutPathIntegral[] = {2, 0}; +const int pointedLayoutPathSum[] = {2}; const ToolboxMessageTree calculChildren[4] = { ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg, nullptr, 0), - ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, new IntegralLayout(new EmptyVisibleLayout(), new EmptyVisibleLayout, new HorizontalLayout(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2(new EmptyVisibleLayout(), new StringLayout("dx",2))), 2, false), false)), - ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg), + ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, + new IntegralLayout( + new EmptyVisibleLayout(), + new EmptyVisibleLayout(), + new HorizontalLayout(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2( + new EmptyVisibleLayout(), + new StringLayout("dx",2))), 2, false), false), + const_cast(&pointedLayoutPathIntegral[0]), + 2), + ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg, nullptr, 0, + new SumLayout( + new HorizontalLayout(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2( + new StringLayout("n=",2), + new EmptyVisibleLayout())), 2, false), + new EmptyVisibleLayout(), + new EmptyVisibleLayout(), + false), + const_cast(&pointedLayoutPathSum[0]), + 1), ToolboxMessageTree(I18n::Message::ProductCommandWithArg, I18n::Message::Product, I18n::Message::ProductCommandWithArg)}; const ToolboxMessageTree complexChildren[5] = { @@ -129,7 +148,11 @@ bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) { // Deal with ExpressionEditor::Controller for now. m_selectableTableView.deselectTable(); ExpressionLayout * newLayout = selectedMessageTree->layout()->clone(); - expressionEditorControllerSender()->insertLayoutAtCursor(newLayout, newLayout->editableChild(2)->editableChild(0)); + ExpressionLayout * pointedLayout = newLayout; + for (int i = 0; i < selectedMessageTree->pointedPathLength(); i++) { + pointedLayout = pointedLayout->editableChild(selectedMessageTree->pointedPath()[i]); + } + expressionEditorControllerSender()->insertLayoutAtCursor(newLayout, pointedLayout); app()->dismissModalViewController(); return true; } diff --git a/escher/include/escher/toolbox_message_tree.h b/escher/include/escher/toolbox_message_tree.h index aebf25db4..253ce36ce 100644 --- a/escher/include/escher/toolbox_message_tree.h +++ b/escher/include/escher/toolbox_message_tree.h @@ -6,23 +6,29 @@ class ToolboxMessageTree : public MessageTree { public: - constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0, Poincare::ExpressionLayout * layout = nullptr) : + constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0, Poincare::ExpressionLayout * layout = nullptr, int * pointedLayoutPath = nullptr, int pointedLayoutPathLength = 0) : MessageTree(label, numberOfChildren), m_children(children), m_text(text), m_insertedText(insertedText), - m_layout(layout) + m_layout(layout), + m_pointedLayoutPath(pointedLayoutPath), + m_pointedLayoutPathLength(pointedLayoutPathLength) { }; const MessageTree * children(int index) const override; I18n::Message text() const; I18n::Message insertedText() const; Poincare::ExpressionLayout * layout() const { return m_layout; } + int * pointedPath() const { return m_pointedLayoutPath; } + int pointedPathLength() const { return m_pointedLayoutPathLength; } private: const ToolboxMessageTree * m_children; I18n::Message m_text; I18n::Message m_insertedText; Poincare::ExpressionLayout * m_layout; + int * m_pointedLayoutPath; + int m_pointedLayoutPathLength; }; #endif From b47a5fa939bf51d002b89f57cfb532608f75b94d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 18:03:11 +0100 Subject: [PATCH 046/257] [poincare] Handle parentheses sizing. Change-Id: I3f790c0eb73b566dd7de7089957ea0d4306821c2 --- apps/expression_editor/controller.cpp | 1 + poincare/include/poincare/expression_layout.h | 4 +- poincare/src/layout/expression_layout.cpp | 3 +- .../src/layout/parenthesis_left_layout.cpp | 37 +++++++++++++++++-- poincare/src/layout/parenthesis_left_layout.h | 3 ++ .../layout/parenthesis_left_right_layout.cpp | 20 ++++++---- .../layout/parenthesis_left_right_layout.h | 5 ++- .../src/layout/parenthesis_right_layout.cpp | 35 ++++++++++++++++-- .../src/layout/parenthesis_right_layout.h | 3 ++ 9 files changed, 95 insertions(+), 16 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index f29c14c61..625ac72a0 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -49,6 +49,7 @@ void Controller::insertLayoutAtCursor(ExpressionLayout * layout, ExpressionLayou m_cursor.setPointedExpressionLayout(pointedLayout); m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); m_cursor.setPositionInside(0); + m_expressionLayout->invalidAllSizesPositionsAndBaselines(); m_view.cursorPositionChanged(); } diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 021f891da..5ffac5992 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -31,7 +31,7 @@ public: KDPoint absoluteOrigin(); KDSize size(); KDCoordinate baseline(); - void invalidAllSizesPositionsAndBaselines(); + virtual void invalidAllSizesPositionsAndBaselines(); /* Hierarchy */ virtual const ExpressionLayout * const * children() const = 0; @@ -65,6 +65,8 @@ public: bool moveDownInside(ExpressionLayoutCursor * cursor); /* Other */ + virtual bool isLeftParenthesis() const { return false; } + virtual bool isRightParenthesis() const { return false; } virtual char XNTChar() const; protected: diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 06321efe7..9f19d4040 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -13,7 +13,8 @@ ExpressionLayout::ExpressionLayout() : m_sized(false), m_baselined(false), m_positioned(false), - m_frame(KDRectZero) { + m_frame(KDRectZero) +{ } const ExpressionLayout * const * ExpressionLayout::ExpressionLayoutArray2(const ExpressionLayout * e1, const ExpressionLayout * e2) { diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index 43e3939db..6af8a7172 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -32,7 +32,6 @@ ExpressionLayout * ParenthesisLeftLayout::clone() const { } void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - //TODO Make sure m_operandHeight is up-to-date. KDRect frame(p.x()+ParenthesisLeftRightLayout::k_externWidthMargin, p.y()+ParenthesisLeftRightLayout::k_externHeightMargin, ParenthesisLeftRightLayout::k_parenthesisCurveWidth, @@ -41,7 +40,7 @@ void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressio ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)topLeftCurve, (KDColor *)(ParenthesisLeftRightLayout::s_parenthesisWorkingBuffer)); frame = KDRect(p.x()+ParenthesisLeftRightLayout::k_externWidthMargin, - p.y() + m_operandHeight - ParenthesisLeftRightLayout::k_parenthesisCurveHeight - ParenthesisLeftRightLayout::k_externHeightMargin, + p.y() + operandHeight() - ParenthesisLeftRightLayout::k_parenthesisCurveHeight - ParenthesisLeftRightLayout::k_externHeightMargin, ParenthesisLeftRightLayout::k_parenthesisCurveWidth, ParenthesisLeftRightLayout::k_parenthesisCurveHeight); @@ -50,8 +49,40 @@ void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressio ctx->fillRect(KDRect(p.x()+ParenthesisLeftRightLayout::k_externWidthMargin, p.y()+ParenthesisLeftRightLayout::k_parenthesisCurveHeight+ParenthesisLeftRightLayout::k_externHeightMargin, ParenthesisLeftRightLayout::k_lineThickness, - m_operandHeight - 2*(ParenthesisLeftRightLayout::k_parenthesisCurveHeight+ParenthesisLeftRightLayout::k_externHeightMargin)), + operandHeight() - 2*(ParenthesisLeftRightLayout::k_parenthesisCurveHeight+ParenthesisLeftRightLayout::k_externHeightMargin)), expressionColor); } +void ParenthesisLeftLayout::computeOperandHeight() { + assert(m_parent != nullptr); + m_operandHeight = 18; + int numberOfBrothers = m_parent->numberOfChildren(); + for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { + ExpressionLayout * brother = m_parent->editableChild(i); + if (brother->isRightParenthesis()) { + return; + } + KDCoordinate brotherHeight = brother->size().height(); + if (brotherHeight > m_operandHeight) { + m_operandHeight = brotherHeight; + } + } +} + +void ParenthesisLeftLayout::computeBaseline() { + assert(m_parent != nullptr); + m_baseline = operandHeight()/2; + int numberOfBrothers = m_parent->numberOfChildren(); + for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { + ExpressionLayout * brother = m_parent->editableChild(i); + if (brother->isRightParenthesis()) { + break; + } + if (brother->baseline() > m_baseline) { + m_baseline = brother->baseline(); + } + } + m_baselined = true; +} + } diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index ad0b60906..538d5c2de 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -9,8 +9,11 @@ class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; ExpressionLayout * clone() const override; + bool isLeftParenthesis() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + void computeOperandHeight() override; + void computeBaseline() override; }; } diff --git a/poincare/src/layout/parenthesis_left_right_layout.cpp b/poincare/src/layout/parenthesis_left_right_layout.cpp index 0764efa73..f3b77ee95 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.cpp +++ b/poincare/src/layout/parenthesis_left_right_layout.cpp @@ -9,9 +9,13 @@ namespace Poincare { ParenthesisLeftRightLayout::ParenthesisLeftRightLayout() : StaticLayoutHierarchy<0>(), - m_operandHeight(18) //TODO + m_operandHeightComputed(false) { - computeBaseline(); +} + +void ParenthesisLeftRightLayout::invalidAllSizesPositionsAndBaselines() { + m_operandHeightComputed = false; + ExpressionLayout::invalidAllSizesPositionsAndBaselines(); } bool ParenthesisLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -49,13 +53,15 @@ bool ParenthesisLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { } KDSize ParenthesisLeftRightLayout::computeSize() { - //TODO: compute the operandHeight according to the brothers - return KDSize(k_widthMargin + k_lineThickness + k_externWidthMargin, m_operandHeight); + return KDSize(k_widthMargin + k_lineThickness + k_externWidthMargin, operandHeight()); } -void ParenthesisLeftRightLayout::computeBaseline() { - m_baseline = m_operandHeight/2; //TODO - m_baselined = true; +KDCoordinate ParenthesisLeftRightLayout::operandHeight() { + if (!m_operandHeightComputed) { + computeOperandHeight(); + m_operandHeightComputed = true; + } + return m_operandHeight; } KDPoint ParenthesisLeftRightLayout::positionOfChild(ExpressionLayout * child) { diff --git a/poincare/src/layout/parenthesis_left_right_layout.h b/poincare/src/layout/parenthesis_left_right_layout.h index 67381f10a..3ad0a296b 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.h +++ b/poincare/src/layout/parenthesis_left_right_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class ParenthesisLeftRightLayout : public StaticLayoutHierarchy<0> { public: ParenthesisLeftRightLayout(); + void invalidAllSizesPositionsAndBaselines() override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; constexpr static KDCoordinate k_parenthesisCurveWidth = 5; @@ -19,8 +20,10 @@ public: protected: KDColor s_parenthesisWorkingBuffer[k_parenthesisCurveHeight*k_parenthesisCurveWidth]; KDSize computeSize() override; - void computeBaseline() override; + KDCoordinate operandHeight(); + virtual void computeOperandHeight() = 0; KDPoint positionOfChild(ExpressionLayout * child) override; + bool m_operandHeightComputed; uint16_t m_operandHeight; }; } diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index d9a8d4c6c..55fc71743 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -32,7 +32,6 @@ ExpressionLayout * ParenthesisRightLayout::clone() const { } void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - //TODO Make sure m_operandHeight is up-to-date. KDRect frame = KDRect(p.x() + ParenthesisLeftRightLayout::k_widthMargin + ParenthesisLeftRightLayout::k_lineThickness - ParenthesisLeftRightLayout::k_parenthesisCurveWidth, p.y() + ParenthesisLeftRightLayout::k_externHeightMargin, ParenthesisLeftRightLayout::k_parenthesisCurveWidth, @@ -41,7 +40,7 @@ void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressi ctx->blendRectWithMask(frame, expressionColor, (const uint8_t *)topRightCurve, (KDColor *)(ParenthesisLeftRightLayout::s_parenthesisWorkingBuffer)); frame = KDRect(p.x() + ParenthesisLeftRightLayout::k_widthMargin + ParenthesisLeftRightLayout::k_lineThickness - ParenthesisLeftRightLayout::k_parenthesisCurveWidth, - p.y() + m_operandHeight - ParenthesisLeftRightLayout::k_parenthesisCurveHeight - ParenthesisLeftRightLayout::k_externHeightMargin, + p.y() + operandHeight() - ParenthesisLeftRightLayout::k_parenthesisCurveHeight - ParenthesisLeftRightLayout::k_externHeightMargin, ParenthesisLeftRightLayout::k_parenthesisCurveWidth, ParenthesisLeftRightLayout::k_parenthesisCurveHeight); @@ -50,10 +49,40 @@ void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressi ctx->fillRect(KDRect(p.x()+ParenthesisLeftRightLayout::k_widthMargin, p.y()+ParenthesisLeftRightLayout::k_parenthesisCurveHeight+2, ParenthesisLeftRightLayout::k_lineThickness, - m_operandHeight - 2*(ParenthesisLeftRightLayout::k_parenthesisCurveHeight+ParenthesisLeftRightLayout::k_externHeightMargin)), + operandHeight() - 2*(ParenthesisLeftRightLayout::k_parenthesisCurveHeight+ParenthesisLeftRightLayout::k_externHeightMargin)), expressionColor); } +void ParenthesisRightLayout::computeOperandHeight() { + m_operandHeight = 18; + assert(m_parent != nullptr); + for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { + ExpressionLayout * brother = m_parent->editableChild(i); + if (brother->isLeftParenthesis()) { + return; + } + KDCoordinate brotherHeight = brother->size().height(); + if (brotherHeight > m_operandHeight) { + m_operandHeight = brotherHeight; + } + } +} + +void ParenthesisRightLayout::computeBaseline() { + assert(m_parent != nullptr); + m_baseline = operandHeight()/2; + for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { + ExpressionLayout * brother = m_parent->editableChild(i); + if (brother->isLeftParenthesis()) { + break; + } + if (brother->baseline() > m_baseline) { + m_baseline = brother->baseline(); + } + } + m_baselined = true; +} + } diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index 7daba2368..c03d19efd 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -9,8 +9,11 @@ class ParenthesisRightLayout : public ParenthesisLeftRightLayout { public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; ExpressionLayout * clone() const override; + bool isRightParenthesis() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + void computeOperandHeight() override; + void computeBaseline() override; }; } From 38d1da9e6df9e2f1fbb81528c1828b7f767479bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 18:03:55 +0100 Subject: [PATCH 047/257] [poincare] Fix bug in IntegralLayout navigation assert. Change-Id: Idecb17678d1e858aca9d453c8e0f44988005c2b0 --- poincare/src/layout/integral_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 4e912dd91..ae3db3355 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -101,7 +101,7 @@ bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { cursor->setPointedExpressionLayout(upperBoundLayout()); return true; } - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); // Case: Right. // Ask the parent. if (m_parent) { From b327989975e49eaa70c504a3810a38742cefdd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 20 Dec 2017 18:04:37 +0100 Subject: [PATCH 048/257] [poincare] Change StringLayout navigation to handle dx in integrals. The cursor should avoid being on the left or right of a string layout, otherwise there will be problems when serializing an integral. Change-Id: If801247638e3d5eb3e36deaafbe9179759b48034 --- poincare/src/layout/string_layout.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index 43996cd7d..f2be896e3 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -43,18 +43,27 @@ bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { bool StringLayout::moveRight(ExpressionLayoutCursor * cursor) { // A StringLayout is not editable, and the cursor cannot go inside it. assert(cursor->pointedExpressionLayout() == this); + assert(m_parent != nullptr); // Case: Left. // Go Right. + // If there is a Right brother, go Left of it. Else go Right of the grandparent. + // //TODO explain that it is because of integrals and baselayouts. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; + int indexOfThis = m_parent->indexOfChild(this); + if (m_parent->editableChild(indexOfThis+1) != nullptr) { + cursor->setPointedExpressionLayout(m_parent->editableChild(indexOfThis+1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + if (m_parent->parent()) { + cursor->setPointedExpressionLayout(const_cast(m_parent->parent())); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } } // Case: Right. // Ask the parent. - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; + return m_parent->moveRight(cursor); } void StringLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { From ad3ca09ba1e1cf1c1191347615da80d591d7221c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 09:46:15 +0100 Subject: [PATCH 049/257] [poincare] Handle nested parentheses when computing height and baseline. Change-Id: I15f266f1dddd1eb49b4d713348f8031c51104a6b --- .../src/layout/parenthesis_left_layout.cpp | 16 ++++++++++++-- .../src/layout/parenthesis_right_layout.cpp | 21 ++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index 6af8a7172..f191d68ee 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -56,11 +56,17 @@ void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressio void ParenthesisLeftLayout::computeOperandHeight() { assert(m_parent != nullptr); m_operandHeight = 18; + int currentNumberOfOpenParentheses = 1; int numberOfBrothers = m_parent->numberOfChildren(); for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { ExpressionLayout * brother = m_parent->editableChild(i); if (brother->isRightParenthesis()) { - return; + currentNumberOfOpenParentheses--; + if (currentNumberOfOpenParentheses == 0) { + return; + } + } else if (brother->isLeftParenthesis()) { + currentNumberOfOpenParentheses++; } KDCoordinate brotherHeight = brother->size().height(); if (brotherHeight > m_operandHeight) { @@ -72,11 +78,17 @@ void ParenthesisLeftLayout::computeOperandHeight() { void ParenthesisLeftLayout::computeBaseline() { assert(m_parent != nullptr); m_baseline = operandHeight()/2; + int currentNumberOfOpenParentheses = 1; int numberOfBrothers = m_parent->numberOfChildren(); for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { ExpressionLayout * brother = m_parent->editableChild(i); if (brother->isRightParenthesis()) { - break; + currentNumberOfOpenParentheses--; + if (currentNumberOfOpenParentheses == 0) { + break; + } + } else if (brother->isLeftParenthesis()) { + currentNumberOfOpenParentheses++; } if (brother->baseline() > m_baseline) { m_baseline = brother->baseline(); diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index 55fc71743..d3b0efb0d 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -54,14 +54,19 @@ void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressi } void ParenthesisRightLayout::computeOperandHeight() { - m_operandHeight = 18; assert(m_parent != nullptr); + m_operandHeight = 18; + int currentNumberOfOpenParentheses = 1; for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { ExpressionLayout * brother = m_parent->editableChild(i); if (brother->isLeftParenthesis()) { - return; - } - KDCoordinate brotherHeight = brother->size().height(); + currentNumberOfOpenParentheses--; + if (currentNumberOfOpenParentheses == 0) { + return; + } + } else if (brother->isRightParenthesis()) { + currentNumberOfOpenParentheses++; + } KDCoordinate brotherHeight = brother->size().height(); if (brotherHeight > m_operandHeight) { m_operandHeight = brotherHeight; } @@ -71,10 +76,16 @@ void ParenthesisRightLayout::computeOperandHeight() { void ParenthesisRightLayout::computeBaseline() { assert(m_parent != nullptr); m_baseline = operandHeight()/2; + int currentNumberOfOpenParentheses = 1; for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { ExpressionLayout * brother = m_parent->editableChild(i); if (brother->isLeftParenthesis()) { - break; + currentNumberOfOpenParentheses--; + if (currentNumberOfOpenParentheses == 0) { + break; + } + } else if (brother->isRightParenthesis()) { + currentNumberOfOpenParentheses++; } if (brother->baseline() > m_baseline) { m_baseline = brother->baseline(); From c697b77437beea3b53f34c8c42f464c9174c4cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 10:41:12 +0100 Subject: [PATCH 050/257] [poincare] UneditableParenthesisLayout left and right. Change-Id: Ib5d7fdb887513270a70fe77a287ccfd638fea098 --- poincare/Makefile | 2 ++ .../uneditable_parenthesis_left_layout.cpp | 33 +++++++++++++++++++ .../uneditable_parenthesis_left_layout.h | 18 ++++++++++ .../uneditable_parenthesis_right_layout.cpp | 33 +++++++++++++++++++ .../uneditable_parenthesis_right_layout.h | 18 ++++++++++ 5 files changed, 104 insertions(+) create mode 100644 poincare/src/layout/uneditable_parenthesis_left_layout.cpp create mode 100644 poincare/src/layout/uneditable_parenthesis_left_layout.h create mode 100644 poincare/src/layout/uneditable_parenthesis_right_layout.cpp create mode 100644 poincare/src/layout/uneditable_parenthesis_right_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index d5e88b035..d20f96750 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -114,6 +114,8 @@ objs += $(addprefix poincare/src/layout/,\ static_layout_hierarchy.o\ string_layout.o\ sum_layout.o\ + uneditable_parenthesis_left_layout.o\ + uneditable_parenthesis_right_layout.o\ ) tests += $(addprefix poincare/test/,\ diff --git a/poincare/src/layout/uneditable_parenthesis_left_layout.cpp b/poincare/src/layout/uneditable_parenthesis_left_layout.cpp new file mode 100644 index 000000000..5281934ee --- /dev/null +++ b/poincare/src/layout/uneditable_parenthesis_left_layout.cpp @@ -0,0 +1,33 @@ +#include "uneditable_parenthesis_left_layout.h" +#include +extern "C" { +#include +} + +namespace Poincare { + +ExpressionLayout * UneditableParenthesisLeftLayout::clone() const { + return new UneditableParenthesisLeftLayout(); +} + +bool UneditableParenthesisLeftLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Ask the parent. + if (m_parent) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return m_parent->moveLeft(cursor); + } + return false; +} + +bool UneditableParenthesisLeftLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Ask the parent. + if (m_parent) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return m_parent->moveRight(cursor); + } + return false; +} + +} diff --git a/poincare/src/layout/uneditable_parenthesis_left_layout.h b/poincare/src/layout/uneditable_parenthesis_left_layout.h new file mode 100644 index 000000000..b3b693330 --- /dev/null +++ b/poincare/src/layout/uneditable_parenthesis_left_layout.h @@ -0,0 +1,18 @@ +#ifndef POINCARE_UNEDITABLE_PARENTHESIS_LEFT_LAYOUT_H +#define POINCARE_UNEDITABLE_PARENTHESIS_LEFT_LAYOUT_H + +#include + +namespace Poincare { + +class UneditableParenthesisLeftLayout : public ParenthesisLeftLayout { +public: + using ParenthesisLeftLayout::ParenthesisLeftLayout; + ExpressionLayout * clone() const override; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; +}; + +} + +#endif diff --git a/poincare/src/layout/uneditable_parenthesis_right_layout.cpp b/poincare/src/layout/uneditable_parenthesis_right_layout.cpp new file mode 100644 index 000000000..bba558231 --- /dev/null +++ b/poincare/src/layout/uneditable_parenthesis_right_layout.cpp @@ -0,0 +1,33 @@ +#include "uneditable_parenthesis_right_layout.h" +#include +extern "C" { +#include +} + +namespace Poincare { + +ExpressionLayout * UneditableParenthesisRightLayout::clone() const { + return new UneditableParenthesisRightLayout(); +} + +bool UneditableParenthesisRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Ask the parent. + if (m_parent) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return m_parent->moveLeft(cursor); + } + return false; +} + +bool UneditableParenthesisRightLayout::moveRight(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + // Ask the parent. + if (m_parent) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return m_parent->moveRight(cursor); + } + return false; +} + +} diff --git a/poincare/src/layout/uneditable_parenthesis_right_layout.h b/poincare/src/layout/uneditable_parenthesis_right_layout.h new file mode 100644 index 000000000..2025f4a25 --- /dev/null +++ b/poincare/src/layout/uneditable_parenthesis_right_layout.h @@ -0,0 +1,18 @@ +#ifndef POINCARE_UNEDITABLE_PARENTHESIS_RIGHT_LAYOUT_H +#define POINCARE_UNEDITABLE_PARENTHESIS_RIGHT_LAYOUT_H + +#include + +namespace Poincare { + +class UneditableParenthesisRightLayout : public ParenthesisRightLayout { +public: + using ParenthesisRightLayout::ParenthesisRightLayout; + ExpressionLayout * clone() const override; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; +}; + +} + +#endif From 95b82adbe36f55c22117b20925aa5007ded87850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 10:41:54 +0100 Subject: [PATCH 051/257] [poincare] Added uneditable parentheses around the sum layout argument. Change-Id: Ib80000b4d41fbb36b318ba9266eb7680c9f1285a --- apps/math_toolbox.cpp | 4 +- poincare/src/layout/sequence_layout.cpp | 2 - poincare/src/layout/sequence_layout.h | 8 +- poincare/src/layout/sum_layout.cpp | 138 +++++++++++++++++++++++- poincare/src/layout/sum_layout.h | 7 +- 5 files changed, 148 insertions(+), 11 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index c9e4ae3ec..d1295a2fb 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -9,7 +9,7 @@ * subtree, the edited text is set at I18n::Message::Default. */ const int pointedLayoutPathIntegral[] = {2, 0}; -const int pointedLayoutPathSum[] = {2}; +const int pointedLayoutPathSum[] = {2, 1}; const ToolboxMessageTree calculChildren[4] = { ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg, nullptr, 0), ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, @@ -30,7 +30,7 @@ const ToolboxMessageTree calculChildren[4] = { new EmptyVisibleLayout(), false), const_cast(&pointedLayoutPathSum[0]), - 1), + 2), ToolboxMessageTree(I18n::Message::ProductCommandWithArg, I18n::Message::Product, I18n::Message::ProductCommandWithArg)}; const ToolboxMessageTree complexChildren[5] = { diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 691a9a29c..364fd3ed7 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -103,7 +103,6 @@ bool SequenceLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * } // If the cursor is Left of the argument, move it to the upper bound. if (argumentLayout() - && previousLayout == argumentLayout() && cursor->positionIsEquivalentTo(argumentLayout(), ExpressionLayoutCursor::Position::Left)) { assert(upperBoundLayout() != nullptr); @@ -119,7 +118,6 @@ bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout } // If the cursor is Left of the argument, move it to the lower bound. if (argumentLayout() - && previousLayout == argumentLayout() && cursor->positionIsEquivalentTo(argumentLayout(), ExpressionLayoutCursor::Position::Left)) { assert(lowerBoundLayout() != nullptr); diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 98e100420..e2eb0e57f 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -17,14 +17,14 @@ public: char XNTChar() const override; protected: constexpr static KDCoordinate k_boundHeightMargin = 2; + constexpr static KDCoordinate k_argumentWidthMargin = 2; ExpressionLayout * lowerBoundLayout(); ExpressionLayout * upperBoundLayout(); - ExpressionLayout * argumentLayout(); -private: + virtual ExpressionLayout * argumentLayout(); KDSize computeSize() override; - void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; - constexpr static KDCoordinate k_argumentWidthMargin = 2; +private: + void computeBaseline() override; }; } diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index 4515eedef..d9febe8ae 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -1,4 +1,8 @@ #include "sum_layout.h" +#include "horizontal_layout.h" +#include "uneditable_parenthesis_left_layout.h" +#include "uneditable_parenthesis_right_layout.h" +#include #include #include @@ -22,19 +26,149 @@ const uint8_t symbolPixel[SumLayout::k_symbolHeight][SumLayout::k_symbolWidth] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, }; +SumLayout::SumLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands) : + SequenceLayout(lowerBound, upperBound, argument, cloneOperands) +{ + UneditableParenthesisLeftLayout * parLeft = new UneditableParenthesisLeftLayout(); + UneditableParenthesisRightLayout * parRight = new UneditableParenthesisRightLayout(); + HorizontalLayout * horLayout = new HorizontalLayout(); + ExpressionLayout * argLayout = editableChild(2); + // We cannot call argument() because it is overrided to handle completely + // built SumLayouts, not SumLayouts in construction. + argLayout->replaceWith(horLayout, false); + horLayout->addChildAtIndex(parLeft, 0); + horLayout->addChildAtIndex(argLayout, 1); + horLayout->addChildAtIndex(parRight, 2); +} + ExpressionLayout * SumLayout::clone() const { SumLayout * layout = new SumLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->argumentLayout(), true); return layout; } +ExpressionLayout * SumLayout::argumentLayout() { + return editableChild(2)->editableChild(1); +} + +bool SumLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the bounds. + // Go Left of the sum. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && ((lowerBoundLayout() + && cursor->pointedExpressionLayout() == lowerBoundLayout()) + || (upperBoundLayout() + && cursor->pointedExpressionLayout() == upperBoundLayout()))) + { + cursor->setPointedExpressionLayout(this); + return true; + } + // Case: Left of the argument. + // Go Right of the lower bound. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && argumentLayout() + && cursor->pointedExpressionLayout() == editableChild(2)) + { + assert(lowerBoundLayout() != nullptr); + cursor->setPointedExpressionLayout(lowerBoundLayout()); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the argument and move Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(argumentLayout() != nullptr); + cursor->setPointedExpressionLayout(argumentLayout()); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +bool SumLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the bounds. + // Go Left of the argument. + if (cursor->position() == ExpressionLayoutCursor::Position::Right + && ((lowerBoundLayout() + && cursor->pointedExpressionLayout() == lowerBoundLayout()) + || (upperBoundLayout() + && cursor->pointedExpressionLayout() == upperBoundLayout()))) + { + assert(argumentLayout() != nullptr); + cursor->setPointedExpressionLayout(argumentLayout()); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Right of the argument. + // Ask the parent. + if (cursor->position() == ExpressionLayoutCursor::Position::Right + && argumentLayout() + && cursor->pointedExpressionLayout() == editableChild(2)) + { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go to the upper bound. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(upperBoundLayout() != nullptr); + cursor->setPointedExpressionLayout(upperBoundLayout()); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize upperBoundSize = upperBoundLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); KDColor workingBuffer[k_symbolWidth*k_symbolHeight]; KDRect symbolFrame(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), - k_symbolWidth, k_symbolHeight); + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), + k_symbolWidth, k_symbolHeight); ctx->blendRectWithMask(symbolFrame, expressionColor, (const uint8_t *)symbolPixel, (KDColor *)workingBuffer); } +KDSize SumLayout::computeSize() { + KDSize argumentSize = editableChild(2)->size(); + KDSize lowerBoundSize = lowerBoundLayout()->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); + return KDSize( + max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSize.width(), + m_baseline + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - argumentLayout()->baseline()) + ); +} + +KDPoint SumLayout::positionOfChild(ExpressionLayout * child) { + KDSize lowerBoundSize = lowerBoundLayout()->size(); + KDSize upperBoundSize = upperBoundLayout()->size(); + KDCoordinate x = 0; + KDCoordinate y = 0; + if (child == lowerBoundLayout()) { + x = max(max(0, (k_symbolWidth-lowerBoundSize.width())/2), (upperBoundSize.width()-lowerBoundSize.width())/2); + y = m_baseline + k_symbolHeight/2 + k_boundHeightMargin; + } else if (child == upperBoundLayout()) { + x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSize.width()-upperBoundSize.width())/2); + y = m_baseline - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); + } else if (child == editableChild(2)) { + x = max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin; + y = m_baseline - argumentLayout()->baseline(); + } else { + assert(false); + } + return KDPoint(x,y); +} + } diff --git a/poincare/src/layout/sum_layout.h b/poincare/src/layout/sum_layout.h index 7218e866f..23d5f698f 100644 --- a/poincare/src/layout/sum_layout.h +++ b/poincare/src/layout/sum_layout.h @@ -7,10 +7,15 @@ namespace Poincare { class SumLayout : public SequenceLayout { public: - using SequenceLayout::SequenceLayout; + SumLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands); ExpressionLayout * clone() const override; + ExpressionLayout * argumentLayout() override; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; private: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + KDSize computeSize() override; + KDPoint positionOfChild(ExpressionLayout * child) override; }; } From b2962abd92557e3180a5b5b6d3eaddf95a038bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 10:53:58 +0100 Subject: [PATCH 052/257] [poincare] Make the Root layout wider to see the cursor position. Change-Id: Iba5ebb30935820c68224ff2aa0e0be2223d8a50d --- poincare/src/layout/nth_root_layout.cpp | 14 +++++++++----- poincare/src/layout/nth_root_layout.h | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index a52194a0f..3609284e1 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -164,16 +164,20 @@ void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, p.y() + m_baseline + radicandSize.height() - radicandLayout()->baseline() + k_heightMargin - k_leftRadixHeight, k_leftRadixWidth, k_leftRadixHeight); ctx->blendRectWithMask(leftRadixFrame, expressionColor, (const uint8_t *)radixPixel, (KDColor *)workingBuffer); + // If the indice is higher than the root. if (indexSize.height() + k_indexHeight > radicandLayout()->baseline() + k_radixLineThickness + k_heightMargin) { + // Vertical radix bar ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin, p.y() + indexSize.height() + k_indexHeight - radicandLayout()->baseline() - k_radixLineThickness - k_heightMargin, k_radixLineThickness, radicandSize.height() + 2*k_heightMargin + k_radixLineThickness), expressionColor); + // Horizontal radix bar ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin, p.y() + indexSize.height() + k_indexHeight - radicandLayout()->baseline() - k_radixLineThickness - k_heightMargin, - radicandSize.width() + 2*k_widthMargin, + radicandSize.width() + 2*k_widthMargin + k_radixHorizontalOverflow, k_radixLineThickness), expressionColor); - ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin + radicandSize.width() + 2*k_widthMargin, + // Right radix bar + ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin + radicandSize.width() + 2*k_widthMargin + k_radixHorizontalOverflow, p.y() + indexSize.height() + k_indexHeight - radicandLayout()->baseline() - k_radixLineThickness - k_heightMargin, k_radixLineThickness, k_rightRadixHeight + k_radixLineThickness), expressionColor); @@ -184,9 +188,9 @@ void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, radicandSize.height() + 2*k_heightMargin + k_radixLineThickness), expressionColor); ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin, p.y(), - radicandSize.width() + 2*k_widthMargin, + radicandSize.width() + 2*k_widthMargin + k_radixHorizontalOverflow, k_radixLineThickness), expressionColor); - ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin + radicandSize.width() + 2*k_widthMargin, + ctx->fillRect(KDRect(p.x() + indexSize.width() + k_widthMargin + radicandSize.width() + 2*k_widthMargin + k_radixHorizontalOverflow, p.y(), k_radixLineThickness, k_rightRadixHeight + k_radixLineThickness), expressionColor); @@ -198,7 +202,7 @@ KDSize NthRootLayout::computeSize() { KDSize radicandSize = radicandLayout()->size(); KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); return KDSize( - indexSize.width() + 3*k_widthMargin + 2*k_radixLineThickness + radicandSize.width(), + indexSize.width() + 3*k_widthMargin + 2*k_radixLineThickness + radicandSize.width() + k_radixHorizontalOverflow, m_baseline + radicandSize.height() - radicandLayout()->baseline() + k_heightMargin ); } diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index aa7d81814..8f54033a7 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -22,6 +22,7 @@ protected: KDPoint positionOfChild(ExpressionLayout * child) override; private: constexpr static KDCoordinate k_rightRadixHeight = 2; + constexpr static KDCoordinate k_radixHorizontalOverflow = 2; constexpr static KDCoordinate k_indexHeight = 5; constexpr static KDCoordinate k_heightMargin = 2; constexpr static KDCoordinate k_widthMargin = 1; From aa4ae376b3ece90bcc39c480f1fc9d03ab5d5e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 11:16:48 +0100 Subject: [PATCH 053/257] [poincare] Fixed the IntegralLayout navigation. The cursor now avoids pointing at the integrand horizontal layout or left of dx layout. It insteads points at the children of the horizontal integrand layout that are not "dx", so an EmptyVisibleLayout can be properly overwritten when needed. Change-Id: Ie5eced3761d2d8f49f02530336981a1285b459fd --- poincare/src/layout/integral_layout.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index ae3db3355..755a27635 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -58,8 +58,8 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go Right of the integrand, Left of "dx". if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(integrandLayout() != nullptr); - cursor->setPointedExpressionLayout(integrandLayout()); - return integrandLayout()->moveLeft(cursor); + cursor->setPointedExpressionLayout(integrandLayout()->editableChild(integrandLayout()->numberOfChildren()-2)); + return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); // Case: Left of the brackets. @@ -80,7 +80,7 @@ bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { && cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(integrandLayout() != nullptr); - cursor->setPointedExpressionLayout(integrandLayout()); + cursor->setPointedExpressionLayout(integrandLayout()->editableChild(0)); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } @@ -95,7 +95,7 @@ bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { } assert(cursor->pointedExpressionLayout() == this); // Case: Left of the integral. - // Go ti the upper bound. + // Go to the upper bound. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { assert(upperBoundLayout() != nullptr); cursor->setPointedExpressionLayout(upperBoundLayout()); From 428be61703444271a66b559868a474741ded65a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 11:29:44 +0100 Subject: [PATCH 054/257] [poincare] Fix navigation in Sum or Sequence layouts. Avoid adding text Left or Right of "n=". Change-Id: I03c980f25bae1cb89feaa9d733bfb3fe5294fed0 --- poincare/src/layout/sequence_layout.cpp | 4 ++-- poincare/src/layout/string_layout.cpp | 23 +++++++++++++++++------ poincare/src/layout/sum_layout.cpp | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 364fd3ed7..360578568 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -31,7 +31,7 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { && cursor->pointedExpressionLayout() == argumentLayout()) { assert(lowerBoundLayout() != nullptr); - cursor->setPointedExpressionLayout(lowerBoundLayout()); + cursor->setPointedExpressionLayout(lowerBoundLayout()->editableChild(1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } @@ -114,7 +114,7 @@ bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout // If the cursor is inside the upper bound, move it to the lower bound. if (upperBoundLayout() && previousLayout == upperBoundLayout()) { assert(lowerBoundLayout() != nullptr); - return lowerBoundLayout()->moveDownInside(cursor); + return lowerBoundLayout()->editableChild(1)->moveDownInside(cursor); } // If the cursor is Left of the argument, move it to the lower bound. if (argumentLayout() diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index f2be896e3..adea25f99 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -27,10 +27,21 @@ bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { // A StringLayout is not editable, and the cursor cannot go inside it. assert(cursor->pointedExpressionLayout() == this); // Case: Right. - // Go Left. + // If there is a Left brother, go Right of it. Else go Left of the + // grandparent. We need to do this to avoid adding text left or right of a + // string layout, for instance left of "n=" in a Sum layout. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; + int indexOfThis = m_parent->indexOfChild(this); + if (m_parent->editableChild(indexOfThis-1) != nullptr) { + cursor->setPointedExpressionLayout(m_parent->editableChild(indexOfThis-1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + if (m_parent->parent()) { + cursor->setPointedExpressionLayout(const_cast(m_parent->parent())); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } } // Case: Left. // Ask the parent. @@ -45,9 +56,9 @@ bool StringLayout::moveRight(ExpressionLayoutCursor * cursor) { assert(cursor->pointedExpressionLayout() == this); assert(m_parent != nullptr); // Case: Left. - // Go Right. - // If there is a Right brother, go Left of it. Else go Right of the grandparent. - // //TODO explain that it is because of integrals and baselayouts. + // If there is a Right brother, go Left of it. Else go Right of the + // grandparent. We need to do this to avoid adding text left or right of a + // string layout, for instance right of "dx" in an integral layout. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { int indexOfThis = m_parent->indexOfChild(this); if (m_parent->editableChild(indexOfThis+1) != nullptr) { diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index d9febe8ae..ef3027cbf 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -69,7 +69,7 @@ bool SumLayout::moveLeft(ExpressionLayoutCursor * cursor) { && cursor->pointedExpressionLayout() == editableChild(2)) { assert(lowerBoundLayout() != nullptr); - cursor->setPointedExpressionLayout(lowerBoundLayout()); + cursor->setPointedExpressionLayout(lowerBoundLayout()->editableChild(1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } From 693fb5e400d3eb61057b6482d22e2bd8012f8f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 11:57:34 +0100 Subject: [PATCH 055/257] [poincare] Clean Layouts. Do not compute the baseline at construction, and use base class constructors. Change-Id: I4361a6d92d7652b2aae2d662388b8d2c90afd3ce --- poincare/src/layout/baseline_relative_layout.cpp | 1 - poincare/src/layout/bracket_layout.cpp | 6 ------ poincare/src/layout/bracket_layout.h | 2 +- poincare/src/layout/char_layout.cpp | 1 - poincare/src/layout/condensed_sum_layout.cpp | 6 ------ poincare/src/layout/condensed_sum_layout.h | 2 +- poincare/src/layout/conjugate_layout.cpp | 6 ------ poincare/src/layout/conjugate_layout.h | 2 +- poincare/src/layout/empty_layout.cpp | 6 ------ poincare/src/layout/empty_layout.h | 2 +- poincare/src/layout/empty_visible_layout.cpp | 1 - poincare/src/layout/fraction_layout.cpp | 6 ------ poincare/src/layout/fraction_layout.h | 2 +- poincare/src/layout/grid_layout.cpp | 1 - poincare/src/layout/horizontal_layout.cpp | 11 ----------- poincare/src/layout/horizontal_layout.h | 3 +-- poincare/src/layout/integral_layout.cpp | 6 ------ poincare/src/layout/integral_layout.h | 2 +- poincare/src/layout/nth_root_layout.cpp | 6 ------ poincare/src/layout/nth_root_layout.h | 2 +- poincare/src/layout/parenthesis_layout.cpp | 1 - poincare/src/layout/sequence_layout.cpp | 6 ------ poincare/src/layout/sequence_layout.h | 2 +- 23 files changed, 9 insertions(+), 74 deletions(-) diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index 39b0bac48..6947ed585 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -9,7 +9,6 @@ BaselineRelativeLayout::BaselineRelativeLayout(ExpressionLayout * base, Expressi StaticLayoutHierarchy(base, indice, cloneOperands), m_type(type) { - computeBaseline(); } ExpressionLayout * BaselineRelativeLayout::clone() const { diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 1ad946b87..38303abf7 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -7,12 +7,6 @@ extern "C" { namespace Poincare { -BracketLayout::BracketLayout(ExpressionLayout * operandLayout, bool cloneOperands) : - StaticLayoutHierarchy<1>(operandLayout, cloneOperands) -{ - computeBaseline(); -} - ExpressionLayout * BracketLayout::clone() const { BracketLayout * layout = new BracketLayout(const_cast(this)->operandLayout(), true); return layout; diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index b9beeb4c7..8de75000d 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -7,7 +7,7 @@ namespace Poincare { class BracketLayout : public StaticLayoutHierarchy<1> { public: - BracketLayout(ExpressionLayout * operandLayout, bool cloneOperands); + using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/char_layout.cpp b/poincare/src/layout/char_layout.cpp index 22357ddfc..866814bda 100644 --- a/poincare/src/layout/char_layout.cpp +++ b/poincare/src/layout/char_layout.cpp @@ -10,7 +10,6 @@ CharLayout::CharLayout(char c, KDText::FontSize fontSize) : m_char(c), m_fontSize(fontSize) { - computeBaseline(); } ExpressionLayout * CharLayout::clone() const { diff --git a/poincare/src/layout/condensed_sum_layout.cpp b/poincare/src/layout/condensed_sum_layout.cpp index 04babee19..a7a511e9e 100644 --- a/poincare/src/layout/condensed_sum_layout.cpp +++ b/poincare/src/layout/condensed_sum_layout.cpp @@ -5,12 +5,6 @@ namespace Poincare { -CondensedSumLayout::CondensedSumLayout(ExpressionLayout * base, ExpressionLayout * subscript, ExpressionLayout * superscript, bool cloneOperands) : - StaticLayoutHierarchy<3>(base, subscript, superscript, cloneOperands) -{ - computeBaseline(); -} - ExpressionLayout * CondensedSumLayout::clone() const { CondensedSumLayout * layout = new CondensedSumLayout(const_cast(this)->baseLayout(), const_cast(this)->subscriptLayout(), const_cast(this)->superscriptLayout(), true); return layout; diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index fa9179acd..20795398d 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -7,7 +7,7 @@ namespace Poincare { class CondensedSumLayout : public StaticLayoutHierarchy<3> { public: - CondensedSumLayout(ExpressionLayout * base, ExpressionLayout * subscript, ExpressionLayout * superscript, bool cloneOperands); + using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index 97317f5dc..19957fe20 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -8,12 +8,6 @@ extern "C" { namespace Poincare { -ConjugateLayout::ConjugateLayout(ExpressionLayout * operand, bool cloneOperands) : - StaticLayoutHierarchy<1>(operand, cloneOperands) -{ - computeBaseline(); -} - ExpressionLayout * ConjugateLayout::clone() const { ConjugateLayout * layout = new ConjugateLayout(const_cast(this)->operandLayout(), true); return layout; diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 732e89e49..c4b4454df 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -7,7 +7,7 @@ namespace Poincare { class ConjugateLayout : public StaticLayoutHierarchy<1> { public: - ConjugateLayout(ExpressionLayout * operand, bool cloneOperands); + using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/empty_layout.cpp b/poincare/src/layout/empty_layout.cpp index 5d8919441..88871bb7c 100644 --- a/poincare/src/layout/empty_layout.cpp +++ b/poincare/src/layout/empty_layout.cpp @@ -4,12 +4,6 @@ namespace Poincare { -EmptyLayout::EmptyLayout() : - StaticLayoutHierarchy<0>() -{ - m_baseline = 0; -} - ExpressionLayout * EmptyLayout::clone() const { EmptyLayout * layout = new EmptyLayout(); return layout; diff --git a/poincare/src/layout/empty_layout.h b/poincare/src/layout/empty_layout.h index 2c746faba..9ca0b9b28 100644 --- a/poincare/src/layout/empty_layout.h +++ b/poincare/src/layout/empty_layout.h @@ -8,7 +8,7 @@ namespace Poincare { class EmptyLayout : public StaticLayoutHierarchy<0> { public: - EmptyLayout(); + using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index f6cdaf7b4..f4291ef24 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -8,7 +8,6 @@ EmptyVisibleLayout::EmptyVisibleLayout() : EmptyLayout(), m_fillRectColor(KDColor::RGB24(0xffd370)) //TODO make static or in Palette? { - computeBaseline(); } ExpressionLayout * EmptyVisibleLayout::clone() const { diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 6fd6651b3..b642671c1 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -6,12 +6,6 @@ namespace Poincare { -FractionLayout::FractionLayout(ExpressionLayout * numerator, ExpressionLayout * denominator, bool cloneOperands) : - StaticLayoutHierarchy<2>(numerator, denominator, cloneOperands) -{ - computeBaseline(); -} - ExpressionLayout * FractionLayout::clone() const { FractionLayout * layout = new FractionLayout(const_cast(this)->numeratorLayout(), const_cast(this)->denominatorLayout(), true); return layout; diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 670718879..0bbb85ac3 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -7,7 +7,7 @@ namespace Poincare { class FractionLayout : public StaticLayoutHierarchy<2> { public: - FractionLayout(ExpressionLayout * numerator, ExpressionLayout * denominator, bool cloneOperands); + using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 504a9c65d..9821533de 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -12,7 +12,6 @@ GridLayout::GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int n m_numberOfRows(numberOfRows), m_numberOfColumns(numberOfColumns) { - computeBaseline(); } ExpressionLayout * GridLayout::clone() const { diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 0be29923c..6f2f882f1 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -10,17 +10,6 @@ extern "C" { namespace Poincare { -HorizontalLayout::HorizontalLayout() : - DynamicLayoutHierarchy() -{ -} - -HorizontalLayout::HorizontalLayout(ExpressionLayout ** childrenLayouts, int childrenCount, bool cloneOperands) : - DynamicLayoutHierarchy(childrenLayouts, childrenCount, cloneOperands) -{ - computeBaseline(); -} - ExpressionLayout * HorizontalLayout::clone() const { HorizontalLayout * layout = new HorizontalLayout(const_cast(children()), numberOfChildren(), true); return layout; diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index d6f8bba01..b3f1129dd 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -7,8 +7,7 @@ namespace Poincare { class HorizontalLayout : public DynamicLayoutHierarchy { public: - HorizontalLayout(); - HorizontalLayout(ExpressionLayout ** layouts, int childrenCount, bool cloneOperands); + using DynamicLayoutHierarchy::DynamicLayoutHierarchy; ExpressionLayout * clone() const override; /* Navigation */ diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 755a27635..59164adb7 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -19,12 +19,6 @@ const uint8_t bottomSymbolPixel[IntegralLayout::k_symbolHeight][IntegralLayout:: {0xFF, 0xFF, 0x00, 0x00}, }; -IntegralLayout::IntegralLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * integrand, bool cloneOperands) : - StaticLayoutHierarchy<3>(upperBound, lowerBound, integrand, cloneOperands) -{ - computeBaseline(); -} - ExpressionLayout * IntegralLayout::clone() const { IntegralLayout * layout = new IntegralLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->integrandLayout(), true); return layout; diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 7390f644a..67b0e5750 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -9,7 +9,7 @@ class IntegralLayout : public StaticLayoutHierarchy<3> { public: constexpr static KDCoordinate k_symbolHeight = 4; constexpr static KDCoordinate k_symbolWidth = 4; - IntegralLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * integrand, bool cloneOperands); + using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 3609284e1..709e3df2f 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -16,12 +16,6 @@ const uint8_t radixPixel[NthRootLayout::k_leftRadixHeight][NthRootLayout::k_left {0xFF, 0xFF, 0xFF, 0xFF, 0x00}, }; -NthRootLayout::NthRootLayout(ExpressionLayout * radicand, ExpressionLayout * index, bool cloneOperands) : - StaticLayoutHierarchy<2>(radicand, index, cloneOperands) -{ - computeBaseline(); -} - ExpressionLayout * NthRootLayout::clone() const { NthRootLayout * layout = new NthRootLayout(const_cast(this)->radicandLayout(), const_cast(this)->indexLayout(), true); return layout; diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index 8f54033a7..5c1ad77d9 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -9,7 +9,7 @@ class NthRootLayout : public StaticLayoutHierarchy<2> { public: constexpr static KDCoordinate k_leftRadixHeight = 8; constexpr static KDCoordinate k_leftRadixWidth = 5; - NthRootLayout(ExpressionLayout * radicand, ExpressionLayout * index, bool cloneOperands); + using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index b5b48641f..0f9cbd1fc 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -15,7 +15,6 @@ ParenthesisLayout::ParenthesisLayout(ExpressionLayout * operand, bool cloneOpera ExpressionLayout * leftParenthesis = new ParenthesisLeftLayout(); ExpressionLayout * rightParenthesis = new ParenthesisRightLayout(); build(ExpressionLayout::ExpressionLayoutArray3(leftParenthesis, operand, rightParenthesis), 3, cloneOperands); - computeBaseline(); } ExpressionLayout * ParenthesisLayout::clone() const { diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 360578568..708b7e1af 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -6,12 +6,6 @@ namespace Poincare { -SequenceLayout::SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands) : - StaticLayoutHierarchy<3>(upperBound, lowerBound, argument, cloneOperands) -{ - computeBaseline(); -} - bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the bounds. // Go Left of the sequence. diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index e2eb0e57f..7df9ce767 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -9,7 +9,7 @@ class SequenceLayout : public StaticLayoutHierarchy<3> { public: constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; - SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands); + using StaticLayoutHierarchy::StaticLayoutHierarchy; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; From b0fd089d87c8129c82a88669348a44f6822d6318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 12:20:56 +0100 Subject: [PATCH 056/257] [poincare] Dynamic size of Bracket Left and Right layouts. Change-Id: Icd0654dc7b63639d4513946b24c0855ffcb38c87 --- poincare/include/poincare/expression_layout.h | 2 + poincare/src/layout/bracket_left_layout.cpp | 52 +++++++++++++++++-- poincare/src/layout/bracket_left_layout.h | 3 ++ .../src/layout/bracket_left_right_layout.cpp | 20 ++++--- .../src/layout/bracket_left_right_layout.h | 6 ++- poincare/src/layout/bracket_right_layout.cpp | 50 ++++++++++++++++-- poincare/src/layout/bracket_right_layout.h | 3 ++ .../src/layout/parenthesis_right_layout.cpp | 3 +- 8 files changed, 124 insertions(+), 15 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 5ffac5992..bf1d7dea9 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -67,6 +67,8 @@ public: /* Other */ virtual bool isLeftParenthesis() const { return false; } virtual bool isRightParenthesis() const { return false; } + virtual bool isLeftBracket() const { return false; } + virtual bool isRightBracket() const { return false; } virtual char XNTChar() const; protected: diff --git a/poincare/src/layout/bracket_left_layout.cpp b/poincare/src/layout/bracket_left_layout.cpp index 07d4cb95e..e0e510572 100644 --- a/poincare/src/layout/bracket_left_layout.cpp +++ b/poincare/src/layout/bracket_left_layout.cpp @@ -1,4 +1,7 @@ #include "bracket_left_layout.h" +extern "C" { +#include +} namespace Poincare { @@ -8,10 +11,53 @@ ExpressionLayout * BracketLeftLayout::clone() const { } void BracketLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - //TODO Make sure m_operandHeight is up-to-date. - ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_lineThickness, m_operandHeight), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_lineThickness, operandHeight()), expressionColor); ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y(), k_bracketWidth, k_lineThickness), expressionColor); - ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y() + m_operandHeight, k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_externWidthMargin, p.y() + operandHeight(), k_bracketWidth, k_lineThickness), expressionColor); +} + +void BracketLeftLayout::computeOperandHeight() { + assert(m_parent != nullptr); + m_operandHeight = BracketLeftRightLayout::k_minimalOperandHeight; + int currentNumberOfOpenBrackets = 1; + int numberOfBrothers = m_parent->numberOfChildren(); + for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { + ExpressionLayout * brother = m_parent->editableChild(i); + if (brother->isRightBracket()) { + currentNumberOfOpenBrackets--; + if (currentNumberOfOpenBrackets == 0) { + return; + } + } else if (brother->isLeftBracket()) { + currentNumberOfOpenBrackets++; + } + KDCoordinate brotherHeight = brother->size().height(); + if (brotherHeight > m_operandHeight) { + m_operandHeight = brotherHeight; + } + } +} + +void BracketLeftLayout::computeBaseline() { + assert(m_parent != nullptr); + m_baseline = operandHeight()/2; + int currentNumberOfOpenBrackets = 1; + int numberOfBrothers = m_parent->numberOfChildren(); + for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { + ExpressionLayout * brother = m_parent->editableChild(i); + if (brother->isRightBracket()) { + currentNumberOfOpenBrackets--; + if (currentNumberOfOpenBrackets == 0) { + break; + } + } else if (brother->isLeftBracket()) { + currentNumberOfOpenBrackets++; + } + if (brother->baseline() > m_baseline) { + m_baseline = brother->baseline(); + } + } + m_baselined = true; } } diff --git a/poincare/src/layout/bracket_left_layout.h b/poincare/src/layout/bracket_left_layout.h index 8f46d06d9..1975b2fc0 100644 --- a/poincare/src/layout/bracket_left_layout.h +++ b/poincare/src/layout/bracket_left_layout.h @@ -9,8 +9,11 @@ class BracketLeftLayout : public BracketLeftRightLayout { public: using BracketLeftRightLayout::BracketLeftRightLayout; ExpressionLayout * clone() const override; + bool isLeftBracket() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + void computeOperandHeight() override; + void computeBaseline() override; }; } diff --git a/poincare/src/layout/bracket_left_right_layout.cpp b/poincare/src/layout/bracket_left_right_layout.cpp index 3a43c0536..d6eefaaa8 100644 --- a/poincare/src/layout/bracket_left_right_layout.cpp +++ b/poincare/src/layout/bracket_left_right_layout.cpp @@ -9,10 +9,15 @@ namespace Poincare { BracketLeftRightLayout::BracketLeftRightLayout() : StaticLayoutHierarchy<0>(), - m_operandHeight(18) //TODO + m_operandHeightComputed(false) { } +void BracketLeftRightLayout::invalidAllSizesPositionsAndBaselines() { + m_operandHeightComputed = false; + ExpressionLayout::invalidAllSizesPositionsAndBaselines(); +} + bool BracketLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { assert(cursor->pointedExpressionLayout() == this); // Case: Right. @@ -49,14 +54,15 @@ bool BracketLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { KDSize BracketLeftRightLayout::computeSize() { - //TODO: compute the operandHeight according to the brothers - return KDSize(k_externWidthMargin + k_lineThickness + k_widthMargin, m_operandHeight); + return KDSize(k_externWidthMargin + k_lineThickness + k_widthMargin, operandHeight()); } -void BracketLeftRightLayout::computeBaseline() { - //TODO: compute the operandHeight according to the brothers - m_baseline = m_operandHeight/2; - m_baselined = true; +KDCoordinate BracketLeftRightLayout::operandHeight() { + if (!m_operandHeightComputed) { + computeOperandHeight(); + m_operandHeightComputed = true; + } + return m_operandHeight; } KDPoint BracketLeftRightLayout::positionOfChild(ExpressionLayout * child) { diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h index 838b9e00e..98ddffd93 100644 --- a/poincare/src/layout/bracket_left_right_layout.h +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class BracketLeftRightLayout : public StaticLayoutHierarchy<0> { public: BracketLeftRightLayout(); + void invalidAllSizesPositionsAndBaselines() override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; constexpr static KDCoordinate k_bracketWidth = 5; @@ -15,9 +16,12 @@ public: constexpr static KDCoordinate k_widthMargin = 5; constexpr static KDCoordinate k_externWidthMargin = 2; protected: + constexpr static KDCoordinate k_minimalOperandHeight = 18; KDSize computeSize() override; - void computeBaseline() override; + KDCoordinate operandHeight(); + virtual void computeOperandHeight() = 0; KDPoint positionOfChild(ExpressionLayout * child) override; + bool m_operandHeightComputed; uint16_t m_operandHeight; }; } diff --git a/poincare/src/layout/bracket_right_layout.cpp b/poincare/src/layout/bracket_right_layout.cpp index c6f8bbb14..8634d6947 100644 --- a/poincare/src/layout/bracket_right_layout.cpp +++ b/poincare/src/layout/bracket_right_layout.cpp @@ -1,4 +1,7 @@ #include "bracket_right_layout.h" +extern "C" { +#include +} namespace Poincare { @@ -8,10 +11,51 @@ ExpressionLayout * BracketRightLayout::clone() const { } void BracketRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - //TODO Make sure m_operandHeight is up-to-date. - ctx->fillRect(KDRect(p.x()+k_widthMargin, p.y(), k_lineThickness, m_operandHeight), expressionColor); + ctx->fillRect(KDRect(p.x()+k_widthMargin, p.y(), k_lineThickness, operandHeight()), expressionColor); ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth+1, p.y(), k_bracketWidth, k_lineThickness), expressionColor); - ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth+1, p.y() + m_operandHeight, k_bracketWidth, k_lineThickness), expressionColor); + ctx->fillRect(KDRect(p.x()+k_widthMargin-k_bracketWidth+1, p.y() + operandHeight(), k_bracketWidth, k_lineThickness), expressionColor); +} + +void BracketRightLayout::computeOperandHeight() { + assert(m_parent != nullptr); + m_operandHeight = BracketLeftRightLayout::k_minimalOperandHeight; + int currentNumberOfOpenBrackets = 1; + for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { + ExpressionLayout * brother = m_parent->editableChild(i); + if (brother->isLeftBracket()) { + currentNumberOfOpenBrackets--; + if (currentNumberOfOpenBrackets == 0) { + return; + } + } else if (brother->isRightBracket()) { + currentNumberOfOpenBrackets++; + } + KDCoordinate brotherHeight = brother->size().height(); + if (brotherHeight > m_operandHeight) { + m_operandHeight = brotherHeight; + } + } +} + +void BracketRightLayout::computeBaseline() { + assert(m_parent != nullptr); + m_baseline = operandHeight()/2; + int currentNumberOfOpenBrackets = 1; + for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { + ExpressionLayout * brother = m_parent->editableChild(i); + if (brother->isLeftBracket()) { + currentNumberOfOpenBrackets--; + if (currentNumberOfOpenBrackets == 0) { + break; + } + } else if (brother->isRightBracket()) { + currentNumberOfOpenBrackets++; + } + if (brother->baseline() > m_baseline) { + m_baseline = brother->baseline(); + } + } + m_baselined = true; } } diff --git a/poincare/src/layout/bracket_right_layout.h b/poincare/src/layout/bracket_right_layout.h index f2c25186a..788664f3e 100644 --- a/poincare/src/layout/bracket_right_layout.h +++ b/poincare/src/layout/bracket_right_layout.h @@ -9,8 +9,11 @@ class BracketRightLayout : public BracketLeftRightLayout { public: using BracketLeftRightLayout::BracketLeftRightLayout; ExpressionLayout * clone() const override; + bool isRightBracket() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + void computeOperandHeight() override; + void computeBaseline() override; }; } diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index d3b0efb0d..35202c273 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -66,7 +66,8 @@ void ParenthesisRightLayout::computeOperandHeight() { } } else if (brother->isRightParenthesis()) { currentNumberOfOpenParentheses++; - } KDCoordinate brotherHeight = brother->size().height(); + } + KDCoordinate brotherHeight = brother->size().height(); if (brotherHeight > m_operandHeight) { m_operandHeight = brotherHeight; } From 406d108aa50fda0bc8697087143b92cf98932244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 13:04:05 +0100 Subject: [PATCH 057/257] [poincare] Sandardize Bracket and Parenthesis minimal height. Change-Id: Iadfce26575d77182ecc12dd100fa9b70b9062802 --- escher/include/escher/metric.h | 1 + poincare/src/layout/bracket_left_layout.cpp | 3 ++- poincare/src/layout/bracket_left_right_layout.h | 1 - poincare/src/layout/bracket_right_layout.cpp | 3 ++- poincare/src/layout/parenthesis_left_layout.cpp | 3 ++- poincare/src/layout/parenthesis_right_layout.cpp | 3 ++- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/escher/include/escher/metric.h b/escher/include/escher/metric.h index 06c060a1c..429c6965a 100644 --- a/escher/include/escher/metric.h +++ b/escher/include/escher/metric.h @@ -27,6 +27,7 @@ public: constexpr static KDCoordinate ToolboxRowHeight = 40; constexpr static KDCoordinate FractionAndConjugateHorizontalOverflow = 2; constexpr static KDCoordinate FractionAndConjugateHorizontalMargin = 2; + constexpr static KDCoordinate MinimalBracketAndParenthesisHeight = 18; }; #endif diff --git a/poincare/src/layout/bracket_left_layout.cpp b/poincare/src/layout/bracket_left_layout.cpp index e0e510572..324b7ae15 100644 --- a/poincare/src/layout/bracket_left_layout.cpp +++ b/poincare/src/layout/bracket_left_layout.cpp @@ -1,4 +1,5 @@ #include "bracket_left_layout.h" +#include extern "C" { #include } @@ -18,7 +19,7 @@ void BracketLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressionCol void BracketLeftLayout::computeOperandHeight() { assert(m_parent != nullptr); - m_operandHeight = BracketLeftRightLayout::k_minimalOperandHeight; + m_operandHeight = Metric::MinimalBracketAndParenthesisHeight; int currentNumberOfOpenBrackets = 1; int numberOfBrothers = m_parent->numberOfChildren(); for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h index 98ddffd93..4af7a09a3 100644 --- a/poincare/src/layout/bracket_left_right_layout.h +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -16,7 +16,6 @@ public: constexpr static KDCoordinate k_widthMargin = 5; constexpr static KDCoordinate k_externWidthMargin = 2; protected: - constexpr static KDCoordinate k_minimalOperandHeight = 18; KDSize computeSize() override; KDCoordinate operandHeight(); virtual void computeOperandHeight() = 0; diff --git a/poincare/src/layout/bracket_right_layout.cpp b/poincare/src/layout/bracket_right_layout.cpp index 8634d6947..a1f5ce663 100644 --- a/poincare/src/layout/bracket_right_layout.cpp +++ b/poincare/src/layout/bracket_right_layout.cpp @@ -1,4 +1,5 @@ #include "bracket_right_layout.h" +#include extern "C" { #include } @@ -18,7 +19,7 @@ void BracketRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionCo void BracketRightLayout::computeOperandHeight() { assert(m_parent != nullptr); - m_operandHeight = BracketLeftRightLayout::k_minimalOperandHeight; + m_operandHeight = Metric::MinimalBracketAndParenthesisHeight; int currentNumberOfOpenBrackets = 1; for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { ExpressionLayout * brother = m_parent->editableChild(i); diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index f191d68ee..1bd3d416a 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -1,4 +1,5 @@ #include "parenthesis_left_layout.h" +#include extern "C" { #include #include @@ -55,7 +56,7 @@ void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressio void ParenthesisLeftLayout::computeOperandHeight() { assert(m_parent != nullptr); - m_operandHeight = 18; + m_operandHeight = Metric::MinimalBracketAndParenthesisHeight; int currentNumberOfOpenParentheses = 1; int numberOfBrothers = m_parent->numberOfChildren(); for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index 35202c273..b248e0150 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -1,4 +1,5 @@ #include "parenthesis_right_layout.h" +#include extern "C" { #include #include @@ -55,7 +56,7 @@ void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressi void ParenthesisRightLayout::computeOperandHeight() { assert(m_parent != nullptr); - m_operandHeight = 18; + m_operandHeight = Metric::MinimalBracketAndParenthesisHeight; int currentNumberOfOpenParentheses = 1; for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { ExpressionLayout * brother = m_parent->editableChild(i); From 1a3c3912374db56013be6566d3897449442d86d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 14:17:11 +0100 Subject: [PATCH 058/257] [expression_editor/poincare] General "delete" rule. Change-Id: I5c16f19aacdac312156f45c88c189adfb72f03e8 --- apps/expression_editor/controller.cpp | 13 +++++++ apps/expression_editor/controller.h | 1 + poincare/include/poincare/expression_layout.h | 2 ++ .../poincare/expression_layout_cursor.h | 1 + poincare/src/expression_layout_cursor.cpp | 4 +++ poincare/src/layout/expression_layout.cpp | 34 +++++++++++++++++++ 6 files changed, 55 insertions(+) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 625ac72a0..1679d3303 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -66,6 +66,11 @@ bool Controller::privateHandleEvent(Ion::Events::Event event) { m_view.layoutSubviews(); return true; } + if (handleDeleteEvent(event)) { + m_expressionLayout->invalidAllSizesPositionsAndBaselines(); + m_view.layoutSubviews(); + return true; + } return false; } @@ -126,4 +131,12 @@ ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { return nullptr; } +bool Controller::handleDeleteEvent(Ion::Events::Event event) { + if (event == Ion::Events::Backspace) { + m_cursor.performBackspace(); + return true; + } + return false; +} + } diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index f34518ff5..588c17d69 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -28,6 +28,7 @@ private: bool privateHandleEvent(Ion::Events::Event event); bool handleMoveEvent(Ion::Events::Event event); Poincare::ExpressionLayout * handleAddEvent(Ion::Events::Event event); + bool handleDeleteEvent(Ion::Events::Event event); ExpressionEditorView m_view; Poincare::ExpressionLayout * m_expressionLayout; Poincare::ExpressionLayoutCursor m_cursor; diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index bf1d7dea9..963c631b7 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -55,6 +55,8 @@ public: /* Dynamic Layout*/ virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } + virtual void removeChildAtIndex(int index, bool deleteAfterRemoval); + virtual void backspaceAtCursor(ExpressionLayoutCursor * cursor); /* Tree navigation */ virtual bool moveLeft(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 5813fee8c..b92bff74e 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -52,6 +52,7 @@ public: ExpressionLayout * addEmptySquarePowerLayout(); ExpressionLayout * addXNTCharLayout(); ExpressionLayout * insertText(const char * text); + void performBackspace(); private: constexpr static KDCoordinate k_cursorHeight = 18; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index d10c759e6..71e6dad4f 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -138,5 +138,9 @@ ExpressionLayout * ExpressionLayoutCursor::insertText(const char * text) { return newChild; } +void ExpressionLayoutCursor::performBackspace() { + m_pointedExpressionLayout->backspaceAtCursor(this); +} + } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 9f19d4040..fe06a8c55 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -201,6 +202,39 @@ void ExpressionLayout::detachChild(const ExpressionLayout * e) { } } +void ExpressionLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { + assert(index >= 0 && index < numberOfChildren()); + replaceChild(editableChild(index), new EmptyVisibleLayout(), deleteAfterRemoval); +} + +void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() != this || m_parent == nullptr) { + return; + } + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + m_parent->backspaceAtCursor(cursor); + return; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + if (numberOfChildren() > 0) { + cursor->setPointedExpressionLayout(editableChild(numberOfChildren()-1)); + cursor->performBackspace(); + return; + } + int indexInParent = m_parent->indexOfChild(this); + ExpressionLayout * previousParent = m_parent; + previousParent->removeChildAtIndex(indexInParent, true); + if (indexInParent < previousParent->numberOfChildren()) { + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + int indexOfNewPointedLayout = indexInParent - 1; + assert(indexOfNewPointedLayout >= 0); + assert(indexOfNewPointedLayout < previousParent->numberOfChildren()); + cursor->setPointedExpressionLayout(previousParent->editableChild(indexOfNewPointedLayout)); +} + char ExpressionLayout::XNTChar() const { if (m_parent == nullptr) { return 'x'; From 69e003d1ef16198a953f542803ce02c68d415358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 14:26:31 +0100 Subject: [PATCH 059/257] [apps] Added layout for AbsoluteValue in toolbox. Change-Id: Ie686aabaa5c3f49af0298fbe0c8b9859e89f638f --- apps/expression_editor/controller.h | 2 +- apps/math_toolbox.cpp | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index 588c17d69..3910844fa 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -22,7 +22,7 @@ public: Toolbox * toolbox() override; /* Callback for Toolbox */ - void insertLayoutAtCursor(ExpressionLayout * layout, ExpressionLayout * pointedLayout); + void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout); private: bool privateHandleEvent(Ion::Events::Event event); diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index d1295a2fb..c76336561 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -3,6 +3,8 @@ #include #include +using namespace Poincare; + /* TODO: find a shorter way to initialize tree models * We create one model tree: each node keeps the label of the row it refers to * and the text which would be edited by clicking on the row. When the node is a @@ -87,13 +89,19 @@ const ToolboxMessageTree predictionChildren[3] = { ToolboxMessageTree(I18n::Message::PredictionCommandWithArg, I18n::Message::Prediction, I18n::Message::PredictionCommandWithArg), ToolboxMessageTree(I18n::Message::ConfidenceCommandWithArg, I18n::Message::Confidence, I18n::Message::ConfidenceCommandWithArg)}; +const int pointedLayoutPathAbs[] = {0}; #if LIST_ARE_DEFINED -const ToolboxMessageTree menu[12] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg), +const ToolboxMessageTree menu[12] = { #elif MATRICES_ARE_DEFINED -const ToolboxMessageTree menu[11] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg), +const ToolboxMessageTree menu[11] = { #else -const ToolboxMessageTree menu[10] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg), +const ToolboxMessageTree menu[10] = { #endif + ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg, nullptr, 0, + new AbsoluteValueLayout( + new EmptyVisibleLayout()), + const_cast(&pointedLayoutPathAbs[0]), + 1), ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommandWithArg), ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg), ToolboxMessageTree(I18n::Message::Calculation, I18n::Message::Default, I18n::Message::Default, calculChildren, 4), From 04be8e1cc2978a4f876a442436e18fdf95a0e7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 14:27:18 +0100 Subject: [PATCH 060/257] [poincare] Delete for BracketLayout. Change-Id: Ifb45ef3d556ccc3f6b1efb9fdca04f6411a3dfc9 --- poincare/src/layout/bracket_layout.cpp | 23 +++++++++++++++++++++++ poincare/src/layout/bracket_layout.h | 1 + 2 files changed, 24 insertions(+) diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 38303abf7..f3433e3f2 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -12,6 +12,29 @@ ExpressionLayout * BracketLayout::clone() const { return layout; } +void BracketLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == operandLayout()) { + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(operandLayout(), true); + if (indexInParent == 0) { + cursor->setPointedExpressionLayout(previousParent); + return; + } + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursor->setPointedExpressionLayout(operandLayout()); + cursor->performBackspace(); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the operand. // Go Left of the brackets. diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index 8de75000d..d11f51681 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -9,6 +9,7 @@ class BracketLayout : public StaticLayoutHierarchy<1> { public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: From f307e15bac0582e4e0478b58acd796eb9877e854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 15:24:40 +0100 Subject: [PATCH 061/257] [poincare] Delete for HorizontalLayout. Change-Id: Iff983beccc14195b09d54b5b5db668b8f7d4eca7 --- .../poincare/dynamic_layout_hierarchy.h | 1 + poincare/include/poincare/expression_layout.h | 3 ++- .../src/layout/dynamic_layout_hierarchy.cpp | 19 +++++++++++++++ poincare/src/layout/empty_layout.h | 1 + poincare/src/layout/expression_layout.cpp | 23 ++++++++++++++++++- poincare/src/layout/horizontal_layout.cpp | 15 ++++++++++++ poincare/src/layout/horizontal_layout.h | 3 +++ 7 files changed, 63 insertions(+), 2 deletions(-) diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index 54da3dfa9..dafe85166 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -21,6 +21,7 @@ public: const ExpressionLayout * const * children() const override { return m_children; }; bool addChildAtIndex(ExpressionLayout * operand, int index) override; + void removeChildAtIndex(int index, bool deleteAfterRemoval) override; protected: const ExpressionLayout ** m_children; int m_numberOfChildren; diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 963c631b7..dcac65950 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -50,7 +50,7 @@ public: virtual void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace = true); ExpressionLayout * replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace); - void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true); + virtual void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true); void detachChild(const ExpressionLayout * e); // Removes a child WITHOUT deleting it /* Dynamic Layout*/ @@ -71,6 +71,7 @@ public: virtual bool isRightParenthesis() const { return false; } virtual bool isLeftBracket() const { return false; } virtual bool isRightBracket() const { return false; } + virtual bool isEmpty() const { return false; } virtual char XNTChar() const; protected: diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index 667347d46..d0bdac6d4 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -1,4 +1,5 @@ #include +#include "empty_visible_layout.h" extern "C" { #include #include @@ -60,4 +61,22 @@ bool DynamicLayoutHierarchy::addChildAtIndex(ExpressionLayout * child, int index return true; } +void DynamicLayoutHierarchy::removeChildAtIndex(int index, bool deleteAfterRemoval) { + if (deleteAfterRemoval) { + delete m_children[index]; + } else { + const_cast(m_children[index])->setParent(nullptr); + } + m_numberOfChildren--; + if (m_numberOfChildren == 0) { + ExpressionLayout * emptyVisibleLayout = new EmptyVisibleLayout(); + replaceWith(emptyVisibleLayout); + return; + } + for (int j=index; jpointedExpressionLayout() != this || m_parent == nullptr) { + + int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); + if (indexOfPointedExpression >= 0) { + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (indexOfPointedExpression == 0) { + cursor->setPointedExpressionLayout(this); + } else { + cursor->setPointedExpressionLayout(editableChild(indexOfPointedExpression - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } + cursor->performBackspace(); + return; + } + assert(cursor->pointedExpressionLayout() == this); + if (m_parent == nullptr) { return; } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { @@ -223,6 +237,13 @@ void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { } int indexInParent = m_parent->indexOfChild(this); ExpressionLayout * previousParent = m_parent; + if (previousParent->numberOfChildren() == 1) { + ExpressionLayout * newLayout = new EmptyVisibleLayout(); + replaceWith(newLayout, true); + cursor->setPointedExpressionLayout(newLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } previousParent->removeChildAtIndex(indexInParent, true); if (indexInParent < previousParent->numberOfChildren()) { cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent)); diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 6f2f882f1..ec015a18b 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -15,6 +15,21 @@ ExpressionLayout * HorizontalLayout::clone() const { return layout; } +void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { + if (newChild->isEmpty()) { + if (numberOfChildren() > 1) { + removeChildAtIndex(indexOfChild(const_cast(oldChild)), deleteOldChild); + delete newChild; + return; + } + if (m_parent) { + replaceWith(newChild); + return; + } + } + ExpressionLayout::replaceChild(oldChild, newChild, deleteOldChild); +} + bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index b3f1129dd..0390d9804 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -10,6 +10,9 @@ public: using DynamicLayoutHierarchy::DynamicLayoutHierarchy; ExpressionLayout * clone() const override; + /* Hierarchy */ + void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; + /* Navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; From f39b365902dd80ee0d4dfcc9c66b6222d2b3dd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 17:16:20 +0100 Subject: [PATCH 062/257] [poincare] Delete for BaselineRelativeLayout. Change-Id: I7b16c52d7eaa0c5a6398aca9a34a017447593737 --- poincare/include/poincare/expression_layout.h | 1 + .../src/layout/baseline_relative_layout.cpp | 31 +++++++++++++++++++ .../src/layout/baseline_relative_layout.h | 1 + .../src/layout/dynamic_layout_hierarchy.cpp | 4 +-- poincare/src/layout/horizontal_layout.cpp | 24 +++++++++++++- poincare/src/layout/horizontal_layout.h | 5 +++ 6 files changed, 63 insertions(+), 3 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index dcac65950..5ec12341f 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -67,6 +67,7 @@ public: bool moveDownInside(ExpressionLayoutCursor * cursor); /* Other */ + virtual bool isHorizontal() const { return false; } virtual bool isLeftParenthesis() const { return false; } virtual bool isRightParenthesis() const { return false; } virtual bool isLeftBracket() const { return false; } diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index 6947ed585..f2b58bb15 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -1,4 +1,5 @@ #include "baseline_relative_layout.h" +#include "empty_visible_layout.h" #include #include #include @@ -16,6 +17,36 @@ ExpressionLayout * BaselineRelativeLayout::clone() const { return layout; } +void BaselineRelativeLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == indiceLayout()) { + if (m_type == Type::Superscript) { + ExpressionLayout * base = baseLayout(); + ExpressionLayout * pointedLayout = base; + if (base->isHorizontal()) { + pointedLayout = base->editableChild(base->numberOfChildren()-1); + } + if (indiceLayout()->isEmpty()) { + replaceWith(base, true); + } + cursor->setPointedExpressionLayout(pointedLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + assert(m_type == Type::Subscript); + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(new EmptyVisibleLayout(), true); + if (indexInParent == 0) { + cursor->setPointedExpressionLayout(previousParent); + return; + } + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + bool BaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { assert(cursor->pointedExpressionLayout() == this); // Case: Right. diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index 1e72783a8..f0cb1f7a0 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -13,6 +13,7 @@ public: }; BaselineRelativeLayout(ExpressionLayout * base, ExpressionLayout * indice, Type type, bool cloneOperands); ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index d0bdac6d4..4d3fdf6c8 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -68,11 +68,11 @@ void DynamicLayoutHierarchy::removeChildAtIndex(int index, bool deleteAfterRemov const_cast(m_children[index])->setParent(nullptr); } m_numberOfChildren--; - if (m_numberOfChildren == 0) { + /*if (m_numberOfChildren == 0) { ExpressionLayout * emptyVisibleLayout = new EmptyVisibleLayout(); replaceWith(emptyVisibleLayout); return; - } + }*/ for (int j=index; jisEmpty()) { if (numberOfChildren() > 1) { + if (!newChild->hasAncestor(oldChild)) { + delete newChild; + } removeChildAtIndex(indexOfChild(const_cast(oldChild)), deleteOldChild); - delete newChild; return; } if (m_parent) { @@ -27,6 +29,13 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio return; } } + if (newChild->isHorizontal()) { + // Steal the children of the new layout then destroy it. + int indexForInsertion = indexOfChild(const_cast(oldChild)); + mergeChildrenAtIndex(newChild, indexForInsertion + 1); + removeChildAtIndex(indexForInsertion, deleteOldChild); + return; + } ExpressionLayout::replaceChild(oldChild, newChild, deleteOldChild); } @@ -176,6 +185,19 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x, y); } +void HorizontalLayout::mergeChildrenAtIndex(ExpressionLayout * eL, int index) { + int indexOfEL = indexOfChild(eL); + if (indexOfEL >= 0) { + removeChildAtIndex(indexOfEL, false); + } + int numChildren = eL->numberOfChildren(); + for (int i = 0; i < numChildren; i++) { + ExpressionLayout * currentChild = eL->editableChild(0); + eL->removeChildAtIndex(0, false); + addChildAtIndex(currentChild, index+i); + } +} + bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // Prevent looping fom child to parent if (previousPreviousLayout == this) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 0390d9804..2c0bfc6a8 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -18,11 +18,16 @@ public: bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + + /* Other */ + bool isHorizontal() const override { return true; } + protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; + void mergeChildrenAtIndex(ExpressionLayout * eL, int index); // WITHOUT delete. private: bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); int indexOfChild(ExpressionLayout * eL) const; From 8563f24aa2b518b480745bbcf0d97a485a11dbfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 17:32:13 +0100 Subject: [PATCH 063/257] [poincare] Add layout to Conjugate in toolbox. Change-Id: I793a16a7e34e6affe2fe3facd9bd17bee77431d8 --- apps/math_toolbox.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index c76336561..8a8d24182 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -35,12 +35,17 @@ const ToolboxMessageTree calculChildren[4] = { 2), ToolboxMessageTree(I18n::Message::ProductCommandWithArg, I18n::Message::Product, I18n::Message::ProductCommandWithArg)}; +const int pointedLayoutPathConj[] = {0}; const ToolboxMessageTree complexChildren[5] = { ToolboxMessageTree(I18n::Message::AbsCommandWithArg,I18n::Message::ComplexAbsoluteValue, I18n::Message::AbsCommandWithArg), ToolboxMessageTree(I18n::Message::ArgCommandWithArg, I18n::Message::Agument, I18n::Message::ArgCommandWithArg), ToolboxMessageTree(I18n::Message::ReCommandWithArg, I18n::Message::RealPart, I18n::Message::ReCommandWithArg), ToolboxMessageTree(I18n::Message::ImCommandWithArg, I18n::Message::ImaginaryPart, I18n::Message::ImCommandWithArg), - ToolboxMessageTree(I18n::Message::ConjCommandWithArg, I18n::Message::Conjugate, I18n::Message::ConjCommandWithArg)}; + ToolboxMessageTree(I18n::Message::ConjCommandWithArg, I18n::Message::Conjugate, I18n::Message::ConjCommandWithArg, nullptr, 0, + new ConjugateLayout( + new EmptyVisibleLayout()), + const_cast(&pointedLayoutPathConj[0]), + 1)}; const ToolboxMessageTree probabilityChildren[2] = { ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommandWithArg), From 7ce93eb847caba725a523c5989b62f71f31447b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 21 Dec 2017 17:32:39 +0100 Subject: [PATCH 064/257] [poincare] Delete for ConjugateLayout. Change-Id: I065a3a3b90f1e7d533ba54ddb4aad0a7df70ac87 --- poincare/src/layout/conjugate_layout.cpp | 17 +++++++++++++++++ poincare/src/layout/conjugate_layout.h | 1 + 2 files changed, 18 insertions(+) diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index 19957fe20..5e74f9b21 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -13,6 +13,23 @@ ExpressionLayout * ConjugateLayout::clone() const { return layout; } +void ConjugateLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == operandLayout()) { + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(operandLayout(), true); + if (indexInParent == 0) { + cursor->setPointedExpressionLayout(previousParent); + return; + } + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the operand. // Move Left. diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index c4b4454df..366c824a5 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -9,6 +9,7 @@ class ConjugateLayout : public StaticLayoutHierarchy<1> { public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: From 2d40e35fe8a12501ceea1b224d17cd1e74020a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 10:01:03 +0100 Subject: [PATCH 065/257] [poincare] Delete for FractionLayout. Change-Id: Ifbbe5c434d278e8223ada3d368c1e948712567d2 --- poincare/src/layout/fraction_layout.cpp | 72 +++++++++++++++++++++++ poincare/src/layout/fraction_layout.h | 1 + poincare/src/layout/horizontal_layout.cpp | 8 +++ poincare/src/layout/horizontal_layout.h | 1 + 4 files changed, 82 insertions(+) diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index b642671c1..671643e30 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -1,4 +1,6 @@ #include "fraction_layout.h" +#include "empty_visible_layout.h" +#include "horizontal_layout.h" #include #include #include @@ -11,6 +13,76 @@ ExpressionLayout * FractionLayout::clone() const { return layout; } +void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // If the cursor is on the left of the denominator, replace the fraction with + // a horizontal juxtaposition of the numerator and the denominator. + if (cursor->pointedExpressionLayout() == denominatorLayout()) { + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (numeratorLayout()->isEmpty()) { + if (denominatorLayout()->isEmpty()) { + // If the numerator and the denominator are empty, replace the fraction + // with an empty layout. + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(new EmptyVisibleLayout(), true); + // Place the cursor on the right of the left brother ofthe fraction if + // there is one. + if (indexInParent > 0) { + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + // Else place the cursor on the Left of the parent. + cursor->setPointedExpressionLayout(previousParent); + return; + } + // If the numerator is empty but not the denominator, replace the fraction + // with its denominator. Place the cursor on the left of the denominator. + ExpressionLayout * nextPointedLayout = denominatorLayout(); + if (denominatorLayout()->isHorizontal()) { + nextPointedLayout = denominatorLayout()->editableChild(0); + } + replaceWith(denominatorLayout(), true); + cursor->setPointedExpressionLayout(nextPointedLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + // If the denominator is empty but not the numerator, replace the fraction + // with the numerator and place the cursor on its right. + if (denominatorLayout()->isEmpty()) { + ExpressionLayout * nextPointedLayout = numeratorLayout(); + if (numeratorLayout()->isHorizontal()) { + nextPointedLayout = numeratorLayout()->editableChild(numeratorLayout()->numberOfChildren() - 1); + } + replaceWith(numeratorLayout(), true); + cursor->setPointedExpressionLayout(nextPointedLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + // If neither the numerator nor the denominator are empty, replace the + // fraction with a juxtaposition of the numerator and denominator. Place the + // cursor in the middle of the juxtaposition, which is right of the + // numerator. + ExpressionLayout * nextPointedLayout = numeratorLayout(); + if (numeratorLayout()->isHorizontal()) { + nextPointedLayout = numeratorLayout()->editableChild(numeratorLayout()->numberOfChildren() - 1); + } + ExpressionLayout * numerator = numeratorLayout(); + ExpressionLayout * denominator = denominatorLayout(); + detachChild(numerator); + detachChild(denominator); + HorizontalLayout * newLayout = new HorizontalLayout(); + newLayout->addOrMergeChildAtIndex(denominator, 0); + newLayout->addOrMergeChildAtIndex(numerator, 0); + // Add the denominator before the numerator to have the right order. + replaceWith(newLayout, true); + cursor->setPointedExpressionLayout(nextPointedLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the numerator or the denominator. // Go Left of the fraction. diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 0bbb85ac3..296b31ccc 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -9,6 +9,7 @@ class FractionLayout : public StaticLayoutHierarchy<2> { public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index b8a4891fc..cd94aa8d8 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -39,6 +39,14 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio ExpressionLayout::replaceChild(oldChild, newChild, deleteOldChild); } +void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index) { + if (eL->isHorizontal()) { + mergeChildrenAtIndex(eL, index); + return; + } + addChildAtIndex(eL, index); +} + bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 2c0bfc6a8..87cf0bd33 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -12,6 +12,7 @@ public: /* Hierarchy */ void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; + void addOrMergeChildAtIndex(ExpressionLayout * eL, int index); /* Navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; From 2c261f7ea93f9b410fc6b223853f833d562b3292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 11:07:50 +0100 Subject: [PATCH 066/257] [poincare] Cleaned duplicate indexOfChild() method. Change-Id: I03fc6cd4e1afe45f609828ae0e32865c8510bf14 --- poincare/src/layout/expression_layout.cpp | 3 +++ poincare/src/layout/horizontal_layout.cpp | 12 ------------ poincare/src/layout/horizontal_layout.h | 1 - 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 9750c14f8..5fdae5833 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -98,6 +98,9 @@ const ExpressionLayout * ExpressionLayout::child(int i) const { } int ExpressionLayout::indexOfChild(ExpressionLayout * child) const { + if (child == nullptr) { + return -1; + } for (int i = 0; i < numberOfChildren(); i++) { if (children()[i] == child) { return i; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index cd94aa8d8..303fb23db 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -250,16 +250,4 @@ bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direct return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } -int HorizontalLayout::indexOfChild(ExpressionLayout * eL) const { - if (eL == nullptr) { - return -1; - } - for (int i = 0; i < numberOfChildren(); i++) { - if (child(i) == eL) { - return i; - } - } - return -1; -} - } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 87cf0bd33..7c58113b9 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -31,7 +31,6 @@ protected: void mergeChildrenAtIndex(ExpressionLayout * eL, int index); // WITHOUT delete. private: bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); - int indexOfChild(ExpressionLayout * eL) const; }; } From fccd9b484b810992fa0bde800cac5dd53a4e82d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 13:19:15 +0100 Subject: [PATCH 067/257] [poincare] Added UneditableHorizontalTrioLayout. Change-Id: Ifd9fd6a0a0714853c1a8cd428b65076b704a8211 --- poincare/Makefile | 1 + poincare/include/poincare_layouts.h | 1 + .../uneditable_horizontal_trio_layout.cpp | 156 ++++++++++++++++++ .../uneditable_horizontal_trio_layout.h | 42 +++++ 4 files changed, 200 insertions(+) create mode 100644 poincare/src/layout/uneditable_horizontal_trio_layout.cpp create mode 100644 poincare/src/layout/uneditable_horizontal_trio_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index d20f96750..b49e17a2c 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -114,6 +114,7 @@ objs += $(addprefix poincare/src/layout/,\ static_layout_hierarchy.o\ string_layout.o\ sum_layout.o\ + uneditable_horizontal_trio_layout.o\ uneditable_parenthesis_left_layout.o\ uneditable_parenthesis_right_layout.o\ ) diff --git a/poincare/include/poincare_layouts.h b/poincare/include/poincare_layouts.h index f3d71feae..4c339e285 100644 --- a/poincare/include/poincare_layouts.h +++ b/poincare/include/poincare_layouts.h @@ -28,5 +28,6 @@ #include #include #include +#include #endif diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.cpp b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp new file mode 100644 index 000000000..15b03993c --- /dev/null +++ b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp @@ -0,0 +1,156 @@ +#include "uneditable_horizontal_trio_layout.h" +#include "empty_visible_layout.h" +#include +extern "C" { +#include +} + +namespace Poincare { + +ExpressionLayout * UneditableHorizontalTrioLayout::clone() const { + UneditableHorizontalTrioLayout * layout = new UneditableHorizontalTrioLayout( + const_cast(this)->leftLayout(), + const_cast(this)->centerLayout(), + const_cast(this)->rightLayout(), + true); + return layout; +} + +void UneditableHorizontalTrioLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(new EmptyVisibleLayout(), true); + if (indexInParent == 0) { + cursor->setPointedExpressionLayout(previousParent); + return; + } + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + +bool UneditableHorizontalTrioLayout::moveLeft(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == centerLayout()) { + // Case: Center layout. + // Go Left. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + // Case: Right. + // Go Right of the center layout's last child if it has one, else go Right + // of the center layout. + ExpressionLayout * grandChild = centerLayout()->editableChild(centerLayout()->numberOfChildren()-1); + if (grandChild != nullptr) { + cursor->setPointedExpressionLayout(grandChild); + return true; + } + cursor->setPointedExpressionLayout(centerLayout()); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +bool UneditableHorizontalTrioLayout::moveRight(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == centerLayout()) { + // Case: Center layout. + // Go Right. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + // Case: Left. + // Go Left of the center layout's first child if it has one, else go Left of + // the center layout. + ExpressionLayout * grandChild = centerLayout()->editableChild(0); + if (grandChild != nullptr) { + cursor->setPointedExpressionLayout(grandChild); + return true; + } + cursor->setPointedExpressionLayout(centerLayout()); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + +void UneditableHorizontalTrioLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { +} + +KDSize UneditableHorizontalTrioLayout::computeSize() { + // TODO: This code is duplicated from horizontal_layout.cpp. + KDCoordinate totalWidth = 0; + int i = 0; + KDCoordinate max_under_baseline = 0; + KDCoordinate max_above_baseline = 0; + while (ExpressionLayout * c = editableChild(i++)) { + KDSize childSize = c->size(); + totalWidth += childSize.width(); + if (childSize.height() - c->baseline() > max_under_baseline) { + max_under_baseline = childSize.height() - c->baseline() ; + } + if (c->baseline() > max_above_baseline) { + max_above_baseline = c->baseline(); + } + } + return KDSize(totalWidth, max_under_baseline + max_above_baseline); +} + +void UneditableHorizontalTrioLayout::computeBaseline() { + // TODO: This code is duplicated from horizontal_layout.cpp. + m_baseline = 0; + for (int i = 0; i < numberOfChildren(); i++) { + if (editableChild(i)->baseline() > m_baseline) { + m_baseline = editableChild(i)->baseline(); + } + } + m_baselined = true; +} + +KDPoint UneditableHorizontalTrioLayout::positionOfChild(ExpressionLayout * child) { + // TODO: This code is duplicated from horizontal_layout.cpp. + KDCoordinate x = 0; + KDCoordinate y = 0; + int index = indexOfChild(child); + if (index > 0) { + ExpressionLayout * previousChild = editableChild(index-1); + assert(previousChild != nullptr); + x = previousChild->origin().x() + previousChild->size().width(); + } + y = baseline() - child->baseline(); + return KDPoint(x, y); +} + +ExpressionLayout * UneditableHorizontalTrioLayout::leftLayout() { + return editableChild(0); +} + +ExpressionLayout * UneditableHorizontalTrioLayout::centerLayout() { + return editableChild(1); +} + +ExpressionLayout * UneditableHorizontalTrioLayout::rightLayout() { + return editableChild(2); +} + +} diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.h b/poincare/src/layout/uneditable_horizontal_trio_layout.h new file mode 100644 index 000000000..d0a356c14 --- /dev/null +++ b/poincare/src/layout/uneditable_horizontal_trio_layout.h @@ -0,0 +1,42 @@ +#ifndef POINCARE_UNEDITABLE_HORIZONTAL_TRIO_LAYOUT_H +#define POINCARE_UNEDITABLE_HORIZONTAL_TRIO_LAYOUT_H + +#include + +namespace Poincare { + +/* UneditableHorizontalTrioLayout has 3 children: a left and a right layout + * (usually parentheses or brackets), and a central layout. + * The cursor can only be: + * - Left or Right of the UneditableHorizontalTrioLayout, + * - Left or Right of the central layout if it is not an horizontal layout, + * - Inside the central layout if it is an horizontal layout. + * This way, the lateral children of an UneditableHorizontalTrioLayout cannot be + * edited, and it it will always have only 3 children. + * This layout can be used to create binomial coefficient layouts, matrix + * layouts or the argument of sum and product layouts. */ + +class UneditableHorizontalTrioLayout : public StaticLayoutHierarchy<3> { +public: + using StaticLayoutHierarchy::StaticLayoutHierarchy; + ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; + + /* Navigation */ + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; + +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + KDSize computeSize() override; + void computeBaseline() override; + KDPoint positionOfChild(ExpressionLayout * child) override; +private: + ExpressionLayout * leftLayout(); + ExpressionLayout * centerLayout(); + ExpressionLayout * rightLayout(); +}; + +} + +#endif From 6f81a6cceb44e7f6ae61182507bbd552f4349c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 10:30:54 +0100 Subject: [PATCH 068/257] [apps] Added layout for binomial coefficient in toolbox. Change-Id: I43bd6ff8a2f812d8bf524d60b559d1b227c0c79f --- apps/math_toolbox.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 8a8d24182..23eff77f3 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -47,8 +47,18 @@ const ToolboxMessageTree complexChildren[5] = { const_cast(&pointedLayoutPathConj[0]), 1)}; +const int pointedLayoutPathBinomial[] = {1,0}; const ToolboxMessageTree probabilityChildren[2] = { - ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommandWithArg), + ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommandWithArg, nullptr, 0, + new UneditableHorizontalTrioLayout( + new ParenthesisLeftLayout(), + new GridLayout(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2( + new EmptyVisibleLayout(), + new EmptyVisibleLayout())), + 2, 1, false), + new ParenthesisRightLayout()), + const_cast(&pointedLayoutPathBinomial[0]), + 2), ToolboxMessageTree(I18n::Message::PermuteCommandWithArg, I18n::Message::Permutation, I18n::Message::PermuteCommandWithArg)}; const ToolboxMessageTree arithmeticChildren[4] = { From 48e20abe73f828c21772fffdcff387fa806ecd2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 13:28:16 +0100 Subject: [PATCH 069/257] [poincare] Navigation and delete in GridLayout. Change-Id: I8357150d9f15dd003ab97e09981d164d57235739 --- poincare/src/layout/expression_layout.cpp | 3 ++- poincare/src/layout/grid_layout.cpp | 31 ++++++++++++++++++++--- poincare/src/layout/grid_layout.h | 1 + poincare/src/layout/horizontal_layout.cpp | 12 +++++++++ poincare/src/layout/horizontal_layout.h | 1 + 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 5fdae5833..3b5bc8316 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -127,7 +127,8 @@ bool ExpressionLayout::hasAncestor(const ExpressionLayout * e) const { void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { if (m_parent) { int brotherIndex = cursor->position() == ExpressionLayoutCursor::Position::Left ? m_parent->indexOfChild(this) : m_parent->indexOfChild(this) + 1; - if (m_parent->addChildAtIndex(brother, brotherIndex)) { + if (m_parent->isHorizontal()) { + m_parent->addChildAtIndex(brother, brotherIndex); return; } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 9821533de..2ad50f177 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -1,4 +1,5 @@ #include "grid_layout.h" +#include "empty_visible_layout.h" #include extern "C" { #include @@ -19,6 +20,30 @@ ExpressionLayout * GridLayout::clone() const { return layout; } +void GridLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // If the cursor is on the left of the grid, delete the grid and its parent: A + // grid only exists for now in binomial coefficient and in matrices, and we + // want to delete their parentheses or brackets too. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); + if (indexOfPointedExpression >= 0 && childIsLeftOfGrid(indexOfPointedExpression)) { + assert(m_parent != nullptr); + assert(m_parent->parent() != nullptr); + ExpressionLayout * grandParent = const_cast(m_parent->parent()); + int indexInGrandParent = grandParent->indexOfChild(m_parent); + m_parent->replaceWith(new EmptyVisibleLayout(), true); + if (indexInGrandParent == 0) { + cursor->setPointedExpressionLayout(grandParent); + return; + } + cursor->setPointedExpressionLayout(grandParent->editableChild(indexInGrandParent-1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + } + ExpressionLayout::backspaceAtCursor(cursor); +} + bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go to the last entry. @@ -38,7 +63,7 @@ bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go Left of the grid cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; + return m_parent->moveLeft(cursor); } // Case: Left of another child. // Go Right of its brother on the left. @@ -72,10 +97,10 @@ bool GridLayout::moveRight(ExpressionLayoutCursor * cursor) { if (childIndex >- 1 && cursor->position() == ExpressionLayoutCursor::Position::Right) { if (childIsRightOfGrid(childIndex)) { // Case: Right of a child on the right of the grid. - // Go Right of the grid. + // Go Right of the grid and move Right. cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; + return m_parent->moveRight(cursor); } // Case: Right of another child. // Go Left of its brother on the right. diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 379fd642f..e2275511b 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -9,6 +9,7 @@ class GridLayout : public DynamicLayoutHierarchy { public: GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands); ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; /* Navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 303fb23db..38d125e6c 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -15,6 +15,18 @@ ExpressionLayout * HorizontalLayout::clone() const { return layout; } +void HorizontalLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // If the cursor was pointing left of the first child of the horizontal + // layout, make it point at the horizontal layout itself. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); + if (indexOfPointedExpression == 0) { + cursor->setPointedExpressionLayout(this); + } + } + ExpressionLayout::backspaceAtCursor(cursor); +} + void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { if (newChild->isEmpty()) { if (numberOfChildren() > 1) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 7c58113b9..a3aef1244 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -9,6 +9,7 @@ class HorizontalLayout : public DynamicLayoutHierarchy { public: using DynamicLayoutHierarchy::DynamicLayoutHierarchy; ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; /* Hierarchy */ void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; From 3baf483a8668a49c7bf288d193564662ed9fe781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 13:46:43 +0100 Subject: [PATCH 070/257] [poincare] Fixed StringLayout navigation bug. Change-Id: I73b99b6a4302b4487357a7e1cef563b43743554c --- poincare/src/layout/string_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index adea25f99..c31c31d71 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -32,7 +32,7 @@ bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { // string layout, for instance left of "n=" in a Sum layout. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { int indexOfThis = m_parent->indexOfChild(this); - if (m_parent->editableChild(indexOfThis-1) != nullptr) { + if (indexOfThis > 1) { cursor->setPointedExpressionLayout(m_parent->editableChild(indexOfThis-1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; From 3415dde6c7b015143d39499d7ed12f7bda099729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 13:47:30 +0100 Subject: [PATCH 071/257] [poincare] Use uneditableHorizontalTrioLayout in SumLayout. Change-Id: I67c5c59d8cdb50506a105dd0929eaa1bc79bca1c --- poincare/src/layout/sum_layout.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index ef3027cbf..82737c7bb 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -1,7 +1,8 @@ #include "sum_layout.h" #include "horizontal_layout.h" -#include "uneditable_parenthesis_left_layout.h" -#include "uneditable_parenthesis_right_layout.h" +#include "parenthesis_left_layout.h" +#include "parenthesis_right_layout.h" +#include "uneditable_horizontal_trio_layout.h" #include #include #include @@ -27,18 +28,12 @@ const uint8_t symbolPixel[SumLayout::k_symbolHeight][SumLayout::k_symbolWidth] = }; SumLayout::SumLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands) : - SequenceLayout(lowerBound, upperBound, argument, cloneOperands) + SequenceLayout() { - UneditableParenthesisLeftLayout * parLeft = new UneditableParenthesisLeftLayout(); - UneditableParenthesisRightLayout * parRight = new UneditableParenthesisRightLayout(); - HorizontalLayout * horLayout = new HorizontalLayout(); - ExpressionLayout * argLayout = editableChild(2); - // We cannot call argument() because it is overrided to handle completely - // built SumLayouts, not SumLayouts in construction. - argLayout->replaceWith(horLayout, false); - horLayout->addChildAtIndex(parLeft, 0); - horLayout->addChildAtIndex(argLayout, 1); - horLayout->addChildAtIndex(parRight, 2); + ParenthesisLeftLayout * parLeft = new ParenthesisLeftLayout(); + ParenthesisRightLayout * parRight = new ParenthesisRightLayout(); + UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, false); + build(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray3(lowerBound, upperBound, horLayout)), 3, false); } ExpressionLayout * SumLayout::clone() const { From abdd85ddff3ce71fe003ac316a12587dc976b108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 14:33:33 +0100 Subject: [PATCH 072/257] [poincare] Delete for BaselineRelativeLayout (Editable or not). Change-Id: I86fb27c35859d742ff26f55397281c2585960b08 --- .../src/layout/baseline_relative_layout.cpp | 19 ++----- .../editable_baseline_relative_layout.cpp | 55 +++++++++++++++++++ .../editable_baseline_relative_layout.h | 1 + 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index f2b58bb15..725898139 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -18,21 +18,10 @@ ExpressionLayout * BaselineRelativeLayout::clone() const { } void BaselineRelativeLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - if (cursor->pointedExpressionLayout() == indiceLayout()) { - if (m_type == Type::Superscript) { - ExpressionLayout * base = baseLayout(); - ExpressionLayout * pointedLayout = base; - if (base->isHorizontal()) { - pointedLayout = base->editableChild(base->numberOfChildren()-1); - } - if (indiceLayout()->isEmpty()) { - replaceWith(base, true); - } - cursor->setPointedExpressionLayout(pointedLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - assert(m_type == Type::Subscript); + if (cursor->pointedExpressionLayout() == indiceLayout() + || (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right)) + { ExpressionLayout * previousParent = m_parent; int indexInParent = previousParent->indexOfChild(this); replaceWith(new EmptyVisibleLayout(), true); diff --git a/poincare/src/layout/editable_baseline_relative_layout.cpp b/poincare/src/layout/editable_baseline_relative_layout.cpp index e5b0d29c1..9e72033d1 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.cpp +++ b/poincare/src/layout/editable_baseline_relative_layout.cpp @@ -1,4 +1,5 @@ #include "editable_baseline_relative_layout.h" +#include "empty_visible_layout.h" #include #include #include @@ -10,6 +11,60 @@ ExpressionLayout * EditableBaselineRelativeLayout::clone() const { return layout; } +void EditableBaselineRelativeLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == indiceLayout()) { + if (m_type == Type::Superscript) { + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + ExpressionLayout * base = baseLayout(); + ExpressionLayout * pointedLayout = base; + if (base->isHorizontal()) { + pointedLayout = base->editableChild(base->numberOfChildren()-1); + } + if (indiceLayout()->isEmpty()) { + if (baseLayout()->isEmpty()) { + // Case: Empty base and indice. + // Replace with an empty layout. + int indexInParent = m_parent->indexOfChild(this); + if (indexInParent == 0) { + pointedLayout = m_parent; + replaceWith(base, true); + cursor->setPointedExpressionLayout(pointedLayout); + return; + } + pointedLayout = m_parent->editableChild(indexInParent - 1); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + replaceWith(base, true); + cursor->setPointedExpressionLayout(pointedLayout); + return; + } + // Case: Empty indice only. + // Replace with the base. + replaceWith(base, true); + cursor->setPointedExpressionLayout(pointedLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + // Case: Non-empty indice. + // Move to the base. + cursor->setPointedExpressionLayout(pointedLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + assert(m_type == Type::Subscript); + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(new EmptyVisibleLayout(), true); + if (indexInParent == 0) { + cursor->setPointedExpressionLayout(previousParent); + return; + } + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + bool EditableBaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the indice. // Go from the indice to the base. diff --git a/poincare/src/layout/editable_baseline_relative_layout.h b/poincare/src/layout/editable_baseline_relative_layout.h index 22c5c968f..af60ba3b9 100644 --- a/poincare/src/layout/editable_baseline_relative_layout.h +++ b/poincare/src/layout/editable_baseline_relative_layout.h @@ -9,6 +9,7 @@ class EditableBaselineRelativeLayout : public BaselineRelativeLayout { public: using BaselineRelativeLayout::BaselineRelativeLayout; ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; From 5d229b2ab0b8b338a65ffb44302600657376d1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 14:34:16 +0100 Subject: [PATCH 073/257] [poincare] Fixed StringLayout navigation. Change-Id: Ib89cf550bb22c3216db6364566d5b08abe9d3889 --- poincare/src/layout/string_layout.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index c31c31d71..55f638fce 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -37,11 +37,9 @@ bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } - if (m_parent->parent()) { - cursor->setPointedExpressionLayout(const_cast(m_parent->parent())); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } + cursor->setPointedExpressionLayout(m_parent); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; } // Case: Left. // Ask the parent. From 527fd9feabb161373a1c5242d472478ee6e0b803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 14:42:38 +0100 Subject: [PATCH 074/257] [poincare] Fixed FractionLayout delete. Change-Id: Idb8e5c4d71cf00c796a82ef1f41ea63b224752ba --- poincare/src/layout/fraction_layout.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 671643e30..aa95c224e 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -80,6 +80,12 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { cursor->setPosition(ExpressionLayoutCursor::Position::Right); return; } + // If the cursor is on the left of the numerator, move Left of the fraction. + if (cursor->pointedExpressionLayout() == numeratorLayout()) { + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + cursor->setPointedExpressionLayout(this); + return; + } ExpressionLayout::backspaceAtCursor(cursor); } From 30b75bfef69faf8318435f42b7c5afbfc21279c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 14:50:39 +0100 Subject: [PATCH 075/257] [poincare] Delete for EmptyVisibleLayout. Change-Id: Iceda680d153ddf622a39a4f46274ce038401ca61 --- poincare/src/layout/empty_visible_layout.cpp | 12 ++++++++++++ poincare/src/layout/empty_visible_layout.h | 1 + 2 files changed, 13 insertions(+) diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index f4291ef24..a7ac20513 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -15,6 +15,18 @@ ExpressionLayout * EmptyVisibleLayout::clone() const { return layout; } +void EmptyVisibleLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->backspaceAtCursor(cursor); + } +} + bool EmptyVisibleLayout::moveLeft(ExpressionLayoutCursor * cursor) { assert(cursor->pointedExpressionLayout() == this); // Case: Right. diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index 1a549d9ce..65714d0ac 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -10,6 +10,7 @@ class EmptyVisibleLayout : public EmptyLayout { public: EmptyVisibleLayout(); ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; protected: From 2a3dc0a83a6d62d2f3b769a60a5bc55301de0bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 15:23:41 +0100 Subject: [PATCH 076/257] [poincare] Delete for integral layouts. Change-Id: I830b759108f857825a576d1dc37b2f85add7688a --- poincare/src/layout/integral_layout.cpp | 48 +++++++++++++++++++++++-- poincare/src/layout/integral_layout.h | 1 + 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 59164adb7..00031c26e 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -24,6 +24,49 @@ ExpressionLayout * IntegralLayout::clone() const { return layout; } +void IntegralLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // Case: Left the upper bound, lower bound or argument. + // Delete the integral, keep the integrand. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && ((upperBoundLayout() + && cursor->pointedExpressionLayout() == upperBoundLayout()) + || (lowerBoundLayout() + && cursor->pointedExpressionLayout() == lowerBoundLayout()) + || cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Left))) + { + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + ExpressionLayout * dxLayout = integrandLayout()->editableChild(integrandLayout()->numberOfChildren()-1); + replaceWith(integrandLayout(), true); + // Remove "dx" + int indexOfdx = previousParent->indexOfChild(dxLayout); + if (indexOfdx >= 0) { + previousParent->removeChildAtIndex(indexOfdx, true); + } + // Place the cursor on the right of the left brother of the integral if + // there is one. + if (indexInParent > 0) { + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + // Else place the cursor on the Left of the parent. + cursor->setPointedExpressionLayout(previousParent); + return; + } + // If the cursor is on the right, move to the integrand. + if (cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Right)) { + assert(integrandLayout()->numberOfChildren() > 1); + ExpressionLayout * layoutLeftOfdx = integrandLayout()->editableChild(integrandLayout()->numberOfChildren()-2); + cursor->setPointedExpressionLayout(layoutLeftOfdx); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + if (m_parent) { + return m_parent->backspaceAtCursor(cursor); + } +} + bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left the upper or lower bound. // Go Left of the integral. @@ -49,10 +92,11 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { } assert(cursor->pointedExpressionLayout() == this); // Case: Right of the integral. - // Go Right of the integrand, Left of "dx". + // Go Left of "dx". if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(integrandLayout() != nullptr); - cursor->setPointedExpressionLayout(integrandLayout()->editableChild(integrandLayout()->numberOfChildren()-2)); + cursor->setPointedExpressionLayout(integrandLayout()->editableChild(integrandLayout()->numberOfChildren() - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 67b0e5750..70d07eed4 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -11,6 +11,7 @@ public: constexpr static KDCoordinate k_symbolWidth = 4; using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; From df77faec28179751ef9644141114410edd84a9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 15:33:05 +0100 Subject: [PATCH 077/257] [poincare] Delete for RootLayout. Change-Id: I4555e94bfa887e63aa0a3e11eff8f3043b5803e7 --- poincare/src/layout/nth_root_layout.cpp | 43 +++++++++++++++++++++++++ poincare/src/layout/nth_root_layout.h | 1 + 2 files changed, 44 insertions(+) diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 709e3df2f..005c67b27 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -21,6 +21,49 @@ ExpressionLayout * NthRootLayout::clone() const { return layout; } +void NthRootLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // Case: Left the index. + // Move Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && cursor->pointedExpressionLayout() == indexLayout()) + { + cursor->setPointedExpressionLayout(this); + return; + } + // Case: Left the radicand. + // Delete the root, keep the radicand. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && cursor->pointedExpressionLayout() == radicandLayout()) + { + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(radicandLayout()); + // Place the cursor on the right of the left brother of the root if there is + // one. + if (indexInParent > 0) { + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + // Else place the cursor on the Left of the parent. + cursor->setPointedExpressionLayout(previousParent); + return; + } + // Case: Right. + // Move to the radicand. + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() ==ExpressionLayoutCursor::Position::Right) { + cursor->setPointedExpressionLayout(radicandLayout()); + return; + } + // Case: Left. + // Ask the parent. + assert(cursor->position() ==ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->backspaceAtCursor(cursor); + } +} + bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the radicand. // Go the index if there is one, else go Left of the root. diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index 5c1ad77d9..d5cceb77f 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -11,6 +11,7 @@ public: constexpr static KDCoordinate k_leftRadixWidth = 5; using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; From af232a8678c2ae57e1e16301d8f06db7a5a1ec81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 16:34:00 +0100 Subject: [PATCH 078/257] [poincare] Delete in SequenceLayout. Change-Id: Ie530516fcddde4d7a93d89993bab5cab30927faa --- poincare/src/layout/sequence_layout.cpp | 69 +++++++++++-- poincare/src/layout/sequence_layout.h | 3 +- poincare/src/layout/sum_layout.cpp | 128 ------------------------ poincare/src/layout/sum_layout.h | 7 +- 4 files changed, 61 insertions(+), 146 deletions(-) diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 708b7e1af..610324ca9 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -1,11 +1,60 @@ #include "sequence_layout.h" -#include "string_layout.h" +#include "parenthesis_left_layout.h" +#include "parenthesis_right_layout.h" +#include "uneditable_horizontal_trio_layout.h" #include #include #include namespace Poincare { +SequenceLayout::SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands) : + StaticLayoutHierarchy() +{ + ParenthesisLeftLayout * parLeft = new ParenthesisLeftLayout(); + ParenthesisRightLayout * parRight = new ParenthesisRightLayout(); + UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, cloneOperands); + build(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray3(lowerBound, upperBound, horLayout)), 3, cloneOperands); +} + +void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // Case: Left of the bounds or of the argument. + // Delete the sequence, keep the argument. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && ((lowerBoundLayout() + && cursor->pointedExpressionLayout() == lowerBoundLayout()) + || (upperBoundLayout() + && cursor->pointedExpressionLayout() == upperBoundLayout()) + || cursor->pointedExpressionLayout() == argumentLayout())) + { + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(argumentLayout(), true); + // Place the cursor on the right of the left brother of the sequence if + // there is one. + if (indexInParent > 0) { + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + // Else place the cursor on the Left of the parent. + cursor->setPointedExpressionLayout(previousParent); + return; + } + // Case: Right. + // Move inside the argument. + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(argumentLayout()); + return; + } + // Case: Left. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + m_parent->backspaceAtCursor(cursor); +} + bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the bounds. // Go Left of the sequence. @@ -22,7 +71,7 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go Right of the lower bound. if (cursor->position() == ExpressionLayoutCursor::Position::Left && argumentLayout() - && cursor->pointedExpressionLayout() == argumentLayout()) + && cursor->pointedExpressionLayout() == editableChild(2)) { assert(lowerBoundLayout() != nullptr); cursor->setPointedExpressionLayout(lowerBoundLayout()->editableChild(1)); @@ -35,7 +84,7 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(argumentLayout() != nullptr); cursor->setPointedExpressionLayout(argumentLayout()); - return argumentLayout()->moveLeft(cursor); + return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); // Case: Left. @@ -64,13 +113,11 @@ bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. if (cursor->position() == ExpressionLayoutCursor::Position::Right && argumentLayout() - && cursor->pointedExpressionLayout() == argumentLayout()) + && cursor->pointedExpressionLayout() == editableChild(2)) { cursor->setPointedExpressionLayout(this); - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; } assert(cursor->pointedExpressionLayout() == this); // Case: Left. @@ -133,11 +180,11 @@ ExpressionLayout * SequenceLayout::lowerBoundLayout() { } ExpressionLayout * SequenceLayout::argumentLayout() { - return editableChild(2); + return editableChild(2)->editableChild(1); } KDSize SequenceLayout::computeSize() { - KDSize argumentSize = argumentLayout()->size(); + KDSize argumentSize = editableChild(2)->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( @@ -162,7 +209,7 @@ KDPoint SequenceLayout::positionOfChild(ExpressionLayout * child) { } else if (child == upperBoundLayout()) { x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSize.width()-upperBoundSize.width())/2); y = m_baseline - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); - } else if (child == argumentLayout()) { + } else if (child == editableChild(2)) { x = max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin; y = m_baseline - argumentLayout()->baseline(); } else { diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 7df9ce767..ca53827d8 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -9,7 +9,8 @@ class SequenceLayout : public StaticLayoutHierarchy<3> { public: constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; - using StaticLayoutHierarchy::StaticLayoutHierarchy; + SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands); + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index 82737c7bb..c59ccb496 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -1,8 +1,4 @@ #include "sum_layout.h" -#include "horizontal_layout.h" -#include "parenthesis_left_layout.h" -#include "parenthesis_right_layout.h" -#include "uneditable_horizontal_trio_layout.h" #include #include #include @@ -27,105 +23,11 @@ const uint8_t symbolPixel[SumLayout::k_symbolHeight][SumLayout::k_symbolWidth] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, }; -SumLayout::SumLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands) : - SequenceLayout() -{ - ParenthesisLeftLayout * parLeft = new ParenthesisLeftLayout(); - ParenthesisRightLayout * parRight = new ParenthesisRightLayout(); - UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, false); - build(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray3(lowerBound, upperBound, horLayout)), 3, false); -} - ExpressionLayout * SumLayout::clone() const { SumLayout * layout = new SumLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->argumentLayout(), true); return layout; } -ExpressionLayout * SumLayout::argumentLayout() { - return editableChild(2)->editableChild(1); -} - -bool SumLayout::moveLeft(ExpressionLayoutCursor * cursor) { - // Case: Left of the bounds. - // Go Left of the sum. - if (cursor->position() == ExpressionLayoutCursor::Position::Left - && ((lowerBoundLayout() - && cursor->pointedExpressionLayout() == lowerBoundLayout()) - || (upperBoundLayout() - && cursor->pointedExpressionLayout() == upperBoundLayout()))) - { - cursor->setPointedExpressionLayout(this); - return true; - } - // Case: Left of the argument. - // Go Right of the lower bound. - if (cursor->position() == ExpressionLayoutCursor::Position::Left - && argumentLayout() - && cursor->pointedExpressionLayout() == editableChild(2)) - { - assert(lowerBoundLayout() != nullptr); - cursor->setPointedExpressionLayout(lowerBoundLayout()->editableChild(1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - assert(cursor->pointedExpressionLayout() == this); - // Case: Right. - // Go to the argument and move Left. - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(argumentLayout() != nullptr); - cursor->setPointedExpressionLayout(argumentLayout()); - return true; - } - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - // Case: Left. - // Ask the parent. - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; -} - -bool SumLayout::moveRight(ExpressionLayoutCursor * cursor) { - // Case: Right of the bounds. - // Go Left of the argument. - if (cursor->position() == ExpressionLayoutCursor::Position::Right - && ((lowerBoundLayout() - && cursor->pointedExpressionLayout() == lowerBoundLayout()) - || (upperBoundLayout() - && cursor->pointedExpressionLayout() == upperBoundLayout()))) - { - assert(argumentLayout() != nullptr); - cursor->setPointedExpressionLayout(argumentLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - // Case: Right of the argument. - // Ask the parent. - if (cursor->position() == ExpressionLayoutCursor::Position::Right - && argumentLayout() - && cursor->pointedExpressionLayout() == editableChild(2)) - { - cursor->setPointedExpressionLayout(this); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - assert(cursor->pointedExpressionLayout() == this); - // Case: Left. - // Go to the upper bound. - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(upperBoundLayout() != nullptr); - cursor->setPointedExpressionLayout(upperBoundLayout()); - return true; - } - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - // Case: Right. - // Ask the parent. - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; -} - void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize upperBoundSize = upperBoundLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); @@ -136,34 +38,4 @@ void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDCo ctx->blendRectWithMask(symbolFrame, expressionColor, (const uint8_t *)symbolPixel, (KDColor *)workingBuffer); } -KDSize SumLayout::computeSize() { - KDSize argumentSize = editableChild(2)->size(); - KDSize lowerBoundSize = lowerBoundLayout()->size(); - KDSize upperBoundSize = upperBoundLayout()->size(); - return KDSize( - max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSize.width(), - m_baseline + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - argumentLayout()->baseline()) - ); -} - -KDPoint SumLayout::positionOfChild(ExpressionLayout * child) { - KDSize lowerBoundSize = lowerBoundLayout()->size(); - KDSize upperBoundSize = upperBoundLayout()->size(); - KDCoordinate x = 0; - KDCoordinate y = 0; - if (child == lowerBoundLayout()) { - x = max(max(0, (k_symbolWidth-lowerBoundSize.width())/2), (upperBoundSize.width()-lowerBoundSize.width())/2); - y = m_baseline + k_symbolHeight/2 + k_boundHeightMargin; - } else if (child == upperBoundLayout()) { - x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSize.width()-upperBoundSize.width())/2); - y = m_baseline - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); - } else if (child == editableChild(2)) { - x = max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin; - y = m_baseline - argumentLayout()->baseline(); - } else { - assert(false); - } - return KDPoint(x,y); -} - } diff --git a/poincare/src/layout/sum_layout.h b/poincare/src/layout/sum_layout.h index 23d5f698f..7218e866f 100644 --- a/poincare/src/layout/sum_layout.h +++ b/poincare/src/layout/sum_layout.h @@ -7,15 +7,10 @@ namespace Poincare { class SumLayout : public SequenceLayout { public: - SumLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands); + using SequenceLayout::SequenceLayout; ExpressionLayout * clone() const override; - ExpressionLayout * argumentLayout() override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; private: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; - KDSize computeSize() override; - KDPoint positionOfChild(ExpressionLayout * child) override; }; } From 44cf9e8979036a8530c84e48b2f54bc23cf84c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 16:34:27 +0100 Subject: [PATCH 079/257] [poincare] Delete for StringLayout. Change-Id: I67ff432cb283ae2cd1d1acd86a0e2baef9dcbe29 --- poincare/src/layout/string_layout.cpp | 10 ++++++++++ poincare/src/layout/string_layout.h | 1 + 2 files changed, 11 insertions(+) diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index 55f638fce..d153214a8 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -23,6 +23,16 @@ ExpressionLayout * StringLayout::clone() const { return layout; } +void StringLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + m_parent->backspaceAtCursor(cursor); +} + bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { // A StringLayout is not editable, and the cursor cannot go inside it. assert(cursor->pointedExpressionLayout() == this); diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index 0a3763811..48f405d33 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -15,6 +15,7 @@ public: StringLayout& operator=(const StringLayout& other) = delete; StringLayout& operator=(StringLayout&& other) = delete; ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; char * text() { return m_string; } bool moveLeft(ExpressionLayoutCursor * cursor) override; From 22b0042deddcd37b93ab2bbcd1c5c116b53b4af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 16:34:59 +0100 Subject: [PATCH 080/257] [poincare] Delete for UneditableHorizontalTrioLayout. Change-Id: Ide310278ed9444cf03dc02dc40c391ff9f3dfd16 --- .../uneditable_horizontal_trio_layout.cpp | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.cpp b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp index 15b03993c..e416dfbb3 100644 --- a/poincare/src/layout/uneditable_horizontal_trio_layout.cpp +++ b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp @@ -17,18 +17,38 @@ ExpressionLayout * UneditableHorizontalTrioLayout::clone() const { } void UneditableHorizontalTrioLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // Case: Left of the center layout (for sequence layouts). + if (cursor->pointedExpressionLayout() == centerLayout() + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + ExpressionLayout * grandParent = const_cast(m_parent->parent()); + assert(grandParent != nullptr); + ExpressionLayout * parent = m_parent; + int indexInGrandParent = grandParent->indexOfChild(parent); + parent->replaceWith(centerLayout(), true); + // Place the cursor on the right of the left brother of the integral if + // there is one. + if (indexInGrandParent > 0) { + cursor->setPointedExpressionLayout(grandParent->editableChild(indexInGrandParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + // Else place the cursor on the Left of the parent. + cursor->setPointedExpressionLayout(grandParent); + return; + } + // Case: Right. + // Move to the argument. if (cursor->pointedExpressionLayout() == this && cursor->position() == ExpressionLayoutCursor::Position::Right) { - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(new EmptyVisibleLayout(), true); - if (indexInParent == 0) { - cursor->setPointedExpressionLayout(previousParent); + // Go Right of the center layout's last child if it has one, else go Right + // of the center layout. + if (centerLayout()->numberOfChildren() > 1) { + cursor->setPointedExpressionLayout(centerLayout()->editableChild(centerLayout()->numberOfChildren()-1)); return; } - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPointedExpressionLayout(centerLayout()); return; } ExpressionLayout::backspaceAtCursor(cursor); @@ -47,9 +67,8 @@ bool UneditableHorizontalTrioLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go Right of the center layout's last child if it has one, else go Right // of the center layout. - ExpressionLayout * grandChild = centerLayout()->editableChild(centerLayout()->numberOfChildren()-1); - if (grandChild != nullptr) { - cursor->setPointedExpressionLayout(grandChild); + if (centerLayout()->numberOfChildren() > 1) { + cursor->setPointedExpressionLayout(centerLayout()->editableChild(centerLayout()->numberOfChildren()-1)); return true; } cursor->setPointedExpressionLayout(centerLayout()); From 47f691c997b9389e00edd52e4a2b6e05f610312c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 16:35:36 +0100 Subject: [PATCH 081/257] [expression_editor] Empty initial layout. Change-Id: I00231be393bf65715f8f8647439c344fe7069851 --- apps/expression_editor/expression_and_layout.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/expression_editor/expression_and_layout.cpp b/apps/expression_editor/expression_and_layout.cpp index 0f777e586..3616751a4 100644 --- a/apps/expression_editor/expression_and_layout.cpp +++ b/apps/expression_editor/expression_and_layout.cpp @@ -1,6 +1,7 @@ #include "expression_and_layout.h" #include #include +#include namespace ExpressionEditor { @@ -39,7 +40,7 @@ ExpressionAndLayout::ExpressionAndLayout() { m_expression = Poincare::Expression::parse(expression); m_expressionLayout = new Poincare::HorizontalLayout(); - m_expressionLayout->addChildAtIndex(new Poincare::EditableStringLayout("1", 1), 0); + m_expressionLayout->addChildAtIndex(new Poincare::EmptyVisibleLayout(), 0); } ExpressionAndLayout::~ExpressionAndLayout() { if (m_expressionLayout) { From 2c5e1b99bb737d4af81ef2e821863f115781f1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 17:06:24 +0100 Subject: [PATCH 082/257] [poincare] Parameter for UneditableHorizontalTrioLayout navigation. This parameter specifies if the cursor can be left and right of the layout. Change-Id: Ia8d5ff45a471e964bf82e8db0465a5f07661884d --- apps/math_toolbox.cpp | 2 +- poincare/src/layout/sequence_layout.cpp | 2 +- .../uneditable_horizontal_trio_layout.cpp | 24 ++++++++++++++++--- .../uneditable_horizontal_trio_layout.h | 3 ++- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 23eff77f3..b9fbc6a54 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -56,7 +56,7 @@ const ToolboxMessageTree probabilityChildren[2] = { new EmptyVisibleLayout(), new EmptyVisibleLayout())), 2, 1, false), - new ParenthesisRightLayout()), + new ParenthesisRightLayout(), false, true), const_cast(&pointedLayoutPathBinomial[0]), 2), ToolboxMessageTree(I18n::Message::PermuteCommandWithArg, I18n::Message::Permutation, I18n::Message::PermuteCommandWithArg)}; diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 610324ca9..f371911e1 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -13,7 +13,7 @@ SequenceLayout::SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * { ParenthesisLeftLayout * parLeft = new ParenthesisLeftLayout(); ParenthesisRightLayout * parRight = new ParenthesisRightLayout(); - UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, cloneOperands); + UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, cloneOperands, false); build(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray3(lowerBound, upperBound, horLayout)), 3, cloneOperands); } diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.cpp b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp index e416dfbb3..ea8ff521d 100644 --- a/poincare/src/layout/uneditable_horizontal_trio_layout.cpp +++ b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp @@ -7,12 +7,18 @@ extern "C" { namespace Poincare { +UneditableHorizontalTrioLayout::UneditableHorizontalTrioLayout(ExpressionLayout * left, ExpressionLayout * central, ExpressionLayout * right, bool cloneOperands, bool cursorAllowedLeftAndRight) : + StaticLayoutHierarchy(left, central, right, cloneOperands), + m_cursorCanBeLeftOrRight(cursorAllowedLeftAndRight) +{ +} + ExpressionLayout * UneditableHorizontalTrioLayout::clone() const { UneditableHorizontalTrioLayout * layout = new UneditableHorizontalTrioLayout( const_cast(this)->leftLayout(), const_cast(this)->centerLayout(), const_cast(this)->rightLayout(), - true); + true, m_cursorCanBeLeftOrRight); return layout; } @@ -60,7 +66,13 @@ bool UneditableHorizontalTrioLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go Left. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); cursor->setPointedExpressionLayout(this); - return true; + if (m_cursorCanBeLeftOrRight) { + return true; + } + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; } assert(cursor->pointedExpressionLayout() == this); if (cursor->position() == ExpressionLayoutCursor::Position::Right) { @@ -89,7 +101,13 @@ bool UneditableHorizontalTrioLayout::moveRight(ExpressionLayoutCursor * cursor) // Go Right. assert(cursor->position() == ExpressionLayoutCursor::Position::Right); cursor->setPointedExpressionLayout(this); - return true; + if (m_cursorCanBeLeftOrRight) { + return true; + } + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; } assert(cursor->pointedExpressionLayout() == this); if (cursor->position() == ExpressionLayoutCursor::Position::Left) { diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.h b/poincare/src/layout/uneditable_horizontal_trio_layout.h index d0a356c14..094b16d39 100644 --- a/poincare/src/layout/uneditable_horizontal_trio_layout.h +++ b/poincare/src/layout/uneditable_horizontal_trio_layout.h @@ -18,7 +18,7 @@ namespace Poincare { class UneditableHorizontalTrioLayout : public StaticLayoutHierarchy<3> { public: - using StaticLayoutHierarchy::StaticLayoutHierarchy; + UneditableHorizontalTrioLayout(ExpressionLayout * left, ExpressionLayout * central, ExpressionLayout * right, bool cloneOperands, bool cursorAllowedLeftAndRight); ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; @@ -35,6 +35,7 @@ private: ExpressionLayout * leftLayout(); ExpressionLayout * centerLayout(); ExpressionLayout * rightLayout(); + bool m_cursorCanBeLeftOrRight; }; } From 894e8a603290f2168f71b6bd90c9b345a84f273e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 17:36:44 +0100 Subject: [PATCH 083/257] [poincare] Fix main layout edition. If its only child is empty, remove it before adding another child. Change-Id: I3047f17c69ff14787e172d99b6e0b3e1f4096f26 --- poincare/src/layout/expression_layout.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 3b5bc8316..d4410fb08 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -141,6 +141,10 @@ void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLay } // If there is no parent, the pointed layout is the main horizontal layout. // Add the "brother" as a child. + // If there is only one empty child, remove it before adding the layout. + if (numberOfChildren() == 1 && editableChild(0)->isEmpty()) { + removeChildAtIndex(0, true); + } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { addChildAtIndex(brother, 0); return; From ceb124335789a01666ac91098066cabe0dd92b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 17:37:49 +0100 Subject: [PATCH 084/257] [poincare] Fix integral layout navigation. Change-Id: Id8e733dfc1c0e5c583a0d3e33ab4c0837c08e782 --- poincare/src/layout/integral_layout.cpp | 3 +-- poincare/src/layout/string_layout.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 00031c26e..a9ddb1298 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -96,8 +96,7 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(integrandLayout() != nullptr); cursor->setPointedExpressionLayout(integrandLayout()->editableChild(integrandLayout()->numberOfChildren() - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; + return cursor->moveLeft(); } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); // Case: Left of the brackets. diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index d153214a8..e1e835993 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -42,7 +42,7 @@ bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { // string layout, for instance left of "n=" in a Sum layout. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { int indexOfThis = m_parent->indexOfChild(this); - if (indexOfThis > 1) { + if (indexOfThis > 0) { cursor->setPointedExpressionLayout(m_parent->editableChild(indexOfThis-1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; From af2a57213514ec467f7fbdf1a4ab6a7a39cbf1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 17:45:06 +0100 Subject: [PATCH 085/257] [poincare] Fix fraction delete. Change-Id: I98d8fc4d835e753cca9138c42273fff43a58478c --- poincare/src/layout/fraction_layout.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index aa95c224e..889b66994 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -86,6 +86,13 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { cursor->setPointedExpressionLayout(this); return; } + // If the cursor is on the Right, move Left of the denominator. + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(denominatorLayout()); + return; + } ExpressionLayout::backspaceAtCursor(cursor); } From 1773dcbc343f117af1c48e125defe744254d5358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 2 Jan 2018 11:15:48 +0100 Subject: [PATCH 086/257] [poincare] Fixed cases where baseline was used without computing it before. To access a layout's baseline, we should always use baseline() instead of m_baseline, in order to compute the baseline if it needs to be computed. Change-Id: I5e859108bb30b7e23e09beb82fe7046bfa25414f --- poincare/src/layout/nth_root_layout.cpp | 8 ++++---- poincare/src/layout/sequence_layout.cpp | 8 ++++---- poincare/src/layout/sum_layout.cpp | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 005c67b27..d23514edc 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -198,7 +198,7 @@ void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); KDColor workingBuffer[k_leftRadixWidth*k_leftRadixHeight]; KDRect leftRadixFrame(p.x() + indexSize.width() + k_widthMargin - k_leftRadixWidth, - p.y() + m_baseline + radicandSize.height() - radicandLayout()->baseline() + k_heightMargin - k_leftRadixHeight, + p.y() + baseline() + radicandSize.height() - radicandLayout()->baseline() + k_heightMargin - k_leftRadixHeight, k_leftRadixWidth, k_leftRadixHeight); ctx->blendRectWithMask(leftRadixFrame, expressionColor, (const uint8_t *)radixPixel, (KDColor *)workingBuffer); // If the indice is higher than the root. @@ -240,7 +240,7 @@ KDSize NthRootLayout::computeSize() { KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); return KDSize( indexSize.width() + 3*k_widthMargin + 2*k_radixLineThickness + radicandSize.width() + k_radixHorizontalOverflow, - m_baseline + radicandSize.height() - radicandLayout()->baseline() + k_heightMargin + baseline() + radicandSize.height() - radicandLayout()->baseline() + k_heightMargin ); } @@ -260,10 +260,10 @@ KDPoint NthRootLayout::positionOfChild(ExpressionLayout * child) { KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); if (child == indexLayout()) { x = 0; - y = m_baseline - indexSize.height() - k_indexHeight; + y = baseline() - indexSize.height() - k_indexHeight; } else if (child == radicandLayout()) { x = indexSize.width() + 2*k_widthMargin + k_radixLineThickness; - y = m_baseline - radicandLayout()->baseline(); + y = baseline() - radicandLayout()->baseline(); } else { assert(false); } diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index f371911e1..d6db66cb7 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -189,7 +189,7 @@ KDSize SequenceLayout::computeSize() { KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSize.width(), - m_baseline + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - argumentLayout()->baseline()) + baseline() + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - argumentLayout()->baseline()) ); } @@ -205,13 +205,13 @@ KDPoint SequenceLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate y = 0; if (child == lowerBoundLayout()) { x = max(max(0, (k_symbolWidth-lowerBoundSize.width())/2), (upperBoundSize.width()-lowerBoundSize.width())/2); - y = m_baseline + k_symbolHeight/2 + k_boundHeightMargin; + y = baseline() + k_symbolHeight/2 + k_boundHeightMargin; } else if (child == upperBoundLayout()) { x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSize.width()-upperBoundSize.width())/2); - y = m_baseline - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); + y = baseline() - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); } else if (child == editableChild(2)) { x = max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin; - y = m_baseline - argumentLayout()->baseline(); + y = baseline() - argumentLayout()->baseline(); } else { assert(false); } diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index c59ccb496..8d198b249 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -31,9 +31,10 @@ ExpressionLayout * SumLayout::clone() const { void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize upperBoundSize = upperBoundLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); + KDCoordinate argBaseline = argumentLayout()->baseline(); KDColor workingBuffer[k_symbolWidth*k_symbolHeight]; KDRect symbolFrame(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argBaseline /*argumentLayout()->baseline()*/-(k_symbolHeight+1)/2), k_symbolWidth, k_symbolHeight); ctx->blendRectWithMask(symbolFrame, expressionColor, (const uint8_t *)symbolPixel, (KDColor *)workingBuffer); } From ccd25a360d6137a43f9fa9cdbf0c53d444b8ffb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 2 Jan 2018 16:11:06 +0100 Subject: [PATCH 087/257] [poincare] Serialize expression layout. We can now convert layouts into text: we will be able to parse them into an Expression. Change-Id: I82f4834c08f5b2c5fb294bdcb9a49257b574e20b --- apps/math_toolbox.cpp | 14 ++- poincare/include/poincare/expression_layout.h | 3 + poincare/include/poincare/layout_engine.h | 46 ++++++- poincare/src/layout/absolute_value_layout.h | 4 + .../src/layout/baseline_relative_layout.cpp | 22 ++++ .../src/layout/baseline_relative_layout.h | 1 + poincare/src/layout/bracket_layout.cpp | 22 ++++ poincare/src/layout/bracket_layout.h | 1 + poincare/src/layout/bracket_left_layout.h | 4 + poincare/src/layout/bracket_right_layout.h | 4 + poincare/src/layout/ceiling_layout.h | 4 + poincare/src/layout/char_layout.h | 4 + poincare/src/layout/condensed_sum_layout.h | 4 + poincare/src/layout/conjugate_layout.h | 4 + poincare/src/layout/empty_layout.cpp | 8 ++ poincare/src/layout/empty_layout.h | 2 + poincare/src/layout/floor_layout.h | 4 + poincare/src/layout/fraction_layout.cpp | 22 ++++ poincare/src/layout/fraction_layout.h | 2 + poincare/src/layout/grid_layout.cpp | 38 ++++++ poincare/src/layout/grid_layout.h | 3 + poincare/src/layout/horizontal_layout.h | 6 + poincare/src/layout/integral_layout.cpp | 53 ++++++++- poincare/src/layout/integral_layout.h | 9 ++ poincare/src/layout/nth_root_layout.h | 11 ++ poincare/src/layout/parenthesis_layout.h | 4 + poincare/src/layout/parenthesis_left_layout.h | 4 + .../src/layout/parenthesis_right_layout.h | 4 + poincare/src/layout/product_layout.cpp | 6 +- poincare/src/layout/product_layout.h | 2 + poincare/src/layout/sequence_layout.cpp | 61 ++++++++-- poincare/src/layout/sequence_layout.h | 4 +- poincare/src/layout/string_layout.cpp | 14 +++ poincare/src/layout/string_layout.h | 2 + poincare/src/layout/sum_layout.cpp | 6 +- poincare/src/layout/sum_layout.h | 2 + .../uneditable_horizontal_trio_layout.h | 5 + poincare/src/layout_engine.cpp | 112 +++++++++++++----- 38 files changed, 471 insertions(+), 50 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index b9fbc6a54..a1b29bf5c 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -10,17 +10,19 @@ using namespace Poincare; * and the text which would be edited by clicking on the row. When the node is a * subtree, the edited text is set at I18n::Message::Default. */ -const int pointedLayoutPathIntegral[] = {2, 0}; -const int pointedLayoutPathSum[] = {2, 1}; +const int pointedLayoutPathIntegral[] = {0, 0}; +const int pointedLayoutPathSum[] = {0, 1}; const ToolboxMessageTree calculChildren[4] = { ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg, nullptr, 0), ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, new IntegralLayout( - new EmptyVisibleLayout(), - new EmptyVisibleLayout(), - new HorizontalLayout(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2( + new HorizontalLayout( + const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2( new EmptyVisibleLayout(), - new StringLayout("dx",2))), 2, false), false), + new StringLayout("dx",2))), 2, false), + new EmptyVisibleLayout(), + new EmptyVisibleLayout(), + false), const_cast(&pointedLayoutPathIntegral[0]), 2), ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg, nullptr, 0, diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 5ec12341f..f366a305f 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -66,6 +66,9 @@ public: virtual bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); bool moveDownInside(ExpressionLayoutCursor * cursor); + /* Expression Engine */ + virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0; + /* Other */ virtual bool isHorizontal() const { return false; } virtual bool isLeftParenthesis() const { return false; } diff --git a/poincare/include/poincare/layout_engine.h b/poincare/include/poincare/layout_engine.h index cf1bc1e00..e1b14d0ef 100644 --- a/poincare/include/poincare/layout_engine.h +++ b/poincare/include/poincare/layout_engine.h @@ -6,13 +6,53 @@ namespace Poincare { class LayoutEngine { + public: + /* Expression to ExpressionLayout */ static ExpressionLayout * createInfixLayout(const Expression * expression, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat, const char * operatorName); static ExpressionLayout * createPrefixLayout(const Expression * expression, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat, const char * operatorName); - typedef bool (*OperandNeedParenthesis)(const Expression * e); - static int writeInfixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName, OperandNeedParenthesis operandNeedParenthesis = [](const Expression * e) { return e->type() == Expression::Type::Opposite; }); - static int writePrefixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName); + /* Expression to Text */ + typedef bool (*OperandNeedsParenthesis)(const Expression * e); + static int writeInfixExpressionTextInBuffer( + const Expression * expression, + char * buffer, + int bufferSize, + const char * operatorName, + OperandNeedsParenthesis operandNeedsParenthesis = [](const Expression * e) { return e->type() == Expression::Type::Opposite; }); + static int writePrefixExpressionTextInBuffer( + const Expression * expression, + char * buffer, + int bufferSize, + const char * operatorName); + + /* ExpressionLayout to Text */ + typedef bool (*ChildNeedsParenthesis)(const char * operatorName); + static int writeInfixExpressionLayoutTextInBuffer( + const ExpressionLayout * expressionLayout, + char * buffer, + int bufferSize, + const char * operatorName, + int firstChildIndex = 0, + int lastChildIndex = -1, + ChildNeedsParenthesis childNeedsParenthesis = [](const char * operatorName) { + return (operatorName[1] == 0 && (operatorName[0] == powerChar || operatorName[0] == divideChar)); }); //TODO + static int writePrefixExpressionLayoutTextInBuffer( + const ExpressionLayout * expressionLayout, + char * buffer, + int bufferSize, + const char * operatorName, + bool writeFirstChild = true); + + /* Write one char in buffer */ + static int writeOneCharInBuffer(char * buffer, int bufferSize, char charToWrite); + +private: + static constexpr char powerChar = '^'; + static constexpr char divideChar = '/'; + // These two functions return the index of the null-terminating char. + static int writeInfixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, int firstChildIndex, int lastChildIndex, OperandNeedsParenthesis operandNeedsParenthesis, ChildNeedsParenthesis childNeedsParenthesis); + static int writePrefixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, bool writeFirstChild = true); }; } diff --git a/poincare/src/layout/absolute_value_layout.h b/poincare/src/layout/absolute_value_layout.h index 55691659c..0be2b78a8 100644 --- a/poincare/src/layout/absolute_value_layout.h +++ b/poincare/src/layout/absolute_value_layout.h @@ -2,6 +2,7 @@ #define POINCARE_ABSOLUTE_VALUE_LAYOUT_H #include "bracket_layout.h" +#include namespace Poincare { @@ -9,6 +10,9 @@ class AbsoluteValueLayout : public BracketLayout { public: using BracketLayout::BracketLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "abs"); + } protected: KDCoordinate widthMargin() const override { return 2; } bool renderTopBar() const override { return false; } diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index 725898139..133d6c563 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -1,6 +1,7 @@ #include "baseline_relative_layout.h" #include "empty_visible_layout.h" #include +#include #include #include @@ -70,6 +71,27 @@ bool BaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +int BaselineRelativeLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (m_type == Type::Subscript) { + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + if (bufferSize == 1) { + return 0; + } + int numberOfChars = LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "_{"); + if (numberOfChars < bufferSize - 1) { + //FIXME what if the buffer is not big enough? + buffer[numberOfChars++] = '}'; + buffer[numberOfChars] = 0; + } + return numberOfChars; + } + assert(m_type == Type::Superscript); + return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "^"); +} + ExpressionLayout * BaselineRelativeLayout::baseLayout() { return editableChild(0); } diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index f0cb1f7a0..184f808a6 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -16,6 +16,7 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: ExpressionLayout * baseLayout(); ExpressionLayout * indiceLayout(); diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index f3433e3f2..993ad2204 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -1,5 +1,6 @@ #include "bracket_layout.h" #include +#include extern "C" { #include #include @@ -90,6 +91,27 @@ bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +int BracketLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + + // Write the opening bracket + int numberOfChar = 0; + buffer[numberOfChar++] = '['; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + + // Write the argument + numberOfChar += const_cast(this)->operandLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the closing bracket + buffer[numberOfChar++] = ']'; + buffer[numberOfChar] = 0; + return numberOfChar; +} + ExpressionLayout * BracketLayout::operandLayout() { return editableChild(0); } diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index d11f51681..94b63398f 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -12,6 +12,7 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: ExpressionLayout * operandLayout(); KDCoordinate externWidthMargin() const { return 2; } diff --git a/poincare/src/layout/bracket_left_layout.h b/poincare/src/layout/bracket_left_layout.h index 1975b2fc0..35af9d32b 100644 --- a/poincare/src/layout/bracket_left_layout.h +++ b/poincare/src/layout/bracket_left_layout.h @@ -2,6 +2,7 @@ #define POINCARE_BRACKET_LEFT_LAYOUT_H #include +#include namespace Poincare { @@ -9,6 +10,9 @@ class BracketLeftLayout : public BracketLeftRightLayout { public: using BracketLeftRightLayout::BracketLeftRightLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, '['); + } bool isLeftBracket() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/bracket_right_layout.h b/poincare/src/layout/bracket_right_layout.h index 788664f3e..bc5af7548 100644 --- a/poincare/src/layout/bracket_right_layout.h +++ b/poincare/src/layout/bracket_right_layout.h @@ -2,6 +2,7 @@ #define POINCARE_BRACKET_RIGHT_LAYOUT_H #include +#include namespace Poincare { @@ -9,6 +10,9 @@ class BracketRightLayout : public BracketLeftRightLayout { public: using BracketLeftRightLayout::BracketLeftRightLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, ']'); + } bool isRightBracket() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/ceiling_layout.h b/poincare/src/layout/ceiling_layout.h index 1dd170093..b09c99f5a 100644 --- a/poincare/src/layout/ceiling_layout.h +++ b/poincare/src/layout/ceiling_layout.h @@ -2,6 +2,7 @@ #define POINCARE_CEILING_LAYOUT_H #include "bracket_layout.h" +#include namespace Poincare { @@ -9,6 +10,9 @@ class CeilingLayout : public BracketLayout { public: using BracketLayout::BracketLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "ceil"); + } protected: bool renderBottomBar() const override { return false; } }; diff --git a/poincare/src/layout/char_layout.h b/poincare/src/layout/char_layout.h index d00625c09..47ba4e336 100644 --- a/poincare/src/layout/char_layout.h +++ b/poincare/src/layout/char_layout.h @@ -2,6 +2,7 @@ #define POINCARE_CHAR_LAYOUT_H #include +#include #include namespace Poincare { @@ -10,6 +11,9 @@ class CharLayout : public StaticLayoutHierarchy<0> { public: CharLayout(char c, KDText::FontSize fontSize = KDText::FontSize::Large); ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, m_char); + } char character() { return m_char; } bool moveLeft(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index 20795398d..2647474cd 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -2,6 +2,7 @@ #define POINCARE_CONDENSED_SUM_LAYOUT_H #include +#include namespace Poincare { @@ -13,6 +14,9 @@ public: bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "sum"); + } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 366c824a5..203b1f1ca 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -2,6 +2,7 @@ #define POINCARE_CONJUGATE_LAYOUT_H #include +#include namespace Poincare { @@ -12,6 +13,9 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "conj"); + } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/empty_layout.cpp b/poincare/src/layout/empty_layout.cpp index 88871bb7c..c7af45bf2 100644 --- a/poincare/src/layout/empty_layout.cpp +++ b/poincare/src/layout/empty_layout.cpp @@ -9,6 +9,14 @@ ExpressionLayout * EmptyLayout::clone() const { return layout; } +int EmptyLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (bufferSize == 0) { + return -1; + } + buffer[0] = 0; + return 0; +} + void EmptyLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { replaceWith(brother, true); } diff --git a/poincare/src/layout/empty_layout.h b/poincare/src/layout/empty_layout.h index 3688e4f21..5d82724f7 100644 --- a/poincare/src/layout/empty_layout.h +++ b/poincare/src/layout/empty_layout.h @@ -2,6 +2,7 @@ #define POINCARE_EMPTY_LAYOUT_H #include +#include #include namespace Poincare { @@ -13,6 +14,7 @@ public: void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; bool isEmpty() const override { return true; } protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { return; } diff --git a/poincare/src/layout/floor_layout.h b/poincare/src/layout/floor_layout.h index 1bfb7e8f3..5e5a9785b 100644 --- a/poincare/src/layout/floor_layout.h +++ b/poincare/src/layout/floor_layout.h @@ -2,6 +2,7 @@ #define POINCARE_FLOOR_LAYOUT_H #include "bracket_layout.h" +#include namespace Poincare { @@ -9,6 +10,9 @@ class FloorLayout : public BracketLayout { public: using BracketLayout::BracketLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "floor"); + } protected: bool renderTopBar() const override { return false; } }; diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 889b66994..71b9555aa 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -178,6 +178,28 @@ bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } +int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + int numberOfChar = 0; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + + // Write the first enclosing parenthesis. + buffer[numberOfChar++] = '('; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + + // Write the content of the fraction + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, "/"); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the second enclosing parenthesis. + buffer[numberOfChar++] = ')'; + buffer[numberOfChar] = 0; + return numberOfChar; +} + void FractionLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDCoordinate fractionLineY = p.y() + numeratorLayout()->size().height() + k_fractionLineMargin; ctx->fillRect(KDRect(p.x()+Metric::FractionAndConjugateHorizontalMargin, fractionLineY, size().width()-2*Metric::FractionAndConjugateHorizontalMargin, 1), expressionColor); diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 296b31ccc..7c551df14 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -2,6 +2,7 @@ #define POINCARE_FRACTION_LAYOUT_H #include +#include namespace Poincare { @@ -14,6 +15,7 @@ public: bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 2ad50f177..b73636fc0 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -1,6 +1,7 @@ #include "grid_layout.h" #include "empty_visible_layout.h" #include +#include extern "C" { #include #include @@ -137,6 +138,43 @@ bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * pr return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } +int GridLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + const ExpressionLayout * editableParent = const_cast(this)->parent(); + assert(editableParent != nullptr); + + // If the grid is a binomial coefficient: + if (editableParent->child(0)->isLeftParenthesis()) { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "binomial"); + } + + assert(editableParent->child(0)->isLeftBracket()); + // The grid is a matrix. + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + int numberOfChar = 0; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + + for (int i = 0; i < m_numberOfRows; i++) { + buffer[numberOfChar++] = '['; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, ",", i*m_numberOfColumns, (i+1) * m_numberOfColumns - 1); + + buffer[numberOfChar++] = ']'; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + if (i < m_numberOfRows - 1) { + buffer[numberOfChar++] = ','; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + } + } + + buffer[numberOfChar] = 0; + return numberOfChar; +} + KDCoordinate GridLayout::rowBaseline(int i) { KDCoordinate rowBaseline = 0; for (int j = 0; j < m_numberOfColumns; j++) { diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index e2275511b..e5a6bde67 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -17,6 +17,9 @@ public: bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + /* Expression engine */ + int writeTextInBuffer(char * buffer, int bufferSize) const override; + protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index a3aef1244..c4aa2a027 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -2,6 +2,7 @@ #define POINCARE_HORIZONTAL_LAYOUT_H #include +#include namespace Poincare { @@ -21,6 +22,11 @@ public: bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + /* Expression Engine */ + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); + } + /* Other */ bool isHorizontal() const override { return true; } diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index a9ddb1298..f41c8bf2c 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -20,7 +20,7 @@ const uint8_t bottomSymbolPixel[IntegralLayout::k_symbolHeight][IntegralLayout:: }; ExpressionLayout * IntegralLayout::clone() const { - IntegralLayout * layout = new IntegralLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->integrandLayout(), true); + IntegralLayout * layout = new IntegralLayout(const_cast(this)->integrandLayout(), const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), true); return layout; } @@ -181,6 +181,53 @@ bool IntegralLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } +int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + + // Write the operator name + int numberOfChar = strlcpy(buffer, "int", bufferSize); + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + + // Write the opening parenthesis + buffer[numberOfChar++] = '('; + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + + // Write the argument without the "dx" + ExpressionLayout * intLayout = const_cast(this)->integrandLayout(); + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(intLayout, buffer+numberOfChar, bufferSize-numberOfChar, "", 0, intLayout->numberOfChildren()-2); + // TODO This works because the argument layout should always be an horizontal + // layout. + + // Write the comma + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + buffer[numberOfChar++] = ','; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the lower bound + numberOfChar += const_cast(this)->lowerBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + + // Write the comma + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + buffer[numberOfChar++] = ','; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the upper bound + numberOfChar += const_cast(this)->upperBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + + // Write the closing parenthesis + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + buffer[numberOfChar++] = ')'; + buffer[numberOfChar] = 0; + return numberOfChar; +} + void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize integrandSize = integrandLayout()->size(); KDSize upperBoundSize = upperBoundLayout()->size(); @@ -232,7 +279,7 @@ KDPoint IntegralLayout::positionOfChild(ExpressionLayout * child) { } ExpressionLayout * IntegralLayout::upperBoundLayout() { - return editableChild(0); + return editableChild(2); } ExpressionLayout * IntegralLayout::lowerBoundLayout() { @@ -240,7 +287,7 @@ ExpressionLayout * IntegralLayout::lowerBoundLayout() { } ExpressionLayout * IntegralLayout::integrandLayout() { - return editableChild(2); + return editableChild(0); } } diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 70d07eed4..35e9769df 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -2,6 +2,7 @@ #define POINCARE_INTEGRAL_LAYOUT_H #include +#include namespace Poincare { @@ -11,11 +12,19 @@ public: constexpr static KDCoordinate k_symbolWidth = 4; using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; + + /* Dynamic Layout*/ void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; + + /* Tree navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + + /* Expression Engine */ + int writeTextInBuffer(char * buffer, int bufferSize) const override; + protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index d5cceb77f..c04f5c7f2 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -2,6 +2,7 @@ #define POINCARE_NTH_ROOT_LAYOUT_H #include +#include namespace Poincare { @@ -11,11 +12,21 @@ public: constexpr static KDCoordinate k_leftRadixWidth = 5; using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; + + /* Dynamic Layout*/ void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; + + /* Tree navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + + /* Expression Engine */ + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "root"); + } + protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/parenthesis_layout.h b/poincare/src/layout/parenthesis_layout.h index 0757c6f5f..f7ed69efd 100644 --- a/poincare/src/layout/parenthesis_layout.h +++ b/poincare/src/layout/parenthesis_layout.h @@ -2,6 +2,7 @@ #define POINCARE_PARENTHESIS_LAYOUT_H #include +#include namespace Poincare { @@ -13,6 +14,9 @@ public: ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); + } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { }; diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index 538d5c2de..782f9da01 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -2,6 +2,7 @@ #define POINCARE_PARENTHESIS_LEFT_LAYOUT_H #include +#include namespace Poincare { @@ -9,6 +10,9 @@ class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, '('); + } bool isLeftParenthesis() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index c03d19efd..137494443 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -2,6 +2,7 @@ #define POINCARE_PARENTHESIS_RIGHT_LAYOUT_H #include +#include namespace Poincare { @@ -9,6 +10,9 @@ class ParenthesisRightLayout : public ParenthesisLeftRightLayout { public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, ')'); + } bool isRightParenthesis() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/product_layout.cpp b/poincare/src/layout/product_layout.cpp index b344736dd..1be482165 100644 --- a/poincare/src/layout/product_layout.cpp +++ b/poincare/src/layout/product_layout.cpp @@ -5,10 +5,14 @@ namespace Poincare { ExpressionLayout * ProductLayout::clone() const { - ProductLayout * layout = new ProductLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->argumentLayout(), true); + ProductLayout * layout = new ProductLayout(const_cast(this)->argumentLayout(), const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), true); return layout; } +int ProductLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + return SequenceLayout::writeDerivedClassInBuffer("product", buffer, bufferSize); +} + void ProductLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize upperBoundSize = upperBoundLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); diff --git a/poincare/src/layout/product_layout.h b/poincare/src/layout/product_layout.h index ae68723be..72750ebbb 100644 --- a/poincare/src/layout/product_layout.h +++ b/poincare/src/layout/product_layout.h @@ -2,6 +2,7 @@ #define POINCARE_PRODUCT_LAYOUT_H #include "sequence_layout.h" +#include namespace Poincare { @@ -9,6 +10,7 @@ class ProductLayout : public SequenceLayout { public: using SequenceLayout::SequenceLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; private: diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index d6db66cb7..6b5e9cf85 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -14,7 +14,7 @@ SequenceLayout::SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * ParenthesisLeftLayout * parLeft = new ParenthesisLeftLayout(); ParenthesisRightLayout * parRight = new ParenthesisRightLayout(); UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, cloneOperands, false); - build(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray3(lowerBound, upperBound, horLayout)), 3, cloneOperands); + build(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray3(horLayout, lowerBound, upperBound)), 3, cloneOperands); } void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { @@ -71,7 +71,7 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go Right of the lower bound. if (cursor->position() == ExpressionLayoutCursor::Position::Left && argumentLayout() - && cursor->pointedExpressionLayout() == editableChild(2)) + && cursor->pointedExpressionLayout() == argumentWithParenthesesLayout()) { assert(lowerBoundLayout() != nullptr); cursor->setPointedExpressionLayout(lowerBoundLayout()->editableChild(1)); @@ -113,7 +113,7 @@ bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. if (cursor->position() == ExpressionLayoutCursor::Position::Right && argumentLayout() - && cursor->pointedExpressionLayout() == editableChild(2)) + && cursor->pointedExpressionLayout() == argumentWithParenthesesLayout()) { cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); @@ -171,8 +171,51 @@ char SequenceLayout::XNTChar() const { return 'n'; } +int SequenceLayout::writeDerivedClassInBuffer(const char * operatorName, char * buffer, int bufferSize) const { + assert(operatorName != nullptr); + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + + // Write the operator name + int numberOfChar = strlcpy(buffer, operatorName, bufferSize); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the opening parenthesis + buffer[numberOfChar++] = '('; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the argument + numberOfChar += const_cast(this)->argumentLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the comma + buffer[numberOfChar++] = ','; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the lower bound without the "n=" + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(const_cast(this)->lowerBoundLayout(), buffer+numberOfChar, bufferSize-numberOfChar, "", 1); + // TODO This works because the lower bound layout should always be an + // horizontal layout. + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the comma + buffer[numberOfChar++] = ','; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the upper bound + numberOfChar += const_cast(this)->upperBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Write the closing parenthesis + buffer[numberOfChar++] = ')'; + buffer[numberOfChar] = 0; + return numberOfChar; +} + ExpressionLayout * SequenceLayout::upperBoundLayout() { - return editableChild(0); + return editableChild(2); } ExpressionLayout * SequenceLayout::lowerBoundLayout() { @@ -180,11 +223,15 @@ ExpressionLayout * SequenceLayout::lowerBoundLayout() { } ExpressionLayout * SequenceLayout::argumentLayout() { - return editableChild(2)->editableChild(1); + return argumentWithParenthesesLayout()->editableChild(1); +} + +ExpressionLayout * SequenceLayout::argumentWithParenthesesLayout() { + return editableChild(0); } KDSize SequenceLayout::computeSize() { - KDSize argumentSize = editableChild(2)->size(); + KDSize argumentSize = argumentWithParenthesesLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( @@ -209,7 +256,7 @@ KDPoint SequenceLayout::positionOfChild(ExpressionLayout * child) { } else if (child == upperBoundLayout()) { x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSize.width()-upperBoundSize.width())/2); y = baseline() - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); - } else if (child == editableChild(2)) { + } else if (child == argumentWithParenthesesLayout()) { x = max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin; y = baseline() - argumentLayout()->baseline(); } else { diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index ca53827d8..418eb6d94 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -19,9 +19,11 @@ public: protected: constexpr static KDCoordinate k_boundHeightMargin = 2; constexpr static KDCoordinate k_argumentWidthMargin = 2; + int writeDerivedClassInBuffer(const char * operatorName, char * buffer, int bufferSize) const; ExpressionLayout * lowerBoundLayout(); ExpressionLayout * upperBoundLayout(); - virtual ExpressionLayout * argumentLayout(); + ExpressionLayout * argumentLayout(); + ExpressionLayout * argumentWithParenthesesLayout(); KDSize computeSize() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index e1e835993..af1ec891f 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -85,6 +85,20 @@ bool StringLayout::moveRight(ExpressionLayoutCursor * cursor) { return m_parent->moveRight(cursor); } +int StringLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + int numberOfChar = strlcpy(buffer, m_string, bufferSize); + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + + buffer[numberOfChar] = 0; + return numberOfChar; +} + void StringLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { ctx->drawString(m_string, p, m_fontSize, expressionColor, backgroundColor); } diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index 48f405d33..40301736b 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -2,6 +2,7 @@ #define POINCARE_STRING_LAYOUT_H #include +#include #include namespace Poincare { @@ -20,6 +21,7 @@ public: char * text() { return m_string; } bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDPoint positionOfChild(ExpressionLayout * child) override; diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index 8d198b249..857ae525e 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -24,10 +24,14 @@ const uint8_t symbolPixel[SumLayout::k_symbolHeight][SumLayout::k_symbolWidth] = }; ExpressionLayout * SumLayout::clone() const { - SumLayout * layout = new SumLayout(const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), const_cast(this)->argumentLayout(), true); + SumLayout * layout = new SumLayout(const_cast(this)->argumentLayout(), const_cast(this)->lowerBoundLayout(), const_cast(this)->upperBoundLayout(), true); return layout; } +int SumLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + return SequenceLayout::writeDerivedClassInBuffer("sum", buffer, bufferSize); +} + void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize upperBoundSize = upperBoundLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); diff --git a/poincare/src/layout/sum_layout.h b/poincare/src/layout/sum_layout.h index 7218e866f..4f8228921 100644 --- a/poincare/src/layout/sum_layout.h +++ b/poincare/src/layout/sum_layout.h @@ -2,6 +2,7 @@ #define POINCARE_SUM_LAYOUT_H #include "sequence_layout.h" +#include namespace Poincare { @@ -9,6 +10,7 @@ class SumLayout : public SequenceLayout { public: using SequenceLayout::SequenceLayout; ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; private: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; }; diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.h b/poincare/src/layout/uneditable_horizontal_trio_layout.h index 094b16d39..484947dd5 100644 --- a/poincare/src/layout/uneditable_horizontal_trio_layout.h +++ b/poincare/src/layout/uneditable_horizontal_trio_layout.h @@ -2,6 +2,7 @@ #define POINCARE_UNEDITABLE_HORIZONTAL_TRIO_LAYOUT_H #include +#include namespace Poincare { @@ -26,6 +27,10 @@ public: bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + /* Expression Engine */ + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); + } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index 2690be522..89a6d6664 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -1,5 +1,5 @@ #include -#include "layout/editable_string_layout.h" +#include "layout/string_layout.h" #include "layout/parenthesis_layout.h" #include "layout/horizontal_layout.h" extern "C" { @@ -16,12 +16,12 @@ ExpressionLayout * LayoutEngine::createInfixLayout(const Expression * expression ExpressionLayout** children_layouts = new ExpressionLayout * [2*numberOfOperands-1]; children_layouts[0] = expression->operand(0)->createLayout(); for (int i=1; ioperand(i)->type() == Expression::Type::Opposite ? new ParenthesisLayout(expression->operand(i)->createLayout(floatDisplayMode, complexFormat), false) : expression->operand(i)->createLayout(floatDisplayMode, complexFormat); } /* HorizontalLayout holds the children layouts so they do not need to be * deleted here. */ - ExpressionLayout * layout = new HorizontalLayout(children_layouts, 2*numberOfOperands-1, false); + ExpressionLayout * layout = new HorizontalLayout(children_layouts, 2*numberOfOperands-1); delete[] children_layouts; return layout; } @@ -34,48 +34,80 @@ ExpressionLayout * LayoutEngine::createPrefixLayout(const Expression * expressio int layoutIndex = 0; grandChildrenLayouts[layoutIndex++] = expression->operand(0)->createLayout(floatDisplayMode, complexFormat); for (int i = 1; i < numberOfOperands; i++) { - grandChildrenLayouts[layoutIndex++] = new EditableStringLayout(",", 1); + grandChildrenLayouts[layoutIndex++] = new StringLayout(",", 1); grandChildrenLayouts[layoutIndex++] = expression->operand(i)->createLayout(floatDisplayMode, complexFormat); } /* HorizontalLayout holds the grand children layouts so they do not need to * be deleted */ - ExpressionLayout * argumentLayouts = new HorizontalLayout(grandChildrenLayouts, 2*numberOfOperands-1, false); + ExpressionLayout * argumentLayouts = new HorizontalLayout(grandChildrenLayouts, 2*numberOfOperands-1); delete [] grandChildrenLayouts; ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = new EditableStringLayout(operatorName, strlen(operatorName)); + childrenLayouts[0] = new StringLayout(operatorName, strlen(operatorName)); childrenLayouts[1] = new ParenthesisLayout(argumentLayouts, false); /* Same comment as above */ - return new HorizontalLayout(childrenLayouts, 2, false); + return new HorizontalLayout(childrenLayouts, 2); } -int LayoutEngine::writeInfixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName, OperandNeedParenthesis operandNeedParenthesis) { +int LayoutEngine::writeInfixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName, OperandNeedsParenthesis operandNeedsParenthesis) { + return writeInfixExpressionOrExpressionLayoutTextInBuffer(expression, nullptr, buffer, bufferSize, operatorName, 0, -1, operandNeedsParenthesis, [](const char * operatorName) { return true; }); +} + +int LayoutEngine::writePrefixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName) { + return writePrefixExpressionOrExpressionLayoutTextInBuffer(expression, nullptr, buffer, bufferSize, operatorName); +} + +int LayoutEngine::writeInfixExpressionLayoutTextInBuffer(const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, int firstChildIndex, int lastChildIndex, ChildNeedsParenthesis childNeedsParenthesis) { + return writeInfixExpressionOrExpressionLayoutTextInBuffer(nullptr, expressionLayout, buffer, bufferSize, operatorName, firstChildIndex, lastChildIndex, [](const Expression * e) { return true; }, childNeedsParenthesis); +} + +int LayoutEngine::writePrefixExpressionLayoutTextInBuffer(const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, bool writeFirstChild) { + return writePrefixExpressionOrExpressionLayoutTextInBuffer(nullptr, expressionLayout, buffer, bufferSize, operatorName, writeFirstChild); +} + +int LayoutEngine::writeInfixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, int firstChildIndex, int lastChildIndex, OperandNeedsParenthesis operandNeedsParenthesis, ChildNeedsParenthesis childNeedsParenthesis) { + assert(expression != nullptr || expressionLayout != nullptr); if (bufferSize == 0) { return -1; } buffer[bufferSize-1] = 0; int numberOfChar = 0; - int numberOfOperands = expression->numberOfOperands(); + int numberOfOperands = (expression != nullptr) ? expression->numberOfOperands() : expressionLayout->numberOfChildren(); assert(numberOfOperands > 1); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - if (operandNeedParenthesis(expression->operand(0))) { - buffer[numberOfChar++] = '('; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; } - numberOfChar += expression->operand(0)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); - if (operandNeedParenthesis(expression->operand(0))) { + + if ((expression != nullptr && operandNeedsParenthesis(expression->operand(firstChildIndex))) + || (expression == nullptr && childNeedsParenthesis(operatorName))) + { + buffer[numberOfChar++] = '('; + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + } + + numberOfChar += (expression != nullptr) ? expression->operand(firstChildIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar) : expressionLayout->child(firstChildIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if ((expression != nullptr && operandNeedsParenthesis(expression->operand(firstChildIndex))) + || (expression == nullptr && childNeedsParenthesis(operatorName))) + { buffer[numberOfChar++] = ')'; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } } - for (int i=1; i= bufferSize-1) { return bufferSize-1; } numberOfChar += strlcpy(buffer+numberOfChar, operatorName, bufferSize-numberOfChar); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - if (operandNeedParenthesis(expression->operand(i))) { + if ((expression != nullptr && operandNeedsParenthesis(expression->operand(i))) + || (expression == nullptr && childNeedsParenthesis(operatorName))) + { buffer[numberOfChar++] = '('; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } } - numberOfChar += expression->operand(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); - if (operandNeedParenthesis(expression->operand(i))) { + numberOfChar += (expression != nullptr) ? expression->operand(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar) : expressionLayout->child(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if ((expression != nullptr && operandNeedsParenthesis(expression->operand(i))) + || (expression == nullptr && childNeedsParenthesis(operatorName))) + { buffer[numberOfChar++] = ')'; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } } @@ -84,24 +116,35 @@ int LayoutEngine::writeInfixExpressionTextInBuffer(const Expression * expression return numberOfChar; } -int LayoutEngine::writePrefixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName) { + +int LayoutEngine::writePrefixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, bool writeFirstChild) { + assert(expression != nullptr || expressionLayout != nullptr); if (bufferSize == 0) { return -1; } buffer[bufferSize-1] = 0; - int numberOfChar = 0; - numberOfChar += strlcpy(buffer, operatorName, bufferSize); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + int numberOfChar = strlcpy(buffer, operatorName, bufferSize); + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + buffer[numberOfChar++] = '('; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - int numberOfOperands = expression->numberOfOperands(); + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + + int numberOfOperands = (expression != nullptr) ? expression->numberOfOperands() : expressionLayout->numberOfChildren(); assert(numberOfOperands > 0); - numberOfChar += expression->operand(0)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); - for (int i = 1; i < numberOfOperands; i++) { + if (!writeFirstChild) { + assert(numberOfOperands > 1); + } + int firstOperandIndex = writeFirstChild ? 0 : 1; + numberOfChar += (expression != nullptr) ? expression->operand(firstOperandIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar) : expressionLayout->child(firstOperandIndex)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + for (int i = firstOperandIndex + 1; i < numberOfOperands; i++) { if (numberOfChar >= bufferSize-1) { return bufferSize-1; } buffer[numberOfChar++] = ','; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - numberOfChar += expression->operand(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += (expression != nullptr) ? expression->operand(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar) : expressionLayout->child(i)->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); } if (numberOfChar >= bufferSize-1) { return bufferSize-1; } buffer[numberOfChar++] = ')'; @@ -109,4 +152,17 @@ int LayoutEngine::writePrefixExpressionTextInBuffer(const Expression * expressio return numberOfChar; } +int LayoutEngine::writeOneCharInBuffer(char * buffer, int bufferSize, char charToWrite) { + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + if (bufferSize == 1) { + return 0; + } + buffer[0] = charToWrite; + buffer[1] = 0; + return 1; +} + } From 332cfb013f2f6045ef3b7ac078d4a854eafc6adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 2 Jan 2018 16:45:40 +0100 Subject: [PATCH 088/257] [ExpressionEditor] TextView to see serialization results. Just for development purposes. Change-Id: I8700818a8d5705e2c610bd448fbcc2deea6b9971 --- .../expression_editor/expression_editor_view.cpp | 16 +++++++++++++++- apps/expression_editor/expression_editor_view.h | 9 ++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/expression_editor/expression_editor_view.cpp b/apps/expression_editor/expression_editor_view.cpp index 5d1047e53..fe825654e 100644 --- a/apps/expression_editor/expression_editor_view.cpp +++ b/apps/expression_editor/expression_editor_view.cpp @@ -7,6 +7,7 @@ ExpressionEditorView::ExpressionEditorView(Responder * parentResponder, Poincare SolidColorView(KDColorWhite), m_scrollableExpressionViewWithCursor(parentResponder, expressionLayout, cursor) { + m_serializerTextView.setText("Hello"); } void ExpressionEditorView::cursorPositionChanged() { @@ -14,7 +15,20 @@ void ExpressionEditorView::cursorPositionChanged() { m_scrollableExpressionViewWithCursor.scrollToCursor(); } +void ExpressionEditorView::setText(const char * text) { + m_serializerTextView.setText(text); +} + +View * ExpressionEditorView::subviewAtIndex(int index) { + assert(index >= 0 && index < 2); + if (index == 0) { + return &m_scrollableExpressionViewWithCursor; + } + return &m_serializerTextView; +} + void ExpressionEditorView::layoutSubviews() { + m_serializerTextView.setFrame(KDRect(0, 0, bounds().width(), 20)); m_scrollableExpressionViewWithCursor.setFrame(KDRect( k_margin, k_margin, @@ -24,7 +38,7 @@ void ExpressionEditorView::layoutSubviews() { } KDSize ExpressionEditorView::minimalSizeForOptimalDisplay() const { - return m_scrollableExpressionViewWithCursor.minimalSizeForOptimalDisplay(); + return KDSize(300, 220); } diff --git a/apps/expression_editor/expression_editor_view.h b/apps/expression_editor/expression_editor_view.h index 49116463e..def2ec2b5 100644 --- a/apps/expression_editor/expression_editor_view.h +++ b/apps/expression_editor/expression_editor_view.h @@ -11,17 +11,16 @@ class ExpressionEditorView : public SolidColorView { public: ExpressionEditorView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor); void cursorPositionChanged(); - int numberOfSubviews() const override { return 1; } + void setText(const char * text); + int numberOfSubviews() const override { return 2; } ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor() { return &m_scrollableExpressionViewWithCursor; } - View * subviewAtIndex(int index) override { - assert(index == 0); - return &m_scrollableExpressionViewWithCursor; - } + View * subviewAtIndex(int index) override; void layoutSubviews() override; KDSize minimalSizeForOptimalDisplay() const override; private: constexpr static KDCoordinate k_margin = 10; ScrollableExpressionViewWithCursor m_scrollableExpressionViewWithCursor; + BufferTextView m_serializerTextView; }; } From 5107343a448c0ec53f4c5284f63f30b0d0a5c1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 2 Jan 2018 17:01:40 +0100 Subject: [PATCH 089/257] [ExpressionEditor] Handle EXE events: show serialized layout. Change-Id: I19be0ab5263cba42caca2ca71fe0082f3339e473 --- apps/expression_editor/controller.cpp | 9 +++++++++ apps/expression_editor/controller.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 1679d3303..888192d9f 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -29,6 +29,10 @@ void Controller::didBecomeFirstResponder() { } bool Controller::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::EXE) { + serializeLayout(); + return true; + } if (privateHandleEvent(event)) { m_view.cursorPositionChanged(); return true; @@ -139,4 +143,9 @@ bool Controller::handleDeleteEvent(Ion::Events::Event event) { return false; } +void Controller::serializeLayout() { + m_expressionLayout->writeTextInBuffer(m_buffer, k_bufferSize); + m_view.setText(const_cast(m_buffer)); +} + } diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index 3910844fa..e777e4103 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -29,9 +29,12 @@ private: bool handleMoveEvent(Ion::Events::Event event); Poincare::ExpressionLayout * handleAddEvent(Ion::Events::Event event); bool handleDeleteEvent(Ion::Events::Event event); + void serializeLayout(); ExpressionEditorView m_view; Poincare::ExpressionLayout * m_expressionLayout; Poincare::ExpressionLayoutCursor m_cursor; + static constexpr int k_bufferSize = 256; + char m_buffer[k_bufferSize]; }; } From 3fe7295f6cfaff168ec705dd8d5a057f69f74e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 10:48:03 +0100 Subject: [PATCH 090/257] [poincare] ExpressionLayoutArray was a method, it is now a class. Change-Id: Iddde7ed9d8a8539193c6547a9e718865ff8e8cc7 --- apps/math_toolbox.cpp | 15 +++++++------- poincare/include/poincare.h | 1 + .../poincare/dynamic_layout_hierarchy.h | 3 ++- poincare/include/poincare/expression_layout.h | 2 -- .../poincare/expression_layout_array.h | 20 +++++++++++++++++++ poincare/src/layout/expression_layout.cpp | 15 -------------- poincare/src/layout/grid_layout.cpp | 2 +- poincare/src/layout/grid_layout.h | 2 +- poincare/src/layout/parenthesis_layout.cpp | 5 +++-- poincare/src/layout/sequence_layout.cpp | 3 ++- .../src/layout/static_layout_hierarchy.cpp | 5 +++-- 11 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 poincare/include/poincare/expression_layout_array.h diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index a1b29bf5c..1b569b848 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -1,5 +1,6 @@ #include "math_toolbox.h" #include "./shared/toolbox_helpers.h" +#include #include #include @@ -17,9 +18,9 @@ const ToolboxMessageTree calculChildren[4] = { ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, new IntegralLayout( new HorizontalLayout( - const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2( + Poincare::ExpressionLayoutArray( new EmptyVisibleLayout(), - new StringLayout("dx",2))), 2, false), + new StringLayout("dx",2)).array(), 2, false), new EmptyVisibleLayout(), new EmptyVisibleLayout(), false), @@ -27,10 +28,10 @@ const ToolboxMessageTree calculChildren[4] = { 2), ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg, nullptr, 0, new SumLayout( - new HorizontalLayout(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2( - new StringLayout("n=",2), - new EmptyVisibleLayout())), 2, false), new EmptyVisibleLayout(), + new HorizontalLayout(Poincare::ExpressionLayoutArray( + new StringLayout("n=",2), + new EmptyVisibleLayout()).array(), 2, false), new EmptyVisibleLayout(), false), const_cast(&pointedLayoutPathSum[0]), @@ -54,9 +55,9 @@ const ToolboxMessageTree probabilityChildren[2] = { ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommandWithArg, nullptr, 0, new UneditableHorizontalTrioLayout( new ParenthesisLeftLayout(), - new GridLayout(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray2( + new GridLayout(Poincare::ExpressionLayoutArray( new EmptyVisibleLayout(), - new EmptyVisibleLayout())), + new EmptyVisibleLayout()).array(), 2, 1, false), new ParenthesisRightLayout(), false, true), const_cast(&pointedLayoutPathBinomial[0]), diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index 3bd0a9a9b..9c2e8e8f1 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index dafe85166..0a7fd488e 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -2,6 +2,7 @@ #define POINCARE_DYNAMIC_LAYOUT_HIERARCHY_H #include +#include namespace Poincare { @@ -10,7 +11,7 @@ public: DynamicLayoutHierarchy(); DynamicLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands = true); DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, bool cloneOperands = true) : - DynamicLayoutHierarchy(ExpressionLayoutArray2(operand1, operand2), 2, cloneOperands) {} + DynamicLayoutHierarchy(ExpressionLayoutArray(operand1, operand2).array(), 2, cloneOperands) {} ~DynamicLayoutHierarchy(); DynamicLayoutHierarchy(const DynamicLayoutHierarchy & other) = delete; DynamicLayoutHierarchy(DynamicLayoutHierarchy && other) = delete; diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index f366a305f..8664ed746 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -21,8 +21,6 @@ public: /* Constructor & Destructor */ ExpressionLayout(); virtual ~ExpressionLayout() = default; - static const ExpressionLayout * const * ExpressionLayoutArray2(const ExpressionLayout * e1, const ExpressionLayout * e2); - static const ExpressionLayout * const * ExpressionLayoutArray3(const ExpressionLayout * e1, const ExpressionLayout * e2, const ExpressionLayout * e3); virtual ExpressionLayout * clone() const = 0; /* Rendering */ diff --git a/poincare/include/poincare/expression_layout_array.h b/poincare/include/poincare/expression_layout_array.h new file mode 100644 index 000000000..6bdae090b --- /dev/null +++ b/poincare/include/poincare/expression_layout_array.h @@ -0,0 +1,20 @@ +#ifndef POINCARE_EXPRESSION_LAYOUT_ARRAY_H +#define POINCARE_EXPRESSION_LAYOUT_ARRAY_H + +#include + +namespace Poincare { + +class ExpressionLayoutArray { +public: + ExpressionLayoutArray(const ExpressionLayout * eL1 = nullptr, const ExpressionLayout * eL2 = nullptr, const ExpressionLayout * eL3 = nullptr) : + m_data{eL1, eL2, eL3} + {} + const ExpressionLayout * const * array() { return const_cast(m_data); } +private: + const ExpressionLayout * m_data[3]; +}; + +} + +#endif diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index d4410fb08..797b016c5 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -18,21 +18,6 @@ ExpressionLayout::ExpressionLayout() : { } -const ExpressionLayout * const * ExpressionLayout::ExpressionLayoutArray2(const ExpressionLayout * e1, const ExpressionLayout * e2) { - static const ExpressionLayout * result[2] = {nullptr, nullptr}; - result[0] = e1; - result[1] = e2; - return result; -} - -const ExpressionLayout * const * ExpressionLayout::ExpressionLayoutArray3(const ExpressionLayout * e1, const ExpressionLayout * e2, const ExpressionLayout * e3) { - static const ExpressionLayout * result[3] = {nullptr, nullptr, nullptr}; - result[0] = e1; - result[1] = e2; - result[2] = e3; - return result; -} - KDPoint ExpressionLayout::origin() { if (m_parent == nullptr) { return absoluteOrigin(); diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index b73636fc0..2d3152b09 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -9,7 +9,7 @@ extern "C" { namespace Poincare { -GridLayout::GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands) : +GridLayout::GridLayout(const ExpressionLayout * const * entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands) : DynamicLayoutHierarchy(entryLayouts, numberOfRows*numberOfColumns, cloneOperands), m_numberOfRows(numberOfRows), m_numberOfColumns(numberOfColumns) diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index e5a6bde67..a00dcb65d 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -7,7 +7,7 @@ namespace Poincare { class GridLayout : public DynamicLayoutHierarchy { public: - GridLayout(ExpressionLayout ** entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands); + GridLayout(const ExpressionLayout * const * entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands); ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index 0f9cbd1fc..cb4c372e1 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -1,7 +1,8 @@ #include "parenthesis_layout.h" -#include #include "parenthesis_left_layout.h" #include "parenthesis_right_layout.h" +#include +#include extern "C" { #include #include @@ -14,7 +15,7 @@ ParenthesisLayout::ParenthesisLayout(ExpressionLayout * operand, bool cloneOpera { ExpressionLayout * leftParenthesis = new ParenthesisLeftLayout(); ExpressionLayout * rightParenthesis = new ParenthesisRightLayout(); - build(ExpressionLayout::ExpressionLayoutArray3(leftParenthesis, operand, rightParenthesis), 3, cloneOperands); + build(ExpressionLayoutArray(leftParenthesis, operand, rightParenthesis).array(), 3, cloneOperands); } ExpressionLayout * ParenthesisLayout::clone() const { diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 6b5e9cf85..53842a678 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -3,6 +3,7 @@ #include "parenthesis_right_layout.h" #include "uneditable_horizontal_trio_layout.h" #include +#include #include #include @@ -14,7 +15,7 @@ SequenceLayout::SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * ParenthesisLeftLayout * parLeft = new ParenthesisLeftLayout(); ParenthesisRightLayout * parRight = new ParenthesisRightLayout(); UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, cloneOperands, false); - build(const_cast(Poincare::ExpressionLayout::ExpressionLayoutArray3(horLayout, lowerBound, upperBound)), 3, cloneOperands); + build(ExpressionLayoutArray(horLayout, lowerBound, upperBound).array(), 3, cloneOperands); } void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { diff --git a/poincare/src/layout/static_layout_hierarchy.cpp b/poincare/src/layout/static_layout_hierarchy.cpp index 27d6c68bb..d6d0d0a11 100644 --- a/poincare/src/layout/static_layout_hierarchy.cpp +++ b/poincare/src/layout/static_layout_hierarchy.cpp @@ -1,4 +1,5 @@ #include +#include extern "C" { #include } @@ -27,13 +28,13 @@ StaticLayoutHierarchy<1>::StaticLayoutHierarchy(const ExpressionLayout * e, bool template<> StaticLayoutHierarchy<2>::StaticLayoutHierarchy(const ExpressionLayout * e1, const ExpressionLayout * e2, bool cloneChildren) : - StaticLayoutHierarchy(ExpressionLayoutArray2(e1, e2), cloneChildren) + StaticLayoutHierarchy(ExpressionLayoutArray(e1, e2).array(), cloneChildren) { } template<> StaticLayoutHierarchy<3>::StaticLayoutHierarchy(const ExpressionLayout * e1, const ExpressionLayout * e2, const ExpressionLayout * e3, bool cloneChildren) : - StaticLayoutHierarchy(ExpressionLayoutArray3(e1, e2, e3), cloneChildren) + StaticLayoutHierarchy(ExpressionLayoutArray(e1, e2, e3).array(), cloneChildren) { } From 8e30d10e43da8d85d6a312d35ebe7543fc21ad17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 11:00:20 +0100 Subject: [PATCH 091/257] [poincare] Changed the arguments order for Sequence layouts. Change-Id: I83c535c5d3e1d263343ab7f656b5c22c82049ad4 --- poincare/src/layout/sequence_layout.cpp | 6 +++++- poincare/src/layout/sequence_layout.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 53842a678..ed7d4e46e 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -9,13 +9,17 @@ namespace Poincare { -SequenceLayout::SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands) : +SequenceLayout::SequenceLayout(ExpressionLayout * argument, ExpressionLayout * lowerBound, ExpressionLayout * upperBound, bool cloneOperands) : StaticLayoutHierarchy() { ParenthesisLeftLayout * parLeft = new ParenthesisLeftLayout(); ParenthesisRightLayout * parRight = new ParenthesisRightLayout(); UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, cloneOperands, false); build(ExpressionLayoutArray(horLayout, lowerBound, upperBound).array(), 3, cloneOperands); + if (cloneOperands) { + delete parLeft; + delete parRight; + } } void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 418eb6d94..0eeedfbd1 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -9,7 +9,7 @@ class SequenceLayout : public StaticLayoutHierarchy<3> { public: constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; - SequenceLayout(ExpressionLayout * lowerBound, ExpressionLayout * upperBound, ExpressionLayout * argument, bool cloneOperands); + SequenceLayout(ExpressionLayout * argument, ExpressionLayout * lowerBound, ExpressionLayout * upperBound, bool cloneOperands); void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; From 57dcf246752f7fdea99d29367de837f512d6b4ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 11:00:53 +0100 Subject: [PATCH 092/257] [poincare] Changed names in StaticLayoutHierarchy::build. For debugging purposes. Change-Id: I10185978cbc590ba0016516e151ecba852bd4d72 --- poincare/src/layout/static_layout_hierarchy.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/poincare/src/layout/static_layout_hierarchy.cpp b/poincare/src/layout/static_layout_hierarchy.cpp index d6d0d0a11..76314772e 100644 --- a/poincare/src/layout/static_layout_hierarchy.cpp +++ b/poincare/src/layout/static_layout_hierarchy.cpp @@ -48,15 +48,15 @@ StaticLayoutHierarchy::~StaticLayoutHierarchy() { } template -void StaticLayoutHierarchy::build(const ExpressionLayout * const * children, int numberOfChildren, bool cloneChildren) { - assert(children != nullptr); - assert(numberOfChildren <= T); - for (int i=0; i < numberOfChildren; i++) { - assert(children[i] != nullptr); - if (cloneChildren) { - m_children[i] = children[i]->clone(); +void StaticLayoutHierarchy::build(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands) { + assert(operands != nullptr); + assert(numberOfOperands <= T); + for (int i=0; i < numberOfOperands; i++) { + assert(operands[i] != nullptr); + if (cloneOperands) { + m_children[i] = operands[i]->clone(); } else { - m_children[i] = children[i]; + m_children[i] = operands[i]; } const_cast(m_children[i])->setParent(this); } From b4358ab99ab992cbd31c57d1f77ad27991d8fddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 11:02:10 +0100 Subject: [PATCH 093/257] [poincare] Changed assert condition in LayoutEngine. The function writeInfixExpressionOrExpressionLayoutTextInBuffer is now used by HorizontalLayout, which might have only 1 argument. Change-Id: Ic22baa4c43847fe1fd4a38e3180b4ae8bef18d19 --- poincare/src/layout_engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index 89a6d6664..a128948a1 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -72,7 +72,7 @@ int LayoutEngine::writeInfixExpressionOrExpressionLayoutTextInBuffer(const Expre buffer[bufferSize-1] = 0; int numberOfChar = 0; int numberOfOperands = (expression != nullptr) ? expression->numberOfOperands() : expressionLayout->numberOfChildren(); - assert(numberOfOperands > 1); + assert(numberOfOperands > 0); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } From 1ced6e23601bcdafc7884948a0d94a6a41f3c9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 14:29:03 +0100 Subject: [PATCH 094/257] [poincare] Empty ListData constructor. Change-Id: I882eb664d74399ab87ef9bd95bc1b255f5a5f87c --- poincare/include/poincare/list_data.h | 1 + poincare/src/list_data.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/poincare/include/poincare/list_data.h b/poincare/include/poincare/list_data.h index dede2436e..87f6a8f2a 100644 --- a/poincare/include/poincare/list_data.h +++ b/poincare/include/poincare/list_data.h @@ -7,6 +7,7 @@ namespace Poincare { class ListData { public: + ListData(); ListData(Expression * operand); ~ListData(); ListData(const ListData& other) = delete; diff --git a/poincare/src/list_data.cpp b/poincare/src/list_data.cpp index 110d6163c..c49ff5ff2 100644 --- a/poincare/src/list_data.cpp +++ b/poincare/src/list_data.cpp @@ -6,6 +6,11 @@ extern "C" { namespace Poincare { +ListData::ListData() : + m_numberOfOperands(0), + m_operands(new Expression*[0]) +{} + ListData::ListData(Expression * operand) : m_numberOfOperands(1), m_operands(new Expression*[1]) From 4fa64d837a4ff527dc8c1a94a11aac3f85904f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 14:29:41 +0100 Subject: [PATCH 095/257] [poincare] Parser rule for function_{args1}(args2). It is parsed as function(args2 concatenated with args1). Change-Id: I478cf7b34c6f49e5d258fe8f6af823a7d7b5941e --- poincare/src/expression_lexer.l | 1 + poincare/src/expression_parser.y | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 783e3de71..b2d04483e 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -155,6 +155,7 @@ inf { poincare_expression_yylval.expression = new Undefined(); return UNDEFINED; \] { return RIGHT_BRACKET; } \, { return COMMA; } \. { return DOT; } +\_ { return UNDERSCORE; } [ ]+ /* Ignore whitespaces */ . { return UNDEFINED_SYMBOL; } diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index dff9e93b8..e48a16e0c 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -66,6 +66,7 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char %token LEFT_BRACKET %token RIGHT_BRACKET %token COMMA +%token UNDERSCORE %token DOT %token EE %token ICOMPLEX @@ -102,8 +103,11 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char %nonassoc RIGHT_PARENTHESIS %nonassoc LEFT_BRACKET %nonassoc RIGHT_BRACKET +%nonassoc LEFT_BRACE +%nonassoc RIGHT_BRACE %nonassoc FUNCTION %left COMMA +%nonassoc UNDERSCORE %nonassoc DIGITS %nonassoc DOT %nonassoc EE @@ -149,7 +153,7 @@ lstData: /* When approximating expressions to double, results are bounded by 1E308 (and * 1E-308 for small numbers). We thus accept decimals whose exponents are in * {-1000, 1000}. However, we have to compute the exponent first to decide - * wether to accept the decimal. The exponent of a Decimal is stored as an + * whether to accept the decimal. The exponent of a Decimal is stored as an * int32_t. We thus have to throw an error when the exponent computation might * overflow. Finally, we escape computation by throwing an error when the length * of the exponent digits is above 4 (0.00...-256 times-...01E1256=1E1000 is @@ -189,6 +193,13 @@ exp: | LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { Poincare::Expression * terms[1] = {$2}; $$ = new Poincare::Parenthesis(terms, false); } /* MATRICES_ARE_DEFINED */ | LEFT_BRACKET mtxData RIGHT_BRACKET { $$ = new Poincare::Matrix($2); delete $2; } + | FUNCTION UNDERSCORE LEFT_BRACE lstData RIGHT_BRACE LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; int totalNumberOfArguments = $4->numberOfOperands()+$7->numberOfOperands(); +if (!$1->hasValidNumberOfOperands(totalNumberOfArguments)) { delete $1; delete $4; delete $7; YYERROR; }; +Poincare::ListData * arguments = new Poincare::ListData(); +for (int i = 0; i < $4->numberOfOperands(); i++) { arguments->pushExpression($4->operands()[i]); } +for (int i = 0; i < $7->numberOfOperands(); i++) { arguments->pushExpression($7->operands()[i]); } +$1->setArgument(arguments, totalNumberOfArguments, false); +$4->detachOperands(); delete $4; $7->detachOperands(); delete $7; arguments->detachOperands(); delete arguments;} | FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; if (!$1->hasValidNumberOfOperands($3->numberOfOperands())) { delete $1; delete $3; YYERROR; } ; $1->setArgument($3, $3->numberOfOperands(), false); $3->detachOperands(); delete $3; } final_exp: From 62ffb424724ef8ac26b1baed38d26d8c605eca99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 15:50:56 +0100 Subject: [PATCH 096/257] [poincare] Fixed invalidation of layout baseline and position. When adding, replacing or detaching a child. Change-Id: I3ef212fbe270cee8d0e3a11402cc6df1228ee8d5 --- poincare/include/poincare/expression_layout.h | 2 +- poincare/src/layout/dynamic_layout_hierarchy.cpp | 2 ++ poincare/src/layout/expression_layout.cpp | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 8664ed746..8f59fc403 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -93,10 +93,10 @@ protected: ExpressionLayout * m_parent; bool m_sized; bool m_baselined; + bool m_positioned; private: bool moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor); void replaceWithJuxtapositionOf(ExpressionLayout * firstLayout, ExpressionLayout * secondLayout); - bool m_positioned; KDRect m_frame; }; diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index 4d3fdf6c8..dba3cf394 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -58,6 +58,8 @@ bool DynamicLayoutHierarchy::addChildAtIndex(ExpressionLayout * child, int index m_children = newChildren; m_numberOfChildren += 1; m_sized = false; + m_positioned = false; + m_baselined = false; return true; } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 797b016c5..6364e64c1 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -184,6 +184,8 @@ void ExpressionLayout::replaceChild(const ExpressionLayout * oldChild, Expressio } } m_sized = false; + m_positioned = false; + m_baselined = false; } void ExpressionLayout::detachChild(const ExpressionLayout * e) { @@ -263,6 +265,8 @@ void ExpressionLayout::detachChildAtIndex(int i) { } op[i] = nullptr; m_sized = false; + m_positioned = false; + m_baselined = false; } bool ExpressionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { From 89760c0f427f8e61e6f1fa01ec9e3e964f6e753f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 17:15:40 +0100 Subject: [PATCH 097/257] [poincare] isCollapsable() for ExpressionLayouts. Tells whether the layout should be collapsed into the numerator (or denominator) of a new FractionLayout brother. Change-Id: Id5c2a55667bec56340d73c2a63dc704fa56c9815 --- poincare/include/poincare/expression_layout.h | 2 ++ poincare/src/layout/char_layout.cpp | 14 ++++++++++++++ poincare/src/layout/char_layout.h | 1 + poincare/src/layout/parenthesis_left_layout.cpp | 5 +++++ poincare/src/layout/parenthesis_left_layout.h | 1 + poincare/src/layout/parenthesis_right_layout.cpp | 5 +++++ poincare/src/layout/parenthesis_right_layout.h | 1 + 7 files changed, 29 insertions(+) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 8f59fc403..b3de44700 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -68,6 +68,8 @@ public: virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0; /* Other */ + virtual bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { return true; } + // isCollapsable is used when adding a brother fraction: should the layout be inserted in the numerator (or denominator)? virtual bool isHorizontal() const { return false; } virtual bool isLeftParenthesis() const { return false; } virtual bool isRightParenthesis() const { return false; } diff --git a/poincare/src/layout/char_layout.cpp b/poincare/src/layout/char_layout.cpp index 866814bda..b4e67dc52 100644 --- a/poincare/src/layout/char_layout.cpp +++ b/poincare/src/layout/char_layout.cpp @@ -1,5 +1,6 @@ #include "char_layout.h" #include +#include #include #include @@ -49,6 +50,19 @@ bool CharLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +bool CharLayout::isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { + if (*numberOfOpenParenthesis <= 0 + && (m_char == '+' + || m_char == '-' + || m_char == '*' + || m_char == Ion::Charset::MultiplicationSign + || m_char == Ion::Charset::MiddleDot)) + { + return false; + } + return true; +} + void CharLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { char string[2] = {m_char, 0}; ctx->drawString(string, p, m_fontSize, expressionColor, backgroundColor); diff --git a/poincare/src/layout/char_layout.h b/poincare/src/layout/char_layout.h index 47ba4e336..28323d228 100644 --- a/poincare/src/layout/char_layout.h +++ b/poincare/src/layout/char_layout.h @@ -18,6 +18,7 @@ public: char character() { return m_char; } bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDPoint positionOfChild(ExpressionLayout * child) override; diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index 1bd3d416a..6cf4e8d68 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -32,6 +32,11 @@ ExpressionLayout * ParenthesisLeftLayout::clone() const { return layout; } +bool ParenthesisLeftLayout::isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { + *numberOfOpenParenthesis = goingLeft ? *numberOfOpenParenthesis - 1 : *numberOfOpenParenthesis + 1; + return true; +} + void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDRect frame(p.x()+ParenthesisLeftRightLayout::k_externWidthMargin, p.y()+ParenthesisLeftRightLayout::k_externHeightMargin, diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index 782f9da01..03b3847c5 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -13,6 +13,7 @@ public: int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, '('); } + bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; bool isLeftParenthesis() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index b248e0150..8681a297b 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -32,6 +32,11 @@ ExpressionLayout * ParenthesisRightLayout::clone() const { return layout; } +bool ParenthesisRightLayout::isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { + *numberOfOpenParenthesis = goingLeft ? *numberOfOpenParenthesis + 1 : *numberOfOpenParenthesis - 1; + return true; +} + void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDRect frame = KDRect(p.x() + ParenthesisLeftRightLayout::k_widthMargin + ParenthesisLeftRightLayout::k_lineThickness - ParenthesisLeftRightLayout::k_parenthesisCurveWidth, p.y() + ParenthesisLeftRightLayout::k_externHeightMargin, diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index 137494443..134c08a24 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -13,6 +13,7 @@ public: int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, ')'); } + bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; bool isRightParenthesis() const override { return true; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; From 25c036a0785cf50b646dabd238728df0d1ed5f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 17:19:02 +0100 Subject: [PATCH 098/257] [expression_editor] Set cursor position according to the layout inserted. Change-Id: Iac33efdeb4b725ae6007282d323f446992873832 --- apps/expression_editor/controller.cpp | 3 --- poincare/src/expression_layout_cursor.cpp | 20 ++++++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 888192d9f..7c717f585 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -63,9 +63,6 @@ bool Controller::privateHandleEvent(Ion::Events::Event event) { } ExpressionLayout * newPointedLayout = handleAddEvent(event); if (newPointedLayout != nullptr) { - m_cursor.setPointedExpressionLayout(newPointedLayout); - m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); - m_cursor.setPositionInside(0); m_expressionLayout->invalidAllSizesPositionsAndBaselines(); m_view.layoutSubviews(); return true; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 71e6dad4f..f24cc664e 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -61,6 +61,8 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyExponentialLayout() { EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); pointedExpressionLayout()->addBrother(this, newChild); + setPointedExpressionLayout(child2); + setPosition(ExpressionLayoutCursor::Position::Left); return child2; } @@ -77,9 +79,11 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyLogarithmLayout() { EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Subscript, false); m_pointedExpressionLayout->addBrother(this, newChild); - m_pointedExpressionLayout = newChild; - m_position = Position::Right; - return insertText("()"); + setPointedExpressionLayout(newChild); + setPosition(ExpressionLayoutCursor::Position::Right); + insertText("()"); + moveLeft(); + return child1; } ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { @@ -87,6 +91,8 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); m_pointedExpressionLayout->addBrother(this, newChild); + setPointedExpressionLayout(child1); + setPosition(ExpressionLayoutCursor::Position::Right); return child1; } @@ -95,6 +101,8 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyRootLayout() { EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); NthRootLayout * newChild = new NthRootLayout(child1, child2, false); m_pointedExpressionLayout->addBrother(this, newChild); + setPointedExpressionLayout(child1); + setPosition(ExpressionLayoutCursor::Position::Right); return child1; } @@ -103,12 +111,16 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptySquarePowerLayout() { CharLayout * child2 = new CharLayout('2'); EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); m_pointedExpressionLayout->addBrother(this, newChild); - return child1; + setPointedExpressionLayout(newChild); + setPosition(ExpressionLayoutCursor::Position::Right); + return newChild; } ExpressionLayout * ExpressionLayoutCursor::addXNTCharLayout() { CharLayout * newChild = new CharLayout(m_pointedExpressionLayout->XNTChar()); m_pointedExpressionLayout->addBrother(this, newChild); + setPointedExpressionLayout(newChild); + setPosition(ExpressionLayoutCursor::Position::Right); return newChild; } From 8a7e4e598c2440c362a5d06614e128559ccf30a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 3 Jan 2018 17:23:35 +0100 Subject: [PATCH 099/257] [expression_editor] Collapse brothers when adding a fraction. Change-Id: I4d75fae152fca4a6671abd1e444f6aaa27c168b5 --- apps/expression_editor/controller.cpp | 2 +- .../poincare/dynamic_layout_hierarchy.h | 2 + .../poincare/expression_layout_cursor.h | 2 +- poincare/src/expression_layout_cursor.cpp | 58 ++++++++++++++----- poincare/src/layout/horizontal_layout.cpp | 10 +++- 5 files changed, 56 insertions(+), 18 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 7c717f585..2df023056 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -106,7 +106,7 @@ bool Controller::handleMoveEvent(Ion::Events::Event event) { ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { if (event == Ion::Events::Division) { - return m_cursor.addEmptyFractionLayout(); + return m_cursor.addFractionLayoutAndCollapseBrothers(); } if (event == Ion::Events::XNT) { return m_cursor.addXNTCharLayout(); diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index 0a7fd488e..8e4cffd6a 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -10,6 +10,8 @@ class DynamicLayoutHierarchy : public ExpressionLayout { public: DynamicLayoutHierarchy(); DynamicLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands = true); + DynamicLayoutHierarchy(const ExpressionLayout * operand, bool cloneOperands = true) : + DynamicLayoutHierarchy(ExpressionLayoutArray(operand).array(), 1, cloneOperands) {} DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, bool cloneOperands = true) : DynamicLayoutHierarchy(ExpressionLayoutArray(operand1, operand2).array(), 2, cloneOperands) {} ~DynamicLayoutHierarchy(); diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index b92bff74e..e6c5e9f71 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -45,7 +45,7 @@ public: /* Edition */ void addLayout(ExpressionLayout * layout); ExpressionLayout * addEmptyExponentialLayout(); - ExpressionLayout * addEmptyFractionLayout(); + ExpressionLayout * addFractionLayoutAndCollapseBrothers(); ExpressionLayout * addEmptyLogarithmLayout(); ExpressionLayout * addEmptyPowerLayout(); ExpressionLayout * addEmptyRootLayout(); diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index f24cc664e..0f55d45fa 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -1,14 +1,5 @@ #include -#include -#include //TODO move from there. -#include //TODO move from there. -#include //TODO move from there. -#include //TODO move from there. -#include //TODO move from there. -#include //TODO move from there. -#include //TODO move from there. -#include //TODO move from there. -#include //TODO move from there. +#include //TODO: finer include? #include #include @@ -66,12 +57,51 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyExponentialLayout() { return child2; } -ExpressionLayout * ExpressionLayoutCursor::addEmptyFractionLayout() { - EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); - EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); +ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers() { + // Add a new FractionLayout + HorizontalLayout * child1 = new HorizontalLayout(new EmptyVisibleLayout()); + HorizontalLayout * child2 = new HorizontalLayout(new EmptyVisibleLayout()); FractionLayout * newChild = new FractionLayout(child1, child2, false); pointedExpressionLayout()->addBrother(this, newChild); - return child1; + + if (!newChild->parent()->isHorizontal()) { + setPointedExpressionLayout(child2->editableChild(0)); + setPosition(Position::Left); + return child2; + } + + int fractionIndexInParent = newChild->parent()->indexOfChild(newChild); + int numberOfBrothers = newChild->parent()->numberOfChildren(); + + // Collapse the brothers on the right + int numberOfOpenParenthesis = 0; + while (fractionIndexInParent < numberOfBrothers - 1) { + ExpressionLayout * rightBrother = newChild->editableParent()->editableChild(fractionIndexInParent+1); + if (rightBrother->isCollapsable(&numberOfOpenParenthesis, false)) { + newChild->editableParent()->removeChildAtIndex(fractionIndexInParent+1, false); + child2->addOrMergeChildAtIndex(rightBrother, child2->numberOfChildren()); + numberOfBrothers--; + } else { + break; + } + } + // Collapse the brothers on the left + numberOfOpenParenthesis = 0; + while (fractionIndexInParent > 0) { + ExpressionLayout * leftBrother = newChild->editableParent()->editableChild(fractionIndexInParent-1); + if (leftBrother->isCollapsable(&numberOfOpenParenthesis, true)) { + newChild->editableParent()->removeChildAtIndex(fractionIndexInParent-1, false); + child1->addOrMergeChildAtIndex(leftBrother, 0); + fractionIndexInParent--; + } else { + break; + } + } + // Set the cursor position + setPointedExpressionLayout(child2->editableChild(0)); + setPosition(Position::Left); + + return child2; } ExpressionLayout * ExpressionLayoutCursor::addEmptyLogarithmLayout() { diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 38d125e6c..6a92ff30d 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -52,11 +52,17 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio } void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index) { + int newIndex = index; + if (numberOfChildren() > 0 && child(0)->isEmpty()) { + removeChildAtIndex(0, true); + newIndex = index == 0 ? 0 : index - 1; + } if (eL->isHorizontal()) { - mergeChildrenAtIndex(eL, index); + mergeChildrenAtIndex(eL, newIndex); return; } - addChildAtIndex(eL, index); + addChildAtIndex(eL, newIndex); + } bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { From 4009a0d87958f0ad9e65ff0a99788aa1be1ce90d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 15:22:52 +0100 Subject: [PATCH 100/257] [poincare] VerticalOffsetLayout and mustHaveLeftBrother() for Layouts. Change-Id: Ibd4666806bb0af2a2babe892c8a9906747c18e9a --- poincare/Makefile | 1 + poincare/include/poincare/expression_layout.h | 1 + .../src/layout/vertical_offset_layout.cpp | 254 ++++++++++++++++++ poincare/src/layout/vertical_offset_layout.h | 37 +++ 4 files changed, 293 insertions(+) create mode 100644 poincare/src/layout/vertical_offset_layout.cpp create mode 100644 poincare/src/layout/vertical_offset_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index b49e17a2c..976ffb545 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -117,6 +117,7 @@ objs += $(addprefix poincare/src/layout/,\ uneditable_horizontal_trio_layout.o\ uneditable_parenthesis_left_layout.o\ uneditable_parenthesis_right_layout.o\ + vertical_offset_layout.o\ ) tests += $(addprefix poincare/test/,\ diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index b3de44700..5b3a927a8 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -70,6 +70,7 @@ public: /* Other */ virtual bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { return true; } // isCollapsable is used when adding a brother fraction: should the layout be inserted in the numerator (or denominator)? + virtual bool mustHaveLeftBrother() const { return false; } virtual bool isHorizontal() const { return false; } virtual bool isLeftParenthesis() const { return false; } virtual bool isRightParenthesis() const { return false; } diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp new file mode 100644 index 000000000..10964d358 --- /dev/null +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -0,0 +1,254 @@ +#include "vertical_offset_layout.h" +#include "empty_visible_layout.h" +#include +#include +#include +#include + +namespace Poincare { + +VerticalOffsetLayout::VerticalOffsetLayout(ExpressionLayout * indice, Type type, bool cloneOperands) : + StaticLayoutHierarchy(indice, cloneOperands), + m_type(type) +{ +} + +ExpressionLayout * VerticalOffsetLayout::clone() const { + VerticalOffsetLayout * layout = new VerticalOffsetLayout(const_cast(this)->indiceLayout(), m_type, true); + return layout; +} + +void VerticalOffsetLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == indiceLayout()) { + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + ExpressionLayout * base = baseLayout(); + if (indiceLayout()->isEmpty()) { + int indexInParent = m_parent->indexOfChild(this); + if (base->isEmpty()) { + // Case: Empty base and indice. + // Replace with the empty base layout. + if (indexInParent <= 1) { + cursor->setPointedExpressionLayout(m_parent); + } else { + cursor->setPointedExpressionLayout(m_parent->editableChild(indexInParent - 2)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } + m_parent->removeChildAtIndex(indexInParent - 1, false); + replaceWith(base, true); + return; + } + // Case: Empty indice only. + // Delete the layout. + cursor->setPointedExpressionLayout(base); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + m_parent->removeChildAtIndex(indexInParent, true); + return; + } + // Case: Non-empty indice. + // Move Left of the VerticalOffsetLayout. + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + +bool VerticalOffsetLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the indice. + // Go Left. + if (indiceLayout() + && cursor->pointedExpressionLayout() == indiceLayout() + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the indice. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); + return true; + } + // Case: Left. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +bool VerticalOffsetLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the indice. + // Go Right. + if (indiceLayout() + && cursor->pointedExpressionLayout() == indiceLayout() + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + cursor->setPointedExpressionLayout(this); + return true; + } + + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go to the indice. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); + return true; + } + // Case: Right. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + +bool VerticalOffsetLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // Case: Superscript. + if (m_type == VerticalOffsetLayout::Type::Superscript) { + // Case: Right. + // Move to the indice. + if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) { + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Left. + // Move to the indice. + if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Left)) { + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + } + // Case: Subscript. + // Case: Left or Right of the indice. + // Put the cursor at the same position, pointing this. + if (m_type == VerticalOffsetLayout::Type::Subscript + && indiceLayout() != nullptr + && (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Left) + || cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Right))) + { + cursor->setPointedExpressionLayout(this); + return true; + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + +bool VerticalOffsetLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // Case: Subscript. + if (m_type == VerticalOffsetLayout::Type::Subscript) { + // Case: Right. + // Move to the indice. + if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) { + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + // Case: Left. + // Move to the indice. + if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Left)) { + assert(indiceLayout() != nullptr); + cursor->setPointedExpressionLayout(indiceLayout()); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + } + // Case: Superscript. + // Case: Left or Right of the indice. + // Put the cursor at the same position, pointing this. + if (m_type == VerticalOffsetLayout::Type::Superscript + && indiceLayout() != nullptr + && cursor->pointedExpressionLayout() == indiceLayout()) + { + cursor->setPointedExpressionLayout(this); + return true; + } + return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); +} + +int VerticalOffsetLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (m_type == Type::Subscript) { + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + if (bufferSize == 1) { + return 0; + } + // If the layout is a subscript, write "_{indice}" + int numberOfChar = LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, '_'); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + numberOfChar += LayoutEngine::writeOneCharInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, '{'); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + numberOfChar += const_cast(this)->indiceLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + numberOfChar += LayoutEngine::writeOneCharInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, '}'); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + return numberOfChar; + } + assert(m_type == Type::Superscript); + // If the layout is a superscript, write "^(indice)" + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "^"); +} + +ExpressionLayout * VerticalOffsetLayout::indiceLayout() { + return editableChild(0); +} + +ExpressionLayout * VerticalOffsetLayout::baseLayout() { + int indexInParent = parent()->indexOfChild(this); + assert(indexInParent > 0); + return editableParent()->editableChild(indexInParent - 1); +} + +void VerticalOffsetLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + // There is nothing to draw for a subscript/superscript, only the position of the child matters +} + +KDSize VerticalOffsetLayout::computeSize() { + KDSize indiceSize = indiceLayout()->size(); + KDCoordinate width = indiceSize.width(); + KDCoordinate height = 0; + if (m_type == Type::Subscript) { + height = positionOfChild(indiceLayout()).y()+ indiceLayout()->size().height(); + } else { + height = indiceLayout()->size().height() + baseLayout()->baseline() - k_indiceHeight; + } + return KDSize(width, height); +} + +void VerticalOffsetLayout::computeBaseline() { + if (m_type == Type::Subscript) { + m_baseline = 0; + } else { + m_baseline = size().height(); + } + m_baselined = true; +} + +KDPoint VerticalOffsetLayout::positionOfChild(ExpressionLayout * child) { + assert(child == indiceLayout()); + if (m_type == Type::Superscript) { + return KDPointZero; + } + assert(m_type == Type::Subscript); + ExpressionLayout * base = baseLayout(); + return KDPoint(0, base->size().height() - base->baseline() - k_indiceHeight); +} + +} diff --git a/poincare/src/layout/vertical_offset_layout.h b/poincare/src/layout/vertical_offset_layout.h new file mode 100644 index 000000000..bf3242cb7 --- /dev/null +++ b/poincare/src/layout/vertical_offset_layout.h @@ -0,0 +1,37 @@ +#ifndef POINCARE_VERTICAL_OFFSET_LAYOUT_H +#define POINCARE_VERTICAL_OFFSET_LAYOUT_H + +#include + +namespace Poincare { + +class VerticalOffsetLayout : public StaticLayoutHierarchy<1> { +public: + enum class Type { + Subscript, + Superscript + }; + VerticalOffsetLayout(ExpressionLayout * indice, Type type, bool cloneOperands); + ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; + bool mustHaveLeftBrother() const override { return true; } +protected: + ExpressionLayout * indiceLayout(); + ExpressionLayout * baseLayout(); + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + KDSize computeSize() override; + void computeBaseline() override; + KDPoint positionOfChild(ExpressionLayout * child) override; + Type m_type; +private: + constexpr static KDCoordinate k_indiceHeight = 5; +}; + +} + +#endif From 9753228a3dc585657509680a2f825d6fbce2dc34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 15:27:10 +0100 Subject: [PATCH 101/257] [poincare] Use the VerticalOffsetLayouts. Change-Id: I6dfc61f95016fd9863b7a4b1f41dc1784560807b --- poincare/include/poincare_layouts.h | 1 + poincare/src/expression_layout_cursor.cpp | 61 ++++++++++++++++------- poincare/src/layout/horizontal_layout.cpp | 33 ++++++++++-- poincare/src/layout/horizontal_layout.h | 3 ++ 4 files changed, 77 insertions(+), 21 deletions(-) diff --git a/poincare/include/poincare_layouts.h b/poincare/include/poincare_layouts.h index 4c339e285..b06cc8993 100644 --- a/poincare/include/poincare_layouts.h +++ b/poincare/include/poincare_layouts.h @@ -29,5 +29,6 @@ #include #include #include +#include #endif diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 0f55d45fa..2007824ab 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -1,4 +1,5 @@ #include +#include #include //TODO: finer include? #include #include @@ -49,12 +50,12 @@ void ExpressionLayoutCursor::addLayout(ExpressionLayout * layout) { ExpressionLayout * ExpressionLayoutCursor::addEmptyExponentialLayout() { CharLayout * child1 = new CharLayout(Ion::Charset::Exponential); - EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); - EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); + VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Superscript, false); + HorizontalLayout * newChild = new HorizontalLayout(child1, offsetLayout, false); pointedExpressionLayout()->addBrother(this, newChild); - setPointedExpressionLayout(child2); - setPosition(ExpressionLayoutCursor::Position::Left); - return child2; + setPointedExpressionLayout(offsetLayout->editableChild(0)); + setPosition(ExpressionLayoutCursor::Position::Right); + return offsetLayout; } ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers() { @@ -105,21 +106,37 @@ ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers( } ExpressionLayout * ExpressionLayoutCursor::addEmptyLogarithmLayout() { - StringLayout * child1 = new StringLayout("log", 3); - EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); - EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Subscript, false); + HorizontalLayout * newChild = new HorizontalLayout( + ExpressionLayoutArray( + new CharLayout('l'), + new CharLayout('o'), + new CharLayout('g')).array(), + 3, + false); + VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Subscript, false); + newChild->addChildAtIndex(offsetLayout, 3); m_pointedExpressionLayout->addBrother(this, newChild); - setPointedExpressionLayout(newChild); + setPointedExpressionLayout(offsetLayout); setPosition(ExpressionLayoutCursor::Position::Right); insertText("()"); - moveLeft(); - return child1; + setPointedExpressionLayout(offsetLayout->editableChild(0)); + setPosition(ExpressionLayoutCursor::Position::Right); + return offsetLayout; } ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { + VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Superscript, false); + // If there is already a base + int numberOfOpenParenthesis = 0; + if (!m_pointedExpressionLayout->isEmpty() && m_pointedExpressionLayout->isCollapsable(&numberOfOpenParenthesis, true)) { + m_pointedExpressionLayout->addBrother(this, offsetLayout); + setPointedExpressionLayout(offsetLayout->editableChild(0)); + setPosition(ExpressionLayoutCursor::Position::Left); + return offsetLayout; + } + // Else, add an empty base EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); - EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); - EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); + HorizontalLayout * newChild = new HorizontalLayout(child1, offsetLayout, false); m_pointedExpressionLayout->addBrother(this, newChild); setPointedExpressionLayout(child1); setPosition(ExpressionLayoutCursor::Position::Right); @@ -137,13 +154,23 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyRootLayout() { } ExpressionLayout * ExpressionLayoutCursor::addEmptySquarePowerLayout() { + CharLayout * indiceLayout = new CharLayout('2'); + VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(indiceLayout, VerticalOffsetLayout::Type::Superscript, false); + // If there is already a base + int numberOfOpenParenthesis = 0; + if (!m_pointedExpressionLayout->isEmpty() && m_pointedExpressionLayout->isCollapsable(&numberOfOpenParenthesis, true)) { + m_pointedExpressionLayout->addBrother(this, offsetLayout); + setPointedExpressionLayout(offsetLayout); + setPosition(ExpressionLayoutCursor::Position::Right); + return offsetLayout; + } + // Else, add an empty base EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); - CharLayout * child2 = new CharLayout('2'); - EditableBaselineRelativeLayout * newChild = new EditableBaselineRelativeLayout(child1, child2, BaselineRelativeLayout::Type::Superscript, false); + HorizontalLayout * newChild = new HorizontalLayout(child1, offsetLayout, false); m_pointedExpressionLayout->addBrother(this, newChild); - setPointedExpressionLayout(newChild); + setPointedExpressionLayout(child1); setPosition(ExpressionLayoutCursor::Position::Right); - return newChild; + return child1; } ExpressionLayout * ExpressionLayoutCursor::addXNTCharLayout() { diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 6a92ff30d..f0a627346 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -1,4 +1,5 @@ #include "horizontal_layout.h" +#include "empty_visible_layout.h" #include "string_layout.h" #include @@ -30,24 +31,30 @@ void HorizontalLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { if (newChild->isEmpty()) { if (numberOfChildren() > 1) { + // If the new layout is empty and the horizontal layout has other + // children, just delete the old child. if (!newChild->hasAncestor(oldChild)) { delete newChild; } removeChildAtIndex(indexOfChild(const_cast(oldChild)), deleteOldChild); return; } + // If the new layout is empty and it was the only horizontal layout child, + // replace the horizontal layout with this empty layout. if (m_parent) { replaceWith(newChild); return; } } + // If the new child is also an horizontal layout, steal the children of the + // new layout then destroy it. if (newChild->isHorizontal()) { - // Steal the children of the new layout then destroy it. int indexForInsertion = indexOfChild(const_cast(oldChild)); mergeChildrenAtIndex(newChild, indexForInsertion + 1); removeChildAtIndex(indexForInsertion, deleteOldChild); return; } + // Else, just replace the child. ExpressionLayout::replaceChild(oldChild, newChild, deleteOldChild); } @@ -167,6 +174,16 @@ bool HorizontalLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayou return moveVertically(ExpressionLayout::VerticalDirection::Down, cursor, previousLayout, previousPreviousLayout); } +void HorizontalLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { + // If the child to remove is at index 0 and its right brother must have a left + // brother (e.g. it is a VerticalOffsetLayout), replace the child with an + // EmptyVisibleLayout instead of removing it. + if (index == 0 && numberOfChildren() > 1 && child(1)->mustHaveLeftBrother()) { + addChildAtIndex(new EmptyVisibleLayout(), index + 1); + } + DynamicLayoutHierarchy::removeChildAtIndex(index, deleteAfterRemoval); +} + void HorizontalLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { } @@ -217,11 +234,19 @@ void HorizontalLayout::mergeChildrenAtIndex(ExpressionLayout * eL, int index) { removeChildAtIndex(indexOfEL, false); } int numChildren = eL->numberOfChildren(); + int currentAdditionIndex = index; for (int i = 0; i < numChildren; i++) { - ExpressionLayout * currentChild = eL->editableChild(0); - eL->removeChildAtIndex(0, false); - addChildAtIndex(currentChild, index+i); + ExpressionLayout * currentChild = eL->editableChild(i); + // Do not add empty children if we can + if (!currentChild->isEmpty() + || i == numChildren - 1 + || (i < numChildren - 1 && eL->editableChild(i+1)->mustHaveLeftBrother())) + { + addChildAtIndex(currentChild, currentAdditionIndex++); + eL->detachChild(currentChild); + } } + delete eL; } bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index c4aa2a027..209fda198 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -22,6 +22,9 @@ public: bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + /* Dynamic layout */ + void removeChildAtIndex(int index, bool deleteAfterRemoval) override; + /* Expression Engine */ int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); From 98faf01b537404fdb9d2ae8d88ac2ed660c8bb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 15:27:44 +0100 Subject: [PATCH 102/257] [poincare] Better Fraction collapsing. Change-Id: Ic898f522ae26cfcd5917f4da85715f85a5861b9f --- .../poincare/dynamic_layout_hierarchy.h | 2 + .../src/layout/dynamic_layout_hierarchy.cpp | 13 ++-- poincare/src/layout/expression_layout.cpp | 2 +- poincare/src/layout/fraction_layout.cpp | 75 ++++++++----------- 4 files changed, 43 insertions(+), 49 deletions(-) diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index 8e4cffd6a..ec698cd46 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -25,6 +25,8 @@ public: bool addChildAtIndex(ExpressionLayout * operand, int index) override; void removeChildAtIndex(int index, bool deleteAfterRemoval) override; + + bool isEmpty() const override; protected: const ExpressionLayout ** m_children; int m_numberOfChildren; diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index dba3cf394..f2cea1145 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -70,15 +70,18 @@ void DynamicLayoutHierarchy::removeChildAtIndex(int index, bool deleteAfterRemov const_cast(m_children[index])->setParent(nullptr); } m_numberOfChildren--; - /*if (m_numberOfChildren == 0) { - ExpressionLayout * emptyVisibleLayout = new EmptyVisibleLayout(); - replaceWith(emptyVisibleLayout); - return; - }*/ for (int j=index; jisEmpty())) + { + return true; + } + return false; } } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 6364e64c1..f3598d780 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -113,7 +113,7 @@ void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLay if (m_parent) { int brotherIndex = cursor->position() == ExpressionLayoutCursor::Position::Left ? m_parent->indexOfChild(this) : m_parent->indexOfChild(this) + 1; if (m_parent->isHorizontal()) { - m_parent->addChildAtIndex(brother, brotherIndex); + static_cast(m_parent)->addOrMergeChildAtIndex(brother, brotherIndex); return; } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 71b9555aa..b499e96b9 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -18,55 +18,44 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { // a horizontal juxtaposition of the numerator and the denominator. if (cursor->pointedExpressionLayout() == denominatorLayout()) { assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - if (numeratorLayout()->isEmpty()) { - if (denominatorLayout()->isEmpty()) { - // If the numerator and the denominator are empty, replace the fraction - // with an empty layout. - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(new EmptyVisibleLayout(), true); - // Place the cursor on the right of the left brother ofthe fraction if - // there is one. - if (indexInParent > 0) { - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - // Else place the cursor on the Left of the parent. - cursor->setPointedExpressionLayout(previousParent); + if (numeratorLayout()->isEmpty() && denominatorLayout()->isEmpty()) { + // If the numerator and the denominator are empty, replace the fraction + // with an empty layout. + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(new EmptyVisibleLayout(), true); + // Place the cursor on the right of the left brother of the fraction if + // there is one. + if (indexInParent > 0) { + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); return; } - // If the numerator is empty but not the denominator, replace the fraction - // with its denominator. Place the cursor on the left of the denominator. - ExpressionLayout * nextPointedLayout = denominatorLayout(); - if (denominatorLayout()->isHorizontal()) { - nextPointedLayout = denominatorLayout()->editableChild(0); - } - replaceWith(denominatorLayout(), true); - cursor->setPointedExpressionLayout(nextPointedLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); + // Else place the cursor on the Left of the parent. + cursor->setPointedExpressionLayout(previousParent); return; } - // If the denominator is empty but not the numerator, replace the fraction - // with the numerator and place the cursor on its right. - if (denominatorLayout()->isEmpty()) { - ExpressionLayout * nextPointedLayout = numeratorLayout(); - if (numeratorLayout()->isHorizontal()) { - nextPointedLayout = numeratorLayout()->editableChild(numeratorLayout()->numberOfChildren() - 1); - } - replaceWith(numeratorLayout(), true); - cursor->setPointedExpressionLayout(nextPointedLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - // If neither the numerator nor the denominator are empty, replace the - // fraction with a juxtaposition of the numerator and denominator. Place the - // cursor in the middle of the juxtaposition, which is right of the - // numerator. + + // Else, replace the fraction with a juxtaposition of the numerator and + // denominator. Place the cursor in the middle of the juxtaposition, which + // is right of the numerator. + + // Prepare the cursor position. ExpressionLayout * nextPointedLayout = numeratorLayout(); - if (numeratorLayout()->isHorizontal()) { + ExpressionLayoutCursor::Position nextPosition = ExpressionLayoutCursor::Position::Right; + if (numeratorLayout()->isEmpty()) { + int indexInParent = m_parent->indexOfChild(this); + if (indexInParent > 0) { + nextPointedLayout = m_parent->editableChild(indexInParent - 1); + } else { + nextPointedLayout = m_parent; + nextPosition = ExpressionLayoutCursor::Position::Left; + } + } else if (numeratorLayout()->isHorizontal()) { nextPointedLayout = numeratorLayout()->editableChild(numeratorLayout()->numberOfChildren() - 1); } + + // Juxtapose. ExpressionLayout * numerator = numeratorLayout(); ExpressionLayout * denominator = denominatorLayout(); detachChild(numerator); @@ -77,7 +66,7 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { // Add the denominator before the numerator to have the right order. replaceWith(newLayout, true); cursor->setPointedExpressionLayout(nextPointedLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); + cursor->setPosition(nextPosition); return; } // If the cursor is on the left of the numerator, move Left of the fraction. From 65d7fd7a01072e51653c68c8d3e194290b1a036d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 15:28:19 +0100 Subject: [PATCH 103/257] [poincare] Added comment to explain baselines. Change-Id: I769c55c48c80bdce6deb8a7fc23ccc36bdc398a9 --- poincare/include/poincare/expression_layout.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 5b3a927a8..e39253317 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -93,6 +93,9 @@ protected: int * resultPositionInside, int * resultScore); KDCoordinate m_baseline; + /* m_baseline is the signed vertical distance from the top of the layout to + * the fraction bar of an hypothetical fraction brother layout. If the top of + * the layout is under that bar, the baseline is negative. */ ExpressionLayout * m_parent; bool m_sized; bool m_baselined; From e8560f7b9789f1ac31b572bcbcc21c0e0cf481ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 15:29:03 +0100 Subject: [PATCH 104/257] [poincare] Fixed coding style. Change-Id: Ic57dfd53a3ae70cf71be08b73935c9f7649c2b76 --- poincare/src/layout/baseline_relative_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index 133d6c563..824c1c286 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -125,7 +125,7 @@ KDPoint BaselineRelativeLayout::positionOfChild(ExpressionLayout * child) { } if (child == indiceLayout()) { x = baseLayout()->size().width(); - y = m_type == Type::Superscript ? 0 : baseLayout()->size().height() - k_indiceHeight; + y = m_type == Type::Superscript ? 0 : baseLayout()->size().height() - k_indiceHeight; } return KDPoint(x,y); } From 0f5019442f1411d2179be3896dbfce7c09f31b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 16:00:24 +0100 Subject: [PATCH 105/257] [poincare] Fixed parenthesis collapsing bug. Pressing "(", "1", "/" collapsed the parenthesis. Change-Id: Iebd8925c1e8518013f0e0aa9a45bb42881583640 --- poincare/src/layout/parenthesis_left_layout.cpp | 3 +++ poincare/src/layout/parenthesis_right_layout.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index 6cf4e8d68..e9e5f638e 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -33,6 +33,9 @@ ExpressionLayout * ParenthesisLeftLayout::clone() const { } bool ParenthesisLeftLayout::isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { + if (*numberOfOpenParenthesis == 0 && goingLeft) { + return false; + } *numberOfOpenParenthesis = goingLeft ? *numberOfOpenParenthesis - 1 : *numberOfOpenParenthesis + 1; return true; } diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index 8681a297b..6d7f73eea 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -33,6 +33,9 @@ ExpressionLayout * ParenthesisRightLayout::clone() const { } bool ParenthesisRightLayout::isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { + if (*numberOfOpenParenthesis == 0 && !goingLeft) { + return false; + } *numberOfOpenParenthesis = goingLeft ? *numberOfOpenParenthesis + 1 : *numberOfOpenParenthesis - 1; return true; } From 21ed3471b1386ce0243faace23f1e8c71f615e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 16:01:37 +0100 Subject: [PATCH 106/257] [poincare] Fixed parenthesis height computing. Before, it did not take the baseline into account. Change-Id: Ib1b220d7c07eab7002497671e9c6ffba8548acfb --- poincare/src/layout/parenthesis_left_layout.cpp | 16 ++++++++++++++-- poincare/src/layout/parenthesis_right_layout.cpp | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index e9e5f638e..6122d5d08 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -65,6 +65,8 @@ void ParenthesisLeftLayout::render(KDContext * ctx, KDPoint p, KDColor expressio void ParenthesisLeftLayout::computeOperandHeight() { assert(m_parent != nullptr); m_operandHeight = Metric::MinimalBracketAndParenthesisHeight; + KDCoordinate max_under_baseline = 0; + KDCoordinate max_above_baseline = 0; int currentNumberOfOpenParentheses = 1; int numberOfBrothers = m_parent->numberOfChildren(); for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { @@ -72,15 +74,25 @@ void ParenthesisLeftLayout::computeOperandHeight() { if (brother->isRightParenthesis()) { currentNumberOfOpenParentheses--; if (currentNumberOfOpenParentheses == 0) { + if (max_under_baseline + max_above_baseline > m_operandHeight) { + m_operandHeight = max_under_baseline + max_above_baseline; + } return; } } else if (brother->isLeftParenthesis()) { currentNumberOfOpenParentheses++; } KDCoordinate brotherHeight = brother->size().height(); - if (brotherHeight > m_operandHeight) { - m_operandHeight = brotherHeight; + KDCoordinate brotherBaseline = brother->baseline(); + if (brotherHeight - brotherBaseline > max_under_baseline) { + max_under_baseline = brotherHeight - brotherBaseline ; } + if (brotherBaseline > max_above_baseline) { + max_above_baseline = brotherBaseline; + } + } + if (max_under_baseline + max_above_baseline > m_operandHeight) { + m_operandHeight = max_under_baseline + max_above_baseline; } } diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index 6d7f73eea..9d3b2c50b 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -65,21 +65,33 @@ void ParenthesisRightLayout::render(KDContext * ctx, KDPoint p, KDColor expressi void ParenthesisRightLayout::computeOperandHeight() { assert(m_parent != nullptr); m_operandHeight = Metric::MinimalBracketAndParenthesisHeight; + KDCoordinate max_under_baseline = 0; + KDCoordinate max_above_baseline = 0; int currentNumberOfOpenParentheses = 1; for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { ExpressionLayout * brother = m_parent->editableChild(i); if (brother->isLeftParenthesis()) { currentNumberOfOpenParentheses--; if (currentNumberOfOpenParentheses == 0) { + if (max_under_baseline + max_above_baseline > m_operandHeight) { + m_operandHeight = max_under_baseline + max_above_baseline; + } return; } } else if (brother->isRightParenthesis()) { currentNumberOfOpenParentheses++; } KDCoordinate brotherHeight = brother->size().height(); - if (brotherHeight > m_operandHeight) { - m_operandHeight = brotherHeight; + KDCoordinate brotherBaseline = brother->baseline(); + if (brotherHeight - brotherBaseline > max_under_baseline) { + max_under_baseline = brotherHeight - brotherBaseline ; } + if (brotherBaseline > max_above_baseline) { + max_above_baseline = brotherBaseline; + } + } + if (max_under_baseline + max_above_baseline > m_operandHeight) { + m_operandHeight = max_under_baseline + max_above_baseline; } } From a998ae454132429863b31ce2a0ca3ac6e9068ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 5 Jan 2018 10:10:54 +0100 Subject: [PATCH 107/257] [poincare] Fixed parenthesis baseline computing. Change-Id: I38ecb8bab67280f6e452bc9ef404a00641060879 --- poincare/src/layout/parenthesis_left_layout.cpp | 17 +++++++++++++++-- .../src/layout/parenthesis_right_layout.cpp | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index 6122d5d08..aaa91ede0 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -98,12 +98,25 @@ void ParenthesisLeftLayout::computeOperandHeight() { void ParenthesisLeftLayout::computeBaseline() { assert(m_parent != nullptr); - m_baseline = operandHeight()/2; int currentNumberOfOpenParentheses = 1; + int indexInParent = m_parent->indexOfChild(this); int numberOfBrothers = m_parent->numberOfChildren(); - for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { + if (indexInParent == numberOfBrothers - 1) { + // The parenthesis is the rightmost child of its parent. + m_baseline = operandHeight()/2; + m_baselined = true; + return; + } + m_baseline = 0; + for (int i = indexInParent + 1; i < numberOfBrothers; i++) { ExpressionLayout * brother = m_parent->editableChild(i); if (brother->isRightParenthesis()) { + if (i == indexInParent + 1) { + // If the parenthesis is immediately closed, we set the baseline to half + // the parenthesis height. + m_baseline = operandHeight()/2; + break; + } currentNumberOfOpenParentheses--; if (currentNumberOfOpenParentheses == 0) { break; diff --git a/poincare/src/layout/parenthesis_right_layout.cpp b/poincare/src/layout/parenthesis_right_layout.cpp index 9d3b2c50b..e0346d42b 100644 --- a/poincare/src/layout/parenthesis_right_layout.cpp +++ b/poincare/src/layout/parenthesis_right_layout.cpp @@ -97,11 +97,24 @@ void ParenthesisRightLayout::computeOperandHeight() { void ParenthesisRightLayout::computeBaseline() { assert(m_parent != nullptr); - m_baseline = operandHeight()/2; int currentNumberOfOpenParentheses = 1; - for (int i = m_parent->indexOfChild(this) - 1; i >= 0; i--) { + int indexInParent = m_parent->indexOfChild(this); + if (indexInParent == 0) { + // The parenthesis is the leftmost child of its parent. + m_baseline = operandHeight()/2; + m_baselined = true; + return; + } + m_baseline = 0; + for (int i = indexInParent - 1; i >= 0; i--) { ExpressionLayout * brother = m_parent->editableChild(i); if (brother->isLeftParenthesis()) { + if (i == indexInParent - 1) { + // If the parenthesis is immediately closed, we set the baseline to half + // the parenthesis height. + m_baseline = operandHeight()/2; + break; + } currentNumberOfOpenParentheses--; if (currentNumberOfOpenParentheses == 0) { break; From 211227e6821e9c15ea44321ec57826da626ccf3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 16:08:00 +0100 Subject: [PATCH 108/257] [poincare] Changed NthRootLayout deleting. Before, nested roots did not get deleted properly. Change-Id: I1d3dce28912a4843a372db8c3a0b479bd11b27f9 --- poincare/src/layout/nth_root_layout.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index d23514edc..2a166bf7d 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -38,8 +38,14 @@ void NthRootLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout * previousParent = m_parent; int indexInParent = previousParent->indexOfChild(this); replaceWith(radicandLayout()); - // Place the cursor on the right of the left brother of the root if there is - // one. + // Place the cursor on the left of what replaced the root if possible. + if (indexInParent < previousParent->numberOfChildren()) { + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + // Else place the cursor on the right of the left brother of the root if + // there is one. if (indexInParent > 0) { cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); From 23eccd2c75e7ca620a9b111a63b0d57231df4dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 16:49:51 +0100 Subject: [PATCH 109/257] [poincare] Cleaned the dynamic methods for layouts. Change-Id: I17db05b01c75a638a56fe2c197a175fd1b04840d --- .../poincare/dynamic_layout_hierarchy.h | 2 ++ poincare/include/poincare/expression_layout.h | 2 ++ .../src/layout/dynamic_layout_hierarchy.cpp | 34 +++++++++++++++++++ poincare/src/layout/expression_layout.cpp | 6 ++++ poincare/src/layout/horizontal_layout.cpp | 26 ++------------ poincare/src/layout/horizontal_layout.h | 1 - 6 files changed, 46 insertions(+), 25 deletions(-) diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index ec698cd46..8099c50ef 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -23,8 +23,10 @@ public: int numberOfChildren() const override { return m_numberOfChildren; } const ExpressionLayout * const * children() const override { return m_children; }; + void addNonEmptyChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion); bool addChildAtIndex(ExpressionLayout * operand, int index) override; void removeChildAtIndex(int index, bool deleteAfterRemoval) override; + void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index); // WITHOUT delete. bool isEmpty() const override; protected: diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index e39253317..1277db657 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -50,6 +50,8 @@ public: ExpressionLayout * replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace); virtual void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true); void detachChild(const ExpressionLayout * e); // Removes a child WITHOUT deleting it + void detachChildren(); //Removes all children WITHOUT deleting them + /* Dynamic Layout*/ virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index f2cea1145..707383ed4 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -42,6 +42,40 @@ DynamicLayoutHierarchy::~DynamicLayoutHierarchy() { delete[] m_children; } +void DynamicLayoutHierarchy::mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index) { + int indexOfEL = indexOfChild(eL); + if (indexOfEL >= 0) { + removeChildAtIndex(indexOfEL, false); + } + addNonEmptyChildrenAtIndex(eL->children(), eL->numberOfChildren(), index); + eL->detachChildren(); + delete eL; +} + +void DynamicLayoutHierarchy::addNonEmptyChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion) { + assert(numberOfOperands > 0); + const ExpressionLayout ** newOperands = new const ExpressionLayout * [m_numberOfChildren+numberOfOperands]; + int currentIndex = 0; + assert(indexForInsertion <= m_numberOfChildren); + for (int i=0; iisEmpty() + || (i < numberOfOperands-1 && operands[i+1]->mustHaveLeftBrother())) + { + const_cast(operands[i])->setParent(this); + newOperands[currentIndex++] = operands[i]; + } + } + for (int i=indexForInsertion; i= 0 && index <= m_numberOfChildren); const ExpressionLayout ** newChildren = new const ExpressionLayout * [m_numberOfChildren+1]; diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index f3598d780..845ab35fd 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -197,6 +197,12 @@ void ExpressionLayout::detachChild(const ExpressionLayout * e) { } } +void ExpressionLayout::detachChildren() { + for (int i = 0; i = 0 && index < numberOfChildren()); replaceChild(editableChild(index), new EmptyVisibleLayout(), deleteAfterRemoval); diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index f0a627346..0840332aa 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -50,7 +50,7 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio // new layout then destroy it. if (newChild->isHorizontal()) { int indexForInsertion = indexOfChild(const_cast(oldChild)); - mergeChildrenAtIndex(newChild, indexForInsertion + 1); + mergeChildrenAtIndex(static_cast(newChild), indexForInsertion + 1); removeChildAtIndex(indexForInsertion, deleteOldChild); return; } @@ -65,11 +65,10 @@ void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index) newIndex = index == 0 ? 0 : index - 1; } if (eL->isHorizontal()) { - mergeChildrenAtIndex(eL, newIndex); + mergeChildrenAtIndex(static_cast(eL), newIndex); return; } addChildAtIndex(eL, newIndex); - } bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -228,27 +227,6 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x, y); } -void HorizontalLayout::mergeChildrenAtIndex(ExpressionLayout * eL, int index) { - int indexOfEL = indexOfChild(eL); - if (indexOfEL >= 0) { - removeChildAtIndex(indexOfEL, false); - } - int numChildren = eL->numberOfChildren(); - int currentAdditionIndex = index; - for (int i = 0; i < numChildren; i++) { - ExpressionLayout * currentChild = eL->editableChild(i); - // Do not add empty children if we can - if (!currentChild->isEmpty() - || i == numChildren - 1 - || (i < numChildren - 1 && eL->editableChild(i+1)->mustHaveLeftBrother())) - { - addChildAtIndex(currentChild, currentAdditionIndex++); - eL->detachChild(currentChild); - } - } - delete eL; -} - bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // Prevent looping fom child to parent if (previousPreviousLayout == this) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 209fda198..223263b22 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -38,7 +38,6 @@ protected: KDSize computeSize() override; void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; - void mergeChildrenAtIndex(ExpressionLayout * eL, int index); // WITHOUT delete. private: bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); }; From bfe4735199f13a751c25159825ec4223e1613c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 16:50:25 +0100 Subject: [PATCH 110/257] [poincare] Fix bug when replacing child in Horizontal layout. Change-Id: I99b6e32932db27376c83eafe1a4ff5044b1d3334 --- poincare/src/layout/horizontal_layout.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 0840332aa..4af8b824f 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -29,6 +29,9 @@ void HorizontalLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { } void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { + if (newChild->hasAncestor(this)) { + newChild->editableParent()->detachChild(newChild); + } if (newChild->isEmpty()) { if (numberOfChildren() > 1) { // If the new layout is empty and the horizontal layout has other From 48dc38da569b9fea4ad1d69695718b454aa123a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 4 Jan 2018 17:47:59 +0100 Subject: [PATCH 111/257] [poincare] Fixed "dx" removal when deleting an IntegralLayout. Change-Id: I65494adf8d5bc732e95270ed6397b49a5303e7b0 --- poincare/src/layout/integral_layout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index f41c8bf2c..59756cd91 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -39,9 +39,9 @@ void IntegralLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout * dxLayout = integrandLayout()->editableChild(integrandLayout()->numberOfChildren()-1); replaceWith(integrandLayout(), true); // Remove "dx" - int indexOfdx = previousParent->indexOfChild(dxLayout); + int indexOfdx = dxLayout->parent()->indexOfChild(dxLayout); if (indexOfdx >= 0) { - previousParent->removeChildAtIndex(indexOfdx, true); + const_cast(dxLayout->parent())->removeChildAtIndex(indexOfdx, true); } // Place the cursor on the right of the left brother of the integral if // there is one. From 7c3b97fe36e26609c3f03825d2ed4c555a4826d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 5 Jan 2018 10:59:02 +0100 Subject: [PATCH 112/257] [poincare] Fixed fraction deletion. There was a problem with the new cursor position. Change-Id: Iac163e236b45b776fc98bdef75e2abc5d13c2b18 --- poincare/src/layout/fraction_layout.cpp | 37 ++++++++++++++++--------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index b499e96b9..c7e6677d6 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -19,20 +19,31 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { if (cursor->pointedExpressionLayout() == denominatorLayout()) { assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (numeratorLayout()->isEmpty() && denominatorLayout()->isEmpty()) { - // If the numerator and the denominator are empty, replace the fraction - // with an empty layout. - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(new EmptyVisibleLayout(), true); - // Place the cursor on the right of the left brother of the fraction if - // there is one. - if (indexInParent > 0) { - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; + // If the numerator and the denominator are empty, move the cursor then + // replace the fraction with an empty layout. + // We need to perform these actions in this order because the replacement + // might delete the fraction's parent: if the parent is an + // HorizontalLayout and the fraction is its only child, the + // HorizontalLayout will be replaced by the new EmptyLayout. + ExpressionLayout * newEmptyLayout = new EmptyVisibleLayout(); + if (!m_parent->isHorizontal() + || (m_parent->isHorizontal() && m_parent->numberOfChildren() == 1)) + { + cursor->setPointedExpressionLayout(newEmptyLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + } else { + assert(m_parent->isHorizontal()); + assert(m_parent->numberOfChildren() > 0); + int indexInParent = m_parent->indexOfChild(this); + if (indexInParent > 0) { + cursor->setPointedExpressionLayout(m_parent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } else { + cursor->setPointedExpressionLayout(m_parent->editableChild(indexInParent + 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + } } - // Else place the cursor on the Left of the parent. - cursor->setPointedExpressionLayout(previousParent); + replaceWith(newEmptyLayout, true); return; } From 4478885566fadb2cb2a6a37e39be52919a966d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 5 Jan 2018 11:51:38 +0100 Subject: [PATCH 113/257] [poincare] "Hard draw" dx in IntegralLayout, instead of layouting it. This simplifies the navigation, edition and serialization of IntegralLayout. Change-Id: I03360bf83eeb0cbd9524c992518dff125900e9a5 --- apps/math_toolbox.cpp | 9 ++--- poincare/src/layout/char_layout.h | 1 + poincare/src/layout/horizontal_layout.h | 1 + poincare/src/layout/integral_layout.cpp | 47 +++++++++++++------------ 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 1b569b848..0798669b9 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -11,21 +11,18 @@ using namespace Poincare; * and the text which would be edited by clicking on the row. When the node is a * subtree, the edited text is set at I18n::Message::Default. */ -const int pointedLayoutPathIntegral[] = {0, 0}; +const int pointedLayoutPathIntegral[] = {0}; const int pointedLayoutPathSum[] = {0, 1}; const ToolboxMessageTree calculChildren[4] = { ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg, nullptr, 0), ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, new IntegralLayout( - new HorizontalLayout( - Poincare::ExpressionLayoutArray( - new EmptyVisibleLayout(), - new StringLayout("dx",2)).array(), 2, false), + new EmptyVisibleLayout(), new EmptyVisibleLayout(), new EmptyVisibleLayout(), false), const_cast(&pointedLayoutPathIntegral[0]), - 2), + 1), ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg, nullptr, 0, new SumLayout( new EmptyVisibleLayout(), diff --git a/poincare/src/layout/char_layout.h b/poincare/src/layout/char_layout.h index 28323d228..cbdb775b8 100644 --- a/poincare/src/layout/char_layout.h +++ b/poincare/src/layout/char_layout.h @@ -16,6 +16,7 @@ public: } char character() { return m_char; } + KDText::FontSize fontSize() const { return m_fontSize; } bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 223263b22..ed0afc9a1 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class HorizontalLayout : public DynamicLayoutHierarchy { + friend class IntegralLayout; public: using DynamicLayoutHierarchy::DynamicLayoutHierarchy; ExpressionLayout * clone() const override; diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 59756cd91..4844e5a6f 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -1,4 +1,7 @@ #include "integral_layout.h" +#include "char_layout.h" +#include "horizontal_layout.h" +#include "string_layout.h" #include #include #include @@ -36,13 +39,7 @@ void IntegralLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { { ExpressionLayout * previousParent = m_parent; int indexInParent = previousParent->indexOfChild(this); - ExpressionLayout * dxLayout = integrandLayout()->editableChild(integrandLayout()->numberOfChildren()-1); replaceWith(integrandLayout(), true); - // Remove "dx" - int indexOfdx = dxLayout->parent()->indexOfChild(dxLayout); - if (indexOfdx >= 0) { - const_cast(dxLayout->parent())->removeChildAtIndex(indexOfdx, true); - } // Place the cursor on the right of the left brother of the integral if // there is one. if (indexInParent > 0) { @@ -55,10 +52,9 @@ void IntegralLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { return; } // If the cursor is on the right, move to the integrand. - if (cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Right)) { - assert(integrandLayout()->numberOfChildren() > 1); - ExpressionLayout * layoutLeftOfdx = integrandLayout()->editableChild(integrandLayout()->numberOfChildren()-2); - cursor->setPointedExpressionLayout(layoutLeftOfdx); + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + cursor->setPointedExpressionLayout(integrandLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return; } @@ -92,11 +88,11 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { } assert(cursor->pointedExpressionLayout() == this); // Case: Right of the integral. - // Go Left of "dx". + // Go to the integrand. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(integrandLayout() != nullptr); - cursor->setPointedExpressionLayout(integrandLayout()->editableChild(integrandLayout()->numberOfChildren() - 1)); - return cursor->moveLeft(); + cursor->setPointedExpressionLayout(integrandLayout()); + return true; } assert(cursor->position() == ExpressionLayoutCursor::Position::Left); // Case: Left of the brackets. @@ -117,18 +113,18 @@ bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { && cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(integrandLayout() != nullptr); - cursor->setPointedExpressionLayout(integrandLayout()->editableChild(0)); + cursor->setPointedExpressionLayout(integrandLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } // Case: Right the integrand. - // Go Right and move Right. + // Go Right. if (integrandLayout() && cursor->pointedExpressionLayout() == integrandLayout() && cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(this); - return m_parent->moveRight(cursor); + return true; } assert(cursor->pointedExpressionLayout() == this); // Case: Left of the integral. @@ -199,11 +195,9 @@ int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize) const { return bufferSize-1; } - // Write the argument without the "dx" + // Write the argument ExpressionLayout * intLayout = const_cast(this)->integrandLayout(); - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(intLayout, buffer+numberOfChar, bufferSize-numberOfChar, "", 0, intLayout->numberOfChildren()-2); - // TODO This works because the argument layout should always be an horizontal - // layout. + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(intLayout, buffer+numberOfChar, bufferSize-numberOfChar, ""); // Write the comma if (numberOfChar >= bufferSize-1) { return bufferSize-1; } @@ -232,6 +226,8 @@ void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDSize integrandSize = integrandLayout()->size(); KDSize upperBoundSize = upperBoundLayout()->size(); KDColor workingBuffer[k_symbolWidth*k_symbolHeight]; + + // Render the integral symbol. KDRect topSymbolFrame(p.x() + k_symbolWidth + k_lineThickness, p.y() + upperBoundSize.height() - k_boundHeightMargin, k_symbolWidth, k_symbolHeight); ctx->blendRectWithMask(topSymbolFrame, expressionColor, (const uint8_t *)topSymbolPixel, (KDColor *)workingBuffer); @@ -241,15 +237,22 @@ void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, ctx->blendRectWithMask(bottomSymbolFrame, expressionColor, (const uint8_t *)bottomSymbolPixel, (KDColor *)workingBuffer); ctx->fillRect(KDRect(p.x() + k_symbolWidth, p.y() + upperBoundSize.height() - k_boundHeightMargin, k_lineThickness, 2*k_boundHeightMargin+2*k_integrandHeigthMargin+integrandSize.height()), expressionColor); + + // Render "dx". + CharLayout * dummydx = new CharLayout('d'); + HorizontalLayout dummyLayout(integrandLayout()->clone(), dummydx, false); + KDPoint dxPosition = dummyLayout.positionOfChild(dummydx); + ctx->drawString("dx", dxPosition.translatedBy(p).translatedBy(positionOfChild(integrandLayout())), dummydx->fontSize(), expressionColor, backgroundColor); } KDSize IntegralLayout::computeSize() { + KDSize dxSize = StringLayout("dx", 2).size(); KDSize integrandSize = integrandLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( - k_symbolWidth+k_lineThickness+k_boundWidthMargin+max(lowerBoundSize.width(), upperBoundSize.width())+k_integrandWidthMargin+integrandSize.width(), - upperBoundSize.height()+ 2*k_integrandHeigthMargin+integrandSize.height()+lowerBoundSize.height()); + k_symbolWidth+k_lineThickness+k_boundWidthMargin+max(lowerBoundSize.width(), upperBoundSize.width())+k_integrandWidthMargin+integrandSize.width()+dxSize.width(), + upperBoundSize.height()+ 2*k_integrandHeigthMargin+max(integrandSize.height(), dxSize.height())+lowerBoundSize.height()); } void IntegralLayout::computeBaseline() { From 4cc107b15f24238694c8811b352508bbde8b6c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 5 Jan 2018 17:23:59 +0100 Subject: [PATCH 114/257] [poincare] "Hard draw" n= in SequenceLayout, instead of layouting it. Change-Id: I79aa6ab0f46c0a05a3c2fe1dd88b287dc09dac17 --- apps/math_toolbox.cpp | 4 +- poincare/src/layout/horizontal_layout.h | 1 + poincare/src/layout/product_layout.cpp | 19 +++++--- poincare/src/layout/sequence_layout.cpp | 58 +++++++++++++++---------- poincare/src/layout/sequence_layout.h | 3 +- poincare/src/layout/string_layout.h | 1 + poincare/src/layout/sum_layout.cpp | 19 +++++--- 7 files changed, 66 insertions(+), 39 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 0798669b9..648bc194f 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -26,9 +26,7 @@ const ToolboxMessageTree calculChildren[4] = { ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg, nullptr, 0, new SumLayout( new EmptyVisibleLayout(), - new HorizontalLayout(Poincare::ExpressionLayoutArray( - new StringLayout("n=",2), - new EmptyVisibleLayout()).array(), 2, false), + new EmptyVisibleLayout(), new EmptyVisibleLayout(), false), const_cast(&pointedLayoutPathSum[0]), diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index ed0afc9a1..bb72a1740 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class HorizontalLayout : public DynamicLayoutHierarchy { friend class IntegralLayout; + friend class SequenceLayout; public: using DynamicLayoutHierarchy::DynamicLayoutHierarchy; ExpressionLayout * clone() const override; diff --git a/poincare/src/layout/product_layout.cpp b/poincare/src/layout/product_layout.cpp index 1be482165..c09a14dad 100644 --- a/poincare/src/layout/product_layout.cpp +++ b/poincare/src/layout/product_layout.cpp @@ -1,6 +1,7 @@ #include "product_layout.h" -#include -#include +#include "char_layout.h" +#include "horizontal_layout.h" +#include namespace Poincare { @@ -14,17 +15,23 @@ int ProductLayout::writeTextInBuffer(char * buffer, int bufferSize) const { } void ProductLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + // Compute sizes. KDSize upperBoundSize = upperBoundLayout()->size(); - KDSize lowerBoundSize = lowerBoundLayout()->size(); - ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), + KDSize lowerBoundSizeWithNEquals = HorizontalLayout(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone()).array(), 3, false).size(); + + // Render the Product symbol. + ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSizeWithNEquals.width()-k_symbolWidth)/2), p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_lineThickness, k_symbolHeight), expressionColor); - ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), + ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSizeWithNEquals.width()-k_symbolWidth)/2), p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_symbolWidth, k_lineThickness), expressionColor); - ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2)+k_symbolWidth, + ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSizeWithNEquals.width()-k_symbolWidth)/2)+k_symbolWidth, p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_lineThickness, k_symbolHeight), expressionColor); + + // Render the "n=". + SequenceLayout::render(ctx, p, expressionColor, backgroundColor); } } diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index ed7d4e46e..1446b83bb 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -1,4 +1,7 @@ #include "sequence_layout.h" +#include "char_layout.h" +#include "horizontal_layout.h" +#include "string_layout.h" #include "parenthesis_left_layout.h" #include "parenthesis_right_layout.h" #include "uneditable_horizontal_trio_layout.h" @@ -79,7 +82,7 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { && cursor->pointedExpressionLayout() == argumentWithParenthesesLayout()) { assert(lowerBoundLayout() != nullptr); - cursor->setPointedExpressionLayout(lowerBoundLayout()->editableChild(1)); + cursor->setPointedExpressionLayout(lowerBoundLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } @@ -160,7 +163,7 @@ bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout // If the cursor is inside the upper bound, move it to the lower bound. if (upperBoundLayout() && previousLayout == upperBoundLayout()) { assert(lowerBoundLayout() != nullptr); - return lowerBoundLayout()->editableChild(1)->moveDownInside(cursor); + return lowerBoundLayout()->moveDownInside(cursor); } // If the cursor is Left of the argument, move it to the lower bound. if (argumentLayout() @@ -199,10 +202,8 @@ int SequenceLayout::writeDerivedClassInBuffer(const char * operatorName, char * buffer[numberOfChar++] = ','; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - // Write the lower bound without the "n=" - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(const_cast(this)->lowerBoundLayout(), buffer+numberOfChar, bufferSize-numberOfChar, "", 1); - // TODO This works because the lower bound layout should always be an - // horizontal layout. + // Write the lower bound + numberOfChar += const_cast(this)->lowerBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the comma @@ -237,32 +238,31 @@ ExpressionLayout * SequenceLayout::argumentWithParenthesesLayout() { KDSize SequenceLayout::computeSize() { KDSize argumentSize = argumentWithParenthesesLayout()->size(); - KDSize lowerBoundSize = lowerBoundLayout()->size(); + KDSize lowerBoundSizeWithNEquals = HorizontalLayout(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone()).array(), 3, false).size(); KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( - max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSize.width(), - baseline() + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSize.height(), argumentSize.height() - argumentLayout()->baseline()) + max(max(k_symbolWidth, lowerBoundSizeWithNEquals.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSize.width(), + baseline() + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSizeWithNEquals.height(), argumentSize.height() - argumentLayout()->baseline()) ); } -void SequenceLayout::computeBaseline() { - m_baseline = max(upperBoundLayout()->size().height()+k_boundHeightMargin+(k_symbolHeight+1)/2, argumentLayout()->baseline()); - m_baselined = true; -} - -KDPoint SequenceLayout::positionOfChild(ExpressionLayout * child) { - KDSize lowerBoundSize = lowerBoundLayout()->size(); +KDPoint SequenceLayout::positionOfChild(ExpressionLayout * eL) { + ExpressionLayout * lowerBoundClone = lowerBoundLayout()->clone(); + HorizontalLayout dummyLayout1(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundClone).array(), 3, false); + KDSize lowerBoundSizeWithNEquals = dummyLayout1.size(); KDSize upperBoundSize = upperBoundLayout()->size(); KDCoordinate x = 0; KDCoordinate y = 0; - if (child == lowerBoundLayout()) { - x = max(max(0, (k_symbolWidth-lowerBoundSize.width())/2), (upperBoundSize.width()-lowerBoundSize.width())/2); + if (eL == lowerBoundLayout()) { + x = dummyLayout1.positionOfChild(lowerBoundClone).x() + +max(max(0, (k_symbolWidth-lowerBoundSizeWithNEquals.width())/2), + (upperBoundSize.width()-lowerBoundSizeWithNEquals.width())/2); y = baseline() + k_symbolHeight/2 + k_boundHeightMargin; - } else if (child == upperBoundLayout()) { - x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSize.width()-upperBoundSize.width())/2); + } else if (eL == upperBoundLayout()) { + x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSizeWithNEquals.width()-upperBoundSize.width())/2); y = baseline() - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); - } else if (child == argumentWithParenthesesLayout()) { - x = max(max(k_symbolWidth, lowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin; + } else if (eL == argumentWithParenthesesLayout()) { + x = max(max(k_symbolWidth, lowerBoundSizeWithNEquals.width()), upperBoundSize.width())+k_argumentWidthMargin; y = baseline() - argumentLayout()->baseline(); } else { assert(false); @@ -270,4 +270,18 @@ KDPoint SequenceLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x,y); } +void SequenceLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + // Render the "n=". + CharLayout * dummyN = new CharLayout('n'); + ExpressionLayout * lowerBoundClone = lowerBoundLayout()->clone(); + HorizontalLayout dummyLayout(ExpressionLayoutArray(dummyN, new CharLayout('='), lowerBoundClone).array(), 3, false); + KDPoint nEqualsPosition = positionOfChild(lowerBoundLayout()).translatedBy((dummyLayout.positionOfChild(lowerBoundClone)).opposite()).translatedBy(dummyLayout.positionOfChild(dummyN)); + ctx->drawString("n=", p.translatedBy(nEqualsPosition), dummyN->fontSize(), expressionColor, backgroundColor); +} + +void SequenceLayout::computeBaseline() { + m_baseline = max(upperBoundLayout()->size().height()+k_boundHeightMargin+(k_symbolHeight+1)/2, argumentLayout()->baseline()); + m_baselined = true; +} + } diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 0eeedfbd1..8fd6e4f69 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -25,7 +25,8 @@ protected: ExpressionLayout * argumentLayout(); ExpressionLayout * argumentWithParenthesesLayout(); KDSize computeSize() override; - KDPoint positionOfChild(ExpressionLayout * child) override; + KDPoint positionOfChild(ExpressionLayout * eL) override; + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; private: void computeBaseline() override; }; diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index 40301736b..8ba55f65e 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -19,6 +19,7 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; char * text() { return m_string; } + KDText::FontSize fontSize() { return m_fontSize; } bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index 857ae525e..88685d135 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -1,7 +1,7 @@ #include "sum_layout.h" -#include -#include -#include +#include "char_layout.h" +#include "horizontal_layout.h" +#include namespace Poincare { @@ -33,14 +33,19 @@ int SumLayout::writeTextInBuffer(char * buffer, int bufferSize) const { } void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + // Computes sizes. KDSize upperBoundSize = upperBoundLayout()->size(); - KDSize lowerBoundSize = lowerBoundLayout()->size(); - KDCoordinate argBaseline = argumentLayout()->baseline(); + KDSize lowerBoundSizeWithNEquals = HorizontalLayout(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone()).array(), 3, false).size(); + + // Render the Sum symbol. KDColor workingBuffer[k_symbolWidth*k_symbolHeight]; - KDRect symbolFrame(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSize.width()-k_symbolWidth)/2), - p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argBaseline /*argumentLayout()->baseline()*/-(k_symbolHeight+1)/2), + KDRect symbolFrame(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSizeWithNEquals.width()-k_symbolWidth)/2), + p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_symbolWidth, k_symbolHeight); ctx->blendRectWithMask(symbolFrame, expressionColor, (const uint8_t *)symbolPixel, (KDColor *)workingBuffer); + + // Render the "n=". + SequenceLayout::render(ctx, p, expressionColor, backgroundColor); } } From 41310a4ecfac0d1fa6874f349e03854c1e3b1934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 10:57:07 +0100 Subject: [PATCH 115/257] [poincare] "Hard draw" the fixed parentheses in SequenceLayout. Change-Id: Id626c85a7db540148bf9cb05ddb968c3f807454f --- apps/math_toolbox.cpp | 4 +- poincare/src/layout/parenthesis_left_layout.h | 1 + .../src/layout/parenthesis_right_layout.h | 1 + poincare/src/layout/product_layout.cpp | 2 +- poincare/src/layout/sequence_layout.cpp | 45 +++++++++---------- poincare/src/layout/sequence_layout.h | 1 - poincare/src/layout/sum_layout.cpp | 2 +- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 648bc194f..15ddc098f 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -12,7 +12,7 @@ using namespace Poincare; * subtree, the edited text is set at I18n::Message::Default. */ const int pointedLayoutPathIntegral[] = {0}; -const int pointedLayoutPathSum[] = {0, 1}; +const int pointedLayoutPathSum[] = {0}; const ToolboxMessageTree calculChildren[4] = { ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg, nullptr, 0), ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, @@ -30,7 +30,7 @@ const ToolboxMessageTree calculChildren[4] = { new EmptyVisibleLayout(), false), const_cast(&pointedLayoutPathSum[0]), - 2), + 1), ToolboxMessageTree(I18n::Message::ProductCommandWithArg, I18n::Message::Product, I18n::Message::ProductCommandWithArg)}; const int pointedLayoutPathConj[] = {0}; diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index 03b3847c5..9b4c34ced 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { + friend class SequenceLayout; public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; ExpressionLayout * clone() const override; diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index 134c08a24..7e1eb8578 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class ParenthesisRightLayout : public ParenthesisLeftRightLayout { + friend class SequenceLayout; public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; ExpressionLayout * clone() const override; diff --git a/poincare/src/layout/product_layout.cpp b/poincare/src/layout/product_layout.cpp index c09a14dad..9ab4732b9 100644 --- a/poincare/src/layout/product_layout.cpp +++ b/poincare/src/layout/product_layout.cpp @@ -30,7 +30,7 @@ void ProductLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, p.y() + max(upperBoundSize.height()+k_boundHeightMargin, argumentLayout()->baseline()-(k_symbolHeight+1)/2), k_lineThickness, k_symbolHeight), expressionColor); - // Render the "n=". + // Render the "n=" and the parentheses. SequenceLayout::render(ctx, p, expressionColor, backgroundColor); } diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 1446b83bb..468768646 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -1,28 +1,17 @@ #include "sequence_layout.h" #include "char_layout.h" #include "horizontal_layout.h" -#include "string_layout.h" #include "parenthesis_left_layout.h" #include "parenthesis_right_layout.h" -#include "uneditable_horizontal_trio_layout.h" #include #include -#include #include namespace Poincare { SequenceLayout::SequenceLayout(ExpressionLayout * argument, ExpressionLayout * lowerBound, ExpressionLayout * upperBound, bool cloneOperands) : - StaticLayoutHierarchy() + StaticLayoutHierarchy(argument, lowerBound, upperBound) { - ParenthesisLeftLayout * parLeft = new ParenthesisLeftLayout(); - ParenthesisRightLayout * parRight = new ParenthesisRightLayout(); - UneditableHorizontalTrioLayout * horLayout = new UneditableHorizontalTrioLayout(parLeft, argument, parRight, cloneOperands, false); - build(ExpressionLayoutArray(horLayout, lowerBound, upperBound).array(), 3, cloneOperands); - if (cloneOperands) { - delete parLeft; - delete parRight; - } } void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { @@ -79,7 +68,7 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go Right of the lower bound. if (cursor->position() == ExpressionLayoutCursor::Position::Left && argumentLayout() - && cursor->pointedExpressionLayout() == argumentWithParenthesesLayout()) + && cursor->pointedExpressionLayout() == argumentLayout()) { assert(lowerBoundLayout() != nullptr); cursor->setPointedExpressionLayout(lowerBoundLayout()); @@ -121,7 +110,7 @@ bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. if (cursor->position() == ExpressionLayoutCursor::Position::Right && argumentLayout() - && cursor->pointedExpressionLayout() == argumentWithParenthesesLayout()) + && cursor->pointedExpressionLayout() == argumentLayout()) { cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); @@ -229,20 +218,19 @@ ExpressionLayout * SequenceLayout::lowerBoundLayout() { } ExpressionLayout * SequenceLayout::argumentLayout() { - return argumentWithParenthesesLayout()->editableChild(1); -} - -ExpressionLayout * SequenceLayout::argumentWithParenthesesLayout() { return editableChild(0); } KDSize SequenceLayout::computeSize() { - KDSize argumentSize = argumentWithParenthesesLayout()->size(); KDSize lowerBoundSizeWithNEquals = HorizontalLayout(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone()).array(), 3, false).size(); + ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); + ParenthesisRightLayout * dummyRightParenthesis = new ParenthesisRightLayout(); + HorizontalLayout dummyLayout2(ExpressionLayoutArray(dummyLeftParenthesis, argumentLayout()->clone(), dummyRightParenthesis).array(), 3, false); + KDSize dummyLayoutSize = dummyLayout2.size(); KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( - max(max(k_symbolWidth, lowerBoundSizeWithNEquals.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSize.width(), - baseline() + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSizeWithNEquals.height(), argumentSize.height() - argumentLayout()->baseline()) + max(max(k_symbolWidth, lowerBoundSizeWithNEquals.width()), upperBoundSize.width())+k_argumentWidthMargin+dummyLayoutSize.width(), + baseline() + max(k_symbolHeight/2+k_boundHeightMargin+lowerBoundSizeWithNEquals.height(), dummyLayoutSize.height() - argumentLayout()->baseline()) ); } @@ -251,6 +239,8 @@ KDPoint SequenceLayout::positionOfChild(ExpressionLayout * eL) { HorizontalLayout dummyLayout1(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundClone).array(), 3, false); KDSize lowerBoundSizeWithNEquals = dummyLayout1.size(); KDSize upperBoundSize = upperBoundLayout()->size(); + ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); + HorizontalLayout dummyLayout2(dummyLeftParenthesis, argumentLayout()->clone(), false); KDCoordinate x = 0; KDCoordinate y = 0; if (eL == lowerBoundLayout()) { @@ -261,8 +251,8 @@ KDPoint SequenceLayout::positionOfChild(ExpressionLayout * eL) { } else if (eL == upperBoundLayout()) { x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSizeWithNEquals.width()-upperBoundSize.width())/2); y = baseline() - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height(); - } else if (eL == argumentWithParenthesesLayout()) { - x = max(max(k_symbolWidth, lowerBoundSizeWithNEquals.width()), upperBoundSize.width())+k_argumentWidthMargin; + } else if (eL == argumentLayout()) { + x = max(max(k_symbolWidth, lowerBoundSizeWithNEquals.width()), upperBoundSize.width())+k_argumentWidthMargin+dummyLeftParenthesis->size().width(); y = baseline() - argumentLayout()->baseline(); } else { assert(false); @@ -277,6 +267,15 @@ void SequenceLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, HorizontalLayout dummyLayout(ExpressionLayoutArray(dummyN, new CharLayout('='), lowerBoundClone).array(), 3, false); KDPoint nEqualsPosition = positionOfChild(lowerBoundLayout()).translatedBy((dummyLayout.positionOfChild(lowerBoundClone)).opposite()).translatedBy(dummyLayout.positionOfChild(dummyN)); ctx->drawString("n=", p.translatedBy(nEqualsPosition), dummyN->fontSize(), expressionColor, backgroundColor); + + // Render the parentheses. + ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); + ParenthesisRightLayout * dummyRightParenthesis = new ParenthesisRightLayout(); + HorizontalLayout dummyLayout2(ExpressionLayoutArray(dummyLeftParenthesis, argumentLayout()->clone(), dummyRightParenthesis).array(), 3, false); + KDPoint leftParenthesisPoint = positionOfChild(argumentLayout()).translatedBy(dummyLayout2.positionOfChild(dummyLeftParenthesis)).translatedBy(dummyLayout2.positionOfChild(dummyLayout2.editableChild(1)).opposite()); + KDPoint rightParenthesisPoint = positionOfChild(argumentLayout()).translatedBy(dummyLayout2.positionOfChild(dummyRightParenthesis)).translatedBy(dummyLayout2.positionOfChild(dummyLayout2.editableChild(1)).opposite()); + dummyLeftParenthesis->render(ctx, p.translatedBy(leftParenthesisPoint), expressionColor, backgroundColor); + dummyRightParenthesis->render(ctx, p.translatedBy(rightParenthesisPoint), expressionColor, backgroundColor); } void SequenceLayout::computeBaseline() { diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 8fd6e4f69..8969398ce 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -23,7 +23,6 @@ protected: ExpressionLayout * lowerBoundLayout(); ExpressionLayout * upperBoundLayout(); ExpressionLayout * argumentLayout(); - ExpressionLayout * argumentWithParenthesesLayout(); KDSize computeSize() override; KDPoint positionOfChild(ExpressionLayout * eL) override; void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index 88685d135..7906d2a0c 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -44,7 +44,7 @@ void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDCo k_symbolWidth, k_symbolHeight); ctx->blendRectWithMask(symbolFrame, expressionColor, (const uint8_t *)symbolPixel, (KDColor *)workingBuffer); - // Render the "n=". + // Render the "n=" and the parentheses. SequenceLayout::render(ctx, p, expressionColor, backgroundColor); } From 83bd562fb85384b9a196d6b8bb606de891b61747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 11:05:34 +0100 Subject: [PATCH 116/257] [poincare] Fixed IntegralLayout serialization. The integrand was not properly written. Change-Id: I063ed0ee58986174a374cc6b06b49bd5ec4a4d7d --- poincare/src/layout/integral_layout.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 4844e5a6f..dfdae4e2d 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -196,27 +196,26 @@ int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize) const { } // Write the argument - ExpressionLayout * intLayout = const_cast(this)->integrandLayout(); - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(intLayout, buffer+numberOfChar, bufferSize-numberOfChar, ""); + numberOfChar += const_cast(this)->integrandLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the comma - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } buffer[numberOfChar++] = ','; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the lower bound numberOfChar += const_cast(this)->lowerBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the comma - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } buffer[numberOfChar++] = ','; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the upper bound numberOfChar += const_cast(this)->upperBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the closing parenthesis - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } buffer[numberOfChar++] = ')'; buffer[numberOfChar] = 0; return numberOfChar; From 55044d8e0b42f5219d0784322bfdf1cf750ea220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 14:39:35 +0100 Subject: [PATCH 117/257] [poincare] Update Expression's privateCreateLayout(). We use the new layouts and no longer the old ones such as StringLayout or BaselineRelativeLayout. Change-Id: Ic15167b694c3adab46f348c8f823ce19b3e5ef33 --- apps/math_toolbox.cpp | 4 +- .../poincare/dynamic_layout_hierarchy.h | 2 + poincare/include/poincare/layout_engine.h | 2 + poincare/include/poincare/product.h | 2 +- poincare/include/poincare/sum.h | 2 +- poincare/src/ceiling.cpp | 4 +- poincare/src/complex.cpp | 21 +++--- poincare/src/decimal.cpp | 4 +- poincare/src/factorial.cpp | 10 +-- poincare/src/integer.cpp | 10 +-- poincare/src/integral.cpp | 10 +-- poincare/src/layout_engine.cpp | 71 ++++++++++++------- poincare/src/logarithm.cpp | 32 ++++----- poincare/src/multiplication.cpp | 34 ++++----- poincare/src/naperian_logarithm.cpp | 3 - poincare/src/opposite.cpp | 23 +++--- poincare/src/parenthesis.cpp | 6 +- poincare/src/power.cpp | 50 +++++++------ poincare/src/product.cpp | 4 +- poincare/src/rational.cpp | 1 - poincare/src/sequence.cpp | 11 +-- poincare/src/store.cpp | 13 ++-- poincare/src/subtraction.cpp | 16 ++--- poincare/src/sum.cpp | 4 +- poincare/src/symbol.cpp | 47 +++++++++--- poincare/src/undefined.cpp | 6 +- 26 files changed, 219 insertions(+), 173 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 15ddc098f..612e4324f 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -48,13 +48,13 @@ const ToolboxMessageTree complexChildren[5] = { const int pointedLayoutPathBinomial[] = {1,0}; const ToolboxMessageTree probabilityChildren[2] = { ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommandWithArg, nullptr, 0, - new UneditableHorizontalTrioLayout( + new HorizontalLayout( new ParenthesisLeftLayout(), new GridLayout(Poincare::ExpressionLayoutArray( new EmptyVisibleLayout(), new EmptyVisibleLayout()).array(), 2, 1, false), - new ParenthesisRightLayout(), false, true), + new ParenthesisRightLayout(), false), const_cast(&pointedLayoutPathBinomial[0]), 2), ToolboxMessageTree(I18n::Message::PermuteCommandWithArg, I18n::Message::Permutation, I18n::Message::PermuteCommandWithArg)}; diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index 8099c50ef..a75e9fc41 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -14,6 +14,8 @@ public: DynamicLayoutHierarchy(ExpressionLayoutArray(operand).array(), 1, cloneOperands) {} DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, bool cloneOperands = true) : DynamicLayoutHierarchy(ExpressionLayoutArray(operand1, operand2).array(), 2, cloneOperands) {} + DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, const ExpressionLayout * operand3, bool cloneOperands = true) : + DynamicLayoutHierarchy(ExpressionLayoutArray(operand1, operand2, operand3).array(), 3, cloneOperands) {} ~DynamicLayoutHierarchy(); DynamicLayoutHierarchy(const DynamicLayoutHierarchy & other) = delete; DynamicLayoutHierarchy(DynamicLayoutHierarchy && other) = delete; diff --git a/poincare/include/poincare/layout_engine.h b/poincare/include/poincare/layout_engine.h index e1b14d0ef..f5838d0f9 100644 --- a/poincare/include/poincare/layout_engine.h +++ b/poincare/include/poincare/layout_engine.h @@ -11,6 +11,8 @@ public: /* Expression to ExpressionLayout */ static ExpressionLayout * createInfixLayout(const Expression * expression, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat, const char * operatorName); static ExpressionLayout * createPrefixLayout(const Expression * expression, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat, const char * operatorName); + static ExpressionLayout * createParenthesedLayout(ExpressionLayout * layout, bool cloneLayout); + static ExpressionLayout * createStringLayout(const char * buffer, int bufferSize, KDText::FontSize fontSize = KDText::FontSize::Large); /* Expression to Text */ typedef bool (*OperandNeedsParenthesis)(const Expression * e); diff --git a/poincare/include/poincare/product.h b/poincare/include/poincare/product.h index ba5fe91c5..954a1aa20 100644 --- a/poincare/include/poincare/product.h +++ b/poincare/include/poincare/product.h @@ -13,7 +13,7 @@ public: private: const char * name() const override; int emptySequenceValue() const override; - ExpressionLayout * createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const override; + ExpressionLayout * createSequenceLayoutWithArgumentLayouts(ExpressionLayout * argumentLayout, ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout) const override; Expression * evaluateWithNextTerm(DoublePrecision p, Expression * a, Expression * b) const override { return templatedApproximateWithNextTerm(a, b); } diff --git a/poincare/include/poincare/sum.h b/poincare/include/poincare/sum.h index 854e59d57..1aae88773 100644 --- a/poincare/include/poincare/sum.h +++ b/poincare/include/poincare/sum.h @@ -13,7 +13,7 @@ public: private: const char * name() const override; int emptySequenceValue() const override; - ExpressionLayout * createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const override; + ExpressionLayout * createSequenceLayoutWithArgumentLayouts(ExpressionLayout * argumentLayout, ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout) const override; Expression * evaluateWithNextTerm(DoublePrecision p, Expression * a, Expression * b) const override { return templatedApproximateWithNextTerm(a, b); } diff --git a/poincare/src/ceiling.cpp b/poincare/src/ceiling.cpp index 3e1b551da..dc6b050b5 100644 --- a/poincare/src/ceiling.cpp +++ b/poincare/src/ceiling.cpp @@ -1,13 +1,13 @@ #include #include "layout/ceiling_layout.h" +#include +#include #include #include #include -#include extern "C" { #include } -#include namespace Poincare { diff --git a/poincare/src/complex.cpp b/poincare/src/complex.cpp index d4cb71a93..7ba3ac97a 100644 --- a/poincare/src/complex.cpp +++ b/poincare/src/complex.cpp @@ -1,14 +1,15 @@ #include +#include +#include "layout/horizontal_layout.h" +#include "layout/vertical_offset_layout.h" +#include +#include extern "C" { #include #include #include #include } -#include -#include "layout/editable_string_layout.h" -#include "layout/editable_baseline_relative_layout.h" -#include namespace Poincare { @@ -443,7 +444,7 @@ ExpressionLayout * Complex::createPolarLayout(Expression::FloatDisplayMode fl if (std::isnan(r()) || (std::isnan(th()) && r() != 0)) { numberOfCharInBase = convertFloatToText(NAN, bufferBase, PrintFloat::k_maxComplexBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode); - return new EditableStringLayout(bufferBase, numberOfCharInBase); + return LayoutEngine::createStringLayout(bufferBase, numberOfCharInBase); } if (r() != 1 || th() == 0) { numberOfCharInBase = convertFloatToText(r(), bufferBase, PrintFloat::k_maxFloatBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode); @@ -463,16 +464,20 @@ ExpressionLayout * Complex::createPolarLayout(Expression::FloatDisplayMode fl bufferSuperscript[numberOfCharInSuperscript] = 0; } if (numberOfCharInSuperscript == 0) { - return new EditableStringLayout(bufferBase, numberOfCharInBase); + return LayoutEngine::createStringLayout(bufferBase, numberOfCharInBase); } - return new EditableBaselineRelativeLayout(new EditableStringLayout(bufferBase, numberOfCharInBase), new EditableStringLayout(bufferSuperscript, numberOfCharInSuperscript), BaselineRelativeLayout::Type::Superscript, false); + ExpressionLayout * result = LayoutEngine::createStringLayout(bufferBase, numberOfCharInBase); + ExpressionLayout * exponentLayout = LayoutEngine::createStringLayout(bufferSuperscript, numberOfCharInSuperscript); + VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(exponentLayout, VerticalOffsetLayout::Type::Superscript, false); + (static_cast(result))->addChildAtIndex(offsetLayout, result->numberOfChildren()); + return result; } template ExpressionLayout * Complex::createCartesianLayout(Expression::FloatDisplayMode floatDisplayMode) const { char buffer[PrintFloat::k_maxComplexBufferLength]; int numberOfChars = convertComplexToText(buffer, PrintFloat::k_maxComplexBufferLength, Preferences::sharedPreferences()->numberOfSignificantDigits(), floatDisplayMode, Expression::ComplexFormat::Cartesian, Ion::Charset::MiddleDot); - return new EditableStringLayout(buffer, numberOfChars); + return LayoutEngine::createStringLayout(buffer, numberOfChars); } template class Complex; diff --git a/poincare/src/decimal.cpp b/poincare/src/decimal.cpp index 400866c16..4ad75aab4 100644 --- a/poincare/src/decimal.cpp +++ b/poincare/src/decimal.cpp @@ -9,8 +9,6 @@ extern "C" { #include } -#include "layout/editable_string_layout.h" - namespace Poincare { int Decimal::exponent(const char * integralPart, int integralPartLength, const char * fractionalPart, int fractionalPartLength, const char * exponent, int exponentLength, bool exponentNegative) { @@ -204,7 +202,7 @@ int Decimal::writeTextInBuffer(char * buffer, int bufferSize) const { ExpressionLayout * Decimal::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { char buffer[255]; int numberOfChars = writeTextInBuffer(buffer, 255); - return new EditableStringLayout(buffer, numberOfChars); + return LayoutEngine::createStringLayout(buffer, numberOfChars); } Expression * Decimal::shallowReduce(Context& context, AngleUnit angleUnit) { diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp index da49dabf0..436b91067 100644 --- a/poincare/src/factorial.cpp +++ b/poincare/src/factorial.cpp @@ -1,5 +1,5 @@ #include -#include "layout/editable_string_layout.h" +#include "layout/char_layout.h" #include "layout/horizontal_layout.h" #include #include @@ -76,10 +76,10 @@ Complex Factorial::computeOnComplex(const Complex c, AngleUnit angleUnit) ExpressionLayout * Factorial::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat); - childrenLayouts[1] = new EditableStringLayout("!", 1); - return new HorizontalLayout(childrenLayouts, 2, false); + HorizontalLayout * result = new HorizontalLayout(); + result->addOrMergeChildAtIndex(operand(0)->createLayout(floatDisplayMode, complexFormat), 0); + result->addChildAtIndex(new CharLayout('!'), result->numberOfChildren()); + return result; } int Factorial::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index cb27eb6ef..b35f601ea 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -1,13 +1,13 @@ #include +#include +#include +#include +#include extern "C" { #include #include #include } -#include -#include -#include "layout/editable_string_layout.h" -#include namespace Poincare { @@ -618,7 +618,7 @@ int Integer::writeTextInBuffer(char * buffer, int bufferSize) const { ExpressionLayout * Integer::createLayout() const { char buffer[255]; int numberOfChars = writeTextInBuffer(buffer, 255); - return new EditableStringLayout(buffer, numberOfChars); + return LayoutEngine::createStringLayout(buffer, numberOfChars); } template float Poincare::Integer::approximate() const; diff --git a/poincare/src/integral.cpp b/poincare/src/integral.cpp index 596c838e2..4846a6c6b 100644 --- a/poincare/src/integral.cpp +++ b/poincare/src/integral.cpp @@ -8,7 +8,6 @@ extern "C" { #include #include } -#include "layout/string_layout.h" #include "layout/integral_layout.h" #include "layout/horizontal_layout.h" @@ -59,10 +58,11 @@ Complex * Integral::templatedApproximate(Context & context, AngleUnit angleUn ExpressionLayout * Integral::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat); - childrenLayouts[1] = new StringLayout("dx", 2); - return new IntegralLayout(operand(1)->createLayout(floatDisplayMode, complexFormat), operand(2)->createLayout(floatDisplayMode, complexFormat), new HorizontalLayout(childrenLayouts, 2, false), false); + return new IntegralLayout( + operand(0)->createLayout(floatDisplayMode, complexFormat), + operand(1)->createLayout(floatDisplayMode, complexFormat), + operand(2)->createLayout(floatDisplayMode, complexFormat), + false); } template diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index a128948a1..45621b54a 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -1,7 +1,9 @@ #include -#include "layout/string_layout.h" -#include "layout/parenthesis_layout.h" +#include "layout/char_layout.h" #include "layout/horizontal_layout.h" +#include "layout/parenthesis_left_layout.h" +#include "layout/parenthesis_right_layout.h" +#include "layout/string_layout.h" extern "C" { #include } @@ -13,39 +15,56 @@ ExpressionLayout * LayoutEngine::createInfixLayout(const Expression * expression assert(complexFormat != Expression::ComplexFormat::Default); int numberOfOperands = expression->numberOfOperands(); assert(numberOfOperands > 1); - ExpressionLayout** children_layouts = new ExpressionLayout * [2*numberOfOperands-1]; - children_layouts[0] = expression->operand(0)->createLayout(); - for (int i=1; ioperand(i)->type() == Expression::Type::Opposite ? new ParenthesisLayout(expression->operand(i)->createLayout(floatDisplayMode, complexFormat), false) : expression->operand(i)->createLayout(floatDisplayMode, complexFormat); + HorizontalLayout * result = new HorizontalLayout(); + result->addOrMergeChildAtIndex(expression->operand(0)->createLayout(), 0); + for (int i = 1; i < numberOfOperands; i++) { + result->addOrMergeChildAtIndex(createStringLayout(operatorName, strlen(operatorName)), result->numberOfChildren()); + result->addOrMergeChildAtIndex( + expression->operand(i)->type() == Expression::Type::Opposite ? + createParenthesedLayout(expression->operand(i)->createLayout(floatDisplayMode, complexFormat), false) : + expression->operand(i)->createLayout(floatDisplayMode, complexFormat), + result->numberOfChildren()); } - /* HorizontalLayout holds the children layouts so they do not need to be - * deleted here. */ - ExpressionLayout * layout = new HorizontalLayout(children_layouts, 2*numberOfOperands-1); - delete[] children_layouts; - return layout; + return result; } ExpressionLayout * LayoutEngine::createPrefixLayout(const Expression * expression, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat, const char * operatorName) { assert(floatDisplayMode != Expression::FloatDisplayMode::Default); assert(complexFormat != Expression::ComplexFormat::Default); int numberOfOperands = expression->numberOfOperands(); - ExpressionLayout ** grandChildrenLayouts = new ExpressionLayout *[2*numberOfOperands-1]; - int layoutIndex = 0; - grandChildrenLayouts[layoutIndex++] = expression->operand(0)->createLayout(floatDisplayMode, complexFormat); + HorizontalLayout * result = new HorizontalLayout(); + + // Add the operator name. + result->addOrMergeChildAtIndex(createStringLayout(operatorName, strlen(operatorName)), 0); + + // Create the layout of arguments separated by commas. + HorizontalLayout * args = new HorizontalLayout(); + args->addOrMergeChildAtIndex(expression->operand(0)->createLayout(floatDisplayMode, complexFormat), 0); for (int i = 1; i < numberOfOperands; i++) { - grandChildrenLayouts[layoutIndex++] = new StringLayout(",", 1); - grandChildrenLayouts[layoutIndex++] = expression->operand(i)->createLayout(floatDisplayMode, complexFormat); + args->addChildAtIndex(new CharLayout(','), args->numberOfChildren()); + args->addOrMergeChildAtIndex(expression->operand(i)->createLayout(floatDisplayMode, complexFormat), args->numberOfChildren()); } - /* HorizontalLayout holds the grand children layouts so they do not need to - * be deleted */ - ExpressionLayout * argumentLayouts = new HorizontalLayout(grandChildrenLayouts, 2*numberOfOperands-1); - delete [] grandChildrenLayouts; - ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = new StringLayout(operatorName, strlen(operatorName)); - childrenLayouts[1] = new ParenthesisLayout(argumentLayouts, false); - /* Same comment as above */ - return new HorizontalLayout(childrenLayouts, 2); + + // Add the parenthesed arguments. + result->addOrMergeChildAtIndex(createParenthesedLayout(args, false), result->numberOfChildren()); + return result; +} + +ExpressionLayout * LayoutEngine::createStringLayout(const char * buffer, int bufferSize, KDText::FontSize fontSize) { + assert(bufferSize > 0); + HorizontalLayout * resultLayout = new HorizontalLayout(); + for (int i = 0; i < bufferSize; i++) { + resultLayout->addChildAtIndex(new CharLayout(buffer[i], fontSize), i); + } + return resultLayout; +} + +ExpressionLayout * LayoutEngine::createParenthesedLayout(ExpressionLayout * layout, bool cloneLayout) { + HorizontalLayout * result = new HorizontalLayout(); + result->addChildAtIndex(new ParenthesisLeftLayout(), 0); + result->addOrMergeChildAtIndex(cloneLayout ? layout->clone() : layout, 1); + result->addChildAtIndex(new ParenthesisRightLayout(), result->numberOfChildren()); + return result; } int LayoutEngine::writeInfixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName, OperandNeedsParenthesis operandNeedsParenthesis) { diff --git a/poincare/src/logarithm.cpp b/poincare/src/logarithm.cpp index e55a830c5..e8f14dd94 100644 --- a/poincare/src/logarithm.cpp +++ b/poincare/src/logarithm.cpp @@ -1,25 +1,23 @@ #include -#include -#include -#include +#include "layout/horizontal_layout.h" +#include "layout/vertical_offset_layout.h" #include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include #include #include extern "C" { #include #include } -#include "layout/editable_baseline_relative_layout.h" -#include "layout/editable_string_layout.h" -#include "layout/horizontal_layout.h" -#include "layout/parenthesis_layout.h" namespace Poincare { @@ -236,10 +234,12 @@ ExpressionLayout * Logarithm::privateCreateLayout(FloatDisplayMode floatDisplayM if (numberOfOperands() == 1) { return LayoutEngine::createPrefixLayout(this, floatDisplayMode, complexFormat, "log"); } - ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = new EditableBaselineRelativeLayout(new EditableStringLayout("log", strlen("log")), operand(1)->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Subscript, false); - childrenLayouts[1] = new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false); - return new HorizontalLayout(childrenLayouts, 2, false); + HorizontalLayout * result = new HorizontalLayout(); + result->addChildAtIndex(LayoutEngine::createStringLayout("log", strlen("log")), 0); + VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(operand(1)->createLayout(floatDisplayMode, complexFormat), VerticalOffsetLayout::Type::Subscript, false); + result->addChildAtIndex(offsetLayout, 1); + result->addOrMergeChildAtIndex(LayoutEngine::createParenthesedLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false), 2); + return result; } } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 98d420dd6..50d17d3b1 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -1,26 +1,22 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include extern "C" { #include #include } -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "layout/string_layout.h" -#include "layout/horizontal_layout.h" -#include "layout/parenthesis_layout.h" namespace Poincare { diff --git a/poincare/src/naperian_logarithm.cpp b/poincare/src/naperian_logarithm.cpp index 6b23eb695..9a4ff62b0 100644 --- a/poincare/src/naperian_logarithm.cpp +++ b/poincare/src/naperian_logarithm.cpp @@ -8,9 +8,6 @@ extern "C" { } #include #include -#include "layout/horizontal_layout.h" -#include "layout/parenthesis_layout.h" -#include "layout/string_layout.h" namespace Poincare { diff --git a/poincare/src/opposite.cpp b/poincare/src/opposite.cpp index cda885309..ec0246192 100644 --- a/poincare/src/opposite.cpp +++ b/poincare/src/opposite.cpp @@ -1,16 +1,16 @@ #include +#include "layout/char_layout.h" +#include "layout/horizontal_layout.h" +#include #include +#include #include -#include #include +#include extern "C" { #include #include } -#include -#include "layout/horizontal_layout.h" -#include "layout/parenthesis_layout.h" -#include "layout/editable_string_layout.h" namespace Poincare { @@ -48,11 +48,14 @@ Expression * Opposite::shallowReduce(Context& context, AngleUnit angleUnit) { ExpressionLayout * Opposite::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - ExpressionLayout * children_layouts[2]; - char string[2] = {'-', '\0'}; - children_layouts[0] = new EditableStringLayout(string, 1); - children_layouts[1] = operand(0)->type() == Type::Opposite ? new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false) : operand(0)->createLayout(floatDisplayMode, complexFormat); - return new HorizontalLayout(children_layouts, 2, false); + HorizontalLayout * result = new HorizontalLayout(new CharLayout('-'), false); + if (operand(0)->type() == Type::Opposite) { + result->addOrMergeChildAtIndex(LayoutEngine::createParenthesedLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false), 1); + return result; + } + result->addOrMergeChildAtIndex(operand(0)->createLayout(floatDisplayMode, complexFormat), 1); + return result; + } int Opposite::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/parenthesis.cpp b/poincare/src/parenthesis.cpp index 214f7ba08..eabde9d9b 100644 --- a/poincare/src/parenthesis.cpp +++ b/poincare/src/parenthesis.cpp @@ -1,9 +1,9 @@ +#include + extern "C" { #include #include } -#include -#include "layout/parenthesis_layout.h" namespace Poincare { @@ -20,7 +20,7 @@ Expression * Parenthesis::clone() const { ExpressionLayout * Parenthesis::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new ParenthesisLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false); + return LayoutEngine::createParenthesedLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false); } Expression * Parenthesis::shallowReduce(Context& context, AngleUnit angleUnit) { diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 3ae0c3b42..0677ca2c3 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -1,27 +1,29 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "layout/horizontal_layout.h" +#include "layout/vertical_offset_layout.h" + extern "C" { #include #include } -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "layout/editable_baseline_relative_layout.h" + namespace Poincare { @@ -121,7 +123,13 @@ ExpressionLayout * Power::privateCreateLayout(FloatDisplayMode floatDisplayMode, if (m_operands[1]->type() == Type::Parenthesis) { indiceOperand = m_operands[1]->operand(0); } - return new EditableBaselineRelativeLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat),indiceOperand->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Superscript, false); + return new HorizontalLayout( + m_operands[0]->createLayout(floatDisplayMode, complexFormat), + new VerticalOffsetLayout( + indiceOperand->createLayout(floatDisplayMode, complexFormat), + VerticalOffsetLayout::Type::Superscript, + false), + false); } int Power::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const { diff --git a/poincare/src/product.cpp b/poincare/src/product.cpp index ee896bd98..ab07fbc0d 100644 --- a/poincare/src/product.cpp +++ b/poincare/src/product.cpp @@ -26,8 +26,8 @@ int Product::emptySequenceValue() const { return 1; } -ExpressionLayout * Product::createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const { - return new ProductLayout(subscriptLayout, superscriptLayout, argumentLayout, false); +ExpressionLayout * Product::createSequenceLayoutWithArgumentLayouts(ExpressionLayout * argumentLayout, ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout) const { + return new ProductLayout(argumentLayout, subscriptLayout, superscriptLayout, false); } template diff --git a/poincare/src/rational.cpp b/poincare/src/rational.cpp index 0929172f5..8bbaa31f7 100644 --- a/poincare/src/rational.cpp +++ b/poincare/src/rational.cpp @@ -7,7 +7,6 @@ extern "C" { } #include #include -#include "layout/string_layout.h" #include "layout/fraction_layout.h" namespace Poincare { diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index 2aa201dad..b5022f94e 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -1,10 +1,8 @@ #include -#include #include -#include +#include #include -#include "layout/string_layout.h" -#include "layout/horizontal_layout.h" +#include extern "C" { #include #include @@ -16,10 +14,7 @@ namespace Poincare { ExpressionLayout * Sequence::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = new StringLayout("n=", 2); - childrenLayouts[1] = operand(1)->createLayout(floatDisplayMode, complexFormat); - return createSequenceLayoutWithArgumentLayouts(new HorizontalLayout(childrenLayouts, 2, false), operand(2)->createLayout(floatDisplayMode, complexFormat), operand(0)->createLayout(floatDisplayMode, complexFormat)); + return createSequenceLayoutWithArgumentLayouts(operand(0)->createLayout(floatDisplayMode, complexFormat), operand(1)->createLayout(floatDisplayMode, complexFormat), operand(2)->createLayout(floatDisplayMode, complexFormat)); } template diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index 03d1c90bb..fbfc5b16d 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -7,8 +7,8 @@ extern "C" { #include #include #include +#include "layout/char_layout.h" #include "layout/horizontal_layout.h" -#include "layout/editable_string_layout.h" namespace Poincare { @@ -28,12 +28,11 @@ int Store::writeTextInBuffer(char * buffer, int bufferSize) const { ExpressionLayout * Store::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - ExpressionLayout * childrenLayouts[3]; - childrenLayouts[0] = value()->createLayout(floatDisplayMode, complexFormat); - const char stoSymbol[2] = {Ion::Charset::Sto, 0}; - childrenLayouts[1] = new EditableStringLayout(stoSymbol, 1); - childrenLayouts[2] = symbol()->createLayout(floatDisplayMode, complexFormat); - return new HorizontalLayout(childrenLayouts, 3, false); + HorizontalLayout * result = new HorizontalLayout(); + result->addOrMergeChildAtIndex(value()->createLayout(floatDisplayMode, complexFormat), 0); + result->addChildAtIndex(new CharLayout(Ion::Charset::Sto), result->numberOfChildren()); + result->addOrMergeChildAtIndex(symbol()->createLayout(floatDisplayMode, complexFormat), result->numberOfChildren()); + return result; } template diff --git a/poincare/src/subtraction.cpp b/poincare/src/subtraction.cpp index 0d4ef8b45..95dab8d20 100644 --- a/poincare/src/subtraction.cpp +++ b/poincare/src/subtraction.cpp @@ -1,18 +1,14 @@ +#include +#include +#include +#include +#include +#include extern "C" { #include #include } -#include -#include -#include -#include -#include -#include -#include "layout/horizontal_layout.h" -#include "layout/string_layout.h" -#include "layout/parenthesis_layout.h" - namespace Poincare { Expression::Type Subtraction::type() const { diff --git a/poincare/src/sum.cpp b/poincare/src/sum.cpp index 0578083e9..fe973047a 100644 --- a/poincare/src/sum.cpp +++ b/poincare/src/sum.cpp @@ -26,8 +26,8 @@ int Sum::emptySequenceValue() const { return 0; } -ExpressionLayout * Sum::createSequenceLayoutWithArgumentLayouts(ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout, ExpressionLayout * argumentLayout) const { - return new SumLayout(subscriptLayout, superscriptLayout, argumentLayout, false); +ExpressionLayout * Sum::createSequenceLayoutWithArgumentLayouts(ExpressionLayout * argumentLayout, ExpressionLayout * subscriptLayout, ExpressionLayout * superscriptLayout) const { + return new SumLayout(argumentLayout, subscriptLayout, superscriptLayout, false); } template diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 5b55e8ffa..7791bb2c5 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -1,9 +1,10 @@ #include -#include #include -#include "layout/baseline_relative_layout.h" -#include "layout/string_layout.h" -#include "layout/editable_string_layout.h" +#include +#include +#include "layout/char_layout.h" +#include "layout/horizontal_layout.h" +#include "layout/vertical_offset_layout.h" #include extern "C" { #include @@ -132,25 +133,49 @@ ExpressionLayout * Symbol::privateCreateLayout(FloatDisplayMode floatDisplayMode assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); if (m_name == SpecialSymbols::Ans) { - return new EditableStringLayout("ans", 3); + return LayoutEngine::createStringLayout("ans", 3); } if (m_name == SpecialSymbols::un) { - return new BaselineRelativeLayout(new StringLayout("u", 1), new StringLayout("n",1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript, false); + return new HorizontalLayout( + new CharLayout('u'), + new VerticalOffsetLayout( + new CharLayout('n', KDText::FontSize::Small), + VerticalOffsetLayout::Type::Subscript, + false), + false); } if (m_name == SpecialSymbols::un1) { - return new BaselineRelativeLayout(new StringLayout("u", 1), new StringLayout("n+1",3, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript, false); + return new HorizontalLayout( + new CharLayout('u'), + new VerticalOffsetLayout( + LayoutEngine::createStringLayout("n+1", 3, KDText::FontSize::Small), + VerticalOffsetLayout::Type::Subscript, + false), + false); } if (m_name == SpecialSymbols::vn) { - return new BaselineRelativeLayout(new StringLayout("v", 1), new StringLayout("n",1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript, false); + return new HorizontalLayout( + new CharLayout('v'), + new VerticalOffsetLayout( + new CharLayout('n', KDText::FontSize::Small), + VerticalOffsetLayout::Type::Subscript, + false), + false); } if (m_name == SpecialSymbols::vn1) { - return new BaselineRelativeLayout(new StringLayout("v", 1), new StringLayout("n+1",3, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript, false); + return new HorizontalLayout( + new CharLayout('v'), + new VerticalOffsetLayout( + LayoutEngine::createStringLayout("n+1", 3, KDText::FontSize::Small), + VerticalOffsetLayout::Type::Subscript, + false), + false); } if (isMatrixSymbol()) { const char mi[] = { 'M', (char)(m_name-(char)SpecialSymbols::M0+'0') }; - return new EditableStringLayout(mi, sizeof(mi)); + return LayoutEngine::createStringLayout(mi, sizeof(mi)); } - return new EditableStringLayout(&m_name, 1); + return LayoutEngine::createStringLayout(&m_name, 1); } int Symbol::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/undefined.cpp b/poincare/src/undefined.cpp index 36b55ff15..d08a811c6 100644 --- a/poincare/src/undefined.cpp +++ b/poincare/src/undefined.cpp @@ -1,8 +1,10 @@ #include +#include + extern "C" { #include +#include } -#include "layout/editable_string_layout.h" namespace Poincare { @@ -21,7 +23,7 @@ template Complex * Undefined::templatedApproximate(Context& conte ExpressionLayout * Undefined::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { char buffer[16]; int numberOfChars = Complex::convertFloatToText(NAN, buffer, 16, 1, floatDisplayMode); - return new EditableStringLayout(buffer, numberOfChars); + return LayoutEngine::createStringLayout(buffer, numberOfChars); } int Undefined::writeTextInBuffer(char * buffer, int bufferSize) const { From dadcd83924e2f247699e7b2739aa9eaa53d81640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 15:02:08 +0100 Subject: [PATCH 118/257] [poincare] Remove uses of outdated layouts, such as StringLayout. Change-Id: I55bb846371c224f8f2e739b759725b0e02759ebd --- apps/expression_editor/expression_and_layout.cpp | 1 - poincare/include/poincare_layouts.h | 6 ------ poincare/src/layout/expression_layout.cpp | 8 ++++---- poincare/src/layout/horizontal_layout.cpp | 2 -- poincare/src/layout/integral_layout.cpp | 3 +-- poincare/src/layout_engine.cpp | 1 - 6 files changed, 5 insertions(+), 16 deletions(-) diff --git a/apps/expression_editor/expression_and_layout.cpp b/apps/expression_editor/expression_and_layout.cpp index 3616751a4..36f09fcfb 100644 --- a/apps/expression_editor/expression_and_layout.cpp +++ b/apps/expression_editor/expression_and_layout.cpp @@ -1,6 +1,5 @@ #include "expression_and_layout.h" #include -#include #include namespace ExpressionEditor { diff --git a/poincare/include/poincare_layouts.h b/poincare/include/poincare_layouts.h index b06cc8993..34191f18d 100644 --- a/poincare/include/poincare_layouts.h +++ b/poincare/include/poincare_layouts.h @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -11,9 +10,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -26,9 +22,7 @@ #include #include #include -#include #include -#include #include #endif diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 845ab35fd..395194d39 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -1,9 +1,9 @@ +#include +#include "empty_visible_layout.h" +#include "horizontal_layout.h" +#include #include #include -#include -#include -#include -#include #include namespace Poincare { diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 4af8b824f..24ebff1c3 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -1,8 +1,6 @@ #include "horizontal_layout.h" #include "empty_visible_layout.h" -#include "string_layout.h" #include - extern "C" { #include #include diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index dfdae4e2d..392525b16 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -1,7 +1,6 @@ #include "integral_layout.h" #include "char_layout.h" #include "horizontal_layout.h" -#include "string_layout.h" #include #include #include @@ -245,7 +244,7 @@ void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, } KDSize IntegralLayout::computeSize() { - KDSize dxSize = StringLayout("dx", 2).size(); + KDSize dxSize = HorizontalLayout(new CharLayout('d'), new CharLayout('x'), false).size(); KDSize integrandSize = integrandLayout()->size(); KDSize lowerBoundSize = lowerBoundLayout()->size(); KDSize upperBoundSize = upperBoundLayout()->size(); diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index 45621b54a..14a1f14f7 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -3,7 +3,6 @@ #include "layout/horizontal_layout.h" #include "layout/parenthesis_left_layout.h" #include "layout/parenthesis_right_layout.h" -#include "layout/string_layout.h" extern "C" { #include } From 36064eff59cc29d2dbdf0e5093add3e9c7513c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 15:00:49 +0100 Subject: [PATCH 119/257] [poincare] Remove outdated layouts, such as StringLayout. Change-Id: I351113cd9a14a1c48896ac9f56153a8513d36a16 --- poincare/Makefile | 7 - .../src/layout/baseline_relative_layout.cpp | 134 ---------- .../src/layout/baseline_relative_layout.h | 34 --- .../editable_baseline_relative_layout.cpp | 244 ------------------ .../editable_baseline_relative_layout.h | 21 -- .../src/layout/editable_string_layout.cpp | 122 --------- poincare/src/layout/editable_string_layout.h | 27 -- poincare/src/layout/string_layout.cpp | 121 --------- poincare/src/layout/string_layout.h | 37 --- .../uneditable_horizontal_trio_layout.cpp | 193 -------------- .../uneditable_horizontal_trio_layout.h | 48 ---- .../uneditable_parenthesis_left_layout.cpp | 33 --- .../uneditable_parenthesis_left_layout.h | 18 -- .../uneditable_parenthesis_right_layout.cpp | 33 --- .../uneditable_parenthesis_right_layout.h | 18 -- 15 files changed, 1090 deletions(-) delete mode 100644 poincare/src/layout/baseline_relative_layout.cpp delete mode 100644 poincare/src/layout/baseline_relative_layout.h delete mode 100644 poincare/src/layout/editable_baseline_relative_layout.cpp delete mode 100644 poincare/src/layout/editable_baseline_relative_layout.h delete mode 100644 poincare/src/layout/editable_string_layout.cpp delete mode 100644 poincare/src/layout/editable_string_layout.h delete mode 100644 poincare/src/layout/string_layout.cpp delete mode 100644 poincare/src/layout/string_layout.h delete mode 100644 poincare/src/layout/uneditable_horizontal_trio_layout.cpp delete mode 100644 poincare/src/layout/uneditable_horizontal_trio_layout.h delete mode 100644 poincare/src/layout/uneditable_parenthesis_left_layout.cpp delete mode 100644 poincare/src/layout/uneditable_parenthesis_left_layout.h delete mode 100644 poincare/src/layout/uneditable_parenthesis_right_layout.cpp delete mode 100644 poincare/src/layout/uneditable_parenthesis_right_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index 976ffb545..f9828e5fe 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -84,7 +84,6 @@ objs += $(addprefix poincare/src/,\ objs += $(addprefix poincare/src/layout/,\ absolute_value_layout.o\ - baseline_relative_layout.o\ bracket_layout.o\ bracket_left_layout.o\ bracket_left_right_layout.o\ @@ -94,8 +93,6 @@ objs += $(addprefix poincare/src/layout/,\ condensed_sum_layout.o\ conjugate_layout.o\ dynamic_layout_hierarchy.o\ - editable_baseline_relative_layout.o\ - editable_string_layout.o\ empty_layout.o\ empty_visible_layout.o\ expression_layout.o\ @@ -112,11 +109,7 @@ objs += $(addprefix poincare/src/layout/,\ product_layout.o\ sequence_layout.o\ static_layout_hierarchy.o\ - string_layout.o\ sum_layout.o\ - uneditable_horizontal_trio_layout.o\ - uneditable_parenthesis_left_layout.o\ - uneditable_parenthesis_right_layout.o\ vertical_offset_layout.o\ ) diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp deleted file mode 100644 index 824c1c286..000000000 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "baseline_relative_layout.h" -#include "empty_visible_layout.h" -#include -#include -#include -#include - -namespace Poincare { - -BaselineRelativeLayout::BaselineRelativeLayout(ExpressionLayout * base, ExpressionLayout * indice, Type type, bool cloneOperands) : - StaticLayoutHierarchy(base, indice, cloneOperands), - m_type(type) -{ -} - -ExpressionLayout * BaselineRelativeLayout::clone() const { - BaselineRelativeLayout * layout = new BaselineRelativeLayout(const_cast(this)->baseLayout(), const_cast(this)->indiceLayout(), m_type, true); - return layout; -} - -void BaselineRelativeLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - if (cursor->pointedExpressionLayout() == indiceLayout() - || (cursor->pointedExpressionLayout() == this - && cursor->position() == ExpressionLayoutCursor::Position::Right)) - { - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(new EmptyVisibleLayout(), true); - if (indexInParent == 0) { - cursor->setPointedExpressionLayout(previousParent); - return; - } - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - ExpressionLayout::backspaceAtCursor(cursor); -} - -bool BaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Case: Right. - // Go Left. - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - // Case: Left. - // Ask the parent. - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; -} - -bool BaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Case: Left. - // Go Right. - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - // Case: Right. - // Ask the parent. - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; -} - -int BaselineRelativeLayout::writeTextInBuffer(char * buffer, int bufferSize) const { - if (m_type == Type::Subscript) { - if (bufferSize == 0) { - return -1; - } - buffer[bufferSize-1] = 0; - if (bufferSize == 1) { - return 0; - } - int numberOfChars = LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "_{"); - if (numberOfChars < bufferSize - 1) { - //FIXME what if the buffer is not big enough? - buffer[numberOfChars++] = '}'; - buffer[numberOfChars] = 0; - } - return numberOfChars; - } - assert(m_type == Type::Superscript); - return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "^"); -} - -ExpressionLayout * BaselineRelativeLayout::baseLayout() { - return editableChild(0); -} - -ExpressionLayout * BaselineRelativeLayout::indiceLayout() { - return editableChild(1); -} - -void BaselineRelativeLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - // There is nothing to draw for a subscript/superscript, only the position of the children matters -} - -KDSize BaselineRelativeLayout::computeSize() { - KDSize baseSize = baseLayout()->size(); - KDSize indiceSize = indiceLayout()->size(); - return KDSize(baseSize.width() + indiceSize.width(), baseSize.height() + indiceSize.height() - k_indiceHeight); -} - -void BaselineRelativeLayout::computeBaseline() { - m_baseline = m_type == Type::Subscript ? baseLayout()->baseline() : - indiceLayout()->size().height() + baseLayout()->baseline() - k_indiceHeight; - m_baselined = true; -} - -KDPoint BaselineRelativeLayout::positionOfChild(ExpressionLayout * child) { - KDCoordinate x = 0; - KDCoordinate y = 0; - if (child == baseLayout() && m_type == Type::Superscript) { - x = 0; - y = indiceLayout()->size().height() - k_indiceHeight; - } - if (child == indiceLayout()) { - x = baseLayout()->size().width(); - y = m_type == Type::Superscript ? 0 : baseLayout()->size().height() - k_indiceHeight; - } - return KDPoint(x,y); -} - -} - diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h deleted file mode 100644 index 184f808a6..000000000 --- a/poincare/src/layout/baseline_relative_layout.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef POINCARE_BASELINE_RELATIVE_LAYOUT_H -#define POINCARE_BASELINE_RELATIVE_LAYOUT_H - -#include - -namespace Poincare { - -class BaselineRelativeLayout : public StaticLayoutHierarchy<2> { -public: - enum class Type { - Subscript, - Superscript - }; - BaselineRelativeLayout(ExpressionLayout * base, ExpressionLayout * indice, Type type, bool cloneOperands); - ExpressionLayout * clone() const override; - void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; -protected: - ExpressionLayout * baseLayout(); - ExpressionLayout * indiceLayout(); - void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; - KDSize computeSize() override; - void computeBaseline() override; - KDPoint positionOfChild(ExpressionLayout * child) override; - Type m_type; -private: - constexpr static KDCoordinate k_indiceHeight = 5; -}; - -} - -#endif diff --git a/poincare/src/layout/editable_baseline_relative_layout.cpp b/poincare/src/layout/editable_baseline_relative_layout.cpp deleted file mode 100644 index 9e72033d1..000000000 --- a/poincare/src/layout/editable_baseline_relative_layout.cpp +++ /dev/null @@ -1,244 +0,0 @@ -#include "editable_baseline_relative_layout.h" -#include "empty_visible_layout.h" -#include -#include -#include - -namespace Poincare { - -ExpressionLayout * EditableBaselineRelativeLayout::clone() const { - EditableBaselineRelativeLayout * layout = new EditableBaselineRelativeLayout(const_cast(this)->baseLayout(), const_cast(this)->indiceLayout(), m_type, true); - return layout; -} - -void EditableBaselineRelativeLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - if (cursor->pointedExpressionLayout() == indiceLayout()) { - if (m_type == Type::Superscript) { - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - ExpressionLayout * base = baseLayout(); - ExpressionLayout * pointedLayout = base; - if (base->isHorizontal()) { - pointedLayout = base->editableChild(base->numberOfChildren()-1); - } - if (indiceLayout()->isEmpty()) { - if (baseLayout()->isEmpty()) { - // Case: Empty base and indice. - // Replace with an empty layout. - int indexInParent = m_parent->indexOfChild(this); - if (indexInParent == 0) { - pointedLayout = m_parent; - replaceWith(base, true); - cursor->setPointedExpressionLayout(pointedLayout); - return; - } - pointedLayout = m_parent->editableChild(indexInParent - 1); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - replaceWith(base, true); - cursor->setPointedExpressionLayout(pointedLayout); - return; - } - // Case: Empty indice only. - // Replace with the base. - replaceWith(base, true); - cursor->setPointedExpressionLayout(pointedLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - // Case: Non-empty indice. - // Move to the base. - cursor->setPointedExpressionLayout(pointedLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - assert(m_type == Type::Subscript); - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(new EmptyVisibleLayout(), true); - if (indexInParent == 0) { - cursor->setPointedExpressionLayout(previousParent); - return; - } - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - ExpressionLayout::backspaceAtCursor(cursor); -} - -bool EditableBaselineRelativeLayout::moveLeft(ExpressionLayoutCursor * cursor) { - // Case: Left of the indice. - // Go from the indice to the base. - if (indiceLayout() - && cursor->pointedExpressionLayout() == indiceLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Left) - { - assert(baseLayout() != nullptr); - cursor->setPointedExpressionLayout(baseLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - // Case: Left of the base. - // Ask the parent. - if (baseLayout() - && cursor->pointedExpressionLayout() == baseLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Left) - { - cursor->setPointedExpressionLayout(this); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; - } - assert(cursor->pointedExpressionLayout() == this); - // Case: Right. - // Go to the indice. - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(indiceLayout() != nullptr); - cursor->setPointedExpressionLayout(indiceLayout()); - return true; - } - // Case: Left. - // Ask the parent. - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; -} - -bool EditableBaselineRelativeLayout::moveRight(ExpressionLayoutCursor * cursor) { - // Case: Right of the base. - // Go from the base to the indice. - if (baseLayout() - && cursor->pointedExpressionLayout() == baseLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Right) - { - assert(indiceLayout() != nullptr); - cursor->setPointedExpressionLayout(indiceLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - // Case: Right of the indice. - // Go Right. - if (indiceLayout() - && cursor->pointedExpressionLayout() == indiceLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Right) - { - cursor->setPointedExpressionLayout(this); - return true; - } - assert(cursor->pointedExpressionLayout() == this); - // Case: Left. - // Go to the base and move Right. - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(baseLayout() != nullptr); - cursor->setPointedExpressionLayout(baseLayout()); - return baseLayout()->moveRight(cursor); - } - // Case: Right. - // Ask the parent. - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - cursor->setPointedExpressionLayout(this); - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; -} - -bool EditableBaselineRelativeLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { - // If the baseline is a superscript: - if (m_type == BaselineRelativeLayout::Type::Superscript) { - // If the cursor is Right of the base layout, move it to the indice. - if (baseLayout() - && previousLayout == baseLayout() - && cursor->positionIsEquivalentTo(baseLayout(), ExpressionLayoutCursor::Position::Right)) - { - assert(indiceLayout() != nullptr); - cursor->setPointedExpressionLayout(indiceLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - cursor->setPositionInside(0); - return true; - } - // If the cursor is Right, move it to the indice. - if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) { - assert(indiceLayout() != nullptr); - cursor->setPointedExpressionLayout(indiceLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - cursor->setPositionInside(0); - return true; - } - } - // If the baseline is a subscript: - if (m_type == BaselineRelativeLayout::Type::Subscript - && indiceLayout() - && previousLayout == indiceLayout()) - { - // If the cursor is Left of the indice layout, move it to the base. - if (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(baseLayout() != nullptr); - cursor->setPointedExpressionLayout(baseLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - cursor->setPositionInside(0); - return true; - } - // If the cursor is Right of the indice layout, move it Right. - if (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Right)) { - cursor->setPointedExpressionLayout(this); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - cursor->setPositionInside(0); - return true; - } - } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); -} - -bool EditableBaselineRelativeLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { - // If the baseline is a subscript: - if (m_type == BaselineRelativeLayout::Type::Subscript) { - // If the cursor is Right of the base layout, move it to the indice. - if (baseLayout() - && previousLayout == baseLayout() - && cursor->positionIsEquivalentTo(baseLayout(), ExpressionLayoutCursor::Position::Right)) - { - assert(indiceLayout() != nullptr); - cursor->setPointedExpressionLayout(indiceLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - cursor->setPositionInside(0); - return true; - } - // If the cursor is Right, move it to the indice. - if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) { - assert(indiceLayout() != nullptr); - cursor->setPointedExpressionLayout(indiceLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - cursor->setPositionInside(0); - return true; - } - } - // If the baseline is a superscript: - if (m_type == BaselineRelativeLayout::Type::Superscript - && indiceLayout() - && previousLayout == indiceLayout()) - { - // If the cursor is Left of the indice layout, move it to the base. - if (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(indiceLayout() != nullptr); - cursor->setPointedExpressionLayout(baseLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - cursor->setPositionInside(0); - return true; - } - // If the cursor is Right of the indice layout, move it Right. - if (cursor->positionIsEquivalentTo(indiceLayout(), ExpressionLayoutCursor::Position::Right)) { - assert(indiceLayout() != nullptr); - cursor->setPointedExpressionLayout(this); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - cursor->setPositionInside(0); - return true; - } - } - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); -} - -} - diff --git a/poincare/src/layout/editable_baseline_relative_layout.h b/poincare/src/layout/editable_baseline_relative_layout.h deleted file mode 100644 index af60ba3b9..000000000 --- a/poincare/src/layout/editable_baseline_relative_layout.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef POINCARE_EDITABLE_BASELINE_RELATIVE_LAYOUT_H -#define POINCARE_EDITABLE_BASELINE_RELATIVE_LAYOUT_H - -#include "baseline_relative_layout.h" - -namespace Poincare { - -class EditableBaselineRelativeLayout : public BaselineRelativeLayout { -public: - using BaselineRelativeLayout::BaselineRelativeLayout; - ExpressionLayout * clone() const override; - void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; -}; - -} - -#endif diff --git a/poincare/src/layout/editable_string_layout.cpp b/poincare/src/layout/editable_string_layout.cpp deleted file mode 100644 index 951989192..000000000 --- a/poincare/src/layout/editable_string_layout.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "editable_string_layout.h" -#include -#include -#include - -namespace Poincare { - -ExpressionLayout * EditableStringLayout::clone() const { - EditableStringLayout * layout = new EditableStringLayout(m_string, strlen(m_string), m_fontSize); - return layout; -} - -bool EditableStringLayout::moveLeft(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Case: Right. - // Go before the last char. - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - size_t stringLength = strlen(m_string); - if (stringLength > 1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Inside); - cursor->setPositionInside(stringLength - 1); - return true; - } - if (stringLength == 1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - assert(stringLength == 0); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; - } - // Case: Inside. - // Go one char left. - if (cursor->position() == ExpressionLayoutCursor::Position::Inside) { - int cursorIndex = cursor->positionInside(); - assert(cursorIndex > 0 && cursorIndex < strlen(m_string)); - if (cursorIndex == 1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - cursor->setPositionInside(cursorIndex - 1); - return true; - } - // Case: Left. - // Ask the parent. - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; -} - -bool EditableStringLayout::moveRight(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Case: Left. - // Go after the first char. - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - size_t stringLength = strlen(m_string); - if (stringLength > 1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Inside); - cursor->setPositionInside(1); - return true; - } - if (stringLength == 1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - assert(stringLength == 0); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; - } - // Case: Inside. - // Go one char right. - if (cursor->position() == ExpressionLayoutCursor::Position::Inside) { - int cursorIndex = cursor->positionInside(); - assert(cursorIndex > 0 && cursorIndex < strlen(m_string)); - if (cursorIndex == strlen(m_string)-1) { - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - cursor->setPositionInside(cursorIndex + 1); - return true; - } - // Case: Right. - // Ask the parent. - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; -} - -void EditableStringLayout::moveCursorInsideAtDirection ( - VerticalDirection direction, - ExpressionLayoutCursor * cursor, - ExpressionLayout ** childResult, - void * resultPosition, - int * resultPositionInside, - int * resultScore) -{ - ExpressionLayout::moveCursorInsideAtDirection(direction, cursor, childResult, resultPosition, resultPositionInside, resultScore); - ExpressionLayoutCursor::Position * castedResultPosition = static_cast(resultPosition); - // Check the distance to Inside cursors. - size_t stringLength = strlen(m_string); - int currentDistance = 0; - KDPoint cursorMiddleLeft = cursor->middleLeftPoint(); - for (int i = 1; i < stringLength; i++) { - currentDistance = cursor->middleLeftPointOfCursor(this, ExpressionLayoutCursor::Position::Inside, i).squareDistanceTo(cursorMiddleLeft); - if (currentDistance < *resultScore) { - *childResult = this; - *castedResultPosition = ExpressionLayoutCursor::Position::Inside; - *resultPositionInside = i; - *resultScore = currentDistance; - } - } -} - -} diff --git a/poincare/src/layout/editable_string_layout.h b/poincare/src/layout/editable_string_layout.h deleted file mode 100644 index 147cb1622..000000000 --- a/poincare/src/layout/editable_string_layout.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef POINCARE_EDITABLE_STRING_LAYOUT_H -#define POINCARE_EDITABLE_STRING_LAYOUT_H - -#include "string_layout.h" -#include - -namespace Poincare { - -class EditableStringLayout : public StringLayout { -public: - using StringLayout::StringLayout; - ExpressionLayout * clone() const override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; -private: - void moveCursorInsideAtDirection ( - VerticalDirection direction, - ExpressionLayoutCursor * cursor, - ExpressionLayout ** childResult, - void * resultPosition, - int * resultPositionInside, - int * resultScore) override; -}; - -} - -#endif diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp deleted file mode 100644 index af1ec891f..000000000 --- a/poincare/src/layout/string_layout.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "string_layout.h" -#include -#include -#include - -namespace Poincare { - -StringLayout::StringLayout(const char * string, size_t length, KDText::FontSize fontSize) : - StaticLayoutHierarchy<0>(), - m_fontSize(fontSize) -{ - m_string = new char[length+1]; - memcpy(m_string, string, length); - m_string[length] = 0; -} - -StringLayout::~StringLayout() { - delete[] m_string; -} - -ExpressionLayout * StringLayout::clone() const { - StringLayout * layout = new StringLayout(m_string, strlen(m_string), m_fontSize); - return layout; -} - -void StringLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return; - } - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - m_parent->backspaceAtCursor(cursor); -} - -bool StringLayout::moveLeft(ExpressionLayoutCursor * cursor) { - // A StringLayout is not editable, and the cursor cannot go inside it. - assert(cursor->pointedExpressionLayout() == this); - // Case: Right. - // If there is a Left brother, go Right of it. Else go Left of the - // grandparent. We need to do this to avoid adding text left or right of a - // string layout, for instance left of "n=" in a Sum layout. - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - int indexOfThis = m_parent->indexOfChild(this); - if (indexOfThis > 0) { - cursor->setPointedExpressionLayout(m_parent->editableChild(indexOfThis-1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - cursor->setPointedExpressionLayout(m_parent); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - // Case: Left. - // Ask the parent. - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; -} - -bool StringLayout::moveRight(ExpressionLayoutCursor * cursor) { - // A StringLayout is not editable, and the cursor cannot go inside it. - assert(cursor->pointedExpressionLayout() == this); - assert(m_parent != nullptr); - // Case: Left. - // If there is a Right brother, go Left of it. Else go Right of the - // grandparent. We need to do this to avoid adding text left or right of a - // string layout, for instance right of "dx" in an integral layout. - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - int indexOfThis = m_parent->indexOfChild(this); - if (m_parent->editableChild(indexOfThis+1) != nullptr) { - cursor->setPointedExpressionLayout(m_parent->editableChild(indexOfThis+1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - if (m_parent->parent()) { - cursor->setPointedExpressionLayout(const_cast(m_parent->parent())); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - } - // Case: Right. - // Ask the parent. - return m_parent->moveRight(cursor); -} - -int StringLayout::writeTextInBuffer(char * buffer, int bufferSize) const { - if (bufferSize == 0) { - return -1; - } - buffer[bufferSize-1] = 0; - int numberOfChar = strlcpy(buffer, m_string, bufferSize); - if (numberOfChar >= bufferSize-1) { - return bufferSize-1; - } - - buffer[numberOfChar] = 0; - return numberOfChar; -} - -void StringLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - ctx->drawString(m_string, p, m_fontSize, expressionColor, backgroundColor); -} - -KDPoint StringLayout::positionOfChild(ExpressionLayout * child) { - assert(false); // We should never be here - return KDPointZero; -} - -KDSize StringLayout::computeSize() { - return KDText::stringSize(m_string, m_fontSize); -} - -void StringLayout::computeBaseline() { - // Half height of the font. - m_baseline = (KDText::charSize(m_fontSize).height()+1)/2; - m_baselined = true; -} - -} diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h deleted file mode 100644 index 8ba55f65e..000000000 --- a/poincare/src/layout/string_layout.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef POINCARE_STRING_LAYOUT_H -#define POINCARE_STRING_LAYOUT_H - -#include -#include -#include - -namespace Poincare { - -class StringLayout : public StaticLayoutHierarchy<0> { -public: - StringLayout(const char * string, size_t length, KDText::FontSize fontSize = KDText::FontSize::Large); - ~StringLayout(); - StringLayout(const StringLayout& other) = delete; - StringLayout(StringLayout&& other) = delete; - StringLayout& operator=(const StringLayout& other) = delete; - StringLayout& operator=(StringLayout&& other) = delete; - ExpressionLayout * clone() const override; - void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - - char * text() { return m_string; } - KDText::FontSize fontSize() { return m_fontSize; } - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; -protected: - void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; - KDPoint positionOfChild(ExpressionLayout * child) override; - KDSize computeSize() override; - void computeBaseline() override; - char * m_string; - KDText::FontSize m_fontSize; -}; - -} - -#endif diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.cpp b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp deleted file mode 100644 index ea8ff521d..000000000 --- a/poincare/src/layout/uneditable_horizontal_trio_layout.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include "uneditable_horizontal_trio_layout.h" -#include "empty_visible_layout.h" -#include -extern "C" { -#include -} - -namespace Poincare { - -UneditableHorizontalTrioLayout::UneditableHorizontalTrioLayout(ExpressionLayout * left, ExpressionLayout * central, ExpressionLayout * right, bool cloneOperands, bool cursorAllowedLeftAndRight) : - StaticLayoutHierarchy(left, central, right, cloneOperands), - m_cursorCanBeLeftOrRight(cursorAllowedLeftAndRight) -{ -} - -ExpressionLayout * UneditableHorizontalTrioLayout::clone() const { - UneditableHorizontalTrioLayout * layout = new UneditableHorizontalTrioLayout( - const_cast(this)->leftLayout(), - const_cast(this)->centerLayout(), - const_cast(this)->rightLayout(), - true, m_cursorCanBeLeftOrRight); - return layout; -} - -void UneditableHorizontalTrioLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // Case: Left of the center layout (for sequence layouts). - if (cursor->pointedExpressionLayout() == centerLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Left) - { - ExpressionLayout * grandParent = const_cast(m_parent->parent()); - assert(grandParent != nullptr); - ExpressionLayout * parent = m_parent; - int indexInGrandParent = grandParent->indexOfChild(parent); - parent->replaceWith(centerLayout(), true); - // Place the cursor on the right of the left brother of the integral if - // there is one. - if (indexInGrandParent > 0) { - cursor->setPointedExpressionLayout(grandParent->editableChild(indexInGrandParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - // Else place the cursor on the Left of the parent. - cursor->setPointedExpressionLayout(grandParent); - return; - } - // Case: Right. - // Move to the argument. - if (cursor->pointedExpressionLayout() == this - && cursor->position() == ExpressionLayoutCursor::Position::Right) - { - // Go Right of the center layout's last child if it has one, else go Right - // of the center layout. - if (centerLayout()->numberOfChildren() > 1) { - cursor->setPointedExpressionLayout(centerLayout()->editableChild(centerLayout()->numberOfChildren()-1)); - return; - } - cursor->setPointedExpressionLayout(centerLayout()); - return; - } - ExpressionLayout::backspaceAtCursor(cursor); -} - -bool UneditableHorizontalTrioLayout::moveLeft(ExpressionLayoutCursor * cursor) { - if (cursor->pointedExpressionLayout() == centerLayout()) { - // Case: Center layout. - // Go Left. - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - cursor->setPointedExpressionLayout(this); - if (m_cursorCanBeLeftOrRight) { - return true; - } - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; - } - assert(cursor->pointedExpressionLayout() == this); - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - // Case: Right. - // Go Right of the center layout's last child if it has one, else go Right - // of the center layout. - if (centerLayout()->numberOfChildren() > 1) { - cursor->setPointedExpressionLayout(centerLayout()->editableChild(centerLayout()->numberOfChildren()-1)); - return true; - } - cursor->setPointedExpressionLayout(centerLayout()); - return true; - } - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - // Case: Left. - // Ask the parent. - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; -} - -bool UneditableHorizontalTrioLayout::moveRight(ExpressionLayoutCursor * cursor) { - if (cursor->pointedExpressionLayout() == centerLayout()) { - // Case: Center layout. - // Go Right. - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - cursor->setPointedExpressionLayout(this); - if (m_cursorCanBeLeftOrRight) { - return true; - } - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; - } - assert(cursor->pointedExpressionLayout() == this); - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - // Case: Left. - // Go Left of the center layout's first child if it has one, else go Left of - // the center layout. - ExpressionLayout * grandChild = centerLayout()->editableChild(0); - if (grandChild != nullptr) { - cursor->setPointedExpressionLayout(grandChild); - return true; - } - cursor->setPointedExpressionLayout(centerLayout()); - return true; - } - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - // Case: Right. - // Ask the parent. - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; -} - -void UneditableHorizontalTrioLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { -} - -KDSize UneditableHorizontalTrioLayout::computeSize() { - // TODO: This code is duplicated from horizontal_layout.cpp. - KDCoordinate totalWidth = 0; - int i = 0; - KDCoordinate max_under_baseline = 0; - KDCoordinate max_above_baseline = 0; - while (ExpressionLayout * c = editableChild(i++)) { - KDSize childSize = c->size(); - totalWidth += childSize.width(); - if (childSize.height() - c->baseline() > max_under_baseline) { - max_under_baseline = childSize.height() - c->baseline() ; - } - if (c->baseline() > max_above_baseline) { - max_above_baseline = c->baseline(); - } - } - return KDSize(totalWidth, max_under_baseline + max_above_baseline); -} - -void UneditableHorizontalTrioLayout::computeBaseline() { - // TODO: This code is duplicated from horizontal_layout.cpp. - m_baseline = 0; - for (int i = 0; i < numberOfChildren(); i++) { - if (editableChild(i)->baseline() > m_baseline) { - m_baseline = editableChild(i)->baseline(); - } - } - m_baselined = true; -} - -KDPoint UneditableHorizontalTrioLayout::positionOfChild(ExpressionLayout * child) { - // TODO: This code is duplicated from horizontal_layout.cpp. - KDCoordinate x = 0; - KDCoordinate y = 0; - int index = indexOfChild(child); - if (index > 0) { - ExpressionLayout * previousChild = editableChild(index-1); - assert(previousChild != nullptr); - x = previousChild->origin().x() + previousChild->size().width(); - } - y = baseline() - child->baseline(); - return KDPoint(x, y); -} - -ExpressionLayout * UneditableHorizontalTrioLayout::leftLayout() { - return editableChild(0); -} - -ExpressionLayout * UneditableHorizontalTrioLayout::centerLayout() { - return editableChild(1); -} - -ExpressionLayout * UneditableHorizontalTrioLayout::rightLayout() { - return editableChild(2); -} - -} diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.h b/poincare/src/layout/uneditable_horizontal_trio_layout.h deleted file mode 100644 index 484947dd5..000000000 --- a/poincare/src/layout/uneditable_horizontal_trio_layout.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef POINCARE_UNEDITABLE_HORIZONTAL_TRIO_LAYOUT_H -#define POINCARE_UNEDITABLE_HORIZONTAL_TRIO_LAYOUT_H - -#include -#include - -namespace Poincare { - -/* UneditableHorizontalTrioLayout has 3 children: a left and a right layout - * (usually parentheses or brackets), and a central layout. - * The cursor can only be: - * - Left or Right of the UneditableHorizontalTrioLayout, - * - Left or Right of the central layout if it is not an horizontal layout, - * - Inside the central layout if it is an horizontal layout. - * This way, the lateral children of an UneditableHorizontalTrioLayout cannot be - * edited, and it it will always have only 3 children. - * This layout can be used to create binomial coefficient layouts, matrix - * layouts or the argument of sum and product layouts. */ - -class UneditableHorizontalTrioLayout : public StaticLayoutHierarchy<3> { -public: - UneditableHorizontalTrioLayout(ExpressionLayout * left, ExpressionLayout * central, ExpressionLayout * right, bool cloneOperands, bool cursorAllowedLeftAndRight); - ExpressionLayout * clone() const override; - void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - - /* Navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - - /* Expression Engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); - } -protected: - void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; - KDSize computeSize() override; - void computeBaseline() override; - KDPoint positionOfChild(ExpressionLayout * child) override; -private: - ExpressionLayout * leftLayout(); - ExpressionLayout * centerLayout(); - ExpressionLayout * rightLayout(); - bool m_cursorCanBeLeftOrRight; -}; - -} - -#endif diff --git a/poincare/src/layout/uneditable_parenthesis_left_layout.cpp b/poincare/src/layout/uneditable_parenthesis_left_layout.cpp deleted file mode 100644 index 5281934ee..000000000 --- a/poincare/src/layout/uneditable_parenthesis_left_layout.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "uneditable_parenthesis_left_layout.h" -#include -extern "C" { -#include -} - -namespace Poincare { - -ExpressionLayout * UneditableParenthesisLeftLayout::clone() const { - return new UneditableParenthesisLeftLayout(); -} - -bool UneditableParenthesisLeftLayout::moveLeft(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Ask the parent. - if (m_parent) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return m_parent->moveLeft(cursor); - } - return false; -} - -bool UneditableParenthesisLeftLayout::moveRight(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Ask the parent. - if (m_parent) { - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return m_parent->moveRight(cursor); - } - return false; -} - -} diff --git a/poincare/src/layout/uneditable_parenthesis_left_layout.h b/poincare/src/layout/uneditable_parenthesis_left_layout.h deleted file mode 100644 index b3b693330..000000000 --- a/poincare/src/layout/uneditable_parenthesis_left_layout.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef POINCARE_UNEDITABLE_PARENTHESIS_LEFT_LAYOUT_H -#define POINCARE_UNEDITABLE_PARENTHESIS_LEFT_LAYOUT_H - -#include - -namespace Poincare { - -class UneditableParenthesisLeftLayout : public ParenthesisLeftLayout { -public: - using ParenthesisLeftLayout::ParenthesisLeftLayout; - ExpressionLayout * clone() const override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; -}; - -} - -#endif diff --git a/poincare/src/layout/uneditable_parenthesis_right_layout.cpp b/poincare/src/layout/uneditable_parenthesis_right_layout.cpp deleted file mode 100644 index bba558231..000000000 --- a/poincare/src/layout/uneditable_parenthesis_right_layout.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "uneditable_parenthesis_right_layout.h" -#include -extern "C" { -#include -} - -namespace Poincare { - -ExpressionLayout * UneditableParenthesisRightLayout::clone() const { - return new UneditableParenthesisRightLayout(); -} - -bool UneditableParenthesisRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Ask the parent. - if (m_parent) { - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return m_parent->moveLeft(cursor); - } - return false; -} - -bool UneditableParenthesisRightLayout::moveRight(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Ask the parent. - if (m_parent) { - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return m_parent->moveRight(cursor); - } - return false; -} - -} diff --git a/poincare/src/layout/uneditable_parenthesis_right_layout.h b/poincare/src/layout/uneditable_parenthesis_right_layout.h deleted file mode 100644 index 2025f4a25..000000000 --- a/poincare/src/layout/uneditable_parenthesis_right_layout.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef POINCARE_UNEDITABLE_PARENTHESIS_RIGHT_LAYOUT_H -#define POINCARE_UNEDITABLE_PARENTHESIS_RIGHT_LAYOUT_H - -#include - -namespace Poincare { - -class UneditableParenthesisRightLayout : public ParenthesisRightLayout { -public: - using ParenthesisRightLayout::ParenthesisRightLayout; - ExpressionLayout * clone() const override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; -}; - -} - -#endif From 6526a82c1761711eeb15789c3b3fd8123cab5cc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 15:11:58 +0100 Subject: [PATCH 120/257] [poincare] No "Inside" position for ExpressionLayoutCursor. Change-Id: Id979c372bb2c4acf8f8708380c7d1f2aeeb5ff06 --- apps/expression_editor/controller.cpp | 3 --- .../expression_view_with_cursor.cpp | 2 -- poincare/include/poincare/expression_layout.h | 3 +-- .../include/poincare/expression_layout_cursor.h | 11 +++-------- poincare/src/expression_layout_cursor.cpp | 15 ++++++--------- poincare/src/layout/expression_layout.cpp | 13 ++++--------- poincare/src/layout/nth_root_layout.cpp | 4 ---- 7 files changed, 14 insertions(+), 37 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 2df023056..052815e49 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -52,7 +52,6 @@ void Controller::insertLayoutAtCursor(ExpressionLayout * layout, ExpressionLayou m_cursor.addLayout(layout); m_cursor.setPointedExpressionLayout(pointedLayout); m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); - m_cursor.setPositionInside(0); m_expressionLayout->invalidAllSizesPositionsAndBaselines(); m_view.cursorPositionChanged(); } @@ -92,13 +91,11 @@ bool Controller::handleMoveEvent(Ion::Events::Event event) { // The cursor should never point to the main HorizontalLayout. m_cursor.setPointedExpressionLayout(m_expressionLayout); m_cursor.setPosition(ExpressionLayoutCursor::Position::Left); - m_cursor.setPositionInside(0); return true; } if (event == Ion::Events::ShiftRight) { m_cursor.setPointedExpressionLayout(m_expressionLayout); m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); - m_cursor.setPositionInside(0); return true; } return false; diff --git a/apps/expression_editor/expression_view_with_cursor.cpp b/apps/expression_editor/expression_view_with_cursor.cpp index 3f501434a..716d23492 100644 --- a/apps/expression_editor/expression_view_with_cursor.cpp +++ b/apps/expression_editor/expression_view_with_cursor.cpp @@ -41,8 +41,6 @@ void ExpressionViewWithCursor::layoutCursorSubview() { KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x(); if (m_cursor->position() == ExpressionLayoutCursor::Position::Right) { cursorX += m_cursor->pointedExpressionLayout()->size().width(); - } else if (m_cursor->position() == ExpressionLayoutCursor::Position::Inside) { - cursorX += m_cursor->positionInside() * KDText::charSize().width(); } KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + m_cursor->pointedExpressionLayout()->baseline()-m_cursor->cursorHeight()/2); m_cursorView.setFrame(KDRect(cursorTopLeftPosition, 1, m_cursor->cursorHeight())); diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 1277db657..c06f89633 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -87,12 +87,11 @@ protected: virtual void computeBaseline() = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; void detachChildAtIndex(int i); - virtual void moveCursorInsideAtDirection ( + void moveCursorInsideAtDirection ( VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout ** childResult, void * resultPosition, - int * resultPositionInside, int * resultScore); KDCoordinate m_baseline; /* m_baseline is the signed vertical distance from the top of the layout to diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index e6c5e9f71..76b335f1c 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -10,14 +10,12 @@ class ExpressionLayoutCursor { public: enum class Position { Left, - Inside, Right }; ExpressionLayoutCursor() : m_pointedExpressionLayout(nullptr), - m_position(Position::Right), - m_positionInside(0) + m_position(Position::Right) {}; /* Getters and setters */ @@ -25,16 +23,14 @@ public: void setPointedExpressionLayout(ExpressionLayout * expressionLayout) { m_pointedExpressionLayout = expressionLayout; } Position position() const { return m_position; } void setPosition(Position position) { m_position = position; } - int positionInside() const { return m_positionInside; } - void setPositionInside(int positionInside) { m_positionInside = positionInside; } KDCoordinate cursorHeight() const { return k_cursorHeight; } /* Comparison */ - bool positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position, int positionIndex = 0); + bool positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position); /* Position */ KDPoint middleLeftPoint(); - KDPoint middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position, int positionInside = 0); + KDPoint middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position); /* Move */ bool moveLeft(); @@ -58,7 +54,6 @@ private: constexpr static KDCoordinate k_cursorHeight = 18; ExpressionLayout * m_pointedExpressionLayout; Position m_position; - int m_positionInside; }; } diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 2007824ab..c8fac396b 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -6,26 +6,23 @@ namespace Poincare { -bool ExpressionLayoutCursor::positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position, int positionIndex) { +bool ExpressionLayoutCursor::positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position) { assert(expressionLayout != nullptr); - return middleLeftPoint() == middleLeftPointOfCursor(expressionLayout, position, positionIndex); + return middleLeftPoint() == middleLeftPointOfCursor(expressionLayout, position); } KDPoint ExpressionLayoutCursor::middleLeftPoint() { - return middleLeftPointOfCursor(m_pointedExpressionLayout, m_position, m_positionInside); + return middleLeftPointOfCursor(m_pointedExpressionLayout, m_position); } -KDPoint ExpressionLayoutCursor::middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position, int positionInside) { +KDPoint ExpressionLayoutCursor::middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position) { KDPoint layoutOrigin = expressionLayout->absoluteOrigin(); KDCoordinate y = layoutOrigin.y() + expressionLayout->baseline() - k_cursorHeight/2; if (position == Position::Left) { return KDPoint(layoutOrigin.x(), y); } - if (position == Position::Right) { - return KDPoint(layoutOrigin.x() + expressionLayout->size().width(), y); - } - assert(position == Position::Inside); - return KDPoint(layoutOrigin.x() + positionInside * KDText::charSize().width(), y); + assert(position == Position::Right); + return KDPoint(layoutOrigin.x() + expressionLayout->size().width(), y); } bool ExpressionLayoutCursor::moveLeft() { diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 395194d39..c46fba418 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -301,12 +301,11 @@ bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutC ExpressionLayout * chilResult = nullptr; ExpressionLayout ** childResultPtr = &chilResult; ExpressionLayoutCursor::Position resultPosition = ExpressionLayoutCursor::Position::Left; - int resultPositionInside = 0; // The distance between the cursor and its next position cannot be greater // than this initial value of score. int resultScore = Ion::Display::Width*Ion::Display::Width + Ion::Display::Height*Ion::Display::Height; - moveCursorInsideAtDirection(direction, cursor, childResultPtr, &resultPosition, &resultPositionInside, &resultScore); + moveCursorInsideAtDirection(direction, cursor, childResultPtr, &resultPosition, &resultScore); // If there is a valid result if (*childResultPtr == nullptr) { @@ -314,7 +313,6 @@ bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutC } cursor->setPointedExpressionLayout(*childResultPtr); cursor->setPosition(resultPosition); - cursor->setPositionInside(resultPositionInside); return true; } @@ -323,7 +321,6 @@ void ExpressionLayout::moveCursorInsideAtDirection ( ExpressionLayoutCursor * cursor, ExpressionLayout ** childResult, void * resultPosition, - int * resultPositionInside, int * resultScore) { ExpressionLayoutCursor::Position * castedResultPosition = static_cast(resultPosition); @@ -333,27 +330,25 @@ void ExpressionLayout::moveCursorInsideAtDirection ( if (layoutIsUnderOrAbove) { // Check the distance to a Left cursor. - int currentDistance = cursor->middleLeftPointOfCursor(this, ExpressionLayoutCursor::Position::Left, 0).squareDistanceTo(cursorMiddleLeft); + int currentDistance = cursor->middleLeftPointOfCursor(this, ExpressionLayoutCursor::Position::Left).squareDistanceTo(cursorMiddleLeft); if (currentDistance <= *resultScore ){ *childResult = this; *castedResultPosition = ExpressionLayoutCursor::Position::Left; - *resultPositionInside = 0; *resultScore = currentDistance; } // Check the distance to a Right cursor. - currentDistance = cursor->middleLeftPointOfCursor(this, ExpressionLayoutCursor::Position::Right, 0).squareDistanceTo(cursorMiddleLeft); + currentDistance = cursor->middleLeftPointOfCursor(this, ExpressionLayoutCursor::Position::Right).squareDistanceTo(cursorMiddleLeft); if (currentDistance < *resultScore) { *childResult = this; *castedResultPosition = ExpressionLayoutCursor::Position::Right; - *resultPositionInside = 0; *resultScore = currentDistance; } } if (layoutIsUnderOrAbove || layoutContains) { int childIndex = 0; while (child(childIndex++)) { - editableChild(childIndex-1)->moveCursorInsideAtDirection(direction, cursor, childResult, castedResultPosition, resultPositionInside, resultScore); + editableChild(childIndex-1)->moveCursorInsideAtDirection(direction, cursor, childResult, castedResultPosition, resultScore); } } } diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 2a166bf7d..8d8ab0aa1 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -162,7 +162,6 @@ bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * p assert(indexLayout() != nullptr); cursor->setPointedExpressionLayout(indexLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); - cursor->setPositionInside(0); return true; } // If the cursor is Left, move it to the index. @@ -172,7 +171,6 @@ bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * p assert(indexLayout() != nullptr); cursor->setPointedExpressionLayout(indexLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - cursor->setPositionInside(0); return true; } return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); @@ -185,14 +183,12 @@ bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * assert(radicandLayout() != nullptr); cursor->setPointedExpressionLayout(radicandLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - cursor->setPositionInside(0); return true; } // If the cursor is Left of the index, move it Left . if (cursor->positionIsEquivalentTo(indexLayout(), ExpressionLayoutCursor::Position::Left)) { cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - cursor->setPositionInside(0); return true; } } From 61e50e1858e745d4c2dd479e4a90d576c633a95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 16:05:52 +0100 Subject: [PATCH 121/257] [poincare] ParenthesisLayout renders parentheses instead of layouting. ParenthesisLayout should be used for uneditable parenthesis, because its parentheses are drawn instead of being part of the Layout tree. Change-Id: Ibce7908fa271cd5e8cd7b2a2b5241d0ea42028f7 --- poincare/src/layout/horizontal_layout.h | 1 + poincare/src/layout/parenthesis_layout.cpp | 112 +++++------------- poincare/src/layout/parenthesis_layout.h | 17 ++- poincare/src/layout/parenthesis_left_layout.h | 1 + .../layout/parenthesis_left_right_layout.cpp | 2 +- .../layout/parenthesis_left_right_layout.h | 1 + .../src/layout/parenthesis_right_layout.h | 1 + 7 files changed, 42 insertions(+), 93 deletions(-) diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index bb72a1740..6b789e770 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class HorizontalLayout : public DynamicLayoutHierarchy { friend class IntegralLayout; + friend class ParenthesisLayout; friend class SequenceLayout; public: using DynamicLayoutHierarchy::DynamicLayoutHierarchy; diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp index cb4c372e1..ed81ff533 100644 --- a/poincare/src/layout/parenthesis_layout.cpp +++ b/poincare/src/layout/parenthesis_layout.cpp @@ -1,5 +1,7 @@ #include "parenthesis_layout.h" +#include "horizontal_layout.h" #include "parenthesis_left_layout.h" +#include "parenthesis_left_right_layout.h" #include "parenthesis_right_layout.h" #include #include @@ -10,31 +12,11 @@ extern "C" { namespace Poincare { -ParenthesisLayout::ParenthesisLayout(ExpressionLayout * operand, bool cloneOperands) : - StaticLayoutHierarchy<3>() -{ - ExpressionLayout * leftParenthesis = new ParenthesisLeftLayout(); - ExpressionLayout * rightParenthesis = new ParenthesisRightLayout(); - build(ExpressionLayoutArray(leftParenthesis, operand, rightParenthesis).array(), 3, cloneOperands); -} - ExpressionLayout * ParenthesisLayout::clone() const { - ParenthesisLayout * layout = new ParenthesisLayout(const_cast(this)->operandLayout(), true); - return layout; + return new ParenthesisLayout(const_cast(this)->operandLayout(), true); } bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { - // Case: Left of the Right parenthesis. - // Go to the operand and move left. - if (rightParenthesisLayout() - && cursor->pointedExpressionLayout() == rightParenthesisLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Left) - { - assert(operandLayout() != nullptr); - cursor->setPointedExpressionLayout(operandLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return operandLayout()->moveLeft(cursor); - } // Case: Left of the operand. // Go Left. if (operandLayout() @@ -44,30 +26,20 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { cursor->setPointedExpressionLayout(this); return true; } - // Case: Left of the Left parenthesis. - // Ask the parent. - if (leftParenthesisLayout() - && cursor->pointedExpressionLayout() == leftParenthesisLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Left) - { - cursor->setPointedExpressionLayout(this); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; - } + assert(cursor->pointedExpressionLayout() == this); - // Case: Right of the parentheses. - // Go Right of the operand. + // Case: Right. + // Go to the operand and move left. if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(operandLayout() != nullptr); cursor->setPointedExpressionLayout(operandLayout()); - return true; + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return operandLayout()->moveLeft(cursor); } - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - // Case: Left of the parentheses. + + // Case: Left. // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (m_parent) { return m_parent->moveLeft(cursor); } @@ -75,17 +47,6 @@ bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { } bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { - // Case: Right of the Left parenthesis. - // Go to the operand and move Right. - if (leftParenthesisLayout() - && cursor->pointedExpressionLayout() == leftParenthesisLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Right) - { - assert(operandLayout() != nullptr); - cursor->setPointedExpressionLayout(operandLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return operandLayout()->moveRight(cursor); - } // Case: Right of the operand. // Go Right. if (operandLayout() @@ -95,29 +56,17 @@ bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { cursor->setPointedExpressionLayout(this); return true; } - // Case: Right of the Right parenthesis. - // Ask the parent. - if (rightParenthesisLayout() - && cursor->pointedExpressionLayout() == rightParenthesisLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Right) - { - cursor->setPointedExpressionLayout(this); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; - } + assert(cursor->pointedExpressionLayout() == this); - // Case: Left of the parentheses. - // Go Left of the operand. + // Case: Left. + // Go Left of the operand and moveRight. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { assert(operandLayout() != nullptr); cursor->setPointedExpressionLayout(operandLayout()); - return true; + return operandLayout()->moveRight(cursor);; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - // Case: Right of the parentheses. + // Case: Right. // Ask the parent. if (m_parent) { return m_parent->moveRight(cursor); @@ -125,9 +74,20 @@ bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +void ParenthesisLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + // Render the parentheses. + ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); + ParenthesisRightLayout * dummyRightParenthesis = new ParenthesisRightLayout(); + HorizontalLayout dummyLayout(dummyLeftParenthesis, operandLayout()->clone(), dummyRightParenthesis, false); + KDPoint leftParenthesisPoint = positionOfChild(operandLayout()).translatedBy(dummyLayout.positionOfChild(dummyLeftParenthesis)).translatedBy(dummyLayout.positionOfChild(dummyLayout.editableChild(1)).opposite()); + KDPoint rightParenthesisPoint = positionOfChild(operandLayout()).translatedBy(dummyLayout.positionOfChild(dummyRightParenthesis)).translatedBy(dummyLayout.positionOfChild(dummyLayout.editableChild(1)).opposite()); + dummyLeftParenthesis->render(ctx, p.translatedBy(leftParenthesisPoint), expressionColor, backgroundColor); + dummyRightParenthesis->render(ctx, p.translatedBy(rightParenthesisPoint), expressionColor, backgroundColor); +} + KDSize ParenthesisLayout::computeSize() { KDSize operandSize = operandLayout()->size(); - return KDSize(operandSize.width() + 2*leftParenthesisLayout()->size().width(), operandSize.height()); + return KDSize(operandSize.width() + 2*ParenthesisLeftRightLayout::parenthesisWidth(), operandSize.height()); } void ParenthesisLayout::computeBaseline() { @@ -136,29 +96,15 @@ void ParenthesisLayout::computeBaseline() { } KDPoint ParenthesisLayout::positionOfChild(ExpressionLayout * child) { - if (child == leftParenthesisLayout()) { - return KDPoint(0, 0); - } if (child == operandLayout()) { - return KDPoint(leftParenthesisLayout()->size().width(), 0); - } - if (child == rightParenthesisLayout()) { - return KDPoint(operandLayout()->origin().x() + operandLayout()->size().width(), 0); + return KDPoint(ParenthesisLeftRightLayout::parenthesisWidth(), 0); } assert(false); return KDPointZero; } ExpressionLayout * ParenthesisLayout::operandLayout() { - return editableChild(1); -} - -ExpressionLayout * ParenthesisLayout::leftParenthesisLayout() { return editableChild(0); } -ExpressionLayout * ParenthesisLayout::rightParenthesisLayout() { - return editableChild(2); -} - } diff --git a/poincare/src/layout/parenthesis_layout.h b/poincare/src/layout/parenthesis_layout.h index f7ed69efd..af110702f 100644 --- a/poincare/src/layout/parenthesis_layout.h +++ b/poincare/src/layout/parenthesis_layout.h @@ -4,22 +4,23 @@ #include #include +/* ParenthesisLayout has one operand and renders the parentheses around it. + * This layout should thus be used for uneditable parentheses, e.g. to create + * binomial coefficient layouts. */ + namespace Poincare { -class ParenthesisLayout : public StaticLayoutHierarchy<3> { +class ParenthesisLayout : public StaticLayoutHierarchy<1> { public: - constexpr static KDCoordinate k_parenthesisCurveWidth = 5; - constexpr static KDCoordinate k_parenthesisCurveHeight = 7; - ParenthesisLayout(ExpressionLayout * operand, bool cloneOperands); + using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); } protected: - void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { - }; + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; @@ -29,8 +30,6 @@ private: constexpr static KDCoordinate k_widthMargin = 5; constexpr static KDCoordinate k_lineThickness = 1; ExpressionLayout * operandLayout(); - ExpressionLayout * leftParenthesisLayout(); - ExpressionLayout * rightParenthesisLayout(); }; } diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index 9b4c34ced..ea383da99 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { + friend class ParenthesisLayout; friend class SequenceLayout; public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; diff --git a/poincare/src/layout/parenthesis_left_right_layout.cpp b/poincare/src/layout/parenthesis_left_right_layout.cpp index f3b77ee95..060596fac 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.cpp +++ b/poincare/src/layout/parenthesis_left_right_layout.cpp @@ -53,7 +53,7 @@ bool ParenthesisLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { } KDSize ParenthesisLeftRightLayout::computeSize() { - return KDSize(k_widthMargin + k_lineThickness + k_externWidthMargin, operandHeight()); + return KDSize(parenthesisWidth(), operandHeight()); } KDCoordinate ParenthesisLeftRightLayout::operandHeight() { diff --git a/poincare/src/layout/parenthesis_left_right_layout.h b/poincare/src/layout/parenthesis_left_right_layout.h index 3ad0a296b..8596d219b 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.h +++ b/poincare/src/layout/parenthesis_left_right_layout.h @@ -11,6 +11,7 @@ public: void invalidAllSizesPositionsAndBaselines() override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + constexpr static KDCoordinate parenthesisWidth() { return k_widthMargin + k_lineThickness + k_externWidthMargin; } constexpr static KDCoordinate k_parenthesisCurveWidth = 5; constexpr static KDCoordinate k_parenthesisCurveHeight = 7; constexpr static KDCoordinate k_externWidthMargin = 1; diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index 7e1eb8578..0c3f8ce7a 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class ParenthesisRightLayout : public ParenthesisLeftRightLayout { + friend class ParenthesisLayout; friend class SequenceLayout; public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; From 6334e2f4353ca845488cb05040b2766e58e1f1d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 16:09:57 +0100 Subject: [PATCH 122/257] [apps] Change MathToolbox's binomial coefficient layout. It now uses a Parenthesis layout. Change-Id: Ia83d7881a57bc91e41d125fef1e2a648d0278946 --- apps/math_toolbox.cpp | 8 +++----- poincare/src/layout/grid_layout.cpp | 4 ++++ poincare/src/layout/grid_layout.h | 6 ++++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 612e4324f..1597980ba 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -45,16 +45,14 @@ const ToolboxMessageTree complexChildren[5] = { const_cast(&pointedLayoutPathConj[0]), 1)}; -const int pointedLayoutPathBinomial[] = {1,0}; +const int pointedLayoutPathBinomial[] = {0, 0}; const ToolboxMessageTree probabilityChildren[2] = { ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommandWithArg, nullptr, 0, - new HorizontalLayout( - new ParenthesisLeftLayout(), + new ParenthesisLayout( new GridLayout(Poincare::ExpressionLayoutArray( new EmptyVisibleLayout(), new EmptyVisibleLayout()).array(), - 2, 1, false), - new ParenthesisRightLayout(), false), + 2, 1, false)), const_cast(&pointedLayoutPathBinomial[0]), 2), ToolboxMessageTree(I18n::Message::PermuteCommandWithArg, I18n::Message::Permutation, I18n::Message::PermuteCommandWithArg)}; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 2d3152b09..5756d1c4c 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -138,6 +138,10 @@ bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * pr return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } +void GridLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { + ExpressionLayout::removeChildAtIndex(index, deleteAfterRemoval); +} + int GridLayout::writeTextInBuffer(char * buffer, int bufferSize) const { const ExpressionLayout * editableParent = const_cast(this)->parent(); assert(editableParent != nullptr); diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index a00dcb65d..7d89e01e6 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -17,6 +17,12 @@ public: bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + + /* Dynamic layout */ + void removeChildAtIndex(int index, bool deleteAfterRemoval) override; + //TODO: is this ok? If we want to delete the grid's children, we have to make + //sure no to call this function. + /* Expression engine */ int writeTextInBuffer(char * buffer, int bufferSize) const override; From 630c6256e1026256e1d6051288bba8844d7c453b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 16:14:44 +0100 Subject: [PATCH 123/257] [poincare] Removed tedious HorizontalLayout creations. There is a HorizontalLayout constructor that takes 3 layouts, so no need to use ExpressionLayoutArray. Change-Id: I51c6b9d44ead2b4d765aad6f5a2140641f4d076b --- poincare/src/layout/product_layout.cpp | 3 +-- poincare/src/layout/sequence_layout.cpp | 11 +++++------ poincare/src/layout/sum_layout.cpp | 3 +-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/poincare/src/layout/product_layout.cpp b/poincare/src/layout/product_layout.cpp index 9ab4732b9..2b9120db7 100644 --- a/poincare/src/layout/product_layout.cpp +++ b/poincare/src/layout/product_layout.cpp @@ -1,7 +1,6 @@ #include "product_layout.h" #include "char_layout.h" #include "horizontal_layout.h" -#include namespace Poincare { @@ -17,7 +16,7 @@ int ProductLayout::writeTextInBuffer(char * buffer, int bufferSize) const { void ProductLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // Compute sizes. KDSize upperBoundSize = upperBoundLayout()->size(); - KDSize lowerBoundSizeWithNEquals = HorizontalLayout(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone()).array(), 3, false).size(); + KDSize lowerBoundSizeWithNEquals = HorizontalLayout(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone(), false).size(); // Render the Product symbol. ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundSizeWithNEquals.width()-k_symbolWidth)/2), diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 468768646..acb342c2b 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -4,7 +4,6 @@ #include "parenthesis_left_layout.h" #include "parenthesis_right_layout.h" #include -#include #include namespace Poincare { @@ -222,10 +221,10 @@ ExpressionLayout * SequenceLayout::argumentLayout() { } KDSize SequenceLayout::computeSize() { - KDSize lowerBoundSizeWithNEquals = HorizontalLayout(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone()).array(), 3, false).size(); + KDSize lowerBoundSizeWithNEquals = HorizontalLayout(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone(), false).size(); ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); ParenthesisRightLayout * dummyRightParenthesis = new ParenthesisRightLayout(); - HorizontalLayout dummyLayout2(ExpressionLayoutArray(dummyLeftParenthesis, argumentLayout()->clone(), dummyRightParenthesis).array(), 3, false); + HorizontalLayout dummyLayout2(dummyLeftParenthesis, argumentLayout()->clone(), dummyRightParenthesis, false); KDSize dummyLayoutSize = dummyLayout2.size(); KDSize upperBoundSize = upperBoundLayout()->size(); return KDSize( @@ -236,7 +235,7 @@ KDSize SequenceLayout::computeSize() { KDPoint SequenceLayout::positionOfChild(ExpressionLayout * eL) { ExpressionLayout * lowerBoundClone = lowerBoundLayout()->clone(); - HorizontalLayout dummyLayout1(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundClone).array(), 3, false); + HorizontalLayout dummyLayout1(new CharLayout('n'), new CharLayout('='), lowerBoundClone, false); KDSize lowerBoundSizeWithNEquals = dummyLayout1.size(); KDSize upperBoundSize = upperBoundLayout()->size(); ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); @@ -264,14 +263,14 @@ void SequenceLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, // Render the "n=". CharLayout * dummyN = new CharLayout('n'); ExpressionLayout * lowerBoundClone = lowerBoundLayout()->clone(); - HorizontalLayout dummyLayout(ExpressionLayoutArray(dummyN, new CharLayout('='), lowerBoundClone).array(), 3, false); + HorizontalLayout dummyLayout(dummyN, new CharLayout('='), lowerBoundClone, false); KDPoint nEqualsPosition = positionOfChild(lowerBoundLayout()).translatedBy((dummyLayout.positionOfChild(lowerBoundClone)).opposite()).translatedBy(dummyLayout.positionOfChild(dummyN)); ctx->drawString("n=", p.translatedBy(nEqualsPosition), dummyN->fontSize(), expressionColor, backgroundColor); // Render the parentheses. ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); ParenthesisRightLayout * dummyRightParenthesis = new ParenthesisRightLayout(); - HorizontalLayout dummyLayout2(ExpressionLayoutArray(dummyLeftParenthesis, argumentLayout()->clone(), dummyRightParenthesis).array(), 3, false); + HorizontalLayout dummyLayout2(dummyLeftParenthesis, argumentLayout()->clone(), dummyRightParenthesis, false); KDPoint leftParenthesisPoint = positionOfChild(argumentLayout()).translatedBy(dummyLayout2.positionOfChild(dummyLeftParenthesis)).translatedBy(dummyLayout2.positionOfChild(dummyLayout2.editableChild(1)).opposite()); KDPoint rightParenthesisPoint = positionOfChild(argumentLayout()).translatedBy(dummyLayout2.positionOfChild(dummyRightParenthesis)).translatedBy(dummyLayout2.positionOfChild(dummyLayout2.editableChild(1)).opposite()); dummyLeftParenthesis->render(ctx, p.translatedBy(leftParenthesisPoint), expressionColor, backgroundColor); diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index 7906d2a0c..a38117c97 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -1,7 +1,6 @@ #include "sum_layout.h" #include "char_layout.h" #include "horizontal_layout.h" -#include namespace Poincare { @@ -35,7 +34,7 @@ int SumLayout::writeTextInBuffer(char * buffer, int bufferSize) const { void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // Computes sizes. KDSize upperBoundSize = upperBoundLayout()->size(); - KDSize lowerBoundSizeWithNEquals = HorizontalLayout(ExpressionLayoutArray(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone()).array(), 3, false).size(); + KDSize lowerBoundSizeWithNEquals = HorizontalLayout(new CharLayout('n'), new CharLayout('='), lowerBoundLayout()->clone(), false).size(); // Render the Sum symbol. KDColor workingBuffer[k_symbolWidth*k_symbolHeight]; From fda1840be4096dd3cea5b0545dc71e430a3833ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 16:19:24 +0100 Subject: [PATCH 124/257] [expression_editor] The button "log" inserts a logarithm without index. Change-Id: Ib82cccb076c34c69c3112ade7a41139da15e96c0 --- poincare/src/expression_layout_cursor.cpp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index c8fac396b..c22d3430b 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -103,22 +103,9 @@ ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers( } ExpressionLayout * ExpressionLayoutCursor::addEmptyLogarithmLayout() { - HorizontalLayout * newChild = new HorizontalLayout( - ExpressionLayoutArray( - new CharLayout('l'), - new CharLayout('o'), - new CharLayout('g')).array(), - 3, - false); - VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Subscript, false); - newChild->addChildAtIndex(offsetLayout, 3); - m_pointedExpressionLayout->addBrother(this, newChild); - setPointedExpressionLayout(offsetLayout); - setPosition(ExpressionLayoutCursor::Position::Right); - insertText("()"); - setPointedExpressionLayout(offsetLayout->editableChild(0)); - setPosition(ExpressionLayoutCursor::Position::Right); - return offsetLayout; + ExpressionLayout * result = insertText("log()"); + setPosition(ExpressionLayoutCursor::Position::Left); + return result; } ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { From 8d188279eb1f44f8fcc176656b7c626ded72ba37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 16:46:57 +0100 Subject: [PATCH 125/257] [poincare] BoundedStaticLayoutHierarchy. Change-Id: I33a1f41458401be5aebbc183e692681b4418c861 --- poincare/Makefile | 1 + .../bounded_static_layout_hierarchy.h | 22 +++++++++++ .../bounded_static_layout_hierarchy.cpp | 37 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 poincare/include/poincare/bounded_static_layout_hierarchy.h create mode 100644 poincare/src/layout/bounded_static_layout_hierarchy.cpp diff --git a/poincare/Makefile b/poincare/Makefile index f9828e5fe..9a1cc88da 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -84,6 +84,7 @@ objs += $(addprefix poincare/src/,\ objs += $(addprefix poincare/src/layout/,\ absolute_value_layout.o\ + bounded_static_layout_hierarchy.o\ bracket_layout.o\ bracket_left_layout.o\ bracket_left_right_layout.o\ diff --git a/poincare/include/poincare/bounded_static_layout_hierarchy.h b/poincare/include/poincare/bounded_static_layout_hierarchy.h new file mode 100644 index 000000000..42a0acc6b --- /dev/null +++ b/poincare/include/poincare/bounded_static_layout_hierarchy.h @@ -0,0 +1,22 @@ +#ifndef POINCARE_BOUNDED_STATIC_LAYOUT_HIERARCHY_H +#define POINCARE_BOUNDED_STATIC_LAYOUT_HIERARCHY_H + +#include + +namespace Poincare { + +template +class BoundedStaticLayoutHierarchy : public StaticLayoutHierarchy { +public: + BoundedStaticLayoutHierarchy(); + BoundedStaticLayoutHierarchy(const ExpressionLayout * expressionLayout, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<2> + BoundedStaticLayoutHierarchy(const ExpressionLayout * expressionLayout1, const ExpressionLayout * expressionLayout2, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<2> + BoundedStaticLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands = true); + int numberOfChildren() const override { return m_numberOfChildren; } +private: + int m_numberOfChildren; +}; + +} + +#endif diff --git a/poincare/src/layout/bounded_static_layout_hierarchy.cpp b/poincare/src/layout/bounded_static_layout_hierarchy.cpp new file mode 100644 index 000000000..12f986e61 --- /dev/null +++ b/poincare/src/layout/bounded_static_layout_hierarchy.cpp @@ -0,0 +1,37 @@ +#include +#include +extern "C" { +#include +} + +namespace Poincare { + +template +BoundedStaticLayoutHierarchy::BoundedStaticLayoutHierarchy() : + StaticLayoutHierarchy(), + m_numberOfChildren(0) +{ +} + +template +BoundedStaticLayoutHierarchy::BoundedStaticLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands) : + m_numberOfChildren(numberOfOperands) +{ + StaticLayoutHierarchy::build(operands, numberOfOperands, cloneOperands); +} + +template<> +BoundedStaticLayoutHierarchy<2>::BoundedStaticLayoutHierarchy(const ExpressionLayout * e, bool cloneOperands) : + BoundedStaticLayoutHierarchy((ExpressionLayout **)&e, 1, cloneOperands) +{ +} + +template<> +BoundedStaticLayoutHierarchy<2>::BoundedStaticLayoutHierarchy(const ExpressionLayout * e1, const ExpressionLayout * e2, bool cloneOperands) : + BoundedStaticLayoutHierarchy(ExpressionLayoutArray(e1, e2).array(), 2, cloneOperands) +{ +} + +template class Poincare::BoundedStaticLayoutHierarchy<2>; + +} From 29e877ec92f6b8a2c66b782e4de27dc6c4f60752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 16:47:26 +0100 Subject: [PATCH 126/257] [poincare] NthRootLayout is now a BoundedStaticLayoutHierarchy. It can now handle having an index or not (simple square root layout). Change-Id: I7a3795c62873fa0a356719b8d572dd5a5be53c94 --- apps/expression_editor/controller.cpp | 2 +- .../poincare/expression_layout_cursor.h | 2 +- poincare/src/expression_layout_cursor.cpp | 5 ++- poincare/src/layout/nth_root_layout.cpp | 33 +++++++++++-------- poincare/src/layout/nth_root_layout.h | 6 ++-- .../src/layout/static_layout_hierarchy.cpp | 3 +- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 052815e49..8e9c77078 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -118,7 +118,7 @@ ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { return m_cursor.addEmptyPowerLayout(); } if (event == Ion::Events::Sqrt) { - return m_cursor.addEmptyRootLayout(); + return m_cursor.addEmptySquareRootLayout(); } if (event == Ion::Events::Square) { return m_cursor.addEmptySquarePowerLayout(); diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 76b335f1c..779cd9318 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -44,7 +44,7 @@ public: ExpressionLayout * addFractionLayoutAndCollapseBrothers(); ExpressionLayout * addEmptyLogarithmLayout(); ExpressionLayout * addEmptyPowerLayout(); - ExpressionLayout * addEmptyRootLayout(); + ExpressionLayout * addEmptySquareRootLayout(); ExpressionLayout * addEmptySquarePowerLayout(); ExpressionLayout * addXNTCharLayout(); ExpressionLayout * insertText(const char * text); diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index c22d3430b..1070b4167 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -127,10 +127,9 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { return child1; } -ExpressionLayout * ExpressionLayoutCursor::addEmptyRootLayout() { +ExpressionLayout * ExpressionLayoutCursor::addEmptySquareRootLayout() { EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); - EmptyVisibleLayout * child2 = new EmptyVisibleLayout(); - NthRootLayout * newChild = new NthRootLayout(child1, child2, false); + NthRootLayout * newChild = new NthRootLayout(child1, false); m_pointedExpressionLayout->addBrother(this, newChild); setPointedExpressionLayout(child1); setPosition(ExpressionLayoutCursor::Position::Right); diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 8d8ab0aa1..8831869c7 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -17,14 +17,18 @@ const uint8_t radixPixel[NthRootLayout::k_leftRadixHeight][NthRootLayout::k_left }; ExpressionLayout * NthRootLayout::clone() const { - NthRootLayout * layout = new NthRootLayout(const_cast(this)->radicandLayout(), const_cast(this)->indexLayout(), true); - return layout; + if (numberOfChildren() == 1) { + return new NthRootLayout(const_cast(this)->radicandLayout(), true); + } + assert(numberOfChildren() == 2); + return new NthRootLayout(const_cast(this)->radicandLayout(), const_cast(this)->indexLayout(), true); } void NthRootLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { // Case: Left the index. // Move Left. - if (cursor->position() == ExpressionLayoutCursor::Position::Left + if (indexLayout() + && cursor->position() == ExpressionLayoutCursor::Position::Left && cursor->pointedExpressionLayout() == indexLayout()) { cursor->setPointedExpressionLayout(this); @@ -64,7 +68,7 @@ void NthRootLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { } // Case: Left. // Ask the parent. - assert(cursor->position() ==ExpressionLayoutCursor::Position::Left); + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (m_parent) { return m_parent->backspaceAtCursor(cursor); } @@ -155,20 +159,20 @@ bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is Left of the radicand, move it to the index. - if (radicandLayout() + if (indexLayout() + && radicandLayout() && previousLayout == radicandLayout() && cursor->positionIsEquivalentTo(radicandLayout(), ExpressionLayoutCursor::Position::Left)) { - assert(indexLayout() != nullptr); cursor->setPointedExpressionLayout(indexLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Right); return true; } // If the cursor is Left, move it to the index. - if (cursor->pointedExpressionLayout() == this + if (indexLayout() + && cursor->pointedExpressionLayout() == this && cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(indexLayout() != nullptr); cursor->setPointedExpressionLayout(indexLayout()); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; @@ -260,12 +264,12 @@ KDPoint NthRootLayout::positionOfChild(ExpressionLayout * child) { KDCoordinate x = 0; KDCoordinate y = 0; KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); - if (child == indexLayout()) { - x = 0; - y = baseline() - indexSize.height() - k_indexHeight; - } else if (child == radicandLayout()) { + if (child == radicandLayout()) { x = indexSize.width() + 2*k_widthMargin + k_radixLineThickness; y = baseline() - radicandLayout()->baseline(); + } else if (indexLayout() && child == indexLayout()) { + x = 0; + y = baseline() - indexSize.height() - k_indexHeight; } else { assert(false); } @@ -277,7 +281,10 @@ ExpressionLayout * NthRootLayout::radicandLayout() { } ExpressionLayout * NthRootLayout::indexLayout() { - return editableChild(1); + if (numberOfChildren() > 1) { + return editableChild(1); + } + return nullptr; } } diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index c04f5c7f2..fb2a54048 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -1,16 +1,16 @@ #ifndef POINCARE_NTH_ROOT_LAYOUT_H #define POINCARE_NTH_ROOT_LAYOUT_H -#include +#include #include namespace Poincare { -class NthRootLayout : public StaticLayoutHierarchy<2> { +class NthRootLayout : public BoundedStaticLayoutHierarchy<2> { public: constexpr static KDCoordinate k_leftRadixHeight = 8; constexpr static KDCoordinate k_leftRadixWidth = 5; - using StaticLayoutHierarchy::StaticLayoutHierarchy; + using BoundedStaticLayoutHierarchy::BoundedStaticLayoutHierarchy; ExpressionLayout * clone() const override; /* Dynamic Layout*/ diff --git a/poincare/src/layout/static_layout_hierarchy.cpp b/poincare/src/layout/static_layout_hierarchy.cpp index 76314772e..224902945 100644 --- a/poincare/src/layout/static_layout_hierarchy.cpp +++ b/poincare/src/layout/static_layout_hierarchy.cpp @@ -52,8 +52,7 @@ void StaticLayoutHierarchy::build(const ExpressionLayout * const * operands, assert(operands != nullptr); assert(numberOfOperands <= T); for (int i=0; i < numberOfOperands; i++) { - assert(operands[i] != nullptr); - if (cloneOperands) { + if (cloneOperands && operands[i] != nullptr) { m_children[i] = operands[i]->clone(); } else { m_children[i] = operands[i]; From 1fb2ab1829c261b65178696c94d25fdaf87ffaa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 8 Jan 2018 16:56:33 +0100 Subject: [PATCH 127/257] [expression_editor] Multiplication button inserts multiplication dots. Change-Id: I9e87487a7419faef161378fc269e1d366c8e1a40 --- apps/expression_editor/controller.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 8e9c77078..8f686e47b 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -1,5 +1,6 @@ #include "controller.h" #include +#include using namespace Poincare; @@ -124,7 +125,12 @@ ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { return m_cursor.addEmptySquarePowerLayout(); } if (event.hasText()) { - return m_cursor.insertText(event.text()); + const char * textToInsert = event.text(); + if (textToInsert[0] == Ion::Charset::MultiplicationSign && textToInsert[1] == 0) { + const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; + return m_cursor.insertText(middleDotString); + } + return m_cursor.insertText(textToInsert); } return nullptr; } From 0575cd2d60f78c97b89ff8e24b211531fd787503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 09:50:04 +0100 Subject: [PATCH 128/257] [poincare] addBrother should first assess if the layout is horizontal. Before, if the cursor was Right of an HorizontalLayout, pressing "/" might put the whole HorizontalLayout as the numerator of the new fraction, because the fraction layout was added as a brother of the HorizontalLayout, not a child. Change-Id: I3b58920e48db49ccd4204c405362d148260461d4 --- poincare/src/layout/expression_layout.cpp | 31 +++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index c46fba418..4c0c196ee 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -110,32 +110,35 @@ bool ExpressionLayout::hasAncestor(const ExpressionLayout * e) const { } void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { - if (m_parent) { - int brotherIndex = cursor->position() == ExpressionLayoutCursor::Position::Left ? m_parent->indexOfChild(this) : m_parent->indexOfChild(this) + 1; - if (m_parent->isHorizontal()) { - static_cast(m_parent)->addOrMergeChildAtIndex(brother, brotherIndex); - return; + // First, assess the special case when the layout is horizontal. + // If so, add the "brother" as a child. + if (isHorizontal()) { + // If there is only one empty child, remove it before adding the layout. + if (numberOfChildren() == 1 && editableChild(0)->isEmpty()) { + removeChildAtIndex(0, true); } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - replaceWithJuxtapositionOf(brother, this, false); + addChildAtIndex(brother, 0); return; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - replaceWithJuxtapositionOf(this, brother, false); + addChildAtIndex(brother, numberOfChildren()); return; } - // If there is no parent, the pointed layout is the main horizontal layout. - // Add the "brother" as a child. - // If there is only one empty child, remove it before adding the layout. - if (numberOfChildren() == 1 && editableChild(0)->isEmpty()) { - removeChildAtIndex(0, true); + + // If the layout is not horizontal, it must have a parent. + assert(m_parent); + int brotherIndex = cursor->position() == ExpressionLayoutCursor::Position::Left ? m_parent->indexOfChild(this) : m_parent->indexOfChild(this) + 1; + if (m_parent->isHorizontal()) { + static_cast(m_parent)->addOrMergeChildAtIndex(brother, brotherIndex); + return; } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - addChildAtIndex(brother, 0); + replaceWithJuxtapositionOf(brother, this, false); return; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - addChildAtIndex(brother, numberOfChildren()); + replaceWithJuxtapositionOf(this, brother, false); return; } From 93f645c3319e9f3fe75d7f0b7a987051a63505c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 09:56:15 +0100 Subject: [PATCH 129/257] [poincare] Better comment for replacing HorizontalLayout with Empty. Change-Id: I6210d63e40f079e5886e7c29cf8e0e305142eb4b --- poincare/src/layout/horizontal_layout.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 24ebff1c3..1ad87670c 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -41,7 +41,8 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio return; } // If the new layout is empty and it was the only horizontal layout child, - // replace the horizontal layout with this empty layout. + // replace the horizontal layout with this empty layout (only if this is not + // the main layout, so only if the layout has a parent. if (m_parent) { replaceWith(newChild); return; From d6fbcbaa00b33d152504d9982b7d1a9b66fa6784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 10:32:03 +0100 Subject: [PATCH 130/257] [poincare] Fixed serialization of square roots and Nth roots. Change-Id: I68f9af1c6fc59d97b1dfb547062cf976012a1e4f --- poincare/src/layout/nth_root_layout.cpp | 41 +++++++++++++++++++++++++ poincare/src/layout/nth_root_layout.h | 4 +-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 8831869c7..4e749d8c9 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -1,4 +1,5 @@ #include "nth_root_layout.h" +#include #include #include #include @@ -199,6 +200,46 @@ bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); } +static_assert('\x90' == Ion::Charset::Root, "Unicode error"); +int NthRootLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + // Case: root(x,n) + if (numberOfChildren() == 2 + && (const_cast(this))->indexLayout() + && !(const_cast(this))->indexLayout()->isEmpty()) + { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "root"); + } + // Case: squareRoot(x) + if (numberOfChildren() == 1) { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "\x90"); + } + // Case: root(x,empty) + // Write "'SquareRootSymbol'('radicandLayout')". + assert((const_cast(this))->indexLayout() && (const_cast(this))->indexLayout()->isEmpty()); + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + int numberOfChar = 0; + + buffer[numberOfChar++] = '\x90'; + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + + buffer[numberOfChar++] = '('; + if (numberOfChar >= bufferSize-1) { + return bufferSize-1; + } + + numberOfChar += (const_cast(this))->radicandLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + buffer[numberOfChar++] = ')'; + buffer[numberOfChar] = 0; + return numberOfChar; +} + void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { KDSize radicandSize = radicandLayout()->size(); KDSize indexSize = indexLayout() != nullptr ? indexLayout()->size() : KDSize(k_leftRadixWidth,0); diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index fb2a54048..86a840b55 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -23,9 +23,7 @@ public: bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; /* Expression Engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "root"); - } + int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; From aaca93e9149a6b428022b4e769581bc4dbb8c4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 11:01:35 +0100 Subject: [PATCH 131/257] [poincare] Helper function to create log layouts. Change-Id: I4f43d11a48e1b8bdddb6660da11e3127778a0bae --- poincare/include/poincare/layout_engine.h | 4 ++++ poincare/src/layout_engine.cpp | 23 +++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/poincare/include/poincare/layout_engine.h b/poincare/include/poincare/layout_engine.h index f5838d0f9..2b8c9984d 100644 --- a/poincare/include/poincare/layout_engine.h +++ b/poincare/include/poincare/layout_engine.h @@ -11,8 +11,12 @@ public: /* Expression to ExpressionLayout */ static ExpressionLayout * createInfixLayout(const Expression * expression, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat, const char * operatorName); static ExpressionLayout * createPrefixLayout(const Expression * expression, Expression::FloatDisplayMode floatDisplayMode, Expression::ComplexFormat complexFormat, const char * operatorName); + + /* Create special layouts */ static ExpressionLayout * createParenthesedLayout(ExpressionLayout * layout, bool cloneLayout); static ExpressionLayout * createStringLayout(const char * buffer, int bufferSize, KDText::FontSize fontSize = KDText::FontSize::Large); + static ExpressionLayout * createLogLayout(ExpressionLayout * argument, ExpressionLayout * index); + /* Expression to Text */ typedef bool (*OperandNeedsParenthesis)(const Expression * e); diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index 14a1f14f7..f54bbba22 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -3,6 +3,7 @@ #include "layout/horizontal_layout.h" #include "layout/parenthesis_left_layout.h" #include "layout/parenthesis_right_layout.h" +#include "layout/vertical_offset_layout.h" extern "C" { #include } @@ -49,6 +50,16 @@ ExpressionLayout * LayoutEngine::createPrefixLayout(const Expression * expressio return result; } +ExpressionLayout * LayoutEngine::createParenthesedLayout(ExpressionLayout * layout, bool cloneLayout) { + HorizontalLayout * result = new HorizontalLayout(); + result->addChildAtIndex(new ParenthesisLeftLayout(), 0); + if (layout != nullptr) { + result->addOrMergeChildAtIndex(cloneLayout ? layout->clone() : layout, 1); + } + result->addChildAtIndex(new ParenthesisRightLayout(), result->numberOfChildren()); + return result; +} + ExpressionLayout * LayoutEngine::createStringLayout(const char * buffer, int bufferSize, KDText::FontSize fontSize) { assert(bufferSize > 0); HorizontalLayout * resultLayout = new HorizontalLayout(); @@ -58,12 +69,12 @@ ExpressionLayout * LayoutEngine::createStringLayout(const char * buffer, int buf return resultLayout; } -ExpressionLayout * LayoutEngine::createParenthesedLayout(ExpressionLayout * layout, bool cloneLayout) { - HorizontalLayout * result = new HorizontalLayout(); - result->addChildAtIndex(new ParenthesisLeftLayout(), 0); - result->addOrMergeChildAtIndex(cloneLayout ? layout->clone() : layout, 1); - result->addChildAtIndex(new ParenthesisRightLayout(), result->numberOfChildren()); - return result; +ExpressionLayout * LayoutEngine::createLogLayout(ExpressionLayout * argument, ExpressionLayout * index) { + HorizontalLayout * resultLayout = static_cast(createStringLayout("log", 3)); + VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(index, VerticalOffsetLayout::Type::Subscript, false); + resultLayout->addChildAtIndex(offsetLayout, resultLayout->numberOfChildren()); + resultLayout->addOrMergeChildAtIndex(createParenthesedLayout(argument, false), resultLayout->numberOfChildren()); + return resultLayout; } int LayoutEngine::writeInfixExpressionTextInBuffer(const Expression * expression, char * buffer, int bufferSize, const char * operatorName, OperandNeedsParenthesis operandNeedsParenthesis) { From 0431326c506ea5c3d5e39070ffc9dc92bdabe496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 11:02:03 +0100 Subject: [PATCH 132/257] [poincare] Use the helper LogLayout creation function. Change-Id: Id43437d3bb2a9e608c08435c6c75f3aa21ac450c --- poincare/src/logarithm.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/poincare/src/logarithm.cpp b/poincare/src/logarithm.cpp index e8f14dd94..75f8a257d 100644 --- a/poincare/src/logarithm.cpp +++ b/poincare/src/logarithm.cpp @@ -234,12 +234,7 @@ ExpressionLayout * Logarithm::privateCreateLayout(FloatDisplayMode floatDisplayM if (numberOfOperands() == 1) { return LayoutEngine::createPrefixLayout(this, floatDisplayMode, complexFormat, "log"); } - HorizontalLayout * result = new HorizontalLayout(); - result->addChildAtIndex(LayoutEngine::createStringLayout("log", strlen("log")), 0); - VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(operand(1)->createLayout(floatDisplayMode, complexFormat), VerticalOffsetLayout::Type::Subscript, false); - result->addChildAtIndex(offsetLayout, 1); - result->addOrMergeChildAtIndex(LayoutEngine::createParenthesedLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false), 2); - return result; + return LayoutEngine::createLogLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), operand(1)->createLayout(floatDisplayMode, complexFormat)); } } From bbd4cb6da92338174e0a2415130246dfdb60b9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 10:56:26 +0100 Subject: [PATCH 133/257] [apps] Added NthRoot and Log layouts in MathToolbox. Change-Id: I3efcf6d56acec542566d22e23b5e3b66fb0af5fc --- apps/math_toolbox.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 1597980ba..d59fdd2ce 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -101,6 +101,8 @@ const ToolboxMessageTree predictionChildren[3] = { ToolboxMessageTree(I18n::Message::ConfidenceCommandWithArg, I18n::Message::Confidence, I18n::Message::ConfidenceCommandWithArg)}; const int pointedLayoutPathAbs[] = {0}; +const int pointedLayoutPathRoot[] = {1}; +const int pointedLayoutPathLog[] = {3,0}; #if LIST_ARE_DEFINED const ToolboxMessageTree menu[12] = { #elif MATRICES_ARE_DEFINED @@ -113,8 +115,16 @@ const ToolboxMessageTree menu[10] = { new EmptyVisibleLayout()), const_cast(&pointedLayoutPathAbs[0]), 1), - ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommandWithArg), - ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg), + ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommandWithArg, nullptr, 0, + new NthRootLayout( + new EmptyVisibleLayout(), + new EmptyVisibleLayout()), + const_cast(&pointedLayoutPathRoot[0]), + 1), + ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg, nullptr, 0, + LayoutEngine::createLogLayout(nullptr, new EmptyVisibleLayout()), + const_cast(&pointedLayoutPathLog[0]), + 2), ToolboxMessageTree(I18n::Message::Calculation, I18n::Message::Default, I18n::Message::Default, calculChildren, 4), ToolboxMessageTree(I18n::Message::ComplexNumber, I18n::Message::Default, I18n::Message::Default, complexChildren, 5), ToolboxMessageTree(I18n::Message::Probability, I18n::Message::Default, I18n::Message::Default, probabilityChildren, 2), From 5f8bda507563d0a75d75d278153504aa8852ebcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 11:07:48 +0100 Subject: [PATCH 134/257] [poincare] Clean LayoutEngine's writeInfixExpressionLayoutTextInBuffer. Change-Id: Ic8e958ef6d3ff965f76c2426d45323ac0d651d76 --- poincare/include/poincare/layout_engine.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/poincare/include/poincare/layout_engine.h b/poincare/include/poincare/layout_engine.h index 2b8c9984d..1f2f8bd82 100644 --- a/poincare/include/poincare/layout_engine.h +++ b/poincare/include/poincare/layout_engine.h @@ -42,7 +42,7 @@ public: int firstChildIndex = 0, int lastChildIndex = -1, ChildNeedsParenthesis childNeedsParenthesis = [](const char * operatorName) { - return (operatorName[1] == 0 && (operatorName[0] == powerChar || operatorName[0] == divideChar)); }); //TODO + return (operatorName[1] == 0 && (operatorName[0] == divideChar)); }); static int writePrefixExpressionLayoutTextInBuffer( const ExpressionLayout * expressionLayout, char * buffer, @@ -54,7 +54,6 @@ public: static int writeOneCharInBuffer(char * buffer, int bufferSize, char charToWrite); private: - static constexpr char powerChar = '^'; static constexpr char divideChar = '/'; // These two functions return the index of the null-terminating char. static int writeInfixExpressionOrExpressionLayoutTextInBuffer(const Expression * expression, const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, const char * operatorName, int firstChildIndex, int lastChildIndex, OperandNeedsParenthesis operandNeedsParenthesis, ChildNeedsParenthesis childNeedsParenthesis); From 73e7f54c7c635d2c2955587f67d93267838ba1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 17:44:05 +0100 Subject: [PATCH 135/257] [expression_editor] Fixed Makefile for the dummy tests. Change-Id: I9f7a380a8271cb40258d8eada1fccf8ac60d04f8 --- apps/expression_editor/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/expression_editor/Makefile b/apps/expression_editor/Makefile index 7edd46555..137280e8a 100644 --- a/apps/expression_editor/Makefile +++ b/apps/expression_editor/Makefile @@ -19,8 +19,5 @@ tests += $(addprefix apps/expression_editor/test/,\ ) test_objs += $(addprefix apps/expression_editor/,\ - controller.o\ - expression_editor_view.o\ expression_view_with_cursor.o\ - scrollable_expression_view_with_cursor.o\ ) From 59c957b5fb1aa1115d18e310b0418b18b850c1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 15:31:25 +0100 Subject: [PATCH 136/257] [expression_editor] DIRTY COMMIT to display a layout value computation. Change-Id: I7a548afe4df9c863f5b5716a819f42141f7fb5c2 --- apps/expression_editor/controller.cpp | 27 ++++++++++++++++++- apps/expression_editor/controller.h | 3 +++ .../expression_editor_view.cpp | 15 ++++++++--- .../expression_editor_view.h | 4 ++- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 8f686e47b..814200eb8 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -1,5 +1,6 @@ #include "controller.h" #include +#include #include using namespace Poincare; @@ -9,7 +10,9 @@ namespace ExpressionEditor { Controller::Controller(Responder * parentResponder, ExpressionLayout * expressionLayout) : ViewController(parentResponder), m_view(parentResponder, expressionLayout, &m_cursor), - m_expressionLayout(expressionLayout) + m_expressionLayout(expressionLayout), + m_resultLayout(nullptr) + //m_context((GlobalContext *)((AppsContainer *)(app()->container()))->globalContext()) { m_cursor.setPointedExpressionLayout(expressionLayout->editableChild(0)); } @@ -32,6 +35,7 @@ void Controller::didBecomeFirstResponder() { bool Controller::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::EXE) { serializeLayout(); + computeResult(); return true; } if (privateHandleEvent(event)) { @@ -148,4 +152,25 @@ void Controller::serializeLayout() { m_view.setText(const_cast(m_buffer)); } +void Controller::computeResult() { + m_expressionLayout->writeTextInBuffer(m_buffer, k_bufferSize); + Expression * result = Expression::parse(m_buffer); + Expression * approxResult = nullptr; + if (result != nullptr) { + Expression::Simplify(&result,*(((AppsContainer *)(app()->container()))->globalContext())); + approxResult = result->approximate(*(((AppsContainer *)(app()->container()))->globalContext())); + delete m_resultLayout; + } else { + approxResult = new Undefined(); + } + m_resultLayout = approxResult->createLayout(); + m_view.setResult(m_resultLayout); + if (result != nullptr) { + delete result; + } + if (approxResult != nullptr) { + delete approxResult; + } +} + } diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index e777e4103..5a02edd17 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -30,11 +30,14 @@ private: Poincare::ExpressionLayout * handleAddEvent(Ion::Events::Event event); bool handleDeleteEvent(Ion::Events::Event event); void serializeLayout(); + void computeResult(); ExpressionEditorView m_view; Poincare::ExpressionLayout * m_expressionLayout; Poincare::ExpressionLayoutCursor m_cursor; static constexpr int k_bufferSize = 256; char m_buffer[k_bufferSize]; + Poincare::ExpressionLayout * m_resultLayout; + //Poincare::Context m_context; }; } diff --git a/apps/expression_editor/expression_editor_view.cpp b/apps/expression_editor/expression_editor_view.cpp index fe825654e..7fc386c89 100644 --- a/apps/expression_editor/expression_editor_view.cpp +++ b/apps/expression_editor/expression_editor_view.cpp @@ -5,7 +5,8 @@ namespace ExpressionEditor { ExpressionEditorView::ExpressionEditorView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor) : SolidColorView(KDColorWhite), - m_scrollableExpressionViewWithCursor(parentResponder, expressionLayout, cursor) + m_scrollableExpressionViewWithCursor(parentResponder, expressionLayout, cursor), + m_resultExpressionView() { m_serializerTextView.setText("Hello"); } @@ -19,19 +20,27 @@ void ExpressionEditorView::setText(const char * text) { m_serializerTextView.setText(text); } +void ExpressionEditorView::setResult(Poincare::ExpressionLayout * eL) { + m_resultExpressionView.setExpressionLayout(eL); +} + View * ExpressionEditorView::subviewAtIndex(int index) { - assert(index >= 0 && index < 2); + assert(index >= 0 && index < 3); if (index == 0) { return &m_scrollableExpressionViewWithCursor; } + if (index == 1) { + return &m_resultExpressionView; + } return &m_serializerTextView; } void ExpressionEditorView::layoutSubviews() { m_serializerTextView.setFrame(KDRect(0, 0, bounds().width(), 20)); + m_resultExpressionView.setFrame(KDRect(20, k_margin, bounds().width() - 2 * k_margin, 50)); m_scrollableExpressionViewWithCursor.setFrame(KDRect( k_margin, - k_margin, + 50+k_margin, bounds().width() - 2 * k_margin, bounds().height() - 2 * k_margin)); markRectAsDirty(bounds()); diff --git a/apps/expression_editor/expression_editor_view.h b/apps/expression_editor/expression_editor_view.h index def2ec2b5..2d0116b35 100644 --- a/apps/expression_editor/expression_editor_view.h +++ b/apps/expression_editor/expression_editor_view.h @@ -12,7 +12,8 @@ public: ExpressionEditorView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor); void cursorPositionChanged(); void setText(const char * text); - int numberOfSubviews() const override { return 2; } + void setResult(Poincare::ExpressionLayout * result); + int numberOfSubviews() const override { return 3; } ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor() { return &m_scrollableExpressionViewWithCursor; } View * subviewAtIndex(int index) override; void layoutSubviews() override; @@ -20,6 +21,7 @@ public: private: constexpr static KDCoordinate k_margin = 10; ScrollableExpressionViewWithCursor m_scrollableExpressionViewWithCursor; + ExpressionView m_resultExpressionView; BufferTextView m_serializerTextView; }; From 5ec88dff8eaa60b5f6c2b1202befab5542ea84ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 15:44:16 +0100 Subject: [PATCH 137/257] [poincare] EmptyExpression now exist and can be parsed. Change-Id: I226026fc866c556d9bf4f57c3622f71136dc841c --- ion/include/ion/charset.h | 3 +- poincare/Makefile | 1 + poincare/include/poincare.h | 1 + poincare/include/poincare/empty_expression.h | 29 ++++++++++++++++++++ poincare/include/poincare/expression.h | 2 ++ poincare/src/empty_expression.cpp | 28 +++++++++++++++++++ poincare/src/expression_lexer.l | 1 + poincare/src/expression_parser.y | 5 +++- 8 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 poincare/include/poincare/empty_expression.h create mode 100644 poincare/src/empty_expression.cpp diff --git a/ion/include/ion/charset.h b/ion/include/ion/charset.h index fb463525f..333c2c4c6 100644 --- a/ion/include/ion/charset.h +++ b/ion/include/ion/charset.h @@ -24,7 +24,8 @@ enum Charset : char { GreaterEqual = (char)146, MultiplicationSign = (char)147, MiddleDot = (char)148, - AlmostEqual = (char)149 + AlmostEqual = (char)149, + Empty = (char)150 // This char is used to be parsed into EmptyExpression. }; } diff --git a/poincare/Makefile b/poincare/Makefile index 9a1cc88da..a04201309 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -26,6 +26,7 @@ objs += $(addprefix poincare/src/,\ division_remainder.o\ division.o\ dynamic_hierarchy.o\ + empty_expression.o\ expression_layout_cursor.o\ expression_lexer.o\ expression_parser.o\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index 9c2e8e8f1..88826ff40 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/include/poincare/empty_expression.h b/poincare/include/poincare/empty_expression.h new file mode 100644 index 000000000..e56ecc47a --- /dev/null +++ b/poincare/include/poincare/empty_expression.h @@ -0,0 +1,29 @@ +#ifndef POINCARE_EMPTY_EXPRESSION_H +#define POINCARE_EMPTY_EXPRESSION_H + +#include +#include + +namespace Poincare { + +/* An empty expression awaits completion by the user. */ + +class EmptyExpression : public StaticHierarchy<0> { +public: + Type type() const override { + return Type::EmptyExpression; + } + Expression * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override;private: + /* Layout */ + ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; + /* Evaluation */ + Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } + template Complex * templatedApproximate(Context& context, AngleUnit angleUnit) const; +}; + +} + +#endif + diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index e29dc0309..4436bce4c 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -74,6 +74,7 @@ class Expression { friend class Trigonometry; friend class ApproximationEngine; friend class SimplificationEngine; + friend class EmptyExpression; public: enum class Type : uint8_t { @@ -136,6 +137,7 @@ public: MatrixTranspose, PredictionInterval, SimplificationRoot, + EmptyExpression }; enum class FloatDisplayMode { Decimal = 0, diff --git a/poincare/src/empty_expression.cpp b/poincare/src/empty_expression.cpp new file mode 100644 index 000000000..b9d7ae2fd --- /dev/null +++ b/poincare/src/empty_expression.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +extern "C" { +#include +} + +namespace Poincare { + +Expression * EmptyExpression::clone() const { + return new EmptyExpression(); +} + +int EmptyExpression::writeTextInBuffer(char * buffer, int bufferSize) const { + return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, Ion::Charset::Empty); +} + +ExpressionLayout * EmptyExpression::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { + return new EmptyVisibleLayout(); +} + +template Complex * EmptyExpression::templatedApproximate(Context& context, AngleUnit angleUnit) const { + return new Complex(Complex::Float(NAN)); +} + +} diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index b2d04483e..577e71acc 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -156,6 +156,7 @@ inf { poincare_expression_yylval.expression = new Undefined(); return UNDEFINED; \, { return COMMA; } \. { return DOT; } \_ { return UNDERSCORE; } +\x96 { poincare_expression_yylval.expression = new EmptyExpression(); return EMPTY; } [ ]+ /* Ignore whitespaces */ . { return UNDEFINED_SYMBOL; } diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index e48a16e0c..0f53054f1 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -51,6 +51,7 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char %token SYMBOL %token FUNCTION %token UNDEFINED +%token EMPTY /* Operator tokens */ %token PLUS @@ -114,6 +115,7 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char %nonassoc ICOMPLEX %nonassoc UNDEFINED %nonassoc SYMBOL +%nonassoc EMPTY /* The "exp" symbol uses the "expression" part of the union. */ %type final_exp; @@ -129,7 +131,7 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char * have some heap-allocated data that need to be discarded. */ %destructor { delete $$; } FUNCTION -%destructor { delete $$; } UNDEFINED final_exp exp number +%destructor { delete $$; } UNDEFINED final_exp exp number EMPTY %destructor { delete $$; } lstData /* MATRICES_ARE_DEFINED */ %destructor { delete $$; } mtxData @@ -180,6 +182,7 @@ symb: * "exp MINUS exp". */ exp: UNDEFINED { $$ = $1; } + | EMPTY { $$ = $1; } | exp BANG { $$ = new Poincare::Factorial($1, false); } | number { $$ = $1; } | symb { $$ = $1; } From 1967fce13af15d720e05b0d903f26c7d011fc6c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 15:45:28 +0100 Subject: [PATCH 138/257] [apps] Toolbox layouts are created by parsing the command of the cell. Change-Id: I511e8af2b2247d1df3ca968191566c2b3f01fe11 --- apps/math_toolbox.cpp | 95 ++++++++------------ apps/shared/toolbox_helpers.cpp | 17 ++++ apps/shared/toolbox_helpers.h | 2 + escher/Makefile | 1 - escher/include/escher/toolbox_message_tree.h | 11 +-- escher/src/toolbox_message_tree.cpp | 13 --- 6 files changed, 62 insertions(+), 77 deletions(-) delete mode 100644 escher/src/toolbox_message_tree.cpp diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index d59fdd2ce..55c160db9 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -11,50 +11,22 @@ using namespace Poincare; * and the text which would be edited by clicking on the row. When the node is a * subtree, the edited text is set at I18n::Message::Default. */ -const int pointedLayoutPathIntegral[] = {0}; -const int pointedLayoutPathSum[] = {0}; + const ToolboxMessageTree calculChildren[4] = { - ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg, nullptr, 0), - ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg, nullptr, 0, - new IntegralLayout( - new EmptyVisibleLayout(), - new EmptyVisibleLayout(), - new EmptyVisibleLayout(), - false), - const_cast(&pointedLayoutPathIntegral[0]), - 1), - ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg, nullptr, 0, - new SumLayout( - new EmptyVisibleLayout(), - new EmptyVisibleLayout(), - new EmptyVisibleLayout(), - false), - const_cast(&pointedLayoutPathSum[0]), - 1), + ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg), + ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg), + ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommandWithArg), ToolboxMessageTree(I18n::Message::ProductCommandWithArg, I18n::Message::Product, I18n::Message::ProductCommandWithArg)}; -const int pointedLayoutPathConj[] = {0}; const ToolboxMessageTree complexChildren[5] = { ToolboxMessageTree(I18n::Message::AbsCommandWithArg,I18n::Message::ComplexAbsoluteValue, I18n::Message::AbsCommandWithArg), ToolboxMessageTree(I18n::Message::ArgCommandWithArg, I18n::Message::Agument, I18n::Message::ArgCommandWithArg), ToolboxMessageTree(I18n::Message::ReCommandWithArg, I18n::Message::RealPart, I18n::Message::ReCommandWithArg), ToolboxMessageTree(I18n::Message::ImCommandWithArg, I18n::Message::ImaginaryPart, I18n::Message::ImCommandWithArg), - ToolboxMessageTree(I18n::Message::ConjCommandWithArg, I18n::Message::Conjugate, I18n::Message::ConjCommandWithArg, nullptr, 0, - new ConjugateLayout( - new EmptyVisibleLayout()), - const_cast(&pointedLayoutPathConj[0]), - 1)}; + ToolboxMessageTree(I18n::Message::ConjCommandWithArg, I18n::Message::Conjugate, I18n::Message::ConjCommandWithArg)}; -const int pointedLayoutPathBinomial[] = {0, 0}; const ToolboxMessageTree probabilityChildren[2] = { - ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommandWithArg, nullptr, 0, - new ParenthesisLayout( - new GridLayout(Poincare::ExpressionLayoutArray( - new EmptyVisibleLayout(), - new EmptyVisibleLayout()).array(), - 2, 1, false)), - const_cast(&pointedLayoutPathBinomial[0]), - 2), + ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommandWithArg), ToolboxMessageTree(I18n::Message::PermuteCommandWithArg, I18n::Message::Permutation, I18n::Message::PermuteCommandWithArg)}; const ToolboxMessageTree arithmeticChildren[4] = { @@ -100,8 +72,6 @@ const ToolboxMessageTree predictionChildren[3] = { ToolboxMessageTree(I18n::Message::PredictionCommandWithArg, I18n::Message::Prediction, I18n::Message::PredictionCommandWithArg), ToolboxMessageTree(I18n::Message::ConfidenceCommandWithArg, I18n::Message::Confidence, I18n::Message::ConfidenceCommandWithArg)}; -const int pointedLayoutPathAbs[] = {0}; -const int pointedLayoutPathRoot[] = {1}; const int pointedLayoutPathLog[] = {3,0}; #if LIST_ARE_DEFINED const ToolboxMessageTree menu[12] = { @@ -110,21 +80,9 @@ const ToolboxMessageTree menu[11] = { #else const ToolboxMessageTree menu[10] = { #endif - ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg, nullptr, 0, - new AbsoluteValueLayout( - new EmptyVisibleLayout()), - const_cast(&pointedLayoutPathAbs[0]), - 1), - ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommandWithArg, nullptr, 0, - new NthRootLayout( - new EmptyVisibleLayout(), - new EmptyVisibleLayout()), - const_cast(&pointedLayoutPathRoot[0]), - 1), - ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg, nullptr, 0, - LayoutEngine::createLogLayout(nullptr, new EmptyVisibleLayout()), - const_cast(&pointedLayoutPathLog[0]), - 2), + ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg), + ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommandWithArg), + ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg, nullptr, 0, const_cast(&pointedLayoutPathLog[0]), 2), ToolboxMessageTree(I18n::Message::Calculation, I18n::Message::Default, I18n::Message::Default, calculChildren, 4), ToolboxMessageTree(I18n::Message::ComplexNumber, I18n::Message::Default, I18n::Message::Default, complexChildren, 5), ToolboxMessageTree(I18n::Message::Probability, I18n::Message::Default, I18n::Message::Default, probabilityChildren, 2), @@ -175,13 +133,38 @@ bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) { return true; } // Deal with ExpressionEditor::Controller for now. + ToolboxMessageTree * messageTree = selectedMessageTree; m_selectableTableView.deselectTable(); - ExpressionLayout * newLayout = selectedMessageTree->layout()->clone(); - ExpressionLayout * pointedLayout = newLayout; - for (int i = 0; i < selectedMessageTree->pointedPathLength(); i++) { - pointedLayout = pointedLayout->editableChild(selectedMessageTree->pointedPath()[i]); + // Translate the message and replace the arguments with Empty chars. + const char * editedText = I18n::translate(messageTree->insertedText()); + char strippedEditedText[strlen(editedText)]; + Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandMessage(messageTree->insertedText(), strippedEditedText); + // Create the layout + Expression * resultExpression = Expression::parse(strippedEditedText); + if (resultExpression != nullptr) { + ExpressionLayout * resultLayout = resultExpression->createLayout(); + // Find the pointed layout. + ExpressionLayout * pointedLayout = resultLayout; + if (messageTree->pointedPath() != nullptr) { + for (int i = 0; i < messageTree->pointedPathLength(); i++) { + assert(messageTree->pointedPath()[i] < pointedLayout->numberOfChildren()); + pointedLayout = pointedLayout->editableChild(messageTree->pointedPath()[i]); + } + } else if (resultLayout->isHorizontal()) { + // If the layout is horizontal, pick the first open parenthesis. + for (int i = 0; i < resultLayout->numberOfChildren(); i++) { + if (resultLayout->editableChild(i)->isLeftParenthesis()) { + pointedLayout = resultLayout->editableChild(i); + break; + } + } + } else if (resultLayout->numberOfChildren() > 0) { + // Else, if the layout has children, pick the first one. + pointedLayout = resultLayout->editableChild(0); + } + // Insert the layout + expressionEditorControllerSender()->insertLayoutAtCursor(resultLayout, pointedLayout); } - expressionEditorControllerSender()->insertLayoutAtCursor(newLayout, pointedLayout); app()->dismissModalViewController(); return true; } diff --git a/apps/shared/toolbox_helpers.cpp b/apps/shared/toolbox_helpers.cpp index 333a38171..a1da1475f 100644 --- a/apps/shared/toolbox_helpers.cpp +++ b/apps/shared/toolbox_helpers.cpp @@ -1,4 +1,5 @@ #include "toolbox_helpers.h" +#include #include namespace Shared { @@ -40,5 +41,21 @@ void TextToInsertForCommandText(const char * command, char * buffer) { buffer[currentNewTextIndex] = 0; } +void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer) { + const char * messageText = I18n::translate(message); + TextToInsertForCommandText(messageText, buffer); + size_t bufferLength = strlen(buffer); + for (size_t i = 0; i < bufferLength; i++) { + if (buffer[i] == '(' || buffer[i] == ',') { + // Shift the buffer to make room for the new char. Use memmove to avoid + // overwritting. + memmove(&buffer[i+2], &buffer[i+1], bufferLength - (i+1) + 1); + bufferLength++; + i++; + buffer[i] = Ion::Charset::Empty; + } + } +} + } } diff --git a/apps/shared/toolbox_helpers.h b/apps/shared/toolbox_helpers.h index e28e8e4cc..98539614d 100644 --- a/apps/shared/toolbox_helpers.h +++ b/apps/shared/toolbox_helpers.h @@ -17,6 +17,8 @@ void TextToInsertForCommandMessage(I18n::Message message, char * buffer); void TextToInsertForCommandText(const char * command, char * buffer); /* Removes the arguments from a command: * - Removes text between parentheses, except commas */ +void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer); +/* Removes the arguments from a command and replaces them with empty chars. */ } } diff --git a/escher/Makefile b/escher/Makefile index a540f4c6b..3a1964bb1 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -70,7 +70,6 @@ objs += $(addprefix escher/src/,\ tiled_view.o\ timer.o\ toolbox.o\ - toolbox_message_tree.o\ view.o\ view_controller.o\ warning_controller.o\ diff --git a/escher/include/escher/toolbox_message_tree.h b/escher/include/escher/toolbox_message_tree.h index 253ce36ce..062271417 100644 --- a/escher/include/escher/toolbox_message_tree.h +++ b/escher/include/escher/toolbox_message_tree.h @@ -6,27 +6,24 @@ class ToolboxMessageTree : public MessageTree { public: - constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0, Poincare::ExpressionLayout * layout = nullptr, int * pointedLayoutPath = nullptr, int pointedLayoutPathLength = 0) : + constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0, int * pointedLayoutPath = nullptr, int pointedLayoutPathLength = 0) : MessageTree(label, numberOfChildren), m_children(children), m_text(text), m_insertedText(insertedText), - m_layout(layout), m_pointedLayoutPath(pointedLayoutPath), m_pointedLayoutPathLength(pointedLayoutPathLength) { }; - const MessageTree * children(int index) const override; - I18n::Message text() const; - I18n::Message insertedText() const; - Poincare::ExpressionLayout * layout() const { return m_layout; } + const MessageTree * children(int index) const override { return &m_children[index]; } + I18n::Message text() const { return m_text; } + I18n::Message insertedText() const { return m_insertedText; } int * pointedPath() const { return m_pointedLayoutPath; } int pointedPathLength() const { return m_pointedLayoutPathLength; } private: const ToolboxMessageTree * m_children; I18n::Message m_text; I18n::Message m_insertedText; - Poincare::ExpressionLayout * m_layout; int * m_pointedLayoutPath; int m_pointedLayoutPathLength; }; diff --git a/escher/src/toolbox_message_tree.cpp b/escher/src/toolbox_message_tree.cpp deleted file mode 100644 index 595e7e300..000000000 --- a/escher/src/toolbox_message_tree.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include - -I18n::Message ToolboxMessageTree::text() const { - return m_text; -} - -I18n::Message ToolboxMessageTree::insertedText() const { - return m_insertedText; -} - -const MessageTree * ToolboxMessageTree::children(int index) const { - return &m_children[index]; -} From 5d39f177ba7bf91560b97fa9e11dc349ea32739f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 15:46:15 +0100 Subject: [PATCH 139/257] [poincare] Decide to delete EmptyLayouts when merging HorizontalLay. A bool in HorizontalLayout::addOrMergeChildAtIndex decides whether to delete the Emtpy new HorizontalLayout children. Change-Id: Ie7acd7f5052891a929c2ae22cb74de389649cba2 --- .../poincare/dynamic_layout_hierarchy.h | 4 ++-- poincare/src/expression_layout_cursor.cpp | 4 ++-- poincare/src/factorial.cpp | 2 +- .../src/layout/dynamic_layout_hierarchy.cpp | 9 +++++---- poincare/src/layout/expression_layout.cpp | 2 +- poincare/src/layout/fraction_layout.cpp | 4 ++-- poincare/src/layout/horizontal_layout.cpp | 6 +++--- poincare/src/layout/horizontal_layout.h | 2 +- poincare/src/layout_engine.cpp | 19 ++++++++++--------- poincare/src/opposite.cpp | 4 ++-- poincare/src/store.cpp | 4 ++-- 11 files changed, 31 insertions(+), 29 deletions(-) diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index a75e9fc41..a40a7fd13 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -25,10 +25,10 @@ public: int numberOfChildren() const override { return m_numberOfChildren; } const ExpressionLayout * const * children() const override { return m_children; }; - void addNonEmptyChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion); + void addChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion, bool removeEmptyChildren); bool addChildAtIndex(ExpressionLayout * operand, int index) override; void removeChildAtIndex(int index, bool deleteAfterRemoval) override; - void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index); // WITHOUT delete. + void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren); // WITHOUT delete. bool isEmpty() const override; protected: diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 1070b4167..b723de7d0 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -77,7 +77,7 @@ ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers( ExpressionLayout * rightBrother = newChild->editableParent()->editableChild(fractionIndexInParent+1); if (rightBrother->isCollapsable(&numberOfOpenParenthesis, false)) { newChild->editableParent()->removeChildAtIndex(fractionIndexInParent+1, false); - child2->addOrMergeChildAtIndex(rightBrother, child2->numberOfChildren()); + child2->addOrMergeChildAtIndex(rightBrother, child2->numberOfChildren(), true); numberOfBrothers--; } else { break; @@ -89,7 +89,7 @@ ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers( ExpressionLayout * leftBrother = newChild->editableParent()->editableChild(fractionIndexInParent-1); if (leftBrother->isCollapsable(&numberOfOpenParenthesis, true)) { newChild->editableParent()->removeChildAtIndex(fractionIndexInParent-1, false); - child1->addOrMergeChildAtIndex(leftBrother, 0); + child1->addOrMergeChildAtIndex(leftBrother, 0, true); fractionIndexInParent--; } else { break; diff --git a/poincare/src/factorial.cpp b/poincare/src/factorial.cpp index 436b91067..aebe1c98e 100644 --- a/poincare/src/factorial.cpp +++ b/poincare/src/factorial.cpp @@ -77,7 +77,7 @@ ExpressionLayout * Factorial::privateCreateLayout(FloatDisplayMode floatDisplayM assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); HorizontalLayout * result = new HorizontalLayout(); - result->addOrMergeChildAtIndex(operand(0)->createLayout(floatDisplayMode, complexFormat), 0); + result->addOrMergeChildAtIndex(operand(0)->createLayout(floatDisplayMode, complexFormat), 0, false); result->addChildAtIndex(new CharLayout('!'), result->numberOfChildren()); return result; } diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index 707383ed4..5e3c0c5ab 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -42,17 +42,17 @@ DynamicLayoutHierarchy::~DynamicLayoutHierarchy() { delete[] m_children; } -void DynamicLayoutHierarchy::mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index) { +void DynamicLayoutHierarchy::mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren) { int indexOfEL = indexOfChild(eL); if (indexOfEL >= 0) { removeChildAtIndex(indexOfEL, false); } - addNonEmptyChildrenAtIndex(eL->children(), eL->numberOfChildren(), index); + addChildrenAtIndex(eL->children(), eL->numberOfChildren(), index, removeEmptyChildren); eL->detachChildren(); delete eL; } -void DynamicLayoutHierarchy::addNonEmptyChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion) { +void DynamicLayoutHierarchy::addChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion, bool removeEmptyChildren) { assert(numberOfOperands > 0); const ExpressionLayout ** newOperands = new const ExpressionLayout * [m_numberOfChildren+numberOfOperands]; int currentIndex = 0; @@ -61,7 +61,8 @@ void DynamicLayoutHierarchy::addNonEmptyChildrenAtIndex(const ExpressionLayout * newOperands[currentIndex++] = m_children[i]; } for (int i=0; iisEmpty() + if (!removeEmptyChildren + || !operands[i]->isEmpty() || (i < numberOfOperands-1 && operands[i+1]->mustHaveLeftBrother())) { const_cast(operands[i])->setParent(this); diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 4c0c196ee..9c0c45435 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -130,7 +130,7 @@ void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLay assert(m_parent); int brotherIndex = cursor->position() == ExpressionLayoutCursor::Position::Left ? m_parent->indexOfChild(this) : m_parent->indexOfChild(this) + 1; if (m_parent->isHorizontal()) { - static_cast(m_parent)->addOrMergeChildAtIndex(brother, brotherIndex); + static_cast(m_parent)->addOrMergeChildAtIndex(brother, brotherIndex, true); return; } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index c7e6677d6..f2c57ae87 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -72,8 +72,8 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { detachChild(numerator); detachChild(denominator); HorizontalLayout * newLayout = new HorizontalLayout(); - newLayout->addOrMergeChildAtIndex(denominator, 0); - newLayout->addOrMergeChildAtIndex(numerator, 0); + newLayout->addOrMergeChildAtIndex(denominator, 0, true); + newLayout->addOrMergeChildAtIndex(numerator, 0, true); // Add the denominator before the numerator to have the right order. replaceWith(newLayout, true); cursor->setPointedExpressionLayout(nextPointedLayout); diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 1ad87670c..7594a6ff2 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -52,7 +52,7 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio // new layout then destroy it. if (newChild->isHorizontal()) { int indexForInsertion = indexOfChild(const_cast(oldChild)); - mergeChildrenAtIndex(static_cast(newChild), indexForInsertion + 1); + mergeChildrenAtIndex(static_cast(newChild), indexForInsertion + 1, true); removeChildAtIndex(indexForInsertion, deleteOldChild); return; } @@ -60,14 +60,14 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio ExpressionLayout::replaceChild(oldChild, newChild, deleteOldChild); } -void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index) { +void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren) { int newIndex = index; if (numberOfChildren() > 0 && child(0)->isEmpty()) { removeChildAtIndex(0, true); newIndex = index == 0 ? 0 : index - 1; } if (eL->isHorizontal()) { - mergeChildrenAtIndex(static_cast(eL), newIndex); + mergeChildrenAtIndex(static_cast(eL), newIndex, removeEmptyChildren); return; } addChildAtIndex(eL, newIndex); diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 6b789e770..14cd7ce5e 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -17,7 +17,7 @@ public: /* Hierarchy */ void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; - void addOrMergeChildAtIndex(ExpressionLayout * eL, int index); + void addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren); /* Navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index f54bbba22..2070791c4 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -16,14 +16,14 @@ ExpressionLayout * LayoutEngine::createInfixLayout(const Expression * expression int numberOfOperands = expression->numberOfOperands(); assert(numberOfOperands > 1); HorizontalLayout * result = new HorizontalLayout(); - result->addOrMergeChildAtIndex(expression->operand(0)->createLayout(), 0); + result->addOrMergeChildAtIndex(expression->operand(0)->createLayout(), 0, true); for (int i = 1; i < numberOfOperands; i++) { - result->addOrMergeChildAtIndex(createStringLayout(operatorName, strlen(operatorName)), result->numberOfChildren()); + result->addOrMergeChildAtIndex(createStringLayout(operatorName, strlen(operatorName)), result->numberOfChildren(), true); result->addOrMergeChildAtIndex( expression->operand(i)->type() == Expression::Type::Opposite ? createParenthesedLayout(expression->operand(i)->createLayout(floatDisplayMode, complexFormat), false) : expression->operand(i)->createLayout(floatDisplayMode, complexFormat), - result->numberOfChildren()); + result->numberOfChildren(), true); } return result; } @@ -32,21 +32,22 @@ ExpressionLayout * LayoutEngine::createPrefixLayout(const Expression * expressio assert(floatDisplayMode != Expression::FloatDisplayMode::Default); assert(complexFormat != Expression::ComplexFormat::Default); int numberOfOperands = expression->numberOfOperands(); + assert(numberOfOperands > 0); HorizontalLayout * result = new HorizontalLayout(); // Add the operator name. - result->addOrMergeChildAtIndex(createStringLayout(operatorName, strlen(operatorName)), 0); + result->addOrMergeChildAtIndex(createStringLayout(operatorName, strlen(operatorName)), 0, true); // Create the layout of arguments separated by commas. HorizontalLayout * args = new HorizontalLayout(); - args->addOrMergeChildAtIndex(expression->operand(0)->createLayout(floatDisplayMode, complexFormat), 0); + args->addOrMergeChildAtIndex(expression->operand(0)->createLayout(floatDisplayMode, complexFormat), 0, true); for (int i = 1; i < numberOfOperands; i++) { args->addChildAtIndex(new CharLayout(','), args->numberOfChildren()); - args->addOrMergeChildAtIndex(expression->operand(i)->createLayout(floatDisplayMode, complexFormat), args->numberOfChildren()); + args->addOrMergeChildAtIndex(expression->operand(i)->createLayout(floatDisplayMode, complexFormat), args->numberOfChildren(), true); } // Add the parenthesed arguments. - result->addOrMergeChildAtIndex(createParenthesedLayout(args, false), result->numberOfChildren()); + result->addOrMergeChildAtIndex(createParenthesedLayout(args, false), result->numberOfChildren(), true); return result; } @@ -54,7 +55,7 @@ ExpressionLayout * LayoutEngine::createParenthesedLayout(ExpressionLayout * layo HorizontalLayout * result = new HorizontalLayout(); result->addChildAtIndex(new ParenthesisLeftLayout(), 0); if (layout != nullptr) { - result->addOrMergeChildAtIndex(cloneLayout ? layout->clone() : layout, 1); + result->addOrMergeChildAtIndex(cloneLayout ? layout->clone() : layout, 1, true); } result->addChildAtIndex(new ParenthesisRightLayout(), result->numberOfChildren()); return result; @@ -73,7 +74,7 @@ ExpressionLayout * LayoutEngine::createLogLayout(ExpressionLayout * argument, Ex HorizontalLayout * resultLayout = static_cast(createStringLayout("log", 3)); VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(index, VerticalOffsetLayout::Type::Subscript, false); resultLayout->addChildAtIndex(offsetLayout, resultLayout->numberOfChildren()); - resultLayout->addOrMergeChildAtIndex(createParenthesedLayout(argument, false), resultLayout->numberOfChildren()); + resultLayout->addOrMergeChildAtIndex(createParenthesedLayout(argument, false), resultLayout->numberOfChildren(), true); return resultLayout; } diff --git a/poincare/src/opposite.cpp b/poincare/src/opposite.cpp index ec0246192..adabe0422 100644 --- a/poincare/src/opposite.cpp +++ b/poincare/src/opposite.cpp @@ -50,10 +50,10 @@ ExpressionLayout * Opposite::privateCreateLayout(FloatDisplayMode floatDisplayMo assert(complexFormat != ComplexFormat::Default); HorizontalLayout * result = new HorizontalLayout(new CharLayout('-'), false); if (operand(0)->type() == Type::Opposite) { - result->addOrMergeChildAtIndex(LayoutEngine::createParenthesedLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false), 1); + result->addOrMergeChildAtIndex(LayoutEngine::createParenthesedLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false), 1, false); return result; } - result->addOrMergeChildAtIndex(operand(0)->createLayout(floatDisplayMode, complexFormat), 1); + result->addOrMergeChildAtIndex(operand(0)->createLayout(floatDisplayMode, complexFormat), 1, false); return result; } diff --git a/poincare/src/store.cpp b/poincare/src/store.cpp index fbfc5b16d..d9a4945f3 100644 --- a/poincare/src/store.cpp +++ b/poincare/src/store.cpp @@ -29,9 +29,9 @@ ExpressionLayout * Store::privateCreateLayout(FloatDisplayMode floatDisplayMode, assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); HorizontalLayout * result = new HorizontalLayout(); - result->addOrMergeChildAtIndex(value()->createLayout(floatDisplayMode, complexFormat), 0); + result->addOrMergeChildAtIndex(value()->createLayout(floatDisplayMode, complexFormat), 0, false); result->addChildAtIndex(new CharLayout(Ion::Charset::Sto), result->numberOfChildren()); - result->addOrMergeChildAtIndex(symbol()->createLayout(floatDisplayMode, complexFormat), result->numberOfChildren()); + result->addOrMergeChildAtIndex(symbol()->createLayout(floatDisplayMode, complexFormat), result->numberOfChildren(), false); return result; } From 6144e9ec1cf9bb461b471b4b0f31351402113e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 16:38:56 +0100 Subject: [PATCH 140/257] [poincare] Remove EmptyLayout, keep EmptyVisibleLayout only. Change-Id: I99bfb397accc94551802a2726ab4b24483db9396 --- poincare/Makefile | 1 - poincare/src/layout/empty_layout.cpp | 49 -------------------- poincare/src/layout/empty_layout.h | 31 ------------- poincare/src/layout/empty_visible_layout.cpp | 14 +++++- poincare/src/layout/empty_visible_layout.h | 11 ++++- 5 files changed, 22 insertions(+), 84 deletions(-) delete mode 100644 poincare/src/layout/empty_layout.cpp delete mode 100644 poincare/src/layout/empty_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index a04201309..ce40174e4 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -95,7 +95,6 @@ objs += $(addprefix poincare/src/layout/,\ condensed_sum_layout.o\ conjugate_layout.o\ dynamic_layout_hierarchy.o\ - empty_layout.o\ empty_visible_layout.o\ expression_layout.o\ floor_layout.o\ diff --git a/poincare/src/layout/empty_layout.cpp b/poincare/src/layout/empty_layout.cpp deleted file mode 100644 index c7af45bf2..000000000 --- a/poincare/src/layout/empty_layout.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "empty_layout.h" -#include -#include - -namespace Poincare { - -ExpressionLayout * EmptyLayout::clone() const { - EmptyLayout * layout = new EmptyLayout(); - return layout; -} - -int EmptyLayout::writeTextInBuffer(char * buffer, int bufferSize) const { - if (bufferSize == 0) { - return -1; - } - buffer[0] = 0; - return 0; -} - -void EmptyLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { - replaceWith(brother, true); -} - -bool EmptyLayout::moveLeft(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Ask the parent. - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; -} - -bool EmptyLayout::moveRight(ExpressionLayoutCursor * cursor) { - assert(cursor->pointedExpressionLayout() == this); - // Ask the parent. - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; -} - -void EmptyLayout::computeBaseline() { - m_baseline = 0; - m_baselined = true; -} - -} diff --git a/poincare/src/layout/empty_layout.h b/poincare/src/layout/empty_layout.h deleted file mode 100644 index 5d82724f7..000000000 --- a/poincare/src/layout/empty_layout.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef POINCARE_EMPTY_LAYOUT_H -#define POINCARE_EMPTY_LAYOUT_H - -#include -#include -#include - -namespace Poincare { - -class EmptyLayout : public StaticLayoutHierarchy<0> { -public: - using StaticLayoutHierarchy::StaticLayoutHierarchy; - ExpressionLayout * clone() const override; - void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; - bool isEmpty() const override { return true; } -protected: - virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override { return; } - virtual KDSize computeSize() override { return KDSizeZero; } - void computeBaseline() override; - KDPoint positionOfChild(ExpressionLayout * child) override { - assert(false); - return KDPointZero; - } -}; - -} - -#endif diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index a7ac20513..3ecceef79 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -5,7 +5,7 @@ namespace Poincare { EmptyVisibleLayout::EmptyVisibleLayout() : - EmptyLayout(), + StaticLayoutHierarchy(), m_fillRectColor(KDColor::RGB24(0xffd370)) //TODO make static or in Palette? { } @@ -15,6 +15,10 @@ ExpressionLayout * EmptyVisibleLayout::clone() const { return layout; } +void EmptyVisibleLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { + replaceWith(brother, true); +} + void EmptyVisibleLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { assert(cursor->pointedExpressionLayout() == this); if (cursor->position() == ExpressionLayoutCursor::Position::Right) { @@ -59,6 +63,14 @@ bool EmptyVisibleLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +int EmptyVisibleLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (bufferSize == 0) { + return -1; + } + buffer[0] = 0; + return 0; +} + void EmptyVisibleLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { ctx->fillRect(KDRect(p.x()+k_marginWidth, p.y()+k_marginHeight, k_width, k_height), m_fillRectColor); ctx->fillRect(KDRect(p.x()+k_marginWidth, p.y()+k_marginHeight, k_width, k_height), m_fillRectColor); diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index 65714d0ac..f96eb0749 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -1,22 +1,29 @@ #ifndef POINCARE_EMPTY_VISIBLE_LAYOUT_H #define POINCARE_EMPTY_VISIBLE_LAYOUT_H -#include "empty_layout.h" +#include #include namespace Poincare { -class EmptyVisibleLayout : public EmptyLayout { +class EmptyVisibleLayout : public StaticLayoutHierarchy<0> { public: EmptyVisibleLayout(); ExpressionLayout * clone() const override; + void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; + bool isEmpty() const override { return true; } protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; virtual KDSize computeSize() override; void computeBaseline() override; + KDPoint positionOfChild(ExpressionLayout * child) override { + assert(false); + return KDPointZero; + } private: constexpr static KDCoordinate k_width = 7; constexpr static KDCoordinate k_height = 13; From cd9c0472c81e13e9b16005579725e7bb14b118e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 17:30:33 +0100 Subject: [PATCH 141/257] [poincare] BinomialCoefficientLayout. Change-Id: I3ea9d9d7d9dbf2884c458eb17340700e14648044 --- poincare/Makefile | 1 + poincare/include/poincare_layouts.h | 1 + poincare/src/binomial_coefficient.cpp | 11 +- .../layout/binomial_coefficient_layout.cpp | 161 ++++++++++++++++++ .../src/layout/binomial_coefficient_layout.h | 33 ++++ poincare/src/layout/grid_layout.h | 1 + poincare/src/layout/horizontal_layout.h | 1 + poincare/src/layout/parenthesis_left_layout.h | 1 + .../src/layout/parenthesis_right_layout.h | 1 + 9 files changed, 205 insertions(+), 6 deletions(-) create mode 100644 poincare/src/layout/binomial_coefficient_layout.cpp create mode 100644 poincare/src/layout/binomial_coefficient_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index ce40174e4..49bd3a0a5 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -85,6 +85,7 @@ objs += $(addprefix poincare/src/,\ objs += $(addprefix poincare/src/layout/,\ absolute_value_layout.o\ + binomial_coefficient_layout.o\ bounded_static_layout_hierarchy.o\ bracket_layout.o\ bracket_left_layout.o\ diff --git a/poincare/include/poincare_layouts.h b/poincare/include/poincare_layouts.h index 34191f18d..875963fe8 100644 --- a/poincare/include/poincare_layouts.h +++ b/poincare/include/poincare_layouts.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/poincare/src/binomial_coefficient.cpp b/poincare/src/binomial_coefficient.cpp index d770e25bf..8cf0a1d73 100644 --- a/poincare/src/binomial_coefficient.cpp +++ b/poincare/src/binomial_coefficient.cpp @@ -2,8 +2,7 @@ #include #include #include -#include "layout/parenthesis_layout.h" -#include "layout/grid_layout.h" +#include "layout/binomial_coefficient_layout.h" extern "C" { #include @@ -76,10 +75,10 @@ Expression * BinomialCoefficient::shallowReduce(Context& context, AngleUnit angl ExpressionLayout * BinomialCoefficient::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - ExpressionLayout * childrenLayouts[2]; - childrenLayouts[0] = operand(0)->createLayout(floatDisplayMode, complexFormat); - childrenLayouts[1] = operand(1)->createLayout(floatDisplayMode, complexFormat); - return new ParenthesisLayout(new GridLayout(childrenLayouts, 2, 1, false), false); + return new BinomialCoefficientLayout( + operand(0)->createLayout(floatDisplayMode, complexFormat), + operand(1)->createLayout(floatDisplayMode, complexFormat), + false); } template diff --git a/poincare/src/layout/binomial_coefficient_layout.cpp b/poincare/src/layout/binomial_coefficient_layout.cpp new file mode 100644 index 000000000..28b253081 --- /dev/null +++ b/poincare/src/layout/binomial_coefficient_layout.cpp @@ -0,0 +1,161 @@ +#include "binomial_coefficient_layout.h" +#include "empty_visible_layout.h" +#include "grid_layout.h" +#include "horizontal_layout.h" +#include "parenthesis_left_layout.h" +#include "parenthesis_left_right_layout.h" +#include "parenthesis_right_layout.h" +#include +#include +extern "C" { +#include +#include +} + +namespace Poincare { + +ExpressionLayout * BinomialCoefficientLayout::clone() const { + return new BinomialCoefficientLayout(const_cast(this)->nLayout(), const_cast(this)->kLayout(), true); +} + +void BinomialCoefficientLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // Case: Left of the children. + // Delete the layout. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && (cursor->pointedExpressionLayout() == nLayout() + || cursor->pointedExpressionLayout() == kLayout())) + { + assert(m_parent != nullptr); + int indexInParent = m_parent->indexOfChild(this); + ExpressionLayout * parent = m_parent; + replaceWith(new EmptyVisibleLayout(), true); + if (indexInParent == 0) { + cursor->setPointedExpressionLayout(parent); + return; + } + cursor->setPointedExpressionLayout(parent->editableChild(indexInParent-1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + +bool BinomialCoefficientLayout::moveLeft(ExpressionLayoutCursor * cursor) { + // Case: Left of the children. + // Go Left. + if (cursor->position() == ExpressionLayoutCursor::Position::Left + && (cursor->pointedExpressionLayout() == nLayout() + || cursor->pointedExpressionLayout() == kLayout())) + { + cursor->setPointedExpressionLayout(this); + return true; + } + + assert(cursor->pointedExpressionLayout() == this); + // Case: Right. + // Go to the kLayout. + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + assert(kLayout() != nullptr); + cursor->setPointedExpressionLayout(kLayout()); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return true; + } + + // Case: Left. + // Ask the parent. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +bool BinomialCoefficientLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Right of the children. + // Go Right. + if (cursor->position() == ExpressionLayoutCursor::Position::Right + && (cursor->pointedExpressionLayout() == nLayout() + || cursor->pointedExpressionLayout() == kLayout())) + { + cursor->setPointedExpressionLayout(this); + return true; + } + + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Go Left of the nLayout. + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + assert(nLayout() != nullptr); + cursor->setPointedExpressionLayout(nLayout()); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + +bool BinomialCoefficientLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // Case: kLayout. + // Move to nLayout. + if (previousLayout == kLayout()) { + return nLayout()->moveUpInside(cursor); + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + +bool BinomialCoefficientLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + // Case: nLayout. + // Move to kLayout. + if (previousLayout == nLayout()) { + return kLayout()->moveDownInside(cursor); + } + return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); +} + +void BinomialCoefficientLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + // Render the parentheses. + ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); + ParenthesisRightLayout * dummyRightParenthesis = new ParenthesisRightLayout(); + GridLayout * dummyGridLayout = new GridLayout(ExpressionLayoutArray(nLayout(), kLayout()).array(), 2, 1, true); + HorizontalLayout dummyLayout(dummyLeftParenthesis, dummyGridLayout, dummyRightParenthesis, false); + KDPoint leftParenthesisPoint = dummyLayout.positionOfChild(dummyLeftParenthesis); + KDPoint rightParenthesisPoint = dummyLayout.positionOfChild(dummyRightParenthesis); + dummyLeftParenthesis->render(ctx, p.translatedBy(leftParenthesisPoint), expressionColor, backgroundColor); + dummyRightParenthesis->render(ctx, p.translatedBy(rightParenthesisPoint), expressionColor, backgroundColor); +} + +KDSize BinomialCoefficientLayout::computeSize() { + KDSize coefficientsSize = GridLayout(ExpressionLayoutArray(nLayout(), kLayout()).array(), 2, 1, true).size(); + return KDSize(coefficientsSize.width() + 2*ParenthesisLeftRightLayout::parenthesisWidth(), coefficientsSize.height()); +} + +void BinomialCoefficientLayout::computeBaseline() { + m_baseline = GridLayout(ExpressionLayoutArray(nLayout(), kLayout()).array(), 2, 1, true).baseline(); + m_baselined = true; +} + +KDPoint BinomialCoefficientLayout::positionOfChild(ExpressionLayout * child) { + ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); + ParenthesisRightLayout * dummyRightParenthesis = new ParenthesisRightLayout(); + GridLayout * dummyGridLayout = new GridLayout(ExpressionLayoutArray(nLayout(), kLayout()).array(), 2, 1, true); + HorizontalLayout dummyLayout(dummyLeftParenthesis, dummyGridLayout, dummyRightParenthesis, false); + if (child == nLayout()) { + return dummyGridLayout->positionOfChild(dummyGridLayout->editableChild(0)).translatedBy(dummyLayout.positionOfChild(dummyGridLayout)); + } + assert(child == kLayout()); + return dummyGridLayout->positionOfChild(dummyGridLayout->editableChild(1)).translatedBy(dummyLayout.positionOfChild(dummyGridLayout)); +} + +ExpressionLayout * BinomialCoefficientLayout::nLayout() { + return editableChild(0); +} + +ExpressionLayout * BinomialCoefficientLayout::kLayout() { + return editableChild(1); +} + +} diff --git a/poincare/src/layout/binomial_coefficient_layout.h b/poincare/src/layout/binomial_coefficient_layout.h new file mode 100644 index 000000000..9fee26479 --- /dev/null +++ b/poincare/src/layout/binomial_coefficient_layout.h @@ -0,0 +1,33 @@ +#ifndef POINCARE_BINOMIAL_COEFFICIENT_LAYOUT_H +#define POINCARE_BINOMIAL_COEFFICIENT_LAYOUT_H + +#include +#include + +namespace Poincare { + +class BinomialCoefficientLayout : public StaticLayoutHierarchy<2> { +public: + using StaticLayoutHierarchy::StaticLayoutHierarchy; + ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; + bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "binomial"); + } +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + KDSize computeSize() override; + void computeBaseline() override; + KDPoint positionOfChild(ExpressionLayout * child) override; +private: + ExpressionLayout * kLayout(); + ExpressionLayout * nLayout(); +}; + +} + +#endif diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 7d89e01e6..4ed010675 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -6,6 +6,7 @@ namespace Poincare { class GridLayout : public DynamicLayoutHierarchy { + friend class BinomialCoefficientLayout; public: GridLayout(const ExpressionLayout * const * entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands); ExpressionLayout * clone() const override; diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 14cd7ce5e..d25fa9921 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class HorizontalLayout : public DynamicLayoutHierarchy { + friend class BinomialCoefficientLayout; friend class IntegralLayout; friend class ParenthesisLayout; friend class SequenceLayout; diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index ea383da99..4e46265ec 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { friend class ParenthesisLayout; + friend class BinomialCoefficientLayout; friend class SequenceLayout; public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index 0c3f8ce7a..3e52cc862 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -8,6 +8,7 @@ namespace Poincare { class ParenthesisRightLayout : public ParenthesisLeftRightLayout { friend class ParenthesisLayout; + friend class BinomialCoefficientLayout; friend class SequenceLayout; public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; From dc9ab66f4921f3ced0833d28b518627db6475c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 9 Jan 2018 17:31:23 +0100 Subject: [PATCH 142/257] [poincare] Remove ParenthesisLayout. Change-Id: I570e85eca45fb89fe0363a000dd7c12835996c15 --- poincare/Makefile | 1 - poincare/include/poincare_layouts.h | 1 - poincare/src/layout/horizontal_layout.h | 1 - poincare/src/layout/parenthesis_layout.cpp | 110 ------------------ poincare/src/layout/parenthesis_layout.h | 37 ------ poincare/src/layout/parenthesis_left_layout.h | 1 - .../src/layout/parenthesis_right_layout.h | 1 - 7 files changed, 152 deletions(-) delete mode 100644 poincare/src/layout/parenthesis_layout.cpp delete mode 100644 poincare/src/layout/parenthesis_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index 49bd3a0a5..38fe3cce4 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -104,7 +104,6 @@ objs += $(addprefix poincare/src/layout/,\ horizontal_layout.o\ integral_layout.o\ nth_root_layout.o\ - parenthesis_layout.o\ parenthesis_left_layout.o\ parenthesis_left_right_layout.o\ parenthesis_right_layout.o\ diff --git a/poincare/include/poincare_layouts.h b/poincare/include/poincare_layouts.h index 875963fe8..2f447e3f9 100644 --- a/poincare/include/poincare_layouts.h +++ b/poincare/include/poincare_layouts.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index d25fa9921..1114dbd40 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -9,7 +9,6 @@ namespace Poincare { class HorizontalLayout : public DynamicLayoutHierarchy { friend class BinomialCoefficientLayout; friend class IntegralLayout; - friend class ParenthesisLayout; friend class SequenceLayout; public: using DynamicLayoutHierarchy::DynamicLayoutHierarchy; diff --git a/poincare/src/layout/parenthesis_layout.cpp b/poincare/src/layout/parenthesis_layout.cpp deleted file mode 100644 index ed81ff533..000000000 --- a/poincare/src/layout/parenthesis_layout.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "parenthesis_layout.h" -#include "horizontal_layout.h" -#include "parenthesis_left_layout.h" -#include "parenthesis_left_right_layout.h" -#include "parenthesis_right_layout.h" -#include -#include -extern "C" { -#include -#include -} - -namespace Poincare { - -ExpressionLayout * ParenthesisLayout::clone() const { - return new ParenthesisLayout(const_cast(this)->operandLayout(), true); -} - -bool ParenthesisLayout::moveLeft(ExpressionLayoutCursor * cursor) { - // Case: Left of the operand. - // Go Left. - if (operandLayout() - && cursor->pointedExpressionLayout() == operandLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Left) - { - cursor->setPointedExpressionLayout(this); - return true; - } - - assert(cursor->pointedExpressionLayout() == this); - // Case: Right. - // Go to the operand and move left. - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - assert(operandLayout() != nullptr); - cursor->setPointedExpressionLayout(operandLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return operandLayout()->moveLeft(cursor); - } - - // Case: Left. - // Ask the parent. - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - if (m_parent) { - return m_parent->moveLeft(cursor); - } - return false; -} - -bool ParenthesisLayout::moveRight(ExpressionLayoutCursor * cursor) { - // Case: Right of the operand. - // Go Right. - if (operandLayout() - && cursor->pointedExpressionLayout() == operandLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Right) - { - cursor->setPointedExpressionLayout(this); - return true; - } - - assert(cursor->pointedExpressionLayout() == this); - // Case: Left. - // Go Left of the operand and moveRight. - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - assert(operandLayout() != nullptr); - cursor->setPointedExpressionLayout(operandLayout()); - return operandLayout()->moveRight(cursor);; - } - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - // Case: Right. - // Ask the parent. - if (m_parent) { - return m_parent->moveRight(cursor); - } - return false; -} - -void ParenthesisLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - // Render the parentheses. - ParenthesisLeftLayout * dummyLeftParenthesis = new ParenthesisLeftLayout(); - ParenthesisRightLayout * dummyRightParenthesis = new ParenthesisRightLayout(); - HorizontalLayout dummyLayout(dummyLeftParenthesis, operandLayout()->clone(), dummyRightParenthesis, false); - KDPoint leftParenthesisPoint = positionOfChild(operandLayout()).translatedBy(dummyLayout.positionOfChild(dummyLeftParenthesis)).translatedBy(dummyLayout.positionOfChild(dummyLayout.editableChild(1)).opposite()); - KDPoint rightParenthesisPoint = positionOfChild(operandLayout()).translatedBy(dummyLayout.positionOfChild(dummyRightParenthesis)).translatedBy(dummyLayout.positionOfChild(dummyLayout.editableChild(1)).opposite()); - dummyLeftParenthesis->render(ctx, p.translatedBy(leftParenthesisPoint), expressionColor, backgroundColor); - dummyRightParenthesis->render(ctx, p.translatedBy(rightParenthesisPoint), expressionColor, backgroundColor); -} - -KDSize ParenthesisLayout::computeSize() { - KDSize operandSize = operandLayout()->size(); - return KDSize(operandSize.width() + 2*ParenthesisLeftRightLayout::parenthesisWidth(), operandSize.height()); -} - -void ParenthesisLayout::computeBaseline() { - m_baseline = operandLayout()->baseline(); - m_baselined = true; -} - -KDPoint ParenthesisLayout::positionOfChild(ExpressionLayout * child) { - if (child == operandLayout()) { - return KDPoint(ParenthesisLeftRightLayout::parenthesisWidth(), 0); - } - assert(false); - return KDPointZero; -} - -ExpressionLayout * ParenthesisLayout::operandLayout() { - return editableChild(0); -} - -} diff --git a/poincare/src/layout/parenthesis_layout.h b/poincare/src/layout/parenthesis_layout.h deleted file mode 100644 index af110702f..000000000 --- a/poincare/src/layout/parenthesis_layout.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef POINCARE_PARENTHESIS_LAYOUT_H -#define POINCARE_PARENTHESIS_LAYOUT_H - -#include -#include - -/* ParenthesisLayout has one operand and renders the parentheses around it. - * This layout should thus be used for uneditable parentheses, e.g. to create - * binomial coefficient layouts. */ - -namespace Poincare { - -class ParenthesisLayout : public StaticLayoutHierarchy<1> { -public: - using StaticLayoutHierarchy::StaticLayoutHierarchy; - ExpressionLayout * clone() const override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); - } -protected: - void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; - KDSize computeSize() override; - void computeBaseline() override; - KDPoint positionOfChild(ExpressionLayout * child) override; -private: - constexpr static KDCoordinate k_externWidthMargin = 1; - constexpr static KDCoordinate k_externHeightMargin = 2; - constexpr static KDCoordinate k_widthMargin = 5; - constexpr static KDCoordinate k_lineThickness = 1; - ExpressionLayout * operandLayout(); -}; - -} - -#endif diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index 4e46265ec..468385383 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -7,7 +7,6 @@ namespace Poincare { class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { - friend class ParenthesisLayout; friend class BinomialCoefficientLayout; friend class SequenceLayout; public: diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index 3e52cc862..fb372b06c 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -7,7 +7,6 @@ namespace Poincare { class ParenthesisRightLayout : public ParenthesisLeftRightLayout { - friend class ParenthesisLayout; friend class BinomialCoefficientLayout; friend class SequenceLayout; public: From 663c90f764260429fbabaa500d3bfe928389db46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 11:20:10 +0100 Subject: [PATCH 143/257] [poincare] MatrixLayout. Change-Id: I57c67a95fadcfd7ea320d4fef49e45b4e166a40d --- poincare/Makefile | 1 + poincare/include/poincare_layouts.h | 1 + poincare/src/layout/bracket_left_layout.h | 1 + poincare/src/layout/bracket_right_layout.h | 1 + poincare/src/layout/grid_layout.cpp | 66 +++++--------------- poincare/src/layout/grid_layout.h | 14 ++--- poincare/src/layout/horizontal_layout.h | 1 + poincare/src/layout/matrix_layout.cpp | 72 ++++++++++++++++++++++ poincare/src/layout/matrix_layout.h | 22 +++++++ 9 files changed, 122 insertions(+), 57 deletions(-) create mode 100644 poincare/src/layout/matrix_layout.cpp create mode 100644 poincare/src/layout/matrix_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index 38fe3cce4..2ef8a3100 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -103,6 +103,7 @@ objs += $(addprefix poincare/src/layout/,\ grid_layout.o\ horizontal_layout.o\ integral_layout.o\ + matrix_layout.o\ nth_root_layout.o\ parenthesis_left_layout.o\ parenthesis_left_right_layout.o\ diff --git a/poincare/include/poincare_layouts.h b/poincare/include/poincare_layouts.h index 2f447e3f9..818351031 100644 --- a/poincare/include/poincare_layouts.h +++ b/poincare/include/poincare_layouts.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/src/layout/bracket_left_layout.h b/poincare/src/layout/bracket_left_layout.h index 35af9d32b..77f9f00bb 100644 --- a/poincare/src/layout/bracket_left_layout.h +++ b/poincare/src/layout/bracket_left_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class BracketLeftLayout : public BracketLeftRightLayout { + friend class MatrixLayout; public: using BracketLeftRightLayout::BracketLeftRightLayout; ExpressionLayout * clone() const override; diff --git a/poincare/src/layout/bracket_right_layout.h b/poincare/src/layout/bracket_right_layout.h index bc5af7548..726d23694 100644 --- a/poincare/src/layout/bracket_right_layout.h +++ b/poincare/src/layout/bracket_right_layout.h @@ -7,6 +7,7 @@ namespace Poincare { class BracketRightLayout : public BracketLeftRightLayout { + friend class MatrixLayout; public: using BracketLeftRightLayout::BracketLeftRightLayout; ExpressionLayout * clone() const override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 5756d1c4c..cd64875a4 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -22,25 +22,28 @@ ExpressionLayout * GridLayout::clone() const { } void GridLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // If the cursor is on the left of the grid, delete the grid and its parent: A - // grid only exists for now in binomial coefficient and in matrices, and we - // want to delete their parentheses or brackets too. if (cursor->position() == ExpressionLayoutCursor::Position::Left) { int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); if (indexOfPointedExpression >= 0 && childIsLeftOfGrid(indexOfPointedExpression)) { + // Case: Left of a left child grid. + // Delete the grid. assert(m_parent != nullptr); - assert(m_parent->parent() != nullptr); - ExpressionLayout * grandParent = const_cast(m_parent->parent()); - int indexInGrandParent = grandParent->indexOfChild(m_parent); - m_parent->replaceWith(new EmptyVisibleLayout(), true); - if (indexInGrandParent == 0) { - cursor->setPointedExpressionLayout(grandParent); + int indexInParent = m_parent->indexOfChild(this); + // Set the new cursor position before deleting. + if (indexInParent == 0) { + cursor->setPointedExpressionLayout(m_parent); return; } - cursor->setPointedExpressionLayout(grandParent->editableChild(indexInGrandParent-1)); + cursor->setPointedExpressionLayout(m_parent->editableChild(indexInParent-1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); + // Delete this. + replaceWith(new EmptyVisibleLayout(), true); return; } + // Case: Left of another child of the grid. + // Move Left. + moveLeft(cursor); + return; } ExpressionLayout::backspaceAtCursor(cursor); } @@ -64,7 +67,7 @@ bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go Left of the grid cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return m_parent->moveLeft(cursor); + return true; } // Case: Left of another child. // Go Right of its brother on the left. @@ -98,10 +101,10 @@ bool GridLayout::moveRight(ExpressionLayoutCursor * cursor) { if (childIndex >- 1 && cursor->position() == ExpressionLayoutCursor::Position::Right) { if (childIsRightOfGrid(childIndex)) { // Case: Right of a child on the right of the grid. - // Go Right of the grid and move Right. + // Go Right of the grid. cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return m_parent->moveRight(cursor); + return true; } // Case: Right of another child. // Go Left of its brother on the right. @@ -142,43 +145,6 @@ void GridLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { ExpressionLayout::removeChildAtIndex(index, deleteAfterRemoval); } -int GridLayout::writeTextInBuffer(char * buffer, int bufferSize) const { - const ExpressionLayout * editableParent = const_cast(this)->parent(); - assert(editableParent != nullptr); - - // If the grid is a binomial coefficient: - if (editableParent->child(0)->isLeftParenthesis()) { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "binomial"); - } - - assert(editableParent->child(0)->isLeftBracket()); - // The grid is a matrix. - if (bufferSize == 0) { - return -1; - } - buffer[bufferSize-1] = 0; - int numberOfChar = 0; - if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - - for (int i = 0; i < m_numberOfRows; i++) { - buffer[numberOfChar++] = '['; - if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, ",", i*m_numberOfColumns, (i+1) * m_numberOfColumns - 1); - - buffer[numberOfChar++] = ']'; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - - if (i < m_numberOfRows - 1) { - buffer[numberOfChar++] = ','; - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - } - } - - buffer[numberOfChar] = 0; - return numberOfChar; -} - KDCoordinate GridLayout::rowBaseline(int i) { KDCoordinate rowBaseline = 0; for (int j = 0; j < m_numberOfColumns; j++) { diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 4ed010675..c9853bd30 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -18,20 +18,23 @@ public: bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - /* Dynamic layout */ void removeChildAtIndex(int index, bool deleteAfterRemoval) override; - //TODO: is this ok? If we want to delete the grid's children, we have to make - //sure no to call this function. + // TODO: This function replaces the child with an EmptyVisibleLayout. Is this + // ok? If we want to delete the grid's children, we have to make sure no to + // call this function. /* Expression engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override { return 0; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; + int indexOfChild(ExpressionLayout * eL) const; + int m_numberOfRows; + int m_numberOfColumns; private: constexpr static KDCoordinate k_gridEntryMargin = 6; KDCoordinate rowBaseline(int i); @@ -39,13 +42,10 @@ private: KDCoordinate height(); KDCoordinate columnWidth(int j); KDCoordinate width(); - int indexOfChild(ExpressionLayout * eL) const; bool childIsLeftOfGrid(int index) const; bool childIsRightOfGrid(int index) const; bool childIsTopOfGrid(int index) const; bool childIsBottomOfGrid(int index) const; - int m_numberOfRows; - int m_numberOfColumns; }; } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 1114dbd40..2e664a39c 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -9,6 +9,7 @@ namespace Poincare { class HorizontalLayout : public DynamicLayoutHierarchy { friend class BinomialCoefficientLayout; friend class IntegralLayout; + friend class MatrixLayout; friend class SequenceLayout; public: using DynamicLayoutHierarchy::DynamicLayoutHierarchy; diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp new file mode 100644 index 000000000..40f452f45 --- /dev/null +++ b/poincare/src/layout/matrix_layout.cpp @@ -0,0 +1,72 @@ +#include "matrix_layout.h" +#include "horizontal_layout.h" +#include "bracket_left_layout.h" +#include "bracket_right_layout.h" +#include +#include +extern "C" { +#include +#include +} + +namespace Poincare { + +ExpressionLayout * MatrixLayout::clone() const { + MatrixLayout * layout = new MatrixLayout(children(), m_numberOfRows, m_numberOfColumns, true); + return layout; +} + +int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + // The grid is a matrix. + if (bufferSize == 0) { + return -1; + } + buffer[bufferSize-1] = 0; + int numberOfChar = 0; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + + buffer[numberOfChar++] = '['; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + + for (int i = 0; i < m_numberOfRows; i++) { + buffer[numberOfChar++] = '['; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, ",", i*m_numberOfColumns, (i+1) * m_numberOfColumns - 1); + + buffer[numberOfChar++] = ']'; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + } + buffer[numberOfChar++] = ']'; + buffer[numberOfChar] = 0; + return numberOfChar; +} + +void MatrixLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + BracketLeftLayout * dummyLeftBracket = new BracketLeftLayout(); + BracketRightLayout * dummyRightBracket = new BracketRightLayout(); + ExpressionLayout * dummyGridLayout = new GridLayout(children(), m_numberOfRows, m_numberOfColumns, true); + HorizontalLayout dummyLayout(dummyLeftBracket, dummyGridLayout, dummyRightBracket, false); + KDPoint leftBracketPoint = dummyLayout.positionOfChild(dummyLeftBracket); + KDPoint rightBracketPoint = dummyLayout.positionOfChild(dummyRightBracket); + dummyLeftBracket->render(ctx, p.translatedBy(leftBracketPoint), expressionColor, backgroundColor); + dummyRightBracket->render(ctx, p.translatedBy(rightBracketPoint), expressionColor, backgroundColor); +} + +KDSize MatrixLayout::computeSize() { + BracketLeftLayout * dummyLeftBracket = new BracketLeftLayout(); + BracketRightLayout * dummyRightBracket = new BracketRightLayout(); +ExpressionLayout * dummyGridLayout = new GridLayout(children(), m_numberOfRows, m_numberOfColumns, true); + HorizontalLayout dummyLayout(dummyLeftBracket, dummyGridLayout, dummyRightBracket, false); + return dummyLayout.size(); +} + +KDPoint MatrixLayout::positionOfChild(ExpressionLayout * child) { + BracketLeftLayout * dummyLeftBracket = new BracketLeftLayout(); + BracketRightLayout * dummyRightBracket = new BracketRightLayout(); +ExpressionLayout * dummyGridLayout = new GridLayout(children(), m_numberOfRows, m_numberOfColumns, true); + HorizontalLayout dummyLayout(dummyLeftBracket, dummyGridLayout, dummyRightBracket, false); + return GridLayout::positionOfChild(child).translatedBy(dummyLayout.positionOfChild(dummyGridLayout)); +} + +} diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h new file mode 100644 index 000000000..910917846 --- /dev/null +++ b/poincare/src/layout/matrix_layout.h @@ -0,0 +1,22 @@ +#ifndef POINCARE_MATRIX_LAYOUT_H +#define POINCARE_MATRIX_LAYOUT_H + +#include + +namespace Poincare { + +class MatrixLayout : public GridLayout { +public: + using GridLayout::GridLayout; + ExpressionLayout * clone() const override; + int writeTextInBuffer(char * buffer, int bufferSize) const override; +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + KDSize computeSize() override; + KDPoint positionOfChild(ExpressionLayout * child) override; +}; + +} + +#endif + From 2c562fdf7a2518742ec06373221463dc779d6f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 11:27:10 +0100 Subject: [PATCH 144/257] [expression_editor] Insert an empty matrix when adding a bracket. Change-Id: I5bf6ab9e097637e0e49f0941fe02e4f5a8e373a2 --- apps/expression_editor/controller.cpp | 11 ++++++++--- .../include/poincare/expression_layout_cursor.h | 1 + poincare/src/expression_layout_cursor.cpp | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index 814200eb8..fdf9702cd 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -130,9 +130,14 @@ ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { } if (event.hasText()) { const char * textToInsert = event.text(); - if (textToInsert[0] == Ion::Charset::MultiplicationSign && textToInsert[1] == 0) { - const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; - return m_cursor.insertText(middleDotString); + if (textToInsert[1] == 0) { + if (textToInsert[0] == Ion::Charset::MultiplicationSign) { + const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; + return m_cursor.insertText(middleDotString); + } + if (textToInsert[0] == '[' || textToInsert[0] == ']') { + return m_cursor.addEmptyMatrixLayout(); + } } return m_cursor.insertText(textToInsert); } diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 779cd9318..a4f5dbb85 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -43,6 +43,7 @@ public: ExpressionLayout * addEmptyExponentialLayout(); ExpressionLayout * addFractionLayoutAndCollapseBrothers(); ExpressionLayout * addEmptyLogarithmLayout(); + ExpressionLayout * addEmptyMatrixLayout(int numberOfRows = 1, int numberOfColumns = 1); ExpressionLayout * addEmptyPowerLayout(); ExpressionLayout * addEmptySquareRootLayout(); ExpressionLayout * addEmptySquarePowerLayout(); diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index b723de7d0..aebbd16b2 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -108,6 +108,21 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyLogarithmLayout() { return result; } +ExpressionLayout * ExpressionLayoutCursor::addEmptyMatrixLayout(int numberOfRows, int numberOfColumns) { + assert(numberOfRows > 0); + assert(numberOfColumns > 0); + int numberOfchildren = (numberOfRows+1)*(numberOfColumns+1); + ExpressionLayout * children[numberOfchildren]; + for (int i = 0; i < numberOfchildren; i++) { + children[i] = new EmptyVisibleLayout(); + } + ExpressionLayout * matrixLayout = new MatrixLayout(const_cast(const_cast(children)), numberOfRows+1, numberOfColumns+1, false); + m_pointedExpressionLayout->addBrother(this, matrixLayout); + setPointedExpressionLayout(matrixLayout->editableChild(0)); + setPosition(ExpressionLayoutCursor::Position::Right); + return matrixLayout; +} + ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Superscript, false); // If there is already a base From 592c12cf0819c0959d7853472d209152e0f3c5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 11:36:42 +0100 Subject: [PATCH 145/257] [poincare] EmptyVisibleLayouts can be Yellow or Grey. Change-Id: Iac07105df5cbf5bcc70b84302a7bf39783716d50 --- poincare/src/layout/empty_visible_layout.cpp | 10 ++++++---- poincare/src/layout/empty_visible_layout.h | 10 +++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index 3ecceef79..e62f812f0 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -1,12 +1,13 @@ #include "empty_visible_layout.h" #include +#include #include namespace Poincare { -EmptyVisibleLayout::EmptyVisibleLayout() : +EmptyVisibleLayout::EmptyVisibleLayout(Color color) : StaticLayoutHierarchy(), - m_fillRectColor(KDColor::RGB24(0xffd370)) //TODO make static or in Palette? + m_color(color) { } @@ -72,8 +73,9 @@ int EmptyVisibleLayout::writeTextInBuffer(char * buffer, int bufferSize) const { } void EmptyVisibleLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - ctx->fillRect(KDRect(p.x()+k_marginWidth, p.y()+k_marginHeight, k_width, k_height), m_fillRectColor); - ctx->fillRect(KDRect(p.x()+k_marginWidth, p.y()+k_marginHeight, k_width, k_height), m_fillRectColor); + KDColor fillColor = m_color == Color::Yellow ? Palette::YellowDark : Palette::GreyBright; + ctx->fillRect(KDRect(p.x()+k_marginWidth, p.y()+k_marginHeight, k_width, k_height), fillColor); + ctx->fillRect(KDRect(p.x()+k_marginWidth, p.y()+k_marginHeight, k_width, k_height), fillColor); } KDSize EmptyVisibleLayout::computeSize() { diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index f96eb0749..ae5a5e5c2 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -8,7 +8,11 @@ namespace Poincare { class EmptyVisibleLayout : public StaticLayoutHierarchy<0> { public: - EmptyVisibleLayout(); + enum class Color { + Yellow, + Grey + }; + EmptyVisibleLayout(Color color = Color::Yellow); ExpressionLayout * clone() const override; void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; @@ -16,6 +20,7 @@ public: bool moveRight(ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; bool isEmpty() const override { return true; } + void setColor(Color color) { m_color = color; } protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; virtual KDSize computeSize() override; @@ -30,8 +35,7 @@ private: constexpr static KDCoordinate k_marginWidth = 1; constexpr static KDCoordinate k_marginHeight = 2; constexpr static KDCoordinate k_lineThickness = 1; - - KDColor m_fillRectColor; + Color m_color; }; } From d105dcc7f9df13c5070ba206a43aeb41a31325b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 12:02:53 +0100 Subject: [PATCH 146/257] [expression_editor] Grey outer cells for MatrixLayout. Change-Id: Iaf33ccd6c746843803b6a971a2b37eaf495fa766 --- poincare/src/expression_layout_cursor.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index aebbd16b2..3f89545d9 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -111,10 +111,15 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyLogarithmLayout() { ExpressionLayout * ExpressionLayoutCursor::addEmptyMatrixLayout(int numberOfRows, int numberOfColumns) { assert(numberOfRows > 0); assert(numberOfColumns > 0); - int numberOfchildren = (numberOfRows+1)*(numberOfColumns+1); - ExpressionLayout * children[numberOfchildren]; - for (int i = 0; i < numberOfchildren; i++) { - children[i] = new EmptyVisibleLayout(); + ExpressionLayout * children[(numberOfRows+1)*(numberOfColumns+1)]; + for (int i = 0; i < numberOfRows + 1; i++) { + for (int j = 0; j < numberOfColumns + 1; j++) { + if (i < numberOfRows && j < numberOfColumns) { + children[i*(numberOfColumns+1)+j] = new EmptyVisibleLayout(EmptyVisibleLayout::Color::Yellow); + } else { + children[i*(numberOfColumns+1)+j] = new EmptyVisibleLayout(EmptyVisibleLayout::Color::Grey); + } + } } ExpressionLayout * matrixLayout = new MatrixLayout(const_cast(const_cast(children)), numberOfRows+1, numberOfColumns+1, false); m_pointedExpressionLayout->addBrother(this, matrixLayout); From 03e33e05e7bba5d3155feb0817907abcaf098bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 14:38:21 +0100 Subject: [PATCH 147/257] [poincare] Layout invalidation when adding children to DynamicLayouts. Change-Id: Ib4609a5e14cce0c5bae44c90629446caea75c164 --- poincare/src/layout/dynamic_layout_hierarchy.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index 5e3c0c5ab..ce8c5fa28 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -75,6 +75,9 @@ void DynamicLayoutHierarchy::addChildrenAtIndex(const ExpressionLayout * const * delete[] m_children; m_children = newOperands; m_numberOfChildren = currentIndex; + m_sized = false; + m_positioned = false; + m_baselined = false; } bool DynamicLayoutHierarchy::addChildAtIndex(ExpressionLayout * child, int index) { From e821ed2ad9e5d3c94a666d4155e57cef65730eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 14:40:00 +0100 Subject: [PATCH 148/257] [poincare] Add a row or a column to a GridLayout. Change-Id: I3e58ce84c05c9d64481942e6e7896409a20ddb8a --- poincare/src/layout/grid_layout.cpp | 37 +++++++++++++++++++++-------- poincare/src/layout/grid_layout.h | 11 ++++++--- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index cd64875a4..bc5b2d7b7 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -226,33 +226,50 @@ KDPoint GridLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x, y); } -int GridLayout::indexOfChild(ExpressionLayout * eL) const { - for (int i = 0; i < m_numberOfRows*m_numberOfColumns; i++) { - if (eL == child(i)) { - return i; - } +void GridLayout::addEmptyRow(EmptyVisibleLayout::Color color) { + ExpressionLayout * newChildren[m_numberOfColumns]; + for (int i = 0; i < m_numberOfColumns; i++) { + newChildren[i] = new EmptyVisibleLayout(color); + } + addChildrenAtIndex(const_cast(const_cast(newChildren)), m_numberOfColumns, numberOfChildren(), false); + m_numberOfRows++; +} + +void GridLayout::addEmptyColumn(EmptyVisibleLayout::Color color) { + m_numberOfColumns++; + for (int i = 0; i < m_numberOfRows; i++) { + addChildAtIndex(new EmptyVisibleLayout(color), i*m_numberOfColumns + m_numberOfColumns-1); } - return -1; } bool GridLayout::childIsLeftOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return (index - m_numberOfColumns * (int)(index / m_numberOfColumns)) == 0; + return columnAtIndex(index) == 0; } bool GridLayout::childIsRightOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return (index - m_numberOfColumns * (int)(index / m_numberOfColumns)) == m_numberOfColumns - 1; + return columnAtIndex(index) == m_numberOfColumns - 1; } bool GridLayout::childIsTopOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return index < m_numberOfColumns; + return rowAtIndex(index) == 0; } bool GridLayout::childIsBottomOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return index > (m_numberOfRows - 1) * m_numberOfColumns - 1; + return rowAtIndex(index) == m_numberOfRows - 1; +} + +int GridLayout::rowAtIndex(int index) const { + assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); + return (int)(index / m_numberOfColumns); +} + +int GridLayout::columnAtIndex(int index) const { + assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); + return index - m_numberOfColumns * rowAtIndex(index); } } diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index c9853bd30..4315910c5 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -2,6 +2,7 @@ #define POINCARE_GRID_LAYOUT_H #include +#include "empty_visible_layout.h" namespace Poincare { @@ -32,7 +33,11 @@ protected: KDSize computeSize() override; void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; - int indexOfChild(ExpressionLayout * eL) const; + void addEmptyRow(EmptyVisibleLayout::Color color); + void addEmptyColumn(EmptyVisibleLayout::Color color); + bool childIsRightOfGrid(int index) const; + bool childIsBottomOfGrid(int index) const; + int rowAtIndex(int index) const; int m_numberOfRows; int m_numberOfColumns; private: @@ -43,9 +48,9 @@ private: KDCoordinate columnWidth(int j); KDCoordinate width(); bool childIsLeftOfGrid(int index) const; - bool childIsRightOfGrid(int index) const; bool childIsTopOfGrid(int index) const; - bool childIsBottomOfGrid(int index) const; + int columnAtIndex(int index) const; + }; } From a499363747b16b966a531fed90aee5b75ccc2bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 14:40:42 +0100 Subject: [PATCH 149/257] [poincare] Editing a grey empty layout adds a Matrix row/column. Change-Id: I37b0c22fd2242d1361146833c3de2f24c296fd66 --- poincare/src/layout/empty_visible_layout.cpp | 8 +++++ poincare/src/layout/matrix_layout.cpp | 35 ++++++++++++++++++-- poincare/src/layout/matrix_layout.h | 2 +- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index e62f812f0..bddbda688 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -1,4 +1,5 @@ #include "empty_visible_layout.h" +#include "matrix_layout.h" #include #include #include @@ -17,7 +18,14 @@ ExpressionLayout * EmptyVisibleLayout::clone() const { } void EmptyVisibleLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { + Color currentColor = m_color; + int indexInParent = m_parent->indexOfChild(this); + ExpressionLayout * parent = m_parent; replaceWith(brother, true); + if (currentColor == Color::Grey) { + // The parent is a MatrixLayout. + static_cast(parent)->newRowOrColumnAtIndex(indexInParent); + } } void EmptyVisibleLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index 40f452f45..95fa9de8a 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -1,4 +1,5 @@ #include "matrix_layout.h" +#include "empty_visible_layout.h" #include "horizontal_layout.h" #include "bracket_left_layout.h" #include "bracket_right_layout.h" @@ -28,11 +29,11 @@ int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { buffer[numberOfChar++] = '['; if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - for (int i = 0; i < m_numberOfRows; i++) { + for (int i = 0; i < m_numberOfRows - 1; i++) { buffer[numberOfChar++] = '['; if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, ",", i*m_numberOfColumns, (i+1) * m_numberOfColumns - 1); + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, ",", i*m_numberOfColumns, i* m_numberOfColumns + m_numberOfColumns - 2); buffer[numberOfChar++] = ']'; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } @@ -42,6 +43,36 @@ int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { return numberOfChar; } +void MatrixLayout::newRowOrColumnAtIndex(int index) { + bool shouldAddNewRow = GridLayout::childIsBottomOfGrid(index); + int correspondingRow = rowAtIndex(index); + // We need to compute this bool before modifying the layout.:w + // + if (GridLayout::childIsRightOfGrid(index)) { + // Color the grey EmptyVisibleLayouts of the column in yellow. + int correspondingColumn = m_numberOfColumns - 1; + for (int i = 0; i < m_numberOfRows - 1; i++) { + ExpressionLayout * lastLayoutOfRow = editableChild(i*m_numberOfColumns+correspondingColumn); + if (lastLayoutOfRow->isEmpty()) { + static_cast(lastLayoutOfRow)->setColor(EmptyVisibleLayout::Color::Yellow); + } + } + // Add a column of grey EmptyVisibleLayouts on the right. + GridLayout::addEmptyColumn(EmptyVisibleLayout::Color::Grey); + } + if (shouldAddNewRow) { + // Color the grey EmptyVisibleLayouts of the row in yellow. + for (int i = 0; i < m_numberOfColumns - 1; i++) { + ExpressionLayout * lastLayoutOfColumn = editableChild(correspondingRow*m_numberOfColumns+i); + if (lastLayoutOfColumn->isEmpty()) { + static_cast(lastLayoutOfColumn)->setColor(EmptyVisibleLayout::Color::Yellow); + } + } + // Add a row of grey EmptyVisibleLayouts at the bottom. + GridLayout::addEmptyRow(EmptyVisibleLayout::Color::Grey); + } +} + void MatrixLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { BracketLeftLayout * dummyLeftBracket = new BracketLeftLayout(); BracketRightLayout * dummyRightBracket = new BracketRightLayout(); diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 910917846..48db8bf3c 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -10,6 +10,7 @@ public: using GridLayout::GridLayout; ExpressionLayout * clone() const override; int writeTextInBuffer(char * buffer, int bufferSize) const override; + void newRowOrColumnAtIndex(int index); protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; @@ -19,4 +20,3 @@ protected: } #endif - From 1717b470c819f195599185a9590bc85411299986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 18:15:06 +0100 Subject: [PATCH 150/257] [poincare] When replacing a layout, ask the parent to move the cursor. Change-Id: I0ddb0e791d328c2f141aefc604569ef4fcc6c0c5 --- poincare/include/poincare/expression_layout.h | 9 ++- .../layout/binomial_coefficient_layout.cpp | 10 +--- poincare/src/layout/bracket_layout.cpp | 14 ++--- poincare/src/layout/conjugate_layout.cpp | 12 +--- poincare/src/layout/expression_layout.cpp | 19 ++++++ poincare/src/layout/fraction_layout.cpp | 24 +------- poincare/src/layout/grid_layout.cpp | 59 +++++++++++-------- poincare/src/layout/grid_layout.h | 6 +- poincare/src/layout/horizontal_layout.cpp | 41 ++++++++++++- poincare/src/layout/horizontal_layout.h | 2 + poincare/src/layout/integral_layout.cpp | 13 +--- poincare/src/layout/matrix_layout.cpp | 17 +++++- poincare/src/layout/matrix_layout.h | 1 + poincare/src/layout/nth_root_layout.cpp | 19 +----- poincare/src/layout/sequence_layout.cpp | 13 +--- .../src/layout/vertical_offset_layout.cpp | 8 +-- 16 files changed, 134 insertions(+), 133 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index c06f89633..691f0f768 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -43,17 +43,16 @@ public: ExpressionLayout * editableParent() { return m_parent; } bool hasAncestor(const ExpressionLayout * e) const; + /* Dynamic Layout */ bool insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor); - virtual void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); - ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace = true); + virtual ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace = true); ExpressionLayout * replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace); + ExpressionLayout * replaceWithAndMoveCursor(ExpressionLayout * newChild, bool deleteAfterReplace, ExpressionLayoutCursor * cursor); virtual void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true); + virtual void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor); void detachChild(const ExpressionLayout * e); // Removes a child WITHOUT deleting it void detachChildren(); //Removes all children WITHOUT deleting them - - - /* Dynamic Layout*/ virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } virtual void removeChildAtIndex(int index, bool deleteAfterRemoval); virtual void backspaceAtCursor(ExpressionLayoutCursor * cursor); diff --git a/poincare/src/layout/binomial_coefficient_layout.cpp b/poincare/src/layout/binomial_coefficient_layout.cpp index 28b253081..0342a1b6f 100644 --- a/poincare/src/layout/binomial_coefficient_layout.cpp +++ b/poincare/src/layout/binomial_coefficient_layout.cpp @@ -26,15 +26,7 @@ void BinomialCoefficientLayout::backspaceAtCursor(ExpressionLayoutCursor * curso || cursor->pointedExpressionLayout() == kLayout())) { assert(m_parent != nullptr); - int indexInParent = m_parent->indexOfChild(this); - ExpressionLayout * parent = m_parent; - replaceWith(new EmptyVisibleLayout(), true); - if (indexInParent == 0) { - cursor->setPointedExpressionLayout(parent); - return; - } - cursor->setPointedExpressionLayout(parent->editableChild(indexInParent-1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); + replaceWithAndMoveCursor(new EmptyVisibleLayout(), true, cursor); return; } ExpressionLayout::backspaceAtCursor(cursor); diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 993ad2204..6d1222e14 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -14,19 +14,15 @@ ExpressionLayout * BracketLayout::clone() const { } void BracketLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // Case: Left of the operand. + // Delete the brackets, keep the operand. if (cursor->pointedExpressionLayout() == operandLayout()) { assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(operandLayout(), true); - if (indexInParent == 0) { - cursor->setPointedExpressionLayout(previousParent); - return; - } - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); + replaceWithAndMoveCursor(operandLayout(), true, cursor); return; } + // Case: Right. + // Move Right of the operand. assert(cursor->pointedExpressionLayout() == this); if (cursor->position() == ExpressionLayoutCursor::Position::Right) { cursor->setPointedExpressionLayout(operandLayout()); diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index 5e74f9b21..645514896 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -14,17 +14,11 @@ ExpressionLayout * ConjugateLayout::clone() const { } void ConjugateLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + // Case: Left of the operand. + // Delete the conjugate, keep the operand. if (cursor->pointedExpressionLayout() == operandLayout()) { assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(operandLayout(), true); - if (indexInParent == 0) { - cursor->setPointedExpressionLayout(previousParent); - return; - } - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); + replaceWithAndMoveCursor(operandLayout(), true, cursor); return; } ExpressionLayout::backspaceAtCursor(cursor); diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 9c0c45435..8587ea8e6 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -164,6 +164,12 @@ ExpressionLayout * ExpressionLayout::replaceWithJuxtapositionOf(ExpressionLayout return layout; } +ExpressionLayout * ExpressionLayout::replaceWithAndMoveCursor(ExpressionLayout * newChild, bool deleteAfterReplace, ExpressionLayoutCursor * cursor) { + assert(m_parent != nullptr); + m_parent->replaceChildAndMoveCursor(this, newChild, deleteAfterReplace, cursor); + return newChild; +} + void ExpressionLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { assert(newChild != nullptr); // Caution: handle the case where we replace an operand with a descendant of ours. @@ -191,6 +197,19 @@ void ExpressionLayout::replaceChild(const ExpressionLayout * oldChild, Expressio m_baselined = false; } +void ExpressionLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { + int oldChildIndex = indexOfChild(const_cast(oldChild)); + assert(oldChildIndex >= 0); + if (oldChildIndex == 0) { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + } else { + cursor->setPointedExpressionLayout(editableChild(oldChildIndex - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } + replaceChild(oldChild, newChild, deleteOldChild); +} + void ExpressionLayout::detachChild(const ExpressionLayout * e) { ExpressionLayout ** op = const_cast(children()); for (int i = 0; i < numberOfChildren(); i++) { diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index f2c57ae87..c425a8e4f 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -21,29 +21,7 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { if (numeratorLayout()->isEmpty() && denominatorLayout()->isEmpty()) { // If the numerator and the denominator are empty, move the cursor then // replace the fraction with an empty layout. - // We need to perform these actions in this order because the replacement - // might delete the fraction's parent: if the parent is an - // HorizontalLayout and the fraction is its only child, the - // HorizontalLayout will be replaced by the new EmptyLayout. - ExpressionLayout * newEmptyLayout = new EmptyVisibleLayout(); - if (!m_parent->isHorizontal() - || (m_parent->isHorizontal() && m_parent->numberOfChildren() == 1)) - { - cursor->setPointedExpressionLayout(newEmptyLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - } else { - assert(m_parent->isHorizontal()); - assert(m_parent->numberOfChildren() > 0); - int indexInParent = m_parent->indexOfChild(this); - if (indexInParent > 0) { - cursor->setPointedExpressionLayout(m_parent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - } else { - cursor->setPointedExpressionLayout(m_parent->editableChild(indexInParent + 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - } - } - replaceWith(newEmptyLayout, true); + replaceWithAndMoveCursor(new EmptyVisibleLayout(), true, cursor); return; } diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index bc5b2d7b7..39790b4d6 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -24,28 +24,33 @@ ExpressionLayout * GridLayout::clone() const { void GridLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { if (cursor->position() == ExpressionLayoutCursor::Position::Left) { int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); - if (indexOfPointedExpression >= 0 && childIsLeftOfGrid(indexOfPointedExpression)) { - // Case: Left of a left child grid. - // Delete the grid. - assert(m_parent != nullptr); - int indexInParent = m_parent->indexOfChild(this); - // Set the new cursor position before deleting. - if (indexInParent == 0) { - cursor->setPointedExpressionLayout(m_parent); + if (indexOfPointedExpression >= 0) { + if (childIsLeftOfGrid(indexOfPointedExpression)) { + // Case: Left of a left child grid. + // Delete the grid. + assert(m_parent != nullptr); + replaceWithAndMoveCursor(new EmptyVisibleLayout(), true, cursor); return; } - cursor->setPointedExpressionLayout(m_parent->editableChild(indexInParent-1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - // Delete this. - replaceWith(new EmptyVisibleLayout(), true); + // Case: Left of another child of the grid. + // Move Left. + moveLeft(cursor); return; } - // Case: Left of another child of the grid. - // Move Left. - moveLeft(cursor); - return; + assert(cursor->pointedExpressionLayout() == this); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->backspaceAtCursor(cursor); + } } - ExpressionLayout::backspaceAtCursor(cursor); + // Case: Right. + // Move to the last child. + assert(cursor->pointedExpressionLayout() == this); + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + cursor->setPointedExpressionLayout(editableChild((m_numberOfRows-1)*(m_numberOfColumns-1))); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; } bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { @@ -244,32 +249,38 @@ void GridLayout::addEmptyColumn(EmptyVisibleLayout::Color color) { bool GridLayout::childIsLeftOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return columnAtIndex(index) == 0; + return columnAtChildIndex(index) == 0; } bool GridLayout::childIsRightOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return columnAtIndex(index) == m_numberOfColumns - 1; + return columnAtChildIndex(index) == m_numberOfColumns - 1; } bool GridLayout::childIsTopOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return rowAtIndex(index) == 0; + return rowAtChildIndex(index) == 0; } bool GridLayout::childIsBottomOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return rowAtIndex(index) == m_numberOfRows - 1; + return rowAtChildIndex(index) == m_numberOfRows - 1; } -int GridLayout::rowAtIndex(int index) const { +int GridLayout::rowAtChildIndex(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); return (int)(index / m_numberOfColumns); } -int GridLayout::columnAtIndex(int index) const { +int GridLayout::columnAtChildIndex(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); - return index - m_numberOfColumns * rowAtIndex(index); + return index - m_numberOfColumns * rowAtChildIndex(index); +} + +int GridLayout::indexAtRowColumn(int rowIndex, int columnIndex) const { + assert(rowIndex >= 0 && rowIndex < m_numberOfRows); + assert(columnIndex >= 0 && columnIndex < m_numberOfColumns); + return rowIndex * m_numberOfColumns + columnIndex; } } diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 4315910c5..bee1df01a 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -37,7 +37,9 @@ protected: void addEmptyColumn(EmptyVisibleLayout::Color color); bool childIsRightOfGrid(int index) const; bool childIsBottomOfGrid(int index) const; - int rowAtIndex(int index) const; + int rowAtChildIndex(int index) const; + int columnAtChildIndex(int index) const; + int indexAtRowColumn(int rowIndex, int columnIndex) const; int m_numberOfRows; int m_numberOfColumns; private: @@ -49,8 +51,6 @@ private: KDCoordinate width(); bool childIsLeftOfGrid(int index) const; bool childIsTopOfGrid(int index) const; - int columnAtIndex(int index) const; - }; } diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 7594a6ff2..62159aa03 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -27,9 +27,18 @@ void HorizontalLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { } void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { + privateReplaceChild(oldChild, newChild, deleteOldChild, nullptr); +} + +void HorizontalLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { + privateReplaceChild(oldChild, newChild, deleteOldChild, cursor); +} + +void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { if (newChild->hasAncestor(this)) { newChild->editableParent()->detachChild(newChild); } + int oldChildIndex = indexOfChild(const_cast(oldChild)); if (newChild->isEmpty()) { if (numberOfChildren() > 1) { // If the new layout is empty and the horizontal layout has other @@ -38,13 +47,27 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio delete newChild; } removeChildAtIndex(indexOfChild(const_cast(oldChild)), deleteOldChild); + if (cursor == nullptr) { + return; + } + if (oldChildIndex == 0) { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + cursor->setPointedExpressionLayout(editableChild(oldChildIndex -1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); return; } // If the new layout is empty and it was the only horizontal layout child, // replace the horizontal layout with this empty layout (only if this is not // the main layout, so only if the layout has a parent. if (m_parent) { - replaceWith(newChild); + if (cursor) { + replaceWithAndMoveCursor(newChild, deleteOldChild, cursor); + return; + } + replaceWith(newChild, deleteOldChild); return; } } @@ -54,10 +77,26 @@ void HorizontalLayout::replaceChild(const ExpressionLayout * oldChild, Expressio int indexForInsertion = indexOfChild(const_cast(oldChild)); mergeChildrenAtIndex(static_cast(newChild), indexForInsertion + 1, true); removeChildAtIndex(indexForInsertion, deleteOldChild); + if (cursor == nullptr) { + return; + } + if (oldChildIndex == 0) { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + cursor->setPointedExpressionLayout(editableChild(oldChildIndex -1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); return; } // Else, just replace the child. ExpressionLayout::replaceChild(oldChild, newChild, deleteOldChild); + if (cursor == nullptr) { + return; + } + cursor->setPointedExpressionLayout(newChild); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; } void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 2e664a39c..98a2d9380 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -18,6 +18,7 @@ public: /* Hierarchy */ void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; + void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; void addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren); /* Navigation */ @@ -44,6 +45,7 @@ protected: KDPoint positionOfChild(ExpressionLayout * child) override; private: bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); + void privateReplaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor); }; } diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 392525b16..3ce10c2d1 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -36,18 +36,7 @@ void IntegralLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { && cursor->pointedExpressionLayout() == lowerBoundLayout()) || cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Left))) { - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(integrandLayout(), true); - // Place the cursor on the right of the left brother of the integral if - // there is one. - if (indexInParent > 0) { - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - // Else place the cursor on the Left of the parent. - cursor->setPointedExpressionLayout(previousParent); + replaceWithAndMoveCursor(integrandLayout(), true, cursor); return; } // If the cursor is on the right, move to the integrand. diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index 95fa9de8a..5ad8a03d5 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -17,6 +17,21 @@ ExpressionLayout * MatrixLayout::clone() const { return layout; } +void MatrixLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { + int oldChildIndex = indexOfChild(const_cast(oldChild)); + int rowIndex = rowAtChildIndex(oldChildIndex); + int columnIndex = columnAtChildIndex(oldChildIndex); + replaceChild(oldChild, newChild, deleteOldChild); + int newIndex = indexAtRowColumn(rowIndex, columnIndex); + if (newIndex < numberOfChildren()) { + cursor->setPointedExpressionLayout(editableChild(newIndex)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + cursor->setPointedExpressionLayout(editableChild(numberOfChildren())); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); +} + int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { // The grid is a matrix. if (bufferSize == 0) { @@ -45,7 +60,7 @@ int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { void MatrixLayout::newRowOrColumnAtIndex(int index) { bool shouldAddNewRow = GridLayout::childIsBottomOfGrid(index); - int correspondingRow = rowAtIndex(index); + int correspondingRow = rowAtChildIndex(index); // We need to compute this bool before modifying the layout.:w // if (GridLayout::childIsRightOfGrid(index)) { diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 48db8bf3c..83008d440 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -9,6 +9,7 @@ class MatrixLayout : public GridLayout { public: using GridLayout::GridLayout; ExpressionLayout * clone() const override; + void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; void newRowOrColumnAtIndex(int index); protected: diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 4e749d8c9..d2df334fe 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -40,24 +40,7 @@ void NthRootLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { if (cursor->position() == ExpressionLayoutCursor::Position::Left && cursor->pointedExpressionLayout() == radicandLayout()) { - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(radicandLayout()); - // Place the cursor on the left of what replaced the root if possible. - if (indexInParent < previousParent->numberOfChildren()) { - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent)); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return; - } - // Else place the cursor on the right of the left brother of the root if - // there is one. - if (indexInParent > 0) { - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - // Else place the cursor on the Left of the parent. - cursor->setPointedExpressionLayout(previousParent); + replaceWithAndMoveCursor(radicandLayout(), true, cursor); return; } // Case: Right. diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index acb342c2b..da31a3400 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -23,18 +23,7 @@ void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { && cursor->pointedExpressionLayout() == upperBoundLayout()) || cursor->pointedExpressionLayout() == argumentLayout())) { - ExpressionLayout * previousParent = m_parent; - int indexInParent = previousParent->indexOfChild(this); - replaceWith(argumentLayout(), true); - // Place the cursor on the right of the left brother of the sequence if - // there is one. - if (indexInParent > 0) { - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - // Else place the cursor on the Left of the parent. - cursor->setPointedExpressionLayout(previousParent); + replaceWithAndMoveCursor(argumentLayout(), true, cursor); return; } // Case: Right. diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp index 10964d358..003ba0452 100644 --- a/poincare/src/layout/vertical_offset_layout.cpp +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -27,14 +27,8 @@ void VerticalOffsetLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { if (base->isEmpty()) { // Case: Empty base and indice. // Replace with the empty base layout. - if (indexInParent <= 1) { - cursor->setPointedExpressionLayout(m_parent); - } else { - cursor->setPointedExpressionLayout(m_parent->editableChild(indexInParent - 2)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - } m_parent->removeChildAtIndex(indexInParent - 1, false); - replaceWith(base, true); + replaceWithAndMoveCursor(base, true, cursor); return; } // Case: Empty indice only. From 95327d0afc5d48bc618d208881b8b8dc7dd0aa0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 10 Jan 2018 17:32:23 +0100 Subject: [PATCH 151/257] [poincare] Remove empty row/column in MatrixLayout. Change-Id: I58f7b7f5e1256afd769f773bef8caea43a40c7a1 --- apps/expression_editor/controller.cpp | 3 +- .../expression_and_layout.cpp | 1 - .../poincare/dynamic_layout_hierarchy.h | 1 + poincare/include/poincare/expression_layout.h | 2 + .../src/layout/bracket_left_right_layout.h | 2 +- .../src/layout/dynamic_layout_hierarchy.cpp | 31 ++++++++++- poincare/src/layout/expression_layout.cpp | 42 +++++++++----- poincare/src/layout/grid_layout.cpp | 16 ++++++ poincare/src/layout/grid_layout.h | 2 + poincare/src/layout/horizontal_layout.cpp | 2 +- poincare/src/layout/matrix_layout.cpp | 55 ++++++++++++++++++- poincare/src/layout/matrix_layout.h | 6 ++ 12 files changed, 142 insertions(+), 21 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index fdf9702cd..f19771346 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -12,9 +12,8 @@ Controller::Controller(Responder * parentResponder, ExpressionLayout * expressio m_view(parentResponder, expressionLayout, &m_cursor), m_expressionLayout(expressionLayout), m_resultLayout(nullptr) - //m_context((GlobalContext *)((AppsContainer *)(app()->container()))->globalContext()) { - m_cursor.setPointedExpressionLayout(expressionLayout->editableChild(0)); + m_cursor.setPointedExpressionLayout(expressionLayout); } void Controller::didBecomeFirstResponder() { diff --git a/apps/expression_editor/expression_and_layout.cpp b/apps/expression_editor/expression_and_layout.cpp index 36f09fcfb..24e0f3df4 100644 --- a/apps/expression_editor/expression_and_layout.cpp +++ b/apps/expression_editor/expression_and_layout.cpp @@ -39,7 +39,6 @@ ExpressionAndLayout::ExpressionAndLayout() { m_expression = Poincare::Expression::parse(expression); m_expressionLayout = new Poincare::HorizontalLayout(); - m_expressionLayout->addChildAtIndex(new Poincare::EmptyVisibleLayout(), 0); } ExpressionAndLayout::~ExpressionAndLayout() { if (m_expressionLayout) { diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index a40a7fd13..4157d15fe 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -28,6 +28,7 @@ public: void addChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion, bool removeEmptyChildren); bool addChildAtIndex(ExpressionLayout * operand, int index) override; void removeChildAtIndex(int index, bool deleteAfterRemoval) override; + void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren); // WITHOUT delete. bool isEmpty() const override; diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 691f0f768..715ad8fbe 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -55,6 +55,7 @@ public: void detachChildren(); //Removes all children WITHOUT deleting them virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } virtual void removeChildAtIndex(int index, bool deleteAfterRemoval); + virtual void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor); virtual void backspaceAtCursor(ExpressionLayoutCursor * cursor); /* Tree navigation */ @@ -78,6 +79,7 @@ public: virtual bool isLeftBracket() const { return false; } virtual bool isRightBracket() const { return false; } virtual bool isEmpty() const { return false; } + virtual bool isMatrix() const { return false; } virtual char XNTChar() const; protected: diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h index 4af7a09a3..98cf4e875 100644 --- a/poincare/src/layout/bracket_left_right_layout.h +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -11,11 +11,11 @@ public: void invalidAllSizesPositionsAndBaselines() override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; +protected: constexpr static KDCoordinate k_bracketWidth = 5; constexpr static KDCoordinate k_lineThickness = 1; constexpr static KDCoordinate k_widthMargin = 5; constexpr static KDCoordinate k_externWidthMargin = 2; -protected: KDSize computeSize() override; KDCoordinate operandHeight(); virtual void computeOperandHeight() = 0; diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index ce8c5fa28..7678abd18 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -1,5 +1,6 @@ #include #include "empty_visible_layout.h" +#include extern "C" { #include #include @@ -113,9 +114,37 @@ void DynamicLayoutHierarchy::removeChildAtIndex(int index, bool deleteAfterRemov } } +void DynamicLayoutHierarchy::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { + assert(index >= 0 && index < numberOfChildren()); + assert(cursor->pointedExpressionLayout() == child(index)); + if (numberOfChildren() == 1) { + if (m_parent) { + if (!deleteAfterRemoval) { + detachChild(editableChild(0)); + } + m_parent->removePointedChildAtIndexAndMoveCursor(m_parent->indexOfChild(this), true, cursor); + return; + } + removeChildAtIndex(index, deleteAfterRemoval); + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + removeChildAtIndex(index, deleteAfterRemoval); + if (index < numberOfChildren()) { + cursor->setPointedExpressionLayout(editableChild(index)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + int indexOfNewPointedLayout = index - 1; + assert(indexOfNewPointedLayout >= 0); + assert(indexOfNewPointedLayout < numberOfChildren()); + cursor->setPointedExpressionLayout(editableChild(indexOfNewPointedLayout)); +} + bool DynamicLayoutHierarchy::isEmpty() const { if (m_numberOfChildren == 0 - || (m_numberOfChildren == 1&& child(0)->isEmpty())) + || (m_numberOfChildren == 1 && child(0)->isEmpty())) { return true; } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 8587ea8e6..f79a62e0e 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -1,6 +1,7 @@ #include #include "empty_visible_layout.h" #include "horizontal_layout.h" +#include "matrix_layout.h" #include #include #include @@ -230,10 +231,26 @@ void ExpressionLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { replaceChild(editableChild(index), new EmptyVisibleLayout(), deleteAfterRemoval); } -void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { +void ExpressionLayout::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { + assert(index >= 0 && index < numberOfChildren()); + assert(cursor->pointedExpressionLayout() == child(index)); + removeChildAtIndex(index, deleteAfterRemoval); + if (index < numberOfChildren()) { + cursor->setPointedExpressionLayout(editableChild(index)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; + } + int indexOfNewPointedLayout = index - 1; + assert(indexOfNewPointedLayout >= 0); + assert(indexOfNewPointedLayout < numberOfChildren()); + cursor->setPointedExpressionLayout(editableChild(indexOfNewPointedLayout)); +} +void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); if (indexOfPointedExpression >= 0) { + // Case: The pointed layout is a child. + // Point to the previous child, else to this. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (indexOfPointedExpression == 0) { cursor->setPointedExpressionLayout(this); @@ -245,14 +262,20 @@ void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { return; } assert(cursor->pointedExpressionLayout() == this); + // Case: this is the pointed layout. if (m_parent == nullptr) { + // If there is no parent, return. return; } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + // Case: Left. + // Ask the parent. m_parent->backspaceAtCursor(cursor); return; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // If the layout has children, move to the last one. if (numberOfChildren() > 0) { cursor->setPointedExpressionLayout(editableChild(numberOfChildren()-1)); cursor->performBackspace(); @@ -260,23 +283,16 @@ void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { } int indexInParent = m_parent->indexOfChild(this); ExpressionLayout * previousParent = m_parent; - if (previousParent->numberOfChildren() == 1) { + // Case: Right. + // If the layout has no child and is only child, replace it with an empty layout. + /*if (previousParent->numberOfChildren() == 1) { ExpressionLayout * newLayout = new EmptyVisibleLayout(); replaceWith(newLayout, true); cursor->setPointedExpressionLayout(newLayout); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return; - } - previousParent->removeChildAtIndex(indexInParent, true); - if (indexInParent < previousParent->numberOfChildren()) { - cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent)); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return; - } - int indexOfNewPointedLayout = indexInParent - 1; - assert(indexOfNewPointedLayout >= 0); - assert(indexOfNewPointedLayout < previousParent->numberOfChildren()); - cursor->setPointedExpressionLayout(previousParent->editableChild(indexOfNewPointedLayout)); + }*/ + previousParent->removePointedChildAtIndexAndMoveCursor(indexInParent, true, cursor); } char ExpressionLayout::XNTChar() const { diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 39790b4d6..831c72f83 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -247,6 +247,22 @@ void GridLayout::addEmptyColumn(EmptyVisibleLayout::Color color) { } } +void GridLayout::deleteRowAtIndex(int index) { + assert(index >= 0 && index < m_numberOfRows); + for (int i = 0; i < m_numberOfColumns; i++) { + DynamicLayoutHierarchy::removeChildAtIndex(index * m_numberOfColumns, true); + } + m_numberOfRows--; +} + +void GridLayout::deleteColumnAtIndex(int index) { + assert(index >= 0 && index < m_numberOfColumns); + for (int i = (m_numberOfRows - 1) * m_numberOfColumns + index; i > -1; i-= m_numberOfColumns) { + DynamicLayoutHierarchy::removeChildAtIndex(i, true); + } + m_numberOfColumns--; +} + bool GridLayout::childIsLeftOfGrid(int index) const { assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns); return columnAtChildIndex(index) == 0; diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index bee1df01a..dd03e309c 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -35,6 +35,8 @@ protected: KDPoint positionOfChild(ExpressionLayout * child) override; void addEmptyRow(EmptyVisibleLayout::Color color); void addEmptyColumn(EmptyVisibleLayout::Color color); + void deleteRowAtIndex(int index); + void deleteColumnAtIndex(int index); bool childIsRightOfGrid(int index) const; bool childIsBottomOfGrid(int index) const; int rowAtChildIndex(int index) const; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 62159aa03..2f75b68e8 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -61,7 +61,7 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex } // If the new layout is empty and it was the only horizontal layout child, // replace the horizontal layout with this empty layout (only if this is not - // the main layout, so only if the layout has a parent. + // the main layout, so only if the layout has a parent). if (m_parent) { if (cursor) { replaceWithAndMoveCursor(newChild, deleteOldChild, cursor); diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index 5ad8a03d5..eee2bcf42 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -17,6 +17,12 @@ ExpressionLayout * MatrixLayout::clone() const { return layout; } +void MatrixLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { + int oldChildIndex = indexOfChild(const_cast(oldChild)); + GridLayout::replaceChild(oldChild, newChild, deleteOldChild); + childWasReplacedAtIndex(oldChildIndex); +} + void MatrixLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { int oldChildIndex = indexOfChild(const_cast(oldChild)); int rowIndex = rowAtChildIndex(oldChildIndex); @@ -59,6 +65,7 @@ int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { } void MatrixLayout::newRowOrColumnAtIndex(int index) { + assert(index >= 0 && index < m_numberOfColumns*m_numberOfRows); bool shouldAddNewRow = GridLayout::childIsBottomOfGrid(index); int correspondingRow = rowAtChildIndex(index); // We need to compute this bool before modifying the layout.:w @@ -73,7 +80,7 @@ void MatrixLayout::newRowOrColumnAtIndex(int index) { } } // Add a column of grey EmptyVisibleLayouts on the right. - GridLayout::addEmptyColumn(EmptyVisibleLayout::Color::Grey); + addEmptyColumn(EmptyVisibleLayout::Color::Grey); } if (shouldAddNewRow) { // Color the grey EmptyVisibleLayouts of the row in yellow. @@ -84,7 +91,30 @@ void MatrixLayout::newRowOrColumnAtIndex(int index) { } } // Add a row of grey EmptyVisibleLayouts at the bottom. - GridLayout::addEmptyRow(EmptyVisibleLayout::Color::Grey); + addEmptyRow(EmptyVisibleLayout::Color::Grey); + } +} + +void MatrixLayout::childWasReplacedAtIndex(int index) { + assert(index >= 0 && index < m_numberOfColumns*m_numberOfRows); + int rowIndex = rowAtChildIndex(index); + int columnIndex = columnAtChildIndex(index); + bool rowIsEmpty = isRowEmpty(rowIndex); + bool columnIsEmpty = isColumnEmpty(columnIndex); + if (rowIsEmpty && m_numberOfRows > 2) { + deleteRowAtIndex(rowIndex); + } + if (columnIsEmpty && m_numberOfColumns > 2) { + deleteColumnAtIndex(columnIndex); + } + if (!rowIsEmpty && !columnIsEmpty) { + ExpressionLayout * newChild = editableChild(index); + if (newChild->isEmpty() + && (childIsRightOfGrid(index) + || childIsBottomOfGrid(index))) + { + static_cast(newChild)->setColor(EmptyVisibleLayout::Color::Grey); + } } } @@ -108,6 +138,7 @@ ExpressionLayout * dummyGridLayout = new GridLayout(children(), m_numberOfRows, } KDPoint MatrixLayout::positionOfChild(ExpressionLayout * child) { + assert(indexOfChild(child) > -1); BracketLeftLayout * dummyLeftBracket = new BracketLeftLayout(); BracketRightLayout * dummyRightBracket = new BracketRightLayout(); ExpressionLayout * dummyGridLayout = new GridLayout(children(), m_numberOfRows, m_numberOfColumns, true); @@ -115,4 +146,24 @@ ExpressionLayout * dummyGridLayout = new GridLayout(children(), m_numberOfRows, return GridLayout::positionOfChild(child).translatedBy(dummyLayout.positionOfChild(dummyGridLayout)); } +bool MatrixLayout::isRowEmpty(int index) const { + assert(index >= 0 && index < m_numberOfRows); + for (int i = index * m_numberOfColumns; i < (index+1) * m_numberOfColumns; i++) { + if (!child(i)->isEmpty()) { + return false; + } + } + return true; +} + +bool MatrixLayout::isColumnEmpty(int index) const { + assert(index >= 0 && index < m_numberOfColumns); + for (int i = index; i < m_numberOfRows * m_numberOfColumns; i+= m_numberOfColumns) { + if (!child(i)->isEmpty()) { + return false; + } + } + return true; +} + } diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 83008d440..047753ca4 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -9,13 +9,19 @@ class MatrixLayout : public GridLayout { public: using GridLayout::GridLayout; ExpressionLayout * clone() const override; + void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; + bool isMatrix() const override { return true; } void newRowOrColumnAtIndex(int index); + void childWasReplacedAtIndex(int index); protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; KDPoint positionOfChild(ExpressionLayout * child) override; +private: + bool isRowEmpty(int index) const; + bool isColumnEmpty(int index) const; }; } From f95bb46cc38e0dd2ff0010953474893dac81c504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 11:08:58 +0100 Subject: [PATCH 152/257] [poincare] Cleaned ExpressionLayout class. Change-Id: I03a49e1a2b199a70608792f0358ddde5a86118d6 --- poincare/include/poincare/expression_layout.h | 67 +++++++++----- poincare/src/layout/expression_layout.cpp | 91 +++++++++---------- poincare/src/layout/horizontal_layout.cpp | 6 +- poincare/src/layout/matrix_layout.cpp | 4 +- 4 files changed, 92 insertions(+), 76 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 715ad8fbe..473827679 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -32,38 +32,60 @@ public: virtual void invalidAllSizesPositionsAndBaselines(); /* Hierarchy */ + + // Children virtual const ExpressionLayout * const * children() const = 0; const ExpressionLayout * child(int i) const; ExpressionLayout * editableChild(int i) { return const_cast(child(i)); } virtual int numberOfChildren() const = 0; - int indexOfChild(ExpressionLayout * child) const; + int indexOfChild(const ExpressionLayout * child) const; - void setParent(ExpressionLayout * parent); + // Parent + void setParent(ExpressionLayout * parent) { m_parent = parent; } const ExpressionLayout * parent() const { return m_parent; } ExpressionLayout * editableParent() { return m_parent; } bool hasAncestor(const ExpressionLayout * e) const; /* Dynamic Layout */ - bool insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor); + + // Add + virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } virtual void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); + + // Replace virtual ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace = true); - ExpressionLayout * replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace); ExpressionLayout * replaceWithAndMoveCursor(ExpressionLayout * newChild, bool deleteAfterReplace, ExpressionLayoutCursor * cursor); virtual void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true); - virtual void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor); - void detachChild(const ExpressionLayout * e); // Removes a child WITHOUT deleting it - void detachChildren(); //Removes all children WITHOUT deleting them - virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } + virtual void replaceChildAndMoveCursor( + const ExpressionLayout * oldChild, + ExpressionLayout * newChild, + bool deleteOldChild, + ExpressionLayoutCursor * cursor); + + // Detach + void detachChild(const ExpressionLayout * e); // Detach a child WITHOUT deleting it + void detachChildren(); // Detach all children WITHOUT deleting them + + // Remove virtual void removeChildAtIndex(int index, bool deleteAfterRemoval); virtual void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor); + + // User input + bool insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor); virtual void backspaceAtCursor(ExpressionLayoutCursor * cursor); /* Tree navigation */ virtual bool moveLeft(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? virtual bool moveRight(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? - virtual bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); + virtual bool moveUp( + ExpressionLayoutCursor * cursor, + ExpressionLayout * previousLayout = nullptr, + ExpressionLayout * previousPreviousLayout = nullptr); + virtual bool moveDown( + ExpressionLayoutCursor * cursor, + ExpressionLayout * previousLayout = nullptr, + ExpressionLayout * previousPreviousLayout = nullptr); bool moveUpInside(ExpressionLayoutCursor * cursor); - virtual bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); bool moveDownInside(ExpressionLayoutCursor * cursor); /* Expression Engine */ @@ -71,7 +93,8 @@ public: /* Other */ virtual bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { return true; } - // isCollapsable is used when adding a brother fraction: should the layout be inserted in the numerator (or denominator)? + /* isCollapsable is used when adding a brother fraction: should the layout be + * inserted in the numerator (or denominator)? */ virtual bool mustHaveLeftBrother() const { return false; } virtual bool isHorizontal() const { return false; } virtual bool isLeftParenthesis() const { return false; } @@ -87,24 +110,24 @@ protected: virtual KDSize computeSize() = 0; virtual void computeBaseline() = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; + ExpressionLayout * m_parent; + KDCoordinate m_baseline; + /* m_baseline is the signed vertical distance from the top of the layout to + * the fraction bar of an hypothetical fraction brother layout. If the top of + * the layout is under that bar, the baseline is negative. */ + bool m_sized; + bool m_baselined; + bool m_positioned; +private: void detachChildAtIndex(int i); + bool moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor); void moveCursorInsideAtDirection ( VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout ** childResult, void * resultPosition, int * resultScore); - KDCoordinate m_baseline; - /* m_baseline is the signed vertical distance from the top of the layout to - * the fraction bar of an hypothetical fraction brother layout. If the top of - * the layout is under that bar, the baseline is negative. */ - ExpressionLayout * m_parent; - bool m_sized; - bool m_baselined; - bool m_positioned; -private: - bool moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor); - void replaceWithJuxtapositionOf(ExpressionLayout * firstLayout, ExpressionLayout * secondLayout); + ExpressionLayout * replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace); KDRect m_frame; }; diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index f79a62e0e..76e7adcc4 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -10,8 +10,8 @@ namespace Poincare { ExpressionLayout::ExpressionLayout() : - m_baseline(0), m_parent(nullptr), + m_baseline(0), m_sized(false), m_baselined(false), m_positioned(false), @@ -19,6 +19,14 @@ ExpressionLayout::ExpressionLayout() : { } +void ExpressionLayout::draw(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { + int i = 0; + while (ExpressionLayout * c = editableChild(i++)) { + c->draw(ctx, p, expressionColor, backgroundColor); + } + render(ctx, absoluteOrigin().translatedBy(p), expressionColor, backgroundColor); +} + KDPoint ExpressionLayout::origin() { if (m_parent == nullptr) { return absoluteOrigin(); @@ -28,14 +36,6 @@ KDPoint ExpressionLayout::origin() { } } -void ExpressionLayout::draw(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { - int i = 0; - while (ExpressionLayout * c = editableChild(i++)) { - c->draw(ctx, p, expressionColor, backgroundColor); - } - render(ctx, absoluteOrigin().translatedBy(p), expressionColor, backgroundColor); -} - KDPoint ExpressionLayout::absoluteOrigin() { if (!m_positioned) { if (m_parent != nullptr) { @@ -83,7 +83,7 @@ const ExpressionLayout * ExpressionLayout::child(int i) const { return nullptr; } -int ExpressionLayout::indexOfChild(ExpressionLayout * child) const { +int ExpressionLayout::indexOfChild(const ExpressionLayout * child) const { if (child == nullptr) { return -1; } @@ -95,10 +95,6 @@ int ExpressionLayout::indexOfChild(ExpressionLayout * child) const { return -1; } -void ExpressionLayout::setParent(ExpressionLayout* parent) { - m_parent = parent; -} - bool ExpressionLayout::hasAncestor(const ExpressionLayout * e) const { assert(m_parent != this); if (m_parent == e) { @@ -143,28 +139,12 @@ void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLay return; } -bool ExpressionLayout::insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor) { - cursor->pointedExpressionLayout()->addBrother(cursor, newChild); - return true; -} - ExpressionLayout * ExpressionLayout::replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace) { assert(m_parent != nullptr); m_parent->replaceChild(this, newChild, deleteAfterReplace); return newChild; } -ExpressionLayout * ExpressionLayout::replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace) { - assert(m_parent != nullptr); - /* One of the children to juxtapose might be "this", so we first have to - * replace "this" with an horizontal layout, then add "this" to the layout. */ - ExpressionLayout * layout = new HorizontalLayout(); - m_parent->replaceChild(this, layout, deleteAfterReplace); - layout->addChildAtIndex(leftChild, 0); - layout->addChildAtIndex(rightChild, 1); - return layout; -} - ExpressionLayout * ExpressionLayout::replaceWithAndMoveCursor(ExpressionLayout * newChild, bool deleteAfterReplace, ExpressionLayoutCursor * cursor) { assert(m_parent != nullptr); m_parent->replaceChildAndMoveCursor(this, newChild, deleteAfterReplace, cursor); @@ -199,7 +179,7 @@ void ExpressionLayout::replaceChild(const ExpressionLayout * oldChild, Expressio } void ExpressionLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { - int oldChildIndex = indexOfChild(const_cast(oldChild)); + int oldChildIndex = indexOfChild(oldChild); assert(oldChildIndex >= 0); if (oldChildIndex == 0) { cursor->setPointedExpressionLayout(this); @@ -212,16 +192,12 @@ void ExpressionLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChi } void ExpressionLayout::detachChild(const ExpressionLayout * e) { - ExpressionLayout ** op = const_cast(children()); - for (int i = 0; i < numberOfChildren(); i++) { - if (op[i] == e) { - detachChildAtIndex(i); - } - } + assert(indexOfChild(e) >= 0); + detachChildAtIndex(indexOfChild(e)); } void ExpressionLayout::detachChildren() { - for (int i = 0; i setPointedExpressionLayout(editableChild(indexOfNewPointedLayout)); } + +bool ExpressionLayout::insertLayoutAtCursor(ExpressionLayout * newChild, ExpressionLayoutCursor * cursor) { + cursor->pointedExpressionLayout()->addBrother(cursor, newChild); + return true; +} + void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); if (indexOfPointedExpression >= 0) { @@ -302,17 +284,6 @@ char ExpressionLayout::XNTChar() const { return m_parent->XNTChar(); } -void ExpressionLayout::detachChildAtIndex(int i) { - ExpressionLayout ** op = const_cast(children()); - if (op[i] != nullptr && op[i]->parent() == this) { - const_cast(op[i])->setParent(nullptr); - } - op[i] = nullptr; - m_sized = false; - m_positioned = false; - m_baselined = false; -} - bool ExpressionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { if (m_parent) { return m_parent->moveUp(cursor, this, previousLayout); @@ -335,6 +306,17 @@ bool ExpressionLayout::moveDownInside(ExpressionLayoutCursor * cursor) { return moveInside(VerticalDirection::Down, cursor); } +void ExpressionLayout::detachChildAtIndex(int i) { + ExpressionLayout ** op = const_cast(children()); + if (op[i] != nullptr && op[i]->parent() == this) { + const_cast(op[i])->setParent(nullptr); + } + op[i] = nullptr; + m_sized = false; + m_positioned = false; + m_baselined = false; +} + bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor) { ExpressionLayout * chilResult = nullptr; ExpressionLayout ** childResultPtr = &chilResult; @@ -391,4 +373,15 @@ void ExpressionLayout::moveCursorInsideAtDirection ( } } +ExpressionLayout * ExpressionLayout::replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace) { + assert(m_parent != nullptr); + /* One of the children to juxtapose might be "this", so we first have to + * replace "this" with an horizontal layout, then add "this" to the layout. */ + ExpressionLayout * layout = new HorizontalLayout(); + m_parent->replaceChild(this, layout, deleteAfterReplace); + layout->addChildAtIndex(leftChild, 0); + layout->addChildAtIndex(rightChild, 1); + return layout; +} + } diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 2f75b68e8..0bc3fc214 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -38,7 +38,7 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex if (newChild->hasAncestor(this)) { newChild->editableParent()->detachChild(newChild); } - int oldChildIndex = indexOfChild(const_cast(oldChild)); + int oldChildIndex = indexOfChild(oldChild); if (newChild->isEmpty()) { if (numberOfChildren() > 1) { // If the new layout is empty and the horizontal layout has other @@ -46,7 +46,7 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex if (!newChild->hasAncestor(oldChild)) { delete newChild; } - removeChildAtIndex(indexOfChild(const_cast(oldChild)), deleteOldChild); + removeChildAtIndex(oldChildIndex, deleteOldChild); if (cursor == nullptr) { return; } @@ -74,7 +74,7 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex // If the new child is also an horizontal layout, steal the children of the // new layout then destroy it. if (newChild->isHorizontal()) { - int indexForInsertion = indexOfChild(const_cast(oldChild)); + int indexForInsertion = indexOfChild(oldChild); mergeChildrenAtIndex(static_cast(newChild), indexForInsertion + 1, true); removeChildAtIndex(indexForInsertion, deleteOldChild); if (cursor == nullptr) { diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index eee2bcf42..f88ddb27c 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -18,13 +18,13 @@ ExpressionLayout * MatrixLayout::clone() const { } void MatrixLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { - int oldChildIndex = indexOfChild(const_cast(oldChild)); + int oldChildIndex = indexOfChild(oldChild); GridLayout::replaceChild(oldChild, newChild, deleteOldChild); childWasReplacedAtIndex(oldChildIndex); } void MatrixLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { - int oldChildIndex = indexOfChild(const_cast(oldChild)); + int oldChildIndex = indexOfChild(oldChild); int rowIndex = rowAtChildIndex(oldChildIndex); int columnIndex = columnAtChildIndex(oldChildIndex); replaceChild(oldChild, newChild, deleteOldChild); From 955c69f0b2aa1895a34f1e63c4517db87471f3ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 11:24:07 +0100 Subject: [PATCH 153/257] [poincare] Changed isEmpty() in DynamicLayoutHierarchy. A DynamicLayoutHierarchy with only an empty children is not empty, but an horizontal layout with only an empty children is empty. Also, a DynamicLayoutHierarchy with no children is not empty (it should always be an intermediary state before adding children). Change-Id: I47b32379f42a95666d75df4d3ba79fabc34d2edc --- poincare/include/poincare/dynamic_layout_hierarchy.h | 1 - poincare/src/layout/dynamic_layout_hierarchy.cpp | 9 --------- poincare/src/layout/horizontal_layout.cpp | 8 ++++++++ poincare/src/layout/horizontal_layout.h | 1 + 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index 4157d15fe..63518b122 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -31,7 +31,6 @@ public: void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren); // WITHOUT delete. - bool isEmpty() const override; protected: const ExpressionLayout ** m_children; int m_numberOfChildren; diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index 7678abd18..8a54de8b3 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -142,13 +142,4 @@ void DynamicLayoutHierarchy::removePointedChildAtIndexAndMoveCursor(int index, b cursor->setPointedExpressionLayout(editableChild(indexOfNewPointedLayout)); } -bool DynamicLayoutHierarchy::isEmpty() const { - if (m_numberOfChildren == 0 - || (m_numberOfChildren == 1 && child(0)->isEmpty())) - { - return true; - } - return false; -} - } diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 0bc3fc214..6a7b91e7a 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -224,6 +224,14 @@ void HorizontalLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { DynamicLayoutHierarchy::removeChildAtIndex(index, deleteAfterRemoval); } +bool HorizontalLayout::isEmpty() const { + if (m_numberOfChildren == 1 && child(0)->isEmpty()) + { + return true; + } + return false; +} + void HorizontalLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 98a2d9380..a8e932797 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -37,6 +37,7 @@ public: /* Other */ bool isHorizontal() const override { return true; } + bool isEmpty() const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; From 914b181e066160d6846ca5c5f0c9f5d4e0b3b155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 11:39:35 +0100 Subject: [PATCH 154/257] [poincare] Change the way to delete a matrix. Delete the matrix if the cursor was right of it. If the cursor is left of a child on the left, now just move Left. Change-Id: I4bccaec9f7c23c4da3dd1d9ab59c8fd6641d5a3f --- poincare/src/layout/grid_layout.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 831c72f83..6fb4874ac 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -25,14 +25,7 @@ void GridLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { if (cursor->position() == ExpressionLayoutCursor::Position::Left) { int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); if (indexOfPointedExpression >= 0) { - if (childIsLeftOfGrid(indexOfPointedExpression)) { - // Case: Left of a left child grid. - // Delete the grid. - assert(m_parent != nullptr); - replaceWithAndMoveCursor(new EmptyVisibleLayout(), true, cursor); - return; - } - // Case: Left of another child of the grid. + // Case: Left of child of the grid. // Move Left. moveLeft(cursor); return; @@ -45,12 +38,9 @@ void GridLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { } } // Case: Right. - // Move to the last child. - assert(cursor->pointedExpressionLayout() == this); - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - cursor->setPointedExpressionLayout(editableChild((m_numberOfRows-1)*(m_numberOfColumns-1))); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; + // Delete the grid. + assert(m_parent != nullptr); + replaceWithAndMoveCursor(new EmptyVisibleLayout(), true, cursor); } bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { From bf4ccd76eaa3ac03714d888d1ca54d6db2e3bde3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 14:11:50 +0100 Subject: [PATCH 155/257] [poincare] Show grey squares in a matrix only if the cursor is in it. Change-Id: I2e622de51a9c7af7b676ae9bd7bb3e9681f5d051 --- apps/expression_editor/controller.cpp | 2 + poincare/include/poincare/expression_layout.h | 4 +- poincare/src/layout/empty_visible_layout.h | 1 + poincare/src/layout/grid_layout.cpp | 4 + poincare/src/layout/grid_layout.h | 4 +- poincare/src/layout/horizontal_layout.cpp | 16 ++- poincare/src/layout/matrix_layout.cpp | 113 +++++++++++++++++- poincare/src/layout/matrix_layout.h | 19 ++- 8 files changed, 155 insertions(+), 8 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index f19771346..cdce47736 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -62,6 +62,8 @@ void Controller::insertLayoutAtCursor(ExpressionLayout * layout, ExpressionLayou bool Controller::privateHandleEvent(Ion::Events::Event event) { if (handleMoveEvent(event)) { + m_expressionLayout->invalidAllSizesPositionsAndBaselines(); + m_view.layoutSubviews(); return true; } ExpressionLayout * newPointedLayout = handleAddEvent(event); diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 473827679..a2f4ab83d 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -85,8 +85,8 @@ public: ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); - bool moveUpInside(ExpressionLayoutCursor * cursor); - bool moveDownInside(ExpressionLayoutCursor * cursor); + virtual bool moveUpInside(ExpressionLayoutCursor * cursor); + virtual bool moveDownInside(ExpressionLayoutCursor * cursor); /* Expression Engine */ virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0; diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index ae5a5e5c2..4d454d97b 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -20,6 +20,7 @@ public: bool moveRight(ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; bool isEmpty() const override { return true; } + Color color() const { return m_color; } void setColor(Color color) { m_color = color; } protected: virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index 6fb4874ac..bf3498872 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -228,6 +228,7 @@ void GridLayout::addEmptyRow(EmptyVisibleLayout::Color color) { } addChildrenAtIndex(const_cast(const_cast(newChildren)), m_numberOfColumns, numberOfChildren(), false); m_numberOfRows++; + invalidAllSizesPositionsAndBaselines(); } void GridLayout::addEmptyColumn(EmptyVisibleLayout::Color color) { @@ -235,6 +236,7 @@ void GridLayout::addEmptyColumn(EmptyVisibleLayout::Color color) { for (int i = 0; i < m_numberOfRows; i++) { addChildAtIndex(new EmptyVisibleLayout(color), i*m_numberOfColumns + m_numberOfColumns-1); } + invalidAllSizesPositionsAndBaselines(); } void GridLayout::deleteRowAtIndex(int index) { @@ -243,6 +245,7 @@ void GridLayout::deleteRowAtIndex(int index) { DynamicLayoutHierarchy::removeChildAtIndex(index * m_numberOfColumns, true); } m_numberOfRows--; + invalidAllSizesPositionsAndBaselines(); } void GridLayout::deleteColumnAtIndex(int index) { @@ -251,6 +254,7 @@ void GridLayout::deleteColumnAtIndex(int index) { DynamicLayoutHierarchy::removeChildAtIndex(i, true); } m_numberOfColumns--; + invalidAllSizesPositionsAndBaselines(); } bool GridLayout::childIsLeftOfGrid(int index) const { diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index dd03e309c..5fac6e1ec 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -38,6 +38,8 @@ protected: void deleteRowAtIndex(int index); void deleteColumnAtIndex(int index); bool childIsRightOfGrid(int index) const; + bool childIsLeftOfGrid(int index) const; + bool childIsTopOfGrid(int index) const; bool childIsBottomOfGrid(int index) const; int rowAtChildIndex(int index) const; int columnAtChildIndex(int index) const; @@ -51,8 +53,6 @@ private: KDCoordinate height(); KDCoordinate columnWidth(int j); KDCoordinate width(); - bool childIsLeftOfGrid(int index) const; - bool childIsTopOfGrid(int index) const; }; } diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 6a7b91e7a..45f1a9747 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -63,13 +63,27 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex // replace the horizontal layout with this empty layout (only if this is not // the main layout, so only if the layout has a parent). if (m_parent) { + if (!deleteOldChild) { + removeChildAtIndex(indexOfChild(oldChild), false); + } if (cursor) { - replaceWithAndMoveCursor(newChild, deleteOldChild, cursor); + replaceWithAndMoveCursor(newChild, true, cursor); return; } replaceWith(newChild, deleteOldChild); return; } + // If this is the main horizontal layout, the old child its only child and + // the new child is Empty, remove the old child and delete the new child. + assert(m_parent == nullptr); + removeChildAtIndex(0, deleteOldChild); + delete newChild; + if (cursor == nullptr) { + return; + } + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return; } // If the new child is also an horizontal layout, steal the children of the // new layout then destroy it. diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index f88ddb27c..afccc9260 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -17,6 +17,85 @@ ExpressionLayout * MatrixLayout::clone() const { return layout; } +bool MatrixLayout::moveLeft(ExpressionLayoutCursor * cursor) { + int childIndex = indexOfChild(cursor->pointedExpressionLayout()); + if (childIndex >- 1 + && cursor->position() == ExpressionLayoutCursor::Position::Left + && childIsLeftOfGrid(childIndex)) + { + // Case: Left of a child on the left of the grid. + // Remove the grey squares of the grid, then go left of the grid. + assert(hasGreySquares()); + removeGreySquares(); + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + return true; + } + // Case: Right. + // Add the grey squares to the matrix, then move to the bottom right non empty + // nor grey child. + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + assert(!hasGreySquares()); + addGreySquares(); + ExpressionLayout * lastChild = editableChild((m_numberOfColumns-1)*(m_numberOfRows-1)); + assert(lastChild != nullptr); + cursor->setPointedExpressionLayout(lastChild); + return true; + } + return GridLayout::moveLeft(cursor); +} + +bool MatrixLayout::moveRight(ExpressionLayoutCursor * cursor) { + // Case: Left. + // Add the grey squares to the matrix,, then go to the first entry. + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + assert(!hasGreySquares()); + addGreySquares(); + assert(m_numberOfColumns*m_numberOfRows >= 1); + ExpressionLayout * firstChild = editableChild(0); + assert(firstChild != nullptr); + cursor->setPointedExpressionLayout(firstChild); + return true; + } + // Case: The cursor points to a grid's child. + int childIndex = indexOfChild(cursor->pointedExpressionLayout()); + if (childIndex >- 1 + && cursor->position() == ExpressionLayoutCursor::Position::Right + && childIsRightOfGrid(childIndex)) + { + // Case: Right of a child on the right of the grid. + // Remove the grey squares of the grid, then go left of the grid. + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + assert(hasGreySquares()); + removeGreySquares(); + return true; + } + return GridLayout::moveRight(cursor); +} + +bool MatrixLayout::moveUpInside(ExpressionLayoutCursor * cursor) { + bool result = GridLayout::moveUpInside(cursor); + if (result) { + assert(!hasGreySquares()); + addGreySquares(); + } + return result; +} + +bool MatrixLayout::moveDownInside(ExpressionLayoutCursor * cursor) { + bool result = GridLayout::moveDownInside(cursor); + if (result) { + assert(!hasGreySquares()); + addGreySquares(); + } + return result; +} + void MatrixLayout::replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) { int oldChildIndex = indexOfChild(oldChild); GridLayout::replaceChild(oldChild, newChild, deleteOldChild); @@ -50,11 +129,13 @@ int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { buffer[numberOfChar++] = '['; if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - for (int i = 0; i < m_numberOfRows - 1; i++) { + int maxRowIndex = hasGreySquares() ? m_numberOfRows - 1 : m_numberOfRows; + int maxColumnIndex = hasGreySquares() ? m_numberOfColumns - 2 : m_numberOfColumns - 1; + for (int i = 0; i < maxRowIndex; i++) { buffer[numberOfChar++] = '['; if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, ",", i*m_numberOfColumns, i* m_numberOfColumns + m_numberOfColumns - 2); + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, ",", i*m_numberOfColumns, i* m_numberOfColumns + maxColumnIndex); buffer[numberOfChar++] = ']'; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } @@ -166,4 +247,32 @@ bool MatrixLayout::isColumnEmpty(int index) const { return true; } +void MatrixLayout::addGreySquares() { + if (!hasGreySquares()) { + addEmptyRow(EmptyVisibleLayout::Color::Grey); + addEmptyColumn(EmptyVisibleLayout::Color::Grey); + } +} + +void MatrixLayout::removeGreySquares() { + if (hasGreySquares()) { + deleteRowAtIndex(m_numberOfRows - 1); + deleteColumnAtIndex(m_numberOfColumns - 1); + } +} + +bool MatrixLayout::hasGreySquares() const { + assert(m_numberOfRows*m_numberOfColumns - 1 >= 0); + const ExpressionLayout * lastChild = child(m_numberOfRows * m_numberOfColumns - 1); + if (lastChild->isEmpty() + && !lastChild->isHorizontal() + && (static_cast(lastChild))->color() == EmptyVisibleLayout::Color::Grey) + { + assert(isRowEmpty(m_numberOfColumns - 1)); + assert(isColumnEmpty(m_numberOfRows - 1)); + return true; + } + return false; +} + } diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 047753ca4..6a58bb0cd 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -9,19 +9,36 @@ class MatrixLayout : public GridLayout { public: using GridLayout::GridLayout; ExpressionLayout * clone() const override; + + /* Navigation */ + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveUpInside(ExpressionLayoutCursor * cursor) override; + bool moveDownInside(ExpressionLayoutCursor * cursor) override; + + /* Dynamic layout */ void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; + + /* Expression engine */ int writeTextInBuffer(char * buffer, int bufferSize) const override; + + /* Other */ bool isMatrix() const override { return true; } + + /* Special matrix method */ void newRowOrColumnAtIndex(int index); - void childWasReplacedAtIndex(int index); protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: + void childWasReplacedAtIndex(int index); bool isRowEmpty(int index) const; bool isColumnEmpty(int index) const; + void addGreySquares(); + void removeGreySquares(); + bool hasGreySquares() const; }; } From e2bd7ddbe0cb9121fd9cebdfcdfab10811a2395c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 14:27:20 +0100 Subject: [PATCH 156/257] [poincare] Fixed deletion bug in MatrixLayout. Change-Id: I0dbc142468320fac4ed8969a3ef2684549315780 --- poincare/src/layout/matrix_layout.cpp | 6 ++++++ poincare/src/layout/matrix_layout.h | 1 + 2 files changed, 7 insertions(+) diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index afccc9260..7626efa06 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -117,6 +117,12 @@ void MatrixLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, cursor->setPosition(ExpressionLayoutCursor::Position::Left); } +void MatrixLayout::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { + assert(index >= 0 && index < numberOfChildren()); + assert(cursor->pointedExpressionLayout() == child(index)); + replaceChildAndMoveCursor(child(index), new EmptyVisibleLayout(), deleteAfterRemoval, cursor); +} + int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { // The grid is a matrix. if (bufferSize == 0) { diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 6a58bb0cd..30dccb142 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -19,6 +19,7 @@ public: /* Dynamic layout */ void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; + void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; /* Expression engine */ int writeTextInBuffer(char * buffer, int bufferSize) const override; From 16fad9f9fb7e47141a422124b314424116319983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 16:50:17 +0100 Subject: [PATCH 157/257] [poincare] Cleaned backspaceAtCursor for layouts. Change-Id: I232fa7af24a9983d3acfb3460042cb32bfcef81f --- poincare/include/poincare/expression_layout.h | 4 +- .../layout/binomial_coefficient_layout.cpp | 14 ----- .../src/layout/binomial_coefficient_layout.h | 1 - poincare/src/layout/bracket_layout.cpp | 17 ++---- poincare/src/layout/conjugate_layout.cpp | 30 ++++++++-- poincare/src/layout/conjugate_layout.h | 2 + poincare/src/layout/expression_layout.cpp | 38 +++--------- poincare/src/layout/fraction_layout.cpp | 19 +++--- poincare/src/layout/grid_layout.cpp | 22 ------- poincare/src/layout/grid_layout.h | 6 +- poincare/src/layout/horizontal_layout.cpp | 60 ++++++++++++++----- poincare/src/layout/integral_layout.cpp | 23 ++----- poincare/src/layout/matrix_layout.cpp | 1 - poincare/src/layout/nth_root_layout.cpp | 31 ++-------- poincare/src/layout/sequence_layout.cpp | 23 ++----- .../src/layout/vertical_offset_layout.cpp | 8 +++ 16 files changed, 121 insertions(+), 178 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index a2f4ab83d..e495c397c 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -75,8 +75,8 @@ public: virtual void backspaceAtCursor(ExpressionLayoutCursor * cursor); /* Tree navigation */ - virtual bool moveLeft(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? - virtual bool moveRight(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure? + virtual bool moveLeft(ExpressionLayoutCursor * cursor) = 0; + virtual bool moveRight(ExpressionLayoutCursor * cursor) = 0; virtual bool moveUp( ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, diff --git a/poincare/src/layout/binomial_coefficient_layout.cpp b/poincare/src/layout/binomial_coefficient_layout.cpp index 0342a1b6f..aec65fd20 100644 --- a/poincare/src/layout/binomial_coefficient_layout.cpp +++ b/poincare/src/layout/binomial_coefficient_layout.cpp @@ -18,20 +18,6 @@ ExpressionLayout * BinomialCoefficientLayout::clone() const { return new BinomialCoefficientLayout(const_cast(this)->nLayout(), const_cast(this)->kLayout(), true); } -void BinomialCoefficientLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // Case: Left of the children. - // Delete the layout. - if (cursor->position() == ExpressionLayoutCursor::Position::Left - && (cursor->pointedExpressionLayout() == nLayout() - || cursor->pointedExpressionLayout() == kLayout())) - { - assert(m_parent != nullptr); - replaceWithAndMoveCursor(new EmptyVisibleLayout(), true, cursor); - return; - } - ExpressionLayout::backspaceAtCursor(cursor); -} - bool BinomialCoefficientLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the children. // Go Left. diff --git a/poincare/src/layout/binomial_coefficient_layout.h b/poincare/src/layout/binomial_coefficient_layout.h index 9fee26479..30dc3da69 100644 --- a/poincare/src/layout/binomial_coefficient_layout.h +++ b/poincare/src/layout/binomial_coefficient_layout.h @@ -10,7 +10,6 @@ class BinomialCoefficientLayout : public StaticLayoutHierarchy<2> { public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; - void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 6d1222e14..38fd0b400 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -14,21 +14,14 @@ ExpressionLayout * BracketLayout::clone() const { } void BracketLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // Case: Left of the operand. - // Delete the brackets, keep the operand. - if (cursor->pointedExpressionLayout() == operandLayout()) { - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + // Case: Right. + // Delete the layout, keep the operand. replaceWithAndMoveCursor(operandLayout(), true, cursor); return; } - // Case: Right. - // Move Right of the operand. - assert(cursor->pointedExpressionLayout() == this); - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - cursor->setPointedExpressionLayout(operandLayout()); - cursor->performBackspace(); - return; - } ExpressionLayout::backspaceAtCursor(cursor); } diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index 645514896..7323e1fd7 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -1,4 +1,5 @@ #include "conjugate_layout.h" +#include "empty_visible_layout.h" #include #include extern "C" { @@ -14,11 +15,13 @@ ExpressionLayout * ConjugateLayout::clone() const { } void ConjugateLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // Case: Left of the operand. - // Delete the conjugate, keep the operand. - if (cursor->pointedExpressionLayout() == operandLayout()) { - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - replaceWithAndMoveCursor(operandLayout(), true, cursor); + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + // Case: Right. + // Move to the operand and delete. + cursor->setPointedExpressionLayout(operandLayout()); + cursor->performBackspace(); return; } ExpressionLayout::backspaceAtCursor(cursor); @@ -78,6 +81,23 @@ bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { return false; } +void ConjugateLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { + assert(oldChild == operandLayout()); + if (newChild->isEmpty()) { + if (!deleteOldChild) { + detachChild(oldChild); + } + replaceWithAndMoveCursor(newChild, true, cursor); + return; + } + ExpressionLayout::replaceChildAndMoveCursor(oldChild, newChild, deleteOldChild, cursor); +} + +void ConjugateLayout::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { + assert(index >= 0 && index < numberOfChildren()); + replaceChildAndMoveCursor(child(index), new EmptyVisibleLayout(), deleteAfterRemoval, cursor); +} + void ConjugateLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { ctx->fillRect(KDRect(p.x()+Metric::FractionAndConjugateHorizontalMargin, p.y(), operandLayout()->size().width()+2*Metric::FractionAndConjugateHorizontalOverflow, k_overlineWidth), expressionColor); } diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 203b1f1ca..f4846619f 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -13,6 +13,8 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; + void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; + void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "conj"); } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 76e7adcc4..8dfe2fb18 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -209,7 +209,6 @@ void ExpressionLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { void ExpressionLayout::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { assert(index >= 0 && index < numberOfChildren()); - assert(cursor->pointedExpressionLayout() == child(index)); removeChildAtIndex(index, deleteAfterRemoval); if (index < numberOfChildren()) { cursor->setPointedExpressionLayout(editableChild(index)); @@ -232,49 +231,30 @@ void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); if (indexOfPointedExpression >= 0) { // Case: The pointed layout is a child. - // Point to the previous child, else to this. + // Move Left. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - if (indexOfPointedExpression == 0) { - cursor->setPointedExpressionLayout(this); - } else { - cursor->setPointedExpressionLayout(editableChild(indexOfPointedExpression - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - } - cursor->performBackspace(); + cursor->moveLeft(); return; } assert(cursor->pointedExpressionLayout() == this); // Case: this is the pointed layout. if (m_parent == nullptr) { - // If there is no parent, return. + // Case: No parent. + // Return. return; } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { // Case: Left. // Ask the parent. - m_parent->backspaceAtCursor(cursor); + if (m_parent) { + m_parent->backspaceAtCursor(cursor); + } return; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); // Case: Right. - // If the layout has children, move to the last one. - if (numberOfChildren() > 0) { - cursor->setPointedExpressionLayout(editableChild(numberOfChildren()-1)); - cursor->performBackspace(); - return; - } - int indexInParent = m_parent->indexOfChild(this); - ExpressionLayout * previousParent = m_parent; - // Case: Right. - // If the layout has no child and is only child, replace it with an empty layout. - /*if (previousParent->numberOfChildren() == 1) { - ExpressionLayout * newLayout = new EmptyVisibleLayout(); - replaceWith(newLayout, true); - cursor->setPointedExpressionLayout(newLayout); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return; - }*/ - previousParent->removePointedChildAtIndexAndMoveCursor(indexInParent, true, cursor); + // Delete the layout. + m_parent->removePointedChildAtIndexAndMoveCursor(m_parent->indexOfChild(this), true, cursor); } char ExpressionLayout::XNTChar() const { diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index c425a8e4f..2f2d14dfe 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -14,13 +14,14 @@ ExpressionLayout * FractionLayout::clone() const { } void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // If the cursor is on the left of the denominator, replace the fraction with - // a horizontal juxtaposition of the numerator and the denominator. + // Case: Left of the denominator. + // Replace the fraction with a horizontal juxtaposition of the numerator and + // the denominator. if (cursor->pointedExpressionLayout() == denominatorLayout()) { assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (numeratorLayout()->isEmpty() && denominatorLayout()->isEmpty()) { - // If the numerator and the denominator are empty, move the cursor then - // replace the fraction with an empty layout. + // Case: Numerator and denominator are empty. + // Move the cursor then replace the fraction with an empty layout. replaceWithAndMoveCursor(new EmptyVisibleLayout(), true, cursor); return; } @@ -58,13 +59,9 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { cursor->setPosition(nextPosition); return; } - // If the cursor is on the left of the numerator, move Left of the fraction. - if (cursor->pointedExpressionLayout() == numeratorLayout()) { - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - cursor->setPointedExpressionLayout(this); - return; - } - // If the cursor is on the Right, move Left of the denominator. + + // Case: Right. + // Move Right of the denominator. if (cursor->pointedExpressionLayout() == this && cursor->position() == ExpressionLayoutCursor::Position::Right) { diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index bf3498872..e7af88579 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -21,28 +21,6 @@ ExpressionLayout * GridLayout::clone() const { return layout; } -void GridLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); - if (indexOfPointedExpression >= 0) { - // Case: Left of child of the grid. - // Move Left. - moveLeft(cursor); - return; - } - assert(cursor->pointedExpressionLayout() == this); - // Case: Left. - // Ask the parent. - if (m_parent) { - return m_parent->backspaceAtCursor(cursor); - } - } - // Case: Right. - // Delete the grid. - assert(m_parent != nullptr); - replaceWithAndMoveCursor(new EmptyVisibleLayout(), true, cursor); -} - bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Right. // Go to the last entry. diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 5fac6e1ec..d7e2915f6 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -11,7 +11,6 @@ class GridLayout : public DynamicLayoutHierarchy { public: GridLayout(const ExpressionLayout * const * entryLayouts, int numberOfRows, int numberOfColumns, bool cloneOperands); ExpressionLayout * clone() const override; - void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; /* Navigation */ bool moveLeft(ExpressionLayoutCursor * cursor) override; @@ -21,9 +20,8 @@ public: /* Dynamic layout */ void removeChildAtIndex(int index, bool deleteAfterRemoval) override; - // TODO: This function replaces the child with an EmptyVisibleLayout. Is this - // ok? If we want to delete the grid's children, we have to make sure no to - // call this function. + // This function replaces the child with an EmptyVisibleLayout. To delete the + // grid's children, do not call this function. /* Expression engine */ int writeTextInBuffer(char * buffer, int bufferSize) const override { return 0; } diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 45f1a9747..19ee6021b 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -15,14 +15,47 @@ ExpressionLayout * HorizontalLayout::clone() const { } void HorizontalLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // If the cursor was pointing left of the first child of the horizontal - // layout, make it point at the horizontal layout itself. + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Left + && m_parent == nullptr) + { + // Case: Left and this is the main layout. + // Return. + return; + } + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right + && m_parent == nullptr + && numberOfChildren() == 0) + { + // Case: Right and this is the main layout with no children. + // Return. + return; + } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { int indexOfPointedExpression = indexOfChild(cursor->pointedExpressionLayout()); - if (indexOfPointedExpression == 0) { - cursor->setPointedExpressionLayout(this); + if (indexOfPointedExpression >= 0) { + // Case: Left of a child. + // Point Right of the previous child. If there is no previous child, point + // Left of this. Perform another backspace. + if (indexOfPointedExpression == 0) { + cursor->setPointedExpressionLayout(this); + } else if (indexOfPointedExpression > 0) { + cursor->setPointedExpressionLayout(editableChild(indexOfPointedExpression - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } + cursor->performBackspace(); + return; } } + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + // Case: Right. + // Point to the last child and perform backspace. + cursor->setPointedExpressionLayout(editableChild(numberOfChildren() - 1)); + cursor->performBackspace(); + return; + } ExpressionLayout::backspaceAtCursor(cursor); } @@ -89,18 +122,17 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex // new layout then destroy it. if (newChild->isHorizontal()) { int indexForInsertion = indexOfChild(oldChild); + if (cursor != nullptr) { + if (oldChildIndex == numberOfChildren() - 1) { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } else { + cursor->setPointedExpressionLayout(editableChild(oldChildIndex + 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + } + } mergeChildrenAtIndex(static_cast(newChild), indexForInsertion + 1, true); removeChildAtIndex(indexForInsertion, deleteOldChild); - if (cursor == nullptr) { - return; - } - if (oldChildIndex == 0) { - cursor->setPointedExpressionLayout(this); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return; - } - cursor->setPointedExpressionLayout(editableChild(oldChildIndex -1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); return; } // Else, just replace the child. diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 3ce10c2d1..80011c669 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -27,28 +27,15 @@ ExpressionLayout * IntegralLayout::clone() const { } void IntegralLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // Case: Left the upper bound, lower bound or argument. - // Delete the integral, keep the integrand. - if (cursor->position() == ExpressionLayoutCursor::Position::Left - && ((upperBoundLayout() - && cursor->pointedExpressionLayout() == upperBoundLayout()) - || (lowerBoundLayout() - && cursor->pointedExpressionLayout() == lowerBoundLayout()) - || cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Left))) + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) { + // Case: Right. + // Delete the layout, keep the integrand. replaceWithAndMoveCursor(integrandLayout(), true, cursor); return; } - // If the cursor is on the right, move to the integrand. - assert(cursor->pointedExpressionLayout() == this); - if (cursor->position() == ExpressionLayoutCursor::Position::Right) { - cursor->setPointedExpressionLayout(integrandLayout()); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; - } - if (m_parent) { - return m_parent->backspaceAtCursor(cursor); - } + ExpressionLayout::backspaceAtCursor(cursor); } bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index 7626efa06..ff18958fc 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -119,7 +119,6 @@ void MatrixLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, void MatrixLayout::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { assert(index >= 0 && index < numberOfChildren()); - assert(cursor->pointedExpressionLayout() == child(index)); replaceChildAndMoveCursor(child(index), new EmptyVisibleLayout(), deleteAfterRemoval, cursor); } diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index d2df334fe..77e4516ab 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -26,36 +26,15 @@ ExpressionLayout * NthRootLayout::clone() const { } void NthRootLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // Case: Left the index. - // Move Left. - if (indexLayout() - && cursor->position() == ExpressionLayoutCursor::Position::Left - && cursor->pointedExpressionLayout() == indexLayout()) - { - cursor->setPointedExpressionLayout(this); - return; - } - // Case: Left the radicand. - // Delete the root, keep the radicand. - if (cursor->position() == ExpressionLayoutCursor::Position::Left - && cursor->pointedExpressionLayout() == radicandLayout()) + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) { + // Case: Right. + // Delete the layout, keep the operand. replaceWithAndMoveCursor(radicandLayout(), true, cursor); return; } - // Case: Right. - // Move to the radicand. - assert(cursor->pointedExpressionLayout() == this); - if (cursor->position() ==ExpressionLayoutCursor::Position::Right) { - cursor->setPointedExpressionLayout(radicandLayout()); - return; - } - // Case: Left. - // Ask the parent. - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - if (m_parent) { - return m_parent->backspaceAtCursor(cursor); - } + ExpressionLayout::backspaceAtCursor(cursor); } bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index da31a3400..8e871c118 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -14,30 +14,15 @@ SequenceLayout::SequenceLayout(ExpressionLayout * argument, ExpressionLayout * l } void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { - // Case: Left of the bounds or of the argument. - // Delete the sequence, keep the argument. - if (cursor->position() == ExpressionLayoutCursor::Position::Left - && ((lowerBoundLayout() - && cursor->pointedExpressionLayout() == lowerBoundLayout()) - || (upperBoundLayout() - && cursor->pointedExpressionLayout() == upperBoundLayout()) - || cursor->pointedExpressionLayout() == argumentLayout())) - { - replaceWithAndMoveCursor(argumentLayout(), true, cursor); - return; - } - // Case: Right. - // Move inside the argument. if (cursor->pointedExpressionLayout() == this && cursor->position() == ExpressionLayoutCursor::Position::Right) { - cursor->setPointedExpressionLayout(argumentLayout()); + // Case: Right. + // Delete the layout, keep the operand. + replaceWithAndMoveCursor(argumentLayout(), true, cursor); return; } - // Case: Left. - // Ask the parent. - assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - m_parent->backspaceAtCursor(cursor); + ExpressionLayout::backspaceAtCursor(cursor); } bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp index 003ba0452..2da4b08b3 100644 --- a/poincare/src/layout/vertical_offset_layout.cpp +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -44,6 +44,14 @@ void VerticalOffsetLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { cursor->setPosition(ExpressionLayoutCursor::Position::Left); return; } + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + // Case: Right. + // Move to the indice. + cursor->setPointedExpressionLayout(indiceLayout()); + return; + } ExpressionLayout::backspaceAtCursor(cursor); } From 1e8935fc2e5a1b351f76a95f2b7b0e8f9211344e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 16:54:02 +0100 Subject: [PATCH 158/257] [poincare] Use MatrixLayout in Expression::Matrix::privateCreateLayout. Change-Id: I60a4212dd5206a8372f4355b9ff1287577428d1b --- poincare/src/matrix.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/poincare/src/matrix.cpp b/poincare/src/matrix.cpp index 09bcb7908..d8f9a8824 100644 --- a/poincare/src/matrix.cpp +++ b/poincare/src/matrix.cpp @@ -7,8 +7,7 @@ extern "C" { #include #include #include -#include "layout/grid_layout.h" -#include "layout/bracket_layout.h" +#include "layout/matrix_layout.h" #include #include #include @@ -102,7 +101,7 @@ ExpressionLayout * Matrix::privateCreateLayout(FloatDisplayMode floatDisplayMode for (int i = 0; i < numberOfOperands(); i++) { childrenLayouts[i] = operand(i)->createLayout(floatDisplayMode, complexFormat); } - ExpressionLayout * layout = new BracketLayout(new GridLayout(childrenLayouts, numberOfRows(), numberOfColumns(), false), false); + ExpressionLayout * layout = new MatrixLayout(childrenLayouts, numberOfRows(), numberOfColumns(), false); delete [] childrenLayouts; return layout; } From 735d79a0fcd04d90e73557103f25ea6a806cd3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 17:50:45 +0100 Subject: [PATCH 159/257] [apps/settings] Use the new layouts in the Settings app. Change-Id: Ic90a78cf58cac28f24b65c5e0c1776c61675bb98 --- apps/settings/Makefile | 1 + apps/settings/helpers.cpp | 27 +++++++++++++++++++++++++++ apps/settings/helpers.h | 15 +++++++++++++++ apps/settings/main_controller.cpp | 11 +++-------- apps/settings/sub_controller.cpp | 10 +++------- 5 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 apps/settings/helpers.cpp create mode 100644 apps/settings/helpers.h diff --git a/apps/settings/Makefile b/apps/settings/Makefile index ac039b8e7..9078f0463 100644 --- a/apps/settings/Makefile +++ b/apps/settings/Makefile @@ -3,6 +3,7 @@ snapshot_headers += apps/settings/app.h app_objs += $(addprefix apps/settings/,\ app.o\ + helpers.o\ language_controller.o\ main_controller.o\ settings_message_tree.o\ diff --git a/apps/settings/helpers.cpp b/apps/settings/helpers.cpp new file mode 100644 index 000000000..2581a0a4c --- /dev/null +++ b/apps/settings/helpers.cpp @@ -0,0 +1,27 @@ +#include "helpers.h" +#include +#include +#include "../../poincare/src/layout/horizontal_layout.h" +#include "../../poincare/src/layout/vertical_offset_layout.h" + +using namespace Poincare; + +namespace Settings { +namespace Helpers { + +ExpressionLayout * CartesianComplexFormat(KDText::FontSize fontSize) { + const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '}; + return LayoutEngine::createStringLayout(text, sizeof(text), fontSize); +} + +ExpressionLayout * PolarComplexFormat(KDText::FontSize fontSize) { + const char base[] = {'r', Ion::Charset::Exponential}; + const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '}; + return new HorizontalLayout( + LayoutEngine::createStringLayout(base, sizeof(base), fontSize), + new VerticalOffsetLayout(LayoutEngine::createStringLayout(superscript, sizeof(superscript), fontSize), VerticalOffsetLayout::Type::Superscript, false), + false); +} + +} +} diff --git a/apps/settings/helpers.h b/apps/settings/helpers.h new file mode 100644 index 000000000..01dacd0ba --- /dev/null +++ b/apps/settings/helpers.h @@ -0,0 +1,15 @@ +#ifndef SETTINGS_HELPERS_H +#define SETTINGS_HELPERS_H + +#include + +namespace Settings { +namespace Helpers { + +Poincare::ExpressionLayout * CartesianComplexFormat(KDText::FontSize fontSize); +Poincare::ExpressionLayout * PolarComplexFormat(KDText::FontSize fontSize); + +} +} + +#endif diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 32a0f7c80..37c1fb4f6 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -1,10 +1,8 @@ #include "main_controller.h" +#include "helpers.h" #include "../global_preferences.h" #include "../i18n.h" -#include "../../poincare/src/layout/baseline_relative_layout.h" -#include "../../poincare/src/layout/string_layout.h" #include -#include using namespace Poincare; @@ -175,12 +173,9 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { m_complexFormatLayout = nullptr; } if (Preferences::sharedPreferences()->complexFormat() == Expression::ComplexFormat::Cartesian) { - const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '}; - m_complexFormatLayout = new StringLayout(text, sizeof(text), KDText::FontSize::Small); + m_complexFormatLayout = Helpers::CartesianComplexFormat(KDText::FontSize::Small); } else { - const char base[] = {'r', Ion::Charset::Exponential}; - const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '}; - m_complexFormatLayout = new BaselineRelativeLayout(new StringLayout(base, sizeof(base), KDText::FontSize::Small), new StringLayout(superscript, sizeof(superscript), KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript); + m_complexFormatLayout = Helpers::PolarComplexFormat(KDText::FontSize::Small); } MessageTableCellWithChevronAndExpression * myExpCell = (MessageTableCellWithChevronAndExpression *)cell; myExpCell->setExpressionLayout(m_complexFormatLayout); diff --git a/apps/settings/sub_controller.cpp b/apps/settings/sub_controller.cpp index 6d5b8ec4e..eacaededa 100644 --- a/apps/settings/sub_controller.cpp +++ b/apps/settings/sub_controller.cpp @@ -1,8 +1,7 @@ #include "sub_controller.h" +#include "helpers.h" #include "../global_preferences.h" #include "../apps_container.h" -#include "../../poincare/src/layout/baseline_relative_layout.h" -#include "../../poincare/src/layout/string_layout.h" #include #include @@ -22,11 +21,8 @@ SubController::SubController(Responder * parentResponder) : m_cells[i].setAccessoryFontSize(KDText::FontSize::Small); m_cells[i].setAccessoryTextColor(Palette::GreyDark); } - const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '}; - m_complexFormatLayout[0] = new StringLayout(text, sizeof(text)); - const char base[] = {'r', Ion::Charset::Exponential}; - const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '}; - m_complexFormatLayout[1] = new BaselineRelativeLayout(new StringLayout(base, sizeof(base)), new StringLayout(superscript, sizeof(superscript)), BaselineRelativeLayout::Type::Superscript); + m_complexFormatLayout[0] = Helpers::CartesianComplexFormat(KDText::FontSize::Large); + m_complexFormatLayout[1] = Helpers::PolarComplexFormat(KDText::FontSize::Large); for (int i = 0; i < 2; i++) { m_complexFormatCells[i].setExpressionLayout(m_complexFormatLayout[i]); } From b7c0a15eb8ef336bad0841fb55c2011edd5f02b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 11 Jan 2018 18:11:44 +0100 Subject: [PATCH 160/257] [apps/regression] Use the new layouts in the Regression app. Change-Id: I3813ed42c35d92e98f6d162ac3788a238f2f836e --- apps/regression/calculation_controller.cpp | 7 ++++--- apps/regression/store_controller.cpp | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/regression/calculation_controller.cpp b/apps/regression/calculation_controller.cpp index 1a937c6ea..6201d910e 100644 --- a/apps/regression/calculation_controller.cpp +++ b/apps/regression/calculation_controller.cpp @@ -1,8 +1,9 @@ #include "calculation_controller.h" #include "../constant.h" #include "../apps_container.h" -#include "../../poincare/src/layout/baseline_relative_layout.h" -#include "../../poincare/src/layout/string_layout.h" +#include "../../poincare/src/layout/char_layout.h" +#include "../../poincare/src/layout/horizontal_layout.h" +#include "../../poincare/src/layout/vertical_offset_layout.h" #include #include @@ -21,7 +22,7 @@ CalculationController::CalculationController(Responder * parentResponder, Button m_calculationCells{}, m_store(store) { - m_r2Layout = new BaselineRelativeLayout(new StringLayout("r", 1, KDText::FontSize::Small), new StringLayout("2", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript); + m_r2Layout = new HorizontalLayout(new CharLayout('r', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('2', KDText::FontSize::Small), VerticalOffsetLayout::Type::Superscript, false), false); } CalculationController::~CalculationController() { diff --git a/apps/regression/store_controller.cpp b/apps/regression/store_controller.cpp index 59617a330..e08bb358d 100644 --- a/apps/regression/store_controller.cpp +++ b/apps/regression/store_controller.cpp @@ -2,8 +2,9 @@ #include "app.h" #include "../apps_container.h" #include "../constant.h" -#include "../../poincare/src/layout/baseline_relative_layout.h" -#include "../../poincare/src/layout/string_layout.h" +#include "../../poincare/src/layout/char_layout.h" +#include "../../poincare/src/layout/horizontal_layout.h" +#include "../../poincare/src/layout/vertical_offset_layout.h" #include using namespace Poincare; @@ -15,8 +16,8 @@ StoreController::StoreController(Responder * parentResponder, Store * store, But Shared::StoreController(parentResponder, store, header), m_titleCells{} { - m_titleLayout[0] = new BaselineRelativeLayout(new StringLayout("X", 1, KDText::FontSize::Small), new StringLayout("i", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - m_titleLayout[1] = new BaselineRelativeLayout(new StringLayout("Y", 1, KDText::FontSize::Small), new StringLayout("i", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_titleLayout[0] = new HorizontalLayout(new CharLayout('X', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('i', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), false); + m_titleLayout[1] = new HorizontalLayout(new CharLayout('Y', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('i', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), false); } StoreController::~StoreController() { From a435c548dabd97b7a9d64cc6a42fa252dd9ef6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 12 Jan 2018 11:09:12 +0100 Subject: [PATCH 161/257] [apps/sequence] Use the new layouts in the Sequence app. Change-Id: I8b079bfabccd54472e0ba0fac17b87dbaf3678ee --- apps/Makefile | 2 +- apps/sequence/graph/term_sum_controller.cpp | 36 ++++++++++------ apps/sequence/list/sequence_toolbox.cpp | 40 +++++++++--------- .../list/type_parameter_controller.cpp | 11 +++-- apps/sequence/sequence.cpp | 42 ++++++++++++------- 5 files changed, 82 insertions(+), 49 deletions(-) diff --git a/apps/Makefile b/apps/Makefile index 9c3ecf405..16482bc60 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,5 +1,5 @@ EPSILON_I18N_LANGUAGES ?= en fr es de pt -EPSILON_APPS ?= expression_editor +EPSILON_APPS ?= expression_editor sequence settings statistics probability regression code include apps/shared/Makefile include apps/home/Makefile diff --git a/apps/sequence/graph/term_sum_controller.cpp b/apps/sequence/graph/term_sum_controller.cpp index cc136bd87..0681afad1 100644 --- a/apps/sequence/graph/term_sum_controller.cpp +++ b/apps/sequence/graph/term_sum_controller.cpp @@ -1,9 +1,10 @@ #include "term_sum_controller.h" #include "../../shared/text_field_delegate.h" -#include "../../../poincare/src/layout/baseline_relative_layout.h" +#include "../../../poincare/src/layout/char_layout.h" #include "../../../poincare/src/layout/condensed_sum_layout.h" -#include "../../../poincare/src/layout/string_layout.h" #include "../../../poincare/src/layout/horizontal_layout.h" +#include "../../../poincare/src/layout/vertical_offset_layout.h" +#include #include #include @@ -197,12 +198,16 @@ void TermSumController::LegendView::setSumSubscript(float start) { delete m_sumLayout; m_sumLayout = nullptr; } - const char sigma[] = {' ',Ion::Charset::CapitalSigma}; + const char sigma[] = {' ', Ion::Charset::CapitalSigma}; char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; Complex::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); - m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr); - m_sum.setExpressionLayout(m_sumLayout); - m_sum.setAlignment(0.0f, 0.5f); + m_sumLayout = new CondensedSumLayout( + LayoutEngine::createStringLayout(sigma, sizeof(sigma), KDText::FontSize::Large), + LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), + nullptr, + false); + m_sum.setExpressionLayout(m_sumLayout); + m_sum.setAlignment(0.0f, 0.5f); } void TermSumController::LegendView::setSumSuperscript(float start, float end) { @@ -215,20 +220,27 @@ void TermSumController::LegendView::setSumSuperscript(float start, float end) { Complex::convertFloatToText(start, bufferStart, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); char bufferEnd[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; Complex::convertFloatToText(end, bufferEnd, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); - m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), new StringLayout(bufferStart, strlen(bufferStart), KDText::FontSize::Small), new StringLayout(bufferEnd, strlen(bufferEnd), KDText::FontSize::Small)); + m_sumLayout = new CondensedSumLayout( + LayoutEngine::createStringLayout(sigma, sizeof(sigma), KDText::FontSize::Large), + LayoutEngine::createStringLayout(bufferStart, strlen(bufferStart), KDText::FontSize::Small), + LayoutEngine::createStringLayout(bufferEnd, strlen(bufferEnd), KDText::FontSize::Small), + false); m_sum.setExpressionLayout(m_sumLayout); m_sum.setAlignment(0.0f, 0.5f); } void TermSumController::LegendView::setSumResult(const char * sequenceName, double result) { - ExpressionLayout * childrenLayouts[3]; char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; strlcpy(buffer, "= ", 3); Complex::convertFloatToText(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - childrenLayouts[2] = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small); - childrenLayouts[1] = new BaselineRelativeLayout(new StringLayout(sequenceName, 1, KDText::FontSize::Small), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - childrenLayouts[0] = m_sumLayout; - m_sumLayout = new HorizontalLayout(childrenLayouts, 3); + m_sumLayout = new HorizontalLayout( + m_sumLayout, + new HorizontalLayout( + new CharLayout(sequenceName[0], KDText::FontSize::Small), + new VerticalOffsetLayout(new CharLayout('n', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false), + LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), + false); m_sum.setExpressionLayout(m_sumLayout); m_sum.setAlignment(0.5f, 0.5f); } diff --git a/apps/sequence/list/sequence_toolbox.cpp b/apps/sequence/list/sequence_toolbox.cpp index ed5a3f49b..fddc7d061 100644 --- a/apps/sequence/list/sequence_toolbox.cpp +++ b/apps/sequence/list/sequence_toolbox.cpp @@ -1,7 +1,9 @@ #include "sequence_toolbox.h" #include "../sequence_store.h" -#include "../../../poincare/src/layout/baseline_relative_layout.h" -#include "../../../poincare/src/layout/string_layout.h" +#include "../../../poincare/src/layout/char_layout.h" +#include "../../../poincare/src/layout/horizontal_layout.h" +#include "../../../poincare/src/layout/vertical_offset_layout.h" +#include #include using namespace Poincare; @@ -91,30 +93,30 @@ void SequenceToolbox::setExtraCells(const char * sequenceName, int recurrenceDep const char * otherSequenceName = SequenceStore::k_sequenceNames[1-sequenceIndex]; for (int j = 0; j < recurrenceDepth; j++) { const char * indice = j == 0 ? "n" : "n+1"; - m_addedCellLayout[j] = new BaselineRelativeLayout(new StringLayout(sequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - m_addedCellLayout[j+recurrenceDepth] = new BaselineRelativeLayout(new StringLayout(otherSequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_addedCellLayout[j] = new HorizontalLayout( + new CharLayout(sequenceName[0], KDText::FontSize::Large), + new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); + m_addedCellLayout[j+recurrenceDepth] = new HorizontalLayout( + new CharLayout(otherSequenceName[0], KDText::FontSize::Large), + new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); } if (recurrenceDepth < 2) { const char * indice = recurrenceDepth == 0 ? "n" : (recurrenceDepth == 1 ? "n+1" : "n+2"); - m_addedCellLayout[2*recurrenceDepth] = new BaselineRelativeLayout(new StringLayout(otherSequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_addedCellLayout[2*recurrenceDepth] = new HorizontalLayout( + new CharLayout(otherSequenceName[0], KDText::FontSize::Large), + new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); } } bool SequenceToolbox::selectAddedCell(int selectedRow){ - char buffer[10]; - BaselineRelativeLayout * layout = (BaselineRelativeLayout *)m_addedCellLayout[selectedRow]; - StringLayout * nameLayout = (StringLayout *)layout->baseLayout(); - StringLayout * subscriptLayout = (StringLayout *)layout->indiceLayout(); - int currentChar = 0; - strlcpy(buffer, nameLayout->text(), strlen(nameLayout->text())+1); - currentChar += strlen(nameLayout->text()); - buffer[currentChar++] = '('; - strlcpy(buffer+currentChar, subscriptLayout->text(), strlen(subscriptLayout->text())+1); - currentChar += strlen(subscriptLayout->text()); - buffer[currentChar++] = ')'; - buffer[currentChar] = 0; - sender()->insertTextAtLocation(buffer, sender()->cursorLocation()); - sender()->setCursorLocation(sender()->cursorLocation()+currentChar); + int bufferSize = 10; + char buffer[bufferSize]; + int currentChar = m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize); + textFieldSender()->insertTextAtLocation(buffer, textFieldSender()->cursorLocation()); + textFieldSender()->setCursorLocation(textFieldSender()->cursorLocation()+currentChar); app()->dismissModalViewController(); return true; } diff --git a/apps/sequence/list/type_parameter_controller.cpp b/apps/sequence/list/type_parameter_controller.cpp index 037aaa98f..4c0bf513c 100644 --- a/apps/sequence/list/type_parameter_controller.cpp +++ b/apps/sequence/list/type_parameter_controller.cpp @@ -2,8 +2,10 @@ #include "list_controller.h" #include "../app.h" #include -#include "../../../poincare/src/layout/baseline_relative_layout.h" -#include "../../../poincare/src/layout/string_layout.h" +#include +#include "../../../poincare/src/layout/char_layout.h" +#include "../../../poincare/src/layout/horizontal_layout.h" +#include "../../../poincare/src/layout/vertical_offset_layout.h" using namespace Poincare; @@ -120,7 +122,10 @@ void TypeParameterController::willDisplayCellAtLocation(HighlightCell * cell, in delete m_expressionLayouts[j]; m_expressionLayouts[j] = nullptr; } - m_expressionLayouts[j] = new BaselineRelativeLayout(new StringLayout(nextName, 1, size), new StringLayout(subscripts[j], strlen(subscripts[j]), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_expressionLayouts[j] = new HorizontalLayout( + new CharLayout(nextName[0], size), + new VerticalOffsetLayout(LayoutEngine::createStringLayout(subscripts[j], strlen(subscripts[j]), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); ExpressionTableCellWithPointer * myCell = (ExpressionTableCellWithPointer *)cell; myCell->setExpressionLayout(m_expressionLayouts[j]); } diff --git a/apps/sequence/sequence.cpp b/apps/sequence/sequence.cpp index 6658dbc0a..a7c204d59 100644 --- a/apps/sequence/sequence.cpp +++ b/apps/sequence/sequence.cpp @@ -1,8 +1,10 @@ #include "sequence.h" #include "sequence_store.h" #include "cache_context.h" -#include "../../poincare/src/layout/string_layout.h" -#include "../../poincare/src/layout/baseline_relative_layout.h" +#include +#include "../../poincare/src/layout/char_layout.h" +#include "../../poincare/src/layout/horizontal_layout.h" +#include "../../poincare/src/layout/vertical_offset_layout.h" #include #include @@ -227,7 +229,10 @@ int Sequence::numberOfElements() { Poincare::ExpressionLayout * Sequence::nameLayout() { if (m_nameLayout == nullptr) { - m_nameLayout = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_nameLayout = new HorizontalLayout( + new CharLayout(name()[0], KDText::FontSize::Large), + new VerticalOffsetLayout(new CharLayout('n', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); } return m_nameLayout; } @@ -235,13 +240,22 @@ Poincare::ExpressionLayout * Sequence::nameLayout() { Poincare::ExpressionLayout * Sequence::definitionName() { if (m_definitionName == nullptr) { if (m_type == Type::Explicit) { - m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n ", 2, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_definitionName = new HorizontalLayout( + new CharLayout(name()[0], KDText::FontSize::Large), + new VerticalOffsetLayout(LayoutEngine::createStringLayout("n ", 2, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); } if (m_type == Type::SingleRecurrence) { - m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+1 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_definitionName = new HorizontalLayout( + new CharLayout(name()[0], KDText::FontSize::Large), + new VerticalOffsetLayout(LayoutEngine::createStringLayout("n+1 ", 4, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); } if (m_type == Type::DoubleRecurrence) { - m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+2 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + m_definitionName = new HorizontalLayout( + new CharLayout(name()[0], KDText::FontSize::Large), + new VerticalOffsetLayout(LayoutEngine::createStringLayout("n+2 ", 4, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); } } return m_definitionName; @@ -251,12 +265,10 @@ Poincare::ExpressionLayout * Sequence::firstInitialConditionName() { char buffer[k_initialRankNumberOfDigits+1]; Integer(m_initialRank).writeTextInBuffer(buffer, k_initialRankNumberOfDigits+1); if (m_firstInitialConditionName == nullptr) { - if (m_type == Type::SingleRecurrence) { - m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - } - if (m_type == Type::DoubleRecurrence) { - m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - } + m_firstInitialConditionName = new HorizontalLayout( + new CharLayout(name()[0], KDText::FontSize::Small), + new VerticalOffsetLayout(new CharLayout('0', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); } return m_firstInitialConditionName; } @@ -266,8 +278,10 @@ Poincare::ExpressionLayout * Sequence::secondInitialConditionName() { Integer(m_initialRank+1).writeTextInBuffer(buffer, k_initialRankNumberOfDigits+1); if (m_secondInitialConditionName == nullptr) { if (m_type == Type::DoubleRecurrence) { - m_secondInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); - + m_secondInitialConditionName = new HorizontalLayout( + new CharLayout(name()[0], KDText::FontSize::Small), + new VerticalOffsetLayout(new CharLayout('1', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + false); } } return m_secondInitialConditionName; From 2ed72127cb3093e00e3541fc4f5e886e1d731b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 12 Jan 2018 11:52:04 +0100 Subject: [PATCH 162/257] [poincare] Remove dangerous default arguments in poincare. Change-Id: I76f2bc057d73c7d151aed62b66eb69a91082910c --- .../include/poincare/bounded_static_layout_hierarchy.h | 6 +++--- poincare/include/poincare/dynamic_layout_hierarchy.h | 8 ++++---- poincare/include/poincare/expression_layout.h | 4 ++-- poincare/include/poincare/static_layout_hierarchy.h | 8 ++++---- poincare/src/expression_layout_cursor.cpp | 4 ++-- poincare/src/layout/horizontal_layout.h | 2 +- poincare/src/layout/matrix_layout.h | 2 +- poincare/src/layout/sequence_layout.cpp | 5 ----- poincare/src/layout/sequence_layout.h | 2 +- 9 files changed, 18 insertions(+), 23 deletions(-) diff --git a/poincare/include/poincare/bounded_static_layout_hierarchy.h b/poincare/include/poincare/bounded_static_layout_hierarchy.h index 42a0acc6b..a54036037 100644 --- a/poincare/include/poincare/bounded_static_layout_hierarchy.h +++ b/poincare/include/poincare/bounded_static_layout_hierarchy.h @@ -9,9 +9,9 @@ template class BoundedStaticLayoutHierarchy : public StaticLayoutHierarchy { public: BoundedStaticLayoutHierarchy(); - BoundedStaticLayoutHierarchy(const ExpressionLayout * expressionLayout, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<2> - BoundedStaticLayoutHierarchy(const ExpressionLayout * expressionLayout1, const ExpressionLayout * expressionLayout2, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<2> - BoundedStaticLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands = true); + BoundedStaticLayoutHierarchy(const ExpressionLayout * expressionLayout, bool cloneOperands); // Specialized constructor for StaticLayoutHierarchy<2> + BoundedStaticLayoutHierarchy(const ExpressionLayout * expressionLayout1, const ExpressionLayout * expressionLayout2, bool cloneOperands); // Specialized constructor for StaticLayoutHierarchy<2> + BoundedStaticLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands); int numberOfChildren() const override { return m_numberOfChildren; } private: int m_numberOfChildren; diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index 63518b122..499f09cef 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -9,12 +9,12 @@ namespace Poincare { class DynamicLayoutHierarchy : public ExpressionLayout { public: DynamicLayoutHierarchy(); - DynamicLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands = true); - DynamicLayoutHierarchy(const ExpressionLayout * operand, bool cloneOperands = true) : + DynamicLayoutHierarchy(const ExpressionLayout * const * operands, int numberOfOperands, bool cloneOperands); + DynamicLayoutHierarchy(const ExpressionLayout * operand, bool cloneOperands) : DynamicLayoutHierarchy(ExpressionLayoutArray(operand).array(), 1, cloneOperands) {} - DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, bool cloneOperands = true) : + DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, bool cloneOperands) : DynamicLayoutHierarchy(ExpressionLayoutArray(operand1, operand2).array(), 2, cloneOperands) {} - DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, const ExpressionLayout * operand3, bool cloneOperands = true) : + DynamicLayoutHierarchy(const ExpressionLayout * operand1, const ExpressionLayout * operand2, const ExpressionLayout * operand3, bool cloneOperands) : DynamicLayoutHierarchy(ExpressionLayoutArray(operand1, operand2, operand3).array(), 3, cloneOperands) {} ~DynamicLayoutHierarchy(); DynamicLayoutHierarchy(const DynamicLayoutHierarchy & other) = delete; diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index e495c397c..3cfd319a6 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -53,9 +53,9 @@ public: virtual void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); // Replace - virtual ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace = true); + virtual ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace); ExpressionLayout * replaceWithAndMoveCursor(ExpressionLayout * newChild, bool deleteAfterReplace, ExpressionLayoutCursor * cursor); - virtual void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true); + virtual void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild); virtual void replaceChildAndMoveCursor( const ExpressionLayout * oldChild, ExpressionLayout * newChild, diff --git a/poincare/include/poincare/static_layout_hierarchy.h b/poincare/include/poincare/static_layout_hierarchy.h index daf4bbc2c..57a31821a 100644 --- a/poincare/include/poincare/static_layout_hierarchy.h +++ b/poincare/include/poincare/static_layout_hierarchy.h @@ -9,10 +9,10 @@ template class StaticLayoutHierarchy : public ExpressionLayout { public: StaticLayoutHierarchy(); - StaticLayoutHierarchy(const ExpressionLayout * const * operands, bool cloneOperands = true); - StaticLayoutHierarchy(const ExpressionLayout * expression, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<1> - StaticLayoutHierarchy(const ExpressionLayout * expression1, const ExpressionLayout * expression2, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<2> - StaticLayoutHierarchy(const ExpressionLayout * expression1, const ExpressionLayout * expression2, const ExpressionLayout * expression3, bool cloneOperands = true); // Specialized constructor for StaticLayoutHierarchy<3> + StaticLayoutHierarchy(const ExpressionLayout * const * operands, bool cloneOperands); + StaticLayoutHierarchy(const ExpressionLayout * expression, bool cloneOperands); // Specialized constructor for StaticLayoutHierarchy<1> + StaticLayoutHierarchy(const ExpressionLayout * expression1, const ExpressionLayout * expression2, bool cloneOperands); // Specialized constructor for StaticLayoutHierarchy<2> + StaticLayoutHierarchy(const ExpressionLayout * expression1, const ExpressionLayout * expression2, const ExpressionLayout * expression3, bool cloneOperands); // Specialized constructor for StaticLayoutHierarchy<3> ~StaticLayoutHierarchy(); StaticLayoutHierarchy(const StaticLayoutHierarchy & other) = delete; StaticLayoutHierarchy(StaticLayoutHierarchy && other) = delete; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 3f89545d9..31ecfeb00 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -57,8 +57,8 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyExponentialLayout() { ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers() { // Add a new FractionLayout - HorizontalLayout * child1 = new HorizontalLayout(new EmptyVisibleLayout()); - HorizontalLayout * child2 = new HorizontalLayout(new EmptyVisibleLayout()); + HorizontalLayout * child1 = new HorizontalLayout(new EmptyVisibleLayout(), false); + HorizontalLayout * child2 = new HorizontalLayout(new EmptyVisibleLayout(), false); FractionLayout * newChild = new FractionLayout(child1, child2, false); pointedExpressionLayout()->addBrother(this, newChild); diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index a8e932797..8516fa977 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -17,7 +17,7 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; /* Hierarchy */ - void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; + void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) override; void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; void addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren); diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 30dccb142..b931bb51b 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -17,7 +17,7 @@ public: bool moveDownInside(ExpressionLayoutCursor * cursor) override; /* Dynamic layout */ - void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild = true) override; + void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) override; void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 8e871c118..b9a91e85b 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -8,11 +8,6 @@ namespace Poincare { -SequenceLayout::SequenceLayout(ExpressionLayout * argument, ExpressionLayout * lowerBound, ExpressionLayout * upperBound, bool cloneOperands) : - StaticLayoutHierarchy(argument, lowerBound, upperBound) -{ -} - void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { if (cursor->pointedExpressionLayout() == this && cursor->position() == ExpressionLayoutCursor::Position::Right) diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 8969398ce..ef92f3f68 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -7,9 +7,9 @@ namespace Poincare { class SequenceLayout : public StaticLayoutHierarchy<3> { public: + using StaticLayoutHierarchy::StaticLayoutHierarchy; constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; - SequenceLayout(ExpressionLayout * argument, ExpressionLayout * lowerBound, ExpressionLayout * upperBound, bool cloneOperands); void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor) override; bool moveRight(ExpressionLayoutCursor * cursor) override; From f6a0a9235f5f221c975fc2a566eb691f15053271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 12 Jan 2018 14:55:25 +0100 Subject: [PATCH 163/257] [apps] Makefile. Enable all the apps. Change-Id: I50d93217a5ae657cccfed285a255ed470e619bf7 --- apps/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/Makefile b/apps/Makefile index 16482bc60..60e285088 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,5 +1,5 @@ EPSILON_I18N_LANGUAGES ?= en fr es de pt -EPSILON_APPS ?= expression_editor sequence settings statistics probability regression code +EPSILON_APPS ?= expression_editor calculation graph sequence settings statistics probability regression code include apps/shared/Makefile include apps/home/Makefile From 5ff32b8162d2926e5a3aac78d805f36543aadda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 12 Jan 2018 16:13:11 +0100 Subject: [PATCH 164/257] [expression_editor] Controller::handleAddEvent returns void. Change-Id: Iaac5fd3d0798f5c2e81d3c982198f402534f6dfe --- apps/expression_editor/controller.cpp | 37 +++++++++++------- apps/expression_editor/controller.h | 2 +- .../poincare/expression_layout_cursor.h | 18 ++++----- poincare/src/expression_layout_cursor.cpp | 39 +++++++------------ 4 files changed, 47 insertions(+), 49 deletions(-) diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp index cdce47736..69ca7ac66 100644 --- a/apps/expression_editor/controller.cpp +++ b/apps/expression_editor/controller.cpp @@ -66,8 +66,7 @@ bool Controller::privateHandleEvent(Ion::Events::Event event) { m_view.layoutSubviews(); return true; } - ExpressionLayout * newPointedLayout = handleAddEvent(event); - if (newPointedLayout != nullptr) { + if (handleAddEvent(event)) { m_expressionLayout->invalidAllSizesPositionsAndBaselines(); m_view.layoutSubviews(); return true; @@ -107,42 +106,52 @@ bool Controller::handleMoveEvent(Ion::Events::Event event) { return false; } -ExpressionLayout * Controller::handleAddEvent(Ion::Events::Event event) { +bool Controller::handleAddEvent(Ion::Events::Event event) { if (event == Ion::Events::Division) { - return m_cursor.addFractionLayoutAndCollapseBrothers(); + m_cursor.addFractionLayoutAndCollapseBrothers(); + return true; } if (event == Ion::Events::XNT) { - return m_cursor.addXNTCharLayout(); + m_cursor.addXNTCharLayout(); + return true; } if (event == Ion::Events::Exp) { - return m_cursor.addEmptyExponentialLayout(); + m_cursor.addEmptyExponentialLayout(); + return true; } if (event == Ion::Events::Log) { - return m_cursor.addEmptyLogarithmLayout(); + m_cursor.addEmptyLogarithmLayout(); + return true; } if (event == Ion::Events::Power) { - return m_cursor.addEmptyPowerLayout(); + m_cursor.addEmptyPowerLayout(); + return true; } if (event == Ion::Events::Sqrt) { - return m_cursor.addEmptySquareRootLayout(); + m_cursor.addEmptySquareRootLayout(); + return true; } if (event == Ion::Events::Square) { - return m_cursor.addEmptySquarePowerLayout(); + m_cursor.addEmptySquarePowerLayout(); + return true; } if (event.hasText()) { const char * textToInsert = event.text(); if (textToInsert[1] == 0) { if (textToInsert[0] == Ion::Charset::MultiplicationSign) { const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; - return m_cursor.insertText(middleDotString); + m_cursor.insertText(middleDotString); + return true; } if (textToInsert[0] == '[' || textToInsert[0] == ']') { - return m_cursor.addEmptyMatrixLayout(); + m_cursor.addEmptyMatrixLayout(); + return true; } } - return m_cursor.insertText(textToInsert); + m_cursor.insertText(textToInsert); + return true; } - return nullptr; + return false; } bool Controller::handleDeleteEvent(Ion::Events::Event event) { diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h index 5a02edd17..546d00680 100644 --- a/apps/expression_editor/controller.h +++ b/apps/expression_editor/controller.h @@ -27,7 +27,7 @@ public: private: bool privateHandleEvent(Ion::Events::Event event); bool handleMoveEvent(Ion::Events::Event event); - Poincare::ExpressionLayout * handleAddEvent(Ion::Events::Event event); + bool handleAddEvent(Ion::Events::Event event); bool handleDeleteEvent(Ion::Events::Event event); void serializeLayout(); void computeResult(); diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index a4f5dbb85..3a444399f 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -40,15 +40,15 @@ public: /* Edition */ void addLayout(ExpressionLayout * layout); - ExpressionLayout * addEmptyExponentialLayout(); - ExpressionLayout * addFractionLayoutAndCollapseBrothers(); - ExpressionLayout * addEmptyLogarithmLayout(); - ExpressionLayout * addEmptyMatrixLayout(int numberOfRows = 1, int numberOfColumns = 1); - ExpressionLayout * addEmptyPowerLayout(); - ExpressionLayout * addEmptySquareRootLayout(); - ExpressionLayout * addEmptySquarePowerLayout(); - ExpressionLayout * addXNTCharLayout(); - ExpressionLayout * insertText(const char * text); + void addEmptyExponentialLayout(); + void addFractionLayoutAndCollapseBrothers(); + void addEmptyLogarithmLayout(); + void addEmptyMatrixLayout(int numberOfRows = 1, int numberOfColumns = 1); + void addEmptyPowerLayout(); + void addEmptySquareRootLayout(); + void addEmptySquarePowerLayout(); + void addXNTCharLayout(); + void insertText(const char * text); void performBackspace(); private: diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 31ecfeb00..86c30a923 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -45,17 +45,16 @@ void ExpressionLayoutCursor::addLayout(ExpressionLayout * layout) { pointedExpressionLayout()->addBrother(this, layout); } -ExpressionLayout * ExpressionLayoutCursor::addEmptyExponentialLayout() { +void ExpressionLayoutCursor::addEmptyExponentialLayout() { CharLayout * child1 = new CharLayout(Ion::Charset::Exponential); VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Superscript, false); HorizontalLayout * newChild = new HorizontalLayout(child1, offsetLayout, false); pointedExpressionLayout()->addBrother(this, newChild); setPointedExpressionLayout(offsetLayout->editableChild(0)); setPosition(ExpressionLayoutCursor::Position::Right); - return offsetLayout; } -ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers() { +void ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers() { // Add a new FractionLayout HorizontalLayout * child1 = new HorizontalLayout(new EmptyVisibleLayout(), false); HorizontalLayout * child2 = new HorizontalLayout(new EmptyVisibleLayout(), false); @@ -65,7 +64,7 @@ ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers( if (!newChild->parent()->isHorizontal()) { setPointedExpressionLayout(child2->editableChild(0)); setPosition(Position::Left); - return child2; + return; } int fractionIndexInParent = newChild->parent()->indexOfChild(newChild); @@ -98,17 +97,14 @@ ExpressionLayout * ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers( // Set the cursor position setPointedExpressionLayout(child2->editableChild(0)); setPosition(Position::Left); - - return child2; } -ExpressionLayout * ExpressionLayoutCursor::addEmptyLogarithmLayout() { - ExpressionLayout * result = insertText("log()"); +void ExpressionLayoutCursor::addEmptyLogarithmLayout() { + insertText("log()"); setPosition(ExpressionLayoutCursor::Position::Left); - return result; } -ExpressionLayout * ExpressionLayoutCursor::addEmptyMatrixLayout(int numberOfRows, int numberOfColumns) { +void ExpressionLayoutCursor::addEmptyMatrixLayout(int numberOfRows, int numberOfColumns) { assert(numberOfRows > 0); assert(numberOfColumns > 0); ExpressionLayout * children[(numberOfRows+1)*(numberOfColumns+1)]; @@ -125,10 +121,9 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyMatrixLayout(int numberOfRows m_pointedExpressionLayout->addBrother(this, matrixLayout); setPointedExpressionLayout(matrixLayout->editableChild(0)); setPosition(ExpressionLayoutCursor::Position::Right); - return matrixLayout; } -ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { +void ExpressionLayoutCursor::addEmptyPowerLayout() { VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Superscript, false); // If there is already a base int numberOfOpenParenthesis = 0; @@ -136,7 +131,7 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { m_pointedExpressionLayout->addBrother(this, offsetLayout); setPointedExpressionLayout(offsetLayout->editableChild(0)); setPosition(ExpressionLayoutCursor::Position::Left); - return offsetLayout; + return; } // Else, add an empty base EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); @@ -144,19 +139,17 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptyPowerLayout() { m_pointedExpressionLayout->addBrother(this, newChild); setPointedExpressionLayout(child1); setPosition(ExpressionLayoutCursor::Position::Right); - return child1; } -ExpressionLayout * ExpressionLayoutCursor::addEmptySquareRootLayout() { +void ExpressionLayoutCursor::addEmptySquareRootLayout() { EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); NthRootLayout * newChild = new NthRootLayout(child1, false); m_pointedExpressionLayout->addBrother(this, newChild); setPointedExpressionLayout(child1); setPosition(ExpressionLayoutCursor::Position::Right); - return child1; } -ExpressionLayout * ExpressionLayoutCursor::addEmptySquarePowerLayout() { +void ExpressionLayoutCursor::addEmptySquarePowerLayout() { CharLayout * indiceLayout = new CharLayout('2'); VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(indiceLayout, VerticalOffsetLayout::Type::Superscript, false); // If there is already a base @@ -165,7 +158,7 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptySquarePowerLayout() { m_pointedExpressionLayout->addBrother(this, offsetLayout); setPointedExpressionLayout(offsetLayout); setPosition(ExpressionLayoutCursor::Position::Right); - return offsetLayout; + return; } // Else, add an empty base EmptyVisibleLayout * child1 = new EmptyVisibleLayout(); @@ -173,21 +166,19 @@ ExpressionLayout * ExpressionLayoutCursor::addEmptySquarePowerLayout() { m_pointedExpressionLayout->addBrother(this, newChild); setPointedExpressionLayout(child1); setPosition(ExpressionLayoutCursor::Position::Right); - return child1; } -ExpressionLayout * ExpressionLayoutCursor::addXNTCharLayout() { +void ExpressionLayoutCursor::addXNTCharLayout() { CharLayout * newChild = new CharLayout(m_pointedExpressionLayout->XNTChar()); m_pointedExpressionLayout->addBrother(this, newChild); setPointedExpressionLayout(newChild); setPosition(ExpressionLayoutCursor::Position::Right); - return newChild; } -ExpressionLayout * ExpressionLayoutCursor::insertText(const char * text) { +void ExpressionLayoutCursor::insertText(const char * text) { int textLength = strlen(text); if (textLength <= 0) { - return nullptr; + return; } ExpressionLayout * newChild = nullptr; for (int i = 0; i < textLength; i++) { @@ -206,8 +197,6 @@ ExpressionLayout * ExpressionLayoutCursor::insertText(const char * text) { m_pointedExpressionLayout = newChild; m_position = Position::Right; } - assert(newChild != nullptr); - return newChild; } void ExpressionLayoutCursor::performBackspace() { From 01880d30c3de617f0af596eb744e65aa8249d283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 15 Jan 2018 11:53:54 +0100 Subject: [PATCH 165/257] [apps/Makefile] Keep only ExpressionEditor and Calculation apps. Change-Id: I34816ec88395114e4d6034f78918253652be5cc9 --- apps/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/Makefile b/apps/Makefile index 60e285088..f99c5bae4 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,5 +1,5 @@ EPSILON_I18N_LANGUAGES ?= en fr es de pt -EPSILON_APPS ?= expression_editor calculation graph sequence settings statistics probability regression code +EPSILON_APPS ?= expression_editor calculation include apps/shared/Makefile include apps/home/Makefile From c0a3aadae4f18ddbd00bba85fcecab291e4d9a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 15 Jan 2018 10:13:32 +0100 Subject: [PATCH 166/257] [escher] EditableExpressionView, its delegate and EVWithCursor. Change-Id: Icb05c756ff17e43a7b306bec685a6040eaec303a --- escher/Makefile | 2 + escher/include/escher.h | 3 + .../include/escher/editable_expression_view.h | 37 +++++ .../editable_expression_view_delegate.h | 19 +++ .../escher/expression_view_with_cursor.h | 36 +++++ escher/src/editable_expression_view.cpp | 134 ++++++++++++++++++ escher/src/expression_view_with_cursor.cpp | 51 +++++++ 7 files changed, 282 insertions(+) create mode 100644 escher/include/escher/editable_expression_view.h create mode 100644 escher/include/escher/editable_expression_view_delegate.h create mode 100644 escher/include/escher/expression_view_with_cursor.h create mode 100644 escher/src/editable_expression_view.cpp create mode 100644 escher/src/expression_view_with_cursor.cpp diff --git a/escher/Makefile b/escher/Makefile index 3a1964bb1..bf54220fe 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -12,6 +12,7 @@ objs += $(addprefix escher/src/,\ dynamic_view_controller.o\ editable_text_cell.o\ ellipsis_view.o\ + editable_expression_view.o\ even_odd_cell.o\ even_odd_cell_with_ellipsis.o\ even_odd_buffer_text_cell.o\ @@ -21,6 +22,7 @@ objs += $(addprefix escher/src/,\ expression_table_cell.o\ expression_table_cell_with_pointer.o\ expression_view.o\ + expression_view_with_cursor.o\ highlight_cell.o\ gauge_view.o\ image_view.o\ diff --git a/escher/include/escher.h b/escher/include/escher.h index 2b3aac774..50dc65933 100644 --- a/escher/include/escher.h +++ b/escher/include/escher.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -22,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/escher/include/escher/editable_expression_view.h b/escher/include/escher/editable_expression_view.h new file mode 100644 index 000000000..5d9f967a6 --- /dev/null +++ b/escher/include/escher/editable_expression_view.h @@ -0,0 +1,37 @@ +#ifndef ESCHER_EDITABLE_EXPRESSION_VIEW_H +#define ESCHER_EDITABLE_EXPRESSION_VIEW_H + +#include +#include +#include +#include + +class EditableExpressionView : public ScrollableView, public ScrollViewDataSource { +public: + EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate = nullptr); + void setDelegate(EditableExpressionViewDelegate * delegate) { m_delegate = delegate; } + ExpressionViewWithCursor * expressionViewWithCursor() { return &m_expressionViewWithCursor; } + bool isEditing() const; + void setEditing(bool isEditing); + void scrollToCursor(); + + /* Responder */ + Toolbox * toolbox() override; + bool handleEvent(Ion::Events::Event event) override; + + bool editableExpressionViewShouldFinishEditing(Ion::Events::Event event); + + /* Callback for MathToolbox */ + void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout); + + /* View */ + KDSize minimalSizeForOptimalDisplay() const override; + +private: + bool privateHandleEvent(Ion::Events::Event event); + void cursorOrLayoutChanged(); + ExpressionViewWithCursor m_expressionViewWithCursor; + EditableExpressionViewDelegate * m_delegate; +}; + +#endif diff --git a/escher/include/escher/editable_expression_view_delegate.h b/escher/include/escher/editable_expression_view_delegate.h new file mode 100644 index 000000000..6eb66bcdd --- /dev/null +++ b/escher/include/escher/editable_expression_view_delegate.h @@ -0,0 +1,19 @@ +#ifndef ESCHER_EDITABLE_EXPRESSION_VIEW_DELEGATE_H +#define ESCHER_EDITABLE_EXPRESSION_VIEW_DELEGATE_H + +#include +#include + +class EditableExpressionView; + +class EditableExpressionViewDelegate { +public: + virtual bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) = 0; + virtual bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) = 0; + /*virtual bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { return false; }; + virtual bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) {return false;}; + virtual bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool textHasChanged) { return returnValue; };*/ // TODO? + virtual Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) = 0; +}; + +#endif diff --git a/escher/include/escher/expression_view_with_cursor.h b/escher/include/escher/expression_view_with_cursor.h new file mode 100644 index 000000000..b362bb5f3 --- /dev/null +++ b/escher/include/escher/expression_view_with_cursor.h @@ -0,0 +1,36 @@ +#ifndef ESCHER_EXPRESSION_VIEW_WITH_CURSOR_H +#define ESCHER_EXPRESSION_VIEW_WITH_CURSOR_H + +#include +#include +#include +#include +#include + +class ExpressionViewWithCursor : public View { +public: + ExpressionViewWithCursor(Poincare::ExpressionLayout * expressionLayout); + Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; } + bool isEditing() const { return m_isEditing; } + void setEditing(bool isEditing) { m_isEditing = isEditing; } + void cursorPositionChanged(); + KDRect cursorRect(); + const ExpressionView * expressionView() const { return &m_expressionView; } + /* View */ + KDSize minimalSizeForOptimalDisplay() const override; +private: + enum class Position { + Top, + Bottom + }; + int numberOfSubviews() const override { return 2; } + View * subviewAtIndex(int index) override; + void layoutSubviews() override; + void layoutCursorSubview(); + Poincare::ExpressionLayoutCursor m_cursor; + ExpressionView m_expressionView; + TextCursorView m_cursorView; + bool m_isEditing; +}; + +#endif diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp new file mode 100644 index 000000000..ef3082d2c --- /dev/null +++ b/escher/src/editable_expression_view.cpp @@ -0,0 +1,134 @@ +#include +#include + +EditableExpressionView::EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate) : + ScrollableView(parentResponder, &m_expressionViewWithCursor, this), + m_expressionViewWithCursor(expressionLayout), + m_delegate(delegate) +{ +} + +bool EditableExpressionView::isEditing() const { + return m_expressionViewWithCursor.isEditing(); +} + +void EditableExpressionView::setEditing(bool isEditing) { + m_expressionViewWithCursor.setEditing(isEditing); +} + +void EditableExpressionView::scrollToCursor() { + scrollToContentRect(m_expressionViewWithCursor.cursorRect(), true); +} + +Toolbox * EditableExpressionView::toolbox() { + if (m_delegate) { + return m_delegate->toolboxForEditableExpressionView(this); + } + return nullptr; +} + +bool EditableExpressionView::handleEvent(Ion::Events::Event event) { + if (privateHandleEvent(event)) { + cursorOrLayoutChanged(); + return true; + } + return false; +} + +bool EditableExpressionView::editableExpressionViewShouldFinishEditing(Ion::Events::Event event) { + return m_delegate->editableExpressionViewShouldFinishEditing(this, event); +} + +KDSize EditableExpressionView::minimalSizeForOptimalDisplay() const { + return m_expressionViewWithCursor.minimalSizeForOptimalDisplay(); +} + +bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { + if (event == Ion::Events::Left) { + return m_expressionViewWithCursor.cursor()->moveLeft(); + } + if (event == Ion::Events::Right) { + return m_expressionViewWithCursor.cursor()->moveRight(); + } + if (event == Ion::Events::Up) { + return m_expressionViewWithCursor.cursor()->moveUp(); + } + if (event == Ion::Events::Down) { + return m_expressionViewWithCursor.cursor()->moveDown(); + } + if (event == Ion::Events::ShiftLeft) { + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Left); + return true; + } + if (event == Ion::Events::ShiftRight) { + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + return true; + } + if (event == Ion::Events::Division) { + m_expressionViewWithCursor.cursor()->addFractionLayoutAndCollapseBrothers(); + return true; + } + if (event == Ion::Events::XNT) { + m_expressionViewWithCursor.cursor()->addXNTCharLayout(); + return true; + } + if (event == Ion::Events::Exp) { + m_expressionViewWithCursor.cursor()->addEmptyExponentialLayout(); + return true; + } + if (event == Ion::Events::Log) { + m_expressionViewWithCursor.cursor()->addEmptyLogarithmLayout(); + return true; + } + if (event == Ion::Events::Power) { + m_expressionViewWithCursor.cursor()->addEmptyPowerLayout(); + return true; + } + if (event == Ion::Events::Sqrt) { + m_expressionViewWithCursor.cursor()->addEmptySquareRootLayout(); + return true; + } + if (event == Ion::Events::Square) { + m_expressionViewWithCursor.cursor()->addEmptySquarePowerLayout(); + return true; + } + if (event.hasText()) { + const char * textToInsert = event.text(); + if (textToInsert[1] == 0) { + if (textToInsert[0] == Ion::Charset::MultiplicationSign) { + const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; + m_expressionViewWithCursor.cursor()->insertText(middleDotString); + return true; + } + if (textToInsert[0] == '[' || textToInsert[0] == ']') { + m_expressionViewWithCursor.cursor()->addEmptyMatrixLayout(); + return true; + } + } + m_expressionViewWithCursor.cursor()->insertText(textToInsert); + return true; + } + if (event == Ion::Events::Backspace) { + m_expressionViewWithCursor.cursor()->performBackspace(); + return true; + } + return false; +} + +void EditableExpressionView::insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout) { + if (layout == nullptr) { + return; + } + m_expressionViewWithCursor.cursor()->addLayout(layout); + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); + cursorOrLayoutChanged(); +} + +void EditableExpressionView::cursorOrLayoutChanged() { + m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); + layoutSubviews(); +} diff --git a/escher/src/expression_view_with_cursor.cpp b/escher/src/expression_view_with_cursor.cpp new file mode 100644 index 000000000..b231aea65 --- /dev/null +++ b/escher/src/expression_view_with_cursor.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +using namespace Poincare; + +ExpressionViewWithCursor::ExpressionViewWithCursor(ExpressionLayout * expressionLayout) : + m_cursor(), + m_expressionView(), + m_cursorView(), + m_isEditing(false) +{ + m_cursor.setPointedExpressionLayout(expressionLayout); + m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); + m_expressionView.setExpressionLayout(expressionLayout); +} + +void ExpressionViewWithCursor::cursorPositionChanged() { + layoutCursorSubview(); +} + +KDRect ExpressionViewWithCursor::cursorRect() { + return m_cursorView.frame(); +} + +KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { + KDSize expressionViewSize = m_expressionView.minimalSizeForOptimalDisplay(); + return KDSize(expressionViewSize.width()+1, m_expressionView.minimalSizeForOptimalDisplay().height()); // +1 for the cursor +} + +View * ExpressionViewWithCursor::subviewAtIndex(int index) { + assert(index >= 0 && index < 2); + View * m_views[] = {&m_expressionView, &m_cursorView}; + return m_views[index]; +} + +void ExpressionViewWithCursor::layoutSubviews() { + m_expressionView.setFrame(bounds()); + layoutCursorSubview(); +} + +void ExpressionViewWithCursor::layoutCursorSubview() { + KDPoint expressionViewOrigin = m_expressionView.drawingOrigin(); + KDPoint cursoredExpressionViewOrigin = m_cursor.pointedExpressionLayout()->absoluteOrigin(); + KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x(); + if (m_cursor.position() == ExpressionLayoutCursor::Position::Right) { + cursorX += m_cursor.pointedExpressionLayout()->size().width(); + } + KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + m_cursor.pointedExpressionLayout()->baseline()-m_cursor.cursorHeight()/2); + m_cursorView.setFrame(KDRect(cursorTopLeftPosition, 1, m_cursor.cursorHeight())); +} From ed82496b56d4bff408da2486a37020ad07237270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 15 Jan 2018 11:48:43 +0100 Subject: [PATCH 167/257] [apps] Handle EditableExpressionView in MathToolbox. Change-Id: Ic85cf67d225c60c90c3ad536d813bb489ceb6fe5 --- apps/math_toolbox.cpp | 105 ++++++++++++++++++++++-------------------- apps/math_toolbox.h | 7 ++- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 55c160db9..f7a37dd10 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -104,67 +104,70 @@ const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbo const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 10); #endif -MathToolbox::MathToolbox() : Toolbox(nullptr, I18n::translate(rootModel()->label())) +MathToolbox::MathToolbox() : + Toolbox(nullptr, I18n::translate(rootModel()->label())), + m_action(actionForTextfield) { } -TextField * MathToolbox::textFieldSender() { - return static_cast(Toolbox::sender()); +void MathToolbox::setSenderAndAction(Responder * sender, Action action) { + setSender(sender); + m_action = action; } -ExpressionEditor::Controller * MathToolbox::expressionEditorControllerSender() { - return static_cast(Toolbox::sender()); +void MathToolbox::actionForEditableExpressionView(void * sender, ToolboxMessageTree * messageTree) { + EditableExpressionView * expressionLayoutEditorSender = static_cast(sender); + // Translate the message and replace the arguments with Empty chars. + const char * textToInsert = I18n::translate(messageTree->insertedText()); + char strippedTextToInsert[strlen(textToInsert)]; + Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandMessage(messageTree->insertedText(), strippedTextToInsert); + // Create the layout + Expression * resultExpression = Expression::parse(strippedTextToInsert); + if (resultExpression == nullptr) { + return; + } + ExpressionLayout * resultLayout = resultExpression->createLayout(); + // Find the pointed layout. + ExpressionLayout * pointedLayout = resultLayout; + if (messageTree->pointedPath() != nullptr) { + for (int i = 0; i < messageTree->pointedPathLength(); i++) { + assert(messageTree->pointedPath()[i] < pointedLayout->numberOfChildren()); + pointedLayout = pointedLayout->editableChild(messageTree->pointedPath()[i]); + } + } else if (resultLayout->isHorizontal()) { + // If the layout is horizontal, pick the first open parenthesis. + for (int i = 0; i < resultLayout->numberOfChildren(); i++) { + if (resultLayout->editableChild(i)->isLeftParenthesis()) { + pointedLayout = resultLayout->editableChild(i); + break; + } + } + } else if (resultLayout->numberOfChildren() > 0) { + // Else, if the layout has children, pick the first one. + pointedLayout = resultLayout->editableChild(0); + } + // Insert the layout + expressionLayoutEditorSender->insertLayoutAtCursor(resultLayout, pointedLayout); +} + +void MathToolbox::actionForTextfield(void * sender, ToolboxMessageTree * messageTree) { + TextField * textFieldSender = static_cast(sender); + if (!textFieldSender->isEditing()) { + textFieldSender->setEditing(true); + } + const char * textToInsert = I18n::translate(messageTree->insertedText()); + char strippedTextToInsert[strlen(textToInsert)]; + // Translate the message and remove the arguments. + Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedTextToInsert); + textFieldSender->insertTextAtLocation(strippedTextToInsert, textFieldSender->cursorLocation()); + int newCursorLocation = textFieldSender->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(strippedTextToInsert); + textFieldSender->setCursorLocation(newCursorLocation); } bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) { - if (0) { - m_selectableTableView.deselectTable(); - ToolboxMessageTree * messageTree = selectedMessageTree; - const char * editedText = I18n::translate(messageTree->insertedText()); - if (!textFieldSender()->isEditing()) { - textFieldSender()->setEditing(true); - } - char strippedEditedText[strlen(editedText)]; - Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedEditedText); - textFieldSender()->insertTextAtLocation(strippedEditedText, textFieldSender()->cursorLocation()); - int newCursorLocation = textFieldSender()->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(strippedEditedText); - textFieldSender()->setCursorLocation(newCursorLocation); - app()->dismissModalViewController(); - return true; - } - // Deal with ExpressionEditor::Controller for now. ToolboxMessageTree * messageTree = selectedMessageTree; m_selectableTableView.deselectTable(); - // Translate the message and replace the arguments with Empty chars. - const char * editedText = I18n::translate(messageTree->insertedText()); - char strippedEditedText[strlen(editedText)]; - Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandMessage(messageTree->insertedText(), strippedEditedText); - // Create the layout - Expression * resultExpression = Expression::parse(strippedEditedText); - if (resultExpression != nullptr) { - ExpressionLayout * resultLayout = resultExpression->createLayout(); - // Find the pointed layout. - ExpressionLayout * pointedLayout = resultLayout; - if (messageTree->pointedPath() != nullptr) { - for (int i = 0; i < messageTree->pointedPathLength(); i++) { - assert(messageTree->pointedPath()[i] < pointedLayout->numberOfChildren()); - pointedLayout = pointedLayout->editableChild(messageTree->pointedPath()[i]); - } - } else if (resultLayout->isHorizontal()) { - // If the layout is horizontal, pick the first open parenthesis. - for (int i = 0; i < resultLayout->numberOfChildren(); i++) { - if (resultLayout->editableChild(i)->isLeftParenthesis()) { - pointedLayout = resultLayout->editableChild(i); - break; - } - } - } else if (resultLayout->numberOfChildren() > 0) { - // Else, if the layout has children, pick the first one. - pointedLayout = resultLayout->editableChild(0); - } - // Insert the layout - expressionEditorControllerSender()->insertLayoutAtCursor(resultLayout, pointedLayout); - } + m_action(sender(), messageTree); app()->dismissModalViewController(); return true; } diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index 9da44865b..6f06148d1 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -8,10 +8,12 @@ class MathToolbox : public Toolbox { public: + typedef void (*Action)(void * sender, ToolboxMessageTree * messageTree); MathToolbox(); + void setSenderAndAction(Responder * sender, Action action); + static void actionForEditableExpressionView(void * sender, ToolboxMessageTree * messageTree); + static void actionForTextfield(void * sender, ToolboxMessageTree * messageTree); protected: - TextField * textFieldSender(); - ExpressionEditor::Controller * expressionEditorControllerSender(); bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override; const ToolboxMessageTree * rootModel() override; MessageTableCellWithMessage * leafCellAtIndex(int index) override; @@ -19,6 +21,7 @@ protected: int maxNumberOfDisplayedRows() override; constexpr static int k_maxNumberOfDisplayedRows = 6; // = 240/40 private: + Action m_action; MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows]; MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows]; }; From 8f58c33c31c71ddb85210b4998e6209d7adf1a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 15 Jan 2018 11:49:38 +0100 Subject: [PATCH 168/257] [apps] Dummy handling of EditableExpressionView in VariableBoxController. Change-Id: I565f613c13ee13d39efb652ae37f281e55f5d999 --- apps/variable_box_controller.cpp | 4 ++++ apps/variable_box_controller.h | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/variable_box_controller.cpp b/apps/variable_box_controller.cpp index 33327e63a..72c2b9b63 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/variable_box_controller.cpp @@ -292,6 +292,10 @@ void VariableBoxController::setTextFieldCaller(TextField * textField) { m_contentViewController.setTextFieldCaller(textField); } +void VariableBoxController::setEditableExpressionViewCaller(EditableExpressionView * editableExpressionView) { + //TODO +} + void VariableBoxController::viewWillAppear() { StackViewController::viewWillAppear(); m_contentViewController.resetPage(); diff --git a/apps/variable_box_controller.h b/apps/variable_box_controller.h index 45218cd74..1617c1a31 100644 --- a/apps/variable_box_controller.h +++ b/apps/variable_box_controller.h @@ -13,6 +13,7 @@ public: VariableBoxController(Poincare::GlobalContext * context); void didBecomeFirstResponder() override; void setTextFieldCaller(TextField * textField); + void setEditableExpressionViewCaller(EditableExpressionView * editableExpressionView); void viewWillAppear() override; void viewDidDisappear() override; private: From 82229250a2750c43cface15d51e59e516ba5e022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 15 Jan 2018 11:50:48 +0100 Subject: [PATCH 169/257] [apps/Shared] EditableExpressionView delegate and delegate app. Change-Id: Ib6e0157e5523a37e4d652b8bd5063762cd0b6735 --- apps/shared/Makefile | 2 + .../editable_expression_view_delegate.cpp | 19 +++++++ .../editable_expression_view_delegate.h | 20 +++++++ ..._editable_expression_view_delegate_app.cpp | 52 +++++++++++++++++++ ...nd_editable_expression_view_delegate_app.h | 21 ++++++++ 5 files changed, 114 insertions(+) create mode 100644 apps/shared/editable_expression_view_delegate.cpp create mode 100644 apps/shared/editable_expression_view_delegate.h create mode 100644 apps/shared/text_field_and_editable_expression_view_delegate_app.cpp create mode 100644 apps/shared/text_field_and_editable_expression_view_delegate_app.h diff --git a/apps/shared/Makefile b/apps/shared/Makefile index 83210f1da..40c3a475c 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -6,6 +6,7 @@ app_objs += $(addprefix apps/shared/,\ curve_view_cursor.o\ curve_view_range.o\ editable_cell_table_view_controller.o\ + editable_expression_view_delegate.o\ float_pair_store.o\ float_parameter_controller.o\ function.o\ @@ -37,6 +38,7 @@ app_objs += $(addprefix apps/shared/,\ store_controller.o\ store_parameter_controller.o\ tab_table_controller.o\ + text_field_and_editable_expression_view_delegate_app.o\ text_field_delegate.o\ text_field_delegate_app.o\ toolbox_helpers.o\ diff --git a/apps/shared/editable_expression_view_delegate.cpp b/apps/shared/editable_expression_view_delegate.cpp new file mode 100644 index 000000000..ab502a270 --- /dev/null +++ b/apps/shared/editable_expression_view_delegate.cpp @@ -0,0 +1,19 @@ +#include "editable_expression_view_delegate.h" + +using namespace Poincare; + +namespace Shared { + +bool EditableExpressionViewDelegate::editableExpressionViewShouldFinishEditing(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) { + return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewShouldFinishEditing(editableExpressionView, event); +} + +bool EditableExpressionViewDelegate::editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) { + return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidReceiveEvent(editableExpressionView, event); +} + +Toolbox * EditableExpressionViewDelegate::toolboxForEditableExpressionView(::EditableExpressionView * editableExpressionView) { + return textFieldAndEditableExpressionViewDelegateApp()->toolboxForEditableExpressionView(editableExpressionView); +} + +} diff --git a/apps/shared/editable_expression_view_delegate.h b/apps/shared/editable_expression_view_delegate.h new file mode 100644 index 000000000..438ae1acc --- /dev/null +++ b/apps/shared/editable_expression_view_delegate.h @@ -0,0 +1,20 @@ +#ifndef SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_H +#define SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_H + +#include +#include "text_field_and_editable_expression_view_delegate_app.h" + +namespace Shared { + +class EditableExpressionViewDelegate : public ::EditableExpressionViewDelegate { +public: + bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; + bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; + Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) override; +private: + virtual TextFieldAndEditableExpressionViewDelegateApp * textFieldAndEditableExpressionViewDelegateApp() = 0; +}; + +} + +#endif diff --git a/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp b/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp new file mode 100644 index 000000000..2fd015231 --- /dev/null +++ b/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp @@ -0,0 +1,52 @@ +#include "text_field_and_editable_expression_view_delegate_app.h" +#include "../i18n.h" +#include "../apps_container.h" + +using namespace Poincare; + +namespace Shared { + +TextFieldAndEditableExpressionViewDelegateApp::TextFieldAndEditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) : + TextFieldDelegateApp(container, snapshot, rootViewController), + EditableExpressionViewDelegate() +{ +} + +bool TextFieldAndEditableExpressionViewDelegateApp::editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) { + return event == Ion::Events::OK || event == Ion::Events::EXE; +} + +bool TextFieldAndEditableExpressionViewDelegateApp::editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) { + if (editableExpressionView->isEditing() && editableExpressionView->editableExpressionViewShouldFinishEditing(event)) { + int bufferSize = 256; + char buffer[bufferSize]; + editableExpressionView->expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); + Expression * exp = Expression::parse(buffer); + if (exp != nullptr) { + delete exp; + } + if (exp == nullptr) { + editableExpressionView->app()->displayWarning(I18n::Message::SyntaxError); + return true; + } + } + if (event == Ion::Events::Var) { + if (!editableExpressionView->isEditing()) { + editableExpressionView->setEditing(true); + } + AppsContainer * appsContainer = (AppsContainer *)editableExpressionView->app()->container(); + VariableBoxController * variableBoxController = appsContainer->variableBoxController(); + variableBoxController->setEditableExpressionViewCaller(editableExpressionView); + editableExpressionView->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin); + return true; + } + return false; +} + +Toolbox * TextFieldAndEditableExpressionViewDelegateApp::toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) { + Toolbox * toolbox = container()->mathToolbox(); + static_cast(toolbox)->setSenderAndAction(editableExpressionView, MathToolbox::actionForEditableExpressionView); + return toolbox; +} + +} diff --git a/apps/shared/text_field_and_editable_expression_view_delegate_app.h b/apps/shared/text_field_and_editable_expression_view_delegate_app.h new file mode 100644 index 000000000..85bc85fc2 --- /dev/null +++ b/apps/shared/text_field_and_editable_expression_view_delegate_app.h @@ -0,0 +1,21 @@ +#ifndef SHARED_TEXT_FIELD_AND_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H +#define SHARED_TEXT_FIELD_AND_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H + +#include "text_field_delegate_app.h" +#include + +namespace Shared { + +class TextFieldAndEditableExpressionViewDelegateApp : public TextFieldDelegateApp, public EditableExpressionViewDelegate { +public: + virtual ~TextFieldAndEditableExpressionViewDelegateApp() = default; + bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; + virtual bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; + Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) override; +protected: + TextFieldAndEditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController); +}; + +} + +#endif From 3ff998ec2c7c6242416342431b44cca8aa2b7b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 14:29:32 +0100 Subject: [PATCH 170/257] [poincare] Fix MatrixLayout size computation. Change-Id: Ib02c70d92d7d4e96c052f7f7671496115cf190f1 --- poincare/src/layout/bracket_left_right_layout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/layout/bracket_left_right_layout.cpp b/poincare/src/layout/bracket_left_right_layout.cpp index d6eefaaa8..f39263fff 100644 --- a/poincare/src/layout/bracket_left_right_layout.cpp +++ b/poincare/src/layout/bracket_left_right_layout.cpp @@ -54,7 +54,7 @@ bool BracketLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { KDSize BracketLeftRightLayout::computeSize() { - return KDSize(k_externWidthMargin + k_lineThickness + k_widthMargin, operandHeight()); + return KDSize(k_externWidthMargin + k_lineThickness + k_widthMargin, operandHeight() + k_lineThickness); } KDCoordinate BracketLeftRightLayout::operandHeight() { From 47ab766549bf5dec078233fdefc23b20534dc0e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 14:30:08 +0100 Subject: [PATCH 171/257] [poincare/lexer] Parse the multiplication dot. Change-Id: I4b12c6c660a7890d7d00b03cad26af5e366b4eaf --- poincare/src/expression_lexer.l | 1 + 1 file changed, 1 insertion(+) diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 577e71acc..57ed5769a 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -143,6 +143,7 @@ inf { poincare_expression_yylval.expression = new Undefined(); return UNDEFINED; \+ { return PLUS; } \- { return MINUS; } \x93 { return MULTIPLY; } +\x94 { return MULTIPLY; } \* { return MULTIPLY; } \/ { return DIVIDE; } \^ { return POW; } From 91c05b3bb759148476b96f70dd2b315166e8c3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 14:47:21 +0100 Subject: [PATCH 172/257] [apps/calculation] EditableExpressionView in calculation app. Change-Id: I8b67353682652695f7296f0222939930f4b21794 --- apps/calculation/app.cpp | 32 ++++- apps/calculation/app.h | 3 +- .../edit_expression_controller.cpp | 124 +++++++++++++++--- apps/calculation/edit_expression_controller.h | 37 ++++-- .../editable_expression_view_delegate.cpp | 16 +++ .../editable_expression_view_delegate.h | 4 + .../include/escher/editable_expression_view.h | 2 +- .../editable_expression_view_delegate.h | 7 +- escher/include/escher/expression_view.h | 1 + .../escher/expression_view_with_cursor.h | 4 +- escher/src/editable_expression_view.cpp | 44 ++++++- escher/src/expression_view.cpp | 7 +- escher/src/expression_view_with_cursor.cpp | 7 +- 13 files changed, 246 insertions(+), 42 deletions(-) diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index 701ce5926..21056ddb4 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -43,7 +43,7 @@ void App::Snapshot::tidy() { } App::App(Container * container, Snapshot * snapshot) : - TextFieldDelegateApp(container, snapshot, &m_editExpressionController), + TextFieldAndEditableExpressionViewDelegateApp(container, snapshot, &m_editExpressionController), m_localContext((GlobalContext *)((AppsContainer *)container)->globalContext(), snapshot->calculationStore()), m_historyController(&m_editExpressionController, snapshot->calculationStore()), m_editExpressionController(&m_modalViewController, &m_historyController, snapshot->calculationStore()) @@ -80,6 +80,36 @@ bool App::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event e return false; } +bool App::editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) { + if ((event == Ion::Events::Var || event == Ion::Events::XNT) && TextFieldAndEditableExpressionViewDelegateApp::editableExpressionViewDidReceiveEvent(editableExpressionView, event)) { + return true; + } + /* Here, we check that the expression entered by the user can be printed with + * less than k_printedExpressionLength characters. Otherwise, we prevent the + * user from adding this expression to the calculation store. */ + if (editableExpressionView->isEditing() && editableExpressionView->editableExpressionViewShouldFinishEditing(event)) { + int bufferLength = TextField::maxBufferSize(); + char bufferForParsing[bufferLength]; + Poincare::ExpressionLayout * expressionLayout = editableExpressionView->expressionViewWithCursor()->expressionView()->expressionLayout(); + expressionLayout->writeTextInBuffer(bufferForParsing, bufferLength); + Expression * exp = Expression::parse(bufferForParsing); + if (exp == nullptr) { + editableExpressionView->app()->displayWarning(I18n::Message::SyntaxError); + return true; + } + char buffer[Calculation::k_printedExpressionSize]; + int length = exp->writeTextInBuffer(buffer, sizeof(buffer)); + delete exp; + /* if the buffer is totally full, it is VERY likely that writeTextInBuffer + * escaped before printing utterly the expression. */ + if (length >= Calculation::k_printedExpressionSize-1) { + displayWarning(I18n::Message::SyntaxError); + return true; + } + } + return false; +} + const char * App::XNT() { return "x"; } diff --git a/apps/calculation/app.h b/apps/calculation/app.h index a9b616599..4ec807891 100644 --- a/apps/calculation/app.h +++ b/apps/calculation/app.h @@ -10,7 +10,7 @@ namespace Calculation { -class App : public Shared::TextFieldDelegateApp { +class App : public Shared::TextFieldAndEditableExpressionViewDelegateApp { public: class Descriptor : public ::App::Descriptor { public: @@ -30,6 +30,7 @@ public: }; Poincare::Context * localContext() override; bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override; + bool editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; const char * XNT() override; private: App(Container * container, Snapshot * snapshot); diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 0df8a0f17..90d8cd36d 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -1,5 +1,6 @@ #include "edit_expression_controller.h" #include "../apps_container.h" +#include "ion/display.h" #include "app.h" #include @@ -7,10 +8,11 @@ using namespace Shared; namespace Calculation { -EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate) : +EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, EditableExpressionViewDelegate * editableExpressionViewDelegate) : View(), m_mainView(subview), - m_textField(parentResponder, m_textBody, TextField::maxBufferSize(), textFieldDelegate) + m_textField(parentResponder, m_textBody, TextField::maxBufferSize(), textFieldDelegate), + m_editableExpressionView(parentResponder, new Poincare::HorizontalLayout(), editableExpressionViewDelegate) { m_textBody[0] = 0; } @@ -20,30 +22,55 @@ int EditExpressionController::ContentView::numberOfSubviews() const { } View * EditExpressionController::ContentView::subviewAtIndex(int index) { - View * views[2] = {m_mainView, &m_textField}; - return views[index]; + assert(index >= 0 && index < numberOfSubviews()); + if (index == 0) { + return m_mainView; + } + assert(index == 1); + if (editionIsInTextField()) { + return &m_textField; + } + return &m_editableExpressionView; } void EditExpressionController::ContentView::layoutSubviews() { - KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - k_textFieldHeight-k_separatorThickness); + KDCoordinate inputViewFrameHeight = inputViewHeight(); + KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - inputViewFrameHeight-k_separatorThickness); m_mainView->setFrame(mainViewFrame); - KDRect inputViewFrame(k_textMargin, bounds().height() - k_textFieldHeight, bounds().width()-k_textMargin, k_textFieldHeight); - m_textField.setFrame(inputViewFrame); + if (editionIsInTextField()) { + KDRect inputViewFrame(k_leftMargin, bounds().height() - inputViewFrameHeight + k_verticalMargin, bounds().width()-k_leftMargin, k_textFieldHeight - k_verticalMargin); + m_textField.setFrame(inputViewFrame); + m_editableExpressionView.setFrame(KDRectZero); + return; + } + KDRect inputViewFrame(k_leftMargin, bounds().height() - inputViewFrameHeight, bounds().width() - k_leftMargin, inputViewFrameHeight); + m_editableExpressionView.setFrame(inputViewFrame); + m_textField.setFrame(KDRectZero); } -void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rect) const { +void EditExpressionController::ContentView::reload() { + layoutSubviews(); + markRectAsDirty(bounds()); +} + +void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rect) const { + KDCoordinate inputViewFrameHeight = inputViewHeight(); // Draw the separator - ctx->fillRect(KDRect(0, bounds().height() -k_textFieldHeight-k_separatorThickness, bounds().width(), k_separatorThickness), Palette::GreyMiddle); - // Color the margin - ctx->fillRect(KDRect(0, bounds().height() -k_textFieldHeight, k_textMargin, k_textFieldHeight), m_textField.backgroundColor()); + ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight-k_separatorThickness, bounds().width(), k_separatorThickness), Palette::GreyMiddle); + // Color the left margin + ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, k_leftMargin, k_textFieldHeight), m_textField.backgroundColor()); + if (!editionIsInTextField()) { + // Color the upper margin + ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, bounds().width(), k_verticalMargin), m_textField.backgroundColor()); + } } -TextField * EditExpressionController::ContentView::textField() { - return &m_textField; +KDCoordinate EditExpressionController::ContentView::inputViewHeight() const { + return k_verticalMargin + (editionIsInTextField() ? k_textFieldHeight : editableExpressionViewHeight()); } -TableView * EditExpressionController::ContentView::mainView() { - return m_mainView; +KDCoordinate EditExpressionController::ContentView::editableExpressionViewHeight() const { + return KDCoordinate(min(0.6*Ion::Display::Height, max(k_textFieldHeight, m_editableExpressionView.minimalSizeForOptimalDisplay().height()+k_verticalMargin))); } EditExpressionController::EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore) : @@ -67,7 +94,11 @@ void EditExpressionController::insertTextBody(const char * text) { bool EditExpressionController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::Up) { if (m_calculationStore->numberOfCalculations() > 0) { - ((ContentView *)view())->textField()->setEditing(false, false); + if (((ContentView *)view())->editionIsInTextField()) { + ((ContentView *)view())->textField()->setEditing(false, false); + } else { + ((ContentView *)view())->editableExpressionView()->setEditing(false); + } app()->setFirstResponder(m_historyController); } return true; @@ -78,8 +109,13 @@ bool EditExpressionController::handleEvent(Ion::Events::Event event) { void EditExpressionController::didBecomeFirstResponder() { int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0; m_historyController->scrollToCell(0, lastRow); - ((ContentView *)view())->textField()->setEditing(true, false); - app()->setFirstResponder(((ContentView *)view())->textField()); + if (((ContentView *)view())->editionIsInTextField()) { + ((ContentView *)view())->textField()->setEditing(true, false); + app()->setFirstResponder(((ContentView *)view())->textField()); + return; + } + ((ContentView *)view())->editableExpressionView()->setEditing(true); + app()->setFirstResponder(((ContentView *)view())->editableExpressionView()); } bool EditExpressionController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) { @@ -110,21 +146,71 @@ bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField, return false; } +bool EditExpressionController::editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) { + bool layoutIsEmpty = expressionLayout()->isHorizontal() && expressionLayout()->numberOfChildren() == 0; + if (editableExpressionView->isEditing() && editableExpressionView->editableExpressionViewShouldFinishEditing(event) && layoutIsEmpty && m_calculationStore->numberOfCalculations() > 0) { + App * calculationApp = (App *)app(); + const char * lastTextBody = m_calculationStore->calculationAtIndex(m_calculationStore->numberOfCalculations()-1)->inputText(); + m_calculationStore->push(lastTextBody, calculationApp->localContext()); + m_historyController->reload(); + ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); + return true; + } + return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidReceiveEvent(editableExpressionView, event); +} + +bool EditExpressionController::editableExpressionViewDidFinishEditing(::EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { + App * calculationApp = (App *)app(); + expressionLayout()->writeTextInBuffer(const_cast(textBody()), ContentView::k_bufferLength); + m_calculationStore->push(textBody(), calculationApp->localContext()); + (const_cast(((ContentView *)view())->editableExpressionView()->expressionViewWithCursor()->expressionView()))->setExpressionLayout(new Poincare::HorizontalLayout()); + reloadView(); + ((ContentView *)view())->editableExpressionView()->setEditing(true); + return true; +} + +bool EditExpressionController::editableExpressionViewDidAbortEditing(::EditableExpressionView * editableExpressionView, const char * text) { + ((ContentView *)view())->editableExpressionView()->setEditing(true); + //TODO ((ContentView *)view())->editableExpressionView()->editableExpressionView()->expressionViewWithCursor()->expressionView()->setLayout(; + return false; +} + +void EditExpressionController::editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) { + assert(editableExpressionView == ((ContentView *)view())->editableExpressionView()); + reloadView(); +} + TextFieldDelegateApp * EditExpressionController::textFieldDelegateApp() { return (App *)app(); } +TextFieldAndEditableExpressionViewDelegateApp * EditExpressionController::textFieldAndEditableExpressionViewDelegateApp() { + return (App *)app(); +} + View * EditExpressionController::loadView() { - return new ContentView(this, (TableView *)m_historyController->view(), this); + return new ContentView(this, (TableView *)m_historyController->view(), this, this); } void EditExpressionController::unloadView(View * view) { delete view; } +void EditExpressionController::reloadView() { + ((ContentView *)view())->reload(); + m_historyController->reload(); + if (m_historyController->numberOfRows() > 0) { + ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); + } +} + void EditExpressionController::viewDidDisappear() { DynamicViewController::viewDidDisappear(); m_historyController->viewDidDisappear(); } +Poincare::ExpressionLayout * EditExpressionController::expressionLayout() { + return ((ContentView *)view())->editableExpressionView()->expressionViewWithCursor()->expressionView()->expressionLayout(); +} + } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 9c019fe4b..b9c8f4514 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -3,6 +3,7 @@ #include #include "../shared/text_field_delegate.h" +#include "../shared/editable_expression_view_delegate.h" #include "history_controller.h" #include "calculation_store.h" #include "text_field.h" @@ -11,7 +12,7 @@ namespace Calculation { class HistoryController; /* TODO: implement a split view */ -class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate { +class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate, public Shared::EditableExpressionViewDelegate { public: EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore); void didBecomeFirstResponder() override; @@ -19,30 +20,50 @@ public: bool handleEvent(Ion::Events::Event event) override; const char * textBody(); void insertTextBody(const char * text); -bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override; + + /* TextFieldDelegate */ + bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override; bool textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) override; bool textFieldDidAbortEditing(::TextField * textField, const char * text) override; + + /* EditableExpressionViewDelegate */ + bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; + bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) override; + bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) override; + void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) override; + private: class ContentView : public View { public: - ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate); + ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, EditableExpressionViewDelegate * editableExpressionViewDelegate); int numberOfSubviews() const override; View * subviewAtIndex(int index) override; void layoutSubviews() override; - TextField * textField(); - TableView * mainView(); + void reload(); + TextField * textField() { return &m_textField; } + EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; } + TableView * mainView() { return m_mainView; } void drawRect(KDContext * ctx, KDRect rect) const override; + bool editionIsInTextField() const { return true; } //TODO + static constexpr int k_bufferLength = TextField::maxBufferSize(); private: - static constexpr KDCoordinate k_textFieldHeight = 37; - static constexpr KDCoordinate k_textMargin= 5; + static constexpr KDCoordinate k_textFieldHeight = 32; //37 + static constexpr KDCoordinate k_leftMargin = 5; + static constexpr KDCoordinate k_verticalMargin = 9; constexpr static int k_separatorThickness = 1; + KDCoordinate inputViewHeight() const; + KDCoordinate editableExpressionViewHeight() const; TableView * m_mainView; TextField m_textField; - char m_textBody[TextField::maxBufferSize()]; + EditableExpressionView m_editableExpressionView; + char m_textBody[k_bufferLength]; }; View * loadView() override; void unloadView(View * view) override; + void reloadView(); Shared::TextFieldDelegateApp * textFieldDelegateApp() override; + Shared::TextFieldAndEditableExpressionViewDelegateApp * textFieldAndEditableExpressionViewDelegateApp() override; + Poincare::ExpressionLayout * expressionLayout(); HistoryController * m_historyController; CalculationStore * m_calculationStore; }; diff --git a/apps/shared/editable_expression_view_delegate.cpp b/apps/shared/editable_expression_view_delegate.cpp index ab502a270..ff7542ed4 100644 --- a/apps/shared/editable_expression_view_delegate.cpp +++ b/apps/shared/editable_expression_view_delegate.cpp @@ -12,6 +12,22 @@ bool EditableExpressionViewDelegate::editableExpressionViewDidReceiveEvent(::Edi return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidReceiveEvent(editableExpressionView, event); } +bool EditableExpressionViewDelegate::editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { + return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidFinishEditing(editableExpressionView, text, event); +} + +bool EditableExpressionViewDelegate::editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) { + return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidAbortEditing(editableExpressionView, text); +} + +bool EditableExpressionViewDelegate::editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) { + return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidHandleEvent(editableExpressionView, event, returnValue, expressionHasChanged); +} + +void EditableExpressionViewDelegate::editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) { + return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidChangeSize(editableExpressionView); +} + Toolbox * EditableExpressionViewDelegate::toolboxForEditableExpressionView(::EditableExpressionView * editableExpressionView) { return textFieldAndEditableExpressionViewDelegateApp()->toolboxForEditableExpressionView(editableExpressionView); } diff --git a/apps/shared/editable_expression_view_delegate.h b/apps/shared/editable_expression_view_delegate.h index 438ae1acc..9c779b642 100644 --- a/apps/shared/editable_expression_view_delegate.h +++ b/apps/shared/editable_expression_view_delegate.h @@ -10,6 +10,10 @@ class EditableExpressionViewDelegate : public ::EditableExpressionViewDelegate { public: bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; + bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) override; + bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) override; + bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) override; + void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) override; Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) override; private: virtual TextFieldAndEditableExpressionViewDelegateApp * textFieldAndEditableExpressionViewDelegateApp() = 0; diff --git a/escher/include/escher/editable_expression_view.h b/escher/include/escher/editable_expression_view.h index 5d9f967a6..8041440ce 100644 --- a/escher/include/escher/editable_expression_view.h +++ b/escher/include/escher/editable_expression_view.h @@ -14,6 +14,7 @@ public: bool isEditing() const; void setEditing(bool isEditing); void scrollToCursor(); + void reload(); /* Responder */ Toolbox * toolbox() override; @@ -29,7 +30,6 @@ public: private: bool privateHandleEvent(Ion::Events::Event event); - void cursorOrLayoutChanged(); ExpressionViewWithCursor m_expressionViewWithCursor; EditableExpressionViewDelegate * m_delegate; }; diff --git a/escher/include/escher/editable_expression_view_delegate.h b/escher/include/escher/editable_expression_view_delegate.h index 6eb66bcdd..a6728caed 100644 --- a/escher/include/escher/editable_expression_view_delegate.h +++ b/escher/include/escher/editable_expression_view_delegate.h @@ -10,9 +10,10 @@ class EditableExpressionViewDelegate { public: virtual bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) = 0; virtual bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) = 0; - /*virtual bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { return false; }; - virtual bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) {return false;}; - virtual bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool textHasChanged) { return returnValue; };*/ // TODO? + virtual bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { return false; } + virtual bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) { return false; } + virtual bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) { return returnValue; } + virtual void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) {} virtual Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) = 0; }; diff --git a/escher/include/escher/expression_view.h b/escher/include/escher/expression_view.h index 25861e61f..cd3577f19 100644 --- a/escher/include/escher/expression_view.h +++ b/escher/include/escher/expression_view.h @@ -23,6 +23,7 @@ public: void setAlignment(float horizontalAlignment, float verticalAlignment); KDSize minimalSizeForOptimalDisplay() const override; KDPoint drawingOrigin() const; + KDPoint absoluteDrawingOrigin() const; private: /* Warning: we do not need to delete the previous expression layout when * deleting object or setting a new expression layout. Indeed, the expression diff --git a/escher/include/escher/expression_view_with_cursor.h b/escher/include/escher/expression_view_with_cursor.h index b362bb5f3..7588769bb 100644 --- a/escher/include/escher/expression_view_with_cursor.h +++ b/escher/include/escher/expression_view_with_cursor.h @@ -10,12 +10,12 @@ class ExpressionViewWithCursor : public View { public: ExpressionViewWithCursor(Poincare::ExpressionLayout * expressionLayout); - Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; } bool isEditing() const { return m_isEditing; } void setEditing(bool isEditing) { m_isEditing = isEditing; } void cursorPositionChanged(); KDRect cursorRect(); - const ExpressionView * expressionView() const { return &m_expressionView; } + Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; } + ExpressionView * expressionView() { return &m_expressionView; } /* View */ KDSize minimalSizeForOptimalDisplay() const override; private: diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index ef3082d2c..023028d0f 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -1,4 +1,5 @@ #include +#include #include EditableExpressionView::EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate) : @@ -28,8 +29,13 @@ Toolbox * EditableExpressionView::toolbox() { } bool EditableExpressionView::handleEvent(Ion::Events::Event event) { + KDSize previousSize = minimalSizeForOptimalDisplay(); if (privateHandleEvent(event)) { - cursorOrLayoutChanged(); + reload(); + KDSize newSize = minimalSizeForOptimalDisplay(); + if (m_delegate && previousSize.height() != newSize.height()) { + m_delegate->editableExpressionViewDidChangeSize(this); + } return true; } return false; @@ -44,6 +50,30 @@ KDSize EditableExpressionView::minimalSizeForOptimalDisplay() const { } bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { + if (m_delegate && m_delegate->editableExpressionViewDidReceiveEvent(this, event)) { + return true; + } + if (Responder::handleEvent(event)) { + /* The only event Responder handles is 'Toolbox' displaying. In that case, + * the EditableExpressionView is forced into editing mode. */ + if (!isEditing()) { + setEditing(true); + } + return true; + } + if (isEditing() && editableExpressionViewShouldFinishEditing(event)) { + setEditing(false); + int bufferSize = TextField::maxBufferSize(); + char buffer[bufferSize]; + m_expressionViewWithCursor.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); + if (m_delegate->editableExpressionViewDidFinishEditing(this, buffer, event)) { + delete m_expressionViewWithCursor.expressionView()->expressionLayout(); + Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout(); + m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout); + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout); + } + return true; + } if (event == Ion::Events::Left) { return m_expressionViewWithCursor.cursor()->moveLeft(); } @@ -121,14 +151,22 @@ void EditableExpressionView::insertLayoutAtCursor(Poincare::ExpressionLayout * l if (layout == nullptr) { return; } + KDSize previousSize = minimalSizeForOptimalDisplay(); m_expressionViewWithCursor.cursor()->addLayout(layout); m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); - cursorOrLayoutChanged(); + KDSize newSize = minimalSizeForOptimalDisplay(); + reload(); + if (m_delegate && previousSize.height() != newSize.height()) { + m_delegate->editableExpressionViewDidChangeSize(this); + } } -void EditableExpressionView::cursorOrLayoutChanged() { +void EditableExpressionView::reload() { m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); + m_expressionViewWithCursor.cursorPositionChanged(); layoutSubviews(); + scrollToCursor(); + markRectAsDirty(bounds()); } diff --git a/escher/src/expression_view.cpp b/escher/src/expression_view.cpp index 0fa196d63..dfd23e3b3 100644 --- a/escher/src/expression_view.cpp +++ b/escher/src/expression_view.cpp @@ -49,8 +49,11 @@ KDSize ExpressionView::minimalSizeForOptimalDisplay() const { KDPoint ExpressionView::drawingOrigin() const { KDSize expressionSize = m_expressionLayout->size(); - return KDPoint(m_horizontalAlignment*(m_frame.width() - expressionSize.width()), - 0.5f*(m_frame.height() - expressionSize.height())); + return KDPoint(m_horizontalAlignment*(m_frame.width() - expressionSize.width()), 0.5f*(m_frame.height() - expressionSize.height())); +} + +KDPoint ExpressionView::absoluteDrawingOrigin() const { + return drawingOrigin().translatedBy(m_frame.topLeft()); } void ExpressionView::drawRect(KDContext * ctx, KDRect rect) const { diff --git a/escher/src/expression_view_with_cursor.cpp b/escher/src/expression_view_with_cursor.cpp index b231aea65..b5889eb06 100644 --- a/escher/src/expression_view_with_cursor.cpp +++ b/escher/src/expression_view_with_cursor.cpp @@ -25,7 +25,10 @@ KDRect ExpressionViewWithCursor::cursorRect() { KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { KDSize expressionViewSize = m_expressionView.minimalSizeForOptimalDisplay(); - return KDSize(expressionViewSize.width()+1, m_expressionView.minimalSizeForOptimalDisplay().height()); // +1 for the cursor + KDSize cursorSize = isEditing() ? m_cursorView.minimalSizeForOptimalDisplay() : KDSizeZero; + KDCoordinate resultWidth = expressionViewSize.width() + cursorSize.width(); + KDCoordinate resultHeight = expressionViewSize.height() + cursorSize.height()/2; + return KDSize(resultWidth, resultHeight); } View * ExpressionViewWithCursor::subviewAtIndex(int index) { @@ -40,7 +43,7 @@ void ExpressionViewWithCursor::layoutSubviews() { } void ExpressionViewWithCursor::layoutCursorSubview() { - KDPoint expressionViewOrigin = m_expressionView.drawingOrigin(); + KDPoint expressionViewOrigin = m_expressionView.absoluteDrawingOrigin(); KDPoint cursoredExpressionViewOrigin = m_cursor.pointedExpressionLayout()->absoluteOrigin(); KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x(); if (m_cursor.position() == ExpressionLayoutCursor::Position::Right) { From 53556ffacff9639af61b02c2248d76c010defe66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 15:17:42 +0100 Subject: [PATCH 173/257] [apps/calculation] Handle "ans" event in EditableExpressionView. Change-Id: I7761f36b5a94bb5c8190cd5b238542280666c256 --- apps/calculation/Makefile | 1 + .../edit_expression_controller.cpp | 2 +- apps/calculation/edit_expression_controller.h | 9 +++--- apps/calculation/editable_expression_view.cpp | 29 +++++++++++++++++++ apps/calculation/editable_expression_view.h | 16 ++++++++++ .../include/escher/editable_expression_view.h | 5 ++-- 6 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 apps/calculation/editable_expression_view.cpp create mode 100644 apps/calculation/editable_expression_view.h diff --git a/apps/calculation/Makefile b/apps/calculation/Makefile index c25380236..420391945 100644 --- a/apps/calculation/Makefile +++ b/apps/calculation/Makefile @@ -5,6 +5,7 @@ app_objs += $(addprefix apps/calculation/,\ app.o\ calculation.o\ calculation_store.o\ + editable_expression_view.o\ edit_expression_controller.o\ history_view_cell.o\ history_controller.o\ diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 90d8cd36d..44b118046 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -175,7 +175,7 @@ bool EditExpressionController::editableExpressionViewDidAbortEditing(::EditableE return false; } -void EditExpressionController::editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) { +void EditExpressionController::editableExpressionViewDidChangeSize(::EditableExpressionView * editableExpressionView) { assert(editableExpressionView == ((ContentView *)view())->editableExpressionView()); reloadView(); } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index b9c8f4514..bf26f73e8 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -2,6 +2,7 @@ #define CALCULATION_EDIT_EXPRESSION_CONTROLLER_H #include +#include "editable_expression_view.h" #include "../shared/text_field_delegate.h" #include "../shared/editable_expression_view_delegate.h" #include "history_controller.h" @@ -27,10 +28,10 @@ public: bool textFieldDidAbortEditing(::TextField * textField, const char * text) override; /* EditableExpressionViewDelegate */ - bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; - bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) override; - bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) override; - void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) override; + bool editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; + bool editableExpressionViewDidFinishEditing(::EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) override; + bool editableExpressionViewDidAbortEditing(::EditableExpressionView * editableExpressionView, const char * text) override; + void editableExpressionViewDidChangeSize(::EditableExpressionView * editableExpressionView) override; private: class ContentView : public View { diff --git a/apps/calculation/editable_expression_view.cpp b/apps/calculation/editable_expression_view.cpp new file mode 100644 index 000000000..fd1d30e8a --- /dev/null +++ b/apps/calculation/editable_expression_view.cpp @@ -0,0 +1,29 @@ +#include "editable_expression_view.h" + +namespace Calculation { + +bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { + if (event == Ion::Events::Back) { + return false; + } + if (event == Ion::Events::Ans) { + m_expressionViewWithCursor.cursor()->insertText("ans"); + return true; + } + Poincare::ExpressionLayout * layout = m_expressionViewWithCursor.expressionView()->expressionLayout(); + bool layoutIsEmpty = layout->isEmpty() + || (layout->isHorizontal() + && layout->numberOfChildren() == 0); + if (isEditing() && layoutIsEmpty && + (event == Ion::Events::Multiplication || + event == Ion::Events::Plus || + event == Ion::Events::Power || + event == Ion::Events::Square || + event == Ion::Events::Division || + event == Ion::Events::Sto)) { + m_expressionViewWithCursor.cursor()->insertText("ans"); + } + return(::EditableExpressionView::privateHandleEvent(event)); +} + +} diff --git a/apps/calculation/editable_expression_view.h b/apps/calculation/editable_expression_view.h new file mode 100644 index 000000000..204328434 --- /dev/null +++ b/apps/calculation/editable_expression_view.h @@ -0,0 +1,16 @@ +#ifndef CALCULATION_EDITABLE_EXPRESSION_VIEW_H +#define CALCULATION_EDITABLE_EXPRESSION_VIEW_H + +#include + +namespace Calculation { + +class EditableExpressionView : public ::EditableExpressionView { + using ::EditableExpressionView::EditableExpressionView; +protected: + bool privateHandleEvent(Ion::Events::Event event) override; +}; + +} + +#endif diff --git a/escher/include/escher/editable_expression_view.h b/escher/include/escher/editable_expression_view.h index 8041440ce..456535f0a 100644 --- a/escher/include/escher/editable_expression_view.h +++ b/escher/include/escher/editable_expression_view.h @@ -28,9 +28,10 @@ public: /* View */ KDSize minimalSizeForOptimalDisplay() const override; -private: - bool privateHandleEvent(Ion::Events::Event event); +protected: + virtual bool privateHandleEvent(Ion::Events::Event event); ExpressionViewWithCursor m_expressionViewWithCursor; +private: EditableExpressionViewDelegate * m_delegate; }; From 86b29f7e2f98df919605c2c30a4d9d1746c51878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 15:25:55 +0100 Subject: [PATCH 174/257] [apps/calculation] Fix rendering bug. When powering off then on the device, the EditableExpressionView had a rendering bug on the bottom left corner. Change-Id: I1792831f949b8e646fff68b9e784c1ff573516fc --- apps/calculation/edit_expression_controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 44b118046..625d25d51 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -58,7 +58,7 @@ void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rec // Draw the separator ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight-k_separatorThickness, bounds().width(), k_separatorThickness), Palette::GreyMiddle); // Color the left margin - ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, k_leftMargin, k_textFieldHeight), m_textField.backgroundColor()); + ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, k_leftMargin, inputViewFrameHeight), m_textField.backgroundColor()); if (!editionIsInTextField()) { // Color the upper margin ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, bounds().width(), k_verticalMargin), m_textField.backgroundColor()); From e1235cdb4f07cfa5e10f6d02d8155a8add3904a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 15:33:57 +0100 Subject: [PATCH 175/257] [escher] EditableExpressionView: Remove the cursor when not editing. Change-Id: If333f6074bce39d71ceb89b9424f7fec26a1f0c6 --- apps/calculation/editable_expression_view.cpp | 6 ++++++ apps/calculation/editable_expression_view.h | 3 ++- escher/include/escher/expression_view_with_cursor.h | 2 +- escher/src/expression_view_with_cursor.cpp | 10 ++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/calculation/editable_expression_view.cpp b/apps/calculation/editable_expression_view.cpp index fd1d30e8a..a06287c2c 100644 --- a/apps/calculation/editable_expression_view.cpp +++ b/apps/calculation/editable_expression_view.cpp @@ -2,6 +2,12 @@ namespace Calculation { +EditableExpressionView::EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate) : + ::EditableExpressionView(parentResponder, expressionLayout, delegate) +{ + setEditing(true); +} + bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { if (event == Ion::Events::Back) { return false; diff --git a/apps/calculation/editable_expression_view.h b/apps/calculation/editable_expression_view.h index 204328434..f873e9115 100644 --- a/apps/calculation/editable_expression_view.h +++ b/apps/calculation/editable_expression_view.h @@ -6,7 +6,8 @@ namespace Calculation { class EditableExpressionView : public ::EditableExpressionView { - using ::EditableExpressionView::EditableExpressionView; +public: + EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate = nullptr); protected: bool privateHandleEvent(Ion::Events::Event event) override; }; diff --git a/escher/include/escher/expression_view_with_cursor.h b/escher/include/escher/expression_view_with_cursor.h index 7588769bb..3128d3aca 100644 --- a/escher/include/escher/expression_view_with_cursor.h +++ b/escher/include/escher/expression_view_with_cursor.h @@ -11,7 +11,7 @@ class ExpressionViewWithCursor : public View { public: ExpressionViewWithCursor(Poincare::ExpressionLayout * expressionLayout); bool isEditing() const { return m_isEditing; } - void setEditing(bool isEditing) { m_isEditing = isEditing; } + void setEditing(bool isEditing); void cursorPositionChanged(); KDRect cursorRect(); Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; } diff --git a/escher/src/expression_view_with_cursor.cpp b/escher/src/expression_view_with_cursor.cpp index b5889eb06..f53fa5aa8 100644 --- a/escher/src/expression_view_with_cursor.cpp +++ b/escher/src/expression_view_with_cursor.cpp @@ -15,6 +15,12 @@ ExpressionViewWithCursor::ExpressionViewWithCursor(ExpressionLayout * expression m_expressionView.setExpressionLayout(expressionLayout); } +void ExpressionViewWithCursor::setEditing(bool isEditing) { + m_isEditing = isEditing; + markRectAsDirty(bounds()); + layoutSubviews(); +} + void ExpressionViewWithCursor::cursorPositionChanged() { layoutCursorSubview(); } @@ -43,6 +49,10 @@ void ExpressionViewWithCursor::layoutSubviews() { } void ExpressionViewWithCursor::layoutCursorSubview() { + if (!m_isEditing) { + m_cursorView.setFrame(KDRectZero); + return; + } KDPoint expressionViewOrigin = m_expressionView.absoluteDrawingOrigin(); KDPoint cursoredExpressionViewOrigin = m_cursor.pointedExpressionLayout()->absoluteOrigin(); KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x(); From 1d701f3305213655c6af8894e376f6b51e9e5286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 16:07:09 +0100 Subject: [PATCH 176/257] [apps] Handle EditableExpressionView in VariableBoxController. Change-Id: Ibd5f1b1a8999241c8aa818a075f48adb28c4032e --- ..._editable_expression_view_delegate_app.cpp | 2 +- apps/shared/text_field_delegate_app.cpp | 2 +- apps/variable_box_controller.cpp | 106 ++++++++++-------- apps/variable_box_controller.h | 14 ++- .../include/escher/editable_expression_view.h | 3 + escher/src/editable_expression_view.cpp | 5 + 6 files changed, 81 insertions(+), 51 deletions(-) diff --git a/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp b/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp index 2fd015231..516c4a466 100644 --- a/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp +++ b/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp @@ -36,7 +36,7 @@ bool TextFieldAndEditableExpressionViewDelegateApp::editableExpressionViewDidRec } AppsContainer * appsContainer = (AppsContainer *)editableExpressionView->app()->container(); VariableBoxController * variableBoxController = appsContainer->variableBoxController(); - variableBoxController->setEditableExpressionViewCaller(editableExpressionView); + variableBoxController->setEditableExpressionViewSender(editableExpressionView); editableExpressionView->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin); return true; } diff --git a/apps/shared/text_field_delegate_app.cpp b/apps/shared/text_field_delegate_app.cpp index 1678f234e..de8df6c42 100644 --- a/apps/shared/text_field_delegate_app.cpp +++ b/apps/shared/text_field_delegate_app.cpp @@ -93,7 +93,7 @@ bool TextFieldDelegateApp::textFieldDidReceiveEvent(TextField * textField, Ion:: } AppsContainer * appsContainer = (AppsContainer *)textField->app()->container(); VariableBoxController * variableBoxController = appsContainer->variableBoxController(); - variableBoxController->setTextFieldCaller(textField); + variableBoxController->setTextFieldSender(textField); textField->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin); return true; } diff --git a/apps/variable_box_controller.cpp b/apps/variable_box_controller.cpp index 72c2b9b63..44be6b710 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/variable_box_controller.cpp @@ -10,7 +10,7 @@ using namespace Poincare; VariableBoxController::ContentViewController::ContentViewController(Responder * parentResponder, GlobalContext * context) : ViewController(parentResponder), m_context(context), - m_textFieldCaller(nullptr), + m_sender(nullptr), m_firstSelectedRow(0), m_previousSelectedRow(0), m_currentPage(Page::RootMenu), @@ -18,14 +18,13 @@ VariableBoxController::ContentViewController::ContentViewController(Responder * { } -const char * VariableBoxController::ContentViewController::title() { - return I18n::translate(I18n::Message::Variables); -} - View * VariableBoxController::ContentViewController::view() { return &m_selectableTableView; } +const char * VariableBoxController::ContentViewController::title() { + return I18n::translate(I18n::Message::Variables); +} void VariableBoxController::ContentViewController::didBecomeFirstResponder() { m_selectableTableView.reloadData(); m_selectableTableView.scrollToCell(0,0); @@ -65,11 +64,7 @@ bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Even char label[3]; putLabelAtIndexInBuffer(selectedRow(), label); const char * editedText = label; - if (!m_textFieldCaller->isEditing()) { - m_textFieldCaller->setEditing(true); - } - m_textFieldCaller->insertTextAtLocation(editedText, m_textFieldCaller->cursorLocation()); - m_textFieldCaller->setCursorLocation(m_textFieldCaller->cursorLocation() + strlen(editedText)); + m_insertTextAction(m_sender, editedText); #if MATRIX_VARIABLES m_selectableTableView.deselectTable(); m_currentPage = Page::RootMenu; @@ -202,21 +197,31 @@ int VariableBoxController::ContentViewController::typeAtLocation(int i, int j) { return 0; } -const Expression * VariableBoxController::ContentViewController::expressionForIndex(int index) { - if (m_currentPage == Page::Scalar) { - const Symbol symbol = Symbol('A'+index); - return m_context->expressionForSymbol(&symbol); - } - if (m_currentPage == Page::Matrix) { - const Symbol symbol = Symbol::matrixSymbol('0'+(char)index); - return m_context->expressionForSymbol(&symbol); - } -#if LIST_VARIABLES - if (m_currentPage == Page::List) { - return nullptr; - } +void VariableBoxController::ContentViewController::setTextFieldSender(TextField * textField) { + m_sender = textField; + m_insertTextAction = &insertTextInTextField; +} + +void VariableBoxController::ContentViewController::setEditableExpressionViewSender(EditableExpressionView * editableExpressionView) { + m_sender = editableExpressionView; + m_insertTextAction = &insertTextInEditableExpressionView; +} + +void VariableBoxController::ContentViewController::reloadData() { + m_selectableTableView.reloadData(); +} + +void VariableBoxController::ContentViewController::resetPage() { +#if MATRIX_VARIABLES + m_currentPage = Page::RootMenu; +#else + m_currentPage = Page::Scalar; #endif - return nullptr; +} + +void VariableBoxController::ContentViewController::viewDidDisappear() { + m_selectableTableView.deselectTable(); + ViewController::viewDidDisappear(); } VariableBoxController::ContentViewController::Page VariableBoxController::ContentViewController::pageAtIndex(int index) { @@ -257,25 +262,38 @@ I18n::Message VariableBoxController::ContentViewController::nodeLabelAtIndex(int return labels[index]; } -void VariableBoxController::ContentViewController::setTextFieldCaller(TextField * textField) { - m_textFieldCaller = textField; -} - -void VariableBoxController::ContentViewController::reloadData() { - m_selectableTableView.reloadData(); -} - -void VariableBoxController::ContentViewController::resetPage() { -#if MATRIX_VARIABLES - m_currentPage = Page::RootMenu; -#else - m_currentPage = Page::Scalar; +const Expression * VariableBoxController::ContentViewController::expressionForIndex(int index) { + if (m_currentPage == Page::Scalar) { + const Symbol symbol = Symbol('A'+index); + return m_context->expressionForSymbol(&symbol); + } + if (m_currentPage == Page::Matrix) { + const Symbol symbol = Symbol::matrixSymbol('0'+(char)index); + return m_context->expressionForSymbol(&symbol); + } +#if LIST_VARIABLES + if (m_currentPage == Page::List) { + return nullptr; + } #endif + return nullptr; } -void VariableBoxController::ContentViewController::viewDidDisappear() { - m_selectableTableView.deselectTable(); - ViewController::viewDidDisappear(); +void VariableBoxController::ContentViewController::insertTextInTextField(void * sender, const char * textToInsert) { + TextField * textField = static_cast(sender); + if (!textField->isEditing()) { + textField->setEditing(true); + } + textField->insertTextAtLocation(textToInsert, textField->cursorLocation()); + textField->setCursorLocation(textField->cursorLocation() + strlen(textToInsert)); +} + +void VariableBoxController::ContentViewController::insertTextInEditableExpressionView(void * sender, const char * textToInsert) { + EditableExpressionView * editableExpressionView = static_cast(sender); + if (!editableExpressionView->isEditing()) { + editableExpressionView->setEditing(true); + } + editableExpressionView->insertTextAtCursor(textToInsert); } VariableBoxController::VariableBoxController(GlobalContext * context) : @@ -288,12 +306,12 @@ void VariableBoxController::didBecomeFirstResponder() { app()->setFirstResponder(&m_contentViewController); } -void VariableBoxController::setTextFieldCaller(TextField * textField) { - m_contentViewController.setTextFieldCaller(textField); +void VariableBoxController::setTextFieldSender(TextField * textField) { + m_contentViewController.setTextFieldSender(textField); } -void VariableBoxController::setEditableExpressionViewCaller(EditableExpressionView * editableExpressionView) { - //TODO +void VariableBoxController::setEditableExpressionViewSender(EditableExpressionView * editableExpressionView) { + m_contentViewController.setEditableExpressionViewSender(editableExpressionView); } void VariableBoxController::viewWillAppear() { diff --git a/apps/variable_box_controller.h b/apps/variable_box_controller.h index 1617c1a31..daa75938e 100644 --- a/apps/variable_box_controller.h +++ b/apps/variable_box_controller.h @@ -10,10 +10,11 @@ class VariableBoxController : public StackViewController { public: + typedef void (*Action)(void * sender, const char * text); VariableBoxController(Poincare::GlobalContext * context); void didBecomeFirstResponder() override; - void setTextFieldCaller(TextField * textField); - void setEditableExpressionViewCaller(EditableExpressionView * editableExpressionView); + void setTextFieldSender(TextField * textField); + void setEditableExpressionViewSender(EditableExpressionView * editableExpressionView); void viewWillAppear() override; void viewDidDisappear() override; private: @@ -32,7 +33,8 @@ private: KDCoordinate cumulatedHeightFromIndex(int j) override; int indexFromCumulatedHeight(KDCoordinate offsetY) override; int typeAtLocation(int i, int j) override; - void setTextFieldCaller(TextField * textField); + void setTextFieldSender(TextField * textField); + void setEditableExpressionViewSender(EditableExpressionView * editableExpressionView); void reloadData(); void resetPage(); void viewDidDisappear() override; @@ -56,9 +58,11 @@ private: void putLabelAtIndexInBuffer(int index, char * buffer); I18n::Message nodeLabelAtIndex(int index); const Poincare::Expression * expressionForIndex(int index); - + static void insertTextInTextField(void * sender, const char * textToInsert); + static void insertTextInEditableExpressionView(void * sender, const char * textToInsert); Poincare::GlobalContext * m_context; - TextField * m_textFieldCaller; + Responder * m_sender; + Action m_insertTextAction; int m_firstSelectedRow; int m_previousSelectedRow; Page m_currentPage; diff --git a/escher/include/escher/editable_expression_view.h b/escher/include/escher/editable_expression_view.h index 456535f0a..b6473af4a 100644 --- a/escher/include/escher/editable_expression_view.h +++ b/escher/include/escher/editable_expression_view.h @@ -25,6 +25,9 @@ public: /* Callback for MathToolbox */ void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout); + /* Callback for VariableBoxController */ + void insertTextAtCursor(const char * text); + /* View */ KDSize minimalSizeForOptimalDisplay() const override; diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index 023028d0f..8f0ccb5c7 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -163,6 +163,11 @@ void EditableExpressionView::insertLayoutAtCursor(Poincare::ExpressionLayout * l } } +void EditableExpressionView::insertTextAtCursor(const char * text) { + m_expressionViewWithCursor.cursor()->insertText(text); + reload(); +} + void EditableExpressionView::reload() { m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); m_expressionViewWithCursor.cursorPositionChanged(); From f50391689f86a452d912b19215ffbde83de2a943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 16:19:26 +0100 Subject: [PATCH 177/257] [apps/calculation] Handle OK event in calculation history. Change-Id: I3e4c309a3bc031476eea0d64d433b535b1220a8f --- apps/calculation/edit_expression_controller.cpp | 14 ++++++++++---- apps/variable_box_controller.cpp | 2 +- escher/include/escher/editable_expression_view.h | 5 +---- escher/src/editable_expression_view.cpp | 10 +++++++++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 625d25d51..3bc7054b9 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -85,10 +85,16 @@ const char * EditExpressionController::textBody() { } void EditExpressionController::insertTextBody(const char * text) { - TextField * tf = ((ContentView *)view())->textField(); - tf->setEditing(true, false); - tf->insertTextAtLocation(text, tf->cursorLocation()); - tf->setCursorLocation(tf->cursorLocation() + strlen(text)); + if (((ContentView *)view())->editionIsInTextField()) { + TextField * tf = ((ContentView *)view())->textField(); + tf->setEditing(true, false); + tf->insertTextAtLocation(text, tf->cursorLocation()); + tf->setCursorLocation(tf->cursorLocation() + strlen(text)); + return; + } + EditableExpressionView * editableExpressionView = ((ContentView *)view())->editableExpressionView(); + editableExpressionView->setEditing(true); + editableExpressionView->insertLayoutFromTextAtCursor(text); } bool EditExpressionController::handleEvent(Ion::Events::Event event) { diff --git a/apps/variable_box_controller.cpp b/apps/variable_box_controller.cpp index 44be6b710..3f14cc49c 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/variable_box_controller.cpp @@ -293,7 +293,7 @@ void VariableBoxController::ContentViewController::insertTextInEditableExpressio if (!editableExpressionView->isEditing()) { editableExpressionView->setEditing(true); } - editableExpressionView->insertTextAtCursor(textToInsert); + editableExpressionView->insertLayoutFromTextAtCursor(textToInsert); } VariableBoxController::VariableBoxController(GlobalContext * context) : diff --git a/escher/include/escher/editable_expression_view.h b/escher/include/escher/editable_expression_view.h index b6473af4a..f4cf92423 100644 --- a/escher/include/escher/editable_expression_view.h +++ b/escher/include/escher/editable_expression_view.h @@ -22,11 +22,8 @@ public: bool editableExpressionViewShouldFinishEditing(Ion::Events::Event event); - /* Callback for MathToolbox */ void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout); - - /* Callback for VariableBoxController */ - void insertTextAtCursor(const char * text); + void insertLayoutFromTextAtCursor(const char * text); /* View */ KDSize minimalSizeForOptimalDisplay() const override; diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index 8f0ccb5c7..d23cf1097 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -163,7 +163,15 @@ void EditableExpressionView::insertLayoutAtCursor(Poincare::ExpressionLayout * l } } -void EditableExpressionView::insertTextAtCursor(const char * text) { +void EditableExpressionView::insertLayoutFromTextAtCursor(const char * text) { + Poincare::Expression * expression = Poincare::Expression::parse(text); + if (expression != nullptr) { + Poincare::ExpressionLayout * layout = expression->createLayout(); + delete expression; + insertLayoutAtCursor(layout, layout); + reload(); + return; + } m_expressionViewWithCursor.cursor()->insertText(text); reload(); } From fc2788cc794dd4cb70c27089eade02dc52ada01c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 16:32:28 +0100 Subject: [PATCH 178/257] [apps/Makefile] Remove the ExpressionEditor app. Change-Id: I5bcb5064bf1335abda8d6e032eb00f1798463797 --- apps/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/Makefile b/apps/Makefile index f99c5bae4..01098023f 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,5 +1,5 @@ EPSILON_I18N_LANGUAGES ?= en fr es de pt -EPSILON_APPS ?= expression_editor calculation +EPSILON_APPS ?= calculation include apps/shared/Makefile include apps/home/Makefile From 62ae5840e9d3199c8a6aaac23b83a009b6ed2026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 16:33:03 +0100 Subject: [PATCH 179/257] [apps/poincare] Handle cursor positioning in EditableExpressionView. There cursor was not in the right place for log(), cos(), ... Change-Id: I8fe1f350f3054460204cb5d40508212642333e3e --- escher/src/editable_expression_view.cpp | 4 ---- poincare/include/poincare/expression_layout_cursor.h | 1 - poincare/src/expression_layout_cursor.cpp | 12 +++++++----- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index d23cf1097..40b4a30b0 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -108,10 +108,6 @@ bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { m_expressionViewWithCursor.cursor()->addEmptyExponentialLayout(); return true; } - if (event == Ion::Events::Log) { - m_expressionViewWithCursor.cursor()->addEmptyLogarithmLayout(); - return true; - } if (event == Ion::Events::Power) { m_expressionViewWithCursor.cursor()->addEmptyPowerLayout(); return true; diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 3a444399f..bf3dcd900 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -42,7 +42,6 @@ public: void addLayout(ExpressionLayout * layout); void addEmptyExponentialLayout(); void addFractionLayoutAndCollapseBrothers(); - void addEmptyLogarithmLayout(); void addEmptyMatrixLayout(int numberOfRows = 1, int numberOfColumns = 1); void addEmptyPowerLayout(); void addEmptySquareRootLayout(); diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 86c30a923..c7ad5e9bb 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -99,11 +99,6 @@ void ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers() { setPosition(Position::Left); } -void ExpressionLayoutCursor::addEmptyLogarithmLayout() { - insertText("log()"); - setPosition(ExpressionLayoutCursor::Position::Left); -} - void ExpressionLayoutCursor::addEmptyMatrixLayout(int numberOfRows, int numberOfColumns) { assert(numberOfRows > 0); assert(numberOfColumns > 0); @@ -181,9 +176,13 @@ void ExpressionLayoutCursor::insertText(const char * text) { return; } ExpressionLayout * newChild = nullptr; + ExpressionLayout * pointedChild = nullptr; for (int i = 0; i < textLength; i++) { if (text[i] == '(') { newChild = new ParenthesisLeftLayout(); + if (pointedChild == nullptr) { + pointedChild = newChild; + } } else if (text[i] == ')') { newChild = new ParenthesisRightLayout(); } else if (text[i] == '[') { @@ -197,6 +196,9 @@ void ExpressionLayoutCursor::insertText(const char * text) { m_pointedExpressionLayout = newChild; m_position = Position::Right; } + if (pointedChild != nullptr) { + m_pointedExpressionLayout = pointedChild; + } } void ExpressionLayoutCursor::performBackspace() { From 7abcfecb9c0d4168515759bbe90ebeca64785689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 16:37:53 +0100 Subject: [PATCH 180/257] [poincare] Change empty Power layout deletion. Change-Id: Id9b6b0c2701d70f436c3a033c23c120a41f7feda --- poincare/src/layout/vertical_offset_layout.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp index 2da4b08b3..6af0a64d6 100644 --- a/poincare/src/layout/vertical_offset_layout.cpp +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -26,9 +26,10 @@ void VerticalOffsetLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { int indexInParent = m_parent->indexOfChild(this); if (base->isEmpty()) { // Case: Empty base and indice. - // Replace with the empty base layout. - m_parent->removeChildAtIndex(indexInParent - 1, false); - replaceWithAndMoveCursor(base, true, cursor); + // Remove both the base and the indice layout. + ExpressionLayout * parent = m_parent; + parent->removePointedChildAtIndexAndMoveCursor(indexInParent, true, cursor); + parent->removePointedChildAtIndexAndMoveCursor(indexInParent-1, true, cursor); return; } // Case: Empty indice only. From 24a22fb3747650e9721b95ede3ee55e9df747f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 16:54:10 +0100 Subject: [PATCH 181/257] [apps/calculation] Delete layout when unloading view. Change-Id: I7c7afc4882051266c04f28cf2823d58c803f05c0 --- apps/calculation/edit_expression_controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 3bc7054b9..93f3b906a 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -199,6 +199,7 @@ View * EditExpressionController::loadView() { } void EditExpressionController::unloadView(View * view) { + delete expressionLayout(); delete view; } From 4673358f6032a6a36ea93ff12b3d9df9ef51e22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 17:28:49 +0100 Subject: [PATCH 182/257] [poincare] Fix RootLayout deletion. Change-Id: If9aa315299ce687e208ff3ea81346cbe29a5d03e --- poincare/src/layout/expression_layout.cpp | 11 +++-------- poincare/src/layout/horizontal_layout.cpp | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 8dfe2fb18..03a789c65 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -180,15 +180,10 @@ void ExpressionLayout::replaceChild(const ExpressionLayout * oldChild, Expressio void ExpressionLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { int oldChildIndex = indexOfChild(oldChild); - assert(oldChildIndex >= 0); - if (oldChildIndex == 0) { - cursor->setPointedExpressionLayout(this); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); - } else { - cursor->setPointedExpressionLayout(editableChild(oldChildIndex - 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - } + assert(indexOfChild(oldChild) >= 0); replaceChild(oldChild, newChild, deleteOldChild); + cursor->setPointedExpressionLayout(newChild); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); } void ExpressionLayout::detachChild(const ExpressionLayout * e) { diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 19ee6021b..0847eabb0 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -141,7 +141,7 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex return; } cursor->setPointedExpressionLayout(newChild); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); return; } From 6f8a1979d21e3fb17ad75f28681fb1b346783aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 17:29:21 +0100 Subject: [PATCH 183/257] [poincare] Remove superfluous parentheses when serializing fractions. Change-Id: I2f24d67293ed26fbe5aab3035c49ae162fdefab0 --- poincare/src/layout/fraction_layout.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 2f2d14dfe..066047caa 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -161,16 +161,10 @@ int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize) const { int numberOfChar = 0; if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - // Write the first enclosing parenthesis. - buffer[numberOfChar++] = '('; - if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - // Write the content of the fraction numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, "/"); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - // Write the second enclosing parenthesis. - buffer[numberOfChar++] = ')'; + if (numberOfChar >= bufferSize-1) { return bufferSize-1; } buffer[numberOfChar] = 0; return numberOfChar; } From 627e96e5e3f9ce56e9189318400972b43eed23cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 17:30:55 +0100 Subject: [PATCH 184/257] [escher] Black cursor color. Change-Id: I150e4f51a1162ded51af5e6a72cdaa70b428965d --- escher/src/text_cursor_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/text_cursor_view.cpp b/escher/src/text_cursor_view.cpp index fd2ea48f1..6ef9a6ebe 100644 --- a/escher/src/text_cursor_view.cpp +++ b/escher/src/text_cursor_view.cpp @@ -2,7 +2,7 @@ void TextCursorView::drawRect(KDContext * ctx, KDRect rect) const { KDCoordinate height = bounds().height(); - ctx->fillRect(KDRect(0, 0, 1, height), KDColorRed); + ctx->fillRect(KDRect(0, 0, 1, height), KDColorBlack); } KDSize TextCursorView::minimalSizeForOptimalDisplay() const { From 51e33b69036482fd232f44f706cf268229f793a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 17:33:58 +0100 Subject: [PATCH 185/257] [apps/calculation] Fix margins. Change-Id: If799563af90c9de4ea02d3177a0ee2375d8ddbb4 --- apps/calculation/edit_expression_controller.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index bf26f73e8..a28d36a41 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -48,9 +48,9 @@ private: bool editionIsInTextField() const { return true; } //TODO static constexpr int k_bufferLength = TextField::maxBufferSize(); private: - static constexpr KDCoordinate k_textFieldHeight = 32; //37 + static constexpr KDCoordinate k_textFieldHeight = 32; static constexpr KDCoordinate k_leftMargin = 5; - static constexpr KDCoordinate k_verticalMargin = 9; + static constexpr KDCoordinate k_verticalMargin = 5; constexpr static int k_separatorThickness = 1; KDCoordinate inputViewHeight() const; KDCoordinate editableExpressionViewHeight() const; From 60127036b7a5bd2af84c3e1d82a649047c86e8c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 16 Jan 2018 18:03:04 +0100 Subject: [PATCH 186/257] [poincare] Fix unused variable. Change-Id: I45cda6d12666a90d24eb4f0f03149ed083e5d68d --- poincare/src/layout/expression_layout.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 03a789c65..ec6184b1b 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -179,7 +179,6 @@ void ExpressionLayout::replaceChild(const ExpressionLayout * oldChild, Expressio } void ExpressionLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { - int oldChildIndex = indexOfChild(oldChild); assert(indexOfChild(oldChild) >= 0); replaceChild(oldChild, newChild, deleteOldChild); cursor->setPointedExpressionLayout(newChild); From 8ab8ef4c5f728ab708acb6e1f19abe2cf7447299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 10:38:43 +0100 Subject: [PATCH 187/257] [apps/settings] Add a setting for the edition mode (1D or 2D). Change-Id: Ia6783d3443a8b059e67a293a517bc652950aab55 --- apps/Makefile | 2 +- apps/settings/base.de.i18n | 3 ++ apps/settings/base.en.i18n | 3 ++ apps/settings/base.es.i18n | 3 ++ apps/settings/base.fr.i18n | 3 ++ apps/settings/base.pt.i18n | 3 ++ apps/settings/main_controller.cpp | 37 +++++++++++++++---------- apps/settings/main_controller.h | 6 ++-- apps/settings/sub_controller.cpp | 8 +++++- poincare/include/poincare/preferences.h | 7 +++++ poincare/src/preferences.cpp | 9 ++++++ 11 files changed, 65 insertions(+), 19 deletions(-) diff --git a/apps/Makefile b/apps/Makefile index 01098023f..4072eb811 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,5 +1,5 @@ EPSILON_I18N_LANGUAGES ?= en fr es de pt -EPSILON_APPS ?= calculation +EPSILON_APPS ?= calculation settings include apps/shared/Makefile include apps/home/Makefile diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n index 37faed397..c7a9992ab 100644 --- a/apps/settings/base.de.i18n +++ b/apps/settings/base.de.i18n @@ -2,6 +2,9 @@ SettingsApp = "Einstellungen" SettingsAppCapital = "EINSTELLUNGEN" AngleUnit = "Winkeleinheit" DisplayMode = "Zahlenformat" +EditionMode = "Editiermodus" +EditionLinear = "1D " +Edition2D = "2D " ComplexFormat = "Komplex" ExamMode = "Testmodus" ActivateExamMode = "Start Testmodus" diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n index 6ed3a0c64..c2188e480 100644 --- a/apps/settings/base.en.i18n +++ b/apps/settings/base.en.i18n @@ -2,6 +2,9 @@ SettingsApp = "Settings" SettingsAppCapital = "SETTINGS" AngleUnit = "Angle measure" DisplayMode = "Result format" +EditionMode = "Edition mode" +EditionLinear = "1D " +Edition2D = "2D " ComplexFormat = "Complex format" ExamMode = "Exam mode" ActivateExamMode = "Activate exam mode" diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n index 169e8c727..a7bdaf690 100644 --- a/apps/settings/base.es.i18n +++ b/apps/settings/base.es.i18n @@ -2,6 +2,9 @@ SettingsApp = "Configuracion" SettingsAppCapital = "CONFIGURACION" AngleUnit = "Medida del angulo" DisplayMode = "Formato resultado" +EditionMode = "Modo edicion" +EditionLinear = "1D " +Edition2D = "2D " ComplexFormat = "Formato complejo" ExamMode = "Modo examen" ActivateExamMode = "Activar el modo examen" diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n index 7f08a1732..7fffe0d16 100644 --- a/apps/settings/base.fr.i18n +++ b/apps/settings/base.fr.i18n @@ -2,6 +2,9 @@ SettingsApp = "Parametres" SettingsAppCapital = "PARAMETRES" AngleUnit = "Unite d'angle" DisplayMode = "Format resultat" +EditionMode = "Mode d'edition" +EditionLinear = "1D " +Edition2D = "2D " ComplexFormat = "Forme complexe" ExamMode = "Mode examen" ActivateExamMode = "Activer le mode examen" diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n index fcceaadcd..788d63e85 100644 --- a/apps/settings/base.pt.i18n +++ b/apps/settings/base.pt.i18n @@ -2,6 +2,9 @@ SettingsApp = "Configuracao" SettingsAppCapital = "CONFIGURACAO" AngleUnit = "Valor do angulo" DisplayMode = "Formato numerico" +EditionMode = "Modo de edicao" +EditionLinear = "1D " +Edition2D = "2D " ComplexFormat = "Complexos" ExamMode = "Modo de Exame" ActivateExamMode = "Inicio modo de exame" diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp index 37c1fb4f6..fe234ca0b 100644 --- a/apps/settings/main_controller.cpp +++ b/apps/settings/main_controller.cpp @@ -9,26 +9,32 @@ using namespace Poincare; namespace Settings { const SettingsMessageTree angleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)}; -const SettingsMessageTree FloatDisplayModeChildren[3] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::SignificantFigures)}; +const SettingsMessageTree editionModeChildren[2] = {SettingsMessageTree(I18n::Message::EditionLinear), SettingsMessageTree(I18n::Message::Edition2D)}; +const SettingsMessageTree floatDisplayModeChildren[3] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::SignificantFigures)}; const SettingsMessageTree complexFormatChildren[2] = {SettingsMessageTree(I18n::Message::Default), SettingsMessageTree(I18n::Message::Default)}; const SettingsMessageTree examChildren[1] = {SettingsMessageTree(I18n::Message::ActivateExamMode)}; const SettingsMessageTree aboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)}; #if OS_WITH_SOFTWARE_UPDATE_PROMPT -const SettingsMessageTree menu[8] = +const SettingsMessageTree menu[9] = #else -const SettingsMessageTree menu[7] = +const SettingsMessageTree menu[8] = #endif - {SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2), SettingsMessageTree(I18n::Message::DisplayMode, FloatDisplayModeChildren, 3), SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2), - SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), SettingsMessageTree(I18n::Message::ExamMode, examChildren, 1), + {SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2), + SettingsMessageTree(I18n::Message::DisplayMode, floatDisplayModeChildren, 3), + SettingsMessageTree(I18n::Message::EditionMode, editionModeChildren, 2), + SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2), + SettingsMessageTree(I18n::Message::Brightness), + SettingsMessageTree(I18n::Message::Language), + SettingsMessageTree(I18n::Message::ExamMode, examChildren, 1), #if OS_WITH_SOFTWARE_UPDATE_PROMPT SettingsMessageTree(I18n::Message::UpdatePopUp), #endif SettingsMessageTree(I18n::Message::About, aboutChildren, 3)}; #if OS_WITH_SOFTWARE_UPDATE_PROMPT -const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 8); +const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 9); #else -const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 7); +const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 8); #endif MainController::MainController(Responder * parentResponder) : @@ -149,14 +155,14 @@ int MainController::reusableCellCount(int type) { } int MainController::typeAtLocation(int i, int j) { - if (j == 2) { + if (j == 3) { return 1; } - if (j == 3) { + if (j == 4) { return 2; } #if OS_WITH_SOFTWARE_UPDATE_PROMPT - if (j == 6) { + if (j == 7) { return 3; } #endif @@ -167,7 +173,7 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { MessageTableCell * myCell = (MessageTableCell *)cell; myCell->setMessage(m_messageTreeModel->children(index)->label()); - if (index == 2) { + if (index == 3) { if (m_complexFormatLayout) { delete m_complexFormatLayout; m_complexFormatLayout = nullptr; @@ -181,19 +187,19 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { myExpCell->setExpressionLayout(m_complexFormatLayout); return; } - if (index == 3) { + if (index == 4) { MessageTableCellWithGauge * myGaugeCell = (MessageTableCellWithGauge *)cell; GaugeView * myGauge = (GaugeView *)myGaugeCell->accessoryView(); myGauge->setLevel((float)GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()/(float)Ion::Backlight::MaxBrightness); return; } - if (index == 4) { + if (index == 5) { int index = (int)GlobalPreferences::sharedGlobalPreferences()->language()-1; static_cast(cell)->setSubtitle(I18n::LanguageNames[index]); return; } #if OS_WITH_SOFTWARE_UPDATE_PROMPT - if (index == 6) { + if (index == 7) { MessageTableCellWithSwitch * mySwitchCell = (MessageTableCellWithSwitch *)cell; SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView(); mySwitch->setState(GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp()); @@ -208,6 +214,9 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) { case 1: myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)Preferences::sharedPreferences()->displayMode())->label()); break; + case 2: + myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)Preferences::sharedPreferences()->editionMode())->label()); + break; default: myTextCell->setSubtitle(I18n::Message::Default); break; diff --git a/apps/settings/main_controller.h b/apps/settings/main_controller.h index 4943fe3de..dd4c95eed 100644 --- a/apps/settings/main_controller.h +++ b/apps/settings/main_controller.h @@ -31,12 +31,12 @@ public: private: StackViewController * stackController() const; #if OS_WITH_SOFTWARE_UPDATE_PROMPT - constexpr static int k_totalNumberOfCell = 8; + constexpr static int k_totalNumberOfCell = 9; MessageTableCellWithSwitch m_updateCell; #else - constexpr static int k_totalNumberOfCell = 7; + constexpr static int k_totalNumberOfCell = 8; #endif - constexpr static int k_numberOfSimpleChevronCells = 5; + constexpr static int k_numberOfSimpleChevronCells = 6; MessageTableCellWithChevronAndMessage m_cells[k_numberOfSimpleChevronCells]; MessageTableCellWithChevronAndExpression m_complexFormatCell; MessageTableCellWithGauge m_brightnessCell; diff --git a/apps/settings/sub_controller.cpp b/apps/settings/sub_controller.cpp index eacaededa..ff071864d 100644 --- a/apps/settings/sub_controller.cpp +++ b/apps/settings/sub_controller.cpp @@ -69,7 +69,7 @@ bool SubController::handleEvent(Ion::Events::Event event) { return true; } if (event == Ion::Events::OK || event == Ion::Events::EXE) { - /* Behavious of "Exam mode" menu*/ + /* Behaviour of "Exam mode" menu*/ if (m_messageTreeModel->label() == I18n::Message::ExamMode) { if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) { return false; @@ -254,6 +254,9 @@ void SubController::setPreferenceWithValueIndex(I18n::Message message, int value if (message == I18n::Message::DisplayMode) { Preferences::sharedPreferences()->setDisplayMode((Expression::FloatDisplayMode)valueIndex); } + if (message == I18n::Message::EditionMode) { + Preferences::sharedPreferences()->setEditionMode((Preferences::EditionMode)valueIndex); + } if (message == I18n::Message::ComplexFormat) { Preferences::sharedPreferences()->setComplexFormat((Expression::ComplexFormat)valueIndex); } @@ -266,6 +269,9 @@ int SubController::valueIndexForPreference(I18n::Message message) { if (message == I18n::Message::DisplayMode) { return (int)Preferences::sharedPreferences()->displayMode(); } + if (message == I18n::Message::EditionMode) { + return (int)Preferences::sharedPreferences()->editionMode(); + } if (message == I18n::Message::ComplexFormat) { return (int)Preferences::sharedPreferences()->complexFormat(); } diff --git a/poincare/include/poincare/preferences.h b/poincare/include/poincare/preferences.h index 40925dbd6..741e117bc 100644 --- a/poincare/include/poincare/preferences.h +++ b/poincare/include/poincare/preferences.h @@ -7,12 +7,18 @@ namespace Poincare { class Preferences { public: + enum class EditionMode { + Edition1D, + Edition2D + }; Preferences(); static Preferences * sharedPreferences(); Expression::AngleUnit angleUnit() const; void setAngleUnit(Expression::AngleUnit angleUnit); Expression::FloatDisplayMode displayMode() const; void setDisplayMode(Expression::FloatDisplayMode FloatDisplayMode); + EditionMode editionMode() const; + void setEditionMode(EditionMode editionMode); Expression::ComplexFormat complexFormat() const; void setComplexFormat(Expression::ComplexFormat complexFormat); char numberOfSignificantDigits() const; @@ -20,6 +26,7 @@ public: private: Expression::AngleUnit m_angleUnit; Expression::FloatDisplayMode m_displayMode; + EditionMode m_editionMode; Expression::ComplexFormat m_complexFormat; char m_numberOfSignificantDigits; }; diff --git a/poincare/src/preferences.cpp b/poincare/src/preferences.cpp index c224419fd..2a432f663 100644 --- a/poincare/src/preferences.cpp +++ b/poincare/src/preferences.cpp @@ -8,6 +8,7 @@ static Preferences s_preferences; Preferences::Preferences() : m_angleUnit(Expression::AngleUnit::Degree), m_displayMode(Expression::FloatDisplayMode::Decimal), + m_editionMode(EditionMode::Edition2D), m_complexFormat(Expression::ComplexFormat::Cartesian), m_numberOfSignificantDigits(PrintFloat::k_numberOfPrintedSignificantDigits) { @@ -33,6 +34,14 @@ void Preferences::setDisplayMode(Expression::FloatDisplayMode FloatDisplayMode) m_displayMode = FloatDisplayMode; } +Preferences::EditionMode Preferences::editionMode() const { + return m_editionMode; +} + +void Preferences::setEditionMode(Preferences::EditionMode editionMode) { + m_editionMode = editionMode; +} + Expression::ComplexFormat Preferences::complexFormat() const { return m_complexFormat; } From 05de98ea04930698f5e0ca263fd052a60fe81bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 10:39:20 +0100 Subject: [PATCH 188/257] [apps/calculation] Fetch the edition mode in the preferences. Change-Id: Iec7cfc5695907b8c410077a48749fd43efb6cc65 --- apps/calculation/edit_expression_controller.cpp | 9 +++++++-- apps/calculation/edit_expression_controller.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 93f3b906a..2a3a9ee27 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -1,7 +1,8 @@ #include "edit_expression_controller.h" -#include "../apps_container.h" -#include "ion/display.h" #include "app.h" +#include "../apps_container.h" +#include +#include #include using namespace Shared; @@ -65,6 +66,10 @@ void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rec } } +bool EditExpressionController::ContentView::editionIsInTextField() const { + return Poincare::Preferences::sharedPreferences()->editionMode() == Poincare::Preferences::EditionMode::Edition1D; +} + KDCoordinate EditExpressionController::ContentView::inputViewHeight() const { return k_verticalMargin + (editionIsInTextField() ? k_textFieldHeight : editableExpressionViewHeight()); } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index a28d36a41..54d0512da 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -45,7 +45,7 @@ private: EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; } TableView * mainView() { return m_mainView; } void drawRect(KDContext * ctx, KDRect rect) const override; - bool editionIsInTextField() const { return true; } //TODO + bool editionIsInTextField() const; static constexpr int k_bufferLength = TextField::maxBufferSize(); private: static constexpr KDCoordinate k_textFieldHeight = 32; From e1811e03991839eed68a8e6c6310b2e75c1a5c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 10:55:34 +0100 Subject: [PATCH 189/257] [apps/calculation] Fix redraw bug. Change-Id: I86cf0839f4aa7f1285ed378850f6d09e811252a2 --- escher/src/editable_expression_view.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index 40b4a30b0..78bed4b2b 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -35,6 +35,7 @@ bool EditableExpressionView::handleEvent(Ion::Events::Event event) { KDSize newSize = minimalSizeForOptimalDisplay(); if (m_delegate && previousSize.height() != newSize.height()) { m_delegate->editableExpressionViewDidChangeSize(this); + reload(); } return true; } @@ -151,9 +152,8 @@ void EditableExpressionView::insertLayoutAtCursor(Poincare::ExpressionLayout * l m_expressionViewWithCursor.cursor()->addLayout(layout); m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); - m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); - KDSize newSize = minimalSizeForOptimalDisplay(); reload(); + KDSize newSize = minimalSizeForOptimalDisplay(); if (m_delegate && previousSize.height() != newSize.height()) { m_delegate->editableExpressionViewDidChangeSize(this); } From cb6a526072c7c2c12602a4a92c8f1b9dcae4affa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 11:59:51 +0100 Subject: [PATCH 190/257] [poincare] Fix bug in matrix layout assert. Change-Id: I84ec8034f9f417b12b91abe84771fec5834ba8b4 --- poincare/src/layout/matrix_layout.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index ff18958fc..82467984e 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -68,7 +68,7 @@ bool MatrixLayout::moveRight(ExpressionLayoutCursor * cursor) { && childIsRightOfGrid(childIndex)) { // Case: Right of a child on the right of the grid. - // Remove the grey squares of the grid, then go left of the grid. + // Remove the grey squares of the grid, then go right of the grid. cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); assert(hasGreySquares()); @@ -273,8 +273,8 @@ bool MatrixLayout::hasGreySquares() const { && !lastChild->isHorizontal() && (static_cast(lastChild))->color() == EmptyVisibleLayout::Color::Grey) { - assert(isRowEmpty(m_numberOfColumns - 1)); - assert(isColumnEmpty(m_numberOfRows - 1)); + assert(isRowEmpty(m_numberOfRows - 1)); + assert(isColumnEmpty(m_numberOfColumns - 1)); return true; } return false; From d8803c610c2f51e7cbdd8f2dc8e1208a0e60f317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 12:11:28 +0100 Subject: [PATCH 191/257] [apps] "New Matrix" item in math toolbox. Change-Id: Iec01ffa96ec64f42d2cbc4b15b14eea7cfe4eaa4 --- apps/code/python_toolbox.cpp | 5 +-- apps/code/variable_box_controller.cpp | 5 +-- apps/math_toolbox.cpp | 13 +++++--- apps/shared.universal.i18n | 1 + apps/shared/toolbox_helpers.cpp | 41 ++++++++++++++++++++----- apps/shared/toolbox_helpers.h | 8 ++--- apps/toolbox.de.i18n | 1 + apps/toolbox.en.i18n | 1 + apps/toolbox.es.i18n | 1 + apps/toolbox.fr.i18n | 1 + apps/toolbox.pt.i18n | 1 + escher/src/editable_expression_view.cpp | 4 +++ poincare/src/layout/matrix_layout.h | 3 +- 13 files changed, 64 insertions(+), 21 deletions(-) diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index c9d7d80ce..1498a58bf 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -289,8 +289,9 @@ bool PythonToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) { m_selectableTableView.deselectTable(); ToolboxMessageTree * node = selectedMessageTree; const char * editedText = I18n::translate(node->insertedText()); - char strippedEditedText[strlen(editedText)+1]; - Shared::ToolboxHelpers::TextToInsertForCommandMessage(node->insertedText(), strippedEditedText); + int strippedEditedTextMaxLength = strlen(editedText)+1; + char strippedEditedText[strippedEditedTextMaxLength]; + Shared::ToolboxHelpers::TextToInsertForCommandMessage(node->insertedText(), strippedEditedText, strippedEditedTextMaxLength); m_action(sender(), const_cast(strippedEditedText)); app()->dismissModalViewController(); return true; diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 657284ff2..9684642aa 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -119,8 +119,9 @@ void VariableBoxController::ContentViewController::willDisplayCellForIndex(Highl } void VariableBoxController::ContentViewController::insertTextInCaller(const char * text) { - char commandBuffer[strlen(text)+1]; - Shared::ToolboxHelpers::TextToInsertForCommandText(text, commandBuffer); + int commandBufferMaxSize = strlen(text)+1; + char commandBuffer[commandBufferMaxSize]; + Shared::ToolboxHelpers::TextToInsertForCommandText(text, commandBuffer, commandBufferMaxSize); if (m_textFieldCaller != nullptr) { if (!m_textFieldCaller->isEditing()) { m_textFieldCaller->setEditing(true); diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index f7a37dd10..1ce07b16e 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -36,7 +36,8 @@ const ToolboxMessageTree arithmeticChildren[4] = { ToolboxMessageTree(I18n::Message::QuoCommandWithArg, I18n::Message::Quotient, I18n::Message::QuoCommandWithArg)}; #if MATRICES_ARE_DEFINED -const ToolboxMessageTree matricesChildren[5] = { +const ToolboxMessageTree matricesChildren[6] = { + ToolboxMessageTree(I18n::Message::MatrixCommandWithArg, I18n::Message::NewMatrix, I18n::Message::MatrixCommandWithArg), ToolboxMessageTree(I18n::Message::InverseCommandWithArg, I18n::Message::Inverse, I18n::Message::InverseCommandWithArg), ToolboxMessageTree(I18n::Message::DeterminantCommandWithArg, I18n::Message::Determinant, I18n::Message::DeterminantCommandWithArg), ToolboxMessageTree(I18n::Message::TransposeCommandWithArg, I18n::Message::Transpose, I18n::Message::TransposeCommandWithArg), @@ -88,7 +89,7 @@ const ToolboxMessageTree menu[10] = { ToolboxMessageTree(I18n::Message::Probability, I18n::Message::Default, I18n::Message::Default, probabilityChildren, 2), ToolboxMessageTree(I18n::Message::Arithmetic, I18n::Message::Default, I18n::Message::Default, arithmeticChildren, 4), #if MATRICES_ARE_DEFINED - ToolboxMessageTree(I18n::Message::Matrices, I18n::Message::Default, I18n::Message::Default, matricesChildren, 5), + ToolboxMessageTree(I18n::Message::Matrices, I18n::Message::Default, I18n::Message::Default, matricesChildren, 6), #endif #if LIST_ARE_DEFINED ToolboxMessageTree(I18n::Message::Lists, I18n::Message::Default, I18n::Message::Default, listesChildren, 5), @@ -119,8 +120,9 @@ void MathToolbox::actionForEditableExpressionView(void * sender, ToolboxMessageT EditableExpressionView * expressionLayoutEditorSender = static_cast(sender); // Translate the message and replace the arguments with Empty chars. const char * textToInsert = I18n::translate(messageTree->insertedText()); + int strippedTextToInsertMaxLength = strlen(textToInsert); char strippedTextToInsert[strlen(textToInsert)]; - Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandMessage(messageTree->insertedText(), strippedTextToInsert); + Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandMessage(messageTree->insertedText(), strippedTextToInsert, strippedTextToInsertMaxLength); // Create the layout Expression * resultExpression = Expression::parse(strippedTextToInsert); if (resultExpression == nullptr) { @@ -156,9 +158,10 @@ void MathToolbox::actionForTextfield(void * sender, ToolboxMessageTree * message textFieldSender->setEditing(true); } const char * textToInsert = I18n::translate(messageTree->insertedText()); - char strippedTextToInsert[strlen(textToInsert)]; + int textToInsertLength = strlen(textToInsert); + char strippedTextToInsert[textToInsertLength]; // Translate the message and remove the arguments. - Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedTextToInsert); + Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedTextToInsert, textToInsertLength); textFieldSender->insertTextAtLocation(strippedTextToInsert, textFieldSender->cursorLocation()); int newCursorLocation = textFieldSender->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(strippedTextToInsert); textFieldSender->setCursorLocation(newCursorLocation); diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n index 5ab160c94..1f06a778b 100644 --- a/apps/shared.universal.i18n +++ b/apps/shared.universal.i18n @@ -32,6 +32,7 @@ LcmCommandWithArg = "lcm(p,q)" LeftIntegralFirstLegend = "P(X≤" LeftIntegralSecondLegend = ")=" LogCommandWithArg = "log(x,a)" +MatrixCommandWithArg = "[[1,2][3,4]]" MaxCommandWithArg = "max(L)" MinCommandWithArg = "min(L)" Mu = "μ" diff --git a/apps/shared/toolbox_helpers.cpp b/apps/shared/toolbox_helpers.cpp index a1da1475f..268162c8d 100644 --- a/apps/shared/toolbox_helpers.cpp +++ b/apps/shared/toolbox_helpers.cpp @@ -1,6 +1,8 @@ #include "toolbox_helpers.h" #include +#include #include +#include namespace Shared { namespace ToolboxHelpers { @@ -10,28 +12,42 @@ int CursorIndexInCommand(const char * text) { if (text[i] == '(' || text[i] == '\'') { return i + 1; } + if (text[i] == ']') { + return (i - 1) > 0 ? i - 1 : 0; + } } return strlen(text); } -void TextToInsertForCommandMessage(I18n::Message message, char * buffer) { +void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize) { const char * messageText = I18n::translate(message); - TextToInsertForCommandText(messageText, buffer); + TextToInsertForCommandText(messageText, buffer, bufferSize); } -void TextToInsertForCommandText(const char * command, char * buffer) { +void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize) { int currentNewTextIndex = 0; + int numberOfOpenParentheses = 0; int numberOfOpenBrackets = 0; bool insideQuote = false; size_t commandLength = strlen(command); for (size_t i = 0; i < commandLength; i++) { if (command[i] == ')') { + numberOfOpenParentheses--; + } + if (command[i] == ']') { numberOfOpenBrackets--; } - if ((numberOfOpenBrackets == 0 || command[i] == ',') && (!insideQuote || command[i] == '\'')) { + if (((numberOfOpenParentheses == 0 && numberOfOpenBrackets == 0) + || command[i] == ',' + || (numberOfOpenBrackets > 0 && (command[i] == ',' || command[i] == '[' || command[i] == ']'))) + && (!insideQuote || command[i] == '\'')) { + assert(currentNewTextIndex < bufferSize); buffer[currentNewTextIndex++] = command[i]; } if (command[i] == '(') { + numberOfOpenParentheses++; + } + if (command[i] == '[') { numberOfOpenBrackets++; } if (command[i] == '\'') { @@ -41,12 +57,23 @@ void TextToInsertForCommandText(const char * command, char * buffer) { buffer[currentNewTextIndex] = 0; } -void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer) { +void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer, int bufferSize) { + if (message == I18n::Message::MatrixCommandWithArg) { + assert(bufferSize >= 6); + // Handle a new matrix command. + buffer[0] = '['; + buffer[1] = '['; + buffer[2] = Ion::Charset::Empty; + buffer[3] = ']'; + buffer[4] = ']'; + buffer[5] = 0; + return; + } const char * messageText = I18n::translate(message); - TextToInsertForCommandText(messageText, buffer); + TextToInsertForCommandText(messageText, buffer, bufferSize); size_t bufferLength = strlen(buffer); for (size_t i = 0; i < bufferLength; i++) { - if (buffer[i] == '(' || buffer[i] == ',') { + if (buffer[i] == '(' || buffer[i] == '[' || buffer[i] == ',') { // Shift the buffer to make room for the new char. Use memmove to avoid // overwritting. memmove(&buffer[i+2], &buffer[i+1], bufferLength - (i+1) + 1); diff --git a/apps/shared/toolbox_helpers.h b/apps/shared/toolbox_helpers.h index 98539614d..d051f5847 100644 --- a/apps/shared/toolbox_helpers.h +++ b/apps/shared/toolbox_helpers.h @@ -13,11 +13,11 @@ int CursorIndexInCommand(const char * text); * - The end of the text */ -void TextToInsertForCommandMessage(I18n::Message message, char * buffer); -void TextToInsertForCommandText(const char * command, char * buffer); +void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize); +void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize); /* Removes the arguments from a command: - * - Removes text between parentheses, except commas */ -void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer); + * - Removes text between parentheses or brackets, except commas */ +void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer, int bufferSize); /* Removes the arguments from a command and replaces them with empty chars. */ } diff --git a/apps/toolbox.de.i18n b/apps/toolbox.de.i18n index a8b6fd1b6..6312f3aad 100644 --- a/apps/toolbox.de.i18n +++ b/apps/toolbox.de.i18n @@ -7,6 +7,7 @@ ComplexNumber = "Komplexen Zahlen" Probability = "Kombinatorik" Arithmetic = "Arithmetisch" Matrices = "Matrizen" +NewMatrix = "Neue Matrix" Lists = "Listen" Approximation = "Approximation" HyperbolicTrigonometry = "Hyperbelfunktionen" diff --git a/apps/toolbox.en.i18n b/apps/toolbox.en.i18n index b1a6e3533..e8103814b 100644 --- a/apps/toolbox.en.i18n +++ b/apps/toolbox.en.i18n @@ -7,6 +7,7 @@ ComplexNumber = "Complex numbers" Probability = "Combinatorics" Arithmetic = "Arithmetic" Matrices = "Matrix" +NewMatrix = "New matrix" Lists = "List" Approximation = "Approximation" HyperbolicTrigonometry = "Hyperbolic trigonometry" diff --git a/apps/toolbox.es.i18n b/apps/toolbox.es.i18n index 90ecf326a..a78d837d4 100644 --- a/apps/toolbox.es.i18n +++ b/apps/toolbox.es.i18n @@ -7,6 +7,7 @@ ComplexNumber = "Numeros complejos" Probability = "Combinatoria" Arithmetic = "Aritmetica" Matrices = "Matriz" +NewMatrix = "Nueva matriz" Lists = "Listas" Approximation = "Aproximacion" HyperbolicTrigonometry = "Trigonometria hiperbolica" diff --git a/apps/toolbox.fr.i18n b/apps/toolbox.fr.i18n index d8cb4b190..d944d0415 100644 --- a/apps/toolbox.fr.i18n +++ b/apps/toolbox.fr.i18n @@ -7,6 +7,7 @@ ComplexNumber = "Nombres complexes" Probability = "Denombrement" Arithmetic = "Arithmetique" Matrices = "Matrices" +NewMatrix = "Nouvelle matrice" Lists = "Listes" Approximation = "Approximation" HyperbolicTrigonometry = "Trigonometrie hyperbolique" diff --git a/apps/toolbox.pt.i18n b/apps/toolbox.pt.i18n index aa1ad1d81..45ade5d5e 100644 --- a/apps/toolbox.pt.i18n +++ b/apps/toolbox.pt.i18n @@ -7,6 +7,7 @@ ComplexNumber = "Numeros complexos" Probability = "Combinatoria" Arithmetic = "Aritmetica" Matrices = "Matrizes" +NewMatrix = "Nova matriz" Lists = "Listas" Approximation = "Aproximacao" HyperbolicTrigonometry = "Funcoes hiperbolicas" diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index 78bed4b2b..01159a81a 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -1,5 +1,6 @@ #include #include +#include #include EditableExpressionView::EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate) : @@ -150,6 +151,9 @@ void EditableExpressionView::insertLayoutAtCursor(Poincare::ExpressionLayout * l } KDSize previousSize = minimalSizeForOptimalDisplay(); m_expressionViewWithCursor.cursor()->addLayout(layout); + if (layout->isMatrix() && pointedLayout->hasAncestor(layout)) { + static_cast(layout)->addGreySquares(); + } m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); reload(); diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index b931bb51b..8208d11b3 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -29,6 +29,8 @@ public: /* Special matrix method */ void newRowOrColumnAtIndex(int index); + void addGreySquares(); + protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; @@ -37,7 +39,6 @@ private: void childWasReplacedAtIndex(int index); bool isRowEmpty(int index) const; bool isColumnEmpty(int index) const; - void addGreySquares(); void removeGreySquares(); bool hasGreySquares() const; }; From 3154decf8ba5d5ce2560967896cf4f51781b9812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 14:10:37 +0100 Subject: [PATCH 192/257] [apps] Fixed bug in MathToolbox. When returning a MathToolbox, the textfield delegate did not set the toolbox action for textfields. Change-Id: I51f78ff5601f784be8e283cf3fb6d3462b776d9a --- apps/math_toolbox.cpp | 4 ++-- apps/math_toolbox.h | 2 +- apps/shared/text_field_delegate_app.cpp | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 1ce07b16e..3910a60c0 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -107,7 +107,7 @@ const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbo MathToolbox::MathToolbox() : Toolbox(nullptr, I18n::translate(rootModel()->label())), - m_action(actionForTextfield) + m_action(actionForTextField) { } @@ -152,7 +152,7 @@ void MathToolbox::actionForEditableExpressionView(void * sender, ToolboxMessageT expressionLayoutEditorSender->insertLayoutAtCursor(resultLayout, pointedLayout); } -void MathToolbox::actionForTextfield(void * sender, ToolboxMessageTree * messageTree) { +void MathToolbox::actionForTextField(void * sender, ToolboxMessageTree * messageTree) { TextField * textFieldSender = static_cast(sender); if (!textFieldSender->isEditing()) { textFieldSender->setEditing(true); diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index 6f06148d1..dbcc8e2cd 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -12,7 +12,7 @@ public: MathToolbox(); void setSenderAndAction(Responder * sender, Action action); static void actionForEditableExpressionView(void * sender, ToolboxMessageTree * messageTree); - static void actionForTextfield(void * sender, ToolboxMessageTree * messageTree); + static void actionForTextField(void * sender, ToolboxMessageTree * messageTree); protected: bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override; const ToolboxMessageTree * rootModel() override; diff --git a/apps/shared/text_field_delegate_app.cpp b/apps/shared/text_field_delegate_app.cpp index de8df6c42..574a47e1f 100644 --- a/apps/shared/text_field_delegate_app.cpp +++ b/apps/shared/text_field_delegate_app.cpp @@ -110,7 +110,9 @@ bool TextFieldDelegateApp::textFieldDidReceiveEvent(TextField * textField, Ion:: } Toolbox * TextFieldDelegateApp::toolboxForTextField(TextField * textField) { - return container()->mathToolbox(); + Toolbox * toolbox = container()->mathToolbox(); + static_cast(toolbox)->setSenderAndAction(textField, MathToolbox::actionForTextField); + return toolbox; } } From 169913b80008dbba99bc7f3779a82a5e701274c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 14:13:51 +0100 Subject: [PATCH 193/257] [apps/calculation] Fix background redraw bug. The margins around the textfield did not redraw themselves properly after dismissing a toolbox for instance. The textfield now takes the full height of edition zone. Change-Id: I0794b8273a880a2dc921c5f492eb0f41aef7fe97 --- apps/calculation/edit_expression_controller.cpp | 8 ++++---- apps/calculation/edit_expression_controller.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 2a3a9ee27..d1fefa9af 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -39,7 +39,7 @@ void EditExpressionController::ContentView::layoutSubviews() { KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - inputViewFrameHeight-k_separatorThickness); m_mainView->setFrame(mainViewFrame); if (editionIsInTextField()) { - KDRect inputViewFrame(k_leftMargin, bounds().height() - inputViewFrameHeight + k_verticalMargin, bounds().width()-k_leftMargin, k_textFieldHeight - k_verticalMargin); + KDRect inputViewFrame(k_leftMargin, bounds().height() - inputViewFrameHeight, bounds().width()-k_leftMargin, k_textFieldHeight); m_textField.setFrame(inputViewFrame); m_editableExpressionView.setFrame(KDRectZero); return; @@ -62,7 +62,7 @@ void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rec ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, k_leftMargin, inputViewFrameHeight), m_textField.backgroundColor()); if (!editionIsInTextField()) { // Color the upper margin - ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, bounds().width(), k_verticalMargin), m_textField.backgroundColor()); + ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, bounds().width(), k_verticalEditableExpressionViewMargin), m_textField.backgroundColor()); } } @@ -71,11 +71,11 @@ bool EditExpressionController::ContentView::editionIsInTextField() const { } KDCoordinate EditExpressionController::ContentView::inputViewHeight() const { - return k_verticalMargin + (editionIsInTextField() ? k_textFieldHeight : editableExpressionViewHeight()); + return editionIsInTextField() ? k_textFieldHeight : k_verticalEditableExpressionViewMargin + editableExpressionViewHeight(); } KDCoordinate EditExpressionController::ContentView::editableExpressionViewHeight() const { - return KDCoordinate(min(0.6*Ion::Display::Height, max(k_textFieldHeight, m_editableExpressionView.minimalSizeForOptimalDisplay().height()+k_verticalMargin))); + return KDCoordinate(min(0.6*Ion::Display::Height, max(k_textFieldHeight, m_editableExpressionView.minimalSizeForOptimalDisplay().height()+k_verticalEditableExpressionViewMargin))); } EditExpressionController::EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore) : diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 54d0512da..9c3d3d4aa 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -48,9 +48,9 @@ private: bool editionIsInTextField() const; static constexpr int k_bufferLength = TextField::maxBufferSize(); private: - static constexpr KDCoordinate k_textFieldHeight = 32; + static constexpr KDCoordinate k_textFieldHeight = 37; static constexpr KDCoordinate k_leftMargin = 5; - static constexpr KDCoordinate k_verticalMargin = 5; + static constexpr KDCoordinate k_verticalEditableExpressionViewMargin = 5; constexpr static int k_separatorThickness = 1; KDCoordinate inputViewHeight() const; KDCoordinate editableExpressionViewHeight() const; From 613d33efbaaf066cbf80b3de16ac7e071bfbcefd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 14:25:20 +0100 Subject: [PATCH 194/257] [poincare] Delete root layout if cursor left of the radicand. Change-Id: I42331f06785680053fa3cc64a95296697f207845 --- poincare/src/layout/nth_root_layout.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 77e4516ab..8c14bfe19 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -30,7 +30,15 @@ void NthRootLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { && cursor->position() == ExpressionLayoutCursor::Position::Right) { // Case: Right. - // Delete the layout, keep the operand. + // Delete the layout, keep the radicand. + replaceWithAndMoveCursor(radicandLayout(), true, cursor); + return; + } + if (cursor->pointedExpressionLayout() == radicandLayout() + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + // Case: Left of the radicand. + // Delete the layout, keep the radicand. replaceWithAndMoveCursor(radicandLayout(), true, cursor); return; } From 776c4246c6948e4f90c401dd4350ff794b3e4164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 14:51:55 +0100 Subject: [PATCH 195/257] [poincare] Delete the integral when left of the integrand. And handle the cursor position. Change-Id: I573a8c7496a3a7b99385e68e8152e491f86cb66c --- poincare/src/layout/expression_layout.cpp | 4 ++- poincare/src/layout/horizontal_layout.cpp | 33 ++++++++++++++++++----- poincare/src/layout/integral_layout.cpp | 8 ++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index ec6184b1b..6c318fb0f 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -180,9 +180,11 @@ void ExpressionLayout::replaceChild(const ExpressionLayout * oldChild, Expressio void ExpressionLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { assert(indexOfChild(oldChild) >= 0); + if (!newChild->hasAncestor(oldChild)) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } replaceChild(oldChild, newChild, deleteOldChild); cursor->setPointedExpressionLayout(newChild); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); } void ExpressionLayout::detachChild(const ExpressionLayout * e) { diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 0847eabb0..e0e27198d 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -68,8 +68,10 @@ void HorizontalLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChi } void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) { + bool oldWasAncestorOfNewLayout = false; if (newChild->hasAncestor(this)) { newChild->editableParent()->detachChild(newChild); + oldWasAncestorOfNewLayout = true; } int oldChildIndex = indexOfChild(oldChild); if (newChild->isEmpty()) { @@ -123,12 +125,28 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex if (newChild->isHorizontal()) { int indexForInsertion = indexOfChild(oldChild); if (cursor != nullptr) { - if (oldChildIndex == numberOfChildren() - 1) { - cursor->setPointedExpressionLayout(this); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); + // If the old layout is not an ancestor of the new layout, or if the + // cursor was on the right of the new layout, place the cursor on the + // right of the new layout, which is left of the next brother or right of + // the parent. + if (!oldWasAncestorOfNewLayout || cursor->position() == ExpressionLayoutCursor::Position::Right) { + if (oldChildIndex == numberOfChildren() - 1) { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } else { + cursor->setPointedExpressionLayout(editableChild(oldChildIndex + 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + } } else { - cursor->setPointedExpressionLayout(editableChild(oldChildIndex + 1)); - cursor->setPosition(ExpressionLayoutCursor::Position::Left); + // Else place the cursor on the left of the new layout, which is right + // of the previous brother or left of the parent. + if (oldChildIndex == 0) { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + } else { + cursor->setPointedExpressionLayout(editableChild(oldChildIndex - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } } } mergeChildrenAtIndex(static_cast(newChild), indexForInsertion + 1, true); @@ -136,13 +154,14 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex return; } // Else, just replace the child. + if (cursor != nullptr && !oldWasAncestorOfNewLayout) { + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } ExpressionLayout::replaceChild(oldChild, newChild, deleteOldChild); if (cursor == nullptr) { return; } cursor->setPointedExpressionLayout(newChild); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return; } void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren) { diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 80011c669..505b14cbc 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -35,6 +35,14 @@ void IntegralLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { replaceWithAndMoveCursor(integrandLayout(), true, cursor); return; } + if (cursor->pointedExpressionLayout() == integrandLayout() + && cursor->position() == ExpressionLayoutCursor::Position::Left) + { + // Case: Left of the integrand. + // Delete the layout, keep the integrand. + replaceWithAndMoveCursor(integrandLayout(), true, cursor); + return; + } ExpressionLayout::backspaceAtCursor(cursor); } From 3cda4a881d88d7cb2703b7db924ec0cb9d6b3fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 15:32:55 +0100 Subject: [PATCH 196/257] [poincare] Fix new power layout bug. There was a problem when assessing if there was a need for an empty base layout. Change-Id: I9d6f84d3cc797fc0a701395dd8289590a4ab849a --- .../poincare/expression_layout_cursor.h | 1 + poincare/src/expression_layout_cursor.cpp | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index bf3dcd900..5cfd89e4a 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -52,6 +52,7 @@ public: private: constexpr static KDCoordinate k_cursorHeight = 18; + bool baseForNewPowerLayout(); ExpressionLayout * m_pointedExpressionLayout; Position m_position; }; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index c7ad5e9bb..87f5de8bb 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -121,8 +121,7 @@ void ExpressionLayoutCursor::addEmptyMatrixLayout(int numberOfRows, int numberOf void ExpressionLayoutCursor::addEmptyPowerLayout() { VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Superscript, false); // If there is already a base - int numberOfOpenParenthesis = 0; - if (!m_pointedExpressionLayout->isEmpty() && m_pointedExpressionLayout->isCollapsable(&numberOfOpenParenthesis, true)) { + if (baseForNewPowerLayout()) { m_pointedExpressionLayout->addBrother(this, offsetLayout); setPointedExpressionLayout(offsetLayout->editableChild(0)); setPosition(ExpressionLayoutCursor::Position::Left); @@ -148,8 +147,7 @@ void ExpressionLayoutCursor::addEmptySquarePowerLayout() { CharLayout * indiceLayout = new CharLayout('2'); VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(indiceLayout, VerticalOffsetLayout::Type::Superscript, false); // If there is already a base - int numberOfOpenParenthesis = 0; - if (!m_pointedExpressionLayout->isEmpty() && m_pointedExpressionLayout->isCollapsable(&numberOfOpenParenthesis, true)) { + if (baseForNewPowerLayout()) { m_pointedExpressionLayout->addBrother(this, offsetLayout); setPointedExpressionLayout(offsetLayout); setPosition(ExpressionLayoutCursor::Position::Right); @@ -205,5 +203,21 @@ void ExpressionLayoutCursor::performBackspace() { m_pointedExpressionLayout->backspaceAtCursor(this); } +bool ExpressionLayoutCursor::baseForNewPowerLayout() { + // Returns true if the layout on the left of the pointed layout is suitable to + // be the base of a new power layout. + int numberOfOpenParenthesis = 0; + int indexInParent = m_pointedExpressionLayout->parent()->indexOfChild(m_pointedExpressionLayout); + return ((m_position == Position::Right + && !m_pointedExpressionLayout->isEmpty() + && m_pointedExpressionLayout->isCollapsable(&numberOfOpenParenthesis, true)) + || (m_position == Position::Left + && m_pointedExpressionLayout->parent() + && m_pointedExpressionLayout->parent()->isHorizontal() + && indexInParent > 0 + && !m_pointedExpressionLayout->editableParent()->editableChild(indexInParent-1)->isEmpty() + && !m_pointedExpressionLayout->editableParent()->editableChild(indexInParent-1)->isCollapsable(&numberOfOpenParenthesis, true))); +} + } From b70cb6dc8a8602a332a274a73f792e92d289afb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 18:06:55 +0100 Subject: [PATCH 197/257] [poincare/parser] Fix precedence bug in the parser. Change-Id: I02a36ca82729085232166d854d596154a355daae --- poincare/src/expression_parser.y | 127 +++++++++++++++++++------------ 1 file changed, 79 insertions(+), 48 deletions(-) diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index 0f53054f1..90d6584f9 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -70,7 +70,6 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char %token UNDERSCORE %token DOT %token EE -%token ICOMPLEX %token STO %token UNDEFINED_SYMBOL @@ -92,9 +91,9 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char * one has the highest precedence. */ %nonassoc STO +%right UNARY_MINUS %left PLUS %left MINUS -%right UNARY_MINUS %left MULTIPLY %left DIVIDE %left IMPLICIT_MULTIPLY @@ -112,13 +111,20 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char %nonassoc DIGITS %nonassoc DOT %nonassoc EE -%nonassoc ICOMPLEX %nonassoc UNDEFINED %nonassoc SYMBOL %nonassoc EMPTY /* The "exp" symbol uses the "expression" part of the union. */ %type final_exp; +%type term; +%type bang; +%type factor; +%type pow; +%type div; +%type mul; +%type min; +%type unmin; %type exp; %type number; %type symb; @@ -131,7 +137,7 @@ void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, char * have some heap-allocated data that need to be discarded. */ %destructor { delete $$; } FUNCTION -%destructor { delete $$; } UNDEFINED final_exp exp number EMPTY +%destructor { delete $$; } UNDEFINED final_exp exp unmin min mul div pow factor bang term number EMPTY %destructor { delete $$; } lstData /* MATRICES_ARE_DEFINED */ %destructor { delete $$; } mtxData @@ -143,14 +149,16 @@ Root: final_exp { *expressionOutput = $1; } + ; + +lstData: exp { $$ = new Poincare::ListData($1); } + | lstData COMMA exp { $$ = $1; $$->pushExpression($3); } + ; -lstData: - exp { $$ = new Poincare::ListData($1); } - | lstData COMMA exp { $$ = $1; $$->pushExpression($3); } /* MATRICES_ARE_DEFINED */ - mtxData: - LEFT_BRACKET lstData RIGHT_BRACKET { $$ = new Poincare::MatrixData($2, false); $2->detachOperands(); delete $2; } - | mtxData LEFT_BRACKET lstData RIGHT_BRACKET { if ($3->numberOfOperands() != $1->numberOfColumns()) { delete $1; delete $3; YYERROR; } ; $$ = $1; $$->pushListData($3, false); $3->detachOperands(); delete $3; } +mtxData: LEFT_BRACKET lstData RIGHT_BRACKET { $$ = new Poincare::MatrixData($2, false); $2->detachOperands(); delete $2; } + | mtxData LEFT_BRACKET lstData RIGHT_BRACKET { if ($3->numberOfOperands() != $1->numberOfColumns()) { delete $1; delete $3; YYERROR; } ; $$ = $1; $$->pushListData($3, false); $3->detachOperands(); delete $3; } + ; /* When approximating expressions to double, results are bounded by 1E308 (and * 1E-308 for small numbers). We thus accept decimals whose exponents are in @@ -161,53 +169,76 @@ lstData: * of the exponent digits is above 4 (0.00...-256 times-...01E1256=1E1000 is * accepted and 1000-...256times...-0E10000 = 1E10256, 10256 does not overflow * an int32_t). */ -number: - DIGITS { $$ = new Poincare::Rational(Poincare::Integer($1.address, false)); } - | DOT DIGITS { $$ = new Poincare::Decimal(Poincare::Decimal::mantissa(nullptr, 0, $2.address, $2.length, false), Poincare::Decimal::exponent(nullptr, 0, $2.address, $2.length, nullptr, 0, false)); } - | DIGITS DOT DIGITS { $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, $3.address, $3.length, false), Poincare::Decimal::exponent($1.address, $1.length, $3.address, $3.length, nullptr, 0, false)); } - | DOT DIGITS EE DIGITS { if ($4.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent(nullptr, 0, $2.address, $2.length, $4.address, $4.length, false); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa(nullptr, 0, $2.address, $2.length, false), exponent); } - | DIGITS DOT DIGITS EE DIGITS { if ($5.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent($1.address, $1.length, $3.address, $3.length, $5.address, $5.length, false); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, $3.address, $3.length, false), exponent); } - | DIGITS EE DIGITS { if ($3.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent($1.address, $1.length, nullptr, 0, $3.address, $3.length, false); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, nullptr, 0, false), exponent); } - | DOT DIGITS EE MINUS DIGITS { if ($5.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent(nullptr, 0, $2.address, $2.length, $5.address, $5.length, true); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa(nullptr, 0, $2.address, $2.length, false), exponent); } - | DIGITS DOT DIGITS EE MINUS DIGITS { if ($6.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent($1.address, $1.length, $3.address, $3.length, $6.address, $6.length, true); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, $3.address, $3.length, false), exponent); } - | DIGITS EE MINUS DIGITS { if ($4.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent($1.address, $1.length, nullptr, 0, $4.address, $4.length, true); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, nullptr, 0, false), exponent); } +number : DIGITS { $$ = new Poincare::Rational(Poincare::Integer($1.address, false)); } + | DOT DIGITS { $$ = new Poincare::Decimal(Poincare::Decimal::mantissa(nullptr, 0, $2.address, $2.length, false), Poincare::Decimal::exponent(nullptr, 0, $2.address, $2.length, nullptr, 0, false)); } + | DIGITS DOT DIGITS { $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, $3.address, $3.length, false), Poincare::Decimal::exponent($1.address, $1.length, $3.address, $3.length, nullptr, 0, false)); } + | DOT DIGITS EE DIGITS { if ($4.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent(nullptr, 0, $2.address, $2.length, $4.address, $4.length, false); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa(nullptr, 0, $2.address, $2.length, false), exponent); } + | DIGITS DOT DIGITS EE DIGITS { if ($5.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent($1.address, $1.length, $3.address, $3.length, $5.address, $5.length, false); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, $3.address, $3.length, false), exponent); } + | DIGITS EE DIGITS { if ($3.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent($1.address, $1.length, nullptr, 0, $3.address, $3.length, false); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, nullptr, 0, false), exponent); } + | DOT DIGITS EE MINUS DIGITS { if ($5.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent(nullptr, 0, $2.address, $2.length, $5.address, $5.length, true); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa(nullptr, 0, $2.address, $2.length, false), exponent); } + | DIGITS DOT DIGITS EE MINUS DIGITS { if ($6.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent($1.address, $1.length, $3.address, $3.length, $6.address, $6.length, true); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, $3.address, $3.length, false), exponent); } + | DIGITS EE MINUS DIGITS { if ($4.length > 4) { YYERROR; }; int exponent = Poincare::Decimal::exponent($1.address, $1.length, nullptr, 0, $4.address, $4.length, true); if (exponent > 1000 || exponent < -1000 ) { YYERROR; }; $$ = new Poincare::Decimal(Poincare::Decimal::mantissa($1.address, $1.length, nullptr, 0, false), exponent); } + ; -symb: - SYMBOL { $$ = new Poincare::Symbol($1); } +symb : SYMBOL { $$ = new Poincare::Symbol($1); } + ; -/* The rules "exp MINUS exp" and "MINUS exp" are sometimes ambiguous. We want - * to favor "exp MINUS exp" over "MINUS exp". Bison by default resolves - * reduce/reduce conflicts in favor of the first grammar rule. Thus, the order - * of the grammar rules is here paramount: "MINUS exp" should always be after - * "exp MINUS exp". */ -exp: - UNDEFINED { $$ = $1; } - | EMPTY { $$ = $1; } - | exp BANG { $$ = new Poincare::Factorial($1, false); } - | number { $$ = $1; } - | symb { $$ = $1; } - | exp PLUS exp { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Addition(terms, 2, false); } - | exp MINUS exp { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Subtraction(terms, false); } - | exp MULTIPLY exp { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Multiplication(terms, 2, false); } - | exp exp %prec IMPLICIT_MULTIPLY { Poincare::Expression * terms[2] = {$1,$2}; $$ = new Poincare::Multiplication(terms, 2, false); } - | exp DIVIDE exp { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Division(terms, false); } - | exp POW exp { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Power(terms, false); } - | MINUS exp %prec UNARY_MINUS { Poincare::Expression * terms[1] = {$2}; $$ = new Poincare::Opposite(terms, false); } - | LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { Poincare::Expression * terms[1] = {$2}; $$ = new Poincare::Parenthesis(terms, false); } -/* MATRICES_ARE_DEFINED */ - | LEFT_BRACKET mtxData RIGHT_BRACKET { $$ = new Poincare::Matrix($2); delete $2; } - | FUNCTION UNDERSCORE LEFT_BRACE lstData RIGHT_BRACE LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; int totalNumberOfArguments = $4->numberOfOperands()+$7->numberOfOperands(); +term : EMPTY { $$ = $1; } + | symb { $$ = $1; } + | UNDEFINED { $$ = $1; } + | number { $$ = $1; } + | FUNCTION UNDERSCORE LEFT_BRACE lstData RIGHT_BRACE LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; int totalNumberOfArguments = $4->numberOfOperands()+$7->numberOfOperands(); if (!$1->hasValidNumberOfOperands(totalNumberOfArguments)) { delete $1; delete $4; delete $7; YYERROR; }; Poincare::ListData * arguments = new Poincare::ListData(); for (int i = 0; i < $4->numberOfOperands(); i++) { arguments->pushExpression($4->operands()[i]); } for (int i = 0; i < $7->numberOfOperands(); i++) { arguments->pushExpression($7->operands()[i]); } $1->setArgument(arguments, totalNumberOfArguments, false); $4->detachOperands(); delete $4; $7->detachOperands(); delete $7; arguments->detachOperands(); delete arguments;} - | FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; if (!$1->hasValidNumberOfOperands($3->numberOfOperands())) { delete $1; delete $3; YYERROR; } ; $1->setArgument($3, $3->numberOfOperands(), false); $3->detachOperands(); delete $3; } + | FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; if (!$1->hasValidNumberOfOperands($3->numberOfOperands())) { delete $1; delete $3; YYERROR; } ; $1->setArgument($3, $3->numberOfOperands(), false); $3->detachOperands(); delete $3; } + | LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { Poincare::Expression * terms[1] = {$2}; $$ = new Poincare::Parenthesis(terms, false); } +/* MATRICES_ARE_DEFINED */ + | LEFT_BRACKET mtxData RIGHT_BRACKET { $$ = new Poincare::Matrix($2); delete $2; } + ; -final_exp: - exp { $$ = $1; } - | exp STO symb { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Store(terms, false); }; +bang : term { $$ = $1; } + | term BANG { $$ = new Poincare::Factorial($1, false); } + ; + +factor : bang { $$ = $1; } + | bang pow %prec IMPLICIT_MULTIPLY { Poincare::Expression * terms[2] = {$1,$2}; $$ = new Poincare::Multiplication(terms, 2, false); } + ; + +pow : factor { $$ = $1; } + | bang POW pow { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Power(terms, false); } + | bang POW MINUS pow { Poincare::Expression * terms1[1] = {$4}; Poincare::Expression * terms[2] = {$1,new Poincare::Opposite(terms1, false)}; $$ = new Poincare::Power(terms, false); } + ; + +div : pow { $$ = $1; } + | div DIVIDE pow { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Division(terms, false); } + | div DIVIDE MINUS pow { Poincare::Expression * terms1[1] = {$4}; Poincare::Expression * terms[2] = {$1,new Poincare::Opposite(terms1, false)}; $$ = new Poincare::Division(terms, false); } + ; + +mul : div { $$ = $1; } + | mul MULTIPLY div { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Multiplication(terms, 2, false); } + | mul MULTIPLY MINUS div { Poincare::Expression * terms1[1] = {$4}; Poincare::Expression * terms[2] = {$1,new Poincare::Opposite(terms1, false)}; $$ = new Poincare::Multiplication(terms, 2, false); } + ; + +min : mul { $$ = $1; } + | mul MINUS min { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Subtraction(terms, false); } + | mul MINUS MINUS min { Poincare::Expression * terms1[1] = {$4}; Poincare::Expression * terms[2] = {$1,new Poincare::Opposite(terms1, false)}; $$ = new Poincare::Subtraction(terms, false); } + ; + +unmin : min { $$ = $1; } + | MINUS min %prec UNARY_MINUS { Poincare::Expression * terms[1] = {$2}; $$ = new Poincare::Opposite(terms, false); } + ; + +exp : unmin { $$ = $1; } + | exp PLUS unmin { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Addition(terms, 2, false); } + ; + +final_exp : exp { $$ = $1; } + | exp STO symb { Poincare::Expression * terms[2] = {$1,$3}; $$ = new Poincare::Store(terms, false); } + ; %% void poincare_expression_yyerror(Poincare::Expression ** expressionOutput, const char * msg) { From 7770f92df88b118e39aeabfe6c2d16ce1ebe6f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 18 Jan 2018 10:26:38 +0100 Subject: [PATCH 198/257] [poincare] canBeOmittedMultiplicationLeft/RightFactor for layouts. Change-Id: I059226e95cb8d931ee65062965a888f4a06e67db --- poincare/include/poincare/expression_layout.h | 7 +++++++ poincare/src/layout/expression_layout.cpp | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 3cfd319a6..28cf1f1e2 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -95,6 +95,13 @@ public: virtual bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { return true; } /* isCollapsable is used when adding a brother fraction: should the layout be * inserted in the numerator (or denominator)? */ + bool canBeOmittedMultiplicationLeftFactor() const; + bool canBeOmittedMultiplicationRightFactor() const; + /* canBeOmittedMultiplicationLeftFactor and RightFactor return true if the + * layout, next to another layout, might be the factor of a multiplication + * with an omitted multiplication sign. For instance, an absolute value layout + * returns true, because |3|2 means |3|*2. A '+' CharLayout returns false, + * because +'something' nevers means +*'something'. */ virtual bool mustHaveLeftBrother() const { return false; } virtual bool isHorizontal() const { return false; } virtual bool isLeftParenthesis() const { return false; } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 6c318fb0f..ffec0e9b8 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -282,6 +282,23 @@ bool ExpressionLayout::moveDownInside(ExpressionLayoutCursor * cursor) { return moveInside(VerticalDirection::Down, cursor); } +bool ExpressionLayout::canBeOmittedMultiplicationLeftFactor() const { + // WARNING: canBeOmittedMultiplicationLeftFactor is true when and only when + // isCollapsable is true too. If isCollapsable changes, it might not be the + // case anymore so make sure to modify this function if needed. + int numberOfOpenParentheses = 0; + return isCollapsable(&numberOfOpenParentheses, true); +} + +bool ExpressionLayout::canBeOmittedMultiplicationRightFactor() const { + // WARNING: canBeOmittedMultiplicationLeftFactor is true when and only when + // isCollapsable is true and mustHaveLeftBrother is false. If one of these + // functions changes, , it might not be the case anymore so make sure to + // modify canBeOmittedMultiplicationRightFactor if needed. + int numberOfOpenParentheses = 0; + return isCollapsable(&numberOfOpenParentheses, false) && !mustHaveLeftBrother(); +} + void ExpressionLayout::detachChildAtIndex(int i) { ExpressionLayout ** op = const_cast(children()); if (op[i] != nullptr && op[i]->parent() == this) { From 8ffac8f69f33b9b67524125482f636dbeecd5b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 18:07:49 +0100 Subject: [PATCH 199/257] [poincare] Fixed fraction serialization. There was a problem with omitted multiplications: 1/2 3 would be computed as 1/(2*3). Change-Id: Ic8e7ebfaa525c8bbf910d7c93fb7a3ca770a2e44 --- poincare/src/layout/fraction_layout.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 066047caa..4b112cfb7 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -2,6 +2,7 @@ #include "empty_visible_layout.h" #include "horizontal_layout.h" #include +#include #include #include #include @@ -161,10 +162,27 @@ int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize) const { int numberOfChar = 0; if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + int indexInParent = -1; + if (m_parent) { + indexInParent = m_parent->indexOfChild(this); + } + + // Add a multiplication if omitted. + if (indexInParent > 0 && m_parent->isHorizontal() && m_parent->child(indexInParent - 1)->canBeOmittedMultiplicationLeftFactor()) { + buffer[numberOfChar++] = Ion::Charset::MiddleDot; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + } + // Write the content of the fraction numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, "/"); - if (numberOfChar >= bufferSize-1) { return bufferSize-1; } + + // Add a multiplication if omitted. + if (indexInParent >= 0 && indexInParent < (m_parent->numberOfChildren() - 1) && m_parent->isHorizontal() && m_parent->child(indexInParent + 1)->canBeOmittedMultiplicationRightFactor()) { + buffer[numberOfChar++] = Ion::Charset::MiddleDot; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + } + buffer[numberOfChar] = 0; return numberOfChar; } From 65666dc35f3a8855c66f27ef00856ed3d58dd8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 17 Jan 2018 18:09:04 +0100 Subject: [PATCH 200/257] [poincare] Fixed vertical offset layout serialization. There was a problem with omitted multiplications: 1^2 3 would be computed as 1^(2*3). Change-Id: Ifc4b0e0bd61fad1b752e1415c6dd0cf3b3b1f3a6 --- poincare/src/layout/vertical_offset_layout.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp index 6af0a64d6..7f3fac07c 100644 --- a/poincare/src/layout/vertical_offset_layout.cpp +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -1,5 +1,6 @@ #include "vertical_offset_layout.h" #include "empty_visible_layout.h" +#include #include #include #include @@ -206,7 +207,19 @@ int VerticalOffsetLayout::writeTextInBuffer(char * buffer, int bufferSize) const } assert(m_type == Type::Superscript); // If the layout is a superscript, write "^(indice)" - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "^"); + int numberOfChar = LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "^"); + + // Add a multiplication if omitted. + int indexInParent = -1; + if (m_parent) { + indexInParent = m_parent->indexOfChild(this); + } + if (indexInParent >= 0 && indexInParent < (m_parent->numberOfChildren() - 1) && m_parent->isHorizontal() && m_parent->child(indexInParent + 1)->canBeOmittedMultiplicationRightFactor()) { + buffer[numberOfChar++] = Ion::Charset::MiddleDot; + if (numberOfChar >= bufferSize-1) { return bufferSize-1;} + } + buffer[numberOfChar] = 0; + return numberOfChar; } ExpressionLayout * VerticalOffsetLayout::indiceLayout() { From 5363eac1489b44b12f71ab66fb5ece2e219fa066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 18 Jan 2018 09:40:24 +0100 Subject: [PATCH 201/257] [poincare] Fixed function operands order in parser. Change-Id: Ieff07d664827a82bdd6fbdda821a4b61feabd795 --- poincare/src/expression_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index 90d6584f9..e617edf6a 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -190,8 +190,8 @@ term : EMPTY { $$ = $1; } | FUNCTION UNDERSCORE LEFT_BRACE lstData RIGHT_BRACE LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; int totalNumberOfArguments = $4->numberOfOperands()+$7->numberOfOperands(); if (!$1->hasValidNumberOfOperands(totalNumberOfArguments)) { delete $1; delete $4; delete $7; YYERROR; }; Poincare::ListData * arguments = new Poincare::ListData(); -for (int i = 0; i < $4->numberOfOperands(); i++) { arguments->pushExpression($4->operands()[i]); } for (int i = 0; i < $7->numberOfOperands(); i++) { arguments->pushExpression($7->operands()[i]); } +for (int i = 0; i < $4->numberOfOperands(); i++) { arguments->pushExpression($4->operands()[i]); } $1->setArgument(arguments, totalNumberOfArguments, false); $4->detachOperands(); delete $4; $7->detachOperands(); delete $7; arguments->detachOperands(); delete arguments;} | FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { $$ = $1; if (!$1->hasValidNumberOfOperands($3->numberOfOperands())) { delete $1; delete $3; YYERROR; } ; $1->setArgument($3, $3->numberOfOperands(), false); $3->detachOperands(); delete $3; } From 440709dace4dfff9f78b737175c4ff134671dd74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 18 Jan 2018 10:26:04 +0100 Subject: [PATCH 202/257] [poincare] Better comment for isCollapsable in ExpressionLayout. Change-Id: I944ec90a52b3b69e90c7a75163716c885ef256b4 --- poincare/include/poincare/expression_layout.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 28cf1f1e2..43992af35 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -94,7 +94,9 @@ public: /* Other */ virtual bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { return true; } /* isCollapsable is used when adding a brother fraction: should the layout be - * inserted in the numerator (or denominator)? */ + * inserted in the numerator (or denominator)? For instance, 1+2|3-4 should + * become 1+ 2/3 - 4 when pressing "Divide": a CharLayout is collapsable if + * its char is not +, -, or *. */ bool canBeOmittedMultiplicationLeftFactor() const; bool canBeOmittedMultiplicationRightFactor() const; /* canBeOmittedMultiplicationLeftFactor and RightFactor return true if the From 1ad4e6e74471e96f4e9dceb5d9991dc6189a4cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 18 Jan 2018 17:55:16 +0100 Subject: [PATCH 203/257] [escher/poincare] Remove unneeded layout computation. When moving a cursor in an EditableExpressionView, do not recompute the layout, unless specified otherwise (for instance when entering or exiting a MatrixLayout). Change-Id: Ic2471095d6f6a08014a79f1d9d8fb7d39a1a6864 --- .../include/escher/editable_expression_view.h | 1 + escher/src/editable_expression_view.cpp | 63 ++++++++++++------- poincare/include/poincare/expression_layout.h | 25 ++++---- .../poincare/expression_layout_cursor.h | 8 +-- poincare/src/expression_layout_cursor.cpp | 16 ++--- .../layout/binomial_coefficient_layout.cpp | 20 +++--- .../src/layout/binomial_coefficient_layout.h | 8 +-- poincare/src/layout/bracket_layout.cpp | 8 +-- poincare/src/layout/bracket_layout.h | 4 +- .../src/layout/bracket_left_right_layout.cpp | 8 +-- .../src/layout/bracket_left_right_layout.h | 4 +- poincare/src/layout/char_layout.cpp | 8 +-- poincare/src/layout/char_layout.h | 4 +- poincare/src/layout/condensed_sum_layout.cpp | 28 ++++----- poincare/src/layout/condensed_sum_layout.h | 8 +-- poincare/src/layout/conjugate_layout.cpp | 8 +-- poincare/src/layout/conjugate_layout.h | 4 +- poincare/src/layout/empty_visible_layout.cpp | 8 +-- poincare/src/layout/empty_visible_layout.h | 4 +- poincare/src/layout/expression_layout.cpp | 23 +++---- poincare/src/layout/fraction_layout.cpp | 24 +++---- poincare/src/layout/fraction_layout.h | 8 +-- poincare/src/layout/grid_layout.cpp | 20 +++--- poincare/src/layout/grid_layout.h | 8 +-- poincare/src/layout/horizontal_layout.cpp | 46 +++++++------- poincare/src/layout/horizontal_layout.h | 10 +-- poincare/src/layout/integral_layout.cpp | 24 +++---- poincare/src/layout/integral_layout.h | 8 +-- poincare/src/layout/matrix_layout.cpp | 22 ++++--- poincare/src/layout/matrix_layout.h | 8 +-- poincare/src/layout/nth_root_layout.cpp | 16 ++--- poincare/src/layout/nth_root_layout.h | 8 +-- .../layout/parenthesis_left_right_layout.cpp | 8 +-- .../layout/parenthesis_left_right_layout.h | 4 +- poincare/src/layout/sequence_layout.cpp | 24 +++---- poincare/src/layout/sequence_layout.h | 8 +-- .../src/layout/vertical_offset_layout.cpp | 16 ++--- poincare/src/layout/vertical_offset_layout.h | 8 +-- 38 files changed, 280 insertions(+), 250 deletions(-) diff --git a/escher/include/escher/editable_expression_view.h b/escher/include/escher/editable_expression_view.h index f4cf92423..84dcd8d9b 100644 --- a/escher/include/escher/editable_expression_view.h +++ b/escher/include/escher/editable_expression_view.h @@ -30,6 +30,7 @@ public: protected: virtual bool privateHandleEvent(Ion::Events::Event event); + bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout); ExpressionViewWithCursor m_expressionViewWithCursor; private: EditableExpressionViewDelegate * m_delegate; diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index 01159a81a..acc66f38d 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -31,6 +31,21 @@ Toolbox * EditableExpressionView::toolbox() { bool EditableExpressionView::handleEvent(Ion::Events::Event event) { KDSize previousSize = minimalSizeForOptimalDisplay(); + bool shouldRecomputeLayout = false; + if (privateHandleMoveEvent(event, &shouldRecomputeLayout)) { + if (!shouldRecomputeLayout) { + m_expressionViewWithCursor.cursorPositionChanged(); + scrollToCursor(); + return true; + } + reload(); + KDSize newSize = minimalSizeForOptimalDisplay(); + if (m_delegate && previousSize.height() != newSize.height()) { + m_delegate->editableExpressionViewDidChangeSize(this); + reload(); + } + return true; + } if (privateHandleEvent(event)) { reload(); KDSize newSize = minimalSizeForOptimalDisplay(); @@ -51,6 +66,32 @@ KDSize EditableExpressionView::minimalSizeForOptimalDisplay() const { return m_expressionViewWithCursor.minimalSizeForOptimalDisplay(); } +bool EditableExpressionView::privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) { + if (event == Ion::Events::Left) { + return m_expressionViewWithCursor.cursor()->moveLeft(shouldRecomputeLayout); + } + if (event == Ion::Events::Right) { + return m_expressionViewWithCursor.cursor()->moveRight(shouldRecomputeLayout); + } + if (event == Ion::Events::Up) { + return m_expressionViewWithCursor.cursor()->moveUp(shouldRecomputeLayout); + } + if (event == Ion::Events::Down) { + return m_expressionViewWithCursor.cursor()->moveDown(shouldRecomputeLayout); + } + if (event == Ion::Events::ShiftLeft) { + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Left); + return true; + } + if (event == Ion::Events::ShiftRight) { + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + return true; + } + return false; +} + bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { if (m_delegate && m_delegate->editableExpressionViewDidReceiveEvent(this, event)) { return true; @@ -76,28 +117,6 @@ bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { } return true; } - if (event == Ion::Events::Left) { - return m_expressionViewWithCursor.cursor()->moveLeft(); - } - if (event == Ion::Events::Right) { - return m_expressionViewWithCursor.cursor()->moveRight(); - } - if (event == Ion::Events::Up) { - return m_expressionViewWithCursor.cursor()->moveUp(); - } - if (event == Ion::Events::Down) { - return m_expressionViewWithCursor.cursor()->moveDown(); - } - if (event == Ion::Events::ShiftLeft) { - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Left); - return true; - } - if (event == Ion::Events::ShiftRight) { - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); - return true; - } if (event == Ion::Events::Division) { m_expressionViewWithCursor.cursor()->addFractionLayoutAndCollapseBrothers(); return true; diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 43992af35..580f89273 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -75,18 +75,20 @@ public: virtual void backspaceAtCursor(ExpressionLayoutCursor * cursor); /* Tree navigation */ - virtual bool moveLeft(ExpressionLayoutCursor * cursor) = 0; - virtual bool moveRight(ExpressionLayoutCursor * cursor) = 0; + virtual bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) = 0; + virtual bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) = 0; virtual bool moveUp( ExpressionLayoutCursor * cursor, + bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); virtual bool moveDown( ExpressionLayoutCursor * cursor, + bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); - virtual bool moveUpInside(ExpressionLayoutCursor * cursor); - virtual bool moveDownInside(ExpressionLayoutCursor * cursor); + virtual bool moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr); + virtual bool moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr); /* Expression Engine */ virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0; @@ -119,6 +121,13 @@ protected: virtual KDSize computeSize() = 0; virtual void computeBaseline() = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; + virtual void moveCursorInsideAtDirection ( + VerticalDirection direction, + ExpressionLayoutCursor * cursor, + bool * shouldRecomputeLayout, + ExpressionLayout ** childResult, + void * resultPosition, + int * resultScore); ExpressionLayout * m_parent; KDCoordinate m_baseline; /* m_baseline is the signed vertical distance from the top of the layout to @@ -129,13 +138,7 @@ protected: bool m_positioned; private: void detachChildAtIndex(int i); - bool moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor); - void moveCursorInsideAtDirection ( - VerticalDirection direction, - ExpressionLayoutCursor * cursor, - ExpressionLayout ** childResult, - void * resultPosition, - int * resultScore); + bool moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout); ExpressionLayout * replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace); KDRect m_frame; }; diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 5cfd89e4a..7145d3c81 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -33,10 +33,10 @@ public: KDPoint middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position); /* Move */ - bool moveLeft(); - bool moveRight(); - bool moveUp(); - bool moveDown(); + bool moveLeft(bool * shouldRecomputeLayout = nullptr); + bool moveRight(bool * shouldRecomputeLayout); + bool moveUp(bool * shouldRecomputeLayout); + bool moveDown(bool * shouldRecomputeLayout); /* Edition */ void addLayout(ExpressionLayout * layout); diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 87f5de8bb..0923f888e 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -25,20 +25,20 @@ KDPoint ExpressionLayoutCursor::middleLeftPointOfCursor(ExpressionLayout * expre return KDPoint(layoutOrigin.x() + expressionLayout->size().width(), y); } -bool ExpressionLayoutCursor::moveLeft() { - return m_pointedExpressionLayout->moveLeft(this); +bool ExpressionLayoutCursor::moveLeft(bool * shouldRecomputeLayout) { + return m_pointedExpressionLayout->moveLeft(this, shouldRecomputeLayout); } -bool ExpressionLayoutCursor::moveRight() { - return m_pointedExpressionLayout->moveRight(this); +bool ExpressionLayoutCursor::moveRight(bool * shouldRecomputeLayout) { + return m_pointedExpressionLayout->moveRight(this, shouldRecomputeLayout); } -bool ExpressionLayoutCursor::moveUp() { - return m_pointedExpressionLayout->moveUp(this); +bool ExpressionLayoutCursor::moveUp(bool * shouldRecomputeLayout) { + return m_pointedExpressionLayout->moveUp(this, shouldRecomputeLayout); } -bool ExpressionLayoutCursor::moveDown() { - return m_pointedExpressionLayout->moveDown(this); +bool ExpressionLayoutCursor::moveDown(bool * shouldRecomputeLayout) { + return m_pointedExpressionLayout->moveDown(this, shouldRecomputeLayout); } void ExpressionLayoutCursor::addLayout(ExpressionLayout * layout) { diff --git a/poincare/src/layout/binomial_coefficient_layout.cpp b/poincare/src/layout/binomial_coefficient_layout.cpp index aec65fd20..93867456a 100644 --- a/poincare/src/layout/binomial_coefficient_layout.cpp +++ b/poincare/src/layout/binomial_coefficient_layout.cpp @@ -18,7 +18,7 @@ ExpressionLayout * BinomialCoefficientLayout::clone() const { return new BinomialCoefficientLayout(const_cast(this)->nLayout(), const_cast(this)->kLayout(), true); } -bool BinomialCoefficientLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool BinomialCoefficientLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left of the children. // Go Left. if (cursor->position() == ExpressionLayoutCursor::Position::Left @@ -43,12 +43,12 @@ bool BinomialCoefficientLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool BinomialCoefficientLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool BinomialCoefficientLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right of the children. // Go Right. if (cursor->position() == ExpressionLayoutCursor::Position::Right @@ -71,27 +71,27 @@ bool BinomialCoefficientLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } -bool BinomialCoefficientLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool BinomialCoefficientLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // Case: kLayout. // Move to nLayout. if (previousLayout == kLayout()) { - return nLayout()->moveUpInside(cursor); + return nLayout()->moveUpInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool BinomialCoefficientLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool BinomialCoefficientLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // Case: nLayout. // Move to kLayout. if (previousLayout == nLayout()) { - return kLayout()->moveDownInside(cursor); + return kLayout()->moveDownInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } void BinomialCoefficientLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { diff --git a/poincare/src/layout/binomial_coefficient_layout.h b/poincare/src/layout/binomial_coefficient_layout.h index 30dc3da69..8cfa19323 100644 --- a/poincare/src/layout/binomial_coefficient_layout.h +++ b/poincare/src/layout/binomial_coefficient_layout.h @@ -10,10 +10,10 @@ class BinomialCoefficientLayout : public StaticLayoutHierarchy<2> { public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "binomial"); } diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 38fd0b400..9fe511f88 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -25,7 +25,7 @@ void BracketLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout::backspaceAtCursor(cursor); } -bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left of the operand. // Go Left of the brackets. if (operandLayout() @@ -47,12 +47,12 @@ bool BracketLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the brackets. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right of the operand. // Go Right of the brackets. if (operandLayout() @@ -75,7 +75,7 @@ bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. cursor->setPointedExpressionLayout(this); if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index 94b63398f..b9a746f36 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -10,8 +10,8 @@ public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: ExpressionLayout * operandLayout(); diff --git a/poincare/src/layout/bracket_left_right_layout.cpp b/poincare/src/layout/bracket_left_right_layout.cpp index f39263fff..540a4ce89 100644 --- a/poincare/src/layout/bracket_left_right_layout.cpp +++ b/poincare/src/layout/bracket_left_right_layout.cpp @@ -18,7 +18,7 @@ void BracketLeftRightLayout::invalidAllSizesPositionsAndBaselines() { ExpressionLayout::invalidAllSizesPositionsAndBaselines(); } -bool BracketLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool BracketLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { assert(cursor->pointedExpressionLayout() == this); // Case: Right. // Go Left. @@ -30,12 +30,12 @@ bool BracketLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool BracketLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool BracketLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { assert(cursor->pointedExpressionLayout() == this); // Case: Left. // Go Right. @@ -47,7 +47,7 @@ bool BracketLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h index 98cf4e875..7dfc9708a 100644 --- a/poincare/src/layout/bracket_left_right_layout.h +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -9,8 +9,8 @@ class BracketLeftRightLayout : public StaticLayoutHierarchy<0> { public: BracketLeftRightLayout(); void invalidAllSizesPositionsAndBaselines() override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; protected: constexpr static KDCoordinate k_bracketWidth = 5; constexpr static KDCoordinate k_lineThickness = 1; diff --git a/poincare/src/layout/char_layout.cpp b/poincare/src/layout/char_layout.cpp index b4e67dc52..0dde197c6 100644 --- a/poincare/src/layout/char_layout.cpp +++ b/poincare/src/layout/char_layout.cpp @@ -18,7 +18,7 @@ ExpressionLayout * CharLayout::clone() const { return layout; } -bool CharLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool CharLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { assert(cursor->pointedExpressionLayout() == this); // Case: Right. // Go Left. @@ -29,12 +29,12 @@ bool CharLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool CharLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool CharLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { assert(cursor->pointedExpressionLayout() == this); // Case: Left. // Go Right. @@ -45,7 +45,7 @@ bool CharLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } diff --git a/poincare/src/layout/char_layout.h b/poincare/src/layout/char_layout.h index cbdb775b8..37ebd3692 100644 --- a/poincare/src/layout/char_layout.h +++ b/poincare/src/layout/char_layout.h @@ -17,8 +17,8 @@ public: char character() { return m_char; } KDText::FontSize fontSize() const { return m_fontSize; } - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/condensed_sum_layout.cpp b/poincare/src/layout/condensed_sum_layout.cpp index a7a511e9e..33058438e 100644 --- a/poincare/src/layout/condensed_sum_layout.cpp +++ b/poincare/src/layout/condensed_sum_layout.cpp @@ -10,7 +10,7 @@ ExpressionLayout * CondensedSumLayout::clone() const { return layout; } -bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left of the bounds. // Go Left of the sum. if (((subscriptLayout() && cursor->pointedExpressionLayout() == subscriptLayout()) @@ -37,18 +37,18 @@ bool CondensedSumLayout::moveLeft(ExpressionLayoutCursor * cursor) { if (cursor->position() == ExpressionLayoutCursor::Position::Right) { assert(baseLayout()); cursor->setPointedExpressionLayout(baseLayout()); - return baseLayout()->moveLeft(cursor); + return baseLayout()->moveLeft(cursor, shouldRecomputeLayout); } // Case: Left. // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right of the bounds. // Go Left of the operand. if (((subscriptLayout() && cursor->pointedExpressionLayout() == subscriptLayout()) @@ -69,7 +69,7 @@ bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor) { cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } @@ -85,16 +85,16 @@ bool CondensedSumLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Right); if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } -bool CondensedSumLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool CondensedSumLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the subscript layout, move it to the superscript. if (subscriptLayout() && previousLayout == subscriptLayout()) { assert(superscriptLayout() != nullptr); - return superscriptLayout()->moveUpInside(cursor); + return superscriptLayout()->moveUpInside(cursor, shouldRecomputeLayout); } // If the cursor is Left of the base layout, move it to the superscript. if (baseLayout() @@ -102,16 +102,16 @@ bool CondensedSumLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayou && cursor->positionIsEquivalentTo(baseLayout(), ExpressionLayoutCursor::Position::Left)) { assert(superscriptLayout() != nullptr); - return superscriptLayout()->moveUpInside(cursor); + return superscriptLayout()->moveUpInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool CondensedSumLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool CondensedSumLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the superscript layout, move it to the subscript. if (superscriptLayout() && previousLayout == superscriptLayout()) { assert(subscriptLayout() != nullptr); - return subscriptLayout()->moveUpInside(cursor); + return subscriptLayout()->moveUpInside(cursor, shouldRecomputeLayout); } // If the cursor is Left of the base layout, move it to the subscript. if (baseLayout() @@ -119,9 +119,9 @@ bool CondensedSumLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLay && cursor->positionIsEquivalentTo(baseLayout(), ExpressionLayoutCursor::Position::Left)) { assert(subscriptLayout() != nullptr); - return subscriptLayout()->moveUpInside(cursor); + return subscriptLayout()->moveUpInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } void CondensedSumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index 2647474cd..d7a236e4e 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -10,10 +10,10 @@ class CondensedSumLayout : public StaticLayoutHierarchy<3> { public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override { return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "sum"); } diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index 7323e1fd7..15e90362d 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -27,7 +27,7 @@ void ConjugateLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout::backspaceAtCursor(cursor); } -bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left of the operand. // Move Left. if (operandLayout() @@ -49,12 +49,12 @@ bool ConjugateLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right of the operand. // Move Right. if (operandLayout() @@ -76,7 +76,7 @@ bool ConjugateLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Right); if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index f4846619f..896e777a0 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -11,8 +11,8 @@ public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override { diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index bddbda688..5e8517611 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -40,7 +40,7 @@ void EmptyVisibleLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { } } -bool EmptyVisibleLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool EmptyVisibleLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { assert(cursor->pointedExpressionLayout() == this); // Case: Right. // Go Left. @@ -51,12 +51,12 @@ bool EmptyVisibleLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool EmptyVisibleLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool EmptyVisibleLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { assert(cursor->pointedExpressionLayout() == this); // Case: Left. // Go Right. @@ -67,7 +67,7 @@ bool EmptyVisibleLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index 4d454d97b..0bab3e9ff 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -16,8 +16,8 @@ public: ExpressionLayout * clone() const override; void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; bool isEmpty() const override { return true; } Color color() const { return m_color; } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index ffec0e9b8..936c7c9fd 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -260,26 +260,26 @@ char ExpressionLayout::XNTChar() const { return m_parent->XNTChar(); } -bool ExpressionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool ExpressionLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { if (m_parent) { - return m_parent->moveUp(cursor, this, previousLayout); + return m_parent->moveUp(cursor, shouldRecomputeLayout, this, previousLayout); } return false; } -bool ExpressionLayout::moveUpInside(ExpressionLayoutCursor * cursor) { - return moveInside(VerticalDirection::Up, cursor); +bool ExpressionLayout::moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { + return moveInside(VerticalDirection::Up, cursor, shouldRecomputeLayout); } -bool ExpressionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool ExpressionLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { if (m_parent) { - return m_parent->moveDown(cursor, this, previousLayout); + return m_parent->moveDown(cursor, shouldRecomputeLayout, this, previousLayout); } return false; } -bool ExpressionLayout::moveDownInside(ExpressionLayoutCursor * cursor) { - return moveInside(VerticalDirection::Down, cursor); +bool ExpressionLayout::moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { + return moveInside(VerticalDirection::Down, cursor, shouldRecomputeLayout); } bool ExpressionLayout::canBeOmittedMultiplicationLeftFactor() const { @@ -310,7 +310,7 @@ void ExpressionLayout::detachChildAtIndex(int i) { m_baselined = false; } -bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor) { +bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { ExpressionLayout * chilResult = nullptr; ExpressionLayout ** childResultPtr = &chilResult; ExpressionLayoutCursor::Position resultPosition = ExpressionLayoutCursor::Position::Left; @@ -318,7 +318,7 @@ bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutC // than this initial value of score. int resultScore = Ion::Display::Width*Ion::Display::Width + Ion::Display::Height*Ion::Display::Height; - moveCursorInsideAtDirection(direction, cursor, childResultPtr, &resultPosition, &resultScore); + moveCursorInsideAtDirection(direction, cursor, shouldRecomputeLayout, childResultPtr, &resultPosition, &resultScore); // If there is a valid result if (*childResultPtr == nullptr) { @@ -332,6 +332,7 @@ bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutC void ExpressionLayout::moveCursorInsideAtDirection ( VerticalDirection direction, ExpressionLayoutCursor * cursor, + bool * shouldRecomputeLayout, ExpressionLayout ** childResult, void * resultPosition, int * resultScore) @@ -361,7 +362,7 @@ void ExpressionLayout::moveCursorInsideAtDirection ( if (layoutIsUnderOrAbove || layoutContains) { int childIndex = 0; while (child(childIndex++)) { - editableChild(childIndex-1)->moveCursorInsideAtDirection(direction, cursor, childResult, castedResultPosition, resultScore); + editableChild(childIndex-1)->moveCursorInsideAtDirection(direction, cursor, shouldRecomputeLayout, childResult, castedResultPosition, resultScore); } } } diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 4b112cfb7..82e6956ff 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -72,7 +72,7 @@ void FractionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout::backspaceAtCursor(cursor); } -bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left of the numerator or the denominator. // Go Left of the fraction. if (((numeratorLayout() && cursor->pointedExpressionLayout() == numeratorLayout()) @@ -94,12 +94,12 @@ bool FractionLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool FractionLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool FractionLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right of the numerator or the denominator. // Go Right of the fraction. if (((numeratorLayout() && cursor->pointedExpressionLayout() == numeratorLayout()) @@ -121,37 +121,37 @@ bool FractionLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Right); if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } -bool FractionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool FractionLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside denominator, move it to the numerator. if (denominatorLayout() && previousLayout == denominatorLayout()) { assert(numeratorLayout() != nullptr); - return numeratorLayout()->moveUpInside(cursor); + return numeratorLayout()->moveUpInside(cursor, shouldRecomputeLayout); } // If the cursor is Left or Right, move it to the numerator. if (cursor->pointedExpressionLayout() == this){ assert(numeratorLayout() != nullptr); - return numeratorLayout()->moveUpInside(cursor); + return numeratorLayout()->moveUpInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside numerator, move it to the denominator. if (numeratorLayout() && previousLayout == numeratorLayout()) { assert(denominatorLayout() != nullptr); - return denominatorLayout()->moveDownInside(cursor); + return denominatorLayout()->moveDownInside(cursor, shouldRecomputeLayout); } // If the cursor is Left or Right, move it to the denominator. if (cursor->pointedExpressionLayout() == this){ assert(denominatorLayout() != nullptr); - return denominatorLayout()->moveDownInside(cursor); + return denominatorLayout()->moveDownInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 7c551df14..2eb341453 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -11,10 +11,10 @@ public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/grid_layout.cpp b/poincare/src/layout/grid_layout.cpp index e7af88579..b5d9f9934 100644 --- a/poincare/src/layout/grid_layout.cpp +++ b/poincare/src/layout/grid_layout.cpp @@ -21,7 +21,7 @@ ExpressionLayout * GridLayout::clone() const { return layout; } -bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right. // Go to the last entry. if (cursor->pointedExpressionLayout() == this @@ -52,12 +52,12 @@ bool GridLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool GridLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool GridLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left. // Go to the first entry. if (cursor->pointedExpressionLayout() == this @@ -89,29 +89,29 @@ bool GridLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } -bool GridLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool GridLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is child that is not on the top row, move it inside the upper // neighbourg. int childIndex = indexOfChild(previousLayout); if (childIndex >- 1 && !childIsTopOfGrid(childIndex)) { - return editableChild(childIndex - m_numberOfColumns)->moveUpInside(cursor); + return editableChild(childIndex - m_numberOfColumns)->moveUpInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is child that is not on the bottom row, move it inside the // lower neighbourg. int childIndex = indexOfChild(previousLayout); if (childIndex >- 1 && !childIsBottomOfGrid(childIndex)) { - return editableChild(childIndex + m_numberOfColumns)->moveDownInside(cursor); + return editableChild(childIndex + m_numberOfColumns)->moveDownInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } void GridLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index d7e2915f6..ad80b8f49 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -13,10 +13,10 @@ public: ExpressionLayout * clone() const override; /* Navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; /* Dynamic layout */ void removeChildAtIndex(int index, bool deleteAfterRemoval) override; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index e0e27198d..baf038e23 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -177,13 +177,13 @@ void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index, addChildAtIndex(eL, newIndex); } -bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left. // Ask the parent. if (cursor->pointedExpressionLayout() == this) { if (cursor->position() == ExpressionLayoutCursor::Position::Left) { if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } @@ -194,14 +194,14 @@ bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { if (numberOfChildren() < 1) { cursor->setPosition(ExpressionLayoutCursor::Position::Left); if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } ExpressionLayout * lastChild = editableChild(numberOfChildren()-1); assert(lastChild != nullptr); cursor->setPointedExpressionLayout(lastChild); - return lastChild->moveLeft(cursor); + return lastChild->moveLeft(cursor, shouldRecomputeLayout); } // Case: The cursor is Left of a child. @@ -213,7 +213,7 @@ bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Ask the parent. if (m_parent) { cursor->setPointedExpressionLayout(this); - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } @@ -221,16 +221,16 @@ bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Go to its left brother and move Left. cursor->setPointedExpressionLayout(editableChild(childIndex-1)); cursor->setPosition(ExpressionLayoutCursor::Position::Right); - return editableChild(childIndex-1)->moveLeft(cursor); + return editableChild(childIndex-1)->moveLeft(cursor, shouldRecomputeLayout); } -bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right. // Ask the parent. if (cursor->pointedExpressionLayout() == this) { if (cursor->position() == ExpressionLayoutCursor::Position::Right) { if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } @@ -241,14 +241,14 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { if (numberOfChildren() < 1) { cursor->setPosition(ExpressionLayoutCursor::Position::Right); if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } ExpressionLayout * firstChild = editableChild(0); assert(firstChild != nullptr); cursor->setPointedExpressionLayout(firstChild); - return firstChild->moveRight(cursor); + return firstChild->moveRight(cursor, shouldRecomputeLayout); } // Case: The cursor is Right of a child. @@ -260,7 +260,7 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. if (m_parent) { cursor->setPointedExpressionLayout(this); - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } @@ -268,15 +268,15 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) { // Go to its right brother and move Right. cursor->setPointedExpressionLayout(editableChild(childIndex+1)); cursor->setPosition(ExpressionLayoutCursor::Position::Left); - return editableChild(childIndex+1)->moveRight(cursor); + return editableChild(childIndex+1)->moveRight(cursor, shouldRecomputeLayout); } -bool HorizontalLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { - return moveVertically(ExpressionLayout::VerticalDirection::Up, cursor, previousLayout, previousPreviousLayout); +bool HorizontalLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + return moveVertically(ExpressionLayout::VerticalDirection::Up, cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool HorizontalLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { - return moveVertically(ExpressionLayout::VerticalDirection::Down, cursor, previousLayout, previousPreviousLayout); +bool HorizontalLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + return moveVertically(ExpressionLayout::VerticalDirection::Down, cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } void HorizontalLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { @@ -341,14 +341,14 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x, y); } -bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // Prevent looping fom child to parent if (previousPreviousLayout == this) { if (direction == ExpressionLayout::VerticalDirection::Up) { - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } assert(direction == ExpressionLayout::VerticalDirection::Down); - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } // If the cursor Left or Right of a child, try moving it up from its brother. int previousLayoutIndex = indexOfChild(previousLayout); @@ -368,10 +368,10 @@ bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direct ExpressionLayoutCursor::Position previousPosition = cursor->position(); cursor->setPointedExpressionLayout(brother); cursor->setPosition(newPosition); - if (direction == ExpressionLayout::VerticalDirection::Up && brother->moveUp(cursor, this, previousLayout)) { + if (direction == ExpressionLayout::VerticalDirection::Up && brother->moveUp(cursor, shouldRecomputeLayout, this, previousLayout)) { return true; } - if (direction == ExpressionLayout::VerticalDirection::Down && brother->moveDown(cursor, this, previousLayout)) { + if (direction == ExpressionLayout::VerticalDirection::Down && brother->moveDown(cursor, shouldRecomputeLayout, this, previousLayout)) { return true; } cursor->setPointedExpressionLayout(previousPointedLayout); @@ -379,10 +379,10 @@ bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direct } } if (direction == ExpressionLayout::VerticalDirection::Up) { - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } assert(direction == ExpressionLayout::VerticalDirection::Down); - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 8516fa977..f6185545f 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -22,10 +22,10 @@ public: void addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren); /* Navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; /* Dynamic layout */ void removeChildAtIndex(int index, bool deleteAfterRemoval) override; @@ -45,7 +45,7 @@ protected: void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: - bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); + bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); void privateReplaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor); }; diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 505b14cbc..48941a195 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -46,7 +46,7 @@ void IntegralLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout::backspaceAtCursor(cursor); } -bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left the upper or lower bound. // Go Left of the integral. if (((upperBoundLayout() @@ -81,12 +81,12 @@ bool IntegralLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left of the brackets. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right the upper or lower bound. // Go Left of the integrand. if (((upperBoundLayout() @@ -121,16 +121,16 @@ bool IntegralLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } -bool IntegralLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool IntegralLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the lower bound, move it to the upper bound. if (lowerBoundLayout() && previousLayout == lowerBoundLayout()) { assert(upperBoundLayout() != nullptr); - return upperBoundLayout()->moveUpInside(cursor); + return upperBoundLayout()->moveUpInside(cursor, shouldRecomputeLayout); } // If the cursor is Left of the integrand, move it to the upper bound. if (integrandLayout() @@ -138,16 +138,16 @@ bool IntegralLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * && cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Left)) { assert(upperBoundLayout() != nullptr); - return upperBoundLayout()->moveUpInside(cursor); + return upperBoundLayout()->moveUpInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool IntegralLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool IntegralLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the upper bound, move it to the lower bound. if (upperBoundLayout() && previousLayout == upperBoundLayout()) { assert(lowerBoundLayout() != nullptr); - return lowerBoundLayout()->moveDownInside(cursor); + return lowerBoundLayout()->moveDownInside(cursor, shouldRecomputeLayout); } // If the cursor is Left of the integrand, move it to the lower bound. if (integrandLayout() @@ -155,9 +155,9 @@ bool IntegralLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout && cursor->positionIsEquivalentTo(integrandLayout(), ExpressionLayoutCursor::Position::Left)) { assert(lowerBoundLayout() != nullptr); - return lowerBoundLayout()->moveDownInside(cursor); + return lowerBoundLayout()->moveDownInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 35e9769df..56cb14999 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -17,10 +17,10 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; /* Tree navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; /* Expression Engine */ int writeTextInBuffer(char * buffer, int bufferSize) const override; diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index 82467984e..753b3e7b4 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -17,7 +17,7 @@ ExpressionLayout * MatrixLayout::clone() const { return layout; } -bool MatrixLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool MatrixLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { int childIndex = indexOfChild(cursor->pointedExpressionLayout()); if (childIndex >- 1 && cursor->position() == ExpressionLayoutCursor::Position::Left @@ -27,6 +27,7 @@ bool MatrixLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Remove the grey squares of the grid, then go left of the grid. assert(hasGreySquares()); removeGreySquares(); + *shouldRecomputeLayout = true; cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; @@ -39,15 +40,16 @@ bool MatrixLayout::moveLeft(ExpressionLayoutCursor * cursor) { { assert(!hasGreySquares()); addGreySquares(); + *shouldRecomputeLayout = true; ExpressionLayout * lastChild = editableChild((m_numberOfColumns-1)*(m_numberOfRows-1)); assert(lastChild != nullptr); cursor->setPointedExpressionLayout(lastChild); return true; } - return GridLayout::moveLeft(cursor); + return GridLayout::moveLeft(cursor, shouldRecomputeLayout); } -bool MatrixLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool MatrixLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left. // Add the grey squares to the matrix,, then go to the first entry. if (cursor->pointedExpressionLayout() == this @@ -55,6 +57,7 @@ bool MatrixLayout::moveRight(ExpressionLayoutCursor * cursor) { { assert(!hasGreySquares()); addGreySquares(); + *shouldRecomputeLayout = true; assert(m_numberOfColumns*m_numberOfRows >= 1); ExpressionLayout * firstChild = editableChild(0); assert(firstChild != nullptr); @@ -73,25 +76,28 @@ bool MatrixLayout::moveRight(ExpressionLayoutCursor * cursor) { cursor->setPosition(ExpressionLayoutCursor::Position::Right); assert(hasGreySquares()); removeGreySquares(); + *shouldRecomputeLayout = true; return true; } - return GridLayout::moveRight(cursor); + return GridLayout::moveRight(cursor, shouldRecomputeLayout); } -bool MatrixLayout::moveUpInside(ExpressionLayoutCursor * cursor) { - bool result = GridLayout::moveUpInside(cursor); +bool MatrixLayout::moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { + bool result = GridLayout::moveUpInside(cursor, shouldRecomputeLayout); if (result) { assert(!hasGreySquares()); addGreySquares(); + *shouldRecomputeLayout = true; } return result; } -bool MatrixLayout::moveDownInside(ExpressionLayoutCursor * cursor) { - bool result = GridLayout::moveDownInside(cursor); +bool MatrixLayout::moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { + bool result = GridLayout::moveDownInside(cursor, shouldRecomputeLayout); if (result) { assert(!hasGreySquares()); addGreySquares(); + *shouldRecomputeLayout = true; } return result; } diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 8208d11b3..2a4633b6d 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -11,10 +11,10 @@ public: ExpressionLayout * clone() const override; /* Navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUpInside(ExpressionLayoutCursor * cursor) override; - bool moveDownInside(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; /* Dynamic layout */ void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) override; diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 8c14bfe19..291171463 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -45,7 +45,7 @@ void NthRootLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout::backspaceAtCursor(cursor); } -bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left of the radicand. // Go the index if there is one, else go Left of the root. if (radicandLayout() @@ -81,12 +81,12 @@ bool NthRootLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right of the radicand. // Go the Right of the root. if (radicandLayout() @@ -123,12 +123,12 @@ bool NthRootLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } -bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is Left of the radicand, move it to the index. if (indexLayout() && radicandLayout() @@ -148,10 +148,10 @@ bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * p cursor->setPosition(ExpressionLayoutCursor::Position::Left); return true; } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { if (indexLayout() && previousLayout == indexLayout()) { // If the cursor is Right of the index, move it to the radicand. if (cursor->positionIsEquivalentTo(indexLayout(), ExpressionLayoutCursor::Position::Right)) { @@ -167,7 +167,7 @@ bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * return true; } } - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } static_assert('\x90' == Ion::Charset::Root, "Unicode error"); diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index 86a840b55..e97d05595 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -17,10 +17,10 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; /* Tree navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; /* Expression Engine */ int writeTextInBuffer(char * buffer, int bufferSize) const override; diff --git a/poincare/src/layout/parenthesis_left_right_layout.cpp b/poincare/src/layout/parenthesis_left_right_layout.cpp index 060596fac..b7d8f819e 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.cpp +++ b/poincare/src/layout/parenthesis_left_right_layout.cpp @@ -18,7 +18,7 @@ void ParenthesisLeftRightLayout::invalidAllSizesPositionsAndBaselines() { ExpressionLayout::invalidAllSizesPositionsAndBaselines(); } -bool ParenthesisLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool ParenthesisLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { assert(cursor->pointedExpressionLayout() == this); // Case: Right. // Go Left. @@ -30,12 +30,12 @@ bool ParenthesisLeftRightLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool ParenthesisLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool ParenthesisLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { assert(cursor->pointedExpressionLayout() == this); // Case: Left. // Go Right. @@ -47,7 +47,7 @@ bool ParenthesisLeftRightLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } diff --git a/poincare/src/layout/parenthesis_left_right_layout.h b/poincare/src/layout/parenthesis_left_right_layout.h index 8596d219b..0dc125452 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.h +++ b/poincare/src/layout/parenthesis_left_right_layout.h @@ -9,8 +9,8 @@ class ParenthesisLeftRightLayout : public StaticLayoutHierarchy<0> { public: ParenthesisLeftRightLayout(); void invalidAllSizesPositionsAndBaselines() override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; constexpr static KDCoordinate parenthesisWidth() { return k_widthMargin + k_lineThickness + k_externWidthMargin; } constexpr static KDCoordinate k_parenthesisCurveWidth = 5; constexpr static KDCoordinate k_parenthesisCurveHeight = 7; diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index b9a91e85b..94a64aa37 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -20,7 +20,7 @@ void SequenceLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout::backspaceAtCursor(cursor); } -bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left of the bounds. // Go Left of the sequence. if (cursor->position() == ExpressionLayoutCursor::Position::Left @@ -55,12 +55,12 @@ bool SequenceLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Case: Left. // Ask the parent. if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right of the bounds. // Go Left of the argument. if (cursor->position() == ExpressionLayoutCursor::Position::Right @@ -96,40 +96,40 @@ bool SequenceLayout::moveRight(ExpressionLayoutCursor * cursor) { // Case: Right. // Ask the parent. if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } -bool SequenceLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool SequenceLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the lower bound, move it to the upper bound. if (lowerBoundLayout() && previousLayout == lowerBoundLayout()) { assert(upperBoundLayout() != nullptr); - return upperBoundLayout()->moveUpInside(cursor); + return upperBoundLayout()->moveUpInside(cursor, shouldRecomputeLayout); } // If the cursor is Left of the argument, move it to the upper bound. if (argumentLayout() && cursor->positionIsEquivalentTo(argumentLayout(), ExpressionLayoutCursor::Position::Left)) { assert(upperBoundLayout() != nullptr); - return upperBoundLayout()->moveUpInside(cursor); + return upperBoundLayout()->moveUpInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // If the cursor is inside the upper bound, move it to the lower bound. if (upperBoundLayout() && previousLayout == upperBoundLayout()) { assert(lowerBoundLayout() != nullptr); - return lowerBoundLayout()->moveDownInside(cursor); + return lowerBoundLayout()->moveDownInside(cursor, shouldRecomputeLayout); } // If the cursor is Left of the argument, move it to the lower bound. if (argumentLayout() && cursor->positionIsEquivalentTo(argumentLayout(), ExpressionLayoutCursor::Position::Left)) { assert(lowerBoundLayout() != nullptr); - return lowerBoundLayout()->moveDownInside(cursor); + return lowerBoundLayout()->moveDownInside(cursor, shouldRecomputeLayout); } - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } char SequenceLayout::XNTChar() const { diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index ef92f3f68..f7c77d5b2 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -11,10 +11,10 @@ public: constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; char XNTChar() const override; protected: constexpr static KDCoordinate k_boundHeightMargin = 2; diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp index 7f3fac07c..89b25fb24 100644 --- a/poincare/src/layout/vertical_offset_layout.cpp +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -57,7 +57,7 @@ void VerticalOffsetLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { ExpressionLayout::backspaceAtCursor(cursor); } -bool VerticalOffsetLayout::moveLeft(ExpressionLayoutCursor * cursor) { +bool VerticalOffsetLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Left of the indice. // Go Left. if (indiceLayout() @@ -81,12 +81,12 @@ bool VerticalOffsetLayout::moveLeft(ExpressionLayoutCursor * cursor) { // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); if (m_parent) { - return m_parent->moveLeft(cursor); + return m_parent->moveLeft(cursor, shouldRecomputeLayout); } return false; } -bool VerticalOffsetLayout::moveRight(ExpressionLayoutCursor * cursor) { +bool VerticalOffsetLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { // Case: Right of the indice. // Go Right. if (indiceLayout() @@ -109,12 +109,12 @@ bool VerticalOffsetLayout::moveRight(ExpressionLayoutCursor * cursor) { // Ask the parent. assert(cursor->position() == ExpressionLayoutCursor::Position::Right); if (m_parent) { - return m_parent->moveRight(cursor); + return m_parent->moveRight(cursor, shouldRecomputeLayout); } return false; } -bool VerticalOffsetLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool VerticalOffsetLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // Case: Superscript. if (m_type == VerticalOffsetLayout::Type::Superscript) { // Case: Right. @@ -145,10 +145,10 @@ bool VerticalOffsetLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLay cursor->setPointedExpressionLayout(this); return true; } - return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -bool VerticalOffsetLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { +bool VerticalOffsetLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // Case: Subscript. if (m_type == VerticalOffsetLayout::Type::Subscript) { // Case: Right. @@ -178,7 +178,7 @@ bool VerticalOffsetLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionL cursor->setPointedExpressionLayout(this); return true; } - return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout); + return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } int VerticalOffsetLayout::writeTextInBuffer(char * buffer, int bufferSize) const { diff --git a/poincare/src/layout/vertical_offset_layout.h b/poincare/src/layout/vertical_offset_layout.h index bf3242cb7..75ca9f1e3 100644 --- a/poincare/src/layout/vertical_offset_layout.h +++ b/poincare/src/layout/vertical_offset_layout.h @@ -14,10 +14,10 @@ public: VerticalOffsetLayout(ExpressionLayout * indice, Type type, bool cloneOperands); ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor) override; - bool moveRight(ExpressionLayoutCursor * cursor) override; - bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; bool mustHaveLeftBrother() const override { return true; } protected: From 865060e2e910f0e7d2e447f96808e6cf628e4dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 09:58:59 +0100 Subject: [PATCH 204/257] [poincare] Add asserts in removePointedChildAtIndexAndMoveCursor. Change-Id: Ifc49b79f18ad53a96a4675d1c6edad69e1c6258f --- poincare/src/layout/conjugate_layout.cpp | 1 + poincare/src/layout/dynamic_layout_hierarchy.cpp | 2 +- poincare/src/layout/expression_layout.cpp | 1 + poincare/src/layout/matrix_layout.cpp | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/poincare/src/layout/conjugate_layout.cpp b/poincare/src/layout/conjugate_layout.cpp index 15e90362d..e9c3fda59 100644 --- a/poincare/src/layout/conjugate_layout.cpp +++ b/poincare/src/layout/conjugate_layout.cpp @@ -95,6 +95,7 @@ void ConjugateLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChil void ConjugateLayout::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { assert(index >= 0 && index < numberOfChildren()); + assert((cursor->pointedExpressionLayout() == child(index)) || (cursor->pointedExpressionLayout()->hasAncestor(child(index)))); replaceChildAndMoveCursor(child(index), new EmptyVisibleLayout(), deleteAfterRemoval, cursor); } diff --git a/poincare/src/layout/dynamic_layout_hierarchy.cpp b/poincare/src/layout/dynamic_layout_hierarchy.cpp index 8a54de8b3..3ed6dd802 100644 --- a/poincare/src/layout/dynamic_layout_hierarchy.cpp +++ b/poincare/src/layout/dynamic_layout_hierarchy.cpp @@ -116,7 +116,7 @@ void DynamicLayoutHierarchy::removeChildAtIndex(int index, bool deleteAfterRemov void DynamicLayoutHierarchy::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { assert(index >= 0 && index < numberOfChildren()); - assert(cursor->pointedExpressionLayout() == child(index)); + assert((cursor->pointedExpressionLayout() == child(index)) || (cursor->pointedExpressionLayout()->hasAncestor(child(index)))); if (numberOfChildren() == 1) { if (m_parent) { if (!deleteAfterRemoval) { diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 936c7c9fd..9faf5b7e0 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -205,6 +205,7 @@ void ExpressionLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { void ExpressionLayout::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { assert(index >= 0 && index < numberOfChildren()); + assert((cursor->pointedExpressionLayout() == child(index)) || (cursor->pointedExpressionLayout()->hasAncestor(child(index)))); removeChildAtIndex(index, deleteAfterRemoval); if (index < numberOfChildren()) { cursor->setPointedExpressionLayout(editableChild(index)); diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index 753b3e7b4..273fd1d3c 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -125,6 +125,7 @@ void MatrixLayout::replaceChildAndMoveCursor(const ExpressionLayout * oldChild, void MatrixLayout::removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) { assert(index >= 0 && index < numberOfChildren()); + assert((cursor->pointedExpressionLayout() == child(index)) || (cursor->pointedExpressionLayout()->hasAncestor(child(index)))); replaceChildAndMoveCursor(child(index), new EmptyVisibleLayout(), deleteAfterRemoval, cursor); } From 511d9e3adaa5f7bc6aa9f5318a5fe3924055d491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 10:00:06 +0100 Subject: [PATCH 205/257] [poincare] Better handling of grey squares in MatrixLayout. Add/remove grey squares when the cursor enters or leaves the matrix on modeUp or moveDown. Recompute the layout if the cursor enters or leaves a matrix: adding or removing grey squares changes the layout of the expression. Change-Id: I356f660cbf96883bd5bf1c4bd2cd160a921a29e7 --- poincare/src/layout/matrix_layout.cpp | 58 ++++++++++++++++++++++++++- poincare/src/layout/matrix_layout.h | 9 +++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index 273fd1d3c..fbec5bd3a 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -82,9 +82,43 @@ bool MatrixLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecom return GridLayout::moveRight(cursor, shouldRecomputeLayout); } +bool MatrixLayout::moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + bool shouldRemoveGreySquares = false; + int childIndex = indexOfChild(previousLayout); + if (childIndex >- 1 && childIsTopOfGrid(childIndex)) { + // The cursor is leaving the matrix, so remove the grey squares. + shouldRemoveGreySquares = true; + } + bool returnValue = GridLayout::moveUp(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); + if (returnValue && shouldRemoveGreySquares) { + assert(hasGreySquares()); + removeGreySquares(); + *shouldRecomputeLayout = true; + } + return returnValue; +} + +bool MatrixLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { + bool shouldRemoveGreySquares = false; + int childIndex = indexOfChild(previousLayout); + if (childIndex >- 1 && childIsBottomOfGrid(childIndex)) { + // The cursor is leaving the matrix, so remove the grey squares. + shouldRemoveGreySquares = true; + } + bool returnValue = GridLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); + if (returnValue && shouldRemoveGreySquares) { + assert(hasGreySquares()); + removeGreySquares(); + *shouldRecomputeLayout = true; + } + return returnValue; +} + bool MatrixLayout::moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { bool result = GridLayout::moveUpInside(cursor, shouldRecomputeLayout); - if (result) { + if (result && cursor->pointedExpressionLayout() != this) { + // Add the grey squares if the cursor is pointing at a matrix descendant, + // not at the matrix itself. assert(!hasGreySquares()); addGreySquares(); *shouldRecomputeLayout = true; @@ -94,7 +128,9 @@ bool MatrixLayout::moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRe bool MatrixLayout::moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { bool result = GridLayout::moveDownInside(cursor, shouldRecomputeLayout); - if (result) { + if (result && cursor->pointedExpressionLayout() != this) { + // Add the grey squares if the cursor is pointing at a matrix descendant, + // not at the matrix itself. assert(!hasGreySquares()); addGreySquares(); *shouldRecomputeLayout = true; @@ -239,6 +275,24 @@ ExpressionLayout * dummyGridLayout = new GridLayout(children(), m_numberOfRows, return GridLayout::positionOfChild(child).translatedBy(dummyLayout.positionOfChild(dummyGridLayout)); } +void MatrixLayout::moveCursorInsideAtDirection ( + VerticalDirection direction, + ExpressionLayoutCursor * cursor, + bool * shouldRecomputeLayout, + ExpressionLayout ** childResult, + void * resultPosition, + int * resultScore) +{ + GridLayout::moveCursorInsideAtDirection(direction, cursor, shouldRecomputeLayout, childResult, resultPosition, resultScore); + if (*childResult != this) { + // Add the grey squares if the cursor is pointing at a matrix descendant, + // not at the matrix itself. + assert(!hasGreySquares()); + addGreySquares(); + *shouldRecomputeLayout = true; + } +} + bool MatrixLayout::isRowEmpty(int index) const { assert(index >= 0 && index < m_numberOfRows); for (int i = index * m_numberOfColumns; i < (index+1) * m_numberOfColumns; i++) { diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 2a4633b6d..78139be13 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -13,6 +13,8 @@ public: /* Navigation */ bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; + bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; bool moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; bool moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; @@ -36,6 +38,13 @@ protected: KDSize computeSize() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: + void moveCursorInsideAtDirection ( + VerticalDirection direction, + ExpressionLayoutCursor * cursor, + bool * shouldRecomputeLayout, + ExpressionLayout ** childResult, + void * resultPosition, + int * resultScore) override; void childWasReplacedAtIndex(int index); bool isRowEmpty(int index) const; bool isColumnEmpty(int index) const; From 7094bcef75c409ea56fac5efc1cc75b2bb2a5664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 15:38:49 +0100 Subject: [PATCH 206/257] [escher] EditableExpressionView handles Paste events. Change-Id: Ie23fe49a4b300592ffb77c5548305d1c50279dd1 --- escher/src/editable_expression_view.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index acc66f38d..a4de32044 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -161,6 +162,13 @@ bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { m_expressionViewWithCursor.cursor()->performBackspace(); return true; } + if (event == Ion::Events::Paste) { + if (!isEditing()) { + setEditing(true); + } + insertLayoutFromTextAtCursor(Clipboard::sharedClipboard()->storedText()); + return true; + } return false; } From a6f93478cde61f0fe2b229e63afd3fe19c18c135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 15:58:07 +0100 Subject: [PATCH 207/257] [poincare] Fix 1/2 3/4 serialization bug. The omitted multiplication fix that serialized "1 2/3 4" into "1*2/3*4" caused a bug and serialized "1/2 3/4" into "1/2**3/4", as well as "1^2 3/4" into "1^(2)**3/4". Change-Id: I59b55a2f13e6eceee68c7e52169c14918391f235 --- poincare/include/poincare/expression_layout.h | 4 ++-- poincare/src/layout/fraction_layout.h | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 580f89273..38ef59c82 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -100,12 +100,12 @@ public: * become 1+ 2/3 - 4 when pressing "Divide": a CharLayout is collapsable if * its char is not +, -, or *. */ bool canBeOmittedMultiplicationLeftFactor() const; - bool canBeOmittedMultiplicationRightFactor() const; + virtual bool canBeOmittedMultiplicationRightFactor() const; /* canBeOmittedMultiplicationLeftFactor and RightFactor return true if the * layout, next to another layout, might be the factor of a multiplication * with an omitted multiplication sign. For instance, an absolute value layout * returns true, because |3|2 means |3|*2. A '+' CharLayout returns false, - * because +'something' nevers means +*'something'. */ + * because +'something' nevers means +*'something'. */ virtual bool mustHaveLeftBrother() const { return false; } virtual bool isHorizontal() const { return false; } virtual bool isLeftParenthesis() const { return false; } diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 2eb341453..02562db82 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -16,6 +16,12 @@ public: bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; + bool canBeOmittedMultiplicationRightFactor() const override { return false; } + /* WARNING: We need to override this function, else 1/2 3/4 would be + * serialized as 1/2**3/4, as the two Fraction layouts think their brother is + * an omitted multiplication layout factor. We have the same problem with + * 2^3 1/2 being serialized as 2^3**1/2, so must override the Right version + * and not canBeOmittedMultiplicationLeftFactor. */ protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; From 2cb895666509e758f87b5947c2264298be789cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 16:18:55 +0100 Subject: [PATCH 208/257] [apps/math_toolbox] Remove the pointedPath from ToolboxMessageTree. Change-Id: I2deb6564321da13ea27975216aa949b68298533c --- apps/math_toolbox.cpp | 10 ++-------- escher/include/escher/toolbox_message_tree.h | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 3910a60c0..6a82fc083 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -73,7 +73,6 @@ const ToolboxMessageTree predictionChildren[3] = { ToolboxMessageTree(I18n::Message::PredictionCommandWithArg, I18n::Message::Prediction, I18n::Message::PredictionCommandWithArg), ToolboxMessageTree(I18n::Message::ConfidenceCommandWithArg, I18n::Message::Confidence, I18n::Message::ConfidenceCommandWithArg)}; -const int pointedLayoutPathLog[] = {3,0}; #if LIST_ARE_DEFINED const ToolboxMessageTree menu[12] = { #elif MATRICES_ARE_DEFINED @@ -83,7 +82,7 @@ const ToolboxMessageTree menu[10] = { #endif ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg), ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommandWithArg), - ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg, nullptr, 0, const_cast(&pointedLayoutPathLog[0]), 2), + ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg), ToolboxMessageTree(I18n::Message::Calculation, I18n::Message::Default, I18n::Message::Default, calculChildren, 4), ToolboxMessageTree(I18n::Message::ComplexNumber, I18n::Message::Default, I18n::Message::Default, complexChildren, 5), ToolboxMessageTree(I18n::Message::Probability, I18n::Message::Default, I18n::Message::Default, probabilityChildren, 2), @@ -131,12 +130,7 @@ void MathToolbox::actionForEditableExpressionView(void * sender, ToolboxMessageT ExpressionLayout * resultLayout = resultExpression->createLayout(); // Find the pointed layout. ExpressionLayout * pointedLayout = resultLayout; - if (messageTree->pointedPath() != nullptr) { - for (int i = 0; i < messageTree->pointedPathLength(); i++) { - assert(messageTree->pointedPath()[i] < pointedLayout->numberOfChildren()); - pointedLayout = pointedLayout->editableChild(messageTree->pointedPath()[i]); - } - } else if (resultLayout->isHorizontal()) { + if (resultLayout->isHorizontal()) { // If the layout is horizontal, pick the first open parenthesis. for (int i = 0; i < resultLayout->numberOfChildren(); i++) { if (resultLayout->editableChild(i)->isLeftParenthesis()) { diff --git a/escher/include/escher/toolbox_message_tree.h b/escher/include/escher/toolbox_message_tree.h index 062271417..48d027403 100644 --- a/escher/include/escher/toolbox_message_tree.h +++ b/escher/include/escher/toolbox_message_tree.h @@ -6,26 +6,20 @@ class ToolboxMessageTree : public MessageTree { public: - constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0, int * pointedLayoutPath = nullptr, int pointedLayoutPathLength = 0) : + constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0) : MessageTree(label, numberOfChildren), m_children(children), m_text(text), - m_insertedText(insertedText), - m_pointedLayoutPath(pointedLayoutPath), - m_pointedLayoutPathLength(pointedLayoutPathLength) + m_insertedText(insertedText) { }; const MessageTree * children(int index) const override { return &m_children[index]; } I18n::Message text() const { return m_text; } I18n::Message insertedText() const { return m_insertedText; } - int * pointedPath() const { return m_pointedLayoutPath; } - int pointedPathLength() const { return m_pointedLayoutPathLength; } private: const ToolboxMessageTree * m_children; I18n::Message m_text; I18n::Message m_insertedText; - int * m_pointedLayoutPath; - int m_pointedLayoutPathLength; }; #endif From f3e6b104107b86007c101197371696f97cccdc2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 16:24:05 +0100 Subject: [PATCH 209/257] [apps/math_toolbox] Handle const char * when selecting a leaf. Else, there would be a problem with sequence_toolbox, where not all toolbox leaves are message trees. Change-Id: Ib4968aad37f6a835b1ea4d77efac2ae1bd19c7ce --- apps/code/app.cpp | 4 ++-- apps/code/variable_box_controller.cpp | 4 ++-- apps/math_toolbox.cpp | 28 +++++++++++++-------------- apps/math_toolbox.h | 6 +++--- apps/shared/toolbox_helpers.cpp | 14 ++++++++------ apps/shared/toolbox_helpers.h | 5 +++-- 6 files changed, 31 insertions(+), 30 deletions(-) diff --git a/apps/code/app.cpp b/apps/code/app.cpp index f59b1b285..9b9d6402a 100644 --- a/apps/code/app.cpp +++ b/apps/code/app.cpp @@ -47,7 +47,7 @@ App::App(Container * container, Snapshot * snapshot) : // insertText() also moves the cursor. We need to re-move it to the // position we want (which is after the first parenthesis or before the // first point). - int deltaCursorLocation = - textArea->cursorLocation() + previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommand(text); + int deltaCursorLocation = - textArea->cursorLocation() + previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommandText(text); // WARNING: This is a dirty and only works because the cursor location we // want is always on the first line of the text we insert. Because of the // auto indentation, it would be difficult to compute the wanted cursor @@ -59,7 +59,7 @@ App::App(Container * container, Snapshot * snapshot) : if (!textField->isEditing()) { textField->setEditing(true); } - int newCursorLocation = textField->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(text); + int newCursorLocation = textField->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommandText(text); if (textField->insertTextAtLocation(text, textField->cursorLocation())) { textField->setCursorLocation(newCursorLocation); }}), diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp index 9684642aa..81127b78e 100644 --- a/apps/code/variable_box_controller.cpp +++ b/apps/code/variable_box_controller.cpp @@ -128,13 +128,13 @@ void VariableBoxController::ContentViewController::insertTextInCaller(const char } int previousCursorLocation = m_textFieldCaller->cursorLocation(); m_textFieldCaller->insertTextAtLocation(commandBuffer, previousCursorLocation); - m_textFieldCaller->setCursorLocation(previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommand(commandBuffer)); + m_textFieldCaller->setCursorLocation(previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommandText(commandBuffer)); return; } if (m_textAreaCaller != nullptr) { int previousCursorLocation = m_textAreaCaller->cursorLocation(); m_textAreaCaller->insertText(commandBuffer); - int deltaCursorLocation = - m_textAreaCaller->cursorLocation() + previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommand(commandBuffer); + int deltaCursorLocation = - m_textAreaCaller->cursorLocation() + previousCursorLocation + Shared::ToolboxHelpers::CursorIndexInCommandText(commandBuffer); m_textAreaCaller->moveCursor(deltaCursorLocation); } } diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 6a82fc083..dc11829a7 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -115,15 +115,14 @@ void MathToolbox::setSenderAndAction(Responder * sender, Action action) { m_action = action; } -void MathToolbox::actionForEditableExpressionView(void * sender, ToolboxMessageTree * messageTree) { +void MathToolbox::actionForEditableExpressionView(void * sender, const char * text) { EditableExpressionView * expressionLayoutEditorSender = static_cast(sender); - // Translate the message and replace the arguments with Empty chars. - const char * textToInsert = I18n::translate(messageTree->insertedText()); - int strippedTextToInsertMaxLength = strlen(textToInsert); - char strippedTextToInsert[strlen(textToInsert)]; - Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandMessage(messageTree->insertedText(), strippedTextToInsert, strippedTextToInsertMaxLength); + // Replace the arguments with Empty chars. + int textToInsertMaxLength = strlen(text); + char textToInsert[textToInsertMaxLength]; + Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandText(text, textToInsert, textToInsertMaxLength); // Create the layout - Expression * resultExpression = Expression::parse(strippedTextToInsert); + Expression * resultExpression = Expression::parse(textToInsert); if (resultExpression == nullptr) { return; } @@ -146,25 +145,24 @@ void MathToolbox::actionForEditableExpressionView(void * sender, ToolboxMessageT expressionLayoutEditorSender->insertLayoutAtCursor(resultLayout, pointedLayout); } -void MathToolbox::actionForTextField(void * sender, ToolboxMessageTree * messageTree) { +void MathToolbox::actionForTextField(void * sender, const char * text) { TextField * textFieldSender = static_cast(sender); if (!textFieldSender->isEditing()) { textFieldSender->setEditing(true); } - const char * textToInsert = I18n::translate(messageTree->insertedText()); - int textToInsertLength = strlen(textToInsert); - char strippedTextToInsert[textToInsertLength]; + int maxTextToInsertLength = strlen(text); + char textToInsert[maxTextToInsertLength]; // Translate the message and remove the arguments. - Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedTextToInsert, textToInsertLength); - textFieldSender->insertTextAtLocation(strippedTextToInsert, textFieldSender->cursorLocation()); - int newCursorLocation = textFieldSender->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommand(strippedTextToInsert); + Shared::ToolboxHelpers::TextToInsertForCommandText(text, textToInsert, maxTextToInsertLength); + textFieldSender->insertTextAtLocation(textToInsert, textFieldSender->cursorLocation()); + int newCursorLocation = textFieldSender->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommandText(text); textFieldSender->setCursorLocation(newCursorLocation); } bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) { ToolboxMessageTree * messageTree = selectedMessageTree; m_selectableTableView.deselectTable(); - m_action(sender(), messageTree); + m_action(sender(), I18n::translate(messageTree->insertedText())); app()->dismissModalViewController(); return true; } diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index dbcc8e2cd..2f607863c 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -8,11 +8,11 @@ class MathToolbox : public Toolbox { public: - typedef void (*Action)(void * sender, ToolboxMessageTree * messageTree); + typedef void (*Action)(void * sender, const char * text); MathToolbox(); void setSenderAndAction(Responder * sender, Action action); - static void actionForEditableExpressionView(void * sender, ToolboxMessageTree * messageTree); - static void actionForTextField(void * sender, ToolboxMessageTree * messageTree); + static void actionForEditableExpressionView(void * sender, const char * text); + static void actionForTextField(void * sender, const char * text); protected: bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override; const ToolboxMessageTree * rootModel() override; diff --git a/apps/shared/toolbox_helpers.cpp b/apps/shared/toolbox_helpers.cpp index 268162c8d..6186dce33 100644 --- a/apps/shared/toolbox_helpers.cpp +++ b/apps/shared/toolbox_helpers.cpp @@ -7,7 +7,7 @@ namespace Shared { namespace ToolboxHelpers { -int CursorIndexInCommand(const char * text) { +int CursorIndexInCommandText(const char * text) { for (size_t i = 0; i < strlen(text); i++) { if (text[i] == '(' || text[i] == '\'') { return i + 1; @@ -20,8 +20,7 @@ int CursorIndexInCommand(const char * text) { } void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize) { - const char * messageText = I18n::translate(message); - TextToInsertForCommandText(messageText, buffer, bufferSize); + TextToInsertForCommandText(I18n::translate(message), buffer, bufferSize); } void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize) { @@ -58,7 +57,11 @@ void TextToInsertForCommandText(const char * command, char * buffer, int bufferS } void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer, int bufferSize) { - if (message == I18n::Message::MatrixCommandWithArg) { + TextToParseIntoLayoutForCommandText(I18n::translate(message), buffer, bufferSize); +} + +void TextToParseIntoLayoutForCommandText(const char * command, char * buffer, int bufferSize) { + if (command == I18n::translate(I18n::Message::MatrixCommandWithArg)) { assert(bufferSize >= 6); // Handle a new matrix command. buffer[0] = '['; @@ -69,8 +72,7 @@ void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer buffer[5] = 0; return; } - const char * messageText = I18n::translate(message); - TextToInsertForCommandText(messageText, buffer, bufferSize); + TextToInsertForCommandText(command, buffer, bufferSize); size_t bufferLength = strlen(buffer); for (size_t i = 0; i < bufferLength; i++) { if (buffer[i] == '(' || buffer[i] == '[' || buffer[i] == ',') { diff --git a/apps/shared/toolbox_helpers.h b/apps/shared/toolbox_helpers.h index d051f5847..0065993a2 100644 --- a/apps/shared/toolbox_helpers.h +++ b/apps/shared/toolbox_helpers.h @@ -6,8 +6,8 @@ namespace Shared { namespace ToolboxHelpers { -int CursorIndexInCommand(const char * text); -/* Returns the index of the cursor position in a Command, which is the smallest +int CursorIndexInCommandText(const char * text); +/* Returns the index of the cursor position in a command, which is the smallest * index between : * - After the first open parenthesis * - The end of the text */ @@ -18,6 +18,7 @@ void TextToInsertForCommandText(const char * command, char * buffer, int bufferS /* Removes the arguments from a command: * - Removes text between parentheses or brackets, except commas */ void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer, int bufferSize); +void TextToParseIntoLayoutForCommandText(const char * command, char * buffer, int bufferSize); /* Removes the arguments from a command and replaces them with empty chars. */ } From 251c4d01afe1c3447b3e2d2c330307aa09cfed30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 16:42:05 +0100 Subject: [PATCH 210/257] [apps/sequence] Fix math_toolbox wrong functions calls. Change-Id: I0b7871e87ea64ef9fbd008d9fb3e6d4cce2e97ca --- apps/math_toolbox.h | 2 +- apps/sequence/list/sequence_toolbox.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index 2f607863c..02be3effa 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -20,8 +20,8 @@ protected: MessageTableCellWithChevron* nodeCellAtIndex(int index) override; int maxNumberOfDisplayedRows() override; constexpr static int k_maxNumberOfDisplayedRows = 6; // = 240/40 -private: Action m_action; +private: MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows]; MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows]; }; diff --git a/apps/sequence/list/sequence_toolbox.cpp b/apps/sequence/list/sequence_toolbox.cpp index fddc7d061..f4346311d 100644 --- a/apps/sequence/list/sequence_toolbox.cpp +++ b/apps/sequence/list/sequence_toolbox.cpp @@ -114,9 +114,8 @@ void SequenceToolbox::setExtraCells(const char * sequenceName, int recurrenceDep bool SequenceToolbox::selectAddedCell(int selectedRow){ int bufferSize = 10; char buffer[bufferSize]; - int currentChar = m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize); - textFieldSender()->insertTextAtLocation(buffer, textFieldSender()->cursorLocation()); - textFieldSender()->setCursorLocation(textFieldSender()->cursorLocation()+currentChar); + m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize); + m_action(sender(), buffer); app()->dismissModalViewController(); return true; } From 64efb45c2487b7fa299d593168fd471784dca5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 17:30:47 +0100 Subject: [PATCH 211/257] [apps/math_toolbox] Cleaner matrix layout insertion. Change-Id: I5c51eb353ac848334626e6ffcaf71f3b94534b2e --- apps/math_toolbox.cpp | 2 +- apps/shared.universal.i18n | 1 + apps/shared/toolbox_helpers.cpp | 15 ++------------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index dc11829a7..a91e93daf 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -37,7 +37,7 @@ const ToolboxMessageTree arithmeticChildren[4] = { #if MATRICES_ARE_DEFINED const ToolboxMessageTree matricesChildren[6] = { - ToolboxMessageTree(I18n::Message::MatrixCommandWithArg, I18n::Message::NewMatrix, I18n::Message::MatrixCommandWithArg), + ToolboxMessageTree(I18n::Message::MatrixCommandWithArg, I18n::Message::NewMatrix, I18n::Message::MatrixCommand), ToolboxMessageTree(I18n::Message::InverseCommandWithArg, I18n::Message::Inverse, I18n::Message::InverseCommandWithArg), ToolboxMessageTree(I18n::Message::DeterminantCommandWithArg, I18n::Message::Determinant, I18n::Message::DeterminantCommandWithArg), ToolboxMessageTree(I18n::Message::TransposeCommandWithArg, I18n::Message::Transpose, I18n::Message::TransposeCommandWithArg), diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n index 1f06a778b..d8147eaf0 100644 --- a/apps/shared.universal.i18n +++ b/apps/shared.universal.i18n @@ -32,6 +32,7 @@ LcmCommandWithArg = "lcm(p,q)" LeftIntegralFirstLegend = "P(X≤" LeftIntegralSecondLegend = ")=" LogCommandWithArg = "log(x,a)" +MatrixCommand = "[[]]" MatrixCommandWithArg = "[[1,2][3,4]]" MaxCommandWithArg = "max(L)" MinCommandWithArg = "min(L)" diff --git a/apps/shared/toolbox_helpers.cpp b/apps/shared/toolbox_helpers.cpp index 6186dce33..33c7b4461 100644 --- a/apps/shared/toolbox_helpers.cpp +++ b/apps/shared/toolbox_helpers.cpp @@ -13,7 +13,7 @@ int CursorIndexInCommandText(const char * text) { return i + 1; } if (text[i] == ']') { - return (i - 1) > 0 ? i - 1 : 0; + return i; } } return strlen(text); @@ -61,21 +61,10 @@ void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer } void TextToParseIntoLayoutForCommandText(const char * command, char * buffer, int bufferSize) { - if (command == I18n::translate(I18n::Message::MatrixCommandWithArg)) { - assert(bufferSize >= 6); - // Handle a new matrix command. - buffer[0] = '['; - buffer[1] = '['; - buffer[2] = Ion::Charset::Empty; - buffer[3] = ']'; - buffer[4] = ']'; - buffer[5] = 0; - return; - } TextToInsertForCommandText(command, buffer, bufferSize); size_t bufferLength = strlen(buffer); for (size_t i = 0; i < bufferLength; i++) { - if (buffer[i] == '(' || buffer[i] == '[' || buffer[i] == ',') { + if (buffer[i] == '(' || buffer[i] == ',' || (i < bufferLength - 1 && buffer[i] == '[' && buffer[i+1] == ']')) { // Shift the buffer to make room for the new char. Use memmove to avoid // overwritting. memmove(&buffer[i+2], &buffer[i+1], bufferLength - (i+1) + 1); From e29691e1f17a9210f172c19152e5ab92a1799b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 17:31:37 +0100 Subject: [PATCH 212/257] [apps/sequence] Fix the insertion of sequence terms in text fields. For instance, the serialization of the V_n layout is "v_{n}", which is what we want to insert in an EditableExpressionView, but not in a Text Field for which we want "v(n)". Change-Id: Iab38058d982322891b530b3afd2d303a266643f9 --- apps/math_toolbox.cpp | 41 ++++++++++++++++--------- apps/math_toolbox.h | 6 ++-- apps/sequence/list/sequence_toolbox.cpp | 21 ++++++++++++- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index a91e93daf..a083d5747 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -115,14 +115,19 @@ void MathToolbox::setSenderAndAction(Responder * sender, Action action) { m_action = action; } -void MathToolbox::actionForEditableExpressionView(void * sender, const char * text) { +void MathToolbox::actionForEditableExpressionView(void * sender, const char * text, bool removeArguments) { EditableExpressionView * expressionLayoutEditorSender = static_cast(sender); - // Replace the arguments with Empty chars. - int textToInsertMaxLength = strlen(text); - char textToInsert[textToInsertMaxLength]; - Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandText(text, textToInsert, textToInsertMaxLength); - // Create the layout - Expression * resultExpression = Expression::parse(textToInsert); + Expression * resultExpression = nullptr; + if (removeArguments) { + // Replace the arguments with Empty chars. + int textToInsertMaxLength = strlen(text); + char textToInsert[textToInsertMaxLength]; + Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandText(text, textToInsert, textToInsertMaxLength); + // Create the layout + resultExpression = Expression::parse(textToInsert); + } else { + resultExpression = Expression::parse(text); + } if (resultExpression == nullptr) { return; } @@ -145,24 +150,30 @@ void MathToolbox::actionForEditableExpressionView(void * sender, const char * te expressionLayoutEditorSender->insertLayoutAtCursor(resultLayout, pointedLayout); } -void MathToolbox::actionForTextField(void * sender, const char * text) { +void MathToolbox::actionForTextField(void * sender, const char * text, bool removeArguments) { TextField * textFieldSender = static_cast(sender); if (!textFieldSender->isEditing()) { textFieldSender->setEditing(true); } - int maxTextToInsertLength = strlen(text); - char textToInsert[maxTextToInsertLength]; - // Translate the message and remove the arguments. - Shared::ToolboxHelpers::TextToInsertForCommandText(text, textToInsert, maxTextToInsertLength); - textFieldSender->insertTextAtLocation(textToInsert, textFieldSender->cursorLocation()); - int newCursorLocation = textFieldSender->cursorLocation() + Shared::ToolboxHelpers::CursorIndexInCommandText(text); + int newCursorLocation = textFieldSender->cursorLocation(); + if (removeArguments) { + int maxTextToInsertLength = strlen(text); + char textToInsert[maxTextToInsertLength]; + // Translate the message and remove the arguments. + Shared::ToolboxHelpers::TextToInsertForCommandText(text, textToInsert, maxTextToInsertLength); + textFieldSender->insertTextAtLocation(textToInsert, textFieldSender->cursorLocation()); + newCursorLocation+= Shared::ToolboxHelpers::CursorIndexInCommandText(textToInsert); + } else { + textFieldSender->insertTextAtLocation(text, textFieldSender->cursorLocation()); + newCursorLocation+= Shared::ToolboxHelpers::CursorIndexInCommandText(text); + } textFieldSender->setCursorLocation(newCursorLocation); } bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) { ToolboxMessageTree * messageTree = selectedMessageTree; m_selectableTableView.deselectTable(); - m_action(sender(), I18n::translate(messageTree->insertedText())); + m_action(sender(), I18n::translate(messageTree->insertedText()), true); app()->dismissModalViewController(); return true; } diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index 02be3effa..913706611 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -8,11 +8,11 @@ class MathToolbox : public Toolbox { public: - typedef void (*Action)(void * sender, const char * text); + typedef void (*Action)(void * sender, const char * text, bool removeArguments); MathToolbox(); void setSenderAndAction(Responder * sender, Action action); - static void actionForEditableExpressionView(void * sender, const char * text); - static void actionForTextField(void * sender, const char * text); + static void actionForEditableExpressionView(void * sender, const char * text, bool removeArguments = true); + static void actionForTextField(void * sender, const char * text, bool removeArguments = true); protected: bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override; const ToolboxMessageTree * rootModel() override; diff --git a/apps/sequence/list/sequence_toolbox.cpp b/apps/sequence/list/sequence_toolbox.cpp index f4346311d..3772521c5 100644 --- a/apps/sequence/list/sequence_toolbox.cpp +++ b/apps/sequence/list/sequence_toolbox.cpp @@ -115,7 +115,26 @@ bool SequenceToolbox::selectAddedCell(int selectedRow){ int bufferSize = 10; char buffer[bufferSize]; m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize); - m_action(sender(), buffer); + if (m_action == MathToolbox::actionForTextField) { + // DIRTY. The symbols are layouted using a Subscript VerticalOffsetLayout, + // which serializes into "_{}", but we want parentheses for text fields. We + // thus need to remove any underscores, and changes brackets into + // parentheses. + for (int i = 0; i < bufferSize; i++) { + if (buffer[i] == '{') { + buffer[i] = '('; + } + if (buffer[i] == '}') { + buffer[i] = ')'; + } + if (buffer[i] == '_') { + memmove(&buffer[i], &buffer[i+1], bufferSize - (i+1) + 1); + bufferSize--; + i--; + } + } + } + m_action(sender(), buffer, false); app()->dismissModalViewController(); return true; } From 17cbcd0ab52fa0f90fd606cb0c2b28019966de85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 19 Jan 2018 17:36:01 +0100 Subject: [PATCH 213/257] [apps/Makefile] Put all the apps back. Change-Id: Ic88eee0e64c4b17364a08a4d4e5bb99fd0481914 --- apps/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/Makefile b/apps/Makefile index 4072eb811..7e5d367ab 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,5 +1,5 @@ EPSILON_I18N_LANGUAGES ?= en fr es de pt -EPSILON_APPS ?= calculation settings +EPSILON_APPS ?= calculation graph sequence settings statistics probability regression code include apps/shared/Makefile include apps/home/Makefile From 4d778b5d9fdccd1a7d780ef7afcd9dd4f9e07a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 22 Jan 2018 17:38:02 +0100 Subject: [PATCH 214/257] [apps/escher/poincare] Use 2D Edition in Sequence and Graph apps. EditableExpressionView is renamed ScrollableViewWithCursor. EditableExpressionView is now a View that displays either a TextField or a ScrollableViewWithCursor, depending on Poincare::Preferences. Change-Id: Id44ddcd9a83f5fd17d65753ca4c94c5c7cda9b8a --- apps/calculation/Makefile | 3 +- apps/calculation/app.cpp | 12 +- apps/calculation/app.h | 4 +- .../edit_expression_controller.cpp | 166 ++++------ apps/calculation/edit_expression_controller.h | 43 +-- apps/calculation/editable_expression_view.cpp | 18 +- apps/calculation/editable_expression_view.h | 4 +- apps/calculation/text_field.cpp | 33 -- apps/calculation/text_field.h | 16 - apps/graph/app.cpp | 2 +- apps/math_toolbox.cpp | 4 +- apps/math_toolbox.h | 2 +- apps/sequence/app.cpp | 2 +- apps/sequence/list/list_controller.cpp | 4 + apps/sequence/list/list_controller.h | 8 +- apps/shared/Makefile | 4 +- .../editable_expression_view_delegate.cpp | 35 -- .../editable_expression_view_delegate.h | 24 -- .../editable_expression_view_delegate_app.cpp | 56 ++++ .../editable_expression_view_delegate_app.h | 21 ++ apps/shared/function_app.cpp | 4 +- apps/shared/function_app.h | 4 +- ...e_expression_view_with_cursor_delegate.cpp | 31 ++ ...ble_expression_view_with_cursor_delegate.h | 23 ++ ..._editable_expression_view_delegate_app.cpp | 52 --- ...nd_editable_expression_view_delegate_app.h | 21 -- apps/variable_box_controller.cpp | 20 +- apps/variable_box_controller.h | 6 +- escher/Makefile | 1 + escher/include/escher.h | 3 +- .../include/escher/editable_expression_view.h | 58 ++-- .../editable_expression_view_delegate.h | 20 -- escher/include/escher/input_view_controller.h | 52 +-- escher/include/escher/modal_view_controller.h | 3 + .../scrollable_expression_view_with_cursor.h | 40 +++ ...ble_expression_view_with_cursor_delegate.h | 19 ++ escher/src/editable_expression_view.cpp | 299 +++++++----------- escher/src/input_view_controller.cpp | 125 ++++---- escher/src/modal_view_controller.cpp | 9 + ...scrollable_expression_view_with_cursor.cpp | 225 +++++++++++++ poincare/include/poincare/expression_layout.h | 1 + poincare/src/layout/expression_layout.cpp | 6 + 42 files changed, 793 insertions(+), 690 deletions(-) delete mode 100644 apps/calculation/text_field.cpp delete mode 100644 apps/calculation/text_field.h delete mode 100644 apps/shared/editable_expression_view_delegate.cpp delete mode 100644 apps/shared/editable_expression_view_delegate.h create mode 100644 apps/shared/editable_expression_view_delegate_app.cpp create mode 100644 apps/shared/editable_expression_view_delegate_app.h create mode 100644 apps/shared/scrollable_expression_view_with_cursor_delegate.cpp create mode 100644 apps/shared/scrollable_expression_view_with_cursor_delegate.h delete mode 100644 apps/shared/text_field_and_editable_expression_view_delegate_app.cpp delete mode 100644 apps/shared/text_field_and_editable_expression_view_delegate_app.h delete mode 100644 escher/include/escher/editable_expression_view_delegate.h create mode 100644 escher/include/escher/scrollable_expression_view_with_cursor.h create mode 100644 escher/include/escher/scrollable_expression_view_with_cursor_delegate.h create mode 100644 escher/src/scrollable_expression_view_with_cursor.cpp diff --git a/apps/calculation/Makefile b/apps/calculation/Makefile index 420391945..226945971 100644 --- a/apps/calculation/Makefile +++ b/apps/calculation/Makefile @@ -5,8 +5,8 @@ app_objs += $(addprefix apps/calculation/,\ app.o\ calculation.o\ calculation_store.o\ - editable_expression_view.o\ edit_expression_controller.o\ + editable_expression_view.o\ history_view_cell.o\ history_controller.o\ local_context.o\ @@ -14,7 +14,6 @@ app_objs += $(addprefix apps/calculation/,\ scrollable_expression_view.o\ scrollable_output_expressions_view.o\ selectable_table_view.o\ - text_field.o\ ) i18n_files += $(addprefix apps/calculation/,\ diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index 21056ddb4..f4bb63e6a 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -43,7 +43,7 @@ void App::Snapshot::tidy() { } App::App(Container * container, Snapshot * snapshot) : - TextFieldAndEditableExpressionViewDelegateApp(container, snapshot, &m_editExpressionController), + EditableExpressionViewDelegateApp(container, snapshot, &m_editExpressionController), m_localContext((GlobalContext *)((AppsContainer *)container)->globalContext(), snapshot->calculationStore()), m_historyController(&m_editExpressionController, snapshot->calculationStore()), m_editExpressionController(&m_modalViewController, &m_historyController, snapshot->calculationStore()) @@ -80,21 +80,21 @@ bool App::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event e return false; } -bool App::editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) { - if ((event == Ion::Events::Var || event == Ion::Events::XNT) && TextFieldAndEditableExpressionViewDelegateApp::editableExpressionViewDidReceiveEvent(editableExpressionView, event)) { +bool App::scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { + if ((event == Ion::Events::Var || event == Ion::Events::XNT) && EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event)) { return true; } /* Here, we check that the expression entered by the user can be printed with * less than k_printedExpressionLength characters. Otherwise, we prevent the * user from adding this expression to the calculation store. */ - if (editableExpressionView->isEditing() && editableExpressionView->editableExpressionViewShouldFinishEditing(event)) { + if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event)) { int bufferLength = TextField::maxBufferSize(); char bufferForParsing[bufferLength]; - Poincare::ExpressionLayout * expressionLayout = editableExpressionView->expressionViewWithCursor()->expressionView()->expressionLayout(); + Poincare::ExpressionLayout * expressionLayout = scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout(); expressionLayout->writeTextInBuffer(bufferForParsing, bufferLength); Expression * exp = Expression::parse(bufferForParsing); if (exp == nullptr) { - editableExpressionView->app()->displayWarning(I18n::Message::SyntaxError); + scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError); return true; } char buffer[Calculation::k_printedExpressionSize]; diff --git a/apps/calculation/app.h b/apps/calculation/app.h index 4ec807891..56d404178 100644 --- a/apps/calculation/app.h +++ b/apps/calculation/app.h @@ -10,7 +10,7 @@ namespace Calculation { -class App : public Shared::TextFieldAndEditableExpressionViewDelegateApp { +class App : public Shared::EditableExpressionViewDelegateApp { public: class Descriptor : public ::App::Descriptor { public: @@ -30,7 +30,7 @@ public: }; Poincare::Context * localContext() override; bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override; - bool editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; const char * XNT() override; private: App(Container * container, Snapshot * snapshot); diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index d1fefa9af..45d9c2474 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -9,17 +9,11 @@ using namespace Shared; namespace Calculation { -EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, EditableExpressionViewDelegate * editableExpressionViewDelegate) : +EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) : View(), m_mainView(subview), - m_textField(parentResponder, m_textBody, TextField::maxBufferSize(), textFieldDelegate), - m_editableExpressionView(parentResponder, new Poincare::HorizontalLayout(), editableExpressionViewDelegate) + m_editableExpressionView(parentResponder, textFieldDelegate, scrollableExpressionViewWithCursorDelegate) { - m_textBody[0] = 0; -} - -int EditExpressionController::ContentView::numberOfSubviews() const { - return 2; } View * EditExpressionController::ContentView::subviewAtIndex(int index) { @@ -28,25 +22,15 @@ View * EditExpressionController::ContentView::subviewAtIndex(int index) { return m_mainView; } assert(index == 1); - if (editionIsInTextField()) { - return &m_textField; - } return &m_editableExpressionView; } void EditExpressionController::ContentView::layoutSubviews() { - KDCoordinate inputViewFrameHeight = inputViewHeight(); - KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - inputViewFrameHeight-k_separatorThickness); + KDCoordinate inputViewFrameHeight = m_editableExpressionView.minimalSizeForOptimalDisplay().height(); + KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - inputViewFrameHeight); m_mainView->setFrame(mainViewFrame); - if (editionIsInTextField()) { - KDRect inputViewFrame(k_leftMargin, bounds().height() - inputViewFrameHeight, bounds().width()-k_leftMargin, k_textFieldHeight); - m_textField.setFrame(inputViewFrame); - m_editableExpressionView.setFrame(KDRectZero); - return; - } - KDRect inputViewFrame(k_leftMargin, bounds().height() - inputViewFrameHeight, bounds().width() - k_leftMargin, inputViewFrameHeight); + KDRect inputViewFrame(0, bounds().height() - inputViewFrameHeight, bounds().width(), inputViewFrameHeight); m_editableExpressionView.setFrame(inputViewFrame); - m_textField.setFrame(KDRectZero); } void EditExpressionController::ContentView::reload() { @@ -54,30 +38,6 @@ void EditExpressionController::ContentView::reload() { markRectAsDirty(bounds()); } -void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rect) const { - KDCoordinate inputViewFrameHeight = inputViewHeight(); - // Draw the separator - ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight-k_separatorThickness, bounds().width(), k_separatorThickness), Palette::GreyMiddle); - // Color the left margin - ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, k_leftMargin, inputViewFrameHeight), m_textField.backgroundColor()); - if (!editionIsInTextField()) { - // Color the upper margin - ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, bounds().width(), k_verticalEditableExpressionViewMargin), m_textField.backgroundColor()); - } -} - -bool EditExpressionController::ContentView::editionIsInTextField() const { - return Poincare::Preferences::sharedPreferences()->editionMode() == Poincare::Preferences::EditionMode::Edition1D; -} - -KDCoordinate EditExpressionController::ContentView::inputViewHeight() const { - return editionIsInTextField() ? k_textFieldHeight : k_verticalEditableExpressionViewMargin + editableExpressionViewHeight(); -} - -KDCoordinate EditExpressionController::ContentView::editableExpressionViewHeight() const { - return KDCoordinate(min(0.6*Ion::Display::Height, max(k_textFieldHeight, m_editableExpressionView.minimalSizeForOptimalDisplay().height()+k_verticalEditableExpressionViewMargin))); -} - EditExpressionController::EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore) : DynamicViewController(parentResponder), m_historyController(historyController), @@ -86,31 +46,18 @@ EditExpressionController::EditExpressionController(Responder * parentResponder, } const char * EditExpressionController::textBody() { - return ((ContentView *)view())->textField()->text(); + return ((ContentView *)view())->editableExpressionView()->text(); } void EditExpressionController::insertTextBody(const char * text) { - if (((ContentView *)view())->editionIsInTextField()) { - TextField * tf = ((ContentView *)view())->textField(); - tf->setEditing(true, false); - tf->insertTextAtLocation(text, tf->cursorLocation()); - tf->setCursorLocation(tf->cursorLocation() + strlen(text)); - return; - } - EditableExpressionView * editableExpressionView = ((ContentView *)view())->editableExpressionView(); - editableExpressionView->setEditing(true); - editableExpressionView->insertLayoutFromTextAtCursor(text); + ((ContentView *)view())->editableExpressionView()->insertText(text); } bool EditExpressionController::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::Up) { if (m_calculationStore->numberOfCalculations() > 0) { - if (((ContentView *)view())->editionIsInTextField()) { - ((ContentView *)view())->textField()->setEditing(false, false); - } else { - ((ContentView *)view())->editableExpressionView()->setEditing(false); - } - app()->setFirstResponder(m_historyController); + ((ContentView *)view())->editableExpressionView()->setEditing(false, false); + app()->setFirstResponder(m_historyController); } return true; } @@ -120,74 +67,48 @@ bool EditExpressionController::handleEvent(Ion::Events::Event event) { void EditExpressionController::didBecomeFirstResponder() { int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0; m_historyController->scrollToCell(0, lastRow); - if (((ContentView *)view())->editionIsInTextField()) { - ((ContentView *)view())->textField()->setEditing(true, false); - app()->setFirstResponder(((ContentView *)view())->textField()); - return; - } - ((ContentView *)view())->editableExpressionView()->setEditing(true); + ((ContentView *)view())->editableExpressionView()->setEditing(true, false); app()->setFirstResponder(((ContentView *)view())->editableExpressionView()); } bool EditExpressionController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) { + assert(textField == ((ContentView *)view())->editableExpressionView()->textField()); if (textField->isEditing() && textField->textFieldShouldFinishEditing(event) && textField->draftTextLength() == 0 && m_calculationStore->numberOfCalculations() > 0) { - App * calculationApp = (App *)app(); - const char * lastTextBody = m_calculationStore->calculationAtIndex(m_calculationStore->numberOfCalculations()-1)->inputText(); - m_calculationStore->push(lastTextBody, calculationApp->localContext()); - m_historyController->reload(); - ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); - return true; + return inputViewDidReceiveEvent(event); } return textFieldDelegateApp()->textFieldDidReceiveEvent(textField, event); } bool EditExpressionController::textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) { - App * calculationApp = (App *)app(); - m_calculationStore->push(textBody(), calculationApp->localContext()); - m_historyController->reload(); - ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); - ((ContentView *)view())->textField()->setEditing(true); - ((ContentView *)view())->textField()->setText(""); - return true; + assert(textField == ((ContentView *)view())->editableExpressionView()->textField()); + return inputViewDidFinishEditing(text, event); } bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField, const char * text) { - ((ContentView *)view())->textField()->setEditing(true); - ((ContentView *)view())->textField()->setText(text); - return false; + assert(textField == ((ContentView *)view())->editableExpressionView()->textField()); + return inputViewDidAbortEditing(text); } -bool EditExpressionController::editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) { - bool layoutIsEmpty = expressionLayout()->isHorizontal() && expressionLayout()->numberOfChildren() == 0; - if (editableExpressionView->isEditing() && editableExpressionView->editableExpressionViewShouldFinishEditing(event) && layoutIsEmpty && m_calculationStore->numberOfCalculations() > 0) { - App * calculationApp = (App *)app(); - const char * lastTextBody = m_calculationStore->calculationAtIndex(m_calculationStore->numberOfCalculations()-1)->inputText(); - m_calculationStore->push(lastTextBody, calculationApp->localContext()); - m_historyController->reload(); - ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); - return true; +bool EditExpressionController::scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { + assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor()); + if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event) && !expressionLayout()->hasText() && m_calculationStore->numberOfCalculations() > 0) { + return inputViewDidReceiveEvent(event); } - return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidReceiveEvent(editableExpressionView, event); + return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event); } -bool EditExpressionController::editableExpressionViewDidFinishEditing(::EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { - App * calculationApp = (App *)app(); - expressionLayout()->writeTextInBuffer(const_cast(textBody()), ContentView::k_bufferLength); - m_calculationStore->push(textBody(), calculationApp->localContext()); - (const_cast(((ContentView *)view())->editableExpressionView()->expressionViewWithCursor()->expressionView()))->setExpressionLayout(new Poincare::HorizontalLayout()); - reloadView(); - ((ContentView *)view())->editableExpressionView()->setEditing(true); - return true; +bool EditExpressionController::scrollableExpressionViewWithCursorDidFinishEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) { + assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor()); + return inputViewDidFinishEditing(text, event); } -bool EditExpressionController::editableExpressionViewDidAbortEditing(::EditableExpressionView * editableExpressionView, const char * text) { - ((ContentView *)view())->editableExpressionView()->setEditing(true); - //TODO ((ContentView *)view())->editableExpressionView()->editableExpressionView()->expressionViewWithCursor()->expressionView()->setLayout(; - return false; +bool EditExpressionController::scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) { + assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor()); + return inputViewDidAbortEditing(text); } -void EditExpressionController::editableExpressionViewDidChangeSize(::EditableExpressionView * editableExpressionView) { - assert(editableExpressionView == ((ContentView *)view())->editableExpressionView()); +void EditExpressionController::scrollableExpressionViewWithCursorDidChangeSize(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor()); reloadView(); } @@ -195,7 +116,7 @@ TextFieldDelegateApp * EditExpressionController::textFieldDelegateApp() { return (App *)app(); } -TextFieldAndEditableExpressionViewDelegateApp * EditExpressionController::textFieldAndEditableExpressionViewDelegateApp() { +EditableExpressionViewDelegateApp * EditExpressionController::editableExpressionViewDelegateApp() { return (App *)app(); } @@ -216,13 +137,38 @@ void EditExpressionController::reloadView() { } } +bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event) { + App * calculationApp = (App *)app(); + const char * lastTextBody = m_calculationStore->calculationAtIndex(m_calculationStore->numberOfCalculations()-1)->inputText(); + m_calculationStore->push(lastTextBody, calculationApp->localContext()); + m_historyController->reload(); + ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); + return true; +} + +bool EditExpressionController::inputViewDidFinishEditing(const char * text, Ion::Events::Event event) { + App * calculationApp = (App *)app(); + m_calculationStore->push(textBody(), calculationApp->localContext()); + m_historyController->reload(); + ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); + ((ContentView *)view())->editableExpressionView()->setEditing(true, true); + ((ContentView *)view())->editableExpressionView()->setText(""); + return true; +} + +bool EditExpressionController::inputViewDidAbortEditing(const char * text) { + ((ContentView *)view())->editableExpressionView()->setEditing(true, true); + ((ContentView *)view())->editableExpressionView()->setText(text); + return false; +} + void EditExpressionController::viewDidDisappear() { DynamicViewController::viewDidDisappear(); m_historyController->viewDidDisappear(); } Poincare::ExpressionLayout * EditExpressionController::expressionLayout() { - return ((ContentView *)view())->editableExpressionView()->expressionViewWithCursor()->expressionView()->expressionLayout(); + return ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor()->expressionViewWithCursor()->expressionView()->expressionLayout(); } } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index 9c3d3d4aa..a2b64b951 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -4,16 +4,15 @@ #include #include "editable_expression_view.h" #include "../shared/text_field_delegate.h" -#include "../shared/editable_expression_view_delegate.h" +#include "../shared/scrollable_expression_view_with_cursor_delegate.h" #include "history_controller.h" #include "calculation_store.h" -#include "text_field.h" namespace Calculation { class HistoryController; /* TODO: implement a split view */ -class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate, public Shared::EditableExpressionViewDelegate { +class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate, public Shared::ScrollableExpressionViewWithCursorDelegate { public: EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore); void didBecomeFirstResponder() override; @@ -27,43 +26,35 @@ public: bool textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) override; bool textFieldDidAbortEditing(::TextField * textField, const char * text) override; - /* EditableExpressionViewDelegate */ - bool editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; - bool editableExpressionViewDidFinishEditing(::EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) override; - bool editableExpressionViewDidAbortEditing(::EditableExpressionView * editableExpressionView, const char * text) override; - void editableExpressionViewDidChangeSize(::EditableExpressionView * editableExpressionView) override; + /* ScrollableExpressionViewWithCursorDelegate */ + bool scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidFinishEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) override; + void scrollableExpressionViewWithCursorDidChangeSize(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; private: class ContentView : public View { public: - ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, EditableExpressionViewDelegate * editableExpressionViewDelegate); - int numberOfSubviews() const override; + ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate); + void reload(); + TableView * mainView() { return m_mainView; } + EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; } + /* View */ + int numberOfSubviews() const override { return 2; } View * subviewAtIndex(int index) override; void layoutSubviews() override; - void reload(); - TextField * textField() { return &m_textField; } - EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; } - TableView * mainView() { return m_mainView; } - void drawRect(KDContext * ctx, KDRect rect) const override; - bool editionIsInTextField() const; - static constexpr int k_bufferLength = TextField::maxBufferSize(); private: - static constexpr KDCoordinate k_textFieldHeight = 37; - static constexpr KDCoordinate k_leftMargin = 5; - static constexpr KDCoordinate k_verticalEditableExpressionViewMargin = 5; - constexpr static int k_separatorThickness = 1; - KDCoordinate inputViewHeight() const; - KDCoordinate editableExpressionViewHeight() const; TableView * m_mainView; - TextField m_textField; EditableExpressionView m_editableExpressionView; - char m_textBody[k_bufferLength]; }; View * loadView() override; void unloadView(View * view) override; void reloadView(); + bool inputViewDidReceiveEvent(Ion::Events::Event event); + bool inputViewDidFinishEditing(const char * text, Ion::Events::Event event); + bool inputViewDidAbortEditing(const char * text); Shared::TextFieldDelegateApp * textFieldDelegateApp() override; - Shared::TextFieldAndEditableExpressionViewDelegateApp * textFieldAndEditableExpressionViewDelegateApp() override; + Shared::EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() override; Poincare::ExpressionLayout * expressionLayout(); HistoryController * m_historyController; CalculationStore * m_calculationStore; diff --git a/apps/calculation/editable_expression_view.cpp b/apps/calculation/editable_expression_view.cpp index a06287c2c..ac9b2000d 100644 --- a/apps/calculation/editable_expression_view.cpp +++ b/apps/calculation/editable_expression_view.cpp @@ -2,34 +2,30 @@ namespace Calculation { -EditableExpressionView::EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate) : - ::EditableExpressionView(parentResponder, expressionLayout, delegate) +EditableExpressionView::EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) : + ::EditableExpressionView(parentResponder, textFieldDelegate, scrollableExpressionViewWithCursorDelegate) { setEditing(true); } -bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { +bool EditableExpressionView::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::Back) { return false; } if (event == Ion::Events::Ans) { - m_expressionViewWithCursor.cursor()->insertText("ans"); + insertText("ans"); return true; } - Poincare::ExpressionLayout * layout = m_expressionViewWithCursor.expressionView()->expressionLayout(); - bool layoutIsEmpty = layout->isEmpty() - || (layout->isHorizontal() - && layout->numberOfChildren() == 0); - if (isEditing() && layoutIsEmpty && + if (isEditing() && isEmpty() && (event == Ion::Events::Multiplication || event == Ion::Events::Plus || event == Ion::Events::Power || event == Ion::Events::Square || event == Ion::Events::Division || event == Ion::Events::Sto)) { - m_expressionViewWithCursor.cursor()->insertText("ans"); + insertText("ans"); } - return(::EditableExpressionView::privateHandleEvent(event)); + return(::EditableExpressionView::handleEvent(event)); } } diff --git a/apps/calculation/editable_expression_view.h b/apps/calculation/editable_expression_view.h index f873e9115..52a1faad3 100644 --- a/apps/calculation/editable_expression_view.h +++ b/apps/calculation/editable_expression_view.h @@ -7,9 +7,9 @@ namespace Calculation { class EditableExpressionView : public ::EditableExpressionView { public: - EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate = nullptr); + EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate); protected: - bool privateHandleEvent(Ion::Events::Event event) override; + bool handleEvent(Ion::Events::Event event) override; }; } diff --git a/apps/calculation/text_field.cpp b/apps/calculation/text_field.cpp deleted file mode 100644 index e9349c201..000000000 --- a/apps/calculation/text_field.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "text_field.h" - -namespace Calculation { - -TextField::TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate) : - ::TextField(parentResponder, textBuffer, textBuffer, textBufferSize, delegate, false) -{ - setEditing(true); -} - -bool TextField::handleEvent(Ion::Events::Event event) { - if (event == Ion::Events::Back) { - return false; - } - if (event == Ion::Events::Ans) { - insertTextAtLocation("ans", cursorLocation()); - setCursorLocation(cursorLocation() + strlen("ans")); - return true; - } - if (isEditing() && draftTextLength() == 0 && - (event == Ion::Events::Multiplication || - event == Ion::Events::Plus || - event == Ion::Events::Power || - event == Ion::Events::Square || - event == Ion::Events::Division || - event == Ion::Events::Sto)) { - insertTextAtLocation("ans", cursorLocation()); - setCursorLocation(cursorLocation() + strlen("ans")); - } - return(::TextField::handleEvent(event)); -} - -} diff --git a/apps/calculation/text_field.h b/apps/calculation/text_field.h deleted file mode 100644 index 6d2f12392..000000000 --- a/apps/calculation/text_field.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CALCULATION_TEXT_FIELD_H -#define CALCULATION_TEXT_FIELD_H - -#include - -namespace Calculation { - -class TextField : public ::TextField { -public: - TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate); - bool handleEvent(Ion::Events::Event event) override; -}; - -} - -#endif diff --git a/apps/graph/app.cpp b/apps/graph/app.cpp index 581877d5f..c1b3d7a0e 100644 --- a/apps/graph/app.cpp +++ b/apps/graph/app.cpp @@ -70,7 +70,7 @@ App::App(Container * container, Snapshot * snapshot) : m_valuesHeader(&m_valuesStackViewController, &m_valuesAlternateEmptyViewController, &m_valuesController), m_valuesStackViewController(&m_tabViewController, &m_valuesHeader), m_tabViewController(&m_inputViewController, snapshot, &m_listStackViewController, &m_graphStackViewController, &m_valuesStackViewController), - m_inputViewController(&m_modalViewController, &m_tabViewController, this) + m_inputViewController(&m_modalViewController, &m_tabViewController, this, this) { } diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index a083d5747..63639f81f 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -115,8 +115,8 @@ void MathToolbox::setSenderAndAction(Responder * sender, Action action) { m_action = action; } -void MathToolbox::actionForEditableExpressionView(void * sender, const char * text, bool removeArguments) { - EditableExpressionView * expressionLayoutEditorSender = static_cast(sender); +void MathToolbox::actionForScrollableExpressionViewWithCursor(void * sender, const char * text, bool removeArguments) { + ScrollableExpressionViewWithCursor * expressionLayoutEditorSender = static_cast(sender); Expression * resultExpression = nullptr; if (removeArguments) { // Replace the arguments with Empty chars. diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index 913706611..68f38e3e9 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -11,7 +11,7 @@ public: typedef void (*Action)(void * sender, const char * text, bool removeArguments); MathToolbox(); void setSenderAndAction(Responder * sender, Action action); - static void actionForEditableExpressionView(void * sender, const char * text, bool removeArguments = true); + static void actionForScrollableExpressionViewWithCursor(void * sender, const char * text, bool removeArguments = true); static void actionForTextField(void * sender, const char * text, bool removeArguments = true); protected: bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override; diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index de681f165..8c9194f5c 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -72,7 +72,7 @@ App::App(Container * container, Snapshot * snapshot) : m_valuesHeader(nullptr, &m_valuesAlternateEmptyViewController, &m_valuesController), m_valuesStackViewController(&m_tabViewController, &m_valuesHeader), m_tabViewController(&m_inputViewController, snapshot, &m_listStackViewController, &m_graphStackViewController, &m_valuesStackViewController), - m_inputViewController(&m_modalViewController, &m_tabViewController, &m_listController) + m_inputViewController(&m_modalViewController, &m_tabViewController, &m_listController, &m_listController) { } diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index c3a8e6031..b8cc8cdeb 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -38,6 +38,10 @@ TextFieldDelegateApp * ListController::textFieldDelegateApp() { return (App *)app(); } +EditableExpressionViewDelegateApp * ListController::editableExpressionViewDelegateApp() { + return (App *)app(); +} + int ListController::numberOfRows() { int numberOfRows = 0; for (int i = 0; i < m_sequenceStore->numberOfFunctions(); i++) { diff --git a/apps/sequence/list/list_controller.h b/apps/sequence/list/list_controller.h index 2fd3f0f35..a8f34882f 100644 --- a/apps/sequence/list/list_controller.h +++ b/apps/sequence/list/list_controller.h @@ -5,16 +5,17 @@ #include "../sequence_title_cell.h" #include "../sequence_store.h" #include "../../shared/function_expression_cell.h" -#include "type_parameter_controller.h" -#include "../../shared/new_function_cell.h" #include "../../shared/list_controller.h" +#include "../../shared/new_function_cell.h" +#include "../../shared/scrollable_expression_view_with_cursor_delegate.h" #include "../../shared/text_field_delegate.h" #include "list_parameter_controller.h" #include "sequence_toolbox.h" +#include "type_parameter_controller.h" namespace Sequence { -class ListController : public Shared::ListController, public Shared::TextFieldDelegate { +class ListController : public Shared::ListController, public Shared::TextFieldDelegate, public Shared::ScrollableExpressionViewWithCursorDelegate { public: ListController(Responder * parentResponder, SequenceStore * sequenceStore, ButtonRowController * header, ButtonRowController * footer); const char * title() override; @@ -25,6 +26,7 @@ public: void selectPreviousNewSequenceCell(); private: Shared::TextFieldDelegateApp * textFieldDelegateApp() override; + Shared::EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() override; void editExpression(Sequence * sequence, int sequenceDefinitionIndex, Ion::Events::Event event); ListParameterController * parameterController() override; int maxNumberOfRows() override; diff --git a/apps/shared/Makefile b/apps/shared/Makefile index 40c3a475c..11e481683 100644 --- a/apps/shared/Makefile +++ b/apps/shared/Makefile @@ -6,7 +6,7 @@ app_objs += $(addprefix apps/shared/,\ curve_view_cursor.o\ curve_view_range.o\ editable_cell_table_view_controller.o\ - editable_expression_view_delegate.o\ + editable_expression_view_delegate_app.o\ float_pair_store.o\ float_parameter_controller.o\ function.o\ @@ -35,10 +35,10 @@ app_objs += $(addprefix apps/shared/,\ parameter_text_field_delegate.o\ range_parameter_controller.o\ regular_table_view_data_source.o\ + scrollable_expression_view_with_cursor_delegate.o\ store_controller.o\ store_parameter_controller.o\ tab_table_controller.o\ - text_field_and_editable_expression_view_delegate_app.o\ text_field_delegate.o\ text_field_delegate_app.o\ toolbox_helpers.o\ diff --git a/apps/shared/editable_expression_view_delegate.cpp b/apps/shared/editable_expression_view_delegate.cpp deleted file mode 100644 index ff7542ed4..000000000 --- a/apps/shared/editable_expression_view_delegate.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "editable_expression_view_delegate.h" - -using namespace Poincare; - -namespace Shared { - -bool EditableExpressionViewDelegate::editableExpressionViewShouldFinishEditing(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) { - return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewShouldFinishEditing(editableExpressionView, event); -} - -bool EditableExpressionViewDelegate::editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) { - return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidReceiveEvent(editableExpressionView, event); -} - -bool EditableExpressionViewDelegate::editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { - return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidFinishEditing(editableExpressionView, text, event); -} - -bool EditableExpressionViewDelegate::editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) { - return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidAbortEditing(editableExpressionView, text); -} - -bool EditableExpressionViewDelegate::editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) { - return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidHandleEvent(editableExpressionView, event, returnValue, expressionHasChanged); -} - -void EditableExpressionViewDelegate::editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) { - return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidChangeSize(editableExpressionView); -} - -Toolbox * EditableExpressionViewDelegate::toolboxForEditableExpressionView(::EditableExpressionView * editableExpressionView) { - return textFieldAndEditableExpressionViewDelegateApp()->toolboxForEditableExpressionView(editableExpressionView); -} - -} diff --git a/apps/shared/editable_expression_view_delegate.h b/apps/shared/editable_expression_view_delegate.h deleted file mode 100644 index 9c779b642..000000000 --- a/apps/shared/editable_expression_view_delegate.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_H -#define SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_H - -#include -#include "text_field_and_editable_expression_view_delegate_app.h" - -namespace Shared { - -class EditableExpressionViewDelegate : public ::EditableExpressionViewDelegate { -public: - bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; - bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; - bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) override; - bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) override; - bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) override; - void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) override; - Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) override; -private: - virtual TextFieldAndEditableExpressionViewDelegateApp * textFieldAndEditableExpressionViewDelegateApp() = 0; -}; - -} - -#endif diff --git a/apps/shared/editable_expression_view_delegate_app.cpp b/apps/shared/editable_expression_view_delegate_app.cpp new file mode 100644 index 000000000..3ce1f53cb --- /dev/null +++ b/apps/shared/editable_expression_view_delegate_app.cpp @@ -0,0 +1,56 @@ +#include "editable_expression_view_delegate_app.h" +#include "../i18n.h" +#include "../apps_container.h" + +using namespace Poincare; + +namespace Shared { + +EditableExpressionViewDelegateApp::EditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) : + TextFieldDelegateApp(container, snapshot, rootViewController), + ScrollableExpressionViewWithCursorDelegate() +{ +} + +bool EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { + return event == Ion::Events::OK || event == Ion::Events::EXE; +} + +bool EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { + if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event)) { + if (!scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout()->hasText()) { + scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError); + return true; + } + int bufferSize = 256; + char buffer[bufferSize]; + scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); + Expression * exp = Expression::parse(buffer); + if (exp != nullptr) { + delete exp; + } + if (exp == nullptr) { + scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError); + return true; + } + } + if (event == Ion::Events::Var) { + if (!scrollableExpressionViewWithCursor->isEditing()) { + scrollableExpressionViewWithCursor->setEditing(true); + } + AppsContainer * appsContainer = (AppsContainer *)scrollableExpressionViewWithCursor->app()->container(); + VariableBoxController * variableBoxController = appsContainer->variableBoxController(); + variableBoxController->setScrollableExpressionViewWithCursorSender(scrollableExpressionViewWithCursor); + scrollableExpressionViewWithCursor->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin); + return true; + } + return false; +} + +Toolbox * EditableExpressionViewDelegateApp::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + Toolbox * toolbox = container()->mathToolbox(); + static_cast(toolbox)->setSenderAndAction(scrollableExpressionViewWithCursor, MathToolbox::actionForScrollableExpressionViewWithCursor); + return toolbox; +} + +} diff --git a/apps/shared/editable_expression_view_delegate_app.h b/apps/shared/editable_expression_view_delegate_app.h new file mode 100644 index 000000000..626b3fac7 --- /dev/null +++ b/apps/shared/editable_expression_view_delegate_app.h @@ -0,0 +1,21 @@ +#ifndef SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H +#define SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H + +#include "text_field_delegate_app.h" +#include + +namespace Shared { + +class EditableExpressionViewDelegateApp : public TextFieldDelegateApp, public ScrollableExpressionViewWithCursorDelegate { +public: + virtual ~EditableExpressionViewDelegateApp() = default; + bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; + virtual bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; + Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; +protected: + EditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController); +}; + +} + +#endif diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index 4e01d51d4..f805efe48 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -47,7 +47,7 @@ void FunctionApp::Snapshot::reset() { } FunctionApp::FunctionApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) : - TextFieldDelegateApp(container, snapshot, rootViewController) + EditableExpressionViewDelegateApp(container, snapshot, rootViewController) { } @@ -56,7 +56,7 @@ void FunctionApp::willBecomeInactive() { m_modalViewController.dismissModalViewController(); } if (inputViewController()->isDisplayingModal()) { - inputViewController()->abortTextFieldEditionAndDismiss(); + inputViewController()->abortEditionAndDismiss(); } ::App::willBecomeInactive(); } diff --git a/apps/shared/function_app.h b/apps/shared/function_app.h index 0c73d582f..b4b59503d 100644 --- a/apps/shared/function_app.h +++ b/apps/shared/function_app.h @@ -2,7 +2,7 @@ #define SHARED_FUNCTION_APP_H #include -#include "text_field_delegate_app.h" +#include "editable_expression_view_delegate_app.h" #include "curve_view_cursor.h" #include "interval.h" @@ -10,7 +10,7 @@ class AppsContainer; namespace Shared { -class FunctionApp : public TextFieldDelegateApp { +class FunctionApp : public EditableExpressionViewDelegateApp { public: class Snapshot : public ::App::Snapshot, public TabViewDataSource { public: diff --git a/apps/shared/scrollable_expression_view_with_cursor_delegate.cpp b/apps/shared/scrollable_expression_view_with_cursor_delegate.cpp new file mode 100644 index 000000000..5174721ff --- /dev/null +++ b/apps/shared/scrollable_expression_view_with_cursor_delegate.cpp @@ -0,0 +1,31 @@ +#include "scrollable_expression_view_with_cursor_delegate.h" + +using namespace Poincare; + +namespace Shared { + +bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { + return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorShouldFinishEditing(scrollableExpressionViewWithCursor, event); +} + +bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { + return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event); +} + +bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) { + return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidFinishEditing(scrollableExpressionViewWithCursor, text, event); +} + +bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) { + return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidAbortEditing(scrollableExpressionViewWithCursor, text); +} + +void ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidChangeSize(scrollableExpressionViewWithCursor); +} + +Toolbox * ScrollableExpressionViewWithCursorDelegate::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + return editableExpressionViewDelegateApp()->toolboxForScrollableExpressionViewWithCursor(scrollableExpressionViewWithCursor); +} + +} diff --git a/apps/shared/scrollable_expression_view_with_cursor_delegate.h b/apps/shared/scrollable_expression_view_with_cursor_delegate.h new file mode 100644 index 000000000..589f6a8db --- /dev/null +++ b/apps/shared/scrollable_expression_view_with_cursor_delegate.h @@ -0,0 +1,23 @@ +#ifndef SHARED_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H +#define SHARED_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H + +#include +#include "editable_expression_view_delegate_app.h" + +namespace Shared { + +class ScrollableExpressionViewWithCursorDelegate : public ::ScrollableExpressionViewWithCursorDelegate { +public: + bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) override; + void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; + Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; +private: + virtual EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() = 0; +}; + +} + +#endif diff --git a/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp b/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp deleted file mode 100644 index 516c4a466..000000000 --- a/apps/shared/text_field_and_editable_expression_view_delegate_app.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "text_field_and_editable_expression_view_delegate_app.h" -#include "../i18n.h" -#include "../apps_container.h" - -using namespace Poincare; - -namespace Shared { - -TextFieldAndEditableExpressionViewDelegateApp::TextFieldAndEditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) : - TextFieldDelegateApp(container, snapshot, rootViewController), - EditableExpressionViewDelegate() -{ -} - -bool TextFieldAndEditableExpressionViewDelegateApp::editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) { - return event == Ion::Events::OK || event == Ion::Events::EXE; -} - -bool TextFieldAndEditableExpressionViewDelegateApp::editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) { - if (editableExpressionView->isEditing() && editableExpressionView->editableExpressionViewShouldFinishEditing(event)) { - int bufferSize = 256; - char buffer[bufferSize]; - editableExpressionView->expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); - Expression * exp = Expression::parse(buffer); - if (exp != nullptr) { - delete exp; - } - if (exp == nullptr) { - editableExpressionView->app()->displayWarning(I18n::Message::SyntaxError); - return true; - } - } - if (event == Ion::Events::Var) { - if (!editableExpressionView->isEditing()) { - editableExpressionView->setEditing(true); - } - AppsContainer * appsContainer = (AppsContainer *)editableExpressionView->app()->container(); - VariableBoxController * variableBoxController = appsContainer->variableBoxController(); - variableBoxController->setEditableExpressionViewSender(editableExpressionView); - editableExpressionView->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin); - return true; - } - return false; -} - -Toolbox * TextFieldAndEditableExpressionViewDelegateApp::toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) { - Toolbox * toolbox = container()->mathToolbox(); - static_cast(toolbox)->setSenderAndAction(editableExpressionView, MathToolbox::actionForEditableExpressionView); - return toolbox; -} - -} diff --git a/apps/shared/text_field_and_editable_expression_view_delegate_app.h b/apps/shared/text_field_and_editable_expression_view_delegate_app.h deleted file mode 100644 index 85bc85fc2..000000000 --- a/apps/shared/text_field_and_editable_expression_view_delegate_app.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SHARED_TEXT_FIELD_AND_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H -#define SHARED_TEXT_FIELD_AND_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H - -#include "text_field_delegate_app.h" -#include - -namespace Shared { - -class TextFieldAndEditableExpressionViewDelegateApp : public TextFieldDelegateApp, public EditableExpressionViewDelegate { -public: - virtual ~TextFieldAndEditableExpressionViewDelegateApp() = default; - bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; - virtual bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override; - Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) override; -protected: - TextFieldAndEditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController); -}; - -} - -#endif diff --git a/apps/variable_box_controller.cpp b/apps/variable_box_controller.cpp index 3f14cc49c..253a38ea9 100644 --- a/apps/variable_box_controller.cpp +++ b/apps/variable_box_controller.cpp @@ -202,9 +202,9 @@ void VariableBoxController::ContentViewController::setTextFieldSender(TextField m_insertTextAction = &insertTextInTextField; } -void VariableBoxController::ContentViewController::setEditableExpressionViewSender(EditableExpressionView * editableExpressionView) { - m_sender = editableExpressionView; - m_insertTextAction = &insertTextInEditableExpressionView; +void VariableBoxController::ContentViewController::setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + m_sender = scrollableExpressionViewWithCursor; + m_insertTextAction = &insertTextInScrollableExpressionViewWithCursor; } void VariableBoxController::ContentViewController::reloadData() { @@ -288,12 +288,12 @@ void VariableBoxController::ContentViewController::insertTextInTextField(void * textField->setCursorLocation(textField->cursorLocation() + strlen(textToInsert)); } -void VariableBoxController::ContentViewController::insertTextInEditableExpressionView(void * sender, const char * textToInsert) { - EditableExpressionView * editableExpressionView = static_cast(sender); - if (!editableExpressionView->isEditing()) { - editableExpressionView->setEditing(true); +void VariableBoxController::ContentViewController::insertTextInScrollableExpressionViewWithCursor(void * sender, const char * textToInsert) { + ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor = static_cast(sender); + if (!scrollableExpressionViewWithCursor->isEditing()) { + scrollableExpressionViewWithCursor->setEditing(true); } - editableExpressionView->insertLayoutFromTextAtCursor(textToInsert); + scrollableExpressionViewWithCursor->insertLayoutFromTextAtCursor(textToInsert); } VariableBoxController::VariableBoxController(GlobalContext * context) : @@ -310,8 +310,8 @@ void VariableBoxController::setTextFieldSender(TextField * textField) { m_contentViewController.setTextFieldSender(textField); } -void VariableBoxController::setEditableExpressionViewSender(EditableExpressionView * editableExpressionView) { - m_contentViewController.setEditableExpressionViewSender(editableExpressionView); +void VariableBoxController::setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + m_contentViewController.setScrollableExpressionViewWithCursorSender(scrollableExpressionViewWithCursor); } void VariableBoxController::viewWillAppear() { diff --git a/apps/variable_box_controller.h b/apps/variable_box_controller.h index daa75938e..512ef2798 100644 --- a/apps/variable_box_controller.h +++ b/apps/variable_box_controller.h @@ -14,7 +14,7 @@ public: VariableBoxController(Poincare::GlobalContext * context); void didBecomeFirstResponder() override; void setTextFieldSender(TextField * textField); - void setEditableExpressionViewSender(EditableExpressionView * editableExpressionView); + void setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor); void viewWillAppear() override; void viewDidDisappear() override; private: @@ -34,7 +34,7 @@ private: int indexFromCumulatedHeight(KDCoordinate offsetY) override; int typeAtLocation(int i, int j) override; void setTextFieldSender(TextField * textField); - void setEditableExpressionViewSender(EditableExpressionView * editableExpressionView); + void setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor); void reloadData(); void resetPage(); void viewDidDisappear() override; @@ -59,7 +59,7 @@ private: I18n::Message nodeLabelAtIndex(int index); const Poincare::Expression * expressionForIndex(int index); static void insertTextInTextField(void * sender, const char * textToInsert); - static void insertTextInEditableExpressionView(void * sender, const char * textToInsert); + static void insertTextInScrollableExpressionViewWithCursor(void * sender, const char * textToInsert); Poincare::GlobalContext * m_context; Responder * m_sender; Action m_insertTextAction; diff --git a/escher/Makefile b/escher/Makefile index bf54220fe..274900e46 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -49,6 +49,7 @@ objs += $(addprefix escher/src/,\ scroll_view_data_source.o\ scroll_view_indicator.o\ scrollable_view.o\ + scrollable_expression_view_with_cursor.o\ selectable_table_view.o\ selectable_table_view_data_source.o\ selectable_table_view_delegate.o\ diff --git a/escher/include/escher.h b/escher/include/escher.h index 50dc65933..9db562c60 100644 --- a/escher/include/escher.h +++ b/escher/include/escher.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -53,6 +52,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/escher/include/escher/editable_expression_view.h b/escher/include/escher/editable_expression_view.h index 84dcd8d9b..d0c6e88b8 100644 --- a/escher/include/escher/editable_expression_view.h +++ b/escher/include/escher/editable_expression_view.h @@ -1,39 +1,49 @@ #ifndef ESCHER_EDITABLE_EXPRESSION_VIEW_H #define ESCHER_EDITABLE_EXPRESSION_VIEW_H -#include -#include -#include -#include +#include +#include +#include +#include -class EditableExpressionView : public ScrollableView, public ScrollViewDataSource { +class EditableExpressionView : public Responder, public View { public: - EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate = nullptr); - void setDelegate(EditableExpressionViewDelegate * delegate) { m_delegate = delegate; } - ExpressionViewWithCursor * expressionViewWithCursor() { return &m_expressionViewWithCursor; } + EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate); + + void setEditing(bool isEditing, bool reinitDraftBuffer = true); bool isEditing() const; - void setEditing(bool isEditing); - void scrollToCursor(); + const char * text(); + void setText(const char * text); + void insertText(const char * text); void reload(); - - /* Responder */ - Toolbox * toolbox() override; - bool handleEvent(Ion::Events::Event event) override; - - bool editableExpressionViewShouldFinishEditing(Ion::Events::Event event); - - void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout); - void insertLayoutFromTextAtCursor(const char * text); + TextField * textField() { return &m_textField; } + ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor() { return &m_scrollableExpressionViewWithCursor; } + bool editionIsInTextField() const; + bool isEmpty() const; + bool heightIsMaximal() const; /* View */ + int numberOfSubviews() const override { return 1; } + View * subviewAtIndex(int index) override; + void layoutSubviews() override; + void drawRect(KDContext * ctx, KDRect rect) const override; KDSize minimalSizeForOptimalDisplay() const override; -protected: - virtual bool privateHandleEvent(Ion::Events::Event event); - bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout); - ExpressionViewWithCursor m_expressionViewWithCursor; + /* Responder */ + void didBecomeFirstResponder() override; + bool handleEvent(Ion::Events::Event event) override; + + static constexpr int k_bufferLength = TextField::maxBufferSize(); private: - EditableExpressionViewDelegate * m_delegate; + static constexpr KDCoordinate k_textFieldHeight = 37; + static constexpr KDCoordinate k_leftMargin = 5; + static constexpr KDCoordinate k_verticalExpressionViewMargin = 5; + constexpr static int k_separatorThickness = 1; + KDCoordinate inputViewHeight() const; + KDCoordinate maximalHeight() const; + TextField m_textField; + ScrollableExpressionViewWithCursor m_scrollableExpressionViewWithCursor; + char m_textBody[k_bufferLength]; }; #endif diff --git a/escher/include/escher/editable_expression_view_delegate.h b/escher/include/escher/editable_expression_view_delegate.h deleted file mode 100644 index a6728caed..000000000 --- a/escher/include/escher/editable_expression_view_delegate.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef ESCHER_EDITABLE_EXPRESSION_VIEW_DELEGATE_H -#define ESCHER_EDITABLE_EXPRESSION_VIEW_DELEGATE_H - -#include -#include - -class EditableExpressionView; - -class EditableExpressionViewDelegate { -public: - virtual bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) = 0; - virtual bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) = 0; - virtual bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { return false; } - virtual bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) { return false; } - virtual bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) { return returnValue; } - virtual void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) {} - virtual Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) = 0; -}; - -#endif diff --git a/escher/include/escher/input_view_controller.h b/escher/include/escher/input_view_controller.h index 52169e9b6..a2f037758 100644 --- a/escher/include/escher/input_view_controller.h +++ b/escher/include/escher/input_view_controller.h @@ -1,53 +1,53 @@ #ifndef ESCHER_INPUT_VIEW_CONTROLLER_H #define ESCHER_INPUT_VIEW_CONTROLLER_H +#include +#include #include #include #include #include -class InputViewController : public ModalViewController, TextFieldDelegate { +class InputViewController : public ModalViewController, TextFieldDelegate, ScrollableExpressionViewWithCursorDelegate { public: - InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate); + InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate); void edit(Responder * caller, Ion::Events::Event event, void * context, const char * initialText, Invocation::Action successAction, Invocation::Action failureAction); const char * textBody(); + void abortEditionAndDismiss(); + + /* TextFieldDelegate */ bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; - void abortTextFieldEditionAndDismiss(); bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; bool textFieldDidAbortEditing(TextField * textField, const char * text) override; Toolbox * toolboxForTextField(TextField * textFied) override; + + /* ScrollableExpressionViewWithCursorDelegate */ + bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override; + bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) override; + void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; + Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; + private: - class TextFieldController : public ViewController { + class EditableExpressionViewController : public ViewController { public: - TextFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate); + EditableExpressionViewController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate); void didBecomeFirstResponder() override; - View * view() override; - TextField * textField(); + View * view() override { return &m_editableExpressionView; } + EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; } private: - class ContentView : public Responder, public View { - public: - ContentView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate); - void didBecomeFirstResponder() override; - TextField * textField(); - void drawRect(KDContext * ctx, KDRect rect) const override; - KDSize minimalSizeForOptimalDisplay() const override; - private: - View * subviewAtIndex(int index) override; - int numberOfSubviews() const override; - void layoutSubviews() override; - constexpr static KDCoordinate k_inputHeight = 37; - constexpr static KDCoordinate k_separatorThickness = 1; - constexpr static KDCoordinate k_textMargin = 5; - TextField m_textField; - char m_textBody[TextField::maxBufferSize()]; - }; - ContentView m_view; + EditableExpressionView m_editableExpressionView; }; - TextFieldController m_textFieldController; + bool inputViewDidFinishEditing(); + bool inputViewDidAbortEditing(); + EditableExpressionViewController m_editableExpressionViewController; Invocation m_successAction; Invocation m_failureAction; TextFieldDelegate * m_textFieldDelegate; + ScrollableExpressionViewWithCursorDelegate * m_scrollableExpressionViewWithCursorDelegate; + bool m_inputViewHeightIsMaximal; }; #endif diff --git a/escher/include/escher/modal_view_controller.h b/escher/include/escher/modal_view_controller.h index ae466b820..3a326a12d 100644 --- a/escher/include/escher/modal_view_controller.h +++ b/escher/include/escher/modal_view_controller.h @@ -17,6 +17,8 @@ public: bool isDisplayingModal(); void viewWillAppear() override; void viewDidDisappear() override; +protected: + void reloadView(); private: class ContentView : public View { public: @@ -29,6 +31,7 @@ private: KDCoordinate topMargin, KDCoordinate leftMargin, KDCoordinate bottomMargin, KDCoordinate rightMargin); void dismissModalView(); bool isDisplayingModal() const; + void reload(); private: KDRect frame() const; View * m_regularView; diff --git a/escher/include/escher/scrollable_expression_view_with_cursor.h b/escher/include/escher/scrollable_expression_view_with_cursor.h new file mode 100644 index 000000000..7983e0ab7 --- /dev/null +++ b/escher/include/escher/scrollable_expression_view_with_cursor.h @@ -0,0 +1,40 @@ +#ifndef ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H +#define ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H + +#include +#include +#include +#include + +class ScrollableExpressionViewWithCursor : public ScrollableView, public ScrollViewDataSource { +public: + ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ScrollableExpressionViewWithCursorDelegate * delegate = nullptr); + void setDelegate(ScrollableExpressionViewWithCursorDelegate * delegate) { m_delegate = delegate; } + ExpressionViewWithCursor * expressionViewWithCursor() { return &m_expressionViewWithCursor; } + bool isEditing() const; + void setEditing(bool isEditing); + void clearLayout(); + void scrollToCursor(); + void reload(); + + /* Responder */ + Toolbox * toolbox() override; + bool handleEvent(Ion::Events::Event event) override; + + bool scrollableExpressionViewWithCursorShouldFinishEditing(Ion::Events::Event event); + + void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout); + void insertLayoutFromTextAtCursor(const char * text); + + /* View */ + KDSize minimalSizeForOptimalDisplay() const override; + +protected: + virtual bool privateHandleEvent(Ion::Events::Event event); + bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout); + ExpressionViewWithCursor m_expressionViewWithCursor; +private: + ScrollableExpressionViewWithCursorDelegate * m_delegate; +}; + +#endif diff --git a/escher/include/escher/scrollable_expression_view_with_cursor_delegate.h b/escher/include/escher/scrollable_expression_view_with_cursor_delegate.h new file mode 100644 index 000000000..56b22b337 --- /dev/null +++ b/escher/include/escher/scrollable_expression_view_with_cursor_delegate.h @@ -0,0 +1,19 @@ +#ifndef ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H +#define ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H + +#include +#include + +class ScrollableExpressionViewWithCursor; + +class ScrollableExpressionViewWithCursorDelegate { +public: + virtual bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) = 0; + virtual bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) = 0; + virtual bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) { return false; } + virtual bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) { return false; } + virtual void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {} + virtual Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) = 0; +}; + +#endif diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index a4de32044..359d129cf 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -1,212 +1,137 @@ #include -#include -#include -#include +#include #include -EditableExpressionView::EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate) : - ScrollableView(parentResponder, &m_expressionViewWithCursor, this), - m_expressionViewWithCursor(expressionLayout), - m_delegate(delegate) +EditableExpressionView::EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) : + Responder(parentResponder), + View(), + m_textField(parentResponder, m_textBody, m_textBody, k_bufferLength, textFieldDelegate, false), + m_scrollableExpressionViewWithCursor(parentResponder, new Poincare::HorizontalLayout(), scrollableExpressionViewWithCursorDelegate) { + m_textBody[0] = 0; +} + +void EditableExpressionView::setEditing(bool isEditing, bool reinitDraftBuffer) { + if (editionIsInTextField()) { + m_textField.setEditing(isEditing, reinitDraftBuffer); + } + if (reinitDraftBuffer) { + m_scrollableExpressionViewWithCursor.clearLayout(); + } + m_scrollableExpressionViewWithCursor.setEditing(isEditing); } bool EditableExpressionView::isEditing() const { - return m_expressionViewWithCursor.isEditing(); + return editionIsInTextField() ? m_textField.isEditing() : m_scrollableExpressionViewWithCursor.isEditing(); } -void EditableExpressionView::setEditing(bool isEditing) { - m_expressionViewWithCursor.setEditing(isEditing); +const char * EditableExpressionView::text() { + if (!editionIsInTextField()) { + m_scrollableExpressionViewWithCursor.expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(m_textBody, k_bufferLength); + } + return m_textBody; } -void EditableExpressionView::scrollToCursor() { - scrollToContentRect(m_expressionViewWithCursor.cursorRect(), true); +void EditableExpressionView::setText(const char * text) { + if (editionIsInTextField()) { + m_textField.setText(text); + } + m_scrollableExpressionViewWithCursor.clearLayout(); + if (strlen(text) > 0) { + m_scrollableExpressionViewWithCursor.insertLayoutFromTextAtCursor(text); + } } -Toolbox * EditableExpressionView::toolbox() { - if (m_delegate) { - return m_delegate->toolboxForEditableExpressionView(this); - } - return nullptr; -} - -bool EditableExpressionView::handleEvent(Ion::Events::Event event) { - KDSize previousSize = minimalSizeForOptimalDisplay(); - bool shouldRecomputeLayout = false; - if (privateHandleMoveEvent(event, &shouldRecomputeLayout)) { - if (!shouldRecomputeLayout) { - m_expressionViewWithCursor.cursorPositionChanged(); - scrollToCursor(); - return true; - } - reload(); - KDSize newSize = minimalSizeForOptimalDisplay(); - if (m_delegate && previousSize.height() != newSize.height()) { - m_delegate->editableExpressionViewDidChangeSize(this); - reload(); - } - return true; - } - if (privateHandleEvent(event)) { - reload(); - KDSize newSize = minimalSizeForOptimalDisplay(); - if (m_delegate && previousSize.height() != newSize.height()) { - m_delegate->editableExpressionViewDidChangeSize(this); - reload(); - } - return true; - } - return false; -} - -bool EditableExpressionView::editableExpressionViewShouldFinishEditing(Ion::Events::Event event) { - return m_delegate->editableExpressionViewShouldFinishEditing(this, event); -} - -KDSize EditableExpressionView::minimalSizeForOptimalDisplay() const { - return m_expressionViewWithCursor.minimalSizeForOptimalDisplay(); -} - -bool EditableExpressionView::privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) { - if (event == Ion::Events::Left) { - return m_expressionViewWithCursor.cursor()->moveLeft(shouldRecomputeLayout); - } - if (event == Ion::Events::Right) { - return m_expressionViewWithCursor.cursor()->moveRight(shouldRecomputeLayout); - } - if (event == Ion::Events::Up) { - return m_expressionViewWithCursor.cursor()->moveUp(shouldRecomputeLayout); - } - if (event == Ion::Events::Down) { - return m_expressionViewWithCursor.cursor()->moveDown(shouldRecomputeLayout); - } - if (event == Ion::Events::ShiftLeft) { - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Left); - return true; - } - if (event == Ion::Events::ShiftRight) { - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); - return true; - } - return false; -} - -bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) { - if (m_delegate && m_delegate->editableExpressionViewDidReceiveEvent(this, event)) { - return true; - } - if (Responder::handleEvent(event)) { - /* The only event Responder handles is 'Toolbox' displaying. In that case, - * the EditableExpressionView is forced into editing mode. */ - if (!isEditing()) { - setEditing(true); - } - return true; - } - if (isEditing() && editableExpressionViewShouldFinishEditing(event)) { - setEditing(false); - int bufferSize = TextField::maxBufferSize(); - char buffer[bufferSize]; - m_expressionViewWithCursor.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); - if (m_delegate->editableExpressionViewDidFinishEditing(this, buffer, event)) { - delete m_expressionViewWithCursor.expressionView()->expressionLayout(); - Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout(); - m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout); - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout); - } - return true; - } - if (event == Ion::Events::Division) { - m_expressionViewWithCursor.cursor()->addFractionLayoutAndCollapseBrothers(); - return true; - } - if (event == Ion::Events::XNT) { - m_expressionViewWithCursor.cursor()->addXNTCharLayout(); - return true; - } - if (event == Ion::Events::Exp) { - m_expressionViewWithCursor.cursor()->addEmptyExponentialLayout(); - return true; - } - if (event == Ion::Events::Power) { - m_expressionViewWithCursor.cursor()->addEmptyPowerLayout(); - return true; - } - if (event == Ion::Events::Sqrt) { - m_expressionViewWithCursor.cursor()->addEmptySquareRootLayout(); - return true; - } - if (event == Ion::Events::Square) { - m_expressionViewWithCursor.cursor()->addEmptySquarePowerLayout(); - return true; - } - if (event.hasText()) { - const char * textToInsert = event.text(); - if (textToInsert[1] == 0) { - if (textToInsert[0] == Ion::Charset::MultiplicationSign) { - const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; - m_expressionViewWithCursor.cursor()->insertText(middleDotString); - return true; - } - if (textToInsert[0] == '[' || textToInsert[0] == ']') { - m_expressionViewWithCursor.cursor()->addEmptyMatrixLayout(); - return true; - } - } - m_expressionViewWithCursor.cursor()->insertText(textToInsert); - return true; - } - if (event == Ion::Events::Backspace) { - m_expressionViewWithCursor.cursor()->performBackspace(); - return true; - } - if (event == Ion::Events::Paste) { - if (!isEditing()) { - setEditing(true); - } - insertLayoutFromTextAtCursor(Clipboard::sharedClipboard()->storedText()); - return true; - } - return false; -} - -void EditableExpressionView::insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout) { - if (layout == nullptr) { +void EditableExpressionView::insertText(const char * text) { + if (editionIsInTextField()) { + m_textField.setEditing(true, false); + m_textField.insertTextAtLocation(text, m_textField.cursorLocation()); + m_textField.setCursorLocation(m_textField.cursorLocation() + strlen(text)); return; } - KDSize previousSize = minimalSizeForOptimalDisplay(); - m_expressionViewWithCursor.cursor()->addLayout(layout); - if (layout->isMatrix() && pointedLayout->hasAncestor(layout)) { - static_cast(layout)->addGreySquares(); - } - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); - reload(); - KDSize newSize = minimalSizeForOptimalDisplay(); - if (m_delegate && previousSize.height() != newSize.height()) { - m_delegate->editableExpressionViewDidChangeSize(this); - } + m_scrollableExpressionViewWithCursor.setEditing(true); + m_scrollableExpressionViewWithCursor.insertLayoutFromTextAtCursor(text); } -void EditableExpressionView::insertLayoutFromTextAtCursor(const char * text) { - Poincare::Expression * expression = Poincare::Expression::parse(text); - if (expression != nullptr) { - Poincare::ExpressionLayout * layout = expression->createLayout(); - delete expression; - insertLayoutAtCursor(layout, layout); - reload(); +View * EditableExpressionView::subviewAtIndex(int index) { + assert(index == 0); + if (editionIsInTextField()) { + return &m_textField; + } + return &m_scrollableExpressionViewWithCursor; +} + +void EditableExpressionView::layoutSubviews() { + KDRect inputViewFrame(k_leftMargin, k_separatorThickness, bounds().width() - k_leftMargin, bounds().height() - k_separatorThickness); + if (editionIsInTextField()) { + m_textField.setFrame(inputViewFrame); + m_scrollableExpressionViewWithCursor.setFrame(KDRectZero); return; } - m_expressionViewWithCursor.cursor()->insertText(text); - reload(); + m_scrollableExpressionViewWithCursor.setFrame(inputViewFrame); + m_textField.setFrame(KDRectZero); } void EditableExpressionView::reload() { - m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); - m_expressionViewWithCursor.cursorPositionChanged(); layoutSubviews(); - scrollToCursor(); markRectAsDirty(bounds()); } + +void EditableExpressionView::drawRect(KDContext * ctx, KDRect rect) const { + // Draw the separator + ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyMiddle); + // Color the left margin + ctx->fillRect(KDRect(0, k_separatorThickness, k_leftMargin, bounds().height() - k_separatorThickness), m_textField.backgroundColor()); + if (!editionIsInTextField()) { + // Color the upper margin + ctx->fillRect(KDRect(0, k_separatorThickness, bounds().width(), k_verticalExpressionViewMargin), m_textField.backgroundColor()); + } +} + +void EditableExpressionView::didBecomeFirstResponder() { + if (editionIsInTextField()) { + app()->setFirstResponder(&m_textField); + return; + } + app()->setFirstResponder(&m_scrollableExpressionViewWithCursor); +} + +bool EditableExpressionView::handleEvent(Ion::Events::Event event) { + return editionIsInTextField() ? m_textField.handleEvent(event) : m_scrollableExpressionViewWithCursor.handleEvent(event); +} + +KDSize EditableExpressionView::minimalSizeForOptimalDisplay() const { + return KDSize(0, inputViewHeight()); +} + +bool EditableExpressionView::editionIsInTextField() const { + return Poincare::Preferences::sharedPreferences()->editionMode() == Poincare::Preferences::EditionMode::Edition1D; +} + +bool EditableExpressionView::isEmpty() const { + if (editionIsInTextField()) { + return m_textField.draftTextLength() == 0; + } + Poincare::ExpressionLayout * layout = const_cast(&m_scrollableExpressionViewWithCursor)->expressionViewWithCursor()->expressionView()->expressionLayout(); + return !layout->hasText(); +} + +bool EditableExpressionView::heightIsMaximal() const { + return inputViewHeight() == k_separatorThickness + k_verticalExpressionViewMargin + maximalHeight(); +} + +KDCoordinate EditableExpressionView::inputViewHeight() const { + if (editionIsInTextField()) { + return k_separatorThickness + k_textFieldHeight; + } + return k_separatorThickness + + k_verticalExpressionViewMargin + + min(maximalHeight(), + max(k_textFieldHeight, + m_scrollableExpressionViewWithCursor.minimalSizeForOptimalDisplay().height() + + k_verticalExpressionViewMargin)); +} + +KDCoordinate EditableExpressionView::maximalHeight() const { + return 0.6*Ion::Display::Height; +} diff --git a/escher/src/input_view_controller.cpp b/escher/src/input_view_controller.cpp index 22fd62fa1..fb89c3d62 100644 --- a/escher/src/input_view_controller.cpp +++ b/escher/src/input_view_controller.cpp @@ -1,89 +1,47 @@ #include #include #include +#include #include -InputViewController::TextFieldController::ContentView::ContentView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate) : - Responder(parentResponder), - View(), - m_textField(this, m_textBody, m_textBody, TextField::maxBufferSize(), textFieldDelegate, false) -{ - m_textBody[0] = 0; -} - -void InputViewController::TextFieldController::ContentView::didBecomeFirstResponder() { - app()->setFirstResponder(&m_textField); -} - -TextField * InputViewController::TextFieldController::ContentView::textField() { - return &m_textField; -} - -void InputViewController::TextFieldController::ContentView::drawRect(KDContext * ctx, KDRect rect) const { - ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyMiddle); - ctx->fillRect(KDRect(0, k_separatorThickness, k_textMargin, bounds().height()-k_separatorThickness), m_textField.backgroundColor()); -} - -KDSize InputViewController::TextFieldController::ContentView::minimalSizeForOptimalDisplay() const { - return KDSize(0, k_inputHeight); -} - -int InputViewController::TextFieldController::ContentView::numberOfSubviews() const { - return 1; -} - -View * InputViewController::TextFieldController::ContentView::subviewAtIndex(int index) { - return &m_textField; -} - -void InputViewController::TextFieldController::ContentView::layoutSubviews() { - m_textField.setFrame(KDRect(k_textMargin, k_separatorThickness, bounds().width()-k_textMargin, bounds().height())); -} - -InputViewController::TextFieldController::TextFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate) : +InputViewController::EditableExpressionViewController::EditableExpressionViewController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) : ViewController(parentResponder), - m_view(this, textFieldDelegate) + m_editableExpressionView(this, textFieldDelegate, scrollableExpressionViewWithCursorDelegate) { } -View * InputViewController::TextFieldController::view() { - return &m_view; +void InputViewController::EditableExpressionViewController::didBecomeFirstResponder() { + app()->setFirstResponder(&m_editableExpressionView); } -void InputViewController::TextFieldController::didBecomeFirstResponder() { - app()->setFirstResponder(&m_view); -} - -TextField * InputViewController::TextFieldController::textField() { - return m_view.textField(); -} - -InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate) : +InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) : ModalViewController(parentResponder, child), - m_textFieldController(this, this), + m_editableExpressionViewController(this, this, this), m_successAction(Invocation(nullptr, nullptr)), m_failureAction(Invocation(nullptr, nullptr)), - m_textFieldDelegate(textFieldDelegate) + m_textFieldDelegate(textFieldDelegate), + m_scrollableExpressionViewWithCursorDelegate(scrollableExpressionViewWithCursorDelegate), + m_inputViewHeightIsMaximal(false) { } const char * InputViewController::textBody() { - return m_textFieldController.textField()->text(); + return m_editableExpressionViewController.editableExpressionView()->text(); } void InputViewController::edit(Responder * caller, Ion::Events::Event event, void * context, const char * initialText, Invocation::Action successAction, Invocation::Action failureAction) { m_successAction = Invocation(successAction, context); m_failureAction = Invocation(failureAction, context); - displayModalViewController(&m_textFieldController, 1.0f, 1.0f); - m_textFieldController.textField()->handleEvent(event); + displayModalViewController(&m_editableExpressionViewController, 1.0f, 1.0f); if (initialText != nullptr) { - m_textFieldController.textField()->insertTextAtLocation(initialText, 0); - m_textFieldController.textField()->setCursorLocation(strlen(initialText)); + m_editableExpressionViewController.editableExpressionView()->setText(initialText); + //TODO is the editableExpressionView always clean before we set the text? Otherwise, problem if there is no initial text. } + m_editableExpressionViewController.editableExpressionView()->handleEvent(event); } -void InputViewController::abortTextFieldEditionAndDismiss() { - m_textFieldController.textField()->setEditing(false); +void InputViewController::abortEditionAndDismiss() { + m_editableExpressionViewController.editableExpressionView()->setEditing(false); dismissModalViewController(); } @@ -92,15 +50,11 @@ bool InputViewController::textFieldShouldFinishEditing(TextField * textField, Io } bool InputViewController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { - m_successAction.perform(this); - dismissModalViewController(); - return true; + return inputViewDidFinishEditing(); } bool InputViewController::textFieldDidAbortEditing(TextField * textField, const char * text) { - m_failureAction.perform(this); - dismissModalViewController(); - return true; + return inputViewDidAbortEditing(); } bool InputViewController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) { @@ -110,3 +64,44 @@ bool InputViewController::textFieldDidReceiveEvent(TextField * textField, Ion::E Toolbox * InputViewController::toolboxForTextField(TextField * textField) { return m_textFieldDelegate->toolboxForTextField(textField); } +bool InputViewController::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { + return event == Ion::Events::OK || event == Ion::Events::EXE; +} + +bool InputViewController::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { + return m_scrollableExpressionViewWithCursorDelegate->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event); +} + +bool InputViewController::scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) { + return inputViewDidFinishEditing(); +} + +bool InputViewController::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) { + return inputViewDidAbortEditing(); +} + +void InputViewController::scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + // Reload the view only if the EditableExpressionView height actually changes, + // i.e. not if the height is already maximal and stays maximal. + bool newInputViewHeightIsMaximal = m_editableExpressionViewController.editableExpressionView()->heightIsMaximal(); + if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) { + m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal; + reloadView(); + } +} + +Toolbox * InputViewController::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + return m_scrollableExpressionViewWithCursorDelegate->toolboxForScrollableExpressionViewWithCursor(scrollableExpressionViewWithCursor); +} + +bool InputViewController::inputViewDidFinishEditing() { + m_successAction.perform(this); + dismissModalViewController(); + return true; +} + +bool InputViewController::inputViewDidAbortEditing() { + m_failureAction.perform(this); + dismissModalViewController(); + return true; +} diff --git a/escher/src/modal_view_controller.cpp b/escher/src/modal_view_controller.cpp index 5780b448f..1f7aaed18 100644 --- a/escher/src/modal_view_controller.cpp +++ b/escher/src/modal_view_controller.cpp @@ -95,6 +95,11 @@ bool ModalViewController::ContentView::isDisplayingModal() const { return m_isDisplayingModal; } +void ModalViewController::ContentView::reload() { + markRectAsDirty(frame()); + layoutSubviews(); +} + ModalViewController::ModalViewController(Responder * parentResponder, ViewController * child) : ViewController(parentResponder), m_contentView(), @@ -162,3 +167,7 @@ void ModalViewController::viewDidDisappear() { } m_regularViewController->viewDidDisappear(); } + +void ModalViewController::reloadView() { + m_contentView.reload(); +} diff --git a/escher/src/scrollable_expression_view_with_cursor.cpp b/escher/src/scrollable_expression_view_with_cursor.cpp new file mode 100644 index 000000000..4ce4d5c6a --- /dev/null +++ b/escher/src/scrollable_expression_view_with_cursor.cpp @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include + +ScrollableExpressionViewWithCursor::ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ScrollableExpressionViewWithCursorDelegate * delegate) : + ScrollableView(parentResponder, &m_expressionViewWithCursor, this), + m_expressionViewWithCursor(expressionLayout), + m_delegate(delegate) +{ +} + +bool ScrollableExpressionViewWithCursor::isEditing() const { + return m_expressionViewWithCursor.isEditing(); +} + +void ScrollableExpressionViewWithCursor::setEditing(bool isEditing) { + m_expressionViewWithCursor.setEditing(isEditing); +} + +void ScrollableExpressionViewWithCursor::clearLayout() { + delete m_expressionViewWithCursor.expressionView()->expressionLayout(); + Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout(); + m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout); + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout); +} + +void ScrollableExpressionViewWithCursor::scrollToCursor() { + scrollToContentRect(m_expressionViewWithCursor.cursorRect(), true); +} + +Toolbox * ScrollableExpressionViewWithCursor::toolbox() { + if (m_delegate) { + return m_delegate->toolboxForScrollableExpressionViewWithCursor(this); + } + return nullptr; +} + +bool ScrollableExpressionViewWithCursor::handleEvent(Ion::Events::Event event) { + KDSize previousSize = minimalSizeForOptimalDisplay(); + bool shouldRecomputeLayout = false; + if (privateHandleMoveEvent(event, &shouldRecomputeLayout)) { + if (!shouldRecomputeLayout) { + m_expressionViewWithCursor.cursorPositionChanged(); + scrollToCursor(); + return true; + } + reload(); + KDSize newSize = minimalSizeForOptimalDisplay(); + if (m_delegate && previousSize.height() != newSize.height()) { + m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this); + reload(); + } + return true; + } + if (privateHandleEvent(event)) { + reload(); + KDSize newSize = minimalSizeForOptimalDisplay(); + if (m_delegate && previousSize.height() != newSize.height()) { + m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this); + reload(); + } + return true; + } + return false; +} + +bool ScrollableExpressionViewWithCursor::scrollableExpressionViewWithCursorShouldFinishEditing(Ion::Events::Event event) { + return m_delegate->scrollableExpressionViewWithCursorShouldFinishEditing(this, event); +} + +KDSize ScrollableExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { + return m_expressionViewWithCursor.minimalSizeForOptimalDisplay(); +} + +bool ScrollableExpressionViewWithCursor::privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) { + if (event == Ion::Events::Left) { + return m_expressionViewWithCursor.cursor()->moveLeft(shouldRecomputeLayout); + } + if (event == Ion::Events::Right) { + return m_expressionViewWithCursor.cursor()->moveRight(shouldRecomputeLayout); + } + if (event == Ion::Events::Up) { + return m_expressionViewWithCursor.cursor()->moveUp(shouldRecomputeLayout); + } + if (event == Ion::Events::Down) { + return m_expressionViewWithCursor.cursor()->moveDown(shouldRecomputeLayout); + } + if (event == Ion::Events::ShiftLeft) { + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Left); + return true; + } + if (event == Ion::Events::ShiftRight) { + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + return true; + } + return false; +} + +bool ScrollableExpressionViewWithCursor::privateHandleEvent(Ion::Events::Event event) { + if (m_delegate && m_delegate->scrollableExpressionViewWithCursorDidReceiveEvent(this, event)) { + return true; + } + if (Responder::handleEvent(event)) { + /* The only event Responder handles is 'Toolbox' displaying. In that case, + * the ScrollableExpressionViewWithCursor is forced into editing mode. */ + if (!isEditing()) { + setEditing(true); + } + return true; + } + if (isEditing() && scrollableExpressionViewWithCursorShouldFinishEditing(event)) { + setEditing(false); + int bufferSize = TextField::maxBufferSize(); + char buffer[bufferSize]; + m_expressionViewWithCursor.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); + if (m_delegate->scrollableExpressionViewWithCursorDidFinishEditing(this, buffer, event)) { + delete m_expressionViewWithCursor.expressionView()->expressionLayout(); + Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout(); + m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout); + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout); + } + return true; + } + if ((event == Ion::Events::OK || event == Ion::Events::EXE) && !isEditing()) { + setEditing(true); + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + return true; + } + if (event == Ion::Events::Division) { + m_expressionViewWithCursor.cursor()->addFractionLayoutAndCollapseBrothers(); + return true; + } + if (event == Ion::Events::XNT) { + m_expressionViewWithCursor.cursor()->addXNTCharLayout(); + return true; + } + if (event == Ion::Events::Exp) { + m_expressionViewWithCursor.cursor()->addEmptyExponentialLayout(); + return true; + } + if (event == Ion::Events::Power) { + m_expressionViewWithCursor.cursor()->addEmptyPowerLayout(); + return true; + } + if (event == Ion::Events::Sqrt) { + m_expressionViewWithCursor.cursor()->addEmptySquareRootLayout(); + return true; + } + if (event == Ion::Events::Square) { + m_expressionViewWithCursor.cursor()->addEmptySquarePowerLayout(); + return true; + } + if (event.hasText()) { + const char * textToInsert = event.text(); + if (textToInsert[1] == 0) { + if (textToInsert[0] == Ion::Charset::MultiplicationSign) { + const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; + m_expressionViewWithCursor.cursor()->insertText(middleDotString); + return true; + } + if (textToInsert[0] == '[' || textToInsert[0] == ']') { + m_expressionViewWithCursor.cursor()->addEmptyMatrixLayout(); + return true; + } + } + m_expressionViewWithCursor.cursor()->insertText(textToInsert); + return true; + } + if (event == Ion::Events::Backspace) { + m_expressionViewWithCursor.cursor()->performBackspace(); + return true; + } + if (event == Ion::Events::Paste) { + if (!isEditing()) { + setEditing(true); + } + insertLayoutFromTextAtCursor(Clipboard::sharedClipboard()->storedText()); + return true; + } + return false; +} + +void ScrollableExpressionViewWithCursor::insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout) { + if (layout == nullptr) { + return; + } + KDSize previousSize = minimalSizeForOptimalDisplay(); + m_expressionViewWithCursor.cursor()->addLayout(layout); + if (layout->isMatrix() && pointedLayout->hasAncestor(layout)) { + static_cast(layout)->addGreySquares(); + } + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + reload(); + KDSize newSize = minimalSizeForOptimalDisplay(); + if (m_delegate && previousSize.height() != newSize.height()) { + m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this); + } +} + +void ScrollableExpressionViewWithCursor::insertLayoutFromTextAtCursor(const char * text) { + Poincare::Expression * expression = Poincare::Expression::parse(text); + if (expression != nullptr) { + Poincare::ExpressionLayout * layout = expression->createLayout(); + delete expression; + insertLayoutAtCursor(layout, layout); + reload(); + return; + } + m_expressionViewWithCursor.cursor()->insertText(text); + reload(); +} + +void ScrollableExpressionViewWithCursor::reload() { + m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); + m_expressionViewWithCursor.cursorPositionChanged(); + layoutSubviews(); + scrollToCursor(); + markRectAsDirty(bounds()); +} diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 38ef59c82..e97f4e73d 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -94,6 +94,7 @@ public: virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0; /* Other */ + bool hasText() const; virtual bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { return true; } /* isCollapsable is used when adding a brother fraction: should the layout be * inserted in the numerator (or denominator)? For instance, 1+2|3-4 should diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 9faf5b7e0..1b22d51b7 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -283,6 +283,12 @@ bool ExpressionLayout::moveDownInside(ExpressionLayoutCursor * cursor, bool * sh return moveInside(VerticalDirection::Down, cursor, shouldRecomputeLayout); } +bool ExpressionLayout::hasText() const { + // A layout has text if it is not empty and it is not an horizontal layout + // with no child or with one child with no text. + return !isEmpty() && !(isHorizontal() && (numberOfChildren() == 0 || (numberOfChildren() == 1 && !child(0)->hasText()))); +} + bool ExpressionLayout::canBeOmittedMultiplicationLeftFactor() const { // WARNING: canBeOmittedMultiplicationLeftFactor is true when and only when // isCollapsable is true too. If isCollapsable changes, it might not be the From a2c0eaa20ba439d60d16b8f7516c2249d1a8993f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 23 Jan 2018 09:53:17 +0100 Subject: [PATCH 215/257] [apps/escher] Remove textFieldDidAbortEditing const char * argument. Also removed the same argument in scrollableExpressionViewWithCursorDidAbortEditing. Change-Id: Iadc6b708cfc0fab44b9fd4edb980cb759d41e8d0 --- apps/calculation/edit_expression_controller.cpp | 14 ++++++++------ apps/calculation/edit_expression_controller.h | 4 ++-- apps/code/console_controller.cpp | 2 +- apps/code/console_controller.h | 2 +- apps/code/menu_controller.cpp | 4 ++-- apps/code/menu_controller.h | 2 +- ...llable_expression_view_with_cursor_delegate.cpp | 4 ++-- ...rollable_expression_view_with_cursor_delegate.h | 2 +- escher/include/escher/input_view_controller.h | 4 ++-- ...rollable_expression_view_with_cursor_delegate.h | 2 +- escher/include/escher/text_field_delegate.h | 2 +- escher/src/input_view_controller.cpp | 4 ++-- escher/src/text_field.cpp | 2 +- 13 files changed, 25 insertions(+), 23 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 45d9c2474..68667378e 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -84,9 +84,9 @@ bool EditExpressionController::textFieldDidFinishEditing(::TextField * textField return inputViewDidFinishEditing(text, event); } -bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField, const char * text) { +bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField) { assert(textField == ((ContentView *)view())->editableExpressionView()->textField()); - return inputViewDidAbortEditing(text); + return inputViewDidAbortEditing(textField->text()); } bool EditExpressionController::scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) { @@ -102,9 +102,9 @@ bool EditExpressionController::scrollableExpressionViewWithCursorDidFinishEditin return inputViewDidFinishEditing(text, event); } -bool EditExpressionController::scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) { +bool EditExpressionController::scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor()); - return inputViewDidAbortEditing(text); + return inputViewDidAbortEditing(nullptr); } void EditExpressionController::scrollableExpressionViewWithCursorDidChangeSize(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { @@ -157,8 +157,10 @@ bool EditExpressionController::inputViewDidFinishEditing(const char * text, Ion: } bool EditExpressionController::inputViewDidAbortEditing(const char * text) { - ((ContentView *)view())->editableExpressionView()->setEditing(true, true); - ((ContentView *)view())->editableExpressionView()->setText(text); + if (text != nullptr) { + ((ContentView *)view())->editableExpressionView()->setEditing(true, true); + ((ContentView *)view())->editableExpressionView()->setText(text); + } return false; } diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h index a2b64b951..864b53aba 100644 --- a/apps/calculation/edit_expression_controller.h +++ b/apps/calculation/edit_expression_controller.h @@ -24,12 +24,12 @@ public: /* TextFieldDelegate */ bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override; bool textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) override; - bool textFieldDidAbortEditing(::TextField * textField, const char * text) override; + bool textFieldDidAbortEditing(::TextField * textField) override; /* ScrollableExpressionViewWithCursorDelegate */ bool scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; bool scrollableExpressionViewWithCursorDidFinishEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override; - bool scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) override; + bool scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; void scrollableExpressionViewWithCursorDidChangeSize(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; private: diff --git a/apps/code/console_controller.cpp b/apps/code/console_controller.cpp index eba0b1396..8d12b0e0c 100644 --- a/apps/code/console_controller.cpp +++ b/apps/code/console_controller.cpp @@ -252,7 +252,7 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c return true; } -bool ConsoleController::textFieldDidAbortEditing(TextField * textField, const char * text) { +bool ConsoleController::textFieldDidAbortEditing(TextField * textField) { stackViewController()->pop(); return true; } diff --git a/apps/code/console_controller.h b/apps/code/console_controller.h index 1037ca76e..78d3a4705 100644 --- a/apps/code/console_controller.h +++ b/apps/code/console_controller.h @@ -56,7 +56,7 @@ public: bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; - bool textFieldDidAbortEditing(TextField * textField, const char * text) override; + bool textFieldDidAbortEditing(TextField * textField) override; Toolbox * toolboxForTextField(TextField * textField) override; // MicroPython::ExecutionEnvironment diff --git a/apps/code/menu_controller.cpp b/apps/code/menu_controller.cpp index 5c3444d19..c65fd7657 100644 --- a/apps/code/menu_controller.cpp +++ b/apps/code/menu_controller.cpp @@ -307,8 +307,8 @@ bool MenuController::textFieldDidFinishEditing(TextField * textField, const char return false; } -bool MenuController::textFieldDidAbortEditing(TextField * textField, const char * text) { - if (strlen(text) <= strlen(ScriptStore::k_scriptExtension)) { +bool MenuController::textFieldDidAbortEditing(TextField * textField) { + if (strlen(textField->text()) <= strlen(ScriptStore::k_scriptExtension)) { // The previous text was an empty name. Use a numbered default script name. char numberedDefaultName[k_defaultScriptNameMaxSize]; numberedDefaultScriptName(numberedDefaultName); diff --git a/apps/code/menu_controller.h b/apps/code/menu_controller.h index af4441f80..89c5c6f4f 100644 --- a/apps/code/menu_controller.h +++ b/apps/code/menu_controller.h @@ -52,7 +52,7 @@ public: bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; - bool textFieldDidAbortEditing(TextField * textField, const char * text) override; + bool textFieldDidAbortEditing(TextField * textField) override; bool textFieldDidHandleEvent(TextField * textField, Ion::Events::Event event, bool returnValue, bool textHasChanged) override; Toolbox * toolboxForTextField(TextField * textField) override { return nullptr; } diff --git a/apps/shared/scrollable_expression_view_with_cursor_delegate.cpp b/apps/shared/scrollable_expression_view_with_cursor_delegate.cpp index 5174721ff..84a29933c 100644 --- a/apps/shared/scrollable_expression_view_with_cursor_delegate.cpp +++ b/apps/shared/scrollable_expression_view_with_cursor_delegate.cpp @@ -16,8 +16,8 @@ bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCur return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidFinishEditing(scrollableExpressionViewWithCursor, text, event); } -bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) { - return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidAbortEditing(scrollableExpressionViewWithCursor, text); +bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidAbortEditing(scrollableExpressionViewWithCursor); } void ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { diff --git a/apps/shared/scrollable_expression_view_with_cursor_delegate.h b/apps/shared/scrollable_expression_view_with_cursor_delegate.h index 589f6a8db..093cecf71 100644 --- a/apps/shared/scrollable_expression_view_with_cursor_delegate.h +++ b/apps/shared/scrollable_expression_view_with_cursor_delegate.h @@ -11,7 +11,7 @@ public: bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override; - bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) override; + bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; private: diff --git a/escher/include/escher/input_view_controller.h b/escher/include/escher/input_view_controller.h index a2f037758..090b6bce1 100644 --- a/escher/include/escher/input_view_controller.h +++ b/escher/include/escher/input_view_controller.h @@ -19,14 +19,14 @@ public: bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; - bool textFieldDidAbortEditing(TextField * textField, const char * text) override; + bool textFieldDidAbortEditing(TextField * textField) override; Toolbox * toolboxForTextField(TextField * textFied) override; /* ScrollableExpressionViewWithCursorDelegate */ bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override; bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override; - bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) override; + bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; diff --git a/escher/include/escher/scrollable_expression_view_with_cursor_delegate.h b/escher/include/escher/scrollable_expression_view_with_cursor_delegate.h index 56b22b337..c2bf5fe96 100644 --- a/escher/include/escher/scrollable_expression_view_with_cursor_delegate.h +++ b/escher/include/escher/scrollable_expression_view_with_cursor_delegate.h @@ -11,7 +11,7 @@ public: virtual bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) = 0; virtual bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) = 0; virtual bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) { return false; } - virtual bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) { return false; } + virtual bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { return false; } virtual void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {} virtual Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) = 0; }; diff --git a/escher/include/escher/text_field_delegate.h b/escher/include/escher/text_field_delegate.h index ad2300e93..349555402 100644 --- a/escher/include/escher/text_field_delegate.h +++ b/escher/include/escher/text_field_delegate.h @@ -8,7 +8,7 @@ public: virtual bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) = 0; virtual bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) = 0; virtual bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { return false; }; - virtual bool textFieldDidAbortEditing(TextField * textField, const char * text) {return false;}; + virtual bool textFieldDidAbortEditing(TextField * textField) {return false;}; virtual bool textFieldDidHandleEvent(TextField * textField, Ion::Events::Event event, bool returnValue, bool textHasChanged) { return returnValue; }; virtual Toolbox * toolboxForTextField(TextField * textField) = 0; }; diff --git a/escher/src/input_view_controller.cpp b/escher/src/input_view_controller.cpp index fb89c3d62..ac5fa9956 100644 --- a/escher/src/input_view_controller.cpp +++ b/escher/src/input_view_controller.cpp @@ -53,7 +53,7 @@ bool InputViewController::textFieldDidFinishEditing(TextField * textField, const return inputViewDidFinishEditing(); } -bool InputViewController::textFieldDidAbortEditing(TextField * textField, const char * text) { +bool InputViewController::textFieldDidAbortEditing(TextField * textField) { return inputViewDidAbortEditing(); } @@ -76,7 +76,7 @@ bool InputViewController::scrollableExpressionViewWithCursorDidFinishEditing(Scr return inputViewDidFinishEditing(); } -bool InputViewController::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text) { +bool InputViewController::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { return inputViewDidAbortEditing(); } diff --git a/escher/src/text_field.cpp b/escher/src/text_field.cpp index f448fbf11..62abe0330 100644 --- a/escher/src/text_field.cpp +++ b/escher/src/text_field.cpp @@ -361,7 +361,7 @@ bool TextField::privateHandleEvent(Ion::Events::Event event) { if (event == Ion::Events::Back && isEditing()) { setEditing(false); reloadScroll(); - m_delegate->textFieldDidAbortEditing(this, text()); + m_delegate->textFieldDidAbortEditing(this); return true; } if (event == Ion::Events::Clear && isEditing()) { From bea0d208c193e98c5ea79af4c8c24651da921fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 23 Jan 2018 09:57:30 +0100 Subject: [PATCH 216/257] [escher] ScrollableExpressionViewWithCursor handles Back event. Change-Id: I8d98040e34740b48ee8285e5356ea94cd48f2e98 --- escher/src/scrollable_expression_view_with_cursor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/escher/src/scrollable_expression_view_with_cursor.cpp b/escher/src/scrollable_expression_view_with_cursor.cpp index 4ce4d5c6a..7a14de953 100644 --- a/escher/src/scrollable_expression_view_with_cursor.cpp +++ b/escher/src/scrollable_expression_view_with_cursor.cpp @@ -131,6 +131,11 @@ bool ScrollableExpressionViewWithCursor::privateHandleEvent(Ion::Events::Event e m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); return true; } + if (event == Ion::Events::Back && isEditing()) { + setEditing(false); + m_delegate->scrollableExpressionViewWithCursorDidAbortEditing(this); + return true; + } if (event == Ion::Events::Division) { m_expressionViewWithCursor.cursor()->addFractionLayoutAndCollapseBrothers(); return true; From 2929409d3e931e03b58f83f36bfd93075f583544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 23 Jan 2018 10:24:38 +0100 Subject: [PATCH 217/257] [escher] Comment about implementing a split view for InputViewController Change-Id: I46b50bac50f958fad956696a02d334a690b0a2b2 --- escher/include/escher/input_view_controller.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/escher/include/escher/input_view_controller.h b/escher/include/escher/input_view_controller.h index 090b6bce1..f8bc02bd5 100644 --- a/escher/include/escher/input_view_controller.h +++ b/escher/include/escher/input_view_controller.h @@ -8,6 +8,9 @@ #include #include +/* TODO Implement a split view. Because we use a modal view, the main view is + * redrawn underneath the modal view, which is visible and ugly. */ + class InputViewController : public ModalViewController, TextFieldDelegate, ScrollableExpressionViewWithCursorDelegate { public: InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate); From 71263285c5d7bcc8f3afbb1393462552a50bfe4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 23 Jan 2018 16:57:16 +0100 Subject: [PATCH 218/257] [poincare] Fixed serialization bug of empty Horizontal layouts. Change-Id: I6a71eb34ae1f734ed86590cadaf086e1c3a1bd44 --- poincare/src/layout/horizontal_layout.cpp | 11 +++++++++++ poincare/src/layout/horizontal_layout.h | 4 +--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index baf038e23..d41889f05 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -289,6 +289,17 @@ void HorizontalLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { DynamicLayoutHierarchy::removeChildAtIndex(index, deleteAfterRemoval); } +int HorizontalLayout::writeTextInBuffer(char * buffer, int bufferSize) const { + if (numberOfChildren() == 0) { + if (bufferSize == 0) { + return -1; + } + buffer[0] = 0; + return 0; + } + return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); +} + bool HorizontalLayout::isEmpty() const { if (m_numberOfChildren == 1 && child(0)->isEmpty()) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index f6185545f..39b38d82d 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -31,9 +31,7 @@ public: void removeChildAtIndex(int index, bool deleteAfterRemoval) override; /* Expression Engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); - } + int writeTextInBuffer(char * buffer, int bufferSize) const override; /* Other */ bool isHorizontal() const override { return true; } From b3c5b93d2169b71a885c9c6fcb10f730effb012a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 23 Jan 2018 17:13:58 +0100 Subject: [PATCH 219/257] [escher] Fix invalid pointer access. A layout might be deleted after calling addLayout: for instance, if the layout is horizontal and added as a child to another horizontal layout, its children are stolen and it is deleted. Change-Id: Icc2c344dd7878d7df2ec72f014a98dd0d27dc258 --- escher/src/scrollable_expression_view_with_cursor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/scrollable_expression_view_with_cursor.cpp b/escher/src/scrollable_expression_view_with_cursor.cpp index 7a14de953..3f1f11a4f 100644 --- a/escher/src/scrollable_expression_view_with_cursor.cpp +++ b/escher/src/scrollable_expression_view_with_cursor.cpp @@ -195,10 +195,10 @@ void ScrollableExpressionViewWithCursor::insertLayoutAtCursor(Poincare::Expressi return; } KDSize previousSize = minimalSizeForOptimalDisplay(); - m_expressionViewWithCursor.cursor()->addLayout(layout); if (layout->isMatrix() && pointedLayout->hasAncestor(layout)) { static_cast(layout)->addGreySquares(); } + m_expressionViewWithCursor.cursor()->addLayout(layout); m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); reload(); From b9a7973961c955ce21422546a63e44c0619fa9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 24 Jan 2018 10:15:16 +0100 Subject: [PATCH 220/257] [escher/poincare] Move the cursor when inserting a layout (if wanted). The new pointed layout can be specified. If not, the cursor will be on the right of the new layout. Change-Id: I5e0c37cf6365447f8eaf354dc5e86a24c6981034 --- apps/math_toolbox.cpp | 6 +- ...scrollable_expression_view_with_cursor.cpp | 12 ++-- poincare/include/poincare/expression_layout.h | 4 +- .../poincare/expression_layout_cursor.h | 1 + poincare/src/expression_layout_cursor.cpp | 4 ++ poincare/src/layout/empty_visible_layout.cpp | 26 ++++---- poincare/src/layout/empty_visible_layout.h | 2 +- poincare/src/layout/expression_layout.cpp | 65 ++++++++++--------- poincare/src/layout/horizontal_layout.cpp | 25 +++++++ poincare/src/layout/horizontal_layout.h | 1 + 10 files changed, 98 insertions(+), 48 deletions(-) diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 63639f81f..d42924e17 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -133,9 +133,10 @@ void MathToolbox::actionForScrollableExpressionViewWithCursor(void * sender, con } ExpressionLayout * resultLayout = resultExpression->createLayout(); // Find the pointed layout. - ExpressionLayout * pointedLayout = resultLayout; + ExpressionLayout * pointedLayout = nullptr; if (resultLayout->isHorizontal()) { // If the layout is horizontal, pick the first open parenthesis. + // For now, all horizontal layouts in MathToolbox have parentheses. for (int i = 0; i < resultLayout->numberOfChildren(); i++) { if (resultLayout->editableChild(i)->isLeftParenthesis()) { pointedLayout = resultLayout->editableChild(i); @@ -146,7 +147,8 @@ void MathToolbox::actionForScrollableExpressionViewWithCursor(void * sender, con // Else, if the layout has children, pick the first one. pointedLayout = resultLayout->editableChild(0); } - // Insert the layout + // Insert the layout. If pointedLayout is nullptr, the cursor will be on the + // right of the inserted layout. expressionLayoutEditorSender->insertLayoutAtCursor(resultLayout, pointedLayout); } diff --git a/escher/src/scrollable_expression_view_with_cursor.cpp b/escher/src/scrollable_expression_view_with_cursor.cpp index 3f1f11a4f..89eb1d303 100644 --- a/escher/src/scrollable_expression_view_with_cursor.cpp +++ b/escher/src/scrollable_expression_view_with_cursor.cpp @@ -198,9 +198,13 @@ void ScrollableExpressionViewWithCursor::insertLayoutAtCursor(Poincare::Expressi if (layout->isMatrix() && pointedLayout->hasAncestor(layout)) { static_cast(layout)->addGreySquares(); } - m_expressionViewWithCursor.cursor()->addLayout(layout); - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + if (pointedLayout != nullptr) { + m_expressionViewWithCursor.cursor()->addLayout(layout); + m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); + m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + } else { + m_expressionViewWithCursor.cursor()->addLayoutAndMoveCursor(layout); + } reload(); KDSize newSize = minimalSizeForOptimalDisplay(); if (m_delegate && previousSize.height() != newSize.height()) { @@ -213,7 +217,7 @@ void ScrollableExpressionViewWithCursor::insertLayoutFromTextAtCursor(const char if (expression != nullptr) { Poincare::ExpressionLayout * layout = expression->createLayout(); delete expression; - insertLayoutAtCursor(layout, layout); + insertLayoutAtCursor(layout, nullptr); reload(); return; } diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index e97f4e73d..60bfeea85 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -50,7 +50,8 @@ public: // Add virtual bool addChildAtIndex(ExpressionLayout * child, int index) { return false; } - virtual void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); + void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); + void addBrotherAndMoveCursor(ExpressionLayoutCursor * cursor, ExpressionLayout * brother); // Replace virtual ExpressionLayout * replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace); @@ -129,6 +130,7 @@ protected: ExpressionLayout ** childResult, void * resultPosition, int * resultScore); + virtual void privateAddBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother, bool moveCursor); ExpressionLayout * m_parent; KDCoordinate m_baseline; /* m_baseline is the signed vertical distance from the top of the layout to diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 7145d3c81..7657d5e18 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -40,6 +40,7 @@ public: /* Edition */ void addLayout(ExpressionLayout * layout); + void addLayoutAndMoveCursor(ExpressionLayout * layout); void addEmptyExponentialLayout(); void addFractionLayoutAndCollapseBrothers(); void addEmptyMatrixLayout(int numberOfRows = 1, int numberOfColumns = 1); diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 0923f888e..947dfedf9 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -45,6 +45,10 @@ void ExpressionLayoutCursor::addLayout(ExpressionLayout * layout) { pointedExpressionLayout()->addBrother(this, layout); } +void ExpressionLayoutCursor::addLayoutAndMoveCursor(ExpressionLayout * layout) { + pointedExpressionLayout()->addBrotherAndMoveCursor(this, layout); +} + void ExpressionLayoutCursor::addEmptyExponentialLayout() { CharLayout * child1 = new CharLayout(Ion::Charset::Exponential); VerticalOffsetLayout * offsetLayout = new VerticalOffsetLayout(new EmptyVisibleLayout(), VerticalOffsetLayout::Type::Superscript, false); diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index 5e8517611..244b8d48a 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -17,17 +17,6 @@ ExpressionLayout * EmptyVisibleLayout::clone() const { return layout; } -void EmptyVisibleLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { - Color currentColor = m_color; - int indexInParent = m_parent->indexOfChild(this); - ExpressionLayout * parent = m_parent; - replaceWith(brother, true); - if (currentColor == Color::Grey) { - // The parent is a MatrixLayout. - static_cast(parent)->newRowOrColumnAtIndex(indexInParent); - } -} - void EmptyVisibleLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { assert(cursor->pointedExpressionLayout() == this); if (cursor->position() == ExpressionLayoutCursor::Position::Right) { @@ -95,4 +84,19 @@ void EmptyVisibleLayout::computeBaseline() { m_baselined = true; } +void EmptyVisibleLayout::privateAddBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother, bool moveCursor) { + Color currentColor = m_color; + int indexInParent = m_parent->indexOfChild(this); + ExpressionLayout * parent = m_parent; + replaceWith(brother, true); + if (moveCursor) { + cursor->setPointedExpressionLayout(brother); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } + if (currentColor == Color::Grey) { + // The parent is a MatrixLayout. + static_cast(parent)->newRowOrColumnAtIndex(indexInParent); + } +} + } diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index 0bab3e9ff..8731a3f55 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -14,7 +14,6 @@ public: }; EmptyVisibleLayout(Color color = Color::Yellow); ExpressionLayout * clone() const override; - void addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; @@ -30,6 +29,7 @@ protected: assert(false); return KDPointZero; } + void privateAddBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother, bool moveCursor) override; private: constexpr static KDCoordinate k_width = 7; constexpr static KDCoordinate k_height = 13; diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 1b22d51b7..958edf102 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -107,36 +107,11 @@ bool ExpressionLayout::hasAncestor(const ExpressionLayout * e) const { } void ExpressionLayout::addBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { - // First, assess the special case when the layout is horizontal. - // If so, add the "brother" as a child. - if (isHorizontal()) { - // If there is only one empty child, remove it before adding the layout. - if (numberOfChildren() == 1 && editableChild(0)->isEmpty()) { - removeChildAtIndex(0, true); - } - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - addChildAtIndex(brother, 0); - return; - } - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - addChildAtIndex(brother, numberOfChildren()); - return; - } + privateAddBrother(cursor, brother, false); +} - // If the layout is not horizontal, it must have a parent. - assert(m_parent); - int brotherIndex = cursor->position() == ExpressionLayoutCursor::Position::Left ? m_parent->indexOfChild(this) : m_parent->indexOfChild(this) + 1; - if (m_parent->isHorizontal()) { - static_cast(m_parent)->addOrMergeChildAtIndex(brother, brotherIndex, true); - return; - } - if (cursor->position() == ExpressionLayoutCursor::Position::Left) { - replaceWithJuxtapositionOf(brother, this, false); - return; - } - assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - replaceWithJuxtapositionOf(this, brother, false); - return; +void ExpressionLayout::addBrotherAndMoveCursor(ExpressionLayoutCursor * cursor, ExpressionLayout * brother) { + privateAddBrother(cursor, brother, true); } ExpressionLayout * ExpressionLayout::replaceWith(ExpressionLayout * newChild, bool deleteAfterReplace) { @@ -374,8 +349,40 @@ void ExpressionLayout::moveCursorInsideAtDirection ( } } +void ExpressionLayout::privateAddBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother, bool moveCursor) { + // The layout must have a parent, because HorizontalLayout overrides + // privateAddBrother and only an HorizontalLayout can be the root layout. + assert(m_parent); + if (m_parent->isHorizontal()) { + int brotherIndex = cursor->position() == ExpressionLayoutCursor::Position::Left ? m_parent->indexOfChild(this) : m_parent->indexOfChild(this) + 1; + if (moveCursor) { + if (brotherIndex < m_parent->numberOfChildren()) { + cursor->setPointedExpressionLayout(m_parent->editableChild(brotherIndex)); + cursor->setPosition(ExpressionLayoutCursor::Position::Left); + } else { + cursor->setPointedExpressionLayout(m_parent); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } + } + static_cast(m_parent)->addOrMergeChildAtIndex(brother, brotherIndex, true); + return; + } + ExpressionLayout * juxtapositionLayout = nullptr; + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + juxtapositionLayout = replaceWithJuxtapositionOf(brother, this, false); + } else { + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + juxtapositionLayout = replaceWithJuxtapositionOf(this, brother, false); + } + if (moveCursor) { + cursor->setPointedExpressionLayout(juxtapositionLayout); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } +} + ExpressionLayout * ExpressionLayout::replaceWithJuxtapositionOf(ExpressionLayout * leftChild, ExpressionLayout * rightChild, bool deleteAfterReplace) { assert(m_parent != nullptr); + assert(!m_parent->isHorizontal()); /* One of the children to juxtapose might be "this", so we first have to * replace "this" with an horizontal layout, then add "this" to the layout. */ ExpressionLayout * layout = new HorizontalLayout(); diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index d41889f05..815161b80 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -352,6 +352,31 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { return KDPoint(x, y); } +void HorizontalLayout::privateAddBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother, bool moveCursor) { + // Add the "brother" as a child. + // If there is only one empty child, remove it before adding the layout. + if (numberOfChildren() == 1 && editableChild(0)->isEmpty()) { + removeChildAtIndex(0, true); + } + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + if (moveCursor) { + if (numberOfChildren() > 0) { + cursor->setPointedExpressionLayout(editableChild(0)); + } else { + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + } + } + addChildAtIndex(brother, 0); + return; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + addChildAtIndex(brother, numberOfChildren()); + if (moveCursor) { + cursor->setPointedExpressionLayout(this); + } +} + bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) { // Prevent looping fom child to parent if (previousPreviousLayout == this) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 39b38d82d..a0d7bdfaa 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -42,6 +42,7 @@ protected: KDSize computeSize() override; void computeBaseline() override; KDPoint positionOfChild(ExpressionLayout * child) override; + void privateAddBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother, bool moveCursor) override; private: bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); void privateReplaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor); From f38bbff447e33e38d346abe63d2c0dfe2d383d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 24 Jan 2018 10:20:09 +0100 Subject: [PATCH 221/257] [escher] Fix responder order bug. EditableExpressionView cannot pass the first responder state to one of its children, otherwise Calculation::EditableExpressionView's overriden handleEvent method is never called. Change-Id: Id2b56b9501e67431e860573cf4c62a16651c3958 --- escher/include/escher/editable_expression_view.h | 1 - escher/src/editable_expression_view.cpp | 8 -------- 2 files changed, 9 deletions(-) diff --git a/escher/include/escher/editable_expression_view.h b/escher/include/escher/editable_expression_view.h index d0c6e88b8..44d5f867e 100644 --- a/escher/include/escher/editable_expression_view.h +++ b/escher/include/escher/editable_expression_view.h @@ -30,7 +30,6 @@ public: KDSize minimalSizeForOptimalDisplay() const override; /* Responder */ - void didBecomeFirstResponder() override; bool handleEvent(Ion::Events::Event event) override; static constexpr int k_bufferLength = TextField::maxBufferSize(); diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index 359d129cf..cc557b04e 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -88,14 +88,6 @@ void EditableExpressionView::drawRect(KDContext * ctx, KDRect rect) const { } } -void EditableExpressionView::didBecomeFirstResponder() { - if (editionIsInTextField()) { - app()->setFirstResponder(&m_textField); - return; - } - app()->setFirstResponder(&m_scrollableExpressionViewWithCursor); -} - bool EditableExpressionView::handleEvent(Ion::Events::Event event) { return editionIsInTextField() ? m_textField.handleEvent(event) : m_scrollableExpressionViewWithCursor.handleEvent(event); } From 4b79175fa8eb5c5f5848df405f69b6d144324a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 25 Jan 2018 17:29:00 +0100 Subject: [PATCH 222/257] [escher] Handle Clear event in ScrollableExpressionViewWithCursor. Change-Id: I8a71a3f866420cd62514a7431f89a468580ff4eb --- escher/src/scrollable_expression_view_with_cursor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/escher/src/scrollable_expression_view_with_cursor.cpp b/escher/src/scrollable_expression_view_with_cursor.cpp index 89eb1d303..fd0f07a1b 100644 --- a/escher/src/scrollable_expression_view_with_cursor.cpp +++ b/escher/src/scrollable_expression_view_with_cursor.cpp @@ -187,6 +187,10 @@ bool ScrollableExpressionViewWithCursor::privateHandleEvent(Ion::Events::Event e insertLayoutFromTextAtCursor(Clipboard::sharedClipboard()->storedText()); return true; } + if (event == Ion::Events::Clear && isEditing()) { + clearLayout(); + return true; + } return false; } From 093131302cf38bace834adaf075365515818a743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 11:00:06 +0100 Subject: [PATCH 223/257] [expression_editor] Delete this app. Change-Id: I4c010ce1948f4c04dff526218d6d85a6d34d109e --- apps/expression_editor/Makefile | 23 --- apps/expression_editor/app.cpp | 29 --- apps/expression_editor/app.h | 38 ---- apps/expression_editor/base.universal.i18n | 2 - apps/expression_editor/controller.cpp | 191 ------------------ apps/expression_editor/controller.h | 45 ----- .../expression_and_layout.cpp | 54 ----- .../expression_editor/expression_and_layout.h | 26 --- .../expression_editor_view.cpp | 55 ----- .../expression_editor_view.h | 30 --- .../expression_view_with_cursor.cpp | 49 ----- .../expression_view_with_cursor.h | 35 ---- ...scrollable_expression_view_with_cursor.cpp | 21 -- .../scrollable_expression_view_with_cursor.h | 25 --- apps/expression_editor/test/dummy_test.cpp | 6 - apps/math_toolbox.h | 1 - 16 files changed, 630 deletions(-) delete mode 100644 apps/expression_editor/Makefile delete mode 100644 apps/expression_editor/app.cpp delete mode 100644 apps/expression_editor/app.h delete mode 100644 apps/expression_editor/base.universal.i18n delete mode 100644 apps/expression_editor/controller.cpp delete mode 100644 apps/expression_editor/controller.h delete mode 100644 apps/expression_editor/expression_and_layout.cpp delete mode 100644 apps/expression_editor/expression_and_layout.h delete mode 100644 apps/expression_editor/expression_editor_view.cpp delete mode 100644 apps/expression_editor/expression_editor_view.h delete mode 100644 apps/expression_editor/expression_view_with_cursor.cpp delete mode 100644 apps/expression_editor/expression_view_with_cursor.h delete mode 100644 apps/expression_editor/scrollable_expression_view_with_cursor.cpp delete mode 100644 apps/expression_editor/scrollable_expression_view_with_cursor.h delete mode 100644 apps/expression_editor/test/dummy_test.cpp diff --git a/apps/expression_editor/Makefile b/apps/expression_editor/Makefile deleted file mode 100644 index 137280e8a..000000000 --- a/apps/expression_editor/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -snapshots += ExpressionEditor::App::Snapshot -snapshot_headers += apps/expression_editor/app.h - -app_objs += $(addprefix apps/expression_editor/,\ - app.o\ - controller.o\ - expression_and_layout.o\ - expression_editor_view.o\ - expression_view_with_cursor.o\ - scrollable_expression_view_with_cursor.o\ -) - -i18n_files += $(addprefix apps/expression_editor/,\ - base.universal.i18n\ -) - -tests += $(addprefix apps/expression_editor/test/,\ - dummy_test.cpp\ -) - -test_objs += $(addprefix apps/expression_editor/,\ - expression_view_with_cursor.o\ -) diff --git a/apps/expression_editor/app.cpp b/apps/expression_editor/app.cpp deleted file mode 100644 index 5ef392b9c..000000000 --- a/apps/expression_editor/app.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "app.h" -#include "../i18n.h" - -namespace ExpressionEditor { - -I18n::Message App::Descriptor::name() { - return I18n::Message::ExpressionEditorApp; -} - -I18n::Message App::Descriptor::upperName() { - return I18n::Message::ExpressionEditorAppCapital; -} - -App * App::Snapshot::unpack(Container * container) { - return new App(container, this); -} - -App::Descriptor * App::Snapshot::descriptor() { - static Descriptor descriptor; - return &descriptor; -} - -App::App(Container * container, Snapshot * snapshot) : - ::App(container, snapshot, &m_controller), - m_controller(&m_modalViewController, snapshot->expressionAndLayout()->expressionLayout()) -{ -} - -} diff --git a/apps/expression_editor/app.h b/apps/expression_editor/app.h deleted file mode 100644 index 84b537833..000000000 --- a/apps/expression_editor/app.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef EXPRESSION_EDITOR_APP_H -#define EXPRESSION_EDITOR_APP_H - -#include -#include -#include "controller.h" -#include "expression_and_layout.h" - -namespace ExpressionEditor { - -/* TODO This app is used for creating ExpressionLayout edition. It should be - * removed when the development is finished. */ - -class App : public ::App { -public: - class Descriptor : public ::App::Descriptor { - public: - I18n::Message name() override; - I18n::Message upperName() override; - }; - class Snapshot : public ::App::Snapshot, public SelectableTableViewDataSource { - public: - App * unpack(Container * container) override; - Descriptor * descriptor() override; - ExpressionAndLayout * expressionAndLayout() { return &m_expressionAndLayout; } - private: - ExpressionAndLayout m_expressionAndLayout; - }; - MathToolbox * mathToolbox() { return &m_toolbox; } -private: - App(Container * container, Snapshot * snapshot); - Controller m_controller; - MathToolbox m_toolbox; -}; - -} - -#endif diff --git a/apps/expression_editor/base.universal.i18n b/apps/expression_editor/base.universal.i18n deleted file mode 100644 index 01a156f37..000000000 --- a/apps/expression_editor/base.universal.i18n +++ /dev/null @@ -1,2 +0,0 @@ -ExpressionEditorApp = "ExpressionEdit" -ExpressionEditorAppCapital = "EXPRESSION EDITOR" diff --git a/apps/expression_editor/controller.cpp b/apps/expression_editor/controller.cpp deleted file mode 100644 index 69ca7ac66..000000000 --- a/apps/expression_editor/controller.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "controller.h" -#include -#include -#include - -using namespace Poincare; - -namespace ExpressionEditor { - -Controller::Controller(Responder * parentResponder, ExpressionLayout * expressionLayout) : - ViewController(parentResponder), - m_view(parentResponder, expressionLayout, &m_cursor), - m_expressionLayout(expressionLayout), - m_resultLayout(nullptr) -{ - m_cursor.setPointedExpressionLayout(expressionLayout); -} - -void Controller::didBecomeFirstResponder() { - m_view.layoutSubviews(); - /* TODO We need the layout to be done in order to scroll to the cursor. We - * thus made ExpressionViewWithCursor's layoutSubviews() public, which is the - * solution used in ModalViewController for instance. A cleaner solution would - * be to split viewWillAppear into loadViewIfNeeded() and viewWillAppear(), in - * order to change App::didBecomeActive to: - * m_modalViewController.loadViewIfNeeded(); - * window->setContentView(view); - * m_modalViewController.viewWillAppear(); - * The scrolling could then be done in viewWillAppear(), without calling - * layoutSubviews() manually. */ - m_view.scrollableExpressionViewWithCursor()->scrollToCursor(); -} - -bool Controller::handleEvent(Ion::Events::Event event) { - if (event == Ion::Events::EXE) { - serializeLayout(); - computeResult(); - return true; - } - if (privateHandleEvent(event)) { - m_view.cursorPositionChanged(); - return true; - } - return Responder::handleEvent(event); -} - -Toolbox * Controller::toolbox() { - ExpressionEditor::App * expressionEditorApp = static_cast(app()); - return expressionEditorApp->mathToolbox(); -} - -void Controller::insertLayoutAtCursor(ExpressionLayout * layout, ExpressionLayout * pointedLayout) { - if (layout == nullptr) { - return; - } - m_cursor.addLayout(layout); - m_cursor.setPointedExpressionLayout(pointedLayout); - m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); - m_expressionLayout->invalidAllSizesPositionsAndBaselines(); - m_view.cursorPositionChanged(); -} - -bool Controller::privateHandleEvent(Ion::Events::Event event) { - if (handleMoveEvent(event)) { - m_expressionLayout->invalidAllSizesPositionsAndBaselines(); - m_view.layoutSubviews(); - return true; - } - if (handleAddEvent(event)) { - m_expressionLayout->invalidAllSizesPositionsAndBaselines(); - m_view.layoutSubviews(); - return true; - } - if (handleDeleteEvent(event)) { - m_expressionLayout->invalidAllSizesPositionsAndBaselines(); - m_view.layoutSubviews(); - return true; - } - return false; -} - -bool Controller::handleMoveEvent(Ion::Events::Event event) { - if (event == Ion::Events::Left) { - return m_cursor.moveLeft(); - } - if (event == Ion::Events::Right) { - return m_cursor.moveRight(); - } - if (event == Ion::Events::Up) { - return m_cursor.moveUp(); - } - if (event == Ion::Events::Down) { - return m_cursor.moveDown(); - } - if (event == Ion::Events::ShiftLeft) { - // The cursor should never point to the main HorizontalLayout. - m_cursor.setPointedExpressionLayout(m_expressionLayout); - m_cursor.setPosition(ExpressionLayoutCursor::Position::Left); - return true; - } - if (event == Ion::Events::ShiftRight) { - m_cursor.setPointedExpressionLayout(m_expressionLayout); - m_cursor.setPosition(ExpressionLayoutCursor::Position::Right); - return true; - } - return false; -} - -bool Controller::handleAddEvent(Ion::Events::Event event) { - if (event == Ion::Events::Division) { - m_cursor.addFractionLayoutAndCollapseBrothers(); - return true; - } - if (event == Ion::Events::XNT) { - m_cursor.addXNTCharLayout(); - return true; - } - if (event == Ion::Events::Exp) { - m_cursor.addEmptyExponentialLayout(); - return true; - } - if (event == Ion::Events::Log) { - m_cursor.addEmptyLogarithmLayout(); - return true; - } - if (event == Ion::Events::Power) { - m_cursor.addEmptyPowerLayout(); - return true; - } - if (event == Ion::Events::Sqrt) { - m_cursor.addEmptySquareRootLayout(); - return true; - } - if (event == Ion::Events::Square) { - m_cursor.addEmptySquarePowerLayout(); - return true; - } - if (event.hasText()) { - const char * textToInsert = event.text(); - if (textToInsert[1] == 0) { - if (textToInsert[0] == Ion::Charset::MultiplicationSign) { - const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; - m_cursor.insertText(middleDotString); - return true; - } - if (textToInsert[0] == '[' || textToInsert[0] == ']') { - m_cursor.addEmptyMatrixLayout(); - return true; - } - } - m_cursor.insertText(textToInsert); - return true; - } - return false; -} - -bool Controller::handleDeleteEvent(Ion::Events::Event event) { - if (event == Ion::Events::Backspace) { - m_cursor.performBackspace(); - return true; - } - return false; -} - -void Controller::serializeLayout() { - m_expressionLayout->writeTextInBuffer(m_buffer, k_bufferSize); - m_view.setText(const_cast(m_buffer)); -} - -void Controller::computeResult() { - m_expressionLayout->writeTextInBuffer(m_buffer, k_bufferSize); - Expression * result = Expression::parse(m_buffer); - Expression * approxResult = nullptr; - if (result != nullptr) { - Expression::Simplify(&result,*(((AppsContainer *)(app()->container()))->globalContext())); - approxResult = result->approximate(*(((AppsContainer *)(app()->container()))->globalContext())); - delete m_resultLayout; - } else { - approxResult = new Undefined(); - } - m_resultLayout = approxResult->createLayout(); - m_view.setResult(m_resultLayout); - if (result != nullptr) { - delete result; - } - if (approxResult != nullptr) { - delete approxResult; - } -} - -} diff --git a/apps/expression_editor/controller.h b/apps/expression_editor/controller.h deleted file mode 100644 index 546d00680..000000000 --- a/apps/expression_editor/controller.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef EXPRESSION_EDITOR_CONTROLLER_H -#define EXPRESSION_EDITOR_CONTROLLER_H - -#include -#include -#include "expression_and_layout.h" -#include "expression_editor_view.h" -extern "C" { -#include -} - -namespace ExpressionEditor { - -class Controller : public ViewController { -public: - Controller(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout); - View * view() override { return &m_view; } - void didBecomeFirstResponder() override; - bool handleEvent(Ion::Events::Event event) override; - - /* Responder */ - Toolbox * toolbox() override; - - /* Callback for Toolbox */ - void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout); - -private: - bool privateHandleEvent(Ion::Events::Event event); - bool handleMoveEvent(Ion::Events::Event event); - bool handleAddEvent(Ion::Events::Event event); - bool handleDeleteEvent(Ion::Events::Event event); - void serializeLayout(); - void computeResult(); - ExpressionEditorView m_view; - Poincare::ExpressionLayout * m_expressionLayout; - Poincare::ExpressionLayoutCursor m_cursor; - static constexpr int k_bufferSize = 256; - char m_buffer[k_bufferSize]; - Poincare::ExpressionLayout * m_resultLayout; - //Poincare::Context m_context; -}; - -} - -#endif diff --git a/apps/expression_editor/expression_and_layout.cpp b/apps/expression_editor/expression_and_layout.cpp deleted file mode 100644 index 24e0f3df4..000000000 --- a/apps/expression_editor/expression_and_layout.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "expression_and_layout.h" -#include -#include - -namespace ExpressionEditor { - -ExpressionAndLayout::ExpressionAndLayout() { - const char * expression = "1"; - //const char * expression = "1+2/(3+4)"; - //const char * expression = "1+2/3+5+8"; - //const char * expression = "[[1+5,2,3][4,5,6]]"; - //const char * expression = "1+2/(7+5/3/467777777)/3+8"; - //const char * expression = "1+2/7467777777"; - //const char * expression = "2385658/(7+5/46)"; - //const char * expression = "1+conj(100)+2"; - //const char * expression = "1+abs(100)+2"; - //const char * expression = "1+root(100,41)+2"; - //const char * expression = "ln(36)"; - //const char * expression = "1+floor(36)+2"; - //const char * expression = "ln(36)+root(542,52)+sum(12,3,4)+int(22,3,4)+conj(988)"; - //const char * expression = "2385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+(1111111)/(2/3+4/5)"; - //const char * expression = "2385658/(int(5/46*7/8,3,45))"; - //const char * expression = "1+binomial(6,88)+1"; - //const char * expression = "[[1+5,2,3][4,5,int(5/46+1,3,4)]]"; - //const char * expression = "2385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]"; - //const char * expression = "1/2+[[1,2,3][4,5,6]]+1"; - //const char * expression = "1+(3+4)+1"; - //const char * expression = "1+product(23,46,123)+[[2,3][5,6]]+1/4"; - //const char * expression = "2385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]"; - //const char * expression = "7/78+int(5/46*7/8,3,45)+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]"; - //const char * expression = "1+conj(39)+abs(3)+root(6000,23)"; - //const char * expression = "1.5+3.4"; - //const char * expression = "abs(5)+int(5/46*7/8,3,4544444)+conj(4)+int(333,4,5)"; - //const char * expression = "conj(int(5/46*7/8,3,45))+conj(4)"; - //const char * expression = "abs(1+conj(conj(4))+(23)+conj(42))+abs(1+2)"; - //const char * expression = "13+(23)"; - //const char * expression = "1+sum(12,3,4)+product(12,3,4)+2"; - //const char * expression = "(1+2^3)-385658/(7/78+int(5/46*7/8,3,45))+sum(12,3,4)+[[1+5,2,3][4/2,5,6]]/123+ln(36)+root(542,52)+sum(12,3,4)+int(22,3,4)+conj(988+2)+abs(conj(345))+conj(conj(conj(3)))+floor(48)+binomial(6,88)+product(23,46,123)+log(10,565)-0.03"; - - m_expression = Poincare::Expression::parse(expression); - m_expressionLayout = new Poincare::HorizontalLayout(); -} -ExpressionAndLayout::~ExpressionAndLayout() { - if (m_expressionLayout) { - delete m_expressionLayout; - m_expressionLayout = nullptr; - } - if (m_expression) { - delete m_expression; - m_expression = nullptr; - } -} - -} diff --git a/apps/expression_editor/expression_and_layout.h b/apps/expression_editor/expression_and_layout.h deleted file mode 100644 index a1ef237fc..000000000 --- a/apps/expression_editor/expression_and_layout.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef EXPRESSION_EDITOR_EXPRESSION_AND_LAYOUT_H -#define EXPRESSION_EDITOR_EXPRESSION_AND_LAYOUT_H - -#include - -namespace ExpressionEditor { - -class ExpressionAndLayout { -public: - ExpressionAndLayout(); - ~ExpressionAndLayout(); - ExpressionAndLayout(const ExpressionAndLayout& other) = delete; - ExpressionAndLayout(ExpressionAndLayout&& other) = delete; - ExpressionAndLayout operator=(const ExpressionAndLayout& other) = delete; - ExpressionAndLayout& operator=(ExpressionAndLayout&& other) = delete; - - Poincare::Expression * expression() { return m_expression; } - Poincare::ExpressionLayout * expressionLayout() { return m_expressionLayout; } -private: - Poincare::Expression * m_expression; - Poincare::ExpressionLayout * m_expressionLayout; -}; - -} - -#endif diff --git a/apps/expression_editor/expression_editor_view.cpp b/apps/expression_editor/expression_editor_view.cpp deleted file mode 100644 index 7fc386c89..000000000 --- a/apps/expression_editor/expression_editor_view.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "expression_editor_view.h" -#include - -namespace ExpressionEditor { - -ExpressionEditorView::ExpressionEditorView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor) : - SolidColorView(KDColorWhite), - m_scrollableExpressionViewWithCursor(parentResponder, expressionLayout, cursor), - m_resultExpressionView() -{ - m_serializerTextView.setText("Hello"); -} - -void ExpressionEditorView::cursorPositionChanged() { - m_scrollableExpressionViewWithCursor.expressionViewWithCursor()->cursorPositionChanged(); - m_scrollableExpressionViewWithCursor.scrollToCursor(); -} - -void ExpressionEditorView::setText(const char * text) { - m_serializerTextView.setText(text); -} - -void ExpressionEditorView::setResult(Poincare::ExpressionLayout * eL) { - m_resultExpressionView.setExpressionLayout(eL); -} - -View * ExpressionEditorView::subviewAtIndex(int index) { - assert(index >= 0 && index < 3); - if (index == 0) { - return &m_scrollableExpressionViewWithCursor; - } - if (index == 1) { - return &m_resultExpressionView; - } - return &m_serializerTextView; -} - -void ExpressionEditorView::layoutSubviews() { - m_serializerTextView.setFrame(KDRect(0, 0, bounds().width(), 20)); - m_resultExpressionView.setFrame(KDRect(20, k_margin, bounds().width() - 2 * k_margin, 50)); - m_scrollableExpressionViewWithCursor.setFrame(KDRect( - k_margin, - 50+k_margin, - bounds().width() - 2 * k_margin, - bounds().height() - 2 * k_margin)); - markRectAsDirty(bounds()); -} - -KDSize ExpressionEditorView::minimalSizeForOptimalDisplay() const { - return KDSize(300, 220); -} - - -} - diff --git a/apps/expression_editor/expression_editor_view.h b/apps/expression_editor/expression_editor_view.h deleted file mode 100644 index 2d0116b35..000000000 --- a/apps/expression_editor/expression_editor_view.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef EXPRESSION_EDITOR_EXPRESSION_EDITOR_VIEW_H -#define EXPRESSION_EDITOR_EXPRESSION_EDITOR_VIEW_H - -#include -#include "expression_and_layout.h" -#include "scrollable_expression_view_with_cursor.h" - -namespace ExpressionEditor { - -class ExpressionEditorView : public SolidColorView { -public: - ExpressionEditorView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor); - void cursorPositionChanged(); - void setText(const char * text); - void setResult(Poincare::ExpressionLayout * result); - int numberOfSubviews() const override { return 3; } - ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor() { return &m_scrollableExpressionViewWithCursor; } - View * subviewAtIndex(int index) override; - void layoutSubviews() override; - KDSize minimalSizeForOptimalDisplay() const override; -private: - constexpr static KDCoordinate k_margin = 10; - ScrollableExpressionViewWithCursor m_scrollableExpressionViewWithCursor; - ExpressionView m_resultExpressionView; - BufferTextView m_serializerTextView; -}; - -} - -#endif diff --git a/apps/expression_editor/expression_view_with_cursor.cpp b/apps/expression_editor/expression_view_with_cursor.cpp deleted file mode 100644 index 716d23492..000000000 --- a/apps/expression_editor/expression_view_with_cursor.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "expression_view_with_cursor.h" -#include - -using namespace Poincare; - -namespace ExpressionEditor { - -ExpressionViewWithCursor::ExpressionViewWithCursor(ExpressionLayout * expressionLayout, ExpressionLayoutCursor * cursor) : - m_cursor(cursor) -{ - m_expressionView.setExpressionLayout(expressionLayout); -} - -void ExpressionViewWithCursor::cursorPositionChanged() { - layoutCursorSubview(); -} - -KDRect ExpressionViewWithCursor::cursorRect() { - return m_cursorView.frame(); -} - -KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { - KDSize expressionViewSize = m_expressionView.minimalSizeForOptimalDisplay(); - return KDSize(expressionViewSize.width()+1, m_expressionView.minimalSizeForOptimalDisplay().height()); // +1 for the cursor -} - -View * ExpressionViewWithCursor::subviewAtIndex(int index) { - assert(index >= 0 && index < 2); - View * m_views[] = {&m_expressionView, &m_cursorView}; - return m_views[index]; -} - -void ExpressionViewWithCursor::layoutSubviews() { - m_expressionView.setFrame(bounds()); - layoutCursorSubview(); -} - -void ExpressionViewWithCursor::layoutCursorSubview() { - KDPoint expressionViewOrigin = m_expressionView.drawingOrigin(); - KDPoint cursoredExpressionViewOrigin = m_cursor->pointedExpressionLayout()->absoluteOrigin(); - KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x(); - if (m_cursor->position() == ExpressionLayoutCursor::Position::Right) { - cursorX += m_cursor->pointedExpressionLayout()->size().width(); - } - KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + m_cursor->pointedExpressionLayout()->baseline()-m_cursor->cursorHeight()/2); - m_cursorView.setFrame(KDRect(cursorTopLeftPosition, 1, m_cursor->cursorHeight())); -} - -} diff --git a/apps/expression_editor/expression_view_with_cursor.h b/apps/expression_editor/expression_view_with_cursor.h deleted file mode 100644 index 79353173c..000000000 --- a/apps/expression_editor/expression_view_with_cursor.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef EXPRESSION_EDITOR_EXPRESSION_VIEW_WITH_CURSOR_H -#define EXPRESSION_EDITOR_EXPRESSION_VIEW_WITH_CURSOR_H - -#include -#include -#include -#include - -namespace ExpressionEditor { - -class ExpressionViewWithCursor : public View { -public: - ExpressionViewWithCursor(Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor); - void cursorPositionChanged(); - KDRect cursorRect(); - const ExpressionView * expressionView() const { return &m_expressionView; } - /* View */ - KDSize minimalSizeForOptimalDisplay() const override; -private: - enum class Position { - Top, - Bottom - }; - int numberOfSubviews() const override { return 2; } - View * subviewAtIndex(int index) override; - void layoutSubviews() override; - void layoutCursorSubview(); - Poincare::ExpressionLayoutCursor * m_cursor; - ExpressionView m_expressionView; - TextCursorView m_cursorView; -}; - -} - -#endif diff --git a/apps/expression_editor/scrollable_expression_view_with_cursor.cpp b/apps/expression_editor/scrollable_expression_view_with_cursor.cpp deleted file mode 100644 index 60b5c1733..000000000 --- a/apps/expression_editor/scrollable_expression_view_with_cursor.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "scrollable_expression_view_with_cursor.h" -#include - -namespace ExpressionEditor { - -ScrollableExpressionViewWithCursor::ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor) : - ScrollableView(parentResponder, &m_expressionViewWithCursor, this), - m_expressionViewWithCursor(expressionLayout, cursor) -{ -} - -KDSize ScrollableExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { - return m_expressionViewWithCursor.minimalSizeForOptimalDisplay(); -} - -void ScrollableExpressionViewWithCursor::scrollToCursor() { - scrollToContentRect(m_expressionViewWithCursor.cursorRect(), true); -} - -} - diff --git a/apps/expression_editor/scrollable_expression_view_with_cursor.h b/apps/expression_editor/scrollable_expression_view_with_cursor.h deleted file mode 100644 index 7083f1153..000000000 --- a/apps/expression_editor/scrollable_expression_view_with_cursor.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EXPRESSION_EDITOR_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H -#define EXPRESSION_EDITOR_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H - -#include -#include -#include -#include "expression_view_with_cursor.h" - -namespace ExpressionEditor { - -class ScrollableExpressionViewWithCursor : public ScrollableView, public ScrollViewDataSource { -public: - ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, Poincare::ExpressionLayoutCursor * cursor); - KDSize minimalSizeForOptimalDisplay() const override; - ExpressionViewWithCursor * expressionViewWithCursor() { return &m_expressionViewWithCursor; } - void scrollToCursor(); - /* ScrollableView */ - bool handleEvent(Ion::Events::Event event) override { return false; } -private: - ExpressionViewWithCursor m_expressionViewWithCursor; -}; - -} - -#endif diff --git a/apps/expression_editor/test/dummy_test.cpp b/apps/expression_editor/test/dummy_test.cpp deleted file mode 100644 index 18e40f6c0..000000000 --- a/apps/expression_editor/test/dummy_test.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include -#include - -QUIZ_CASE() { - assert(true); -} diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index 68f38e3e9..2e5b0131a 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -4,7 +4,6 @@ #define MATRICES_ARE_DEFINED 1 #include #include -#include class MathToolbox : public Toolbox { public: From ab8140c1c3a0f56c349e608240b4e3cf1d6b8df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 11:36:34 +0100 Subject: [PATCH 224/257] [poincare] Pointer shouldRecomputeLayout mandatory for layout navigation This fixes a bug. Change-Id: I9bb5ff3a3f365865d85f89efcd970e3ac5096536 --- poincare/include/poincare/expression_layout.h | 8 ++++---- poincare/include/poincare/expression_layout_cursor.h | 2 +- poincare/src/layout/binomial_coefficient_layout.h | 4 ++-- poincare/src/layout/bracket_layout.h | 4 ++-- poincare/src/layout/bracket_left_right_layout.h | 4 ++-- poincare/src/layout/char_layout.h | 4 ++-- poincare/src/layout/condensed_sum_layout.h | 4 ++-- poincare/src/layout/conjugate_layout.h | 4 ++-- poincare/src/layout/empty_visible_layout.h | 4 ++-- poincare/src/layout/expression_layout.cpp | 3 ++- poincare/src/layout/fraction_layout.h | 4 ++-- poincare/src/layout/grid_layout.h | 4 ++-- poincare/src/layout/horizontal_layout.h | 4 ++-- poincare/src/layout/integral_layout.h | 4 ++-- poincare/src/layout/matrix_layout.h | 8 ++++---- poincare/src/layout/nth_root_layout.h | 4 ++-- poincare/src/layout/parenthesis_left_right_layout.h | 4 ++-- poincare/src/layout/sequence_layout.h | 4 ++-- poincare/src/layout/vertical_offset_layout.h | 4 ++-- 19 files changed, 41 insertions(+), 40 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 60bfeea85..2a7da4542 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -76,8 +76,8 @@ public: virtual void backspaceAtCursor(ExpressionLayoutCursor * cursor); /* Tree navigation */ - virtual bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) = 0; - virtual bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) = 0; + virtual bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) = 0; + virtual bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) = 0; virtual bool moveUp( ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, @@ -88,8 +88,8 @@ public: bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr); - virtual bool moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr); - virtual bool moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr); + virtual bool moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout); + virtual bool moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout); /* Expression Engine */ virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0; diff --git a/poincare/include/poincare/expression_layout_cursor.h b/poincare/include/poincare/expression_layout_cursor.h index 7657d5e18..2d6791e9a 100644 --- a/poincare/include/poincare/expression_layout_cursor.h +++ b/poincare/include/poincare/expression_layout_cursor.h @@ -33,7 +33,7 @@ public: KDPoint middleLeftPointOfCursor(ExpressionLayout * expressionLayout, Position position); /* Move */ - bool moveLeft(bool * shouldRecomputeLayout = nullptr); + bool moveLeft(bool * shouldRecomputeLayout); bool moveRight(bool * shouldRecomputeLayout); bool moveUp(bool * shouldRecomputeLayout); bool moveDown(bool * shouldRecomputeLayout); diff --git a/poincare/src/layout/binomial_coefficient_layout.h b/poincare/src/layout/binomial_coefficient_layout.h index 8cfa19323..a77b9426b 100644 --- a/poincare/src/layout/binomial_coefficient_layout.h +++ b/poincare/src/layout/binomial_coefficient_layout.h @@ -10,8 +10,8 @@ class BinomialCoefficientLayout : public StaticLayoutHierarchy<2> { public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; int writeTextInBuffer(char * buffer, int bufferSize) const override { diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index b9a746f36..9c9deaf66 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -10,8 +10,8 @@ public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; protected: ExpressionLayout * operandLayout(); diff --git a/poincare/src/layout/bracket_left_right_layout.h b/poincare/src/layout/bracket_left_right_layout.h index 7dfc9708a..9791e18c4 100644 --- a/poincare/src/layout/bracket_left_right_layout.h +++ b/poincare/src/layout/bracket_left_right_layout.h @@ -9,8 +9,8 @@ class BracketLeftRightLayout : public StaticLayoutHierarchy<0> { public: BracketLeftRightLayout(); void invalidAllSizesPositionsAndBaselines() override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; protected: constexpr static KDCoordinate k_bracketWidth = 5; constexpr static KDCoordinate k_lineThickness = 1; diff --git a/poincare/src/layout/char_layout.h b/poincare/src/layout/char_layout.h index 37ebd3692..48a7590c2 100644 --- a/poincare/src/layout/char_layout.h +++ b/poincare/src/layout/char_layout.h @@ -17,8 +17,8 @@ public: char character() { return m_char; } KDText::FontSize fontSize() const { return m_fontSize; } - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index d7a236e4e..3026ef0b5 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -10,8 +10,8 @@ class CondensedSumLayout : public StaticLayoutHierarchy<3> { public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override { diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 896e777a0..5b1f2097e 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -11,8 +11,8 @@ public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; int writeTextInBuffer(char * buffer, int bufferSize) const override { diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index 8731a3f55..c554a9188 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -15,8 +15,8 @@ public: EmptyVisibleLayout(Color color = Color::Yellow); ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; bool isEmpty() const override { return true; } Color color() const { return m_color; } diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index 958edf102..c318adfc3 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -205,7 +205,8 @@ void ExpressionLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { // Case: The pointed layout is a child. // Move Left. assert(cursor->position() == ExpressionLayoutCursor::Position::Left); - cursor->moveLeft(); + bool shouldRecomputeLayout = false; + cursor->moveLeft(&shouldRecomputeLayout); return; } assert(cursor->pointedExpressionLayout() == this); diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 02562db82..044d60158 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -11,8 +11,8 @@ public: using StaticLayoutHierarchy::StaticLayoutHierarchy; ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index ad80b8f49..9bd6b467e 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -13,8 +13,8 @@ public: ExpressionLayout * clone() const override; /* Navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index a0d7bdfaa..89e79e592 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -22,8 +22,8 @@ public: void addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren); /* Navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 56cb14999..6241c756d 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -17,8 +17,8 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; /* Tree navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 78139be13..767686e37 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -11,12 +11,12 @@ public: ExpressionLayout * clone() const override; /* Navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; - bool moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveUpInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; /* Dynamic layout */ void replaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild) override; diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index e97d05595..db5eec064 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -17,8 +17,8 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; /* Tree navigation */ - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; diff --git a/poincare/src/layout/parenthesis_left_right_layout.h b/poincare/src/layout/parenthesis_left_right_layout.h index 0dc125452..b40f2536d 100644 --- a/poincare/src/layout/parenthesis_left_right_layout.h +++ b/poincare/src/layout/parenthesis_left_right_layout.h @@ -9,8 +9,8 @@ class ParenthesisLeftRightLayout : public StaticLayoutHierarchy<0> { public: ParenthesisLeftRightLayout(); void invalidAllSizesPositionsAndBaselines() override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; constexpr static KDCoordinate parenthesisWidth() { return k_widthMargin + k_lineThickness + k_externWidthMargin; } constexpr static KDCoordinate k_parenthesisCurveWidth = 5; constexpr static KDCoordinate k_parenthesisCurveHeight = 7; diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index f7c77d5b2..7299ca914 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -11,8 +11,8 @@ public: constexpr static KDCoordinate k_symbolHeight = 15; constexpr static KDCoordinate k_symbolWidth = 9; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; char XNTChar() const override; diff --git a/poincare/src/layout/vertical_offset_layout.h b/poincare/src/layout/vertical_offset_layout.h index 75ca9f1e3..bfceadee1 100644 --- a/poincare/src/layout/vertical_offset_layout.h +++ b/poincare/src/layout/vertical_offset_layout.h @@ -14,8 +14,8 @@ public: VerticalOffsetLayout(ExpressionLayout * indice, Type type, bool cloneOperands); ExpressionLayout * clone() const override; void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; - bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; - bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr) override; + bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; + bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; int writeTextInBuffer(char * buffer, int bufferSize) const override; From 95f859ce80eab99276a9a7d1020f50500e180690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 11:55:04 +0100 Subject: [PATCH 225/257] [apps/sequence] Set sender for sequence toolbox. Change-Id: I3fe78127273083fb4f8f680ea3e6394f99913a12 --- apps/sequence/list/list_controller.cpp | 25 ++++++++++++++++++------- apps/sequence/list/list_controller.h | 2 ++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index b8cc8cdeb..e03f0e821 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -24,13 +24,14 @@ const char * ListController::title() { } Toolbox * ListController::toolboxForTextField(TextField * textField) { - int recurrenceDepth = -1; - int sequenceDefinition = sequenceDefinitionForRow(selectedRow()); - Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(selectedRow())); - if (sequenceDefinition == 0) { - recurrenceDepth = sequence->numberOfElements()-1; - } - m_sequenceToolbox.setExtraCells(sequence->name(), recurrenceDepth); + setToolboxExtraCells(); + m_sequenceToolbox.setSenderAndAction(textField, MathToolbox::actionForTextField); + return &m_sequenceToolbox; +} + +Toolbox * ListController::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { + setToolboxExtraCells(); + m_sequenceToolbox.setSenderAndAction(scrollableExpressionViewWithCursor, MathToolbox::actionForScrollableExpressionViewWithCursor); return &m_sequenceToolbox; } @@ -308,4 +309,14 @@ void ListController::unloadView(View * view) { Shared::ListController::unloadView(view); } +void ListController::setToolboxExtraCells() { + int recurrenceDepth = -1; + int sequenceDefinition = sequenceDefinitionForRow(selectedRow()); + Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(selectedRow())); + if (sequenceDefinition == 0) { + recurrenceDepth = sequence->numberOfElements()-1; + } + m_sequenceToolbox.setExtraCells(sequence->name(), recurrenceDepth); +} + } diff --git a/apps/sequence/list/list_controller.h b/apps/sequence/list/list_controller.h index a8f34882f..78ae667a0 100644 --- a/apps/sequence/list/list_controller.h +++ b/apps/sequence/list/list_controller.h @@ -23,6 +23,7 @@ public: virtual KDCoordinate rowHeight(int j) override; void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; Toolbox * toolboxForTextField(TextField * textField) override; + Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override; void selectPreviousNewSequenceCell(); private: Shared::TextFieldDelegateApp * textFieldDelegateApp() override; @@ -43,6 +44,7 @@ private: void reinitExpression(Shared::Function * function) override; View * loadView() override; void unloadView(View * view) override; + void setToolboxExtraCells(); static constexpr KDCoordinate k_emptySubRowHeight = 30; constexpr static int k_maxNumberOfRows = 3*MaxNumberOfSequences; SequenceStore * m_sequenceStore; From 30ac81db284c28f984db71c37ecb35165cadd0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 12:03:19 +0100 Subject: [PATCH 226/257] [poincare/lexer] Add rules to recognize symbols such as "u_{n}". Change-Id: Ib6976e3b02357a975241ef5314a5999f967d6a45 --- poincare/src/expression_lexer.l | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 57ed5769a..d8753a6c1 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -89,6 +89,10 @@ u\(n\) { poincare_expression_yylval.character = Symbol::SpecialSymbols::un; retu u\(n\+1\) { poincare_expression_yylval.character = Symbol::SpecialSymbols::un1; return SYMBOL; } v\(n\) { poincare_expression_yylval.character = Symbol::SpecialSymbols::vn; return SYMBOL; } v\(n\+1\) { poincare_expression_yylval.character = Symbol::SpecialSymbols::vn1; return SYMBOL; } +u\_\{n\} { poincare_expression_yylval.character = Symbol::SpecialSymbols::un; return SYMBOL; } +u\_\{n\+1\} { poincare_expression_yylval.character = Symbol::SpecialSymbols::un1; return SYMBOL; } +v\_\{n\} { poincare_expression_yylval.character = Symbol::SpecialSymbols::vn; return SYMBOL; } +v\_\{n\+1\} { poincare_expression_yylval.character = Symbol::SpecialSymbols::vn1; return SYMBOL; } acos { poincare_expression_yylval.expression = new ArcCosine(); return FUNCTION; } acosh { poincare_expression_yylval.expression = new HyperbolicArcCosine(); return FUNCTION; } abs { poincare_expression_yylval.expression = new AbsoluteValue(); return FUNCTION; } From acf8fe25ff7d5a64c056241b0bd26a6832b5546b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 14:20:08 +0100 Subject: [PATCH 227/257] [escher] Fix text field bug when editing a sequence. The InputViewController inserted the text to edit in the TextField then set the edition to true, which deleted the text. Change-Id: Id77e740c0b615066e647512a19731214a435a2f0 --- escher/src/input_view_controller.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/escher/src/input_view_controller.cpp b/escher/src/input_view_controller.cpp index ac5fa9956..d04c5edcb 100644 --- a/escher/src/input_view_controller.cpp +++ b/escher/src/input_view_controller.cpp @@ -33,11 +33,10 @@ void InputViewController::edit(Responder * caller, Ion::Events::Event event, voi m_successAction = Invocation(successAction, context); m_failureAction = Invocation(failureAction, context); displayModalViewController(&m_editableExpressionViewController, 1.0f, 1.0f); + m_editableExpressionViewController.editableExpressionView()->handleEvent(event); if (initialText != nullptr) { m_editableExpressionViewController.editableExpressionView()->setText(initialText); - //TODO is the editableExpressionView always clean before we set the text? Otherwise, problem if there is no initial text. } - m_editableExpressionViewController.editableExpressionView()->handleEvent(event); } void InputViewController::abortEditionAndDismiss() { From bc21aa919f1124323dbdd501da3ae5abb68269f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 14:27:45 +0100 Subject: [PATCH 228/257] [escher] Missing return statement. Change-Id: I96feaeac32a8a01098b5446e9bc11321442b1022 --- escher/src/editable_expression_view.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index cc557b04e..8881f48f4 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -35,6 +35,7 @@ const char * EditableExpressionView::text() { void EditableExpressionView::setText(const char * text) { if (editionIsInTextField()) { m_textField.setText(text); + return; } m_scrollableExpressionViewWithCursor.clearLayout(); if (strlen(text) > 0) { From 2c79071d0764317416cc9bae39e8ae3dfd0d84f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 14:44:39 +0100 Subject: [PATCH 229/257] [poincare] Fix bug in HorizontalLayout. Adding a brother should add it has a child, or merge it if the "brother" is an horizontal layout! Change-Id: I77e993ef2270fd1bf61599d688f3835feb8c0971 --- poincare/src/layout/horizontal_layout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 815161b80..e9285e151 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -367,11 +367,11 @@ void HorizontalLayout::privateAddBrother(ExpressionLayoutCursor * cursor, Expres cursor->setPosition(ExpressionLayoutCursor::Position::Right); } } - addChildAtIndex(brother, 0); + addOrMergeChildAtIndex(brother, 0, false); return; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - addChildAtIndex(brother, numberOfChildren()); + addOrMergeChildAtIndex(brother, numberOfChildren(), false); if (moveCursor) { cursor->setPointedExpressionLayout(this); } From 8f17807fc16617d5648d2965119c35d19a8833bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 14:54:35 +0100 Subject: [PATCH 230/257] [poincare] Fixed power layout insertion bug. The method to determine if an empty base layout should also be inserted had a bug. Change-Id: I6c5e0de033eaee8a21a39f3eaffa18b259865a6e --- poincare/src/expression_layout_cursor.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 947dfedf9..11e25ea3f 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -211,16 +211,24 @@ bool ExpressionLayoutCursor::baseForNewPowerLayout() { // Returns true if the layout on the left of the pointed layout is suitable to // be the base of a new power layout. int numberOfOpenParenthesis = 0; - int indexInParent = m_pointedExpressionLayout->parent()->indexOfChild(m_pointedExpressionLayout); - return ((m_position == Position::Right - && !m_pointedExpressionLayout->isEmpty() - && m_pointedExpressionLayout->isCollapsable(&numberOfOpenParenthesis, true)) - || (m_position == Position::Left - && m_pointedExpressionLayout->parent() + if (m_position == Position::Right + && !m_pointedExpressionLayout->isEmpty() + && m_pointedExpressionLayout->isCollapsable(&numberOfOpenParenthesis, true)) + { + return true; + } + if (m_pointedExpressionLayout->parent() != nullptr) { + int indexInParent = m_pointedExpressionLayout->parent()->indexOfChild(m_pointedExpressionLayout); + if (m_position == Position::Left && m_pointedExpressionLayout->parent()->isHorizontal() && indexInParent > 0 && !m_pointedExpressionLayout->editableParent()->editableChild(indexInParent-1)->isEmpty() - && !m_pointedExpressionLayout->editableParent()->editableChild(indexInParent-1)->isCollapsable(&numberOfOpenParenthesis, true))); + && !m_pointedExpressionLayout->editableParent()->editableChild(indexInParent-1)->isCollapsable(&numberOfOpenParenthesis, true)) + { + return true; + } + } + return false; } } From fa1dcbf434df0fc9466b3216b4e34b8fea93f99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 15:03:47 +0100 Subject: [PATCH 231/257] [poincare] Fix SquareRoot layout creation. Change-Id: I9985735a5a00b1acf14993996f63be5dc91d9c14 --- poincare/src/square_root.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/square_root.cpp b/poincare/src/square_root.cpp index ccb695d2d..37cf805a0 100644 --- a/poincare/src/square_root.cpp +++ b/poincare/src/square_root.cpp @@ -52,7 +52,7 @@ Expression * SquareRoot::shallowReduce(Context& context, AngleUnit angleUnit) { ExpressionLayout * SquareRoot::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { assert(floatDisplayMode != FloatDisplayMode::Default); assert(complexFormat != ComplexFormat::Default); - return new NthRootLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), nullptr, false); + return new NthRootLayout(operand(0)->createLayout(floatDisplayMode, complexFormat), false); } } From d217832ba12d9482dde692319de36a0b17c345df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 17:32:56 +0100 Subject: [PATCH 232/257] [poincare] Fix bug when inserting a fraction between base and indice. Change-Id: I4e3f6a5b6aee251a99e580dde7cb65b753f99ac5 --- poincare/src/expression_layout_cursor.cpp | 11 ++++++++--- poincare/src/layout/char_layout.cpp | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 11e25ea3f..805b6bb65 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -76,11 +76,16 @@ void ExpressionLayoutCursor::addFractionLayoutAndCollapseBrothers() { // Collapse the brothers on the right int numberOfOpenParenthesis = 0; - while (fractionIndexInParent < numberOfBrothers - 1) { - ExpressionLayout * rightBrother = newChild->editableParent()->editableChild(fractionIndexInParent+1); + bool canCollapseOnRight = true; + if (fractionIndexInParent < numberOfBrothers - 1) { + canCollapseOnRight = !(newChild->editableParent()->editableChild(fractionIndexInParent+1)->mustHaveLeftBrother()); + } + ExpressionLayout * rightBrother = nullptr; + while (canCollapseOnRight && fractionIndexInParent < numberOfBrothers - 1) { + rightBrother = newChild->editableParent()->editableChild(fractionIndexInParent+1); if (rightBrother->isCollapsable(&numberOfOpenParenthesis, false)) { newChild->editableParent()->removeChildAtIndex(fractionIndexInParent+1, false); - child2->addOrMergeChildAtIndex(rightBrother, child2->numberOfChildren(), true); + child2->addOrMergeChildAtIndex(rightBrother, child2->numberOfChildren(), false); numberOfBrothers--; } else { break; diff --git a/poincare/src/layout/char_layout.cpp b/poincare/src/layout/char_layout.cpp index 0dde197c6..2a86c61f2 100644 --- a/poincare/src/layout/char_layout.cpp +++ b/poincare/src/layout/char_layout.cpp @@ -56,7 +56,8 @@ bool CharLayout::isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) co || m_char == '-' || m_char == '*' || m_char == Ion::Charset::MultiplicationSign - || m_char == Ion::Charset::MiddleDot)) + || m_char == Ion::Charset::MiddleDot + || m_char == ',')) { return false; } From d5a24bd71ca65589881aaeb368b92af7e60e1a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 26 Jan 2018 18:14:06 +0100 Subject: [PATCH 233/257] [To remove] Change-Id: Ifbd887c0ddbdec71c8495eca10354352ffa1418e --- apps/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/Makefile b/apps/Makefile index 7e5d367ab..01af17fff 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,5 +1,5 @@ EPSILON_I18N_LANGUAGES ?= en fr es de pt -EPSILON_APPS ?= calculation graph sequence settings statistics probability regression code +EPSILON_APPS ?= calculation graph sequence settings include apps/shared/Makefile include apps/home/Makefile From eb03b713c332a1daac1aad1a3c5c4f4648993259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 29 Jan 2018 13:32:54 +0100 Subject: [PATCH 234/257] [poincare] Fix bug when layouting a left parenthesis. When the parenthesis is the base of a vertical offset superscript, its height and baseline should be default values, else it creates an infinite loop because the parenthesis needs the superscript position, which needs the parenthesis position. Change-Id: Ib5f7d7cbd1cb48b5de8251cdda64b271e50f216f --- .../src/layout/parenthesis_left_layout.cpp | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/poincare/src/layout/parenthesis_left_layout.cpp b/poincare/src/layout/parenthesis_left_layout.cpp index aaa91ede0..2ed96c93a 100644 --- a/poincare/src/layout/parenthesis_left_layout.cpp +++ b/poincare/src/layout/parenthesis_left_layout.cpp @@ -67,9 +67,18 @@ void ParenthesisLeftLayout::computeOperandHeight() { m_operandHeight = Metric::MinimalBracketAndParenthesisHeight; KDCoordinate max_under_baseline = 0; KDCoordinate max_above_baseline = 0; + int indexInParent = m_parent->indexOfChild(this); int currentNumberOfOpenParentheses = 1; int numberOfBrothers = m_parent->numberOfChildren(); - for (int i = m_parent->indexOfChild(this) + 1; i < numberOfBrothers; i++) { + if (indexInParent < numberOfBrothers - 1 + && m_parent->child(indexInParent + 1)->mustHaveLeftBrother()) + { + // If the parenthesis is the base of a superscript layout, it should have a + // default height, else it creates an infinite loop because the parenthesis + // needs the superscript height, which needs the parenthesis height. + return; + } + for (int i = indexInParent + 1; i < numberOfBrothers; i++) { ExpressionLayout * brother = m_parent->editableChild(i); if (brother->isRightParenthesis()) { currentNumberOfOpenParentheses--; @@ -107,6 +116,16 @@ void ParenthesisLeftLayout::computeBaseline() { m_baselined = true; return; } + if (m_parent->child(indexInParent + 1)->mustHaveLeftBrother()) { + // If the parenthesis is the base of a superscript layout, it should have a + // default baseline, else it creates an infinite loop because the + // parenthesis needs the superscript height, which needs the parenthesis + // baseline. + m_baseline = operandHeight()/2; + m_baselined = true; + return; + } + m_baseline = 0; for (int i = indexInParent + 1; i < numberOfBrothers; i++) { ExpressionLayout * brother = m_parent->editableChild(i); From e375e571adbd34b83b449819f9abf7b7527bba46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 29 Jan 2018 14:00:40 +0100 Subject: [PATCH 235/257] [poincare] Remove empty child when inserting in HorizontalLayout Change-Id: I393469cc28c83e6ab28d73a524ec62fab8165696 --- poincare/src/layout/horizontal_layout.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index e9285e151..27bff6bb9 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -354,11 +354,11 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { void HorizontalLayout::privateAddBrother(ExpressionLayoutCursor * cursor, ExpressionLayout * brother, bool moveCursor) { // Add the "brother" as a child. - // If there is only one empty child, remove it before adding the layout. - if (numberOfChildren() == 1 && editableChild(0)->isEmpty()) { - removeChildAtIndex(0, true); - } if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + // If the first child is empty, remove it before adding the layout. + if (numberOfChildren() > 0 && editableChild(0)->isEmpty()) { + removeChildAtIndex(0, true); + } if (moveCursor) { if (numberOfChildren() > 0) { cursor->setPointedExpressionLayout(editableChild(0)); @@ -371,7 +371,12 @@ void HorizontalLayout::privateAddBrother(ExpressionLayoutCursor * cursor, Expres return; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - addOrMergeChildAtIndex(brother, numberOfChildren(), false); + // If the first child is empty, remove it before adding the layout. + int childrenCount = numberOfChildren(); + if (childrenCount > 0 && editableChild(childrenCount - 1)->isEmpty()) { + removeChildAtIndex(childrenCount - 1, true); + } + addOrMergeChildAtIndex(brother, childrenCount, false); if (moveCursor) { cursor->setPointedExpressionLayout(this); } From 40ef1d1caa755c16b232f5ca1d72f0992558c98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 29 Jan 2018 14:10:38 +0100 Subject: [PATCH 236/257] [poincare] Fix cursor position bug when deleting VerticalOffsetLayout. Change-Id: Ie53030e5bff6876c75a785a61f6c43604bee2b05 --- poincare/src/layout/vertical_offset_layout.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp index 89b25fb24..b5e58b3dc 100644 --- a/poincare/src/layout/vertical_offset_layout.cpp +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -29,6 +29,8 @@ void VerticalOffsetLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { // Case: Empty base and indice. // Remove both the base and the indice layout. ExpressionLayout * parent = m_parent; + cursor->setPointedExpressionLayout(this); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); parent->removePointedChildAtIndexAndMoveCursor(indexInParent, true, cursor); parent->removePointedChildAtIndexAndMoveCursor(indexInParent-1, true, cursor); return; From 8d62aa90f8302b1171c88a67e2e8b01f46769d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 29 Jan 2018 15:29:58 +0100 Subject: [PATCH 237/257] [poincare] Better removal of empty child in HorizontalLayout Change-Id: I126af718ec8a983b22f07ab49fd3298b8b416ea5 --- poincare/src/layout/horizontal_layout.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 27bff6bb9..fe6dcd92b 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -166,7 +166,7 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren) { int newIndex = index; - if (numberOfChildren() > 0 && child(0)->isEmpty()) { + if (numberOfChildren() > 0 && child(0)->isEmpty() && (numberOfChildren() < 1 || !child(1)->mustHaveLeftBrother())) { removeChildAtIndex(0, true); newIndex = index == 0 ? 0 : index - 1; } @@ -371,12 +371,12 @@ void HorizontalLayout::privateAddBrother(ExpressionLayoutCursor * cursor, Expres return; } assert(cursor->position() == ExpressionLayoutCursor::Position::Right); - // If the first child is empty, remove it before adding the layout. + // If the last child is empty, remove it before adding the layout. int childrenCount = numberOfChildren(); if (childrenCount > 0 && editableChild(childrenCount - 1)->isEmpty()) { removeChildAtIndex(childrenCount - 1, true); } - addOrMergeChildAtIndex(brother, childrenCount, false); + addOrMergeChildAtIndex(brother, numberOfChildren(), false); if (moveCursor) { cursor->setPointedExpressionLayout(this); } From 7e1e811082fe7b4414f11c09bbc91859438220a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 29 Jan 2018 15:31:21 +0100 Subject: [PATCH 238/257] [poincare] Fix bug when deleting an empty VerticalOffsetLayout. Change-Id: Ic2d2248c783a718521c65b7cc2e15406926a8e94 --- poincare/src/layout/vertical_offset_layout.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp index b5e58b3dc..5180c986f 100644 --- a/poincare/src/layout/vertical_offset_layout.cpp +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -32,6 +32,8 @@ void VerticalOffsetLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { cursor->setPointedExpressionLayout(this); cursor->setPosition(ExpressionLayoutCursor::Position::Right); parent->removePointedChildAtIndexAndMoveCursor(indexInParent, true, cursor); + cursor->setPointedExpressionLayout(parent->editableChild(indexInParent-1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); parent->removePointedChildAtIndexAndMoveCursor(indexInParent-1, true, cursor); return; } From 7fd3b965eb9c90e5b39e0b9655073a8f243b8adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 29 Jan 2018 16:11:06 +0100 Subject: [PATCH 239/257] [poincare] Fixed HorizontalLayout empty child removal. Change-Id: Ic956a98b2637dafeda7c6e7476caa789ce398321 --- .../poincare/dynamic_layout_hierarchy.h | 4 +- poincare/src/expression_layout_cursor.cpp | 1 - poincare/src/layout/empty_visible_layout.cpp | 13 ++-- poincare/src/layout/horizontal_layout.cpp | 67 ++++++++++++++----- poincare/src/layout/horizontal_layout.h | 5 ++ 5 files changed, 68 insertions(+), 22 deletions(-) diff --git a/poincare/include/poincare/dynamic_layout_hierarchy.h b/poincare/include/poincare/dynamic_layout_hierarchy.h index 499f09cef..43dbb606e 100644 --- a/poincare/include/poincare/dynamic_layout_hierarchy.h +++ b/poincare/include/poincare/dynamic_layout_hierarchy.h @@ -25,11 +25,11 @@ public: int numberOfChildren() const override { return m_numberOfChildren; } const ExpressionLayout * const * children() const override { return m_children; }; - void addChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion, bool removeEmptyChildren); + virtual void addChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion, bool removeEmptyChildren); bool addChildAtIndex(ExpressionLayout * operand, int index) override; void removeChildAtIndex(int index, bool deleteAfterRemoval) override; void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; - void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren); // WITHOUT delete. + virtual void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren); // WITHOUT delete. protected: const ExpressionLayout ** m_children; diff --git a/poincare/src/expression_layout_cursor.cpp b/poincare/src/expression_layout_cursor.cpp index 805b6bb65..90b0aaabb 100644 --- a/poincare/src/expression_layout_cursor.cpp +++ b/poincare/src/expression_layout_cursor.cpp @@ -217,7 +217,6 @@ bool ExpressionLayoutCursor::baseForNewPowerLayout() { // be the base of a new power layout. int numberOfOpenParenthesis = 0; if (m_position == Position::Right - && !m_pointedExpressionLayout->isEmpty() && m_pointedExpressionLayout->isCollapsable(&numberOfOpenParenthesis, true)) { return true; diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index 244b8d48a..bcc59d66c 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -88,10 +88,15 @@ void EmptyVisibleLayout::privateAddBrother(ExpressionLayoutCursor * cursor, Expr Color currentColor = m_color; int indexInParent = m_parent->indexOfChild(this); ExpressionLayout * parent = m_parent; - replaceWith(brother, true); - if (moveCursor) { - cursor->setPointedExpressionLayout(brother); - cursor->setPosition(ExpressionLayoutCursor::Position::Right); + if (brother->mustHaveLeftBrother()) { + m_color = Color::Yellow; + ExpressionLayout::privateAddBrother(cursor, brother, moveCursor); + } else { + if (moveCursor) { + replaceWithAndMoveCursor(brother, true, cursor); + } else { + replaceWith(brother, true); + } } if (currentColor == Color::Grey) { // The parent is a MatrixLayout. diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index fe6dcd92b..63bd346c5 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -149,8 +149,11 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex } } } + bool oldChildRemovedAtMerge = oldChild->isEmpty(); mergeChildrenAtIndex(static_cast(newChild), indexForInsertion + 1, true); - removeChildAtIndex(indexForInsertion, deleteOldChild); + if (!oldChildRemovedAtMerge) { + removeChildAtIndex(indexForInsertion, deleteOldChild); + } return; } // Else, just replace the child. @@ -165,16 +168,11 @@ void HorizontalLayout::privateReplaceChild(const ExpressionLayout * oldChild, Ex } void HorizontalLayout::addOrMergeChildAtIndex(ExpressionLayout * eL, int index, bool removeEmptyChildren) { - int newIndex = index; - if (numberOfChildren() > 0 && child(0)->isEmpty() && (numberOfChildren() < 1 || !child(1)->mustHaveLeftBrother())) { - removeChildAtIndex(0, true); - newIndex = index == 0 ? 0 : index - 1; - } if (eL->isHorizontal()) { - mergeChildrenAtIndex(static_cast(eL), newIndex, removeEmptyChildren); + mergeChildrenAtIndex(static_cast(eL), index, removeEmptyChildren); return; } - addChildAtIndex(eL, newIndex); + addChildAtIndex(eL, index); } bool HorizontalLayout::moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) { @@ -279,14 +277,25 @@ bool HorizontalLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRe return moveVertically(ExpressionLayout::VerticalDirection::Down, cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } + +void HorizontalLayout::addChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion, bool removeEmptyChildren) { + int newIndex = removeEmptyChildBeforeInsertionAtIndex(indexForInsertion, operands[0]->mustHaveLeftBrother()); + DynamicLayoutHierarchy::addChildrenAtIndex(operands, numberOfOperands, newIndex, removeEmptyChildren); +} + +bool HorizontalLayout::addChildAtIndex(ExpressionLayout * operand, int index) { + int newIndex = removeEmptyChildBeforeInsertionAtIndex(index, operand->mustHaveLeftBrother()); + return DynamicLayoutHierarchy::addChildAtIndex(operand, newIndex); +} + void HorizontalLayout::removeChildAtIndex(int index, bool deleteAfterRemoval) { - // If the child to remove is at index 0 and its right brother must have a left - // brother (e.g. it is a VerticalOffsetLayout), replace the child with an - // EmptyVisibleLayout instead of removing it. - if (index == 0 && numberOfChildren() > 1 && child(1)->mustHaveLeftBrother()) { - addChildAtIndex(new EmptyVisibleLayout(), index + 1); - } - DynamicLayoutHierarchy::removeChildAtIndex(index, deleteAfterRemoval); + privateRemoveChildAtIndex(index, deleteAfterRemoval, false); +} + +void HorizontalLayout::mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren) { + bool shouldRemoveOnLeft = eL->numberOfChildren() > 0 ? eL->child(0)->mustHaveLeftBrother() : true; + int newIndex = removeEmptyChildBeforeInsertionAtIndex(index, shouldRemoveOnLeft); + DynamicLayoutHierarchy::mergeChildrenAtIndex(eL, newIndex, removeEmptyChildren); } int HorizontalLayout::writeTextInBuffer(char * buffer, int bufferSize) const { @@ -426,4 +435,32 @@ bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direct return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } +void HorizontalLayout::privateRemoveChildAtIndex(int index, bool deleteAfterRemoval, bool forceRemove) { + // If the child to remove is at index 0 and its right brother must have a left + // brother (e.g. it is a VerticalOffsetLayout), replace the child with an + // EmptyVisibleLayout instead of removing it. + if ( !forceRemove && index == 0 && numberOfChildren() > 1 && child(1)->mustHaveLeftBrother()) { + addChildAtIndex(new EmptyVisibleLayout(), index + 1); + } + DynamicLayoutHierarchy::removeChildAtIndex(index, deleteAfterRemoval); +} + +int HorizontalLayout::removeEmptyChildBeforeInsertionAtIndex(int index, bool shouldRemoveOnLeft) { + int newIndex = index; + // If empty, remove the child that would be on the right of the inserted + // layout. + if (newIndex < numberOfChildren() + && child(newIndex)->isEmpty()) + { + privateRemoveChildAtIndex(newIndex, true, true); + } + // If empty, remove the child that would be on the left of the inserted + // layout. + if ( shouldRemoveOnLeft && newIndex - 1 > 0 && newIndex - 1 < numberOfChildren() -1 && child(newIndex - 1)->isEmpty()) { + privateRemoveChildAtIndex(newIndex-1, true, true); + newIndex = index - 1; + } + return newIndex; +} + } diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 89e79e592..5d3c6d9d7 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -28,7 +28,10 @@ public: bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; /* Dynamic layout */ + void addChildrenAtIndex(const ExpressionLayout * const * operands, int numberOfOperands, int indexForInsertion, bool removeEmptyChildren) override; + bool addChildAtIndex(ExpressionLayout * operand, int index) override; void removeChildAtIndex(int index, bool deleteAfterRemoval) override; + void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren) override; /* Expression Engine */ int writeTextInBuffer(char * buffer, int bufferSize) const override; @@ -46,6 +49,8 @@ protected: private: bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout); void privateReplaceChild(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor); + void privateRemoveChildAtIndex(int index, bool deleteAfterRemoval, bool forceRemove); + int removeEmptyChildBeforeInsertionAtIndex(int index, bool shouldRemoveOnLeft); }; } From 214e490112ba848030050868655fa40a2b7a03b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Mon, 29 Jan 2018 17:58:11 +0100 Subject: [PATCH 240/257] [poincare] Fixed grey squares bug when moving up in nested matrices. Before, too many grey squares were added. Change-Id: I0694dc943f82006fe3367dea9750d2feb83071ad --- poincare/include/poincare/expression_layout.h | 3 ++- poincare/src/layout/expression_layout.cpp | 14 ++++++++++++++ poincare/src/layout/matrix_layout.cpp | 18 ------------------ poincare/src/layout/matrix_layout.h | 7 ------- 4 files changed, 16 insertions(+), 26 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 2a7da4542..8de6d3878 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -95,6 +95,7 @@ public: virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0; /* Other */ + bool addGreySquaresToAllMatrixAncestors(); bool hasText() const; virtual bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const { return true; } /* isCollapsable is used when adding a brother fraction: should the layout be @@ -123,7 +124,7 @@ protected: virtual KDSize computeSize() = 0; virtual void computeBaseline() = 0; virtual KDPoint positionOfChild(ExpressionLayout * child) = 0; - virtual void moveCursorInsideAtDirection ( + void moveCursorInsideAtDirection ( VerticalDirection direction, ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, diff --git a/poincare/src/layout/expression_layout.cpp b/poincare/src/layout/expression_layout.cpp index c318adfc3..8d9feb31c 100644 --- a/poincare/src/layout/expression_layout.cpp +++ b/poincare/src/layout/expression_layout.cpp @@ -259,6 +259,19 @@ bool ExpressionLayout::moveDownInside(ExpressionLayoutCursor * cursor, bool * sh return moveInside(VerticalDirection::Down, cursor, shouldRecomputeLayout); } +bool ExpressionLayout::addGreySquaresToAllMatrixAncestors() { + bool addedSquares = false; + ExpressionLayout * currentAncestor = m_parent; + while (currentAncestor != nullptr) { + if (currentAncestor->isMatrix()) { + static_cast(currentAncestor)->addGreySquares(); + addedSquares = true; + } + currentAncestor = currentAncestor->editableParent(); + } + return addedSquares; +} + bool ExpressionLayout::hasText() const { // A layout has text if it is not empty and it is not an horizontal layout // with no child or with one child with no text. @@ -309,6 +322,7 @@ bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutC } cursor->setPointedExpressionLayout(*childResultPtr); cursor->setPosition(resultPosition); + *shouldRecomputeLayout = (*childResultPtr)->addGreySquaresToAllMatrixAncestors(); return true; } diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index fbec5bd3a..282e99081 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -275,24 +275,6 @@ ExpressionLayout * dummyGridLayout = new GridLayout(children(), m_numberOfRows, return GridLayout::positionOfChild(child).translatedBy(dummyLayout.positionOfChild(dummyGridLayout)); } -void MatrixLayout::moveCursorInsideAtDirection ( - VerticalDirection direction, - ExpressionLayoutCursor * cursor, - bool * shouldRecomputeLayout, - ExpressionLayout ** childResult, - void * resultPosition, - int * resultScore) -{ - GridLayout::moveCursorInsideAtDirection(direction, cursor, shouldRecomputeLayout, childResult, resultPosition, resultScore); - if (*childResult != this) { - // Add the grey squares if the cursor is pointing at a matrix descendant, - // not at the matrix itself. - assert(!hasGreySquares()); - addGreySquares(); - *shouldRecomputeLayout = true; - } -} - bool MatrixLayout::isRowEmpty(int index) const { assert(index >= 0 && index < m_numberOfRows); for (int i = index * m_numberOfColumns; i < (index+1) * m_numberOfColumns; i++) { diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 767686e37..0c595d32d 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -38,13 +38,6 @@ protected: KDSize computeSize() override; KDPoint positionOfChild(ExpressionLayout * child) override; private: - void moveCursorInsideAtDirection ( - VerticalDirection direction, - ExpressionLayoutCursor * cursor, - bool * shouldRecomputeLayout, - ExpressionLayout ** childResult, - void * resultPosition, - int * resultScore) override; void childWasReplacedAtIndex(int index); bool isRowEmpty(int index) const; bool isColumnEmpty(int index) const; From 90068b5cc764f7b7199dfd2e1394b79e5badafd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 31 Jan 2018 10:32:07 +0100 Subject: [PATCH 241/257] [poincare] Fix Matrix copy bug. When selecting a matrix in the calculation history and pressing 'OK', in the apps Calculation, there was a nullptr bug. Change-Id: I8f05771b76bcb3c68b51cf8ca33a49011144abf9 --- escher/src/scrollable_expression_view_with_cursor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escher/src/scrollable_expression_view_with_cursor.cpp b/escher/src/scrollable_expression_view_with_cursor.cpp index fd0f07a1b..c80e887a8 100644 --- a/escher/src/scrollable_expression_view_with_cursor.cpp +++ b/escher/src/scrollable_expression_view_with_cursor.cpp @@ -199,7 +199,7 @@ void ScrollableExpressionViewWithCursor::insertLayoutAtCursor(Poincare::Expressi return; } KDSize previousSize = minimalSizeForOptimalDisplay(); - if (layout->isMatrix() && pointedLayout->hasAncestor(layout)) { + if (layout->isMatrix() && pointedLayout && pointedLayout->hasAncestor(layout)) { static_cast(layout)->addGreySquares(); } if (pointedLayout != nullptr) { From ac84a2e045a492ecb10fce43304c1190d8fecb80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Apr 2018 17:26:49 +0200 Subject: [PATCH 242/257] [poincare] Fix EmptyExpression. Change-Id: I317bbb546af5a42de3c896b2e9a92a8040a95d22 --- poincare/include/poincare/empty_expression.h | 5 +++-- poincare/src/empty_expression.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/poincare/include/poincare/empty_expression.h b/poincare/include/poincare/empty_expression.h index e56ecc47a..09d1cbb9d 100644 --- a/poincare/include/poincare/empty_expression.h +++ b/poincare/include/poincare/empty_expression.h @@ -14,9 +14,10 @@ public: return Type::EmptyExpression; } Expression * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override;private: + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; +private: /* Layout */ - ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override; + ExpressionLayout * privateCreateLayout(PrintFloat::Mode floatDisplayMode, ComplexFormat complexFormat) const override; /* Evaluation */ Expression * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } Expression * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate(context, angleUnit); } diff --git a/poincare/src/empty_expression.cpp b/poincare/src/empty_expression.cpp index b9d7ae2fd..455e26b59 100644 --- a/poincare/src/empty_expression.cpp +++ b/poincare/src/empty_expression.cpp @@ -13,11 +13,11 @@ Expression * EmptyExpression::clone() const { return new EmptyExpression(); } -int EmptyExpression::writeTextInBuffer(char * buffer, int bufferSize) const { +int EmptyExpression::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, Ion::Charset::Empty); } -ExpressionLayout * EmptyExpression::privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const { +ExpressionLayout * EmptyExpression::privateCreateLayout(PrintFloat::Mode floatDisplayMode, ComplexFormat complexFormat) const { return new EmptyVisibleLayout(); } From f504b52dac235c711a45b214a9e65e3bf9a6cbf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Apr 2018 17:27:10 +0200 Subject: [PATCH 243/257] [poincare] Remove un-needed function typedef. Change-Id: I36b17a1978f03e51064c8e11768dcc9fad5b9b35 --- poincare/include/poincare/layout_engine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/poincare/include/poincare/layout_engine.h b/poincare/include/poincare/layout_engine.h index 1be9c9f08..818f38e82 100644 --- a/poincare/include/poincare/layout_engine.h +++ b/poincare/include/poincare/layout_engine.h @@ -18,7 +18,6 @@ public: static ExpressionLayout * createLogLayout(ExpressionLayout * argument, ExpressionLayout * index); /* Expression to Text */ - typedef bool (*OperandNeedsParenthesis)(const Expression * e); static int writeInfixExpressionTextInBuffer( const Expression * expression, char * buffer, From 9f9692b009897a8d9a79c3b580fff8a75a977f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Apr 2018 17:49:51 +0200 Subject: [PATCH 244/257] [poincare] Add numberOfSignificantDigits arguent in writetextInBuffer Change-Id: I1bef3462dbdfd94bff0af0e9d569d0ecf63d157c --- poincare/include/poincare/expression_layout.h | 3 ++- poincare/include/poincare/integer.h | 3 ++- poincare/src/layout/absolute_value_layout.h | 5 +++-- poincare/src/layout/binomial_coefficient_layout.h | 5 +++-- poincare/src/layout/bracket_layout.cpp | 2 +- poincare/src/layout/bracket_layout.h | 3 ++- poincare/src/layout/bracket_left_layout.h | 2 +- poincare/src/layout/bracket_right_layout.h | 2 +- poincare/src/layout/ceiling_layout.h | 4 ++-- poincare/src/layout/char_layout.h | 2 +- poincare/src/layout/condensed_sum_layout.h | 4 ++-- poincare/src/layout/conjugate_layout.h | 4 ++-- poincare/src/layout/empty_visible_layout.cpp | 2 +- poincare/src/layout/empty_visible_layout.h | 2 +- poincare/src/layout/floor_layout.h | 4 ++-- poincare/src/layout/fraction_layout.cpp | 4 ++-- poincare/src/layout/fraction_layout.h | 2 +- poincare/src/layout/grid_layout.h | 2 +- poincare/src/layout/horizontal_layout.cpp | 4 ++-- poincare/src/layout/horizontal_layout.h | 2 +- poincare/src/layout/integral_layout.cpp | 8 ++++---- poincare/src/layout/integral_layout.h | 2 +- poincare/src/layout/matrix_layout.cpp | 4 ++-- poincare/src/layout/matrix_layout.h | 2 +- poincare/src/layout/nth_root_layout.cpp | 8 ++++---- poincare/src/layout/nth_root_layout.h | 2 +- poincare/src/layout/parenthesis_left_layout.h | 2 +- poincare/src/layout/parenthesis_right_layout.h | 2 +- poincare/src/layout/product_layout.cpp | 4 ++-- poincare/src/layout/product_layout.h | 2 +- poincare/src/layout/sequence_layout.cpp | 8 ++++---- poincare/src/layout/sequence_layout.h | 2 +- poincare/src/layout/sum_layout.cpp | 4 ++-- poincare/src/layout/sum_layout.h | 2 +- poincare/src/layout/vertical_offset_layout.cpp | 6 +++--- poincare/src/layout/vertical_offset_layout.h | 2 +- 36 files changed, 63 insertions(+), 58 deletions(-) diff --git a/poincare/include/poincare/expression_layout.h b/poincare/include/poincare/expression_layout.h index 8de6d3878..ec5bc978c 100644 --- a/poincare/include/poincare/expression_layout.h +++ b/poincare/include/poincare/expression_layout.h @@ -2,6 +2,7 @@ #define POINCARE_EXPRESSION_LAYOUT_H #include +#include namespace Poincare { @@ -92,7 +93,7 @@ public: virtual bool moveDownInside(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout); /* Expression Engine */ - virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0; + virtual int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const = 0; /* Other */ bool addGreySquaresToAllMatrixAncestors(); diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index 3889d28c2..659e446e6 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -3,10 +3,11 @@ #include #include -#include namespace Poincare { +class ExpressionLayout; + /* All algorithm should be improved with: * Modern Computer Arithmetic, Richard P. Brent and Paul Zimmermann */ diff --git a/poincare/src/layout/absolute_value_layout.h b/poincare/src/layout/absolute_value_layout.h index 0be2b78a8..eddb3ad55 100644 --- a/poincare/src/layout/absolute_value_layout.h +++ b/poincare/src/layout/absolute_value_layout.h @@ -3,6 +3,7 @@ #include "bracket_layout.h" #include +#include namespace Poincare { @@ -10,8 +11,8 @@ class AbsoluteValueLayout : public BracketLayout { public: using BracketLayout::BracketLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "abs"); + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "abs"); } protected: KDCoordinate widthMargin() const override { return 2; } diff --git a/poincare/src/layout/binomial_coefficient_layout.h b/poincare/src/layout/binomial_coefficient_layout.h index a77b9426b..5ba22a114 100644 --- a/poincare/src/layout/binomial_coefficient_layout.h +++ b/poincare/src/layout/binomial_coefficient_layout.h @@ -3,6 +3,7 @@ #include #include +#include namespace Poincare { @@ -14,8 +15,8 @@ public: bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout = nullptr, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "binomial"); + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "binomial"); } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/bracket_layout.cpp b/poincare/src/layout/bracket_layout.cpp index 9fe511f88..5544e628c 100644 --- a/poincare/src/layout/bracket_layout.cpp +++ b/poincare/src/layout/bracket_layout.cpp @@ -80,7 +80,7 @@ bool BracketLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shouldReco return false; } -int BracketLayout::writeTextInBuffer(char * buffer, int bufferSize) const { +int BracketLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { if (bufferSize == 0) { return -1; } diff --git a/poincare/src/layout/bracket_layout.h b/poincare/src/layout/bracket_layout.h index 9c9deaf66..6ddb363b7 100644 --- a/poincare/src/layout/bracket_layout.h +++ b/poincare/src/layout/bracket_layout.h @@ -2,6 +2,7 @@ #define POINCARE_BRACKET_LAYOUT_H #include +#include namespace Poincare { @@ -12,7 +13,7 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; protected: ExpressionLayout * operandLayout(); KDCoordinate externWidthMargin() const { return 2; } diff --git a/poincare/src/layout/bracket_left_layout.h b/poincare/src/layout/bracket_left_layout.h index 77f9f00bb..9db160521 100644 --- a/poincare/src/layout/bracket_left_layout.h +++ b/poincare/src/layout/bracket_left_layout.h @@ -11,7 +11,7 @@ class BracketLeftLayout : public BracketLeftRightLayout { public: using BracketLeftRightLayout::BracketLeftRightLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, '['); } bool isLeftBracket() const override { return true; } diff --git a/poincare/src/layout/bracket_right_layout.h b/poincare/src/layout/bracket_right_layout.h index 726d23694..1b303c0d2 100644 --- a/poincare/src/layout/bracket_right_layout.h +++ b/poincare/src/layout/bracket_right_layout.h @@ -11,7 +11,7 @@ class BracketRightLayout : public BracketLeftRightLayout { public: using BracketLeftRightLayout::BracketLeftRightLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, ']'); } bool isRightBracket() const override { return true; } diff --git a/poincare/src/layout/ceiling_layout.h b/poincare/src/layout/ceiling_layout.h index b09c99f5a..1d60673d4 100644 --- a/poincare/src/layout/ceiling_layout.h +++ b/poincare/src/layout/ceiling_layout.h @@ -10,8 +10,8 @@ class CeilingLayout : public BracketLayout { public: using BracketLayout::BracketLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "ceil"); + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "ceil"); } protected: bool renderBottomBar() const override { return false; } diff --git a/poincare/src/layout/char_layout.h b/poincare/src/layout/char_layout.h index 48a7590c2..90b7de8bb 100644 --- a/poincare/src/layout/char_layout.h +++ b/poincare/src/layout/char_layout.h @@ -11,7 +11,7 @@ class CharLayout : public StaticLayoutHierarchy<0> { public: CharLayout(char c, KDText::FontSize fontSize = KDText::FontSize::Large); ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, m_char); } diff --git a/poincare/src/layout/condensed_sum_layout.h b/poincare/src/layout/condensed_sum_layout.h index 3026ef0b5..aa76d39d9 100644 --- a/poincare/src/layout/condensed_sum_layout.h +++ b/poincare/src/layout/condensed_sum_layout.h @@ -14,8 +14,8 @@ public: bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "sum"); + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "sum"); } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/conjugate_layout.h b/poincare/src/layout/conjugate_layout.h index 5b1f2097e..52b7f321e 100644 --- a/poincare/src/layout/conjugate_layout.h +++ b/poincare/src/layout/conjugate_layout.h @@ -15,8 +15,8 @@ public: bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; void replaceChildAndMoveCursor(const ExpressionLayout * oldChild, ExpressionLayout * newChild, bool deleteOldChild, ExpressionLayoutCursor * cursor) override; void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "conj"); + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "conj"); } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/empty_visible_layout.cpp b/poincare/src/layout/empty_visible_layout.cpp index bcc59d66c..770ef69a5 100644 --- a/poincare/src/layout/empty_visible_layout.cpp +++ b/poincare/src/layout/empty_visible_layout.cpp @@ -61,7 +61,7 @@ bool EmptyVisibleLayout::moveRight(ExpressionLayoutCursor * cursor, bool * shoul return false; } -int EmptyVisibleLayout::writeTextInBuffer(char * buffer, int bufferSize) const { +int EmptyVisibleLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { if (bufferSize == 0) { return -1; } diff --git a/poincare/src/layout/empty_visible_layout.h b/poincare/src/layout/empty_visible_layout.h index c554a9188..c9d0aa123 100644 --- a/poincare/src/layout/empty_visible_layout.h +++ b/poincare/src/layout/empty_visible_layout.h @@ -17,7 +17,7 @@ public: void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; bool moveLeft(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; bool isEmpty() const override { return true; } Color color() const { return m_color; } void setColor(Color color) { m_color = color; } diff --git a/poincare/src/layout/floor_layout.h b/poincare/src/layout/floor_layout.h index 5e5a9785b..8d8d65227 100644 --- a/poincare/src/layout/floor_layout.h +++ b/poincare/src/layout/floor_layout.h @@ -10,8 +10,8 @@ class FloorLayout : public BracketLayout { public: using BracketLayout::BracketLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "floor"); + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "floor"); } protected: bool renderTopBar() const override { return false; } diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 82e6956ff..173394484 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -154,7 +154,7 @@ bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldReco return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize) const { +int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const { if (bufferSize == 0) { return -1; } @@ -174,7 +174,7 @@ int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize) const { } // Write the content of the fraction - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, "/"); + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits "/"); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Add a multiplication if omitted. diff --git a/poincare/src/layout/fraction_layout.h b/poincare/src/layout/fraction_layout.h index 044d60158..c71dd5ef9 100644 --- a/poincare/src/layout/fraction_layout.h +++ b/poincare/src/layout/fraction_layout.h @@ -15,7 +15,7 @@ public: bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; bool canBeOmittedMultiplicationRightFactor() const override { return false; } /* WARNING: We need to override this function, else 1/2 3/4 would be * serialized as 1/2**3/4, as the two Fraction layouts think their brother is diff --git a/poincare/src/layout/grid_layout.h b/poincare/src/layout/grid_layout.h index 9bd6b467e..b0e981ae4 100644 --- a/poincare/src/layout/grid_layout.h +++ b/poincare/src/layout/grid_layout.h @@ -24,7 +24,7 @@ public: // grid's children, do not call this function. /* Expression engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override { return 0; } + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { return 0; } protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index 63bd346c5..adbb8a68d 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -298,7 +298,7 @@ void HorizontalLayout::mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int ind DynamicLayoutHierarchy::mergeChildrenAtIndex(eL, newIndex, removeEmptyChildren); } -int HorizontalLayout::writeTextInBuffer(char * buffer, int bufferSize) const { +int HorizontalLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const { if (numberOfChildren() == 0) { if (bufferSize == 0) { return -1; @@ -306,7 +306,7 @@ int HorizontalLayout::writeTextInBuffer(char * buffer, int bufferSize) const { buffer[0] = 0; return 0; } - return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, ""); + return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, ""); } bool HorizontalLayout::isEmpty() const { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index 5d3c6d9d7..e714e73a9 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -34,7 +34,7 @@ public: void mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int index, bool removeEmptyChildren) override; /* Expression Engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; /* Other */ bool isHorizontal() const override { return true; } diff --git a/poincare/src/layout/integral_layout.cpp b/poincare/src/layout/integral_layout.cpp index 48941a195..2184a1cd3 100644 --- a/poincare/src/layout/integral_layout.cpp +++ b/poincare/src/layout/integral_layout.cpp @@ -160,7 +160,7 @@ bool IntegralLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldReco return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize) const { +int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { if (bufferSize == 0) { return -1; } @@ -179,7 +179,7 @@ int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize) const { } // Write the argument - numberOfChar += const_cast(this)->integrandLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += const_cast(this)->integrandLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the comma @@ -187,7 +187,7 @@ int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize) const { if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the lower bound - numberOfChar += const_cast(this)->lowerBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += const_cast(this)->lowerBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the comma @@ -195,7 +195,7 @@ int IntegralLayout::writeTextInBuffer(char * buffer, int bufferSize) const { if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the upper bound - numberOfChar += const_cast(this)->upperBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += const_cast(this)->upperBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the closing parenthesis diff --git a/poincare/src/layout/integral_layout.h b/poincare/src/layout/integral_layout.h index 6241c756d..a5866df1b 100644 --- a/poincare/src/layout/integral_layout.h +++ b/poincare/src/layout/integral_layout.h @@ -23,7 +23,7 @@ public: bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; /* Expression Engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/matrix_layout.cpp b/poincare/src/layout/matrix_layout.cpp index 282e99081..209d3455f 100644 --- a/poincare/src/layout/matrix_layout.cpp +++ b/poincare/src/layout/matrix_layout.cpp @@ -165,7 +165,7 @@ void MatrixLayout::removePointedChildAtIndexAndMoveCursor(int index, bool delete replaceChildAndMoveCursor(child(index), new EmptyVisibleLayout(), deleteAfterRemoval, cursor); } -int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { +int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { // The grid is a matrix. if (bufferSize == 0) { return -1; @@ -183,7 +183,7 @@ int MatrixLayout::writeTextInBuffer(char * buffer, int bufferSize) const { buffer[numberOfChar++] = '['; if (numberOfChar >= bufferSize-1) { return bufferSize-1;} - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, ",", i*m_numberOfColumns, i* m_numberOfColumns + maxColumnIndex); + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits, ",", i*m_numberOfColumns, i* m_numberOfColumns + maxColumnIndex); buffer[numberOfChar++] = ']'; if (numberOfChar >= bufferSize-1) { return bufferSize-1; } diff --git a/poincare/src/layout/matrix_layout.h b/poincare/src/layout/matrix_layout.h index 0c595d32d..f18cba8aa 100644 --- a/poincare/src/layout/matrix_layout.h +++ b/poincare/src/layout/matrix_layout.h @@ -24,7 +24,7 @@ public: void removePointedChildAtIndexAndMoveCursor(int index, bool deleteAfterRemoval, ExpressionLayoutCursor * cursor) override; /* Expression engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; /* Other */ bool isMatrix() const override { return true; } diff --git a/poincare/src/layout/nth_root_layout.cpp b/poincare/src/layout/nth_root_layout.cpp index 291171463..80ce7f0cc 100644 --- a/poincare/src/layout/nth_root_layout.cpp +++ b/poincare/src/layout/nth_root_layout.cpp @@ -171,17 +171,17 @@ bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecom } static_assert('\x90' == Ion::Charset::Root, "Unicode error"); -int NthRootLayout::writeTextInBuffer(char * buffer, int bufferSize) const { +int NthRootLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { // Case: root(x,n) if (numberOfChildren() == 2 && (const_cast(this))->indexLayout() && !(const_cast(this))->indexLayout()->isEmpty()) { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "root"); + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "root"); } // Case: squareRoot(x) if (numberOfChildren() == 1) { - return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "\x90"); + return LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "\x90"); } // Case: root(x,empty) // Write "'SquareRootSymbol'('radicandLayout')". @@ -202,7 +202,7 @@ int NthRootLayout::writeTextInBuffer(char * buffer, int bufferSize) const { return bufferSize-1; } - numberOfChar += (const_cast(this))->radicandLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += (const_cast(this))->radicandLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } buffer[numberOfChar++] = ')'; diff --git a/poincare/src/layout/nth_root_layout.h b/poincare/src/layout/nth_root_layout.h index db5eec064..c46ccbe86 100644 --- a/poincare/src/layout/nth_root_layout.h +++ b/poincare/src/layout/nth_root_layout.h @@ -23,7 +23,7 @@ public: bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; /* Expression Engine */ - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; diff --git a/poincare/src/layout/parenthesis_left_layout.h b/poincare/src/layout/parenthesis_left_layout.h index 468385383..99c070fe4 100644 --- a/poincare/src/layout/parenthesis_left_layout.h +++ b/poincare/src/layout/parenthesis_left_layout.h @@ -12,7 +12,7 @@ class ParenthesisLeftLayout : public ParenthesisLeftRightLayout { public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, '('); } bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; diff --git a/poincare/src/layout/parenthesis_right_layout.h b/poincare/src/layout/parenthesis_right_layout.h index fb372b06c..edf361dfb 100644 --- a/poincare/src/layout/parenthesis_right_layout.h +++ b/poincare/src/layout/parenthesis_right_layout.h @@ -12,7 +12,7 @@ class ParenthesisRightLayout : public ParenthesisLeftRightLayout { public: using ParenthesisLeftRightLayout::ParenthesisLeftRightLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override { + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override { return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, ')'); } bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override; diff --git a/poincare/src/layout/product_layout.cpp b/poincare/src/layout/product_layout.cpp index 2b9120db7..f850b8860 100644 --- a/poincare/src/layout/product_layout.cpp +++ b/poincare/src/layout/product_layout.cpp @@ -9,8 +9,8 @@ ExpressionLayout * ProductLayout::clone() const { return layout; } -int ProductLayout::writeTextInBuffer(char * buffer, int bufferSize) const { - return SequenceLayout::writeDerivedClassInBuffer("product", buffer, bufferSize); +int ProductLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { + return SequenceLayout::writeDerivedClassInBuffer("product", buffer, bufferSize, numberOfSignificantDigits); } void ProductLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { diff --git a/poincare/src/layout/product_layout.h b/poincare/src/layout/product_layout.h index 72750ebbb..090aab63d 100644 --- a/poincare/src/layout/product_layout.h +++ b/poincare/src/layout/product_layout.h @@ -10,7 +10,7 @@ class ProductLayout : public SequenceLayout { public: using SequenceLayout::SequenceLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; private: diff --git a/poincare/src/layout/sequence_layout.cpp b/poincare/src/layout/sequence_layout.cpp index 94a64aa37..dd1066051 100644 --- a/poincare/src/layout/sequence_layout.cpp +++ b/poincare/src/layout/sequence_layout.cpp @@ -136,7 +136,7 @@ char SequenceLayout::XNTChar() const { return 'n'; } -int SequenceLayout::writeDerivedClassInBuffer(const char * operatorName, char * buffer, int bufferSize) const { +int SequenceLayout::writeDerivedClassInBuffer(const char * operatorName, char * buffer, int bufferSize, int numberOfSignificantDigits) const { assert(operatorName != nullptr); if (bufferSize == 0) { return -1; @@ -152,7 +152,7 @@ int SequenceLayout::writeDerivedClassInBuffer(const char * operatorName, char * if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the argument - numberOfChar += const_cast(this)->argumentLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += const_cast(this)->argumentLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the comma @@ -160,7 +160,7 @@ int SequenceLayout::writeDerivedClassInBuffer(const char * operatorName, char * if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the lower bound - numberOfChar += const_cast(this)->lowerBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += const_cast(this)->lowerBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the comma @@ -168,7 +168,7 @@ int SequenceLayout::writeDerivedClassInBuffer(const char * operatorName, char * if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the upper bound - numberOfChar += const_cast(this)->upperBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += const_cast(this)->upperBoundLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Write the closing parenthesis diff --git a/poincare/src/layout/sequence_layout.h b/poincare/src/layout/sequence_layout.h index 7299ca914..164ead79d 100644 --- a/poincare/src/layout/sequence_layout.h +++ b/poincare/src/layout/sequence_layout.h @@ -19,7 +19,7 @@ public: protected: constexpr static KDCoordinate k_boundHeightMargin = 2; constexpr static KDCoordinate k_argumentWidthMargin = 2; - int writeDerivedClassInBuffer(const char * operatorName, char * buffer, int bufferSize) const; + int writeDerivedClassInBuffer(const char * operatorName, char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const; ExpressionLayout * lowerBoundLayout(); ExpressionLayout * upperBoundLayout(); ExpressionLayout * argumentLayout(); diff --git a/poincare/src/layout/sum_layout.cpp b/poincare/src/layout/sum_layout.cpp index a38117c97..41c274556 100644 --- a/poincare/src/layout/sum_layout.cpp +++ b/poincare/src/layout/sum_layout.cpp @@ -27,8 +27,8 @@ ExpressionLayout * SumLayout::clone() const { return layout; } -int SumLayout::writeTextInBuffer(char * buffer, int bufferSize) const { - return SequenceLayout::writeDerivedClassInBuffer("sum", buffer, bufferSize); +int SumLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { + return SequenceLayout::writeDerivedClassInBuffer("sum", buffer, bufferSize, numberOfSignificantDigits); } void SumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { diff --git a/poincare/src/layout/sum_layout.h b/poincare/src/layout/sum_layout.h index 4f8228921..205ee0831 100644 --- a/poincare/src/layout/sum_layout.h +++ b/poincare/src/layout/sum_layout.h @@ -10,7 +10,7 @@ class SumLayout : public SequenceLayout { public: using SequenceLayout::SequenceLayout; ExpressionLayout * clone() const override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; private: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; }; diff --git a/poincare/src/layout/vertical_offset_layout.cpp b/poincare/src/layout/vertical_offset_layout.cpp index 5180c986f..0448502f2 100644 --- a/poincare/src/layout/vertical_offset_layout.cpp +++ b/poincare/src/layout/vertical_offset_layout.cpp @@ -185,7 +185,7 @@ bool VerticalOffsetLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shou return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -int VerticalOffsetLayout::writeTextInBuffer(char * buffer, int bufferSize) const { +int VerticalOffsetLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { if (m_type == Type::Subscript) { if (bufferSize == 0) { return -1; @@ -201,7 +201,7 @@ int VerticalOffsetLayout::writeTextInBuffer(char * buffer, int bufferSize) const numberOfChar += LayoutEngine::writeOneCharInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, '{'); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } - numberOfChar += const_cast(this)->indiceLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar); + numberOfChar += const_cast(this)->indiceLayout()->writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } numberOfChar += LayoutEngine::writeOneCharInBuffer(buffer+numberOfChar, bufferSize-numberOfChar, '}'); @@ -211,7 +211,7 @@ int VerticalOffsetLayout::writeTextInBuffer(char * buffer, int bufferSize) const } assert(m_type == Type::Superscript); // If the layout is a superscript, write "^(indice)" - int numberOfChar = LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, "^"); + int numberOfChar = LayoutEngine::writePrefixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "^"); // Add a multiplication if omitted. int indexInParent = -1; diff --git a/poincare/src/layout/vertical_offset_layout.h b/poincare/src/layout/vertical_offset_layout.h index bfceadee1..d63ca2e9c 100644 --- a/poincare/src/layout/vertical_offset_layout.h +++ b/poincare/src/layout/vertical_offset_layout.h @@ -18,7 +18,7 @@ public: bool moveRight(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override; bool moveUp(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; bool moveDown(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override; - int writeTextInBuffer(char * buffer, int bufferSize) const override; + int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override; bool mustHaveLeftBrother() const override { return true; } protected: ExpressionLayout * indiceLayout(); From 6044ca8493732cb5bed482040c5d0813653e6c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Apr 2018 17:55:31 +0200 Subject: [PATCH 245/257] [poincare] Fix too many arguments problem Change-Id: Ie3018b2b82f0c87b1551ab2bcd9c80bb41212ecb --- poincare/src/layout_engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poincare/src/layout_engine.cpp b/poincare/src/layout_engine.cpp index dd0a6c68b..9b2e43ddb 100644 --- a/poincare/src/layout_engine.cpp +++ b/poincare/src/layout_engine.cpp @@ -87,7 +87,7 @@ int LayoutEngine::writePrefixExpressionTextInBuffer(const Expression * expressio } int LayoutEngine::writeInfixExpressionLayoutTextInBuffer(const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, int numberOfDigits, const char * operatorName, int firstChildIndex, int lastChildIndex, ChildNeedsParenthesis childNeedsParenthesis) { - return writeInfixExpressionOrExpressionLayoutTextInBuffer(nullptr, expressionLayout, buffer, bufferSize, numberOfDigits, operatorName, firstChildIndex, lastChildIndex, [](const Expression * e) { return true; }, childNeedsParenthesis); + return writeInfixExpressionOrExpressionLayoutTextInBuffer(nullptr, expressionLayout, buffer, bufferSize, numberOfDigits, operatorName, firstChildIndex, lastChildIndex, childNeedsParenthesis); } int LayoutEngine::writePrefixExpressionLayoutTextInBuffer(const ExpressionLayout * expressionLayout, char * buffer, int bufferSize, int numberOfDigits, const char * operatorName, bool writeFirstChild) { From 0e67cc6b11b7f0e10de5645521526d5e98e8a587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Apr 2018 17:56:13 +0200 Subject: [PATCH 246/257] [poincare] Add missing header Change-Id: Ic0a90940b16a3d4c30c85e22fba9ab5d4f1006c8 --- poincare/src/symbol.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 545a64217..abcb886f2 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include From 1c6e8119b3b6b5147376bb9d6d0ed93a4e0e5070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Apr 2018 18:03:19 +0200 Subject: [PATCH 247/257] [apps] Remove use of StringLayout Change-Id: I4b8cac2fa778ebddb3e2b1f3f0f75182deb45a61 --- apps/shared/sum_graph_controller.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 0f162a333..52f351b61 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -1,8 +1,7 @@ #include "sum_graph_controller.h" #include "../apps_container.h" +#include #include "../../poincare/src/layout/condensed_sum_layout.h" -#include "../../poincare/src/layout/string_layout.h" -#include "../../poincare/src/layout/horizontal_layout.h" #include #include @@ -245,23 +244,23 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl } const char sigma[] = {' ', m_sumSymbol}; if (step == Step::FirstParameter) { - m_sumLayout = new StringLayout(sigma, sizeof(sigma)); + m_sumLayout = LayoutEngine::createStringLayout(sigma, sizeof(sigma)); } else if (step == Step::SecondParameter) { char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)]; PrintFloat::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, PrintFloat::Mode::Decimal); - m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr); + m_sumLayout = new CondensedSumLayout(LayoutEngine::createStringLayout(sigma, sizeof(sigma)), LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr); } else { char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; PrintFloat::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal); - ExpressionLayout * start = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small); + ExpressionLayout * start = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small); PrintFloat::convertFloatToText(end, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal); - ExpressionLayout * end = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small); - m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), start, end); + ExpressionLayout * end = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small); + m_sumLayout = new CondensedSumLayout(LayoutEngine::createStringLayout(sigma, sizeof(sigma)), start, end); ExpressionLayout * childrenLayouts[3]; strlcpy(buffer, "= ", 3); PrintFloat::convertFloatToText(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - childrenLayouts[2] = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small); + childrenLayouts[2] = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small); childrenLayouts[1] = functionLayout; childrenLayouts[0] = m_sumLayout; m_sumLayout = new HorizontalLayout(childrenLayouts, 3); From a6e6416e09ca3d1bf9b37b98a4f7ba9baac2e8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Apr 2018 18:03:40 +0200 Subject: [PATCH 248/257] [poincare] Fix code typos Change-Id: I02143e1b99d3cf2f4ced6954bf2e612542c01642 --- poincare/src/layout/fraction_layout.cpp | 4 ++-- poincare/src/layout/horizontal_layout.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/poincare/src/layout/fraction_layout.cpp b/poincare/src/layout/fraction_layout.cpp index 173394484..7702cad28 100644 --- a/poincare/src/layout/fraction_layout.cpp +++ b/poincare/src/layout/fraction_layout.cpp @@ -154,7 +154,7 @@ bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, bool * shouldReco return ExpressionLayout::moveDown(cursor, shouldRecomputeLayout, previousLayout, previousPreviousLayout); } -int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const { +int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { if (bufferSize == 0) { return -1; } @@ -174,7 +174,7 @@ int FractionLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberO } // Write the content of the fraction - numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits "/"); + numberOfChar += LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer+numberOfChar, bufferSize-numberOfChar, numberOfSignificantDigits, "/"); if (numberOfChar >= bufferSize-1) { return bufferSize-1; } // Add a multiplication if omitted. diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index adbb8a68d..7c454e760 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -298,7 +298,7 @@ void HorizontalLayout::mergeChildrenAtIndex(DynamicLayoutHierarchy * eL, int ind DynamicLayoutHierarchy::mergeChildrenAtIndex(eL, newIndex, removeEmptyChildren); } -int HorizontalLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const { +int HorizontalLayout::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { if (numberOfChildren() == 0) { if (bufferSize == 0) { return -1; From 7991c5376fb7f4de17861b99f68df6f27f4f7680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Tue, 10 Apr 2018 18:14:55 +0200 Subject: [PATCH 249/257] [apps] Fix typos Change-Id: I650d0d98daab5959e9efab79b78905533316b85d --- apps/shared/sum_graph_controller.cpp | 4 ++-- apps/shared/sum_graph_controller.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 52f351b61..f646a4029 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -144,7 +144,7 @@ bool SumGraphController::textFieldDidFinishEditing(TextField * textField, const return false; } -bool SumGraphController::textFieldDidAbortEditing(TextField * textField, const char * text) { +bool SumGraphController::textFieldDidAbortEditing(TextField * textField) { char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)]; double parameter = NAN; switch(m_step) { @@ -265,7 +265,7 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl childrenLayouts[0] = m_sumLayout; m_sumLayout = new HorizontalLayout(childrenLayouts, 3); } - m_sum.setExpression(m_sumLayout); + m_sum.setExpressionLayout(m_sumLayout); if (step == Step::Result) { m_sum.setAlignment(0.5f, 0.5f); } else { diff --git a/apps/shared/sum_graph_controller.h b/apps/shared/sum_graph_controller.h index 4915de927..98a110957 100644 --- a/apps/shared/sum_graph_controller.h +++ b/apps/shared/sum_graph_controller.h @@ -20,7 +20,7 @@ public: bool handleEvent(Ion::Events::Event event) override; void setFunction(Function * function); bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; - bool textFieldDidAbortEditing(TextField * textField, const char * text) override; + bool textFieldDidAbortEditing(TextField * textField) override; bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; protected: virtual bool moveCursorHorizontallyToPosition(double position); From 6d3c67e9db47ed8cf34ac480f9d513cfc8f1daa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Apr 2018 10:21:25 +0200 Subject: [PATCH 250/257] [apps] Merge apps/sequence/graph/term_sum_controller.cpp Change-Id: I9cbcbb73f4f475590762e29ab98999bd42906e74 --- apps/sequence/graph/term_sum_controller.cpp | 113 +------------------- 1 file changed, 5 insertions(+), 108 deletions(-) diff --git a/apps/sequence/graph/term_sum_controller.cpp b/apps/sequence/graph/term_sum_controller.cpp index 1cdf439c8..4d0574fae 100644 --- a/apps/sequence/graph/term_sum_controller.cpp +++ b/apps/sequence/graph/term_sum_controller.cpp @@ -2,9 +2,7 @@ #include "../../shared/text_field_delegate.h" #include "../app.h" -#include #include "../../../poincare/src/layout/char_layout.h" -#include "../../../poincare/src/layout/condensed_sum_layout.h" #include "../../../poincare/src/layout/horizontal_layout.h" #include "../../../poincare/src/layout/vertical_offset_layout.h" @@ -52,115 +50,14 @@ double TermSumController::cursorNextStep(double x, int direction) { return std::round(m_cursor->x()+delta); } -<<<<<<< HEAD ExpressionLayout * TermSumController::createFunctionLayout(const char * functionName) { - return new BaselineRelativeLayout(new StringLayout(functionName, 1, KDText::FontSize::Small), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); -======= -/* Legend View */ - -TermSumController::LegendView::LegendView() : - m_sum(0.0f, 0.5f, KDColorBlack, Palette::GreyBright), - m_sumLayout(nullptr), - m_legend(KDText::FontSize::Small, I18n::Message::Default, 0.0f, 0.5f, KDColorBlack, Palette::GreyBright) -{ -} - -TermSumController::LegendView::~LegendView() { - if (m_sumLayout != nullptr) { - delete m_sumLayout; - m_sumLayout = nullptr; - } -} - -void TermSumController::LegendView::drawRect(KDContext * ctx, KDRect rect) const { - ctx->fillRect(KDRect(0, bounds().height() - k_legendHeight, bounds().width(), k_legendHeight), Palette::GreyMiddle); -} - -KDSize TermSumController::LegendView::minimalSizeForOptimalDisplay() const { - return KDSize(0, k_legendHeight); -} - -void TermSumController::LegendView::setLegendMessage(I18n::Message message) { - m_legend.setMessage(message); - layoutSubviews(); -} - -void TermSumController::LegendView::setSumSubscript(float start) { - if (m_sumLayout) { - delete m_sumLayout; - m_sumLayout = nullptr; - } - const char sigma[] = {' ', Ion::Charset::CapitalSigma}; - char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; - Complex::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); - m_sumLayout = new CondensedSumLayout( - LayoutEngine::createStringLayout(sigma, sizeof(sigma), KDText::FontSize::Large), - LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), - nullptr, - false); - m_sum.setExpressionLayout(m_sumLayout); - m_sum.setAlignment(0.0f, 0.5f); -} - -void TermSumController::LegendView::setSumSuperscript(float start, float end) { - if (m_sumLayout) { - delete m_sumLayout; - m_sumLayout = nullptr; - } - const char sigma[] = {' ', Ion::Charset::CapitalSigma}; - char bufferStart[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; - Complex::convertFloatToText(start, bufferStart, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); - char bufferEnd[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; - Complex::convertFloatToText(end, bufferEnd, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal); - m_sumLayout = new CondensedSumLayout( - LayoutEngine::createStringLayout(sigma, sizeof(sigma), KDText::FontSize::Large), - LayoutEngine::createStringLayout(bufferStart, strlen(bufferStart), KDText::FontSize::Small), - LayoutEngine::createStringLayout(bufferEnd, strlen(bufferEnd), KDText::FontSize::Small), - false); - m_sum.setExpressionLayout(m_sumLayout); - m_sum.setAlignment(0.0f, 0.5f); -} - -void TermSumController::LegendView::setSumResult(const char * sequenceName, double result) { - char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; - strlcpy(buffer, "= ", 3); - Complex::convertFloatToText(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); - m_sumLayout = new HorizontalLayout( - m_sumLayout, - new HorizontalLayout( - new CharLayout(sequenceName[0], KDText::FontSize::Small), - new VerticalOffsetLayout(new CharLayout('n', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), + return new HorizontalLayout( + new CharLayout(functionName[0], KDText::FontSize::Small), + new VerticalOffsetLayout( + new CharLayout('n', KDText::FontSize::Small), + VerticalOffsetLayout::Type::Subscript, false), - LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), false); - m_sum.setExpressionLayout(m_sumLayout); - m_sum.setAlignment(0.5f, 0.5f); -} - -int TermSumController::LegendView::numberOfSubviews() const { - return 2; -} - -View * TermSumController::LegendView::subviewAtIndex(int index) { - assert(index >= 0 && index < 2); - if (index == 0) { - return &m_sum; - } - return &m_legend; -} - -void TermSumController::LegendView::layoutSubviews() { - KDCoordinate width = bounds().width(); - KDCoordinate heigth = bounds().height(); - KDSize legendSize = m_legend.minimalSizeForOptimalDisplay(); - if (legendSize.width() > 0) { - m_sum.setFrame(KDRect(0, 0, width-legendSize.width(), heigth)); - m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth)); - return; - } - m_sum.setFrame(bounds()); - m_legend.setFrame(KDRectZero); ->>>>>>> SaisieJolieRebase1201 } } From 2146dd6422083315204e9cb99f0b89d5f734523d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Apr 2018 10:40:06 +0200 Subject: [PATCH 251/257] [apps] Fix wrong method call Change-Id: I2695d7c659f18edb1839cdf7c8282cc69862a4e5 --- apps/calculation/edit_expression_controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index bcaa408da..37cd3c772 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -158,8 +158,8 @@ bool EditExpressionController::inputViewDidFinishEditing(const char * text, Ion: m_calculationStore->push(textBody(), calculationApp->localContext()); m_historyController->reload(); ((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1); - ((ContentView *)view())->textField()->setEditing(true); - ((ContentView *)view())->textField()->setText(""); + ((ContentView *)view())->editableExpressionView()->setEditing(true); + ((ContentView *)view())->editableExpressionView()->setText(""); return true; } From cbaba85daae76668f614ad8ce9778224f37a316e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Apr 2018 10:41:28 +0200 Subject: [PATCH 252/257] [apps] Fix missing arguments in layout creation. Change-Id: If819c6f8d067b80d5672774ca303b68e21cf0d7a --- apps/shared/sum_graph_controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index f646a4029..27c9f6f56 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -248,7 +248,7 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl } else if (step == Step::SecondParameter) { char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)]; PrintFloat::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, PrintFloat::Mode::Decimal); - m_sumLayout = new CondensedSumLayout(LayoutEngine::createStringLayout(sigma, sizeof(sigma)), LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr); + m_sumLayout = new CondensedSumLayout(LayoutEngine::createStringLayout(sigma, sizeof(sigma)), LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr, false); } else { char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; PrintFloat::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal); @@ -263,7 +263,7 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl childrenLayouts[2] = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small); childrenLayouts[1] = functionLayout; childrenLayouts[0] = m_sumLayout; - m_sumLayout = new HorizontalLayout(childrenLayouts, 3); + m_sumLayout = new HorizontalLayout(childrenLayouts, 3, false); } m_sum.setExpressionLayout(m_sumLayout); if (step == Step::Result) { From 44e8eb1285c549c920df4f9f281b31740d945059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Apr 2018 10:42:20 +0200 Subject: [PATCH 253/257] [escher] EditableExpressionView, fix setEditing It should only apply to the TextField or ScrollableExpressionViewWithCursor depending on the edition mode. Change-Id: I2ae4a3a4e956dc1d51729c9497642b9c236f9069 --- escher/src/editable_expression_view.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/escher/src/editable_expression_view.cpp b/escher/src/editable_expression_view.cpp index add967f2d..00c98bd13 100644 --- a/escher/src/editable_expression_view.cpp +++ b/escher/src/editable_expression_view.cpp @@ -14,11 +14,12 @@ EditableExpressionView::EditableExpressionView(Responder * parentResponder, Text void EditableExpressionView::setEditing(bool isEditing, bool reinitDraftBuffer) { if (editionIsInTextField()) { m_textField.setEditing(isEditing, reinitDraftBuffer); + } else { + if (reinitDraftBuffer) { + m_scrollableExpressionViewWithCursor.clearLayout(); + } + m_scrollableExpressionViewWithCursor.setEditing(isEditing); } - if (reinitDraftBuffer) { - m_scrollableExpressionViewWithCursor.clearLayout(); - } - m_scrollableExpressionViewWithCursor.setEditing(isEditing); } bool EditableExpressionView::isEditing() const { From 5984b24107f339ba085734e24d8892f3095d14ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Apr 2018 16:53:38 +0200 Subject: [PATCH 254/257] [apps] Remove obsolete StringLayout. Change-Id: Ib8ef9f6b89ead2674b3bc1f19131afdd73f0e823 --- apps/graph/graph/integral_graph_controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/graph/graph/integral_graph_controller.cpp b/apps/graph/graph/integral_graph_controller.cpp index 49fd032fc..c83d43113 100644 --- a/apps/graph/graph/integral_graph_controller.cpp +++ b/apps/graph/graph/integral_graph_controller.cpp @@ -1,6 +1,6 @@ #include "integral_graph_controller.h" #include "../../shared/text_field_delegate.h" -#include "../../../poincare/src/layout/string_layout.h" +#include #include "../app.h" #include @@ -39,7 +39,7 @@ double IntegralGraphController::cursorNextStep(double x, int direction) { ExpressionLayout * IntegralGraphController::createFunctionLayout(const char * functionName) { char buffer[7] = "0(x)dx"; buffer[0] = functionName[0]; - return new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small); + return LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small); } } From 749c93e1af9925819bfedc521b49134d01dbb94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Apr 2018 16:56:35 +0200 Subject: [PATCH 255/257] [apps/sequence] Fix obsolete code. Change-Id: I4f6c1792ac245c072a3d70108a55518473c3fe80 --- apps/sequence/list/list_controller.cpp | 2 +- apps/sequence/list/sequence_toolbox.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index 9c3207232..3a4a7f185 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -25,7 +25,7 @@ const char * ListController::title() { Toolbox * ListController::toolboxForTextInput(TextInput * textInput) { setToolboxExtraCells(); - m_sequenceToolbox.setSenderAndAction(textField, MathToolbox::actionForTextInput); + m_sequenceToolbox.setSenderAndAction(textInput, MathToolbox::actionForTextInput); return &m_sequenceToolbox; } diff --git a/apps/sequence/list/sequence_toolbox.cpp b/apps/sequence/list/sequence_toolbox.cpp index 9d321a4cb..04509ceb0 100644 --- a/apps/sequence/list/sequence_toolbox.cpp +++ b/apps/sequence/list/sequence_toolbox.cpp @@ -106,7 +106,7 @@ void SequenceToolbox::setExtraCells(const char * sequenceName, int recurrenceDep false); } for (int index = 0; index < k_maxNumberOfDisplayedRows; index++) { - m_addedCells[index].setExpression(m_addedCellLayout[index]); + m_addedCells[index].setExpressionLayout(m_addedCellLayout[index]); } } @@ -114,7 +114,7 @@ bool SequenceToolbox::selectAddedCell(int selectedRow){ int bufferSize = 10; char buffer[bufferSize]; m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize); - if (m_action == MathToolbox::actionForTextField) { + if (m_action == MathToolbox::actionForTextInput) { // DIRTY. The symbols are layouted using a Subscript VerticalOffsetLayout, // which serializes into "_{}", but we want parentheses for text fields. We // thus need to remove any underscores, and changes brackets into From 88aaab64ba7543000c4d452df59f541b44f6a3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Apr 2018 17:10:09 +0200 Subject: [PATCH 256/257] [apps] Fix obsolete code in Code and Shared Change-Id: Ie6ce0f753bf05cb5f6dd5ed974db2a715b21624e --- apps/code/menu_controller.cpp | 2 +- apps/shared/sum_graph_controller.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/code/menu_controller.cpp b/apps/code/menu_controller.cpp index d85139c24..11338bc88 100644 --- a/apps/code/menu_controller.cpp +++ b/apps/code/menu_controller.cpp @@ -55,7 +55,7 @@ void MenuController::willExitResponderChain(Responder * nextFirstResponder) { TextField * tf = static_cast(m_selectableTableView.selectedCell())->editableTextCell()->textField(); if (tf->isEditing()) { tf->setEditing(false); - textFieldDidAbortEditing(tf, tf->text()); + textFieldDidAbortEditing(tf); } } } diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 27c9f6f56..5244263a7 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -248,15 +248,22 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl } else if (step == Step::SecondParameter) { char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)]; PrintFloat::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, PrintFloat::Mode::Decimal); - m_sumLayout = new CondensedSumLayout(LayoutEngine::createStringLayout(sigma, sizeof(sigma)), LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr, false); + m_sumLayout = new CondensedSumLayout( + LayoutEngine::createStringLayout(sigma, sizeof(sigma)), + LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small), + nullptr, + false); } else { char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)]; PrintFloat::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal); ExpressionLayout * start = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small); PrintFloat::convertFloatToText(end, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal); ExpressionLayout * end = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small); - m_sumLayout = new CondensedSumLayout(LayoutEngine::createStringLayout(sigma, sizeof(sigma)), start, end); - + m_sumLayout = new CondensedSumLayout( + LayoutEngine::createStringLayout(sigma, sizeof(sigma)), + start, + end, + false); ExpressionLayout * childrenLayouts[3]; strlcpy(buffer, "= ", 3); PrintFloat::convertFloatToText(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits); From 0fcd2a90f6680e37242be07404a6c3b1c5b02f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 11 Apr 2018 17:11:05 +0200 Subject: [PATCH 257/257] [apps] Fix comment aesthetics Change-Id: I3e91391f0751515efe50ec4e4335a2421f2acbee --- apps/sequence/list/sequence_toolbox.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/sequence/list/sequence_toolbox.cpp b/apps/sequence/list/sequence_toolbox.cpp index 04509ceb0..08d67f4fd 100644 --- a/apps/sequence/list/sequence_toolbox.cpp +++ b/apps/sequence/list/sequence_toolbox.cpp @@ -115,10 +115,10 @@ bool SequenceToolbox::selectAddedCell(int selectedRow){ char buffer[bufferSize]; m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize); if (m_action == MathToolbox::actionForTextInput) { - // DIRTY. The symbols are layouted using a Subscript VerticalOffsetLayout, - // which serializes into "_{}", but we want parentheses for text fields. We - // thus need to remove any underscores, and changes brackets into - // parentheses. + /* DIRTY. The symbols are layouted using a Subscript VerticalOffsetLayout, + * which serializes into "_{}", but we want parentheses for text fields. We + * thus need to remove any underscores, and changes brackets into + * parentheses. */ for (int i = 0; i < bufferSize; i++) { if (buffer[i] == '{') { buffer[i] = '(';