I'm trying to print a color gradient. When running, nothing is displayed, but when I select the entire window area with the mouse cursor, the colors appear but not a color gradient.
Function smooth
takes the color and dimension information and starts the ncurses environment.
Colors are defined using the init_color
function for and combined in pairs using init_pair
to create custom color pairs.
Pixels are displayed using the mvaddch
functions to place an empty character (' ') on the screen in the appropriate positions. Each column is divided into three equal parts, and each part is displayed with a different pair of colors.
The code:
#include <ncurses.h>
struct Color {
int red, green, blue;
};
void smooth(int rows, int cols, struct Color leftColor, struct Color rightColor) {
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int r, g, b;
r = leftColor.red + ((float)j / cols) * (rightColor.red - leftColor.red);
g = leftColor.green + ((float)j / cols) * (rightColor.green - leftColor.green);
b = leftColor.blue + ((float)j / cols) * (rightColor.blue - leftColor.blue);
init_color(COLOR_BLACK, 0, 0, 0);
init_color(COLOR_RED, r * 1000 / 255, 0, 0);
init_color(COLOR_GREEN, 0, g * 1000 / 255, 0);
init_color(COLOR_BLUE, 0, 0, b * 1000 / 255);
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_BLUE, COLOR_BLACK);
attron(COLOR_PAIR(1));
mvaddch(i, j, ' ');
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(2));
mvaddch(i, j + cols, ' ');
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
mvaddch(i, j + 2 * cols, ' ');
attroff(COLOR_PAIR(3));
}
}
refresh();
getch();
endwin();
}
int main() {
int y, x;
struct Color left, right;
printf("Enter the RGB values for the left color: ");
scanf("%d %d %d", &left.red, &left.green, &left.blue);
printf("Enter the RGB values for the right color: ");
scanf("%d %d %d", &right.red, &right.green, &right.blue);
printf("Height: ");
scanf("%d", &y);
printf("Width: ");
scanf("%d", &x);
smooth(y, x, left, right);
return 0;
}
You inverted foreground and background. You use a black background and a variable foreground color (well, not so variable, see later). So, since you print a space, foreground color is useless. And only background is taken into account. Which is black. So you have a black screen
Unless you select some part with the mouse. In which case, usual behaviour is to revert foreground and background. So there, you see what you expected to see.
Once that corrected, you should get those 3 plain colors as result. Not what you expected. But that is for another reason: you can't recycle colors and pairs. They are supposed to be unique. And even if the terminal (which nowadays is the case of most terminal) has the ability to print a almost infinite number of colors, well, curses anyway needs that color index when you refresh (see for yourself: try to update colors in a loop, after the draw - and doing some refresh each times - you'll see that what you have already printed change colors. Color palette does not impact only future prints, but also past ones. So, you need a different color number and a different pair number for each color you use. Not just 1,2,3 recycled
Also, don't redefine COLOR_BLACK
, COLOR_RED
, etc. They are already defined.
And don't use the predefined color, unless you want to mess up your terminal (so, no color under 16)
All together,
#include <ncurses.h>
#include <unistd.h>
struct Color {
int red, green, blue;
};
void smooth(int rows, int cols, struct Color leftColor, struct Color rightColor) {
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int r, g, b;
r = leftColor.red + ((float)j / cols) * (rightColor.red - leftColor.red);
g = leftColor.green + ((float)j / cols) * (rightColor.green - leftColor.green);
b = leftColor.blue + ((float)j / cols) * (rightColor.blue - leftColor.blue);
// I use j+16 color index, so a unique one, that won't be update afterward
// I avoid using 16 first ones, because I like my default terminal colors
init_color(j+16, r*1000/255, 0, 0);
init_pair(j+16, COLOR_BLACK, j+16); // likewise for pairs`
// Likewise for green
init_color(j+16+cols, 0, g*1000/255, 0);
init_pair(j+16+cols, COLOR_BLACK, j+16+cols);
// Likewise for blue
init_color(j+16+2*cols, 0, 0, b*1000/255);
init_pair(j+16+2*cols, COLOR_BLACK, j+16+2*cols);
// And likewise for all together, since I find quite strange your 3 red/green/blue
// gradient, and suspect that this 4th one is the one you wanted
init_color(j+16+3*cols, r*1000/255, g*1000/255, b*1000/255);
init_pair(j+16+3*cols, COLOR_BLACK, j+16+3*cols);
attron(COLOR_PAIR(16+j));
mvaddch(i, j, 'r'); // Just to be sure, and don't get fooled by space, I print something
attroff(COLOR_PAIR(16+j));
attron(COLOR_PAIR(j+16+cols));
mvaddch(i, j + cols, 'g');
attroff(COLOR_PAIR(j+16+cols));
attron(COLOR_PAIR(j+16+2*cols));
mvaddch(i, j + 2 * cols, 'b');
attroff(COLOR_PAIR(j+16+2*cols));
attron(COLOR_PAIR(j+16+3*cols));
mvaddch(i, j + 3 * cols, 'X');
attroff(COLOR_PAIR(j+16+3*cols));
}
}
refresh();
getch();
// To make my point about "don't reuse color", here what happens we you do anyway
for(int i=0; ;i++){
for(int j=0; j<cols; j++){
init_color((j+i)%cols+16, j*1000/cols, 0, 0);
init_color((j+i)%cols+16+cols, 0, j*1000/cols, 0);
init_color((j+i)%cols+16+2*cols, 0, 0, j*1000/cols);
init_color((j+i)%cols+16+3*cols, j*1000/cols, j*1000/cols, j*1000/cols);
}
refresh();
usleep(100000);
}
endwin();
}
int main() {
int y, x;
struct Color left, right;
// Because I prefer minimal reproducible example, I hard code values (for SO only obviously)
// People don't necessarily know what to fill these values (between 0 and 255? 0 and 1?) with
// Besides, interactive program are wasting people time. Just print something, and explain
// what you expected
left.red=255; left.green=0; left.blue=0;
right.red=0; right.green=255; right.blue=0;
y=25;
x=20;
smooth(y, x, left, right);
return 0;
}
See the animation at the end: I haven't reprinted anything. Just changed the color (not even the pairs). And int changes the whole terminal colors.
So, this is what happens when you init_color(1,...)
: it updates everything on the screen that will and that has been printed with color 1.