188 lines
3.6 KiB
C++
188 lines
3.6 KiB
C++
#include "StatusBarManager.h"
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.h>
|
|
|
|
using std::cout;
|
|
using std::flush;
|
|
using std::string;
|
|
|
|
StatusBarManager::StatusBarManager()
|
|
: m_is_started(false)
|
|
{}
|
|
|
|
StatusBarManager::~StatusBarManager()
|
|
{
|
|
if(m_is_started)
|
|
{
|
|
stop();
|
|
}
|
|
}
|
|
|
|
StatusBarManager::TermSize StatusBarManager::get_terminal_size()
|
|
{
|
|
struct winsize win;
|
|
StatusBarManager::TermSize result = { 0, 0 };
|
|
|
|
if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
result.rows = win.ws_row;
|
|
result.columns = win.ws_col;
|
|
|
|
return result;
|
|
}
|
|
|
|
void StatusBarManager::setup_terminal_scroll_area(int nr_rows)
|
|
{
|
|
int status_rows = m_progress_messages.size();
|
|
if (nr_rows <= 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// scroll down a bit to avoid visual glitch when the screen
|
|
// area shrinks by needed ammount of rows
|
|
for (int i = 0; i < status_rows; ++i)
|
|
{
|
|
cout << std::endl;
|
|
}
|
|
|
|
// save cursor
|
|
cout << "\e7";
|
|
|
|
// set scroll region (this will place the cursor in the top left)
|
|
cout << "\e[0;" << std::to_string(nr_rows - status_rows) << "r";
|
|
|
|
// restore cursor but ensure its inside the scrolling area
|
|
cout << "\e8";
|
|
cout << "\e[" << status_rows << "A";
|
|
|
|
// ensure its flushed
|
|
flush(cout);
|
|
|
|
// Leftovers from apt
|
|
#if 0
|
|
// setup tty size to ensure xterm/linux console are working properly too
|
|
// see bug #731738
|
|
struct winsize win;
|
|
if (ioctl(child_pty, TIOCGWINSZ, (char *)&win) != -1)
|
|
{
|
|
win.ws_row = nr_rows - 1;
|
|
ioctl(child_pty, TIOCSWINSZ, (char *)&win);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void StatusBarManager::start()
|
|
{
|
|
if (!m_is_started)
|
|
{
|
|
int const nr_terminal_rows = get_terminal_size().rows;
|
|
setup_terminal_scroll_area(nr_terminal_rows);
|
|
m_is_started = true;
|
|
}
|
|
}
|
|
|
|
void StatusBarManager::stop()
|
|
{
|
|
if (m_is_started)
|
|
{
|
|
int const nr_terminal_rows = get_terminal_size().rows;
|
|
if (nr_terminal_rows > 0)
|
|
{
|
|
setup_terminal_scroll_area(nr_terminal_rows + m_progress_messages.size());
|
|
|
|
// override the progress line (sledgehammer)
|
|
static const char* clear_screen_below_cursor = "\e[J";
|
|
cout << clear_screen_below_cursor;
|
|
flush(cout);
|
|
}
|
|
|
|
m_is_started = false;
|
|
}
|
|
}
|
|
|
|
bool StatusBarManager::draw_status_line()
|
|
{
|
|
if (!m_is_started)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
StatusBarManager::TermSize const size = get_terminal_size();
|
|
if (size.rows < 1 || size.columns < 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static string save_cursor = "\e7";
|
|
static string restore_cursor = "\e8";
|
|
|
|
// green
|
|
static string set_bg_color = "\e[42m";
|
|
// black
|
|
static string set_fg_color = "\e[30m";
|
|
|
|
static string restore_bg = "\e[49m";
|
|
static string restore_fg = "\e[39m";
|
|
|
|
cout << save_cursor;
|
|
|
|
int status_rows = m_progress_messages.size();
|
|
for (int i = 0; i < status_rows; ++i)
|
|
{
|
|
// move cursor position to current row
|
|
cout << "\e[" << std::to_string(size.rows + 1 - status_rows + i) << ";0f"
|
|
<< set_bg_color
|
|
<< set_fg_color;
|
|
if (nullptr != m_progress_messages[i])
|
|
{
|
|
cout << *(m_progress_messages[i]);
|
|
}
|
|
flush(cout);
|
|
}
|
|
|
|
cout << restore_bg
|
|
<< restore_fg;
|
|
flush(cout);
|
|
|
|
// leftover progress-bar from apt
|
|
#if 0
|
|
// draw text progress bar
|
|
int padding = 4;
|
|
auto const progressbar_size = size.columns - padding - String::DisplayLength(progress_str);
|
|
auto const current_percent = percentage / 100.0f;
|
|
cout << " "
|
|
<< GetTextProgressStr(current_percent, progressbar_size)
|
|
<< " ";
|
|
flush(cout);
|
|
#endif
|
|
|
|
// restore
|
|
cout << restore_cursor;
|
|
flush(cout);
|
|
|
|
return true;
|
|
}
|
|
|
|
void StatusBarManager::add_progress_message(Progress* message)
|
|
{
|
|
if (message == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_progress_messages.push_back(message);
|
|
}
|
|
|
|
void StatusBarManager::clear()
|
|
{
|
|
m_progress_messages.clear();
|
|
}
|