Merge from ClockworkMod recovery

Change-Id: Id5b312147173ced559a62d97029acede6c2f8766
diff --git a/ui.c b/ui.c
index 84a9b85..d973a50 100644
--- a/ui.c
+++ b/ui.c
@@ -29,11 +29,25 @@
 #include "minui/minui.h"
 #include "recovery_ui.h"
 
+#ifdef BOARD_HAS_NO_SELECT_BUTTON
+static int gShowBackButton = 1;
+#else
+static int gShowBackButton = 0;
+#endif
+
 #define MAX_COLS 96
 #define MAX_ROWS 32
 
-#define CHAR_WIDTH 10
-#define CHAR_HEIGHT 18
+#define MENU_MAX_COLS 64
+#define MENU_MAX_ROWS 250
+
+#ifndef BOARD_LDPI_RECOVERY
+  #define CHAR_WIDTH 10
+  #define CHAR_HEIGHT 18
+#else
+  #define CHAR_WIDTH 7
+  #define CHAR_HEIGHT 16
+#endif
 
 #define PROGRESSBAR_INDETERMINATE_STATES 6
 #define PROGRESSBAR_INDETERMINATE_FPS 15
@@ -43,6 +57,7 @@
 static gr_surface gProgressBarIndeterminate[PROGRESSBAR_INDETERMINATE_STATES];
 static gr_surface gProgressBarEmpty;
 static gr_surface gProgressBarFill;
+static int ui_has_initialized = 0;
 
 static const struct { gr_surface* surface; const char *name; } BITMAPS[] = {
     { &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" },
@@ -79,9 +94,10 @@
 static int text_col = 0, text_row = 0, text_top = 0;
 static int show_text = 0;
 
-static char menu[MAX_ROWS][MAX_COLS];
+static char menu[MENU_MAX_ROWS][MENU_MAX_COLS];
 static int show_menu = 0;
 static int menu_top = 0, menu_items = 0, menu_sel = 0;
+static int menu_show_start = 0;             // this is line which menu display is starting at 
 
 // Key event input queue
 static pthread_mutex_t key_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -148,10 +164,15 @@
   }
 }
 
+#define MENU_TEXT_COLOR 7, 133, 74, 255
+#define NORMAL_TEXT_COLOR 200, 200, 200, 255
+#define HEADER_TEXT_COLOR NORMAL_TEXT_COLOR
+
 // Redraw everything on the screen.  Does not flip pages.
 // Should only be called with gUpdateMutex locked.
 static void draw_screen_locked(void)
 {
+    if (!ui_has_initialized) return;
     draw_background_locked(gCurrentIcon);
     draw_progress_locked();
 
@@ -160,29 +181,43 @@
         gr_fill(0, 0, gr_fb_width(), gr_fb_height());
 
         int i = 0;
+        int j = 0;
+        int row = 0;            // current row that we are drawing on
         if (show_menu) {
-            gr_color(64, 96, 255, 255);
-            gr_fill(0, (menu_top+menu_sel) * CHAR_HEIGHT,
-                    gr_fb_width(), (menu_top+menu_sel+1)*CHAR_HEIGHT+1);
+            gr_color(MENU_TEXT_COLOR);
+            gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
+                    gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);
 
-            for (; i < menu_top + menu_items; ++i) {
+            gr_color(HEADER_TEXT_COLOR);
+            for (i = 0; i < menu_top; ++i) {
+                draw_text_line(i, menu[i]);
+                row++;
+            }
+
+            if (menu_items - menu_show_start + menu_top >= MAX_ROWS)
+                j = MAX_ROWS - menu_top;
+            else
+                j = menu_items - menu_show_start;
+
+            gr_color(MENU_TEXT_COLOR);
+            for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                 if (i == menu_top + menu_sel) {
                     gr_color(255, 255, 255, 255);
-                    draw_text_line(i, menu[i]);
-                    gr_color(64, 96, 255, 255);
+                    draw_text_line(i - menu_show_start , menu[i]);
+                    gr_color(MENU_TEXT_COLOR);
                 } else {
-                    draw_text_line(i, menu[i]);
+                    gr_color(MENU_TEXT_COLOR);
+                    draw_text_line(i - menu_show_start, menu[i]);
                 }
+                row++;
             }
-            gr_fill(0, i*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
-                    gr_fb_width(), i*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
-            ++i;
+            gr_fill(0, row*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
+                    gr_fb_width(), row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
         }
 
-        gr_color(255, 255, 0, 255);
-
-        for (; i < text_rows; ++i) {
-            draw_text_line(i, text[(i+text_top) % text_rows]);
+        gr_color(NORMAL_TEXT_COLOR);
+        for (; row < text_rows; ++row) {
+            draw_text_line(row, text[(row+text_top) % text_rows]);
         }
     }
 }
@@ -191,6 +226,7 @@
 // Should only be called with gUpdateMutex locked.
 static void update_screen_locked(void)
 {
+    if (!ui_has_initialized) return;
     draw_screen_locked();
     gr_flip();
 }
@@ -199,6 +235,7 @@
 // Should only be called with gUpdateMutex locked.
 static void update_progress_locked(void)
 {
+    if (!ui_has_initialized) return;
     if (show_text || !gPagesIdentical) {
         draw_screen_locked();    // Must redraw the whole screen
         gPagesIdentical = 1;
@@ -308,6 +345,7 @@
 
 void ui_init(void)
 {
+    ui_has_initialized = 1;
     gr_init();
     ev_init();
 
@@ -337,6 +375,23 @@
     pthread_create(&t, NULL, input_thread, NULL);
 }
 
+char *ui_copy_image(int icon, int *width, int *height, int *bpp) {
+    pthread_mutex_lock(&gUpdateMutex);
+    draw_background_locked(gBackgroundIcon[icon]);
+    *width = gr_fb_width();
+    *height = gr_fb_height();
+    *bpp = sizeof(gr_pixel) * 8;
+    int size = *width * *height * sizeof(gr_pixel);
+    char *ret = malloc(size);
+    if (ret == NULL) {
+        LOGE("Can't allocate %d bytes for image\n", size);
+    } else {
+        memcpy(ret, gr_fb_data(), size);
+    }
+    pthread_mutex_unlock(&gUpdateMutex);
+    return ret;
+}
+
 void ui_set_background(int icon)
 {
     pthread_mutex_lock(&gUpdateMutex);
@@ -425,7 +480,17 @@
     pthread_mutex_unlock(&gUpdateMutex);
 }
 
-void ui_start_menu(char** headers, char** items, int initial_selection) {
+void ui_reset_text_col()
+{
+    pthread_mutex_lock(&gUpdateMutex);
+    text_col = 0;
+    pthread_mutex_unlock(&gUpdateMutex);
+}
+
+#define MENU_ITEM_HEADER " - "
+#define MENU_ITEM_HEADER_LENGTH strlen(MENU_ITEM_HEADER)
+
+int ui_start_menu(char** headers, char** items, int initial_selection) {
     int i;
     pthread_mutex_lock(&gUpdateMutex);
     if (text_rows > 0 && text_cols > 0) {
@@ -435,17 +500,28 @@
             menu[i][text_cols-1] = '\0';
         }
         menu_top = i;
-        for (; i < text_rows; ++i) {
+        for (; i < MENU_MAX_ROWS; ++i) {
             if (items[i-menu_top] == NULL) break;
-            strncpy(menu[i], items[i-menu_top], text_cols-1);
+            strcpy(menu[i], MENU_ITEM_HEADER);
+            strncpy(menu[i] + MENU_ITEM_HEADER_LENGTH, items[i-menu_top], text_cols-1 - MENU_ITEM_HEADER_LENGTH);
             menu[i][text_cols-1] = '\0';
         }
+
+        if (gShowBackButton) {
+            strcpy(menu[i], " - +++++Go Back+++++");
+            ++i;
+        }
+
         menu_items = i - menu_top;
         show_menu = 1;
-        menu_sel = initial_selection;
+        menu_sel = menu_show_start = initial_selection;
         update_screen_locked();
     }
     pthread_mutex_unlock(&gUpdateMutex);
+    if (gShowBackButton) {
+        return menu_items - 1;
+    }
+    return menu_items;
 }
 
 int ui_menu_select(int sel) {
@@ -454,9 +530,21 @@
     if (show_menu > 0) {
         old_sel = menu_sel;
         menu_sel = sel;
-        if (menu_sel < 0) menu_sel = 0;
-        if (menu_sel >= menu_items) menu_sel = menu_items-1;
+
+        if (menu_sel < 0) menu_sel = menu_items + menu_sel;
+        if (menu_sel >= menu_items) menu_sel = menu_sel - menu_items;
+
+
+        if (menu_sel < menu_show_start && menu_show_start > 0) {
+            menu_show_start = menu_sel;
+        }
+
+        if (menu_sel - menu_show_start + menu_top >= text_rows) {
+            menu_show_start = menu_sel + menu_top - text_rows + 1;
+        }
+
         sel = menu_sel;
+
         if (menu_sel != old_sel) update_screen_locked();
     }
     pthread_mutex_unlock(&gUpdateMutex);
@@ -513,3 +601,15 @@
     key_queue_len = 0;
     pthread_mutex_unlock(&key_queue_mutex);
 }
+
+void ui_set_show_text(int value) {
+    show_text = value;
+}
+
+void ui_set_showing_back_button(int showBackButton) {
+    gShowBackButton = showBackButton;
+}
+
+int ui_get_showing_back_button() {
+    return gShowBackButton;
+}