mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
Merge branch 'omega-hotfix' into omega-dev
This commit is contained in:
@@ -24,6 +24,13 @@ int ExpressionsListController::reusableCellCount(int type) {
|
||||
return k_maxNumberOfCells;
|
||||
}
|
||||
|
||||
void ExpressionsListController::viewDidDisappear() {
|
||||
// Reset cell memoization to avoid taking extra space in the pool
|
||||
for (int i = 0; i < k_maxNumberOfCells; i++) {
|
||||
m_cells[i].setLayout(Layout());
|
||||
}
|
||||
}
|
||||
|
||||
HighlightCell * ExpressionsListController::reusableCell(int index, int type) {
|
||||
return &m_cells[index];
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ public:
|
||||
ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController);
|
||||
|
||||
// Responder
|
||||
void viewDidDisappear() override;
|
||||
void didEnterResponderChain(Responder * previousFirstResponder) override;
|
||||
|
||||
//ListViewDataSource
|
||||
|
||||
@@ -42,6 +42,10 @@ void IllustratedListController::viewDidDisappear() {
|
||||
Poincare::Symbol s = Poincare::Symbol::Builder(expressionSymbol());
|
||||
context->setExpressionForSymbolAbstract(m_savedExpression, s);
|
||||
}
|
||||
// Reset cell memoization to avoid taking extra space in the pool
|
||||
for (int i = 0; i < k_maxNumberOfAdditionalCalculations; i++) {
|
||||
m_additionalCalculationCells[i].resetMemoization();
|
||||
}
|
||||
}
|
||||
|
||||
int IllustratedListController::numberOfRows() const {
|
||||
|
||||
@@ -32,8 +32,12 @@ bool ListController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
char buffer[Constant::MaxSerializedExpressionSize];
|
||||
textAtIndex(buffer, Constant::MaxSerializedExpressionSize, selectedRow());
|
||||
m_editExpressionController->insertTextBody(buffer);
|
||||
/* The order is important here: we dismiss the pop-up first because it
|
||||
* clears the Poincare pool from the layouts used to display the pop-up.
|
||||
* Thereby it frees memory to do Poincare computations required by
|
||||
* insertTextBody. */
|
||||
Container::activeApp()->dismissModalViewController();
|
||||
m_editExpressionController->insertTextBody(buffer);
|
||||
Container::activeApp()->setFirstResponder(m_editExpressionController);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,15 @@
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
void ScrollableThreeExpressionsView::resetMemoization() {
|
||||
setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout());
|
||||
}
|
||||
|
||||
void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) {
|
||||
Poincare::Context * context = App::app()->localContext();
|
||||
|
||||
// Clean the layouts to make room in the pool
|
||||
setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout());
|
||||
resetMemoization();
|
||||
|
||||
// Create the input layout
|
||||
Poincare::Layout inputLayout = calculation->createInputLayout();
|
||||
|
||||
@@ -14,6 +14,7 @@ public:
|
||||
setMargins(Metric::CommonSmallMargin, Metric::CommonSmallMargin, Metric::CommonSmallMargin, Metric::CommonSmallMargin); // Left Right margins are already added by TableCell
|
||||
setBackgroundColor(KDColorWhite);
|
||||
}
|
||||
void resetMemoization();
|
||||
void setCalculation(Calculation * calculation);
|
||||
private:
|
||||
class ContentCell : public Shared::AbstractScrollableMultipleExpressionsView::ContentCell {
|
||||
@@ -50,6 +51,7 @@ public:
|
||||
View * labelView() const override { return (View *)&m_view; }
|
||||
|
||||
void setHighlighted(bool highlight) override { m_view.evenOddCell()->setHighlighted(highlight); }
|
||||
void resetMemoization() { m_view.resetMemoization(); }
|
||||
void setCalculation(Calculation * calculation);
|
||||
void setDisplayCenter(bool display);
|
||||
ScrollableThreeExpressionsView::SubviewPosition selectedSubviewPosition() { return m_view.selectedSubviewPosition(); }
|
||||
|
||||
@@ -313,6 +313,12 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
|
||||
return m_displayOutput;
|
||||
}
|
||||
|
||||
void Calculation::forceDisplayOutput(DisplayOutput d) {
|
||||
m_displayOutput = d;
|
||||
// Reset heights memoization as it might have changed when we modify the display output
|
||||
m_height = -1;
|
||||
m_expandedHeight = -1;
|
||||
}
|
||||
bool Calculation::shouldOnlyDisplayExactOutput() {
|
||||
/* If the input is a "store in a function", do not display the approximate
|
||||
* result. This prevents x->f(x) from displaying x = undef. */
|
||||
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
|
||||
// Displayed output
|
||||
DisplayOutput displayOutput(Poincare::Context * context);
|
||||
void forceDisplayOutput(DisplayOutput d) { m_displayOutput = d; }
|
||||
void forceDisplayOutput(DisplayOutput d);
|
||||
bool shouldOnlyDisplayExactOutput();
|
||||
EqualSign exactAndApproximateDisplayedOutputsAreEqual(Poincare::Context * context);
|
||||
|
||||
|
||||
@@ -231,6 +231,10 @@ void HistoryController::historyViewCellDidChangeSelection(HistoryViewCell ** cel
|
||||
m_selectableTableView.reloadData();
|
||||
}
|
||||
|
||||
// It might be necessary to scroll to the sub type if the cell overflows the screen
|
||||
if (selectedRow() >= 0) {
|
||||
m_selectableTableView.scrollToSubviewOfTypeOfCellAtLocation(type, m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
|
||||
}
|
||||
// Fill the selected cell and the previous selected cell because cells repartition might have changed
|
||||
*cell = static_cast<HistoryViewCell *>(m_selectableTableView.selectedCell());
|
||||
*previousCell = static_cast<HistoryViewCell *>(m_selectableTableView.cellAtLocation(previousSelectedCellX, previousSelectedCellY));
|
||||
|
||||
@@ -309,9 +309,6 @@ bool HistoryViewCell::handleEvent(Ion::Events::Event event) {
|
||||
otherSubviewType = HistoryViewCellDataSource::SubviewType::Output;
|
||||
}
|
||||
m_dataSource->setSelectedSubviewType(otherSubviewType, true);
|
||||
CalculationSelectableTableView * tableView = (CalculationSelectableTableView *)parentResponder();
|
||||
tableView->scrollToSubviewOfTypeOfCellAtLocation(otherSubviewType, tableView->selectedColumn(), tableView->selectedRow());
|
||||
Container::activeApp()->setFirstResponder(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -24,18 +24,6 @@ void CalculationSelectableTableView::scrollToCell(int i, int j) {
|
||||
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(dataSource()->numberOfRows()) - maxContentHeightDisplayableWithoutScrolling();
|
||||
setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
|
||||
}
|
||||
if (dataSource()->numberOfRows() > j && dataSource()->numberOfColumns() > i && dataSource()->rowHeight(j) > bounds().height()) {
|
||||
KDCoordinate contentOffsetX = contentOffset().x();
|
||||
KDCoordinate contentOffsetY = contentOffset().y();
|
||||
if (contentOffsetY > dataSource()->cumulatedHeightFromIndex(j) && contentOffsetY > dataSource()->cumulatedHeightFromIndex(j+1)) {
|
||||
// Let's scroll the tableView to align the top of the cell to the top
|
||||
contentOffsetY = dataSource()->cumulatedHeightFromIndex(j);
|
||||
} else {
|
||||
// Let's scroll the tableView to align the bottom of the cell to the bottom
|
||||
contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling();
|
||||
}
|
||||
setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
|
||||
}
|
||||
}
|
||||
|
||||
void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(HistoryViewCellDataSource::SubviewType subviewType, int i, int j) {
|
||||
@@ -44,10 +32,8 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo
|
||||
}
|
||||
/* As we scroll, the selected calculation does not use the same history view
|
||||
* cell, thus, we want to deselect the previous used history view cell. */
|
||||
if (selectedRow() >= 0) {
|
||||
HighlightCell * previousCell = selectedCell();
|
||||
previousCell->setHighlighted(false);
|
||||
}
|
||||
unhighlightSelectedCell();
|
||||
|
||||
/* Main part of the scroll */
|
||||
KDCoordinate contentOffsetX = contentOffset().x();
|
||||
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling();
|
||||
@@ -58,16 +44,13 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo
|
||||
contentOffsetY = dataSource()->cumulatedHeightFromIndex(j);
|
||||
}
|
||||
}
|
||||
/* For the same reason, we have to rehighlight the new history view cell and
|
||||
* inform the delegate which history view cell is highlighted even if the
|
||||
* selected calculation has not changed. */
|
||||
setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
|
||||
HighlightCell * cell = cellAtLocation(i, j);
|
||||
/* For the same reason, we have to rehighlight the new history view cell and
|
||||
* reselect the first responder. */
|
||||
HistoryViewCell * cell = (HistoryViewCell *)(selectedCell());
|
||||
assert(cell);
|
||||
cell->setHighlighted(true);
|
||||
if (m_delegate) {
|
||||
m_delegate->tableViewDidChangeSelection(this, selectedColumn(), selectedRow());
|
||||
}
|
||||
Container::activeApp()->setFirstResponder(cell);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ void FunctionApp::Snapshot::storageDidChangeForRecord(const Ion::Storage::Record
|
||||
|
||||
void FunctionApp::willBecomeInactive() {
|
||||
if (m_modalViewController.isDisplayingModal()) {
|
||||
m_modalViewController.dismissModalViewController();
|
||||
m_modalViewController.dismissModalViewController(true);
|
||||
}
|
||||
if (inputViewController()->isDisplayingModal()) {
|
||||
inputViewController()->abortEditionAndDismiss();
|
||||
|
||||
@@ -60,7 +60,7 @@ App::App(Snapshot * snapshot) :
|
||||
|
||||
void App::willBecomeInactive() {
|
||||
if (m_modalViewController.isDisplayingModal()) {
|
||||
m_modalViewController.dismissModalViewController();
|
||||
m_modalViewController.dismissModalViewController(true);
|
||||
}
|
||||
if (inputViewController()->isDisplayingModal()) {
|
||||
inputViewController()->abortEditionAndDismiss();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "shared/continuous_function.h"
|
||||
#include <escher/metric.h>
|
||||
#include <ion/unicode/utf8_decoder.h>
|
||||
#include <poincare/exception_checkpoint.h>
|
||||
#include <poincare/layout_helper.h>
|
||||
#include <poincare/matrix_layout.h>
|
||||
#include <poincare/preferences.h>
|
||||
@@ -235,10 +236,20 @@ Layout VariableBoxController::expressionLayoutForRecord(Storage::Record record,
|
||||
assert(m_firstMemoizedLayoutIndex >= 0);
|
||||
}
|
||||
assert(index >= m_firstMemoizedLayoutIndex && index < m_firstMemoizedLayoutIndex + k_maxNumberOfDisplayedRows);
|
||||
Layout result;
|
||||
if (m_layouts[index-m_firstMemoizedLayoutIndex].isUninitialized()) {
|
||||
m_layouts[index-m_firstMemoizedLayoutIndex] = GlobalContext::LayoutForRecord(record);
|
||||
/* Creating the layout of a very long variable might throw a pool exception.
|
||||
* We want to catch it and return a dummy layout instead, otherwise the user
|
||||
* won't be able to open the variable box again, until she deletes the
|
||||
* problematic variable -> and she has no help to remember its name, as she
|
||||
* can't open the variable box. */
|
||||
Poincare::ExceptionCheckpoint ecp;
|
||||
if (ExceptionRun(ecp)) {
|
||||
result = GlobalContext::LayoutForRecord(record);
|
||||
}
|
||||
}
|
||||
return m_layouts[index-m_firstMemoizedLayoutIndex];
|
||||
m_layouts[index-m_firstMemoizedLayoutIndex] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
const char * VariableBoxController::extension() const {
|
||||
|
||||
@@ -32,10 +32,9 @@ public:
|
||||
bool selectCellAtLocation(int i, int j, bool setFirstResponder = true, bool withinTemporarySelection = false);
|
||||
HighlightCell * selectedCell();
|
||||
protected:
|
||||
void unhighlightSelectedCell();
|
||||
SelectableTableViewDataSource * m_selectionDataSource;
|
||||
SelectableTableViewDelegate * m_delegate;
|
||||
private:
|
||||
void unhighlightSelectedCell();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -81,8 +81,33 @@ void ScrollView::scrollToContentPoint(KDPoint p, bool allowOverscroll) {
|
||||
}
|
||||
|
||||
void ScrollView::scrollToContentRect(KDRect rect, bool allowOverscroll) {
|
||||
scrollToContentPoint(rect.topLeft(), allowOverscroll);
|
||||
scrollToContentPoint(rect.bottomRight(), allowOverscroll);
|
||||
KDPoint tl = rect.topLeft();
|
||||
KDPoint br = rect.bottomRight();
|
||||
KDRect visibleRect = visibleContentRect();
|
||||
/* We first check that we can display the whole rect. If we can't, we focus
|
||||
* the croll to the closest part of the rect. */
|
||||
if (visibleRect.height() < rect.height()) {
|
||||
// The visible rect is too small to display 'rect'
|
||||
if (rect.top() >= visibleRect.top()) {
|
||||
// We scroll to display the top part of rect
|
||||
br = KDPoint(br.x(), rect.top() + visibleRect.height());
|
||||
} else {
|
||||
// We scroll to display the bottom part of rect
|
||||
tl = KDPoint(tl.x(), rect.bottom() - visibleRect.height());
|
||||
}
|
||||
}
|
||||
if (visibleRect.width() < rect.width()) {
|
||||
// The visible rect is too small to display 'rect'
|
||||
if (rect.left() >= visibleRect.left()) {
|
||||
// We scroll to display the left part of rect
|
||||
br = KDPoint(rect.left() + visibleRect.width(), br.y());
|
||||
} else {
|
||||
// We scroll to display the right part of rect
|
||||
tl = KDPoint(rect.right() - visibleRect.width(), tl.y());
|
||||
}
|
||||
}
|
||||
scrollToContentPoint(tl, allowOverscroll);
|
||||
scrollToContentPoint(br, allowOverscroll);
|
||||
}
|
||||
|
||||
KDRect ScrollView::visibleContentRect() {
|
||||
|
||||
@@ -39,7 +39,7 @@ int FunctionNode::getVariables(Context * context, isVariableTest isVariable, cha
|
||||
Function f(this);
|
||||
Expression e = SymbolAbstract::Expand(f, context, true);
|
||||
if (e.isUninitialized()) {
|
||||
return 0;
|
||||
return nextVariableIndex;
|
||||
}
|
||||
return e.node()->getVariables(context, isVariable, variables, maxSizeVariable, nextVariableIndex);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@ void MicroPython::ExecutionEnvironment::runCode(const char * str) {
|
||||
assert(sCurrentExecutionEnvironment == nullptr);
|
||||
sCurrentExecutionEnvironment = this;
|
||||
|
||||
/* Set the user interruption now, as it is needed for the normal execution and
|
||||
* for the exception handling (because of print). */
|
||||
mp_hal_set_interrupt_char((int)Ion::Keyboard::Key::Back);
|
||||
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(0, str, strlen(str), false);
|
||||
@@ -41,9 +45,7 @@ void MicroPython::ExecutionEnvironment::runCode(const char * str) {
|
||||
// TODO: add a parameter when other input types (file, eval) are required
|
||||
mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_SINGLE_INPUT);
|
||||
mp_obj_t module_fun = mp_compile(&pt, lex->source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_hal_set_interrupt_char((int)Ion::Keyboard::Key::Back);
|
||||
mp_call_function_0(module_fun);
|
||||
mp_hal_set_interrupt_char(-1); // Disable interrupt
|
||||
nlr_pop();
|
||||
} else { // Uncaught exception
|
||||
/* mp_obj_print_exception is supposed to handle error printing. However,
|
||||
@@ -81,6 +83,9 @@ void MicroPython::ExecutionEnvironment::runCode(const char * str) {
|
||||
/* End of mp_obj_print_exception. */
|
||||
}
|
||||
|
||||
// Disable the user interruption
|
||||
mp_hal_set_interrupt_char(-1);
|
||||
|
||||
assert(sCurrentExecutionEnvironment == this);
|
||||
sCurrentExecutionEnvironment = nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user