summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2013-05-07 18:52:23 +0200
committerMaxime Coste <frrrwww@gmail.com>2013-05-13 14:25:05 +0200
commit56ab33c9d6dc0255bf15ebd1fbc216766ffb247c (patch)
tree40f3cff1b16397f1ea4ab4c7bff7c69b3cd8a606 /src
parentd80815b927b54be6fb51d244b567f52185ee6cea (diff)
support specifying colors with RGB components
Diffstat (limited to 'src')
-rw-r--r--src/color.cc57
-rw-r--r--src/color.hh23
-rw-r--r--src/color_registry.cc28
-rw-r--r--src/display_buffer.hh2
-rw-r--r--src/highlighters.cc4
-rw-r--r--src/ncurses.cc85
-rw-r--r--src/remote.cc25
7 files changed, 168 insertions, 56 deletions
diff --git a/src/color.cc b/src/color.cc
index f1b3ef8a..6067dcc5 100644
--- a/src/color.cc
+++ b/src/color.cc
@@ -2,37 +2,54 @@
#include "exception.hh"
+#include <stdlib.h>
+
namespace Kakoune
{
Color str_to_color(const String& color)
{
- if (color == "default") return Color::Default;
- if (color == "black") return Color::Black;
- if (color == "red") return Color::Red;
- if (color == "green") return Color::Green;
- if (color == "yellow") return Color::Yellow;
- if (color == "blue") return Color::Blue;
- if (color == "magenta") return Color::Magenta;
- if (color == "cyan") return Color::Cyan;
- if (color == "white") return Color::White;
+ if (color == "default") return Colors::Default;
+ if (color == "black") return Colors::Black;
+ if (color == "red") return Colors::Red;
+ if (color == "green") return Colors::Green;
+ if (color == "yellow") return Colors::Yellow;
+ if (color == "blue") return Colors::Blue;
+ if (color == "magenta") return Colors::Magenta;
+ if (color == "cyan") return Colors::Cyan;
+ if (color == "white") return Colors::White;
+
+ static const Regex rgb_regex{"rgb:[0-9a-fA-F]{6}"};
+ if (boost::regex_match(color, rgb_regex))
+ {
+ long int l = strtol(color.c_str() + 4, NULL, 16);
+ return { (unsigned char)((l >> 16) & 0xFF),
+ (unsigned char)((l >> 8) & 0xFF),
+ (unsigned char)(l & 0xFF) };
+ }
throw runtime_error("Unable to parse color '" + color + "'");
- return Color::Default;
+ return Colors::Default;
}
String color_to_str(const Color& color)
{
- switch (color)
+ switch (color.color)
{
- case Color::Default: return "default";
- case Color::Black: return "black";
- case Color::Red: return "red";
- case Color::Green: return "green";
- case Color::Yellow: return "yellow";
- case Color::Blue: return "blue";
- case Color::Magenta: return "magenta";
- case Color::Cyan: return "cyan";
- case Color::White: return "white";
+ case Colors::Default: return "default";
+ case Colors::Black: return "black";
+ case Colors::Red: return "red";
+ case Colors::Green: return "green";
+ case Colors::Yellow: return "yellow";
+ case Colors::Blue: return "blue";
+ case Colors::Magenta: return "magenta";
+ case Colors::Cyan: return "cyan";
+ case Colors::White: return "white";
+ case Colors::RGB:
+ {
+ char buffer[11];
+ sprintf(buffer, "rgb:%02x%02x%02x", color.r, color.g, color.b);
+ return buffer;
+ }
}
kak_assert(false);
return "default";
diff --git a/src/color.hh b/src/color.hh
index 0cd7d18c..9cc5abf5 100644
--- a/src/color.hh
+++ b/src/color.hh
@@ -8,7 +8,7 @@ namespace Kakoune
class String;
-enum class Color : char
+enum class Colors : char
{
Default,
Black,
@@ -18,7 +18,26 @@ enum class Color : char
Blue,
Magenta,
Cyan,
- White
+ White,
+ RGB,
+};
+
+struct Color
+{
+ Colors color;
+ unsigned char r;
+ unsigned char g;
+ unsigned char b;
+
+ Color() : Color{Colors::Default} {}
+ Color(Colors c) : color{c}, r{0}, g{0}, b{0} {}
+ Color(unsigned char r, unsigned char g, unsigned char b)
+ : color{Colors::RGB}, r{r}, g{g}, b{b} {}
+
+ bool operator==(const Color& c) const
+ { return color == c.color and r == c.r and g == c.g and b == c.b; }
+ bool operator!=(const Color& c) const
+ { return color != c.color or r != c.r or g != c.g or b != c.b; }
};
using ColorPair = std::pair<Color, Color>;
diff --git a/src/color_registry.cc b/src/color_registry.cc
index f35b3177..2b68ea22 100644
--- a/src/color_registry.cc
+++ b/src/color_registry.cc
@@ -15,7 +15,7 @@ const ColorPair& ColorRegistry::operator[](const String& colordesc)
ColorPair colpair{ str_to_color(String(colordesc.begin(), it)),
it != colordesc.end() ?
str_to_color(String(it+1, colordesc.end()))
- : Color::Default };
+ : Colors::Default };
return (m_aliases[colordesc] = colpair);
}
@@ -32,7 +32,7 @@ void ColorRegistry::register_alias(const String& name, const String& colordesc,
auto it = std::find(colordesc.begin(), colordesc.end(), ',');
auto fg = str_to_color(String(colordesc.begin(), it));
- auto bg = Color::Default;
+ auto bg = Color{Colors::Default};
if (it != colordesc.end())
bg = str_to_color(String(it+1, colordesc.end()));
@@ -41,18 +41,18 @@ void ColorRegistry::register_alias(const String& name, const String& colordesc,
ColorRegistry::ColorRegistry()
: m_aliases{
- { "PrimarySelection", { Color::Cyan, Color::Blue } },
- { "SecondarySelection", { Color::Black, Color::Blue } },
- { "PrimaryCursor", { Color::Black, Color::White } },
- { "SecondaryCursor", { Color::Black, Color::White } },
- { "LineNumbers", { Color::Black, Color::White } },
- { "MenuForeground", { Color::Blue, Color::Cyan } },
- { "MenuBackground", { Color::Cyan, Color::Blue } },
- { "Information", { Color::Black, Color::Yellow } },
- { "Error", { Color::Black, Color::Red } },
- { "StatusLine", { Color::Cyan, Color::Default } },
- { "StatusCursor", { Color::Black, Color::Cyan } },
- { "Prompt", { Color::Yellow, Color::Default} },
+ { "PrimarySelection", { Colors::Cyan, Colors::Blue } },
+ { "SecondarySelection", { Colors::Black, Colors::Blue } },
+ { "PrimaryCursor", { Colors::Black, Colors::White } },
+ { "SecondaryCursor", { Colors::Black, Colors::White } },
+ { "LineNumbers", { Colors::Black, Colors::White } },
+ { "MenuForeground", { Colors::Blue, Colors::Cyan } },
+ { "MenuBackground", { Colors::Cyan, Colors::Blue } },
+ { "Information", { Colors::Black, Colors::Yellow } },
+ { "Error", { Colors::Black, Colors::Red } },
+ { "StatusLine", { Colors::Cyan, Colors::Default } },
+ { "StatusCursor", { Colors::Black, Colors::Cyan } },
+ { "Prompt", { Colors::Yellow, Colors::Default} },
}
{}
diff --git a/src/display_buffer.hh b/src/display_buffer.hh
index 82940259..f7abe4c3 100644
--- a/src/display_buffer.hh
+++ b/src/display_buffer.hh
@@ -115,7 +115,7 @@ struct DisplayAtom
AtomContent content;
DisplayAtom(AtomContent content,
- ColorPair colors = {Color::Default, Color::Default},
+ ColorPair colors = {Colors::Default, Colors::Default},
Attribute attribute = Normal)
: content{std::move(content)}, colors{colors}, attribute{attribute}
{}
diff --git a/src/highlighters.cc b/src/highlighters.cc
index aef857c5..be06189b 100644
--- a/src/highlighters.cc
+++ b/src/highlighters.cc
@@ -323,7 +323,7 @@ void expand_unprintable(DisplayBuffer& display_buffer)
if ((it+1).underlying_iterator() != atom_it->content.end())
atom_it = line.split(atom_it, (it+1).underlying_iterator());
atom_it->content.replace(str);
- atom_it->colors = { Color::Red, Color::Black };
+ atom_it->colors = { Colors::Red, Colors::Black };
break;
}
}
@@ -361,7 +361,7 @@ public:
String content = it != lines.end() ? std::get<2>(*it) : empty;
content += String(' ', width - content.char_length());
DisplayAtom atom{AtomContent(std::move(content))};
- atom.colors = { it != lines.end() ? std::get<1>(*it) : Color::Default , m_bg };
+ atom.colors = { it != lines.end() ? std::get<1>(*it) : Colors::Default , m_bg };
line.insert(line.begin(), std::move(atom));
}
}
diff --git a/src/ncurses.cc b/src/ncurses.cc
index 80d78e9a..f4e44d90 100644
--- a/src/ncurses.cc
+++ b/src/ncurses.cc
@@ -26,22 +26,73 @@ static void set_attribute(int attribute, bool on)
attroff(attribute);
}
-static int nc_color(Color color)
+static bool operator<(const Color& lhs, const Color& rhs)
{
- switch (color)
+ if (lhs.color == rhs.color and lhs.color == Colors::RGB)
+ return lhs.r == rhs.r ? (lhs.g == rhs.g ? lhs.b < rhs.b
+ : lhs.g < rhs.g)
+ : lhs.r < rhs.r;
+ return lhs.color < rhs.color;
+}
+
+static int nc_color(const Color& color)
+{
+ static std::map<Color, int> colors = {
+ { Colors::Default, -1 },
+ { Colors::Black, COLOR_BLACK },
+ { Colors::Red, COLOR_RED },
+ { Colors::Green, COLOR_GREEN },
+ { Colors::Yellow, COLOR_YELLOW },
+ { Colors::Blue, COLOR_BLUE },
+ { Colors::Magenta, COLOR_MAGENTA },
+ { Colors::Cyan, COLOR_CYAN },
+ { Colors::White, COLOR_WHITE },
+ };
+ static int next_color = 8;
+
+ auto it = colors.find(color);
+ if (it != colors.end())
+ return it->second;
+ else if (can_change_color() and COLORS > 8)
{
- case Color::Black: return COLOR_BLACK;
- case Color::Red: return COLOR_RED;
- case Color::Green: return COLOR_GREEN;
- case Color::Yellow: return COLOR_YELLOW;
- case Color::Blue: return COLOR_BLUE;
- case Color::Magenta: return COLOR_MAGENTA;
- case Color::Cyan: return COLOR_CYAN;
- case Color::White: return COLOR_WHITE;
-
- case Color::Default:
- default:
- return -1;
+ kak_assert(color.color == Colors::RGB);
+ if (next_color > COLORS)
+ next_color = 8;
+ init_color(next_color,
+ color.r * 1000 / 255,
+ color.g * 1000 / 255,
+ color.b * 1000 / 255);
+ colors[color] = next_color;
+ return next_color++;
+ }
+ else
+ {
+ kak_assert(color.color == Colors::RGB);
+ // project to closest color.
+ struct BuiltinColor { int id; unsigned char r, g, b; };
+ static constexpr BuiltinColor builtins[] = {
+ { COLOR_BLACK, 0, 0, 0 },
+ { COLOR_RED, 255, 0, 0 },
+ { COLOR_GREEN, 0, 255, 0 },
+ { COLOR_YELLOW, 255, 255, 0 },
+ { COLOR_BLUE, 0, 0, 255 },
+ { COLOR_MAGENTA, 255, 0, 255 },
+ { COLOR_CYAN, 0, 255, 255 },
+ { COLOR_WHITE, 255, 255, 255 }
+ };
+ auto sq = [](int x) { return x * x; };
+ int lowestDist = INT_MAX;
+ int closestCol = -1;
+ for (auto& col : builtins)
+ {
+ int dist = sq(color.r - col.r) + sq(color.g - col.g) + sq(color.b - col.b);
+ if (dist < lowestDist)
+ {
+ lowestDist = dist;
+ closestCol = col.id;
+ }
+ }
+ return closestCol;
}
}
@@ -68,7 +119,7 @@ static void set_color(WINDOW* window, const ColorPair colors)
if (current_pair != -1)
wattroff(window, COLOR_PAIR(current_pair));
- if (colors.first != Color::Default or colors.second != Color::Default)
+ if (colors.first != Colors::Default or colors.second != Colors::Default)
{
current_pair = get_color_pair(colors);
wattron(window, COLOR_PAIR(current_pair));
@@ -202,7 +253,7 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
set_attribute(A_REVERSE, 0);
set_attribute(A_BLINK, 0);
set_attribute(A_BOLD, 0);
- set_color(stdscr, { Color::Blue, Color::Default });
+ set_color(stdscr, { Colors::Blue, Colors::Default });
for (;line_index < m_dimensions.line; ++line_index)
{
move((int)line_index, 0);
@@ -321,7 +372,7 @@ void NCursesUI::draw_menu()
auto menu_fg = get_color_pair(m_menu_fg);
auto menu_bg = get_color_pair(m_menu_bg);
- auto scroll_fg = get_color_pair({ Color::White, Color::White });
+ auto scroll_fg = get_color_pair({ Colors::White, Colors::White });
auto scroll_bg = get_color_pair(m_menu_bg);
wattron(m_menu_win, COLOR_PAIR(menu_bg));
diff --git a/src/remote.cc b/src/remote.cc
index 7b68f6f8..94128871 100644
--- a/src/remote.cc
+++ b/src/remote.cc
@@ -75,6 +75,17 @@ public:
write(memoryview<T>(vec));
}
+ void write(const Color& color)
+ {
+ write(color.color);
+ if (color.color == Colors::RGB)
+ {
+ write(color.r);
+ write(color.g);
+ write(color.b);
+ }
+ }
+
void write(const ColorPair& colors)
{
write(colors.first);
@@ -150,6 +161,20 @@ std::vector<T> read_vector(int socket)
}
template<>
+Color read<Color>(int socket)
+{
+ Color res;
+ res.color = read<Colors>(socket);
+ if (res.color == Colors::RGB)
+ {
+ res.r = read<unsigned char>(socket);
+ res.g = read<unsigned char>(socket);
+ res.b = read<unsigned char>(socket);
+ }
+ return res;
+}
+
+template<>
ColorPair read<ColorPair>(int socket)
{
ColorPair res;