1 #include <unistd.h>
2 #include "demo.h"
3
4 static void
grow_rgb8(uint32_t * rgb)5 grow_rgb8(uint32_t* rgb){
6 int r = ncchannel_r(*rgb);
7 int g = ncchannel_g(*rgb);
8 int b = ncchannel_b(*rgb);
9 int delta = (*rgb & 0x80000000ul) ? -1 : 1;
10 if(b == r){
11 b += delta;
12 }else if(g == r){
13 g += delta;
14 }else{
15 r += delta;
16 }
17 if(b == 256 || r == 256 || g == 256){
18 b = r = g = 255;
19 *rgb |= 0x80000000ul;
20 }else if(b == -1 || r == -1 || g == -1){
21 b = r = g = 0;
22 *rgb &= ~0x80000000ul;
23 }
24 *rgb = (*rgb & 0xff000000ul) | (r * 65536 + g * 256 + b);
25 }
26
27 static struct ncplane*
legend(struct notcurses * nc,const char * msg)28 legend(struct notcurses* nc, const char* msg){
29 unsigned dimx, dimy;
30 notcurses_term_dim_yx(nc, &dimy, &dimx);
31 ncplane_options nopts = {
32 .rows = 3,
33 .cols = strlen(msg) + 4,
34 .y = 3,
35 .x = NCALIGN_CENTER,
36 .flags = NCPLANE_OPTION_HORALIGNED,
37 };
38 struct ncplane* n = ncplane_create(notcurses_stdplane(nc), &nopts);
39 if(n == NULL){
40 return NULL;
41 }
42 nccell c = NCCELL_TRIVIAL_INITIALIZER;
43 nccell_set_fg_rgb8(&c, 0, 0, 0); // darken surrounding characters by half
44 nccell_set_fg_alpha(&c, NCALPHA_BLEND);
45 nccell_set_bg_alpha(&c, NCALPHA_TRANSPARENT); // don't touch background
46 if(ncplane_set_base_cell(n, &c)){
47 ncplane_destroy(n);
48 return NULL;
49 }
50 if(ncplane_set_fg_rgb(n, 0xd78700) || ncplane_set_bg_rgb(n, 0)){
51 ncplane_destroy(n);
52 return NULL;
53 }
54 ncplane_on_styles(n, NCSTYLE_BOLD | NCSTYLE_ITALIC);
55 if(ncplane_printf_aligned(n, 1, NCALIGN_CENTER, " %s ", msg) < 0){
56 ncplane_destroy(n);
57 return NULL;
58 }
59 return n;
60 }
61
62 static int
slideitslideit(struct notcurses * nc,struct ncplane * n,uint64_t deadline,int * vely,int * velx)63 slideitslideit(struct notcurses* nc, struct ncplane* n, uint64_t deadline,
64 int* vely, int* velx){
65 int yoff, xoff;
66 unsigned dimy, dimx;
67 notcurses_term_dim_yx(nc, &dimy, &dimx);
68 unsigned ny, nx;
69 ncplane_dim_yx(n, &ny, &nx);
70 ncplane_yx(n, &yoff, &xoff);
71 struct timespec iterdelay;
72 timespec_div(&demodelay, 60, &iterdelay);
73 struct timespec cur;
74 do{
75 DEMO_RENDER(nc);
76 yoff += *vely;
77 xoff += *velx;
78 if(xoff <= 1){
79 xoff = 1;
80 *velx = -*velx;
81 }else if((unsigned)xoff >= dimx - nx){
82 xoff = dimx - nx - 1;
83 *velx = -*velx;
84 }
85 if(yoff <= 2){
86 yoff = 2;
87 *vely = -*vely;
88 }else if((unsigned)yoff >= dimy - ny){
89 yoff = dimy - ny - 1;
90 *vely = -*vely;
91 }
92 ncplane_move_yx(n, yoff, xoff);
93 demo_nanosleep(nc, &iterdelay);
94 clock_gettime(CLOCK_MONOTONIC, &cur);
95 }while(timespec_to_ns(&cur) < deadline);
96 return 0;
97 }
98
99 // run panels atop the display in an exploration of transparency
100 static int
slidepanel(struct notcurses * nc,struct ncplane * stdn)101 slidepanel(struct notcurses* nc, struct ncplane* stdn){
102 unsigned dimy, dimx;
103 notcurses_term_dim_yx(nc, &dimy, &dimx);
104 int ny = dimy / 4;
105 int nx = dimx / 3;
106 int yoff = rand() % (dimy - ny - 2) + 1; // don't start atop a border
107 int xoff = rand() % (dimx - nx - 2) + 1;
108 struct ncplane* l;
109
110 // First we just create a plane with no styling and no glyphs.
111 struct ncplane_options nopts = {
112 .y = yoff,
113 .x = xoff,
114 .rows = ny,
115 .cols = nx,
116 };
117 struct ncplane* n = ncplane_create(stdn, &nopts);
118
119 // Zero-initialized channels use the default color, opaquely. Since we have
120 // no glyph, we should show underlying glyphs in the default colors. The
121 // background default might be transparent, at the window level (i.e. a copy
122 // of the underlying desktop).
123 nccell c = NCCELL_CHAR_INITIALIZER(' ');
124 struct timespec cur;
125 ncplane_set_base_cell(n, &c);
126 clock_gettime(CLOCK_MONOTONIC, &cur);
127 uint64_t deadlinens = timespec_to_ns(&cur) + timespec_to_ns(&demodelay);
128 int velx = rand() % 4 + 1;
129 int vely = rand() % 4 + 1;
130 l = legend(nc, "default background, all opaque, whitespace glyph");
131 int err = slideitslideit(nc, n, deadlinens, &vely, &velx);
132 if(err){
133 ncplane_destroy(n);
134 ncplane_destroy(l);
135 return err;
136 }
137 ncplane_destroy(l);
138
139 nccell_load_char(n, &c, '\0');
140 ncplane_set_base_cell(n, &c);
141 clock_gettime(CLOCK_MONOTONIC, &cur);
142 deadlinens = timespec_to_ns(&cur) + timespec_to_ns(&demodelay);
143 l = legend(nc, "default background, all opaque, no glyph");
144 if( (err = slideitslideit(nc, n, deadlinens, &vely, &velx)) ){
145 ncplane_destroy(n);
146 ncplane_destroy(l);
147 return err;
148 }
149 ncplane_destroy(l);
150
151 // Next, we set our foreground transparent, allowing characters underneath to
152 // be seen in their natural colors. Our background remains opaque+default.
153 nccell_set_fg_alpha(&c, NCALPHA_TRANSPARENT);
154 ncplane_set_base_cell(n, &c);
155 clock_gettime(CLOCK_MONOTONIC, &cur);
156 deadlinens = timespec_to_ns(&cur) + timespec_to_ns(&demodelay);
157 l = legend(nc, "default background, fg transparent, no glyph");
158 if( (err = slideitslideit(nc, n, deadlinens, &vely, &velx)) ){
159 ncplane_destroy(n);
160 ncplane_destroy(l);
161 return err;
162 }
163 ncplane_destroy(l);
164
165 // Set the foreground color, setting it to blend. We should get the underlying
166 // glyphs in a blended color, with the default background color.
167 nccell_set_fg_rgb(&c, 0x80c080);
168 nccell_set_fg_alpha(&c, NCALPHA_BLEND);
169 ncplane_set_base_cell(n, &c);
170 clock_gettime(CLOCK_MONOTONIC, &cur);
171 l = legend(nc, "default background, fg blended, no glyph");
172 deadlinens = timespec_to_ns(&cur) + timespec_to_ns(&demodelay);
173 if( (err = slideitslideit(nc, n, deadlinens, &vely, &velx)) ){
174 ncplane_destroy(n);
175 ncplane_destroy(l);
176 return err;
177 }
178 ncplane_destroy(l);
179
180 // Opaque foreground color. This produces underlying glyphs in the specified,
181 // fixed color, with the default background color.
182 nccell_set_fg_rgb(&c, 0x80c080);
183 nccell_set_fg_alpha(&c, NCALPHA_OPAQUE);
184 ncplane_set_base_cell(n, &c);
185 clock_gettime(CLOCK_MONOTONIC, &cur);
186 l = legend(nc, "default background, fg colored opaque, no glyph");
187 deadlinens = timespec_to_ns(&cur) + timespec_to_ns(&demodelay);
188 if( (err = slideitslideit(nc, n, deadlinens, &vely, &velx)) ){
189 ncplane_destroy(n);
190 ncplane_destroy(l);
191 return err;
192 }
193 ncplane_destroy(l);
194
195 // Now we replace the characters with X's, colored as underneath us.
196 // Our background color remains opaque default.
197 nccell_load_char(n, &c, 'X');
198 nccell_set_fg_default(&c);
199 nccell_set_fg_alpha(&c, NCALPHA_TRANSPARENT);
200 nccell_set_bg_alpha(&c, NCALPHA_OPAQUE);
201 ncplane_set_base_cell(n, &c);
202 clock_gettime(CLOCK_MONOTONIC, &cur);
203 l = legend(nc, "default colors, fg transparent, print glyph");
204 deadlinens = timespec_to_ns(&cur) + timespec_to_ns(&demodelay);
205 if( (err = slideitslideit(nc, n, deadlinens, &vely, &velx)) ){
206 ncplane_destroy(n);
207 ncplane_destroy(l);
208 return err;
209 }
210 ncplane_destroy(l);
211
212 // Now we replace the characters with X's, but draw the foreground and
213 // background color from below us.
214 nccell_set_fg_alpha(&c, NCALPHA_TRANSPARENT);
215 nccell_set_bg_alpha(&c, NCALPHA_TRANSPARENT);
216 ncplane_set_base_cell(n, &c);
217 clock_gettime(CLOCK_MONOTONIC, &cur);
218 l = legend(nc, "all transparent, print glyph");
219 deadlinens = timespec_to_ns(&cur) + timespec_to_ns(&demodelay);
220 if( (err = slideitslideit(nc, n, deadlinens, &vely, &velx)) ){
221 ncplane_destroy(n);
222 ncplane_destroy(l);
223 return err;
224 }
225 ncplane_destroy(l);
226
227 // Finally, we populate the plane for the first time with non-transparent
228 // characters. We blend, however, to show the underlying color in our glyphs.
229 nccell_set_fg_alpha(&c, NCALPHA_BLEND);
230 nccell_set_bg_alpha(&c, NCALPHA_BLEND);
231 nccell_set_fg_rgb(&c, 0x80c080);
232 nccell_set_bg_rgb(&c, 0x204080);
233 ncplane_set_base_cell(n, &c);
234 clock_gettime(CLOCK_MONOTONIC, &cur);
235 l = legend(nc, "all blended, print glyph");
236 deadlinens = timespec_to_ns(&cur) + timespec_to_ns(&demodelay);
237 if( (err = slideitslideit(nc, n, deadlinens, &vely, &velx)) ){
238 ncplane_destroy(n);
239 ncplane_destroy(l);
240 return err;
241 }
242 ncplane_destroy(l);
243
244 char* logop = find_data("notcurses.png");
245 struct ncvisual* ncv = ncvisual_from_file(logop);
246 if(ncv == NULL){
247 ncplane_destroy(n);
248 return err;
249 }
250 free(logop);
251 struct ncvisual_options vopts = {
252 .n = n,
253 .scaling = NCSCALE_STRETCH,
254 .blitter = NCBLIT_PIXEL,
255 };
256 if(ncvisual_blit(nc, ncv, &vopts) == NULL){
257 ncplane_destroy(n);
258 return err;
259 }
260 ncvisual_destroy(ncv);
261 clock_gettime(CLOCK_MONOTONIC, &cur);
262 l = legend(nc, "partially-transparent image");
263 deadlinens = timespec_to_ns(&cur) + 2 * timespec_to_ns(&demodelay);
264 if( (err = slideitslideit(nc, n, deadlinens, &vely, &velx)) ){
265 ncplane_destroy(n);
266 ncplane_destroy(l);
267 return err;
268 }
269 ncplane_destroy(l);
270
271 return ncplane_destroy(n);
272 }
273
274 // draws a border along the perimeter, then fills the inside with position
275 // markers, each a slightly different color. the goal is to make sure we can
276 // have a great many colors, that they progress reasonably through the space,
277 // and that we can write to every coordinate.
trans_demo(struct notcurses * nc,uint64_t startns)278 int trans_demo(struct notcurses* nc, uint64_t startns){
279 (void)startns;
280 unsigned maxx, maxy;
281 struct ncplane* n = notcurses_stddim_yx(nc, &maxy, &maxx);
282 ncplane_set_fg_rgb8(n, 255, 255, 255);
283 uint64_t channels = 0;
284 ncchannels_set_fg_rgb8(&channels, 0, 128, 128);
285 ncchannels_set_bg_rgb8(&channels, 90, 0, 90);
286 unsigned y = 1, x = 0;
287 ncplane_cursor_move_yx(n, y, x);
288 if(ncplane_rounded_box_sized(n, 0, channels, maxy - 1, maxx, 0)){
289 return -1;
290 }
291 uint32_t rgb = 0;
292 while(++y < maxy - 1){
293 x = 1;
294 if(ncplane_cursor_move_yx(n, y, x)){
295 return -1;
296 }
297 while(x < maxx - 1){
298 ncplane_set_fg_rgb8(n, (rgb & 0xff0000) >> 16u, (rgb & 0xff00) >> 8u, rgb & 0xff);
299 ncplane_set_bg_rgb8(n, 0, 10, 0);
300 ncplane_putchar(n, x % 10 + '0');
301 grow_rgb8(&rgb);
302 ++x;
303 }
304 }
305 if(notcurses_canfade(nc)){
306 struct ncplane* l = legend(nc, "what say we explore transparency together?");
307 DEMO_RENDER(nc);
308 struct timespec now;
309 clock_gettime(CLOCK_MONOTONIC, &now);
310 int err;
311 if( (err = ncplane_pulse(l, &demodelay, pulser, &now)) != 2){
312 return err;
313 }
314 ncplane_destroy(l);
315 }
316 return slidepanel(nc, n);
317 }
318