diff --git a/apps/shared/storage_expression_model_list_controller.cpp b/apps/shared/storage_expression_model_list_controller.cpp index 36fe8b55c..b18c8607d 100644 --- a/apps/shared/storage_expression_model_list_controller.cpp +++ b/apps/shared/storage_expression_model_list_controller.cpp @@ -6,11 +6,104 @@ namespace Shared { StorageExpressionModelListController::StorageExpressionModelListController(Responder * parentResponder, I18n::Message text) : ViewController(parentResponder), - m_addNewModel() + m_addNewModel(), + m_memoizedCellHeight {-1, -1, -1, -1, -1}, + m_cumulatedHeightForSelectedIndex(-1) { m_addNewModel.setMessage(text); } +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 + int currentSelectedRow = selectedRow(); + + // The previously selected cell's height might have changed. + m_memoizedCellHeight[currentSelectedMemoizedIndex] = -1; + + // 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] = -1; + // Update m_cumulatedHeightForSelectedIndex + if (previousSelectedRow >= 0) { + m_cumulatedHeightForSelectedIndex+= memoizedRowHeight(previousSelectedRow); + } else { + assert(currentSelectedRow == 0); + m_cumulatedHeightForSelectedIndex = 0; + } + } 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] = -1; + // Update m_cumulatedHeightForSelectedIndex + if (currentSelectedRow >= 0) { + m_cumulatedHeightForSelectedIndex-= memoizedRowHeight(currentSelectedRow); + } else { + m_cumulatedHeightForSelectedIndex = 0; + } + } else if (previousSelectedRow != currentSelectedRow) { + resetMemoization(); + } +} + +KDCoordinate StorageExpressionModelListController::memoizedRowHeight(int j) { + if (j < 0) { + return 0; + } + int currentSelectedRow = selectedRow(); + constexpr int halfMemoizationCount = k_memoizedCellHeightsCount/2; + if (j >= currentSelectedRow - halfMemoizationCount && j <= currentSelectedRow + halfMemoizationCount) { + int memoizedIndex = j - (currentSelectedRow - halfMemoizationCount); + if (m_memoizedCellHeight[memoizedIndex] < 0) { + m_memoizedCellHeight[memoizedIndex] = expressionRowHeight(j); + } + return m_memoizedCellHeight[memoizedIndex]; + } + return expressionRowHeight(j); +} + +KDCoordinate StorageExpressionModelListController::memoizedCumulatedHeightFromIndex(int j) { + if (j <= 0) { + return 0; + } + int currentSelectedRow = selectedRow(); + constexpr int halfMemoizationCount = k_memoizedCellHeightsCount/2; + /* If j is not easily computable from the memoized values, compute it the hard + * way. */ + if (j < currentSelectedRow - halfMemoizationCount || j > currentSelectedRow + halfMemoizationCount) { + return notMemoizedCumulatedHeightFromIndex(j); + } + // Recompute the memoized cumulatedHeight if needed + if (m_cumulatedHeightForSelectedIndex < 0) { + m_cumulatedHeightForSelectedIndex = notMemoizedCumulatedHeightFromIndex(currentSelectedRow); + } + /* Compute the wanted cumulated height by adding/removing memoized cell + * heights */ + KDCoordinate result = m_cumulatedHeightForSelectedIndex; + if (j <= currentSelectedRow) { + /* If j is smaller than the selected row, remove cell heights from the + * memoized value */ + for (int i = j; i < currentSelectedRow; i++) { + result -= memoizedRowHeight(i); + } + } else { + /* If j is bigger than the selected row, add cell heights to the memoized + * value */ + assert(j > currentSelectedRow && j <= currentSelectedRow + halfMemoizationCount); + for (int i = currentSelectedRow; i < j; i++) { + result += memoizedRowHeight(i); + } + } + return result; +} + int StorageExpressionModelListController::numberOfExpressionRows() { return 1 + modelStore()->numberOfModels(); } @@ -122,4 +215,11 @@ bool StorageExpressionModelListController::isAddEmptyRow(int j) { return j == modelStore()->numberOfModels(); } +void StorageExpressionModelListController::resetMemoization() { + m_cumulatedHeightForSelectedIndex = -1; + for (int i = 0; i < k_memoizedCellHeightsCount; i++) { + m_memoizedCellHeight[i] = -1; + } +} + } diff --git a/apps/shared/storage_expression_model_list_controller.h b/apps/shared/storage_expression_model_list_controller.h index 5c6eaa806..43282e015 100644 --- a/apps/shared/storage_expression_model_list_controller.h +++ b/apps/shared/storage_expression_model_list_controller.h @@ -12,11 +12,15 @@ public: StorageExpressionModelListController(Responder * parentResponder, I18n::Message text); protected: static constexpr KDCoordinate k_expressionMargin = 5; - /* Table Data Source */ + // Memoization of cell heights + void tableSelectionDidChange(int previousSelectedRow); + KDCoordinate memoizedRowHeight(int j); + KDCoordinate memoizedCumulatedHeightFromIndex(int j); + // TableViewDataSource virtual int numberOfExpressionRows(); virtual KDCoordinate expressionRowHeight(int j); virtual void willDisplayExpressionCellAtIndex(HighlightCell * cell, int j); - /* Responder */ + // Responder bool handleEventOnExpression(Ion::Events::Event event); virtual void addEmptyModel(); virtual void didChangeModelsList() {} @@ -26,11 +30,20 @@ protected: virtual bool removeModelRow(Ion::Storage::Record record); virtual int modelIndexForRow(int j) { return j; } virtual bool isAddEmptyRow(int j); - /* View Controller */ + // ViewController virtual SelectableTableView * selectableTableView() = 0; virtual StorageExpressionModelStore * modelStore() = 0; virtual InputViewController * inputController() = 0; EvenOddMessageTextCell m_addNewModel; +private: + // Memoization + static constexpr int k_memoizedCellHeightsCount = 5; + static_assert(StorageExpressionModelListController::k_memoizedCellHeightsCount == 5, "Wrong array size in initialization of StorageExpressionModelListController::m_memoizedCellHeight."); +static_assert(StorageExpressionModelListController::k_memoizedCellHeightsCount % 2 == 1, "StorageExpressionModelListController::k_memoizedCellHeightsCount should be odd to be able to compute the middle element."); + void resetMemoization(); + virtual KDCoordinate notMemoizedCumulatedHeightFromIndex(int j) = 0; + KDCoordinate m_memoizedCellHeight[k_memoizedCellHeightsCount]; + KDCoordinate m_cumulatedHeightForSelectedIndex; }; } diff --git a/apps/shared/storage_function_list_controller.cpp b/apps/shared/storage_function_list_controller.cpp index 80241aac3..1628b1000 100644 --- a/apps/shared/storage_function_list_controller.cpp +++ b/apps/shared/storage_function_list_controller.cpp @@ -20,9 +20,7 @@ StorageFunctionListController::StorageFunctionListController(Responder * parentR TabViewController * tabController = list->tabController(); tabController->setActiveTab(2); }, this), KDFont::SmallFont, Palette::PurpleBright), - m_titlesColumnWidth(k_minTitleColumnWidth), - m_memoizedCellHeight {-1, -1, -1, -1, -1}, - m_cumulatedHeightForSelectedIndex(-1) + m_titlesColumnWidth(k_minTitleColumnWidth) { m_selectableTableView.setMargins(0); m_selectableTableView.setVerticalCellOverlap(0); @@ -36,54 +34,11 @@ void StorageFunctionListController::viewWillAppear() { } KDCoordinate StorageFunctionListController::rowHeight(int j) { - if (j < 0) { - return 0; - } - int currentSelectedRow = selectedRow(); - constexpr int halfMemoizationCount = k_memoizedCellHeightsCount/2; - if (j >= currentSelectedRow - halfMemoizationCount && j <= currentSelectedRow + halfMemoizationCount) { - int memoizedIndex = j - (currentSelectedRow - halfMemoizationCount); - if (m_memoizedCellHeight[memoizedIndex] < 0) { - m_memoizedCellHeight[memoizedIndex] = expressionRowHeight(j); - } - return m_memoizedCellHeight[memoizedIndex]; - } - return expressionRowHeight(j); + return StorageExpressionModelListController::memoizedRowHeight(j); } KDCoordinate StorageFunctionListController::cumulatedHeightFromIndex(int j) { - if (j <= 0) { - return 0; - } - int currentSelectedRow = selectedRow(); - constexpr int halfMemoizationCount = k_memoizedCellHeightsCount/2; - /* If j is not easily computable from the memoized values, compute it the hard - * way. */ - if (j < currentSelectedRow - halfMemoizationCount || j > currentSelectedRow + halfMemoizationCount) { - return TableViewDataSource::cumulatedHeightFromIndex(j); - } - // Recompute the memoized cumulatedHeight if needed - if (m_cumulatedHeightForSelectedIndex < 0) { - m_cumulatedHeightForSelectedIndex = TableViewDataSource::cumulatedHeightFromIndex(currentSelectedRow); - } - /* Compute the wanted cumulated height by adding/removing memoized cell - * heights */ - KDCoordinate result = m_cumulatedHeightForSelectedIndex; - if (j <= currentSelectedRow) { - /* If j is smaller than the selected row, remove cell heights from the - * memoized value */ - for (int i = j; i < currentSelectedRow; i++) { - result -= rowHeight(i); - } - } else { - /* If j is bigger than the selected row, add cell heights to the memoized - * value */ - assert(j > currentSelectedRow && j <= currentSelectedRow + halfMemoizationCount); - for (int i = currentSelectedRow; i < j; i++) { - result += rowHeight(i); - } - } - return result; + return StorageExpressionModelListController::memoizedCumulatedHeightFromIndex(j); } KDCoordinate StorageFunctionListController::columnWidth(int i) { @@ -260,44 +215,9 @@ void StorageFunctionListController::willExitResponderChain(Responder * nextFirst /* SelectableTableViewDelegate */ void StorageFunctionListController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) { - constexpr int currentSelectedMemoizedIndex = k_memoizedCellHeightsCount/2 + 1; // Needs k_memoizedCellHeightsCount to be odd, which is static asserted in storage_function_list_controller.h - int currentSelectedY = selectedRow(); - - // The previously selected cell's height might have changed. - m_memoizedCellHeight[currentSelectedMemoizedIndex] = -1; - - // Update m_cumulatedHeightForSelectedIndex if we scrolled one cell up/down - if (currentSelectedY == previousSelectedCellY + 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] = -1; - // Update m_cumulatedHeightForSelectedIndex - if (previousSelectedCellY >= 0) { - m_cumulatedHeightForSelectedIndex+= rowHeight(previousSelectedCellY); - } else { - assert(currentSelectedY == 0); - m_cumulatedHeightForSelectedIndex = 0; - } - } else if (currentSelectedY == previousSelectedCellY - 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] = -1; - // Update m_cumulatedHeightForSelectedIndex - if (currentSelectedY >= 0) { - m_cumulatedHeightForSelectedIndex-= rowHeight(currentSelectedY); - } else { - m_cumulatedHeightForSelectedIndex = 0; - } - } else if (previousSelectedCellY != currentSelectedY) { - resetMemoization(); - } - + // Update memoization of cell heights + StorageExpressionModelListController::tableSelectionDidChange(previousSelectedCellY); + // Do not select the cell left of the "addEmptyFunction" cell if (isAddEmptyRow(selectedRow()) && selectedColumn() == 0) { t->selectCellAtLocation(1, numberOfRows()-1); } @@ -351,11 +271,8 @@ void StorageFunctionListController::didChangeModelsList() { computeTitlesColumnWidth(); } -void StorageFunctionListController::resetMemoization() { - m_cumulatedHeightForSelectedIndex = -1; - for (int i = 0; i < k_memoizedCellHeightsCount; i++) { - m_memoizedCellHeight[i] = -1; - } +KDCoordinate StorageFunctionListController::notMemoizedCumulatedHeightFromIndex(int j) { + return TableViewDataSource::cumulatedHeightFromIndex(j); } } diff --git a/apps/shared/storage_function_list_controller.h b/apps/shared/storage_function_list_controller.h index 98cea28ec..c47644ad1 100644 --- a/apps/shared/storage_function_list_controller.h +++ b/apps/shared/storage_function_list_controller.h @@ -58,25 +58,20 @@ protected: private: static constexpr KDCoordinate k_minTitleColumnWidth = 65; static constexpr KDCoordinate k_functionTitleSumOfMargins = 2*Metric::HistoryHorizontalMargin; - static constexpr int k_memoizedCellHeightsCount = 5; - static_assert(StorageFunctionListController::k_memoizedCellHeightsCount == 5, "Wrong array size in initialization of StorageFunctionListController::m_memoizedCellHeight."); -static_assert(StorageFunctionListController::k_memoizedCellHeightsCount % 2 == 1, "StorageFunctionListController::k_memoizedCellHeightsCount should be odd to be able to compute the middle element."); TabViewController * tabController() const; InputViewController * inputController() override; KDCoordinate maxFunctionNameWidth(); void didChangeModelsList() override; + KDCoordinate notMemoizedCumulatedHeightFromIndex(int j) override; virtual StorageListParameterController * parameterController() = 0; virtual int maxNumberOfDisplayableRows() = 0; virtual FunctionTitleCell * titleCells(int index) = 0; virtual HighlightCell * expressionCells(int index) = 0; virtual void willDisplayTitleCellAtIndex(HighlightCell * cell, int j) = 0; - void resetMemoization(); EvenOddCell m_emptyCell; Button m_plotButton; Button m_valuesButton; KDCoordinate m_titlesColumnWidth; - KDCoordinate m_memoizedCellHeight[k_memoizedCellHeightsCount]; - KDCoordinate m_cumulatedHeightForSelectedIndex; }; }