recovery: compute displayable item count while drawing

Change-Id: Iece9359a5d7fd768748716bc9281578650fcc2d0
diff --git a/recovery_ui/include/recovery_ui/screen_ui.h b/recovery_ui/include/recovery_ui/screen_ui.h
index 7a3b72d..f9336ab 100644
--- a/recovery_ui/include/recovery_ui/screen_ui.h
+++ b/recovery_ui/include/recovery_ui/screen_ui.h
@@ -107,6 +107,7 @@
   virtual int DrawItems(int x, int y, int screen_width, bool long_press) const = 0;
   virtual size_t ItemsCount() const = 0;
   virtual bool IsMain() const = 0;
+  virtual void SetMenuHeight(int height) = 0;
 
  protected:
   Menu(size_t initial_selection, const DrawInterface& draw_func);
@@ -121,7 +122,7 @@
  public:
   // Constructs a Menu instance with the given |headers|, |items| and properties. Sets the initial
   // selection to |initial_selection|.
-  TextMenu(bool wrappable, size_t max_items, size_t max_length,
+  TextMenu(bool wrappable, size_t max_length,
            const std::vector<std::string>& headers, const std::vector<std::string>& items,
            size_t initial_selection, int char_height, const DrawInterface& draw_funcs);
 
@@ -165,11 +166,23 @@
   // |cur_selection_str| if the items exceed the screen limit.
   bool ItemsOverflow(std::string* cur_selection_str) const;
 
+  // The number of displayable items is only known after we started drawing the menu (to consider logo, header, etc.)
+  // Make it settable after the menu is created
+  void SetMenuHeight(int height) {
+    if (!calibrated_height_) {
+      max_display_items_ = height / draw_funcs_.MenuItemHeight();
+      menu_start_ = std::max(0, (int)selection_ - (int)max_display_items_ + 1);
+      calibrated_height_ = true;
+    }
+  }
+
  private:
   // The menu is scrollable to display more items. Used on wear devices who have smaller screens.
   const bool wrappable_;
+  // Did we compute our max height already?
+  bool calibrated_height_;
   // The max number of menu items to fit vertically on a screen.
-  const size_t max_display_items_;
+  size_t max_display_items_;
   // The length of each item to fit horizontally on a screen.
   const size_t max_item_length_;
   // The menu headers.
@@ -204,6 +217,7 @@
   bool IsMain() const override {
     return true;
   }
+  void SetMenuHeight(int height __unused) override {}
 
   // Checks if all the header and items are valid GRSurface's; and that they can fit in the area
   // defined by |max_width| and |max_height|.
diff --git a/recovery_ui/screen_ui.cpp b/recovery_ui/screen_ui.cpp
index c9c2cd7..63c4d4a 100644
--- a/recovery_ui/screen_ui.cpp
+++ b/recovery_ui/screen_ui.cpp
@@ -67,22 +67,20 @@
   return selection_;
 }
 
-TextMenu::TextMenu(bool wrappable, size_t max_items, size_t max_length,
+TextMenu::TextMenu(bool wrappable, size_t max_length,
                    const std::vector<std::string>& headers, const std::vector<std::string>& items,
                    size_t initial_selection, int char_height, const DrawInterface& draw_funcs)
     : Menu(initial_selection, draw_funcs),
       wrappable_(wrappable),
-      max_display_items_(max_items),
+      calibrated_height_(false),
       max_item_length_(max_length),
       text_headers_(headers),
       char_height_(char_height) {
-  CHECK_LE(max_items, static_cast<size_t>(std::numeric_limits<int>::max()));
 
   size_t items_count = items.size();
   for (size_t i = 0; i < items_count; ++i) {
     text_items_.emplace_back(items[i].substr(0, max_item_length_));
   }
-  menu_start_ = std::max(0, (int)selection_ - (int)max_display_items_ + 1);
 
   CHECK(!text_items_.empty());
 }
@@ -832,6 +830,7 @@
 
     y += menu_->DrawHeader(x, y);
     menu_start_y_ = y + 12; // Skip horizontal rule and some margin
+    menu_->SetMenuHeight(std::max(0, ScreenHeight() - menu_start_y_));
     y += menu_->DrawItems(x, y, ScreenWidth(), IsLongPress());
   }
 
@@ -1324,12 +1323,9 @@
                                                    size_t initial_selection) const {
   int menu_char_width = MenuCharWidth();
   int menu_char_height = MenuCharHeight();
-  int menu_item_padding = MenuItemPadding();
-  int menu_rows = (ScreenHeight() - margin_height_*2 - gr_get_height(lineage_logo_.get()))
-                  / (menu_char_height + 2 * menu_item_padding) - text_headers.size();
   int menu_cols = (ScreenWidth() - margin_width_*2 - kMenuIndent) / menu_char_width;
   bool wrap_selection = !HasThreeButtons() && !HasTouchScreen();
-  return std::make_unique<TextMenu>(wrap_selection, menu_rows, menu_cols, text_headers, text_items,
+  return std::make_unique<TextMenu>(wrap_selection, menu_cols, text_headers, text_items,
                                     initial_selection, menu_char_height, *menu_draw_funcs_);
 }
 
diff --git a/recovery_ui/wear_ui.cpp b/recovery_ui/wear_ui.cpp
index 7aaf59b..ecedc1c 100644
--- a/recovery_ui/wear_ui.cpp
+++ b/recovery_ui/wear_ui.cpp
@@ -99,9 +99,8 @@
                                                  const std::vector<std::string>& text_items,
                                                  size_t initial_selection) const {
   if (text_rows_ > 0 && text_cols_ > 0) {
-    return std::make_unique<TextMenu>(false, text_rows_ - menu_unusable_rows_ - 1,
-                                      text_cols_ - 1, text_headers, text_items, initial_selection,
-                                      char_height_, *this);
+    return std::make_unique<TextMenu>(false, text_cols_ - 1, text_headers, text_items,
+                                      initial_selection, char_height_, *this);
   }
 
   return nullptr;