diff --git a/apps/graph/list/storage_list_controller.cpp b/apps/graph/list/storage_list_controller.cpp index 83b4bcd5a..1ccfcaaaa 100644 --- a/apps/graph/list/storage_list_controller.cpp +++ b/apps/graph/list/storage_list_controller.cpp @@ -170,4 +170,15 @@ void StorageListController::setFunctionNameInTextField(ExpiringPointersetText(bufferName); } +KDCoordinate StorageListController::privateBaseline(int j) const { + assert(j>=0 && j((const_cast(&m_selectableTableView))->cellAtLocation(1, j)); + Poincare::Layout layout = cell->layout(); + if (layout.isUninitialized()) { + return -1; + } + return 0.5*(const_cast(this)->rowHeight(j)-layout.layoutSize().height())+layout.baseline(); + +} + } diff --git a/apps/graph/list/storage_list_controller.h b/apps/graph/list/storage_list_controller.h index eabe0c52f..a8c65d9fa 100644 --- a/apps/graph/list/storage_list_controller.h +++ b/apps/graph/list/storage_list_controller.h @@ -33,6 +33,7 @@ private: return static_cast(app()); } void setFunctionNameInTextField(Shared::ExpiringPointer function, TextField * textField); + KDCoordinate privateBaseline(int j) const override; TextFieldFunctionTitleCell m_functionTitleCells[k_maxNumberOfDisplayableRows]; Shared::FunctionExpressionCell m_expressionCells[k_maxNumberOfDisplayableRows]; ListParameterController m_parameterController; diff --git a/apps/shared/function_title_cell.cpp b/apps/shared/function_title_cell.cpp index f730ad2c9..4a94c8649 100644 --- a/apps/shared/function_title_cell.cpp +++ b/apps/shared/function_title_cell.cpp @@ -3,12 +3,6 @@ namespace Shared { -FunctionTitleCell::FunctionTitleCell(Orientation orientation) : - EvenOddCell(), - m_orientation(orientation) -{ -} - void FunctionTitleCell::setOrientation(Orientation orientation) { m_orientation = orientation; reloadCell(); @@ -19,6 +13,13 @@ void FunctionTitleCell::setColor(KDColor color) { reloadCell(); } +void FunctionTitleCell::setBaseline(KDCoordinate baseline) { + if (m_baseline != baseline) { + m_baseline = baseline; + reloadCell(); + } +} + void FunctionTitleCell::drawRect(KDContext * ctx, KDRect rect) const { if (m_orientation == Orientation::VerticalIndicator){ ctx->fillRect(KDRect(0, 0, k_colorIndicatorThickness, bounds().height()), m_functionColor); diff --git a/apps/shared/function_title_cell.h b/apps/shared/function_title_cell.h index 74ca4d439..8fbadb0d5 100644 --- a/apps/shared/function_title_cell.h +++ b/apps/shared/function_title_cell.h @@ -11,15 +11,22 @@ public: HorizontalIndicator, VerticalIndicator }; - FunctionTitleCell(Orientation orientation = Orientation::VerticalIndicator); + FunctionTitleCell(Orientation orientation = Orientation::VerticalIndicator) : + EvenOddCell(), + m_orientation(orientation), + m_baseline(-1), + m_functionColor(KDColorBlack) + {} virtual void setOrientation(Orientation orientation); virtual void setColor(KDColor color); void drawRect(KDContext * ctx, KDRect rect) const override; + void setBaseline(KDCoordinate baseline); virtual const KDFont * font() const = 0; protected: constexpr static KDCoordinate k_separatorThickness = 1; constexpr static KDCoordinate k_colorIndicatorThickness = 2; Orientation m_orientation; + KDCoordinate m_baseline; private: KDColor m_functionColor; }; diff --git a/apps/shared/storage_expression_model_list_controller.cpp b/apps/shared/storage_expression_model_list_controller.cpp index d11522dd1..ff4945be8 100644 --- a/apps/shared/storage_expression_model_list_controller.cpp +++ b/apps/shared/storage_expression_model_list_controller.cpp @@ -15,20 +15,18 @@ StorageExpressionModelListController::StorageExpressionModelListController(Respo } void StorageExpressionModelListController::tableSelectionDidChange(int previousSelectedRow) { - constexpr int currentSelectedMemoizedIndex = k_memoizedCellHeightsCount/2 + 1; // Needs k_memoizedCellHeightsCount to be odd, which is static asserted in the header file + constexpr int currentSelectedMemoizedIndex = k_memoizedCellsCount/2 + 1; // Needs k_memoizedCellsCount to be odd, which is static asserted in the header file int currentSelectedRow = selectedRow(); // The previously selected cell's height might have changed. - m_memoizedCellHeight[currentSelectedMemoizedIndex] = k_resetedMemoizedValue; + resetMemoizationForIndex(currentSelectedMemoizedIndex); // Update m_cumulatedHeightForSelectedIndex if we scrolled one cell up/down if (currentSelectedRow == previousSelectedRow + 1) { /* We selected the cell under the previous cell. Shift the memoized cell * heights. */ - for (int i = 0; i < k_memoizedCellHeightsCount - 1; i++) { - m_memoizedCellHeight[i] = m_memoizedCellHeight[i+1]; - } - m_memoizedCellHeight[k_memoizedCellHeightsCount-1] = k_resetedMemoizedValue; + shiftMemoization(true); + resetMemoizationForIndex(k_memoizedCellsCount-1); // Update m_cumulatedHeightForSelectedIndex if (previousSelectedRow >= 0) { m_cumulatedHeightForSelectedIndex+= memoizedRowHeight(previousSelectedRow); @@ -39,10 +37,8 @@ void StorageExpressionModelListController::tableSelectionDidChange(int previousS } else if (currentSelectedRow == previousSelectedRow - 1) { /* We selected the cell above the previous cell. Shift the memoized cell * heights. */ - for (int i = k_memoizedCellHeightsCount - 1; i > 0; i--) { - m_memoizedCellHeight[i] = m_memoizedCellHeight[i-1]; - } - m_memoizedCellHeight[0] = k_resetedMemoizedValue; + shiftMemoization(false); + resetMemoizationForIndex(0); // Update m_cumulatedHeightForSelectedIndex if (currentSelectedRow >= 0) { m_cumulatedHeightForSelectedIndex-= memoizedRowHeight(currentSelectedRow); @@ -59,7 +55,7 @@ KDCoordinate StorageExpressionModelListController::memoizedRowHeight(int j) { return 0; } int currentSelectedRow = selectedRow(); - constexpr int halfMemoizationCount = k_memoizedCellHeightsCount/2; + constexpr int halfMemoizationCount = k_memoizedCellsCount/2; if (j >= currentSelectedRow - halfMemoizationCount && j <= currentSelectedRow + halfMemoizationCount) { int memoizedIndex = j - (currentSelectedRow - halfMemoizationCount); if (m_memoizedCellHeight[memoizedIndex] == k_resetedMemoizedValue) { @@ -75,7 +71,7 @@ KDCoordinate StorageExpressionModelListController::memoizedCumulatedHeightFromIn return 0; } int currentSelectedRow = selectedRow(); - constexpr int halfMemoizationCount = k_memoizedCellHeightsCount/2; + constexpr int halfMemoizationCount = k_memoizedCellsCount/2; /* If j is not easily computable from the memoized values, compute it the hard * way. */ if (j < currentSelectedRow - halfMemoizationCount || j > currentSelectedRow + halfMemoizationCount) { @@ -210,7 +206,7 @@ void StorageExpressionModelListController::editExpression(Ion::Events::Event eve bool StorageExpressionModelListController::editSelectedRecordWithText(const char * text) { Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(selectedRow())); - ExpiringPointer model = modelStore()->modelForRecord(record); + ExpiringPointer model = modelStore()->modelForRecord(record); return (model->setContent(text) == Ion::Storage::Record::ErrorStatus::None); } @@ -224,10 +220,27 @@ bool StorageExpressionModelListController::isAddEmptyRow(int j) { return j == modelStore()->numberOfModels(); } +void StorageExpressionModelListController::resetMemoizationForIndex(int index) { + assert(index >= 0 && index < k_memoizedCellsCount); + m_memoizedCellHeight[index] = k_resetedMemoizedValue; +} + +void StorageExpressionModelListController::shiftMemoization(bool newCellIsUnder) { + if (newCellIsUnder) { + for (int i = 0; i < k_memoizedCellsCount - 1; i++) { + m_memoizedCellHeight[i] = m_memoizedCellHeight[i+1]; + } + } else { + for (int i = k_memoizedCellsCount - 1; i > 0; i--) { + m_memoizedCellHeight[i] = m_memoizedCellHeight[i-1]; + } + } +} + void StorageExpressionModelListController::resetMemoization() { m_cumulatedHeightForSelectedIndex = k_resetedMemoizedValue; - for (int i = 0; i < k_memoizedCellHeightsCount; i++) { - m_memoizedCellHeight[i] = k_resetedMemoizedValue; + for (int i = 0; i < k_memoizedCellsCount; i++) { + resetMemoizationForIndex(i); } } diff --git a/apps/shared/storage_expression_model_list_controller.h b/apps/shared/storage_expression_model_list_controller.h index 1d5b2961b..577b5a930 100644 --- a/apps/shared/storage_expression_model_list_controller.h +++ b/apps/shared/storage_expression_model_list_controller.h @@ -37,7 +37,7 @@ protected: EvenOddMessageTextCell m_addNewModel; protected: // Memoization - static constexpr int k_memoizedCellHeightsCount = 7; + static constexpr int k_memoizedCellsCount = 7; /* We use memoization to speed up indexFromHeight(offset) in the children * classes: if offset is "around" the memoized cumulatedHeightForIndex, we can * compute its value easily by adding/substracting memoized row heights. We @@ -48,18 +48,20 @@ protected: * (ScreenHeight - Metric::TitleBarHeight - Metric::TabHeight - ButtonRowHeight * - currentSelectedRowHeight) / Metric::StoreRowHeight * = (240-18-27-20-50)/50 = 2.5 */ - static_assert(StorageExpressionModelListController::k_memoizedCellHeightsCount % 2 == 1, "StorageExpressionModelListController::k_memoizedCellHeightsCount should be odd."); + static_assert(StorageExpressionModelListController::k_memoizedCellsCount % 2 == 1, "StorageExpressionModelListController::k_memoizedCellsCount should be odd."); /* We memoize values for indexes around the selectedRow index. - * k_memoizedCellHeightsCount needs to be odd to compute things such as: - * constexpr int halfMemoizationCount = k_memoizedCellHeightsCount/2; + * k_memoizedCellsCount needs to be odd to compute things such as: + * constexpr int halfMemoizationCount = k_memoizedCellsCount/2; * if (j < selectedRow - halfMemoizationCount * || j > selectedRow + halfMemoizationCount) { ... } */ + virtual void resetMemoizationForIndex(int index); + virtual void shiftMemoization(bool newCellIsUnder); private: // Memoization static constexpr int k_resetedMemoizedValue = -1; void resetMemoization(); virtual KDCoordinate notMemoizedCumulatedHeightFromIndex(int j) = 0; - KDCoordinate m_memoizedCellHeight[k_memoizedCellHeightsCount]; + KDCoordinate m_memoizedCellHeight[k_memoizedCellsCount]; KDCoordinate m_cumulatedHeightForSelectedIndex; }; diff --git a/apps/shared/storage_function_list_controller.cpp b/apps/shared/storage_function_list_controller.cpp index 188159d1f..bf91cff67 100644 --- a/apps/shared/storage_function_list_controller.cpp +++ b/apps/shared/storage_function_list_controller.cpp @@ -25,6 +25,12 @@ StorageFunctionListController::StorageFunctionListController(Responder * parentR }, this), KDFont::SmallFont, Palette::PurpleBright), m_titlesColumnWidth(k_minTitleColumnWidth) { + /* m_memoizedCellBaseline is not initialized by the call to + * resetMemoizationForIndex in StorageExpressionModelListController's + * constructor, because it is a virtual method in a constructor. */ + for (int i = 0; i < k_memoizedCellsCount; i++) { + m_memoizedCellBaseline[i] = -1; + } m_selectableTableView.setMargins(0); m_selectableTableView.setVerticalCellOverlap(0); } @@ -98,7 +104,7 @@ int StorageFunctionListController::indexFromCumulatedHeight(KDCoordinate offsetY KDCoordinate currentCumulatedHeight = cumulatedHeightFromIndex(currentSelectedRow); if (offsetY > currentCumulatedHeight) { - int iMax = min(k_memoizedCellHeightsCount/2 + 1, rowsCount - currentSelectedRow); + int iMax = min(k_memoizedCellsCount/2 + 1, rowsCount - currentSelectedRow); for (int i = 0; i < iMax; i++) { currentCumulatedHeight+= rowHeight(currentSelectedRow + i); if (offsetY <= currentCumulatedHeight) { @@ -106,7 +112,7 @@ int StorageFunctionListController::indexFromCumulatedHeight(KDCoordinate offsetY } } } else { - int iMax = min(k_memoizedCellHeightsCount/2, currentSelectedRow); + int iMax = min(k_memoizedCellsCount/2, currentSelectedRow); for (int i = 1; i <= iMax; i++) { currentCumulatedHeight-= rowHeight(currentSelectedRow-i); if (offsetY > currentCumulatedHeight) { @@ -313,4 +319,39 @@ KDCoordinate StorageFunctionListController::notMemoizedCumulatedHeightFromIndex( return TableViewDataSource::cumulatedHeightFromIndex(j); } +KDCoordinate StorageFunctionListController::baseline(int j) { + if (j < 0) { + return -1; + } + int currentSelectedRow = selectedRow(); + constexpr int halfMemoizationCount = k_memoizedCellsCount/2; + if (j >= currentSelectedRow - halfMemoizationCount && j <= currentSelectedRow + halfMemoizationCount) { + int memoizedIndex = j - (currentSelectedRow - halfMemoizationCount); + if (m_memoizedCellBaseline[memoizedIndex] < 0) { + m_memoizedCellBaseline[memoizedIndex] = privateBaseline(j); + } + return m_memoizedCellBaseline[memoizedIndex]; + } + return privateBaseline(j); +} + +void StorageFunctionListController::resetMemoizationForIndex(int index) { + assert(index >= 0 && index < k_memoizedCellsCount); + m_memoizedCellBaseline[index] = -1; + StorageExpressionModelListController::resetMemoizationForIndex(index); +} + +void StorageFunctionListController::shiftMemoization(bool newCellIsUnder) { + if (newCellIsUnder) { + for (int i = 0; i < k_memoizedCellsCount - 1; i++) { + m_memoizedCellBaseline[i] = m_memoizedCellBaseline[i+1]; + } + } else { + for (int i = k_memoizedCellsCount - 1; i > 0; i--) { + m_memoizedCellBaseline[i] = m_memoizedCellBaseline[i-1]; + } + } + StorageExpressionModelListController::shiftMemoization(newCellIsUnder); +} + } diff --git a/apps/shared/storage_function_list_controller.h b/apps/shared/storage_function_list_controller.h index c8e21fb30..433be3b12 100644 --- a/apps/shared/storage_function_list_controller.h +++ b/apps/shared/storage_function_list_controller.h @@ -55,6 +55,9 @@ protected: void configureFunction(Ion::Storage::Record record); void computeTitlesColumnWidth(); StorageFunctionStore * modelStore() override; + KDCoordinate baseline(int j); + void resetMemoizationForIndex(int index) override; + void shiftMemoization(bool newCellIsUnder) override; SelectableTableView m_selectableTableView; private: static constexpr KDCoordinate k_minTitleColumnWidth = 65; @@ -69,10 +72,12 @@ private: virtual FunctionTitleCell * titleCells(int index) = 0; virtual HighlightCell * expressionCells(int index) = 0; virtual void willDisplayTitleCellAtIndex(HighlightCell * cell, int j) = 0; + virtual KDCoordinate privateBaseline(int j) const = 0; EvenOddCell m_emptyCell; Button m_plotButton; Button m_valuesButton; KDCoordinate m_titlesColumnWidth; + KDCoordinate m_memoizedCellBaseline[k_memoizedCellsCount]; }; }