X-Git-Url: http://git.ieval.ro/?p=xfishtank.git;a=blobdiff_plain;f=src%2Fui.c;fp=src%2Fui.c;h=50180850feb40da05f8ade326b40585919d2a990;hp=0000000000000000000000000000000000000000;hb=4c1bd65b5f48075ff80be1e401beb5ff21b4b89e;hpb=4deccbc95c1e3e86669d84c2f6922ee6a5f5180a diff --git a/src/ui.c b/src/ui.c new file mode 100644 index 0000000..5018085 --- /dev/null +++ b/src/ui.c @@ -0,0 +1,586 @@ +/* -copyright- +#-# Copyright © 2021 Eric Bina, Dave Black, TJ Phan, +#-# Vincent Renardias, Willem Vermin +#-# +#-# Permission is hereby granted, free of charge, to any person +#-# obtaining a copy of this software and associated documentation +#-# files (the “Software”), to deal in the Software without +#-# restriction, including without limitation the rights to use, +#-# copy, modify, merge, publish, distribute, sublicense, and/or +#-# sell copies of the Software, and to permit persons to whom +#-# the Software is furnished to do so, subject to the following +#-# conditions: +#-# +#-# The above copyright notice and this permission notice shall +#-# be included in all copies or substantial portions of the Software. +#-# +#-# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +#-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +#-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +#-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +#-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +#-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +#-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +#-# OTHER DEALINGS IN THE SOFTWARE. +#-# +*/ + +#include +#include +#include "ui_xml.h" +#include "ui.h" +#include "debug.h" +#include "xfishtank.h" +#include "utils.h" +#include "fishes.h" + +//#include "xfishtank.xpm" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +#define MODULE_EXPORT extern "C" G_MODULE_EXPORT +#else +#define MODULE_EXPORT G_MODULE_EXPORT +#endif + +int FlagsChanged = 1; + +static int human_action = 1; /* is it a human who is playing with the buttons? */ + +#define NTYPES 16 +static GtkBuilder *builder; +static GtkWidget *hauptfenster; +static GtkStyleContext *hauptfenstersc; +static char buf[100]; +static GtkWidget *id_fishes; +static GtkWidget *id_fishesvalue; +static GtkWidget *id_speed; +static GtkWidget *id_speedvalue; +static GtkWidget *id_bubbles; +//static GtkWidget *id_squish; +static GtkWidget *id_logo1; +static GtkWidget *id_logo2; +static GtkWidget *id_logo3; +static GtkWidget *id_bubble_color; +static GtkWidget *id_bg_color; +static GtkWidget *id_bubblesvalue; +//static GtkWidget *id_squish_picture; + +static int logo[3]; +static int flip[3]; + +static void handle_css(void); +static void init_ids(void); +static void init_pixmaps(void); +static FILE *openflagsfile(char *mode); +static float scale_to_bubblesfactor(float scale); +static void ab(float Max, float Min, float *a, float *b); +static float fishes_to_scale(float n); +static float bubblesfactor_to_scale(float n); +static float scale_to_fishes(float scale); +static float speedfactor_to_scale(float n); +static float scale_to_speedfactor(float scale); +static void init_pixmap(GtkWidget *id, int n, int flip); +static int do_animate(void *dummy); + + +// Sometimes it is good to have a logarithmic scale, such that +// +// V = a*M*10**s + b +// +// where: V = parameter (e.g. SpeedFactor) +// M = desired maximum of V (e.g. 4.0) +// s = value of the gtkscale (0 .. 1.0) +// Furthermore: m = desired minimum of V (e.g. 0.2) +// +// Then: +// a = (M - m)/(9*M) +// b = m - a*M +// +// The placement of a is a logical choice, the placement of b is +// more or less random. I need a constant next to a, because I want +// to define minimum V AND maximum V. +// +// Given V, compute s: +// +// s = log10((V-b)/(a*M)) +// + +void ab(float Max, float Min, float *a, float *b) +{ + *a = (Max - Min)/(9.0*Max); + *b = Min - (*a)*Max; +} + +static const float MaxBubbles = 500; +static const float MinBubbles = 1; + +static const float MaxFishes = 200; +static const float MinFishes = 1.0; + +static const float MaxSpeed = 400; +static const float MinSpeed = 30; + +void handle_css() +{ +} + + +void show_dialog(int type, const char *format, const char *text) +{ + GtkMessageType message_type; + if (type == 1) + message_type = GTK_MESSAGE_ERROR; + else + message_type = GTK_MESSAGE_INFO; + + GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(hauptfenster), + GTK_DIALOG_MODAL, + message_type, + GTK_BUTTONS_OK, + format, + text + ); + g_signal_connect(m,"response",G_CALLBACK(gtk_main_quit),NULL); + gtk_widget_show_all(m); +} + +void init_ids() +{ + id_fishes = GTK_WIDGET(gtk_builder_get_object(builder, "id-fishes")); + id_fishesvalue = GTK_WIDGET(gtk_builder_get_object(builder, "id-fishesvalue")); + id_speed = GTK_WIDGET(gtk_builder_get_object(builder, "id-speed")); + id_speedvalue = GTK_WIDGET(gtk_builder_get_object(builder, "id-speedvalue")); + id_logo1 = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo1")); + id_logo2 = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo2")); + id_logo3 = GTK_WIDGET(gtk_builder_get_object(builder, "id-logo3")); + id_bubble_color = GTK_WIDGET(gtk_builder_get_object(builder, "id-bubble-color")); + id_bg_color = GTK_WIDGET(gtk_builder_get_object(builder, "id-bg-color")); + id_bubbles = GTK_WIDGET(gtk_builder_get_object(builder, "id-bubbles")); + //id_squish = GTK_WIDGET(gtk_builder_get_object(builder, "id-squish")); + id_bubblesvalue = GTK_WIDGET(gtk_builder_get_object(builder, "id-bubblesvalue")); + //id_squish_picture = GTK_WIDGET(gtk_builder_get_object(builder, "id-squish-picture")); +} + +int do_animate(void *dummy) +{ + (void)dummy; + int m = drand48()*3; + P("m: %d %d\n",m, logo[m]); + // needs adjustment if NUM_FRAMES != 2 + if (logo[m]%NUM_FRAMES) + logo[m]--; + else + logo[m]++; + GtkWidget *id; + switch(m) + { + case 0: + id = id_logo1; + break; + case 1: + id = id_logo2; + break; + case 2: + id = id_logo3; + break; + } + init_pixmap(id, logo[m], flip[m]); + + return TRUE; +} + +void init_pixmap(GtkWidget *id, int n, int flip) +{ + int w,h; + float w0,h0; + + GdkPixbuf *pixbuf, *pixbuf1, *pixbuf2; + pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)fishes[n]); + w0 = gdk_pixbuf_get_width(pixbuf); + h0 = gdk_pixbuf_get_height(pixbuf); + if (w0 > h0) + { + w = 64; + h = h0/w0*w; + } + else + { + h = 64; + w = w0/h0*h; + } + + pixbuf1 = gdk_pixbuf_scale_simple(pixbuf,w,h,GDK_INTERP_BILINEAR); + g_object_unref(pixbuf); + + if(flip) + { + pixbuf2 = gdk_pixbuf_flip(pixbuf1,1); + gtk_image_set_from_pixbuf(GTK_IMAGE(id),pixbuf2); + g_object_unref(pixbuf2); + } + else + gtk_image_set_from_pixbuf(GTK_IMAGE(id),pixbuf1); + + g_object_unref(pixbuf1); +} + +void init_pixmaps() +{ + int i; + for (i=0; i<3; i++) + { + logo[i] = NUM_FRAMES*(int)(drand48()*NUM_FISH); + flip[i] = drand48()*2; + } + init_pixmap(id_logo1,logo[0],flip[0]); + init_pixmap(id_logo2,logo[1],flip[1]); + init_pixmap(id_logo3,logo[2],flip[2]); +} + +void set_buttons() +{ + int h = human_action; + human_action = 0; + + gtk_range_set_value(GTK_RANGE(id_fishes), fishes_to_scale(flimit)); + sprintf(buf,"%d",flimit); + gtk_label_set_text(GTK_LABEL(id_fishesvalue),buf); + + gtk_range_set_value(GTK_RANGE(id_bubbles),bubblesfactor_to_scale(blimit)); + sprintf(buf,"%d",(int)(blimit)); + gtk_label_set_text(GTK_LABEL(id_bubblesvalue),buf); + + gtk_range_set_value(GTK_RANGE(id_speed),speedfactor_to_scale(100*speedfactor)); + P("speedfactor: %f %f\n",speedfactor, speedfactor_to_scale(100*speedfactor)); + sprintf(buf,"%d",(int)(100*speedfactor)); + gtk_label_set_text(GTK_LABEL(id_speedvalue),buf); + + GdkRGBA color; + P("bcolor: %s\n",bcolorstring); + gdk_rgba_parse(&color, bcolorstring); + gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(id_bubble_color),&color); + + P("bgcolor: %s\n",bgcolorstring); + gdk_rgba_parse(&color, bgcolorstring); + gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(id_bg_color),&color); + + human_action = h; + + FlagsChanged = 1; +} + + +MODULE_EXPORT void button_fishes(GtkWidget *w) +{ + if (!human_action) + return; + float value = gtk_range_get_value(GTK_RANGE(w)); + P("fishes: %f\n",value); + create_fishes(scale_to_fishes(value)); + FlagsChanged = 1; + + sprintf(buf,"%d",flimit); + gtk_label_set_text(GTK_LABEL(id_fishesvalue),buf); +} + +MODULE_EXPORT void button_bubbles(GtkWidget *w) +{ + if (!human_action) + return; + float value = gtk_range_get_value(GTK_RANGE(w)); + P("bubbles: %f %d\n",value,blimit); + create_bubbles(scale_to_bubblesfactor(value)); + FlagsChanged = 1; + + sprintf(buf,"%d",blimit); + gtk_label_set_text(GTK_LABEL(id_bubblesvalue),buf); +} + +MODULE_EXPORT void button_speed(GtkWidget *w) +{ + if (!human_action) + return; + float value = gtk_range_get_value(GTK_RANGE(w)); + P("speedfactor: %f %f\n",value,speedfactor); + setspeed(scale_to_speedfactor(value)); + P("speedfactor: %f\n",speedfactor); + FlagsChanged = 1; + + sprintf(buf,"%d",(int)(100*speedfactor)); + gtk_label_set_text(GTK_LABEL(id_speedvalue),buf); +} + + +MODULE_EXPORT void button_defaults() +{ + set_defaults(); + create_fishes(flimit); + create_bubbles(blimit); + setbcolor(); + setbgcolor(); + setspeed(speedfactor); + if (!human_action) + return; + set_buttons(); +} + +#if 0 +MODULE_EXPORT void button_squish(GtkWidget *w) +{ + if (!human_action) + return; + int value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); + P("squish: %d\n",value); + handle_squish(value); + FlagsChanged = 1; +} +#endif +MODULE_EXPORT void button_iconify() +{ + if (!human_action) + return; + gtk_window_iconify(GTK_WINDOW(hauptfenster)); +} + +MODULE_EXPORT void button_bubble_color(GtkWidget *w) +{ + GdkRGBA color; + if (!human_action) + return; + gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color); + free(bcolorstring); + rgba2color(&color,&bcolorstring); + setbcolor(); + FlagsChanged = 1; +} + +MODULE_EXPORT void button_bg_color(GtkWidget *w) +{ + GdkRGBA color; + if (!human_action) + return; + gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color); + free(bgcolorstring); + rgba2color(&color,&bgcolorstring); + setbgcolor(); + FlagsChanged = 1; +} + +#if 0 +MODULE_EXPORT void button_guts_color(GtkWidget *w) +{ + GdkRGBA color; + if (!human_action) + return; + gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color); + free(gutsColor); + rgba2color(&color,&gutsColor); + setgutsgcColor(); + FlagsChanged = 1; +} +#endif + +#if 0 +MODULE_EXPORT void button_squish_color(GtkWidget *w) +{ + GdkRGBA color; + if (!human_action) + return; + gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color); + free(gutsColor); + rgba2color(&color,&gutsColor); +} +#endif + +FILE *openflagsfile(char *mode) +{ + char *h = getenv("HOME"); + if (h == NULL) + return NULL; + char *flagsfile = (char*)malloc((strlen(h)+strlen(FLAGSFILE)+2)*sizeof(char)); + flagsfile[0] = 0; + strcat(flagsfile,h); + strcat(flagsfile,"/"); + strcat(flagsfile,FLAGSFILE); + FILE *f = fopen(flagsfile,mode); + P("openflagsfile %s %s\n",flagsfile,mode); + free(flagsfile); + return f; +} + +void ReadFlags() +{ + FILE *f = openflagsfile(_("r")); + if (f == NULL) + { + I("Cannot read $HOME/%s\n",FLAGSFILE); + return; + } + int lineno = 1; + while(1) + { + char *line = NULL; + size_t n = 0; + int m = getline(&line,&n,f); + if (m<0) + break; + P("ReadFlags: %d [%s]\n",lineno,line); + char *flag = (char*)malloc((strlen(line)+1)*sizeof(char)); + m = sscanf(line, "%s", flag); + if (m == EOF || m == 0) + continue; + char *rest = line + strlen(flag); + + char *p; + p = rest; + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + rest = p; + p = &line[strlen(line)-1]; + while (*p == ' ' || *p == '\t' || *p == '\n') + p--; + *(p+1) = 0; + + P("ReadFlags: %s [%s]\n",flag,rest); + if(!strcmp(flag,"fishes")) + { + flimit = atoi(rest); + P("flimit: %d\n",flimit); + } + else if(!strcmp(flag,"bubbles")) + { + blimit = atoi(rest); + P("bubbles: %d\n",blimit); + } + else if(!strcmp(flag,"speed")) + { + speedfactor = atoi(rest)/100.0; + P("speedfactor: %d\n",(int)(100*speedfactor)); + } + else if(!strcmp(flag,"bc")) + { + if(bcolorstring) + free(bcolorstring); + bcolorstring = strdup(rest); + P("bcolorstring: %s\n",bcolorstring); + } + else if(!strcmp(flag,"bgc")) + { + if(bgcolorstring) + free(bgcolorstring); + bgcolorstring = strdup(rest); + P("bcolorstring: %s\n",bgcolorstring); + } + lineno++; + free(line); + free(flag); + } + fclose(f); +} + +void WriteFlags() +{ + FILE *f = openflagsfile(_("w")); + if (f == NULL) + { + I("Cannot write $HOME/%s\n",FLAGSFILE); + return; + } + fprintf(f, "fishes %d\n", flimit); + fprintf(f, "bubbles %d\n", blimit); + if (bcolorstring && strlen(bcolorstring)) + fprintf(f, "bc %s\n", bcolorstring); + if(bgcolorstring && strlen(bgcolorstring)) + fprintf(f, "bgc %s\n", bgcolorstring); + fprintf(f, "speed %d\n", (int)(100*speedfactor)); + fclose(f); + init_pixmaps(); +} + +float bubblesfactor_to_scale(float n) +{ + float a,b; + ab(MaxBubbles, MinBubbles,&a,&b); + return mylog10f((n-b)/(a*MaxBubbles)); +} + + +float scale_to_bubblesfactor(float scale) +{ + float a,b; + ab(MaxBubbles, MinBubbles,&a,&b); + return a * MaxBubbles*myexp10f(scale) + b; +} + +float fishes_to_scale(float n) +{ + float a,b; + ab(MaxFishes, MinFishes, &a, &b); + float rc = mylog10f((n-b)/(a*MaxFishes)); + P("ftos %f %f\n",n,rc); + return rc; +} + +float scale_to_fishes(float scale) +{ + float a,b; + ab(MaxFishes, MinFishes, &a, &b); + return a * MaxFishes*myexp10f(scale) + b; +} + +float speedfactor_to_scale(float n) +{ + float a,b; + ab(MaxSpeed, MinSpeed, &a, &b); + float rc = mylog10f((n-b)/(a*MaxSpeed)); + P("stos %f %f\n",n,rc); + return rc; +} + +float scale_to_speedfactor(float scale) +{ + float a,b; + ab(MaxSpeed, MinSpeed, &a, &b); + return 0.01*(a * MaxSpeed*myexp10f(scale) + b); +} + +void iconify() +{ + gtk_window_iconify(GTK_WINDOW(hauptfenster)); +} + +void ui() +{ + P("here is uiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\n"); + + builder = gtk_builder_new_from_string (xfishtank_xml, -1); + gtk_builder_connect_signals (builder, builder); + hauptfenster = GTK_WIDGET(gtk_builder_get_object(builder, "hauptfenster")); + + hauptfenstersc = gtk_widget_get_style_context(hauptfenster); + + handle_css(); + char wtitle[100]; + wtitle[0] = 0; + strcat(wtitle,"XfishtanK"); +#ifdef HAVE_CONFIG_H + strcat(wtitle,"-"); + strncat(wtitle,VERSION,99 - strlen(wtitle)); +#endif + gtk_window_set_title(GTK_WINDOW(hauptfenster),wtitle); + gtk_window_set_resizable(GTK_WINDOW(hauptfenster),False); + gtk_widget_show_all (hauptfenster); + g_signal_connect (GTK_WINDOW(hauptfenster), "delete-event", G_CALLBACK (gtk_main_quit), NULL); + g_signal_connect (GTK_WINDOW(hauptfenster), "destroy", G_CALLBACK (gtk_main_quit), NULL); + + init_ids(); + + init_pixmaps(); + set_buttons(); + g_timeout_add_full(G_PRIORITY_DEFAULT, 150, do_animate ,NULL, NULL); +} +