diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 90a403b10..62e76ab7c 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -173,6 +173,7 @@ bool print_trackers = false; bool print_peers = false; bool print_log = false; bool print_downloads = false; +bool print_matrix = false; bool print_file_progress = false; bool show_pad_files = false; bool show_dht_status = false; @@ -377,9 +378,10 @@ FILE* g_log_file = 0; std::string const& piece_bar(libtorrent::bitfield const& p, int width) { #ifdef _WIN32 - int const table_size = 2; + int const table_size = 5; #else int const table_size = 18; + width *= 2; // we only print one character for every two "slots" #endif double const piece_per_char = p.size() / double(width); @@ -396,6 +398,10 @@ std::string const& piece_bar(libtorrent::bitfield const& p, int width) // the [piece, piece + pieces_per_char) range is the pieces that are represented by each character double piece = 0; + + // we print two blocks at a time, so calculate the color in pair + int color[2]; + int last_color[2] = { -1, -1}; for (int i = 0; i < width; ++i, piece += piece_per_char) { int num_pieces = 0; @@ -403,15 +409,31 @@ std::string const& piece_bar(libtorrent::bitfield const& p, int width) int end = (std::max)(int(piece + piece_per_char), int(piece) + 1); for (int k = int(piece); k < end; ++k, ++num_pieces) if (p[k]) ++num_have; - int color = int(std::ceil(num_have / float((std::max)(num_pieces, 1)) * (table_size - 1))); + int const c = int(std::ceil(num_have / float((std::max)(num_pieces, 1)) * (table_size - 1))); char buf[40]; -#ifdef _WIN32 - snprintf(buf, sizeof(buf), "\x1b[4%dm", color ? 7 : 0); + color[i & 1] = c; + +#ifndef _WIN32 + if ((i & 1) == 1) + { + // now, print color[0] and [1] + // bg determines whether we're settings foreground or background color + static int const bg[] = { 38, 48}; + for (int i = 0; i < 2; ++i) + { + if (color[i] != last_color[i]) + { + snprintf(buf, sizeof(buf), "\x1b[%d;5;%dm", bg[i & 1], 232 + color[i]); + last_color[i] = color[i]; + bar += buf; + } + } + bar += "\u258C"; + } #else - snprintf(buf, sizeof(buf), "\x1b[48;5;%dm", 232 + color); + static char const table[] = {' ', '\xb0', '\xb1', '\xb2', '\xdb'}; + bar += table[c]; #endif - bar += buf; - bar += " "; } bar += esc("0"); bar += "]"; @@ -1913,6 +1935,7 @@ int main(int argc, char* argv[]) if (c == 'i') print_peers = !print_peers; if (c == 'l') print_log = !print_log; if (c == 'd') print_downloads = !print_downloads; + if (c == 'y') print_matrix = !print_matrix; if (c == 'f') print_file_progress = !print_file_progress; if (c == 'P') show_pad_files = !show_pad_files; if (c == 'g') show_dht_status = !show_dht_status; @@ -1956,8 +1979,8 @@ int main(int argc, char* argv[]) "[i] toggle show peers [d] toggle show downloading pieces\n" "[u] show uTP stats [f] toggle show files\n" "[g] show DHT [x] toggle disk cache stats\n" - "[t] show trackers [l] show alert log\n" - "[P] show pad files (in file list)\n" + "[t] show trackers [l] toggle show log\n" + "[P] show pad files (in file list) [y] toggle show piece matrix\n" "\n" "COLUMN OPTIONS\n" "[1] toggle IP column [2]\n" @@ -2096,6 +2119,13 @@ int main(int argc, char* argv[]) } } + if (print_matrix) + { + int height = 0; + print(piece_matrix(s.pieces, terminal_width, &height).c_str()); + pos += height; + } + if (print_downloads) { h.get_download_queue(queue); diff --git a/examples/print.cpp b/examples/print.cpp index 83f888c77..c02ab00bf 100644 --- a/examples/print.cpp +++ b/examples/print.cpp @@ -128,6 +128,101 @@ std::string const& progress_bar(int progress, int width, color_code c return bar; } +bool get_piece(libtorrent::bitfield const& p, int index) +{ + if (index < 0 || index >= p.size()) return false; + return p.get_bit(index); +} + +#ifndef _WIN32 +// this function uses the block characters that splits up the glyph in 4 +// segments and provide all combinations of a segment lit or not. This allows us +// to print 4 pieces per character. +std::string piece_matrix(libtorrent::bitfield const& p, int width, int* height) +{ + // print two rows of pieces at a time + int piece = 0; + ++*height; + std::string ret; + ret.reserve((p.size() + width * 2 - 1) / width / 2 * 4); + while (piece < p.size()) + { + for (int i = 0; i < width; ++i) + { + // each character has 4 pieces. store them in a byte to use for lookups + int const c = get_piece(p, piece) + | (get_piece(p, piece+1) << 1) + | (get_piece(p, width*2+piece) << 2) + | (get_piece(p, width*2+piece+1) << 3); + + // we have 4 bits, 16 different combinations + static char const* const chars[] = + { + " ", // no bit is set 0000 + "\u2598", // upper left 0001 + "\u259d", // upper right 0010 + "\u2580", // both top bits 0011 + "\u2596", // lower left 0100 + "\u258c", // both left bits 0101 + "\u259e", // upper right, lower left 0110 + "\u259b", // left and upper sides 0111 + "\u2597", // lower right 1000 + "\u259a", // lower right, upper left 1001 + "\u2590", // right side 1010 + "\u259c", // lower right, top side 1011 + "\u2584", // both lower bits 1100 + "\u2599", // both lower, top left 1101 + "\u259f", // both lower, top right 1110 + "\x1b[7m \x1b[27m" // all bits are set (full block) + }; + + ret += chars[c]; + piece += 2; + } + ret += '\n'; + ++*height; + piece += width * 2; // skip another row, as we've already printed it + } + return ret; +} +#else +// on MS-DOS terminals, we only have block characters for upper half and lower +// half. This lets us print two pieces per character. +std::string piece_matrix(libtorrent::bitfield const& p, int width, int* height) +{ + // print two rows of pieces at a time + int piece = 0; + ++*height; + std::string ret; + ret.reserve((p.size() + width * 2 - 1) / width); + while (piece < p.size()) + { + for (int i = 0; i < width; ++i) + { + // each character has 8 pieces. store them in a byte to use for lookups + // the ordering of these bits + int const c = get_piece(p, piece) + | (get_piece(p, width*2+piece) << 1); + + static char const* const chars[] = + { + " ", // no piece 00 + "\xdf", // top piece 01 + "\xdc", // bottom piece 10 + "\xdb" // both pieces 11 + }; + + ret += chars[c]; + ++piece; + } + ret += '\n'; + ++*height; + piece += width * 2; // skip another row, as we've already printed it + } + return ret; +} +#endif + void set_cursor_pos(int x, int y) { #ifdef _WIN32 diff --git a/examples/print.hpp b/examples/print.hpp index 7ac9e2045..497073153 100644 --- a/examples/print.hpp +++ b/examples/print.hpp @@ -2,6 +2,7 @@ #define PRINT_HPP_ #include +#include "libtorrent/bitfield.hpp" enum color_code { @@ -36,6 +37,7 @@ void clear_screen(); void clear_rows(int y1, int y2); void terminal_size(int* terminal_width, int* terminal_height); +std::string piece_matrix(libtorrent::bitfield const& p, int width, int* height); void print(char const* str);