1 #include <cctype>
2 #include <cstdlib>
3 #include <climits>
4 #include <cmath>
5 #include <cstring>
6 #include <cerrno>
7 #ifdef DEBUG
8 #ifdef __linux__
9 #define MEMCHECK
10 #include <malloc.h>
11 #endif
12 #endif
13 
14 #include "config.h"
15 #include "filter.h"
16 #include "ui_helper.h"
17 #include "plane.h"
18 #include "timers.h"
19 #include "zoom.h"
20 #include "xmenu.h"
21 #include "xerror.h"
22 #include "autopilot.h"
23 #include "grlib.h"
24 #include "play.h"
25 
26 #ifdef HAVE_LIBGEN_H
27 #include <libgen.h>
28 #endif
29 
30 #include "i18n.h"
31 
32 #ifndef M_PI
33 #define M_PI 3.14159265358979323846
34 #endif
35 
36 #define WAITTIME 50000
37 #define WAITTIME1 200000
38 #define WAITTIME2 2000000
39 #define uih_palettechg(uih)                                                    \
40     if (!uih->recalculatemode && uih->queue->palettechg != NULL)               \
41     uih->recalculatemode = UIH_PALETTEDRAW, uih->display = 1
42 #include "misc-f.h"
43 
44 static struct filter *uih_getinstance(const struct filteraction *a);
45 static void uih_destroyinstance(struct filter *f);
46 static int uih_require(struct filter *f, struct requirements *r);
47 static int uih_initialize(struct filter *f, struct initdata *i);
48 static const rgb_t uicolors[] = {
49     {0, 0, 0},    {255, 255, 255}, {255, 65, 0},
50     {64, 64, 64}, {128, 128, 128}, {128 + 64, 128 + 64, 128 + 64}};
51 
52 static const rgb_t uibwcolors[] = {{0, 0, 0},       {255, 255, 255},
53                                    {255, 255, 255}, {255, 255, 255},
54                                    {255, 255, 255}, {255, 255, 255}};
55 
56 static const struct filteraction uih_filter = {"XaoS's user interface layer",
57                                                "ui",
58                                                0,
59                                                uih_getinstance,
60                                                uih_destroyinstance,
61                                                NULL,
62                                                uih_require,
63                                                uih_initialize,
64                                                convertupgeneric,
65                                                convertdowngeneric,
66                                                NULL};
67 
68 static uih_context *uih;
69 static int waitcount, waitcount1, waitcount2;
70 
71 const struct filteraction *const uih_filters[MAXFILTERS] = {&edge_filter,
72                                                             &edge2_filter,
73                                                             &threed_filter,
74                                                             &starfield_filter,
75                                                             &stereogram_filter,
76                                                             &interlace_filter,
77                                                             &blur_filter,
78                                                             &emboss_filter,
79                                                             &palette_filter,
80                                                             &antialias_filter,
81                                                             NULL};
82 
83 const int uih_nfilters = 10;
84 
uih_invalidatepos(uih_context * uih)85 static void uih_invalidatepos(uih_context *uih)
86 {
87     uih->xcenterm = INT_MAX;
88     uih->xcenterm = INT_MAX;
89 }
90 
uih_finishpalette(struct uih_context * uih)91 static void uih_finishpalette(struct uih_context *uih)
92 {
93     if (uih->image->palette->flags & UNFINISHED) {
94         if (uih->image->palette->allocfinished != NULL)
95             uih->image->palette->allocfinished(uih->image->palette);
96         uih->image->palette->flags &= ~UNFINISHED;
97     }
98 }
99 
uih_getcoord(uih_context * uih,int x,int y,number_t * xr,number_t * yr)100 static void uih_getcoord(uih_context *uih, int x, int y, number_t *xr,
101                          number_t *yr)
102 {
103     uih->uifilter->action->convertdown(uih->uifilter, &x, &y);
104     *xr = (((number_t)(uih->fcontext->rs.nc +
105                        (x) * ((uih->fcontext->rs.mc - uih->fcontext->rs.nc) /
106                               (number_t)uih->zengine->image->width))));
107     *yr = (((number_t)(uih->fcontext->rs.ni +
108                        (y) * ((uih->fcontext->rs.mi - uih->fcontext->rs.ni) /
109                               (number_t)uih->zengine->image->height))));
110     rotateback(*(uih->fcontext), *xr, *yr);
111 }
112 
uih_enablefilter(uih_context * c,int n)113 int uih_enablefilter(uih_context *c, int n)
114 {
115     if (c->filter[n] == NULL) {
116         struct filter *f, *f1;
117         int i, wascycling = 0;
118         if (c->cycling)
119             uih_cycling_off(c), wascycling = 1;
120         f = uih_filters[n]->getinstance(uih_filters[n]);
121         f1 = c->uifilter;
122         if (c->fixedcolor != NULL)
123             f1 = c->fixedcolor;
124         for (i = MAXFILTERS - 1; i > n; i--) {
125             if (c->filter[i])
126                 f1 = c->filter[i];
127         }
128         uih_newimage(c);
129         insertfilter(f, f1);
130         if (!initqueue(c->queue)) {
131             c->ddatalost = 1;
132             removefilter(f);
133             f->action->destroyinstance(f);
134             if (!initqueue(c->queue)) {
135                 x_fatalerror(
136                     "Fatal error. Can not continue - initialization of queue can not be performed eigher with or without filter");
137             }
138             if (wascycling)
139                 uih_cycling_on(c);
140             if (!strcmp("palette", uih_filters[n]->shortname)) {
141                 uih_updatemenus(c, "palettef");
142             } else {
143                 uih_updatemenus(c, uih_filters[n]->shortname);
144             }
145             return 0;
146         } else
147             c->filter[n] = f;
148         if (wascycling)
149             uih_cycling_on(c);
150         if (!strcmp("palette", uih_filters[n]->shortname)) {
151             uih_updatemenus(c, "palettef");
152         } else {
153             uih_updatemenus(c, uih_filters[n]->shortname);
154         }
155         return 1;
156     }
157     return 0;
158 }
159 
uih_disablefilter(uih_context * c,int n)160 void uih_disablefilter(uih_context *c, int n)
161 {
162     if (n == c->aliasnum)
163         return;
164     if (c->filter[n] != NULL) {
165         int wascycling = 0;
166         struct filter *f = c->filter[n];
167         if (c->cycling)
168             uih_cycling_off(c), wascycling = 1;
169         uih_newimage(c);
170         removefilter(f);
171         if (!initqueue(c->queue)) {
172             struct filter *f1;
173             int i;
174             c->ddatalost = 1;
175             f1 = c->uifilter;
176             if (c->fixedcolor != NULL)
177                 f1 = c->fixedcolor;
178             for (i = MAXFILTERS - 1; i > n; i--) {
179                 if (c->filter[i])
180                     f1 = c->filter[i];
181             }
182             insertfilter(f, f1);
183             if (!initqueue(c->queue)) {
184                 x_fatalerror("Fatal error. Can not continue");
185             }
186         } else
187             f->action->destroyinstance(f), c->filter[n] = NULL;
188         if (wascycling)
189             uih_cycling_on(c);
190         if (!strcmp("palette", uih_filters[n]->shortname)) {
191             uih_updatemenus(c, "palettef");
192         } else {
193             uih_updatemenus(c, uih_filters[n]->shortname);
194         }
195     }
196 }
197 
uih_fastrotateenable(uih_context * c)198 int uih_fastrotateenable(uih_context *c)
199 {
200     int wascycling = 0;
201     if (c->juliamode)
202         uih_disablejulia(c);
203     if (!c->fastrotate && !c->juliamode) {
204         if (c->cycling)
205             uih_cycling_off(c), wascycling = 1;
206         c->rotatef = rotate_filter.getinstance(&rotate_filter);
207         if (c->rotatef == NULL)
208             goto end;
209         uih_newimage(c);
210         addfilter(c->rotatef, c->zengine);
211         if (!initqueue(c->queue))
212             goto end2;
213         if (wascycling)
214             uih_cycling_on(c);
215         c->fastrotate = 1;
216         return 1;
217     }
218     return 0;
219 end2:
220     removefilter(c->rotatef);
221     initqueue(c->queue);
222     c->rotatef->action->destroyinstance(c->rotatef);
223 end:
224     if (wascycling)
225         uih_cycling_on(c);
226     return 0;
227 }
228 
uih_fastrotatedisable(uih_context * c)229 void uih_fastrotatedisable(uih_context *c)
230 {
231     if (c->fastrotate) {
232         int wascycling = 0;
233         uih_rotatemode(c, ROTATE_NONE);
234         if (c->cycling)
235             uih_cycling_off(c), wascycling = 1;
236         c->fastrotate = 0;
237         removefilter(c->rotatef);
238         initqueue(c->queue);
239         c->rotatef->action->destroyinstance(c->rotatef);
240         uih_newimage(c);
241         if (wascycling)
242             uih_cycling_on(c);
243     }
244 }
245 
uih_rotate(struct uih_context * c,int n)246 void uih_rotate(struct uih_context *c, int n)
247 {
248     if (!n)
249         uih_fastrotate(c, 0);
250     else {
251         uih_fastrotate(c, 1);
252         uih_rotatemode(c, n);
253     }
254 }
255 
uih_fixedcolordisable(uih_context *)256 static void uih_fixedcolordisable(uih_context * /*c*/)
257 {
258 #ifdef SCONVERTORS
259     if (c->fixedcolor != NULL) {
260         int wascycling = 0;
261         if (c->cycling)
262             uih_cycling_off(c), wascycling = 1;
263         initqueue(c->queue);
264         removefilter(c->fixedcolor);
265         initqueue(c->queue);
266         c->fixedcolor->action->destroyinstance(c->fixedcolor);
267         c->fixedcolor = NULL;
268         uih_newimage(c);
269         if (wascycling)
270             uih_cycling_on(c);
271     }
272 #endif
273 }
274 
uih_fixedcolorenable(uih_context *)275 static int uih_fixedcolorenable(uih_context * /*c*/)
276 {
277 #ifdef SCONVERTORS
278     const struct filteraction *fa = NULL;
279     int wascycling = 0;
280     preallocpalette(c->palette);
281     switch (c->image->palette->type) {
282 #ifdef SFIXEDCOLOR
283         case FIXEDCOLOR:
284             fa = &fixedcolor_filter;
285             break;
286 #endif
287 #ifdef SBITMAPS
288         case LBITMAP:
289         case MBITMAP:
290         case LIBITMAP:
291         case MIBITMAP:
292             fa = &bitmap_filter;
293             break;
294 #endif
295         default:
296             x_fatalerror("Unsupported image type. Recompile XaoS");
297     }
298     if (c->fixedcolor != NULL && c->fixedcolor->action != fa)
299         uih_fixedcolordisable(c);
300     if (c->fixedcolor == NULL) {
301         if (c->cycling)
302             uih_cycling_off(c), wascycling = 1;
303         c->fixedcolor = fa->getinstance(fa);
304         if (c->fixedcolor == NULL)
305             goto end;
306         uih_newimage(c);
307         addfilter(c->fixedcolor, c->uifilter->previous);
308         if (!initqueue(c->queue))
309             goto end2;
310         if (wascycling)
311             uih_cycling_on(c);
312         return 1;
313     }
314     return 0;
315 end2:
316     removefilter(c->fixedcolor);
317     c->fixedcolor->action->destroyinstance(c->fixedcolor);
318     c->fixedcolor = NULL;
319     initqueue(c->queue);
320 end:
321     if (wascycling)
322         uih_cycling_on(c);
323     return 0;
324 #else
325     x_fatalerror("Fixed color not supported, please recompile XaoS");
326     return 0;
327 #endif
328 }
329 
uih_fastrotate(uih_context * c,int mode)330 int uih_fastrotate(uih_context *c, int mode)
331 {
332     if (mode)
333         return (uih_fastrotateenable(c));
334     uih_fastrotatedisable(c);
335     return 1;
336 }
337 
uih_angle(uih_context * c,number_t angle)338 void uih_angle(uih_context *c, number_t angle)
339 {
340     if (angle != c->fcontext->angle) {
341         if (!c->fastrotate) {
342             c->fcontext->version++;
343             uih_newimage(c);
344         }
345         c->fcontext->angle = angle;
346         uih_animate_image(c);
347     }
348 }
349 
uih_rotatemode(uih_context * c,int mode)350 void uih_rotatemode(uih_context *c, int mode)
351 {
352     const char *names[] = {"norotate", "mouserotate", "controtate"};
353     if (c->fastrotate) {
354         if (c->rotatemode != mode) {
355             c->rotatemode = mode;
356             if (mode == ROTATE_CONTINUOUS)
357                 tl_reset_timer(c->doittimer);
358             uih_updatemenus(c, names[mode]);
359         }
360     }
361 }
362 
uih_enablejulia(uih_context * c)363 int uih_enablejulia(uih_context *c)
364 {
365     int wascycling = 0;
366     if (!c->juliamode && c->fcontext->mandelbrot
367         /*&&c->fcontext->currentformula->calculate_julia != NULL */) {
368         struct filter *addf = c->zengine;
369         uih_newimage(c);
370         if (c->fastrotate)
371             uih_fastrotatedisable(c);
372         if (c->cycling)
373             uih_cycling_off(c), wascycling = 1;
374         if (c->fcontext->currentformula->calculate_julia == NULL ||
375             c->fcontext->slowmode)
376             c->julia = zoom_filter.getinstance(&zoom_filter);
377         else
378             c->julia = julia_filter.getinstance(&julia_filter);
379         if (c->julia == NULL)
380             goto end;
381 
382         c->subwindow = subwindow_filter.getinstance(&subwindow_filter);
383         if (c->subwindow == NULL)
384             goto end2;
385         if (c->fcontext->currentformula->calculate_julia != NULL &&
386             !c->fcontext->slowmode) {
387             c->smalliter = smalliter_filter.getinstance(&smalliter_filter);
388             if (c->smalliter == NULL)
389                 goto end3;
390         } else
391             c->smalliter = NULL;
392         addfilter(c->subwindow, addf);
393         if (c->fcontext->currentformula->calculate_julia != NULL &&
394             !c->fcontext->slowmode) {
395             addfilter(c->smalliter, addf);
396         }
397         addfilter(c->julia, addf);
398         subwindow_setsecond(c->subwindow, addf);
399         if (!initqueue(c->queue))
400             goto end4;
401         if (c->fcontext->currentformula->calculate_julia == NULL ||
402             c->fcontext->slowmode)
403             c->juliamode = 2;
404         else
405             c->juliamode = 1;
406         uih_updatemenus(c, "fastjulia");
407         return 1;
408     }
409     uih_updatemenus(c, "fastjulia");
410     return 0;
411 end4:;
412     removefilter(c->subwindow);
413     removefilter(c->julia);
414     if (c->smalliter != NULL)
415         removefilter(c->smalliter);
416     initqueue(c->queue);
417 end3:;
418     c->smalliter->action->destroyinstance(c->smalliter);
419 end2:;
420     c->subwindow->action->destroyinstance(c->subwindow);
421 end:;
422     c->julia->action->destroyinstance(c->julia);
423     if (wascycling)
424         uih_cycling_on(c);
425     uih_updatemenus(c, "fastjulia");
426     return 0;
427 }
428 
uih_disablejulia(uih_context * c)429 void uih_disablejulia(uih_context *c)
430 {
431     int wascycling = 0;
432     if (c->juliamode) {
433         uih_newimage(c);
434         c->fcontext->version++;
435         if (c->cycling)
436             uih_cycling_off(c), wascycling = 1;
437         removefilter(c->subwindow);
438         removefilter(c->julia);
439         if (c->smalliter != NULL)
440             removefilter(c->smalliter);
441         initqueue(c->queue);
442         if (c->smalliter != NULL)
443             c->smalliter->action->destroyinstance(c->smalliter);
444         c->subwindow->action->destroyinstance(c->subwindow);
445         c->julia->action->destroyinstance(c->julia);
446         if (wascycling)
447             uih_cycling_on(c);
448         c->juliamode = 0;
449         uih_updatemenus(c, "fastjulia");
450     }
451 }
452 
uih_setjuliamode(uih_context * c,int mode)453 int uih_setjuliamode(uih_context *c, int mode)
454 {
455     if (mode)
456         return uih_enablejulia(c);
457     uih_disablejulia(c);
458     return 1;
459 }
460 
uih_rotationspeed(uih_context * c,number_t speed)461 void uih_rotationspeed(uih_context *c, number_t speed)
462 {
463     c->rotationspeed = speed;
464 }
465 
uih_cyclinghandler(void * userdata,int n)466 static void uih_cyclinghandler(void *userdata, int n)
467 {
468     struct uih_context *uih = (struct uih_context *)userdata;
469     int direct;
470     if (uih->zengine->fractalc->palette != NULL &&
471         uih->zengine->fractalc->palette->cyclecolors == NULL)
472         return;
473     direct = uih->direction * uih->cyclingdirection * n;
474     if (direct > 0)
475         direct %= uih->zengine->fractalc->palette->size - 1;
476     else
477         direct = -((-direct) % (uih->zengine->fractalc->palette->size - 1));
478     if (direct) {
479         uih->paletteshift += direct;
480         while (uih->paletteshift < 0)
481             uih->paletteshift += uih->zengine->fractalc->palette->size - 1;
482         uih->paletteshift =
483             uih->paletteshift % (uih->zengine->fractalc->palette->size - 1);
484         uih->zengine->fractalc->palette->cyclecolors(
485             uih->zengine->fractalc->palette, direct);
486         if (uih->flags & UPDATE_AFTER_PALETTE &&
487             (!uih->play || !uih->nonfractalscreen))
488             uih->display = 1;
489         uih_palettechg(uih);
490     }
491 }
492 
uih_cycling_off(struct uih_context * c)493 void uih_cycling_off(struct uih_context *c)
494 {
495     if (c->cycling) {
496         tl_free_timer(c->cyclingtimer);
497         c->cycling = 0;
498         uih_updatemenus(c, "cycling");
499         uih_updatemenus(c, "rcycling");
500     }
501 }
502 
uih_display(struct uih_context * c)503 void uih_display(struct uih_context *c)
504 {
505     c->display = 1;
506     c->nonfractalscreen = 0;
507     if (c->clearscreen)
508         c->clearscreen = 0;
509     c->displaytext = 0;
510     c->nletters = 0;
511     c->display = 1;
512     if (c->text[0] != NULL)
513         free(c->text[0]), c->text[0] = NULL;
514     if (c->text[1] != NULL)
515         free(c->text[1]), c->text[1] = NULL;
516     if (c->text[2] != NULL)
517         free(c->text[2]), c->text[2] = NULL;
518     if (c->play)
519         uih_clear_lines(c);
520 }
521 
uih_cycling_stop(struct uih_context * c)522 void uih_cycling_stop(struct uih_context *c)
523 {
524     if (c->cycling && !c->stopped) {
525         tl_remove_timer(c->cyclingtimer);
526         c->stopped = 1;
527     }
528 }
529 
uih_cycling_continue(struct uih_context * c)530 void uih_cycling_continue(struct uih_context *c)
531 {
532     if (c->cycling && c->stopped) {
533         c->stopped = 0;
534         tl_add_timer(syncgroup, c->cyclingtimer);
535     }
536 }
537 
uih_loadfile(struct uih_context * c,xio_constpath d)538 void uih_loadfile(struct uih_context *c, xio_constpath d)
539 {
540     int los = strlen(d);
541     char ext[4];
542     if(los < 3)
543         return;
544     memcpy(ext, &d[los-3], 3);
545     if(strcmp(ext, "png") == 0) {
546         uih_loadpngfile(c, d);
547         return;
548     }
549 
550     xio_file f;
551     f = xio_ropen(d);
552     if (f == NULL) {
553         uih_error(c, strerror(errno));
554         return;
555     }
556     uih_load(c, f, d);
557     return;
558 }
559 
uih_loadstr(struct uih_context * c,const char * data)560 void uih_loadstr(struct uih_context *c, const char *data)
561 {
562     xio_file f;
563     f = xio_strropen(data);
564     uih_load(c, f, "");
565     return;
566 }
567 
uih_playstr(struct uih_context * c,const char * data)568 void uih_playstr(struct uih_context *c, const char *data)
569 {
570     xio_file f;
571     f = xio_strropen(mystrdup(data));
572     uih_replayenable(c, f, "", 1);
573     return;
574 }
575 
uih_recalculate(struct uih_context * c)576 void uih_recalculate(struct uih_context *c)
577 {
578     c->fcontext->version++;
579     uih_newimage(c);
580 }
581 
uih_playfile(struct uih_context * c,xio_constpath d)582 void uih_playfile(struct uih_context *c, xio_constpath d)
583 {
584     xio_file f;
585     if (c->play)
586         uih_replaydisable(c);
587     f = xio_ropen(d);
588     if (f == NULL) {
589         uih_error(c, strerror(errno));
590         return;
591     }
592     uih_replayenable(c, f, d, 1);
593     return;
594 }
595 
uih_playtutorial(struct uih_context * c,const char * name)596 void uih_playtutorial(struct uih_context *c, const char *name)
597 {
598     xio_pathdata tmp;
599     xio_file f = XIO_FAILED;
600 
601     f = xio_gettutorial(name, tmp);
602     if (f == NULL) {
603         uih_error(c, TR("Error", "Tutorial files not found. Reinstall XaoS"));
604         return;
605     }
606     uih_replayenable(c, f, tmp, 1);
607     if (c->passfunc != NULL) {
608         c->passfunc(c, 1, TR("Message", "Preparing first image"), 0);
609     }
610 }
611 
uih_loadexample(struct uih_context * c)612 void uih_loadexample(struct uih_context *c)
613 {
614     xio_pathdata name;
615     xio_file f = xio_getrandomexample(name);
616     c->errstring = NULL;
617     if (f == NULL) {
618         uih_error(c, TR("Error", "Could not open examples"));
619         return;
620     }
621     uih_load(c, f, name);
622     if (c->errstring == NULL) {
623         char s[256];
624 #ifdef HAVE_LIBGEN_H
625         sprintf(s, TR("Message", "File %s loaded."), basename(name));
626 #else
627         sprintf(s, TR("Message", "File %s loaded."), name);
628 #endif
629         uih_message(c, s);
630     }
631 }
632 
uih_loadpngfile(struct uih_context * c,xio_constpath d)633 void uih_loadpngfile(struct uih_context *c, xio_constpath d)
634 {
635     xio_file f;
636     f = xio_ropen(d);
637     if (f == NULL) {
638         uih_error(c, strerror(errno));
639         return;
640     }
641     const char* xpf_chunk = readpng(d);
642     if(xpf_chunk == NULL) {
643         uih_error(c, TR("Error", "Could not open image"));
644         return;
645     }
646     xio_file xpf_data = xio_strropen(xpf_chunk);
647     uih_load(c, xpf_data, d);
648     if(c->errstring == NULL) {
649         char s[256];
650         sprintf(s, TR("Message", "File %s loaded."), d);
651         uih_message(c, s);
652     }
653     return;
654 }
655 
uih_savepngfile(struct uih_context * c,xio_constpath d)656 void uih_savepngfile(struct uih_context *c, xio_constpath d)
657 {
658     const char *s;
659     if (c->passfunc != NULL) {
660         c->passfunc(c, 1, TR("Message", "Saving image..."), 0);
661     }
662     if (c->recalculatemode) {
663         uih_newimage(c);
664         uih_clearwindows(c);
665         uih_do_fractal(c);
666     }
667     if (c->interrupt) {
668         uih_message(c, TR("Message", "Save interrupted"));
669         return;
670     }
671     c->errstring = NULL;
672     xio_file xpf_data = xio_strwopen();
673     uih_save_position(c, xpf_data, UIH_SAVEPOS);
674     s = uih_save(c, d, xpf_data);
675     if (s != NULL)
676         uih_error(c, s);
677     if (c->errstring == NULL) {
678         char s[256];
679         sprintf(s, TR("Message", "File %s saved."), d);
680         uih_message(c, s);
681     }
682 }
683 
uih_saveposfile(struct uih_context * c,xio_constpath d)684 void uih_saveposfile(struct uih_context *c, xio_constpath d)
685 {
686     xio_file f;
687     c->errstring = NULL;
688     f = xio_wopen(d);
689     if (f == XIO_FAILED) {
690         uih_error(c, TR("Message", "Can not open file"));
691         return;
692     }
693     uih_save_position(c, f, UIH_SAVEPOS);
694     if (c->errstring == NULL) {
695         char s[256];
696         sprintf(s, TR("Message", "File %s saved."), d);
697         uih_message(c, s);
698     }
699 }
700 
uih_savepostostr(struct uih_context * c)701 char *uih_savepostostr(struct uih_context *c)
702 {
703     xio_file f;
704     c->errstring = NULL;
705     f = xio_strwopen();
706     uih_save_position(c, f, UIH_SAVEPOS);
707     return (xio_getstring(f));
708 }
709 
uih_saveundo(struct uih_context * c)710 void uih_saveundo(struct uih_context *c)
711 {
712     xio_file f;
713     if (c->play)
714         return;
715     c->errstring = NULL;
716     if (c->undo.undos[c->undo.last])
717         free(c->undo.undos[c->undo.last]);
718     f = xio_strwopen();
719     uih_save_position(c, f, UIH_SAVEPOS);
720     c->undo.undos[c->undo.last] = xio_getstring(f);
721     c->undo.last = (c->undo.last + 1) % UNDOLEVEL;
722 }
723 
uih_undo(struct uih_context * c)724 void uih_undo(struct uih_context *c)
725 {
726     xio_file f;
727     int pos = c->undo.last - 2;
728     if (pos < 0)
729         pos = UNDOLEVEL + pos;
730     if (c->undo.undos[pos]) {
731         f = xio_strropen(c->undo.undos[pos]);
732         c->undo.undos[pos] = NULL;
733         c->undo.last = pos;
734         uih_load(c, f, "");
735     }
736 }
737 
uih_redo(struct uih_context * c)738 void uih_redo(struct uih_context *c)
739 {
740     xio_file f;
741     int pos = c->undo.last;
742     if (c->undo.undos[pos]) {
743         f = xio_strropen(c->undo.undos[pos]);
744         c->undo.undos[pos] = NULL;
745         c->undo.last = pos;
746         uih_load(c, f, "");
747     }
748 }
749 
750 extern xio_pathdata configfile;
uih_savecfg(struct uih_context * c)751 void uih_savecfg(struct uih_context *c)
752 {
753     xio_file f;
754     c->errstring = NULL;
755     f = xio_wopen(configfile);
756     if (f == XIO_FAILED) {
757         uih_message(c, (char *)xio_errorstring());
758         return;
759     }
760     uih_save_position(c, f, UIH_SAVEALL);
761     if (c->errstring == NULL) {
762         char s[256];
763         sprintf(s, TR("Message", "File %s saved."), configfile);
764         uih_message(c, s);
765     }
766 }
767 
uih_saveanimfile(struct uih_context * c,xio_constpath d)768 void uih_saveanimfile(struct uih_context *c, xio_constpath d)
769 {
770     xio_file f;
771     c->errstring = NULL;
772     if (c->save) {
773         uih_save_disable(c);
774         uih_updatemenus(c, "record");
775         return;
776     }
777     f = xio_wopen(d);
778     if (f == XIO_FAILED) {
779         uih_message(c, (char *)xio_errorstring());
780         return;
781     }
782     uih_save_enable(c, f, UIH_SAVEANIMATION);
783     if (c->errstring == NULL) {
784         char s[256];
785         sprintf(s, TR("Message", "Recording to file %s enabled."), d);
786         uih_message(c, s);
787     }
788     uih_updatemenus(c, "record");
789 }
790 
uih_save(struct uih_context * c,xio_constpath filename,xio_file xpf_data)791 const char *uih_save(struct uih_context *c, xio_constpath filename, xio_file xpf_data)
792 {
793     const char *r;
794     uih_cycling_stop(c);
795     uih_stoptimers(c);
796     uih_clearwindows(c);
797     r = writepng(filename, c->queue->saveimage, xpf_data);
798     uih_cycling_continue(c);
799     uih_resumetimers(c);
800     return (r);
801 }
802 
uih_setcycling(struct uih_context * c,int speed)803 void uih_setcycling(struct uih_context *c, int speed)
804 {
805     c->cyclingspeed = speed;
806     if (c->cyclingspeed < 0)
807         c->direction = -1;
808     else
809         c->direction = 1;
810     if (c->cycling) {
811         if (c->cyclingspeed)
812             tl_set_interval(c->cyclingtimer,
813                             1000000 / c->cyclingspeed * c->direction);
814         else
815             tl_set_interval(c->cyclingtimer, 1000000 * 100);
816     }
817 }
818 
uih_cycling_on(struct uih_context * c)819 int uih_cycling_on(struct uih_context *c)
820 {
821     if (c->zengine->fractalc->palette != NULL &&
822         c->zengine->fractalc->palette->cyclecolors != NULL) {
823         c->cycling = 1;
824         tl_update_time();
825         c->cyclingtimer = tl_create_timer();
826         uih_emulatetimers(c);
827         uih_setcycling(c, c->cyclingspeed);
828         tl_set_multihandler(c->cyclingtimer, uih_cyclinghandler, c);
829         tl_add_timer(syncgroup, c->cyclingtimer);
830     } else {
831         uih_updatemenus(c, "cycling");
832         uih_updatemenus(c, "rcycling");
833         return 0;
834     }
835     uih_updatemenus(c, "cycling");
836     uih_updatemenus(c, "rcycling");
837     return 1;
838 }
839 
uih_cycling(struct uih_context * uih,int mode)840 int uih_cycling(struct uih_context *uih, int mode)
841 {
842     if (mode)
843         return (uih_cycling_on(uih));
844     uih_cycling_off(uih);
845     return 1;
846 }
847 
uih_waitfunc(struct filter * f)848 static void uih_waitfunc(struct filter *f)
849 {
850     int l;
851     tl_process_group(syncgroup, NULL);
852     l = tl_lookup_timer(uih->calculatetimer);
853     if (uih->interrupt)
854         f->interrupt = 1, uih->endtime = l;
855     if (uih->interruptiblemode) {
856         if (f->incalculation && !uih->starttime)
857             uih->starttime = l;
858         else if (uih->starttime && !f->incalculation && !uih->endtime)
859             uih->endtime = l;
860         if ((uih->maxtime && l > uih->maxtime && f->readyforinterrupt) ||
861             uih->interrupt)
862             f->interrupt = 1, uih->endtime = l;
863     }
864     if ((l) > (waitcount + 1) * WAITTIME) {
865         int display = 0;
866         if (!uih->interruptiblemode && l > (waitcount1 + 1) * WAITTIME1) {
867             display = 1;
868             waitcount1 = l / WAITTIME1;
869         }
870         if (f->image == uih->image && !uih->interruptiblemode &&
871             l > (waitcount2 + 1) * WAITTIME2) {
872             if (!uih->play)
873                 uih->display = 1, uih_finishpalette(uih), display = 1;
874             waitcount2 = l / WAITTIME2;
875         }
876         if (uih->passfunc != NULL) {
877             f->interrupt |= uih->passfunc(
878                 uih, display, f->pass,
879                 (float)(f->max ? f->pos * 100.0 / f->max : 100.0));
880             uih->display = 0;
881         }
882         waitcount = l / WAITTIME;
883     }
884     uih_clearwindows(uih);
885 }
886 
uih_do_fractal(uih_context * c)887 void uih_do_fractal(uih_context *c)
888 {
889     int flags;
890     int time;
891 
892     c->interrupt = 0;
893     c->display = 0;
894     uih = c;
895     if (c->juliamode && !c->fcontext->mandelbrot) {
896         uih_disablejulia(c);
897     }
898     if ((c->juliamode == 1 &&
899          (c->fcontext->currentformula->calculate_julia == NULL ||
900           c->fcontext->slowmode)) ||
901         (c->juliamode == 2 &&
902          c->fcontext->currentformula->calculate_julia != NULL &&
903          !c->fcontext->slowmode)) {
904         uih_disablejulia(c);
905         uih_enablejulia(c);
906         c->fcontext->version++;
907     }
908 
909     tl_update_time();
910     if (c->recalculatemode < c->fastmode && c->emulator == NULL &&
911         !c->fixedstep)
912         c->interruptiblemode = 1;
913     else
914         c->interruptiblemode = 0;
915     if (!c->interruptiblemode && c->recalculatemode > UIH_ANIMATION) {
916         if (c->longwait != NULL)
917             c->longwait(c);
918         uih_stoptimers(c);
919     }
920 
921     tl_update_time();
922     tl_reset_timer(c->calculatetimer);
923     c->starttime = 0;
924     c->endtime = 0;
925     waitcount = tl_lookup_timer(c->calculatetimer) / WAITTIME + 2;
926     waitcount1 = tl_lookup_timer(c->calculatetimer) / WAITTIME1 + 1;
927     waitcount2 = tl_lookup_timer(c->calculatetimer) / WAITTIME2 + 1;
928     c->incalculation = 1;
929 
930     if (!(c->flags & ROTATE_INSIDE_CALCULATION))
931         uih_cycling_stop(c);
932 
933     time = tl_lookup_timer(c->doittimer);
934     if (c->rotatemode == ROTATE_CONTINUOUS) {
935         c->fcontext->angle += c->rotationspeed * time / 1000000.0;
936     }
937 
938     tl_reset_timer(c->doittimer);
939     c->indofractal = 1;
940     if (c->recalculatemode < UIH_PALETTEDRAW) {
941         if (c->queue->palettechg != NULL)
942             flags = c->queue->palettechg->action->doit(c->queue->palettechg,
943                                                        PALETTEONLY, 0);
944         else
945             flags = CHANGED;
946     } else
947         flags = c->uifilter->previous->action->doit(
948             c->uifilter->previous, c->interruptiblemode ? INTERRUPTIBLE : 0,
949             time);
950     c->indofractal = 0;
951 
952     if (!(c->flags & ROTATE_INSIDE_CALCULATION))
953         uih_cycling_continue(c);
954 
955     c->dirty = 0;
956     if (c->inanimation)
957         c->inanimation--;
958     c->ddatalost = 0;
959     c->recalculatemode = 0;
960 
961     if (flags & ANIMATION)
962         c->fastanimation = 1;
963     else
964         c->fastanimation = 0;
965     if (c->emulator)
966         c->inanimation = 1;
967     if (flags & (ANIMATION | INCOMPLETE) ||
968         (c->rotatemode == ROTATE_CONTINUOUS)) {
969         tl_resume_timer(c->doittimer);
970         c->incomplete = 1;
971         c->inanimation = 2;
972         if (flags & INCOMPLETE)
973             c->recalculatemode = UIH_ANIMATION;
974         else
975             c->recalculatemode = UIH_FILTERANIMATION;
976         c->display = 1;
977     } else {
978         tl_stop_timer(c->doittimer);
979         c->incomplete = 0;
980     }
981     if ((flags & CHANGED) && (!c->play || !c->nonfractalscreen)) {
982         c->display = 1;
983         if (flags & INEXACT)
984             c->dirty = 1;
985     } else
986         c->incalculation = 0;
987     uih_callcomplette(c);
988     if (c->autopilot)
989         c->inanimation = 1;
990 }
991 
uih_prepare_image(uih_context * c)992 void uih_prepare_image(uih_context *c)
993 {
994     if (c->play)
995         uih_update_lines(c);
996     if (c->display) {
997         uih_clearwindows(c);
998         xprepareimage(c->image);
999         if (uih_needrecalculate(c))
1000             uih_do_fractal(c);
1001     }
1002 }
1003 
uih_callcomplette(uih_context * c)1004 void uih_callcomplette(uih_context *c)
1005 {
1006     if (!c->incomplete && !c->display && !c->recalculatemode &&
1007         !c->inanimation && c->complettehandler != NULL) {
1008         c->complettehandler(c->handlerdata);
1009     }
1010 }
1011 
uih_setcomplettehandler(uih_context * c,void (h)(void *),void * d)1012 void uih_setcomplettehandler(uih_context *c, void(h)(void *), void *d)
1013 {
1014     c->complettehandler = h;
1015     c->handlerdata = d;
1016 }
1017 
uih_letterspersec(uih_context * c,int n)1018 void uih_letterspersec(uih_context *c, int n)
1019 {
1020     if (n < 1)
1021         n = 1;
1022     c->letterspersec = n;
1023 }
1024 
uih_displayed(uih_context * c)1025 double uih_displayed(uih_context *c)
1026 {
1027     int drawingtime;
1028     uih_finishpalette(c);
1029     if (c->indofractal)
1030         return 0; /*image is currently calculating */
1031     if (c->recalculatemode)
1032         c->display = 1;
1033     else
1034         c->display = 0;
1035     tl_update_time();
1036     uih_resumetimers(c);
1037     c->nonfractalscreen = 0;
1038     c->nletters = 0;
1039     if (c->incalculation) {
1040         c->incalculation = 0;
1041         drawingtime = tl_lookup_timer(c->calculatetimer);
1042         if (c->emulator)
1043             drawingtime = 0;
1044         if (c->lasttime == -1 || (drawingtime && c->lasttime &&
1045                                   (drawingtime / c->lasttime < 0.2 ||
1046                                    drawingtime / c->lasttime > 4)))
1047             c->lasttime = drawingtime;
1048         c->lasttime = (c->lasttime * 30 + drawingtime) / 31;
1049         c->lastspeed = c->lasttime ? 1000000.0 / c->lasttime : 100.0;
1050         if (c->interruptiblemode) {
1051             int i;
1052             int time1, time;
1053             time1 = drawingtime;
1054             time1 -= c->endtime;
1055             time = (drawingtime - c->endtime) + c->starttime;
1056             if (c->times[0][0] == -1) {
1057                 for (i = 0; i < AVRGSIZE; i++)
1058                     c->times[0][i] = time, c->times[1][i] = time1;
1059                 c->count[0] = time * AVRGSIZE, c->count[1] = time1 * AVRGSIZE;
1060             }
1061             c->timespos = (c->timespos + 1) % AVRGSIZE;
1062             c->count[0] += time - c->times[0][c->timespos];
1063             c->count[1] += time1 - c->times[1][c->timespos];
1064             c->times[0][c->timespos] = time;
1065             c->times[1][c->timespos] = time1;
1066             c->maxtime = (c->count[0] * 5) / AVRGSIZE;
1067             if (c->step || c->pressed ||
1068                 (c->play &&
1069                  (c->playc->morph || c->playc->morphangle ||
1070                   c->playc->morphjulia || c->playc->lines.morphing)) ||
1071                 (c->rotatemode == ROTATE_CONTINUOUS) || c->fastanimation) {
1072                 if (c->maxtime > 1000000 / 25)
1073                     c->maxtime = c->count[0] * 3 / AVRGSIZE;
1074                 if (c->maxtime > 1000000 / 15)
1075                     c->maxtime = 1000000 / 15;
1076             } else {
1077                 c->maxtime = 1000000 / 3;
1078             }
1079             if (c->maxtime < 1000000 / 30)
1080                 c->maxtime = 1000000 / 30;
1081             c->maxtime -= c->count[1] / AVRGSIZE;
1082             if (c->maxtime < c->starttime + 10000)
1083                 c->maxtime = c->starttime + 10000;
1084         }
1085     }
1086     uih_callcomplette(c);
1087     return (c->lastspeed);
1088 }
1089 
uih_text(uih_context * c,const char * text)1090 void uih_text(uih_context *c, const char *text)
1091 {
1092     int i, l;
1093     c->display = 1;
1094     if (c->text[c->ytextpos])
1095         free(c->text[c->ytextpos]);
1096     c->textpos[c->ytextpos] = c->xtextpos;
1097     c->textcolor[c->ytextpos] = c->color;
1098     c->displaytext |= 1 << c->ytextpos;
1099     c->text[c->ytextpos] = mystrdup(text);
1100     l = (int)strlen(text);
1101     c->todisplayletters = 0;
1102     for (i = 0; i < l; i++) {
1103         if (!isspace(text[i]) && !ispunct(text[i]))
1104             c->todisplayletters++;
1105         if (text[i] == '-')
1106             c->todisplayletters += 3;
1107         if (text[i] == '.')
1108             c->todisplayletters += 2;
1109     }
1110     c->step = 0;
1111 }
1112 
uih_clearscreen(uih_context * c)1113 void uih_clearscreen(uih_context *c)
1114 {
1115     c->clearscreen = 1;
1116     if (c->save)
1117         c->savec->clearscreen = 1;
1118     if (c->displaytext)
1119         c->displaytext = 0;
1120     if (c->text[0] != NULL)
1121         free(c->text[0]), c->text[0] = NULL;
1122     if (c->text[1] != NULL)
1123         free(c->text[1]), c->text[1] = NULL;
1124     if (c->text[2] != NULL)
1125         free(c->text[2]), c->text[2] = NULL;
1126     c->nletters = 0;
1127     c->display = 1;
1128     if (c->play)
1129         uih_clear_lines(c);
1130 }
1131 
uih_settextpos(uih_context * c,int x,int y)1132 void uih_settextpos(uih_context *c, int x, int y)
1133 {
1134     const char *names1[] = {
1135         "ytextposup",
1136         "ytextposmiddle",
1137         "ytextposbottom",
1138     };
1139     const char *names2[] = {
1140         "xtextposleft",
1141         "xtextposcenter",
1142         "xtextposright",
1143     };
1144     c->xtextpos = x;
1145     c->ytextpos = y;
1146     uih_updatemenus(c, names1[y]);
1147     uih_updatemenus(c, names2[x]);
1148 }
1149 
1150 /*timing routines */
1151 
uih_tbreak(uih_context * c)1152 void uih_tbreak(uih_context *c) { c->tbreak = 1; }
1153 
uih_emulatetimers(uih_context * c)1154 void uih_emulatetimers(uih_context *c)
1155 {
1156     if (c->emulator == NULL)
1157         return;
1158     tl_emulate_timer(c->maintimer, c->emulator);
1159     tl_emulate_timer(c->doittimer, c->emulator);
1160     if (c->autopilot)
1161         tl_emulate_timer(c->autopilottimer, c->emulator);
1162     if (c->cycling) {
1163         tl_emulate_timer(c->cyclingtimer, c->emulator);
1164     }
1165     if (c->play) {
1166         tl_emulate_timer(c->playc->timer, c->emulator);
1167     }
1168     if (c->save) {
1169         tl_emulate_timer(c->savec->timer, c->emulator);
1170         tl_emulate_timer(c->savec->synctimer, c->emulator);
1171     }
1172 }
1173 
uih_unemulatetimers(uih_context * c)1174 static void uih_unemulatetimers(uih_context *c)
1175 {
1176     tl_unemulate_timer(c->maintimer);
1177     tl_unemulate_timer(c->doittimer);
1178     if (c->autopilot)
1179         tl_unemulate_timer(c->autopilottimer);
1180     if (c->cycling)
1181         tl_unemulate_timer(c->cyclingtimer);
1182     if (c->play) {
1183         tl_unemulate_timer(c->playc->timer);
1184     }
1185     if (c->save) {
1186         tl_unemulate_timer(c->savec->timer);
1187         tl_unemulate_timer(c->savec->synctimer);
1188     }
1189 }
1190 
uih_constantframetime(uih_context * c,int time)1191 void uih_constantframetime(uih_context *c, int time)
1192 {
1193     if (c->emulator == NULL)
1194         c->emulator = tl_create_emulator();
1195     c->emulatedframetime = time;
1196     uih_emulatetimers(c);
1197 }
1198 
uih_noconstantframetime(uih_context * c)1199 void uih_noconstantframetime(uih_context *c)
1200 {
1201     if (c->emulator == NULL)
1202         return;
1203     uih_unemulatetimers(c);
1204     tl_free_emulator(c->emulator);
1205     c->emulator = NULL;
1206 }
1207 
uih_stoptimers(uih_context * c)1208 void uih_stoptimers(uih_context *c)
1209 {
1210     if (!c->stoppedtimers) {
1211         c->stoppedtimers = 1;
1212         c->display = 1;
1213         tl_stop_timer(c->maintimer);
1214         tl_stop_timer(c->doittimer);
1215         if (c->autopilot)
1216             tl_stop_timer(c->autopilottimer);
1217         if (c->play) {
1218             tl_stop_timer(c->playc->timer);
1219             if (c->cycling)
1220                 tl_stop_timer(c->cyclingtimer);
1221         }
1222         if (c->save) {
1223             tl_stop_timer(c->savec->timer);
1224             tl_stop_timer(c->savec->synctimer);
1225             if (c->cycling)
1226                 tl_stop_timer(c->cyclingtimer);
1227         }
1228     }
1229 }
1230 
uih_slowdowntimers(uih_context * c,int time)1231 void uih_slowdowntimers(uih_context *c, int time)
1232 {
1233     tl_slowdown_timer(c->maintimer, time);
1234     if (c->autopilot)
1235         tl_slowdown_timer(c->autopilottimer, time);
1236     if (c->play) {
1237         tl_slowdown_timer(c->playc->timer, time);
1238         if (c->cycling)
1239             tl_slowdown_timer(c->cyclingtimer, time);
1240     }
1241     if (c->save) {
1242         tl_slowdown_timer(c->savec->timer, time);
1243         tl_slowdown_timer(c->savec->synctimer, time);
1244         if (c->cycling)
1245             tl_slowdown_timer(c->cyclingtimer, time);
1246     }
1247 }
1248 
uih_resumetimers(uih_context * c)1249 void uih_resumetimers(uih_context *c)
1250 {
1251     if (c->stoppedtimers) {
1252         c->stoppedtimers = 0;
1253         tl_resume_timer(c->maintimer);
1254         if (c->cycling)
1255             tl_resume_timer(c->cyclingtimer);
1256         if (c->autopilot)
1257             tl_resume_timer(c->autopilottimer);
1258         if (c->play) {
1259             tl_resume_timer(c->playc->timer);
1260         }
1261         if (c->save) {
1262             tl_resume_timer(c->savec->timer);
1263             tl_resume_timer(c->savec->synctimer);
1264         }
1265     }
1266 }
1267 
1268 /*autopilot implementation */
1269 
uih_changed(void)1270 static void uih_changed(void) { uih_newimage(uih); }
1271 
uih_autopilothandler(void * uih1,int n)1272 static void uih_autopilothandler(void *uih1, int n)
1273 {
1274     uih = (uih_context *)uih1;
1275     do_autopilot(uih, &uih->autopilotx, &uih->autopiloty,
1276                  &uih->autopilotbuttons, uih_changed, n);
1277 }
1278 
uih_zoom(uih_context * uih)1279 static inline void uih_zoom(uih_context *uih)
1280 {
1281     uih->step += uih->speedup * 2 * uih->mul;
1282     if (uih->step > uih->maxstep)
1283         uih->step = uih->maxstep;
1284     else if (uih->step < -uih->maxstep)
1285         uih->step = -uih->maxstep;
1286 }
1287 
uih_unzoom(uih_context * uih)1288 static inline void uih_unzoom(uih_context *uih)
1289 {
1290     uih->step -= uih->speedup * 2 * uih->mul;
1291     if (uih->step > uih->maxstep)
1292         uih->step = uih->maxstep;
1293     else if (uih->step < -uih->maxstep)
1294         uih->step = -uih->maxstep;
1295 }
1296 
uih_slowdown(uih_context * uih)1297 static inline void uih_slowdown(uih_context *uih)
1298 {
1299     if (uih->step > 0) {
1300         if (uih->step < uih->speedup * uih->mul)
1301             uih->step = 0;
1302         else
1303             uih->step -= uih->speedup * uih->mul;
1304     } else if (uih->step < 0) {
1305         if (uih->step > -uih->speedup * uih->mul)
1306             uih->step = 0;
1307         else
1308             uih->step += uih->speedup * uih->mul;
1309     }
1310 }
1311 
uih_zoomupdate(uih_context * uih)1312 static inline void uih_zoomupdate(uih_context *uih)
1313 {
1314     number_t x;
1315     number_t y;
1316     number_t mmul = pow((double)(1 - uih->step), (double)uih->mul);
1317     number_t mc = uih->fcontext->s.cr - uih->fcontext->s.rr / 2;
1318     number_t nc = uih->fcontext->s.cr + uih->fcontext->s.rr / 2;
1319     number_t mi = uih->fcontext->s.ci - uih->fcontext->s.ri / 2;
1320     number_t ni = uih->fcontext->s.ci + uih->fcontext->s.ri / 2;
1321     x = uih->xcenter, y = uih->ycenter;
1322     mc = x + (mc - x) * (mmul);
1323     nc = x + (nc - x) * (mmul);
1324     mi = y + (mi - y) * (mmul);
1325     ni = y + (ni - y) * (mmul);
1326     uih->fcontext->s.rr = nc - mc;
1327     uih->fcontext->s.ri = ni - mi;
1328     uih->fcontext->s.cr = (nc + mc) / 2;
1329     uih->fcontext->s.ci = (ni + mi) / 2;
1330     uih_animate_image(uih);
1331 }
1332 
1333 /*main uih loop */
1334 
uih_update(uih_context * c,int mousex,int mousey,int mousebuttons)1335 int uih_update(uih_context *c, int mousex, int mousey, int mousebuttons)
1336 {
1337     int inmovement = 0;
1338     int slowdown = 1;
1339     int time;
1340     uih = c;
1341 
1342     if (!mousebuttons && uih->lastbuttons)
1343         uih_saveundo(c);
1344     uih->lastbuttons = mousebuttons;
1345     if (c->incalculation)
1346         return 0;
1347     if (c->emulator != NULL)
1348         tl_elpased(c->emulator, c->emulatedframetime);
1349 
1350     if (mousebuttons == (BUTTON1 | BUTTON3))
1351         mousebuttons = BUTTON2;
1352     tl_process_group(syncgroup, NULL); /*First we need to update timing */
1353     tl_update_time();
1354     time = tl_lookup_timer(c->maintimer);
1355     if (c->autopilot) { /*now handle autopilot */
1356         tl_process_group(c->autopilotgroup, NULL);
1357     }
1358     if (!c->inanimation)
1359         time = 0;
1360     if (time > 2000000) {
1361         uih_slowdowntimers(uih, time - 2000000);
1362         time = 2000000;
1363     }
1364     if (c->inanimation)
1365         c->inanimation--;
1366     tl_reset_timer(c->maintimer);
1367     c->mul = (double)time / FRAMETIME;
1368     if (c->fixedstep)
1369         c->mul = 0.3;
1370     if (c->tbreak)
1371         c->mul = 1, c->tbreak--;
1372     if (c->mul == 0)
1373         c->mul = 0.00000001;
1374     if (c->play) {
1375         uih_playupdate(c);
1376         if (!c->play) {
1377             c->inanimation = 2;
1378             return 1;
1379         }
1380         if (c->playc->lines.morphing) /*inmovement=1, c->display=1; */
1381             uih_update_lines(c);
1382         if (c->step)
1383             uih_zoomupdate(c), inmovement = 1;
1384         switch (c->zoomactive) {
1385             case 1:
1386                 uih_zoom(c), inmovement = 1;
1387                 break;
1388             case -1:
1389                 uih_unzoom(c), inmovement = 1;
1390                 break;
1391             default:
1392                 uih_slowdown(c);
1393         }
1394         if (c->playc->morph) {
1395             int timer = tl_lookup_timer(c->playc->timer) - c->playc->starttime;
1396             number_t mmul = /*(tl_lookup_timer (c->playc->timer) -
1397                                c->playc->starttime) / (number_t)
1398                                (c->playc->frametime - c->playc->starttime); */
1399                 MORPHVALUE(timer, c->playc->frametime - c->playc->starttime,
1400                            c->playc->morphtimes[0], c->playc->morphtimes[1]);
1401             number_t srr, drr;
1402             number_t mmul1;
1403             if (c->playc->source.rr * c->fcontext->windowwidth >
1404                 c->playc->source.ri * c->fcontext->windowheight)
1405                 srr = c->playc->source.rr;
1406             else
1407                 srr = c->playc->source.ri;
1408             if (c->playc->destination.rr * c->fcontext->windowwidth >
1409                 c->playc->destination.ri * c->fcontext->windowheight)
1410                 drr = c->playc->destination.rr;
1411             else
1412                 drr = c->playc->destination.ri;
1413             if (srr == drr)
1414                 mmul1 = mmul;
1415             else
1416                 mmul1 = (exp(log(srr) + ((log(drr) - log(srr)) * mmul)) - srr) /
1417                         (drr - srr);
1418             if (mmul1 > 1)
1419                 mmul1 = 1;
1420             if (mmul1 < 0)
1421                 mmul1 = 0;
1422             inmovement = 1;
1423             c->fcontext->s.rr =
1424                 c->playc->source.rr +
1425                 (c->playc->destination.rr - c->playc->source.rr) * mmul1;
1426             c->fcontext->s.ri =
1427                 c->playc->source.ri +
1428                 (c->playc->destination.ri - c->playc->source.ri) * mmul1;
1429             c->fcontext->s.cr =
1430                 c->playc->source.cr +
1431                 (c->playc->destination.cr - c->playc->source.cr) * mmul1;
1432             c->fcontext->s.ci =
1433                 c->playc->source.ci +
1434                 (c->playc->destination.ci - c->playc->source.ci) * mmul1;
1435             uih_animate_image(c);
1436         }
1437         if (c->playc->morphjulia) {
1438             int timer = tl_lookup_timer(c->playc->timer) - c->playc->starttime;
1439             number_t mmul = /*(tl_lookup_timer (c->playc->timer) -
1440                                c->playc->starttime) / (number_t)
1441                                (c->playc->frametime - c->playc->starttime); */
1442                 MORPHVALUE(timer, c->playc->frametime - c->playc->starttime,
1443                            c->playc->morphjuliatimes[0],
1444                            c->playc->morphjuliatimes[1]);
1445             uih_setjuliaseed(
1446                 uih, c->playc->sr + (c->playc->dr - c->playc->sr) * mmul,
1447                 c->fcontext->pim =
1448                     c->playc->si + (c->playc->di - c->playc->si) * mmul);
1449             inmovement = 1;
1450         }
1451         if (c->playc->morphangle) {
1452             int timer = tl_lookup_timer(c->playc->timer) - c->playc->starttime;
1453             number_t mmul = /*(tl_lookup_timer (c->playc->timer) -
1454                                c->playc->starttime) / (number_t)
1455                                (c->playc->frametime - c->playc->starttime); */
1456                 MORPHVALUE(timer, c->playc->frametime - c->playc->starttime,
1457                            c->playc->morphangletimes[0],
1458                            c->playc->morphangletimes[1]);
1459             uih_angle(uih,
1460                       c->playc->srcangle +
1461                           (c->playc->destangle - c->playc->srcangle) * mmul);
1462             inmovement = 1;
1463         }
1464     } else {
1465         if (!c->juliamode) {
1466             if (c->autopilot) { /*now handle autopilot */
1467                 mousex = c->autopilotx;
1468                 mousey = c->autopiloty;
1469                 mousebuttons = c->autopilotbuttons;
1470                 inmovement = 1;
1471             }
1472             if (c->step) {
1473                 number_t x;
1474                 number_t y;
1475                 if (mousex != c->xcenterm || mousey != c->ycenterm) {
1476                     c->xcenterm = mousex;
1477                     c->ycenterm = mousey;
1478                     uih_getcoord(uih, mousex, mousey, &x, &y);
1479                     c->xcenter = x;
1480                     c->ycenter = y;
1481                 }
1482                 uih_zoomupdate(c), inmovement = 1;
1483             }
1484             c->zoomactive = 0;
1485             if (c->rotatemode != ROTATE_MOUSE)
1486                 switch (mousebuttons) { /*process buttons */
1487                     case BUTTON1:
1488                         c->zoomactive = 1;
1489                         inmovement = 1;
1490                         break;
1491                     case BUTTON3:
1492                         c->zoomactive = -1;
1493                         inmovement = 1;
1494                         break;
1495                 }
1496             uih_saveframe(c);
1497             if (c->rotatemode != ROTATE_MOUSE) {
1498                 c->rotatepressed = 0;
1499                 switch (mousebuttons) { /*process buttons */
1500                     case BUTTON1:
1501                         uih_zoom(c), slowdown = 0;
1502                         break;
1503                     case BUTTON3:
1504                         uih_unzoom(c), slowdown = 0;
1505                         break;
1506                     case BUTTON2: { /* handles panning */
1507                         number_t x, y;
1508                         uih_getcoord(uih, mousex, mousey, &x, &y);
1509                         if (c->pressed && (c->oldx != x || c->oldy != y)) {
1510                             c->fcontext->s.cr -= x - c->oldx;
1511                             c->fcontext->s.ci -= y - c->oldy;
1512                             uih_animate_image(c);
1513                             c->moved = 1;
1514                         }
1515                         c->speed = 0;
1516 
1517                         /* issue 115 - disable rotation to update panning */
1518                         if(c->pressed == 0) {
1519                             int old_mode = c->rotatemode;
1520                             uih_rotate(c, 0);
1521                             uih_getcoord(uih, mousex, mousey, &c->oldx, &c->oldy);
1522                             uih_rotate(c, old_mode);
1523                         }
1524                         c->pressed = 1;
1525                     } break;
1526                 }
1527             } else {
1528                 if (mousebuttons & BUTTON1) {
1529                     number_t x, y;
1530                     number_t angle;
1531 
1532                     x = (mousex - c->image->width / 2) * c->image->pixelwidth;
1533                     y = (mousey - c->image->height / 2) * c->image->pixelheight;
1534                     angle = -atan2(x, y) * 180 / M_PI;
1535                     if (c->rotatepressed) {
1536                         uih_angle(uih,
1537                                   c->fcontext->angle + angle - c->oldangle);
1538                     }
1539                     c->rotatepressed = 1;
1540                     c->oldangle = angle;
1541                 } else if (mousebuttons & BUTTON2) {
1542                     number_t x, y;
1543                     uih_getcoord(uih, mousex, mousey, &x, &y);
1544                     if (c->pressed && (c->oldx != x || c->oldy != y)) {
1545                         c->fcontext->s.cr -= x - c->oldx;
1546                         c->fcontext->s.ci -= y - c->oldy;
1547                         uih_animate_image(c);
1548                         c->moved = 1;
1549                     }
1550                     c->speed = 0;
1551 
1552                     /* issue 115 - disable rotation to update panning */
1553                     if(c->pressed == 0) {
1554                         int old_mode = c->rotatemode;
1555                         uih_rotate(c, 0);
1556                         uih_getcoord(uih, mousex, mousey, &c->oldx, &c->oldy);
1557                         uih_rotate(c, old_mode);
1558                     }
1559                     c->pressed = 1;
1560                 } else
1561                     c->rotatepressed = 0;
1562             }
1563             if (!(mousebuttons & BUTTON2))
1564                 c->pressed = 0;
1565             if (slowdown)
1566                 uih_slowdown(c);
1567         } else {
1568             if (mousebuttons & BUTTON1) {
1569                 number_t x, x1 = c->fcontext->pre;
1570                 number_t y, y1 = c->fcontext->pim;
1571                 c->zoomactive = 0;
1572                 uih_getcoord(uih, mousex, mousey, &x, &y);
1573                 c->fcontext->pre = x;
1574                 c->fcontext->pim = y;
1575                 uih_saveframe(c);
1576                 c->pressed = 1;
1577                 recalculate(c->fcontext->plane, &c->fcontext->pre,
1578                             &c->fcontext->pim);
1579                 if (c->fcontext->pre != x1 || c->fcontext->pim != y1) {
1580                     uih_animate_image(c);
1581                 }
1582             } else
1583                 c->pressed = 0;
1584         }
1585     }
1586     if (!inmovement)
1587         uih_tbreak(c);
1588     if (c->incomplete)
1589         inmovement = 1;
1590     if (!c->recalculatemode && !c->display)
1591         uih_finishpalette(c);
1592     if (!inmovement)
1593         uih_callcomplette(c);
1594     if (c->inanimation < inmovement * 2)
1595         c->inanimation = inmovement * 2;
1596     return (inmovement * 2);
1597 }
1598 
1599 /*actions that can be used be user interface */
1600 
uih_autopilot_on(uih_context * c)1601 void uih_autopilot_on(uih_context *c)
1602 {
1603     if (!c->autopilot) {
1604         clean_autopilot(c);
1605         uih_autopilothandler(c, 1);
1606         tl_update_time();
1607         uih_resumetimers(c);
1608         c->autopilottimer = tl_create_timer();
1609         c->autopilotgroup = tl_create_group();
1610         tl_set_multihandler(c->autopilottimer, uih_autopilothandler, c);
1611         tl_set_interval(c->autopilottimer, 1000000 / 25);
1612         tl_reset_timer(c->autopilottimer);
1613         tl_add_timer(c->autopilotgroup, c->autopilottimer);
1614         tl_update_time();
1615         c->autopilot = 1;
1616         uih_emulatetimers(c);
1617         uih_updatemenus(c, "autopilot");
1618     }
1619 }
1620 
uih_autopilot_off(uih_context * c)1621 void uih_autopilot_off(uih_context *c)
1622 {
1623     if (c->autopilot) {
1624         tl_remove_timer(c->autopilottimer);
1625         tl_free_timer(c->autopilottimer);
1626         tl_free_group(c->autopilotgroup);
1627         c->autopilot = 0;
1628         uih_updatemenus(c, "autopilot");
1629     }
1630 }
1631 
uih_mkdefaultpalette(uih_context * c)1632 void uih_mkdefaultpalette(uih_context *c)
1633 {
1634     if (c->zengine->fractalc->palette == NULL)
1635         return;
1636     uih_cycling_stop(c);
1637     if (mkdefaultpalette(c->zengine->fractalc->palette) != 0) {
1638         uih_newimage(c);
1639     }
1640     uih_palettechg(c);
1641     c->paletteshift = 0;
1642     c->manualpaletteshift = 0;
1643     c->palettechanged = 1;
1644     c->palettetype = 0;
1645     uih_finishpalette(c);
1646     uih_cycling_continue(c);
1647 }
1648 
uih_mkpalette(uih_context * c)1649 void uih_mkpalette(uih_context *c)
1650 {
1651     int seed;
1652     int alg = rand() % PALGORITHMS;
1653     if (c->zengine->fractalc->palette == NULL)
1654         return;
1655     uih_cycling_stop(c);
1656     if (mkpalette(c->zengine->fractalc->palette, seed = rand(), alg) != 0) {
1657         uih_newimage(c);
1658     }
1659     uih_palettechg(c);
1660     c->paletteshift = 0;
1661     c->manualpaletteshift = 0;
1662     c->paletteseed = seed;
1663     uih_finishpalette(c);
1664     c->palettechanged = 1;
1665     c->palettetype = alg + 1;
1666     uih_cycling_continue(c);
1667 }
1668 
1669 /*Basic inicialization routines */
1670 
uih_alloctables(uih_context * c)1671 static void uih_alloctables(uih_context *c)
1672 {
1673     c->zengine = zoom_filter.getinstance(&zoom_filter);
1674     if (c->zengine == NULL)
1675         return;
1676     c->fcontext = make_fractalc(0, c->image->pixelwidth * c->image->width,
1677                                 c->image->pixelheight * c->image->height);
1678     uih_updatemenus(c, "periodicity") uih_updatemenus(c, "in0")
1679         uih_updatemenus(c, "int0") uih_updatemenus(c, "out0")
1680             uih_updatemenus(c, "outt0") uih_updatemenus(c, "plane0")
1681                 uih_updatemenus(c, "guess3") uih = c;
1682     c->uifilter = uih_filter.getinstance(&uih_filter);
1683     c->queue = create_queue(c->uifilter);
1684     insertfilter(c->zengine, c->uifilter);
1685 }
1686 
uih_initqueue(uih_context * c)1687 static int uih_initqueue(uih_context *c) { return (initqueue(c->queue)); }
1688 
uih_setmaxstep(uih_context * c,number_t p)1689 void uih_setmaxstep(uih_context *c, number_t p) { c->maxstep = p; }
1690 
uih_setspeedup(uih_context * c,number_t p)1691 void uih_setspeedup(uih_context *c, number_t p) { c->speedup = p; }
1692 
uih_setmaxiter(uih_context * c,int maxiter)1693 void uih_setmaxiter(uih_context *c, int maxiter)
1694 {
1695     if (maxiter < 1)
1696         maxiter = 1;
1697     if (maxiter > 2000000)
1698         maxiter = 2000000;
1699     if (c->fcontext->maxiter != (unsigned int)maxiter) {
1700         c->fcontext->maxiter = maxiter;
1701         c->fcontext->version++;
1702         uih_newimage(c);
1703     }
1704 }
1705 
uih_setbailout(uih_context * c,number_t bailout)1706 void uih_setbailout(uih_context *c, number_t bailout)
1707 {
1708     if (bailout < 0)
1709         bailout = 0;
1710     if (c->fcontext->bailout != (number_t)bailout) {
1711         c->fcontext->bailout = bailout;
1712         c->fcontext->version++;
1713         uih_newimage(c);
1714     }
1715 }
1716 
uih_setincoloringmode(uih_context * c,int mode)1717 void uih_setincoloringmode(uih_context *c, int mode)
1718 {
1719     if (mode < 0)
1720         mode = rand() % INCOLORING;
1721     if (mode > INCOLORING)
1722         mode = INCOLORING;
1723     if (c->fcontext->incoloringmode != mode) {
1724         char str[10];
1725         c->fcontext->incoloringmode = mode;
1726         c->fcontext->version++;
1727         uih_newimage(c);
1728         sprintf(str, "in%i", mode);
1729         uih_updatemenus(c, str);
1730     }
1731 }
1732 
uih_setintcolor(uih_context * c,int mode)1733 void uih_setintcolor(uih_context *c, int mode)
1734 {
1735     if (mode < 0)
1736         mode = rand() % TCOLOR;
1737     if (mode > TCOLOR)
1738         mode = TCOLOR;
1739     if (c->fcontext->intcolor != mode) {
1740         char str[10];
1741         c->fcontext->intcolor = mode;
1742         if (c->fcontext->incoloringmode == 10) {
1743             c->fcontext->version++;
1744             uih_newimage(c);
1745         }
1746         sprintf(str, "int%i", mode);
1747         uih_updatemenus(c, str);
1748     }
1749 }
1750 
uih_setouttcolor(uih_context * c,int mode)1751 void uih_setouttcolor(uih_context *c, int mode)
1752 {
1753     if (mode < 0)
1754         mode = rand() % TCOLOR;
1755     if (mode > TCOLOR)
1756         mode = TCOLOR;
1757     if (c->fcontext->outtcolor != mode) {
1758         char str[10];
1759         c->fcontext->outtcolor = mode;
1760         if (c->fcontext->coloringmode == 10) {
1761             c->fcontext->version++;
1762             uih_newimage(c);
1763         }
1764         sprintf(str, "outt%i", mode);
1765         uih_updatemenus(c, str);
1766     }
1767 }
1768 
uih_setperbutation(uih_context * c,number_t zre,number_t zim)1769 void uih_setperbutation(uih_context *c, number_t zre, number_t zim)
1770 {
1771     if (c->fcontext->bre != zre || c->fcontext->bim != zim) {
1772         c->fcontext->bre = zre;
1773         c->fcontext->bim = zim;
1774         if (c->fcontext->mandelbrot) {
1775             c->fcontext->version++;
1776             uih_newimage(c);
1777         }
1778         uih_updatemenus(c, "uiperturbation");
1779     }
1780 }
1781 
uih_perbutation(uih_context * c,int mousex,int mousey)1782 void uih_perbutation(uih_context *c, int mousex, int mousey)
1783 {
1784     number_t r, i;
1785     uih_getcoord(c, mousex, mousey, &r, &i);
1786     uih_setperbutation(c, r, i);
1787 }
1788 
uih_setjuliaseed(uih_context * c,number_t zre,number_t zim)1789 void uih_setjuliaseed(uih_context *c, number_t zre, number_t zim)
1790 {
1791     if (c->fcontext->pre != zre || c->fcontext->pim != zim) {
1792         c->fcontext->pre = zre;
1793         c->fcontext->pim = zim;
1794         if (c->juliamode) {
1795             uih_animate_image(c);
1796         } else {
1797             if (!c->fcontext->mandelbrot) {
1798                 c->fcontext->version++;
1799                 if (c->playc && c->playc->morphjulia)
1800                     uih_animate_image(c);
1801                 else
1802                     uih_newimage(c);
1803             }
1804         }
1805     }
1806 }
1807 
uih_setfastmode(uih_context * c,int mode)1808 void uih_setfastmode(uih_context *c, int mode)
1809 {
1810     const char *names[] = {"nodynamic", "nodynamic", "dynamicanimation",
1811                            "dynamicnew", "dynamicnew"};
1812     if (mode < 0)
1813         mode = 0;
1814     c->fastmode = mode;
1815     uih_updatemenus(c, names[mode]);
1816 }
1817 
uih_setoutcoloringmode(uih_context * c,int mode)1818 void uih_setoutcoloringmode(uih_context *c, int mode)
1819 {
1820     if (mode < 0)
1821         mode = rand() % OUTCOLORING;
1822     if (mode > OUTCOLORING)
1823         mode = OUTCOLORING - 1;
1824     if (c->fcontext->coloringmode != mode) {
1825         char str[10];
1826         c->fcontext->coloringmode = mode;
1827         c->fcontext->version++;
1828         uih_newimage(c);
1829         sprintf(str, "out%i", mode);
1830         uih_updatemenus(c, str);
1831     }
1832 }
1833 
uih_setplane(uih_context * c,int mode)1834 void uih_setplane(uih_context *c, int mode)
1835 {
1836     int i;
1837 
1838     if (mode < 0)
1839         mode = 0;
1840     for (i = 0; planename[i] != NULL; i++)
1841         ;
1842     if (mode >= i)
1843         mode = i - 1;
1844     if (mode < 0)
1845         mode = rand() % i;
1846     uih_invalidatepos(c);
1847     if (c->fcontext->plane != mode) {
1848         char str[20];
1849         c->fcontext->plane = mode;
1850         // if ( c->fcontext->plane == P_USER )
1851         // printf("USER NOT IMPLEMENTED");
1852         // uih_sffein( c, "z^3-c" )
1853         c->fcontext->version++;
1854         uih_newimage(c);
1855         sprintf(str, "plane%i", mode);
1856         uih_updatemenus(c, str);
1857     }
1858 }
1859 
uih_screentofractalcoord(uih_context * c,int mousex,int mousey,number_t * re,number_t * im)1860 void uih_screentofractalcoord(uih_context *c, int mousex, int mousey,
1861                               number_t *re, number_t *im)
1862 {
1863     uih_getcoord(c, mousex, mousey, re, im);
1864     recalculate(c->fcontext->plane, re, im);
1865 }
1866 
uih_setmandelbrot(uih_context * c,int mode,int mousex,int mousey)1867 void uih_setmandelbrot(uih_context *c, int mode, int mousex, int mousey)
1868 {
1869     if (mode < 0)
1870         mode = 0;
1871     if (mode > 1)
1872         mode = 1;
1873     if (c->fcontext->mandelbrot != mode) {
1874         c->fcontext->mandelbrot = mode;
1875         if (c->fcontext->mandelbrot == 0 && !c->juliamode) {
1876             uih_getcoord(c, mousex, mousey, &c->fcontext->pre,
1877                          &c->fcontext->pim);
1878             recalculate(c->fcontext->plane, &c->fcontext->pre,
1879                         &c->fcontext->pim);
1880         } else
1881             uih_disablejulia(c);
1882         c->fcontext->version++;
1883         uih_newimage(c);
1884         uih_updatemenus(c, "uimandelbrot");
1885     }
1886 }
1887 
uih_setguessing(uih_context * c,int range)1888 void uih_setguessing(uih_context *c, int range)
1889 {
1890     char str[10];
1891     c->fcontext->range = range;
1892     if (range <= 1) {
1893         uih_updatemenus(c, "noguess");
1894     } else if (range > 8) {
1895         uih_updatemenus(c, "guessall");
1896     } else {
1897         sprintf(str, "guess%i", range);
1898         uih_updatemenus(c, str);
1899     }
1900 }
1901 
uih_setperiodicity(uih_context * c,int periodicity)1902 void uih_setperiodicity(uih_context *c, int periodicity)
1903 {
1904     c->fcontext->periodicity = periodicity;
1905     uih_updatemenus(c, "periodicity");
1906 }
1907 
uih_interrupt(uih_context * c)1908 void uih_interrupt(uih_context *c)
1909 {
1910     if (c->incalculation)
1911         c->interrupt = 1;
1912 }
1913 
uih_stopzooming(uih_context * c)1914 void uih_stopzooming(uih_context *c) { c->speed = 0; }
1915 
uih_updateimage(uih_context * c,struct image * image)1916 int uih_updateimage(uih_context *c, struct image *image)
1917 {
1918     /*exit(); */
1919     c->image = image;
1920     c->palette = image->palette;
1921     c->queue->isinitialized = 0;
1922     c->ddatalost = 1;
1923     fractalc_resize_to(c->fcontext, c->image->pixelwidth * c->image->width,
1924                        c->image->pixelheight * c->image->height);
1925     c->display = 1;
1926     c->palette->ncells = sizeof(uicolors) / sizeof(rgb_t);
1927     c->palette->prergb = uicolors;
1928     if (c->palette->type & BITMAPS)
1929         c->palette->prergb = uibwcolors;
1930     c->inanimation = 2;
1931     uih_newimage(c);
1932     if (image->palette->type & (FIXEDCOLOR | BITMAPS))
1933         uih_fixedcolorenable(c);
1934     else
1935         uih_fixedcolordisable(c);
1936     return (uih_initqueue(c));
1937 }
1938 
uih_getcscreensizes(struct uih_context * uih,int * x,int * y,int * w,int * h,void *)1939 static void uih_getcscreensizes(struct uih_context *uih, int *x, int *y, int *w,
1940                                 int *h, void * /*data*/)
1941 {
1942     *x = 0;
1943     *y = 0;
1944     if (uih->clearscreen)
1945         *w = uih->image->width, *h = uih->image->height;
1946     else
1947         *w = *h = 0;
1948 }
1949 
uih_drawcscreen(struct uih_context * uih,void *)1950 static void uih_drawcscreen(struct uih_context *uih, void * /*data*/)
1951 {
1952     if (uih->clearscreen)
1953         clear_image(uih->image);
1954 }
1955 
1956 struct uih_context *
uih_mkcontext(int flags,struct image * image,int (* passfunc)(struct uih_context *,int,const char *,float),void (* longwait)(struct uih_context *),void (* upd)(struct uih_context *,const char *))1957 uih_mkcontext(int flags, struct image *image,
1958               int (*passfunc)(struct uih_context *, int, const char *, float),
1959               void (*longwait)(struct uih_context *),
1960               void (*upd)(struct uih_context *, const char *))
1961 {
1962     uih_context *uih;
1963     uih = (uih_context *)calloc(sizeof(*uih), 1); /*setup parameters */
1964     uih->updatemenus = upd;
1965     uih->autopilot = 0;
1966     uih->flags = flags;
1967     uih->image = image;
1968     uih->playstring = NULL;
1969     uih->palette = image->palette;
1970     uih->menuroot = "root";
1971     uih->palette->ncells = sizeof(uicolors) / sizeof(rgb_t);
1972     uih->palette->prergb = uicolors;
1973     if (uih->palette->type & BITMAPS) {
1974         uih->palette->prergb = uibwcolors;
1975     }
1976     uih->speed = 0;
1977     uih->step = 0;
1978     uih->color = 0;
1979     uih->speedup = STEP;
1980     uih->maxstep = MAXSTEP;
1981     uih->lasttime = -1;
1982     uih->recalculatemode = UIH_NEW_IMAGE;
1983     uih->display = 1;
1984     uih->fastmode = 2;
1985     uih_updatemenus(uih, "dynamicanimation");
1986     uih->aliasnum = -1;
1987     uih->direction = 1;
1988     uih->cyclingdirection = 1;
1989     uih->cyclingspeed = ROTATIONSPEED;
1990     uih->ddatalost = 1;
1991     uih->xtextpos = 1;
1992     uih_updatemenus(uih, "xtextleft");
1993     uih->complettehandler = 0;
1994     uih->ytextpos = 1;
1995     uih_updatemenus(uih, "ytextup");
1996     uih->display = 0;
1997     uih->errstring = NULL;
1998     uih->rotatemode = 0;
1999     uih_updatemenus(uih, "norotate");
2000     uih->rotationspeed = 10;
2001     uih->longwait = longwait;
2002     uih->passfunc = passfunc;
2003     uih->nletters = 0;
2004     uih->letterspersec = 15;
2005     uih->maintimer = tl_create_timer();
2006     uih->calculatetimer = tl_create_timer();
2007     uih->doittimer = tl_create_timer();
2008     tl_update_time();
2009     tl_reset_timer(uih->maintimer);
2010     tl_reset_timer(uih->calculatetimer);
2011     tl_stop_timer(uih->doittimer);
2012     tl_reset_timer(uih->doittimer);
2013     uih_alloctables(uih);
2014     uih_initqueue(uih); /*FIXME return value should not be ignored */
2015     if (image->palette->type & (FIXEDCOLOR | BITMAPS))
2016         uih_fixedcolorenable(uih);
2017     uih_mkdefaultpalette(uih);
2018     uih_stoptimers(uih);
2019     clean_autopilot(uih);
2020     uih_newimage(uih);
2021     uih->cscreenwindow = uih_registerw(uih, uih_getcscreensizes,
2022                                        uih_drawcscreen, 0, NONTRANSPARENTW);
2023     uih_initmessages(uih);
2024     uih_inittext(uih);
2025     uih_emulatetimers(uih);
2026 #ifdef USE_SFFE
2027     sffe_parse(&uih->fcontext->userformula, USER_FORMULA);
2028     sffe_parse(&uih->fcontext->userinitial, "");
2029 #endif
2030     uih_setformula(uih, 0);
2031     uih_saveundo(uih);
2032     return (uih);
2033 }
2034 
uih_savepalette(uih_context * c)2035 void uih_savepalette(uih_context *c)
2036 {
2037     if (c->palette2 != NULL)
2038         destroypalette(c->palette2);
2039     if (c->zengine->fractalc->palette != NULL)
2040         c->palette2 = clonepalette(c->zengine->fractalc->palette);
2041 }
2042 
uih_restorepalette(uih_context * uih)2043 void uih_restorepalette(uih_context *uih)
2044 {
2045     if (uih->palette2 != NULL) {
2046         if (uih->zengine->fractalc->palette != NULL)
2047             restorepalette(uih->zengine->fractalc->palette, uih->palette2);
2048         destroypalette(uih->palette2);
2049     }
2050     uih->palette2 = NULL;
2051     uih_finishpalette(uih);
2052 }
2053 
uih_loadpalette(uih_context * c,struct palette * palette)2054 void uih_loadpalette(uih_context *c, struct palette *palette)
2055 {
2056     if (c->palette2)
2057         destroypalette(c->palette2);
2058     c->palette2 = clonepalette(palette);
2059     uih_restorepalette(c);
2060     uih_palettechg(c);
2061 }
2062 
uih_clonepalette(uih_context * c)2063 struct palette *uih_clonepalette(uih_context *c)
2064 {
2065     if (c->zengine->fractalc->palette != NULL)
2066         return clonepalette(c->zengine->fractalc->palette);
2067     // I hope this is OK:
2068     return NULL;
2069 }
2070 
uih_setformula(uih_context * c,int num)2071 void uih_setformula(uih_context *c, int num)
2072 {
2073     set_formula(c->fcontext, num);
2074     uih_newimage(c);
2075     uih_updatemenus(c, "uimandelbrot");
2076     uih_updatemenus(c, "uiperturbation");
2077     uih_updatemenus(c, c->fcontext->currentformula->shortname);
2078 }
2079 
uih_sffeset(uih_context * c,sffe * parser,const char * formula)2080 void uih_sffeset(uih_context *c, sffe *parser, const char *formula)
2081 {
2082     char error[200];
2083     char previous[200];
2084     if (c->fcontext->userformula->expression)
2085         strcpy(previous, c->fcontext->userformula->expression);
2086     else
2087         strcpy(previous, USER_FORMULA);
2088     parser->errormsg = error;
2089     int errorcode = sffe_parse(&parser, formula);
2090     if (errorcode > 0) {
2091         if (errorcode != EmptyFormula || parser != c->fcontext->userinitial) {
2092             tl_update_time(); // otherwise error doesn't display long enough
2093             uih_error(c, error);
2094             sffe_parse(&parser, previous);
2095         }
2096     } else {
2097         if (parser->expression)
2098             uih_message(c, parser->expression);
2099         sffe_setlocal(c->fcontext);
2100         if (!(c->fcontext->currentformula->flags & SFFE_FRACTAL)) {
2101             uih_play_formula(c, "user");
2102         } else {
2103             uih_recalculate(c);
2104         }
2105     }
2106     parser->errormsg = NULL;
2107 }
2108 
uih_initstate(struct uih_context * uih)2109 void uih_initstate(struct uih_context *uih)
2110 {
2111     int i;
2112     int ver = uih->fcontext->version;
2113     uih->step = 0;
2114     uih->speedup = STEP;
2115     uih->maxstep = MAXSTEP;
2116     uih_fastrotatedisable(uih);
2117     uih_disablejulia(uih);
2118     uih->color = 0;
2119     uih_cycling_off(uih);
2120     for (i = 0; i < uih_nfilters; i++)
2121         uih_disablefilter(uih, i);
2122     uih_setperbutation(uih, 0, 0);
2123     set_formula(uih->fcontext, 0);
2124 #ifdef USE_SFFE
2125     sffe_parse(&uih->fcontext->userformula, USER_FORMULA);
2126     sffe_parse(&uih->fcontext->userinitial, "");
2127 #endif
2128     uih_setperiodicity(uih, 1);
2129     uih_setmaxiter(uih, 170);
2130     uih_setbailout(uih, 4);
2131     uih_setincoloringmode(uih, 0);
2132     uih_setoutcoloringmode(uih, 0);
2133     uih_setcycling(uih, 30);
2134     uih_display(uih);
2135     uih_setfastmode(uih, 2);
2136     uih_setintcolor(uih, 0);
2137     uih_setouttcolor(uih, 0);
2138     uih_setplane(uih, 0);
2139     uih_setguessing(uih, 3);
2140     uih_angle(uih, 0);
2141     uih_rotatemode(uih, 0);
2142     uih_rotationspeed(uih, 10);
2143     uih->xtextpos = 1;
2144     uih->ytextpos = 1;
2145     if (uih->playc) {
2146         uih->playc->morphtimes[0] = 0;
2147         uih->playc->morphtimes[1] = 0;
2148         uih->playc->morphjuliatimes[0] = 0;
2149         uih->playc->morphjuliatimes[1] = 0;
2150         uih->playc->morphangletimes[0] = 0;
2151         uih->playc->morphangletimes[1] = 0;
2152         uih->playc->morphlinetimes[0] = 0;
2153         uih->playc->morphlinetimes[1] = 0;
2154     }
2155     if (mkdefaultpalette(uih->zengine->fractalc->palette) != 0 ||
2156         uih->recalculatemode || uih->fcontext->version != ver) {
2157         uih_newimage(uih);
2158     }
2159 }
2160 
uih_freecontext(uih_context * c)2161 void uih_freecontext(uih_context *c)
2162 {
2163     struct filter *f;
2164     int i;
2165     if (c->emulator != NULL)
2166         uih_noconstantframetime(c);
2167     for (i = 0; i < UNDOLEVEL; i++)
2168         if (c->undo.undos[i])
2169             free(c->undo.undos[i]), c->undo.undos[i] = 0;
2170     while (c->queue->first) {
2171         f = c->queue->first;
2172         removefilter(c->queue->first);
2173         f->action->destroyinstance(f);
2174     }
2175     uih_destroymessages(c);
2176     uih_destroytext(c);
2177     uih_removew(c, c->cscreenwindow);
2178     free(c->queue);
2179     free_fractalc(c->fcontext);
2180     free(c);
2181 }
2182 
uih_getinstance(const struct filteraction * a)2183 static struct filter *uih_getinstance(const struct filteraction *a)
2184 {
2185     struct filter *f = createfilter(a);
2186     f->data = uih;
2187     f->name = "XaoS's user interface layer";
2188     return (f);
2189 }
2190 
uih_destroyinstance(struct filter * f)2191 static void uih_destroyinstance(struct filter *f)
2192 {
2193     struct uih_context *c = (struct uih_context *)f->data;
2194     if (c->autopilot)
2195         uih_autopilot_off(c);
2196     if (c->cycling)
2197         uih_cycling_off(c);
2198     tl_free_timer(c->maintimer);
2199     tl_free_timer(c->calculatetimer);
2200     tl_free_timer(c->doittimer);
2201     if (c->save)
2202         uih_save_disable(c);
2203     if (c->play)
2204         uih_replaydisable(c);
2205     free(f);
2206 }
2207 
2208 static int wascycling;
uih_require(struct filter * f,struct requirements * r)2209 static int uih_require(struct filter *f, struct requirements *r)
2210 {
2211     struct uih_context *uih;
2212     uih = (struct uih_context *)f->data;
2213     f->req = *r;
2214     uih_clearwindows(uih);
2215     if (uih->cycling)
2216         uih_cycling_off(uih), wascycling = 1;
2217     if (!(r->supportedmask & uih->image->palette->type))
2218         return 0;
2219     /*FIXME something should be done here :) */
2220     return (1);
2221 }
2222 
uih_initialize(struct filter * f,struct initdata * i)2223 static int uih_initialize(struct filter *f, struct initdata *i)
2224 {
2225     struct uih_context *uih;
2226     int returnval;
2227     uih = (struct uih_context *)f->data;
2228     f->queue->saveimage = uih->image;
2229     i->fractalc = uih->fcontext;
2230     uih_setfont(uih);
2231     tl_update_time();
2232     f->image = uih->image;
2233     f->wait_function = uih_waitfunc;
2234     uih->times[0][0] = -1;
2235     i->image = uih->image;
2236     f->fractalc = i->fractalc;
2237     f->image->palette->flags |= FINISHLATER;
2238     i->fractalc->palette = uih->image->palette;
2239     i->wait_function = uih_waitfunc;
2240     /*FIXME datalost should be handled in better way */
2241     if (uih->ddatalost)
2242         i->flags |= DATALOST;
2243     uih->tbreak = 2;
2244     uih_invalidatepos(uih);
2245     clean_autopilot(uih);
2246     returnval = f->previous->action->initialize(f->previous, i);
2247     if (wascycling)
2248         uih_cycling_on(uih), wascycling = 0;
2249     return returnval;
2250 }
2251 
uih_inhibittextsw(uih_context * c)2252 void uih_inhibittextsw(uih_context *c)
2253 {
2254     c->inhibittextoutput ^= 1;
2255     uih_updatemenus(c, "inhibittextoutput");
2256 }
2257 
uih_inhibittextselected(uih_context * c)2258 int uih_inhibittextselected(uih_context *c)
2259 {
2260     if (c == NULL)
2261         return 0;
2262     return c->inhibittextoutput;
2263 }
2264 
2265 static char statustext[256];
2266 static int statusstart;
2267 static struct uih_window *statuswindow = NULL;
2268 static int ministatusstart;
2269 static struct uih_window *ministatuswindow = NULL;
2270 static struct uih_window *cartesiangridwindow = NULL;
2271 
uih_updatestatus(uih_context * uih)2272 void uih_updatestatus(uih_context *uih)
2273 {
2274     double times =
2275         (uih->fcontext->currentformula->v.rr) / (uih->fcontext->s.rr);
2276     double timesnop = log(times) / log(10.0);
2277     double speed;
2278     uih_drawwindows(uih);
2279     uih_cycling_continue(uih);
2280     speed = uih_displayed(uih);
2281     sprintf(
2282         statustext,
2283         TR("Message",
2284            "%s %.2f times (%.1fE) %2.2f frames/sec %c %i %i %i %u            "),
2285         times < 1 ? TR("Message", "unzoomed") : TR("Message", "zoomed"),
2286         times < 1 ? 1.0 / times : times, timesnop, speed,
2287         uih->autopilot ? 'A' : ' ', uih->fcontext->coloringmode + 1,
2288         uih->fcontext->incoloringmode + 1, uih->fcontext->plane + 1,
2289         uih->fcontext->maxiter);
2290 
2291     STAT(printf(TR("Message", "framerate:%f\n"), speed));
2292 }
2293 
2294 #ifdef MEMCHECK
2295 #define STATUSLINES 13
2296 #else
2297 #define STATUSLINES 11
2298 #endif
2299 
uih_updatestarts(uih_context * uih)2300 void uih_updatestarts(uih_context *uih)
2301 {
2302     int y = 0;
2303     ministatusstart = y;
2304     if (ministatuswindow != NULL)
2305         y += xtextheight(uih->image, uih->font);
2306     statusstart = y;
2307     if (statuswindow != NULL)
2308         y += xtextheight(uih->image, uih->font) * STATUSLINES;
2309     uih->messg.messagestart = y;
2310 }
2311 
uih_statuspos(uih_context * uih,int * x,int * y,int * w,int * h,void *)2312 static void uih_statuspos(uih_context *uih, int *x, int *y, int *w, int *h,
2313                           void * /*data*/)
2314 {
2315     *x = 0;
2316     *y = statusstart;
2317     *w = uih->image->width;
2318     *h = xtextheight(uih->image, uih->font) * STATUSLINES;
2319 }
2320 
uih_drawstatus(uih_context * uih,void *)2321 static void uih_drawstatus(uih_context *uih, void * /*data*/)
2322 {
2323     char str[6000];
2324     int h = xtextheight(uih->image, uih->font);
2325     sprintf(str, TR("Message", "Fractal name:%s"),
2326             uih->fcontext->currentformula->name[!uih->fcontext->mandelbrot]);
2327     xprint(uih->image, uih->font, 0, statusstart, str, FGCOLOR(uih),
2328            BGCOLOR(uih), 0);
2329     sprintf(str, TR("Message", "Fractal type:%s"),
2330             uih->fcontext->mandelbrot ? TR("Message", "Mandelbrot")
2331                                       : TR("Message", "Julia"));
2332 #ifdef USE_SFFE
2333     if (uih->fcontext->currentformula->flags & SFFE_FRACTAL &&
2334         uih->fcontext->userformula->expression) {
2335         sprintf(str, TR("Message", "Formula:%s"),
2336                 uih->fcontext->userformula->expression);
2337     };
2338 #endif
2339     xprint(uih->image, uih->font, 0, statusstart + h, str, FGCOLOR(uih),
2340            BGCOLOR(uih), 0);
2341     sprintf(str, TR("Message", "View:[%1.12f,%1.12f]"),
2342             (double)uih->fcontext->s.cr, (double)uih->fcontext->s.ci);
2343     xprint(uih->image, uih->font, 0, statusstart + 2 * h, str, FGCOLOR(uih),
2344            BGCOLOR(uih), 0);
2345     sprintf(str, TR("Message", "size:[%1.12f,%1.12f]"),
2346             (double)uih->fcontext->s.rr, (double)uih->fcontext->s.ri);
2347     xprint(uih->image, uih->font, 0, statusstart + 3 * h, str, FGCOLOR(uih),
2348            BGCOLOR(uih), 0);
2349     sprintf(str, TR("Message", "Rotation:%4.2f   Screen size:%i:%i"),
2350             (double)uih->fcontext->angle, uih->image->width,
2351             uih->image->height);
2352     xprint(uih->image, uih->font, 0, statusstart + 4 * h, str, FGCOLOR(uih),
2353            BGCOLOR(uih), 0);
2354     sprintf(str, TR("Message", "Iterations:%-4u Palette size:%i"),
2355             uih->fcontext->maxiter, uih->image->palette->size);
2356     xprint(uih->image, uih->font, 0, statusstart + 5 * h, str, FGCOLOR(uih),
2357            BGCOLOR(uih), 0);
2358     sprintf(str, TR("Message", "Bailout:%4.2f"),
2359             (double)uih->fcontext->bailout);
2360     xprint(uih->image, uih->font, 0, statusstart + 6 * h, str, FGCOLOR(uih),
2361            BGCOLOR(uih), 0);
2362     sprintf(str, TR("Message", "Autopilot:%-4s  Plane:%s"),
2363             uih->autopilot ? TR("Message", "On") : TR("Message", "Off"),
2364             planename[uih->fcontext->plane]);
2365     xprint(uih->image, uih->font, 0, statusstart + 7 * h, str, FGCOLOR(uih),
2366            BGCOLOR(uih), 0);
2367     sprintf(str, TR("Message", "incoloring:%s    outcoloring:%s"),
2368             incolorname[uih->fcontext->incoloringmode],
2369             outcolorname[uih->fcontext->coloringmode]);
2370     xprint(uih->image, uih->font, 0, statusstart + 8 * h, str, FGCOLOR(uih),
2371            BGCOLOR(uih), 0);
2372     sprintf(str, TR("Message", "zoomspeed:%f"), (float)uih->maxstep * 1000);
2373     xprint(uih->image, uih->font, 0, statusstart + 9 * h, str, FGCOLOR(uih),
2374            BGCOLOR(uih), 0);
2375     if (uih->fcontext->mandelbrot)
2376         strcpy(str, TR("Message", "Parameter:none"));
2377     else
2378         sprintf(str, TR("Message", "Parameter:[%f,%f]"),
2379                 (float)uih->fcontext->pre, (float)uih->fcontext->pim);
2380     xprint(uih->image, uih->font, 0, statusstart + 10 * h, str, FGCOLOR(uih),
2381            BGCOLOR(uih), 0);
2382 #ifdef MEMCHECK
2383     {
2384         struct mallinfo i = mallinfo();
2385         sprintf(str, "Allocated arena:%i Wasted:%i %i", i.arena, i.ordblks,
2386                 i.fordblks);
2387         xprint(uih->image, uih->font, 0, statusstart + 11 * h, str,
2388                FGCOLOR(uih), BGCOLOR(uih), 0);
2389         sprintf(str, "Mmaped blocks%i Mmaped area:%i keep:%i", i.hblks,
2390                 i.hblkhd, i.keepcost);
2391         xprint(uih->image, uih->font, 0, statusstart + 12 * h, str,
2392                FGCOLOR(uih), BGCOLOR(uih), 0);
2393     }
2394 #endif
2395 }
2396 
uih_status(uih_context * uih)2397 void uih_status(uih_context *uih)
2398 {
2399     if (statuswindow == NULL) {
2400         statuswindow =
2401             uih_registerw(uih, uih_statuspos, uih_drawstatus, NULL, 0);
2402     } else {
2403         uih_removew(uih, statuswindow);
2404         statuswindow = NULL;
2405     }
2406     uih_updatemenus(uih, "status");
2407     uih_updatemenus(uih, "animministatus");
2408     uih_updatestarts(uih);
2409 }
2410 
uih_statusenabled(uih_context *)2411 int uih_statusenabled(uih_context * /*uih*/) { return (statuswindow != NULL); }
2412 
uih_ministatuspos(uih_context * uih,int * x,int * y,int * w,int * h,void *)2413 static void uih_ministatuspos(uih_context *uih, int *x, int *y, int *w, int *h,
2414                               void * /*data*/)
2415 {
2416     *x = 0;
2417     *y = ministatusstart;
2418     *w = uih->image->width;
2419     *h = xtextheight(uih->image, uih->font);
2420 }
2421 
uih_drawministatus(uih_context * uih,void *)2422 static void uih_drawministatus(uih_context *uih, void * /*data*/)
2423 {
2424     xprint(uih->image, uih->font, 0, ministatusstart, statustext, FGCOLOR(uih),
2425            BGCOLOR(uih), 0);
2426 }
2427 
uih_ministatus(uih_context * uih)2428 void uih_ministatus(uih_context *uih)
2429 {
2430     if (ministatuswindow == NULL) {
2431         ministatuswindow =
2432             uih_registerw(uih, uih_ministatuspos, uih_drawministatus, NULL, 0);
2433     } else {
2434         uih_removew(uih, ministatuswindow);
2435         ministatuswindow = NULL;
2436     }
2437     uih_updatestarts(uih);
2438     uih_updatemenus(uih, "ministatus");
2439     uih_updatemenus(uih, "animministatus");
2440 }
2441 
uih_ministatusenabled(uih_context *)2442 int uih_ministatusenabled(uih_context * /*uih*/)
2443 {
2444     return (ministatuswindow != NULL);
2445 }
2446 
uih_cartesiangridpos(uih_context * uih,int * x,int * y,int * w,int * h,void *)2447 static void uih_cartesiangridpos(uih_context *uih, int *x, int *y, int *w, int *h,
2448                               void * /*data*/)
2449 {
2450     *x = 0;
2451     *y = 0;
2452     *w = uih->image->width;
2453     *h = uih->image->height-30; // Leave some padding, FIXME
2454     fflush(stdout);
2455 }
2456 
uih_drawcartesiangrid(uih_context * uih,void *)2457 static void uih_drawcartesiangrid(uih_context *uih, void * /*data*/)
2458 {
2459     overlayGrid(uih, FGCOLOR(uih));
2460 }
2461 
uih_cartesiangrid(uih_context * uih)2462 void uih_cartesiangrid(uih_context *uih)
2463 {
2464     double currzoom =
2465         (uih->fcontext->currentformula->v.rr) / (uih->fcontext->s.rr);
2466 
2467     if (cartesiangridwindow == NULL and currzoom < 100000) {
2468         cartesiangridwindow =
2469             uih_registerw(uih, uih_cartesiangridpos, uih_drawcartesiangrid, NULL, 0);
2470     } else {
2471         if(cartesiangridwindow) {
2472             uih_removew(uih, cartesiangridwindow);
2473             cartesiangridwindow = NULL;
2474         } else {
2475             uih_error(uih, "Cartesian Grid not supported on zoom > 100000x");
2476         }
2477     }
2478 
2479     uih_updatestarts(uih);
2480     uih_updatemenus(uih, "cartesiangrid");
2481     uih_updatemenus(uih, "animcartesiangrid");
2482 }
2483 
uih_cartesiangridenabled(uih_context *)2484 int uih_cartesiangridenabled(uih_context * /*uih*/)
2485 {
2486     return (cartesiangridwindow != NULL);
2487 }
2488