mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
Merge branch 'SaisieJolieRebase1201' into SaisieJolieMerge10Apr
Change-Id: I802dbb9f7c0eebf75a1b6cd21ddd194e89b53752
This commit is contained in:
@@ -6,13 +6,13 @@ app_objs += $(addprefix apps/calculation/,\
|
||||
calculation.o\
|
||||
calculation_store.o\
|
||||
edit_expression_controller.o\
|
||||
editable_expression_view.o\
|
||||
history_view_cell.o\
|
||||
history_controller.o\
|
||||
output_expressions_view.o\
|
||||
scrollable_expression_view.o\
|
||||
scrollable_output_expressions_view.o\
|
||||
selectable_table_view.o\
|
||||
text_field.o\
|
||||
)
|
||||
|
||||
i18n_files += $(addprefix apps/calculation/,\
|
||||
|
||||
@@ -43,7 +43,7 @@ void App::Snapshot::tidy() {
|
||||
}
|
||||
|
||||
App::App(Container * container, Snapshot * snapshot) :
|
||||
TextFieldDelegateApp(container, snapshot, &m_editExpressionController),
|
||||
EditableExpressionViewDelegateApp(container, snapshot, &m_editExpressionController),
|
||||
m_historyController(&m_editExpressionController, snapshot->calculationStore()),
|
||||
m_editExpressionController(&m_modalViewController, &m_historyController, snapshot->calculationStore())
|
||||
{
|
||||
@@ -85,6 +85,36 @@ bool App::textInputIsCorrect(const char * text) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool App::scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
|
||||
if ((event == Ion::Events::Var || event == Ion::Events::XNT) && EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event)) {
|
||||
return true;
|
||||
}
|
||||
/* Here, we check that the expression entered by the user can be printed with
|
||||
* less than k_printedExpressionLength characters. Otherwise, we prevent the
|
||||
* user from adding this expression to the calculation store. */
|
||||
if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event)) {
|
||||
int bufferLength = TextField::maxBufferSize();
|
||||
char bufferForParsing[bufferLength];
|
||||
Poincare::ExpressionLayout * expressionLayout = scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout();
|
||||
expressionLayout->writeTextInBuffer(bufferForParsing, bufferLength);
|
||||
Expression * exp = Expression::parse(bufferForParsing);
|
||||
if (exp == nullptr) {
|
||||
scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
char buffer[Calculation::k_printedExpressionSize];
|
||||
int length = exp->writeTextInBuffer(buffer, sizeof(buffer));
|
||||
delete exp;
|
||||
/* if the buffer is totally full, it is VERY likely that writeTextInBuffer
|
||||
* escaped before printing utterly the expression. */
|
||||
if (length >= Calculation::k_printedExpressionSize-1) {
|
||||
displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * App::XNT() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class App : public Shared::TextFieldDelegateApp {
|
||||
class App : public Shared::EditableExpressionViewDelegateApp {
|
||||
public:
|
||||
class Descriptor : public ::App::Descriptor {
|
||||
public:
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
};
|
||||
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
|
||||
bool textInputIsCorrect(const char * text);
|
||||
bool scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
|
||||
const char * XNT() override;
|
||||
private:
|
||||
App(Container * container, Snapshot * snapshot);
|
||||
|
||||
@@ -1,49 +1,41 @@
|
||||
#include "edit_expression_controller.h"
|
||||
#include "../apps_container.h"
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include <ion/display.h>
|
||||
#include <poincare/preferences.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Shared;
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate) :
|
||||
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
|
||||
View(),
|
||||
m_mainView(subview),
|
||||
m_textField(parentResponder, m_textBody, TextField::maxBufferSize(), textFieldDelegate)
|
||||
m_editableExpressionView(parentResponder, textFieldDelegate, scrollableExpressionViewWithCursorDelegate)
|
||||
{
|
||||
m_textBody[0] = 0;
|
||||
}
|
||||
|
||||
int EditExpressionController::ContentView::numberOfSubviews() const {
|
||||
return 2;
|
||||
}
|
||||
|
||||
View * EditExpressionController::ContentView::subviewAtIndex(int index) {
|
||||
View * views[2] = {m_mainView, &m_textField};
|
||||
return views[index];
|
||||
assert(index >= 0 && index < numberOfSubviews());
|
||||
if (index == 0) {
|
||||
return m_mainView;
|
||||
}
|
||||
assert(index == 1);
|
||||
return &m_editableExpressionView;
|
||||
}
|
||||
|
||||
void EditExpressionController::ContentView::layoutSubviews() {
|
||||
KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - k_textFieldHeight-k_separatorThickness);
|
||||
KDCoordinate inputViewFrameHeight = m_editableExpressionView.minimalSizeForOptimalDisplay().height();
|
||||
KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - inputViewFrameHeight);
|
||||
m_mainView->setFrame(mainViewFrame);
|
||||
KDRect inputViewFrame(k_textMargin, bounds().height() - k_textFieldHeight, bounds().width()-k_textMargin, k_textFieldHeight);
|
||||
m_textField.setFrame(inputViewFrame);
|
||||
KDRect inputViewFrame(0, bounds().height() - inputViewFrameHeight, bounds().width(), inputViewFrameHeight);
|
||||
m_editableExpressionView.setFrame(inputViewFrame);
|
||||
}
|
||||
|
||||
void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
// Draw the separator
|
||||
ctx->fillRect(KDRect(0, bounds().height() -k_textFieldHeight-k_separatorThickness, bounds().width(), k_separatorThickness), Palette::GreyMiddle);
|
||||
// Color the margin
|
||||
ctx->fillRect(KDRect(0, bounds().height() -k_textFieldHeight, k_textMargin, k_textFieldHeight), m_textField.backgroundColor());
|
||||
}
|
||||
|
||||
TextField * EditExpressionController::ContentView::textField() {
|
||||
return &m_textField;
|
||||
}
|
||||
|
||||
TableView * EditExpressionController::ContentView::mainView() {
|
||||
return m_mainView;
|
||||
void EditExpressionController::ContentView::reload() {
|
||||
layoutSubviews();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
EditExpressionController::EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore) :
|
||||
@@ -55,20 +47,18 @@ EditExpressionController::EditExpressionController(Responder * parentResponder,
|
||||
}
|
||||
|
||||
const char * EditExpressionController::textBody() {
|
||||
return ((ContentView *)view())->textField()->text();
|
||||
return ((ContentView *)view())->editableExpressionView()->text();
|
||||
}
|
||||
|
||||
void EditExpressionController::insertTextBody(const char * text) {
|
||||
TextField * tf = ((ContentView *)view())->textField();
|
||||
tf->setEditing(true, false);
|
||||
tf->handleEventWithText(text);
|
||||
((ContentView *)view())->editableExpressionView()->insertText(text);
|
||||
}
|
||||
|
||||
bool EditExpressionController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Up) {
|
||||
if (m_calculationStore->numberOfCalculations() > 0) {
|
||||
m_cacheBuffer[0] = 0;
|
||||
((ContentView *)view())->textField()->setEditing(false, false);
|
||||
((ContentView *)view())->editableExpressionView()->setEditing(false, false);
|
||||
app()->setFirstResponder(m_historyController);
|
||||
}
|
||||
return true;
|
||||
@@ -79,27 +69,90 @@ bool EditExpressionController::handleEvent(Ion::Events::Event event) {
|
||||
void EditExpressionController::didBecomeFirstResponder() {
|
||||
int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0;
|
||||
m_historyController->scrollToCell(0, lastRow);
|
||||
((ContentView *)view())->textField()->setEditing(true, false);
|
||||
app()->setFirstResponder(((ContentView *)view())->textField());
|
||||
((ContentView *)view())->editableExpressionView()->setEditing(true, false);
|
||||
app()->setFirstResponder(((ContentView *)view())->editableExpressionView());
|
||||
}
|
||||
|
||||
bool EditExpressionController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) {
|
||||
assert(textField == ((ContentView *)view())->editableExpressionView()->textField());
|
||||
if (textField->isEditing() && textField->textFieldShouldFinishEditing(event) && textField->draftTextLength() == 0 && m_cacheBuffer[0] != 0) {
|
||||
App * calculationApp = (App *)app();
|
||||
/* The input text store in m_cacheBuffer might have beed correct the first
|
||||
* time but then be too long when replacing ans in another context */
|
||||
if (!calculationApp->textInputIsCorrect(m_cacheBuffer)) {
|
||||
return true;
|
||||
}
|
||||
m_calculationStore->push(m_cacheBuffer, calculationApp->localContext());
|
||||
m_historyController->reload();
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
return true;
|
||||
return inputViewDidReceiveEvent(event);
|
||||
}
|
||||
return textFieldDelegateApp()->textFieldDidReceiveEvent(textField, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) {
|
||||
assert(textField == ((ContentView *)view())->editableExpressionView()->textField());
|
||||
return inputViewDidFinishEditing(text, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField) {
|
||||
assert(textField == ((ContentView *)view())->editableExpressionView()->textField());
|
||||
return inputViewDidAbortEditing(textField->text());
|
||||
}
|
||||
|
||||
bool EditExpressionController::scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
|
||||
assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor());
|
||||
if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event) && !expressionLayout()->hasText() && m_calculationStore->numberOfCalculations() > 0) {
|
||||
return inputViewDidReceiveEvent(event);
|
||||
}
|
||||
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::scrollableExpressionViewWithCursorDidFinishEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) {
|
||||
assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor());
|
||||
return inputViewDidFinishEditing(text, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor());
|
||||
return inputViewDidAbortEditing(nullptr);
|
||||
}
|
||||
|
||||
void EditExpressionController::scrollableExpressionViewWithCursorDidChangeSize(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor());
|
||||
reloadView();
|
||||
}
|
||||
|
||||
TextFieldDelegateApp * EditExpressionController::textFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
EditableExpressionViewDelegateApp * EditExpressionController::editableExpressionViewDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
View * EditExpressionController::loadView() {
|
||||
return new ContentView(this, (TableView *)m_historyController->view(), this, this);
|
||||
}
|
||||
|
||||
void EditExpressionController::unloadView(View * view) {
|
||||
delete expressionLayout();
|
||||
delete view;
|
||||
}
|
||||
|
||||
void EditExpressionController::reloadView() {
|
||||
((ContentView *)view())->reload();
|
||||
m_historyController->reload();
|
||||
if (m_historyController->numberOfRows() > 0) {
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
}
|
||||
}
|
||||
|
||||
bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event) {
|
||||
App * calculationApp = (App *)app();
|
||||
/* The input text store in m_cacheBuffer might have beed correct the first
|
||||
* time but then be too long when replacing ans in another context */
|
||||
if (!calculationApp->textInputIsCorrect(m_cacheBuffer)) {
|
||||
return true;
|
||||
}
|
||||
m_calculationStore->push(m_cacheBuffer, calculationApp->localContext());
|
||||
m_historyController->reload();
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditExpressionController::inputViewDidFinishEditing(const char * text, Ion::Events::Event event) {
|
||||
App * calculationApp = (App *)app();
|
||||
strlcpy(m_cacheBuffer, textBody(), TextField::maxBufferSize());
|
||||
m_calculationStore->push(textBody(), calculationApp->localContext());
|
||||
@@ -110,27 +163,21 @@ bool EditExpressionController::textFieldDidFinishEditing(::TextField * textField
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField, const char * text) {
|
||||
((ContentView *)view())->textField()->setEditing(true);
|
||||
((ContentView *)view())->textField()->setText(text);
|
||||
bool EditExpressionController::inputViewDidAbortEditing(const char * text) {
|
||||
if (text != nullptr) {
|
||||
((ContentView *)view())->editableExpressionView()->setEditing(true, true);
|
||||
((ContentView *)view())->editableExpressionView()->setText(text);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TextFieldDelegateApp * EditExpressionController::textFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
View * EditExpressionController::loadView() {
|
||||
return new ContentView(this, (TableView *)m_historyController->view(), this);
|
||||
}
|
||||
|
||||
void EditExpressionController::unloadView(View * view) {
|
||||
delete view;
|
||||
}
|
||||
|
||||
void EditExpressionController::viewDidDisappear() {
|
||||
DynamicViewController::viewDidDisappear();
|
||||
m_historyController->viewDidDisappear();
|
||||
}
|
||||
|
||||
Poincare::ExpressionLayout * EditExpressionController::expressionLayout() {
|
||||
return ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor()->expressionViewWithCursor()->expressionView()->expressionLayout();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
#define CALCULATION_EDIT_EXPRESSION_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "editable_expression_view.h"
|
||||
#include "../shared/text_field_delegate.h"
|
||||
#include "../shared/scrollable_expression_view_with_cursor_delegate.h"
|
||||
#include "history_controller.h"
|
||||
#include "calculation_store.h"
|
||||
#include "text_field.h"
|
||||
|
||||
namespace Calculation {
|
||||
class HistoryController;
|
||||
|
||||
/* TODO: implement a split view */
|
||||
class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate {
|
||||
class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate, public Shared::ScrollableExpressionViewWithCursorDelegate {
|
||||
public:
|
||||
EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore);
|
||||
void didBecomeFirstResponder() override;
|
||||
@@ -19,31 +20,43 @@ public:
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
const char * textBody();
|
||||
void insertTextBody(const char * text);
|
||||
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
|
||||
|
||||
/* TextFieldDelegate */
|
||||
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(::TextField * textField, const char * text) override;
|
||||
bool textFieldDidAbortEditing(::TextField * textField) override;
|
||||
|
||||
/* ScrollableExpressionViewWithCursorDelegate */
|
||||
bool scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
|
||||
bool scrollableExpressionViewWithCursorDidFinishEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override;
|
||||
bool scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
void scrollableExpressionViewWithCursorDidChangeSize(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate);
|
||||
int numberOfSubviews() const override;
|
||||
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
|
||||
void reload();
|
||||
TableView * mainView() { return m_mainView; }
|
||||
EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; }
|
||||
/* View */
|
||||
int numberOfSubviews() const override { return 2; }
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
TextField * textField();
|
||||
TableView * mainView();
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
private:
|
||||
static constexpr KDCoordinate k_textFieldHeight = 37;
|
||||
static constexpr KDCoordinate k_textMargin= 5;
|
||||
constexpr static int k_separatorThickness = 1;
|
||||
TableView * m_mainView;
|
||||
TextField m_textField;
|
||||
char m_textBody[TextField::maxBufferSize()];
|
||||
EditableExpressionView m_editableExpressionView;
|
||||
};
|
||||
View * loadView() override;
|
||||
void unloadView(View * view) override;
|
||||
void reloadView();
|
||||
bool inputViewDidReceiveEvent(Ion::Events::Event event);
|
||||
bool inputViewDidFinishEditing(const char * text, Ion::Events::Event event);
|
||||
bool inputViewDidAbortEditing(const char * text);
|
||||
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
|
||||
char m_cacheBuffer[TextField::maxBufferSize()];
|
||||
Shared::EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() override;
|
||||
Poincare::ExpressionLayout * expressionLayout();
|
||||
HistoryController * m_historyController;
|
||||
CalculationStore * m_calculationStore;
|
||||
};
|
||||
|
||||
31
apps/calculation/editable_expression_view.cpp
Normal file
31
apps/calculation/editable_expression_view.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "editable_expression_view.h"
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
EditableExpressionView::EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
|
||||
::EditableExpressionView(parentResponder, textFieldDelegate, scrollableExpressionViewWithCursorDelegate)
|
||||
{
|
||||
setEditing(true);
|
||||
}
|
||||
|
||||
bool EditableExpressionView::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Back) {
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::Ans) {
|
||||
insertText("ans");
|
||||
return true;
|
||||
}
|
||||
if (isEditing() && isEmpty() &&
|
||||
(event == Ion::Events::Multiplication ||
|
||||
event == Ion::Events::Plus ||
|
||||
event == Ion::Events::Power ||
|
||||
event == Ion::Events::Square ||
|
||||
event == Ion::Events::Division ||
|
||||
event == Ion::Events::Sto)) {
|
||||
insertText("ans");
|
||||
}
|
||||
return(::EditableExpressionView::handleEvent(event));
|
||||
}
|
||||
|
||||
}
|
||||
17
apps/calculation/editable_expression_view.h
Normal file
17
apps/calculation/editable_expression_view.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef CALCULATION_EDITABLE_EXPRESSION_VIEW_H
|
||||
#define CALCULATION_EDITABLE_EXPRESSION_VIEW_H
|
||||
|
||||
#include <escher.h>
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class EditableExpressionView : public ::EditableExpressionView {
|
||||
public:
|
||||
EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
|
||||
protected:
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -83,7 +83,7 @@ void HistoryViewCell::layoutSubviews() {
|
||||
}
|
||||
|
||||
void HistoryViewCell::setCalculation(Calculation * calculation) {
|
||||
m_inputView.setExpression(calculation->inputLayout());
|
||||
m_inputView.setExpressionLayout(calculation->inputLayout());
|
||||
App * calculationApp = (App *)app();
|
||||
/* Both output expressions have to be updated at the same time. The
|
||||
* outputView points to deleted layouts and a call to
|
||||
|
||||
@@ -16,8 +16,8 @@ OutputExpressionsView::OutputExpressionsView(Responder * parentResponder) :
|
||||
}
|
||||
|
||||
void OutputExpressionsView::setExpressions(ExpressionLayout ** expressionsLayout) {
|
||||
m_approximateExpressionView.setExpression(expressionsLayout[0]);
|
||||
m_exactExpressionView.setExpression(expressionsLayout[1]);
|
||||
m_approximateExpressionView.setExpressionLayout(expressionsLayout[0]);
|
||||
m_exactExpressionView.setExpressionLayout(expressionsLayout[1]);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ ScrollableExpressionView::ScrollableExpressionView(Responder * parentResponder)
|
||||
{
|
||||
}
|
||||
|
||||
void ScrollableExpressionView::setExpression(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpression(expressionLayout);
|
||||
void ScrollableExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpressionLayout(expressionLayout);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Calculation {
|
||||
class ScrollableExpressionView : public ScrollableView, public ScrollViewDataSource {
|
||||
public:
|
||||
ScrollableExpressionView(Responder * parentResponder);
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setBackgroundColor(KDColor backgroundColor);
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
private:
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "text_field.h"
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
TextField::TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate) :
|
||||
::TextField(parentResponder, textBuffer, textBuffer, textBufferSize, delegate, false)
|
||||
{
|
||||
setEditing(true);
|
||||
}
|
||||
|
||||
bool TextField::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Back) {
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::Ans) {
|
||||
return handleEventWithText("ans");
|
||||
}
|
||||
if (isEditing() && draftTextLength() == 0 &&
|
||||
(event == Ion::Events::Multiplication ||
|
||||
event == Ion::Events::Plus ||
|
||||
event == Ion::Events::Power ||
|
||||
event == Ion::Events::Square ||
|
||||
event == Ion::Events::Division ||
|
||||
event == Ion::Events::Sto)) {
|
||||
handleEventWithText("ans");
|
||||
}
|
||||
return(::TextField::handleEvent(event));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef CALCULATION_TEXT_FIELD_H
|
||||
#define CALCULATION_TEXT_FIELD_H
|
||||
|
||||
#include <escher.h>
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class TextField : public ::TextField {
|
||||
public:
|
||||
TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate);
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -277,7 +277,7 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConsoleController::textFieldDidAbortEditing(TextField * textField, const char * text) {
|
||||
bool ConsoleController::textFieldDidAbortEditing(TextField * textField) {
|
||||
if (inputRunLoopActive()) {
|
||||
askInputRunLoopTermination();
|
||||
} else {
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField, const char * text) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
Toolbox * toolboxForTextInput(TextInput * textInput) override;
|
||||
|
||||
// MicroPython::ExecutionEnvironment
|
||||
|
||||
@@ -343,8 +343,8 @@ bool MenuController::textFieldDidFinishEditing(TextField * textField, const char
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MenuController::textFieldDidAbortEditing(TextField * textField, const char * text) {
|
||||
if (strlen(text) <= strlen(ScriptStore::k_scriptExtension)) {
|
||||
bool MenuController::textFieldDidAbortEditing(TextField * textField) {
|
||||
if (strlen(textField->text()) <= strlen(ScriptStore::k_scriptExtension)) {
|
||||
// The previous text was an empty name. Use a numbered default script name.
|
||||
char numberedDefaultName[k_defaultScriptNameMaxSize];
|
||||
numberedDefaultScriptName(numberedDefaultName);
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField, const char * text) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
bool textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textHasChanged) override;
|
||||
Toolbox * toolboxForTextInput(TextInput * textInput) override { return nullptr; }
|
||||
|
||||
|
||||
@@ -291,8 +291,9 @@ bool PythonToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) {
|
||||
m_selectableTableView.deselectTable();
|
||||
ToolboxMessageTree * node = selectedMessageTree;
|
||||
const char * editedText = I18n::translate(node->insertedText());
|
||||
char strippedEditedText[strlen(editedText)+1];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandMessage(node->insertedText(), strippedEditedText);
|
||||
int strippedEditedTextMaxLength = strlen(editedText)+1;
|
||||
char strippedEditedText[strippedEditedTextMaxLength];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandMessage(node->insertedText(), strippedEditedText, strippedEditedTextMaxLength);
|
||||
TextInput * textInput = static_cast<TextInput *>(sender());
|
||||
textInput->handleEventWithText(strippedEditedText, true);
|
||||
app()->dismissModalViewController();
|
||||
|
||||
@@ -113,8 +113,9 @@ void VariableBoxController::ContentViewController::willDisplayCellForIndex(Highl
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::insertTextInCaller(const char * text) {
|
||||
char commandBuffer[strlen(text)+1];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandText(text, commandBuffer);
|
||||
int commandBufferMaxSize = strlen(text)+1;
|
||||
char commandBuffer[commandBufferMaxSize];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandText(text, commandBuffer, commandBufferMaxSize);
|
||||
m_textInputCaller->handleEventWithText(commandBuffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ App::App(Container * container, Snapshot * snapshot) :
|
||||
m_valuesHeader(&m_valuesStackViewController, &m_valuesAlternateEmptyViewController, &m_valuesController),
|
||||
m_valuesStackViewController(&m_tabViewController, &m_valuesHeader),
|
||||
m_tabViewController(&m_inputViewController, snapshot, &m_listStackViewController, &m_graphStackViewController, &m_valuesStackViewController),
|
||||
m_inputViewController(&m_modalViewController, &m_tabViewController, this)
|
||||
m_inputViewController(&m_modalViewController, &m_tabViewController, this, this)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) {
|
||||
void ListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) {
|
||||
FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell;
|
||||
Function * f = m_functionStore->functionAtIndex(j);
|
||||
myCell->setExpression(f->layout());
|
||||
myCell->setExpressionLayout(f->layout());
|
||||
bool active = f->isActive();
|
||||
KDColor textColor = active ? KDColorBlack : Palette::GreyDark;
|
||||
myCell->setTextColor(textColor);
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#include "math_toolbox.h"
|
||||
#include "./shared/toolbox_helpers.h"
|
||||
#include <poincare/expression_layout_array.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
/* TODO: find a shorter way to initialize tree models
|
||||
* We create one model tree: each node keeps the label of the row it refers to
|
||||
* and the text which would be edited by clicking on the row. When the node is a
|
||||
* subtree, the edited text is set at I18n::Message::Default. */
|
||||
|
||||
|
||||
const ToolboxMessageTree calculChildren[4] = {
|
||||
ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg),
|
||||
@@ -33,7 +37,8 @@ const ToolboxMessageTree arithmeticChildren[5] = {
|
||||
ToolboxMessageTree(I18n::Message::QuoCommandWithArg, I18n::Message::Quotient, I18n::Message::QuoCommandWithArg)};
|
||||
|
||||
#if MATRICES_ARE_DEFINED
|
||||
const ToolboxMessageTree matricesChildren[5] = {
|
||||
const ToolboxMessageTree matricesChildren[6] = {
|
||||
ToolboxMessageTree(I18n::Message::MatrixCommandWithArg, I18n::Message::NewMatrix, I18n::Message::MatrixCommand),
|
||||
ToolboxMessageTree(I18n::Message::InverseCommandWithArg, I18n::Message::Inverse, I18n::Message::InverseCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::DeterminantCommandWithArg, I18n::Message::Determinant, I18n::Message::DeterminantCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::TransposeCommandWithArg, I18n::Message::Transpose, I18n::Message::TransposeCommandWithArg),
|
||||
@@ -72,12 +77,13 @@ const ToolboxMessageTree predictionChildren[3] = {
|
||||
ToolboxMessageTree(I18n::Message::ConfidenceCommandWithArg, I18n::Message::Confidence, I18n::Message::ConfidenceCommandWithArg)};
|
||||
|
||||
#if LIST_ARE_DEFINED
|
||||
const ToolboxMessageTree menu[12] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg),
|
||||
const ToolboxMessageTree menu[12] = {
|
||||
#elif MATRICES_ARE_DEFINED
|
||||
const ToolboxMessageTree menu[11] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg),
|
||||
const ToolboxMessageTree menu[11] = {
|
||||
#else
|
||||
const ToolboxMessageTree menu[10] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg),
|
||||
const ToolboxMessageTree menu[10] = {
|
||||
#endif
|
||||
ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::Calculation, I18n::Message::Default, I18n::Message::Default, calculChildren, 4),
|
||||
@@ -85,7 +91,7 @@ const ToolboxMessageTree menu[10] = {ToolboxMessageTree(I18n::Message::AbsComman
|
||||
ToolboxMessageTree(I18n::Message::Probability, I18n::Message::Default, I18n::Message::Default, probabilityChildren, 2),
|
||||
ToolboxMessageTree(I18n::Message::Arithmetic, I18n::Message::Default, I18n::Message::Default, arithmeticChildren, 5),
|
||||
#if MATRICES_ARE_DEFINED
|
||||
ToolboxMessageTree(I18n::Message::Matrices, I18n::Message::Default, I18n::Message::Default, matricesChildren, 5),
|
||||
ToolboxMessageTree(I18n::Message::Matrices, I18n::Message::Default, I18n::Message::Default, matricesChildren, 6),
|
||||
#endif
|
||||
#if LIST_ARE_DEFINED
|
||||
ToolboxMessageTree(I18n::Message::Lists, I18n::Message::Default, I18n::Message::Default, listesChildren, 5),
|
||||
@@ -101,21 +107,71 @@ const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbo
|
||||
const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 10);
|
||||
#endif
|
||||
|
||||
MathToolbox::MathToolbox() : Toolbox(nullptr, I18n::translate(rootModel()->label()))
|
||||
MathToolbox::MathToolbox() :
|
||||
Toolbox(nullptr, I18n::translate(rootModel()->label())),
|
||||
m_action(actionForTextInput)
|
||||
{
|
||||
}
|
||||
|
||||
TextField * MathToolbox::sender() {
|
||||
return (TextField *)Toolbox::sender();
|
||||
void MathToolbox::setSenderAndAction(Responder * sender, Action action) {
|
||||
setSender(sender);
|
||||
m_action = action;
|
||||
}
|
||||
|
||||
void MathToolbox::actionForScrollableExpressionViewWithCursor(void * sender, const char * text, bool removeArguments) {
|
||||
ScrollableExpressionViewWithCursor * expressionLayoutEditorSender = static_cast<ScrollableExpressionViewWithCursor *>(sender);
|
||||
Expression * resultExpression = nullptr;
|
||||
if (removeArguments) {
|
||||
// Replace the arguments with Empty chars.
|
||||
int textToInsertMaxLength = strlen(text);
|
||||
char textToInsert[textToInsertMaxLength];
|
||||
Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandText(text, textToInsert, textToInsertMaxLength);
|
||||
// Create the layout
|
||||
resultExpression = Expression::parse(textToInsert);
|
||||
} else {
|
||||
resultExpression = Expression::parse(text);
|
||||
}
|
||||
if (resultExpression == nullptr) {
|
||||
return;
|
||||
}
|
||||
ExpressionLayout * resultLayout = resultExpression->createLayout();
|
||||
// Find the pointed layout.
|
||||
ExpressionLayout * pointedLayout = nullptr;
|
||||
if (resultLayout->isHorizontal()) {
|
||||
// If the layout is horizontal, pick the first open parenthesis.
|
||||
// For now, all horizontal layouts in MathToolbox have parentheses.
|
||||
for (int i = 0; i < resultLayout->numberOfChildren(); i++) {
|
||||
if (resultLayout->editableChild(i)->isLeftParenthesis()) {
|
||||
pointedLayout = resultLayout->editableChild(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (resultLayout->numberOfChildren() > 0) {
|
||||
// Else, if the layout has children, pick the first one.
|
||||
pointedLayout = resultLayout->editableChild(0);
|
||||
}
|
||||
// Insert the layout. If pointedLayout is nullptr, the cursor will be on the
|
||||
// right of the inserted layout.
|
||||
expressionLayoutEditorSender->insertLayoutAtCursor(resultLayout, pointedLayout);
|
||||
}
|
||||
|
||||
void MathToolbox::actionForTextInput(void * sender, const char * text, bool removeArguments) {
|
||||
TextInput * textInputSender = static_cast<TextInput *>(sender);
|
||||
if (removeArguments) {
|
||||
int maxTextToInsertLength = strlen(text);
|
||||
char textToInsert[maxTextToInsertLength];
|
||||
// Translate the message and remove the arguments.
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandText(text, textToInsert, maxTextToInsertLength);
|
||||
textInputSender->handleEventWithText(textToInsert);
|
||||
} else {
|
||||
textInputSender->handleEventWithText(text);
|
||||
}
|
||||
}
|
||||
|
||||
bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) {
|
||||
m_selectableTableView.deselectTable();
|
||||
ToolboxMessageTree * messageTree = selectedMessageTree;
|
||||
const char * editedText = I18n::translate(messageTree->insertedText());
|
||||
char strippedEditedText[strlen(editedText)];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedEditedText);
|
||||
sender()->handleEventWithText(strippedEditedText);
|
||||
m_selectableTableView.deselectTable();
|
||||
m_action(sender(), I18n::translate(messageTree->insertedText()), true);
|
||||
app()->dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,15 +7,19 @@
|
||||
|
||||
class MathToolbox : public Toolbox {
|
||||
public:
|
||||
typedef void (*Action)(void * sender, const char * text, bool removeArguments);
|
||||
MathToolbox();
|
||||
void setSenderAndAction(Responder * sender, Action action);
|
||||
static void actionForScrollableExpressionViewWithCursor(void * sender, const char * text, bool removeArguments = true);
|
||||
static void actionForTextInput(void * sender, const char * text, bool removeArguments = true);
|
||||
protected:
|
||||
TextField * sender() override;
|
||||
bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override;
|
||||
const ToolboxMessageTree * rootModel() override;
|
||||
MessageTableCellWithMessage * leafCellAtIndex(int index) override;
|
||||
MessageTableCellWithChevron* nodeCellAtIndex(int index) override;
|
||||
int maxNumberOfDisplayedRows() override;
|
||||
constexpr static int k_maxNumberOfDisplayedRows = 6; // = 240/40
|
||||
Action m_action;
|
||||
private:
|
||||
MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows];
|
||||
MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows];
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "calculation_controller.h"
|
||||
#include "../constant.h"
|
||||
#include "../apps_container.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include "../../poincare/src/layout/char_layout.h"
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../poincare/src/layout/vertical_offset_layout.h"
|
||||
#include <poincare.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -21,7 +22,7 @@ CalculationController::CalculationController(Responder * parentResponder, Button
|
||||
m_calculationCells{},
|
||||
m_store(store)
|
||||
{
|
||||
m_r2Layout = new BaselineRelativeLayout(new StringLayout("r", 1, KDText::FontSize::Small), new StringLayout("2", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript);
|
||||
m_r2Layout = new HorizontalLayout(new CharLayout('r', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('2', KDText::FontSize::Small), VerticalOffsetLayout::Type::Superscript, false), false);
|
||||
}
|
||||
|
||||
CalculationController::~CalculationController() {
|
||||
@@ -129,7 +130,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
|
||||
if (i == 0) {
|
||||
if (j == numberOfRows()-1) {
|
||||
EvenOddExpressionCell * myCell = (EvenOddExpressionCell *)cell;
|
||||
myCell->setExpression(m_r2Layout);
|
||||
myCell->setExpressionLayout(m_r2Layout);
|
||||
return;
|
||||
}
|
||||
EvenOddMessageTextCell * myCell = (EvenOddMessageTextCell *)cell;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include "../constant.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include "../../poincare/src/layout/char_layout.h"
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../poincare/src/layout/vertical_offset_layout.h"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
@@ -15,8 +16,8 @@ StoreController::StoreController(Responder * parentResponder, Store * store, But
|
||||
Shared::StoreController(parentResponder, store, header),
|
||||
m_titleCells{}
|
||||
{
|
||||
m_titleLayout[0] = new BaselineRelativeLayout(new StringLayout("X", 1, KDText::FontSize::Small), new StringLayout("i", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_titleLayout[1] = new BaselineRelativeLayout(new StringLayout("Y", 1, KDText::FontSize::Small), new StringLayout("i", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_titleLayout[0] = new HorizontalLayout(new CharLayout('X', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('i', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), false);
|
||||
m_titleLayout[1] = new HorizontalLayout(new CharLayout('Y', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('i', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), false);
|
||||
}
|
||||
|
||||
StoreController::~StoreController() {
|
||||
@@ -34,7 +35,7 @@ void StoreController::willDisplayCellAtLocation(HighlightCell * cell, int i, int
|
||||
return;
|
||||
}
|
||||
EvenOddExpressionCell * mytitleCell = (EvenOddExpressionCell *)cell;
|
||||
mytitleCell->setExpression(m_titleLayout[i]);
|
||||
mytitleCell->setExpressionLayout(m_titleLayout[i]);
|
||||
}
|
||||
|
||||
HighlightCell * StoreController::titleCells(int index) {
|
||||
|
||||
@@ -72,7 +72,7 @@ App::App(Container * container, Snapshot * snapshot) :
|
||||
m_valuesHeader(nullptr, &m_valuesAlternateEmptyViewController, &m_valuesController),
|
||||
m_valuesStackViewController(&m_tabViewController, &m_valuesHeader),
|
||||
m_tabViewController(&m_inputViewController, snapshot, &m_listStackViewController, &m_graphStackViewController, &m_valuesStackViewController),
|
||||
m_inputViewController(&m_modalViewController, &m_tabViewController, &m_listController)
|
||||
m_inputViewController(&m_modalViewController, &m_tabViewController, &m_listController, &m_listController)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
#include "term_sum_controller.h"
|
||||
#include "../../shared/text_field_delegate.h"
|
||||
#include "../../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../../poincare/src/layout/string_layout.h"
|
||||
#include "../app.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <poincare/layout_engine.h>
|
||||
#include "../../../poincare/src/layout/char_layout.h"
|
||||
#include "../../../poincare/src/layout/condensed_sum_layout.h"
|
||||
#include "../../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../../poincare/src/layout/vertical_offset_layout.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
extern "C" {
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
}
|
||||
|
||||
using namespace Shared;
|
||||
using namespace Poincare;
|
||||
@@ -45,8 +52,115 @@ double TermSumController::cursorNextStep(double x, int direction) {
|
||||
return std::round(m_cursor->x()+delta);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
ExpressionLayout * TermSumController::createFunctionLayout(const char * functionName) {
|
||||
return new BaselineRelativeLayout(new StringLayout(functionName, 1, KDText::FontSize::Small), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
=======
|
||||
/* Legend View */
|
||||
|
||||
TermSumController::LegendView::LegendView() :
|
||||
m_sum(0.0f, 0.5f, KDColorBlack, Palette::GreyBright),
|
||||
m_sumLayout(nullptr),
|
||||
m_legend(KDText::FontSize::Small, I18n::Message::Default, 0.0f, 0.5f, KDColorBlack, Palette::GreyBright)
|
||||
{
|
||||
}
|
||||
|
||||
TermSumController::LegendView::~LegendView() {
|
||||
if (m_sumLayout != nullptr) {
|
||||
delete m_sumLayout;
|
||||
m_sumLayout = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TermSumController::LegendView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(KDRect(0, bounds().height() - k_legendHeight, bounds().width(), k_legendHeight), Palette::GreyMiddle);
|
||||
}
|
||||
|
||||
KDSize TermSumController::LegendView::minimalSizeForOptimalDisplay() const {
|
||||
return KDSize(0, k_legendHeight);
|
||||
}
|
||||
|
||||
void TermSumController::LegendView::setLegendMessage(I18n::Message message) {
|
||||
m_legend.setMessage(message);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void TermSumController::LegendView::setSumSubscript(float start) {
|
||||
if (m_sumLayout) {
|
||||
delete m_sumLayout;
|
||||
m_sumLayout = nullptr;
|
||||
}
|
||||
const char sigma[] = {' ', Ion::Charset::CapitalSigma};
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
Complex<float>::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal);
|
||||
m_sumLayout = new CondensedSumLayout(
|
||||
LayoutEngine::createStringLayout(sigma, sizeof(sigma), KDText::FontSize::Large),
|
||||
LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small),
|
||||
nullptr,
|
||||
false);
|
||||
m_sum.setExpressionLayout(m_sumLayout);
|
||||
m_sum.setAlignment(0.0f, 0.5f);
|
||||
}
|
||||
|
||||
void TermSumController::LegendView::setSumSuperscript(float start, float end) {
|
||||
if (m_sumLayout) {
|
||||
delete m_sumLayout;
|
||||
m_sumLayout = nullptr;
|
||||
}
|
||||
const char sigma[] = {' ', Ion::Charset::CapitalSigma};
|
||||
char bufferStart[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
Complex<float>::convertFloatToText(start, bufferStart, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal);
|
||||
char bufferEnd[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
Complex<float>::convertFloatToText(end, bufferEnd, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal);
|
||||
m_sumLayout = new CondensedSumLayout(
|
||||
LayoutEngine::createStringLayout(sigma, sizeof(sigma), KDText::FontSize::Large),
|
||||
LayoutEngine::createStringLayout(bufferStart, strlen(bufferStart), KDText::FontSize::Small),
|
||||
LayoutEngine::createStringLayout(bufferEnd, strlen(bufferEnd), KDText::FontSize::Small),
|
||||
false);
|
||||
m_sum.setExpressionLayout(m_sumLayout);
|
||||
m_sum.setAlignment(0.0f, 0.5f);
|
||||
}
|
||||
|
||||
void TermSumController::LegendView::setSumResult(const char * sequenceName, double result) {
|
||||
char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
strlcpy(buffer, "= ", 3);
|
||||
Complex<double>::convertFloatToText(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
m_sumLayout = new HorizontalLayout(
|
||||
m_sumLayout,
|
||||
new HorizontalLayout(
|
||||
new CharLayout(sequenceName[0], KDText::FontSize::Small),
|
||||
new VerticalOffsetLayout(new CharLayout('n', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false),
|
||||
LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small),
|
||||
false);
|
||||
m_sum.setExpressionLayout(m_sumLayout);
|
||||
m_sum.setAlignment(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
int TermSumController::LegendView::numberOfSubviews() const {
|
||||
return 2;
|
||||
}
|
||||
|
||||
View * TermSumController::LegendView::subviewAtIndex(int index) {
|
||||
assert(index >= 0 && index < 2);
|
||||
if (index == 0) {
|
||||
return &m_sum;
|
||||
}
|
||||
return &m_legend;
|
||||
}
|
||||
|
||||
void TermSumController::LegendView::layoutSubviews() {
|
||||
KDCoordinate width = bounds().width();
|
||||
KDCoordinate heigth = bounds().height();
|
||||
KDSize legendSize = m_legend.minimalSizeForOptimalDisplay();
|
||||
if (legendSize.width() > 0) {
|
||||
m_sum.setFrame(KDRect(0, 0, width-legendSize.width(), heigth));
|
||||
m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth));
|
||||
return;
|
||||
}
|
||||
m_sum.setFrame(bounds());
|
||||
m_legend.setFrame(KDRectZero);
|
||||
>>>>>>> SaisieJolieRebase1201
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,13 +24,14 @@ const char * ListController::title() {
|
||||
}
|
||||
|
||||
Toolbox * ListController::toolboxForTextInput(TextInput * textInput) {
|
||||
int recurrenceDepth = -1;
|
||||
int sequenceDefinition = sequenceDefinitionForRow(selectedRow());
|
||||
Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(selectedRow()));
|
||||
if (sequenceDefinition == 0) {
|
||||
recurrenceDepth = sequence->numberOfElements()-1;
|
||||
}
|
||||
m_sequenceToolbox.setExtraCells(sequence->name(), recurrenceDepth);
|
||||
setToolboxExtraCells();
|
||||
m_sequenceToolbox.setSenderAndAction(textField, MathToolbox::actionForTextInput);
|
||||
return &m_sequenceToolbox;
|
||||
}
|
||||
|
||||
Toolbox * ListController::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
setToolboxExtraCells();
|
||||
m_sequenceToolbox.setSenderAndAction(scrollableExpressionViewWithCursor, MathToolbox::actionForScrollableExpressionViewWithCursor);
|
||||
return &m_sequenceToolbox;
|
||||
}
|
||||
|
||||
@@ -38,6 +39,10 @@ TextFieldDelegateApp * ListController::textFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
EditableExpressionViewDelegateApp * ListController::editableExpressionViewDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
int ListController::numberOfRows() {
|
||||
int numberOfRows = 0;
|
||||
for (int i = 0; i < m_sequenceStore->numberOfFunctions(); i++) {
|
||||
@@ -169,13 +174,13 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) {
|
||||
SequenceTitleCell * myCell = (SequenceTitleCell *)cell;
|
||||
Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(j));
|
||||
if (sequenceDefinitionForRow(j) == 0) {
|
||||
myCell->setExpression(sequence->definitionName());
|
||||
myCell->setExpressionLayout(sequence->definitionName());
|
||||
}
|
||||
if (sequenceDefinitionForRow(j) == 1) {
|
||||
myCell->setExpression(sequence->firstInitialConditionName());
|
||||
myCell->setExpressionLayout(sequence->firstInitialConditionName());
|
||||
}
|
||||
if (sequenceDefinitionForRow(j) == 2) {
|
||||
myCell->setExpression(sequence->secondInitialConditionName());
|
||||
myCell->setExpressionLayout(sequence->secondInitialConditionName());
|
||||
}
|
||||
KDColor nameColor = sequence->isActive() ? sequence->color() : Palette::GreyDark;
|
||||
myCell->setColor(nameColor);
|
||||
@@ -185,13 +190,13 @@ void ListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int
|
||||
FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell;
|
||||
Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(j));
|
||||
if (sequenceDefinitionForRow(j) == 0) {
|
||||
myCell->setExpression(sequence->layout());
|
||||
myCell->setExpressionLayout(sequence->layout());
|
||||
}
|
||||
if (sequenceDefinitionForRow(j) == 1) {
|
||||
myCell->setExpression(sequence->firstInitialConditionLayout());
|
||||
myCell->setExpressionLayout(sequence->firstInitialConditionLayout());
|
||||
}
|
||||
if (sequenceDefinitionForRow(j) == 2) {
|
||||
myCell->setExpression(sequence->secondInitialConditionLayout());
|
||||
myCell->setExpressionLayout(sequence->secondInitialConditionLayout());
|
||||
}
|
||||
bool active = sequence->isActive();
|
||||
KDColor textColor = active ? KDColorBlack : Palette::GreyDark;
|
||||
@@ -304,4 +309,14 @@ void ListController::unloadView(View * view) {
|
||||
Shared::ListController::unloadView(view);
|
||||
}
|
||||
|
||||
void ListController::setToolboxExtraCells() {
|
||||
int recurrenceDepth = -1;
|
||||
int sequenceDefinition = sequenceDefinitionForRow(selectedRow());
|
||||
Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(selectedRow()));
|
||||
if (sequenceDefinition == 0) {
|
||||
recurrenceDepth = sequence->numberOfElements()-1;
|
||||
}
|
||||
m_sequenceToolbox.setExtraCells(sequence->name(), recurrenceDepth);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
#include "../sequence_title_cell.h"
|
||||
#include "../sequence_store.h"
|
||||
#include "../../shared/function_expression_cell.h"
|
||||
#include "type_parameter_controller.h"
|
||||
#include "../../shared/new_function_cell.h"
|
||||
#include "../../shared/list_controller.h"
|
||||
#include "../../shared/new_function_cell.h"
|
||||
#include "../../shared/scrollable_expression_view_with_cursor_delegate.h"
|
||||
#include "../../shared/text_field_delegate.h"
|
||||
#include "list_parameter_controller.h"
|
||||
#include "sequence_toolbox.h"
|
||||
#include "type_parameter_controller.h"
|
||||
|
||||
namespace Sequence {
|
||||
|
||||
class ListController : public Shared::ListController, public Shared::TextFieldDelegate {
|
||||
class ListController : public Shared::ListController, public Shared::TextFieldDelegate, public Shared::ScrollableExpressionViewWithCursorDelegate {
|
||||
public:
|
||||
ListController(Responder * parentResponder, SequenceStore * sequenceStore, ButtonRowController * header, ButtonRowController * footer);
|
||||
const char * title() override;
|
||||
@@ -22,9 +23,11 @@ public:
|
||||
virtual KDCoordinate rowHeight(int j) override;
|
||||
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
|
||||
Toolbox * toolboxForTextInput(TextInput * textInput) override;
|
||||
Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
void selectPreviousNewSequenceCell();
|
||||
private:
|
||||
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
|
||||
Shared::EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() override;
|
||||
void editExpression(Sequence * sequence, int sequenceDefinitionIndex, Ion::Events::Event event);
|
||||
ListParameterController * parameterController() override;
|
||||
int maxNumberOfRows() override;
|
||||
@@ -41,6 +44,7 @@ private:
|
||||
void reinitExpression(Shared::Function * function) override;
|
||||
View * loadView() override;
|
||||
void unloadView(View * view) override;
|
||||
void setToolboxExtraCells();
|
||||
static constexpr KDCoordinate k_emptySubRowHeight = 30;
|
||||
constexpr static int k_maxNumberOfRows = 3*MaxNumberOfSequences;
|
||||
SequenceStore * m_sequenceStore;
|
||||
|
||||
@@ -103,7 +103,7 @@ void ListParameterController::willDisplayCellForIndex(HighlightCell * cell, int
|
||||
cell->setHighlighted(index == selectedRow()); // See FIXME in SelectableTableView::reloadData()
|
||||
Shared::ListParameterController::willDisplayCellForIndex(cell, index);
|
||||
if (cell == &m_typeCell && m_sequence != nullptr) {
|
||||
m_typeCell.setExpression(m_sequence->definitionName());
|
||||
m_typeCell.setExpressionLayout(m_sequence->definitionName());
|
||||
}
|
||||
if (cell == &m_initialRankCell && m_sequence != nullptr) {
|
||||
MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *) cell;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "sequence_toolbox.h"
|
||||
#include "../sequence_store.h"
|
||||
#include "../../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../../poincare/src/layout/string_layout.h"
|
||||
#include "../../../poincare/src/layout/char_layout.h"
|
||||
#include "../../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../../poincare/src/layout/vertical_offset_layout.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
@@ -87,12 +89,21 @@ void SequenceToolbox::setExtraCells(const char * sequenceName, int recurrenceDep
|
||||
const char * otherSequenceName = SequenceStore::k_sequenceNames[1-sequenceIndex];
|
||||
for (int j = 0; j < recurrenceDepth; j++) {
|
||||
const char * indice = j == 0 ? "n" : "n+1";
|
||||
m_addedCellLayout[j] = new BaselineRelativeLayout(new StringLayout(sequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_addedCellLayout[j+recurrenceDepth] = new BaselineRelativeLayout(new StringLayout(otherSequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_addedCellLayout[j] = new HorizontalLayout(
|
||||
new CharLayout(sequenceName[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
m_addedCellLayout[j+recurrenceDepth] = new HorizontalLayout(
|
||||
new CharLayout(otherSequenceName[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
if (recurrenceDepth < 2) {
|
||||
const char * indice = recurrenceDepth == 0 ? "n" : (recurrenceDepth == 1 ? "n+1" : "n+2");
|
||||
m_addedCellLayout[2*recurrenceDepth] = new BaselineRelativeLayout(new StringLayout(otherSequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_addedCellLayout[2*recurrenceDepth] = new HorizontalLayout(
|
||||
new CharLayout(otherSequenceName[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
for (int index = 0; index < k_maxNumberOfDisplayedRows; index++) {
|
||||
m_addedCells[index].setExpression(m_addedCellLayout[index]);
|
||||
@@ -100,19 +111,29 @@ void SequenceToolbox::setExtraCells(const char * sequenceName, int recurrenceDep
|
||||
}
|
||||
|
||||
bool SequenceToolbox::selectAddedCell(int selectedRow){
|
||||
char buffer[10];
|
||||
BaselineRelativeLayout * layout = (BaselineRelativeLayout *)m_addedCellLayout[selectedRow];
|
||||
StringLayout * nameLayout = (StringLayout *)layout->baseLayout();
|
||||
StringLayout * subscriptLayout = (StringLayout *)layout->indiceLayout();
|
||||
int currentChar = 0;
|
||||
strlcpy(buffer, nameLayout->text(), strlen(nameLayout->text())+1);
|
||||
currentChar += strlen(nameLayout->text());
|
||||
buffer[currentChar++] = '(';
|
||||
strlcpy(buffer+currentChar, subscriptLayout->text(), strlen(subscriptLayout->text())+1);
|
||||
currentChar += strlen(subscriptLayout->text());
|
||||
buffer[currentChar++] = ')';
|
||||
buffer[currentChar] = 0;
|
||||
sender()->handleEventWithText(buffer);
|
||||
int bufferSize = 10;
|
||||
char buffer[bufferSize];
|
||||
m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize);
|
||||
if (m_action == MathToolbox::actionForTextField) {
|
||||
// DIRTY. The symbols are layouted using a Subscript VerticalOffsetLayout,
|
||||
// which serializes into "_{}", but we want parentheses for text fields. We
|
||||
// thus need to remove any underscores, and changes brackets into
|
||||
// parentheses.
|
||||
for (int i = 0; i < bufferSize; i++) {
|
||||
if (buffer[i] == '{') {
|
||||
buffer[i] = '(';
|
||||
}
|
||||
if (buffer[i] == '}') {
|
||||
buffer[i] = ')';
|
||||
}
|
||||
if (buffer[i] == '_') {
|
||||
memmove(&buffer[i], &buffer[i+1], bufferSize - (i+1) + 1);
|
||||
bufferSize--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_action(sender(), buffer, false);
|
||||
app()->dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#include "list_controller.h"
|
||||
#include "../app.h"
|
||||
#include <assert.h>
|
||||
#include "../../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../../poincare/src/layout/string_layout.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include "../../../poincare/src/layout/char_layout.h"
|
||||
#include "../../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../../poincare/src/layout/vertical_offset_layout.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
@@ -124,9 +126,12 @@ void TypeParameterController::willDisplayCellAtLocation(HighlightCell * cell, in
|
||||
delete m_expressionLayouts[j];
|
||||
m_expressionLayouts[j] = nullptr;
|
||||
}
|
||||
m_expressionLayouts[j] = new BaselineRelativeLayout(new StringLayout(nextName, 1, size), new StringLayout(subscripts[j], strlen(subscripts[j]), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_expressionLayouts[j] = new HorizontalLayout(
|
||||
new CharLayout(nextName[0], size),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(subscripts[j], strlen(subscripts[j]), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
ExpressionTableCellWithPointer * myCell = (ExpressionTableCellWithPointer *)cell;
|
||||
myCell->setExpression(m_expressionLayouts[j]);
|
||||
myCell->setExpressionLayout(m_expressionLayouts[j]);
|
||||
}
|
||||
|
||||
void TypeParameterController::setSequence(Sequence * sequence) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "sequence.h"
|
||||
#include "sequence_store.h"
|
||||
#include "cache_context.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include "../../poincare/src/layout/char_layout.h"
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../poincare/src/layout/vertical_offset_layout.h"
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
|
||||
@@ -221,7 +223,10 @@ int Sequence::numberOfElements() {
|
||||
|
||||
Poincare::ExpressionLayout * Sequence::nameLayout() {
|
||||
if (m_nameLayout == nullptr) {
|
||||
m_nameLayout = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_nameLayout = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(new CharLayout('n', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
return m_nameLayout;
|
||||
}
|
||||
@@ -229,13 +234,22 @@ Poincare::ExpressionLayout * Sequence::nameLayout() {
|
||||
Poincare::ExpressionLayout * Sequence::definitionName() {
|
||||
if (m_definitionName == nullptr) {
|
||||
if (m_type == Type::Explicit) {
|
||||
m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n ", 2, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_definitionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout("n ", 2, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
if (m_type == Type::SingleRecurrence) {
|
||||
m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+1 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_definitionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout("n+1 ", 4, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
if (m_type == Type::DoubleRecurrence) {
|
||||
m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+2 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_definitionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout("n+2 ", 4, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
}
|
||||
return m_definitionName;
|
||||
@@ -245,12 +259,10 @@ Poincare::ExpressionLayout * Sequence::firstInitialConditionName() {
|
||||
char buffer[k_initialRankNumberOfDigits+1];
|
||||
Integer(m_initialRank).writeTextInBuffer(buffer, k_initialRankNumberOfDigits+1);
|
||||
if (m_firstInitialConditionName == nullptr) {
|
||||
if (m_type == Type::SingleRecurrence) {
|
||||
m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
}
|
||||
if (m_type == Type::DoubleRecurrence) {
|
||||
m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
}
|
||||
m_firstInitialConditionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Small),
|
||||
new VerticalOffsetLayout(new CharLayout('0', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
return m_firstInitialConditionName;
|
||||
}
|
||||
@@ -260,8 +272,10 @@ Poincare::ExpressionLayout * Sequence::secondInitialConditionName() {
|
||||
Integer(m_initialRank+1).writeTextInBuffer(buffer, k_initialRankNumberOfDigits+1);
|
||||
if (m_secondInitialConditionName == nullptr) {
|
||||
if (m_type == Type::DoubleRecurrence) {
|
||||
m_secondInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
|
||||
m_secondInitialConditionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Small),
|
||||
new VerticalOffsetLayout(new CharLayout('1', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
}
|
||||
return m_secondInitialConditionName;
|
||||
|
||||
@@ -12,8 +12,8 @@ SequenceTitleCell::SequenceTitleCell(Orientation orientation) :
|
||||
{
|
||||
}
|
||||
|
||||
void SequenceTitleCell::setExpression(Poincare::ExpressionLayout * expressionLayout) {
|
||||
m_titleTextView.setExpression(expressionLayout);
|
||||
void SequenceTitleCell::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
|
||||
m_titleTextView.setExpressionLayout(expressionLayout);
|
||||
}
|
||||
|
||||
void SequenceTitleCell::setHighlighted(bool highlight) {
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Sequence {
|
||||
class SequenceTitleCell : public Shared::FunctionTitleCell {
|
||||
public:
|
||||
SequenceTitleCell(Orientation orientation);
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setEven(bool even) override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setColor(KDColor color) override;
|
||||
|
||||
@@ -30,7 +30,7 @@ void ValuesController::willDisplayCellAtLocation(HighlightCell * cell, int i, in
|
||||
if (j == 0 && i > 0) {
|
||||
SequenceTitleCell * myCell = (SequenceTitleCell *)cell;
|
||||
Sequence * sequence = m_sequenceStore->activeFunctionAtIndex(i-1);
|
||||
myCell->setExpression(sequence->nameLayout());
|
||||
myCell->setExpressionLayout(sequence->nameLayout());
|
||||
myCell->setColor(sequence->color());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ snapshot_headers += apps/settings/app.h
|
||||
|
||||
app_objs += $(addprefix apps/settings/,\
|
||||
app.o\
|
||||
helpers.o\
|
||||
language_controller.o\
|
||||
main_controller.o\
|
||||
settings_message_tree.o\
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Einstellungen"
|
||||
SettingsAppCapital = "EINSTELLUNGEN"
|
||||
AngleUnit = "Winkeleinheit"
|
||||
DisplayMode = "Zahlenformat"
|
||||
EditionMode = "Editiermodus"
|
||||
EditionLinear = "1D "
|
||||
Edition2D = "2D "
|
||||
ComplexFormat = "Komplex"
|
||||
ExamMode = "Testmodus"
|
||||
ActivateExamMode = "Start Testmodus"
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Settings"
|
||||
SettingsAppCapital = "SETTINGS"
|
||||
AngleUnit = "Angle measure"
|
||||
DisplayMode = "Result format"
|
||||
EditionMode = "Edition mode"
|
||||
EditionLinear = "1D "
|
||||
Edition2D = "2D "
|
||||
ComplexFormat = "Complex format"
|
||||
ExamMode = "Exam mode"
|
||||
ActivateExamMode = "Activate exam mode"
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Configuracion"
|
||||
SettingsAppCapital = "CONFIGURACION"
|
||||
AngleUnit = "Medida del angulo"
|
||||
DisplayMode = "Formato resultado"
|
||||
EditionMode = "Modo edicion"
|
||||
EditionLinear = "1D "
|
||||
Edition2D = "2D "
|
||||
ComplexFormat = "Formato complejo"
|
||||
ExamMode = "Modo examen"
|
||||
ActivateExamMode = "Activar el modo examen"
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Parametres"
|
||||
SettingsAppCapital = "PARAMETRES"
|
||||
AngleUnit = "Unite d'angle"
|
||||
DisplayMode = "Format resultat"
|
||||
EditionMode = "Mode d'edition"
|
||||
EditionLinear = "1D "
|
||||
Edition2D = "2D "
|
||||
ComplexFormat = "Forme complexe"
|
||||
ExamMode = "Mode examen"
|
||||
ActivateExamMode = "Activer le mode examen"
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Configuracao"
|
||||
SettingsAppCapital = "CONFIGURACAO"
|
||||
AngleUnit = "Valor do angulo"
|
||||
DisplayMode = "Formato numerico"
|
||||
EditionMode = "Modo de edicao"
|
||||
EditionLinear = "1D "
|
||||
Edition2D = "2D "
|
||||
ComplexFormat = "Complexos"
|
||||
ExamMode = "Modo de Exame"
|
||||
ActivateExamMode = "Inicio modo de exame"
|
||||
|
||||
27
apps/settings/helpers.cpp
Normal file
27
apps/settings/helpers.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "helpers.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include <ion/charset.h>
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../poincare/src/layout/vertical_offset_layout.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Settings {
|
||||
namespace Helpers {
|
||||
|
||||
ExpressionLayout * CartesianComplexFormat(KDText::FontSize fontSize) {
|
||||
const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '};
|
||||
return LayoutEngine::createStringLayout(text, sizeof(text), fontSize);
|
||||
}
|
||||
|
||||
ExpressionLayout * PolarComplexFormat(KDText::FontSize fontSize) {
|
||||
const char base[] = {'r', Ion::Charset::Exponential};
|
||||
const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '};
|
||||
return new HorizontalLayout(
|
||||
LayoutEngine::createStringLayout(base, sizeof(base), fontSize),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(superscript, sizeof(superscript), fontSize), VerticalOffsetLayout::Type::Superscript, false),
|
||||
false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
15
apps/settings/helpers.h
Normal file
15
apps/settings/helpers.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef SETTINGS_HELPERS_H
|
||||
#define SETTINGS_HELPERS_H
|
||||
|
||||
#include <poincare/expression_layout.h>
|
||||
|
||||
namespace Settings {
|
||||
namespace Helpers {
|
||||
|
||||
Poincare::ExpressionLayout * CartesianComplexFormat(KDText::FontSize fontSize);
|
||||
Poincare::ExpressionLayout * PolarComplexFormat(KDText::FontSize fontSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,36 +1,40 @@
|
||||
#include "main_controller.h"
|
||||
#include "helpers.h"
|
||||
#include "../global_preferences.h"
|
||||
#include "../i18n.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include <assert.h>
|
||||
#include <poincare.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Settings {
|
||||
|
||||
const SettingsMessageTree angleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)};
|
||||
const SettingsMessageTree FloatDisplayModeChildren[3] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::SignificantFigures)};
|
||||
const SettingsMessageTree editionModeChildren[2] = {SettingsMessageTree(I18n::Message::EditionLinear), SettingsMessageTree(I18n::Message::Edition2D)};
|
||||
const SettingsMessageTree floatDisplayModeChildren[3] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::SignificantFigures)};
|
||||
const SettingsMessageTree complexFormatChildren[2] = {SettingsMessageTree(I18n::Message::Default), SettingsMessageTree(I18n::Message::Default)};
|
||||
const SettingsMessageTree examChildren[1] = {SettingsMessageTree(I18n::Message::ActivateExamMode)};
|
||||
const SettingsMessageTree aboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)};
|
||||
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
const SettingsMessageTree menu[8] =
|
||||
const SettingsMessageTree menu[9] =
|
||||
#else
|
||||
const SettingsMessageTree menu[7] =
|
||||
const SettingsMessageTree menu[8] =
|
||||
#endif
|
||||
{SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2), SettingsMessageTree(I18n::Message::DisplayMode, FloatDisplayModeChildren, 3), SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2),
|
||||
SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), SettingsMessageTree(I18n::Message::ExamMode, examChildren, 1),
|
||||
{SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2),
|
||||
SettingsMessageTree(I18n::Message::DisplayMode, floatDisplayModeChildren, 3),
|
||||
SettingsMessageTree(I18n::Message::EditionMode, editionModeChildren, 2),
|
||||
SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2),
|
||||
SettingsMessageTree(I18n::Message::Brightness),
|
||||
SettingsMessageTree(I18n::Message::Language),
|
||||
SettingsMessageTree(I18n::Message::ExamMode, examChildren, 1),
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
SettingsMessageTree(I18n::Message::UpdatePopUp),
|
||||
#endif
|
||||
SettingsMessageTree(I18n::Message::About, aboutChildren, 3)};
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 8);
|
||||
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 9);
|
||||
#else
|
||||
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 7);
|
||||
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 8);
|
||||
#endif
|
||||
|
||||
MainController::MainController(Responder * parentResponder) :
|
||||
@@ -151,14 +155,14 @@ int MainController::reusableCellCount(int type) {
|
||||
}
|
||||
|
||||
int MainController::typeAtLocation(int i, int j) {
|
||||
if (j == 2) {
|
||||
if (j == 3) {
|
||||
return 1;
|
||||
}
|
||||
if (j == 3) {
|
||||
if (j == 4) {
|
||||
return 2;
|
||||
}
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
if (j == 6) {
|
||||
if (j == 7) {
|
||||
return 3;
|
||||
}
|
||||
#endif
|
||||
@@ -169,36 +173,33 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
MessageTableCell * myCell = (MessageTableCell *)cell;
|
||||
myCell->setMessage(m_messageTreeModel->children(index)->label());
|
||||
|
||||
if (index == 2) {
|
||||
if (index == 3) {
|
||||
if (m_complexFormatLayout) {
|
||||
delete m_complexFormatLayout;
|
||||
m_complexFormatLayout = nullptr;
|
||||
}
|
||||
if (Preferences::sharedPreferences()->complexFormat() == Expression::ComplexFormat::Cartesian) {
|
||||
const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '};
|
||||
m_complexFormatLayout = new StringLayout(text, sizeof(text), KDText::FontSize::Small);
|
||||
m_complexFormatLayout = Helpers::CartesianComplexFormat(KDText::FontSize::Small);
|
||||
} else {
|
||||
const char base[] = {'r', Ion::Charset::Exponential};
|
||||
const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '};
|
||||
m_complexFormatLayout = new BaselineRelativeLayout(new StringLayout(base, sizeof(base), KDText::FontSize::Small), new StringLayout(superscript, sizeof(superscript), KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript);
|
||||
m_complexFormatLayout = Helpers::PolarComplexFormat(KDText::FontSize::Small);
|
||||
}
|
||||
MessageTableCellWithChevronAndExpression * myExpCell = (MessageTableCellWithChevronAndExpression *)cell;
|
||||
myExpCell->setExpression(m_complexFormatLayout);
|
||||
myExpCell->setExpressionLayout(m_complexFormatLayout);
|
||||
return;
|
||||
}
|
||||
if (index == 3) {
|
||||
if (index == 4) {
|
||||
MessageTableCellWithGauge * myGaugeCell = (MessageTableCellWithGauge *)cell;
|
||||
GaugeView * myGauge = (GaugeView *)myGaugeCell->accessoryView();
|
||||
myGauge->setLevel((float)GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()/(float)Ion::Backlight::MaxBrightness);
|
||||
return;
|
||||
}
|
||||
if (index == 4) {
|
||||
if (index == 5) {
|
||||
int index = (int)GlobalPreferences::sharedGlobalPreferences()->language()-1;
|
||||
static_cast<MessageTableCellWithChevronAndMessage *>(cell)->setSubtitle(I18n::LanguageNames[index]);
|
||||
return;
|
||||
}
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
if (index == 6) {
|
||||
if (index == 7) {
|
||||
MessageTableCellWithSwitch * mySwitchCell = (MessageTableCellWithSwitch *)cell;
|
||||
SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView();
|
||||
mySwitch->setState(GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp());
|
||||
@@ -213,6 +214,9 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
case 1:
|
||||
myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)Preferences::sharedPreferences()->displayMode())->label());
|
||||
break;
|
||||
case 2:
|
||||
myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)Preferences::sharedPreferences()->editionMode())->label());
|
||||
break;
|
||||
default:
|
||||
myTextCell->setSubtitle(I18n::Message::Default);
|
||||
break;
|
||||
|
||||
@@ -31,12 +31,12 @@ public:
|
||||
private:
|
||||
StackViewController * stackController() const;
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
constexpr static int k_totalNumberOfCell = 8;
|
||||
constexpr static int k_totalNumberOfCell = 9;
|
||||
MessageTableCellWithSwitch m_updateCell;
|
||||
#else
|
||||
constexpr static int k_totalNumberOfCell = 7;
|
||||
constexpr static int k_totalNumberOfCell = 8;
|
||||
#endif
|
||||
constexpr static int k_numberOfSimpleChevronCells = 5;
|
||||
constexpr static int k_numberOfSimpleChevronCells = 6;
|
||||
MessageTableCellWithChevronAndMessage m_cells[k_numberOfSimpleChevronCells];
|
||||
MessageTableCellWithChevronAndExpression m_complexFormatCell;
|
||||
MessageTableCellWithGauge m_brightnessCell;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "sub_controller.h"
|
||||
#include "helpers.h"
|
||||
#include "../global_preferences.h"
|
||||
#include "../apps_container.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
|
||||
@@ -22,13 +21,10 @@ SubController::SubController(Responder * parentResponder) :
|
||||
m_cells[i].setAccessoryFontSize(KDText::FontSize::Small);
|
||||
m_cells[i].setAccessoryTextColor(Palette::GreyDark);
|
||||
}
|
||||
const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '};
|
||||
m_complexFormatLayout[0] = new StringLayout(text, sizeof(text));
|
||||
const char base[] = {'r', Ion::Charset::Exponential};
|
||||
const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '};
|
||||
m_complexFormatLayout[1] = new BaselineRelativeLayout(new StringLayout(base, sizeof(base)), new StringLayout(superscript, sizeof(superscript)), BaselineRelativeLayout::Type::Superscript);
|
||||
m_complexFormatLayout[0] = Helpers::CartesianComplexFormat(KDText::FontSize::Large);
|
||||
m_complexFormatLayout[1] = Helpers::PolarComplexFormat(KDText::FontSize::Large);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
m_complexFormatCells[i].setExpression(m_complexFormatLayout[i]);
|
||||
m_complexFormatCells[i].setExpressionLayout(m_complexFormatLayout[i]);
|
||||
}
|
||||
m_editableCell.setMessage(I18n::Message::SignificantFigures);
|
||||
m_editableCell.setMessageFontSize(KDText::FontSize::Large);
|
||||
@@ -73,7 +69,7 @@ bool SubController::handleEvent(Ion::Events::Event event) {
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
/* Behavious of "Exam mode" menu*/
|
||||
/* Behaviour of "Exam mode" menu*/
|
||||
if (m_messageTreeModel->label() == I18n::Message::ExamMode) {
|
||||
if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) {
|
||||
return false;
|
||||
@@ -258,6 +254,9 @@ void SubController::setPreferenceWithValueIndex(I18n::Message message, int value
|
||||
if (message == I18n::Message::DisplayMode) {
|
||||
Preferences::sharedPreferences()->setDisplayMode((PrintFloat::Mode)valueIndex);
|
||||
}
|
||||
if (message == I18n::Message::EditionMode) {
|
||||
Preferences::sharedPreferences()->setEditionMode((Preferences::EditionMode)valueIndex);
|
||||
}
|
||||
if (message == I18n::Message::ComplexFormat) {
|
||||
Preferences::sharedPreferences()->setComplexFormat((Expression::ComplexFormat)valueIndex);
|
||||
}
|
||||
@@ -270,6 +269,9 @@ int SubController::valueIndexForPreference(I18n::Message message) {
|
||||
if (message == I18n::Message::DisplayMode) {
|
||||
return (int)Preferences::sharedPreferences()->displayMode();
|
||||
}
|
||||
if (message == I18n::Message::EditionMode) {
|
||||
return (int)Preferences::sharedPreferences()->editionMode();
|
||||
}
|
||||
if (message == I18n::Message::ComplexFormat) {
|
||||
return (int)Preferences::sharedPreferences()->complexFormat();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ LcmCommandWithArg = "lcm(p,q)"
|
||||
LeftIntegralFirstLegend = "P(X≤"
|
||||
LeftIntegralSecondLegend = ")="
|
||||
LogCommandWithArg = "log(x,a)"
|
||||
MatrixCommand = "[[]]"
|
||||
MatrixCommandWithArg = "[[1,2][3,4]]"
|
||||
MaxCommandWithArg = "max(L)"
|
||||
MinCommandWithArg = "min(L)"
|
||||
Mu = "μ"
|
||||
|
||||
@@ -6,6 +6,7 @@ app_objs += $(addprefix apps/shared/,\
|
||||
curve_view_cursor.o\
|
||||
curve_view_range.o\
|
||||
editable_cell_table_view_controller.o\
|
||||
editable_expression_view_delegate_app.o\
|
||||
float_pair_store.o\
|
||||
float_parameter_controller.o\
|
||||
function.o\
|
||||
@@ -37,6 +38,7 @@ app_objs += $(addprefix apps/shared/,\
|
||||
regular_table_view_data_source.o\
|
||||
round_cursor_view.o\
|
||||
simple_interactive_curve_view_controller.o\
|
||||
scrollable_expression_view_with_cursor_delegate.o\
|
||||
store_controller.o\
|
||||
store_parameter_controller.o\
|
||||
sum_graph_controller.o\
|
||||
|
||||
56
apps/shared/editable_expression_view_delegate_app.cpp
Normal file
56
apps/shared/editable_expression_view_delegate_app.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "editable_expression_view_delegate_app.h"
|
||||
#include "../i18n.h"
|
||||
#include "../apps_container.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
EditableExpressionViewDelegateApp::EditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) :
|
||||
TextFieldDelegateApp(container, snapshot, rootViewController),
|
||||
ScrollableExpressionViewWithCursorDelegate()
|
||||
{
|
||||
}
|
||||
|
||||
bool EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
|
||||
return event == Ion::Events::OK || event == Ion::Events::EXE;
|
||||
}
|
||||
|
||||
bool EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
|
||||
if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event)) {
|
||||
if (!scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout()->hasText()) {
|
||||
scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
int bufferSize = 256;
|
||||
char buffer[bufferSize];
|
||||
scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize);
|
||||
Expression * exp = Expression::parse(buffer);
|
||||
if (exp != nullptr) {
|
||||
delete exp;
|
||||
}
|
||||
if (exp == nullptr) {
|
||||
scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (event == Ion::Events::Var) {
|
||||
if (!scrollableExpressionViewWithCursor->isEditing()) {
|
||||
scrollableExpressionViewWithCursor->setEditing(true);
|
||||
}
|
||||
AppsContainer * appsContainer = (AppsContainer *)scrollableExpressionViewWithCursor->app()->container();
|
||||
VariableBoxController * variableBoxController = appsContainer->variableBoxController();
|
||||
variableBoxController->setScrollableExpressionViewWithCursorSender(scrollableExpressionViewWithCursor);
|
||||
scrollableExpressionViewWithCursor->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Toolbox * EditableExpressionViewDelegateApp::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
Toolbox * toolbox = container()->mathToolbox();
|
||||
static_cast<MathToolbox *>(toolbox)->setSenderAndAction(scrollableExpressionViewWithCursor, MathToolbox::actionForScrollableExpressionViewWithCursor);
|
||||
return toolbox;
|
||||
}
|
||||
|
||||
}
|
||||
21
apps/shared/editable_expression_view_delegate_app.h
Normal file
21
apps/shared/editable_expression_view_delegate_app.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H
|
||||
#define SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H
|
||||
|
||||
#include "text_field_delegate_app.h"
|
||||
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class EditableExpressionViewDelegateApp : public TextFieldDelegateApp, public ScrollableExpressionViewWithCursorDelegate {
|
||||
public:
|
||||
virtual ~EditableExpressionViewDelegateApp() = default;
|
||||
bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
|
||||
virtual bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
|
||||
Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
protected:
|
||||
EditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -53,7 +53,7 @@ void FunctionApp::Snapshot::reset() {
|
||||
}
|
||||
|
||||
FunctionApp::FunctionApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) :
|
||||
TextFieldDelegateApp(container, snapshot, rootViewController)
|
||||
EditableExpressionViewDelegateApp(container, snapshot, rootViewController)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ void FunctionApp::willBecomeInactive() {
|
||||
m_modalViewController.dismissModalViewController();
|
||||
}
|
||||
if (inputViewController()->isDisplayingModal()) {
|
||||
inputViewController()->abortTextFieldEditionAndDismiss();
|
||||
inputViewController()->abortEditionAndDismiss();
|
||||
}
|
||||
::App::willBecomeInactive();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define SHARED_FUNCTION_APP_H
|
||||
|
||||
#include <poincare.h>
|
||||
#include "text_field_delegate_app.h"
|
||||
#include "editable_expression_view_delegate_app.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "interval.h"
|
||||
|
||||
@@ -10,7 +10,7 @@ class AppsContainer;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class FunctionApp : public TextFieldDelegateApp {
|
||||
class FunctionApp : public EditableExpressionViewDelegateApp {
|
||||
public:
|
||||
class Snapshot : public ::App::Snapshot, public TabViewDataSource {
|
||||
public:
|
||||
|
||||
@@ -11,8 +11,8 @@ FunctionExpressionCell::FunctionExpressionCell() :
|
||||
{
|
||||
}
|
||||
|
||||
void FunctionExpressionCell::setExpression(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpression(expressionLayout);
|
||||
void FunctionExpressionCell::setExpressionLayout(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpressionLayout(expressionLayout);
|
||||
}
|
||||
|
||||
void FunctionExpressionCell::setTextColor(KDColor textColor) {
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Shared {
|
||||
class FunctionExpressionCell : public EvenOddCell {
|
||||
public:
|
||||
FunctionExpressionCell();
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setTextColor(KDColor color);
|
||||
void setEven(bool even) override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "scrollable_expression_view_with_cursor_delegate.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
|
||||
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorShouldFinishEditing(scrollableExpressionViewWithCursor, event);
|
||||
}
|
||||
|
||||
bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
|
||||
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event);
|
||||
}
|
||||
|
||||
bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) {
|
||||
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidFinishEditing(scrollableExpressionViewWithCursor, text, event);
|
||||
}
|
||||
|
||||
bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidAbortEditing(scrollableExpressionViewWithCursor);
|
||||
}
|
||||
|
||||
void ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidChangeSize(scrollableExpressionViewWithCursor);
|
||||
}
|
||||
|
||||
Toolbox * ScrollableExpressionViewWithCursorDelegate::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
return editableExpressionViewDelegateApp()->toolboxForScrollableExpressionViewWithCursor(scrollableExpressionViewWithCursor);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef SHARED_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H
|
||||
#define SHARED_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H
|
||||
|
||||
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
|
||||
#include "editable_expression_view_delegate_app.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ScrollableExpressionViewWithCursorDelegate : public ::ScrollableExpressionViewWithCursorDelegate {
|
||||
public:
|
||||
bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
|
||||
bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
|
||||
bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override;
|
||||
bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
private:
|
||||
virtual EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -93,7 +93,7 @@ bool TextFieldDelegateApp::textFieldDidReceiveEvent(TextField * textField, Ion::
|
||||
}
|
||||
AppsContainer * appsContainer = (AppsContainer *)textField->app()->container();
|
||||
VariableBoxController * variableBoxController = appsContainer->variableBoxController();
|
||||
variableBoxController->setTextFieldCaller(textField);
|
||||
variableBoxController->setTextFieldSender(textField);
|
||||
textField->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
|
||||
return true;
|
||||
}
|
||||
@@ -108,7 +108,9 @@ bool TextFieldDelegateApp::textFieldDidReceiveEvent(TextField * textField, Ion::
|
||||
}
|
||||
|
||||
Toolbox * TextFieldDelegateApp::toolboxForTextInput(TextInput * textInput) {
|
||||
return container()->mathToolbox();
|
||||
Toolbox * toolbox = container()->mathToolbox();
|
||||
static_cast<MathToolbox *>(toolbox)->setSenderAndAction(textInput, MathToolbox::actionForTextInput);
|
||||
return toolbox;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +1,52 @@
|
||||
#include "toolbox_helpers.h"
|
||||
#include <ion/charset.h>
|
||||
#include <apps/i18n.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
namespace ToolboxHelpers {
|
||||
|
||||
int CursorIndexInCommand(const char * text) {
|
||||
int CursorIndexInCommandText(const char * text) {
|
||||
for (size_t i = 0; i < strlen(text); i++) {
|
||||
if (text[i] == '(' || text[i] == '\'') {
|
||||
return i + 1;
|
||||
}
|
||||
if (text[i] == ']') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return strlen(text);
|
||||
}
|
||||
|
||||
void TextToInsertForCommandMessage(I18n::Message message, char * buffer) {
|
||||
const char * messageText = I18n::translate(message);
|
||||
TextToInsertForCommandText(messageText, buffer);
|
||||
void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize) {
|
||||
TextToInsertForCommandText(I18n::translate(message), buffer, bufferSize);
|
||||
}
|
||||
|
||||
void TextToInsertForCommandText(const char * command, char * buffer) {
|
||||
void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize) {
|
||||
int currentNewTextIndex = 0;
|
||||
int numberOfOpenParentheses = 0;
|
||||
int numberOfOpenBrackets = 0;
|
||||
bool insideQuote = false;
|
||||
size_t commandLength = strlen(command);
|
||||
for (size_t i = 0; i < commandLength; i++) {
|
||||
if (command[i] == ')') {
|
||||
numberOfOpenParentheses--;
|
||||
}
|
||||
if (command[i] == ']') {
|
||||
numberOfOpenBrackets--;
|
||||
}
|
||||
if ((numberOfOpenBrackets == 0 || command[i] == ',') && (!insideQuote || command[i] == '\'')) {
|
||||
if (((numberOfOpenParentheses == 0 && numberOfOpenBrackets == 0)
|
||||
|| command[i] == ','
|
||||
|| (numberOfOpenBrackets > 0 && (command[i] == ',' || command[i] == '[' || command[i] == ']')))
|
||||
&& (!insideQuote || command[i] == '\'')) {
|
||||
assert(currentNewTextIndex < bufferSize);
|
||||
buffer[currentNewTextIndex++] = command[i];
|
||||
}
|
||||
if (command[i] == '(') {
|
||||
numberOfOpenParentheses++;
|
||||
}
|
||||
if (command[i] == '[') {
|
||||
numberOfOpenBrackets++;
|
||||
}
|
||||
if (command[i] == '\'') {
|
||||
@@ -40,5 +56,24 @@ void TextToInsertForCommandText(const char * command, char * buffer) {
|
||||
buffer[currentNewTextIndex] = 0;
|
||||
}
|
||||
|
||||
void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer, int bufferSize) {
|
||||
TextToParseIntoLayoutForCommandText(I18n::translate(message), buffer, bufferSize);
|
||||
}
|
||||
|
||||
void TextToParseIntoLayoutForCommandText(const char * command, char * buffer, int bufferSize) {
|
||||
TextToInsertForCommandText(command, buffer, bufferSize);
|
||||
size_t bufferLength = strlen(buffer);
|
||||
for (size_t i = 0; i < bufferLength; i++) {
|
||||
if (buffer[i] == '(' || buffer[i] == ',' || (i < bufferLength - 1 && buffer[i] == '[' && buffer[i+1] == ']')) {
|
||||
// Shift the buffer to make room for the new char. Use memmove to avoid
|
||||
// overwritting.
|
||||
memmove(&buffer[i+2], &buffer[i+1], bufferLength - (i+1) + 1);
|
||||
bufferLength++;
|
||||
i++;
|
||||
buffer[i] = Ion::Charset::Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,20 @@
|
||||
namespace Shared {
|
||||
namespace ToolboxHelpers {
|
||||
|
||||
int CursorIndexInCommand(const char * text);
|
||||
/* Returns the index of the cursor position in a Command, which is the smallest
|
||||
int CursorIndexInCommandText(const char * text);
|
||||
/* Returns the index of the cursor position in a command, which is the smallest
|
||||
* index between :
|
||||
* - After the first open parenthesis
|
||||
* - The end of the text */
|
||||
|
||||
|
||||
void TextToInsertForCommandMessage(I18n::Message message, char * buffer);
|
||||
void TextToInsertForCommandText(const char * command, char * buffer);
|
||||
void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize);
|
||||
void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize);
|
||||
/* Removes the arguments from a command:
|
||||
* - Removes text between parentheses, except commas */
|
||||
* - Removes text between parentheses or brackets, except commas */
|
||||
void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer, int bufferSize);
|
||||
void TextToParseIntoLayoutForCommandText(const char * command, char * buffer, int bufferSize);
|
||||
/* Removes the arguments from a command and replaces them with empty chars. */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Komplexen Zahlen"
|
||||
Probability = "Kombinatorik"
|
||||
Arithmetic = "Arithmetisch"
|
||||
Matrices = "Matrizen"
|
||||
NewMatrix = "Neue Matrix"
|
||||
Lists = "Listen"
|
||||
HyperbolicTrigonometry = "Hyperbelfunktionen"
|
||||
Fluctuation = "Konfidenzintervall"
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Complex numbers"
|
||||
Probability = "Combinatorics"
|
||||
Arithmetic = "Arithmetic"
|
||||
Matrices = "Matrix"
|
||||
NewMatrix = "New matrix"
|
||||
Lists = "List"
|
||||
HyperbolicTrigonometry = "Hyperbolic trigonometry"
|
||||
Fluctuation = "Prediction Interval"
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Numeros complejos"
|
||||
Probability = "Combinatoria"
|
||||
Arithmetic = "Aritmetica"
|
||||
Matrices = "Matriz"
|
||||
NewMatrix = "Nueva matriz"
|
||||
Lists = "Listas"
|
||||
HyperbolicTrigonometry = "Trigonometria hiperbolica"
|
||||
Fluctuation = "Interval de prediccion"
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Nombres complexes"
|
||||
Probability = "Denombrement"
|
||||
Arithmetic = "Arithmetique"
|
||||
Matrices = "Matrices"
|
||||
NewMatrix = "Nouvelle matrice"
|
||||
Lists = "Listes"
|
||||
HyperbolicTrigonometry = "Trigonometrie hyperbolique"
|
||||
Fluctuation = "Intervalle fluctuation"
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Numeros complexos"
|
||||
Probability = "Combinatoria"
|
||||
Arithmetic = "Aritmetica"
|
||||
Matrices = "Matrizes"
|
||||
NewMatrix = "Nova matriz"
|
||||
Lists = "Listas"
|
||||
HyperbolicTrigonometry = "Funcoes hiperbolicas"
|
||||
Fluctuation = "Intervalo de confianca"
|
||||
|
||||
@@ -10,7 +10,7 @@ using namespace Poincare;
|
||||
VariableBoxController::ContentViewController::ContentViewController(Responder * parentResponder, GlobalContext * context) :
|
||||
ViewController(parentResponder),
|
||||
m_context(context),
|
||||
m_textFieldCaller(nullptr),
|
||||
m_sender(nullptr),
|
||||
m_firstSelectedRow(0),
|
||||
m_previousSelectedRow(0),
|
||||
m_currentPage(Page::RootMenu),
|
||||
@@ -18,14 +18,13 @@ VariableBoxController::ContentViewController::ContentViewController(Responder *
|
||||
{
|
||||
}
|
||||
|
||||
const char * VariableBoxController::ContentViewController::title() {
|
||||
return I18n::translate(I18n::Message::Variables);
|
||||
}
|
||||
|
||||
View * VariableBoxController::ContentViewController::view() {
|
||||
return &m_selectableTableView;
|
||||
}
|
||||
|
||||
const char * VariableBoxController::ContentViewController::title() {
|
||||
return I18n::translate(I18n::Message::Variables);
|
||||
}
|
||||
void VariableBoxController::ContentViewController::didBecomeFirstResponder() {
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.scrollToCell(0,0);
|
||||
@@ -65,7 +64,7 @@ bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Even
|
||||
char label[3];
|
||||
putLabelAtIndexInBuffer(selectedRow(), label);
|
||||
const char * editedText = label;
|
||||
m_textFieldCaller->handleEventWithText(editedText);
|
||||
m_insertTextAction(m_sender, editedText);
|
||||
#if MATRIX_VARIABLES
|
||||
m_selectableTableView.deselectTable();
|
||||
m_currentPage = Page::RootMenu;
|
||||
@@ -198,21 +197,31 @@ int VariableBoxController::ContentViewController::typeAtLocation(int i, int j) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Expression * VariableBoxController::ContentViewController::expressionForIndex(int index) {
|
||||
if (m_currentPage == Page::Scalar) {
|
||||
const Symbol symbol = Symbol('A'+index);
|
||||
return m_context->expressionForSymbol(&symbol);
|
||||
}
|
||||
if (m_currentPage == Page::Matrix) {
|
||||
const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
|
||||
return m_context->expressionForSymbol(&symbol);
|
||||
}
|
||||
#if LIST_VARIABLES
|
||||
if (m_currentPage == Page::List) {
|
||||
return nullptr;
|
||||
}
|
||||
void VariableBoxController::ContentViewController::setTextFieldSender(TextField * textField) {
|
||||
m_sender = textField;
|
||||
m_insertTextAction = &insertTextInTextInput;
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
m_sender = scrollableExpressionViewWithCursor;
|
||||
m_insertTextAction = &insertTextInScrollableExpressionViewWithCursor;
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::reloadData() {
|
||||
m_selectableTableView.reloadData();
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::resetPage() {
|
||||
#if MATRIX_VARIABLES
|
||||
m_currentPage = Page::RootMenu;
|
||||
#else
|
||||
m_currentPage = Page::Scalar;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::viewDidDisappear() {
|
||||
m_selectableTableView.deselectTable();
|
||||
ViewController::viewDidDisappear();
|
||||
}
|
||||
|
||||
VariableBoxController::ContentViewController::Page VariableBoxController::ContentViewController::pageAtIndex(int index) {
|
||||
@@ -253,25 +262,34 @@ I18n::Message VariableBoxController::ContentViewController::nodeLabelAtIndex(int
|
||||
return labels[index];
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::setTextFieldCaller(TextField * textField) {
|
||||
m_textFieldCaller = textField;
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::reloadData() {
|
||||
m_selectableTableView.reloadData();
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::resetPage() {
|
||||
#if MATRIX_VARIABLES
|
||||
m_currentPage = Page::RootMenu;
|
||||
#else
|
||||
m_currentPage = Page::Scalar;
|
||||
const Expression * VariableBoxController::ContentViewController::expressionForIndex(int index) {
|
||||
if (m_currentPage == Page::Scalar) {
|
||||
const Symbol symbol = Symbol('A'+index);
|
||||
return m_context->expressionForSymbol(&symbol);
|
||||
}
|
||||
if (m_currentPage == Page::Matrix) {
|
||||
const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
|
||||
return m_context->expressionForSymbol(&symbol);
|
||||
}
|
||||
#if LIST_VARIABLES
|
||||
if (m_currentPage == Page::List) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::viewDidDisappear() {
|
||||
m_selectableTableView.deselectTable();
|
||||
ViewController::viewDidDisappear();
|
||||
void VariableBoxController::ContentViewController::insertTextInTextInput(void * sender, const char * textToInsert) {
|
||||
TextInput * textInput = static_cast<TextInput *>(sender);
|
||||
textInput->handleEventWithText(textToInsert);
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::insertTextInScrollableExpressionViewWithCursor(void * sender, const char * textToInsert) {
|
||||
ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor = static_cast<ScrollableExpressionViewWithCursor *>(sender);
|
||||
if (!scrollableExpressionViewWithCursor->isEditing()) {
|
||||
scrollableExpressionViewWithCursor->setEditing(true);
|
||||
}
|
||||
scrollableExpressionViewWithCursor->insertLayoutFromTextAtCursor(textToInsert);
|
||||
}
|
||||
|
||||
VariableBoxController::VariableBoxController(GlobalContext * context) :
|
||||
@@ -284,8 +302,12 @@ void VariableBoxController::didBecomeFirstResponder() {
|
||||
app()->setFirstResponder(&m_contentViewController);
|
||||
}
|
||||
|
||||
void VariableBoxController::setTextFieldCaller(TextField * textField) {
|
||||
m_contentViewController.setTextFieldCaller(textField);
|
||||
void VariableBoxController::setTextFieldSender(TextField * textField) {
|
||||
m_contentViewController.setTextFieldSender(textField);
|
||||
}
|
||||
|
||||
void VariableBoxController::setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
m_contentViewController.setScrollableExpressionViewWithCursorSender(scrollableExpressionViewWithCursor);
|
||||
}
|
||||
|
||||
void VariableBoxController::viewWillAppear() {
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
|
||||
class VariableBoxController : public StackViewController {
|
||||
public:
|
||||
typedef void (*Action)(void * sender, const char * text);
|
||||
VariableBoxController(Poincare::GlobalContext * context);
|
||||
void didBecomeFirstResponder() override;
|
||||
void setTextFieldCaller(TextField * textField);
|
||||
void setTextFieldSender(TextField * textField);
|
||||
void setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor);
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
private:
|
||||
@@ -31,7 +33,8 @@ private:
|
||||
KDCoordinate cumulatedHeightFromIndex(int j) override;
|
||||
int indexFromCumulatedHeight(KDCoordinate offsetY) override;
|
||||
int typeAtLocation(int i, int j) override;
|
||||
void setTextFieldCaller(TextField * textField);
|
||||
void setTextFieldSender(TextField * textField);
|
||||
void setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor);
|
||||
void reloadData();
|
||||
void resetPage();
|
||||
void viewDidDisappear() override;
|
||||
@@ -55,9 +58,11 @@ private:
|
||||
void putLabelAtIndexInBuffer(int index, char * buffer);
|
||||
I18n::Message nodeLabelAtIndex(int index);
|
||||
const Poincare::Expression * expressionForIndex(int index);
|
||||
|
||||
static void insertTextInTextInput(void * sender, const char * textToInsert);
|
||||
static void insertTextInScrollableExpressionViewWithCursor(void * sender, const char * textToInsert);
|
||||
Poincare::GlobalContext * m_context;
|
||||
TextField * m_textFieldCaller;
|
||||
Responder * m_sender;
|
||||
Action m_insertTextAction;
|
||||
int m_firstSelectedRow;
|
||||
int m_previousSelectedRow;
|
||||
Page m_currentPage;
|
||||
|
||||
@@ -91,7 +91,7 @@ void VariableBoxLeafCell::setExpression(const Expression * expression) {
|
||||
if (expression) {
|
||||
m_expressionLayout = expression->createLayout();
|
||||
}
|
||||
m_expressionView.setExpression(m_expressionLayout);
|
||||
m_expressionView.setExpressionLayout(m_expressionLayout);
|
||||
}
|
||||
|
||||
void VariableBoxLeafCell::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
|
||||
@@ -12,6 +12,7 @@ objs += $(addprefix escher/src/,\
|
||||
dynamic_view_controller.o\
|
||||
editable_text_cell.o\
|
||||
ellipsis_view.o\
|
||||
editable_expression_view.o\
|
||||
even_odd_cell.o\
|
||||
even_odd_cell_with_ellipsis.o\
|
||||
even_odd_buffer_text_cell.o\
|
||||
@@ -21,6 +22,7 @@ objs += $(addprefix escher/src/,\
|
||||
expression_table_cell.o\
|
||||
expression_table_cell_with_pointer.o\
|
||||
expression_view.o\
|
||||
expression_view_with_cursor.o\
|
||||
highlight_cell.o\
|
||||
gauge_view.o\
|
||||
image_view.o\
|
||||
@@ -48,6 +50,7 @@ objs += $(addprefix escher/src/,\
|
||||
scroll_view_data_source.o\
|
||||
scroll_view_indicator.o\
|
||||
scrollable_view.o\
|
||||
scrollable_expression_view_with_cursor.o\
|
||||
selectable_table_view.o\
|
||||
selectable_table_view_data_source.o\
|
||||
selectable_table_view_delegate.o\
|
||||
@@ -73,7 +76,6 @@ objs += $(addprefix escher/src/,\
|
||||
tiled_view.o\
|
||||
timer.o\
|
||||
toolbox.o\
|
||||
toolbox_message_tree.o\
|
||||
view.o\
|
||||
view_controller.o\
|
||||
warning_controller.o\
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <escher/clipboard.h>
|
||||
#include <escher/container.h>
|
||||
#include <escher/dynamic_view_controller.h>
|
||||
#include <escher/editable_expression_view.h>
|
||||
#include <escher/editable_text_cell.h>
|
||||
#include <escher/ellipsis_view.h>
|
||||
#include <escher/even_odd_cell.h>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <escher/expression_table_cell.h>
|
||||
#include <escher/expression_table_cell_with_pointer.h>
|
||||
#include <escher/expression_view.h>
|
||||
#include <escher/expression_view_with_cursor.h>
|
||||
#include <escher/gauge_view.h>
|
||||
#include <escher/highlight_cell.h>
|
||||
#include <escher/image.h>
|
||||
@@ -51,6 +53,8 @@
|
||||
#include <escher/scroll_view_data_source.h>
|
||||
#include <escher/scroll_view_indicator.h>
|
||||
#include <escher/scrollable_view.h>
|
||||
#include <escher/scrollable_expression_view_with_cursor.h>
|
||||
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
|
||||
#include <escher/selectable_table_view.h>
|
||||
#include <escher/selectable_table_view_data_source.h>
|
||||
#include <escher/selectable_table_view_delegate.h>
|
||||
|
||||
48
escher/include/escher/editable_expression_view.h
Normal file
48
escher/include/escher/editable_expression_view.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef ESCHER_EDITABLE_EXPRESSION_VIEW_H
|
||||
#define ESCHER_EDITABLE_EXPRESSION_VIEW_H
|
||||
|
||||
#include <escher/scrollable_expression_view_with_cursor.h>
|
||||
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <escher/text_field_delegate.h>
|
||||
|
||||
class EditableExpressionView : public Responder, public View {
|
||||
public:
|
||||
EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
|
||||
|
||||
void setEditing(bool isEditing, bool reinitDraftBuffer = true);
|
||||
bool isEditing() const;
|
||||
const char * text();
|
||||
void setText(const char * text);
|
||||
void insertText(const char * text);
|
||||
void reload();
|
||||
TextField * textField() { return &m_textField; }
|
||||
ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor() { return &m_scrollableExpressionViewWithCursor; }
|
||||
bool editionIsInTextField() const;
|
||||
bool isEmpty() const;
|
||||
bool heightIsMaximal() const;
|
||||
|
||||
/* View */
|
||||
int numberOfSubviews() const override { return 1; }
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
|
||||
/* Responder */
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
|
||||
static constexpr int k_bufferLength = TextField::maxBufferSize();
|
||||
private:
|
||||
static constexpr KDCoordinate k_textFieldHeight = 37;
|
||||
static constexpr KDCoordinate k_leftMargin = 5;
|
||||
static constexpr KDCoordinate k_verticalExpressionViewMargin = 5;
|
||||
constexpr static int k_separatorThickness = 1;
|
||||
KDCoordinate inputViewHeight() const;
|
||||
KDCoordinate maximalHeight() const;
|
||||
TextField m_textField;
|
||||
ScrollableExpressionViewWithCursor m_scrollableExpressionViewWithCursor;
|
||||
char m_textBody[k_bufferLength];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
|
||||
void setEven(bool even) override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setBackgroundColor(KDColor backgroundColor);
|
||||
void setTextColor(KDColor textColor);
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
|
||||
@@ -9,7 +9,7 @@ public:
|
||||
ExpressionTableCell(Layout layout = Layout::Horizontal);
|
||||
View * labelView() const override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
private:
|
||||
ExpressionView m_labelExpressionView;
|
||||
};
|
||||
|
||||
@@ -16,12 +16,14 @@ public:
|
||||
ExpressionView(float horizontalAlignment = 0.0f, float verticalAlignment = 0.5f,
|
||||
KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
|
||||
Poincare::ExpressionLayout * expressionLayout() const;
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setBackgroundColor(KDColor backgroundColor);
|
||||
void setTextColor(KDColor textColor);
|
||||
void setAlignment(float horizontalAlignment, float verticalAlignment);
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
KDPoint drawingOrigin() const;
|
||||
KDPoint absoluteDrawingOrigin() const;
|
||||
private:
|
||||
/* Warning: we do not need to delete the previous expression layout when
|
||||
* deleting object or setting a new expression layout. Indeed, the expression
|
||||
|
||||
36
escher/include/escher/expression_view_with_cursor.h
Normal file
36
escher/include/escher/expression_view_with_cursor.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef ESCHER_EXPRESSION_VIEW_WITH_CURSOR_H
|
||||
#define ESCHER_EXPRESSION_VIEW_WITH_CURSOR_H
|
||||
|
||||
#include <escher/expression_view.h>
|
||||
#include <escher/text_cursor_view.h>
|
||||
#include <kandinsky/point.h>
|
||||
#include <poincare/expression_layout.h>
|
||||
#include <poincare/expression_layout_cursor.h>
|
||||
|
||||
class ExpressionViewWithCursor : public View {
|
||||
public:
|
||||
ExpressionViewWithCursor(Poincare::ExpressionLayout * expressionLayout);
|
||||
bool isEditing() const { return m_isEditing; }
|
||||
void setEditing(bool isEditing);
|
||||
void cursorPositionChanged();
|
||||
KDRect cursorRect();
|
||||
Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; }
|
||||
ExpressionView * expressionView() { return &m_expressionView; }
|
||||
/* View */
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
private:
|
||||
enum class Position {
|
||||
Top,
|
||||
Bottom
|
||||
};
|
||||
int numberOfSubviews() const override { return 2; }
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
void layoutCursorSubview();
|
||||
Poincare::ExpressionLayoutCursor m_cursor;
|
||||
ExpressionView m_expressionView;
|
||||
TextCursorView m_cursorView;
|
||||
bool m_isEditing;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,53 +1,56 @@
|
||||
#ifndef ESCHER_INPUT_VIEW_CONTROLLER_H
|
||||
#define ESCHER_INPUT_VIEW_CONTROLLER_H
|
||||
|
||||
#include <escher/editable_expression_view.h>
|
||||
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
|
||||
#include <escher/modal_view_controller.h>
|
||||
#include <escher/invocation.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <escher/text_field_delegate.h>
|
||||
|
||||
class InputViewController : public ModalViewController, TextFieldDelegate {
|
||||
/* TODO Implement a split view. Because we use a modal view, the main view is
|
||||
* redrawn underneath the modal view, which is visible and ugly. */
|
||||
|
||||
class InputViewController : public ModalViewController, TextFieldDelegate, ScrollableExpressionViewWithCursorDelegate {
|
||||
public:
|
||||
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate);
|
||||
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
|
||||
void edit(Responder * caller, Ion::Events::Event event, void * context, const char * initialText, Invocation::Action successAction, Invocation::Action failureAction);
|
||||
const char * textBody();
|
||||
void abortEditionAndDismiss();
|
||||
|
||||
/* TextFieldDelegate */
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
void abortTextFieldEditionAndDismiss();
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField, const char * text) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
Toolbox * toolboxForTextInput(TextInput * textInput) override;
|
||||
|
||||
/* ScrollableExpressionViewWithCursorDelegate */
|
||||
bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
|
||||
bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
|
||||
bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override;
|
||||
bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
|
||||
|
||||
private:
|
||||
class TextFieldController : public ViewController {
|
||||
class EditableExpressionViewController : public ViewController {
|
||||
public:
|
||||
TextFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate);
|
||||
EditableExpressionViewController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
|
||||
void didBecomeFirstResponder() override;
|
||||
View * view() override;
|
||||
TextField * textField();
|
||||
View * view() override { return &m_editableExpressionView; }
|
||||
EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; }
|
||||
private:
|
||||
class ContentView : public Responder, public View {
|
||||
public:
|
||||
ContentView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate);
|
||||
void didBecomeFirstResponder() override;
|
||||
TextField * textField();
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
private:
|
||||
View * subviewAtIndex(int index) override;
|
||||
int numberOfSubviews() const override;
|
||||
void layoutSubviews() override;
|
||||
constexpr static KDCoordinate k_inputHeight = 37;
|
||||
constexpr static KDCoordinate k_separatorThickness = 1;
|
||||
constexpr static KDCoordinate k_textMargin = 5;
|
||||
TextField m_textField;
|
||||
char m_textBody[TextField::maxBufferSize()];
|
||||
};
|
||||
ContentView m_view;
|
||||
EditableExpressionView m_editableExpressionView;
|
||||
};
|
||||
TextFieldController m_textFieldController;
|
||||
bool inputViewDidFinishEditing();
|
||||
bool inputViewDidAbortEditing();
|
||||
EditableExpressionViewController m_editableExpressionViewController;
|
||||
Invocation m_successAction;
|
||||
Invocation m_failureAction;
|
||||
TextFieldDelegate * m_textFieldDelegate;
|
||||
ScrollableExpressionViewWithCursorDelegate * m_scrollableExpressionViewWithCursorDelegate;
|
||||
bool m_inputViewHeightIsMaximal;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,7 @@ public:
|
||||
MessageTableCellWithChevronAndExpression(I18n::Message message = (I18n::Message)0, KDText::FontSize size = KDText::FontSize::Small);
|
||||
View * subAccessoryView() const override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
private:
|
||||
ExpressionView m_subtitleView;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,9 @@ public:
|
||||
constexpr static KDCoordinate StoreRowHeight = 50;
|
||||
constexpr static KDCoordinate ToolboxRowHeight = 40;
|
||||
constexpr static KDCoordinate StackTitleHeight = 20;
|
||||
constexpr static KDCoordinate FractionAndConjugateHorizontalOverflow = 2;
|
||||
constexpr static KDCoordinate FractionAndConjugateHorizontalMargin = 2;
|
||||
constexpr static KDCoordinate MinimalBracketAndParenthesisHeight = 18;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,8 @@ public:
|
||||
bool isDisplayingModal();
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
protected:
|
||||
void reloadView();
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
@@ -29,6 +31,7 @@ private:
|
||||
KDCoordinate topMargin, KDCoordinate leftMargin, KDCoordinate bottomMargin, KDCoordinate rightMargin);
|
||||
void dismissModalView();
|
||||
bool isDisplayingModal() const;
|
||||
void reload();
|
||||
private:
|
||||
KDRect frame() const;
|
||||
View * m_regularView;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H
|
||||
#define ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H
|
||||
|
||||
#include <escher/scrollable_view.h>
|
||||
#include <escher/expression_view_with_cursor.h>
|
||||
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
|
||||
#include <poincare/expression_layout_cursor.h>
|
||||
|
||||
class ScrollableExpressionViewWithCursor : public ScrollableView, public ScrollViewDataSource {
|
||||
public:
|
||||
ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ScrollableExpressionViewWithCursorDelegate * delegate = nullptr);
|
||||
void setDelegate(ScrollableExpressionViewWithCursorDelegate * delegate) { m_delegate = delegate; }
|
||||
ExpressionViewWithCursor * expressionViewWithCursor() { return &m_expressionViewWithCursor; }
|
||||
bool isEditing() const;
|
||||
void setEditing(bool isEditing);
|
||||
void clearLayout();
|
||||
void scrollToCursor();
|
||||
void reload();
|
||||
|
||||
/* Responder */
|
||||
Toolbox * toolbox() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
|
||||
bool scrollableExpressionViewWithCursorShouldFinishEditing(Ion::Events::Event event);
|
||||
|
||||
void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout);
|
||||
void insertLayoutFromTextAtCursor(const char * text);
|
||||
|
||||
/* View */
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
|
||||
protected:
|
||||
virtual bool privateHandleEvent(Ion::Events::Event event);
|
||||
bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout);
|
||||
ExpressionViewWithCursor m_expressionViewWithCursor;
|
||||
private:
|
||||
ScrollableExpressionViewWithCursorDelegate * m_delegate;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H
|
||||
#define ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H
|
||||
|
||||
#include <escher/toolbox.h>
|
||||
#include <ion/events.h>
|
||||
|
||||
class ScrollableExpressionViewWithCursor;
|
||||
|
||||
class ScrollableExpressionViewWithCursorDelegate {
|
||||
public:
|
||||
virtual bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) = 0;
|
||||
virtual bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) = 0;
|
||||
virtual bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) { return false; }
|
||||
virtual bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { return false; }
|
||||
virtual void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {}
|
||||
virtual Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
virtual bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) = 0;
|
||||
virtual bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) = 0;
|
||||
virtual bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { return false; };
|
||||
virtual bool textFieldDidAbortEditing(TextField * textField, const char * text) {return false;};
|
||||
virtual bool textFieldDidAbortEditing(TextField * textField) {return false;};
|
||||
virtual bool textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textHasChanged) { return returnValue; };
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ESCHER_TOOLBOX_MESSAGE_TREE_H
|
||||
|
||||
#include <escher/message_tree.h>
|
||||
#include <poincare_layouts.h>
|
||||
|
||||
class ToolboxMessageTree : public MessageTree {
|
||||
public:
|
||||
@@ -12,9 +13,9 @@ public:
|
||||
m_insertedText(insertedText)
|
||||
{
|
||||
};
|
||||
const MessageTree * children(int index) const override;
|
||||
I18n::Message text() const;
|
||||
I18n::Message insertedText() const;
|
||||
const MessageTree * children(int index) const override { return &m_children[index]; }
|
||||
I18n::Message text() const { return m_text; }
|
||||
I18n::Message insertedText() const { return m_insertedText; }
|
||||
private:
|
||||
const ToolboxMessageTree * m_children;
|
||||
I18n::Message m_text;
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
KDPoint pointFromPointInView(View * view, KDPoint point);
|
||||
|
||||
KDRect bounds() const;
|
||||
KDRect frame() const;
|
||||
View * subview(int index);
|
||||
|
||||
virtual KDSize minimalSizeForOptimalDisplay() const;
|
||||
|
||||
128
escher/src/editable_expression_view.cpp
Normal file
128
escher/src/editable_expression_view.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include <escher/editable_expression_view.h>
|
||||
#include <poincare/preferences.h>
|
||||
#include <assert.h>
|
||||
|
||||
EditableExpressionView::EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
|
||||
Responder(parentResponder),
|
||||
View(),
|
||||
m_textField(parentResponder, m_textBody, m_textBody, k_bufferLength, textFieldDelegate, false),
|
||||
m_scrollableExpressionViewWithCursor(parentResponder, new Poincare::HorizontalLayout(), scrollableExpressionViewWithCursorDelegate)
|
||||
{
|
||||
m_textBody[0] = 0;
|
||||
}
|
||||
|
||||
void EditableExpressionView::setEditing(bool isEditing, bool reinitDraftBuffer) {
|
||||
if (editionIsInTextField()) {
|
||||
m_textField.setEditing(isEditing, reinitDraftBuffer);
|
||||
}
|
||||
if (reinitDraftBuffer) {
|
||||
m_scrollableExpressionViewWithCursor.clearLayout();
|
||||
}
|
||||
m_scrollableExpressionViewWithCursor.setEditing(isEditing);
|
||||
}
|
||||
|
||||
bool EditableExpressionView::isEditing() const {
|
||||
return editionIsInTextField() ? m_textField.isEditing() : m_scrollableExpressionViewWithCursor.isEditing();
|
||||
}
|
||||
|
||||
const char * EditableExpressionView::text() {
|
||||
if (!editionIsInTextField()) {
|
||||
m_scrollableExpressionViewWithCursor.expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(m_textBody, k_bufferLength);
|
||||
}
|
||||
return m_textBody;
|
||||
}
|
||||
|
||||
void EditableExpressionView::setText(const char * text) {
|
||||
if (editionIsInTextField()) {
|
||||
m_textField.setText(text);
|
||||
return;
|
||||
}
|
||||
m_scrollableExpressionViewWithCursor.clearLayout();
|
||||
if (strlen(text) > 0) {
|
||||
m_scrollableExpressionViewWithCursor.insertLayoutFromTextAtCursor(text);
|
||||
}
|
||||
}
|
||||
|
||||
void EditableExpressionView::insertText(const char * text) {
|
||||
if (editionIsInTextField()) {
|
||||
m_textField.handleEventWithText(text);
|
||||
} else {
|
||||
m_scrollableExpressionViewWithCursor.setEditing(true);
|
||||
m_scrollableExpressionViewWithCursor.insertLayoutFromTextAtCursor(text);
|
||||
}
|
||||
}
|
||||
|
||||
View * EditableExpressionView::subviewAtIndex(int index) {
|
||||
assert(index == 0);
|
||||
if (editionIsInTextField()) {
|
||||
return &m_textField;
|
||||
}
|
||||
return &m_scrollableExpressionViewWithCursor;
|
||||
}
|
||||
|
||||
void EditableExpressionView::layoutSubviews() {
|
||||
KDRect inputViewFrame(k_leftMargin, k_separatorThickness, bounds().width() - k_leftMargin, bounds().height() - k_separatorThickness);
|
||||
if (editionIsInTextField()) {
|
||||
m_textField.setFrame(inputViewFrame);
|
||||
m_scrollableExpressionViewWithCursor.setFrame(KDRectZero);
|
||||
return;
|
||||
}
|
||||
m_scrollableExpressionViewWithCursor.setFrame(inputViewFrame);
|
||||
m_textField.setFrame(KDRectZero);
|
||||
}
|
||||
|
||||
void EditableExpressionView::reload() {
|
||||
layoutSubviews();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
void EditableExpressionView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
// Draw the separator
|
||||
ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyMiddle);
|
||||
// Color the left margin
|
||||
ctx->fillRect(KDRect(0, k_separatorThickness, k_leftMargin, bounds().height() - k_separatorThickness), m_textField.backgroundColor());
|
||||
if (!editionIsInTextField()) {
|
||||
// Color the upper margin
|
||||
ctx->fillRect(KDRect(0, k_separatorThickness, bounds().width(), k_verticalExpressionViewMargin), m_textField.backgroundColor());
|
||||
}
|
||||
}
|
||||
|
||||
bool EditableExpressionView::handleEvent(Ion::Events::Event event) {
|
||||
return editionIsInTextField() ? m_textField.handleEvent(event) : m_scrollableExpressionViewWithCursor.handleEvent(event);
|
||||
}
|
||||
|
||||
KDSize EditableExpressionView::minimalSizeForOptimalDisplay() const {
|
||||
return KDSize(0, inputViewHeight());
|
||||
}
|
||||
|
||||
bool EditableExpressionView::editionIsInTextField() const {
|
||||
return Poincare::Preferences::sharedPreferences()->editionMode() == Poincare::Preferences::EditionMode::Edition1D;
|
||||
}
|
||||
|
||||
bool EditableExpressionView::isEmpty() const {
|
||||
if (editionIsInTextField()) {
|
||||
return m_textField.draftTextLength() == 0;
|
||||
}
|
||||
Poincare::ExpressionLayout * layout = const_cast<ScrollableExpressionViewWithCursor *>(&m_scrollableExpressionViewWithCursor)->expressionViewWithCursor()->expressionView()->expressionLayout();
|
||||
return !layout->hasText();
|
||||
}
|
||||
|
||||
bool EditableExpressionView::heightIsMaximal() const {
|
||||
return inputViewHeight() == k_separatorThickness + k_verticalExpressionViewMargin + maximalHeight();
|
||||
}
|
||||
|
||||
KDCoordinate EditableExpressionView::inputViewHeight() const {
|
||||
if (editionIsInTextField()) {
|
||||
return k_separatorThickness + k_textFieldHeight;
|
||||
}
|
||||
return k_separatorThickness
|
||||
+ k_verticalExpressionViewMargin
|
||||
+ min(maximalHeight(),
|
||||
max(k_textFieldHeight,
|
||||
m_scrollableExpressionViewWithCursor.minimalSizeForOptimalDisplay().height()
|
||||
+ k_verticalExpressionViewMargin));
|
||||
}
|
||||
|
||||
KDCoordinate EditableExpressionView::maximalHeight() const {
|
||||
return 0.6*Ion::Display::Height;
|
||||
}
|
||||
@@ -19,8 +19,8 @@ void EvenOddExpressionCell::setEven(bool even) {
|
||||
m_expressionView.setBackgroundColor(backgroundColor());
|
||||
}
|
||||
|
||||
void EvenOddExpressionCell::setExpression(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpression(expressionLayout);
|
||||
void EvenOddExpressionCell::setExpressionLayout(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpressionLayout(expressionLayout);
|
||||
}
|
||||
|
||||
void EvenOddExpressionCell::setBackgroundColor(KDColor backgroundColor) {
|
||||
|
||||
@@ -18,7 +18,7 @@ void ExpressionTableCell::setHighlighted(bool highlight) {
|
||||
m_labelExpressionView.setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
void ExpressionTableCell::setExpression(Poincare::ExpressionLayout * expressionLayout) {
|
||||
m_labelExpressionView.setExpression(expressionLayout);
|
||||
void ExpressionTableCell::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
|
||||
m_labelExpressionView.setExpressionLayout(expressionLayout);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ ExpressionLayout * ExpressionView::expressionLayout() const {
|
||||
return m_expressionLayout;
|
||||
}
|
||||
|
||||
void ExpressionView::setExpression(ExpressionLayout * expressionLayout) {
|
||||
void ExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) {
|
||||
m_expressionLayout = expressionLayout;
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
@@ -47,13 +47,18 @@ KDSize ExpressionView::minimalSizeForOptimalDisplay() const {
|
||||
return m_expressionLayout->size();
|
||||
}
|
||||
|
||||
KDPoint ExpressionView::drawingOrigin() const {
|
||||
KDSize expressionSize = m_expressionLayout->size();
|
||||
return KDPoint(m_horizontalAlignment*(m_frame.width() - expressionSize.width()), 0.5f*(m_frame.height() - expressionSize.height()));
|
||||
}
|
||||
|
||||
KDPoint ExpressionView::absoluteDrawingOrigin() const {
|
||||
return drawingOrigin().translatedBy(m_frame.topLeft());
|
||||
}
|
||||
|
||||
void ExpressionView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(rect, m_backgroundColor);
|
||||
if (m_expressionLayout != nullptr) {
|
||||
//Position the origin of expression
|
||||
KDSize expressionSize = m_expressionLayout->size();
|
||||
KDPoint origin(m_horizontalAlignment*(m_frame.width() - expressionSize.width()),
|
||||
0.5f*(m_frame.height() - expressionSize.height()));
|
||||
m_expressionLayout->draw(ctx, origin, m_textColor, m_backgroundColor);
|
||||
m_expressionLayout->draw(ctx, drawingOrigin(), m_textColor, m_backgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
64
escher/src/expression_view_with_cursor.cpp
Normal file
64
escher/src/expression_view_with_cursor.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include <escher/expression_view_with_cursor.h>
|
||||
#include <kandinsky/rect.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
ExpressionViewWithCursor::ExpressionViewWithCursor(ExpressionLayout * expressionLayout) :
|
||||
m_cursor(),
|
||||
m_expressionView(),
|
||||
m_cursorView(),
|
||||
m_isEditing(false)
|
||||
{
|
||||
m_cursor.setPointedExpressionLayout(expressionLayout);
|
||||
m_cursor.setPosition(ExpressionLayoutCursor::Position::Right);
|
||||
m_expressionView.setExpressionLayout(expressionLayout);
|
||||
}
|
||||
|
||||
void ExpressionViewWithCursor::setEditing(bool isEditing) {
|
||||
m_isEditing = isEditing;
|
||||
markRectAsDirty(bounds());
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void ExpressionViewWithCursor::cursorPositionChanged() {
|
||||
layoutCursorSubview();
|
||||
}
|
||||
|
||||
KDRect ExpressionViewWithCursor::cursorRect() {
|
||||
return m_cursorView.frame();
|
||||
}
|
||||
|
||||
KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const {
|
||||
KDSize expressionViewSize = m_expressionView.minimalSizeForOptimalDisplay();
|
||||
KDSize cursorSize = isEditing() ? m_cursorView.minimalSizeForOptimalDisplay() : KDSizeZero;
|
||||
KDCoordinate resultWidth = expressionViewSize.width() + cursorSize.width();
|
||||
KDCoordinate resultHeight = expressionViewSize.height() + cursorSize.height()/2;
|
||||
return KDSize(resultWidth, resultHeight);
|
||||
}
|
||||
|
||||
View * ExpressionViewWithCursor::subviewAtIndex(int index) {
|
||||
assert(index >= 0 && index < 2);
|
||||
View * m_views[] = {&m_expressionView, &m_cursorView};
|
||||
return m_views[index];
|
||||
}
|
||||
|
||||
void ExpressionViewWithCursor::layoutSubviews() {
|
||||
m_expressionView.setFrame(bounds());
|
||||
layoutCursorSubview();
|
||||
}
|
||||
|
||||
void ExpressionViewWithCursor::layoutCursorSubview() {
|
||||
if (!m_isEditing) {
|
||||
m_cursorView.setFrame(KDRectZero);
|
||||
return;
|
||||
}
|
||||
KDPoint expressionViewOrigin = m_expressionView.absoluteDrawingOrigin();
|
||||
KDPoint cursoredExpressionViewOrigin = m_cursor.pointedExpressionLayout()->absoluteOrigin();
|
||||
KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x();
|
||||
if (m_cursor.position() == ExpressionLayoutCursor::Position::Right) {
|
||||
cursorX += m_cursor.pointedExpressionLayout()->size().width();
|
||||
}
|
||||
KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + m_cursor.pointedExpressionLayout()->baseline()-m_cursor.cursorHeight()/2);
|
||||
m_cursorView.setFrame(KDRect(cursorTopLeftPosition, 1, m_cursor.cursorHeight()));
|
||||
}
|
||||
@@ -1,88 +1,46 @@
|
||||
#include <escher/input_view_controller.h>
|
||||
#include <escher/app.h>
|
||||
#include <escher/palette.h>
|
||||
#include <poincare/src/layout/horizontal_layout.h>
|
||||
#include <assert.h>
|
||||
|
||||
InputViewController::TextFieldController::ContentView::ContentView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate) :
|
||||
Responder(parentResponder),
|
||||
View(),
|
||||
m_textField(this, m_textBody, m_textBody, TextField::maxBufferSize(), textFieldDelegate, false)
|
||||
{
|
||||
m_textBody[0] = 0;
|
||||
}
|
||||
|
||||
void InputViewController::TextFieldController::ContentView::didBecomeFirstResponder() {
|
||||
app()->setFirstResponder(&m_textField);
|
||||
}
|
||||
|
||||
TextField * InputViewController::TextFieldController::ContentView::textField() {
|
||||
return &m_textField;
|
||||
}
|
||||
|
||||
void InputViewController::TextFieldController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyMiddle);
|
||||
ctx->fillRect(KDRect(0, k_separatorThickness, k_textMargin, bounds().height()-k_separatorThickness), m_textField.backgroundColor());
|
||||
}
|
||||
|
||||
KDSize InputViewController::TextFieldController::ContentView::minimalSizeForOptimalDisplay() const {
|
||||
return KDSize(0, k_inputHeight);
|
||||
}
|
||||
|
||||
int InputViewController::TextFieldController::ContentView::numberOfSubviews() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
View * InputViewController::TextFieldController::ContentView::subviewAtIndex(int index) {
|
||||
return &m_textField;
|
||||
}
|
||||
|
||||
void InputViewController::TextFieldController::ContentView::layoutSubviews() {
|
||||
m_textField.setFrame(KDRect(k_textMargin, k_separatorThickness, bounds().width()-k_textMargin, bounds().height()));
|
||||
}
|
||||
|
||||
InputViewController::TextFieldController::TextFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate) :
|
||||
InputViewController::EditableExpressionViewController::EditableExpressionViewController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
|
||||
ViewController(parentResponder),
|
||||
m_view(this, textFieldDelegate)
|
||||
m_editableExpressionView(this, textFieldDelegate, scrollableExpressionViewWithCursorDelegate)
|
||||
{
|
||||
}
|
||||
|
||||
View * InputViewController::TextFieldController::view() {
|
||||
return &m_view;
|
||||
void InputViewController::EditableExpressionViewController::didBecomeFirstResponder() {
|
||||
app()->setFirstResponder(&m_editableExpressionView);
|
||||
}
|
||||
|
||||
void InputViewController::TextFieldController::didBecomeFirstResponder() {
|
||||
app()->setFirstResponder(&m_view);
|
||||
}
|
||||
|
||||
TextField * InputViewController::TextFieldController::textField() {
|
||||
return m_view.textField();
|
||||
}
|
||||
|
||||
InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate) :
|
||||
InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
|
||||
ModalViewController(parentResponder, child),
|
||||
m_textFieldController(this, this),
|
||||
m_editableExpressionViewController(this, this, this),
|
||||
m_successAction(Invocation(nullptr, nullptr)),
|
||||
m_failureAction(Invocation(nullptr, nullptr)),
|
||||
m_textFieldDelegate(textFieldDelegate)
|
||||
m_textFieldDelegate(textFieldDelegate),
|
||||
m_scrollableExpressionViewWithCursorDelegate(scrollableExpressionViewWithCursorDelegate),
|
||||
m_inputViewHeightIsMaximal(false)
|
||||
{
|
||||
}
|
||||
|
||||
const char * InputViewController::textBody() {
|
||||
return m_textFieldController.textField()->text();
|
||||
return m_editableExpressionViewController.editableExpressionView()->text();
|
||||
}
|
||||
|
||||
void InputViewController::edit(Responder * caller, Ion::Events::Event event, void * context, const char * initialText, Invocation::Action successAction, Invocation::Action failureAction) {
|
||||
m_successAction = Invocation(successAction, context);
|
||||
m_failureAction = Invocation(failureAction, context);
|
||||
displayModalViewController(&m_textFieldController, 1.0f, 1.0f);
|
||||
m_textFieldController.textField()->handleEvent(event);
|
||||
displayModalViewController(&m_editableExpressionViewController, 1.0f, 1.0f);
|
||||
m_editableExpressionViewController.editableExpressionView()->handleEvent(event);
|
||||
if (initialText != nullptr) {
|
||||
m_textFieldController.textField()->handleEventWithText(initialText);
|
||||
m_editableExpressionViewController.editableExpressionView()->setText(initialText);
|
||||
}
|
||||
}
|
||||
|
||||
void InputViewController::abortTextFieldEditionAndDismiss() {
|
||||
m_textFieldController.textField()->setEditing(false);
|
||||
void InputViewController::abortEditionAndDismiss() {
|
||||
m_editableExpressionViewController.editableExpressionView()->setEditing(false);
|
||||
dismissModalViewController();
|
||||
}
|
||||
|
||||
@@ -91,15 +49,11 @@ bool InputViewController::textFieldShouldFinishEditing(TextField * textField, Io
|
||||
}
|
||||
|
||||
bool InputViewController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
|
||||
m_successAction.perform(this);
|
||||
dismissModalViewController();
|
||||
return true;
|
||||
return inputViewDidFinishEditing();
|
||||
}
|
||||
|
||||
bool InputViewController::textFieldDidAbortEditing(TextField * textField, const char * text) {
|
||||
m_failureAction.perform(this);
|
||||
dismissModalViewController();
|
||||
return true;
|
||||
bool InputViewController::textFieldDidAbortEditing(TextField * textField) {
|
||||
return inputViewDidAbortEditing();
|
||||
}
|
||||
|
||||
bool InputViewController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
|
||||
@@ -109,3 +63,45 @@ bool InputViewController::textFieldDidReceiveEvent(TextField * textField, Ion::E
|
||||
Toolbox * InputViewController::toolboxForTextInput(TextInput * input) {
|
||||
return m_textFieldDelegate->toolboxForTextInput(input);
|
||||
}
|
||||
|
||||
bool InputViewController::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
|
||||
return event == Ion::Events::OK || event == Ion::Events::EXE;
|
||||
}
|
||||
|
||||
bool InputViewController::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
|
||||
return m_scrollableExpressionViewWithCursorDelegate->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event);
|
||||
}
|
||||
|
||||
bool InputViewController::scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) {
|
||||
return inputViewDidFinishEditing();
|
||||
}
|
||||
|
||||
bool InputViewController::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
return inputViewDidAbortEditing();
|
||||
}
|
||||
|
||||
void InputViewController::scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
// Reload the view only if the EditableExpressionView height actually changes,
|
||||
// i.e. not if the height is already maximal and stays maximal.
|
||||
bool newInputViewHeightIsMaximal = m_editableExpressionViewController.editableExpressionView()->heightIsMaximal();
|
||||
if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) {
|
||||
m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal;
|
||||
reloadView();
|
||||
}
|
||||
}
|
||||
|
||||
Toolbox * InputViewController::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
|
||||
return m_scrollableExpressionViewWithCursorDelegate->toolboxForScrollableExpressionViewWithCursor(scrollableExpressionViewWithCursor);
|
||||
}
|
||||
|
||||
bool InputViewController::inputViewDidFinishEditing() {
|
||||
m_successAction.perform(this);
|
||||
dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputViewController::inputViewDidAbortEditing() {
|
||||
m_failureAction.perform(this);
|
||||
dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ void MessageTableCellWithChevronAndExpression::setHighlighted(bool highlight) {
|
||||
m_subtitleView.setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
void MessageTableCellWithChevronAndExpression::setExpression(Poincare::ExpressionLayout * expressionLayout) {
|
||||
m_subtitleView.setExpression(expressionLayout);
|
||||
void MessageTableCellWithChevronAndExpression::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
|
||||
m_subtitleView.setExpressionLayout(expressionLayout);
|
||||
reloadCell();
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
@@ -95,6 +95,11 @@ bool ModalViewController::ContentView::isDisplayingModal() const {
|
||||
return m_isDisplayingModal;
|
||||
}
|
||||
|
||||
void ModalViewController::ContentView::reload() {
|
||||
markRectAsDirty(frame());
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
ModalViewController::ModalViewController(Responder * parentResponder, ViewController * child) :
|
||||
ViewController(parentResponder),
|
||||
m_contentView(),
|
||||
@@ -162,3 +167,7 @@ void ModalViewController::viewDidDisappear() {
|
||||
}
|
||||
m_regularViewController->viewDidDisappear();
|
||||
}
|
||||
|
||||
void ModalViewController::reloadView() {
|
||||
m_contentView.reload();
|
||||
}
|
||||
|
||||
238
escher/src/scrollable_expression_view_with_cursor.cpp
Normal file
238
escher/src/scrollable_expression_view_with_cursor.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
#include <escher/scrollable_expression_view_with_cursor.h>
|
||||
#include <escher/clipboard.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <poincare/src/layout/matrix_layout.h>
|
||||
#include <assert.h>
|
||||
|
||||
ScrollableExpressionViewWithCursor::ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ScrollableExpressionViewWithCursorDelegate * delegate) :
|
||||
ScrollableView(parentResponder, &m_expressionViewWithCursor, this),
|
||||
m_expressionViewWithCursor(expressionLayout),
|
||||
m_delegate(delegate)
|
||||
{
|
||||
}
|
||||
|
||||
bool ScrollableExpressionViewWithCursor::isEditing() const {
|
||||
return m_expressionViewWithCursor.isEditing();
|
||||
}
|
||||
|
||||
void ScrollableExpressionViewWithCursor::setEditing(bool isEditing) {
|
||||
m_expressionViewWithCursor.setEditing(isEditing);
|
||||
}
|
||||
|
||||
void ScrollableExpressionViewWithCursor::clearLayout() {
|
||||
delete m_expressionViewWithCursor.expressionView()->expressionLayout();
|
||||
Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout();
|
||||
m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout);
|
||||
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout);
|
||||
}
|
||||
|
||||
void ScrollableExpressionViewWithCursor::scrollToCursor() {
|
||||
scrollToContentRect(m_expressionViewWithCursor.cursorRect(), true);
|
||||
}
|
||||
|
||||
Toolbox * ScrollableExpressionViewWithCursor::toolbox() {
|
||||
if (m_delegate) {
|
||||
return m_delegate->toolboxForScrollableExpressionViewWithCursor(this);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ScrollableExpressionViewWithCursor::handleEvent(Ion::Events::Event event) {
|
||||
KDSize previousSize = minimalSizeForOptimalDisplay();
|
||||
bool shouldRecomputeLayout = false;
|
||||
if (privateHandleMoveEvent(event, &shouldRecomputeLayout)) {
|
||||
if (!shouldRecomputeLayout) {
|
||||
m_expressionViewWithCursor.cursorPositionChanged();
|
||||
scrollToCursor();
|
||||
return true;
|
||||
}
|
||||
reload();
|
||||
KDSize newSize = minimalSizeForOptimalDisplay();
|
||||
if (m_delegate && previousSize.height() != newSize.height()) {
|
||||
m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this);
|
||||
reload();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (privateHandleEvent(event)) {
|
||||
reload();
|
||||
KDSize newSize = minimalSizeForOptimalDisplay();
|
||||
if (m_delegate && previousSize.height() != newSize.height()) {
|
||||
m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this);
|
||||
reload();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScrollableExpressionViewWithCursor::scrollableExpressionViewWithCursorShouldFinishEditing(Ion::Events::Event event) {
|
||||
return m_delegate->scrollableExpressionViewWithCursorShouldFinishEditing(this, event);
|
||||
}
|
||||
|
||||
KDSize ScrollableExpressionViewWithCursor::minimalSizeForOptimalDisplay() const {
|
||||
return m_expressionViewWithCursor.minimalSizeForOptimalDisplay();
|
||||
}
|
||||
|
||||
bool ScrollableExpressionViewWithCursor::privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) {
|
||||
if (event == Ion::Events::Left) {
|
||||
return m_expressionViewWithCursor.cursor()->moveLeft(shouldRecomputeLayout);
|
||||
}
|
||||
if (event == Ion::Events::Right) {
|
||||
return m_expressionViewWithCursor.cursor()->moveRight(shouldRecomputeLayout);
|
||||
}
|
||||
if (event == Ion::Events::Up) {
|
||||
return m_expressionViewWithCursor.cursor()->moveUp(shouldRecomputeLayout);
|
||||
}
|
||||
if (event == Ion::Events::Down) {
|
||||
return m_expressionViewWithCursor.cursor()->moveDown(shouldRecomputeLayout);
|
||||
}
|
||||
if (event == Ion::Events::ShiftLeft) {
|
||||
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout());
|
||||
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Left);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::ShiftRight) {
|
||||
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout());
|
||||
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScrollableExpressionViewWithCursor::privateHandleEvent(Ion::Events::Event event) {
|
||||
if (m_delegate && m_delegate->scrollableExpressionViewWithCursorDidReceiveEvent(this, event)) {
|
||||
return true;
|
||||
}
|
||||
if (Responder::handleEvent(event)) {
|
||||
/* The only event Responder handles is 'Toolbox' displaying. In that case,
|
||||
* the ScrollableExpressionViewWithCursor is forced into editing mode. */
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (isEditing() && scrollableExpressionViewWithCursorShouldFinishEditing(event)) {
|
||||
setEditing(false);
|
||||
int bufferSize = TextField::maxBufferSize();
|
||||
char buffer[bufferSize];
|
||||
m_expressionViewWithCursor.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize);
|
||||
if (m_delegate->scrollableExpressionViewWithCursorDidFinishEditing(this, buffer, event)) {
|
||||
delete m_expressionViewWithCursor.expressionView()->expressionLayout();
|
||||
Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout();
|
||||
m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout);
|
||||
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && !isEditing()) {
|
||||
setEditing(true);
|
||||
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout());
|
||||
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Back && isEditing()) {
|
||||
setEditing(false);
|
||||
m_delegate->scrollableExpressionViewWithCursorDidAbortEditing(this);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Division) {
|
||||
m_expressionViewWithCursor.cursor()->addFractionLayoutAndCollapseBrothers();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::XNT) {
|
||||
m_expressionViewWithCursor.cursor()->addXNTCharLayout();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Exp) {
|
||||
m_expressionViewWithCursor.cursor()->addEmptyExponentialLayout();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Power) {
|
||||
m_expressionViewWithCursor.cursor()->addEmptyPowerLayout();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Sqrt) {
|
||||
m_expressionViewWithCursor.cursor()->addEmptySquareRootLayout();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Square) {
|
||||
m_expressionViewWithCursor.cursor()->addEmptySquarePowerLayout();
|
||||
return true;
|
||||
}
|
||||
if (event.hasText()) {
|
||||
const char * textToInsert = event.text();
|
||||
if (textToInsert[1] == 0) {
|
||||
if (textToInsert[0] == Ion::Charset::MultiplicationSign) {
|
||||
const char middleDotString[] = {Ion::Charset::MiddleDot, 0};
|
||||
m_expressionViewWithCursor.cursor()->insertText(middleDotString);
|
||||
return true;
|
||||
}
|
||||
if (textToInsert[0] == '[' || textToInsert[0] == ']') {
|
||||
m_expressionViewWithCursor.cursor()->addEmptyMatrixLayout();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
m_expressionViewWithCursor.cursor()->insertText(textToInsert);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Backspace) {
|
||||
m_expressionViewWithCursor.cursor()->performBackspace();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Paste) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
insertLayoutFromTextAtCursor(Clipboard::sharedClipboard()->storedText());
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Clear && isEditing()) {
|
||||
clearLayout();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScrollableExpressionViewWithCursor::insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout) {
|
||||
if (layout == nullptr) {
|
||||
return;
|
||||
}
|
||||
KDSize previousSize = minimalSizeForOptimalDisplay();
|
||||
if (layout->isMatrix() && pointedLayout && pointedLayout->hasAncestor(layout)) {
|
||||
static_cast<Poincare::MatrixLayout *>(layout)->addGreySquares();
|
||||
}
|
||||
if (pointedLayout != nullptr) {
|
||||
m_expressionViewWithCursor.cursor()->addLayout(layout);
|
||||
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout);
|
||||
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
|
||||
} else {
|
||||
m_expressionViewWithCursor.cursor()->addLayoutAndMoveCursor(layout);
|
||||
}
|
||||
reload();
|
||||
KDSize newSize = minimalSizeForOptimalDisplay();
|
||||
if (m_delegate && previousSize.height() != newSize.height()) {
|
||||
m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollableExpressionViewWithCursor::insertLayoutFromTextAtCursor(const char * text) {
|
||||
Poincare::Expression * expression = Poincare::Expression::parse(text);
|
||||
if (expression != nullptr) {
|
||||
Poincare::ExpressionLayout * layout = expression->createLayout();
|
||||
delete expression;
|
||||
insertLayoutAtCursor(layout, nullptr);
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
m_expressionViewWithCursor.cursor()->insertText(text);
|
||||
reload();
|
||||
}
|
||||
|
||||
void ScrollableExpressionViewWithCursor::reload() {
|
||||
m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines();
|
||||
m_expressionViewWithCursor.cursorPositionChanged();
|
||||
layoutSubviews();
|
||||
scrollToCursor();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
@@ -249,7 +249,7 @@ bool TextField::privateHandleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Back && isEditing()) {
|
||||
setEditing(false);
|
||||
reloadScroll();
|
||||
m_delegate->textFieldDidAbortEditing(this, text());
|
||||
m_delegate->textFieldDidAbortEditing(this);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Clear && isEditing()) {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include <escher/toolbox_message_tree.h>
|
||||
|
||||
I18n::Message ToolboxMessageTree::text() const {
|
||||
return m_text;
|
||||
}
|
||||
|
||||
I18n::Message ToolboxMessageTree::insertedText() const {
|
||||
return m_insertedText;
|
||||
}
|
||||
|
||||
const MessageTree * ToolboxMessageTree::children(int index) const {
|
||||
return &m_children[index];
|
||||
}
|
||||
@@ -158,6 +158,10 @@ KDRect View::bounds() const {
|
||||
return m_frame.movedTo(KDPointZero);
|
||||
}
|
||||
|
||||
KDRect View::frame() const {
|
||||
return KDRect(m_frame);
|
||||
}
|
||||
|
||||
KDPoint View::absoluteOrigin() const {
|
||||
if (m_superview == nullptr) {
|
||||
assert(this == (View *)window());
|
||||
|
||||
@@ -24,7 +24,8 @@ enum Charset : char {
|
||||
GreaterEqual = (char)146,
|
||||
MultiplicationSign = (char)147,
|
||||
MiddleDot = (char)148,
|
||||
AlmostEqual = (char)149
|
||||
AlmostEqual = (char)149,
|
||||
Empty = (char)150 // This char is used to be parsed into EmptyExpression.
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
bool operator !=(const KDPoint &other) const {
|
||||
return !(operator ==(other));
|
||||
}
|
||||
uint16_t squareDistanceTo(KDPoint other) const;
|
||||
private:
|
||||
KDCoordinate m_x;
|
||||
KDCoordinate m_y;
|
||||
|
||||
@@ -45,6 +45,8 @@ public:
|
||||
KDCoordinate left() const { return m_x; }
|
||||
|
||||
KDPoint topLeft() const { return KDPoint(left(), top()); }
|
||||
KDPoint topRight() const { return KDPoint(right(), top()); }
|
||||
KDPoint bottomLeft() const { return KDPoint(left(), bottom()); }
|
||||
KDPoint bottomRight() const { return KDPoint(right(), bottom()); }
|
||||
|
||||
bool operator ==(const KDRect &other) const {
|
||||
@@ -61,6 +63,8 @@ public:
|
||||
KDRect intersectedWith(const KDRect & other) const;
|
||||
KDRect unionedWith(const KDRect & other) const; // Returns the smallest rectangle containing r1 and r2
|
||||
bool contains(KDPoint p) const;
|
||||
bool isAbove(KDPoint p) const;
|
||||
bool isUnder(KDPoint p) const;
|
||||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -7,3 +7,7 @@ KDPoint KDPoint::translatedBy(KDPoint other) const {
|
||||
KDPoint KDPoint::opposite() const {
|
||||
return KDPoint(-m_x, -m_y);
|
||||
}
|
||||
|
||||
uint16_t KDPoint::squareDistanceTo(KDPoint other) const {
|
||||
return (m_x-other.x()) * (m_x-other.x()) + (m_y-other.y()) * (m_y-other.y());
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user