2 #-# Copyright © 2021 Eric Bina, Dave Black, TJ Phan,
3 #-# Vincent Renardias, Willem Vermin
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
14 #-# The above copyright notice and this permission notice shall
15 #-# be included in all copies or substantial portions of the Software.
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.
33 #include "xfishtank.h"
37 //#include "xfishtank.xpm"
44 #define MODULE_EXPORT extern "C" G_MODULE_EXPORT
46 #define MODULE_EXPORT G_MODULE_EXPORT
51 static int human_action
= 1; /* is it a human who is playing with the buttons? */
54 static GtkBuilder
*builder
;
55 static GtkWidget
*hauptfenster
;
56 static GtkStyleContext
*hauptfenstersc
;
58 static GtkWidget
*id_fishes
;
59 static GtkWidget
*id_fishesvalue
;
60 static GtkWidget
*id_speed
;
61 static GtkWidget
*id_speedvalue
;
62 static GtkWidget
*id_bubbles
;
63 //static GtkWidget *id_squish;
64 static GtkWidget
*id_logo1
;
65 static GtkWidget
*id_logo2
;
66 static GtkWidget
*id_logo3
;
67 static GtkWidget
*id_bubble_color
;
68 static GtkWidget
*id_bg_color
;
69 static GtkWidget
*id_bubblesvalue
;
70 //static GtkWidget *id_squish_picture;
75 static void handle_css(void);
76 static void init_ids(void);
77 static void init_pixmaps(void);
78 static FILE *openflagsfile(char *mode
);
79 static float scale_to_bubblesfactor(float scale
);
80 static void ab(float Max
, float Min
, float *a
, float *b
);
81 static float fishes_to_scale(float n
);
82 static float bubblesfactor_to_scale(float n
);
83 static float scale_to_fishes(float scale
);
84 static float speedfactor_to_scale(float n
);
85 static float scale_to_speedfactor(float scale
);
86 static void init_pixmap(GtkWidget
*id
, int n
, int flip
);
87 static int do_animate(void *dummy
);
90 // Sometimes it is good to have a logarithmic scale, such that
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)
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.
107 // Given V, compute s:
109 // s = log10((V-b)/(a*M))
112 void ab(float Max
, float Min
, float *a
, float *b
)
114 *a
= (Max
- Min
)/(9.0*Max
);
118 static const float MaxBubbles
= 500;
119 static const float MinBubbles
= 1;
121 static const float MaxFishes
= 200;
122 static const float MinFishes
= 1.0;
124 static const float MaxSpeed
= 400;
125 static const float MinSpeed
= 30;
132 void show_dialog(int type
, const char *format
, const char *text
)
134 GtkMessageType message_type
;
136 message_type
= GTK_MESSAGE_ERROR
;
138 message_type
= GTK_MESSAGE_INFO
;
140 GtkWidget
*m
= gtk_message_dialog_new(GTK_WINDOW(hauptfenster
),
147 g_signal_connect(m
,"response",G_CALLBACK(gtk_main_quit
),NULL
);
148 gtk_widget_show_all(m
);
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"));
168 int do_animate(void *dummy
)
172 P("m: %d %d\n",m
, logo
[m
]);
173 // needs adjustment if NUM_FRAMES != 2
174 if (logo
[m
]%NUM_FRAMES
)
191 init_pixmap(id
, logo
[m
], flip
[m
]);
196 void init_pixmap(GtkWidget
*id
, int n
, int flip
)
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
);
216 pixbuf1
= gdk_pixbuf_scale_simple(pixbuf
,w
,h
,GDK_INTERP_BILINEAR
);
217 g_object_unref(pixbuf
);
221 pixbuf2
= gdk_pixbuf_flip(pixbuf1
,1);
222 gtk_image_set_from_pixbuf(GTK_IMAGE(id
),pixbuf2
);
223 g_object_unref(pixbuf2
);
226 gtk_image_set_from_pixbuf(GTK_IMAGE(id
),pixbuf1
);
228 g_object_unref(pixbuf1
);
236 logo
[i
] = NUM_FRAMES
*(int)(drand48()*NUM_FISH
);
237 flip
[i
] = drand48()*2;
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]);
246 int h
= human_action
;
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
);
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
);
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
);
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
);
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
);
277 MODULE_EXPORT
void button_fishes(GtkWidget
*w
)
281 float value
= gtk_range_get_value(GTK_RANGE(w
));
282 P("fishes: %f\n",value
);
283 create_fishes(scale_to_fishes(value
));
286 sprintf(buf
,"%d",flimit
);
287 gtk_label_set_text(GTK_LABEL(id_fishesvalue
),buf
);
290 MODULE_EXPORT
void button_bubbles(GtkWidget
*w
)
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
));
299 sprintf(buf
,"%d",blimit
);
300 gtk_label_set_text(GTK_LABEL(id_bubblesvalue
),buf
);
303 MODULE_EXPORT
void button_speed(GtkWidget
*w
)
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
);
313 sprintf(buf
,"%d",(int)(100*speedfactor
));
314 gtk_label_set_text(GTK_LABEL(id_speedvalue
),buf
);
318 MODULE_EXPORT
void button_defaults()
321 create_fishes(flimit
);
322 create_bubbles(blimit
);
325 setspeed(speedfactor
);
332 MODULE_EXPORT
void button_squish(GtkWidget
*w
)
336 int value
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w
));
337 P("squish: %d\n",value
);
338 handle_squish(value
);
342 MODULE_EXPORT
void button_iconify()
346 gtk_window_iconify(GTK_WINDOW(hauptfenster
));
349 MODULE_EXPORT
void button_bubble_color(GtkWidget
*w
)
354 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w
),&color
);
356 rgba2color(&color
,&bcolorstring
);
361 MODULE_EXPORT
void button_bg_color(GtkWidget
*w
)
366 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w
),&color
);
368 rgba2color(&color
,&bgcolorstring
);
374 MODULE_EXPORT
void button_guts_color(GtkWidget
*w
)
379 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w
),&color
);
381 rgba2color(&color
,&gutsColor
);
388 MODULE_EXPORT
void button_squish_color(GtkWidget
*w
)
393 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w
),&color
);
395 rgba2color(&color
,&gutsColor
);
399 FILE *openflagsfile(char *mode
)
401 char *h
= getenv("HOME");
404 char *flagsfile
= (char*)malloc((strlen(h
)+strlen(FLAGSFILE
)+2)*sizeof(char));
407 strcat(flagsfile
,"/");
408 strcat(flagsfile
,FLAGSFILE
);
409 FILE *f
= fopen(flagsfile
,mode
);
410 P("openflagsfile %s %s\n",flagsfile
,mode
);
417 FILE *f
= openflagsfile(_("r"));
420 I("Cannot read $HOME/%s\n",FLAGSFILE
);
428 int m
= getline(&line
,&n
,f
);
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)
436 char *rest
= line
+ strlen(flag
);
440 while (*p
== ' ' || *p
== '\t' || *p
== '\n')
443 p
= &line
[strlen(line
)-1];
444 while (*p
== ' ' || *p
== '\t' || *p
== '\n')
448 P("ReadFlags: %s [%s]\n",flag
,rest
);
449 if(!strcmp(flag
,"fishes"))
452 P("flimit: %d\n",flimit
);
454 else if(!strcmp(flag
,"bubbles"))
457 P("bubbles: %d\n",blimit
);
459 else if(!strcmp(flag
,"speed"))
461 speedfactor
= atoi(rest
)/100.0;
462 P("speedfactor: %d\n",(int)(100*speedfactor
));
464 else if(!strcmp(flag
,"bc"))
468 bcolorstring
= strdup(rest
);
469 P("bcolorstring: %s\n",bcolorstring
);
471 else if(!strcmp(flag
,"bgc"))
475 bgcolorstring
= strdup(rest
);
476 P("bcolorstring: %s\n",bgcolorstring
);
487 FILE *f
= openflagsfile(_("w"));
490 I("Cannot write $HOME/%s\n",FLAGSFILE
);
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
));
504 float bubblesfactor_to_scale(float n
)
507 ab(MaxBubbles
, MinBubbles
,&a
,&b
);
508 return mylog10f((n
-b
)/(a
*MaxBubbles
));
512 float scale_to_bubblesfactor(float scale
)
515 ab(MaxBubbles
, MinBubbles
,&a
,&b
);
516 return a
* MaxBubbles
*myexp10f(scale
) + b
;
519 float fishes_to_scale(float n
)
522 ab(MaxFishes
, MinFishes
, &a
, &b
);
523 float rc
= mylog10f((n
-b
)/(a
*MaxFishes
));
524 P("ftos %f %f\n",n
,rc
);
528 float scale_to_fishes(float scale
)
531 ab(MaxFishes
, MinFishes
, &a
, &b
);
532 return a
* MaxFishes
*myexp10f(scale
) + b
;
535 float speedfactor_to_scale(float n
)
538 ab(MaxSpeed
, MinSpeed
, &a
, &b
);
539 float rc
= mylog10f((n
-b
)/(a
*MaxSpeed
));
540 P("stos %f %f\n",n
,rc
);
544 float scale_to_speedfactor(float scale
)
547 ab(MaxSpeed
, MinSpeed
, &a
, &b
);
548 return 0.01*(a
* MaxSpeed
*myexp10f(scale
) + b
);
553 gtk_window_iconify(GTK_WINDOW(hauptfenster
));
558 P("here is uiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\n");
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"));
564 hauptfenstersc
= gtk_widget_get_style_context(hauptfenster
);
569 strcat(wtitle
,"XfishtanK");
572 strncat(wtitle
,VERSION
,99 - strlen(wtitle
));
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
);
584 g_timeout_add_full(G_PRIORITY_DEFAULT
, 150, do_animate
,NULL
, NULL
);