00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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,
00119 NULL,
00120 (GClassInitFunc) gcu_periodic_class_init,
00121 NULL,
00122 NULL,
00123 sizeof (GcuPeriodic),
00124 0,
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 }