mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[apps/calculation] Add a "ctrl-z" system
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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 *);}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user