diff options
Diffstat (limited to 'screen_ui.cpp')
-rw-r--r-- | screen_ui.cpp | 553 |
1 files changed, 435 insertions, 118 deletions
diff --git a/screen_ui.cpp b/screen_ui.cpp index ff95915..46f4add 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -30,16 +30,16 @@ #include <vector> -#include "base/strings.h" -#include "cutils/properties.h" +#include <base/strings.h> +#include <base/stringprintf.h> +#include <cutils/properties.h> + #include "common.h" #include "device.h" #include "minui/minui.h" #include "screen_ui.h" #include "ui.h" - -static int char_width; -static int char_height; +#include "cutils/properties.h" // Return the current time as a double (including fractions of a second). static double now() { @@ -58,6 +58,8 @@ ScreenRecoveryUI::ScreenRecoveryUI() : progressScopeSize(0), progress(0), pagesIdentical(false), + log_text_cols_(0), + log_text_rows_(0), text_cols_(0), text_rows_(0), text_(nullptr), @@ -66,20 +68,34 @@ ScreenRecoveryUI::ScreenRecoveryUI() : text_top_(0), show_text(false), show_text_ever(false), + dialog_icon(NONE), + dialog_text(nullptr), + dialog_show_log(false), menu_(nullptr), + menu_headers_(nullptr), + header_items(0), show_menu(false), menu_items(0), menu_sel(0), + sysbar_state(0), file_viewer_text_(nullptr), animation_fps(20), installing_frames(-1), stage(-1), - max_stage(-1) { - - for (int i = 0; i < 5; i++) { + max_stage(-1), + rainbow(false), + wrap_count(0) { + + headerIcon = nullptr; + sysbarBackIcon = nullptr; + sysbarBackHighlightIcon = nullptr; + sysbarHomeIcon = nullptr; + sysbarHomeHighlightIcon = nullptr; + for (int i = 0; i < NR_ICONS; i++) { backgroundIcon[i] = nullptr; } pthread_mutex_init(&updateMutex, nullptr); + pthread_cond_init(&progressCondition, NULL); } // Clear the screen and draw the currently selected background icon (if any). @@ -101,14 +117,16 @@ void ScreenRecoveryUI::draw_background_locked(Icon icon) { int textWidth = gr_get_width(text_surface); int textHeight = gr_get_height(text_surface); int stageHeight = gr_get_height(stageMarkerEmpty); + int availableHeight = icon == INSTALLING_UPDATE && !DialogShowing() && show_text + ? 3 * gr_fb_height() / 4 : gr_fb_height(); int sh = (max_stage >= 0) ? stageHeight : 0; iconX = (gr_fb_width() - iconWidth) / 2; - iconY = (gr_fb_height() - (iconHeight+textHeight+40+sh)) / 2; + iconY = (availableHeight - (iconHeight+textHeight+40+sh)) / 2; int textX = (gr_fb_width() - textWidth) / 2; - int textY = ((gr_fb_height() - (iconHeight+textHeight+40+sh)) / 2) + iconHeight + 40; + int textY = ((availableHeight - (iconHeight+textHeight+40+sh)) / 2) + iconHeight + 40; gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY); if (stageHeight > 0) { @@ -122,6 +140,8 @@ void ScreenRecoveryUI::draw_background_locked(Icon icon) { } } + LOGV("textX=%d textY=%d iconX=%d iconY=%d", textX, textY, iconX, iconY); + gr_color(255, 255, 255, 255); gr_texticon(textX, textY, text_surface); } @@ -130,7 +150,7 @@ void ScreenRecoveryUI::draw_background_locked(Icon icon) { // Draw the progress bar (if any) on the screen. Does not flip pages. // Should only be called with updateMutex locked. void ScreenRecoveryUI::draw_progress_locked() { - if (currentIcon == ERROR) return; + if (currentIcon == D_ERROR) return; if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { GRSurface* icon = installation[installingFrame]; @@ -142,8 +162,11 @@ void ScreenRecoveryUI::draw_progress_locked() { int width = gr_get_width(progressBarEmpty); int height = gr_get_height(progressBarEmpty); - int dx = (gr_fb_width() - width)/2; - int dy = (3*gr_fb_height() + iconHeight - 2*height)/4; + int bottomOfUsableHeight = show_text ? 3 * gr_fb_height() / 4 : gr_fb_height(); + int bottomOfIcon = bottomOfUsableHeight / 2 + iconHeight / 2; + + int dx = (gr_fb_width() - width) / 2; + int dy = bottomOfIcon + (bottomOfUsableHeight - bottomOfIcon) / 2 - height / 2; // Erase behind the progress bar (in case this was a progress-only update) gr_color(0, 0, 0, 255); @@ -184,13 +207,13 @@ void ScreenRecoveryUI::SetColor(UIElement e) { break; case MENU: case MENU_SEL_BG: - gr_color(0, 106, 157, 255); + gr_color(106, 103, 102, 255); break; case MENU_SEL_BG_ACTIVE: - gr_color(0, 156, 100, 255); + gr_color(138, 135, 134, 255); break; case MENU_SEL_FG: - gr_color(255, 255, 255, 255); + gr_color(0, 177, 229, 255); break; case LOG: gr_color(196, 196, 196, 255); @@ -198,6 +221,9 @@ void ScreenRecoveryUI::SetColor(UIElement e) { case TEXT_FILL: gr_color(0, 0, 0, 160); break; + case ERROR_TEXT: + gr_color(255, 0, 0, 255); + break; default: gr_color(255, 255, 255, 255); break; @@ -213,7 +239,7 @@ void ScreenRecoveryUI::DrawHorizontalRule(int* y) { void ScreenRecoveryUI::DrawTextLine(int* y, const char* line, bool bold) { gr_text(4, *y, line, bold); - *y += char_height + 4; + *y += char_height_ + 4; } void ScreenRecoveryUI::DrawTextLines(int* y, const char* const* lines) { @@ -233,63 +259,193 @@ static const char* LONG_PRESS_HELP[] = { NULL }; +int ScreenRecoveryUI::draw_header_icon() +{ + GRSurface* surface = headerIcon; + int iw = header_width_; + int ih = header_height_; + int ix = (gr_fb_width() - iw) / 2; + int iy = 0; + gr_blit(surface, 0, 0, iw, ih, ix, iy); + return ih; +} + +void ScreenRecoveryUI::draw_menu_item(int textrow, const char *text, int selected) +{ + if (selected) { + SetColor(MENU_SEL_BG); + gr_fill(0, (textrow) * char_height_, + gr_fb_width(), (textrow+3) * char_height_ - 1); + SetColor(MENU_SEL_FG); + gr_text(4, (textrow+1) * char_height_ - 1, text, 0); + SetColor(MENU); + } + else { + SetColor(MENU); + gr_text(4, (textrow+1) * char_height_ - 1, text, 0); + } +} + +void ScreenRecoveryUI::draw_sysbar() +{ + GRSurface* surface; + int sw = gr_fb_width(); + int sh = gr_fb_height(); + int iw; + int ih; + SetColor(TEXT_FILL); + gr_fill(0, sh - sysbar_height_, sw, sh); + + // Left third is back button + if (!HasBackKey()) { + if (sysbar_state & SYSBAR_BACK) { + surface = sysbarBackHighlightIcon; + } + else { + surface = sysbarBackIcon; + } + iw = gr_get_width(surface); + ih = gr_get_height(surface); + gr_blit(surface, 0, 0, iw, ih, + 1 * (sw / 6) - (iw / 2), sh - ih); + } + + // Middle third is home button + if (!HasHomeKey()) { + if (sysbar_state & SYSBAR_HOME) { + surface = sysbarHomeHighlightIcon; + } + else { + surface = sysbarHomeIcon; + } + iw = gr_get_width(surface); + ih = gr_get_height(surface); + gr_blit(surface, 0, 0, iw, ih, + 3 * (sw / 6) - (iw / 2), sh - ih); + } +} + +void ScreenRecoveryUI::draw_dialog() +{ + int x, y, w, h; + + if (dialog_icon == HEADLESS) { + return; + } + draw_header_icon(); + draw_sysbar(); + + int iconHeight = gr_get_height(backgroundIcon[dialog_icon]); + + x = (gr_fb_width()/2 - (char_width_ * strlen(dialog_text))/2); + if (dialog_show_log) { + y = gr_get_height(headerIcon) + char_height_; + } + else { + y = (gr_fb_height()/2 + iconHeight/2); + } + + SetColor(ERROR_TEXT); + gr_text(x, y, dialog_text, 0); + y += char_height_ + 2; + + if (dialog_show_log) { + int cx, cy; + gr_set_font("log"); + gr_font_size(&cx, &cy); + + size_t row; + for (row = 0; row < log_text_rows_; ++row) { + gr_text(2, y, text_[row], 0); + y += cy + 2; + } + gr_set_font("menu"); + } + + if (dialog_icon == D_ERROR) { + /* + * This could be improved... + * + * Draw rect around text "Okay". + * Text is centered horizontally. + * Bottom of text is 4 lines from bottom of screen. + * Rect width 4px + * Rect padding 8px + */ + w = char_width_ * 4; + h = char_height_; + x = gr_fb_width()/2 - w/2; + y = gr_fb_height() - h - 4 * char_height_; + SetColor(HEADER); + gr_fill(x-(4+8), y-(4+8), x+w+(4+8), y+h+(4+8)); + SetColor(MENU_SEL_BG); + gr_fill(x-8, y-8, x+w+8, y+h+8); + SetColor(MENU_SEL_FG); + gr_text(x, y, "Okay", 0); + } +} + // Redraw everything on the screen. Does not flip pages. // Should only be called with updateMutex locked. void ScreenRecoveryUI::draw_screen_locked() { - if (!show_text) { - draw_background_locked(currentIcon); - draw_progress_locked(); - } else { - gr_color(0, 0, 0, 255); - gr_clear(); + draw_background_locked(currentIcon); - int y = 0; - if (show_menu) { - char recovery_fingerprint[PROPERTY_VALUE_MAX]; - property_get("ro.bootimage.build.fingerprint", recovery_fingerprint, ""); + if (DialogShowing()) { + draw_dialog(); + return; + } - SetColor(INFO); - DrawTextLine(&y, "Android Recovery", true); - for (auto& chunk : android::base::Split(recovery_fingerprint, ":")) { - DrawTextLine(&y, chunk.c_str(), false); - } - DrawTextLines(&y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP); - - SetColor(HEADER); - DrawTextLines(&y, menu_headers_); - - SetColor(MENU); - DrawHorizontalRule(&y); - y += 4; - for (int i = 0; i < menu_items; ++i) { - if (i == menu_sel) { - // Draw the highlight bar. - SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG); - gr_fill(0, y - 2, gr_fb_width(), y + char_height + 2); - // Bold white text for the selected item. - SetColor(MENU_SEL_FG); - gr_text(4, y, menu_[i], true); - SetColor(MENU); - } else { - gr_text(4, y, menu_[i], false); - } - y += char_height + 4; + if (show_text) { + if (currentIcon == ERASING || currentIcon == INSTALLING_UPDATE || currentIcon == VIEWING_LOG) { + size_t y = currentIcon == INSTALLING_UPDATE ? gr_fb_height() / 4 : header_height_ + 4; + + SetColor(LOG); + int cx, cy; + gr_set_font("log"); + gr_font_size(&cx, &cy); + // display from the bottom up, until we hit the top of the + // screen or we've displayed the entire text buffer. + size_t ty, count; + int row = (text_first_row_ + log_text_rows_ - 1) % log_text_rows_; + for (ty = gr_fb_height() - cy, count = 0; + ty > y + 2 && count < log_text_rows_; + ty -= (cy + 2), ++count) { + gr_text(4, ty, text_[row], 0); + --row; + if (row < 0) row = log_text_rows_ - 1; } - DrawHorizontalRule(&y); + gr_set_font("menu"); + return; } - // display from the bottom up, until we hit the top of the - // screen, the bottom of the menu, or we've displayed the - // entire text buffer. - SetColor(LOG); - int row = (text_top_ + text_rows_ - 1) % text_rows_; - size_t count = 0; - for (int ty = gr_fb_height() - char_height; - ty >= y && count < text_rows_; - ty -= char_height, ++count) { - gr_text(0, ty, text_[row], false); - --row; - if (row < 0) row = text_rows_ - 1; + if (show_menu) { + int i, y; + draw_header_icon(); + draw_sysbar(); + + // Divider + y = text_first_row_ * char_height_; + SetColor(MENU_SEL_FG); + gr_fill(0, y - 1, gr_fb_width(), y); + + if (header_items > 0) { + for (i = 0; i < header_items; ++i) { + draw_menu_item(text_first_row_ + 3*i, + menu_headers_[i], false); + } + y = (text_first_row_ + 3*header_items) * char_height_; + SetColor(MENU_SEL_FG); + gr_fill(0, y - 1, gr_fb_width(), y); + } + int nr_items = menu_items - menu_show_start_; + if (header_items + nr_items > max_menu_rows_) + nr_items = max_menu_rows_ - header_items; + for (i = 0; i < nr_items; ++i) { + const char* text = menu_[menu_show_start_ + i]; + draw_menu_item(text_first_row_ + 3 * (header_items + i), + menu_[menu_show_start_ + i], + ((menu_show_start_ + i) == menu_sel)); + } } } } @@ -297,20 +453,9 @@ void ScreenRecoveryUI::draw_screen_locked() { // Redraw everything on the screen and flip the screen (make it visible). // Should only be called with updateMutex locked. void ScreenRecoveryUI::update_screen_locked() { - draw_screen_locked(); - gr_flip(); -} - -// Updates only the progress bar, if possible, otherwise redraws the screen. -// Should only be called with updateMutex locked. -void ScreenRecoveryUI::update_progress_locked() { - if (show_text || !pagesIdentical) { - draw_screen_locked(); // Must redraw the whole screen - pagesIdentical = true; - } else { - draw_progress_locked(); // Draw only the progress bar and overlays - } - gr_flip(); + update_waiting = true; + pthread_cond_signal(&progressCondition); + LOGV("%s: %p\n", __func__, __builtin_return_address(0)); } // Keeps the progress bar updated, even when the process is otherwise busy. @@ -319,20 +464,31 @@ void* ScreenRecoveryUI::ProgressThreadStartRoutine(void* data) { return nullptr; } +void ScreenRecoveryUI::OMGRainbows() +{ + rainbow = rainbow ? false : true; + set_rainbow_mode(rainbow); + property_set("sys.rainbow.recovery", rainbow ? "1" : "0"); +} + void ScreenRecoveryUI::ProgressThreadLoop() { double interval = 1.0 / animation_fps; while (true) { - double start = now(); pthread_mutex_lock(&updateMutex); + if (progressBarType == EMPTY && !update_waiting) + pthread_cond_wait(&progressCondition, &updateMutex); - int redraw = 0; + bool redraw = false; + double start = now(); + + LOGV("loop %f show_text=%d progressBarType=%d waiting=%d\n", start, show_text, progressBarType, update_waiting ); // update the installation animation, if active // skip this if we have a text overlay (too expensive to update) if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) && - installing_frames > 0 && !show_text) { + installing_frames > 0) { installingFrame = (installingFrame + 1) % installing_frames; - redraw = 1; + redraw = true; } // move the progress bar forward on timed intervals, if configured @@ -343,13 +499,26 @@ void ScreenRecoveryUI::ProgressThreadLoop() { if (p > 1.0) p = 1.0; if (p > progress) { progress = p; - redraw = 1; + redraw = true; } } - if (redraw) update_progress_locked(); + if (update_waiting || !pagesIdentical) { + LOGV("call draw_screen_locked\n"); + draw_screen_locked(); + if (!update_waiting) + pagesIdentical = true; + } + if (redraw) { + LOGV("call draw_progress_locked\n"); + draw_progress_locked(); + } + gr_flip(); + + update_waiting = false; pthread_mutex_unlock(&updateMutex); + double end = now(); // minimum of 20ms delay between frames double delay = interval - (end-start); @@ -391,23 +560,47 @@ static char** Alloc2d(size_t rows, size_t cols) { void ScreenRecoveryUI::Init() { gr_init(); - gr_font_size(&char_width, &char_height); - text_rows_ = gr_fb_height() / char_height; - text_cols_ = gr_fb_width() / char_width; + gr_set_font("log"); + gr_font_size(&log_char_width_, &log_char_height_); + gr_set_font("menu"); + gr_font_size(&char_width_, &char_height_); + + text_col_ = text_row_ = 0; + text_top_ = 1; + + LoadBitmap("icon_header", &headerIcon); + LoadBitmap("icon_sysbar_back", &sysbarBackIcon); + LoadBitmap("icon_sysbar_back_highlight", &sysbarBackHighlightIcon); + LoadBitmap("icon_sysbar_home", &sysbarHomeIcon); + LoadBitmap("icon_sysbar_home_highlight", &sysbarHomeHighlightIcon); + + header_height_ = gr_get_height(headerIcon); + header_width_ = gr_get_width(headerIcon); + + sysbar_height_ = gr_get_height(sysbarBackIcon); - text_ = Alloc2d(text_rows_, text_cols_ + 1); + text_rows_ = (gr_fb_height() - sysbar_height_) / char_height_; + text_cols_ = gr_fb_width() / char_width_; + + log_text_rows_ = (gr_fb_height() - sysbar_height_) / log_char_height_; + log_text_cols_ = gr_fb_width() / log_char_width_; + + text_ = Alloc2d(log_text_rows_, log_text_cols_ + 1); file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1); menu_ = Alloc2d(text_rows_, text_cols_ + 1); - text_col_ = text_row_ = 0; - text_top_ = 1; + text_first_row_ = (header_height_ / char_height_) + 1; + menu_item_start_ = text_first_row_ * char_height_; + max_menu_rows_ = (text_rows_ - text_first_row_) / 3; backgroundIcon[NONE] = nullptr; LoadBitmapArray("icon_installing", &installing_frames, &installation); backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : nullptr; backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE]; - LoadBitmap("icon_error", &backgroundIcon[ERROR]); - backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR]; + LoadBitmap("icon_info", &backgroundIcon[D_INFO]); + LoadBitmap("icon_error", &backgroundIcon[D_ERROR]); + backgroundIcon[NO_COMMAND] = backgroundIcon[D_ERROR]; + LoadBitmap("icon_headless", &backgroundIcon[HEADLESS]); LoadBitmap("progress_empty", &progressBarEmpty); LoadBitmap("progress_fill", &progressBarFill); @@ -417,7 +610,7 @@ void ScreenRecoveryUI::Init() { LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]); LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]); LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]); - LoadLocalizedBitmap("error_text", &backgroundText[ERROR]); + LoadLocalizedBitmap("error_text", &backgroundText[D_ERROR]); pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this); @@ -467,7 +660,8 @@ void ScreenRecoveryUI::SetProgressType(ProgressType type) { progressScopeStart = 0; progressScopeSize = 0; progress = 0; - update_progress_locked(); + + update_screen_locked(); pthread_mutex_unlock(&updateMutex); } @@ -479,7 +673,8 @@ void ScreenRecoveryUI::ShowProgress(float portion, float seconds) { progressScopeTime = now(); progressScopeDuration = seconds; progress = 0; - update_progress_locked(); + + update_screen_locked(); pthread_mutex_unlock(&updateMutex); } @@ -493,7 +688,7 @@ void ScreenRecoveryUI::SetProgress(float fraction) { float scale = width * progressScopeSize; if ((int) (progress * scale) != (int) (fraction * scale)) { progress = fraction; - update_progress_locked(); + update_screen_locked(); } } pthread_mutex_unlock(&updateMutex); @@ -506,23 +701,22 @@ void ScreenRecoveryUI::SetStage(int current, int max) { pthread_mutex_unlock(&updateMutex); } -void ScreenRecoveryUI::Print(const char *fmt, ...) { - char buf[256]; - va_list ap; - va_start(ap, fmt); - vsnprintf(buf, 256, fmt, ap); - va_end(ap); +void ScreenRecoveryUI::PrintV(const char* fmt, bool copy_to_stdout, va_list ap) { + std::string str; + android::base::StringAppendV(&str, fmt, ap); - fputs(buf, stdout); + if (copy_to_stdout) { + fputs(str.c_str(), stdout); + } pthread_mutex_lock(&updateMutex); - if (text_rows_ > 0 && text_cols_ > 0) { - for (const char* ptr = buf; *ptr != '\0'; ++ptr) { - if (*ptr == '\n' || text_col_ >= text_cols_) { + if (log_text_rows_ > 0 && log_text_cols_ > 0) { + for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) { + if (*ptr == '\n' || text_col_ >= log_text_cols_) { text_[text_row_][text_col_] = '\0'; text_col_ = 0; - text_row_ = (text_row_ + 1) % text_rows_; - if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; + text_row_ = (text_row_ + 1) % log_text_rows_; + if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % log_text_rows_; } if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr; } @@ -532,6 +726,20 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) { pthread_mutex_unlock(&updateMutex); } +void ScreenRecoveryUI::Print(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + PrintV(fmt, true, ap); + va_end(ap); +} + +void ScreenRecoveryUI::PrintOnScreenOnly(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + PrintV(fmt, false, ap); + va_end(ap); +} + void ScreenRecoveryUI::PutChar(char ch) { pthread_mutex_lock(&updateMutex); if (ch != '\n') text_[text_row_][text_col_++] = ch; @@ -549,8 +757,8 @@ void ScreenRecoveryUI::ClearText() { text_col_ = 0; text_row_ = 0; text_top_ = 1; - for (size_t i = 0; i < text_rows_; ++i) { - memset(text_[i], 0, text_cols_ + 1); + for (size_t i = 0; i < log_text_rows_; ++i) { + memset(text_[i], 0, log_text_cols_ + 1); } pthread_mutex_unlock(&updateMutex); } @@ -560,13 +768,15 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) { offsets.push_back(ftell(fp)); ClearText(); + SetBackground(RecoveryUI::VIEWING_LOG); + struct stat sb; fstat(fileno(fp), &sb); bool show_prompt = false; while (true) { if (show_prompt) { - Print("--(%d%% of %d bytes)--", + PrintOnScreenOnly("--(%d%% of %d bytes)--", static_cast<int>(100 * (double(ftell(fp)) / double(sb.st_size))), static_cast<int>(sb.st_size)); Redraw(); @@ -630,11 +840,82 @@ void ScreenRecoveryUI::ShowFile(const char* filename) { text_top_ = old_text_top; } +void ScreenRecoveryUI::DialogShowInfo(const char* text) +{ + pthread_mutex_lock(&updateMutex); + free(dialog_text); + dialog_text = strdup(text); + dialog_show_log = false; + dialog_icon = D_INFO; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void ScreenRecoveryUI::DialogShowError(const char* text) +{ + pthread_mutex_lock(&updateMutex); + free(dialog_text); + dialog_text = strdup(text); + dialog_show_log = false; + dialog_icon = D_ERROR; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void ScreenRecoveryUI::DialogShowErrorLog(const char* text) +{ + pthread_mutex_lock(&updateMutex); + free(dialog_text); + dialog_text = strdup(text); + dialog_show_log = true; + dialog_icon = D_ERROR; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void ScreenRecoveryUI::DialogDismiss() +{ + pthread_mutex_lock(&updateMutex); + free(dialog_text); + dialog_text = NULL; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void ScreenRecoveryUI::SetHeadlessMode() +{ + pthread_mutex_lock(&updateMutex); + free(dialog_text); + dialog_text = strdup(""); + dialog_show_log = false; + dialog_icon = HEADLESS; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void ScreenRecoveryUI::SetSysbarState(int state) +{ + if (HasBackKey()) { + state &= ~SYSBAR_BACK; + } + if (HasHomeKey()) { + state &= ~SYSBAR_HOME; + } + sysbar_state = state; + Redraw(); +} + void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const * items, int initial_selection) { pthread_mutex_lock(&updateMutex); if (text_rows_ > 0 && text_cols_ > 0) { + header_items = 0; menu_headers_ = headers; + if (menu_headers_) { + while (menu_headers_[header_items]) { + ++header_items; + } + } size_t i = 0; for (; i < text_rows_ && items[i] != nullptr; ++i) { strncpy(menu_[i], items[i], text_cols_ - 1); @@ -643,22 +924,59 @@ void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const menu_items = i; show_menu = true; menu_sel = initial_selection; + if (menu_show_start_ <= menu_sel - max_menu_rows_ || + menu_show_start_ > menu_sel) { + menu_show_start_ = menu_sel; + } update_screen_locked(); } pthread_mutex_unlock(&updateMutex); } -int ScreenRecoveryUI::SelectMenu(int sel) { +int ScreenRecoveryUI::SelectMenu(int sel, bool abs /* = false */) { + int wrapped = 0; pthread_mutex_lock(&updateMutex); + if (abs) { + sel += menu_show_start_ - header_items; + } if (show_menu) { int old_sel = menu_sel; menu_sel = sel; // Wrap at top and bottom. - if (menu_sel < 0) menu_sel = menu_items - 1; - if (menu_sel >= menu_items) menu_sel = 0; - + if (rainbow) { + if (menu_sel > old_sel) { + move_rainbow(1); + } else if (menu_sel < old_sel) { + move_rainbow(-1); + } + } + if (menu_sel < 0) { + wrapped = -1; + menu_sel = menu_items + menu_sel; + } + if (menu_sel >= menu_items) { + wrapped = 1; + 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_ >= max_menu_rows_ - header_items) { + menu_show_start_ = menu_sel - (max_menu_rows_ - header_items) + 1; + } sel = menu_sel; + if (wrapped != 0) { + if (wrap_count / wrapped > 0) { + wrap_count += wrapped; + } else { + wrap_count = wrapped; + } + if (wrap_count / wrapped >= 5) { + wrap_count = 0; + OMGRainbows(); + } + } if (menu_sel != old_sel) update_screen_locked(); } pthread_mutex_unlock(&updateMutex); @@ -669,7 +987,6 @@ void ScreenRecoveryUI::EndMenu() { pthread_mutex_lock(&updateMutex); if (show_menu && text_rows_ > 0 && text_cols_ > 0) { show_menu = false; - update_screen_locked(); } pthread_mutex_unlock(&updateMutex); } |