Merge branch Tree into master

This commit is contained in:
Léa Saviot
2018-07-19 14:01:02 +02:00
219 changed files with 7627 additions and 765 deletions

View File

@@ -66,18 +66,18 @@ bool App::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event e
return false;
}
bool App::expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
if ((event == Ion::Events::Var || event == Ion::Events::XNT) && ExpressionFieldDelegateApp::expressionLayoutFieldDidReceiveEvent(expressionLayoutField, event)) {
bool App::layoutFieldDidReceiveEvent(::LayoutField * layoutField, Ion::Events::Event event) {
if ((event == Ion::Events::Var || event == Ion::Events::XNT) && ExpressionFieldDelegateApp::layoutFieldDidReceiveEvent(layoutField, event)) {
return true;
}
if (expressionLayoutField->isEditing() && expressionLayoutField->expressionLayoutFieldShouldFinishEditing(event)) {
if (!expressionLayoutField->hasText()) {
if (layoutField->isEditing() && layoutField->layoutFieldShouldFinishEditing(event)) {
if (!layoutField->hasText()) {
return true;
}
int bufferLength = Calculation::k_printedExpressionSize;
char bufferForParsing[bufferLength];
expressionLayoutField->writeTextInBuffer(bufferForParsing, bufferLength);
layoutField->writeTextInBuffer(bufferForParsing, bufferLength);
if (!textInputIsCorrect(bufferForParsing)) {
displayWarning(I18n::Message::SyntaxError);

View File

@@ -29,7 +29,7 @@ public:
};
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
bool textInputIsCorrect(const char * text);
bool expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
bool layoutFieldDidReceiveEvent(::LayoutField * layoutField, Ion::Events::Event event) override;
const char * XNT() override;
private:
App(Container * container, Snapshot * snapshot);

View File

@@ -69,21 +69,18 @@ void Calculation::setContent(const char * c, Context * context, Expression * ans
KDCoordinate Calculation::height(Context * context) {
if (m_height < 0) {
ExpressionLayout * inputLayout = createInputLayout();
KDCoordinate inputHeight = inputLayout->size().height();
delete inputLayout;
Poincare::ExpressionLayout * approximateLayout = createApproximateOutputLayout(context);
KDCoordinate approximateOutputHeight = approximateLayout->size().height();
LayoutRef inputLayout = createInputLayout();
KDCoordinate inputHeight = inputLayout.layoutSize().height();
LayoutRef approximateLayout = createApproximateOutputLayout(context);
KDCoordinate approximateOutputHeight = approximateLayout.layoutSize().height();
if (shouldOnlyDisplayApproximateOutput(context)) {
m_height = inputHeight+approximateOutputHeight;
} else {
Poincare::ExpressionLayout * exactLayout = createExactOutputLayout(context);
KDCoordinate exactOutputHeight = exactLayout->size().height();
KDCoordinate outputHeight = max(exactLayout->baseline(), approximateLayout->baseline()) + max(exactOutputHeight-exactLayout->baseline(), approximateOutputHeight-approximateLayout->baseline());
delete exactLayout;
LayoutRef exactLayout = createExactOutputLayout(context);
KDCoordinate exactOutputHeight = exactLayout.layoutSize().height();
KDCoordinate outputHeight = max(exactLayout.baseline(), approximateLayout.baseline()) + max(exactOutputHeight-exactLayout.baseline(), approximateOutputHeight-approximateLayout.baseline());
m_height = inputHeight + outputHeight;
}
delete approximateLayout;
}
return m_height;
}
@@ -107,11 +104,11 @@ Expression * Calculation::input() {
return m_input;
}
ExpressionLayout * Calculation::createInputLayout() {
LayoutRef Calculation::createInputLayout() {
if (input() != nullptr) {
return input()->createLayout(PrintFloat::Mode::Decimal, PrintFloat::k_numberOfStoredSignificantDigits);
}
return nullptr;
return LayoutRef(nullptr);
}
bool Calculation::isEmpty() {
@@ -159,11 +156,11 @@ Expression * Calculation::exactOutput(Context * context) {
return m_exactOutput;
}
ExpressionLayout * Calculation::createExactOutputLayout(Context * context) {
LayoutRef Calculation::createExactOutputLayout(Context * context) {
if (exactOutput(context) != nullptr) {
return PoincareHelpers::CreateLayout(exactOutput(context));
}
return nullptr;
return LayoutRef(nullptr);
}
Expression * Calculation::approximateOutput(Context * context) {
@@ -181,11 +178,11 @@ Expression * Calculation::approximateOutput(Context * context) {
return m_approximateOutput;
}
ExpressionLayout * Calculation::createApproximateOutputLayout(Context * context) {
LayoutRef Calculation::createApproximateOutputLayout(Context * context) {
if (approximateOutput(context) != nullptr) {
return PoincareHelpers::CreateLayout(approximateOutput(context));
}
return nullptr;
return LayoutRef(nullptr);
}
bool Calculation::shouldOnlyDisplayApproximateOutput(Context * context) {

View File

@@ -29,11 +29,11 @@ public:
const char * exactOutputText();
const char * approximateOutputText();
Poincare::Expression * input();
Poincare::ExpressionLayout * createInputLayout();
Poincare::LayoutRef createInputLayout();
Poincare::Expression * approximateOutput(Poincare::Context * context);
Poincare::Expression * exactOutput(Poincare::Context * context);
Poincare::ExpressionLayout * createExactOutputLayout(Poincare::Context * context);
Poincare::ExpressionLayout * createApproximateOutputLayout(Poincare::Context * context);
Poincare::LayoutRef createExactOutputLayout(Poincare::Context * context);
Poincare::LayoutRef createApproximateOutputLayout(Poincare::Context * context);
bool isEmpty();
void tidy();
bool shouldOnlyDisplayApproximateOutput(Poincare::Context * context);

View File

@@ -10,19 +10,14 @@ using namespace Poincare;
namespace Calculation {
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate) :
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) :
View(),
m_mainView(subview),
m_layout(new Poincare::HorizontalLayout()),
m_expressionField(parentResponder, m_textBody, k_bufferLength, m_layout, textFieldDelegate, expressionLayoutFieldDelegate)
m_expressionField(parentResponder, m_textBody, k_bufferLength, Poincare::HorizontalLayoutRef(), textFieldDelegate, layoutFieldDelegate)
{
m_textBody[0] = 0;
}
EditExpressionController::ContentView::~ContentView() {
delete m_layout;
}
View * EditExpressionController::ContentView::subviewAtIndex(int index) {
assert(index >= 0 && index < numberOfSubviews());
if (index == 0) {
@@ -92,22 +87,22 @@ bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField)
return inputViewDidAbortEditing(textField->text());
}
bool EditExpressionController::expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
if (expressionLayoutField->isEditing() && expressionLayoutField->expressionLayoutFieldShouldFinishEditing(event) && !expressionLayoutField->hasText() && m_calculationStore->numberOfCalculations() > 0) {
bool EditExpressionController::layoutFieldDidReceiveEvent(::LayoutField * layoutField, Ion::Events::Event event) {
if (layoutField->isEditing() && layoutField->layoutFieldShouldFinishEditing(event) && !layoutField->hasText() && m_calculationStore->numberOfCalculations() > 0) {
return inputViewDidReceiveEvent(event);
}
return expressionFieldDelegateApp()->expressionLayoutFieldDidReceiveEvent(expressionLayoutField, event);
return expressionFieldDelegateApp()->layoutFieldDidReceiveEvent(layoutField, event);
}
bool EditExpressionController::expressionLayoutFieldDidFinishEditing(::ExpressionLayoutField * expressionLayoutField, ExpressionLayout * layout, Ion::Events::Event event) {
return inputViewDidFinishEditing(nullptr, layout);
bool EditExpressionController::layoutFieldDidFinishEditing(::LayoutField * layoutField, LayoutRef layoutR, Ion::Events::Event event) {
return inputViewDidFinishEditing(nullptr, layoutR);
}
bool EditExpressionController::expressionLayoutFieldDidAbortEditing(::ExpressionLayoutField * expressionLayoutField) {
bool EditExpressionController::layoutFieldDidAbortEditing(::LayoutField * layoutField) {
return inputViewDidAbortEditing(nullptr);
}
void EditExpressionController::expressionLayoutFieldDidChangeSize(::ExpressionLayoutField * expressionLayoutField) {
void EditExpressionController::layoutFieldDidChangeSize(::LayoutField * layoutField) {
/* Reload the view only if the ExpressionField height actually changes, i.e.
* not if the height is already maximal and stays maximal. */
if (view()) {
@@ -157,14 +152,14 @@ bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event
}
bool EditExpressionController::inputViewDidFinishEditing(const char * text, ExpressionLayout * layout) {
bool EditExpressionController::inputViewDidFinishEditing(const char * text, LayoutRef layoutR) {
App * calculationApp = (App *)app();
if (layout == nullptr) {
if (!layoutR.isDefined()) {
assert(text);
strlcpy(m_cacheBuffer, text, Calculation::k_printedExpressionSize);
} else {
assert(layout);
layout->writeTextInBuffer(m_cacheBuffer, Calculation::k_printedExpressionSize);
assert(layoutR.isDefined());
layoutR.writeTextInBuffer(m_cacheBuffer, Calculation::k_printedExpressionSize);
}
m_calculationStore->push(m_cacheBuffer, calculationApp->localContext());
m_historyController->reload();

View File

@@ -2,10 +2,10 @@
#define CALCULATION_EDIT_EXPRESSION_CONTROLLER_H
#include <escher.h>
#include <poincare/expression_layout.h>
#include <poincare/layout_reference.h>
#include "expression_field.h"
#include "../shared/text_field_delegate.h"
#include "../shared/expression_layout_field_delegate.h"
#include "../shared/layout_field_delegate.h"
#include "history_controller.h"
#include "calculation_store.h"
@@ -13,7 +13,7 @@ namespace Calculation {
class HistoryController;
/* TODO: implement a split view */
class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate, public Shared::ExpressionLayoutFieldDelegate {
class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate, public Shared::LayoutFieldDelegate {
public:
EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore);
void didBecomeFirstResponder() override;
@@ -26,21 +26,16 @@ public:
bool textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) override;
bool textFieldDidAbortEditing(::TextField * textField) override;
/* ExpressionLayoutFieldDelegate */
bool expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
bool expressionLayoutFieldDidFinishEditing(::ExpressionLayoutField * expressionLayoutField, Poincare::ExpressionLayout * layout, Ion::Events::Event event) override;
bool expressionLayoutFieldDidAbortEditing(::ExpressionLayoutField * expressionLayoutField) override;
void expressionLayoutFieldDidChangeSize(::ExpressionLayoutField * expressionLayoutField) override;
/* LayoutFieldDelegate */
bool layoutFieldDidReceiveEvent(::LayoutField * layoutField, Ion::Events::Event event) override;
bool layoutFieldDidFinishEditing(::LayoutField * layoutField, Poincare::LayoutRef layoutR, Ion::Events::Event event) override;
bool layoutFieldDidAbortEditing(::LayoutField * layoutField) override;
void layoutFieldDidChangeSize(::LayoutField * layoutField) override;
private:
class ContentView : public View {
public:
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate);
~ContentView();
ContentView(const ContentView& other) = delete;
ContentView(ContentView&& other) = delete;
ContentView& operator=(const ContentView& other) = delete;
ContentView& operator=(ContentView&& other) = delete;
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate);
void reload();
TableView * mainView() { return m_mainView; }
ExpressionField * expressionField() { return &m_expressionField; }
@@ -52,14 +47,13 @@ private:
static constexpr int k_bufferLength = TextField::maxBufferSize();
TableView * m_mainView;
char m_textBody[k_bufferLength];
Poincare::ExpressionLayout * m_layout;
ExpressionField m_expressionField;
};
View * loadView() override;
void unloadView(View * view) override;
void reloadView();
bool inputViewDidReceiveEvent(Ion::Events::Event event);
bool inputViewDidFinishEditing(const char * text, Poincare::ExpressionLayout * layout);
bool inputViewDidFinishEditing(const char * text, Poincare::LayoutRef layoutR);
bool inputViewDidAbortEditing(const char * text);
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
Shared::ExpressionFieldDelegateApp * expressionFieldDelegateApp() override;

View File

@@ -18,25 +18,10 @@ HistoryViewCell::HistoryViewCell(Responder * parentResponder) :
{
}
HistoryViewCell::~HistoryViewCell() {
if (m_inputLayout != nullptr) {
delete m_inputLayout;
m_inputLayout = nullptr;
}
if (m_exactOutputLayout != nullptr) {
delete m_exactOutputLayout;
m_exactOutputLayout = nullptr;
}
if (m_approximateOutputLayout != nullptr) {
delete m_approximateOutputLayout;
m_approximateOutputLayout = nullptr;
}
}
Shared::ScrollableExactApproximateExpressionsView * HistoryViewCell::outputView() {
return &m_scrollableOutputView;
}
void HistoryViewCell::setEven(bool even) {
EvenOddCell::setEven(even);
m_inputView.setBackgroundColor(backgroundColor());
@@ -57,11 +42,11 @@ void HistoryViewCell::setHighlighted(bool highlight) {
reloadScroll();
}
Poincare::ExpressionLayout * HistoryViewCell::expressionLayout() const {
Poincare::LayoutRef HistoryViewCell::layoutRef() const {
if (m_selectedSubviewType == SubviewType::Input) {
return m_inputLayout;
} else {
return m_scrollableOutputView.expressionLayout();
return m_scrollableOutputView.layoutRef();
}
}
@@ -109,27 +94,20 @@ void HistoryViewCell::layoutSubviews() {
}
void HistoryViewCell::setCalculation(Calculation * calculation) {
if (m_inputLayout) {
delete m_inputLayout;
}
m_inputLayout = calculation->createInputLayout();
m_inputView.setExpressionLayout(m_inputLayout);
m_inputView.setLayoutRef(m_inputLayout);
App * calculationApp = (App *)app();
/* Both output expressions have to be updated at the same time. Otherwise,
* when updating one layout, if the second one still points to a deleted
* layout, calling to layoutSubviews() would fail. */
if (m_exactOutputLayout) {
delete m_exactOutputLayout;
m_exactOutputLayout = nullptr;
if (m_exactOutputLayout.isDefined()) {
m_exactOutputLayout = Poincare::LayoutRef(nullptr);
}
if (!calculation->shouldOnlyDisplayApproximateOutput(calculationApp->localContext())) {
m_exactOutputLayout = calculation->createExactOutputLayout(calculationApp->localContext());
}
if (m_approximateOutputLayout) {
delete m_approximateOutputLayout;
}
m_approximateOutputLayout = calculation->createApproximateOutputLayout(calculationApp->localContext());
Poincare::ExpressionLayout * outputExpressions[2] = {m_approximateOutputLayout, m_exactOutputLayout};
Poincare::LayoutRef outputExpressions[2] = {m_approximateOutputLayout, m_exactOutputLayout};
m_scrollableOutputView.setExpressions(outputExpressions);
I18n::Message equalMessage = calculation->exactAndApproximateDisplayedOutputsAreEqual(calculationApp->localContext()) == Calculation::EqualSign::Equal ? I18n::Message::Equal : I18n::Message::AlmostEqual;
m_scrollableOutputView.setEqualMessage(equalMessage);

View File

@@ -15,7 +15,6 @@ public:
Output
};
HistoryViewCell(Responder * parentResponder);
~HistoryViewCell();
void reloadCell() override;
void reloadScroll();
void setEven(bool even) override;
@@ -23,7 +22,7 @@ public:
Responder * responder() override {
return this;
}
Poincare::ExpressionLayout * expressionLayout() const override;
Poincare::LayoutRef layoutRef() const override;
KDColor backgroundColor() const override;
void setCalculation(Calculation * calculation);
int numberOfSubviews() const override;
@@ -37,9 +36,9 @@ public:
Shared::ScrollableExactApproximateExpressionsView * outputView();
private:
constexpr static KDCoordinate k_resultWidth = 80;
Poincare::ExpressionLayout * m_inputLayout;
Poincare::ExpressionLayout * m_exactOutputLayout;
Poincare::ExpressionLayout * m_approximateOutputLayout;
Poincare::LayoutRef m_inputLayout;
Poincare::LayoutRef m_exactOutputLayout;
Poincare::LayoutRef m_approximateOutputLayout;
ScrollableExpressionView m_inputView;
Shared::ScrollableExactApproximateExpressionsView m_scrollableOutputView;
SubviewType m_selectedSubviewType;

View File

@@ -10,8 +10,8 @@ ScrollableExpressionView::ScrollableExpressionView(Responder * parentResponder)
{
}
void ScrollableExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) {
m_expressionView.setExpressionLayout(expressionLayout);
void ScrollableExpressionView::setLayoutRef(LayoutRef layoutRef) {
m_expressionView.setLayoutRef(layoutRef);
layoutSubviews();
}

View File

@@ -8,7 +8,7 @@ namespace Calculation {
class ScrollableExpressionView : public ScrollableView, public ScrollViewDataSource {
public:
ScrollableExpressionView(Responder * parentResponder);
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
void setLayoutRef(Poincare::LayoutRef layoutRef);
void setBackgroundColor(KDColor backgroundColor) override;
KDSize minimalSizeForOptimalDisplay() const override;
private:

View File

@@ -10,7 +10,6 @@ app_objs += $(addprefix apps/shared/,\
double_pair_store.o\
editable_cell_table_view_controller.o\
expression_field_delegate_app.o\
expression_layout_field_delegate.o\
expression_model.o\
expression_model_list_controller.o\
expression_model_store.o\
@@ -36,6 +35,7 @@ app_objs += $(addprefix apps/shared/,\
interval.o\
interval_parameter_controller.o\
language_controller.o\
layout_field_delegate.o\
list_parameter_controller.o\
margin_even_odd_message_text_cell.o\
memoized_curve_view_range.o\

View File

@@ -9,31 +9,31 @@ namespace Shared {
ExpressionFieldDelegateApp::ExpressionFieldDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) :
TextFieldDelegateApp(container, snapshot, rootViewController),
ExpressionLayoutFieldDelegate()
LayoutFieldDelegate()
{
}
char ExpressionFieldDelegateApp::privateXNT(ExpressionLayoutField * expressionLayoutField) {
char xntCharFromLayout = expressionLayoutField->XNTChar();
char ExpressionFieldDelegateApp::privateXNT(LayoutField * layoutField) {
char xntCharFromLayout = layoutField->XNTChar();
if (xntCharFromLayout != Ion::Charset::Empty) {
return xntCharFromLayout;
}
return XNT()[0];
}
bool ExpressionFieldDelegateApp::expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
bool ExpressionFieldDelegateApp::layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) {
return event == Ion::Events::OK || event == Ion::Events::EXE;
}
bool ExpressionFieldDelegateApp::expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
if (expressionLayoutField->isEditing() && expressionLayoutField->expressionLayoutFieldShouldFinishEditing(event)) {
if (!expressionLayoutField->hasText()) {
expressionLayoutField->app()->displayWarning(I18n::Message::SyntaxError);
bool ExpressionFieldDelegateApp::layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) {
if (layoutField->isEditing() && layoutField->layoutFieldShouldFinishEditing(event)) {
if (!layoutField->hasText()) {
layoutField->app()->displayWarning(I18n::Message::SyntaxError);
return true;
}
char buffer[TextField::maxBufferSize()];
int bufferSize = TextField::maxBufferSize();
int length = expressionLayoutField->writeTextInBuffer(buffer, bufferSize);
int length = layoutField->writeTextInBuffer(buffer, bufferSize);
Expression * exp = Expression::parse(buffer);
if (exp != nullptr) {
delete exp;
@@ -45,33 +45,33 @@ bool ExpressionFieldDelegateApp::expressionLayoutFieldDidReceiveEvent(Expression
return true;
}
if (exp == nullptr) {
expressionLayoutField->app()->displayWarning(I18n::Message::SyntaxError);
layoutField->app()->displayWarning(I18n::Message::SyntaxError);
return true;
}
}
if (event == Ion::Events::Var) {
if (!expressionLayoutField->isEditing()) {
expressionLayoutField->setEditing(true);
if (!layoutField->isEditing()) {
layoutField->setEditing(true);
}
AppsContainer * appsContainer = (AppsContainer *)expressionLayoutField->app()->container();
AppsContainer * appsContainer = (AppsContainer *)layoutField->app()->container();
VariableBoxController * variableBoxController = appsContainer->variableBoxController();
variableBoxController->setSender(expressionLayoutField);
expressionLayoutField->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
variableBoxController->setSender(layoutField);
layoutField->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
return true;
}
if (event == Ion::Events::XNT) {
if (!expressionLayoutField->isEditing()) {
expressionLayoutField->setEditing(true);
if (!layoutField->isEditing()) {
layoutField->setEditing(true);
}
const char xnt[2] = {privateXNT(expressionLayoutField), 0};
return expressionLayoutField->handleEventWithText(xnt);
const char xnt[2] = {privateXNT(layoutField), 0};
return layoutField->handleEventWithText(xnt);
}
return false;
}
Toolbox * ExpressionFieldDelegateApp::toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) {
Toolbox * ExpressionFieldDelegateApp::toolboxForLayoutField(LayoutField * layoutField) {
Toolbox * toolbox = container()->mathToolbox();
toolbox->setSender(expressionLayoutField);
toolbox->setSender(layoutField);
return toolbox;
}

View File

@@ -2,18 +2,18 @@
#define SHARED_EXPRESSION_FIELD_DELEGATE_APP_H
#include "text_field_delegate_app.h"
#include <escher/expression_layout_field_delegate.h>
#include <escher/layout_field_delegate.h>
namespace Shared {
class ExpressionFieldDelegateApp : public TextFieldDelegateApp, public ExpressionLayoutFieldDelegate {
class ExpressionFieldDelegateApp : public TextFieldDelegateApp, public LayoutFieldDelegate {
public:
virtual ~ExpressionFieldDelegateApp() = default;
bool expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
virtual bool expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) override;
bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) override;
virtual bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) override;
Toolbox * toolboxForLayoutField(LayoutField * layoutField) override;
protected:
char privateXNT(ExpressionLayoutField * expressionLayoutField);
char privateXNT(LayoutField * layoutField);
ExpressionFieldDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController);
};

View File

@@ -1,31 +0,0 @@
#include "expression_layout_field_delegate.h"
using namespace Poincare;
namespace Shared {
bool ExpressionLayoutFieldDelegate::expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
return expressionFieldDelegateApp()->expressionLayoutFieldShouldFinishEditing(expressionLayoutField, event);
}
bool ExpressionLayoutFieldDelegate::expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
return expressionFieldDelegateApp()->expressionLayoutFieldDidReceiveEvent(expressionLayoutField, event);
}
bool ExpressionLayoutFieldDelegate::expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, ExpressionLayout * layout, Ion::Events::Event event) {
return expressionFieldDelegateApp()->expressionLayoutFieldDidFinishEditing(expressionLayoutField, layout, event);
}
bool ExpressionLayoutFieldDelegate::expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) {
return expressionFieldDelegateApp()->expressionLayoutFieldDidAbortEditing(expressionLayoutField);
}
void ExpressionLayoutFieldDelegate::expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) {
return expressionFieldDelegateApp()->expressionLayoutFieldDidChangeSize(expressionLayoutField);
}
Toolbox * ExpressionLayoutFieldDelegate::toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) {
return expressionFieldDelegateApp()->toolboxForExpressionLayoutField(expressionLayoutField);
}
}

View File

@@ -1,23 +0,0 @@
#ifndef SHARED_EXPRESSION_LAYOUT_FIELD_DELEGATE_H
#define SHARED_EXPRESSION_LAYOUT_FIELD_DELEGATE_H
#include <escher/expression_layout_field_delegate.h>
#include "expression_field_delegate_app.h"
namespace Shared {
class ExpressionLayoutFieldDelegate : public ::ExpressionLayoutFieldDelegate {
public:
bool expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
bool expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
bool expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, Poincare::ExpressionLayout * layout, Ion::Events::Event event) override;
bool expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) override;
void expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) override;
Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) override;
private:
virtual ExpressionFieldDelegateApp * expressionFieldDelegateApp() = 0;
};
}
#endif

View File

@@ -11,16 +11,15 @@ namespace Shared {
ExpressionModel::ExpressionModel() :
m_text{0},
m_expression(nullptr),
m_layout(nullptr)
m_layoutRef(nullptr)
{
}
ExpressionModel::~ExpressionModel() {
/* We cannot call tidy here because tidy is a virtual function and does not
* do the same thing for all children class. */
if (m_layout != nullptr) {
delete m_layout;
m_layout = nullptr;
if (m_layoutRef.isDefined()) {
m_layoutRef = LayoutRef(nullptr);
}
if (m_expression != nullptr) {
delete m_expression;
@@ -45,15 +44,15 @@ Poincare::Expression * ExpressionModel::expression(Poincare::Context * context)
return m_expression;
}
Poincare::ExpressionLayout * ExpressionModel::layout() {
if (m_layout == nullptr) {
LayoutRef ExpressionModel::layoutRef() {
if (!m_layoutRef.isDefined()) {
Expression * nonSimplifiedExpression = Expression::parse(m_text);
if (nonSimplifiedExpression != nullptr) {
m_layout = PoincareHelpers::CreateLayout(nonSimplifiedExpression);
m_layoutRef = PoincareHelpers::CreateLayout(nonSimplifiedExpression);
delete nonSimplifiedExpression;
}
}
return m_layout;
return m_layoutRef;
}
bool ExpressionModel::isDefined() {
@@ -69,9 +68,8 @@ void ExpressionModel::setContent(const char * c) {
/* We cannot call tidy here because tidy is a virtual function and does not
* do the same thing for all children class. And here we want to delete only
* the m_layout and m_expression. */
if (m_layout != nullptr) {
delete m_layout;
m_layout = nullptr;
if (m_layoutRef.isDefined()) {
m_layoutRef = LayoutRef(nullptr);
}
if (m_expression != nullptr) {
delete m_expression;
@@ -80,9 +78,8 @@ void ExpressionModel::setContent(const char * c) {
}
void ExpressionModel::tidy() {
if (m_layout != nullptr) {
delete m_layout;
m_layout = nullptr;
if (m_layoutRef.isDefined()) {
m_layoutRef = LayoutRef(nullptr);
}
if (m_expression != nullptr) {
delete m_expression;

View File

@@ -17,7 +17,7 @@ public:
ExpressionModel(ExpressionModel&& other) = delete;
const char * text() const;
Poincare::Expression * expression(Poincare::Context * context) const;
Poincare::ExpressionLayout * layout();
Poincare::LayoutRef layoutRef();
/* Here, isDefined is the exact contrary of isEmpty. However, for Sequence
* inheriting from ExpressionModel, isEmpty and isDefined have not exactly
* opposite meaning. For instance, u(n+1)=u(n) & u(0) = ... is not empty and
@@ -35,7 +35,7 @@ private:
static_assert((k_dataLengthInBytes & 0x3) == 0, "The expression model data size is not a multiple of 4 bytes (cannot compute crc)"); // Assert that dataLengthInBytes is a multiple of 4
char m_text[k_expressionBufferSize];
mutable Poincare::Expression * m_expression;
mutable Poincare::ExpressionLayout * m_layout;
mutable Poincare::LayoutRef m_layoutRef;
};
}

View File

@@ -23,17 +23,17 @@ KDCoordinate ExpressionModelListController::expressionRowHeight(int j) {
return Metric::StoreRowHeight;
}
ExpressionModel * m = modelStore()->modelAtIndex(j);
if (m->layout() == nullptr) {
if (!m->layoutRef().isDefined()) {
return Metric::StoreRowHeight;
}
KDCoordinate modelSize = m->layout()->size().height();
KDCoordinate modelSize = m->layoutRef().layoutSize().height();
return modelSize + Metric::StoreRowHeight - KDText::charSize().height();
}
void ExpressionModelListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) {
EvenOddExpressionCell * myCell = (EvenOddExpressionCell *)cell;
ExpressionModel * m = modelStore()->modelAtIndex(j);
myCell->setExpressionLayout(m->layout());
myCell->setLayoutRef(m->layoutRef());
}
/* Responder */

View File

@@ -0,0 +1,31 @@
#include "layout_field_delegate.h"
using namespace Poincare;
namespace Shared {
bool LayoutFieldDelegate::layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) {
return expressionFieldDelegateApp()->layoutFieldShouldFinishEditing(layoutField, event);
}
bool LayoutFieldDelegate::layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) {
return expressionFieldDelegateApp()->layoutFieldDidReceiveEvent(layoutField, event);
}
bool LayoutFieldDelegate::layoutFieldDidFinishEditing(LayoutField * layoutField, LayoutRef layoutR, Ion::Events::Event event) {
return expressionFieldDelegateApp()->layoutFieldDidFinishEditing(layoutField, layoutR, event);
}
bool LayoutFieldDelegate::layoutFieldDidAbortEditing(LayoutField * layoutField) {
return expressionFieldDelegateApp()->layoutFieldDidAbortEditing(layoutField);
}
void LayoutFieldDelegate::layoutFieldDidChangeSize(LayoutField * layoutField) {
return expressionFieldDelegateApp()->layoutFieldDidChangeSize(layoutField);
}
Toolbox * LayoutFieldDelegate::toolboxForLayoutField(LayoutField * layoutField) {
return expressionFieldDelegateApp()->toolboxForLayoutField(layoutField);
}
}

View File

@@ -0,0 +1,23 @@
#ifndef SHARED_LAYOUT_FIELD_DELEGATE_H
#define SHARED_LAYOUT_FIELD_DELEGATE_H
#include <escher/layout_field_delegate.h>
#include "expression_field_delegate_app.h"
namespace Shared {
class LayoutFieldDelegate : public ::LayoutFieldDelegate {
public:
bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) override;
bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) override;
bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::LayoutRef layoutR, Ion::Events::Event event) override;
bool layoutFieldDidAbortEditing(LayoutField * layoutField) override;
void layoutFieldDidChangeSize(LayoutField * layoutField) override;
Toolbox * toolboxForLayoutField(LayoutField * layoutField) override;
private:
virtual ExpressionFieldDelegateApp * expressionFieldDelegateApp() = 0;
};
}
#endif

View File

@@ -7,7 +7,7 @@ namespace Shared {
namespace PoincareHelpers {
inline Poincare::ExpressionLayout * CreateLayout(const Poincare::Expression * e) {
inline Poincare::LayoutRef CreateLayout(const Poincare::Expression * e) {
return e->createLayout(Poincare::Preferences::sharedPreferences()->displayMode(), Poincare::Preferences::sharedPreferences()->numberOfSignificantDigits());
}

View File

@@ -9,8 +9,8 @@ namespace Shared {
class ScrollableExactApproximateExpressionsCell : public ::EvenOddCell, public Responder {
public:
ScrollableExactApproximateExpressionsCell(Responder * parentResponder = nullptr);
void setExpressions(Poincare::ExpressionLayout ** expressionsLayout) {
return m_view.setExpressions(expressionsLayout);
void setExpressions(Poincare::LayoutRef * layoutRefs) {
return m_view.setExpressions(layoutRefs); // TODO rename setLayouts
}
void setEqualMessage(I18n::Message equalSignMessage) {
return m_view.setEqualMessage(equalSignMessage);
@@ -22,7 +22,7 @@ public:
Responder * responder() override {
return this;
}
Poincare::ExpressionLayout * expressionLayout() const override { return m_view.expressionLayout(); }
Poincare::LayoutRef layoutRef() const override { return m_view.layoutRef(); }
void didBecomeFirstResponder() override;
constexpr static KDCoordinate k_margin = 5;
private:

View File

@@ -49,8 +49,8 @@ KDSize ScrollableExactApproximateExpressionsView::ContentCell::minimalSizeForOpt
return approximateExpressionSize;
}
KDSize exactExpressionSize = m_exactExpressionView.minimalSizeForOptimalDisplay();
KDCoordinate exactBaseline = m_exactExpressionView.expressionLayout()->baseline();
KDCoordinate approximateBaseline = m_approximateExpressionView.expressionLayout()->baseline();
KDCoordinate exactBaseline = m_exactExpressionView.layoutRef().baseline();
KDCoordinate approximateBaseline = m_approximateExpressionView.layoutRef().baseline();
KDCoordinate height = max(exactBaseline, approximateBaseline) + max(exactExpressionSize.height()-exactBaseline, approximateExpressionSize.height()-approximateBaseline);
KDSize approximateSignSize = m_approximateSign.minimalSizeForOptimalDisplay();
return KDSize(exactExpressionSize.width()+approximateSignSize.width()+approximateExpressionSize.width()+2*k_digitHorizontalMargin, height);
@@ -61,16 +61,16 @@ void ScrollableExactApproximateExpressionsView::ContentCell::setSelectedSubviewT
setHighlighted(isHighlighted());
}
Poincare::ExpressionLayout * ScrollableExactApproximateExpressionsView::ContentCell::expressionLayout() const {
Poincare::LayoutRef ScrollableExactApproximateExpressionsView::ContentCell::layoutRef() const {
if (m_selectedSubviewType == SubviewType::ExactOutput) {
return m_exactExpressionView.expressionLayout();
return m_exactExpressionView.layoutRef();
} else {
return m_approximateExpressionView.expressionLayout();
return m_approximateExpressionView.layoutRef();
}
}
int ScrollableExactApproximateExpressionsView::ContentCell::numberOfSubviews() const {
if (m_exactExpressionView.expressionLayout() != nullptr) {
if (m_exactExpressionView.layoutRef().isDefined()) {
return 3;
}
return 1;
@@ -88,8 +88,8 @@ void ScrollableExactApproximateExpressionsView::ContentCell::layoutSubviews() {
m_approximateExpressionView.setFrame(KDRect(0, 0, approximateExpressionSize.width(), height));
return;
}
KDCoordinate exactBaseline = m_exactExpressionView.expressionLayout()->baseline();
KDCoordinate approximateBaseline = m_approximateExpressionView.expressionLayout()->baseline();
KDCoordinate exactBaseline = m_exactExpressionView.layoutRef().baseline();
KDCoordinate approximateBaseline = m_approximateExpressionView.layoutRef().baseline();
KDCoordinate baseline = max(exactBaseline, approximateBaseline);
KDSize exactExpressionSize = m_exactExpressionView.minimalSizeForOptimalDisplay();
KDSize approximateSignSize = m_approximateSign.minimalSizeForOptimalDisplay();
@@ -103,9 +103,10 @@ ScrollableExactApproximateExpressionsView::ScrollableExactApproximateExpressions
m_contentCell()
{
}
void ScrollableExactApproximateExpressionsView::setExpressions(ExpressionLayout ** expressionsLayout) {
m_contentCell.approximateExpressionView()->setExpressionLayout(expressionsLayout[0]);
m_contentCell.exactExpressionView()->setExpressionLayout(expressionsLayout[1]);
void ScrollableExactApproximateExpressionsView::setExpressions(Poincare::LayoutRef * layoutRefs) {
m_contentCell.approximateExpressionView()->setLayoutRef(layoutRefs[0]);
m_contentCell.exactExpressionView()->setLayoutRef(layoutRefs[1]);
m_contentCell.layoutSubviews();
}
@@ -114,7 +115,7 @@ void ScrollableExactApproximateExpressionsView::setEqualMessage(I18n::Message eq
}
void ScrollableExactApproximateExpressionsView::didBecomeFirstResponder() {
if (m_contentCell.exactExpressionView()->expressionLayout() == nullptr) {
if (!m_contentCell.exactExpressionView()->layoutRef().isDefined()) {
setSelectedSubviewType(SubviewType::ApproximativeOutput);
} else {
setSelectedSubviewType(SubviewType::ExactOutput);
@@ -122,7 +123,7 @@ void ScrollableExactApproximateExpressionsView::didBecomeFirstResponder() {
}
bool ScrollableExactApproximateExpressionsView::handleEvent(Ion::Events::Event event) {
if (m_contentCell.exactExpressionView()->expressionLayout() == nullptr) {
if (!m_contentCell.exactExpressionView()->layoutRef().isDefined()) {
return ScrollableView::handleEvent(event);
}
bool rightExpressionIsVisible = minimalSizeForOptimalDisplay().width() - m_contentCell.approximateExpressionView()->minimalSizeForOptimalDisplay().width() - m_manualScrollingOffset.x() < bounds().width()

View File

@@ -15,7 +15,7 @@ public:
::EvenOddCell * evenOddCell() {
return &m_contentCell;
}
void setExpressions(Poincare::ExpressionLayout ** expressionsLayout);
void setExpressions(Poincare::LayoutRef * layoutRefs);
void setEqualMessage(I18n::Message equalSignMessage);
SubviewType selectedSubviewType() {
return m_contentCell.selectedSubviewType();
@@ -26,8 +26,8 @@ public:
void didBecomeFirstResponder() override;
bool handleEvent(Ion::Events::Event event) override;
KDSize minimalSizeForOptimalDisplay() const override;
Poincare::ExpressionLayout * expressionLayout() const {
return m_contentCell.expressionLayout();
Poincare::LayoutRef layoutRef() const {
return m_contentCell.layoutRef();
}
private:
class ContentCell : public ::EvenOddCell {
@@ -52,7 +52,7 @@ private:
void setSelectedSubviewType(SubviewType subviewType);
void layoutSubviews() override;
int numberOfSubviews() const override;
Poincare::ExpressionLayout * expressionLayout() const override;
Poincare::LayoutRef layoutRef() const override;
private:
View * subviewAtIndex(int index) override;
constexpr static KDCoordinate k_digitHorizontalMargin = 10;

View File

@@ -203,7 +203,7 @@ bool SumGraphController::handleEnter() {
SumGraphController::LegendView::LegendView(SumGraphController * controller, char sumSymbol) :
m_sum(0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
m_sumLayout(nullptr),
m_sumLayoutRef(nullptr),
m_legend(KDText::FontSize::Small, I18n::Message::Default, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
m_editableZone(controller, m_draftText, m_draftText, TextField::maxBufferSize(), controller, false, KDText::FontSize::Small, 0.0f, 0.5f, KDColorBlack, Palette::GreyMiddle),
m_sumSymbol(sumSymbol)
@@ -211,13 +211,6 @@ SumGraphController::LegendView::LegendView(SumGraphController * controller, char
m_draftText[0] = 0;
}
SumGraphController::LegendView::~LegendView() {
if (m_sumLayout != nullptr) {
delete m_sumLayout;
m_sumLayout = nullptr;
}
}
void SumGraphController::LegendView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(bounds(), Palette::GreyMiddle);
}
@@ -239,28 +232,26 @@ void SumGraphController::LegendView::setEditableZone(double d) {
void SumGraphController::LegendView::setSumSymbol(Step step, double start, double end, double result, ExpressionLayout * functionLayout) {
assert(step == Step::Result || functionLayout == nullptr);
if (m_sumLayout) {
delete m_sumLayout;
m_sumLayout = nullptr;
}
const char sigma[] = {' ', m_sumSymbol};
if (step == Step::FirstParameter) {
m_sumLayout = LayoutEngine::createStringLayout(sigma, sizeof(sigma));
m_sumLayoutRef = LayoutEngine::createStringLayout(sigma, sizeof(sigma));
} else if (step == Step::SecondParameter) {
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
PrintFloat::convertFloatToText<double>(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
m_sumLayout = new CondensedSumLayout(
m_sumLayoutRef = LayoutEngine::createStringLayout(sigma, sizeof(sigma));/* TODO new CondensedSumLayout(
LayoutEngine::createStringLayout(sigma, sizeof(sigma)),
LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small),
new EmptyLayout(EmptyLayout::Color::Yellow, false, KDText::FontSize::Small, false),
false);
false); */
} else {
m_sumLayoutRef = LayoutEngine::createStringLayout(sigma, sizeof(sigma));
/* TODO
char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
PrintFloat::convertFloatToText<double>(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
ExpressionLayout * start = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
ExpressionLayout * start = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
PrintFloat::convertFloatToText<double>(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(
ExpressionLayout * end = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
m_sumLayoutRef = new CondensedSumLayout(
LayoutEngine::createStringLayout(sigma, sizeof(sigma)),
start,
end,
@@ -270,10 +261,10 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl
PoincareHelpers::ConvertFloatToText<double>(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
childrenLayouts[2] = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
childrenLayouts[1] = functionLayout;
childrenLayouts[0] = m_sumLayout;
m_sumLayout = new HorizontalLayout(childrenLayouts, 3, false);
childrenLayouts[0] = m_sumLayoutRef;
m_sumLayoutRef = new HorizontalLayout(childrenLayouts, 3, false);*/
}
m_sum.setExpressionLayout(m_sumLayout);
m_sum.setLayoutRef(m_sumLayoutRef);
if (step == Step::Result) {
m_sum.setAlignment(0.5f, 0.5f);
} else {

View File

@@ -49,7 +49,6 @@ private:
class LegendView : public View {
public:
LegendView(SumGraphController * controller, char sumSymbol);
~LegendView();
LegendView(const LegendView& other) = delete;
LegendView(LegendView&& other) = delete;
LegendView& operator=(const LegendView& other) = delete;
@@ -71,7 +70,7 @@ private:
void layoutSubviews() override;
void layoutSubviews(Step step);
ExpressionView m_sum;
Poincare::ExpressionLayout * m_sumLayout;
Poincare::LayoutRef m_sumLayoutRef;
MessageTextView m_legend;
TextField m_editableZone;
char m_draftText[TextField::maxBufferSize()];

11
apps/tree/Makefile Normal file
View File

@@ -0,0 +1,11 @@
app_objs = $(addprefix apps/tree/,\
addition_node.o\
expression_node.o\
expression_reference.o\
layout_cursor.o\
layout_node.o\
layout_reference.o\
tree_node.o\
tree_pool.o\
)

View File

@@ -0,0 +1,48 @@
#include "addition_node.h"
#include "float_node.h"
bool AdditionNode::shallowReduce() {
if (ExpressionNode::shallowReduce()) {
return true;
}
/* Step 1: Addition is associative, so let's start by merging children which
* also are additions themselves. */
int i = 0;
int initialNumberOfChildren = numberOfChildren();
while (i < initialNumberOfChildren) {
ExpressionNode * currentChild = child(i);
if (currentChild->type() == Type::Addition) {
TreeRef(this).mergeChildren(TreeRef(currentChild));
// Is it ok to modify memory while executing ?
continue;
}
i++;
}
// Step 2: Sort the operands
sortChildren();
/* Step 3: Factorize like terms. Thanks to the simplification order, those are
* next to each other at this point. */
i = 0;
while (i < numberOfChildren()-1) {
ExpressionNode * e1 = child(i);
ExpressionNode * e2 = child(i+1);
if (e1->type() == Type::Float && e2->type() == Type::Float) {
float sum = e1->approximate() + e2->approximate();
// Remove first e2 then e1, else the pointers change
removeChild(e2);
removeChild(e1);
FloatRef f(sum);
addChildAtIndex(f.node(), i);
continue;
}
/*if (TermsHaveIdenticalNonRationalFactors(e1, e2)) { //TODO
factorizeOperands(e1, e2); //TODO
continue;
}*/
i++;
}
return false;
}

50
apps/tree/addition_node.h Normal file
View File

@@ -0,0 +1,50 @@
#ifndef ADDITION_NODE_H
#define ADDITION_NODE_H
#include "expression_reference.h"
#include "expression_node.h"
class AdditionNode : public ExpressionNode {
public:
const char * description() const override { return "Addition"; }
size_t size() const override { return sizeof(AdditionNode); }
Type type() const override { return Type::Addition; }
float approximate() override {
float result = 0.0f;
for (int i=0; i<numberOfChildren(); i++) {
float approximateI = child(i)->approximate();
if (approximateI == -1) {
return -1;
}
result += approximateI;
}
return result;
}
bool shallowReduce() override;
int numberOfChildren() const override { return m_numberOfChildren; }
void incrementNumberOfChildren(int increment = 1) override { m_numberOfChildren+= increment; }
void decrementNumberOfChildren(int decrement = 1) override {
assert(m_numberOfChildren > 0);
m_numberOfChildren-= decrement;
}
void eraseNumberOfChildren() override {
m_numberOfChildren = 0;
}
private:
int m_numberOfChildren;
};
class AdditionRef : public ExpressionReference<AdditionNode> {
public:
AdditionRef(ExpressionRef e1, ExpressionRef e2) :
ExpressionReference<AdditionNode>()
{
addChild(e2);
addChild(e1);
}
};
#endif

View File

@@ -0,0 +1,26 @@
#ifndef ALLOCATION_FAILED_EXPRESSION_NODE_H
#define ALLOCATION_FAILED_EXPRESSION_NODE_H
#include "expression_node.h"
#include "expression_reference.h"
#include <stdio.h>
class AllocationFailedExpressionNode : public ExpressionNode {
public:
// ExpressionNode
float approximate() override { return -1; } // Should return nan
// TreeNode
size_t size() const override { return sizeof(AllocationFailedExpressionNode); }
const char * description() const override { return "Allocation Failed"; }
Type type() const override { return Type::AllocationFailure; }
int numberOfChildren() const override { return 0; }
bool isAllocationFailure() const override { return true; }
};
class AllocationFailedExpressionRef : public ExpressionReference<AllocationFailedExpressionNode> {
public:
using ExpressionReference<AllocationFailedExpressionNode>::ExpressionReference;
};
#endif

View File

@@ -0,0 +1,11 @@
#include "expression_node.h"
#include "allocation_failed_expression_node.h"
#include "expression_reference.h"
TreeNode * ExpressionNode::FailedAllocationStaticNode() {
return ExpressionRef::FailedAllocationStaticNode();
}
void ExpressionNode::sortChildren() {
ExpressionRef(this).sortChildren();
}

View File

@@ -0,0 +1,47 @@
#ifndef EXPRESSION_NODE_H
#define EXPRESSION_NODE_H
#include <poincare/serializable_node.h>
#include <stdint.h>
class ExpressionNode : public SerializableNode {
public:
enum class Type : uint8_t {
AllocationFailure = 0,
Float = 1,
Addition,
SimplificationRoot
};
// Expression
virtual Type type() const = 0;
virtual float approximate() = 0;
void deepReduce() {
for (int i = 0; i < numberOfChildren(); i++) {
child(i)->deepReduce();
}
shallowReduce();
}
virtual bool shallowReduce() {
for (int i = 0; i < numberOfChildren(); i++) {
if (child(i)->isAllocationFailure()) {
replaceWithAllocationFailure();
return true;
}
}
return false;
}
// Allocation failure
static TreeNode * FailedAllocationStaticNode();
TreeNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); }
// Hierarchy
ExpressionNode * child(int i) { return static_cast<ExpressionNode *>(childTreeAtIndex(i)); }
protected:
void sortChildren();
};
#endif

View File

@@ -0,0 +1,12 @@
#include "expression_reference.h"
#include "allocation_failed_expression_node.h"
template<>
TreeNode * ExpressionRef::FailedAllocationStaticNode() {
static AllocationFailedExpressionNode FailureNode;
if (FailureNode.identifier() >= -1) {
int newIdentifier = TreePool::sharedPool()->registerStaticNode(&FailureNode);
FailureNode.rename(newIdentifier);
}
return &FailureNode;
}

View File

@@ -0,0 +1,64 @@
#ifndef POINCARE_EXPRESSION_REFERENCE_H
#define POINCARE_EXPRESSION_REFERENCE_H
#include <poincare/expression_node.h>
#include <poincare/serializable_reference.h>
#include <stdio.h>
template <class T>
class ExpressionReference : public SerializableReference<T> {
public:
using SerializableReference<T>::SerializableReference;
/* Allow every ExpressionReference<T> to be transformed into an
* ExpressionReference<ExpressionNode>, i.e. ExpressionRef */
operator ExpressionReference<ExpressionNode>() const {
return ExpressionReference<ExpressionNode>(this->node());
}
static TreeNode * FailedAllocationStaticNode();
ExpressionReference<ExpressionNode> childAtIndex(int i) {
return ExpressionReference<ExpressionNode>(TreeReference<T>::treeChildAtIndex(i).node());
}
void replaceChildAtIndex(int oldChildIndex, ExpressionReference<ExpressionNode> newChild) {
TreeReference<T>::replaceChildAtIndex(oldChildIndex, newChild);
}
float approximate() const {
return this->typedNode()->approximate();
}
ExpressionReference<ExpressionNode> deepReduce() {
ExpressionReference<ExpressionNode> result = ExpressionReference<ExpressionNode>(this->clone().node());
result.typedNode()->deepReduce();
return result;
}
void shallowReduce() {
return this->typedNode()->shallowReduce();
}
void sortChildren() {
for (int i = this->numberOfChildren()-1; i > 0; i--) {
bool isSorted = true;
for (int j = 0; j < this->numberOfChildren()-1; j++) {
if (this->childAtIndex(j).typedNode()->type() > this->childAtIndex(j+1).typedNode()->type()) {
this->swapChildren(j, j+1);
isSorted = false;
}
}
if (isSorted) {
return;
}
}
}
};
typedef ExpressionReference<ExpressionNode> ExpressionRef;
#endif

34
apps/tree/float_node.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef FLOAT_NODE_H
#define FLOAT_NODE_H
#include "expression_reference.h"
#include "expression_node.h"
class FloatNode : public ExpressionNode {
public:
FloatNode(float value = 0) :
ExpressionNode(),
m_value(value)
{}
size_t size() const override { return sizeof(FloatNode); }
Type type() const override { return Type::Float; }
int numberOfChildren() const override { return 0; }
float approximate() override { return m_value; }
const char * description() const override {
return m_value > 1 ? "BigFloat" : "SmallFloat";
}
void setFloat(float f) { m_value = f; }
private:
float m_value;
};
class FloatRef : public ExpressionReference<FloatNode> {
public:
FloatRef(float f) : ExpressionReference<FloatNode>() {
if (!(this->node()->isAllocationFailure())) {
this->typedNode()->setFloat(f);
}
}
};
#endif

8
apps/tree/refs.h Normal file
View File

@@ -0,0 +1,8 @@
#include "addition_node.h"
#include "allocation_failed_expression_node.h"
#include "float_node.h"
#include "char_layout_node.h"
#include "horizontal_layout_node.h"
#include "layout_cursor.h"

341
apps/tree/test.cpp Normal file
View File

@@ -0,0 +1,341 @@
#include "refs.h"
#include <stdio.h>
namespace Test {
void logPool() {
TreePool::sharedPool()->log();
}
void assert_expression_approximates_to(ExpressionRef e, float result) {
float b = e.approximate();
if (b > result) {
assert(b - result < 0.000001f);
} else {
assert(result - b < 0.000001f);
}
}
AdditionRef buildAddition() {
int initialNumberOfNodes = TreePool::sharedPool()->numberOfNodes();
FloatRef smallFloat(0.2f);
FloatRef bigFloat(3.4f);
AdditionRef a(smallFloat, bigFloat);
assert(TreePool::sharedPool()->numberOfNodes() == initialNumberOfNodes + 3);
return a;
}
void testAddition() {
#if TREE_LOG
printf("Addition test\n");
#endif
int initialNumberOfNodes = TreePool::sharedPool()->numberOfNodes();
AdditionRef a = buildAddition();
assert(TreePool::sharedPool()->numberOfNodes() == initialNumberOfNodes + 3);
assert_expression_approximates_to(a, 3.6f);
FloatRef smallFloat(1.3f);
a.replaceChildAtIndex(0, smallFloat);
assert_expression_approximates_to(a, 4.7f);
int firstChildIdentifier = a.childAtIndex(0).identifier();
int secondChildIdentifier = a.childAtIndex(1).identifier();
a.swapChildren(1,0);
assert(a.childAtIndex(0).identifier() == secondChildIdentifier);
assert(a.childAtIndex(1).identifier() == firstChildIdentifier);
}
void createNodes() {
FloatRef smallFloat(0.2f);
FloatRef bigFloat(3.4f);
AdditionRef a(smallFloat, bigFloat);
ExpressionRef e = a;
ExpressionRef f = e;
}
void testPoolEmpties() {
#if TREE_LOG
printf("Pool empties test\n");
#endif
int initialNumberOfNodes = TreePool::sharedPool()->numberOfNodes();
createNodes();
assert(TreePool::sharedPool()->numberOfNodes() == initialNumberOfNodes);
}
void testCursorCreateAndRetain() {
#if TREE_LOG
printf("Cursor create and retain test\n");
#endif
int initialNumberOfNodes = TreePool::sharedPool()->numberOfNodes();
CharLayoutRef aChar('a');
CharLayoutRef bChar('b');
int aCharID = aChar.identifier();
int bCharID = bChar.identifier();
assert(bCharID = aCharID + 1);
assert(aChar.nodeRetainCount() == 1);
assert(bChar.nodeRetainCount() == 1);
assert(strcmp(aChar.node()->description(), "Char a") == 0);
assert(strcmp(bChar.node()->description(), "Char b") == 0);
assert(TreePool::sharedPool()->numberOfNodes() == initialNumberOfNodes + 2);
HorizontalLayoutRef h(aChar, bChar);
assert(aChar.identifier() == aCharID);
assert(bChar.identifier() == bCharID);
assert(h.identifier() == bCharID + 1);
assert(aChar.nodeRetainCount() == 2);
assert(bChar.nodeRetainCount() == 2);
assert(h.nodeRetainCount() == 1);
assert(aChar == h.childAtIndex(0));
assert(bChar == h.childAtIndex(1));
LayoutCursor cursorA = aChar.cursor();
assert(cursorA.layoutIdentifier() == aChar.identifier());
assert(aChar.nodeRetainCount() == 3);
}
void testCursorMoveLeft() {
#if TREE_LOG
printf("Cursor move left test\n");
#endif
CharLayoutRef aChar('a');
CharLayoutRef bChar('b');
HorizontalLayoutRef h(aChar, bChar);
LayoutCursor cursor = h.childAtIndex(1).cursor();
assert(bChar.nodeRetainCount() == 3);
assert(cursor.layoutIdentifier() == h.childAtIndex(1).identifier());
bool recompute = false;
assert(cursor.layoutIdentifier() == bChar.identifier());
assert(cursor.position() == LayoutCursor::Position::Right);
cursor.moveLeft(&recompute);
assert(cursor.layoutIdentifier() == bChar.identifier());
assert(cursor.position() == LayoutCursor::Position::Left);
assert(bChar.nodeRetainCount() == 3);
assert(aChar.nodeRetainCount() == 2);
cursor.moveLeft(&recompute);
assert(cursor.layoutIdentifier() == aChar.identifier());
assert(cursor.position() == LayoutCursor::Position::Left);
assert(aChar.nodeRetainCount() == 3);
}
void testPoolExpressionAllocationFail() {
#if TREE_LOG
printf("Pool expression allocation fail test\n");
#endif
// Fill the pool for size 256
FloatRef f1(0.0f);
FloatRef f2(1.0f);
AdditionRef a1(f1, f2);
assert_expression_approximates_to(a1, 1);
FloatRef f3(2.0f);
FloatRef f4(3.0f);
FloatRef f5(4.0f);
FloatRef f6(5.0f);
FloatRef f7(6.0f);
FloatRef f8(7.0f);
FloatRef f9(8.0f);
// Allocation fail
FloatRef f11(10.0f);
AdditionRef a(f11, f3);
assert_expression_approximates_to(a, -1);
f1.replaceWith(f11);
assert_expression_approximates_to(a1, -1);
}
void testPoolExpressionAllocationFail2() {
#if TREE_LOG
printf("Pool expression allocation multiple fail test\n");
#endif
// Fill the pool for size 256
FloatRef f1(0.0f);
FloatRef f2(1.0f);
AdditionRef a1(f1, f2);
assert_expression_approximates_to(a1, 1);
FloatRef f3(2.0f);
FloatRef f4(3.0f);
AdditionRef a2(f3, f4);
assert_expression_approximates_to(a2, 5);
FloatRef f5(4.0f);
FloatRef f6(5.0f);
FloatRef f7(6.0f);
FloatRef f8(7.0f);
// Allocation fail
FloatRef f9(8.0f);
FloatRef f10(8.0f);
f1.replaceWith(f9);
assert_expression_approximates_to(a1, -1);
f3.replaceWith(f10);
assert_expression_approximates_to(a2, -1);
assert_expression_approximates_to(a1, -1);
}
void testPoolExpressionAllocationFailOnImbricatedAdditions() {
#if TREE_LOG
printf("Pool expression allocation fail second test\n");
#endif
// Fill the pool for size 256
FloatRef f1(0.0f);
FloatRef f2(1.0f);
AdditionRef a1(f1, f2);
assert_expression_approximates_to(a1, 1);
FloatRef f3(2.0f);
AdditionRef a2(a1, f3);
assert_expression_approximates_to(a2, 3);
FloatRef f4(3.0f);
FloatRef f5(4.0f);
FloatRef f6(5.0f);
FloatRef f7(6.0f);
FloatRef f8(7.0f);
// Allocation fail
FloatRef f9(7.0f);
f1.replaceWith(f9);
assert_expression_approximates_to(a2, -1);
a2.removeChild(a1);
assert_expression_approximates_to(a2, 2);
}
void testStealOperand() {
#if TREE_LOG
printf("Steal operand test\n");
#endif
FloatRef f1(0.0f);
FloatRef f2(1.0f);
AdditionRef a1(f1, f2);
assert_expression_approximates_to(a1, 1);
FloatRef f3(2.0f);
FloatRef f4(3.0f);
AdditionRef a2(f4, f3);
assert_expression_approximates_to(a2, 5);
a1.addChild(f4);
assert_expression_approximates_to(a1, 4);
assert_expression_approximates_to(a2, 2);
}
void testSimplify() {
#if TREE_LOG
printf("Simplify test\n");
#endif
AdditionRef a(
AdditionRef(
FloatRef(0.0f),
FloatRef(1.0f)),
FloatRef(2.0f));
assert_expression_approximates_to(a, 3);
ExpressionRef b = a.deepReduce();
assert_expression_approximates_to(a, 3);
assert_expression_approximates_to(b, 3);
assert(b.numberOfChildren() == 1);
assert(b.childAtIndex(0).typedNode()->type() == ExpressionNode::Type::Float);
assert(b.childAtIndex(0).typedNode()->approximate() == 3.0f);
}
void testChildSort() {
#if TREE_LOG
printf("Child sort test\n");
#endif
AdditionRef a(
AdditionRef(
FloatRef(1.0f),
FloatRef(2.0f)),
FloatRef(3.0f));
a.addChild(FloatRef(0.0f));
assert(a.childAtIndex(0).typedNode()->type() == ExpressionNode::Type::Float);
assert(a.childAtIndex(1).typedNode()->type() == ExpressionNode::Type::Addition);
assert(a.childAtIndex(2).typedNode()->type() == ExpressionNode::Type::Float);
a.sortChildren();
assert(a.childAtIndex(0).typedNode()->type() == ExpressionNode::Type::Float);
assert(a.childAtIndex(1).typedNode()->type() == ExpressionNode::Type::Float);
assert(a.childAtIndex(2).typedNode()->type() == ExpressionNode::Type::Addition);
}
void testPoolLayoutAllocationFail() {
#if TREE_LOG
printf("Pool layout allocation fail test\n");
#endif
// Fill the pool for size 256
CharLayoutRef char1('a');
CharLayoutRef char2('b');
CharLayoutRef char3('a');
CharLayoutRef char4('b');
CharLayoutRef char5('a');
CharLayoutRef char6('b');
CharLayoutRef char7('a');
CharLayoutRef char8('b');
CharLayoutRef char9('a');
CharLayoutRef char10('b');
// Allocation fail
CharLayoutRef char11('a');
assert(strcmp(char11.node()->description(), "Allocation Failed") == 0);
}
typedef void (test)();
void runTest(test t) {
int initialNumberOfNodes = TreePool::sharedPool()->numberOfNodes();
t();
assert(TreePool::sharedPool()->numberOfNodes() == initialNumberOfNodes);
}
int main() {
#if TREE_LOG
printf("\n*******************\nStart running tests\n*******************\n\n");
#endif
assert(TreePool::sharedPool()->numberOfNodes() == 0);
runTest(testAddition);
runTest(testPoolEmpties);
runTest(testCursorCreateAndRetain);
runTest(testCursorMoveLeft);
runTest(testPoolExpressionAllocationFail);
runTest(testPoolExpressionAllocationFail2);
runTest(testPoolExpressionAllocationFailOnImbricatedAdditions);
runTest(testStealOperand);
runTest(testSimplify);
runTest(testChildSort);
runTest(testPoolLayoutAllocationFail);
#if TREE_LOG
printf("\n*******************\nEnd of tests\n*******************\n\n");
#endif
return 0;
}
}

View File

@@ -150,16 +150,16 @@ void VariableBoxController::ContentViewController::willDisplayCellForIndex(Highl
if (evaluation) {
/* TODO: implement list contexts */
// TODO: handle matrix and scalar!
ExpressionLayout * layout = expressionLayoutForIndex(index);
LayoutRef layoutR = layoutRefForIndex(index);
const Matrix * matrixEvaluation = static_cast<const Matrix *>(evaluation);
myCell->setExpressionLayout(layout);
myCell->setLayoutRef(layoutR);
char buffer[2*PrintFloat::bufferSizeForFloatsWithPrecision(2)+1];
int numberOfChars = PrintFloat::convertFloatToText<float>(matrixEvaluation->numberOfRows(), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(2), 2, PrintFloat::Mode::Decimal);
buffer[numberOfChars++] = 'x';
PrintFloat::convertFloatToText<float>(matrixEvaluation->numberOfColumns(), buffer+numberOfChars, PrintFloat::bufferSizeForFloatsWithPrecision(2), 2, PrintFloat::Mode::Decimal);
myCell->setSubtitle(buffer);
} else {
myCell->setExpressionLayout(nullptr);
myCell->setLayoutRef(LayoutRef(nullptr));
myCell->setSubtitle(I18n::translate(I18n::Message::Empty));
}
}
@@ -168,9 +168,9 @@ KDCoordinate VariableBoxController::ContentViewController::rowHeight(int index)
if (m_currentPage == Page::RootMenu || m_currentPage == Page::Scalar) {
return Metric::ToolboxRowHeight;
}
ExpressionLayout * expressionLayout = expressionLayoutForIndex(index);
if (expressionLayout) {
return expressionLayout->size().height()+k_leafMargin;
LayoutRef layoutR = layoutRefForIndex(index);
if (layoutR.isDefined()) {
return layoutR.layoutSize().height()+k_leafMargin;
}
return Metric::ToolboxRowHeight;
}
@@ -254,10 +254,10 @@ const Expression * VariableBoxController::ContentViewController::expressionForIn
return nullptr;
}
ExpressionLayout * VariableBoxController::ContentViewController::expressionLayoutForIndex(int index) {
LayoutRef VariableBoxController::ContentViewController::layoutRefForIndex(int index) {
if (m_currentPage == Page::Matrix) {
const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
return m_context->expressionLayoutForSymbol(&symbol, Constant::ShortNumberOfSignificantDigits);
return m_context->layoutForSymbol(&symbol, Constant::ShortNumberOfSignificantDigits);
}
#if LIST_VARIABLES
if (m_currentPage == Page::List) {

View File

@@ -53,7 +53,7 @@ private:
void putLabelAtIndexInBuffer(int index, char * buffer);
I18n::Message nodeLabelAtIndex(int index);
const Poincare::Expression * expressionForIndex(int index);
Poincare::ExpressionLayout * expressionLayoutForIndex(int index);
Poincare::LayoutRef layoutRefForIndex(int index);
Poincare::GlobalContext * m_context;
Responder * m_sender;
int m_firstSelectedRow;

View File

@@ -76,8 +76,8 @@ void VariableBoxLeafCell::setSubtitle(const char * text) {
layoutSubviews();
}
void VariableBoxLeafCell::setExpressionLayout(ExpressionLayout * expressionLayout) {
m_expressionView.setExpressionLayout(expressionLayout);
void VariableBoxLeafCell::setLayoutRef(LayoutRef layoutRef) {
m_expressionView.setLayoutRef(layoutRef);
}
void VariableBoxLeafCell::drawRect(KDContext * ctx, KDRect rect) const {

View File

@@ -11,7 +11,7 @@ public:
void reloadCell() override;
void setLabel(const char * text);
void setSubtitle(const char * text);
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
void setLayoutRef(Poincare::LayoutRef layoutRef);
void drawRect(KDContext * ctx, KDRect rect) const override;
const char * text() const override {
return m_labelView.text();

View File

@@ -8,7 +8,7 @@ CXXFLAGS = -std=c++11 -fno-exceptions -fno-rtti -fno-threadsafe-statics
# Flags - Optimizations
ifeq ($(DEBUG),1)
SFLAGS = -Og -g
SFLAGS = -O0 -g
else
SFLAGS = -Os
endif

View File

@@ -29,6 +29,7 @@ objs += $(addprefix escher/src/,\
invocation.o\
input_view_controller.o\
key_view.o\
layout_field.o\
list_view_data_source.o\
message_table_cell.o\
message_table_cell_with_buffer.o\
@@ -51,8 +52,6 @@ objs += $(addprefix escher/src/,\
scroll_view_data_source.o\
scroll_view_indicator.o\
scrollable_view.o\
expression_layout_field.o\
expression_layout_field_content_view.o\
selectable_table_view.o\
selectable_table_view_data_source.o\
selectable_table_view_delegate.o\

View File

@@ -32,6 +32,8 @@
#include <escher/invocation.h>
#include <escher/i18n.h>
#include <escher/key_view.h>
#include <escher/layout_field.h>
#include <escher/layout_field_delegate.h>
#include <escher/list_view_data_source.h>
#include <escher/message_table_cell.h>
#include <escher/message_table_cell_with_buffer.h>
@@ -54,8 +56,6 @@
#include <escher/scroll_view_data_source.h>
#include <escher/scroll_view_indicator.h>
#include <escher/scrollable_view.h>
#include <escher/expression_layout_field.h>
#include <escher/expression_layout_field_delegate.h>
#include <escher/selectable_table_view.h>
#include <escher/selectable_table_view_data_source.h>
#include <escher/selectable_table_view_delegate.h>

View File

@@ -8,7 +8,7 @@ class Clipboard {
public:
static Clipboard * sharedClipboard();
void store(const char * storedText);
void store(Poincare::ExpressionLayout * layout);
void store(Poincare::LayoutRef layoutR);
const char * storedText();
void reset();
private:

View File

@@ -10,14 +10,14 @@ public:
KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
void setEven(bool even) override;
void setHighlighted(bool highlight) override;
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
void setLayoutRef(Poincare::LayoutRef layoutRef);
void setBackgroundColor(KDColor backgroundColor);
void setTextColor(KDColor textColor);
KDSize minimalSizeForOptimalDisplay() const override;
void setAlignment(float horizontalAlignment, float verticalAlignment);
void setLeftMargin(KDCoordinate margin);
void setRightMargin(KDCoordinate margin);
Poincare::ExpressionLayout * expressionLayout() const override { return m_expressionView.expressionLayout(); }
Poincare::LayoutRef layoutRef() const override { return m_expressionView.layoutRef(); }
void drawRect(KDContext * ctx, KDRect rect) const override;
protected:
int numberOfSubviews() const override;

View File

@@ -1,15 +1,15 @@
#ifndef ESCHER_EXPRESSION_FIELD_H
#define ESCHER_EXPRESSION_FIELD_H
#include <escher/expression_layout_field.h>
#include <escher/expression_layout_field_delegate.h>
#include <escher/layout_field.h>
#include <escher/layout_field_delegate.h>
#include <escher/text_field.h>
#include <escher/text_field_delegate.h>
#include <poincare/expression_layout.h>
#include <poincare/layout_reference.h>
class ExpressionField : public Responder, public View {
public:
ExpressionField(Responder * parentResponder, char * textBuffer, int textBufferLength, Poincare::ExpressionLayout * layout, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate);
ExpressionField(Responder * parentResponder, char * textBuffer, int textBufferLength, Poincare::LayoutRef layout, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate);
void setEditing(bool isEditing, bool reinitDraftBuffer = true);
bool isEditing() const;
@@ -44,7 +44,7 @@ private:
KDCoordinate inputViewHeight() const;
KDCoordinate maximalHeight() const;
TextField m_textField;
ExpressionLayoutField m_expressionLayoutField;
LayoutField m_layoutField;
char * m_textBuffer;
int m_textBufferLength;
};

View File

@@ -1,81 +0,0 @@
#ifndef ESCHER_EXPRESSION_LAYOUT_FIELD_H
#define ESCHER_EXPRESSION_LAYOUT_FIELD_H
#include <escher/expression_view.h>
#include <escher/expression_layout_field_delegate.h>
#include <escher/scrollable_view.h>
#include <escher/text_cursor_view.h>
#include <escher/text_field.h>
#include <kandinsky/point.h>
#include <poincare/expression_layout.h>
#include <poincare/expression_layout_cursor.h>
class ExpressionLayoutField : public ScrollableView, public ScrollViewDataSource {
public:
ExpressionLayoutField(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ExpressionLayoutFieldDelegate * delegate = nullptr);
void setDelegate(ExpressionLayoutFieldDelegate * delegate) { m_delegate = delegate; }
bool isEditing() const;
void setEditing(bool isEditing);
void clearLayout();
void scrollToCursor();
void reload();
bool hasText() const;
int writeTextInBuffer(char * buffer, int bufferLength);
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override;
Poincare::ExpressionLayout * expressionLayout() const;
char XNTChar();
void setBackgroundColor(KDColor c) override;
/* Responder */
Toolbox * toolbox() override;
bool handleEvent(Ion::Events::Event event) override;
bool expressionLayoutFieldShouldFinishEditing(Ion::Events::Event event);
/* View */
KDSize minimalSizeForOptimalDisplay() const override;
protected:
virtual bool privateHandleEvent(Ion::Events::Event event);
bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout);
private:
constexpr static int k_maxNumberOfLayouts = 152;
static_assert(k_maxNumberOfLayouts == TextField::maxBufferSize(), "Maximal number of layouts in a layout field should be equal to max number of char in text field");
void scrollRightOfLayout(Poincare::ExpressionLayout * layout);
void scrollToBaselinedRect(KDRect rect, KDCoordinate baseline);
void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout, bool forceCursorRightOfLayout = false);
class ContentView : public View {
public:
ContentView(Poincare::ExpressionLayout * expressionLayout);
bool isEditing() const { return m_isEditing; }
void setEditing(bool isEditing);
void setBackgroundColor(KDColor c);
void setCursor(Poincare::ExpressionLayoutCursor cursor) { m_cursor = cursor; }
void cursorPositionChanged();
KDRect cursorRect();
Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; }
const ExpressionView * expressionView() const { return &m_expressionView; }
ExpressionView * editableExpressionView() { return &m_expressionView; }
void clearLayout();
/* 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;
};
ContentView m_contentView;
ExpressionLayoutFieldDelegate * m_delegate;
};
#endif

View File

@@ -1,19 +0,0 @@
#ifndef ESCHER_EXPRESSION_LAYOUT_FIELD_DELEGATE_H
#define ESCHER_EXPRESSION_LAYOUT_FIELD_DELEGATE_H
#include <escher/toolbox.h>
#include <ion/events.h>
class ExpressionLayoutField;
class ExpressionLayoutFieldDelegate {
public:
virtual bool expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) = 0;
virtual bool expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) = 0;
virtual bool expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, Poincare::ExpressionLayout * layout, Ion::Events::Event event) { return false; }
virtual bool expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) { return false; }
virtual void expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) {}
virtual Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) = 0;
};
#endif

View File

@@ -9,8 +9,8 @@ public:
ExpressionTableCell(Layout layout = Layout::Horizontal);
View * labelView() const override;
void setHighlighted(bool highlight) override;
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
Poincare::ExpressionLayout * expressionLayout() const override { return m_labelExpressionView.expressionLayout(); }
void setLayoutRef(Poincare::LayoutRef layoutR);
Poincare::LayoutRef layoutRef() const override { return m_labelExpressionView.layoutRef(); }
private:
ExpressionView m_labelExpressionView;
};

View File

@@ -4,6 +4,7 @@
#include <escher/view.h>
#include <kandinsky/color.h>
#include <poincare/expression_layout.h>
#include <poincare/layout_reference.h>
/* This class does not handle the expression layout as the size of the layout is
* needed to compute the size of table cells hosting the expression. As the size
@@ -15,8 +16,8 @@ class ExpressionView : public View {
public:
ExpressionView(float horizontalAlignment = 0.0f, float verticalAlignment = 0.5f,
KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
Poincare::ExpressionLayout * expressionLayout() const;
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
Poincare::LayoutRef layoutRef() const { return m_layoutRef; }
void setLayoutRef(Poincare::LayoutRef layoutRef);
void drawRect(KDContext * ctx, KDRect rect) const override;
void setBackgroundColor(KDColor backgroundColor);
void setTextColor(KDColor textColor);
@@ -32,7 +33,7 @@ private:
* layout is always possessed by a controller which only gives a pointer to
* the expression view (without cloning it). The named controller is then
* responsible for freeing the expression layout when required. */
Poincare::ExpressionLayout * m_expressionLayout;
mutable Poincare::LayoutRef m_layoutRef; // TODO find better way to have minimalSizeForOptimalDisplay const
float m_horizontalAlignment;
float m_verticalAlignment;
KDColor m_textColor;

View File

@@ -4,6 +4,7 @@
#include <escher/view.h>
#include <escher/responder.h>
#include <poincare.h>
#include <poincare/layout_reference.h>
class HighlightCell : public View {
public:
@@ -17,8 +18,8 @@ public:
virtual const char * text() const {
return nullptr;
}
virtual Poincare::ExpressionLayout * expressionLayout() const {
return nullptr;
virtual Poincare::LayoutRef layoutRef() const {
return Poincare::LayoutRef(nullptr);
}
protected:
bool m_highlighted;

View File

@@ -2,7 +2,7 @@
#define ESCHER_INPUT_VIEW_CONTROLLER_H
#include <escher/expression_field.h>
#include <escher/expression_layout_field_delegate.h>
#include <escher/layout_field_delegate.h>
#include <escher/modal_view_controller.h>
#include <escher/invocation.h>
#include <escher/text_field.h>
@@ -12,9 +12,9 @@
/* 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, ExpressionLayoutFieldDelegate {
class InputViewController : public ModalViewController, TextFieldDelegate, LayoutFieldDelegate {
public:
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate);
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate);
void edit(Responder * caller, Ion::Events::Event event, void * context, const char * initialText, Invocation::Action successAction, Invocation::Action failureAction);
const char * textBody();
void abortEditionAndDismiss();
@@ -26,19 +26,18 @@ public:
bool textFieldDidAbortEditing(TextField * textField) override;
Toolbox * toolboxForTextInput(TextInput * textInput) override;
/* ExpressionLayoutFieldDelegate */
bool expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
bool expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
bool expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, Poincare::ExpressionLayout * layout, Ion::Events::Event event) override;
bool expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) override;
void expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) override;
Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) override;
/* LayoutFieldDelegate */
bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) override;
bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) override;
bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::LayoutRef layoutR, Ion::Events::Event event) override;
bool layoutFieldDidAbortEditing(LayoutField * layoutField) override;
void layoutFieldDidChangeSize(LayoutField * layoutField) override;
Toolbox * toolboxForLayoutField(LayoutField * layoutField) override;
private:
class ExpressionFieldController : public ViewController {
public:
ExpressionFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate);
~ExpressionFieldController();
ExpressionFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate);
ExpressionFieldController(const ExpressionFieldController& other) = delete;
ExpressionFieldController(ExpressionFieldController&& other) = delete;
ExpressionFieldController& operator=(const ExpressionFieldController& other) = delete;
@@ -48,7 +47,7 @@ private:
ExpressionField * expressionField() { return &m_expressionField; }
private:
static constexpr int k_bufferLength = TextField::maxBufferSize();
Poincare::ExpressionLayout * m_layout;
Poincare::LayoutRef m_layout;
char m_textBuffer[k_bufferLength];
ExpressionField m_expressionField;
};
@@ -58,7 +57,7 @@ private:
Invocation m_successAction;
Invocation m_failureAction;
TextFieldDelegate * m_textFieldDelegate;
ExpressionLayoutFieldDelegate * m_expressionLayoutFieldDelegate;
LayoutFieldDelegate * m_layoutFieldDelegate;
bool m_inputViewHeightIsMaximal;
};

View File

@@ -0,0 +1,122 @@
#ifndef ESCHER_LAYOUT_FIELD_H
#define ESCHER_LAYOUT_FIELD_H
#include <escher/expression_view.h>
#include <escher/layout_field_delegate.h>
#include <escher/scrollable_view.h>
#include <escher/text_cursor_view.h>
#include <escher/text_field.h>
#include <kandinsky/point.h>
#include <poincare/layout_reference.h>
#include <poincare/layout_cursor.h>
class LayoutField : public ScrollableView, public ScrollViewDataSource {
public:
LayoutField(Responder * parentResponder, Poincare::LayoutRef layoutR, LayoutFieldDelegate * delegate = nullptr) :
ScrollableView(parentResponder, &m_contentView, this),
m_contentView(layoutR),
m_delegate(delegate)
{}
void setDelegate(LayoutFieldDelegate * delegate) { m_delegate = delegate; }
bool isEditing() const { return m_contentView.isEditing(); }
void setEditing(bool isEditing) { m_contentView.setEditing(isEditing); }
void clearLayout() { m_contentView.clearLayout(); }
void scrollToCursor() {
scrollToBaselinedRect(m_contentView.cursorRect(), m_contentView.cursor()->baseline());
}
void reload();
bool hasText() const { return layoutRef().hasText(); }
int writeTextInBuffer(char * buffer, int bufferLength) { return layoutRef().writeTextInBuffer(buffer, bufferLength); }
Poincare::LayoutRef layoutRef() const { return m_contentView.expressionView()->layoutRef(); }
char XNTChar() { return m_contentView.cursor()->layoutReference().XNTChar(); }
// ScrollableView
void setBackgroundColor(KDColor c) override {
ScrollableView::setBackgroundColor(c);
m_contentView.setBackgroundColor(c);
}
/* Responder */
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override;
bool handleEvent(Ion::Events::Event event) override;
Toolbox * toolbox() override {
return m_delegate != nullptr ? m_delegate->toolboxForLayoutField(this) : nullptr;
}
bool layoutFieldShouldFinishEditing(Ion::Events::Event event) { // TODO REMOVE ?
return m_delegate->layoutFieldShouldFinishEditing(this, event);
}
/* View */
KDSize minimalSizeForOptimalDisplay() const override {
KDSize contentViewSize = m_contentView.minimalSizeForOptimalDisplay();
return KDSize(contentViewSize.width(), contentViewSize.height());
}
protected:
virtual bool privateHandleEvent(Ion::Events::Event event);
bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout);
private:
constexpr static int k_maxNumberOfLayouts = 152;
static_assert(k_maxNumberOfLayouts == TextField::maxBufferSize(), "Maximal number of layouts in a layout field should be equal to max number of char in text field");
void scrollRightOfLayout(Poincare::LayoutRef layoutR);
void scrollToBaselinedRect(KDRect rect, KDCoordinate baseline);
void insertLayoutAtCursor(Poincare::LayoutRef layoutR, Poincare::LayoutRef pointedLayoutRef, bool forceCursorRightOfLayout = false);
class ContentView : public View {
public:
ContentView(Poincare::LayoutRef layoutR) :
m_cursor(layoutR, Poincare::LayoutCursor::Position::Right),
m_expressionView(0.0f, 0.5f, KDColorBlack, KDColorWhite),
m_cursorView(),
m_isEditing(false)
{
m_expressionView.setLayoutRef(layoutR);
}
bool isEditing() const { return m_isEditing; }
void setEditing(bool isEditing) {
m_isEditing = isEditing;
markRectAsDirty(bounds());
layoutSubviews();
}
void setBackgroundColor(KDColor c) { m_expressionView.setBackgroundColor(c); }
void setCursor(Poincare::LayoutCursor cursor) { m_cursor = cursor; }
void cursorPositionChanged() { layoutCursorSubview(); }
KDRect cursorRect() { return m_cursorView.frame(); }
Poincare::LayoutCursor * cursor() { return &m_cursor; }
const ExpressionView * expressionView() const { return &m_expressionView; }
ExpressionView * editableExpressionView() { return &m_expressionView; }
void clearLayout() { m_cursor.clearLayout(); }
/* View */
KDSize minimalSizeForOptimalDisplay() const override {
KDSize evSize = m_expressionView.minimalSizeForOptimalDisplay();
return KDSize(evSize.width() + Poincare::LayoutCursor::k_cursorWidth, evSize.height());
}
private:
enum class Position {
Top,
Bottom
};
int numberOfSubviews() const override { return 2; }
View * subviewAtIndex(int index) override {
assert(index >= 0 && index < 2);
View * m_views[] = {&m_expressionView, &m_cursorView};
return m_views[index];
}
void layoutSubviews() override {
m_expressionView.setFrame(bounds());
layoutCursorSubview();
}
void layoutCursorSubview();
Poincare::LayoutCursor m_cursor;
ExpressionView m_expressionView;
TextCursorView m_cursorView;
bool m_isEditing;
};
ContentView m_contentView;
LayoutFieldDelegate * m_delegate;
};
#endif

View File

@@ -0,0 +1,19 @@
#ifndef ESCHER_LAYOUT_FIELD_DELEGATE_H
#define ESCHER_LAYOUT_FIELD_DELEGATE_H
#include <escher/toolbox.h>
#include <ion/events.h>
class LayoutField;
class LayoutFieldDelegate {
public:
virtual bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) = 0;
virtual bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) = 0;
virtual bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::LayoutRef layoutR, Ion::Events::Event event) { return false; }
virtual bool layoutFieldDidAbortEditing(LayoutField * layoutField) { return false; }
virtual void layoutFieldDidChangeSize(LayoutField * layoutField) {}
virtual Toolbox * toolboxForLayoutField(LayoutField * layoutField) = 0;
};
#endif

View File

@@ -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 setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
void setLayoutRef(Poincare::LayoutRef layoutR);
private:
ExpressionView m_subtitleView;
};

View File

@@ -9,7 +9,7 @@ public:
MessageTableCellWithExpression(I18n::Message message = (I18n::Message)0, KDText::FontSize size = KDText::FontSize::Small);
View * accessoryView() const override;
void setHighlighted(bool highlight) override;
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
void setLayoutRef(Poincare::LayoutRef layout);
private:
ExpressionView m_subtitleView;
};

View File

@@ -10,8 +10,8 @@ void Clipboard::store(const char * storedText) {
strlcpy(m_textBuffer, storedText, TextField::maxBufferSize());
}
void Clipboard::store(Poincare::ExpressionLayout * layout) {
layout->writeTextInBuffer(m_textBuffer, TextField::maxBufferSize());
void Clipboard::store(Poincare::LayoutRef layoutR) {
layoutR.writeTextInBuffer(m_textBuffer, TextField::maxBufferSize());
}
const char * Clipboard::storedText() {

View File

@@ -23,8 +23,8 @@ void EvenOddExpressionCell::setEven(bool even) {
m_expressionView.setBackgroundColor(backgroundColor());
}
void EvenOddExpressionCell::setExpressionLayout(ExpressionLayout * expressionLayout) {
m_expressionView.setExpressionLayout(expressionLayout);
void EvenOddExpressionCell::setLayoutRef(LayoutRef layoutR) {
m_expressionView.setLayoutRef(layoutR);
}
void EvenOddExpressionCell::setBackgroundColor(KDColor backgroundColor) {

View File

@@ -2,11 +2,11 @@
#include <poincare/preferences.h>
#include <assert.h>
ExpressionField::ExpressionField(Responder * parentResponder, char * textBuffer, int textBufferLength, Poincare::ExpressionLayout * layout, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate) :
ExpressionField::ExpressionField(Responder * parentResponder, char * textBuffer, int textBufferLength, Poincare::LayoutRef layout, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) :
Responder(parentResponder),
View(),
m_textField(parentResponder, textBuffer, textBuffer, textBufferLength, textFieldDelegate, false, KDText::FontSize::Large, 0.0f, 0.5f, KDColorBlack, KDColorWhite),
m_expressionLayoutField(parentResponder, layout, expressionLayoutFieldDelegate),
m_layoutField(parentResponder, layout, layoutFieldDelegate),
m_textBuffer(textBuffer),
m_textBufferLength(textBufferLength)
{
@@ -15,9 +15,9 @@ ExpressionField::ExpressionField(Responder * parentResponder, char * textBuffer,
m_textField.setBackgroundColor(KDColorWhite);
m_textField.setColorsBackground(true);
// Initialize layout field
m_expressionLayoutField.setMargins(k_verticalMargin, k_horizontalMargin, k_verticalMargin, k_horizontalMargin);
m_expressionLayoutField.setBackgroundColor(KDColorWhite);
m_expressionLayoutField.setColorsBackground(true);
m_layoutField.setMargins(k_verticalMargin, k_horizontalMargin, k_verticalMargin, k_horizontalMargin);
m_layoutField.setBackgroundColor(KDColorWhite);
m_layoutField.setColorsBackground(true);
}
void ExpressionField::setEditing(bool isEditing, bool reinitDraftBuffer) {
@@ -25,19 +25,19 @@ void ExpressionField::setEditing(bool isEditing, bool reinitDraftBuffer) {
m_textField.setEditing(isEditing, reinitDraftBuffer);
} else {
if (reinitDraftBuffer) {
m_expressionLayoutField.clearLayout();
m_layoutField.clearLayout();
}
m_expressionLayoutField.setEditing(isEditing);
m_layoutField.setEditing(isEditing);
}
}
bool ExpressionField::isEditing() const {
return editionIsInTextField() ? m_textField.isEditing() : m_expressionLayoutField.isEditing();
return editionIsInTextField() ? m_textField.isEditing() : m_layoutField.isEditing();
}
const char * ExpressionField::text() {
if (!editionIsInTextField()) {
m_expressionLayoutField.writeTextInBuffer(m_textBuffer, m_textBufferLength);
m_layoutField.writeTextInBuffer(m_textBuffer, m_textBufferLength);
}
return m_textBuffer;
}
@@ -46,8 +46,8 @@ void ExpressionField::setText(const char * text) {
if (editionIsInTextField()) {
m_textField.setText(text);
} else {
m_expressionLayoutField.clearLayout();
m_expressionLayoutField.handleEventWithText(text, false, true);
m_layoutField.clearLayout();
m_layoutField.handleEventWithText(text, false, true);
}
}
@@ -56,17 +56,17 @@ View * ExpressionField::subviewAtIndex(int index) {
if (editionIsInTextField()) {
return &m_textField;
}
return &m_expressionLayoutField;
return &m_layoutField;
}
void ExpressionField::layoutSubviews() {
KDRect inputViewFrame(0, k_separatorThickness, bounds().width(), bounds().height() - k_separatorThickness);
if (editionIsInTextField()) {
m_textField.setFrame(inputViewFrame);
m_expressionLayoutField.setFrame(KDRectZero);
m_layoutField.setFrame(KDRectZero);
return;
}
m_expressionLayoutField.setFrame(inputViewFrame);
m_layoutField.setFrame(inputViewFrame);
m_textField.setFrame(KDRectZero);
}
@@ -81,7 +81,7 @@ void ExpressionField::drawRect(KDContext * ctx, KDRect rect) const {
}
bool ExpressionField::handleEvent(Ion::Events::Event event) {
return editionIsInTextField() ? m_textField.handleEvent(event) : m_expressionLayoutField.handleEvent(event);
return editionIsInTextField() ? m_textField.handleEvent(event) : m_layoutField.handleEvent(event);
}
KDSize ExpressionField::minimalSizeForOptimalDisplay() const {
@@ -93,7 +93,7 @@ bool ExpressionField::editionIsInTextField() const {
}
bool ExpressionField::isEmpty() const {
return editionIsInTextField() ? (m_textField.draftTextLength() == 0) : !m_expressionLayoutField.hasText();
return editionIsInTextField() ? (m_textField.draftTextLength() == 0) : !m_layoutField.hasText();
}
bool ExpressionField::heightIsMaximal() const {
@@ -104,7 +104,7 @@ bool ExpressionField::handleEventWithText(const char * text, bool indentation, b
if (editionIsInTextField()) {
return m_textField.handleEventWithText(text, indentation, forceCursorRightOfText);
} else {
return m_expressionLayoutField.handleEventWithText(text, indentation, forceCursorRightOfText);
return m_layoutField.handleEventWithText(text, indentation, forceCursorRightOfText);
}
}
@@ -112,7 +112,7 @@ KDCoordinate ExpressionField::inputViewHeight() const {
return k_separatorThickness
+ (editionIsInTextField() ? k_textFieldHeight :
min(maximalHeight(),
max(k_textFieldHeight, m_expressionLayoutField.minimalSizeForOptimalDisplay().height() + 2*k_verticalMargin )));
max(k_textFieldHeight, m_layoutField.minimalSizeForOptimalDisplay().height() + 2*k_verticalMargin )));
}
KDCoordinate ExpressionField::maximalHeight() const {

View File

@@ -1,74 +0,0 @@
#include <escher/expression_layout_field.h>
#include <kandinsky/rect.h>
#include <assert.h>
using namespace Poincare;
ExpressionLayoutField::ContentView::ContentView(ExpressionLayout * expressionLayout) :
m_cursor(expressionLayout, ExpressionLayoutCursor::Position::Right),
m_expressionView(0.0f, 0.5f, KDColorBlack, KDColorWhite),
m_cursorView(),
m_isEditing(false)
{
m_expressionView.setExpressionLayout(expressionLayout);
}
void ExpressionLayoutField::ContentView::setEditing(bool isEditing) {
m_isEditing = isEditing;
markRectAsDirty(bounds());
layoutSubviews();
}
void ExpressionLayoutField::ContentView::setBackgroundColor(KDColor c) {
m_expressionView.setBackgroundColor(c);
}
void ExpressionLayoutField::ContentView::cursorPositionChanged() {
layoutCursorSubview();
}
KDRect ExpressionLayoutField::ContentView::cursorRect() {
return m_cursorView.frame();
}
void ExpressionLayoutField::ContentView::clearLayout() {
m_cursor.clearLayout();
}
KDSize ExpressionLayoutField::ContentView::minimalSizeForOptimalDisplay() const {
KDSize evSize = m_expressionView.minimalSizeForOptimalDisplay();
return KDSize(evSize.width() + ExpressionLayoutCursor::k_cursorWidth, evSize.height());
}
View * ExpressionLayoutField::ContentView::subviewAtIndex(int index) {
assert(index >= 0 && index < 2);
View * m_views[] = {&m_expressionView, &m_cursorView};
return m_views[index];
}
void ExpressionLayoutField::ContentView::layoutSubviews() {
m_expressionView.setFrame(bounds());
layoutCursorSubview();
}
void ExpressionLayoutField::ContentView::layoutCursorSubview() {
if (!m_isEditing) {
m_cursorView.setFrame(KDRectZero);
return;
}
KDPoint expressionViewOrigin = m_expressionView.absoluteDrawingOrigin();
ExpressionLayout * pointedLayout = m_cursor.pointedExpressionLayout();
ExpressionLayoutCursor::Position cursorPosition = m_cursor.position();
ExpressionLayoutCursor eqCursor = pointedLayout->equivalentCursor(m_cursor);
if (pointedLayout->hasChild(eqCursor.pointedExpressionLayout())) {
pointedLayout = eqCursor.pointedExpressionLayout();
cursorPosition = eqCursor.position();
}
KDPoint cursoredExpressionViewOrigin = pointedLayout->absoluteOrigin();
KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x();
if (cursorPosition == ExpressionLayoutCursor::Position::Right) {
cursorX += pointedLayout->size().width();
}
KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + pointedLayout->baseline() - m_cursor.baseline());
m_cursorView.setFrame(KDRect(cursorTopLeftPosition, ExpressionLayoutCursor::k_cursorWidth, m_cursor.cursorHeight()));
}

View File

@@ -18,7 +18,7 @@ void ExpressionTableCell::setHighlighted(bool highlight) {
m_labelExpressionView.setBackgroundColor(backgroundColor);
}
void ExpressionTableCell::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
m_labelExpressionView.setExpressionLayout(expressionLayout);
void ExpressionTableCell::setLayoutRef(Poincare::LayoutRef layoutR) {
m_labelExpressionView.setLayoutRef(layoutR);
layoutSubviews();
}

View File

@@ -3,7 +3,7 @@ using namespace Poincare;
ExpressionView::ExpressionView(float horizontalAlignment, float verticalAlignment,
KDColor textColor, KDColor backgroundColor) :
m_expressionLayout(nullptr),
m_layoutRef(nullptr),
m_horizontalAlignment(horizontalAlignment),
m_verticalAlignment(verticalAlignment),
m_textColor(textColor),
@@ -12,12 +12,8 @@ ExpressionView::ExpressionView(float horizontalAlignment, float verticalAlignmen
{
}
ExpressionLayout * ExpressionView::expressionLayout() const {
return m_expressionLayout;
}
void ExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) {
m_expressionLayout = expressionLayout;
void ExpressionView::setLayoutRef(LayoutRef layoutR) {
m_layoutRef = layoutR;
markRectAsDirty(bounds());
}
@@ -42,19 +38,19 @@ void ExpressionView::setAlignment(float horizontalAlignment, float verticalAlign
}
int ExpressionView::numberOfLayouts() const {
return m_expressionLayout->numberOfDescendants(true);
return m_layoutRef.numberOfDescendants(true);
}
KDSize ExpressionView::minimalSizeForOptimalDisplay() const {
if (m_expressionLayout == nullptr) {
if (!m_layoutRef.isDefined()) {
return KDSizeZero;
}
KDSize expressionSize = m_expressionLayout->size();
KDSize expressionSize = m_layoutRef.layoutSize();
return KDSize(expressionSize.width() + 2*m_horizontalMargin, expressionSize.height());
}
KDPoint ExpressionView::drawingOrigin() const {
KDSize expressionSize = m_expressionLayout->size();
KDSize expressionSize = m_layoutRef.layoutSize();
return KDPoint(m_horizontalMargin + m_horizontalAlignment*(m_frame.width() - 2*m_horizontalMargin - expressionSize.width()), max(0, (m_frame.height() - expressionSize.height())/2));
}
@@ -64,7 +60,7 @@ KDPoint ExpressionView::absoluteDrawingOrigin() const {
void ExpressionView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(rect, m_backgroundColor);
if (m_expressionLayout != nullptr) {
m_expressionLayout->draw(ctx, drawingOrigin(), m_textColor, m_backgroundColor);
if (m_layoutRef.isDefined()) {
m_layoutRef.draw(ctx, drawingOrigin(), m_textColor, m_backgroundColor);
}
}

View File

@@ -1,32 +1,28 @@
#include <escher/input_view_controller.h>
#include <escher/app.h>
#include <escher/palette.h>
#include <poincare/src/layout/horizontal_layout.h>
#include <poincare/horizontal_layout_node.h>
#include <assert.h>
InputViewController::ExpressionFieldController::ExpressionFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate) :
InputViewController::ExpressionFieldController::ExpressionFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) :
ViewController(parentResponder),
m_layout(new Poincare::HorizontalLayout()),
m_expressionField(this, m_textBuffer, k_bufferLength, m_layout, textFieldDelegate, expressionLayoutFieldDelegate)
m_layout(Poincare::HorizontalLayoutRef()),
m_expressionField(this, m_textBuffer, k_bufferLength, m_layout, textFieldDelegate, layoutFieldDelegate)
{
m_textBuffer[0] = 0;
}
InputViewController::ExpressionFieldController::~ExpressionFieldController() {
delete m_layout;
}
void InputViewController::ExpressionFieldController::didBecomeFirstResponder() {
app()->setFirstResponder(&m_expressionField);
}
InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate) :
InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) :
ModalViewController(parentResponder, child),
m_expressionFieldController(this, this, this),
m_successAction(Invocation(nullptr, nullptr)),
m_failureAction(Invocation(nullptr, nullptr)),
m_textFieldDelegate(textFieldDelegate),
m_expressionLayoutFieldDelegate(expressionLayoutFieldDelegate),
m_layoutFieldDelegate(layoutFieldDelegate),
m_inputViewHeightIsMaximal(false)
{
}
@@ -74,27 +70,27 @@ Toolbox * InputViewController::toolboxForTextInput(TextInput * input) {
return m_textFieldDelegate->toolboxForTextInput(input);
}
bool InputViewController::expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
bool InputViewController::layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) {
return event == Ion::Events::OK || event == Ion::Events::EXE;
}
bool InputViewController::expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
return m_expressionLayoutFieldDelegate->expressionLayoutFieldDidReceiveEvent(expressionLayoutField, event);
bool InputViewController::layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) {
return m_layoutFieldDelegate->layoutFieldDidReceiveEvent(layoutField, event);
}
bool InputViewController::expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, Poincare::ExpressionLayout * layout, Ion::Events::Event event) {
bool InputViewController::layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::LayoutRef layoutR, Ion::Events::Event event) {
inputViewDidFinishEditing();
m_expressionLayoutFieldDelegate->expressionLayoutFieldDidFinishEditing(expressionLayoutField, layout, event);
m_layoutFieldDelegate->layoutFieldDidFinishEditing(layoutField, layoutR, event);
return true;
}
bool InputViewController::expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) {
bool InputViewController::layoutFieldDidAbortEditing(LayoutField * layoutField) {
inputViewDidAbortEditing();
m_expressionLayoutFieldDelegate->expressionLayoutFieldDidAbortEditing(expressionLayoutField);
m_layoutFieldDelegate->layoutFieldDidAbortEditing(layoutField);
return true;
}
void InputViewController::expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) {
void InputViewController::layoutFieldDidChangeSize(LayoutField * layoutField) {
/* Reload the view only if the ExpressionField height actually changes, i.e.
* not if the height is already maximal and stays maximal. */
bool newInputViewHeightIsMaximal = m_expressionFieldController.expressionField()->heightIsMaximal();
@@ -104,8 +100,8 @@ void InputViewController::expressionLayoutFieldDidChangeSize(ExpressionLayoutFie
}
}
Toolbox * InputViewController::toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) {
return m_expressionLayoutFieldDelegate->toolboxForExpressionLayoutField(expressionLayoutField);
Toolbox * InputViewController::toolboxForLayoutField(LayoutField * layoutField) {
return m_layoutFieldDelegate->toolboxForLayoutField(layoutField);
}
void InputViewController::inputViewDidFinishEditing() {

268
escher/src/layout_field.cpp Normal file
View File

@@ -0,0 +1,268 @@
#include <escher/layout_field.h>
#include <apps/i18n.h>
#include <escher/clipboard.h>
#include <escher/text_field.h>
#include <poincare/expression.h>
#include <poincare/expression_layout_cursor.h>
//#include <poincare/src/layout/matrix_layout.h> //TODO
#include <assert.h>
#include <string.h>
using namespace Poincare;
void LayoutField::ContentView::layoutCursorSubview() {
if (!m_isEditing) {
m_cursorView.setFrame(KDRectZero);
return;
}
KDPoint expressionViewOrigin = m_expressionView.absoluteDrawingOrigin();
LayoutRef pointedLayoutR = m_cursor.layoutReference();
LayoutCursor::Position cursorPosition = m_cursor.position();
LayoutCursor eqCursor = pointedLayoutR.equivalentCursor(&m_cursor);
if (pointedLayoutR.hasChild(eqCursor.layoutReference())) {
pointedLayoutR = eqCursor.layoutReference();
cursorPosition = eqCursor.position();
}
KDPoint cursoredExpressionViewOrigin = pointedLayoutR.absoluteOrigin();
KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x();
if (cursorPosition == LayoutCursor::Position::Right) {
cursorX += pointedLayoutR.layoutSize().width();
}
KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + pointedLayoutR.baseline() - m_cursor.baseline());
m_cursorView.setFrame(KDRect(cursorTopLeftPosition, LayoutCursor::k_cursorWidth, m_cursor.cursorHeight()));
}
void LayoutField::reload() {
KDSize previousSize = minimalSizeForOptimalDisplay();
layoutRef().invalidAllSizesPositionsAndBaselines();
KDSize newSize = minimalSizeForOptimalDisplay();
if (m_delegate && previousSize.height() != newSize.height()) {
m_delegate->layoutFieldDidChangeSize(this);
}
m_contentView.cursorPositionChanged();
scrollToCursor();
markRectAsDirty(bounds());
}
bool LayoutField::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
if (text[0] == 0) {
// The text is empty
return true;
}
int currentNumberOfLayouts = m_contentView.expressionView()->numberOfLayouts();
if (currentNumberOfLayouts >= k_maxNumberOfLayouts - 6) {
/* We add -6 because in some cases (Ion::Events::Division,
* Ion::Events::Exp...) we let the layout cursor handle the layout insertion
* and these events may add at most 6 layouts (e.g *10^•). */
return true;
}
// Handle special cases
if (strcmp(text, Ion::Events::Division.text()) == 0) {
m_contentView.cursor()->addFractionLayoutAndCollapseSiblings();
} else if (strcmp(text, Ion::Events::Exp.text()) == 0) {
m_contentView.cursor()->addEmptyExponentialLayout();
} else if (strcmp(text, Ion::Events::Power.text()) == 0) {
m_contentView.cursor()->addEmptyPowerLayout();
} else if (strcmp(text, Ion::Events::Sqrt.text()) == 0) {
m_contentView.cursor()->addEmptySquareRootLayout();
} else if (strcmp(text, Ion::Events::Square.text()) == 0) {
m_contentView.cursor()->addEmptySquarePowerLayout();
} else if (strcmp(text, Ion::Events::EE.text()) == 0) {
m_contentView.cursor()->addEmptyTenPowerLayout();
} else if ((strcmp(text, "[") == 0) || (strcmp(text, "]") == 0)) {
m_contentView.cursor()->addEmptyMatrixLayout();
} else {
Expression * resultExpression = Expression::parse(text);
if (resultExpression == nullptr) {
m_contentView.cursor()->insertText(text);
return true;
}
LayoutRef resultLayoutRef = resultExpression->createLayout(Poincare::Preferences::sharedPreferences()->displayMode(), Poincare::Preferences::sharedPreferences()->numberOfSignificantDigits());
delete resultExpression;
if (currentNumberOfLayouts + resultLayoutRef.numberOfDescendants(true) >= k_maxNumberOfLayouts) {
return true;
}
// Find the pointed layout.
LayoutRef pointedLayoutRef(nullptr);
if (strcmp(text, I18n::translate(I18n::Message::RandomCommandWithArg)) == 0) {
/* Special case: if the text is "random()", the cursor should not be set
* inside the parentheses. */
pointedLayoutRef = resultLayoutRef;
} else if (resultLayoutRef.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 < resultLayoutRef.numberOfChildren(); i++) {
LayoutRef l = resultLayoutRef.childAtIndex(i);
if (l.isLeftParenthesis()) {
pointedLayoutRef = l;
break;
}
}
}
/* Insert the layout. If pointedLayout is nullptr, the cursor will be on the
* right of the inserted layout. */
insertLayoutAtCursor(resultLayoutRef, pointedLayoutRef, forceCursorRightOfText);
}
return true;
}
bool LayoutField::handleEvent(Ion::Events::Event event) {
bool didHandleEvent = false;
bool shouldRecomputeLayout = m_contentView.cursor()->showEmptyLayoutIfNeeded();
bool moveEventChangedLayout = false;
if (privateHandleMoveEvent(event, &moveEventChangedLayout)) {
if (!isEditing()) {
setEditing(true);
}
shouldRecomputeLayout = shouldRecomputeLayout || moveEventChangedLayout;
didHandleEvent = true;
} else if (privateHandleEvent(event)) {
shouldRecomputeLayout = true;
didHandleEvent = true;
}
if (didHandleEvent) {
shouldRecomputeLayout = m_contentView.cursor()->hideEmptyLayoutIfNeeded() || shouldRecomputeLayout;
if (!shouldRecomputeLayout) {
m_contentView.cursorPositionChanged();
scrollToCursor();
} else {
reload();
}
return true;
}
m_contentView.cursor()->hideEmptyLayoutIfNeeded();
return false;
}
bool LayoutField::privateHandleEvent(Ion::Events::Event event) {
if (m_delegate && m_delegate->layoutFieldDidReceiveEvent(this, event)) {
return true;
}
if (Responder::handleEvent(event)) {
/* The only event Responder handles is 'Toolbox' displaying. In that case,
* the ExpressionLayoutField is forced into editing mode. */
if (!isEditing()) {
setEditing(true);
}
return true;
}
if (isEditing() && m_delegate->layoutFieldShouldFinishEditing(this, event)) { //TODO use class method?
setEditing(false);
if (m_delegate->layoutFieldDidFinishEditing(this, layoutRef(), event)) {
clearLayout();
}
return true;
}
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && !isEditing()) {
setEditing(true);
m_contentView.cursor()->setLayoutReference(layoutRef());
m_contentView.cursor()->setPosition(LayoutCursor::Position::Right);
return true;
}
if (event == Ion::Events::Back && isEditing()) {
clearLayout();
setEditing(false);
m_delegate->layoutFieldDidAbortEditing(this);
return true;
}
if (event.hasText() || event == Ion::Events::Paste || event == Ion::Events::Backspace) {
if (!isEditing()) {
setEditing(true);
}
if (event.hasText()) {
handleEventWithText(event.text());
} else if (event == Ion::Events::Paste) {
handleEventWithText(Clipboard::sharedClipboard()->storedText(), false, true);
} else {
assert(event == Ion::Events::Backspace);
m_contentView.cursor()->performBackspace();
}
return true;
}
if (event == Ion::Events::Clear && isEditing()) {
clearLayout();
return true;
}
return false;
}
bool LayoutField::privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) {
LayoutCursor result;
if (event == Ion::Events::Left) {
result = m_contentView.cursor()->cursorAtDirection(LayoutCursor::MoveDirection::Left, shouldRecomputeLayout);
} else if (event == Ion::Events::Right) {
result = m_contentView.cursor()->cursorAtDirection(LayoutCursor::MoveDirection::Right, shouldRecomputeLayout);
} else if (event == Ion::Events::Up) {
result = m_contentView.cursor()->cursorAtDirection(LayoutCursor::MoveDirection::Up, shouldRecomputeLayout);
} else if (event == Ion::Events::Down) {
result = m_contentView.cursor()->cursorAtDirection(LayoutCursor::MoveDirection::Down, shouldRecomputeLayout);
} else if (event == Ion::Events::ShiftLeft) {
*shouldRecomputeLayout = true;
if (m_contentView.cursor()->layoutReference().removeGreySquaresFromAllMatrixAncestors()) {
*shouldRecomputeLayout = true;
}
result.setLayoutReference(layoutRef());
result.setPosition(LayoutCursor::Position::Left);
} else if (event == Ion::Events::ShiftRight) {
if (m_contentView.cursor()->layoutReference().removeGreySquaresFromAllMatrixAncestors()) {
*shouldRecomputeLayout = true;
}
result.setLayoutReference(layoutRef());
result.setPosition(LayoutCursor::Position::Right);
}
if (result.isDefined()) {
m_contentView.setCursor(result);
return true;
}
return false;
}
void LayoutField::scrollRightOfLayout(LayoutRef layoutR) {
KDRect layoutRect(layoutR.absoluteOrigin().translatedBy(m_contentView.expressionView()->drawingOrigin()), layoutR.layoutSize());
scrollToBaselinedRect(layoutRect, layoutR.baseline());
}
void LayoutField::scrollToBaselinedRect(KDRect rect, KDCoordinate baseline) {
scrollToContentRect(rect, true);
// Show the rect area around its baseline
KDCoordinate underBaseline = rect.height() - baseline;
KDCoordinate minAroundBaseline = min(baseline, underBaseline);
minAroundBaseline = min(minAroundBaseline, bounds().height() / 2);
KDRect balancedRect(rect.x(), rect.y() + baseline - minAroundBaseline, rect.width(), 2 * minAroundBaseline);
scrollToContentRect(balancedRect, true);
}
void LayoutField::insertLayoutAtCursor(LayoutRef layoutR, LayoutRef pointedLayoutR, bool forceCursorRightOfLayout) {
if (!layoutR.isDefined()) {
return;
}
m_contentView.cursor()->showEmptyLayoutIfNeeded();
bool layoutWillBeMerged = layoutR.isHorizontal();
LayoutRef lastMergedLayoutChild = layoutWillBeMerged ? layoutR.childAtIndex(layoutR.numberOfChildren()-1) : LayoutRef(nullptr);
m_contentView.cursor()->addLayoutAndMoveCursor(layoutR);
if (!forceCursorRightOfLayout) {
if (pointedLayoutR.isDefined() && pointedLayoutR.parent().isDefined() && (!layoutWillBeMerged || pointedLayoutR != layoutR)) {
// Make sure the layout was inserted (its parent is not nullptr)
m_contentView.cursor()->setLayoutReference(pointedLayoutR);
m_contentView.cursor()->setPosition(LayoutCursor::Position::Right);
} else if (!layoutWillBeMerged && layoutR.parent().isDefined()) { //&& !layoutR.isAllocationFailure()) {
m_contentView.cursor()->setLayoutReference(layoutR.layoutToPointWhenInserting());
m_contentView.cursor()->setPosition(LayoutCursor::Position::Right);
}
} else if (!layoutWillBeMerged && layoutR.parent().isDefined()) {
m_contentView.cursor()->setLayoutReference(layoutR);
m_contentView.cursor()->setPosition(LayoutCursor::Position::Right);
}
m_contentView.cursor()->layoutReference().addGreySquaresToAllMatrixAncestors();
m_contentView.cursor()->hideEmptyLayoutIfNeeded();
reload();
if (!layoutWillBeMerged) {
scrollRightOfLayout(layoutR);
} else {
assert(lastMergedLayoutChild.isDefined());
scrollRightOfLayout(lastMergedLayoutChild);
}
scrollToCursor();
}

View File

@@ -17,8 +17,8 @@ void MessageTableCellWithChevronAndExpression::setHighlighted(bool highlight) {
m_subtitleView.setBackgroundColor(backgroundColor);
}
void MessageTableCellWithChevronAndExpression::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
m_subtitleView.setExpressionLayout(expressionLayout);
void MessageTableCellWithChevronAndExpression::setLayoutRef(Poincare::LayoutRef layoutR) {
m_subtitleView.setLayoutRef(layoutR);
reloadCell();
layoutSubviews();
}

View File

@@ -17,8 +17,8 @@ void MessageTableCellWithExpression::setHighlighted(bool highlight) {
m_subtitleView.setBackgroundColor(backgroundColor);
}
void MessageTableCellWithExpression::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
m_subtitleView.setExpressionLayout(expressionLayout);
void MessageTableCellWithExpression::setLayoutRef(Poincare::LayoutRef layout) {
m_subtitleView.setLayoutRef(layout);
reloadCell();
layoutSubviews();
}

View File

@@ -128,9 +128,9 @@ bool SelectableTableView::handleEvent(Ion::Events::Event event) {
Clipboard::sharedClipboard()->store(text);
return true;
}
Poincare::ExpressionLayout * layout = cell->expressionLayout();
if (layout) {
Clipboard::sharedClipboard()->store(layout);
Poincare::LayoutRef layoutR = cell->layoutRef();
if (layoutR.isDefined()) {
Clipboard::sharedClipboard()->store(layoutR);
return true;
}
}

View File

@@ -2,6 +2,31 @@ SFLAGS += -Ipoincare/include
#include poincare/src/simplify/Makefile
#include poincare/src/simplification/Makefile
objs += $(addprefix poincare/src/,\
tree_node.o\
tree_pool.o\
)
objs += $(addprefix poincare/src/,\
bracket_layout_node.o\
bracket_pair_layout_node.o\
char_layout_node.o\
conjugate_layout_node.o\
empty_layout_node.o\
horizontal_layout_node.o\
layout_cursor.o\
layout_node.o\
layout_reference.o\
left_parenthesis_layout_node.o\
left_square_bracket_layout_node.o\
nth_root_layout_node.o\
product_layout_node.o\
right_parenthesis_layout_node.o\
right_square_bracket_layout_node.o\
sequence_layout_node.o\
sum_layout_node.o\
vertical_offset_layout_node.o\
)
objs += $(addprefix poincare/src/,\
absolute_value.o\

View File

@@ -4,16 +4,22 @@
#define MATRICES_ARE_DEFINED 1
#include <poincare/absolute_value.h>
#include <poincare/absolute_value_layout_node.h>
#include <poincare/addition.h>
#include <poincare/approximation.h>
#include <poincare/allocation_failed_layout_node.h>
#include <poincare/arc_cosine.h>
#include <poincare/arc_sine.h>
#include <poincare/arc_tangent.h>
#include <poincare/binomial_coefficient.h>
#include <poincare/bracket_pair_layout_node.h>
#include <poincare/char_layout_node.h>
#include <poincare/ceiling.h>
#include <poincare/ceiling_layout_node.h>
#include <poincare/complex_argument.h>
#include <poincare/confidence_interval.h>
#include <poincare/conjugate.h>
#include <poincare/conjugate_layout_node.h>
#include <poincare/context.h>
#include <poincare/cosine.h>
#include <poincare/decimal.h>
@@ -23,6 +29,7 @@
#include <poincare/division_quotient.h>
#include <poincare/division_remainder.h>
#include <poincare/empty_expression.h>
#include <poincare/empty_layout_node.h>
#include <poincare/equal.h>
#include <poincare/expression.h>
#include <poincare/expression_array.h>
@@ -32,9 +39,11 @@
#include <poincare/expression_layout_cursor.h>
#include <poincare/factorial.h>
#include <poincare/floor.h>
#include <poincare/floor_layout_node.h>
#include <poincare/frac_part.h>
#include <poincare/global_context.h>
#include <poincare/great_common_divisor.h>
#include <poincare/horizontal_layout_node.h>
#include <poincare/hyperbolic_arc_cosine.h>
#include <poincare/hyperbolic_arc_sine.h>
#include <poincare/hyperbolic_arc_tangent.h>
@@ -43,7 +52,12 @@
#include <poincare/hyperbolic_tangent.h>
#include <poincare/imaginary_part.h>
#include <poincare/integral.h>
#include <poincare/layout_cursor.h>
#include <poincare/layout_node.h>
#include <poincare/layout_reference.h>
#include <poincare/least_common_multiple.h>
#include <poincare/left_parenthesis_layout_node.h>
#include <poincare/left_square_bracket_layout_node.h>
#include <poincare/logarithm.h>
#include <poincare/matrix.h>
#include <poincare/matrix_dimension.h>
@@ -53,6 +67,7 @@
#include <poincare/multiplication.h>
#include <poincare/naperian_logarithm.h>
#include <poincare/nth_root.h>
#include <poincare/nth_root_layout_node.h>
#include <poincare/opposite.h>
#include <poincare/parenthesis.h>
#include <poincare/permute_coefficient.h>
@@ -60,19 +75,30 @@
#include <poincare/prediction_interval.h>
#include <poincare/preferences.h>
#include <poincare/product.h>
#include <poincare/product_layout_node.h>
#include <poincare/randint.h>
#include <poincare/random.h>
#include <poincare/rational.h>
#include <poincare/real_part.h>
#include <poincare/right_parenthesis_layout_node.h>
#include <poincare/right_square_bracket_layout_node.h>
#include <poincare/round.h>
#include <poincare/serializable_node.h>
#include <poincare/serializable_reference.h>
#include <poincare/sine.h>
#include <poincare/square_root.h>
#include <poincare/square_bracket_layout_node.h>
#include <poincare/store.h>
#include <poincare/subtraction.h>
#include <poincare/sum.h>
#include <poincare/sum_layout_node.h>
#include <poincare/symbol.h>
#include <poincare/tangent.h>
#include <poincare/tree_node.h>
#include <poincare/tree_pool.h>
#include <poincare/tree_reference.h>
#include <poincare/undefined.h>
#include <poincare/variable_context.h>
#include <poincare/vertical_offset_layout_node.h>
#endif

View File

@@ -16,7 +16,7 @@ public:
private:
Expression * setSign(Sign s, Context & context, AngleUnit angleUnit) override;
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "abs");
}

View File

@@ -0,0 +1,37 @@
#ifndef POINCARE_ABSOLUTE_VALUE_LAYOUT_NODE_H
#define POINCARE_ABSOLUTE_VALUE_LAYOUT_NODE_H
#include <poincare/bracket_pair_layout_node.h>
namespace Poincare {
class AbsoluteValueLayoutNode : public BracketPairLayoutNode {
public:
using BracketPairLayoutNode::BracketPairLayoutNode;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::writePrefixSerializableRefTextInBuffer(SerializableRef(const_cast<AbsoluteValueLayoutNode *>(this)), buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "abs");
}
// TreeNode
size_t size() const override { return sizeof(AbsoluteValueLayoutNode); }
#if TREE_LOG
const char * description() const override { return "AbsoluteValueLayout"; }
#endif
private:
KDCoordinate widthMargin() const override { return 2; }
virtual KDCoordinate verticalExternMargin() const override { return 1; }
bool renderTopBar() const override { return false; }
bool renderBottomBar() const override { return false; }
};
class AbsoluteValueLayoutRef : public LayoutReference<AbsoluteValueLayoutNode> {
public:
AbsoluteValueLayoutRef(TreeNode * n) : LayoutReference<AbsoluteValueLayoutNode>(n) {}
AbsoluteValueLayoutRef(LayoutRef l) : LayoutReference<AbsoluteValueLayoutNode>() {
addChildTreeAtIndex(l, 0);
}
};
}
#endif

View File

@@ -32,7 +32,7 @@ public:
private:
/* Layout */
bool needParenthesisWithParent(const Expression * e) const override;
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createInfixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -0,0 +1,53 @@
#ifndef POINCARE_ALLOCATION_FAILED_LAYOUT_NODE_H
#define POINCARE_ALLOCATION_FAILED_LAYOUT_NODE_H
#include "layout_node.h"
#include "layout_reference.h"
#include "layout_cursor.h"
namespace Poincare {
class AllocationFailedLayoutNode : public LayoutNode {
public:
// LayoutNode
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
assert(false);
return 0;
}
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override {}
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override {}
LayoutCursor equivalentCursor(LayoutCursor * cursor) override { return LayoutCursor(); }
void deleteBeforeCursor(LayoutCursor * cursor) override { }
// TreeNode
size_t size() const override { return sizeof(AllocationFailedLayoutNode); }
const char * description() const override { return "Allocation Failed"; }
int numberOfChildren() const override { return 0; }
bool isAllocationFailure() const override { return true; }
protected:
// LayoutNode
void computeSize() override { m_sized = true; }
void computeBaseline() override { m_baselined = true; }
KDPoint positionOfChild(LayoutNode * child) override {
assert(false);
return KDPointZero;
}
private:
bool willAddSibling(LayoutCursor * cursor, LayoutNode * sibling, bool moveCursor) override { return false; }
bool willReplaceChild(LayoutNode * oldChild, LayoutNode * newChild, LayoutCursor * cursor, bool force) override { return false; }
bool willRemoveChild(LayoutNode * l, LayoutCursor * cursor, bool force) override { return false; }
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override {}
};
class AllocationFailedLayoutRef : public LayoutReference<AllocationFailedLayoutNode> {
public:
AllocationFailedLayoutRef() : LayoutReference<AllocationFailedLayoutNode>() {}
AllocationFailedLayoutRef(TreeNode * aNode) : LayoutReference<AllocationFailedLayoutNode>(aNode) {}
};
}
#endif

View File

@@ -43,7 +43,7 @@ public:
}
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
assert(false);
return nullptr;
}

View File

@@ -15,7 +15,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -15,7 +15,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -15,7 +15,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -16,7 +16,7 @@ public:
private:
constexpr static int k_maxNValue = 300;
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "binomial");
}

View File

@@ -0,0 +1,41 @@
#ifndef POINCARE_BRACKET_LAYOUT_NODE_H
#define POINCARE_BRACKET_LAYOUT_NODE_H
#include <poincare/layout_cursor.h>
#include <poincare/layout_node.h>
#include <poincare/layout_reference.h>
namespace Poincare {
class BracketLayoutNode : public LayoutNode {
public:
BracketLayoutNode() :
LayoutNode(),
m_childHeightComputed(false),
m_childHeight(0)
{}
// LayoutNode
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void invalidAllSizesPositionsAndBaselines() override;
// TreeNode
size_t size() const override { return sizeof(BracketLayoutNode); }
int numberOfChildren() const override { return 0; }
#if TREE_LOG
const char * description() const override { return "BracketLayout"; }
#endif
protected:
// LayoutNode
void computeBaseline() override;
KDPoint positionOfChild(LayoutNode * child) override;
KDCoordinate childHeight();
void computeChildHeight();
bool m_childHeightComputed;
uint16_t m_childHeight;
};
}
#endif

View File

@@ -0,0 +1,52 @@
#ifndef POINCARE_BRACKET_PAIR_LAYOUT_NODE_H
#define POINCARE_BRACKET_PAIR_LAYOUT_NODE_H
#include <poincare/layout_cursor.h>
#include <poincare/layout_node.h>
#include <poincare/layout_reference.h>
namespace Poincare {
class BracketPairLayoutNode : public LayoutNode {
//TODO friend class MatrixLayout;
public:
using LayoutNode::LayoutNode;
// LayoutNode
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void deleteBeforeCursor(LayoutCursor * cursor) override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
bool shouldCollapseSiblingsOnRight() const override{ return true; }
void didCollapseSiblings(LayoutCursor * cursor) override;
// TreeNode
size_t size() const override { return sizeof(BracketPairLayoutNode); }
int numberOfChildren() const override { return 1; }
#if TREE_LOG
const char * description() const override { return "BracketPairLayout"; }
#endif
protected:
// LayoutNode
void computeBaseline() override;
void computeSize() override;
KDPoint positionOfChild(LayoutNode * child) override;
LayoutNode * childLayout() { return childAtIndex(0); }
private:
KDCoordinate externWidthMargin() const { return 2; }
virtual KDCoordinate widthMargin() const { return 5; }
virtual KDCoordinate verticalExternMargin() const { return 0; }
constexpr static KDCoordinate k_bracketWidth = 5;
constexpr static KDCoordinate k_lineThickness = 1;
constexpr static KDCoordinate k_verticalMargin = 1;
virtual bool renderTopBar() const { return true; }
virtual bool renderBottomBar() const { return true; }
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
};
}
#endif

View File

@@ -14,7 +14,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name());
}

View File

@@ -0,0 +1,35 @@
#ifndef POINCARE_CEILING_LAYOUT_NODE_H
#define POINCARE_CEILING_LAYOUT_NODE_H
#include <poincare/bracket_pair_layout_node.h>
#include <poincare/layout_engine.h>
namespace Poincare {
class CeilingLayoutNode : public BracketPairLayoutNode {
public:
using BracketPairLayoutNode::BracketPairLayoutNode;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::writePrefixSerializableRefTextInBuffer(SerializableRef(const_cast<CeilingLayoutNode *>(this)), buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "ceil");
}
// TreeNode
size_t size() const override { return sizeof(CeilingLayoutNode); }
#if TREE_LOG
const char * description() const override { return "CeilingLayout"; }
#endif
protected:
bool renderBottomBar() const override { return false; }
};
class CeilingLayoutRef : public LayoutReference<CeilingLayoutNode> {
public:
CeilingLayoutRef(TreeNode * n) : LayoutReference<CeilingLayoutNode>(n) {}
CeilingLayoutRef(LayoutRef l) : LayoutReference<CeilingLayoutNode>() {
addChildTreeAtIndex(l, 0);
}
};
}
#endif

View File

@@ -0,0 +1,78 @@
#ifndef POINCARE_CHAR_LAYOUT_NODE_H
#define POINCARE_CHAR_LAYOUT_NODE_H
#include <poincare/layout_cursor.h>
#include <poincare/layout_node.h>
#include <poincare/layout_reference.h>
namespace Poincare {
class CharLayoutNode : public LayoutNode {
public:
CharLayoutNode(char c = 'a', KDText::FontSize fontSize = KDText::FontSize::Large) :
LayoutNode(),
m_char(c),
m_fontSize(fontSize)
{}
// CharLayout
void setChar(char c) { m_char = c; }
KDText::FontSize fontSize() const { return m_fontSize; }
void setFontSize(KDText::FontSize fontSize) { m_fontSize = fontSize; }
// LayoutNode
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
bool isCollapsable(int * numberOfOpenParenthesis, bool goingLeft) const override;
// TreeNode
size_t size() const override { return sizeof(CharLayoutNode); }
int numberOfChildren() const override { return 0; }
#if TREE_LOG
const char * description() const override {
static char Description[] = "Char a";
Description[5] = m_char;
return Description;
}
#endif
protected:
// LayoutNode
void computeSize() override;
void computeBaseline() override;
KDPoint positionOfChild(LayoutNode * child) override {
assert(false);
return KDPointZero;
}
private:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
char m_char;
KDText::FontSize m_fontSize;
};
class CharLayoutRef : public LayoutReference<CharLayoutNode> {
public:
CharLayoutRef(char c, KDText::FontSize fontSize = KDText::FontSize::Large) :
LayoutReference<CharLayoutNode>()
{
if (!(this->node()->isAllocationFailure())) {
this->typedNode()->setChar(c);
this->typedNode()->setFontSize(fontSize);
}
}
CharLayoutRef(TreeNode * t) : LayoutReference<CharLayoutNode>(t) {}
KDText::FontSize fontSize() const {
if (!(this->node()->isAllocationFailure())) {
return this->typedNode()->fontSize();
}
return KDText::FontSize::Large;
}
};
}
#endif

View File

@@ -0,0 +1,65 @@
#ifndef POINCARE_COMPLEX_H
#define POINCARE_COMPLEX_H
#include <poincare/preferences.h>
#include <poincare/static_hierarchy.h>
#include <poincare/integer.h>
#include <assert.h>
namespace Poincare {
template<typename T>
class Complex : public StaticHierarchy<0> {
public:
Complex() : m_a(0), m_b(0) {}
static Complex<T> Float(T x);
static Complex<T> Cartesian(T a, T b);
static Complex<T> Polar(T r, T theta);
Complex(const char * integralPart, int integralPartLength, bool integralNegative,
const char * fractionalPart, int fractionalPartLength,
const char * exponent, int exponentLength, bool exponentNegative);
Complex(const Complex & other);
Complex& operator=(const Complex& other);
T a() const;
T b() const;
T r() const;
T th() const;
Complex<T> conjugate() const;
T toScalar() const;
/* Expression */
Expression::Type type() const override;
Complex<T> * clone() const override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
/* Properties */
bool needParenthesisWithParent(const Expression * e) const override;
/* Simplification: complex does not implement simplificationOrderSameType
* because Complex expressions are always transformed into an addition of
* Decimal and I symbol before compared with another Expression. */
private:
Complex(T a, T b);
/* Layout */
LayoutRef privateCreateLayout(PrintFloat::Mode floatDisplayMode, Expression::ComplexFormat complexFormat) const override;
/* Simplification */
static Expression * CreateDecimal(T f);
Expression * shallowReduce(Context & context, AngleUnit angleUnit) override;
/* Evaluation */
Expression * privateApproximate(Expression::SinglePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }
Expression * privateApproximate(Expression::DoublePrecision p, Context& context, Expression::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, angleUnit); }
template<typename U> Complex<U> * templatedApproximate(Context& context, Expression::AngleUnit angleUnit) const;
/* convertComplexToText and convertFloatToTextPrivate return the string length
* of the buffer (does not count the 0 last char)*/
int convertComplexToText(char * buffer, int bufferSize, int numberOfSignificantDigits, PrintFloat::Mode floatDisplayMode, Expression::ComplexFormat complexFormat, char multiplicationSign) const;
LayoutRef createPolarLayout(PrintFloat::Mode floatDisplayMode) const;
LayoutRef createCartesianLayout(PrintFloat::Mode floatDisplayMode) const;
T m_a;
T m_b;
};
}
#endif

View File

@@ -14,7 +14,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -14,7 +14,7 @@ public:
int polynomialDegree(char symbolName) const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -14,7 +14,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::writePrefixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "conj");
}

View File

@@ -0,0 +1,54 @@
#ifndef POINCARE_CONJUGATE_LAYOUT_NODE_H
#define POINCARE_CONJUGATE_LAYOUT_NODE_H
#include <poincare/layout_cursor.h>
#include <poincare/layout_node.h>
#include <poincare/layout_reference.h>
namespace Poincare {
class ConjugateLayoutNode : public LayoutNode {
public:
using LayoutNode::LayoutNode;
// LayoutNode
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
bool shouldCollapseSiblingsOnRight() const override { return true; }
// TreeNode
size_t size() const override { return sizeof(ConjugateLayoutNode); }
int numberOfChildren() const override { return 1; }
#if TREE_LOG
const char * description() const override {
return "ConjugateLayout";
}
#endif
protected:
// LayoutNode
void computeSize() override;
void computeBaseline() override;
KDPoint positionOfChild(LayoutNode * child) override;
private:
constexpr static KDCoordinate k_overlineWidth = 1;
constexpr static KDCoordinate k_overlineVerticalMargin = 1;
bool willReplaceChild(LayoutNode * oldChild, LayoutNode * newChild, LayoutCursor * cursor, bool force) override;
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
LayoutNode * childLayout() { return childAtIndex(0); }
};
class ConjugateLayoutRef : public LayoutReference<ConjugateLayoutNode> {
public:
ConjugateLayoutRef(LayoutRef l) :
LayoutReference<ConjugateLayoutNode>()
{
addChildTreeAtIndex(l, 0);
}
ConjugateLayoutRef(TreeNode * n) : LayoutReference<ConjugateLayoutNode>(n) {}
};
}
#endif

View File

@@ -19,7 +19,7 @@ public:
template<typename T> static std::complex<T> computeOnComplex(const std::complex<T> c, AngleUnit angleUnit = AngleUnit::Radian);
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -31,7 +31,7 @@ private:
int simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const override;
/* Layout */
bool needParenthesisWithParent(const Expression * e) const override;
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
/* Simplification */
Expression * shallowReduce(Context& context, AngleUnit angleUnit) override;
Expression * shallowBeautify(Context& context, AngleUnit angleUnit) override;

View File

@@ -15,7 +15,7 @@ public:
int polynomialDegree(char symbolName) const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -13,7 +13,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {

View File

@@ -20,7 +20,7 @@ public:
private:
/* Layout */
bool needParenthesisWithParent(const Expression * e) const override;
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "/");
}

View File

@@ -4,6 +4,7 @@
#include <poincare/layout_engine.h>
#include <poincare/static_hierarchy.h>
#include <poincare/evaluation.h>
#include <poincare/char_layout_node.h>
namespace Poincare {
@@ -14,7 +15,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
@@ -26,7 +27,7 @@ private:
/* Evaluation */
Evaluation<float> * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }
Evaluation<double> * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate<double>(context, angleUnit); }
template<typename T> Complex<T> * templatedApproximate(Context& context, AngleUnit angleUnit) const;
template<typename T> Complex<T> * templatedApproximate(Context& context, AngleUnit angleUnit) const;
};
}

View File

@@ -14,7 +14,7 @@ public:
Expression * clone() const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::createPrefixLayout(this, floatDisplayMode, numberOfSignificantDigits, name());
}
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
@@ -26,8 +26,7 @@ private:
/* Evaluation */
Evaluation<float> * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }
Evaluation<double> * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate<double>(context, angleUnit); }
template<typename T> Complex<T> * templatedApproximate(Context& context, AngleUnit angleUnit) const;
template<typename T> Complex<T> * templatedApproximate(Context& context, AngleUnit angleUnit) const;
};
}

View File

@@ -17,7 +17,7 @@ public:
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
private:
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
/* Evaluation */
Evaluation<float> * privateApproximate(SinglePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }
Evaluation<double> * privateApproximate(DoublePrecision p, Context& context, AngleUnit angleUnit) const override { return templatedApproximate<double>(context, angleUnit); }

View File

@@ -0,0 +1,95 @@
#ifndef POINCARE_EMPTY_LAYOUT_NODE_H
#define POINCARE_EMPTY_LAYOUT_NODE_H
#include <poincare/layout_cursor.h>
#include <poincare/layout_node.h>
#include <poincare/layout_reference.h>
namespace Poincare {
class EmptyLayoutNode : public LayoutNode {
public:
enum class Color {
Yellow,
Grey
};
EmptyLayoutNode(Color color = Color::Yellow, bool visible = true, KDText::FontSize fontSize = KDText::FontSize::Large, bool margins = true) :
LayoutNode(),
m_isVisible(visible),
m_color(color),
m_fontSize(fontSize),
m_margins(margins)
{}
// EmptyLayout
Color color() const { return m_color; }
void setColor(Color color) { m_color = color; }
bool isVisible() const { return m_isVisible; }
void setVisible(bool visible) { m_isVisible = visible; }
void setMargins(bool margins) { m_margins = margins; }
void setFontSize(KDText::FontSize fontSize) { m_fontSize = fontSize; }
// LayoutNode
void deleteBeforeCursor(LayoutCursor * cursor) override;
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
bool isEmpty() const override { return true; }
// TreeNode
size_t size() const override { return sizeof(EmptyLayoutNode); }
int numberOfChildren() const override { return 0; }
#if TREE_LOG
const char * description() const override { return "Empty"; }
#endif
protected:
// LayoutNode
void computeSize() override;
void computeBaseline() override;
KDPoint positionOfChild(LayoutNode * child) override {
assert(false);
return KDPointZero;
}
private:
constexpr static KDCoordinate k_marginWidth = 1;
constexpr static KDCoordinate k_marginHeight = 3;
constexpr static KDCoordinate k_lineThickness = 1;
KDCoordinate height() const { return KDText::charSize(m_fontSize).height() - 2*k_marginHeight; }
KDCoordinate width() const { return KDText::charSize(m_fontSize).width() - 2*k_marginWidth; }
// LayoutNode
void moveCursorVertically(VerticalDirection direction, LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited) override;
bool willAddSibling(LayoutCursor * cursor, LayoutNode * sibling, bool moveCursor) override;
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
bool m_isVisible;
Color m_color;
KDText::FontSize m_fontSize;
bool m_margins;
};
class EmptyLayoutRef : public LayoutReference<EmptyLayoutNode> {
public:
EmptyLayoutRef(TreeNode * eNode) : LayoutReference<EmptyLayoutNode>(eNode) {}
EmptyLayoutRef(EmptyLayoutNode::Color color = EmptyLayoutNode::Color::Yellow, bool visible = true, KDText::FontSize fontSize = KDText::FontSize::Large, bool margins = true) :
LayoutReference<EmptyLayoutNode>()
{
if (!(this->node()->isAllocationFailure())) {
this->typedNode()->setColor(color);
this->typedNode()->setVisible(visible);
this->typedNode()->setFontSize(fontSize);
this->typedNode()->setMargins(margins);
}
}
void setVisible(bool visible) {
if (!(this->node()->isAllocationFailure())) {
this->typedNode()->setVisible(visible);
}
}
};
}
#endif

View File

@@ -19,7 +19,7 @@ private:
/* Simplification */
Expression * shallowReduce(Context& context, AngleUnit angleUnit) override;
/* Layout */
ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override;
int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, "=");
}

View File

@@ -1,7 +1,7 @@
#ifndef POINCARE_EXPRESSION_H
#define POINCARE_EXPRESSION_H
#include <poincare/expression_layout.h>
#include <poincare/layout_reference.h>
#include <poincare/print_float.h>
#include <complex>
extern "C" {
@@ -247,7 +247,7 @@ public:
bool isEqualToItsApproximationLayout(Expression * approximation, int bufferSize, AngleUnit angleUnit, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits, Context & context);
/* Layout Engine */
virtual ExpressionLayout * createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const = 0; // Returned object must be deleted
virtual LayoutRef createLayout(PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits) const = 0;
virtual int writeTextInBuffer(char * buffer, int bufferSize, PrintFloat::Mode floatDisplayMode, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const = 0;
/* Simplification */

Some files were not shown because too many files have changed in this diff Show More