gcuperiodic.c

00001 /* 
00002  * Gnome Chemisty Utils
00003  * gcuperiodic.c 
00004  *
00005  * Copyright (C) 2002-2010 Jean Bréfort <jean.brefort@normalesup.org>
00006  *
00007  * This program is free software; you can redistribute it and/or 
00008  * modify it under the terms of the GNU General Public License as 
00009  * published by the Free Software Foundation; either version 2 of the
00010  * License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
00020  * USA
00021  */
00022 
00023 #include "config.h"
00024 #include "gcuperiodic.h"
00025 #include "chemistry.h"
00026 #include <goffice/goffice.h>
00027 #include <string.h>
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <glib/gi18n-lib.h>
00031 
00032 struct _GcuPeriodic
00033 {
00034         GtkBin bin;
00035         
00036         GtkVBox* vbox;
00037         GtkToggleButton* buttons[119];
00038         GtkLabel* labels[119];
00039         GtkNotebook *book;
00040         guint Z;
00041         gboolean can_unselect;
00042         unsigned colorstyle;
00043         GArray *colorschemes;
00044         unsigned nbschemes;
00045 };
00046 
00047 struct _GcuPeriodicClass
00048 {
00049         GtkBinClass parent_class;
00050 
00051         void (* element_changed_event)(GcuPeriodic *periodic);
00052 };
00053 
00054 static unsigned DefaultRed[4], DefaultGreen[4], DefaultBlue[4];
00055 
00056 GType
00057 gcu_periodic_color_style_get_type (void)
00058 {
00059   static GType etype = 0;
00060   if (etype == 0) {
00061     static const GEnumValue values[] = {
00062       { GCU_PERIODIC_COLOR_NONE, "GCU_PERIODIC_COLOR_NONE", "none" },
00063       { GCU_PERIODIC_COLOR_DEFAULT, "GCU_PERIODIC_COLOR_DEFAULT", "default" },
00064       { 0, NULL, NULL }
00065     };
00066     etype = g_enum_register_static ("GcuPeriodicColorStyle", values);
00067   }
00068   return etype;
00069 }
00070 #define GCU_TYPE_PERIODIC_COLOR_STYLE_TYPE (gcu_periodic_color_style_get_type())
00071 
00072 static GtkBinClass *parent_class = NULL;
00073 
00074 struct ColorScheme {
00075         GcuPeriodicColorFunc f;
00076         int page;
00077         gpointer data;
00078 };
00079 
00080 enum {
00081   ELEMENT_CHANGED,
00082   LAST_SIGNAL
00083 };
00084 
00085 enum {
00086         PROP_0,
00087         PROP_CAN_UNSELECT,
00088         PROP_COLOR_STYLE
00089 };
00090 
00091 static guint gcu_periodic_signals[LAST_SIGNAL] = { 0 };
00092 
00093 static void gcu_periodic_class_init (GcuPeriodicClass  *klass);
00094 static void gcu_periodic_init(GcuPeriodic *periodic);
00095 static void gcu_periodic_finalize(GObject *object);
00096 static void gcu_periodic_size_allocate(GcuPeriodic* w, GtkAllocation *allocation);
00097 static void gcu_periodic_size_request(GcuPeriodic* w, GtkRequisition *requisition);
00098 static void gcu_periodic_set_property (GObject              *object,
00099                                             guint                 param_id,
00100                                             const GValue         *value,
00101                                             GParamSpec           *pspec);
00102 static void gcu_periodic_get_property (GObject              *object,
00103                                             guint                 param_id,
00104                                             GValue               *value,
00105                                             GParamSpec           *pspec);
00106 static void on_clicked(GtkToggleButton *button, GcuPeriodic* periodic);
00107 
00108 GType
00109 gcu_periodic_get_type (void)
00110 {
00111         static GType periodic_type = 0;
00112   
00113         if (!periodic_type)
00114         {
00115                 static const GTypeInfo periodic_info =
00116                 {
00117                         sizeof (GcuPeriodicClass),
00118                         NULL,           /* base_init */
00119                         NULL,           /* base_finalize */
00120                         (GClassInitFunc) gcu_periodic_class_init,
00121                         NULL,           /* class_finalize */
00122                         NULL,           /* class_data */
00123                         sizeof (GcuPeriodic),
00124                         0,              /* n_preallocs */
00125                         (GInstanceInitFunc) gcu_periodic_init,
00126                         NULL
00127                 };
00128 
00129                 periodic_type = g_type_register_static (GTK_TYPE_BIN, "GcuPeriodic", &periodic_info, 0);
00130         }
00131   
00132         return periodic_type;
00133 }
00134 
00135 void gcu_periodic_class_init (GcuPeriodicClass *klass)
00136 {
00137         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
00138         GtkWidgetClass * widget_class = GTK_WIDGET_CLASS (klass);
00139         parent_class = (GtkBinClass*) g_type_class_peek_parent (klass);
00140         
00141         gobject_class->set_property = gcu_periodic_set_property;
00142         gobject_class->get_property = gcu_periodic_get_property;
00143         klass->element_changed_event = NULL;
00144         gcu_periodic_signals[ELEMENT_CHANGED] =
00145         g_signal_new ("element_changed",
00146                                   G_TYPE_FROM_CLASS(gobject_class),
00147                                   G_SIGNAL_RUN_LAST,
00148                                   G_STRUCT_OFFSET(GcuPeriodicClass, element_changed_event),
00149                                   NULL, NULL,
00150                                   g_cclosure_marshal_VOID__UINT,
00151                                   G_TYPE_NONE, 1,
00152                                   G_TYPE_UINT
00153                                   );
00154         g_object_class_install_property
00155                         (gobject_class,
00156                          PROP_CAN_UNSELECT,
00157                          g_param_spec_boolean ("can_unselect", NULL, NULL,
00158                                    FALSE,
00159                                    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
00160         g_object_class_install_property
00161                         (gobject_class,
00162                          PROP_COLOR_STYLE,
00163                          g_param_spec_uint ("color-style", NULL, NULL,
00164                                                                 GCU_PERIODIC_COLOR_NONE, G_MAXUINT,
00165                                                                 GCU_PERIODIC_COLOR_NONE,
00166                                                                 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
00167         gobject_class->finalize = gcu_periodic_finalize;
00168         widget_class->size_request = (void(*)(GtkWidget*, GtkRequisition*)) gcu_periodic_size_request;
00169         widget_class->size_allocate = (void(*)(GtkWidget*, GtkAllocation*)) gcu_periodic_size_allocate;
00170 }
00171 
00172 void gcu_periodic_init (GcuPeriodic *periodic)
00173 {
00174         GtkBuilder* xml;
00175         GtkStyle* style;
00176         char name[8] = "elt";
00177         GtkToggleButton* button;
00178         int i;
00179         xml = go_gtk_builder_new (UIDIR"/gcuperiodic.ui", GETTEXT_PACKAGE, NULL);
00180         g_return_if_fail (xml);
00181         periodic->vbox = GTK_VBOX (gtk_builder_get_object (xml, "vbox1"));
00182         periodic->book = GTK_NOTEBOOK (gtk_builder_get_object (xml, "book"));
00183         periodic->colorstyle = GCU_PERIODIC_COLOR_NONE;
00184         memset(periodic->buttons, 0, sizeof (GtkToggleButton*) * 119);
00185         for (i = 1; i <= 118; i++) {
00186                 sprintf(name + 3, "%d", i);
00187                 button = (GtkToggleButton*) gtk_builder_get_object (xml, name);
00188                 if (GTK_IS_TOGGLE_BUTTON (button)) {
00189                         gtk_widget_set_tooltip_text (GTK_WIDGET(button), gcu_element_get_name(i));
00190                         periodic->buttons[i] = button;
00191                         periodic->labels[i] = GTK_LABEL (gtk_bin_get_child (GTK_BIN (button)));
00192                         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (on_clicked), periodic);
00193                 }
00194         }
00195         style = gtk_style_copy (gtk_widget_get_style (GTK_WIDGET (periodic->buttons[1])));
00196         DefaultRed[0] = style->bg[0].red;
00197         DefaultGreen[0] = style->bg[0].green;
00198         DefaultBlue[0] = style->bg[0].blue;
00199         DefaultRed[1] = style->bg[1].red;
00200         DefaultGreen[1] = style->bg[1].green;
00201         DefaultBlue[1] = style->bg[1].blue;
00202         DefaultRed[2] = style->bg[2].red;
00203         DefaultGreen[2] = style->bg[2].green;
00204         DefaultBlue[2] = style->bg[2].blue;
00205         DefaultRed[3] = style->bg[3].red;
00206         DefaultGreen[3] = style->bg[3].green;
00207         DefaultBlue[3] = style->bg[3].blue;
00208         g_object_unref (style);
00209         periodic->Z = 0;
00210         gtk_container_add (GTK_CONTAINER (periodic), GTK_WIDGET (periodic->vbox));
00211         gtk_widget_show_all (GTK_WIDGET (periodic));
00212         periodic->colorschemes = g_array_new (FALSE, FALSE, sizeof (struct ColorScheme));
00213         g_object_unref (xml);
00214 }
00215 
00216 static void gcu_periodic_finalize (GObject *object)
00217 {
00218         GcuPeriodic *periodic = (GcuPeriodic*) object;
00219 
00220         g_array_free (periodic->colorschemes, FALSE);
00221 
00222         if (G_OBJECT_CLASS (parent_class)->finalize)
00223                 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
00224 }
00225 
00226 GtkWidget* gcu_periodic_new()
00227 {
00228         GtkBin* bin = GTK_BIN(g_object_new(GCU_TYPE_PERIODIC, NULL));
00229         return GTK_WIDGET(bin);
00230 }
00231 
00232 void on_clicked (GtkToggleButton *button, GcuPeriodic* periodic)
00233 {
00234         static gboolean change = FALSE;
00235         if (button != periodic->buttons[0]) {
00236                 const gchar* name;
00237                 change = TRUE;
00238                 if (periodic->buttons[0])
00239                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (periodic->buttons[0]), FALSE);
00240                 periodic->buttons[0] = button;
00241                 name = gtk_buildable_get_name (GTK_BUILDABLE (periodic->buttons[0]));
00242                 periodic->Z = atoi (name + 3);
00243                 g_signal_emit (periodic, gcu_periodic_signals[ELEMENT_CHANGED], 0, periodic->Z);
00244                 change = FALSE;
00245         } else if (!change) {
00246                 if (periodic->can_unselect) {
00247                         periodic->buttons[0] = NULL;
00248                         periodic->Z = 0;
00249                         g_signal_emit (periodic, gcu_periodic_signals[ELEMENT_CHANGED], 0, 0);
00250                 } else if (periodic->buttons[0])
00251                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (periodic->buttons[0]), TRUE);
00252         }
00253 }
00254 
00255 void gcu_periodic_size_allocate(GcuPeriodic* w, GtkAllocation *allocation)
00256 {
00257         GtkWidget *widget = gtk_bin_get_child (GTK_BIN (w));
00258         gboolean visible = FALSE;
00259         if (widget)
00260                 g_object_get (G_OBJECT (widget), "visible", &visible, NULL);
00261         if (visible)
00262                 gtk_widget_size_allocate (widget, allocation);
00263         (GTK_WIDGET_CLASS(parent_class))->size_allocate(GTK_WIDGET(w), allocation);
00264 }
00265 
00266 void gcu_periodic_size_request(GcuPeriodic* w, GtkRequisition *requisition)
00267 {
00268         gtk_widget_size_request (gtk_bin_get_child (GTK_BIN (w)), requisition);
00269 }
00270 
00271 guint gcu_periodic_get_element(GcuPeriodic* periodic)
00272 {
00273         g_return_val_if_fail(GCU_IS_PERIODIC(periodic), 0);
00274         return periodic->Z;
00275 }
00276 
00277 void gcu_periodic_set_element (GcuPeriodic* periodic, guint element)
00278 {
00279         g_return_if_fail(GCU_IS_PERIODIC(periodic));
00280         if (periodic->can_unselect && periodic->buttons[0]) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(periodic->buttons[0]), FALSE);
00281         if (element) 
00282         {
00283                 gtk_toggle_button_set_active(periodic->buttons[element], TRUE);
00284                 periodic->buttons[0] = periodic->buttons[element];
00285                 periodic->Z = element;
00286         }
00287         else if (periodic->can_unselect)
00288         {
00289                 periodic->buttons[0] = NULL;
00290                 periodic->Z = 0;
00291         }
00292 }
00293 
00294 static void
00295 gcu_periodic_set_property (GObject              *object,
00296                                 guint                 param_id,
00297                                 const GValue         *value,
00298                                 GParamSpec           *pspec)
00299 {
00300         GcuPeriodic *periodic;
00301         g_return_if_fail (object != NULL);
00302         g_return_if_fail (GCU_IS_PERIODIC (object));
00303 
00304         periodic = GCU_PERIODIC (object);
00305 
00306         switch (param_id) {
00307         case PROP_CAN_UNSELECT:
00308                 periodic->can_unselect = g_value_get_boolean (value);
00309                 break;
00310 
00311         case PROP_COLOR_STYLE: {
00312                 unsigned style = g_value_get_uint (value);
00313                 if (style < GCU_PERIODIC_COLOR_MAX + periodic->nbschemes) {
00314                         periodic->colorstyle = style;
00315                         int page = (style >= GCU_PERIODIC_COLOR_MAX)? 
00316                                 g_array_index (periodic->colorschemes, struct ColorScheme, style - GCU_PERIODIC_COLOR_MAX).page: 0;
00317                         gtk_notebook_set_current_page (periodic->book, page);
00318                         gcu_periodic_set_colors (periodic);
00319                 } else
00320                         g_warning (_("Out of range value %d for property \"color-style\" for GcuPeriodic instance %p\n"), style, periodic);
00321                 break;
00322         }
00323 
00324         default:
00325                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
00326                 break;
00327         }
00328 }
00329 
00330 static void
00331 gcu_periodic_get_property (GObject              *object,
00332                                 guint                 param_id,
00333                                 GValue               *value,
00334                                 GParamSpec           *pspec)
00335 {
00336         GcuPeriodic *periodic;
00337 
00338         g_return_if_fail (object != NULL);
00339         g_return_if_fail (GCU_IS_PERIODIC (object));
00340 
00341         periodic = GCU_PERIODIC (object);
00342 
00343         switch (param_id) {
00344         case PROP_CAN_UNSELECT:
00345                 g_value_set_boolean (value, periodic->can_unselect);
00346                 break;
00347 
00348         case PROP_COLOR_STYLE:
00349                 g_value_set_uint (value, periodic->colorstyle);
00350                 break;
00351 
00352         default:
00353                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
00354                 break;
00355         }
00356 }
00357 
00358 void gcu_periodic_set_colors(GcuPeriodic *periodic)
00359 {
00360         GtkStyle* style;
00361         const double *colors;
00362         PangoAttribute *attr;
00363         PangoAttrList *l;
00364         int i;
00365         GdkColor color;
00366         GcuPeriodicColorFunc func = NULL;
00367         gpointer data = NULL;
00368         if (periodic->colorstyle >= GCU_PERIODIC_COLOR_MAX) {
00369                 func = g_array_index (periodic->colorschemes, struct ColorScheme, periodic->colorstyle - GCU_PERIODIC_COLOR_MAX).f;
00370                 data = g_array_index (periodic->colorschemes, struct ColorScheme, periodic->colorstyle - GCU_PERIODIC_COLOR_MAX).data;
00371         }
00372         for (i = 1; i <= 118; i++)
00373         {
00374                 if (!periodic->buttons[i]) continue;
00375                 style = gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(periodic->buttons[i])));
00376                 switch (periodic->colorstyle)
00377                 {
00378                 case GCU_PERIODIC_COLOR_NONE:
00379                         style->bg[0].red = DefaultRed[0];
00380                         style->bg[0].green = DefaultGreen[0];
00381                         style->bg[0].blue = DefaultBlue[0];
00382                         style->bg[1].red = DefaultRed[0];
00383                         style->bg[1].green = DefaultGreen[1];
00384                         style->bg[1].blue = DefaultBlue[1];
00385                         style->bg[2].red = DefaultRed[1];
00386                         style->bg[2].green = DefaultGreen[2];
00387                         style->bg[2].blue = DefaultBlue[2];
00388                         style->bg[3].red = DefaultRed[3];
00389                         style->bg[3].green = DefaultGreen[3];
00390                         style->bg[3].blue = DefaultBlue[3];
00391                         attr = pango_attr_foreground_new (0, 0, 0);
00392                         attr->start_index = 0;
00393                         attr->end_index = 100;
00394                         l = pango_attr_list_new ();
00395                         pango_attr_list_insert (l, attr);
00396                         gtk_label_set_attributes (periodic->labels[i], l);
00397                 break;
00398                 case GCU_PERIODIC_COLOR_DEFAULT:
00399                         colors = gcu_element_get_default_color(i);
00400                         style->bg[0].red = style->bg[1].red = style->bg[2].red = style->bg[3].red = (guint16) (colors[0] * 65535.0);
00401                         style->bg[0].green = style->bg[1].green = style->bg[2].green = style->bg[3].green = (guint16) (colors[1] * 65535.0);
00402                         style->bg[0].blue = style->bg[1].blue = style->bg[2].blue = style->bg[3].blue = (guint16) (colors[2] * 65535.0);
00403                         if (colors[0] > 0.6 ||  colors[1] > 0.6 || colors[2] > 0.6)
00404                                 attr = pango_attr_foreground_new (0, 0, 0);
00405                         else
00406                                 attr = pango_attr_foreground_new (65535, 65535, 65535);
00407                         attr->start_index = 0;
00408                         attr->end_index = 100;
00409                         l = pango_attr_list_new ();
00410                         pango_attr_list_insert (l, attr);
00411                         gtk_label_set_attributes (periodic->labels[i], l);
00412                         break;
00413                 default: {
00414                         func (i, &color, data);
00415                         style->bg[0] = style->bg[1] = style->bg[2] = style->bg[3] = color;
00416                         if (color.red > 39321 ||  color.green > 39321 || color.blue > 39321)
00417                                 attr = pango_attr_foreground_new (0, 0, 0);
00418                         else
00419                                 attr = pango_attr_foreground_new (65535, 65535, 65535);
00420                         attr->start_index = 0;
00421                         attr->end_index = 100;
00422                         l = pango_attr_list_new ();
00423                         pango_attr_list_insert (l, attr);
00424                         gtk_label_set_attributes (periodic->labels[i], l);
00425                         break;
00426                 }
00427                 }
00428                 gtk_widget_set_style(GTK_WIDGET(periodic->buttons[i]), style);
00429                 g_object_unref(style);
00430         }
00431 }
00432 
00433 int     gcu_periodic_add_color_scheme (GcuPeriodic *periodic,
00434                 GcuPeriodicColorFunc func, GtkWidget *extra_widget, gpointer user_data)
00435 {
00436         struct ColorScheme s;
00437         s.f = func;
00438         if (extra_widget)
00439                 s.page = gtk_notebook_append_page (periodic->book, extra_widget, NULL);
00440         else
00441                 s.page = 0;
00442         s.data = user_data;
00443         g_array_append_val (periodic->colorschemes, s);
00444         return GCU_PERIODIC_COLOR_MAX + periodic->nbschemes++;
00445 }

Generated on Wed May 5 13:06:46 2010 for The Gnome Chemistry Utils by  doxygen 1.5.9