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