diff options
Diffstat (limited to 'screen_ui.cpp')
-rw-r--r-- | screen_ui.cpp | 758 |
1 files changed, 381 insertions, 377 deletions
diff --git a/screen_ui.cpp b/screen_ui.cpp index c41bb22e1..6172b631a 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -45,9 +45,9 @@ // Return the current time as a double (including fractions of a second). static double now() { - struct timeval tv; - gettimeofday(&tv, nullptr); - return tv.tv_sec + tv.tv_usec / 1000000.0; + struct timeval tv; + gettimeofday(&tv, nullptr); + return tv.tv_sec + tv.tv_usec / 1000000.0; } ScreenRecoveryUI::ScreenRecoveryUI() @@ -83,24 +83,29 @@ ScreenRecoveryUI::ScreenRecoveryUI() updateMutex(PTHREAD_MUTEX_INITIALIZER) {} GRSurface* ScreenRecoveryUI::GetCurrentFrame() { - if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { - return intro_done ? loopFrames[current_frame] : introFrames[current_frame]; - } - return error_icon; + if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { + return intro_done ? loopFrames[current_frame] : introFrames[current_frame]; + } + return error_icon; } GRSurface* ScreenRecoveryUI::GetCurrentText() { - switch (currentIcon) { - case ERASING: return erasing_text; - case ERROR: return error_text; - case INSTALLING_UPDATE: return installing_text; - case NO_COMMAND: return no_command_text; - case NONE: abort(); - } + switch (currentIcon) { + case ERASING: + return erasing_text; + case ERROR: + return error_text; + case INSTALLING_UPDATE: + return installing_text; + case NO_COMMAND: + return no_command_text; + case NONE: + abort(); + } } int ScreenRecoveryUI::PixelsFromDp(int dp) const { - return dp * density_; + return dp * density_; } // Here's the intended layout: @@ -121,53 +126,52 @@ int ScreenRecoveryUI::PixelsFromDp(int dp) const { enum Layout { PORTRAIT = 0, PORTRAIT_LARGE = 1, LANDSCAPE = 2, LANDSCAPE_LARGE = 3, LAYOUT_MAX }; enum Dimension { PROGRESS = 0, TEXT = 1, ICON = 2, DIMENSION_MAX }; static constexpr int kLayouts[LAYOUT_MAX][DIMENSION_MAX] = { - { 194, 32, 68, }, // PORTRAIT - { 340, 32, 68, }, // PORTRAIT_LARGE - { 131, 26, 56, }, // LANDSCAPE - { 262, 52, 112, }, // LANDSCAPE_LARGE + { 194, 32, 68, }, // PORTRAIT + { 340, 32, 68, }, // PORTRAIT_LARGE + { 131, 26, 56, }, // LANDSCAPE + { 262, 52, 112, }, // LANDSCAPE_LARGE }; int ScreenRecoveryUI::GetAnimationBaseline() { - return GetTextBaseline() - PixelsFromDp(kLayouts[layout_][ICON]) - - gr_get_height(loopFrames[0]); + return GetTextBaseline() - PixelsFromDp(kLayouts[layout_][ICON]) - gr_get_height(loopFrames[0]); } int ScreenRecoveryUI::GetTextBaseline() { - return GetProgressBaseline() - PixelsFromDp(kLayouts[layout_][TEXT]) - - gr_get_height(installing_text); + return GetProgressBaseline() - PixelsFromDp(kLayouts[layout_][TEXT]) - + gr_get_height(installing_text); } int ScreenRecoveryUI::GetProgressBaseline() { - return gr_fb_height() - PixelsFromDp(kLayouts[layout_][PROGRESS]) - - gr_get_height(progressBarFill); + return gr_fb_height() - PixelsFromDp(kLayouts[layout_][PROGRESS]) - + gr_get_height(progressBarFill); } // Clear the screen and draw the currently selected background icon (if any). // Should only be called with updateMutex locked. void ScreenRecoveryUI::draw_background_locked() { - pagesIdentical = false; - gr_color(0, 0, 0, 255); - gr_clear(); - - if (currentIcon != NONE) { - if (max_stage != -1) { - int stage_height = gr_get_height(stageMarkerEmpty); - int stage_width = gr_get_width(stageMarkerEmpty); - int x = (gr_fb_width() - max_stage * gr_get_width(stageMarkerEmpty)) / 2; - int y = gr_fb_height() - stage_height; - for (int i = 0; i < max_stage; ++i) { - GRSurface* stage_surface = (i < stage) ? stageMarkerFill : stageMarkerEmpty; - gr_blit(stage_surface, 0, 0, stage_width, stage_height, x, y); - x += stage_width; - } - } + pagesIdentical = false; + gr_color(0, 0, 0, 255); + gr_clear(); - GRSurface* text_surface = GetCurrentText(); - int text_x = (gr_fb_width() - gr_get_width(text_surface)) / 2; - int text_y = GetTextBaseline(); - gr_color(255, 255, 255, 255); - gr_texticon(text_x, text_y, text_surface); + if (currentIcon != NONE) { + if (max_stage != -1) { + int stage_height = gr_get_height(stageMarkerEmpty); + int stage_width = gr_get_width(stageMarkerEmpty); + int x = (gr_fb_width() - max_stage * gr_get_width(stageMarkerEmpty)) / 2; + int y = gr_fb_height() - stage_height; + for (int i = 0; i < max_stage; ++i) { + GRSurface* stage_surface = (i < stage) ? stageMarkerFill : stageMarkerEmpty; + gr_blit(stage_surface, 0, 0, stage_width, stage_height, x, y); + x += stage_width; + } } + + GRSurface* text_surface = GetCurrentText(); + int text_x = (gr_fb_width() - gr_get_width(text_surface)) / 2; + int text_y = GetTextBaseline(); + gr_color(255, 255, 255, 255); + gr_texticon(text_x, text_y, text_surface); + } } // Draws the animation and progress bar (if any) on the screen. @@ -221,66 +225,66 @@ void ScreenRecoveryUI::draw_foreground_locked() { } void ScreenRecoveryUI::SetColor(UIElement e) { - switch (e) { - case INFO: - gr_color(249, 194, 0, 255); - break; - case HEADER: - gr_color(247, 0, 6, 255); - break; - case MENU: - case MENU_SEL_BG: - gr_color(0, 106, 157, 255); - break; - case MENU_SEL_BG_ACTIVE: - gr_color(0, 156, 100, 255); - break; - case MENU_SEL_FG: - gr_color(255, 255, 255, 255); - break; - case LOG: - gr_color(196, 196, 196, 255); - break; - case TEXT_FILL: - gr_color(0, 0, 0, 160); - break; - default: - gr_color(255, 255, 255, 255); - break; - } + switch (e) { + case INFO: + gr_color(249, 194, 0, 255); + break; + case HEADER: + gr_color(247, 0, 6, 255); + break; + case MENU: + case MENU_SEL_BG: + gr_color(0, 106, 157, 255); + break; + case MENU_SEL_BG_ACTIVE: + gr_color(0, 156, 100, 255); + break; + case MENU_SEL_FG: + gr_color(255, 255, 255, 255); + break; + case LOG: + gr_color(196, 196, 196, 255); + break; + case TEXT_FILL: + gr_color(0, 0, 0, 160); + break; + default: + gr_color(255, 255, 255, 255); + break; + } } void ScreenRecoveryUI::DrawHorizontalRule(int* y) { - SetColor(MENU); - *y += 4; - gr_fill(0, *y, gr_fb_width(), *y + 2); - *y += 4; + SetColor(MENU); + *y += 4; + gr_fill(0, *y, gr_fb_width(), *y + 2); + *y += 4; } void ScreenRecoveryUI::DrawHighlightBar(int x, int y, int width, int height) const { - gr_fill(x, y, x + width, y + height); + gr_fill(x, y, x + width, y + height); } void ScreenRecoveryUI::DrawTextLine(int x, int* y, const char* line, bool bold) const { - gr_text(gr_sys_font(), x, *y, line, bold); - *y += char_height_ + 4; + gr_text(gr_sys_font(), x, *y, line, bold); + *y += char_height_ + 4; } void ScreenRecoveryUI::DrawTextLines(int x, int* y, const char* const* lines) const { - for (size_t i = 0; lines != nullptr && lines[i] != nullptr; ++i) { - DrawTextLine(x, y, lines[i], false); - } + for (size_t i = 0; lines != nullptr && lines[i] != nullptr; ++i) { + DrawTextLine(x, y, lines[i], false); + } } static const char* REGULAR_HELP[] = { - "Use volume up/down and power.", - NULL + "Use volume up/down and power.", + NULL }; static const char* LONG_PRESS_HELP[] = { - "Any button cycles highlight.", - "Long-press activates.", - NULL + "Any button cycles highlight.", + "Long-press activates.", + NULL }; // Redraws everything on the screen. Does not flip pages. Should only be called with updateMutex @@ -336,8 +340,8 @@ void ScreenRecoveryUI::draw_screen_locked() { SetColor(LOG); int row = (text_top_ + text_rows_ - 1) % text_rows_; size_t count = 0; - for (int ty = gr_fb_height() - kMarginHeight - char_height_; - ty >= y && count < text_rows_; ty -= char_height_, ++count) { + for (int ty = gr_fb_height() - kMarginHeight - char_height_; ty >= y && count < text_rows_; + ty -= char_height_, ++count) { int temp_y = ty; DrawTextLine(x, &temp_y, text_[row], false); --row; @@ -348,81 +352,81 @@ 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(); + 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_foreground_locked(); // Draw only the progress bar and overlays - } - gr_flip(); + if (show_text || !pagesIdentical) { + draw_screen_locked(); // Must redraw the whole screen + pagesIdentical = true; + } else { + draw_foreground_locked(); // Draw only the progress bar and overlays + } + gr_flip(); } // Keeps the progress bar updated, even when the process is otherwise busy. void* ScreenRecoveryUI::ProgressThreadStartRoutine(void* data) { - reinterpret_cast<ScreenRecoveryUI*>(data)->ProgressThreadLoop(); - return nullptr; + reinterpret_cast<ScreenRecoveryUI*>(data)->ProgressThreadLoop(); + return nullptr; } void ScreenRecoveryUI::ProgressThreadLoop() { - double interval = 1.0 / animation_fps; - while (true) { - double start = now(); - pthread_mutex_lock(&updateMutex); - - bool redraw = false; - - // update the installation animation, if active - // skip this if we have a text overlay (too expensive to update) - if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) && !show_text) { - if (!intro_done) { - if (current_frame == intro_frames - 1) { - intro_done = true; - current_frame = 0; - } else { - ++current_frame; - } - } else { - current_frame = (current_frame + 1) % loop_frames; - } - - redraw = true; - } + double interval = 1.0 / animation_fps; + while (true) { + double start = now(); + pthread_mutex_lock(&updateMutex); - // move the progress bar forward on timed intervals, if configured - int duration = progressScopeDuration; - if (progressBarType == DETERMINATE && duration > 0) { - double elapsed = now() - progressScopeTime; - float p = 1.0 * elapsed / duration; - if (p > 1.0) p = 1.0; - if (p > progress) { - progress = p; - redraw = true; - } + bool redraw = false; + + // update the installation animation, if active + // skip this if we have a text overlay (too expensive to update) + if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) && !show_text) { + if (!intro_done) { + if (current_frame == intro_frames - 1) { + intro_done = true; + current_frame = 0; + } else { + ++current_frame; } + } else { + current_frame = (current_frame + 1) % loop_frames; + } - if (redraw) update_progress_locked(); + redraw = true; + } - pthread_mutex_unlock(&updateMutex); - double end = now(); - // minimum of 20ms delay between frames - double delay = interval - (end-start); - if (delay < 0.02) delay = 0.02; - usleep(static_cast<useconds_t>(delay * 1000000)); + // move the progress bar forward on timed intervals, if configured + int duration = progressScopeDuration; + if (progressBarType == DETERMINATE && duration > 0) { + double elapsed = now() - progressScopeTime; + float p = 1.0 * elapsed / duration; + if (p > 1.0) p = 1.0; + if (p > progress) { + progress = p; + redraw = true; + } } + + if (redraw) update_progress_locked(); + + pthread_mutex_unlock(&updateMutex); + double end = now(); + // minimum of 20ms delay between frames + double delay = interval - (end - start); + if (delay < 0.02) delay = 0.02; + usleep(static_cast<useconds_t>(delay * 1000000)); + } } void ScreenRecoveryUI::LoadBitmap(const char* filename, GRSurface** surface) { - int result = res_create_display_surface(filename, surface); - if (result < 0) { - LOG(ERROR) << "couldn't load bitmap " << filename << " (error " << result << ")"; - } + int result = res_create_display_surface(filename, surface); + if (result < 0) { + LOG(ERROR) << "couldn't load bitmap " << filename << " (error " << result << ")"; + } } void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) { @@ -433,22 +437,22 @@ void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** sur } static char** Alloc2d(size_t rows, size_t cols) { - char** result = new char*[rows]; - for (size_t i = 0; i < rows; ++i) { - result[i] = new char[cols]; - memset(result[i], 0, cols); - } - return result; + char** result = new char*[rows]; + for (size_t i = 0; i < rows; ++i) { + result[i] = new char[cols]; + memset(result[i], 0, cols); + } + return result; } // Choose the right background string to display during update. void ScreenRecoveryUI::SetSystemUpdateText(bool security_update) { - if (security_update) { - LoadLocalizedBitmap("installing_security_text", &installing_text); - } else { - LoadLocalizedBitmap("installing_text", &installing_text); - } - Redraw(); + if (security_update) { + LoadLocalizedBitmap("installing_security_text", &installing_text); + } else { + LoadLocalizedBitmap("installing_text", &installing_text); + } + Redraw(); } bool ScreenRecoveryUI::InitTextParams() { @@ -504,309 +508,309 @@ bool ScreenRecoveryUI::Init(const std::string& locale) { } void ScreenRecoveryUI::LoadAnimation() { - std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/res/images"), closedir); - dirent* de; - std::vector<std::string> intro_frame_names; - std::vector<std::string> loop_frame_names; - - while ((de = readdir(dir.get())) != nullptr) { - int value, num_chars; - if (sscanf(de->d_name, "intro%d%n.png", &value, &num_chars) == 1) { - intro_frame_names.emplace_back(de->d_name, num_chars); - } else if (sscanf(de->d_name, "loop%d%n.png", &value, &num_chars) == 1) { - loop_frame_names.emplace_back(de->d_name, num_chars); - } + std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/res/images"), closedir); + dirent* de; + std::vector<std::string> intro_frame_names; + std::vector<std::string> loop_frame_names; + + while ((de = readdir(dir.get())) != nullptr) { + int value, num_chars; + if (sscanf(de->d_name, "intro%d%n.png", &value, &num_chars) == 1) { + intro_frame_names.emplace_back(de->d_name, num_chars); + } else if (sscanf(de->d_name, "loop%d%n.png", &value, &num_chars) == 1) { + loop_frame_names.emplace_back(de->d_name, num_chars); } + } - intro_frames = intro_frame_names.size(); - loop_frames = loop_frame_names.size(); + intro_frames = intro_frame_names.size(); + loop_frames = loop_frame_names.size(); - // It's okay to not have an intro. - if (intro_frames == 0) intro_done = true; - // But you must have an animation. - if (loop_frames == 0) abort(); + // It's okay to not have an intro. + if (intro_frames == 0) intro_done = true; + // But you must have an animation. + if (loop_frames == 0) abort(); - std::sort(intro_frame_names.begin(), intro_frame_names.end()); - std::sort(loop_frame_names.begin(), loop_frame_names.end()); + std::sort(intro_frame_names.begin(), intro_frame_names.end()); + std::sort(loop_frame_names.begin(), loop_frame_names.end()); - introFrames = new GRSurface*[intro_frames]; - for (size_t i = 0; i < intro_frames; i++) { - LoadBitmap(intro_frame_names.at(i).c_str(), &introFrames[i]); - } + introFrames = new GRSurface*[intro_frames]; + for (size_t i = 0; i < intro_frames; i++) { + LoadBitmap(intro_frame_names.at(i).c_str(), &introFrames[i]); + } - loopFrames = new GRSurface*[loop_frames]; - for (size_t i = 0; i < loop_frames; i++) { - LoadBitmap(loop_frame_names.at(i).c_str(), &loopFrames[i]); - } + loopFrames = new GRSurface*[loop_frames]; + for (size_t i = 0; i < loop_frames; i++) { + LoadBitmap(loop_frame_names.at(i).c_str(), &loopFrames[i]); + } } void ScreenRecoveryUI::SetBackground(Icon icon) { - pthread_mutex_lock(&updateMutex); + pthread_mutex_lock(&updateMutex); - currentIcon = icon; - update_screen_locked(); + currentIcon = icon; + update_screen_locked(); - pthread_mutex_unlock(&updateMutex); + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::SetProgressType(ProgressType type) { - pthread_mutex_lock(&updateMutex); - if (progressBarType != type) { - progressBarType = type; - } - progressScopeStart = 0; - progressScopeSize = 0; - progress = 0; - update_progress_locked(); - pthread_mutex_unlock(&updateMutex); + pthread_mutex_lock(&updateMutex); + if (progressBarType != type) { + progressBarType = type; + } + progressScopeStart = 0; + progressScopeSize = 0; + progress = 0; + update_progress_locked(); + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::ShowProgress(float portion, float seconds) { - pthread_mutex_lock(&updateMutex); - progressBarType = DETERMINATE; - progressScopeStart += progressScopeSize; - progressScopeSize = portion; - progressScopeTime = now(); - progressScopeDuration = seconds; - progress = 0; - update_progress_locked(); - pthread_mutex_unlock(&updateMutex); + pthread_mutex_lock(&updateMutex); + progressBarType = DETERMINATE; + progressScopeStart += progressScopeSize; + progressScopeSize = portion; + progressScopeTime = now(); + progressScopeDuration = seconds; + progress = 0; + update_progress_locked(); + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::SetProgress(float fraction) { - pthread_mutex_lock(&updateMutex); - if (fraction < 0.0) fraction = 0.0; - if (fraction > 1.0) fraction = 1.0; - if (progressBarType == DETERMINATE && fraction > progress) { - // Skip updates that aren't visibly different. - int width = gr_get_width(progressBarEmpty); - float scale = width * progressScopeSize; - if ((int) (progress * scale) != (int) (fraction * scale)) { - progress = fraction; - update_progress_locked(); - } + pthread_mutex_lock(&updateMutex); + if (fraction < 0.0) fraction = 0.0; + if (fraction > 1.0) fraction = 1.0; + if (progressBarType == DETERMINATE && fraction > progress) { + // Skip updates that aren't visibly different. + int width = gr_get_width(progressBarEmpty); + float scale = width * progressScopeSize; + if ((int)(progress * scale) != (int)(fraction * scale)) { + progress = fraction; + update_progress_locked(); } - pthread_mutex_unlock(&updateMutex); + } + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::SetStage(int current, int max) { - pthread_mutex_lock(&updateMutex); - stage = current; - max_stage = max; - pthread_mutex_unlock(&updateMutex); + pthread_mutex_lock(&updateMutex); + stage = current; + max_stage = max; + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::PrintV(const char* fmt, bool copy_to_stdout, va_list ap) { - std::string str; - android::base::StringAppendV(&str, fmt, ap); + std::string str; + android::base::StringAppendV(&str, fmt, ap); - if (copy_to_stdout) { - fputs(str.c_str(), 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 = str.c_str(); *ptr != '\0'; ++ptr) { - if (*ptr == '\n' || text_col_ >= 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_; - } - if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr; - } + pthread_mutex_lock(&updateMutex); + if (text_rows_ > 0 && text_cols_ > 0) { + for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) { + if (*ptr == '\n' || text_col_ >= text_cols_) { text_[text_row_][text_col_] = '\0'; - update_screen_locked(); + text_col_ = 0; + text_row_ = (text_row_ + 1) % text_rows_; + if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; + } + if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr; } - pthread_mutex_unlock(&updateMutex); + text_[text_row_][text_col_] = '\0'; + update_screen_locked(); + } + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::Print(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - PrintV(fmt, true, ap); - va_end(ap); + 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); + 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; - if (ch == '\n' || text_col_ >= text_cols_) { - text_col_ = 0; - ++text_row_; + pthread_mutex_lock(&updateMutex); + if (ch != '\n') text_[text_row_][text_col_++] = ch; + if (ch == '\n' || text_col_ >= text_cols_) { + text_col_ = 0; + ++text_row_; - if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; - } - pthread_mutex_unlock(&updateMutex); + if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; + } + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::ClearText() { - pthread_mutex_lock(&updateMutex); - 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); - } - pthread_mutex_unlock(&updateMutex); + pthread_mutex_lock(&updateMutex); + 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); + } + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::ShowFile(FILE* fp) { - std::vector<off_t> offsets; - offsets.push_back(ftello(fp)); - ClearText(); - - struct stat sb; - fstat(fileno(fp), &sb); - - bool show_prompt = false; - while (true) { - if (show_prompt) { - PrintOnScreenOnly("--(%d%% of %d bytes)--", - static_cast<int>(100 * (double(ftello(fp)) / double(sb.st_size))), - static_cast<int>(sb.st_size)); - Redraw(); - while (show_prompt) { - show_prompt = false; - int key = WaitKey(); - if (key == KEY_POWER || key == KEY_ENTER) { - return; - } else if (key == KEY_UP || key == KEY_VOLUMEUP) { - if (offsets.size() <= 1) { - show_prompt = true; - } else { - offsets.pop_back(); - fseek(fp, offsets.back(), SEEK_SET); - } - } else { - if (feof(fp)) { - return; - } - offsets.push_back(ftello(fp)); - } - } - ClearText(); - } - - int ch = getc(fp); - if (ch == EOF) { - while (text_row_ < text_rows_ - 1) PutChar('\n'); + std::vector<off_t> offsets; + offsets.push_back(ftello(fp)); + ClearText(); + + struct stat sb; + fstat(fileno(fp), &sb); + + bool show_prompt = false; + while (true) { + if (show_prompt) { + PrintOnScreenOnly("--(%d%% of %d bytes)--", + static_cast<int>(100 * (double(ftello(fp)) / double(sb.st_size))), + static_cast<int>(sb.st_size)); + Redraw(); + while (show_prompt) { + show_prompt = false; + int key = WaitKey(); + if (key == KEY_POWER || key == KEY_ENTER) { + return; + } else if (key == KEY_UP || key == KEY_VOLUMEUP) { + if (offsets.size() <= 1) { show_prompt = true; + } else { + offsets.pop_back(); + fseek(fp, offsets.back(), SEEK_SET); + } } else { - PutChar(ch); - if (text_col_ == 0 && text_row_ >= text_rows_ - 1) { - show_prompt = true; - } + if (feof(fp)) { + return; + } + offsets.push_back(ftello(fp)); } + } + ClearText(); } + + int ch = getc(fp); + if (ch == EOF) { + while (text_row_ < text_rows_ - 1) PutChar('\n'); + show_prompt = true; + } else { + PutChar(ch); + if (text_col_ == 0 && text_row_ >= text_rows_ - 1) { + show_prompt = true; + } + } + } } void ScreenRecoveryUI::ShowFile(const char* filename) { - FILE* fp = fopen_path(filename, "re"); - if (fp == nullptr) { - Print(" Unable to open %s: %s\n", filename, strerror(errno)); - return; - } + FILE* fp = fopen_path(filename, "re"); + if (fp == nullptr) { + Print(" Unable to open %s: %s\n", filename, strerror(errno)); + return; + } - char** old_text = text_; - size_t old_text_col = text_col_; - size_t old_text_row = text_row_; - size_t old_text_top = text_top_; + char** old_text = text_; + size_t old_text_col = text_col_; + size_t old_text_row = text_row_; + size_t old_text_top = text_top_; - // Swap in the alternate screen and clear it. - text_ = file_viewer_text_; - ClearText(); + // Swap in the alternate screen and clear it. + text_ = file_viewer_text_; + ClearText(); - ShowFile(fp); - fclose(fp); + ShowFile(fp); + fclose(fp); - text_ = old_text; - text_col_ = old_text_col; - text_row_ = old_text_row; - text_top_ = old_text_top; + text_ = old_text; + text_col_ = old_text_col; + text_row_ = old_text_row; + text_top_ = old_text_top; } -void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const * items, +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) { - menu_headers_ = headers; - size_t i = 0; - for (; i < text_rows_ && items[i] != nullptr; ++i) { - strncpy(menu_[i], items[i], text_cols_ - 1); - menu_[i][text_cols_ - 1] = '\0'; - } - menu_items = i; - show_menu = true; - menu_sel = initial_selection; - update_screen_locked(); + pthread_mutex_lock(&updateMutex); + if (text_rows_ > 0 && text_cols_ > 0) { + menu_headers_ = headers; + size_t i = 0; + for (; i < text_rows_ && items[i] != nullptr; ++i) { + strncpy(menu_[i], items[i], text_cols_ - 1); + menu_[i][text_cols_ - 1] = '\0'; } - pthread_mutex_unlock(&updateMutex); + menu_items = i; + show_menu = true; + menu_sel = initial_selection; + update_screen_locked(); + } + pthread_mutex_unlock(&updateMutex); } int ScreenRecoveryUI::SelectMenu(int sel) { - pthread_mutex_lock(&updateMutex); - if (show_menu) { - int old_sel = menu_sel; - menu_sel = sel; + pthread_mutex_lock(&updateMutex); + 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; + // Wrap at top and bottom. + if (menu_sel < 0) menu_sel = menu_items - 1; + if (menu_sel >= menu_items) menu_sel = 0; - sel = menu_sel; - if (menu_sel != old_sel) update_screen_locked(); - } - pthread_mutex_unlock(&updateMutex); - return sel; + sel = menu_sel; + if (menu_sel != old_sel) update_screen_locked(); + } + pthread_mutex_unlock(&updateMutex); + return sel; } 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); + pthread_mutex_lock(&updateMutex); + if (show_menu && text_rows_ > 0 && text_cols_ > 0) { + show_menu = false; + update_screen_locked(); + } + pthread_mutex_unlock(&updateMutex); } bool ScreenRecoveryUI::IsTextVisible() { - pthread_mutex_lock(&updateMutex); - int visible = show_text; - pthread_mutex_unlock(&updateMutex); - return visible; + pthread_mutex_lock(&updateMutex); + int visible = show_text; + pthread_mutex_unlock(&updateMutex); + return visible; } bool ScreenRecoveryUI::WasTextEverVisible() { - pthread_mutex_lock(&updateMutex); - int ever_visible = show_text_ever; - pthread_mutex_unlock(&updateMutex); - return ever_visible; + pthread_mutex_lock(&updateMutex); + int ever_visible = show_text_ever; + pthread_mutex_unlock(&updateMutex); + return ever_visible; } void ScreenRecoveryUI::ShowText(bool visible) { - pthread_mutex_lock(&updateMutex); - show_text = visible; - if (show_text) show_text_ever = true; - update_screen_locked(); - pthread_mutex_unlock(&updateMutex); + pthread_mutex_lock(&updateMutex); + show_text = visible; + if (show_text) show_text_ever = true; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::Redraw() { - pthread_mutex_lock(&updateMutex); - update_screen_locked(); - pthread_mutex_unlock(&updateMutex); + pthread_mutex_lock(&updateMutex); + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::KeyLongPress(int) { - // Redraw so that if we're in the menu, the highlight - // will change color to indicate a successful long press. - Redraw(); + // Redraw so that if we're in the menu, the highlight + // will change color to indicate a successful long press. + Redraw(); } |