[escher][apps] CHange textField API

Change-Id: I766d153b7f7429473f297707a08358051123accc
This commit is contained in:
Émilie Feral
2016-12-13 16:00:55 +01:00
parent fed6664b42
commit 8c284ba34f
35 changed files with 470 additions and 378 deletions

View File

@@ -9,7 +9,7 @@ App::App(Container * container, Context * context) :
m_evaluateContext(EvaluateContext(context, &m_calculationStore)),
m_calculationStore(CalculationStore()),
m_historyController(HistoryController(&m_editExpressionController, &m_calculationStore)),
m_editExpressionController(EditExpressionController(&m_modalViewController, &m_historyController, &m_calculationStore, this))
m_editExpressionController(EditExpressionController(&m_modalViewController, &m_historyController, &m_calculationStore))
{
}

View File

@@ -4,10 +4,10 @@
namespace Calculation {
EditExpressionController::ContentView::ContentView(TableView * subview, TextFieldDelegate * textFieldDelegate) :
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate) :
View(),
m_mainView(subview),
m_textField(nullptr, m_textBody, 255, textFieldDelegate)
m_textField(parentResponder, m_textBody, 255, textFieldDelegate)
{
m_textBody[0] = 0;
}
@@ -43,13 +43,12 @@ TableView * EditExpressionController::ContentView::mainView() {
return m_mainView;
}
EditExpressionController::EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore, TextFieldDelegate * textFieldDelegate) :
EditExpressionController::EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore) :
ViewController(parentResponder),
m_contentView((TableView *)historyController->view(), textFieldDelegate),
m_contentView(this, (TableView *)historyController->view(), this),
m_historyController(historyController),
m_calculationStore(calculationStore)
{
m_contentView.textField()->setParentResponder(this);
}
View * EditExpressionController::view() {
@@ -69,19 +68,6 @@ void EditExpressionController::setTextBody(const char * text) {
}
bool EditExpressionController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK) {
Calculation calculation = Calculation();
App * calculationApp = (App *)app();
calculation.setContent(textBody(), calculationApp->evaluateContext());
m_calculationStore->push(&calculation);
m_historyController->reload();
m_contentView.mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
m_contentView.textField()->setText("");
return true;
}
if (event == Ion::Events::Back) {
return true;
}
if (event == Ion::Events::Up) {
if (m_calculationStore->numberOfCalculations() > 0) {
app()->setFirstResponder(m_historyController);
@@ -95,9 +81,20 @@ void EditExpressionController::didBecomeFirstResponder() {
app()->setFirstResponder(m_contentView.textField());
}
void EditExpressionController::edit(const char * initialContent) {
setTextBody(initialContent);
app()->setFirstResponder(this);
bool EditExpressionController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) {
App * myApp = (App *)app();
return myApp->textFieldDidReceiveEvent(textField, event);
}
bool EditExpressionController::textFieldDidFinishEditing(::TextField * textField, const char * text) {
Calculation calculation = Calculation();
App * calculationApp = (App *)app();
calculation.setContent(textBody(), calculationApp->evaluateContext());
m_calculationStore->push(&calculation);
m_historyController->reload();
m_contentView.mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
m_contentView.textField()->setText("");
return true;
}
}

View File

@@ -9,20 +9,21 @@
namespace Calculation {
class HistoryController;
class EditExpressionController : public ViewController {
class EditExpressionController : public ViewController, public TextFieldDelegate {
public:
EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore, TextFieldDelegate * textFieldDelegate);
EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore);
View * view() override;
const char * title() const override;
void didBecomeFirstResponder() override;
bool handleEvent(Ion::Events::Event event) override;
void edit(const char * initialContent);
const char * textBody();
void setTextBody(const char * text);
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
bool textFieldDidFinishEditing(::TextField * textField, const char * text) override;
private:
class ContentView : public View {
public:
ContentView(TableView * subview, TextFieldDelegate * textFieldDelegate);
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate);
int numberOfSubviews() const override;
View * subviewAtIndex(int index) override;
void layoutSubviews() override;

View File

@@ -81,9 +81,9 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
int focusRow = m_selectableTableView.selectedRow();
HistoryViewCell * selectedCell = (HistoryViewCell *)m_selectableTableView.cellAtLocation(0, focusRow);
HistoryViewCell::SubviewType subviewType = selectedCell->selectedSubviewType();
m_selectableTableView.deselectTable();
EditExpressionController * editController = (EditExpressionController *)parentResponder();
m_calculationStore->deleteCalculationAtIndex(focusRow);
m_selectableTableView.deselectTable();
reload();
if (numberOfRows()== 0) {
app()->setFirstResponder(editController);

View File

@@ -3,12 +3,20 @@
namespace Calculation {
TextField::TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate) :
::TextField(parentResponder, textBuffer, textBufferSize, delegate)
::TextField(parentResponder, textBuffer, textBuffer, textBufferSize, delegate)
{
m_isEditing = true;
}
bool TextField::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::Back) {
return false;
}
if (event == Ion::Events::Ans) {
if (!isEditing()) {
setEditing(true);
setText("");
}
insertTextAtLocation("ans", cursorLocation());
setCursorLocation(cursorLocation() + strlen("ans"));
return true;
@@ -19,10 +27,18 @@ bool TextField::handleEvent(Ion::Events::Event event) {
event == Ion::Events::Minus ||
event == Ion::Events::Dot ||
event == Ion::Events::Division)) {
if (!isEditing()) {
setEditing(true);
setText("");
}
insertTextAtLocation("ans", cursorLocation());
setCursorLocation(cursorLocation() + strlen("ans"));
}
return(::TextField::handleEvent(event));
}
void TextField::setEditing(bool isEditing) {
m_isEditing = true;
}
}

View File

@@ -9,6 +9,7 @@ class TextField : public ::TextField {
public:
TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate);
bool handleEvent(Ion::Events::Event event) override;
void setEditing(bool isEditing) override;
};
}

View File

@@ -23,7 +23,7 @@ bool ExpressionTextFieldDelegate::cursorInToken(TextField * textField, const cha
}
bool ExpressionTextFieldDelegate::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
if (event == Ion::Events::OK) {
if (event == Ion::Events::OK && textField->isEditing()) {
Expression * exp = Expression::parse(textField->text());
if (exp == nullptr) {
if (textField->textLength() == 0) {
@@ -42,14 +42,14 @@ bool ExpressionTextFieldDelegate::textFieldDidReceiveEvent(TextField * textField
delete exp;
}
}
if (event == Ion::Events::Toolbox) {
if (event == Ion::Events::Toolbox && textField->isEditing()) {
AppsContainer * appsContainer = (AppsContainer *)textField->app()->container();
ToolboxController * toolboxController = appsContainer->toolboxController();
toolboxController->setTextFieldCaller(textField);
textField->app()->displayModalViewController(toolboxController, 0.f, 0.f, 50, 50, 0, 50);
return true;
}
if (event == Ion::Events::Var) {
if (event == Ion::Events::Var && textField->isEditing()) {
AppsContainer * appsContainer = (AppsContainer *)textField->app()->container();
VariableBoxController * variableBoxController = appsContainer->variableBoxController();
variableBoxController->setTextFieldCaller(textField);
@@ -57,6 +57,10 @@ bool ExpressionTextFieldDelegate::textFieldDidReceiveEvent(TextField * textField
return true;
}
if (event == Ion::Events::XNT) {
if (!textField->isEditing()) {
textField->setEditing(true);
textField->setText("");
}
if (cursorInToken(textField, "sum(") || cursorInToken(textField, "product(")) {
textField->insertTextAtLocation("n", textField->cursorLocation());
textField->setCursorLocation(textField->cursorLocation()+strlen("n"));

View File

@@ -6,7 +6,7 @@
FloatParameterController::FloatParameterController(Responder * parentResponder) :
ViewController(parentResponder),
m_selectableTableView(SelectableTableView(this, this, Metric::TopMargin, Metric::RightMargin,
Metric::BottomMargin, Metric::LeftMargin))
Metric::BottomMargin, Metric::LeftMargin, this))
{
}
@@ -24,52 +24,27 @@ int FloatParameterController::activeCell() {
}
void FloatParameterController::willDisplayCellForIndex(TableViewCell * cell, int index) {
TextMenuListCell * myCell = (TextMenuListCell *) cell;
EditableTextMenuListCell * myCell = (EditableTextMenuListCell *) cell;
char buffer[Constant::FloatBufferSizeInScientificMode];
Float(parameterAtIndex(index)).convertFloatToText(buffer, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaInScientificMode);
myCell->setAccessoryText(buffer);
}
bool FloatParameterController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK) {
editParameter();
return true;
}
if (event.hasText()) {
editParameter(event.text());
return true;
}
return false;
bool FloatParameterController::textFieldDidFinishEditing(TextField * textField, const char * text) {
AppsContainer * appsContainer = (AppsContainer *)app()->container();
Context * globalContext = appsContainer->context();
float floatBody = Expression::parse(text)->approximate(*globalContext);
setParameterAtIndex(m_selectableTableView.selectedRow(), floatBody);
willDisplayCellForIndex(m_selectableTableView.cellAtLocation(m_selectableTableView.selectedColumn(),
m_selectableTableView.selectedRow()), activeCell());
return true;
}
void FloatParameterController::editParameter(const char * initialText) {
/* This code assumes that the active cell remains the one which is edited
* until the invocation is performed. This could lead to concurrency issue in
* other cases. */
char initialTextContent[255];
int cursorDelta = 0;
if (initialText) {
strlcpy(initialTextContent, initialText, sizeof(initialTextContent));
cursorDelta = strlen(initialText) > 1 ? -1 : 0;
} else {
TextMenuListCell * textMenuListCell = (TextMenuListCell *)reusableCell(activeCell());
strlcpy(initialTextContent, textMenuListCell->accessoryText(), sizeof(initialTextContent));
}
int cursorLocation = strlen(initialTextContent) + cursorDelta;
EditableTextMenuListCell * cell = (EditableTextMenuListCell *)m_selectableTableView.cellAtLocation(0, activeCell());
cell->setParentResponder(&m_selectableTableView);
cell->editValue(textFieldDelegate(), initialTextContent, cursorLocation, this,
[](void * context, void * sender){
FloatParameterController * floatParameterController = (FloatParameterController *)context;
int activeCell = floatParameterController->activeCell();
EditableTextMenuListCell * cell = (EditableTextMenuListCell *)sender;
const char * textBody = cell->editedText();
AppsContainer * appsContainer = (AppsContainer *)floatParameterController->app()->container();
Context * globalContext = appsContainer->context();
float floatBody = Expression::parse(textBody)->approximate(*globalContext);
floatParameterController->setParameterAtIndex(activeCell, floatBody);
floatParameterController->willDisplayCellForIndex(cell, activeCell);
});
void FloatParameterController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) {
EditableTextMenuListCell * myCell = (EditableTextMenuListCell *)t->cellAtLocation(previousSelectedCellX, previousSelectedCellY);
myCell->setEditing(false);
EditableTextMenuListCell * myNewCell = (EditableTextMenuListCell *)t->cellAtLocation(t->selectedColumn(), t->selectedRow());
app()->setFirstResponder(myNewCell);
}
KDCoordinate FloatParameterController::cellHeight() {

View File

@@ -7,18 +7,18 @@
/* This controller edits float parameter of any model (given through
* parameterAtIndex and setParameterAtIndex). */
class FloatParameterController : public ViewController, public SimpleListViewDataSource {
class FloatParameterController : public ViewController, public SimpleListViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate {
public:
FloatParameterController(Responder * parentResponder);
int activeCell();
void editParameter(const char * initialText = nullptr);
virtual ExpressionTextFieldDelegate * textFieldDelegate() = 0;
View * view() override;
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;
KDCoordinate cellHeight() override;
void willDisplayCellForIndex(TableViewCell * cell, int index) override;
bool textFieldDidFinishEditing(TextField * textField, const char * text) override;
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) override;
protected:
int activeCell();
SelectableTableView m_selectableTableView;
private:
virtual float parameterAtIndex(int index) = 0;

View File

@@ -1,4 +1,5 @@
#include "goto_parameter_controller.h"
#include "../app.h"
#include <assert.h>
namespace Graph {
@@ -9,6 +10,8 @@ GoToParameterController::GoToParameterController(Responder * parentResponder, Gr
m_graphView(graphView),
m_function(nullptr)
{
m_abscisseCell.setParentResponder(&m_selectableTableView);
m_abscisseCell.setDelegate(this);
}
ExpressionTextFieldDelegate * GoToParameterController::textFieldDelegate() {
@@ -46,4 +49,10 @@ int GoToParameterController::reusableCellCount() {
void GoToParameterController::setFunction(Function * function) {
m_function = function;
}
bool GoToParameterController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
App * myApp = (App *)app();
return myApp->textFieldDidReceiveEvent(textField, event);
}
}

View File

@@ -15,6 +15,7 @@ public:
TableViewCell * reusableCell(int index) override;
int reusableCellCount() override;
void setFunction(Function * function);
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
private:
float parameterAtIndex(int index) override;
void setParameterAtIndex(int parameterIndex, float f) override;

View File

@@ -1,4 +1,6 @@
#include "window_parameter_controller.h"
#include "../app.h"
#include "../../apps_container.h"
#include <assert.h>
namespace Graph {
@@ -13,6 +15,10 @@ WindowParameterController::WindowParameterController(Responder * parentResponder
m_windowCells[1].setText("Xmax");
m_windowCells[2].setText("Ymin");
m_windowCells[3].setText("Ymax");
for (int k = 0; k < k_numberOfTextCell; k++) {
m_windowCells[k].setParentResponder(&m_selectableTableView);
m_windowCells[k].setDelegate(this);
}
}
ExpressionTextFieldDelegate * WindowParameterController::textFieldDelegate() {
@@ -40,6 +46,31 @@ void WindowParameterController::willDisplayCellForIndex(TableViewCell * cell, in
FloatParameterController::willDisplayCellForIndex(cell, index);
}
bool WindowParameterController::textFieldDidFinishEditing(TextField * textField, const char * text) {
AppsContainer * appsContainer = (AppsContainer *)app()->container();
Context * globalContext = appsContainer->context();
float floatBody = Expression::parse(text)->approximate(*globalContext);
setParameterAtIndex(m_selectableTableView.selectedRow(), floatBody);
willDisplayCellForIndex(m_selectableTableView.cellAtLocation(m_selectableTableView.selectedColumn(),
m_selectableTableView.selectedRow()), activeCell());
m_selectableTableView.reloadData();
return true;
}
void WindowParameterController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) {
if (previousSelectedCellX == 0 && previousSelectedCellY >= 0 && previousSelectedCellY !=2) {
EditableTextMenuListCell * myCell = (EditableTextMenuListCell *)t->cellAtLocation(previousSelectedCellX, previousSelectedCellY);
myCell->setEditing(false);
app()->setFirstResponder(t);
}
if (t->selectedColumn() == 0 && t->selectedRow() >= 0 && t->selectedRow() !=2) {
EditableTextMenuListCell * myNewCell = (EditableTextMenuListCell *)t->cellAtLocation(t->selectedColumn(), t->selectedRow());
if ((t->selectedRow() == 0 || t->selectedRow() == 1) || !m_graphWindow->yAuto()) {
app()->setFirstResponder(myNewCell);
}
}
}
bool WindowParameterController::handleEvent(Ion::Events::Event event) {
m_graphView->initCursorPosition();
if (activeCell() == 2) {
@@ -53,7 +84,7 @@ bool WindowParameterController::handleEvent(Ion::Events::Event event) {
if (m_graphWindow->yAuto() && (activeCell() == 3 || activeCell() == 4)) {
return false;
}
return FloatParameterController::handleEvent(event);
return false;
}
float WindowParameterController::parameterAtIndex(int index) {
@@ -109,4 +140,9 @@ int WindowParameterController::reusableCellCount() {
return k_numberOfTextCell+1;
}
bool WindowParameterController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
App * myApp = (App *)app();
return myApp->textFieldDidReceiveEvent(textField, event);
}
}

View File

@@ -16,7 +16,10 @@ public:
TableViewCell * reusableCell(int index) override;
int reusableCellCount() override;
void willDisplayCellForIndex(TableViewCell * cell, int index) override;
bool textFieldDidFinishEditing(TextField * textField, const char * text) override;
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) override;
bool handleEvent(Ion::Events::Event event) override;
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
private:
float parameterAtIndex(int index) override;
void setParameterAtIndex(int parameterIndex, float f) override;

View File

@@ -119,19 +119,10 @@ void ListController::configureFunction(Function * function) {
stack->push(&m_parameterController);
}
void ListController::editExpression(FunctionExpressionView * functionCell, const char * initialText) {
char initialTextContent[255];
int cursorDelta = 0;
if (initialText) {
strlcpy(initialTextContent, initialText, sizeof(initialTextContent));
cursorDelta = strlen(initialText) > 1 ? -1 : 0;
} else {
strlcpy(initialTextContent, functionCell->function()->text(), sizeof(initialTextContent));
}
int cursorLocation = strlen(initialTextContent) + cursorDelta;
void ListController::editExpression(FunctionExpressionView * functionCell, Ion::Events::Event event) {
App * myApp = (App *)app();
InputViewController * inputController = myApp->inputViewController();
inputController->edit(this, initialTextContent, cursorLocation, functionCell,
inputController->edit(this, event, functionCell,
[](void * context, void * sender){
FunctionExpressionView * myCell = (FunctionExpressionView *) context;
Function * myFunction = myCell->function();
@@ -154,15 +145,11 @@ bool ListController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK) {
return handleEnter();
}
if (event == Ion::Events::XNT && m_selectableTableView.selectedColumn() == 1){
FunctionExpressionView * functionCell = (FunctionExpressionView *)(m_selectableTableView.cellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow()));
editExpression(functionCell, "x");
}
if (!event.hasText() || m_selectableTableView.selectedColumn() == 0) {
if ((!event.hasText() && event != Ion::Events::XNT) || m_selectableTableView.selectedColumn() == 0) {
return false;
}
FunctionExpressionView * functionCell = (FunctionExpressionView *)(m_selectableTableView.cellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow()));
editExpression(functionCell, event.text());
editExpression(functionCell, event);
return true;
}
@@ -188,7 +175,7 @@ bool ListController::handleEnter() {
return false;
}
FunctionExpressionView * functionCell = (FunctionExpressionView *)(m_selectableTableView.cellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow()));
editExpression(functionCell);
editExpression(functionCell, Ion::Events::OK);
return true;
}
default:

View File

@@ -32,7 +32,7 @@ public:
int reusableCellCount(int type) override;
int typeAtLocation(int i, int j) override;
void configureFunction(Function * function);
void editExpression(FunctionExpressionView * functionCell, const char * initialText = nullptr);
void editExpression(FunctionExpressionView * functionCell, Ion::Events::Event event);
private:
static constexpr KDCoordinate k_verticalFunctionMargin = 50-12;

View File

@@ -1,57 +1,53 @@
#include "editable_value_cell.h"
#include "../../apps_container.h"
#include <assert.h>
#include "../app.h"
namespace Graph {
EditableValueCell::EditableValueCell() :
ValueCell(),
EvenOddCell(),
Responder(nullptr),
m_textField(TextField(this, m_textBody, 255, nullptr)),
m_isEditing(false),
m_successAction(Invocation(nullptr, nullptr))
m_textField(TextField(this, m_textBody, m_draftTextBody, 255, nullptr, 1.0f, 0.5f, KDColorBlack, KDColorWhite))
{
}
const char * EditableValueCell::editedText() const {
void EditableValueCell::setDelegate(TextFieldDelegate * delegate) {
m_textField.setTextFieldDelegate(delegate);
}
void EditableValueCell::reloadCell() {
EvenOddCell::reloadCell();
m_textField.setBackgroundColor(backgroundColor());
}
const char * EditableValueCell::text() const {
return m_textField.text();
}
void EditableValueCell::setText(const char * textContent) {
m_textField.setText(textContent);
}
int EditableValueCell::numberOfSubviews() const {
return 1;
}
View * EditableValueCell::subviewAtIndex(int index) {
assert(index == 0);
if (m_isEditing) {
return &m_textField;
}
return &m_bufferTextView;
return &m_textField;
}
void EditableValueCell::layoutSubviews() {
m_bufferTextView.setFrame(bounds());
m_textField.setFrame(bounds());
}
bool EditableValueCell::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK) {
m_isEditing = false;
m_successAction.perform(this);
app()->setFirstResponder(parentResponder());
return true;
}
m_isEditing = false;
app()->setFirstResponder(parentResponder());
return false;
}
void EditableValueCell::editValue(const char * initialText, int cursorPosition, void * context, Invocation::Action successAction) {
markRectAsDirty(bounds());
App * myApp = (App *)app();
m_textField.setTextFieldDelegate(myApp);
void EditableValueCell::didBecomeFirstResponder() {
app()->setFirstResponder(&m_textField);
m_isEditing = true;
m_textField.setText(initialText);
m_textField.setCursorLocation(cursorPosition);
m_successAction = Invocation(successAction, context);
}
void EditableValueCell::setEditing(bool isEditing) {
m_textField.setEditing(isEditing);
}
}

View File

@@ -3,22 +3,24 @@
#include <escher.h>
#include <poincare.h>
#include "value_cell.h"
namespace Graph {
class EditableValueCell : public ValueCell, public Responder {
class EditableValueCell : public EvenOddCell, public Responder {
public:
EditableValueCell();
const char * editedText() const;
void setDelegate(TextFieldDelegate * delegate);
void reloadCell() override;
const char * text() const;
void setText(const char * textContent);
int numberOfSubviews() const override;
View * subviewAtIndex(int index) override;
void layoutSubviews() override;
bool handleEvent(Ion::Events::Event event) override;
void editValue(const char * initialText, int cursorLocation, void * context, Invocation::Action successAction);
void didBecomeFirstResponder() override;
void setEditing(bool isEditing);
private:
TextField m_textField;
char m_textBody[255];
bool m_isEditing;
Invocation m_successAction;
char m_draftTextBody[255];
};
}

View File

@@ -1,4 +1,5 @@
#include "interval_parameter_controller.h"
#include "../app.h"
#include <assert.h>
namespace Graph {
@@ -6,9 +7,9 @@ namespace Graph {
IntervalParameterController::IntervalParameterController(Responder * parentResponder, Interval * interval) :
FloatParameterController(parentResponder),
m_interval(interval),
m_intervalStartCell(EditableTextMenuListCell((char*)"X Debut")),
m_intervalEndCell(EditableTextMenuListCell((char*)"X Fin")),
m_intervalStepCell(EditableTextMenuListCell((char*)"Pas"))
m_intervalStartCell(EditableTextMenuListCell((char*)"X Debut", &m_selectableTableView, this)),
m_intervalEndCell(EditableTextMenuListCell((char*)"X Fin", &m_selectableTableView, this)),
m_intervalStepCell(EditableTextMenuListCell((char*)"Pas", &m_selectableTableView, this))
{
}
@@ -70,4 +71,9 @@ int IntervalParameterController::reusableCellCount() {
return k_totalNumberOfCell;
}
bool IntervalParameterController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
App * myApp = (App *)app();
return myApp->textFieldDidReceiveEvent(textField, event);
}
}

View File

@@ -16,6 +16,7 @@ public:
int numberOfRows() override;
TableViewCell * reusableCell(int index) override;
int reusableCellCount() override;
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
private:
float parameterAtIndex(int index) override;
void setParameterAtIndex(int parameterIndex, float f) override;

View File

@@ -9,7 +9,7 @@ namespace Graph {
ValuesController::ValuesController(Responder * parentResponder, FunctionStore * functionStore, HeaderViewController * header) :
ViewController(parentResponder),
HeaderViewDelegate(header),
m_selectableTableView(SelectableTableView(this, this, k_topMargin, k_rightMargin, k_bottomMargin, k_leftMargin)),
m_selectableTableView(SelectableTableView(this, this, k_topMargin, k_rightMargin, k_bottomMargin, k_leftMargin, this)),
m_functionStore(functionStore),
m_intervalParameterController(IntervalParameterController(this, &m_interval)),
m_abscissaParameterController(AbscissaParameterController(this, &m_intervalParameterController)),
@@ -24,6 +24,10 @@ ValuesController::ValuesController(Responder * parentResponder, FunctionStore *
m_interval.setStart(0);
m_interval.setEnd(10);
m_interval.setStep(1);
for (int k = 0; k < k_maxNumberOfAbscissaCells; k++) {
m_abscissaCells[k].setParentResponder(&m_selectableTableView);
m_abscissaCells[k].setDelegate(this);
}
}
View * ValuesController::view() {
@@ -195,26 +199,29 @@ bool ValuesController::handleEvent(Ion::Events::Event event) {
}
return true;
}
if (activeColumn() == 0) {
editValue();
return true;
}
return false;
}
if (activeRow() == -1) {
return headerViewController()->handleEvent(event);
}
if (event.hasText()) {
if (activeColumn() == 0 && activeRow() > 0) {
editValue(event.text());
return true;
}
return false;
}
return false;
}
bool ValuesController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
App * myApp = (App *)app();
return myApp->textFieldDidReceiveEvent(textField, event);
}
bool ValuesController::textFieldDidFinishEditing(TextField * textField, const char * text) {
AppsContainer * appsContainer = (AppsContainer *)app()->container();
Context * globalContext = appsContainer->context();
float floatBody = Expression::parse(text)->approximate(*globalContext);
m_interval.setElement(activeRow()-1, floatBody);
willDisplayCellAtLocation(m_selectableTableView.cellAtLocation(activeColumn(), activeRow()), activeColumn(), activeRow());
m_selectableTableView.reloadData();
return true;
}
void ValuesController::configureAbscissa() {
StackViewController * stack = stackController();
@@ -235,38 +242,16 @@ void ValuesController::configureDerivativeFunction() {
stack->push(&m_derivativeParameterController);
}
void ValuesController::editValue(const char * initialText) {
/* This code assumes that the active cell remains the one which is edited
* until the invocation is performed. This could lead to concurrency issue in
* other cases. */
char initialTextContent[255];
int cursorDelta = 0;
if (initialText) {
strlcpy(initialTextContent, initialText, sizeof(initialTextContent));
cursorDelta = strlen(initialText) > 1 ? -1 : 0;
} else {
if (activeRow() > m_interval.numberOfElements()) {
initialTextContent[0] = 0;
} else {
Float(m_interval.element(activeRow()-1)).convertFloatToText(initialTextContent, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaInScientificMode);
}
void ValuesController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) {
if (previousSelectedCellX == 0 && previousSelectedCellY > 0) {
EditableValueCell * myCell = (EditableValueCell *)t->cellAtLocation(previousSelectedCellX, previousSelectedCellY);
myCell->setEditing(false);
app()->setFirstResponder(t);
}
if (t->selectedRow() > 0 && t->selectedColumn() == 0) {
EditableValueCell * myCell = (EditableValueCell *)t->cellAtLocation(t->selectedColumn(), t->selectedRow());
app()->setFirstResponder(myCell);
}
int cursorLocation = strlen(initialTextContent) + cursorDelta;
EditableValueCell * cell = (EditableValueCell *)m_selectableTableView.cellAtLocation(0, activeRow());
cell->setParentResponder(&m_selectableTableView);
cell->editValue(initialTextContent, cursorLocation, this,
[](void * context, void * sender){
ValuesController * valuesController = (ValuesController *)context;
int activeRow = valuesController->activeRow();
int activeColumn = valuesController->activeColumn();
EditableValueCell * cell = (EditableValueCell *)sender;
const char * textBody = cell->editedText();
AppsContainer * appsContainer = (AppsContainer *)valuesController->app()->container();
Context * globalContext = appsContainer->context();
float floatBody = Expression::parse(textBody)->approximate(*globalContext);
valuesController->interval()->setElement(activeRow-1, floatBody);
valuesController->willDisplayCellAtLocation(cell, activeColumn, activeRow);
});
}
int ValuesController::typeAtLocation(int i, int j) {

View File

@@ -15,19 +15,17 @@
namespace Graph {
class ValuesController : public ViewController, public HeaderViewDelegate, public TableViewDataSource, public AlternateEmptyViewDelegate {
class ValuesController : public ViewController, public HeaderViewDelegate, public TableViewDataSource, public AlternateEmptyViewDelegate, public SelectableTableViewDelegate, public TextFieldDelegate {
public:
ValuesController(Responder * parentResponder, FunctionStore * functionStore, HeaderViewController * header);
int activeRow();
int activeColumn();
Interval * interval();
void editValue(const char * initialText = nullptr);
View * view() override;
const char * title() const override;
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
bool textFieldDidFinishEditing(TextField * textField, const char * text) override;
ViewController * intervalParameterController();
int numberOfButtons() const override;
Button * buttonAtIndex(int index) override;
@@ -48,6 +46,8 @@ public:
bool isEmpty() override;
const char * emptyMessage() override;
Responder * defaultController() override;
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) override;
static constexpr KDCoordinate k_topMargin = 10;
static constexpr KDCoordinate k_bottomMargin = 5;
@@ -58,6 +58,8 @@ public:
static constexpr KDCoordinate k_ordinateCellWidth = 100;
private:
int activeRow();
int activeColumn();
Function * functionAtColumn(int i);
bool isDerivativeColumn(int i);
Responder * tabController() const;

View File

@@ -12,6 +12,8 @@ CalculationController::ContentView::ContentView(Responder * parentResponder, Law
{
for (int k = 0; k < k_maxNumberOfEditableFields; k++) {
m_calculationCell[k].setParentResponder(parentResponder);
CalculationController * parentController = (CalculationController *)parentResponder;
m_calculationCell[k].setDelegate(parentController);
}
}
@@ -58,14 +60,17 @@ View * CalculationController::ContentView::subviewAtIndex(int index) {
return &m_text[2];
}
if (index == 3 || index == 5 || index == 7) {
char buffer[Constant::FloatBufferSizeInScientificMode];
Float(m_law->calculationElementAtIndex((index - 3)/2)).convertFloatToText(buffer, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaInScientificMode);
m_calculationCell[(index - 3)/2].setText(buffer);
return &m_calculationCell[(index - 3)/2];
}
return nullptr;
}
void CalculationController::ContentView::willDisplayEditableCellAtIndex(int index) {
char buffer[Constant::FloatBufferSizeInScientificMode];
Float(m_law->calculationElementAtIndex(index)).convertFloatToText(buffer, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaInScientificMode);
m_calculationCell[index].setText(buffer);
}
void CalculationController::ContentView::layoutSubviews() {
markRectAsDirty(bounds());
KDCoordinate xCoordinate = 0;
@@ -97,6 +102,10 @@ void CalculationController::ContentView::layoutSubviews() {
m_text[2].setFrame(KDRect(xCoordinate, 0, numberOfCharacters*k_charWidth, ImageTableView::k_imageHeight));
xCoordinate += numberOfCharacters*k_charWidth + k_textMargin;
m_calculationCell[2].setFrame(KDRect(xCoordinate, 0, k_textFieldWidth, ImageTableView::k_imageHeight));
for (int k = 0; k < k_maxNumberOfEditableFields; k++) {
willDisplayEditableCellAtIndex(k);
}
}
@@ -133,37 +142,12 @@ const char * CalculationController::title() const {
}
bool CalculationController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK && m_highlightedSubviewIndex == 0) {
m_contentView.imageTableView()->select(true);
app()->setFirstResponder(m_contentView.imageTableView());
return true;
}
if ((event == Ion::Events::OK || event.hasText()) && m_highlightedSubviewIndex > 0) {
App * myApp = (App *)app();
EditableTextCell * calculCell = m_contentView.calculationCellAtIndex(m_highlightedSubviewIndex-1);
const char * initialText = calculCell->text();
if (event.hasText()) {
initialText = event.text();
}
calculCell->editValue(myApp, initialText, strlen(calculCell->text()), this,
[](void * context, void * sender){
CalculationController * calculationController = (CalculationController *)context;
Law * law = calculationController->law();
int highlightedSubviewIndex = calculationController->highlightedSubviewIndex();
EditableTextCell * cell = (EditableTextCell *)sender;
const char * textBody = cell->editedText();
AppsContainer * appsContainer = (AppsContainer *)calculationController->app()->container();
Context * globalContext = appsContainer->context();
float floatBody = Expression::parse(textBody)->approximate(*globalContext);
law->setCalculationElementAtIndex(floatBody, highlightedSubviewIndex-1);
});
return true;
}
if ((event == Ion::Events::Left && m_highlightedSubviewIndex > 0) || (event == Ion::Events::Right && m_highlightedSubviewIndex < ContentView::k_maxNumberOfEditableFields - 1)) {
if (m_highlightedSubviewIndex == 0) {
app()->setFirstResponder(this);
m_contentView.imageTableView()->select(false);
m_contentView.imageTableView()->setHighlight(false);
m_contentView.layoutSubviews();
} else {
EditableTextCell * calculCell = m_contentView.calculationCellAtIndex(m_highlightedSubviewIndex-1);
calculCell->setHighlighted(false);
@@ -172,14 +156,38 @@ bool CalculationController::handleEvent(Ion::Events::Event event) {
if (m_highlightedSubviewIndex > 0) {
EditableTextCell * newCalculCell = m_contentView.calculationCellAtIndex(m_highlightedSubviewIndex-1);
newCalculCell->setHighlighted(true);
app()->setFirstResponder(newCalculCell);
} else {
m_contentView.imageTableView()->setHighlight(true);
app()->setFirstResponder(this);
}
return true;
}
if (event == Ion::Events::OK && m_highlightedSubviewIndex == 0) {
m_contentView.imageTableView()->select(true);
app()->setFirstResponder(m_contentView.imageTableView());
return true;
}
return false;
}
bool CalculationController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
App * myApp = (App *)app();
return myApp->textFieldDidReceiveEvent(textField, event);
}
bool CalculationController::textFieldDidFinishEditing(TextField * textField, const char * text) {
AppsContainer * appsContainer = (AppsContainer *)app()->container();
Context * globalContext = appsContainer->context();
float floatBody = Expression::parse(text)->approximate(*globalContext);
m_law->setCalculationElementAtIndex(floatBody, m_highlightedSubviewIndex-1);
for (int k = 0; k < ContentView::k_maxNumberOfEditableFields; k++) {
m_contentView.willDisplayEditableCellAtIndex(k);
}
return true;
}
void CalculationController::didBecomeFirstResponder() {
m_contentView.layoutSubviews();
for (int subviewIndex = 0; subviewIndex < 2; subviewIndex++) {
@@ -190,6 +198,7 @@ void CalculationController::didBecomeFirstResponder() {
m_contentView.imageTableView()->setHighlight(false);
EditableTextCell * calculCell = m_contentView.calculationCellAtIndex(m_highlightedSubviewIndex-1);
calculCell->setHighlighted(true);
app()->setFirstResponder(calculCell);
} else {
m_contentView.imageTableView()->setHighlight(true);
}
@@ -200,10 +209,6 @@ Law * CalculationController::law() {
return m_law;
}
int CalculationController::highlightedSubviewIndex() const {
return m_highlightedSubviewIndex;
}
void CalculationController::selectSubview(int subviewIndex) {
m_highlightedSubviewIndex = subviewIndex;
}

View File

@@ -8,7 +8,7 @@
namespace Probability {
class CalculationController : public ViewController {
class CalculationController : public ViewController, public TextFieldDelegate {
public:
CalculationController(Responder * parentResponder, Law * law);
View * view() override;
@@ -16,8 +16,9 @@ public:
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;
Law * law();
int highlightedSubviewIndex() const;
void selectSubview(int subviewIndex);
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
bool textFieldDidFinishEditing(TextField * textField, const char * text) override;
private:
class ContentView : public View {
public:
@@ -27,6 +28,7 @@ private:
LawCurveView * lawCurveView();
ImageTableView * imageTableView();
EditableTextCell * calculationCellAtIndex(int index);
void willDisplayEditableCellAtIndex(int index);
constexpr static int k_maxNumberOfEditableFields = 3;
private:
constexpr static KDCoordinate k_textFieldWidth = 35;

View File

@@ -1,5 +1,6 @@
#include "parameters_controller.h"
#include "../constant.h"
#include "app.h"
#include <assert.h>
#include <string.h>
@@ -74,6 +75,10 @@ ParametersController::ParametersController(Responder * parentResponder, Law * la
m_buttonSelected(false),
m_calculationController(CalculationController(nullptr, law))
{
for (int k = 0; k < k_maxNumberOfCells; k++) {
m_menuListCell[k].setParentResponder(&m_selectableTableView);
m_menuListCell[k].setDelegate(this);
}
}
ExpressionTextFieldDelegate * ParametersController::textFieldDelegate() {
@@ -150,7 +155,7 @@ int ParametersController::numberOfRows() {
};
void ParametersController::willDisplayCellForIndex(TableViewCell * cell, int index) {
TextMenuListCell * myCell = (TextMenuListCell *) cell;
EditableTextMenuListCell * myCell = (EditableTextMenuListCell *) cell;
myCell->setText(m_law->parameterNameAtIndex(index));
FloatParameterController::willDisplayCellForIndex(cell, index);
}
@@ -173,5 +178,10 @@ void ParametersController::setParameterAtIndex(int parameterIndex, float f) {
m_law->setParameterAtIndex(f, parameterIndex);
}
bool ParametersController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
App * myApp = (App *)app();
return myApp->textFieldDidReceiveEvent(textField, event);
}
}

View File

@@ -22,6 +22,7 @@ public:
void willDisplayCellForIndex(TableViewCell * cell, int index) override;
TableViewCell * reusableCell(int index) override;
int reusableCellCount() override;
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
private:
float parameterAtIndex(int index) override;
void setParameterAtIndex(int parameterIndex, float f) override;
@@ -43,7 +44,8 @@ private:
PointerTextView m_secondParameterDefinition;
SelectableTableView * m_selectableTableView;
};
EditableTextMenuListCell m_menuListCell[2];
constexpr static int k_maxNumberOfCells = 2;
EditableTextMenuListCell m_menuListCell[k_maxNumberOfCells];
ContentView m_contentView;
Law * m_law;
bool m_buttonSelected;

View File

@@ -1,8 +1,6 @@
#ifndef ESCHER_EDITABLE_TEXT_CELL_H
#define ESCHER_EDITABLE_TEXT_CELL_H
#include <escher/buffer_text_view.h>
#include <escher/invocation.h>
#include <escher/responder.h>
#include <escher/table_view_cell.h>
#include <escher/text_field_delegate.h>
@@ -10,25 +8,22 @@
class EditableTextCell : public TableViewCell, public Responder {
public:
EditableTextCell(Responder * parentResponder = nullptr);
EditableTextCell(Responder * parentResponder = nullptr, TextFieldDelegate * delegate = nullptr);
void setDelegate(TextFieldDelegate * delegate);
void reloadCell() override;
const char * editedText() const;
const char * text() const;
void setText(const char * textContent);
int numberOfSubviews() const override;
View * subviewAtIndex(int index) override;
void layoutSubviews() override;
void drawRect(KDContext * ctx, KDRect rect) const override;
void editValue(TextFieldDelegate * textFieldDelegate, const char * initialText, int cursorLocation, void * context, Invocation::Action successAction);
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;
void setEditing(bool isEditing);
private:
constexpr static KDCoordinate k_textHeight = 12;
constexpr static KDCoordinate k_separatorThickness = 1;
TextField m_textField;
char m_textBody[255];
bool m_isEditing;
Invocation m_successAction;
BufferTextView m_bufferText;
char m_draftTextBody[255];
};
#endif

View File

@@ -1,26 +1,28 @@
#ifndef ESCHER_EDITABLE_TEXT_MENU_LIST_CELL_H
#define ESCHER_EDITABLE_TEXT_MENU_LIST_CELL_H
#include <escher/text_menu_list_cell.h>
#include <escher/text_field.h>
#include <escher/invocation.h>
#include <escher/editable_text_cell.h>
#include <escher/menu_list_cell.h>
#include <escher/responder.h>
class EditableTextMenuListCell : public Responder, public TextMenuListCell {
class EditableTextMenuListCell : public Responder, public MenuListCell {
public:
EditableTextMenuListCell(char * label = nullptr);
EditableTextMenuListCell(char * label = nullptr, Responder * parentResponder = nullptr, TextFieldDelegate * textFieldDelegate = nullptr);
void setDelegate(TextFieldDelegate * delegate);
View * accessoryView() const override;
const char * editedText() const;
void layoutSubviews() override;
bool handleEvent(Ion::Events::Event event) override;
void editValue(TextFieldDelegate * textFieldDelegate, const char * initialText, int cursorLocation, void * context, Invocation::Action successAction);
void didBecomeFirstResponder() override;
void setEditing(bool isEditing);
void reloadCell() override;
void setAccessoryText(const char * text);
void setTextColor(KDColor color) override;
private:
constexpr static KDCoordinate k_textWidth = 7*7;
constexpr static KDCoordinate k_textHeight = 12;
TextField m_textField;
char m_textBody[255];
bool m_isEditing;
Invocation m_successAction;
char m_draftTextBody[255];
};
#endif

View File

@@ -6,13 +6,15 @@
#include <escher/text_field.h>
#include <escher/text_field_delegate.h>
class InputViewController : public ModalViewController {
class InputViewController : public ModalViewController, TextFieldDelegate {
public:
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate = nullptr);
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate);
const char * title() const override;
bool handleEvent(Ion::Events::Event event) override;
void edit(Responder * caller, const char * initialContent, int cursorPosition, void * context, Invocation::Action successAction, Invocation::Action failureAction);
void edit(Responder * caller, Ion::Events::Event event, void * context, Invocation::Action successAction, Invocation::Action failureAction);
const char * textBody();
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
bool textFieldDidFinishEditing(TextField * textField, const char * text) override;
bool textFieldDidAbortEditing(TextField * textField, const char * text) override;
private:
class TextFieldController : public ViewController {
public:
@@ -24,11 +26,10 @@ private:
TextField m_textField;
char m_textBody[255];
};
void showInput();
void setTextBody(const char * text);
TextFieldController m_textFieldController;
Invocation m_successAction;
Invocation m_failureAction;
TextFieldDelegate * m_textFieldDelegate;
};
#endif

View File

@@ -8,7 +8,8 @@
class TextField : public View, public Responder {
public:
TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate = nullptr);
TextField(Responder * parentResponder, char * textBuffer, char * draftTextBuffer, size_t textBufferSize, TextFieldDelegate * delegate = nullptr,
float horizontalAlignment = 0.0f, float verticalAlignment = 0.5f, KDColor textColor = KDColorBlack, KDColor = KDColorWhite);
// View
void drawRect(KDContext * ctx, KDRect rect) const override;
// Responder
@@ -24,17 +25,28 @@ public:
void setCursorLocation(int location);
void insertTextAtLocation(const char * text, int location);
KDSize minimalSizeForOptimalDisplay() override;
protected:
void setBackgroundColor(KDColor backgroundColor);
void setTextColor(KDColor textColor);
void setAlignment(float horizontalAlignment, float verticalAlignment);
void reload();
bool isEditing() const;
virtual void setEditing(bool isEditing);
protected:
#if ESCHER_VIEW_LOGGING
const char * className() const override;
#endif
bool m_isEditing;
char * m_textBuffer;
char * m_draftTextBuffer;
size_t m_currentTextLength;
size_t m_currentCursorLocation;
private:
size_t m_textBufferSize;
TextFieldDelegate * m_delegate;
float m_horizontalAlignment;
float m_verticalAlignment;
KDColor m_textColor;
KDColor m_backgroundColor;
};
#endif

View File

@@ -6,6 +6,8 @@ class TextField;
class TextFieldDelegate {
public:
virtual bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) = 0;
virtual bool textFieldDidFinishEditing(TextField * textField, const char * text) {return false;};
virtual bool textFieldDidAbortEditing(TextField * textField, const char * text) {return false;};
};
#endif

View File

@@ -3,32 +3,29 @@
#include <escher/palette.h>
#include <assert.h>
EditableTextCell::EditableTextCell(Responder * parentResponder) :
EditableTextCell::EditableTextCell(Responder * parentResponder, TextFieldDelegate * delegate) :
TableViewCell(),
Responder(parentResponder),
m_textField(TextField(this, m_textBody, 255, nullptr)),
m_isEditing(false),
m_successAction(Invocation(nullptr, nullptr)),
m_bufferText(BufferTextView())
m_textField(TextField(this, m_textBody, m_draftTextBody, 255, delegate))
{
}
void EditableTextCell::setDelegate(TextFieldDelegate * delegate) {
m_textField.setTextFieldDelegate(delegate);
}
void EditableTextCell::reloadCell() {
TableViewCell::reloadCell();
KDColor backgroundColor = isHighlighted()? Palette::FocusCellBackgroundColor : Palette::CellBackgroundColor;
m_bufferText.setBackgroundColor(backgroundColor);
}
const char * EditableTextCell::editedText() const {
return m_textField.text();
m_textField.setBackgroundColor(backgroundColor);
}
const char * EditableTextCell::text() const {
return m_bufferText.text();
return m_textField.text();
}
void EditableTextCell::setText(const char * text) {
m_bufferText.setText(text);
m_textField.setText(text);
}
int EditableTextCell::numberOfSubviews() const {
@@ -37,42 +34,20 @@ int EditableTextCell::numberOfSubviews() const {
View * EditableTextCell::subviewAtIndex(int index) {
assert(index == 0);
if (m_isEditing) {
return &m_textField;
}
return &m_bufferText;
return &m_textField;
}
void EditableTextCell::layoutSubviews() {
KDCoordinate width = bounds().width();
KDCoordinate height = bounds().height();
m_textField.setFrame(KDRect(k_separatorThickness, (height - k_textHeight)/2, width - k_separatorThickness, k_textHeight));
m_bufferText.setFrame(KDRect(k_separatorThickness, (height - k_textHeight)/2, width - k_separatorThickness, k_textHeight));
}
void EditableTextCell::drawRect(KDContext * ctx, KDRect rect) const {
KDColor backgroundColor = isHighlighted() ? Palette::FocusCellBackgroundColor : Palette::CellBackgroundColor;
ctx->fillRect(rect, backgroundColor);
}
bool EditableTextCell::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK) {
m_isEditing = false;
m_successAction.perform(this);
app()->setFirstResponder(parentResponder());
return true;
}
m_isEditing = false;
app()->setFirstResponder(parentResponder());
return false;
}
void EditableTextCell::editValue(TextFieldDelegate * textFieldDelegate, const char * initialText, int cursorPosition, void * context, Invocation::Action successAction) {
markRectAsDirty(bounds());
m_textField.setTextFieldDelegate(textFieldDelegate);
void EditableTextCell::didBecomeFirstResponder() {
app()->setFirstResponder(&m_textField);
m_isEditing = true;
m_textField.setText(initialText);
m_textField.setCursorLocation(cursorPosition);
m_successAction = Invocation(successAction, context);
}
void EditableTextCell::setEditing(bool isEditing) {
m_textField.setEditing(isEditing);
}

View File

@@ -1,20 +1,19 @@
#include <escher/editable_text_menu_list_cell.h>
#include <escher/app.h>
EditableTextMenuListCell::EditableTextMenuListCell(char * label) :
Responder(nullptr),
TextMenuListCell(label),
m_textField(TextField(this, m_textBody, 255, nullptr)),
m_isEditing(false),
m_successAction(Invocation(nullptr, nullptr))
EditableTextMenuListCell::EditableTextMenuListCell(char * label, Responder * parentResponder, TextFieldDelegate * textFieldDelegate) :
Responder(parentResponder),
MenuListCell(label),
m_textField(TextField(this, m_textBody, m_draftTextBody, 255, textFieldDelegate))
{
}
void EditableTextMenuListCell::setDelegate(TextFieldDelegate * delegate) {
m_textField.setTextFieldDelegate(delegate);
}
View * EditableTextMenuListCell::accessoryView() const {
if (m_isEditing) {
return (View *)&m_textField;
}
return (View *)&m_accessoryView;
return (View *)&m_textField;
}
const char * EditableTextMenuListCell::editedText() const {
@@ -22,32 +21,31 @@ const char * EditableTextMenuListCell::editedText() const {
}
void EditableTextMenuListCell::layoutSubviews() {
TextMenuListCell::layoutSubviews();
MenuListCell::layoutSubviews();
KDCoordinate width = bounds().width();
KDCoordinate height = bounds().height();
m_textField.setFrame(KDRect(width - k_textWidth - k_separatorThickness, (height - k_textHeight)/2, k_textWidth - k_separatorThickness, k_textHeight));
m_accessoryView.setFrame(KDRect(width - k_textWidth - k_separatorThickness, (height - k_textHeight)/2, k_textWidth - k_separatorThickness, k_textHeight));
}
bool EditableTextMenuListCell::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK) {
m_isEditing = false;
m_successAction.perform(this);
app()->setFirstResponder(parentResponder());
return true;
}
m_isEditing = false;
app()->setFirstResponder(parentResponder());
return false;
}
void EditableTextMenuListCell::editValue(TextFieldDelegate * textFieldDelegate, const char * initialText, int cursorPosition, void * context, Invocation::Action successAction) {
markRectAsDirty(bounds());
m_textField.setTextFieldDelegate(textFieldDelegate);
void EditableTextMenuListCell::didBecomeFirstResponder() {
app()->setFirstResponder(&m_textField);
m_isEditing = true;
m_textField.setText(initialText);
m_textField.setCursorLocation(cursorPosition);
m_successAction = Invocation(successAction, context);
}
}
void EditableTextMenuListCell::setEditing(bool isEditing) {
m_textField.setEditing(isEditing);
}
void EditableTextMenuListCell::reloadCell() {
MenuListCell::reloadCell();
KDColor backgroundColor = isHighlighted()? Palette::FocusCellBackgroundColor : Palette::CellBackgroundColor;
m_textField.setBackgroundColor(backgroundColor);
}
void EditableTextMenuListCell::setAccessoryText(const char * text) {
m_textField.setText(text);
}
void EditableTextMenuListCell::setTextColor(KDColor color) {
m_textField.setTextColor(color);
MenuListCell::setTextColor(color);
}

View File

@@ -4,7 +4,7 @@
InputViewController::TextFieldController::TextFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate) :
ViewController(parentResponder),
m_textField(parentResponder, m_textBody, 255, textFieldDelegate)
m_textField(parentResponder, m_textBody, m_textBody, 255, textFieldDelegate)
{
m_textBody[0] = 0;
}
@@ -23,9 +23,10 @@ TextField * InputViewController::TextFieldController::textField() {
InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate) :
ModalViewController(parentResponder, child),
m_textFieldController(TextFieldController(this, textFieldDelegate)),
m_textFieldController(TextFieldController(this, this)),
m_successAction(Invocation(nullptr, nullptr)),
m_failureAction(Invocation(nullptr, nullptr))
m_failureAction(Invocation(nullptr, nullptr)),
m_textFieldDelegate(textFieldDelegate)
{
}
@@ -37,35 +38,27 @@ const char * InputViewController::textBody() {
return m_textFieldController.textField()->text();
}
void InputViewController::showInput() {
void InputViewController::edit(Responder * caller, Ion::Events::Event event, void * context, Invocation::Action successAction, Invocation::Action failureAction) {
m_successAction = Invocation(successAction, context);
m_failureAction = Invocation(failureAction, context);
m_textFieldController.textField()->handleEvent(event);
displayModalViewController(&m_textFieldController, 1.0f, 1.0f);
}
void InputViewController::setTextBody(const char * text) {
m_textFieldController.textField()->setText(text);
bool InputViewController::textFieldDidFinishEditing(TextField * textField, const char * text) {
m_successAction.perform(this);
m_textFieldController.textField()->setText("");
dismissModalViewController();
return true;
}
bool InputViewController::handleEvent(Ion::Events::Event event) {
if (!isDisplayingModal()) {
return false;
}
if (event == Ion::Events::OK) {
m_successAction.perform(this);
dismissModalViewController();
return true;
}
if (event == Ion::Events::Back) {
m_failureAction.perform(this);
dismissModalViewController();
return true;
}
return false;
bool InputViewController::textFieldDidAbortEditing(TextField * textField, const char * text) {
m_failureAction.perform(this);
m_textFieldController.textField()->setText("");
dismissModalViewController();
return true;
}
void InputViewController::edit(Responder * caller, const char * initialContent, int cursorPosition, void * context, Invocation::Action successAction, Invocation::Action failureAction) {
m_successAction = Invocation(successAction, context);
m_failureAction = Invocation(failureAction, context);
setTextBody(initialContent);
m_textFieldController.textField()->setCursorLocation(cursorPosition);
showInput();
bool InputViewController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
return m_textFieldDelegate->textFieldDidReceiveEvent(textField, event);
}

View File

@@ -33,8 +33,13 @@ void SelectableTableView::deselectTable() {
TableViewCell * previousCell = cellAtLocation(m_selectedCellX, m_selectedCellY);
previousCell->setHighlighted(false);
}
int previousSelectedCellX = m_selectedCellX;
int previousSelectedCellY = m_selectedCellY;
m_selectedCellX = 0;
m_selectedCellY = -1;
if (m_delegate) {
m_delegate->tableViewDidChangeSelection(this, previousSelectedCellX, previousSelectedCellY);
}
}
bool SelectableTableView::selectCellAtLocation(int i, int j) {

View File

@@ -1,22 +1,38 @@
#include <escher/text_field.h>
#include <assert.h>
TextField::TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate) :
TextField::TextField(Responder * parentResponder, char * textBuffer, char * draftTextBuffer,
size_t textBufferSize, TextFieldDelegate * delegate,
float horizontalAlignment, float verticalAlignment, KDColor textColor, KDColor backgroundColor) :
View(),
Responder(parentResponder),
m_isEditing(false),
m_textBuffer(textBuffer),
m_draftTextBuffer(draftTextBuffer),
m_currentTextLength(0),
m_currentCursorLocation(0),
m_textBufferSize(textBufferSize),
m_delegate(delegate)
m_delegate(delegate),
m_horizontalAlignment(horizontalAlignment),
m_verticalAlignment(verticalAlignment),
m_textColor(textColor),
m_backgroundColor(backgroundColor)
{
}
/* View */
const char * TextField::text() const {
if (m_isEditing) {
return (const char *)m_draftTextBuffer;
}
return (const char *)m_textBuffer;
}
void TextField::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(rect, KDColorWhite);
ctx->drawString(m_textBuffer, KDPointZero);
ctx->fillRect(rect, m_backgroundColor);
KDSize textSize = KDText::stringSize(text());
KDPoint origin(m_horizontalAlignment*(m_frame.width() - textSize.width()),
m_verticalAlignment*(m_frame.height() - textSize.height()));
ctx->drawString(text(), origin, m_textColor, m_backgroundColor);
}
#if ESCHER_VIEW_LOGGING
@@ -25,13 +41,29 @@ const char * TextField::className() const {
}
#endif
void TextField::reload() {
KDSize sizeText = KDText::stringSize(m_textBuffer);
KDRect dirtyZone(0, 0, sizeText.width(), sizeText.height());
markRectAsDirty(dirtyZone);
void TextField::setBackgroundColor(KDColor backgroundColor) {
m_backgroundColor = backgroundColor;
markRectAsDirty(bounds());
}
/* Responder */
void TextField::setTextColor(KDColor textColor) {
m_textColor = textColor;
markRectAsDirty(bounds());
}
void TextField::setAlignment(float horizontalAlignment, float verticalAlignment) {
m_horizontalAlignment = horizontalAlignment;
m_verticalAlignment = verticalAlignment;
markRectAsDirty(bounds());
}
void TextField::reload() {
KDSize textSize = KDText::stringSize(text());
KDPoint origin(m_horizontalAlignment*(m_frame.width() - textSize.width()),
m_verticalAlignment*(m_frame.height() - textSize.height()));
KDRect dirtyZone(origin, textSize);
markRectAsDirty(dirtyZone);
}
bool TextField::handleEvent(Ion::Events::Event event) {
if (m_delegate) {
@@ -39,43 +71,63 @@ bool TextField::handleEvent(Ion::Events::Event event) {
return true;
}
}
if (event == Ion::Events::Left) {
if (event == Ion::Events::OK) {
if (m_isEditing) {
strlcpy(m_textBuffer, m_draftTextBuffer, m_textBufferSize);
setEditing(false);
m_delegate->textFieldDidFinishEditing(this, text());
return true;
}
setEditing(true);
strlcpy(m_draftTextBuffer, m_textBuffer, m_textBufferSize);
setCursorLocation(strlen(m_draftTextBuffer));
return true;
}
if (event == Ion::Events::Left && m_isEditing) {
if (m_currentCursorLocation > 0) {
m_currentCursorLocation--;
}
return true;
}
if (event == Ion::Events::Right) {
if (event == Ion::Events::Right && m_isEditing) {
if (m_currentCursorLocation < m_currentTextLength) {
m_currentCursorLocation++;
}
return true;
}
if (event == Ion::Events::Backspace) {
if (event == Ion::Events::Backspace && m_isEditing) {
if (m_currentCursorLocation > 0) {
reload();
m_currentTextLength--;
m_currentCursorLocation--;
for (int k = m_currentCursorLocation; k < m_currentTextLength; k ++) {
m_textBuffer[k] = m_textBuffer[k+1];
m_draftTextBuffer[k] = m_draftTextBuffer[k+1];
}
m_textBuffer[m_currentTextLength] = 0;
m_draftTextBuffer[m_currentTextLength] = 0;
}
return true;
}
if (event.hasText()) {
insertTextAtLocation(event.text(), cursorLocation());
if (m_isEditing) {
insertTextAtLocation(event.text(), cursorLocation());
} else {
strlcpy(m_draftTextBuffer, event.text(), m_textBufferSize);
m_currentTextLength = strlen(event.text());
setCursorLocation(0);
}
int cursorDelta = strlen(event.text()) > 1 ? -1 : 0;
setCursorLocation(cursorLocation() + strlen(event.text()) + cursorDelta);
setEditing(true);
return true;
}
if (event == Ion::Events::Back && m_isEditing) {
m_delegate->textFieldDidAbortEditing(this, text());
setEditing(false);
return true;
}
return false;
}
const char * TextField::text() const {
return (const char *)m_textBuffer;
}
int TextField::textLength() const {
assert(strlen(text()) == m_currentTextLength);
return m_currentTextLength;
@@ -83,9 +135,13 @@ int TextField::textLength() const {
void TextField::setText(const char * text) {
reload();
strlcpy(m_textBuffer, text, m_textBufferSize);
m_currentCursorLocation = strlen(text);
m_currentTextLength = m_currentCursorLocation;
if (m_isEditing) {
strlcpy(m_draftTextBuffer, text, m_textBufferSize);
m_currentCursorLocation = strlen(text);
m_currentTextLength = m_currentCursorLocation;
} else {
strlcpy(m_textBuffer, text, m_textBufferSize);
}
reload();
}
@@ -105,19 +161,31 @@ void TextField::insertTextAtLocation(const char * text, int location) {
return;
}
for (int k = m_currentTextLength; k >= location && k >= 0; k--) {
m_textBuffer[k+textSize] = m_textBuffer[k];
m_draftTextBuffer[k+textSize] = m_draftTextBuffer[k];
}
strlcpy(&m_textBuffer[location], text, textSize);
m_textBuffer[location+textSize-1] = text[textSize-1];
strlcpy(&m_draftTextBuffer[location], text, textSize);
m_draftTextBuffer[location+textSize-1] = text[textSize-1];
m_currentTextLength += textSize;
reload();
}
KDSize TextField::minimalSizeForOptimalDisplay() {
KDSize textSize = KDText::stringSize(m_textBuffer);
KDSize textSize = KDText::stringSize(m_draftTextBuffer);
return KDSize(0, textSize.height());
}
void TextField::setTextFieldDelegate(TextFieldDelegate * delegate) {
m_delegate = delegate;
}
bool TextField::isEditing() const {
return m_isEditing;
}
void TextField::setEditing(bool isEditing) {
if (m_isEditing == isEditing) {
return;
}
m_isEditing = isEditing;
markRectAsDirty(bounds());
}