[apps/calculation] Add a "ctrl-z" system

This commit is contained in:
Laury
2022-02-15 22:24:50 +01:00
parent 893a2a550d
commit f3d632c462
8 changed files with 55 additions and 13 deletions

View File

@@ -16,14 +16,24 @@ CalculationStore::CalculationStore(char * buffer, int size) :
m_buffer(buffer),
m_bufferSize(size),
m_calculationAreaEnd(m_buffer),
m_numberOfCalculations(0)
m_numberOfCalculations(0),
m_trashIndex(-1)
{
assert(m_buffer != nullptr);
assert(m_bufferSize > 0);
}
// Returns an expiring pointer to the calculation of index i
// Returns an expiring pointer to the calculation of index i, and ignore the trash
ExpiringPointer<Calculation> CalculationStore::calculationAtIndex(int i) {
if (m_trashIndex == -1 || i < m_trashIndex) {
return realCalculationAtIndex(i);
} else {
return realCalculationAtIndex(i + 1);
}
}
// Returns an expiring pointer to the real calculation of index i
ExpiringPointer<Calculation> CalculationStore::realCalculationAtIndex(int i) {
assert(i >= 0 && i < m_numberOfCalculations);
// m_buffer is the address of the oldest calculation in calculation store
Calculation * c = (Calculation *) m_buffer;
@@ -36,12 +46,13 @@ ExpiringPointer<Calculation> CalculationStore::calculationAtIndex(int i) {
// Pushes an expression in the store
ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context * context, HeightComputer heightComputer) {
emptyTrash();
/* Compute ans now, before the buffer is updated and before the calculation
* might be deleted */
Expression ans = ansExpression(context);
/* Prepare the buffer for the new calculation
*The minimal size to store the new calculation is the minimal size of a calculation plus the pointer to its end */
* The minimal size to store the new calculation is the minimal size of a calculation plus the pointer to its end */
int minSize = Calculation::MinimalSize() + sizeof(Calculation *);
assert(m_bufferSize > minSize);
while (remainingBufferSize() < minSize) {
@@ -132,15 +143,23 @@ ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context *
// Delete the calculation of index i
void CalculationStore::deleteCalculationAtIndex(int i) {
if (m_trashIndex != -1) {
emptyTrash();
}
m_trashIndex = i;
}
// Delete the calculation of index i, internal algorithm
void CalculationStore::realDeleteCalculationAtIndex(int i) {
assert(i >= 0 && i < m_numberOfCalculations);
if (i == 0) {
ExpiringPointer<Calculation> lastCalculationPointer = calculationAtIndex(0);
ExpiringPointer<Calculation> lastCalculationPointer = realCalculationAtIndex(0);
m_calculationAreaEnd = (char *)(lastCalculationPointer.pointer());
m_numberOfCalculations--;
return;
}
char * calcI = (char *)calculationAtIndex(i).pointer();
char * nextCalc = (char *) calculationAtIndex(i-1).pointer();
char * calcI = (char *)realCalculationAtIndex(i).pointer();
char * nextCalc = (char *) realCalculationAtIndex(i-1).pointer();
assert(m_calculationAreaEnd >= nextCalc);
size_t slidingSize = m_calculationAreaEnd - nextCalc;
// Slide the i-1 most recent calculations right after the i+1'th
@@ -200,6 +219,12 @@ bool CalculationStore::pushSerializeExpression(Expression e, char * location, ch
return expressionIsPushed;
}
void CalculationStore::emptyTrash() {
if (m_trashIndex != -1) {
realDeleteCalculationAtIndex(m_trashIndex);
m_trashIndex = -1;
}
}
Shared::ExpiringPointer<Calculation> CalculationStore::emptyStoreAndPushUndef(Context * context, HeightComputer heightComputer) {
@@ -211,9 +236,9 @@ Shared::ExpiringPointer<Calculation> CalculationStore::emptyStoreAndPushUndef(Co
// Recompute memoized pointers to the calculations after index i
void CalculationStore::recomputeMemoizedPointersAfterCalculationIndex(int index) {
assert(index < m_numberOfCalculations);
assert(index < numberOfCalculations());
// Clear pointer and recompute new ones
Calculation * c = calculationAtIndex(index).pointer();
Calculation * c = realCalculationAtIndex(index).pointer();
Calculation * nextCalc;
while (index != 0) {
nextCalc = c->next();

View File

@@ -41,11 +41,15 @@ public:
void deleteCalculationAtIndex(int i);
void deleteAll();
int remainingBufferSize() const { assert(m_calculationAreaEnd >= m_buffer); return m_bufferSize - (m_calculationAreaEnd - m_buffer) - m_numberOfCalculations*sizeof(Calculation*); }
int numberOfCalculations() const { return m_numberOfCalculations; }
int numberOfCalculations() const { return m_numberOfCalculations - (m_trashIndex != -1); }
Poincare::Expression ansExpression(Poincare::Context * context);
int bufferSize() { return m_bufferSize; }
void reinsertTrash() { m_trashIndex = -1; }
private:
void emptyTrash();
Shared::ExpiringPointer<Calculation> realCalculationAtIndex(int i);
void realDeleteCalculationAtIndex(int i);
class CalculationIterator {
public:
@@ -70,6 +74,7 @@ private:
int m_bufferSize;
const char * m_calculationAreaEnd;
int m_numberOfCalculations;
int m_trashIndex;
size_t deleteOldestCalculation();
char * addressOfPointerToCalculationOfIndex(int i) {return m_buffer + m_bufferSize - (m_numberOfCalculations - i)*sizeof(Calculation *);}

View File

@@ -68,6 +68,15 @@ void EditExpressionController::memoizeInput() {
*m_cacheBufferInformation = m_contentView.expressionField()->moveCursorAndDumpContent(m_cacheBuffer, k_cacheBufferSize);
}
bool EditExpressionController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::ShiftBack) {
m_historyController->reinsertTrash();
m_historyController->reload();
return true;
}
return false;
}
void EditExpressionController::viewWillAppear() {
m_historyController->viewWillAppear();
}

View File

@@ -31,6 +31,7 @@ public:
void insertTextBody(const char * text);
void restoreInput();
void memoizeInput();
bool handleEvent(Ion::Events::Event event) override;
/* TextFieldDelegate */
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;

View File

@@ -35,6 +35,7 @@ public:
int typeAtLocation(int i, int j) override;
void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1) override;
void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override;
void reinsertTrash() { m_calculationStore->reinsertTrash(); }
private:
int storeIndex(int i) { return numberOfRows() - i - 1; }
Shared::ExpiringPointer<Calculation> calculationAtIndex(int i);

View File

@@ -142,6 +142,7 @@ constexpr Event ShiftRight = Event::ShiftKey(Keyboard::Key::Right);
constexpr Event ShiftUp = Event::ShiftKey(Keyboard::Key::Up);
constexpr Event ShiftDown = Event::ShiftKey(Keyboard::Key::Down);
constexpr Event ShiftOK = Event::ShiftKey(Keyboard::Key::OK);
constexpr Event ShiftBack = Event::ShiftKey(Keyboard::Key::Back);
constexpr Event AlphaLock = Event::ShiftKey(Keyboard::Key::Alpha);
constexpr Event Cut = Event::ShiftKey(Keyboard::Key::XNT);

View File

@@ -16,7 +16,7 @@ const EventData s_dataForEvent[4 * Event::PageSize] = {
T("1"), T("2"), T("3"), T("+"), T("-"), U(),
T("0"), T("."), T(""), TL(), TL(), U(),
// Shift
TL(), TL(), TL(), TL(), TL(), U(),
TL(), TL(), TL(), TL(), TL(), TL(),
TL(), U(), U(), U(), U(), U(),
U(), U(), TL(), TL(), TL(), TL(),
T("["), T("]"), T("{"), T("}"), T("_"), T(""),
@@ -61,7 +61,7 @@ const char * const s_nameForEvent[255] = {
"One", "Two", "Three", "Plus", "Minus", nullptr,
"Zero", "Dot", "EE", "Ans", "EXE", nullptr,
//Shift,
"ShiftLeft", "ShiftUp", "ShiftDown", "ShiftRight", "ShiftOK", nullptr,
"ShiftLeft", "ShiftUp", "ShiftDown", "ShiftRight", "ShiftOK", "ShiftBack",
"ShiftHome", nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, "AlphaLock", "Cut", "Copy", "Paste", "Clear",
"LeftBracket", "RightBracket", "LeftBrace", "RightBrace", "Underscore", "Sto",

View File

@@ -16,7 +16,7 @@ const EventData s_dataForEvent[4 * Event::PageSize] = {
T("1"), T("2"), T("3"), T("+"), T("-"), U(),
T("0"), T("."), T(""), TL(), TL(), U(),
// Shift
TL(), TL(), TL(), TL(), TL(), U(),
TL(), TL(), TL(), TL(), TL(), TL(),
TL(), U(), U(), U(), U(), U(),
U(), U(), TL(), TL(), TL(), TL(),
T("["), T("]"), T("{"), T("}"), T("_"), T(""),
@@ -61,7 +61,7 @@ const char * const s_nameForEvent[255] = {
"One", "Two", "Three", "Plus", "Minus", nullptr,
"Zero", "Dot", "EE", "Ans", "EXE", nullptr,
//Shift,
"ShiftLeft", "ShiftUp", "ShiftDown", "ShiftRight", "ShiftOK", nullptr,
"ShiftLeft", "ShiftUp", "ShiftDown", "ShiftRight", "ShiftOK", "ShiftBack",
"ShiftHome", nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, "AlphaLock", "Cut", "Copy", "Paste", "Clear",
"LeftBracket", "RightBracket", "LeftBrace", "RightBrace", "Underscore", "Sto",