mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
Merge branch Tree into master
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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\
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
31
apps/shared/layout_field_delegate.cpp
Normal file
31
apps/shared/layout_field_delegate.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
23
apps/shared/layout_field_delegate.h
Normal file
23
apps/shared/layout_field_delegate.h
Normal 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
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
11
apps/tree/Makefile
Normal 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\
|
||||
)
|
||||
|
||||
48
apps/tree/addition_node.cpp
Normal file
48
apps/tree/addition_node.cpp
Normal 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
50
apps/tree/addition_node.h
Normal 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
|
||||
26
apps/tree/allocation_failed_expression_node.h
Normal file
26
apps/tree/allocation_failed_expression_node.h
Normal 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
|
||||
11
apps/tree/expression_node.cpp
Normal file
11
apps/tree/expression_node.cpp
Normal 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();
|
||||
}
|
||||
47
apps/tree/expression_node.h
Normal file
47
apps/tree/expression_node.h
Normal 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
|
||||
12
apps/tree/expression_reference.cpp
Normal file
12
apps/tree/expression_reference.cpp
Normal 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;
|
||||
}
|
||||
64
apps/tree/expression_reference.h
Normal file
64
apps/tree/expression_reference.h
Normal 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
34
apps/tree/float_node.h
Normal 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
8
apps/tree/refs.h
Normal 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
341
apps/tree/test.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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\
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
122
escher/include/escher/layout_field.h
Normal file
122
escher/include/escher/layout_field.h
Normal 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
|
||||
19
escher/include/escher/layout_field_delegate.h
Normal file
19
escher/include/escher/layout_field_delegate.h
Normal 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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
268
escher/src/layout_field.cpp
Normal 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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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\
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
37
poincare/include/poincare/absolute_value_layout_node.h
Normal file
37
poincare/include/poincare/absolute_value_layout_node.h
Normal 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
|
||||
@@ -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 {
|
||||
|
||||
53
poincare/include/poincare/allocation_failed_layout_node.h
Normal file
53
poincare/include/poincare/allocation_failed_layout_node.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
41
poincare/include/poincare/bracket_layout_node.h
Normal file
41
poincare/include/poincare/bracket_layout_node.h
Normal 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
|
||||
52
poincare/include/poincare/bracket_pair_layout_node.h
Normal file
52
poincare/include/poincare/bracket_pair_layout_node.h
Normal 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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
35
poincare/include/poincare/ceiling_layout_node.h
Normal file
35
poincare/include/poincare/ceiling_layout_node.h
Normal 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
|
||||
78
poincare/include/poincare/char_layout_node.h
Normal file
78
poincare/include/poincare/char_layout_node.h
Normal 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
|
||||
65
poincare/include/poincare/complex.h
Normal file
65
poincare/include/poincare/complex.h
Normal 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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
54
poincare/include/poincare/conjugate_layout_node.h
Normal file
54
poincare/include/poincare/conjugate_layout_node.h
Normal 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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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, "/");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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); }
|
||||
|
||||
95
poincare/include/poincare/empty_layout_node.h
Normal file
95
poincare/include/poincare/empty_layout_node.h
Normal 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
|
||||
@@ -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, "=");
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user