Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add color support for the TUI #1350

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 20 additions & 36 deletions src/command_ui.cc
Original file line number Diff line number Diff line change
@@ -1,39 +1,3 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <[email protected]>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY

#include "config.h"

#include <sys/types.h>
Expand All @@ -47,8 +11,10 @@

#include "core/manager.h"
#include "core/view_manager.h"
#include "display/canvas.h"
#include "ui/root.h"
#include "ui/download_list.h"
#include "display/color_map.h"
#include "rpc/parse.h"

#include "globals.h"
Expand Down Expand Up @@ -796,6 +762,13 @@ cmd_status_throttle_names(bool up, const torrent::Object::list_type& args) {
return torrent::Object();
}

torrent::Object
apply_set_color(int color_id, const torrent::Object::string_type& color_str) {
control->object_storage()->set_str_string(display::color_vars[color_id], color_str);
display::Canvas::build_colors();
return torrent::Object();
}

void
initialize_command_ui() {
CMD2_VAR_STRING("keys.layout", "qwerty");
Expand Down Expand Up @@ -893,4 +866,15 @@ initialize_command_ui() {

CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2));
CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2));

// Build set/get methods for all color definitions
for (int color_id = 1; color_id < display::RCOLOR_MAX; color_id++) {
control->object_storage()->insert_str(display::color_vars[color_id], "", rpc::object_storage::flag_string_type);
CMD2_ANY_STRING(std::string(display::color_vars[color_id]) + ".set", [color_id](const auto&, const auto& arg) {
return apply_set_color(color_id, arg);
});
CMD2_ANY(display::color_vars[color_id], [color_id](const auto&, const auto&) {
return control->object_storage()->get_str(display::color_vars[color_id]);
});
}
}
163 changes: 120 additions & 43 deletions src/display/canvas.cc
Original file line number Diff line number Diff line change
@@ -1,45 +1,9 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <[email protected]>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY

#include "config.h"

#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <torrent/exceptions.h>
#include <unistd.h>

#include "rpc/parse_commands.h"

Expand All @@ -48,14 +12,16 @@
namespace display {

bool Canvas::m_isInitialized = false;
bool Canvas::m_isDaemon = false;
bool Canvas::m_isDaemon = false;
// Maps ncurses color IDs to a ncurses attribute int
std::unordered_map<int, int> Canvas::m_attr_map = {};

Canvas::Canvas(int x, int y, int width, int height) {
if (!m_isDaemon) {
m_window = newwin(height, width, y, x);
m_window = newwin(height, width, y, x);

if (m_window == NULL)
throw torrent::internal_error("Could not allocate ncurses canvas.");
if (m_window == NULL)
throw torrent::internal_error("Could not allocate ncurses canvas.");
}
}

Expand All @@ -73,7 +39,7 @@ Canvas::print_attributes(unsigned int x, unsigned int y, const char* first, cons
move(x, y);

attr_t org_attr;
short org_pair;
short org_pair;
wattr_get(m_window, &org_attr, &org_pair, NULL);

attributes_list::const_iterator attrItr = attributes->begin();
Expand Down Expand Up @@ -111,6 +77,9 @@ Canvas::initialize() {

if (!m_isDaemon) {
initscr();
start_color();
use_default_colors();
Canvas::build_colors();
raw();
noecho();
nodelay(stdscr, TRUE);
Expand All @@ -119,6 +88,114 @@ Canvas::initialize() {
}
}

// Function wrapper for what possibly is a macro
int
get_colors() {
return COLORS;
}

// Turns the string color definitions from the "ui.color.*" RPC
// commands into valid ncurses color pairs
void
Canvas::build_colors() {

// This may get called early in the start process by the config
// file, so we need to delay building until initscr() has a chance
// to run
if (!m_isInitialized || m_isDaemon)
return;

// basic color names, index maps to ncurses COLOR_*
static const char* color_names[] = {
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"};

// Those hold the background colors of "odd" and "even"
int bg_odd = -1;
int bg_even = -1;

for (int k = 1; k < RCOLOR_MAX; k++) {
init_pair(k, -1, -1);
std::string color_def = rpc::call_command_string(color_vars[k]);
if (color_def.empty())
continue; // Use terminal default if definition is empty

short color[2] = {-1, -1}; // fg, bg
short color_idx = 0; // 0 = fg; 1 = bg
short bright = 0;
unsigned long attr = A_NORMAL;

// Process string as space-separated words
size_t start = 0, end = 0;
while (true) {
end = color_def.find(' ', start);
std::string word = color_def.substr(start, end - start);

if (word == "bold")
attr |= A_BOLD;
else if (word == "standout")
attr |= A_STANDOUT;
else if (word == "underline")
attr |= A_UNDERLINE;
else if (word == "reverse")
attr |= A_REVERSE;
else if (word == "blink")
attr |= A_BLINK;
else if (word == "dim")
attr |= A_DIM;
else if (word == "on") {
color_idx = 1;
bright = 0;
} // Switch to background color
else if (word == "gray" || word == "grey")
color[color_idx] = bright ? 7 : 8; // Bright gray is white
else if (word == "bright")
bright = 8;
else if (word.find_first_not_of("0123456789") == std::string::npos) {
// Handle numeric index
short c = -1;
sscanf(word.c_str(), "%hd", &c);
color[color_idx] = c;
} else
for (short c = 0; c < 8; c++) { // Check for basic color names
if (word == color_names[c]) {
color[color_idx] = bright + c;
break;
}
}
if (end == std::string::npos)
break;
start = end + 1;
}

// Check that fg & bg color index is valid
if ((color[0] != -1 && color[0] >= get_colors()) || (color[1] != -1 && color[1] >= get_colors())) {
char buf[33];
sprintf(buf, "%d", get_colors());
Canvas::cleanup();
throw torrent::input_error(color_def + ": your terminal only supports " + buf + " colors.");
}

m_attr_map[k] = attr; // overwrite or insert the value
init_pair(k, color[0], color[1]);
if (k == RCOLOR_EVEN)
bg_even = color[1];
if (k == RCOLOR_ODD)
bg_odd = color[1];
}

// Now make copies of the basic colors with the "odd" and "even" definitions mixed in
for (int k = 1; k < RCOLOR_MAX; k++) {
short fg, bg;
pair_content(k, &fg, &bg);

// Replace the background color, and mix in the attributes
m_attr_map[k + 1 * RCOLOR_MAX] = m_attr_map[k] | m_attr_map[RCOLOR_EVEN];
m_attr_map[k + 2 * RCOLOR_MAX] = m_attr_map[k] | m_attr_map[RCOLOR_ODD];
init_pair(k + 1 * RCOLOR_MAX, fg, bg == -1 ? bg_even : bg);
init_pair(k + 2 * RCOLOR_MAX, fg, bg == -1 ? bg_odd : bg);
}
}

void
Canvas::cleanup() {
if (!m_isInitialized)
Expand All @@ -143,4 +220,4 @@ Canvas::term_size() {
return std::pair<int, int>(80, 24);
}

}
} // namespace display
Loading
Loading