Update upstream source from tag 'upstream/3.1.1'
[xfishtank.git] / src / ui.c
CommitLineData
4c1bd65b
MG
1/* -copyright-
2#-# Copyright © 2021 Eric Bina, Dave Black, TJ Phan,
3#-# Vincent Renardias, Willem Vermin
4#-#
5#-# Permission is hereby granted, free of charge, to any person
6#-# obtaining a copy of this software and associated documentation
7#-# files (the “Software”), to deal in the Software without
8#-# restriction, including without limitation the rights to use,
9#-# copy, modify, merge, publish, distribute, sublicense, and/or
10#-# sell copies of the Software, and to permit persons to whom
11#-# the Software is furnished to do so, subject to the following
12#-# conditions:
13#-#
14#-# The above copyright notice and this permission notice shall
15#-# be included in all copies or substantial portions of the Software.
16#-#
17#-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
18#-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19#-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20#-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21#-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22#-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23#-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24#-# OTHER DEALINGS IN THE SOFTWARE.
25#-#
26*/
27
28#include <gtk/gtk.h>
29#include <math.h>
30#include "ui_xml.h"
31#include "ui.h"
32#include "debug.h"
33#include "xfishtank.h"
34#include "utils.h"
35#include "fishes.h"
36
37//#include "xfishtank.xpm"
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43#ifdef __cplusplus
44#define MODULE_EXPORT extern "C" G_MODULE_EXPORT
45#else
46#define MODULE_EXPORT G_MODULE_EXPORT
47#endif
48
49int FlagsChanged = 1;
50
51static int human_action = 1; /* is it a human who is playing with the buttons? */
52
53#define NTYPES 16
54static GtkBuilder *builder;
55static GtkWidget *hauptfenster;
56static GtkStyleContext *hauptfenstersc;
57static char buf[100];
58static GtkWidget *id_fishes;
59static GtkWidget *id_fishesvalue;
60static GtkWidget *id_speed;
61static GtkWidget *id_speedvalue;
62static GtkWidget *id_bubbles;
63//static GtkWidget *id_squish;
64static GtkWidget *id_logo1;
65static GtkWidget *id_logo2;
66static GtkWidget *id_logo3;
67static GtkWidget *id_bubble_color;
68static GtkWidget *id_bg_color;
69static GtkWidget *id_bubblesvalue;
70//static GtkWidget *id_squish_picture;
71
72static int logo[3];
73static int flip[3];
74
75static void handle_css(void);
76static void init_ids(void);
77static void init_pixmaps(void);
78static FILE *openflagsfile(char *mode);
79static float scale_to_bubblesfactor(float scale);
80static void ab(float Max, float Min, float *a, float *b);
81static float fishes_to_scale(float n);
82static float bubblesfactor_to_scale(float n);
83static float scale_to_fishes(float scale);
84static float speedfactor_to_scale(float n);
85static float scale_to_speedfactor(float scale);
86static void init_pixmap(GtkWidget *id, int n, int flip);
87static int do_animate(void *dummy);
88
89
90// Sometimes it is good to have a logarithmic scale, such that
91//
92// V = a*M*10**s + b
93//
94// where: V = parameter (e.g. SpeedFactor)
95// M = desired maximum of V (e.g. 4.0)
96// s = value of the gtkscale (0 .. 1.0)
97// Furthermore: m = desired minimum of V (e.g. 0.2)
98//
99// Then:
100// a = (M - m)/(9*M)
101// b = m - a*M
102//
103// The placement of a is a logical choice, the placement of b is
104// more or less random. I need a constant next to a, because I want
105// to define minimum V AND maximum V.
106//
107// Given V, compute s:
108//
109// s = log10((V-b)/(a*M))
110//
111
112void ab(float Max, float Min, float *a, float *b)
113{
114 *a = (Max - Min)/(9.0*Max);
115 *b = Min - (*a)*Max;
116}
117
118static const float MaxBubbles = 500;
119static const float MinBubbles = 1;
120
121static const float MaxFishes = 200;
122static const float MinFishes = 1.0;
123
124static const float MaxSpeed = 400;
125static const float MinSpeed = 30;
126
127void handle_css()
128{
129}
130
131
132void show_dialog(int type, const char *format, const char *text)
133{
134 GtkMessageType message_type;
135 if (type == 1)
136 message_type = GTK_MESSAGE_ERROR;
137 else
138 message_type = GTK_MESSAGE_INFO;
139
140 GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(hauptfenster),
141 GTK_DIALOG_MODAL,
142 message_type,
143 GTK_BUTTONS_OK,
144 format,
145 text
146 );
147 g_signal_connect(m,"response",G_CALLBACK(gtk_main_quit),NULL);
148 gtk_widget_show_all(m);
149}
150
151void init_ids()
152{
153 id_fishes = GTK_WIDGET(gtk_builder_get_object(builder, "id-fishes"));
154 id_fishesvalue = GTK_WIDGET(gtk_builder_get_object(builder, "id-fishesvalue"));
155 id_speed = GTK_WIDGET(gtk_builder_get_object(builder, "id-speed"));
156 id_speedvalue = GTK_WIDGET(gtk_builder_get_object(builder, "id-speedvalue"));
157 id_logo1 = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo1"));
158 id_logo2 = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo2"));
159 id_logo3 = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo3"));
160 id_bubble_color = GTK_WIDGET(gtk_builder_get_object(builder, "id-bubble-color"));
161 id_bg_color = GTK_WIDGET(gtk_builder_get_object(builder, "id-bg-color"));
162 id_bubbles = GTK_WIDGET(gtk_builder_get_object(builder, "id-bubbles"));
163 //id_squish = GTK_WIDGET(gtk_builder_get_object(builder, "id-squish"));
164 id_bubblesvalue = GTK_WIDGET(gtk_builder_get_object(builder, "id-bubblesvalue"));
165 //id_squish_picture = GTK_WIDGET(gtk_builder_get_object(builder, "id-squish-picture"));
166}
167
168int do_animate(void *dummy)
169{
170 (void)dummy;
171 int m = drand48()*3;
172 P("m: %d %d\n",m, logo[m]);
173 // needs adjustment if NUM_FRAMES != 2
174 if (logo[m]%NUM_FRAMES)
175 logo[m]--;
176 else
177 logo[m]++;
178 GtkWidget *id;
179 switch(m)
180 {
181 case 0:
182 id = id_logo1;
183 break;
184 case 1:
185 id = id_logo2;
186 break;
187 case 2:
188 id = id_logo3;
189 break;
190 }
191 init_pixmap(id, logo[m], flip[m]);
192
193 return TRUE;
194}
195
196void init_pixmap(GtkWidget *id, int n, int flip)
197{
198 int w,h;
199 float w0,h0;
200
201 GdkPixbuf *pixbuf, *pixbuf1, *pixbuf2;
202 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)fishes[n]);
203 w0 = gdk_pixbuf_get_width(pixbuf);
204 h0 = gdk_pixbuf_get_height(pixbuf);
205 if (w0 > h0)
206 {
207 w = 64;
208 h = h0/w0*w;
209 }
210 else
211 {
212 h = 64;
213 w = w0/h0*h;
214 }
215
216 pixbuf1 = gdk_pixbuf_scale_simple(pixbuf,w,h,GDK_INTERP_BILINEAR);
217 g_object_unref(pixbuf);
218
219 if(flip)
220 {
221 pixbuf2 = gdk_pixbuf_flip(pixbuf1,1);
222 gtk_image_set_from_pixbuf(GTK_IMAGE(id),pixbuf2);
223 g_object_unref(pixbuf2);
224 }
225 else
226 gtk_image_set_from_pixbuf(GTK_IMAGE(id),pixbuf1);
227
228 g_object_unref(pixbuf1);
229}
230
231void init_pixmaps()
232{
233 int i;
234 for (i=0; i<3; i++)
235 {
236 logo[i] = NUM_FRAMES*(int)(drand48()*NUM_FISH);
237 flip[i] = drand48()*2;
238 }
239 init_pixmap(id_logo1,logo[0],flip[0]);
240 init_pixmap(id_logo2,logo[1],flip[1]);
241 init_pixmap(id_logo3,logo[2],flip[2]);
242}
243
244void set_buttons()
245{
246 int h = human_action;
247 human_action = 0;
248
249 gtk_range_set_value(GTK_RANGE(id_fishes), fishes_to_scale(flimit));
250 sprintf(buf,"%d",flimit);
251 gtk_label_set_text(GTK_LABEL(id_fishesvalue),buf);
252
253 gtk_range_set_value(GTK_RANGE(id_bubbles),bubblesfactor_to_scale(blimit));
254 sprintf(buf,"%d",(int)(blimit));
255 gtk_label_set_text(GTK_LABEL(id_bubblesvalue),buf);
256
257 gtk_range_set_value(GTK_RANGE(id_speed),speedfactor_to_scale(100*speedfactor));
258 P("speedfactor: %f %f\n",speedfactor, speedfactor_to_scale(100*speedfactor));
259 sprintf(buf,"%d",(int)(100*speedfactor));
260 gtk_label_set_text(GTK_LABEL(id_speedvalue),buf);
261
262 GdkRGBA color;
263 P("bcolor: %s\n",bcolorstring);
264 gdk_rgba_parse(&color, bcolorstring);
265 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(id_bubble_color),&color);
266
267 P("bgcolor: %s\n",bgcolorstring);
268 gdk_rgba_parse(&color, bgcolorstring);
269 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(id_bg_color),&color);
270
271 human_action = h;
272
273 FlagsChanged = 1;
274}
275
276
277MODULE_EXPORT void button_fishes(GtkWidget *w)
278{
279 if (!human_action)
280 return;
281 float value = gtk_range_get_value(GTK_RANGE(w));
282 P("fishes: %f\n",value);
283 create_fishes(scale_to_fishes(value));
284 FlagsChanged = 1;
285
286 sprintf(buf,"%d",flimit);
287 gtk_label_set_text(GTK_LABEL(id_fishesvalue),buf);
288}
289
290MODULE_EXPORT void button_bubbles(GtkWidget *w)
291{
292 if (!human_action)
293 return;
294 float value = gtk_range_get_value(GTK_RANGE(w));
295 P("bubbles: %f %d\n",value,blimit);
296 create_bubbles(scale_to_bubblesfactor(value));
297 FlagsChanged = 1;
298
299 sprintf(buf,"%d",blimit);
300 gtk_label_set_text(GTK_LABEL(id_bubblesvalue),buf);
301}
302
303MODULE_EXPORT void button_speed(GtkWidget *w)
304{
305 if (!human_action)
306 return;
307 float value = gtk_range_get_value(GTK_RANGE(w));
308 P("speedfactor: %f %f\n",value,speedfactor);
309 setspeed(scale_to_speedfactor(value));
310 P("speedfactor: %f\n",speedfactor);
311 FlagsChanged = 1;
312
313 sprintf(buf,"%d",(int)(100*speedfactor));
314 gtk_label_set_text(GTK_LABEL(id_speedvalue),buf);
315}
316
317
318MODULE_EXPORT void button_defaults()
319{
320 set_defaults();
321 create_fishes(flimit);
322 create_bubbles(blimit);
323 setbcolor();
324 setbgcolor();
325 setspeed(speedfactor);
326 if (!human_action)
327 return;
328 set_buttons();
329}
330
331#if 0
332MODULE_EXPORT void button_squish(GtkWidget *w)
333{
334 if (!human_action)
335 return;
336 int value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
337 P("squish: %d\n",value);
338 handle_squish(value);
339 FlagsChanged = 1;
340}
341#endif
342MODULE_EXPORT void button_iconify()
343{
344 if (!human_action)
345 return;
346 gtk_window_iconify(GTK_WINDOW(hauptfenster));
347}
348
349MODULE_EXPORT void button_bubble_color(GtkWidget *w)
350{
351 GdkRGBA color;
352 if (!human_action)
353 return;
354 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color);
355 free(bcolorstring);
356 rgba2color(&color,&bcolorstring);
357 setbcolor();
358 FlagsChanged = 1;
359}
360
361MODULE_EXPORT void button_bg_color(GtkWidget *w)
362{
363 GdkRGBA color;
364 if (!human_action)
365 return;
366 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color);
367 free(bgcolorstring);
368 rgba2color(&color,&bgcolorstring);
369 setbgcolor();
370 FlagsChanged = 1;
371}
372
373#if 0
374MODULE_EXPORT void button_guts_color(GtkWidget *w)
375{
376 GdkRGBA color;
377 if (!human_action)
378 return;
379 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color);
380 free(gutsColor);
381 rgba2color(&color,&gutsColor);
382 setgutsgcColor();
383 FlagsChanged = 1;
384}
385#endif
386
387#if 0
388MODULE_EXPORT void button_squish_color(GtkWidget *w)
389{
390 GdkRGBA color;
391 if (!human_action)
392 return;
393 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color);
394 free(gutsColor);
395 rgba2color(&color,&gutsColor);
396}
397#endif
398
399FILE *openflagsfile(char *mode)
400{
401 char *h = getenv("HOME");
402 if (h == NULL)
403 return NULL;
404 char *flagsfile = (char*)malloc((strlen(h)+strlen(FLAGSFILE)+2)*sizeof(char));
405 flagsfile[0] = 0;
406 strcat(flagsfile,h);
407 strcat(flagsfile,"/");
408 strcat(flagsfile,FLAGSFILE);
409 FILE *f = fopen(flagsfile,mode);
410 P("openflagsfile %s %s\n",flagsfile,mode);
411 free(flagsfile);
412 return f;
413}
414
415void ReadFlags()
416{
417 FILE *f = openflagsfile(_("r"));
418 if (f == NULL)
419 {
420 I("Cannot read $HOME/%s\n",FLAGSFILE);
421 return;
422 }
423 int lineno = 1;
424 while(1)
425 {
426 char *line = NULL;
427 size_t n = 0;
428 int m = getline(&line,&n,f);
429 if (m<0)
430 break;
431 P("ReadFlags: %d [%s]\n",lineno,line);
432 char *flag = (char*)malloc((strlen(line)+1)*sizeof(char));
433 m = sscanf(line, "%s", flag);
434 if (m == EOF || m == 0)
435 continue;
436 char *rest = line + strlen(flag);
437
438 char *p;
439 p = rest;
440 while (*p == ' ' || *p == '\t' || *p == '\n')
441 p++;
442 rest = p;
443 p = &line[strlen(line)-1];
444 while (*p == ' ' || *p == '\t' || *p == '\n')
445 p--;
446 *(p+1) = 0;
447
448 P("ReadFlags: %s [%s]\n",flag,rest);
449 if(!strcmp(flag,"fishes"))
450 {
451 flimit = atoi(rest);
452 P("flimit: %d\n",flimit);
453 }
454 else if(!strcmp(flag,"bubbles"))
455 {
456 blimit = atoi(rest);
457 P("bubbles: %d\n",blimit);
458 }
459 else if(!strcmp(flag,"speed"))
460 {
461 speedfactor = atoi(rest)/100.0;
462 P("speedfactor: %d\n",(int)(100*speedfactor));
463 }
464 else if(!strcmp(flag,"bc"))
465 {
466 if(bcolorstring)
467 free(bcolorstring);
468 bcolorstring = strdup(rest);
469 P("bcolorstring: %s\n",bcolorstring);
470 }
471 else if(!strcmp(flag,"bgc"))
472 {
473 if(bgcolorstring)
474 free(bgcolorstring);
475 bgcolorstring = strdup(rest);
476 P("bcolorstring: %s\n",bgcolorstring);
477 }
478 lineno++;
479 free(line);
480 free(flag);
481 }
482 fclose(f);
483}
484
485void WriteFlags()
486{
487 FILE *f = openflagsfile(_("w"));
488 if (f == NULL)
489 {
490 I("Cannot write $HOME/%s\n",FLAGSFILE);
491 return;
492 }
493 fprintf(f, "fishes %d\n", flimit);
494 fprintf(f, "bubbles %d\n", blimit);
495 if (bcolorstring && strlen(bcolorstring))
496 fprintf(f, "bc %s\n", bcolorstring);
497 if(bgcolorstring && strlen(bgcolorstring))
498 fprintf(f, "bgc %s\n", bgcolorstring);
499 fprintf(f, "speed %d\n", (int)(100*speedfactor));
500 fclose(f);
501 init_pixmaps();
502}
503
504float bubblesfactor_to_scale(float n)
505{
506 float a,b;
507 ab(MaxBubbles, MinBubbles,&a,&b);
508 return mylog10f((n-b)/(a*MaxBubbles));
509}
510
511
512float scale_to_bubblesfactor(float scale)
513{
514 float a,b;
515 ab(MaxBubbles, MinBubbles,&a,&b);
516 return a * MaxBubbles*myexp10f(scale) + b;
517}
518
519float fishes_to_scale(float n)
520{
521 float a,b;
522 ab(MaxFishes, MinFishes, &a, &b);
523 float rc = mylog10f((n-b)/(a*MaxFishes));
524 P("ftos %f %f\n",n,rc);
525 return rc;
526}
527
528float scale_to_fishes(float scale)
529{
530 float a,b;
531 ab(MaxFishes, MinFishes, &a, &b);
532 return a * MaxFishes*myexp10f(scale) + b;
533}
534
535float speedfactor_to_scale(float n)
536{
537 float a,b;
538 ab(MaxSpeed, MinSpeed, &a, &b);
539 float rc = mylog10f((n-b)/(a*MaxSpeed));
540 P("stos %f %f\n",n,rc);
541 return rc;
542}
543
544float scale_to_speedfactor(float scale)
545{
546 float a,b;
547 ab(MaxSpeed, MinSpeed, &a, &b);
548 return 0.01*(a * MaxSpeed*myexp10f(scale) + b);
549}
550
551void iconify()
552{
553 gtk_window_iconify(GTK_WINDOW(hauptfenster));
554}
555
556void ui()
557{
558 P("here is uiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\n");
559
560 builder = gtk_builder_new_from_string (xfishtank_xml, -1);
561 gtk_builder_connect_signals (builder, builder);
562 hauptfenster = GTK_WIDGET(gtk_builder_get_object(builder, "hauptfenster"));
563
564 hauptfenstersc = gtk_widget_get_style_context(hauptfenster);
565
566 handle_css();
567 char wtitle[100];
568 wtitle[0] = 0;
569 strcat(wtitle,"XfishtanK");
570#ifdef HAVE_CONFIG_H
571 strcat(wtitle,"-");
572 strncat(wtitle,VERSION,99 - strlen(wtitle));
573#endif
574 gtk_window_set_title(GTK_WINDOW(hauptfenster),wtitle);
575 gtk_window_set_resizable(GTK_WINDOW(hauptfenster),False);
576 gtk_widget_show_all (hauptfenster);
577 g_signal_connect (GTK_WINDOW(hauptfenster), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
578 g_signal_connect (GTK_WINDOW(hauptfenster), "destroy", G_CALLBACK (gtk_main_quit), NULL);
579
580 init_ids();
581
582 init_pixmaps();
583 set_buttons();
584 g_timeout_add_full(G_PRIORITY_DEFAULT, 150, do_animate ,NULL, NULL);
585}
586
This page took 0.0389 seconds and 4 git commands to generate.