From f52737c4b0840bd8271d2e7ce3967cd470b65813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Kov=C3=A1cs?= Date: Sat, 20 Jan 2024 23:13:27 +0100 Subject: [PATCH] Change file encodings to Unix --- src/engine/3dd.h | 2 +- src/engine/anti.cpp | 2 +- src/engine/blur.cpp | 2 +- src/engine/btrace.cpp | 2 +- src/engine/btraced.h | 2 +- src/engine/calculate.h | 2 +- src/engine/docalc.h | 2 +- src/engine/edge.cpp | 2 +- src/engine/edge2.cpp | 2 +- src/engine/edge2d.h | 2 +- src/engine/edged.h | 2 +- src/engine/emboss.cpp | 2 +- src/engine/filter.cpp | 2 +- src/engine/formulas.cpp | 2 +- src/engine/fractal.cpp | 2 +- src/engine/interlace.cpp | 2 +- src/engine/itersmall.cpp | 2 +- src/engine/julia.cpp | 2 +- src/engine/julia.h | 2 +- src/engine/paletted.h | 2 +- src/engine/palettef.cpp | 2 +- src/engine/plane.cpp | 2 +- src/engine/rotate.cpp | 2 +- src/engine/rotated.h | 2 +- src/engine/star.cpp | 2 +- src/engine/stard.h | 2 +- src/engine/stereod.h | 2 +- src/engine/stereogram.cpp | 2 +- src/engine/subwindow.cpp | 2 +- src/engine/zoom.cpp | 2 +- src/engine/zoomd.h | 2 +- src/formeval/formeval.cpp | 2 +- src/formeval/formeval.h | 2 +- src/include/btrace.h | 2 +- src/include/c256.h | 2 +- src/include/catalog.h | 2 +- src/include/cmplx.h | 2 +- src/include/filter.h | 2 +- src/include/formulas.h | 2 +- src/include/fractal.h | 2 +- src/include/generic.h | 2 +- src/include/grlib.h | 2 +- src/include/gsl/gsl_complex.h | 2 +- src/include/gsl/gsl_inline.h | 2 +- src/include/gsl/gsl_machine.h | 2 +- src/include/gsl/gsl_math.h | 2 +- src/include/gsl/gsl_minmax.h | 2 +- src/include/gsl/gsl_nan.h | 2 +- src/include/gsl/gsl_pow_int.h | 2 +- src/include/gsl/gsl_precision.h | 2 +- src/include/gsl/gsl_types.h | 2 +- src/include/i18n.h | 22 +- src/include/misc-f.h | 2 +- src/include/param.h | 2 +- src/include/pixel_t.h | 2 +- src/include/plane.h | 2 +- src/include/sffe.h | 2 +- src/include/sffe_cmplx_gsl.h | 2 +- src/include/timers.h | 2 +- src/include/true24.h | 2 +- src/include/xerror.h | 2 +- src/include/xio.h | 2 +- src/include/xthread.h | 2 +- src/include/zoom.h | 2 +- src/sffe/About | 6 +- src/sffe/gsl_complex_math.c | 6 +- src/sffe/sffe.cpp | 6 +- src/sffe/sffe_cmplx_gsl.cpp | 4 +- src/ui-hlp/ui-hlp.pri | 26 +- src/ui/customdialog.h | 80 +- src/ui/fractalwidget.cpp | 166 +- src/ui/fractalwidget.h | 84 +- src/ui/image_qt.cpp | 434 ++--- src/ui/mainwindow.cpp | 3182 +++++++++++++++---------------- src/ui/mainwindow.h | 180 +- src/ui/ui.h | 2 +- src/ui/xaos.rc | 2 +- src/util/catalog.cpp | 2 +- src/util/grlibd.h | 2 +- src/util/image.cpp | 2 +- src/util/palette.cpp | 2 +- src/util/random.cpp | 2 +- src/util/thread.cpp | 2 +- src/util/timers.cpp | 2 +- src/util/util.pri | 28 +- src/util/xerror.cpp | 2 +- src/util/xmenu.cpp | 2 +- src/util/xstdio.cpp | 2 +- src/util/xstring.cpp | 2 +- 89 files changed, 2188 insertions(+), 2188 deletions(-) diff --git a/src/engine/3dd.h b/src/engine/3dd.h index 40b3454d..5733489c 100644 --- a/src/engine/3dd.h +++ b/src/engine/3dd.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static void convert_3d(struct filter *f, int *x1, int *y1) { struct threeddata *data = (struct threeddata *)f->data; diff --git a/src/engine/anti.cpp b/src/engine/anti.cpp index 4f4e03f2..463678d0 100644 --- a/src/engine/anti.cpp +++ b/src/engine/anti.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #ifndef __cplusplus #include #endif diff --git a/src/engine/blur.cpp b/src/engine/blur.cpp index 57fff26d..f7d3637d 100644 --- a/src/engine/blur.cpp +++ b/src/engine/blur.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include #include diff --git a/src/engine/btrace.cpp b/src/engine/btrace.cpp index 14bd2e6b..1d339de5 100644 --- a/src/engine/btrace.cpp +++ b/src/engine/btrace.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include #include diff --git a/src/engine/btraced.h b/src/engine/btraced.h index 90a53afb..7f7210cb 100644 --- a/src/engine/btraced.h +++ b/src/engine/btraced.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static void tracecolor(int xstart, int ystart, int xend, int yend, int x, int y) { diff --git a/src/engine/calculate.h b/src/engine/calculate.h index 4cefa193..b11eba6a 100644 --- a/src/engine/calculate.h +++ b/src/engine/calculate.h @@ -1,4 +1,4 @@ - + static pixel32_t inline calculate(number_t x, number_t y, int periodicity); static pixel32_t inline calculate(number_t x, number_t y, int periodicity) { diff --git a/src/engine/docalc.h b/src/engine/docalc.h index 584776b9..41a38f2b 100644 --- a/src/engine/docalc.h +++ b/src/engine/docalc.h @@ -1,4 +1,4 @@ - + /* Hello reader! * Are you sure you want read this? Its very cryptic and strange code. YOU diff --git a/src/engine/edge.cpp b/src/engine/edge.cpp index e91e46c3..0371e759 100644 --- a/src/engine/edge.cpp +++ b/src/engine/edge.cpp @@ -1,4 +1,4 @@ -/* An edge detection filter. +/* An edge detection filter. * This is very simple filter - it initializes smalliter image and then * does an simple edge detection algo on it. */ diff --git a/src/engine/edge2.cpp b/src/engine/edge2.cpp index e5307620..1ad375d2 100644 --- a/src/engine/edge2.cpp +++ b/src/engine/edge2.cpp @@ -1,4 +1,4 @@ -/* An edge detection filter. +/* An edge detection filter. * This is very simple filter - it initializes smalliter image and then * does an simple edge detection algo on it. */ diff --git a/src/engine/edge2d.h b/src/engine/edge2d.h index d04fd40d..a23f858b 100644 --- a/src/engine/edge2d.h +++ b/src/engine/edge2d.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static void do_edge(void *data, struct taskinfo */*task*/, int r1, int r2) { struct filter *f = (struct filter *)data; diff --git a/src/engine/edged.h b/src/engine/edged.h index bdc79ce4..322d1800 100644 --- a/src/engine/edged.h +++ b/src/engine/edged.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static void do_edge(void *data, struct taskinfo */*task*/, int r1, int r2) { struct filter *f = (struct filter *)data; diff --git a/src/engine/emboss.cpp b/src/engine/emboss.cpp index 30f5b420..d25a3d72 100644 --- a/src/engine/emboss.cpp +++ b/src/engine/emboss.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include #include "filter.h" diff --git a/src/engine/filter.cpp b/src/engine/filter.cpp index 26ac5854..68679474 100644 --- a/src/engine/filter.cpp +++ b/src/engine/filter.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "config.h" diff --git a/src/engine/formulas.cpp b/src/engine/formulas.cpp index f8658cb3..f8e7fc67 100644 --- a/src/engine/formulas.cpp +++ b/src/engine/formulas.cpp @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/engine/fractal.cpp b/src/engine/fractal.cpp index 41abe5f5..d1681797 100644 --- a/src/engine/fractal.cpp +++ b/src/engine/fractal.cpp @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/engine/interlace.cpp b/src/engine/interlace.cpp index 0c7cc1c5..bb49aa22 100644 --- a/src/engine/interlace.cpp +++ b/src/engine/interlace.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include /*for NULL */ #include /*for memcpy */ diff --git a/src/engine/itersmall.cpp b/src/engine/itersmall.cpp index 8b9666ce..9af97423 100644 --- a/src/engine/itersmall.cpp +++ b/src/engine/itersmall.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include "config.h" #include #define SLARGEITER diff --git a/src/engine/julia.cpp b/src/engine/julia.cpp index 128f357e..4c48772f 100644 --- a/src/engine/julia.cpp +++ b/src/engine/julia.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "config.h" #include diff --git a/src/engine/julia.h b/src/engine/julia.h index 8773a6c6..ae823f61 100644 --- a/src/engine/julia.h +++ b/src/engine/julia.h @@ -1,4 +1,4 @@ -#ifndef JULIA_H +#ifndef JULIA_H #define JULIA_H void init_julia(struct image *img, number_t rangep, number_t range, number_t xdelta, number_t ystep); diff --git a/src/engine/paletted.h b/src/engine/paletted.h index 17d683ee..9db29580 100644 --- a/src/engine/paletted.h +++ b/src/engine/paletted.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static void cpalette(void *data, struct taskinfo */*task*/, int r1, int r2) { pixel8_t *src, *srcend; diff --git a/src/engine/palettef.cpp b/src/engine/palettef.cpp index 6e7a2f0e..bb410cec 100644 --- a/src/engine/palettef.cpp +++ b/src/engine/palettef.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include #include "filter.h" diff --git a/src/engine/plane.cpp b/src/engine/plane.cpp index f6b4f136..a34ff1e5 100644 --- a/src/engine/plane.cpp +++ b/src/engine/plane.cpp @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/engine/rotate.cpp b/src/engine/rotate.cpp index 9b4db4e2..2ace6609 100644 --- a/src/engine/rotate.cpp +++ b/src/engine/rotate.cpp @@ -1,4 +1,4 @@ -/* An rotation filter. Uses bressemham algorithm combined with dda to rotate +/* An rotation filter. Uses bressemham algorithm combined with dda to rotate * image around center * This filter is used internally by XaoS and is unvisible to normal user in * 'E' menu. diff --git a/src/engine/rotated.h b/src/engine/rotated.h index 014cd4ff..16211836 100644 --- a/src/engine/rotated.h +++ b/src/engine/rotated.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static void do_rotate(void *data, struct taskinfo */*task*/, int r1, int r2) { struct filter *f = (struct filter *)data; diff --git a/src/engine/star.cpp b/src/engine/star.cpp index 1be46e73..ef17b70b 100644 --- a/src/engine/star.cpp +++ b/src/engine/star.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include "config.h" #include #include diff --git a/src/engine/stard.h b/src/engine/stard.h index 9b405b74..a07094f0 100644 --- a/src/engine/stard.h +++ b/src/engine/stard.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static void do_starfield(void *data, struct taskinfo */*task*/, int r1, int r2) { struct filter *f = (struct filter *)data; diff --git a/src/engine/stereod.h b/src/engine/stereod.h index 36f3c6ee..d49fef43 100644 --- a/src/engine/stereod.h +++ b/src/engine/stereod.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static void do_stereogram(void *data, struct taskinfo */*task*/, int r1, int r2) { struct filter *f = (struct filter *)data; diff --git a/src/engine/stereogram.cpp b/src/engine/stereogram.cpp index 61b7bfd0..ffc8dc08 100644 --- a/src/engine/stereogram.cpp +++ b/src/engine/stereogram.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include "xthread.h" #include "filter.h" diff --git a/src/engine/subwindow.cpp b/src/engine/subwindow.cpp index c59a2d5d..252306aa 100644 --- a/src/engine/subwindow.cpp +++ b/src/engine/subwindow.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include /*for NULL */ #include /*for memcpy */ diff --git a/src/engine/zoom.cpp b/src/engine/zoom.cpp index a35e0bcf..5e1d500a 100644 --- a/src/engine/zoom.cpp +++ b/src/engine/zoom.cpp @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/engine/zoomd.h b/src/engine/zoomd.h index 847a9e06..927100fe 100644 --- a/src/engine/zoomd.h +++ b/src/engine/zoomd.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED /* this two routines implements solid guessing. They are almost same. One * calculates lines, second rows. diff --git a/src/formeval/formeval.cpp b/src/formeval/formeval.cpp index dd5810a0..5c558dd8 100644 --- a/src/formeval/formeval.cpp +++ b/src/formeval/formeval.cpp @@ -1,4 +1,4 @@ -/* +/* * XaoS Formula Evaluator * Copyright (c) 2020 J.B. Langston * diff --git a/src/formeval/formeval.h b/src/formeval/formeval.h index 88fe58f7..793b571e 100644 --- a/src/formeval/formeval.h +++ b/src/formeval/formeval.h @@ -1,4 +1,4 @@ -/* +/* * XaoS Formula Evaluator * Copyright (c) 2020 J.B. Langston * diff --git a/src/include/btrace.h b/src/include/btrace.h index 17a68a15..10b95e12 100644 --- a/src/include/btrace.h +++ b/src/include/btrace.h @@ -1,4 +1,4 @@ -#ifndef BTRACE_H +#ifndef BTRACE_H #define BTRACE_H int boundarytrace(int x1, int y1, int x2, int y2, number_t *xpos, number_t *ypos); diff --git a/src/include/c256.h b/src/include/c256.h index 59886530..9dae060a 100644 --- a/src/include/c256.h +++ b/src/include/c256.h @@ -1,4 +1,4 @@ -#ifdef cpixel_t +#ifdef cpixel_t #undef cpixel_t #undef cpixeldata_t #undef cppixel_t diff --git a/src/include/catalog.h b/src/include/catalog.h index 25af6ac8..b41921d1 100644 --- a/src/include/catalog.h +++ b/src/include/catalog.h @@ -1,4 +1,4 @@ -/* Small library to handle catalog files +/* Small library to handle catalog files */ #ifndef CATALOG_H #define CATALOG_H diff --git a/src/include/cmplx.h b/src/include/cmplx.h index 15e05088..9d65dda4 100644 --- a/src/include/cmplx.h +++ b/src/include/cmplx.h @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/include/filter.h b/src/include/filter.h index a3de357f..44737cd4 100644 --- a/src/include/filter.h +++ b/src/include/filter.h @@ -1,4 +1,4 @@ -#ifndef IMAGE_H +#ifndef IMAGE_H #define IMAGE_H #include "config.h" diff --git a/src/include/formulas.h b/src/include/formulas.h index 8d25facc..c9c37bf3 100644 --- a/src/include/formulas.h +++ b/src/include/formulas.h @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/include/fractal.h b/src/include/fractal.h index 0ed0b03f..2d3054ae 100644 --- a/src/include/fractal.h +++ b/src/include/fractal.h @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/include/generic.h b/src/include/generic.h index a5e62d23..cdf4efff 100644 --- a/src/include/generic.h +++ b/src/include/generic.h @@ -1,4 +1,4 @@ -#undef p_set +#undef p_set #undef p_get #undef p_setp #undef bpp1 diff --git a/src/include/grlib.h b/src/include/grlib.h index baf6225a..f63e0c96 100644 --- a/src/include/grlib.h +++ b/src/include/grlib.h @@ -1,4 +1,4 @@ -#ifndef _TEXT_H +#ifndef _TEXT_H #define _TEXT_H #define TEXT_PRESSED 1 #include "ui_helper.h" diff --git a/src/include/gsl/gsl_complex.h b/src/include/gsl/gsl_complex.h index 39063882..527723e6 100644 --- a/src/include/gsl/gsl_complex.h +++ b/src/include/gsl/gsl_complex.h @@ -1,4 +1,4 @@ -/* complex/gsl_complex.h +/* complex/gsl_complex.h * * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough * diff --git a/src/include/gsl/gsl_inline.h b/src/include/gsl/gsl_inline.h index 4d1604b4..4c38d93d 100644 --- a/src/include/gsl/gsl_inline.h +++ b/src/include/gsl/gsl_inline.h @@ -1,4 +1,4 @@ -/* gsl_inline.h +/* gsl_inline.h * * Copyright (C) 2008, 2009 Brian Gough * diff --git a/src/include/gsl/gsl_machine.h b/src/include/gsl/gsl_machine.h index f6c7e7a9..5737a103 100644 --- a/src/include/gsl/gsl_machine.h +++ b/src/include/gsl/gsl_machine.h @@ -1,4 +1,4 @@ -/* Author: B. Gough and G. Jungman */ +/* Author: B. Gough and G. Jungman */ #ifndef __GSL_MACHINE_H__ #define __GSL_MACHINE_H__ diff --git a/src/include/gsl/gsl_math.h b/src/include/gsl/gsl_math.h index 280c2fbd..a5005cd2 100644 --- a/src/include/gsl/gsl_math.h +++ b/src/include/gsl/gsl_math.h @@ -1,4 +1,4 @@ -/* gsl_math.h +/* gsl_math.h * * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 2007 Gerard Jungman, Brian * Gough diff --git a/src/include/gsl/gsl_minmax.h b/src/include/gsl/gsl_minmax.h index 4af43512..a5ad417d 100644 --- a/src/include/gsl/gsl_minmax.h +++ b/src/include/gsl/gsl_minmax.h @@ -1,4 +1,4 @@ -/* gsl_minmax.h +/* gsl_minmax.h * * Copyright (C) 2008 Gerard Jungman, Brian Gough * diff --git a/src/include/gsl/gsl_nan.h b/src/include/gsl/gsl_nan.h index aa2632d4..8e3a28fb 100644 --- a/src/include/gsl/gsl_nan.h +++ b/src/include/gsl/gsl_nan.h @@ -1,4 +1,4 @@ -/* gsl_nan.h +/* gsl_nan.h * * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough * diff --git a/src/include/gsl/gsl_pow_int.h b/src/include/gsl/gsl_pow_int.h index 95556afe..de3ca1e3 100644 --- a/src/include/gsl/gsl_pow_int.h +++ b/src/include/gsl/gsl_pow_int.h @@ -1,4 +1,4 @@ -/* gsl_pow_int.h +/* gsl_pow_int.h * * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 2007 Gerard Jungman, Brian * Gough diff --git a/src/include/gsl/gsl_precision.h b/src/include/gsl/gsl_precision.h index 6ca7b0f9..2e417495 100644 --- a/src/include/gsl/gsl_precision.h +++ b/src/include/gsl/gsl_precision.h @@ -1,4 +1,4 @@ -/* gsl_precision.h +/* gsl_precision.h * * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman * diff --git a/src/include/gsl/gsl_types.h b/src/include/gsl/gsl_types.h index a41035db..e972d8c2 100644 --- a/src/include/gsl/gsl_types.h +++ b/src/include/gsl/gsl_types.h @@ -1,4 +1,4 @@ -/* gsl_types.h +/* gsl_types.h * * Copyright (C) 2001, 2007 Brian Gough * diff --git a/src/include/i18n.h b/src/include/i18n.h index 7930339e..ad6953da 100644 --- a/src/include/i18n.h +++ b/src/include/i18n.h @@ -1,11 +1,11 @@ -#ifndef I18N_H -#define I18N_H - -const char *qt_gettext(const char *context, const char *text); -void setLanguage(const char *lang); -const char *getLanguage(); -const char *lang1(int i); -const char *lang2(int i); - -#define TR(context, text) qt_gettext(context, text) -#endif +#ifndef I18N_H +#define I18N_H + +const char *qt_gettext(const char *context, const char *text); +void setLanguage(const char *lang); +const char *getLanguage(); +const char *lang1(int i); +const char *lang2(int i); + +#define TR(context, text) qt_gettext(context, text) +#endif diff --git a/src/include/misc-f.h b/src/include/misc-f.h index 34aebbc5..d7dd0534 100644 --- a/src/include/misc-f.h +++ b/src/include/misc-f.h @@ -1,4 +1,4 @@ -#ifndef IUTIL_H +#ifndef IUTIL_H #define IUTIL_H #include "xio.h" #include "config.h" diff --git a/src/include/param.h b/src/include/param.h index 8d356d51..7cb9dc8a 100644 --- a/src/include/param.h +++ b/src/include/param.h @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/include/pixel_t.h b/src/include/pixel_t.h index f127118a..a34af7d5 100644 --- a/src/include/pixel_t.h +++ b/src/include/pixel_t.h @@ -1,4 +1,4 @@ -#ifndef PIXEL_T_H +#ifndef PIXEL_T_H #define PIXEL_T_H #include typedef uint8_t pixel8_t; diff --git a/src/include/plane.h b/src/include/plane.h index 2a842a50..884a4471 100644 --- a/src/include/plane.h +++ b/src/include/plane.h @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/include/sffe.h b/src/include/sffe.h index 18457d21..9678c13f 100644 --- a/src/include/sffe.h +++ b/src/include/sffe.h @@ -1,4 +1,4 @@ -/*///////////////////////////////////////////////////////////////////////////////////// +/*///////////////////////////////////////////////////////////////////////////////////// // project : sFFe ( SegFault (or Segmentation Fault :) ) formula evalutaor ) // author : Mateusz Malczak ( mateusz@malczak.info ) // wpage : diff --git a/src/include/sffe_cmplx_gsl.h b/src/include/sffe_cmplx_gsl.h index 8f0091f0..18a42a3a 100644 --- a/src/include/sffe_cmplx_gsl.h +++ b/src/include/sffe_cmplx_gsl.h @@ -1,4 +1,4 @@ -/*///////////////////////////////////////////////////////////////////////////////////// +/*///////////////////////////////////////////////////////////////////////////////////// // project : sFFe ( SegFault (or Segmentation Fault :) ) formula evalutaor ) // author : Mateusz Malczak ( mateusz@malczak.info ) // wpage : diff --git a/src/include/timers.h b/src/include/timers.h index fe861917..e09fcacd 100644 --- a/src/include/timers.h +++ b/src/include/timers.h @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/include/true24.h b/src/include/true24.h index e28d45d7..1b96d1f9 100644 --- a/src/include/true24.h +++ b/src/include/true24.h @@ -1,4 +1,4 @@ -#ifdef cpixel_t +#ifdef cpixel_t #undef cpixel_t #undef cpixeldata_t #undef cppixel_t diff --git a/src/include/xerror.h b/src/include/xerror.h index 3da7d37a..873306ad 100644 --- a/src/include/xerror.h +++ b/src/include/xerror.h @@ -1,4 +1,4 @@ -#ifndef XERROR_H +#ifndef XERROR_H #define XERROR_H void x_message(const char *text, ...); void x_error(const char *text, ...); diff --git a/src/include/xio.h b/src/include/xio.h index b9bd1c35..10d4e86b 100644 --- a/src/include/xio.h +++ b/src/include/xio.h @@ -1,4 +1,4 @@ -/* This is implementation of input/output routines similar to stdio. +/* This is implementation of input/output routines similar to stdio. purpose of this library is to hide differences between OSes (Mac OS don't have stdio!) and allow general streams to strings etc. */ #ifndef XIO1_H diff --git a/src/include/xthread.h b/src/include/xthread.h index a654ac83..3e541268 100644 --- a/src/include/xthread.h +++ b/src/include/xthread.h @@ -1,4 +1,4 @@ -/* +/* * An XaoS thread API implementation * Many functions are implemented as macros that maps simple * XaoS thread API into architecture depended API. diff --git a/src/include/zoom.h b/src/include/zoom.h index 6a7d1891..45f37619 100644 --- a/src/include/zoom.h +++ b/src/include/zoom.h @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/sffe/About b/src/sffe/About index bea04563..9b35b8d8 100644 --- a/src/sffe/About +++ b/src/sffe/About @@ -1,4 +1,4 @@ -SFFE ( Segfautlabs Formula Evaluator ) -sffe is very fast complex math formula evaluator written in C. -you can read more about sffe lib at +SFFE (SegFaultlabs Formula Evaluator) +sffe is very fast complex math formula evaluator written in C. +you can read more about sffe lib at http://www.segfaultlabs.com/projects/sffe diff --git a/src/sffe/gsl_complex_math.c b/src/sffe/gsl_complex_math.c index 4ffbd532..e86f02a5 100644 --- a/src/sffe/gsl_complex_math.c +++ b/src/sffe/gsl_complex_math.c @@ -1,6 +1,6 @@ -/* complex/math.c +/* complex/math.c * - * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Jorma Olavi T�htinen, Brian + * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Jorma Olavi Tähtinen, Brian * Gough * * This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ /* Basic complex arithmetic functions - * Original version by Jorma Olavi T�htinen + * Original version by Jorma Olavi Tähtinen * * Modified for GSL by Brian Gough, 3/2000 */ diff --git a/src/sffe/sffe.cpp b/src/sffe/sffe.cpp index c5becb45..0ddeb847 100644 --- a/src/sffe/sffe.cpp +++ b/src/sffe/sffe.cpp @@ -1,6 +1,6 @@ -/*///////////////////////////////////////////////////////////////////////////////////// -// project : sFFe ( SegFault (or Segmentation Fault :) ) formula evalutor ) -// author : Mateusz Malczak ( mateusz@malczak.info ) +/*///////////////////////////////////////////////////////////////////////////////////// +// project : sFFe ( SegFault (or Segmentation Fault :) ) formula evalautor ) +// author : Mateusz Malczak (mateusz@malczak.info) // wpage : malczak.info /////////////////////////////////////////////////////////////////////////////////////*/ diff --git a/src/sffe/sffe_cmplx_gsl.cpp b/src/sffe/sffe_cmplx_gsl.cpp index 083ea755..4ee5fa7e 100644 --- a/src/sffe/sffe_cmplx_gsl.cpp +++ b/src/sffe/sffe_cmplx_gsl.cpp @@ -1,6 +1,6 @@ -/*///////////////////////////////////////////////////////////////////////////////////// +/*///////////////////////////////////////////////////////////////////////////////////// // project : sFFe ( SegFault (or Segmentation Fault :) ) formula evalutaor ) -// author : Mateusz Malczak ( mateusz@malczak.info ) +// author : Mateusz Malczak (mateusz@malczak.info) // wpage : www.segfaultlabs.com/projects/sffe /////////////////////////////////////////////////////////////////////////////////////// // special build for XaoS, for more info visit diff --git a/src/ui-hlp/ui-hlp.pri b/src/ui-hlp/ui-hlp.pri index 176386d8..eb7c7d94 100644 --- a/src/ui-hlp/ui-hlp.pri +++ b/src/ui-hlp/ui-hlp.pri @@ -1,13 +1,13 @@ -SOURCES += $$PWD/autopilot.cpp \ - $$PWD/menu.cpp \ - $$PWD/ui_helper.cpp \ - $$PWD/play.cpp \ - $$PWD/render.cpp \ - $$PWD/playtext.cpp \ - $$PWD/save.cpp \ - $$PWD/messg.cpp \ - $$PWD/wstack.cpp - -HEADERS += $$PWD/play.h \ - $$PWD/autod.h \ - $$PWD/autopilot.h +SOURCES += $$PWD/autopilot.cpp \ + $$PWD/menu.cpp \ + $$PWD/ui_helper.cpp \ + $$PWD/play.cpp \ + $$PWD/render.cpp \ + $$PWD/playtext.cpp \ + $$PWD/save.cpp \ + $$PWD/messg.cpp \ + $$PWD/wstack.cpp + +HEADERS += $$PWD/play.h \ + $$PWD/autod.h \ + $$PWD/autopilot.h diff --git a/src/ui/customdialog.h b/src/ui/customdialog.h index c9ac2136..908288b5 100644 --- a/src/ui/customdialog.h +++ b/src/ui/customdialog.h @@ -1,40 +1,40 @@ -#ifndef CUSTOMDIALOG_H -#define CUSTOMDIALOG_H - -#include -#include -#include -#include - -#include "ui.h" - -extern QStringList fnames; - -class CustomDialog : public QDialog -{ - Q_OBJECT - private: - struct palette *gradientpal; - uih_context *palcontext; - const menuitem *m_menuitem; - const menudialog *m_dialog; - dialogparam *m_parameters; - QSpinBox *algono, *seedno, *shiftno; - QLabel *img; - QSlider *seedslider, *algoslider, *shiftslider; - unsigned char newColors[][3]; - private slots: - void chooseInputFile(); - void chooseInputFiles(); - void chooseOutputFile(); - void updateVisualiser(); - void colorPicker(); - public: - CustomDialog(struct uih_context *uih, const menuitem *item, - const menudialog *dialog, QWidget *parent = 0); - void accept(); - dialogparam *parameters(); - static QString format(number_t number); -}; - -#endif // CUSTOMDIALOG_H +#ifndef CUSTOMDIALOG_H +#define CUSTOMDIALOG_H + +#include +#include +#include +#include + +#include "ui.h" + +extern QStringList fnames; + +class CustomDialog : public QDialog +{ + Q_OBJECT + private: + struct palette *gradientpal; + uih_context *palcontext; + const menuitem *m_menuitem; + const menudialog *m_dialog; + dialogparam *m_parameters; + QSpinBox *algono, *seedno, *shiftno; + QLabel *img; + QSlider *seedslider, *algoslider, *shiftslider; + unsigned char newColors[][3]; + private slots: + void chooseInputFile(); + void chooseInputFiles(); + void chooseOutputFile(); + void updateVisualiser(); + void colorPicker(); + public: + CustomDialog(struct uih_context *uih, const menuitem *item, + const menudialog *dialog, QWidget *parent = 0); + void accept(); + dialogparam *parameters(); + static QString format(number_t number); +}; + +#endif // CUSTOMDIALOG_H diff --git a/src/ui/fractalwidget.cpp b/src/ui/fractalwidget.cpp index df4f9e59..af0870fc 100644 --- a/src/ui/fractalwidget.cpp +++ b/src/ui/fractalwidget.cpp @@ -1,85 +1,85 @@ -#include "fractalwidget.h" - -#include -#ifdef USE_OPENGL -#include -#endif - -#include "ui.h" -#include "filter.h" - -FractalWidget::FractalWidget() -{ - m_image = NULL; - setMouseTracking(true); - setAutoFillBackground(false); - setAttribute(Qt::WA_OpaquePaintEvent, true); -} - -QPointF FractalWidget::mousePosition() { return m_mousePosition; } - -void FractalWidget::setImage(struct image *image) { m_image = image; } - -QSize FractalWidget::sizeHint() const { return QSize(800, 600); } - -#ifdef USE_OPENGL -void FractalWidget::paintGL() -{ - if (m_image) { - QImage *qimage = - reinterpret_cast(m_image->data)[m_image->currimage]; - // QImage glimage = QGLWidget::convertToOpenGLFormat(*qimage); - // glDrawPixels(glimage.width(), glimage.height(), GL_RGBA, - // GL_UNSIGNED_BYTE, glimage.bits()); +#include "fractalwidget.h" + +#include +#ifdef USE_OPENGL +#include +#endif + +#include "ui.h" +#include "filter.h" + +FractalWidget::FractalWidget() +{ + m_image = NULL; + setMouseTracking(true); + setAutoFillBackground(false); + setAttribute(Qt::WA_OpaquePaintEvent, true); +} + +QPointF FractalWidget::mousePosition() { return m_mousePosition; } + +void FractalWidget::setImage(struct image *image) { m_image = image; } + +QSize FractalWidget::sizeHint() const { return QSize(800, 600); } + +#ifdef USE_OPENGL +void FractalWidget::paintGL() +{ + if (m_image) { + QImage *qimage = + reinterpret_cast(m_image->data)[m_image->currimage]; + // QImage glimage = QGLWidget::convertToOpenGLFormat(*qimage); + // glDrawPixels(glimage.width(), glimage.height(), GL_RGBA, + // GL_UNSIGNED_BYTE, glimage.bits()); // For some reason, Qt 6 requires mirroring the image and using another color space. // The old convertToOpenGLFormat is no longer supported in Qt 6. - QImage mirrored = qimage->mirrored(false, true); - glDrawPixels(qimage->width(), qimage->height(), GL_BGRA_EXT, - GL_UNSIGNED_BYTE, mirrored.bits()); - } -} - -void FractalWidget::resizeGL(int w, int h) -{ - glViewport(0, 0, w, h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, w, 0, h, -1, 1); - glMatrixMode(GL_MODELVIEW); -} -#else -void FractalWidget::paintEvent(QPaintEvent */*event*/) -{ - if (m_image) { - QPainter painter(this); - QImage *qimage = - reinterpret_cast(m_image->data)[m_image->currimage]; - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.drawImage(0, 0, *qimage); - } -} -#endif - -void FractalWidget::mousePressEvent(QMouseEvent *event) -{ - m_mousePosition = event->pos(); - event->ignore(); -} - -void FractalWidget::mouseReleaseEvent(QMouseEvent *event) -{ - m_mousePosition = event->pos(); - event->ignore(); -} - -void FractalWidget::mouseMoveEvent(QMouseEvent *event) -{ - m_mousePosition = event->pos(); - event->ignore(); -} - -void FractalWidget::wheelEvent(QWheelEvent *event) -{ - m_mousePosition = event->position(); - event->ignore(); -} + QImage mirrored = qimage->mirrored(false, true); + glDrawPixels(qimage->width(), qimage->height(), GL_BGRA_EXT, + GL_UNSIGNED_BYTE, mirrored.bits()); + } +} + +void FractalWidget::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, w, 0, h, -1, 1); + glMatrixMode(GL_MODELVIEW); +} +#else +void FractalWidget::paintEvent(QPaintEvent */*event*/) +{ + if (m_image) { + QPainter painter(this); + QImage *qimage = + reinterpret_cast(m_image->data)[m_image->currimage]; + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawImage(0, 0, *qimage); + } +} +#endif + +void FractalWidget::mousePressEvent(QMouseEvent *event) +{ + m_mousePosition = event->pos(); + event->ignore(); +} + +void FractalWidget::mouseReleaseEvent(QMouseEvent *event) +{ + m_mousePosition = event->pos(); + event->ignore(); +} + +void FractalWidget::mouseMoveEvent(QMouseEvent *event) +{ + m_mousePosition = event->pos(); + event->ignore(); +} + +void FractalWidget::wheelEvent(QWheelEvent *event) +{ + m_mousePosition = event->position(); + event->ignore(); +} diff --git a/src/ui/fractalwidget.h b/src/ui/fractalwidget.h index 90ae2ff8..dedc441d 100644 --- a/src/ui/fractalwidget.h +++ b/src/ui/fractalwidget.h @@ -1,42 +1,42 @@ -#ifndef FRACTALWIDGET_H -#define FRACTALWIDGET_H - -#include "config.h" -#include -#ifdef USE_OPENGL -#include -#endif -class QImage; -class QPoint; - -#ifdef USE_OPENGL -class FractalWidget : public QOpenGLWidget -#else -class FractalWidget : public QWidget -#endif -{ - Q_OBJECT - private: - struct image *m_image = NULL; - QSize m_sizeHint; - QPointF m_mousePosition = QPointF(0.0, 0.0); - - protected: - void mouseMoveEvent(QMouseEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void wheelEvent(QWheelEvent *event); -#ifdef USE_OPENGL - void paintGL(); - void resizeGL(int w, int h); -#else - void paintEvent(QPaintEvent *event); -#endif - public: - FractalWidget(); - QSize sizeHint() const; - QPointF mousePosition(); - void setImage(struct image *image); -}; - -#endif // FRACTALWIDGET_H +#ifndef FRACTALWIDGET_H +#define FRACTALWIDGET_H + +#include "config.h" +#include +#ifdef USE_OPENGL +#include +#endif +class QImage; +class QPoint; + +#ifdef USE_OPENGL +class FractalWidget : public QOpenGLWidget +#else +class FractalWidget : public QWidget +#endif +{ + Q_OBJECT + private: + struct image *m_image = NULL; + QSize m_sizeHint; + QPointF m_mousePosition = QPointF(0.0, 0.0); + + protected: + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); +#ifdef USE_OPENGL + void paintGL(); + void resizeGL(int w, int h); +#else + void paintEvent(QPaintEvent *event); +#endif + public: + FractalWidget(); + QSize sizeHint() const; + QPointF mousePosition(); + void setImage(struct image *image); +}; + +#endif // FRACTALWIDGET_H diff --git a/src/ui/image_qt.cpp b/src/ui/image_qt.cpp index 725a5ec2..42b97494 100644 --- a/src/ui/image_qt.cpp +++ b/src/ui/image_qt.cpp @@ -1,217 +1,217 @@ -#include -#include "config.h" -#include "filter.h" -#include "grlib.h" -#include "xio.h" -#include "misc-f.h" - -void rgbtohex (int r, int g, int b, char color[6]) { - QColor rgb(r, g, b); - QString hex = rgb.name(); - hex.remove(0, 1); - strcpy(color, hex.toStdString().c_str()); -} - -void hextorgb (char *hexcolor, rgb_t color) { - QString hexa = hexcolor; - hexa.push_front('#'); - QColor hex(hexa); - QColor rgb = hex.toRgb(); - color[0] = rgb.red(); - color[1] = rgb.green(); - color[2] = rgb.blue(); -} - -static QFont getFont(void *font) { - if (font) - return *reinterpret_cast(font); - else - return QFont(QApplication::font().family(), 12); -} - -int xprint(struct image *image, void *font, int x, int y, - const char *text, int fgcolor, int bgcolor, int mode) -{ - char line[BUFSIZ]; - int pos = strcspn(text, "\n"); - strncpy(line, text, pos); - line[pos] = '\0'; - - QImage *qimage = reinterpret_cast(image->data)[image->currimage]; - QFontMetrics metrics(getFont(font), qimage); - QPainter painter(qimage); - painter.setFont(getFont(font)); - - if (mode == TEXT_PRESSED) { - painter.setPen(fgcolor); - painter.drawText(x + 1, y + 1 + metrics.ascent(), line); - } else { - painter.setPen(bgcolor); - painter.drawText(x + 1, y + 1 + metrics.ascent(), line); - painter.setPen(fgcolor); - painter.drawText(x, y + metrics.ascent(), line); - } - - return strlen(line); -} - -int xtextwidth(struct image */*image*/, void *font, const char *text) -{ - char line[BUFSIZ]; - int pos = strcspn(text, "\n"); - strncpy(line, text, pos); - line[pos] = '\0'; - - QFontMetrics metrics(getFont(font)); - return metrics.horizontalAdvance(line) + 1; -} - -int xtextheight(struct image */*image*/, void *font) -{ - QFontMetrics metrics(getFont(font)); - return metrics.height() + 1; -} - -int xtextcharw(struct image */*image*/, void *font, const char c) -{ - QFontMetrics metrics(getFont(font)); - return metrics.horizontalAdvance(c); -} - -// Saves image as png with xpf chunk data -const char *writepng(xio_constpath filename, const struct image *image, xio_file xpf_data) -{ - QImage *qimage = reinterpret_cast(image->data)[image->currimage]; - if(xpf_data != NULL){ - QString xpf_chunk = xio_getstring(xpf_data); - qimage->setText("Metadata", xpf_chunk); - } - if(!qimage->save(filename)) - return "Invalid file extension"; - return NULL; -} - -// Reads png image and xpf associated data -const char* readpng(xio_constpath filename) -{ - QImageReader reader(filename); - const QImage xaos_image = reader.read(); - QString xpf_chunk = xaos_image.text("Metadata"); - const char *xpf_data = NULL; - if(xpf_chunk != QString() or !xpf_chunk.isEmpty()) - xpf_data = mystrdup(xpf_chunk.toStdString().c_str()); - return xpf_data; -} - -static void freeImage(struct image *img) -{ - free(img); -} - -struct image *create_image_qt(int width, int height, struct palette *palette, - float pixelwidth, float pixelheight) -{ - QImage **data = new QImage *[2]; - data[0] = new QImage(width, height, QImage::Format_RGB32); - data[1] = new QImage(width, height, QImage::Format_RGB32); - struct image *img = create_image_cont( - width, height, data[0]->bytesPerLine(), 2, data[0]->bits(), - data[1]->bits(), palette, NULL, 0, pixelwidth, pixelheight); - if (!img) { - delete data[0]; - delete data[1]; - delete[] data; - return NULL; - } - img->data = data; - img->free = freeImage; - return img; -} - -void overlayGrid(uih_context *c, int fgcolor) -{ - struct image* image = c->image; - QImage *qimage = reinterpret_cast(image->data)[image->currimage]; - QPainter painter(qimage); - QPen pen; - pen.setColor(fgcolor); - pen.setWidth(2); - painter.setPen(pen); - - //Find fractal origin (0,0) - long long int x1 = (0 - c->fcontext->rs.nc) / - (c->fcontext->rs.mc - c->fcontext->rs.nc) * - c->zengine->image->width; - long long int y1 = (0 - c->fcontext->rs.ni) / - (c->fcontext->rs.mi - c->fcontext->rs.ni) * - c->zengine->image->height; - - /* FIXME Support greater zoom*/ - double currzoom = - (c->fcontext->currentformula->v.rr) / (c->fcontext->s.rr); - if(currzoom > 100000){ - uih_error(c, "Cartesian Grid not supported on zoom > 100000x"); - uih_message(c, "Re-enable after zooming out"); - uih_cartesiangrid(c); - } - - // Find next coordinate (1,1) - long long int x2 = (1 - c->fcontext->rs.nc) / - (c->fcontext->rs.mc - c->fcontext->rs.nc) * - c->zengine->image->width; - long long int y2 = (1 - c->fcontext->rs.ni) / - (c->fcontext->rs.mi - c->fcontext->rs.ni) * - c->zengine->image->height; - - // Find current zoom level - long double rr = c->fcontext->s.rr/10.0; - long double counter=0; - while(rr<1){ - rr*=10; - counter++; - } - - // Set step size - long double xinterval = x2-x1; - long double yinterval = y2-y1; - long double xstep = xinterval/pow(10.0, counter - 1); - long double ystep = yinterval/pow(10.0, counter - 1); - - // Do Not draw smaller coordinates if step size is too low - // Draw Boundary Boxes - if(xstep > 1 and ystep > 1){ - for(long double i=x1; i<=image->width; i+=xstep*10){ - painter.drawLine(i, 0, i, image->height); - } - for(long double i=x1; i>=0; i-=xstep*10){ - painter.drawLine(i, 0, i, image->height); - } - for(long double i=y1; i<=image->height; i+=ystep*10){ - painter.drawLine(0, i, image->width, i); - } - for(long double i=y1; i>=0; i-=ystep*10){ - painter.drawLine(0, i, image->width, i); - } - } - - pen.setWidth(1); - pen.setStyle(Qt::DashLine); - painter.setPen(pen); - - // Draw grid boxes - if(xstep > 1 and ystep > 1){ - for(long double i=x1; i<=image->width; i+=xstep){ - painter.drawLine(i, 0, i, image->height); - } - for(long double i=x1; i>=0; i-=xstep){ - painter.drawLine(i, 0, i, image->height); - } - for(long double i=y1; i<=image->height; i+=ystep){ - painter.drawLine(0, i, image->width, i); - } - for(long double i=y1; i>=0; i-=ystep){ - painter.drawLine(0, i, image->width, i); - } - } - return; -} +#include +#include "config.h" +#include "filter.h" +#include "grlib.h" +#include "xio.h" +#include "misc-f.h" + +void rgbtohex (int r, int g, int b, char color[6]) { + QColor rgb(r, g, b); + QString hex = rgb.name(); + hex.remove(0, 1); + strcpy(color, hex.toStdString().c_str()); +} + +void hextorgb (char *hexcolor, rgb_t color) { + QString hexa = hexcolor; + hexa.push_front('#'); + QColor hex(hexa); + QColor rgb = hex.toRgb(); + color[0] = rgb.red(); + color[1] = rgb.green(); + color[2] = rgb.blue(); +} + +static QFont getFont(void *font) { + if (font) + return *reinterpret_cast(font); + else + return QFont(QApplication::font().family(), 12); +} + +int xprint(struct image *image, void *font, int x, int y, + const char *text, int fgcolor, int bgcolor, int mode) +{ + char line[BUFSIZ]; + int pos = strcspn(text, "\n"); + strncpy(line, text, pos); + line[pos] = '\0'; + + QImage *qimage = reinterpret_cast(image->data)[image->currimage]; + QFontMetrics metrics(getFont(font), qimage); + QPainter painter(qimage); + painter.setFont(getFont(font)); + + if (mode == TEXT_PRESSED) { + painter.setPen(fgcolor); + painter.drawText(x + 1, y + 1 + metrics.ascent(), line); + } else { + painter.setPen(bgcolor); + painter.drawText(x + 1, y + 1 + metrics.ascent(), line); + painter.setPen(fgcolor); + painter.drawText(x, y + metrics.ascent(), line); + } + + return strlen(line); +} + +int xtextwidth(struct image */*image*/, void *font, const char *text) +{ + char line[BUFSIZ]; + int pos = strcspn(text, "\n"); + strncpy(line, text, pos); + line[pos] = '\0'; + + QFontMetrics metrics(getFont(font)); + return metrics.horizontalAdvance(line) + 1; +} + +int xtextheight(struct image */*image*/, void *font) +{ + QFontMetrics metrics(getFont(font)); + return metrics.height() + 1; +} + +int xtextcharw(struct image */*image*/, void *font, const char c) +{ + QFontMetrics metrics(getFont(font)); + return metrics.horizontalAdvance(c); +} + +// Saves image as png with xpf chunk data +const char *writepng(xio_constpath filename, const struct image *image, xio_file xpf_data) +{ + QImage *qimage = reinterpret_cast(image->data)[image->currimage]; + if(xpf_data != NULL){ + QString xpf_chunk = xio_getstring(xpf_data); + qimage->setText("Metadata", xpf_chunk); + } + if(!qimage->save(filename)) + return "Invalid file extension"; + return NULL; +} + +// Reads png image and xpf associated data +const char* readpng(xio_constpath filename) +{ + QImageReader reader(filename); + const QImage xaos_image = reader.read(); + QString xpf_chunk = xaos_image.text("Metadata"); + const char *xpf_data = NULL; + if(xpf_chunk != QString() or !xpf_chunk.isEmpty()) + xpf_data = mystrdup(xpf_chunk.toStdString().c_str()); + return xpf_data; +} + +static void freeImage(struct image *img) +{ + free(img); +} + +struct image *create_image_qt(int width, int height, struct palette *palette, + float pixelwidth, float pixelheight) +{ + QImage **data = new QImage *[2]; + data[0] = new QImage(width, height, QImage::Format_RGB32); + data[1] = new QImage(width, height, QImage::Format_RGB32); + struct image *img = create_image_cont( + width, height, data[0]->bytesPerLine(), 2, data[0]->bits(), + data[1]->bits(), palette, NULL, 0, pixelwidth, pixelheight); + if (!img) { + delete data[0]; + delete data[1]; + delete[] data; + return NULL; + } + img->data = data; + img->free = freeImage; + return img; +} + +void overlayGrid(uih_context *c, int fgcolor) +{ + struct image* image = c->image; + QImage *qimage = reinterpret_cast(image->data)[image->currimage]; + QPainter painter(qimage); + QPen pen; + pen.setColor(fgcolor); + pen.setWidth(2); + painter.setPen(pen); + + //Find fractal origin (0,0) + long long int x1 = (0 - c->fcontext->rs.nc) / + (c->fcontext->rs.mc - c->fcontext->rs.nc) * + c->zengine->image->width; + long long int y1 = (0 - c->fcontext->rs.ni) / + (c->fcontext->rs.mi - c->fcontext->rs.ni) * + c->zengine->image->height; + + /* FIXME Support greater zoom*/ + double currzoom = + (c->fcontext->currentformula->v.rr) / (c->fcontext->s.rr); + if(currzoom > 100000){ + uih_error(c, "Cartesian Grid not supported on zoom > 100000x"); + uih_message(c, "Re-enable after zooming out"); + uih_cartesiangrid(c); + } + + // Find next coordinate (1,1) + long long int x2 = (1 - c->fcontext->rs.nc) / + (c->fcontext->rs.mc - c->fcontext->rs.nc) * + c->zengine->image->width; + long long int y2 = (1 - c->fcontext->rs.ni) / + (c->fcontext->rs.mi - c->fcontext->rs.ni) * + c->zengine->image->height; + + // Find current zoom level + long double rr = c->fcontext->s.rr/10.0; + long double counter=0; + while(rr<1){ + rr*=10; + counter++; + } + + // Set step size + long double xinterval = x2-x1; + long double yinterval = y2-y1; + long double xstep = xinterval/pow(10.0, counter - 1); + long double ystep = yinterval/pow(10.0, counter - 1); + + // Do Not draw smaller coordinates if step size is too low + // Draw Boundary Boxes + if(xstep > 1 and ystep > 1){ + for(long double i=x1; i<=image->width; i+=xstep*10){ + painter.drawLine(i, 0, i, image->height); + } + for(long double i=x1; i>=0; i-=xstep*10){ + painter.drawLine(i, 0, i, image->height); + } + for(long double i=y1; i<=image->height; i+=ystep*10){ + painter.drawLine(0, i, image->width, i); + } + for(long double i=y1; i>=0; i-=ystep*10){ + painter.drawLine(0, i, image->width, i); + } + } + + pen.setWidth(1); + pen.setStyle(Qt::DashLine); + painter.setPen(pen); + + // Draw grid boxes + if(xstep > 1 and ystep > 1){ + for(long double i=x1; i<=image->width; i+=xstep){ + painter.drawLine(i, 0, i, image->height); + } + for(long double i=x1; i>=0; i-=xstep){ + painter.drawLine(i, 0, i, image->height); + } + for(long double i=y1; i<=image->height; i+=ystep){ + painter.drawLine(0, i, image->width, i); + } + for(long double i=y1; i>=0; i-=ystep){ + painter.drawLine(0, i, image->width, i); + } + } + return; +} diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 3e214b23..acfdac54 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -1,1591 +1,1591 @@ -#include -#include -#include -#include - -#include "mainwindow.h" -#include "fractalwidget.h" -#include "customdialog.h" - -#include "ui.h" -#include "ui_helper.h" -#include "timers.h" -#include "i18n.h" -#include "xerror.h" -#include "filter.h" -#include "xthread.h" - -#ifdef __EMSCRIPTEN__ -#include -#include -#include -#include -#endif - -void MainWindow::printSpeed() -{ - int c = 0; - int x, y = 0; - int linesize = uih->image->bytesperpixel * uih->image->height; - int size = linesize * uih->image->height; - showStatus("Preparing for speedtest"); - uih->passfunc = NULL; - tl_sleep(1000000); - for (c = 0; c < 5; c++) - widget->repaint(); - QCoreApplication::processEvents(QEventLoop::AllEvents); - showStatus("Measuring display speed"); - tl_sleep(1000000); - tl_update_time(); - tl_reset_timer(maintimer); - c = 0; - while (tl_lookup_timer(maintimer) < 5000000) { - widget->repaint(); - QCoreApplication::processEvents(QEventLoop::AllEvents); - tl_update_time(); - c++; - } - x_message("Driver speed: %g FPS (%.4f MBPS)", c / 5.0, - c * (double)size / 5.0 / 1024 / 1024); - - showStatus("Measuring memcpy speed"); - for (c = 0; c < 5; c++) { - for (x = 0; x < uih->image->height; x++) - memcpy(uih->image->currlines[y], uih->image->oldlines[y], linesize); - } - tl_update_time(); - tl_reset_timer(maintimer); - c = 0; - while (tl_lookup_timer(maintimer) < 5000000) { - for (x = 0; x < uih->image->height; x++) - memcpy(uih->image->currlines[y], uih->image->oldlines[y], linesize); - tl_update_time(), c++; - } - x_message("Memcpy speed: %g FPS (%.4f MBPS)", c / 5.0, - c * (double)size / 5.0 / 1024 / 1024); - - showStatus("Measuring missaligned memcpy speed"); - tl_update_time(); - tl_reset_timer(maintimer); - c = 0; - while (tl_lookup_timer(maintimer) < 5000000) { - for (x = 0; x < uih->image->height; x++) - memcpy(uih->image->currlines[y] + 1, uih->image->oldlines[y] + 2, - linesize - 2); - tl_update_time(), c++; - } - x_message("Missaligned memcpy speed: %g FPS (%.4f MBPS)", c / 5.0, - c * (double)size / 5.0 / 1024 / 1024); - - showStatus("Measuring size6 memcpy speed"); - tl_update_time(); - tl_reset_timer(maintimer); - c = 0; - while (tl_lookup_timer(maintimer) < 5000000) { - int x, y; - for (y = 0; y < uih->image->height; y++) - for (x = 0; x < linesize - 6; x += 6) { - memcpy(uih->image->currlines[y] + x, - uih->image->oldlines[y] + x, 6); - } - tl_update_time(), c++; - } - x_message("Size 6 memcpy speed: %g FPS (%.4f MBPS)", c / 5.0, - c * (double)size / 5.0 / 1024 / 1024); - - widget->repaint(); - showStatus("Measuring calculation speed"); - speed_test(uih->fcontext, uih->image); - showStatus("Measuring new image calculation loop"); - uih_prepare_image(uih); - tl_update_time(); - tl_reset_timer(maintimer); - for (c = 0; c < 5; c++) - uih_newimage(uih), uih->fcontext->version++, uih_prepare_image(uih); - widget->repaint(); - x_message("New image caluclation took %g seconds (%.2g fps)", - tl_lookup_timer(maintimer) / 5.0 / 1000000.0, - 5000000.0 / tl_lookup_timer(maintimer)); - tl_update_time(); - for (c = 0; c < 5; c++) - uih_animate_image(uih), uih_prepare_image(uih), c++; - c = 0; - tl_update_time(); - tl_reset_timer(maintimer); - showStatus("Measuring zooming algorithm loop"); - while (tl_lookup_timer(maintimer) < 5000000) - uih_animate_image(uih), uih_prepare_image(uih), tl_update_time(), c++; - x_message("Approximation loop speed: %g FPS", c / 5.0); - ui_quit(0); -} - -void MainWindow::menuActivate(const menuitem *item, dialogparam *d) -{ - if (item == NULL) - return; - if (item->type == MENU_SUBMENU) { - popupMenu(item->shortname); - return; - } else { - if (menu_havedialog(item, uih) && d == NULL) { - showDialog(item->shortname); - return; - } - if (uih->incalculation && !(item->flags & MENUFLAG_INCALC)) { - menu_addqueue(item, d); - if (item->flags & MENUFLAG_INTERRUPT) - uih_interrupt(uih); - return; - } - if (item->flags & MENUFLAG_CHECKBOX) { - char s[256]; - uih_updatestatus(uih); - widget->repaint(); - if (!menu_enabled(item, uih)) - sprintf(s, TR("Message", "Enabling: %s. "), item->name); - else - sprintf(s, TR("Message", "Disabling: %s. "), item->name); - uih_message(uih, s); - } else - uih_message(uih, item->name); - uih_saveundo(uih); - menu_activate(item, uih, d); - if (d != NULL) - menu_destroydialog(item, d, uih); - } -} - -void MainWindow::processQueue() -{ - const menuitem *item; - dialogparam *d; - if (uih->incalculation) - return; - while ((item = menu_delqueue(&d)) != NULL) { - menuActivate(item, d); - } -} - -int MainWindow::processKey(int key) -{ - int sym = tolower(key); - if (sym == ' ') { - uih->display = 1; - if (uih->play) { - if (uih->incalculation) { - uih_updatestatus(uih); - widget->repaint(); - } else { - uih_skipframe(uih); - showStatus(TR("Message", "Skipping, please wait...")); - } - } - } else { - char mkey[2]; - mkey[0] = key; - mkey[1] = 0; - const menuitem *item; - item = menu_findkey(mkey, uih->menuroot); - if (item == NULL) { - mkey[0] = sym; - item = menu_findkey(mkey, uih->menuroot); - } - if (item != NULL) { - dialogparam *p = NULL; - if (menu_havedialog(item, uih)) { - const menudialog *d = menu_getdialog(uih, item); - int mousex, mousey; - mousex = widget->mousePosition().x(); - mousey = widget->mousePosition().y(); - if (d[0].question != NULL && d[1].question == NULL && - d[0].type == DIALOG_COORD) { - p = (dialogparam *)malloc(sizeof(dialogparam)); - uih_screentofractalcoord(uih, mousex, mousey, p->dcoord, - p->dcoord + 1); - } - } - menuActivate(item, p); - } - } - processQueue(); - return 0; -} - -#define KEYLEFT 1 -#define KEYRIGHT 2 -#define KEYUP 4 -#define KEYDOWN 8 - -bool MainWindow::processArrows(int *counter, const char *text, int speed, - int keys, int lastkeys, int down, int up, - bool tenskip, int min, int max) -{ - static int pid = -1; - bool changed = false; - if (tl_lookup_timer(arrowtimer) > 1000000) - tl_reset_timer(arrowtimer); - if ((keys & up) && !(lastkeys & up)) { - (*counter)++; - tenskip = false; - changed = true; - tl_reset_timer(arrowtimer); - } - if ((keys & down) && !(lastkeys & down)) { - (*counter)--; - tenskip = false; - changed = true; - tl_reset_timer(arrowtimer); - } - while (tl_lookup_timer(arrowtimer) > speed * FRAMETIME) { - tl_slowdown_timer(arrowtimer, speed * FRAMETIME); - if (keys & up) { - if (tenskip && !(*counter % 10)) - (*counter) += 10; - else - (*counter)++; - changed = true; - } - if (keys & down) { - if (tenskip && !(*counter % 10)) - (*counter) -= 10; - else - (*counter)--; - changed = true; - } - } - if (changed) { - if (*counter > max) - *counter = max; - if (*counter < min) - *counter = min; - char str[80]; - sprintf(str, text, *counter); - uih_rmmessage(uih, pid); - pid = uih_message(uih, str); - } - return changed; -} - -#define ROTATESPEEDUP 30 - -void MainWindow::processEvents(bool wait) -{ - char str[80]; - static int spid; - QCoreApplication::processEvents(wait ? QEventLoop::WaitForMoreEvents - : QEventLoop::AllEvents); - static bool dirty = false; - static int lastkey; - static int maxiter; - - int mousex = widget->mousePosition().x(); - int mousey = widget->mousePosition().y(); - int buttons = mouseButtons(); - int key = keyCombination(); - tl_update_time(); - assert(!((key) & ~(KEYLEFT | KEYRIGHT | KEYUP | KEYDOWN)) && - !((buttons) & ~(BUTTON1 | BUTTON2 | BUTTON3))); - uih_update(uih, mousex, mousey, buttons); - if (uih->play) { - processArrows(&uih->letterspersec, - TR("Message", "Letters per second %i "), 2, key, lastkey, - KEYLEFT, KEYRIGHT, false, 1, INT_MAX); - return; - } - if (!uih->cycling) { - if (uih->rotatemode == ROTATE_CONTINUOUS) { - static int rpid; - if (key == KEYRIGHT) - uih->rotationspeed += - ROTATESPEEDUP * tl_lookup_timer(maintimer) / 1000000.0; - else if (key == KEYLEFT) - uih->rotationspeed -= - ROTATESPEEDUP * tl_lookup_timer(maintimer) / 1000000.0; - if (key & (KEYLEFT | KEYRIGHT)) { - uih_rmmessage(uih, rpid); - sprintf( - str, - TR("Message", "Rotation speed:%2.2f degrees per second "), - (float)uih->rotationspeed); - rpid = uih_message(uih, str); - } - tl_reset_timer(maintimer); - } else { - if (!dirty) - maxiter = uih->fcontext->maxiter; - if (processArrows(&maxiter, TR("Message", "Iterations: %i "), 1, - key, lastkey, KEYLEFT, KEYRIGHT, false, 1, - INT_MAX) || - (key & (KEYLEFT | KEYRIGHT))) { - dirty = true; - lastkey = key; - return; - } - } - } - if (dirty) { - if (uih->incalculation) - uih_interrupt(uih); - else { - uih_setmaxiter(uih, maxiter); - dirty = false; - } - } - if (uih->cycling) { - if (processArrows(&uih->cyclingspeed, - TR("Message", "Cycling speed: %i "), 1, key, - lastkey, KEYLEFT, KEYRIGHT, 0, -1000000, INT_MAX)) { - uih_setcycling(uih, uih->cyclingspeed); - } - } - if (tl_lookup_timer(maintimer) > FRAMETIME || buttons) { - double mul1 = tl_lookup_timer(maintimer) / FRAMETIME; - double su = 1 + (SPEEDUP - 1) * mul1; - if (su > 2 * SPEEDUP) - su = SPEEDUP; - tl_reset_timer(maintimer); - if (key & KEYUP) - uih->speedup *= su, uih->maxstep *= su; - else if (key & KEYDOWN) - uih->speedup /= su, uih->maxstep /= su; - if (key & (KEYUP | KEYDOWN)) { - sprintf(str, TR("Message", "speed:%2.2f "), - (double)uih->speedup * (1.0 / STEP)); - uih_rmmessage(uih, spid); - spid = uih_message(uih, str); - } - } - lastkey = key; - return; -} - -struct image *MainWindow::makeImage(int width, int height) -{ - struct palette *palette; - union paletteinfo info; - info.truec.rmask = 0xff0000; - info.truec.gmask = 0x00ff00; - info.truec.bmask = 0x0000ff; - palette = - createpalette(0, 0, TRUECOLOR, 0, 0, NULL, NULL, NULL, NULL, &info); - if (!palette) { - x_error(TR("Error", "Can not create palette")); - x_error(TR("Error", "XaoS is out of memory.")); - ui_quit(-1); - } - struct image *image = - create_image_qt(width, height, palette, pixelwidth, pixelheight); - if (!image) { - x_error(TR("Error", "Can not create image")); - x_error(TR("Error", "XaoS is out of memory.")); - ui_quit(-1); - } - widget->setImage(image); - return image; -} - -void MainWindow::resizeImage(int width, int height) -{ - /* Prevent crash on startup for Mac OS X */ - if (!uih) - return; - - if (uih->incalculation) { - uih_interrupt(uih); - return; - } - uih_clearwindows(uih); - uih_stoptimers(uih); - uih_cycling_stop(uih); - uih_savepalette(uih); - assert(width > 0 && width < 65000 && height > 0 && height < 65000); - if (width != uih->image->width || height != uih->image->height) { - destroy_image(uih->image); - destroypalette(uih->palette); - struct image *image = makeImage(width, height); - if (!uih_updateimage(uih, image)) { - x_error(TR("Error", "Can not allocate tables")); - x_error(TR("Error", "XaoS is out of memory.")); - ui_quit(-1); - } - tl_process_group(syncgroup, NULL); - tl_reset_timer(maintimer); - tl_reset_timer(arrowtimer); - uih_newimage(uih); - } - uih_newimage(uih); - uih_restorepalette(uih); - uih->display = 1; - uih_cycling_continue(uih); -} - -xio_pathdata configfile; - -void MainWindow::eventLoop() -{ - QTimer eventTimer; - eventTimer.setTimerType(Qt::PreciseTimer); - - connect(&eventTimer, &QTimer::timeout, this, [=]() { - int inmovement = 1; - - widget->setCursor(uih->play ? Qt::ForbiddenCursor : Qt::CrossCursor); - - if (uih->display) { - uih_prepare_image(uih); - uih_updatestatus(uih); - widget->repaint(); - showStatus(""); - } - - int time = tl_process_group(syncgroup, nullptr); - if (time != -1) { - if (!inmovement && !uih->inanimation) { - if (time > 1000000 / 50) - time = 1000000 / 50; - if (time > delaytime) { - QThread::usleep(time - delaytime); - tl_update_time(); - } - } - inmovement = 1; - } - - if (delaytime || maxframerate) { - tl_update_time(); - time = tl_lookup_timer(loopt); - tl_reset_timer(loopt); - time = 1000000 / maxframerate - time; - if (time < delaytime) - time = delaytime; - if (time) { - QThread::usleep(time); - tl_update_time(); - } - } - - processQueue(); - processEvents(!inmovement && !uih->inanimation); - inmovement = 0; - - if (shouldResize) { - resizeImage(widget->size().width(), widget->size().height()); - shouldResize = false; - } - }); - - // Start the event timer - eventTimer.start(0); - - // Enter the Qt event loop - QCoreApplication::exec(); -} - -void MainWindow::updateMenus(const char *name) -{ - const struct menuitem *item; - if (name == NULL) { - buildMenu(uih->menuroot); - return; - } - item = menu_findcommand(name); - if (item == NULL) - return; - if (item->flags & (MENUFLAG_CHECKBOX | MENUFLAG_RADIO)) { - toggleMenu(name); - } -} - -void ui_updatemenus(struct uih_context *uih, const char *name) -{ - if (uih->data) { - MainWindow *window = reinterpret_cast(uih->data); - window->updateMenus(name); - } -} - -int MainWindow::showProgress(int display, const char *text, float percent) -{ - char str[80]; - processEvents(false); - if (!uih->play) { - if (uih->display) { - if (nthreads == 1) - uih_drawwindows(uih); - widget->repaint(); - uih_cycling_continue(uih); - display = 1; - } - if (!uih->interruptiblemode && !uih->play) { - if (display) { - if (percent) - sprintf(str, "%s %3.2f%% ", text, (double)percent); - else - sprintf(str, "%s ", text); - showStatus(str); - } - } - } - return 0; -} - -static int ui_passfunc(struct uih_context *uih, int display, const char *text, - float percent) -{ - if (uih->data) { - MainWindow *window = reinterpret_cast(uih->data); - return window->showProgress(display, text, percent); - } - return 0; -} - -void MainWindow::pleaseWait() -{ - char s[100]; - if (uih->play) - return; - widget->setCursor(Qt::WaitCursor); - sprintf(s, TR("Message", "Please wait while calculating %s"), - uih->fcontext->currentformula->name[!uih->fcontext->mandelbrot]); - showStatus(s); -} - -static void ui_message(struct uih_context *uih) -{ - if (uih->data) { - MainWindow *window = reinterpret_cast(uih->data); - window->pleaseWait(); - } -} - -void MainWindow::chooseFont() -{ - QFontDialog *fontDialog = new QFontDialog(this); - QSettings settings; - QFont qfont(settings.value("MainWindow/messageFontFamily").toString(), - settings.value("MainWindow/messageFontSize").toInt()); - fontDialog->setCurrentFont(qfont); - connect(fontDialog, &QFontDialog::fontSelected, - [=](const QFont &messageFont) { - QSettings settings; - settings.setValue("MainWindow/messageFontFamily", messageFont.family()); - settings.setValue("MainWindow/messageFontSize", - messageFont.pointSize()); - uih->font = (void *) &messageFont; - }); - fontDialog->open(); -} - -MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) -{ - menuBarRef = menuBar(); - setWindowTitle(QCoreApplication::applicationName()); - setMouseTracking(true); - - widget = new FractalWidget(); - setCentralWidget(widget); - - readSettings(); - - widget->setCursor(Qt::WaitCursor); - showStatus("Initializing. Please wait."); - show(); - - QScreen *screen = windowHandle()->screen(); - if (!pixelwidth) - pixelwidth = 2.54 / screen->physicalDotsPerInchX(); - if (!pixelheight) - pixelheight = 2.54 / screen->physicalDotsPerInchY(); - - int width = widget->size().width(); - int height = widget->size().height(); - struct image *image = makeImage(width, height); - uih = uih_mkcontext(PIXELSIZE, image, ui_passfunc, ui_message, - ui_updatemenus); - uih->data = this; - uih->font = &messageFont; - buildMenu(uih->menuroot); - uih->fcontext->version++; - uih_newimage(uih); - QSettings settings; - - // Try to load a catalog for the current language and if it doesn't exist, - // default to English. Fixes "No catalog loaded" messages on tutorials - // when using a language XaoS doesn't support - //if (!uih_loadcatalog(uih, QLocale::system().name().left(2).toUtf8())) - if (!uih_loadcatalog(uih, QString(getLanguage()).left(2).toUtf8())) - uih_loadcatalog(uih, "en"); - - tl_update_time(); - maintimer = tl_create_timer(); - arrowtimer = tl_create_timer(); - loopt = tl_create_timer(); - tl_reset_timer(maintimer); - tl_reset_timer(arrowtimer); - - if (getenv("HOME") != NULL) { - char home[256], *env = getenv("HOME"); - int maxsize = - 255 - (int)strlen(CONFIGFILE) - 1; /*Avoid buffer overflow */ - int i; - for (i = 0; i < maxsize && env[i]; i++) - home[i] = env[i]; - home[i] = 0; - xio_addfname(configfile, home, CONFIGFILE); - } else - xio_addfname(configfile, XIO_EMPTYPATH, CONFIGFILE); - xio_file f = xio_ropen(configfile); /*load the configuration file */ - if (f != XIO_FAILED) { - uih_load(uih, f, configfile); - if (uih->errstring) { - x_error("Configuration file %s load failed", configfile); - uih_printmessages(uih); - x_error("Hint: try to remove it"); - ui_quit(1); - } - } - - const menuitem *item; - dialogparam *d; - while ((item = menu_delqueue(&d)) != NULL) { - uih_saveundo(uih); - menu_activate(item, uih, d); - } - - char welcome[80]; - sprintf(welcome, TR("Message", "Welcome to XaoS version %s"), XaoS_VERSION); - uih_message(uih, welcome); - if (printspeed) - printSpeed(); - -#ifdef __EMSCRIPTEN__ - // Obtain a command via URL: - emscripten::val location = emscripten::val::global("location"); - auto href = location["href"].as(); - int q = href.find("?"); - if (q == std::string::npos) { - return; // No command was started with "?", stop and return. - } - auto command = href.substr(q + 1); - if (command.length() == 0) { - return; // No command was given, stop and return. - } - // std::cerr << "command = " << command << "\n"; - - // Manual url_decode: - const char *src = command.c_str(); - char *dst = new char[command.length() + 1]; - char *com = dst; - // Taken from https://stackoverflow.com/questions/2673207/c-c-url-decode-library - char a, b; - while (*src) { - if ((*src == '%') && - ((a = src[1]) && (b = src[2])) && - (isxdigit(a) && isxdigit(b))) { - if (a >= 'a') - a -= 'a'-'A'; - if (a >= 'A') - a -= ('A' - 10); - else - a -= '0'; - if (b >= 'a') - b -= 'a'-'A'; - if (b >= 'A') - b -= ('A' - 10); - else - b -= '0'; - *dst++ = 16*a+b; - src+=3; - } else if (*src == '+') { - *dst++ = ' '; - src++; - } else { - *dst++ = *src++; - } - } - *dst++ = '\0'; - // printf("command = %s\n", com); - uih_loadstr(uih, com); -#endif - -} - -MainWindow::~MainWindow() -{ - uih_cycling_off(uih); - uih_freecatalog(uih); - uih_freecontext(uih); - tl_free_timer(maintimer); - tl_free_timer(arrowtimer); - tl_free_timer(loopt); - // Sometimes the image pointer is set to to 0xFEEEFEEEFEEEFEEE when we get - // here and it crashes without this guard. Not sure why. Possibly - // related to https://sourceforge.net/p/mingw-w64/bugs/727/ - if (uih->image != (image *)0xFEEEFEEEFEEEFEEE) { - destroypalette(uih->image->palette); - destroy_image(uih->image); - } -} - -void MainWindow::readSettings() -{ - QSettings settings; - restoreGeometry(settings.value("MainWindow/geometry").toByteArray()); - restoreState(settings.value("MainWindow/windowState").toByteArray()); - QString fontFamily = settings - .value("MainWindow/messageFontFamily", - QApplication::font().family()) - .toString(); - int fontSize = settings - .value("MainWindow/messageFontSize", - 12) - .toInt(); - messageFont = QFont(fontFamily, fontSize); - -} - -void MainWindow::writeSettings() -{ - QSettings settings; - settings.setValue("MainWindow/geometry", saveGeometry()); - settings.setValue("MainWindow/windowState", saveState()); -} - -void MainWindow::closeEvent(QCloseEvent *) -{ - writeSettings(); - ui_quit(0); -} - -QKeySequence::StandardKey MainWindow::keyForItem(const QString &name) -{ - if (name == "initstate") - return QKeySequence::New; - if (name == "loadpos") - return QKeySequence::Open; - if (name == "savepos") - return QKeySequence::Save; - if (name == "quit") - return QKeySequence::Quit; - if (name == "undo") - return QKeySequence::Undo; - if (name == "redo") - return QKeySequence::Redo; - if (name == "fullscreen" || name == "fullscreena") - return QKeySequence::FullScreen; - if (name == "interrupt") - return QKeySequence::Cancel; - if (name == "recalculate") - return QKeySequence::Refresh; - if (name == "help") - return QKeySequence::HelpContents; - if (name == "copyurl") - return QKeySequence::Copy; - if (name == "saveimg") - return QKeySequence::SaveAs; - if (name == "fractalinfo") - return QKeySequence::WhatsThis; - if (name == "autopilot") - return QKeySequence::ZoomIn; - - return QKeySequence::UnknownKey; -} - -void MainWindow::buildMenu(const char *name) -{ - menuBarRef->clear(); - foreach (QAction *action, actions()) - removeAction(action); - - const menuitem *item; - for (int i = 0; (item = menu_item(name, i)) != NULL; i++) { - if (item->type == MENU_SUBMENU) { - QMenu *menu = menuBarRef->addMenu(QString(item->name)); - buildMenu(item->shortname, menu, false); - } - } -} - -void MainWindow::buildMenu(const char *name, QMenu *parent, bool numbered) -{ - QActionGroup *group = 0; - - connect(parent, SIGNAL(aboutToShow()), SLOT(updateMenuCheckmarks())); - - const menuitem *item; - for (int i = 0, n = 0; (item = menu_item(name, i)) != NULL; i++) { - - QString itemName(item->name); - if (numbered) { - char c; - if (n < 9) - c = n + '1'; - else if (n == 9) - c = '0'; - else - c = 'A' + n - 10; - itemName = QString::asprintf("&%c ", c) + itemName; - - if (item->type != MENU_SEPARATOR) - n++; - } - - if (item->type == MENU_DIALOG || item->type == MENU_CUSTOMDIALOG) - itemName += "..."; - - if (item->type == MENU_SEPARATOR) { - parent->addSeparator(); - } else if (item->type == MENU_SUBMENU) { - QMenu *menu = parent->addMenu(itemName); - buildMenu(item->shortname, menu, numbered); - } else { - QAction *action = new QAction(itemName, parent); - action->setShortcuts(keyForItem(item->shortname)); - action->setObjectName(item->shortname); - if (item->flags & (MENUFLAG_RADIO | MENUFLAG_CHECKBOX)) { - action->setCheckable(true); - action->setChecked(menu_enabled(item, uih)); - if (item->flags & MENUFLAG_RADIO) { - if (!group) - group = new QActionGroup(parent); - action->setActionGroup(group); - } - } - connect(action, SIGNAL(triggered()), this, - SLOT(activateMenuItem())); - parent->addAction(action); - if (action->shortcut() != QKeySequence::UnknownKey) - addAction( - action); // so that shortcuts work when menubar is hidden - } - } -} - -void MainWindow::popupMenu(const char *name) -{ - QMenu *menu = new QMenu(this); - buildMenu(name, menu, true); - menu->exec(QCursor::pos()); - delete menu; -} - -void MainWindow::toggleMenu(const char *name) -{ - const menuitem *item = menu_findcommand(name); - QAction *action = menuBarRef->findChild(name); - if (action) - action->setChecked(menu_enabled(item, uih)); -} - -void MainWindow::activateMenuItem() -{ - QAction *action = qobject_cast(sender()); - const menuitem *item = menu_findcommand(action->objectName().toUtf8()); - menuActivate(item, NULL); -} - -void MainWindow::updateMenuCheckmarks() -{ - QMenu *menu = qobject_cast(sender()); - foreach (QAction *action, menu->actions()) { - if (action->isCheckable()) { - const menuitem *item = - menu_findcommand(action->objectName().toUtf8()); - action->setChecked(menu_enabled(item, uih)); - } - } -} - -struct palette *gradientpal; QSpinBox *seedno, *algono, *shiftno; QLabel *img; - -void MainWindow::updateVisualiser() -{ - // Get updated Colors - int colors[101][3]; - getPaletteColor(gradientpal, seedno->value(), - algono->value()-1 < 0? 0:algono->value()-1, shiftno->value(), colors); - - // Load Curve - QImage palImage(100, 1, QImage::Format_RGB32); - - // Fill Curve - for(int i=0;i<100;i++) { - QRgb value = qRgb(colors[i][0], colors[i][1], colors[i][2]); - palImage.setPixelColor(i, 0, value); - } - - // Save Result - QPixmap newImage = QPixmap::fromImage(palImage.scaled(algono->width(), - algono->height())); - img->setPixmap(newImage); -} - -unsigned char newColors[32][3]; - -void MainWindow::colorPicker() -{ - QPushButton* button = qobject_cast(sender()); - int idx = button->objectName().toInt(); - QColorDialog* qColorDialog = new QColorDialog(this); - QColor currentColor(newColors[idx][0], newColors[idx][1], newColors[idx][2]); - qColorDialog->setCurrentColor(currentColor); - qColorDialog->setModal(false); - connect(qColorDialog, &QColorDialog::colorSelected, qColorDialog, - [=](const QColor &color) { - QPalette pal = button->palette(); - button->setAutoFillBackground(true); - pal.setColor(QPalette::Button, color); - button->setPalette(pal); - button->update(); - newColors[idx][0] = color.red(); - newColors[idx][1] = color.green(); - newColors[idx][2] = color.blue(); - }); - qColorDialog->open(); -} - -void MainWindow::showDialog(const char *name) -{ - const menuitem *item = menu_findcommand(name); - if (!item) - return; - - const menudialog *dialog = menu_getdialog(uih, item); - if (!dialog) - return; - - int nitems; - for (nitems = 0; dialog[nitems].question; nitems++) - ; - - if (nitems == 1 && - (dialog[0].type == DIALOG_IFILE || dialog[0].type == DIALOG_OFILE)) { - QString filter = - QString("*.%1").arg(QFileInfo(dialog[0].defstr).completeSuffix()); - QSettings settings; - QString fileLocation = - settings.value("MainWindow/lastFileLocation", QDir::homePath()) - .toString(); - if (dialog[0].type == DIALOG_IFILE) { - // fileName = QFileDialog::getOpenFileName(this, item->name, fileLocation, filter); - QFileDialog *qFileDialog = new QFileDialog(this); - // qFileDialog->setWindowTitle(dialog->question); - qFileDialog->setWindowTitle(item->name); - qFileDialog->setDirectory(fileLocation); - qFileDialog->setNameFilter(filter); - connect(qFileDialog, &QFileDialog::fileSelected, - [=](const QString &value) { - QString fileName = value; - if (!fileName.isNull()) { - QString ext = "." + QFileInfo(dialog[0].defstr).suffix(); - - if (!fileName.endsWith(".xpf") and !fileName.endsWith(".png") - and !fileName.endsWith(ext)) - fileName += ext; - - dialogparam *param = (dialogparam *)malloc(sizeof(dialogparam)); - param->dstring = strdup(fileName.toUtf8()); - menuActivate(item, param); - QSettings settings; - settings.setValue("MainWindow/lastFileLocation", - QFileInfo(fileName).absolutePath()); - } - }); - qFileDialog->open(); - } - else if (dialog[0].type == DIALOG_OFILE) { - char defname[256]; - strcpy(defname, - QDir(fileLocation).filePath(dialog[0].defstr).toUtf8()); - char *split = strchr(defname, '*'); - *split = 0; - strcpy(defname, xio_getfilename(defname, split + 1)); - // fileName = QFileDialog::getSaveFileName(this, item->name, defname, filter); - QFileDialog *qFileDialog = new QFileDialog(this); - qFileDialog->setWindowTitle(item->name); - qFileDialog->setDirectory(fileLocation); - qFileDialog->setNameFilter(filter); - qFileDialog->setAcceptMode(QFileDialog::AcceptSave); - connect(qFileDialog, &QFileDialog::fileSelected, - [=](const QString &value) { - QString fileName = value; - if (!fileName.isNull()) { - QString ext = "." + QFileInfo(dialog[0].defstr).suffix(); - - if (!fileName.endsWith(".xpf") and !fileName.endsWith(".png") - and !fileName.endsWith(ext)) - fileName += ext; - - dialogparam *param = (dialogparam *)malloc(sizeof(dialogparam)); - param->dstring = strdup(fileName.toUtf8()); - menuActivate(item, param); - QSettings settings; - settings.setValue("MainWindow/lastFileLocation", - QFileInfo(fileName).absolutePath()); - } - }); - qFileDialog->open(); - } - } else { - - dialogparam *param = (dialogparam *)malloc(sizeof(dialogparam)); - - switch (dialog->type) { - case DIALOG_INT: - case DIALOG_FLOAT: - case DIALOG_STRING: - case DIALOG_KEYSTRING: - { - QInputDialog *qInputDialog = new QInputDialog(this); - qInputDialog->setLabelText(dialog->question); - qInputDialog->setWindowTitle(item->name); - switch (dialog->type) { - case DIALOG_INT: - { - qInputDialog->setIntMaximum(1000000); - qInputDialog->setIntValue(dialog->defint); - connect(qInputDialog, &QInputDialog::intValueSelected, qInputDialog, - [=](const unsigned long int &value) { - param->dint = value; - menuActivate(item, param); - }); - break; - } - case DIALOG_FLOAT: - { - qInputDialog->setDoubleMaximum(1000000); - qInputDialog->setDoubleValue(dialog->deffloat); - connect(qInputDialog, &QInputDialog::doubleValueSelected, qInputDialog, - [=](const double &value) { - param->number = value; - menuActivate(item, param); - }); - break; - } - case DIALOG_STRING: - { - qInputDialog->setTextValue(dialog->defstr); - connect(qInputDialog, &QInputDialog::textValueSelected, qInputDialog, - [=](const QString &text) { - param->dstring = strdup((char *) text.toStdString().c_str()); - menuActivate(item, param); - }); - break; - } - case DIALOG_KEYSTRING: - { - qInputDialog->setTextValue(dialog->defstr); - connect(qInputDialog, &QInputDialog::textValueSelected, qInputDialog, - [=](const QString &text) { - param->dstring = strdup((char *) text.toStdString().c_str()); - menuActivate(item, param); - }); - break; - } - } - qInputDialog->open(); - break; - } - case DIALOG_COORD: - { - QDialog *qDialog = new QDialog(this); - qDialog->setWindowTitle(item->name); - QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); - QFormLayout *formLayout = new QFormLayout(); - QString label(dialog->question); - QLineEdit *real = new QLineEdit(CustomDialog::format(dialog->deffloat), qDialog); - QFontMetrics metric(real->font()); - real->setMinimumWidth(metric.horizontalAdvance(real->text()) * 1.1); - real->setObjectName("real"); - QLineEdit *imag = new QLineEdit(CustomDialog::format(dialog->deffloat2), qDialog); - imag->setObjectName("imag"); - imag->setMinimumWidth(metric.horizontalAdvance(imag->text()) * 1.1); - // imag->setValidator(new QDoubleValidator(imag)); - QBoxLayout *layout = new QBoxLayout(QBoxLayout::LeftToRight); - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(real); - layout->addWidget(new QLabel("+", qDialog)); - layout->addWidget(imag); - layout->addWidget(new QLabel("i", qDialog)); - formLayout->addRow(label, layout); - dialogLayout->addLayout(formLayout); - QDialogButtonBox *buttonBox = - new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), - Qt::Horizontal, qDialog); - connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); - connect(real, SIGNAL(textEdited(QString)), qDialog, SLOT(update())); - dialogLayout->addWidget(buttonBox); - qDialog->setLayout(dialogLayout); - connect(qDialog, &QDialog::accepted, qDialog, - [=](void){ - QLineEdit *real = qDialog->findChild("real"); - param->dcoord[0] = real->text().toDouble(); - QLineEdit *imag = qDialog->findChild("imag"); - param->dcoord[1] = imag->text().toDouble(); - menuActivate(item, param); - }); - qDialog->adjustSize(); // this is sometimes too high in WASM, FIXME, maybe Qt6 bug? - qDialog->open(); - break; - } - case DIALOG_PALSLIDER: - { - QDialog *qDialog = new QDialog(this); - qDialog->setWindowTitle(item->name); - QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); - gradientpal = clonepalette(uih->image->palette); - uih_context *palcontext; - palcontext = uih; - // 3 inputs decide color, Algorithm Number, Seed and shift - // For Algorithm number - QSlider *seedslider, *algoslider, *shiftslider; - algono = new QSpinBox(this); - QString label(dialog->question); - algono->setObjectName(label + "algono"); - algono->setValue(palcontext->palettetype); - algono->setRange(1, 3); - - // Algo Slider - algoslider = new QSlider(Qt::Horizontal, qDialog); - algoslider->setObjectName(label + "-algono"); - algoslider->setRange(1, PALGORITHMS); - algoslider->setValue(algono->value()); - // algoslider->setMinimumWidth(this->width()*2); - - // For Seed Number - seedno = new QSpinBox(qDialog); - seedno->setObjectName(label + "seedno"); - seedno->setRange(0, gradientpal->size); - seedno->setValue(palcontext->paletteseed); - - // Seed Slider - seedslider = new QSlider(Qt::Horizontal, qDialog); - seedslider->setObjectName(label + "-seedno"); - seedslider->setRange(0, gradientpal->size); - seedslider->setValue(seedno->value()); - - // For Shift Number - shiftno = new QSpinBox(this); - shiftno->setObjectName(label + "shiftno"); - shiftno->setRange(0, gradientpal->size); - shiftno->setValue(palcontext->paletteshift + palcontext->manualpaletteshift); - - // Shift Slider - shiftslider = new QSlider(Qt::Horizontal, qDialog); - shiftslider->setObjectName(label + "-shiftno"); - shiftslider->setRange(0, gradientpal->size); - shiftslider->setValue(shiftno->value()); - - // Add them to Layout - QFormLayout *formLayout = new QFormLayout(); - formLayout->addRow("Algorithm", algono); - formLayout->addWidget(algoslider); - formLayout->addRow("Seed", seedno); - formLayout->addWidget(seedslider); - formLayout->addRow("Shift", shiftno); - formLayout->addWidget(shiftslider); - - img = new QLabel(qDialog); - img->setScaledContents(true); - formLayout->addRow(img); - updateVisualiser(); - - connect(algono,SIGNAL(valueChanged(int)), algoslider, SLOT(setValue(int))); - connect(algoslider, SIGNAL(valueChanged(int)), algono, SLOT(setValue(int))); - connect(algono, SIGNAL(valueChanged(int)), this, SLOT(updateVisualiser())); - connect(seedno,SIGNAL(valueChanged(int)), seedslider, SLOT(setValue(int))); - connect(seedslider, SIGNAL(valueChanged(int)), seedno, SLOT(setValue(int))); - connect(seedno, SIGNAL(valueChanged(int)), this, SLOT(updateVisualiser())); - connect(shiftno,SIGNAL(valueChanged(int)), shiftslider, SLOT(setValue(int))); - connect(shiftslider, SIGNAL(valueChanged(int)), shiftno, SLOT(setValue(int))); - connect(shiftno, SIGNAL(valueChanged(int)), this, SLOT(updateVisualiser())); - - dialogLayout->addLayout(formLayout); - QDialogButtonBox *buttonBox = - new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), - Qt::Horizontal, qDialog); - - connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); - - dialogLayout->addWidget(buttonBox); - qDialog->setLayout(dialogLayout); - - connect(qDialog, &QDialog::accepted, qDialog, - [=](void){ - QSlider *algo = qDialog->findChild(label + "-algono"); - palcontext->palettetype = algo->sliderPosition(); - palcontext->manualpaletteshift = 0; - QSlider *seed = qDialog->findChild(label + "-seedno"); - palcontext->paletteseed = seed->sliderPosition(); - QSlider *shift = qDialog->findChild(label + "-shiftno"); - palcontext->paletteshift = shift->sliderPosition(); - param->dint = 1; - menuActivate(item, param); - destroypalette(gradientpal); - }); - qDialog->open(); - break; - } - case DIALOG_PALPICKER: - { - QDialog *qDialog = new QDialog(this); - qDialog->setWindowTitle(item->name); - QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); - - uih_context *palcontext; - palcontext = uih; - getDEFSEGMENTColor(newColors); - - QList< QPushButton* > buttons; - QBoxLayout *layout1 = new QBoxLayout(QBoxLayout::LeftToRight); - QBoxLayout *layout2 = new QBoxLayout(QBoxLayout::LeftToRight); - QBoxLayout *layout3 = new QBoxLayout(QBoxLayout::LeftToRight); - for(auto bidx = 0; bidx < 31; ++bidx ) { - auto button = new QPushButton{ QString::number(bidx) }; - button->setObjectName(QString::number(bidx)); - QColor color(newColors[bidx][0], newColors[bidx][1], newColors[bidx][2]); - QPalette pal = button->palette(); - button->setAutoFillBackground(true); - pal.setColor(QPalette::Button, color); - button->setPalette(pal); - button->update(); - buttons << button; - if(bidx <= 10) - layout1->addWidget(button); - else if(bidx>10 and bidx <= 20) - layout2->addWidget(button); - else - layout3->addWidget(button); - - connect(button, SIGNAL(clicked()), this, SLOT(colorPicker())); - } - QFormLayout *formLayout = new QFormLayout(); - formLayout->addRow(layout1); - formLayout->addRow(layout2); - formLayout->addRow(layout3); - dialogLayout->addLayout(formLayout); - QDialogButtonBox *buttonBox = - new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), - Qt::Horizontal, qDialog); - - connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); - - dialogLayout->addWidget(buttonBox); - qDialog->setLayout(dialogLayout); - - connect(qDialog, &QDialog::accepted, qDialog, - [=](void){ - mkcustompalette(palcontext->image->palette, newColors); - menuActivate(item, param); - }); - qDialog->open(); - break; - } - case DIALOG_LIST: // This is used only in Formulas/UserFormulas - { - QDialog *qDialog = new QDialog(this); - qDialog->setWindowTitle(item->name); - QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); - - QComboBox *list = new QComboBox(this); - QString label(dialog->question); - list->setObjectName(label); - list->setEditable(true); - list->addItem(dialog->defstr); - list->setObjectName(label + "-data"); - - QSettings settings; - QStringList formulas = settings.value("Formulas/UserFormulas").toStringList(); - - for (int j = 0; j < formulas.count(); j++) { - bool found = false; - for (int i = 0; i < list->count(); i++) { - if (QString::compare(list->itemText(i), formulas[j], Qt::CaseSensitive) == 0) { - found = true; - } - } - if (!found) - list->addItem(formulas[j]); - } - - // list->addItems(formulas); - - QFormLayout *formLayout = new QFormLayout(); - formLayout->addRow(label, list); - dialogLayout->addLayout(formLayout); - - QDialogButtonBox *buttonBox = - new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), - Qt::Horizontal, qDialog); - - connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); - dialogLayout->addWidget(buttonBox); - qDialog->setLayout(dialogLayout); - qDialog->adjustSize(); // this is sometimes too high in WASM, FIXME, maybe Qt6 bug? - - connect(qDialog, &QDialog::accepted, qDialog, - [=](void){ - QComboBox *selected = qDialog->findChild(label + "-data"); - param->dstring = strdup(selected->currentText().toUtf8()); - menuActivate(item, param); - }); - qDialog->open(); - break; - } - case DIALOG_CHOICE: - { - QDialog *qDialog = new QDialog(this); - qDialog->setWindowTitle(item->name); - QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); - - QComboBox *combo = new QComboBox(this); - QString label(dialog->question); - combo->setObjectName(label); - - const char **str = (const char **)dialog->defstr; - for (int j = 0; str[j] != NULL; j++) - combo->addItem(str[j]); - combo->setCurrentIndex(dialog->defint); - QFormLayout *formLayout = new QFormLayout(); - formLayout->addRow(label, combo); - dialogLayout->addLayout(formLayout); - - QDialogButtonBox *buttonBox = - new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), - Qt::Horizontal, qDialog); - - connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); - dialogLayout->addWidget(buttonBox); - qDialog->setLayout(dialogLayout); - qDialog->adjustSize(); // this is sometimes too high in WASM, FIXME, maybe Qt6 bug? - - connect(qDialog, &QDialog::accepted, qDialog, - [=](void){ - QComboBox *selected = qDialog->findChild(label); - param->dint = selected->currentIndex(); - menuActivate(item, param); - }); - qDialog->open(); - break; - } - default: - { - CustomDialog customDialog(uih, item, dialog, this); - if (customDialog.exec() == QDialog::Accepted) - menuActivate(item, customDialog.parameters()); - } - } - } -} - -#ifdef __wasm -#define STATUS_VIA_STDOUT -//#define STATUS_VIA_PROGRESSBAR -#else -#define STATUS_VIA_PROGRESSBAR -// #define STATUS_VIA_WINDOWTITLE -#endif - -QProgressDialog *qProgressDialog; -int progress = 0; -void MainWindow::showStatus(const char *text) -{ -// This is not working properly, maybe because of a missing QTimer event/setting. -#ifdef STATUS_VIA_UIH_MESSAGE - if (uih != NULL) { - uih_message(uih, text); - uih_updatestatus(uih); - } -#endif - -#ifdef STATUS_VIA_WINDOWTITLE - if (strlen(text)) - setWindowTitle( - QCoreApplication::applicationName().append(" - ").append(text)); - else - setWindowTitle(QCoreApplication::applicationName()); -#endif - -#ifdef STATUS_VIA_STDOUT - std::cout << "STATUS: " << text << "\n"; -#endif - -// This feature is experimental. It works natively but not in WASM. -#ifdef STATUS_VIA_PROGRESSBAR - bool newProgress = (qProgressDialog == NULL); - if (QString(text) == "") { - if (!newProgress) { - qProgressDialog->close(); - progress = 0; - return; - } - } - - if (newProgress) { - qProgressDialog = new QProgressDialog(this); - } else { - qProgressDialog->setValue(progress); - qProgressDialog->setMinimumDuration(0); - QString t = QString(text).trimmed(); - if (t.endsWith("%")) { - progress = t.right(6).left(5).toDouble(); // save the percentage - // std::cout << "t=" << t.toStdString() << " progress=" << progress << "\n"; - t = t.left(t.length()-6); // remove the percentage - } - - qProgressDialog->setCancelButton(NULL); - qProgressDialog->setWindowTitle(t); - if (progress < 100) { - progress++; - } - else { - progress=0; - } - } - - if (newProgress) { - qProgressDialog->show(); - } -#endif -} - -int MainWindow::mouseButtons() -{ - int mouseButtons = 0; - if (m_keyboardModifiers & Qt::ShiftModifier) { - // Shift key makes left and right buttons emulate middle button - if (m_mouseButtons & (Qt::LeftButton | Qt::RightButton)) - mouseButtons |= BUTTON2; - } else { - // Otherwise, mouse buttons map normally - if (m_mouseButtons & Qt::LeftButton) - mouseButtons |= BUTTON1; - if (m_mouseButtons & Qt::MiddleButton) - mouseButtons |= BUTTON2; - if (m_mouseButtons & Qt::RightButton) - mouseButtons |= BUTTON3; - } - // handle mouse wheel operations - if (m_mouseWheel > 0) - mouseButtons |= BUTTON1; - if (m_mouseWheel < 0) - mouseButtons |= BUTTON3; - if (m_mouseWheel != 0) { - timespec timenow; - clock_gettime(CLOCK_REALTIME, &timenow); - long elapsed = timenow.tv_sec * 1.0e9 + timenow.tv_nsec - - wheeltimer.tv_sec * 1.0e9 - wheeltimer.tv_nsec; - if (elapsed > 1.0e9) // timing is hardcoded here - m_mouseWheel = 0; - } - return mouseButtons; -} - -int MainWindow::keyCombination() { return m_keyCombination; } - -void MainWindow::mousePressEvent(QMouseEvent *event) -{ - m_mouseButtons = event->buttons(); -} - -void MainWindow::mouseReleaseEvent(QMouseEvent *event) -{ - m_mouseButtons = event->buttons(); -} - -void MainWindow::wheelEvent(QWheelEvent *event) -{ - m_mouseWheel = event->angleDelta().y(); - clock_gettime(CLOCK_REALTIME, &wheeltimer); -} - -void MainWindow::keyPressEvent(QKeyEvent *event) -{ - m_keyboardModifiers = event->modifiers(); - - switch (event->key()) { - case Qt::Key_Left: - m_keyCombination |= KEYLEFT; - break; - case Qt::Key_Right: - m_keyCombination |= KEYRIGHT; - break; - case Qt::Key_Up: - m_keyCombination |= KEYUP; - break; - case Qt::Key_Down: - m_keyCombination |= KEYDOWN; - break; - default: - if (!event->text().isEmpty()) - processKey(event->text().toUtf8()[0]); - else - event->ignore(); - } -} - -void MainWindow::keyReleaseEvent(QKeyEvent *event) -{ - m_keyboardModifiers = event->modifiers(); - - switch (event->key()) { - case Qt::Key_Left: - m_keyCombination &= ~KEYLEFT; - break; - case Qt::Key_Right: - m_keyCombination &= ~KEYRIGHT; - break; - case Qt::Key_Up: - m_keyCombination &= ~KEYUP; - break; - case Qt::Key_Down: - m_keyCombination &= ~KEYDOWN; - break; - default: - event->ignore(); - } -} - -#ifndef Q_OS_MACOS -#ifndef USE_OPENGL - -void MainWindow::showFullScreen() -{ - menuBarRef->setParent(centralWidget()); - QMainWindow::showFullScreen(); -} - -void MainWindow::showNormal() -{ - setMenuBar(menuBarRef); - menuBarRef->show(); - QMainWindow::showNormal(); -} - -void MainWindow::mouseMoveEvent(QMouseEvent *event) -{ - if (isFullScreen()) { - if (event->pos().y() < menuBarRef->sizeHint().height()) - menuBarRef->show(); - else - menuBarRef->hide(); - } -} -#endif -#endif - -void MainWindow::resizeEvent(QResizeEvent * /*event*/) -{ -#ifndef Q_OS_MACOS -#ifndef USE_OPENGL - if (isFullScreen()) - menuBarRef->resize(size().width(), menuBarRef->sizeHint().height()); -#endif -#endif - shouldResize = true; -} +#include +#include +#include +#include + +#include "mainwindow.h" +#include "fractalwidget.h" +#include "customdialog.h" + +#include "ui.h" +#include "ui_helper.h" +#include "timers.h" +#include "i18n.h" +#include "xerror.h" +#include "filter.h" +#include "xthread.h" + +#ifdef __EMSCRIPTEN__ +#include +#include +#include +#include +#endif + +void MainWindow::printSpeed() +{ + int c = 0; + int x, y = 0; + int linesize = uih->image->bytesperpixel * uih->image->height; + int size = linesize * uih->image->height; + showStatus("Preparing for speedtest"); + uih->passfunc = NULL; + tl_sleep(1000000); + for (c = 0; c < 5; c++) + widget->repaint(); + QCoreApplication::processEvents(QEventLoop::AllEvents); + showStatus("Measuring display speed"); + tl_sleep(1000000); + tl_update_time(); + tl_reset_timer(maintimer); + c = 0; + while (tl_lookup_timer(maintimer) < 5000000) { + widget->repaint(); + QCoreApplication::processEvents(QEventLoop::AllEvents); + tl_update_time(); + c++; + } + x_message("Driver speed: %g FPS (%.4f MBPS)", c / 5.0, + c * (double)size / 5.0 / 1024 / 1024); + + showStatus("Measuring memcpy speed"); + for (c = 0; c < 5; c++) { + for (x = 0; x < uih->image->height; x++) + memcpy(uih->image->currlines[y], uih->image->oldlines[y], linesize); + } + tl_update_time(); + tl_reset_timer(maintimer); + c = 0; + while (tl_lookup_timer(maintimer) < 5000000) { + for (x = 0; x < uih->image->height; x++) + memcpy(uih->image->currlines[y], uih->image->oldlines[y], linesize); + tl_update_time(), c++; + } + x_message("Memcpy speed: %g FPS (%.4f MBPS)", c / 5.0, + c * (double)size / 5.0 / 1024 / 1024); + + showStatus("Measuring missaligned memcpy speed"); + tl_update_time(); + tl_reset_timer(maintimer); + c = 0; + while (tl_lookup_timer(maintimer) < 5000000) { + for (x = 0; x < uih->image->height; x++) + memcpy(uih->image->currlines[y] + 1, uih->image->oldlines[y] + 2, + linesize - 2); + tl_update_time(), c++; + } + x_message("Missaligned memcpy speed: %g FPS (%.4f MBPS)", c / 5.0, + c * (double)size / 5.0 / 1024 / 1024); + + showStatus("Measuring size6 memcpy speed"); + tl_update_time(); + tl_reset_timer(maintimer); + c = 0; + while (tl_lookup_timer(maintimer) < 5000000) { + int x, y; + for (y = 0; y < uih->image->height; y++) + for (x = 0; x < linesize - 6; x += 6) { + memcpy(uih->image->currlines[y] + x, + uih->image->oldlines[y] + x, 6); + } + tl_update_time(), c++; + } + x_message("Size 6 memcpy speed: %g FPS (%.4f MBPS)", c / 5.0, + c * (double)size / 5.0 / 1024 / 1024); + + widget->repaint(); + showStatus("Measuring calculation speed"); + speed_test(uih->fcontext, uih->image); + showStatus("Measuring new image calculation loop"); + uih_prepare_image(uih); + tl_update_time(); + tl_reset_timer(maintimer); + for (c = 0; c < 5; c++) + uih_newimage(uih), uih->fcontext->version++, uih_prepare_image(uih); + widget->repaint(); + x_message("New image caluclation took %g seconds (%.2g fps)", + tl_lookup_timer(maintimer) / 5.0 / 1000000.0, + 5000000.0 / tl_lookup_timer(maintimer)); + tl_update_time(); + for (c = 0; c < 5; c++) + uih_animate_image(uih), uih_prepare_image(uih), c++; + c = 0; + tl_update_time(); + tl_reset_timer(maintimer); + showStatus("Measuring zooming algorithm loop"); + while (tl_lookup_timer(maintimer) < 5000000) + uih_animate_image(uih), uih_prepare_image(uih), tl_update_time(), c++; + x_message("Approximation loop speed: %g FPS", c / 5.0); + ui_quit(0); +} + +void MainWindow::menuActivate(const menuitem *item, dialogparam *d) +{ + if (item == NULL) + return; + if (item->type == MENU_SUBMENU) { + popupMenu(item->shortname); + return; + } else { + if (menu_havedialog(item, uih) && d == NULL) { + showDialog(item->shortname); + return; + } + if (uih->incalculation && !(item->flags & MENUFLAG_INCALC)) { + menu_addqueue(item, d); + if (item->flags & MENUFLAG_INTERRUPT) + uih_interrupt(uih); + return; + } + if (item->flags & MENUFLAG_CHECKBOX) { + char s[256]; + uih_updatestatus(uih); + widget->repaint(); + if (!menu_enabled(item, uih)) + sprintf(s, TR("Message", "Enabling: %s. "), item->name); + else + sprintf(s, TR("Message", "Disabling: %s. "), item->name); + uih_message(uih, s); + } else + uih_message(uih, item->name); + uih_saveundo(uih); + menu_activate(item, uih, d); + if (d != NULL) + menu_destroydialog(item, d, uih); + } +} + +void MainWindow::processQueue() +{ + const menuitem *item; + dialogparam *d; + if (uih->incalculation) + return; + while ((item = menu_delqueue(&d)) != NULL) { + menuActivate(item, d); + } +} + +int MainWindow::processKey(int key) +{ + int sym = tolower(key); + if (sym == ' ') { + uih->display = 1; + if (uih->play) { + if (uih->incalculation) { + uih_updatestatus(uih); + widget->repaint(); + } else { + uih_skipframe(uih); + showStatus(TR("Message", "Skipping, please wait...")); + } + } + } else { + char mkey[2]; + mkey[0] = key; + mkey[1] = 0; + const menuitem *item; + item = menu_findkey(mkey, uih->menuroot); + if (item == NULL) { + mkey[0] = sym; + item = menu_findkey(mkey, uih->menuroot); + } + if (item != NULL) { + dialogparam *p = NULL; + if (menu_havedialog(item, uih)) { + const menudialog *d = menu_getdialog(uih, item); + int mousex, mousey; + mousex = widget->mousePosition().x(); + mousey = widget->mousePosition().y(); + if (d[0].question != NULL && d[1].question == NULL && + d[0].type == DIALOG_COORD) { + p = (dialogparam *)malloc(sizeof(dialogparam)); + uih_screentofractalcoord(uih, mousex, mousey, p->dcoord, + p->dcoord + 1); + } + } + menuActivate(item, p); + } + } + processQueue(); + return 0; +} + +#define KEYLEFT 1 +#define KEYRIGHT 2 +#define KEYUP 4 +#define KEYDOWN 8 + +bool MainWindow::processArrows(int *counter, const char *text, int speed, + int keys, int lastkeys, int down, int up, + bool tenskip, int min, int max) +{ + static int pid = -1; + bool changed = false; + if (tl_lookup_timer(arrowtimer) > 1000000) + tl_reset_timer(arrowtimer); + if ((keys & up) && !(lastkeys & up)) { + (*counter)++; + tenskip = false; + changed = true; + tl_reset_timer(arrowtimer); + } + if ((keys & down) && !(lastkeys & down)) { + (*counter)--; + tenskip = false; + changed = true; + tl_reset_timer(arrowtimer); + } + while (tl_lookup_timer(arrowtimer) > speed * FRAMETIME) { + tl_slowdown_timer(arrowtimer, speed * FRAMETIME); + if (keys & up) { + if (tenskip && !(*counter % 10)) + (*counter) += 10; + else + (*counter)++; + changed = true; + } + if (keys & down) { + if (tenskip && !(*counter % 10)) + (*counter) -= 10; + else + (*counter)--; + changed = true; + } + } + if (changed) { + if (*counter > max) + *counter = max; + if (*counter < min) + *counter = min; + char str[80]; + sprintf(str, text, *counter); + uih_rmmessage(uih, pid); + pid = uih_message(uih, str); + } + return changed; +} + +#define ROTATESPEEDUP 30 + +void MainWindow::processEvents(bool wait) +{ + char str[80]; + static int spid; + QCoreApplication::processEvents(wait ? QEventLoop::WaitForMoreEvents + : QEventLoop::AllEvents); + static bool dirty = false; + static int lastkey; + static int maxiter; + + int mousex = widget->mousePosition().x(); + int mousey = widget->mousePosition().y(); + int buttons = mouseButtons(); + int key = keyCombination(); + tl_update_time(); + assert(!((key) & ~(KEYLEFT | KEYRIGHT | KEYUP | KEYDOWN)) && + !((buttons) & ~(BUTTON1 | BUTTON2 | BUTTON3))); + uih_update(uih, mousex, mousey, buttons); + if (uih->play) { + processArrows(&uih->letterspersec, + TR("Message", "Letters per second %i "), 2, key, lastkey, + KEYLEFT, KEYRIGHT, false, 1, INT_MAX); + return; + } + if (!uih->cycling) { + if (uih->rotatemode == ROTATE_CONTINUOUS) { + static int rpid; + if (key == KEYRIGHT) + uih->rotationspeed += + ROTATESPEEDUP * tl_lookup_timer(maintimer) / 1000000.0; + else if (key == KEYLEFT) + uih->rotationspeed -= + ROTATESPEEDUP * tl_lookup_timer(maintimer) / 1000000.0; + if (key & (KEYLEFT | KEYRIGHT)) { + uih_rmmessage(uih, rpid); + sprintf( + str, + TR("Message", "Rotation speed:%2.2f degrees per second "), + (float)uih->rotationspeed); + rpid = uih_message(uih, str); + } + tl_reset_timer(maintimer); + } else { + if (!dirty) + maxiter = uih->fcontext->maxiter; + if (processArrows(&maxiter, TR("Message", "Iterations: %i "), 1, + key, lastkey, KEYLEFT, KEYRIGHT, false, 1, + INT_MAX) || + (key & (KEYLEFT | KEYRIGHT))) { + dirty = true; + lastkey = key; + return; + } + } + } + if (dirty) { + if (uih->incalculation) + uih_interrupt(uih); + else { + uih_setmaxiter(uih, maxiter); + dirty = false; + } + } + if (uih->cycling) { + if (processArrows(&uih->cyclingspeed, + TR("Message", "Cycling speed: %i "), 1, key, + lastkey, KEYLEFT, KEYRIGHT, 0, -1000000, INT_MAX)) { + uih_setcycling(uih, uih->cyclingspeed); + } + } + if (tl_lookup_timer(maintimer) > FRAMETIME || buttons) { + double mul1 = tl_lookup_timer(maintimer) / FRAMETIME; + double su = 1 + (SPEEDUP - 1) * mul1; + if (su > 2 * SPEEDUP) + su = SPEEDUP; + tl_reset_timer(maintimer); + if (key & KEYUP) + uih->speedup *= su, uih->maxstep *= su; + else if (key & KEYDOWN) + uih->speedup /= su, uih->maxstep /= su; + if (key & (KEYUP | KEYDOWN)) { + sprintf(str, TR("Message", "speed:%2.2f "), + (double)uih->speedup * (1.0 / STEP)); + uih_rmmessage(uih, spid); + spid = uih_message(uih, str); + } + } + lastkey = key; + return; +} + +struct image *MainWindow::makeImage(int width, int height) +{ + struct palette *palette; + union paletteinfo info; + info.truec.rmask = 0xff0000; + info.truec.gmask = 0x00ff00; + info.truec.bmask = 0x0000ff; + palette = + createpalette(0, 0, TRUECOLOR, 0, 0, NULL, NULL, NULL, NULL, &info); + if (!palette) { + x_error(TR("Error", "Can not create palette")); + x_error(TR("Error", "XaoS is out of memory.")); + ui_quit(-1); + } + struct image *image = + create_image_qt(width, height, palette, pixelwidth, pixelheight); + if (!image) { + x_error(TR("Error", "Can not create image")); + x_error(TR("Error", "XaoS is out of memory.")); + ui_quit(-1); + } + widget->setImage(image); + return image; +} + +void MainWindow::resizeImage(int width, int height) +{ + /* Prevent crash on startup for Mac OS X */ + if (!uih) + return; + + if (uih->incalculation) { + uih_interrupt(uih); + return; + } + uih_clearwindows(uih); + uih_stoptimers(uih); + uih_cycling_stop(uih); + uih_savepalette(uih); + assert(width > 0 && width < 65000 && height > 0 && height < 65000); + if (width != uih->image->width || height != uih->image->height) { + destroy_image(uih->image); + destroypalette(uih->palette); + struct image *image = makeImage(width, height); + if (!uih_updateimage(uih, image)) { + x_error(TR("Error", "Can not allocate tables")); + x_error(TR("Error", "XaoS is out of memory.")); + ui_quit(-1); + } + tl_process_group(syncgroup, NULL); + tl_reset_timer(maintimer); + tl_reset_timer(arrowtimer); + uih_newimage(uih); + } + uih_newimage(uih); + uih_restorepalette(uih); + uih->display = 1; + uih_cycling_continue(uih); +} + +xio_pathdata configfile; + +void MainWindow::eventLoop() +{ + QTimer eventTimer; + eventTimer.setTimerType(Qt::PreciseTimer); + + connect(&eventTimer, &QTimer::timeout, this, [=]() { + int inmovement = 1; + + widget->setCursor(uih->play ? Qt::ForbiddenCursor : Qt::CrossCursor); + + if (uih->display) { + uih_prepare_image(uih); + uih_updatestatus(uih); + widget->repaint(); + showStatus(""); + } + + int time = tl_process_group(syncgroup, nullptr); + if (time != -1) { + if (!inmovement && !uih->inanimation) { + if (time > 1000000 / 50) + time = 1000000 / 50; + if (time > delaytime) { + QThread::usleep(time - delaytime); + tl_update_time(); + } + } + inmovement = 1; + } + + if (delaytime || maxframerate) { + tl_update_time(); + time = tl_lookup_timer(loopt); + tl_reset_timer(loopt); + time = 1000000 / maxframerate - time; + if (time < delaytime) + time = delaytime; + if (time) { + QThread::usleep(time); + tl_update_time(); + } + } + + processQueue(); + processEvents(!inmovement && !uih->inanimation); + inmovement = 0; + + if (shouldResize) { + resizeImage(widget->size().width(), widget->size().height()); + shouldResize = false; + } + }); + + // Start the event timer + eventTimer.start(0); + + // Enter the Qt event loop + QCoreApplication::exec(); +} + +void MainWindow::updateMenus(const char *name) +{ + const struct menuitem *item; + if (name == NULL) { + buildMenu(uih->menuroot); + return; + } + item = menu_findcommand(name); + if (item == NULL) + return; + if (item->flags & (MENUFLAG_CHECKBOX | MENUFLAG_RADIO)) { + toggleMenu(name); + } +} + +void ui_updatemenus(struct uih_context *uih, const char *name) +{ + if (uih->data) { + MainWindow *window = reinterpret_cast(uih->data); + window->updateMenus(name); + } +} + +int MainWindow::showProgress(int display, const char *text, float percent) +{ + char str[80]; + processEvents(false); + if (!uih->play) { + if (uih->display) { + if (nthreads == 1) + uih_drawwindows(uih); + widget->repaint(); + uih_cycling_continue(uih); + display = 1; + } + if (!uih->interruptiblemode && !uih->play) { + if (display) { + if (percent) + sprintf(str, "%s %3.2f%% ", text, (double)percent); + else + sprintf(str, "%s ", text); + showStatus(str); + } + } + } + return 0; +} + +static int ui_passfunc(struct uih_context *uih, int display, const char *text, + float percent) +{ + if (uih->data) { + MainWindow *window = reinterpret_cast(uih->data); + return window->showProgress(display, text, percent); + } + return 0; +} + +void MainWindow::pleaseWait() +{ + char s[100]; + if (uih->play) + return; + widget->setCursor(Qt::WaitCursor); + sprintf(s, TR("Message", "Please wait while calculating %s"), + uih->fcontext->currentformula->name[!uih->fcontext->mandelbrot]); + showStatus(s); +} + +static void ui_message(struct uih_context *uih) +{ + if (uih->data) { + MainWindow *window = reinterpret_cast(uih->data); + window->pleaseWait(); + } +} + +void MainWindow::chooseFont() +{ + QFontDialog *fontDialog = new QFontDialog(this); + QSettings settings; + QFont qfont(settings.value("MainWindow/messageFontFamily").toString(), + settings.value("MainWindow/messageFontSize").toInt()); + fontDialog->setCurrentFont(qfont); + connect(fontDialog, &QFontDialog::fontSelected, + [=](const QFont &messageFont) { + QSettings settings; + settings.setValue("MainWindow/messageFontFamily", messageFont.family()); + settings.setValue("MainWindow/messageFontSize", + messageFont.pointSize()); + uih->font = (void *) &messageFont; + }); + fontDialog->open(); +} + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) +{ + menuBarRef = menuBar(); + setWindowTitle(QCoreApplication::applicationName()); + setMouseTracking(true); + + widget = new FractalWidget(); + setCentralWidget(widget); + + readSettings(); + + widget->setCursor(Qt::WaitCursor); + showStatus("Initializing. Please wait."); + show(); + + QScreen *screen = windowHandle()->screen(); + if (!pixelwidth) + pixelwidth = 2.54 / screen->physicalDotsPerInchX(); + if (!pixelheight) + pixelheight = 2.54 / screen->physicalDotsPerInchY(); + + int width = widget->size().width(); + int height = widget->size().height(); + struct image *image = makeImage(width, height); + uih = uih_mkcontext(PIXELSIZE, image, ui_passfunc, ui_message, + ui_updatemenus); + uih->data = this; + uih->font = &messageFont; + buildMenu(uih->menuroot); + uih->fcontext->version++; + uih_newimage(uih); + QSettings settings; + + // Try to load a catalog for the current language and if it doesn't exist, + // default to English. Fixes "No catalog loaded" messages on tutorials + // when using a language XaoS doesn't support + //if (!uih_loadcatalog(uih, QLocale::system().name().left(2).toUtf8())) + if (!uih_loadcatalog(uih, QString(getLanguage()).left(2).toUtf8())) + uih_loadcatalog(uih, "en"); + + tl_update_time(); + maintimer = tl_create_timer(); + arrowtimer = tl_create_timer(); + loopt = tl_create_timer(); + tl_reset_timer(maintimer); + tl_reset_timer(arrowtimer); + + if (getenv("HOME") != NULL) { + char home[256], *env = getenv("HOME"); + int maxsize = + 255 - (int)strlen(CONFIGFILE) - 1; /*Avoid buffer overflow */ + int i; + for (i = 0; i < maxsize && env[i]; i++) + home[i] = env[i]; + home[i] = 0; + xio_addfname(configfile, home, CONFIGFILE); + } else + xio_addfname(configfile, XIO_EMPTYPATH, CONFIGFILE); + xio_file f = xio_ropen(configfile); /*load the configuration file */ + if (f != XIO_FAILED) { + uih_load(uih, f, configfile); + if (uih->errstring) { + x_error("Configuration file %s load failed", configfile); + uih_printmessages(uih); + x_error("Hint: try to remove it"); + ui_quit(1); + } + } + + const menuitem *item; + dialogparam *d; + while ((item = menu_delqueue(&d)) != NULL) { + uih_saveundo(uih); + menu_activate(item, uih, d); + } + + char welcome[80]; + sprintf(welcome, TR("Message", "Welcome to XaoS version %s"), XaoS_VERSION); + uih_message(uih, welcome); + if (printspeed) + printSpeed(); + +#ifdef __EMSCRIPTEN__ + // Obtain a command via URL: + emscripten::val location = emscripten::val::global("location"); + auto href = location["href"].as(); + int q = href.find("?"); + if (q == std::string::npos) { + return; // No command was started with "?", stop and return. + } + auto command = href.substr(q + 1); + if (command.length() == 0) { + return; // No command was given, stop and return. + } + // std::cerr << "command = " << command << "\n"; + + // Manual url_decode: + const char *src = command.c_str(); + char *dst = new char[command.length() + 1]; + char *com = dst; + // Taken from https://stackoverflow.com/questions/2673207/c-c-url-decode-library + char a, b; + while (*src) { + if ((*src == '%') && + ((a = src[1]) && (b = src[2])) && + (isxdigit(a) && isxdigit(b))) { + if (a >= 'a') + a -= 'a'-'A'; + if (a >= 'A') + a -= ('A' - 10); + else + a -= '0'; + if (b >= 'a') + b -= 'a'-'A'; + if (b >= 'A') + b -= ('A' - 10); + else + b -= '0'; + *dst++ = 16*a+b; + src+=3; + } else if (*src == '+') { + *dst++ = ' '; + src++; + } else { + *dst++ = *src++; + } + } + *dst++ = '\0'; + // printf("command = %s\n", com); + uih_loadstr(uih, com); +#endif + +} + +MainWindow::~MainWindow() +{ + uih_cycling_off(uih); + uih_freecatalog(uih); + uih_freecontext(uih); + tl_free_timer(maintimer); + tl_free_timer(arrowtimer); + tl_free_timer(loopt); + // Sometimes the image pointer is set to to 0xFEEEFEEEFEEEFEEE when we get + // here and it crashes without this guard. Not sure why. Possibly + // related to https://sourceforge.net/p/mingw-w64/bugs/727/ + if (uih->image != (image *)0xFEEEFEEEFEEEFEEE) { + destroypalette(uih->image->palette); + destroy_image(uih->image); + } +} + +void MainWindow::readSettings() +{ + QSettings settings; + restoreGeometry(settings.value("MainWindow/geometry").toByteArray()); + restoreState(settings.value("MainWindow/windowState").toByteArray()); + QString fontFamily = settings + .value("MainWindow/messageFontFamily", + QApplication::font().family()) + .toString(); + int fontSize = settings + .value("MainWindow/messageFontSize", + 12) + .toInt(); + messageFont = QFont(fontFamily, fontSize); + +} + +void MainWindow::writeSettings() +{ + QSettings settings; + settings.setValue("MainWindow/geometry", saveGeometry()); + settings.setValue("MainWindow/windowState", saveState()); +} + +void MainWindow::closeEvent(QCloseEvent *) +{ + writeSettings(); + ui_quit(0); +} + +QKeySequence::StandardKey MainWindow::keyForItem(const QString &name) +{ + if (name == "initstate") + return QKeySequence::New; + if (name == "loadpos") + return QKeySequence::Open; + if (name == "savepos") + return QKeySequence::Save; + if (name == "quit") + return QKeySequence::Quit; + if (name == "undo") + return QKeySequence::Undo; + if (name == "redo") + return QKeySequence::Redo; + if (name == "fullscreen" || name == "fullscreena") + return QKeySequence::FullScreen; + if (name == "interrupt") + return QKeySequence::Cancel; + if (name == "recalculate") + return QKeySequence::Refresh; + if (name == "help") + return QKeySequence::HelpContents; + if (name == "copyurl") + return QKeySequence::Copy; + if (name == "saveimg") + return QKeySequence::SaveAs; + if (name == "fractalinfo") + return QKeySequence::WhatsThis; + if (name == "autopilot") + return QKeySequence::ZoomIn; + + return QKeySequence::UnknownKey; +} + +void MainWindow::buildMenu(const char *name) +{ + menuBarRef->clear(); + foreach (QAction *action, actions()) + removeAction(action); + + const menuitem *item; + for (int i = 0; (item = menu_item(name, i)) != NULL; i++) { + if (item->type == MENU_SUBMENU) { + QMenu *menu = menuBarRef->addMenu(QString(item->name)); + buildMenu(item->shortname, menu, false); + } + } +} + +void MainWindow::buildMenu(const char *name, QMenu *parent, bool numbered) +{ + QActionGroup *group = 0; + + connect(parent, SIGNAL(aboutToShow()), SLOT(updateMenuCheckmarks())); + + const menuitem *item; + for (int i = 0, n = 0; (item = menu_item(name, i)) != NULL; i++) { + + QString itemName(item->name); + if (numbered) { + char c; + if (n < 9) + c = n + '1'; + else if (n == 9) + c = '0'; + else + c = 'A' + n - 10; + itemName = QString::asprintf("&%c ", c) + itemName; + + if (item->type != MENU_SEPARATOR) + n++; + } + + if (item->type == MENU_DIALOG || item->type == MENU_CUSTOMDIALOG) + itemName += "..."; + + if (item->type == MENU_SEPARATOR) { + parent->addSeparator(); + } else if (item->type == MENU_SUBMENU) { + QMenu *menu = parent->addMenu(itemName); + buildMenu(item->shortname, menu, numbered); + } else { + QAction *action = new QAction(itemName, parent); + action->setShortcuts(keyForItem(item->shortname)); + action->setObjectName(item->shortname); + if (item->flags & (MENUFLAG_RADIO | MENUFLAG_CHECKBOX)) { + action->setCheckable(true); + action->setChecked(menu_enabled(item, uih)); + if (item->flags & MENUFLAG_RADIO) { + if (!group) + group = new QActionGroup(parent); + action->setActionGroup(group); + } + } + connect(action, SIGNAL(triggered()), this, + SLOT(activateMenuItem())); + parent->addAction(action); + if (action->shortcut() != QKeySequence::UnknownKey) + addAction( + action); // so that shortcuts work when menubar is hidden + } + } +} + +void MainWindow::popupMenu(const char *name) +{ + QMenu *menu = new QMenu(this); + buildMenu(name, menu, true); + menu->exec(QCursor::pos()); + delete menu; +} + +void MainWindow::toggleMenu(const char *name) +{ + const menuitem *item = menu_findcommand(name); + QAction *action = menuBarRef->findChild(name); + if (action) + action->setChecked(menu_enabled(item, uih)); +} + +void MainWindow::activateMenuItem() +{ + QAction *action = qobject_cast(sender()); + const menuitem *item = menu_findcommand(action->objectName().toUtf8()); + menuActivate(item, NULL); +} + +void MainWindow::updateMenuCheckmarks() +{ + QMenu *menu = qobject_cast(sender()); + foreach (QAction *action, menu->actions()) { + if (action->isCheckable()) { + const menuitem *item = + menu_findcommand(action->objectName().toUtf8()); + action->setChecked(menu_enabled(item, uih)); + } + } +} + +struct palette *gradientpal; QSpinBox *seedno, *algono, *shiftno; QLabel *img; + +void MainWindow::updateVisualiser() +{ + // Get updated Colors + int colors[101][3]; + getPaletteColor(gradientpal, seedno->value(), + algono->value()-1 < 0? 0:algono->value()-1, shiftno->value(), colors); + + // Load Curve + QImage palImage(100, 1, QImage::Format_RGB32); + + // Fill Curve + for(int i=0;i<100;i++) { + QRgb value = qRgb(colors[i][0], colors[i][1], colors[i][2]); + palImage.setPixelColor(i, 0, value); + } + + // Save Result + QPixmap newImage = QPixmap::fromImage(palImage.scaled(algono->width(), + algono->height())); + img->setPixmap(newImage); +} + +unsigned char newColors[32][3]; + +void MainWindow::colorPicker() +{ + QPushButton* button = qobject_cast(sender()); + int idx = button->objectName().toInt(); + QColorDialog* qColorDialog = new QColorDialog(this); + QColor currentColor(newColors[idx][0], newColors[idx][1], newColors[idx][2]); + qColorDialog->setCurrentColor(currentColor); + qColorDialog->setModal(false); + connect(qColorDialog, &QColorDialog::colorSelected, qColorDialog, + [=](const QColor &color) { + QPalette pal = button->palette(); + button->setAutoFillBackground(true); + pal.setColor(QPalette::Button, color); + button->setPalette(pal); + button->update(); + newColors[idx][0] = color.red(); + newColors[idx][1] = color.green(); + newColors[idx][2] = color.blue(); + }); + qColorDialog->open(); +} + +void MainWindow::showDialog(const char *name) +{ + const menuitem *item = menu_findcommand(name); + if (!item) + return; + + const menudialog *dialog = menu_getdialog(uih, item); + if (!dialog) + return; + + int nitems; + for (nitems = 0; dialog[nitems].question; nitems++) + ; + + if (nitems == 1 && + (dialog[0].type == DIALOG_IFILE || dialog[0].type == DIALOG_OFILE)) { + QString filter = + QString("*.%1").arg(QFileInfo(dialog[0].defstr).completeSuffix()); + QSettings settings; + QString fileLocation = + settings.value("MainWindow/lastFileLocation", QDir::homePath()) + .toString(); + if (dialog[0].type == DIALOG_IFILE) { + // fileName = QFileDialog::getOpenFileName(this, item->name, fileLocation, filter); + QFileDialog *qFileDialog = new QFileDialog(this); + // qFileDialog->setWindowTitle(dialog->question); + qFileDialog->setWindowTitle(item->name); + qFileDialog->setDirectory(fileLocation); + qFileDialog->setNameFilter(filter); + connect(qFileDialog, &QFileDialog::fileSelected, + [=](const QString &value) { + QString fileName = value; + if (!fileName.isNull()) { + QString ext = "." + QFileInfo(dialog[0].defstr).suffix(); + + if (!fileName.endsWith(".xpf") and !fileName.endsWith(".png") + and !fileName.endsWith(ext)) + fileName += ext; + + dialogparam *param = (dialogparam *)malloc(sizeof(dialogparam)); + param->dstring = strdup(fileName.toUtf8()); + menuActivate(item, param); + QSettings settings; + settings.setValue("MainWindow/lastFileLocation", + QFileInfo(fileName).absolutePath()); + } + }); + qFileDialog->open(); + } + else if (dialog[0].type == DIALOG_OFILE) { + char defname[256]; + strcpy(defname, + QDir(fileLocation).filePath(dialog[0].defstr).toUtf8()); + char *split = strchr(defname, '*'); + *split = 0; + strcpy(defname, xio_getfilename(defname, split + 1)); + // fileName = QFileDialog::getSaveFileName(this, item->name, defname, filter); + QFileDialog *qFileDialog = new QFileDialog(this); + qFileDialog->setWindowTitle(item->name); + qFileDialog->setDirectory(fileLocation); + qFileDialog->setNameFilter(filter); + qFileDialog->setAcceptMode(QFileDialog::AcceptSave); + connect(qFileDialog, &QFileDialog::fileSelected, + [=](const QString &value) { + QString fileName = value; + if (!fileName.isNull()) { + QString ext = "." + QFileInfo(dialog[0].defstr).suffix(); + + if (!fileName.endsWith(".xpf") and !fileName.endsWith(".png") + and !fileName.endsWith(ext)) + fileName += ext; + + dialogparam *param = (dialogparam *)malloc(sizeof(dialogparam)); + param->dstring = strdup(fileName.toUtf8()); + menuActivate(item, param); + QSettings settings; + settings.setValue("MainWindow/lastFileLocation", + QFileInfo(fileName).absolutePath()); + } + }); + qFileDialog->open(); + } + } else { + + dialogparam *param = (dialogparam *)malloc(sizeof(dialogparam)); + + switch (dialog->type) { + case DIALOG_INT: + case DIALOG_FLOAT: + case DIALOG_STRING: + case DIALOG_KEYSTRING: + { + QInputDialog *qInputDialog = new QInputDialog(this); + qInputDialog->setLabelText(dialog->question); + qInputDialog->setWindowTitle(item->name); + switch (dialog->type) { + case DIALOG_INT: + { + qInputDialog->setIntMaximum(1000000); + qInputDialog->setIntValue(dialog->defint); + connect(qInputDialog, &QInputDialog::intValueSelected, qInputDialog, + [=](const unsigned long int &value) { + param->dint = value; + menuActivate(item, param); + }); + break; + } + case DIALOG_FLOAT: + { + qInputDialog->setDoubleMaximum(1000000); + qInputDialog->setDoubleValue(dialog->deffloat); + connect(qInputDialog, &QInputDialog::doubleValueSelected, qInputDialog, + [=](const double &value) { + param->number = value; + menuActivate(item, param); + }); + break; + } + case DIALOG_STRING: + { + qInputDialog->setTextValue(dialog->defstr); + connect(qInputDialog, &QInputDialog::textValueSelected, qInputDialog, + [=](const QString &text) { + param->dstring = strdup((char *) text.toStdString().c_str()); + menuActivate(item, param); + }); + break; + } + case DIALOG_KEYSTRING: + { + qInputDialog->setTextValue(dialog->defstr); + connect(qInputDialog, &QInputDialog::textValueSelected, qInputDialog, + [=](const QString &text) { + param->dstring = strdup((char *) text.toStdString().c_str()); + menuActivate(item, param); + }); + break; + } + } + qInputDialog->open(); + break; + } + case DIALOG_COORD: + { + QDialog *qDialog = new QDialog(this); + qDialog->setWindowTitle(item->name); + QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); + QFormLayout *formLayout = new QFormLayout(); + QString label(dialog->question); + QLineEdit *real = new QLineEdit(CustomDialog::format(dialog->deffloat), qDialog); + QFontMetrics metric(real->font()); + real->setMinimumWidth(metric.horizontalAdvance(real->text()) * 1.1); + real->setObjectName("real"); + QLineEdit *imag = new QLineEdit(CustomDialog::format(dialog->deffloat2), qDialog); + imag->setObjectName("imag"); + imag->setMinimumWidth(metric.horizontalAdvance(imag->text()) * 1.1); + // imag->setValidator(new QDoubleValidator(imag)); + QBoxLayout *layout = new QBoxLayout(QBoxLayout::LeftToRight); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(real); + layout->addWidget(new QLabel("+", qDialog)); + layout->addWidget(imag); + layout->addWidget(new QLabel("i", qDialog)); + formLayout->addRow(label, layout); + dialogLayout->addLayout(formLayout); + QDialogButtonBox *buttonBox = + new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), + Qt::Horizontal, qDialog); + connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); + connect(real, SIGNAL(textEdited(QString)), qDialog, SLOT(update())); + dialogLayout->addWidget(buttonBox); + qDialog->setLayout(dialogLayout); + connect(qDialog, &QDialog::accepted, qDialog, + [=](void){ + QLineEdit *real = qDialog->findChild("real"); + param->dcoord[0] = real->text().toDouble(); + QLineEdit *imag = qDialog->findChild("imag"); + param->dcoord[1] = imag->text().toDouble(); + menuActivate(item, param); + }); + qDialog->adjustSize(); // this is sometimes too high in WASM, FIXME, maybe Qt6 bug? + qDialog->open(); + break; + } + case DIALOG_PALSLIDER: + { + QDialog *qDialog = new QDialog(this); + qDialog->setWindowTitle(item->name); + QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); + gradientpal = clonepalette(uih->image->palette); + uih_context *palcontext; + palcontext = uih; + // 3 inputs decide color, Algorithm Number, Seed and shift + // For Algorithm number + QSlider *seedslider, *algoslider, *shiftslider; + algono = new QSpinBox(this); + QString label(dialog->question); + algono->setObjectName(label + "algono"); + algono->setValue(palcontext->palettetype); + algono->setRange(1, 3); + + // Algo Slider + algoslider = new QSlider(Qt::Horizontal, qDialog); + algoslider->setObjectName(label + "-algono"); + algoslider->setRange(1, PALGORITHMS); + algoslider->setValue(algono->value()); + // algoslider->setMinimumWidth(this->width()*2); + + // For Seed Number + seedno = new QSpinBox(qDialog); + seedno->setObjectName(label + "seedno"); + seedno->setRange(0, gradientpal->size); + seedno->setValue(palcontext->paletteseed); + + // Seed Slider + seedslider = new QSlider(Qt::Horizontal, qDialog); + seedslider->setObjectName(label + "-seedno"); + seedslider->setRange(0, gradientpal->size); + seedslider->setValue(seedno->value()); + + // For Shift Number + shiftno = new QSpinBox(this); + shiftno->setObjectName(label + "shiftno"); + shiftno->setRange(0, gradientpal->size); + shiftno->setValue(palcontext->paletteshift + palcontext->manualpaletteshift); + + // Shift Slider + shiftslider = new QSlider(Qt::Horizontal, qDialog); + shiftslider->setObjectName(label + "-shiftno"); + shiftslider->setRange(0, gradientpal->size); + shiftslider->setValue(shiftno->value()); + + // Add them to Layout + QFormLayout *formLayout = new QFormLayout(); + formLayout->addRow("Algorithm", algono); + formLayout->addWidget(algoslider); + formLayout->addRow("Seed", seedno); + formLayout->addWidget(seedslider); + formLayout->addRow("Shift", shiftno); + formLayout->addWidget(shiftslider); + + img = new QLabel(qDialog); + img->setScaledContents(true); + formLayout->addRow(img); + updateVisualiser(); + + connect(algono,SIGNAL(valueChanged(int)), algoslider, SLOT(setValue(int))); + connect(algoslider, SIGNAL(valueChanged(int)), algono, SLOT(setValue(int))); + connect(algono, SIGNAL(valueChanged(int)), this, SLOT(updateVisualiser())); + connect(seedno,SIGNAL(valueChanged(int)), seedslider, SLOT(setValue(int))); + connect(seedslider, SIGNAL(valueChanged(int)), seedno, SLOT(setValue(int))); + connect(seedno, SIGNAL(valueChanged(int)), this, SLOT(updateVisualiser())); + connect(shiftno,SIGNAL(valueChanged(int)), shiftslider, SLOT(setValue(int))); + connect(shiftslider, SIGNAL(valueChanged(int)), shiftno, SLOT(setValue(int))); + connect(shiftno, SIGNAL(valueChanged(int)), this, SLOT(updateVisualiser())); + + dialogLayout->addLayout(formLayout); + QDialogButtonBox *buttonBox = + new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), + Qt::Horizontal, qDialog); + + connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); + + dialogLayout->addWidget(buttonBox); + qDialog->setLayout(dialogLayout); + + connect(qDialog, &QDialog::accepted, qDialog, + [=](void){ + QSlider *algo = qDialog->findChild(label + "-algono"); + palcontext->palettetype = algo->sliderPosition(); + palcontext->manualpaletteshift = 0; + QSlider *seed = qDialog->findChild(label + "-seedno"); + palcontext->paletteseed = seed->sliderPosition(); + QSlider *shift = qDialog->findChild(label + "-shiftno"); + palcontext->paletteshift = shift->sliderPosition(); + param->dint = 1; + menuActivate(item, param); + destroypalette(gradientpal); + }); + qDialog->open(); + break; + } + case DIALOG_PALPICKER: + { + QDialog *qDialog = new QDialog(this); + qDialog->setWindowTitle(item->name); + QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); + + uih_context *palcontext; + palcontext = uih; + getDEFSEGMENTColor(newColors); + + QList< QPushButton* > buttons; + QBoxLayout *layout1 = new QBoxLayout(QBoxLayout::LeftToRight); + QBoxLayout *layout2 = new QBoxLayout(QBoxLayout::LeftToRight); + QBoxLayout *layout3 = new QBoxLayout(QBoxLayout::LeftToRight); + for(auto bidx = 0; bidx < 31; ++bidx ) { + auto button = new QPushButton{ QString::number(bidx) }; + button->setObjectName(QString::number(bidx)); + QColor color(newColors[bidx][0], newColors[bidx][1], newColors[bidx][2]); + QPalette pal = button->palette(); + button->setAutoFillBackground(true); + pal.setColor(QPalette::Button, color); + button->setPalette(pal); + button->update(); + buttons << button; + if(bidx <= 10) + layout1->addWidget(button); + else if(bidx>10 and bidx <= 20) + layout2->addWidget(button); + else + layout3->addWidget(button); + + connect(button, SIGNAL(clicked()), this, SLOT(colorPicker())); + } + QFormLayout *formLayout = new QFormLayout(); + formLayout->addRow(layout1); + formLayout->addRow(layout2); + formLayout->addRow(layout3); + dialogLayout->addLayout(formLayout); + QDialogButtonBox *buttonBox = + new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), + Qt::Horizontal, qDialog); + + connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); + + dialogLayout->addWidget(buttonBox); + qDialog->setLayout(dialogLayout); + + connect(qDialog, &QDialog::accepted, qDialog, + [=](void){ + mkcustompalette(palcontext->image->palette, newColors); + menuActivate(item, param); + }); + qDialog->open(); + break; + } + case DIALOG_LIST: // This is used only in Formulas/UserFormulas + { + QDialog *qDialog = new QDialog(this); + qDialog->setWindowTitle(item->name); + QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); + + QComboBox *list = new QComboBox(this); + QString label(dialog->question); + list->setObjectName(label); + list->setEditable(true); + list->addItem(dialog->defstr); + list->setObjectName(label + "-data"); + + QSettings settings; + QStringList formulas = settings.value("Formulas/UserFormulas").toStringList(); + + for (int j = 0; j < formulas.count(); j++) { + bool found = false; + for (int i = 0; i < list->count(); i++) { + if (QString::compare(list->itemText(i), formulas[j], Qt::CaseSensitive) == 0) { + found = true; + } + } + if (!found) + list->addItem(formulas[j]); + } + + // list->addItems(formulas); + + QFormLayout *formLayout = new QFormLayout(); + formLayout->addRow(label, list); + dialogLayout->addLayout(formLayout); + + QDialogButtonBox *buttonBox = + new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), + Qt::Horizontal, qDialog); + + connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); + dialogLayout->addWidget(buttonBox); + qDialog->setLayout(dialogLayout); + qDialog->adjustSize(); // this is sometimes too high in WASM, FIXME, maybe Qt6 bug? + + connect(qDialog, &QDialog::accepted, qDialog, + [=](void){ + QComboBox *selected = qDialog->findChild(label + "-data"); + param->dstring = strdup(selected->currentText().toUtf8()); + menuActivate(item, param); + }); + qDialog->open(); + break; + } + case DIALOG_CHOICE: + { + QDialog *qDialog = new QDialog(this); + qDialog->setWindowTitle(item->name); + QBoxLayout *dialogLayout = new QBoxLayout(QBoxLayout::TopToBottom, qDialog); + + QComboBox *combo = new QComboBox(this); + QString label(dialog->question); + combo->setObjectName(label); + + const char **str = (const char **)dialog->defstr; + for (int j = 0; str[j] != NULL; j++) + combo->addItem(str[j]); + combo->setCurrentIndex(dialog->defint); + QFormLayout *formLayout = new QFormLayout(); + formLayout->addRow(label, combo); + dialogLayout->addLayout(formLayout); + + QDialogButtonBox *buttonBox = + new QDialogButtonBox((QDialogButtonBox::Ok | QDialogButtonBox::Cancel), + Qt::Horizontal, qDialog); + + connect(buttonBox, SIGNAL(accepted()), qDialog, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), qDialog, SLOT(reject())); + dialogLayout->addWidget(buttonBox); + qDialog->setLayout(dialogLayout); + qDialog->adjustSize(); // this is sometimes too high in WASM, FIXME, maybe Qt6 bug? + + connect(qDialog, &QDialog::accepted, qDialog, + [=](void){ + QComboBox *selected = qDialog->findChild(label); + param->dint = selected->currentIndex(); + menuActivate(item, param); + }); + qDialog->open(); + break; + } + default: + { + CustomDialog customDialog(uih, item, dialog, this); + if (customDialog.exec() == QDialog::Accepted) + menuActivate(item, customDialog.parameters()); + } + } + } +} + +#ifdef __wasm +#define STATUS_VIA_STDOUT +//#define STATUS_VIA_PROGRESSBAR +#else +#define STATUS_VIA_PROGRESSBAR +// #define STATUS_VIA_WINDOWTITLE +#endif + +QProgressDialog *qProgressDialog; +int progress = 0; +void MainWindow::showStatus(const char *text) +{ +// This is not working properly, maybe because of a missing QTimer event/setting. +#ifdef STATUS_VIA_UIH_MESSAGE + if (uih != NULL) { + uih_message(uih, text); + uih_updatestatus(uih); + } +#endif + +#ifdef STATUS_VIA_WINDOWTITLE + if (strlen(text)) + setWindowTitle( + QCoreApplication::applicationName().append(" - ").append(text)); + else + setWindowTitle(QCoreApplication::applicationName()); +#endif + +#ifdef STATUS_VIA_STDOUT + std::cout << "STATUS: " << text << "\n"; +#endif + +// This feature is experimental. It works natively but not in WASM. +#ifdef STATUS_VIA_PROGRESSBAR + bool newProgress = (qProgressDialog == NULL); + if (QString(text) == "") { + if (!newProgress) { + qProgressDialog->close(); + progress = 0; + return; + } + } + + if (newProgress) { + qProgressDialog = new QProgressDialog(this); + } else { + qProgressDialog->setValue(progress); + qProgressDialog->setMinimumDuration(0); + QString t = QString(text).trimmed(); + if (t.endsWith("%")) { + progress = t.right(6).left(5).toDouble(); // save the percentage + // std::cout << "t=" << t.toStdString() << " progress=" << progress << "\n"; + t = t.left(t.length()-6); // remove the percentage + } + + qProgressDialog->setCancelButton(NULL); + qProgressDialog->setWindowTitle(t); + if (progress < 100) { + progress++; + } + else { + progress=0; + } + } + + if (newProgress) { + qProgressDialog->show(); + } +#endif +} + +int MainWindow::mouseButtons() +{ + int mouseButtons = 0; + if (m_keyboardModifiers & Qt::ShiftModifier) { + // Shift key makes left and right buttons emulate middle button + if (m_mouseButtons & (Qt::LeftButton | Qt::RightButton)) + mouseButtons |= BUTTON2; + } else { + // Otherwise, mouse buttons map normally + if (m_mouseButtons & Qt::LeftButton) + mouseButtons |= BUTTON1; + if (m_mouseButtons & Qt::MiddleButton) + mouseButtons |= BUTTON2; + if (m_mouseButtons & Qt::RightButton) + mouseButtons |= BUTTON3; + } + // handle mouse wheel operations + if (m_mouseWheel > 0) + mouseButtons |= BUTTON1; + if (m_mouseWheel < 0) + mouseButtons |= BUTTON3; + if (m_mouseWheel != 0) { + timespec timenow; + clock_gettime(CLOCK_REALTIME, &timenow); + long elapsed = timenow.tv_sec * 1.0e9 + timenow.tv_nsec - + wheeltimer.tv_sec * 1.0e9 - wheeltimer.tv_nsec; + if (elapsed > 1.0e9) // timing is hardcoded here + m_mouseWheel = 0; + } + return mouseButtons; +} + +int MainWindow::keyCombination() { return m_keyCombination; } + +void MainWindow::mousePressEvent(QMouseEvent *event) +{ + m_mouseButtons = event->buttons(); +} + +void MainWindow::mouseReleaseEvent(QMouseEvent *event) +{ + m_mouseButtons = event->buttons(); +} + +void MainWindow::wheelEvent(QWheelEvent *event) +{ + m_mouseWheel = event->angleDelta().y(); + clock_gettime(CLOCK_REALTIME, &wheeltimer); +} + +void MainWindow::keyPressEvent(QKeyEvent *event) +{ + m_keyboardModifiers = event->modifiers(); + + switch (event->key()) { + case Qt::Key_Left: + m_keyCombination |= KEYLEFT; + break; + case Qt::Key_Right: + m_keyCombination |= KEYRIGHT; + break; + case Qt::Key_Up: + m_keyCombination |= KEYUP; + break; + case Qt::Key_Down: + m_keyCombination |= KEYDOWN; + break; + default: + if (!event->text().isEmpty()) + processKey(event->text().toUtf8()[0]); + else + event->ignore(); + } +} + +void MainWindow::keyReleaseEvent(QKeyEvent *event) +{ + m_keyboardModifiers = event->modifiers(); + + switch (event->key()) { + case Qt::Key_Left: + m_keyCombination &= ~KEYLEFT; + break; + case Qt::Key_Right: + m_keyCombination &= ~KEYRIGHT; + break; + case Qt::Key_Up: + m_keyCombination &= ~KEYUP; + break; + case Qt::Key_Down: + m_keyCombination &= ~KEYDOWN; + break; + default: + event->ignore(); + } +} + +#ifndef Q_OS_MACOS +#ifndef USE_OPENGL + +void MainWindow::showFullScreen() +{ + menuBarRef->setParent(centralWidget()); + QMainWindow::showFullScreen(); +} + +void MainWindow::showNormal() +{ + setMenuBar(menuBarRef); + menuBarRef->show(); + QMainWindow::showNormal(); +} + +void MainWindow::mouseMoveEvent(QMouseEvent *event) +{ + if (isFullScreen()) { + if (event->pos().y() < menuBarRef->sizeHint().height()) + menuBarRef->show(); + else + menuBarRef->hide(); + } +} +#endif +#endif + +void MainWindow::resizeEvent(QResizeEvent * /*event*/) +{ +#ifndef Q_OS_MACOS +#ifndef USE_OPENGL + if (isFullScreen()) + menuBarRef->resize(size().width(), menuBarRef->sizeHint().height()); +#endif +#endif + shouldResize = true; +} diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 54cc3d4f..a74b07c3 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -1,90 +1,90 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include - -#include "ui_helper.h" -#include "timers.h" -#include "xmenu.h" - -class QImage; -class FractalWidget; -class MainWindow : public QMainWindow -{ - Q_OBJECT - private: - Qt::MouseButtons m_mouseButtons = Qt::NoButton; - int m_mouseWheel = 0; - timespec wheeltimer; - Qt::KeyboardModifiers m_keyboardModifiers = Qt::NoModifier; - int m_keyCombination = 0; - bool shouldResize = false; - FractalWidget *widget; - uih_context *uih; - tl_timer *maintimer; - tl_timer *loopt; - tl_timer *arrowtimer; - QMenuBar *menuBarRef; - QFont messageFont; - - static QKeySequence::StandardKey keyForItem(const QString &name); - void buildMenu(const char *name, QMenu *parent, bool numbered); - void buildMenu(const char *name, QMenu *parent); - void buildMenu(const char *name); - void popupMenu(const char *name); - void toggleMenu(const char *name); - void showDialog(const char *name); - void showStatus(const char *text); - int mouseButtons(); - int keyCombination(); - void readSettings(); - void writeSettings(); - void menuActivate(const menuitem *item, dialogparam *d); - void processQueue(); - int processKey(int key); - bool processArrows(int *counter, const char *text, int speed, int keys, - int lastkeys, int down, int up, bool tenskip, int min, - int max); - void processEvents(bool wait); - struct image *makeImage(int width, int height); - void resizeImage(int width, int height); - void printSpeed(); - - protected: - void closeEvent(QCloseEvent *); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void wheelEvent(QWheelEvent *event); - void keyPressEvent(QKeyEvent *event); - void keyReleaseEvent(QKeyEvent *event); - void resizeEvent(QResizeEvent *event); -#ifndef Q_OS_MACOS -#ifndef USE_OPENGL - void mouseMoveEvent(QMouseEvent *event); -#endif -#endif -private slots: - void activateMenuItem(); - void updateMenuCheckmarks(); - void updateVisualiser(); - void colorPicker(); - - public: - MainWindow(QWidget *parent = 0); - ~MainWindow(); - -#ifndef Q_OS_MACOS -#ifndef USE_OPENGL - void showFullScreen(); - void showNormal(); -#endif -#endif - void pleaseWait(); - int showProgress(int display, const char *text, float percent); - void updateMenus(const char *name); - void init(); - void eventLoop(); - void chooseFont(); -}; - -#endif // MAINWINDOW_H +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +#include "ui_helper.h" +#include "timers.h" +#include "xmenu.h" + +class QImage; +class FractalWidget; +class MainWindow : public QMainWindow +{ + Q_OBJECT + private: + Qt::MouseButtons m_mouseButtons = Qt::NoButton; + int m_mouseWheel = 0; + timespec wheeltimer; + Qt::KeyboardModifiers m_keyboardModifiers = Qt::NoModifier; + int m_keyCombination = 0; + bool shouldResize = false; + FractalWidget *widget; + uih_context *uih; + tl_timer *maintimer; + tl_timer *loopt; + tl_timer *arrowtimer; + QMenuBar *menuBarRef; + QFont messageFont; + + static QKeySequence::StandardKey keyForItem(const QString &name); + void buildMenu(const char *name, QMenu *parent, bool numbered); + void buildMenu(const char *name, QMenu *parent); + void buildMenu(const char *name); + void popupMenu(const char *name); + void toggleMenu(const char *name); + void showDialog(const char *name); + void showStatus(const char *text); + int mouseButtons(); + int keyCombination(); + void readSettings(); + void writeSettings(); + void menuActivate(const menuitem *item, dialogparam *d); + void processQueue(); + int processKey(int key); + bool processArrows(int *counter, const char *text, int speed, int keys, + int lastkeys, int down, int up, bool tenskip, int min, + int max); + void processEvents(bool wait); + struct image *makeImage(int width, int height); + void resizeImage(int width, int height); + void printSpeed(); + + protected: + void closeEvent(QCloseEvent *); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + void resizeEvent(QResizeEvent *event); +#ifndef Q_OS_MACOS +#ifndef USE_OPENGL + void mouseMoveEvent(QMouseEvent *event); +#endif +#endif +private slots: + void activateMenuItem(); + void updateMenuCheckmarks(); + void updateVisualiser(); + void colorPicker(); + + public: + MainWindow(QWidget *parent = 0); + ~MainWindow(); + +#ifndef Q_OS_MACOS +#ifndef USE_OPENGL + void showFullScreen(); + void showNormal(); +#endif +#endif + void pleaseWait(); + int showProgress(int display, const char *text, float percent); + void updateMenus(const char *name); + void init(); + void eventLoop(); + void chooseFont(); +}; + +#endif // MAINWINDOW_H diff --git a/src/ui/ui.h b/src/ui/ui.h index 30bf6aec..48221517 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/ui/xaos.rc b/src/ui/xaos.rc index 6235fef3..ffe15d3d 100644 --- a/src/ui/xaos.rc +++ b/src/ui/xaos.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "xaos.ico" +IDI_ICON1 ICON DISCARDABLE "xaos.ico" diff --git a/src/util/catalog.cpp b/src/util/catalog.cpp index a90243d0..37157512 100644 --- a/src/util/catalog.cpp +++ b/src/util/catalog.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include #include "catalog.h" diff --git a/src/util/grlibd.h b/src/util/grlibd.h index 7eae4205..cd4542dd 100644 --- a/src/util/grlibd.h +++ b/src/util/grlibd.h @@ -1,4 +1,4 @@ -#ifndef UNSUPPORTED +#ifndef UNSUPPORTED static inline void hline(struct image *img, int x, int y, int length, int fgcolor) diff --git a/src/util/image.cpp b/src/util/image.cpp index b367b8dc..edc2446a 100644 --- a/src/util/image.cpp +++ b/src/util/image.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/util/palette.cpp b/src/util/palette.cpp index c60d04eb..1097a840 100644 --- a/src/util/palette.cpp +++ b/src/util/palette.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/util/random.cpp b/src/util/random.cpp index 94cf8a0b..75b389f1 100644 --- a/src/util/random.cpp +++ b/src/util/random.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * diff --git a/src/util/thread.cpp b/src/util/thread.cpp index 1af2704a..2f83b484 100644 --- a/src/util/thread.cpp +++ b/src/util/thread.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "xthread.h" diff --git a/src/util/timers.cpp b/src/util/timers.cpp index afb81028..15961ce5 100644 --- a/src/util/timers.cpp +++ b/src/util/timers.cpp @@ -1,4 +1,4 @@ -/* +/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * diff --git a/src/util/util.pri b/src/util/util.pri index d2ce30ce..d882b389 100644 --- a/src/util/util.pri +++ b/src/util/util.pri @@ -1,14 +1,14 @@ -SOURCES += \ - $$PWD/catalog.cpp \ - $$PWD/image.cpp \ - $$PWD/palette.cpp \ - $$PWD/thread.cpp \ - $$PWD/xstring.cpp \ - $$PWD/xerror.cpp \ - $$PWD/xstdio.cpp \ - $$PWD/xmenu.cpp \ - $$PWD/random.cpp \ - $$PWD/timers.cpp - -HEADERS += \ - $$PWD/grlibd.h +SOURCES += \ + $$PWD/catalog.cpp \ + $$PWD/image.cpp \ + $$PWD/palette.cpp \ + $$PWD/thread.cpp \ + $$PWD/xstring.cpp \ + $$PWD/xerror.cpp \ + $$PWD/xstdio.cpp \ + $$PWD/xmenu.cpp \ + $$PWD/random.cpp \ + $$PWD/timers.cpp + +HEADERS += \ + $$PWD/grlibd.h diff --git a/src/util/xerror.cpp b/src/util/xerror.cpp index d84e245e..9750f4cb 100644 --- a/src/util/xerror.cpp +++ b/src/util/xerror.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "config.h" diff --git a/src/util/xmenu.cpp b/src/util/xmenu.cpp index 2eb2f382..0b2ddc07 100644 --- a/src/util/xmenu.cpp +++ b/src/util/xmenu.cpp @@ -1,4 +1,4 @@ -#define __USE_MINGW_ANSI_STDIO 1 // for long double support on Windows +#define __USE_MINGW_ANSI_STDIO 1 // for long double support on Windows #include #include #include diff --git a/src/util/xstdio.cpp b/src/util/xstdio.cpp index 61fe6b31..5e3c8707 100644 --- a/src/util/xstdio.cpp +++ b/src/util/xstdio.cpp @@ -1,4 +1,4 @@ -#include "config.h" +#include "config.h" #include #include #include diff --git a/src/util/xstring.cpp b/src/util/xstring.cpp index d54930da..3df8bd79 100644 --- a/src/util/xstring.cpp +++ b/src/util/xstring.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "config.h"