1 // -*- C++ -*-
2 
3 /*
4  * Gnome Crystal
5  * atomsdlg.cc
6  *
7  * Copyright (C) 2002-2011 Jean Bréfort <jean.brefort@normalesup.org>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 3 of the
12  * License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22  * USA
23  */
24 
25 #include "config.h"
26 #include "atom.h"
27 #include "atomsdlg.h"
28 #include "document.h"
29 #include "application.h"
30 #include <gcu/element.h>
31 #include <list>
32 #include <string>
33 #include <glib/gi18n.h>
34 
35 using namespace std;
36 using namespace gcu;
37 
38 namespace gcr {
39 
40 enum
41 {
42 	COLUMN_ELT,
43 	COLUMN_X,
44 	COLUMN_Y,
45 	COLUMN_Z
46 };
47 
48 struct AtomStruct {
49 	unsigned short Elt;
50 	double x, y, z;
51 	GcuAtomicRadius Radius;
52 	double EffectiveRadiusRatio;
53 	bool CustomColor;
54 	double Blue, Red, Green, Alpha;
55 };
56 
57 class AtomsDlgPrivate
58 {
59 public:
60 	static void AddRow (AtomsDlg *pBox);
61 	static void DeleteRow (AtomsDlg *pBox);
62 	static void DeleteAll (AtomsDlg *pBox);
63 	static void SelectAll (AtomsDlg *pBox);
64 	static void SelectElt (AtomsDlg *pBox);
65 	static void ValueChanged (AtomsDlg *pBox, unsigned row, unsigned column);
66 	static void RowSelected (AtomsDlg *pBox, int row);
67 	static void ElementChanged (AtomsDlg *pBox, unsigned Z);
68 	static void SetElement (unsigned i, AtomsDlg *pBox);
69 	static void ColorSet (GtkColorButton *btn, AtomsDlg *pBox);
70 	static void SetColor (unsigned i, AtomsDlg *pBox);
71 	static void ColorToggled (GtkToggleButton *btn, AtomsDlg *pBox);
72 	static void ChargeChanged (GtkSpinButton *btn, AtomsDlg *pBox);
73 	static void SetCharge (unsigned i, AtomsDlg *pBox);
74 	static void RadiusTypeChanged (GtkComboBox *menu, AtomsDlg *pBox);
75 	static void RadiusIndexChanged(GtkComboBox *menu, AtomsDlg *pBox);
76 	static bool RadiusEdited (AtomsDlg *pBox);
77 	static void SetRadius (unsigned i, AtomsDlg *pBox);
78 	static void RadiusScaleChanged (GtkSpinButton *btn, AtomsDlg *pBox);
79 	static void SetRadiusScale (unsigned i, AtomsDlg *pBox);
80 };
81 
AddRow(AtomsDlg * pBox)82 void AtomsDlgPrivate::AddRow (AtomsDlg *pBox)
83 {
84 	Atom *new_atom;
85 	if (pBox->m_AtomSelected >= 0)
86 		new_atom = new Atom (*pBox->m_Atoms[pBox->m_AtomSelected]);
87 	else {
88 		new_atom = new Atom (pBox->m_nElt, 0., 0., 0.);
89 		// FIXME: keep the radius value, but the scale should be overriden
90 		new_atom->SetRadius (pBox->m_Radius);
91 		new_atom->SetEffectiveRadiusRatio (gtk_spin_button_get_value (pBox->ScaleBtn) / 100.);
92 		GdkRGBA rgba;
93 		gtk_color_button_get_rgba (pBox->AtomColor, &rgba);
94 		new_atom->SetColor (rgba.red, rgba.green, rgba.blue, rgba.alpha);
95 	}
96 	unsigned new_row = gcr_grid_append_row (pBox->m_Grid,
97 	                                        (new_atom->GetZ ())? Element::Symbol (new_atom->GetZ ()): _("Unknown"),
98 	                                        new_atom->x (), new_atom->y (), new_atom->z ()),
99 			 max_row = pBox->m_Atoms.capacity ();
100 	if (new_row >= max_row)
101 		pBox->m_Atoms.resize (max_row + 10);
102 	pBox->m_Atoms[new_row] = new_atom;
103 	pBox->m_pDoc->GetAtomList ()->push_back (new_atom);
104 	pBox->m_pDoc->Update ();
105 	pBox->m_pDoc->SetDirty (true);
106 	gtk_widget_set_sensitive (pBox->DeleteAllBtn, true);
107 }
108 
DeleteRow(AtomsDlg * pBox)109 void AtomsDlgPrivate::DeleteRow (AtomsDlg *pBox)
110 {
111 	pBox->m_pDoc->GetAtomList ()->remove (pBox->m_Atoms[pBox->m_AtomSelected]);
112 	delete pBox->m_Atoms[pBox->m_AtomSelected];
113 	pBox->m_Atoms.erase (pBox->m_Atoms.begin () + pBox->m_AtomSelected);
114 	gcr_grid_delete_row (GCR_GRID (pBox->m_Grid), pBox->m_AtomSelected);
115 	pBox->m_pDoc->Update ();
116 	pBox->m_pDoc->SetDirty (true);
117 	gtk_widget_set_sensitive (pBox->DeleteAllBtn, !pBox->m_pDoc->GetAtomList ()->empty ());
118 }
119 
DeleteAll(AtomsDlg * pBox)120 void AtomsDlgPrivate::DeleteAll (AtomsDlg *pBox)
121 {
122 	gcr_grid_delete_all (pBox->m_Grid);
123 	for (unsigned i = 0; i < pBox->m_pDoc->GetAtomList ()->size (); i++)
124 		delete pBox->m_Atoms[i];
125 	pBox->m_Atoms.clear ();
126 	pBox->m_pDoc->GetAtomList ()->clear ();
127 	pBox->m_pDoc->Update ();
128 	pBox->m_pDoc->SetDirty (true);
129 	gtk_widget_set_sensitive (pBox->DeleteAllBtn, false);
130 }
131 
SelectAll(AtomsDlg * pBox)132 void AtomsDlgPrivate::SelectAll (AtomsDlg *pBox)
133 {
134 	gcr_grid_select_all (pBox->m_Grid);
135 }
136 
SelectElt(AtomsDlg * pBox)137 void AtomsDlgPrivate::SelectElt (AtomsDlg *pBox)
138 {
139 	for (unsigned i = 0; i < pBox->m_pDoc->GetAtomList ()->size (); i++)
140 		if (pBox->m_Atoms[i]->GetZ () == pBox->m_nElt)
141 			gcr_grid_add_row_to_selection (pBox->m_Grid, i);
142 }
143 
ValueChanged(AtomsDlg * pBox,unsigned row,unsigned column)144 void AtomsDlgPrivate::ValueChanged (AtomsDlg *pBox, unsigned row, unsigned column)
145 {
146 	double coord = gcr_grid_get_double (pBox->m_Grid, row, column);
147 	switch (column) {
148 	case COLUMN_X:
149 		pBox->m_Atoms[pBox->m_AtomSelected]->x () = coord;
150 		break;
151 	case COLUMN_Y:
152 		pBox->m_Atoms[pBox->m_AtomSelected]->y () = coord;
153 		break;
154 	case COLUMN_Z:
155 		pBox->m_Atoms[pBox->m_AtomSelected]->z () = coord;
156 		break;
157 	}
158 	pBox->m_pDoc->Update ();
159 	pBox->m_pDoc->SetDirty (true);
160 }
161 
RowSelected(AtomsDlg * pBox,int row)162 void AtomsDlgPrivate::RowSelected (AtomsDlg *pBox, int row)
163 {
164 	pBox->m_AtomSelected = row;
165 	gtk_widget_set_sensitive (pBox->DeleteBtn, row >= 0);
166 	if (row >= 0) {
167 		pBox->m_nElt = pBox->m_Atoms[row]->GetZ ();
168 		// update the color
169 		g_signal_handler_block (pBox->AtomColor, pBox->m_ColorSignalID);
170 		GdkRGBA rgba, color;
171 		pBox->m_Atoms[row]->GetColor (rgba);
172 		gtk_color_button_set_rgba (pBox->AtomColor, &rgba);
173 		g_signal_handler_unblock (pBox->AtomColor, pBox->m_ColorSignalID);
174 		if (pBox->m_nElt) {
175 			double *Colors = Element::GetElement (pBox->m_nElt)->GetDefaultColor ();
176 			color.red = Colors[0];
177 			color.green = Colors[1];
178 			color.blue = Colors[2];
179 			color.alpha = 1.;
180 			gtk_toggle_button_set_active (pBox->CustomColor,
181 			                              static_cast < float > (color.red) != static_cast < float > (rgba.red) ||
182 				                          static_cast < float > (color.green) != static_cast < float > (rgba.green) ||
183 				                          static_cast < float > (color.blue) != static_cast < float > (rgba.blue) ||
184 				                          static_cast < float > (color.alpha) != static_cast < float > (rgba.alpha));
185 			pBox->m_Radii = Element::GetElement (pBox->m_nElt)->GetRadii ();
186 		} else {
187 			gtk_toggle_button_set_active (pBox->CustomColor, true);
188 			pBox->m_Radii = NULL;
189 		}
190 		pBox->m_Radius = pBox->m_Atoms[row]->GetRadius ();
191 		pBox->m_RadiusType = pBox->m_Radius.type;
192 		// set the charge
193 		g_signal_handler_block (pBox->ChargeBtn, pBox->m_ChargeSignalID);
194 		gtk_spin_button_set_value (pBox->ChargeBtn, (pBox->m_Charge = pBox->m_Radius.charge));
195 		g_signal_handler_unblock (pBox->ChargeBtn, pBox->m_ChargeSignalID);
196 		// last, radii
197 		g_signal_handler_block (pBox->ScaleBtn, pBox->m_ScaleSignalID);
198 		gtk_spin_button_set_value (pBox->ScaleBtn, pBox->m_Atoms[row]->GetEffectiveRadiusRatio () * 100.);
199 		g_signal_handler_unblock (pBox->ScaleBtn, pBox->m_ScaleSignalID);
200 		g_signal_handler_block (pBox->RadiusTypeMenu, pBox->m_RadiusTypeSignalID);
201 		gtk_combo_box_set_active (GTK_COMBO_BOX (pBox->RadiusTypeMenu), (pBox->m_Radius.type == GCU_RADIUS_UNKNOWN)? 0: pBox->m_Radius.type - 1);
202 		g_signal_handler_unblock (pBox->RadiusTypeMenu, pBox->m_RadiusTypeSignalID);
203 		pBox->PopulateRadiiMenu ();
204 		char *buf;
205 		buf = gcu_value_get_string (reinterpret_cast < GcuValue * > (&pBox->m_Radius.value));
206 		gtk_entry_set_text (pBox->AtomR, buf);
207 		g_free (buf);
208 	}
209 }
210 
SetElement(unsigned i,AtomsDlg * pBox)211 void AtomsDlgPrivate::SetElement (unsigned i, AtomsDlg *pBox)
212 {
213 	pBox->m_Atoms[i]->SetZ (pBox->m_nElt);
214 	gcr_grid_set_string (pBox->m_Grid, i, 0, pBox->m_nElt > 0? Element::GetElement (pBox->m_nElt)->GetSymbol (): _("Unknown"));
215 	pBox->m_Atoms[i]->SetRadius (pBox->m_Radius);
216 	pBox->m_Atoms[i]->SetColor (pBox->m_RGBA.red, pBox->m_RGBA.green, pBox->m_RGBA.blue, pBox->m_RGBA.alpha);
217 }
218 
ElementChanged(AtomsDlg * pBox,unsigned Z)219 void AtomsDlgPrivate::ElementChanged (AtomsDlg *pBox, unsigned Z)
220 {
221 	if ((pBox->m_nElt = Z)) {
222 		pBox->m_Radii = Element::GetElement (Z)->GetRadii ();
223 		if ((pBox->m_RadiusType == GCU_IONIC) && (pBox->m_Charge == 0)) {
224 			pBox->m_RadiusType = GCU_RADIUS_UNKNOWN;
225 			gtk_combo_box_set_active (GTK_COMBO_BOX (pBox->RadiusTypeMenu), 0);
226 		} else
227 			pBox->PopulateRadiiMenu ();
228 		gtk_toggle_button_set_active (pBox->CustomColor, false);
229 		double *Colors = Element::GetElement (Z)->GetDefaultColor ();
230 		pBox->m_RGBA.red = Colors[0];
231 		pBox->m_RGBA.green = Colors[1];
232 		pBox->m_RGBA.blue = Colors[2];
233 		pBox->m_RGBA.alpha = 1.;
234 		gtk_color_button_set_rgba (pBox->AtomColor, &pBox->m_RGBA);
235 	} else {
236 		pBox->m_Radii = NULL;
237 		gtk_toggle_button_set_active (pBox->CustomColor, true);
238 	}
239 	if (pBox->m_AtomSelected >= 0) {
240 		gcr_grid_for_each_selected (pBox->m_Grid, reinterpret_cast < GridCb > (SetElement), pBox);
241 		pBox->m_pDoc->Update ();
242 		pBox->m_pDoc->SetDirty (true);
243 	}
244 }
245 
SetColor(unsigned i,AtomsDlg * pBox)246 void AtomsDlgPrivate::SetColor (unsigned i, AtomsDlg *pBox)
247 {
248 	pBox->m_Atoms[i]->SetColor (pBox->m_RGBA.red, pBox->m_RGBA.green, pBox->m_RGBA.blue, pBox->m_RGBA.alpha);
249 }
250 
ColorSet(GtkColorButton * btn,AtomsDlg * pBox)251 void AtomsDlgPrivate::ColorSet (GtkColorButton *btn, AtomsDlg *pBox)
252 {
253 	if (pBox->m_AtomSelected >= 0) {
254 		gtk_color_button_get_rgba (btn, &pBox->m_RGBA);
255 		gcr_grid_for_each_selected (pBox->m_Grid, reinterpret_cast < GridCb > (SetColor), pBox);
256 		pBox->m_pDoc->Update ();
257 		pBox->m_pDoc->SetDirty (true);
258 	}
259 }
260 
ColorToggled(GtkToggleButton * btn,AtomsDlg * pBox)261 void AtomsDlgPrivate::ColorToggled (GtkToggleButton *btn, AtomsDlg *pBox)
262 {
263 	gtk_widget_set_sensitive (GTK_WIDGET(pBox->AtomColor), gtk_toggle_button_get_active (btn));
264 }
265 
SetCharge(unsigned i,AtomsDlg * pBox)266 void AtomsDlgPrivate::SetCharge (unsigned i, AtomsDlg *pBox)
267 {
268 		pBox->m_Atoms[i]->SetCharge (pBox->m_Charge);
269 		pBox->m_Atoms[i]->SetRadius (pBox->m_Radius);
270 }
271 
ChargeChanged(GtkSpinButton * btn,AtomsDlg * pBox)272 void AtomsDlgPrivate::ChargeChanged (GtkSpinButton *btn, AtomsDlg *pBox)
273 {
274 	int charge = gtk_spin_button_get_value_as_int (btn);
275 	if (pBox->m_Charge == charge)
276 		return;
277 	int index = -1;
278 	pBox->m_Charge = charge;
279 	if (charge) {
280 		pBox->m_RadiusType = GCU_IONIC;
281 		index = 1;
282 	} else if (pBox->m_RadiusType == GCU_IONIC) {
283 		pBox->m_RadiusType = GCU_RADIUS_UNKNOWN;
284 		index = 0;
285 	}
286 	if (index >= 0)
287 		gtk_combo_box_set_active (GTK_COMBO_BOX (pBox->RadiusTypeMenu), index);
288 	pBox->PopulateRadiiMenu ();
289 	if (pBox->m_AtomSelected >= 0) {
290 		gcr_grid_for_each_selected (pBox->m_Grid, reinterpret_cast < GridCb > (SetCharge), pBox);
291 		pBox->m_pDoc->Update ();
292 		pBox->m_pDoc->SetDirty (true);
293 	}
294 }
295 
RadiusTypeChanged(GtkComboBox * menu,AtomsDlg * pBox)296 void AtomsDlgPrivate::RadiusTypeChanged (GtkComboBox *menu, AtomsDlg *pBox)
297 {
298 	int type = gtk_combo_box_get_active (menu);
299 	if (type)
300 		type++; //skip GCU_ATOMIC
301 	if (type == pBox->m_RadiusType)
302 		return;
303 	int charges[17];
304 	memset (charges, 0, 17 * sizeof (int));
305 	pBox->m_RadiusType = type;
306 	if  ((type == GCU_IONIC) && pBox->m_Radii) {
307 		if (pBox->m_Charge)
308 			return;
309 		const GcuAtomicRadius **radius = pBox->m_Radii;
310 		while (*radius)
311 		{
312 			if ((*radius)->type != GCU_IONIC) {
313 				radius++;
314 				continue;
315 			}
316 			if (((*radius)->charge < -8) || ((*radius)->charge > 8)) {
317 				radius ++;
318 				continue;
319 			}
320 			charges[(*radius)->charge + 8]++;
321 			radius++;
322 		}
323 		int max = 0;
324 		pBox->m_Charge = 8;
325 		for (int i = 0; i < 17; i++) {
326 			if (charges[i] > max) {
327 				pBox->m_Charge = i - 8;
328 				max = charges[i];
329 			} else if (charges[i] == max) {
330 				/*FIXME: This is the most problematic case. The policy here is
331 				to take the smallest charge and if the two charges have the same absolute
332 				value, take the negative one. We might have something better in gchemutils.*/
333 				if ((abs (i - 8) < abs (pBox->m_Charge)) || i < 8) {
334 					pBox->m_Charge = i - 8;
335 					max = charges[i];
336 				}
337 			}
338 		}
339 	} else
340 		pBox->m_Charge = 0;
341 	gtk_spin_button_set_value (pBox->ChargeBtn, pBox->m_Charge);
342 	pBox->PopulateRadiiMenu ();
343 	if (pBox->m_AtomSelected >= 0) {
344 		gcr_grid_for_each_selected (pBox->m_Grid, reinterpret_cast < GridCb > (SetRadius), pBox);
345 		pBox->m_pDoc->Update ();
346 		pBox->m_pDoc->SetDirty (true);
347 	}
348 }
349 
RadiusIndexChanged(GtkComboBox * menu,AtomsDlg * pBox)350 void AtomsDlgPrivate::RadiusIndexChanged (GtkComboBox *menu, AtomsDlg *pBox)
351 {
352 //	pBox->SetRadiusIndex (gtk_combo_box_get_active (menu));
353 	int i = pBox->m_RadiiIndex[gtk_combo_box_get_active (menu)];
354 	gtk_widget_set_sensitive (GTK_WIDGET (pBox->AtomR), i < 0);
355 	if (i >= 0) {
356 		pBox->m_Radius = *(pBox->m_Radii[i]);
357 		char buf[20];
358 		g_snprintf (buf, sizeof (buf), "%g", pBox->m_Radius.value.value);
359 		gtk_entry_set_text (pBox->AtomR, buf);
360 	} else {
361 		pBox->m_Radius.scale = "custom";
362 		pBox->m_Radius.spin = GCU_N_A_SPIN;
363 		pBox->m_Radius.charge = pBox->m_Charge;
364 		pBox->m_Radius.cn = -1;
365 		pBox->m_Radius.type = static_cast < gcu_radius_type > (pBox->m_RadiusType);
366 	}
367 	if (pBox->m_AtomSelected >= 0) {
368 		gcr_grid_for_each_selected (pBox->m_Grid, reinterpret_cast < GridCb > (SetRadius), pBox);
369 		pBox->m_pDoc->Update ();
370 		pBox->m_pDoc->SetDirty (true);
371 	}
372 }
373 
SetRadius(unsigned i,AtomsDlg * pBox)374 void AtomsDlgPrivate::SetRadius (unsigned i, AtomsDlg *pBox)
375 {
376 		pBox->m_Atoms[i]->SetRadius (pBox->m_Radius);
377 }
378 
RadiusEdited(AtomsDlg * pBox)379 bool AtomsDlgPrivate::RadiusEdited (AtomsDlg *pBox)
380 {
381 	g_signal_handler_block (pBox->AtomR, pBox->m_EntryFocusOutSignalID);
382 	if (pBox->GetNumber (pBox->AtomR, &(pBox->m_Radius.value.value), gcugtk::Min, 0) && pBox->m_AtomSelected >= 0) {
383 		gcr_grid_for_each_selected (pBox->m_Grid, reinterpret_cast < GridCb > (SetRadius), pBox);
384 		pBox->m_pDoc->Update ();
385 		pBox->m_pDoc->SetDirty (true);
386 	}
387 	g_signal_handler_unblock (pBox->AtomR, pBox->m_EntryFocusOutSignalID);
388 	return false;
389 }
390 
SetRadiusScale(unsigned i,AtomsDlg * pBox)391 void AtomsDlgPrivate::SetRadiusScale (unsigned i, AtomsDlg *pBox)
392 {
393 		pBox->m_Atoms[i]->SetEffectiveRadiusRatio (pBox->m_Ratio);
394 }
395 
RadiusScaleChanged(GtkSpinButton * btn,AtomsDlg * pBox)396 void AtomsDlgPrivate::RadiusScaleChanged (GtkSpinButton *btn, AtomsDlg *pBox)
397 {
398 	pBox->m_Ratio = gtk_spin_button_get_value (btn) / 100.;
399 	if (pBox->m_AtomSelected >= 0) {
400 		gcr_grid_for_each_selected (pBox->m_Grid, reinterpret_cast < GridCb > (SetRadiusScale), pBox);
401 		pBox->m_pDoc->Update ();
402 		pBox->m_pDoc->SetDirty (true);
403 	}
404 }
405 
AtomsDlg(Application * App,Document * pDoc)406 AtomsDlg::AtomsDlg (Application *App, Document* pDoc): gcugtk::Dialog (App, UIDIR"/atoms.ui", "atoms", GETTEXT_PACKAGE, pDoc)
407 {
408 	m_pDoc = pDoc;
409 	m_Closing = false;
410 	GtkWidget *frame = GetWidget ("mendeleiev");
411 	periodic = (GcuPeriodic*) gcu_periodic_new ();
412 	g_signal_connect_swapped (G_OBJECT (periodic), "element_changed", G_CALLBACK (AtomsDlgPrivate::ElementChanged), this);
413 	g_object_set (G_OBJECT (periodic), "can_unselect", TRUE, "color-style", GCU_PERIODIC_COLOR_DEFAULT, NULL);
414 	gtk_container_add (GTK_CONTAINER (frame), (GtkWidget *) periodic);
415 	GtkWidget *button = GetWidget ("add");
416 	g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (AtomsDlgPrivate::AddRow), this);
417 	DeleteBtn = GetWidget ("delete");
418 	gtk_widget_set_sensitive (DeleteBtn, false);
419 	g_signal_connect_swapped (G_OBJECT (DeleteBtn), "clicked", G_CALLBACK (AtomsDlgPrivate::DeleteRow), this);
420 	DeleteAllBtn = GetWidget ("delete_all");
421 	g_signal_connect_swapped (G_OBJECT (DeleteAllBtn), "clicked", G_CALLBACK (AtomsDlgPrivate::DeleteAll), this);
422 	g_signal_connect_swapped (GetObject ("select-all"), "clicked", G_CALLBACK (AtomsDlgPrivate::SelectAll), this);
423 	SelectEltBtn = GetWidget ("select-elt");
424 	g_signal_connect_swapped (G_OBJECT (SelectEltBtn), "clicked", G_CALLBACK (AtomsDlgPrivate::SelectElt), this);
425 	m_Grid = GCR_GRID (gcr_grid_new (_("Atom"), G_TYPE_STRING, _("x"), G_TYPE_DOUBLE, _("y"), G_TYPE_DOUBLE, _("z"), G_TYPE_DOUBLE, NULL));
426 	gcr_grid_set_allow_multiple_selection (m_Grid, true);
427 	g_object_set (G_OBJECT (m_Grid), "expand", true, NULL);
428 	gcr_grid_customize_column (m_Grid, COLUMN_ELT, strlen ("Unknown"), false);
429 	gtk_grid_attach (GTK_GRID (GetWidget ("atoms-grid")), GTK_WIDGET (m_Grid), 3, 1, 1, 5);
430 	g_signal_connect_swapped (G_OBJECT (m_Grid), "row-selected", G_CALLBACK (AtomsDlgPrivate::RowSelected), this);
431 	g_signal_connect_swapped (G_OBJECT (m_Grid), "value-changed", G_CALLBACK (AtomsDlgPrivate::ValueChanged), this);
432 	m_nElt = 0;
433 	m_AtomSelected = -1;
434 	gcr::AtomList* Atoms = m_pDoc->GetAtomList ();
435 	m_Atoms.resize ((Atoms->size () / 10 + 1) * 10);
436 	list < gcr::Atom * >::iterator i, end = Atoms->end ();
437 	for (i = Atoms->begin (); i != end; i++)
438 		m_Atoms[gcr_grid_append_row (m_Grid, ((*i)->GetZ () > 0)? Element::Symbol ((*i)->GetZ ()): _("Unknown"), (*i)->x (), (*i)->y (), (*i)->z ())] = *i;
439 	if (Atoms->empty ())
440 		gtk_widget_set_sensitive (DeleteAllBtn, false);
441 	AtomColor = GTK_COLOR_BUTTON (GetWidget ("color"));
442 	m_ColorSignalID = g_signal_connect (G_OBJECT (AtomColor), "color-set", G_CALLBACK (AtomsDlgPrivate::ColorSet), this);
443 	CustomColor = GTK_TOGGLE_BUTTON (GetWidget ("custom_color"));
444 	gtk_toggle_button_set_active (CustomColor, true);
445 	g_signal_connect (G_OBJECT (CustomColor), "toggled", G_CALLBACK (AtomsDlgPrivate::ColorToggled), this);
446 	ChargeBtn = GTK_SPIN_BUTTON (GetWidget ("charge"));
447 	m_ChargeSignalID = g_signal_connect (G_OBJECT (ChargeBtn), "value-changed", G_CALLBACK (AtomsDlgPrivate::ChargeChanged), this);
448 	RadiusTypeMenu = GTK_COMBO_BOX_TEXT (GetWidget ("radius-type"));
449 	gtk_combo_box_set_active (GTK_COMBO_BOX (RadiusTypeMenu), 0);
450 	m_RadiusTypeSignalID = g_signal_connect (G_OBJECT (RadiusTypeMenu), "changed", G_CALLBACK (AtomsDlgPrivate::RadiusTypeChanged), this);
451 	RadiusMenu = GTK_COMBO_BOX_TEXT (GetWidget ("radius-menu"));
452 	m_RadiiSignalID = g_signal_connect (G_OBJECT (RadiusMenu), "changed", G_CALLBACK (AtomsDlgPrivate::RadiusIndexChanged), this);
453 	AtomR = GTK_ENTRY (GetWidget ("atomr"));
454 	g_signal_connect_swapped (G_OBJECT (AtomR), "activate", G_CALLBACK (AtomsDlgPrivate::RadiusEdited), this);
455 	m_EntryFocusOutSignalID = g_signal_connect_swapped (G_OBJECT (AtomR), "focus-out-event", G_CALLBACK (AtomsDlgPrivate::RadiusEdited), this);
456 	ScaleBtn = GTK_SPIN_BUTTON (GetWidget ("scale-btn"));
457 	m_ScaleSignalID = g_signal_connect (G_OBJECT (ScaleBtn), "value-changed", G_CALLBACK (AtomsDlgPrivate::RadiusScaleChanged), this);
458 	m_ScaleSignalID = g_signal_connect (G_OBJECT (ScaleBtn), "activate", G_CALLBACK (AtomsDlgPrivate::RadiusScaleChanged), this);
459 	m_RadiusType = m_Charge = 0;
460 	m_Radii = NULL;
461 	m_Radius.type = GCU_RADIUS_UNKNOWN;
462 	m_Radius.cn = -1;
463 	m_Radius.spin = GCU_N_A_SPIN;
464 	m_Radius.value.value = 0.;
465 	m_Radius.value.prec = 0;
466 	m_Radius.value.delta = 0;
467 	m_Radius.scale = "custom";
468 	PopulateRadiiMenu ();
469 	gtk_widget_show_all (GTK_WIDGET (dialog));
470 }
471 
~AtomsDlg()472 AtomsDlg::~AtomsDlg ()
473 {
474 }
475 
PopulateRadiiMenu()476 void AtomsDlg::PopulateRadiiMenu ()
477 {
478 	const GcuAtomicRadius **radius = m_Radii;
479 	int i = m_RadiiIndex.size () - 2, j = 1, selected = 0;
480 	g_signal_handler_block (RadiusMenu, m_RadiiSignalID);
481 	for (int j = 0; j <= i; j++)
482 		gtk_combo_box_text_remove (RadiusMenu, 1);
483 	m_RadiiIndex.clear ();
484 	string str;
485 	m_RadiiIndex.push_back (-1);
486 	i = 0;
487 	if (radius)
488 		while (*radius) {
489 			if (((*radius)->type != m_RadiusType) ||  ((*radius)->charge != m_Charge) || ((*radius)->value.value <= 0.)) {
490 				radius++;
491 				i++;
492 				continue;
493 			}
494 			str = ((*radius)->scale)? (*radius)->scale: "";
495 			if ((*radius)->cn > 0) {
496 	/*Note for translators: c.n. is for coordination number*/
497 				str += _(" c.n.=");
498 				char buf[16];
499 				g_snprintf(buf, sizeof(buf), " %u", (*radius)->cn);
500 				str += buf;
501 			}
502 			if ((*radius)->spin != GCU_N_A_SPIN)
503 				str += string(" (") + string(((*radius)->spin == GCU_LOW_SPIN)? _("low spin"): _("high spin")) + string(")");
504 			if (!str.length())
505 				str = _("Database");
506 			gtk_combo_box_text_append_text (RadiusMenu, str.c_str ());
507 			if (m_Radius.cn == (*radius)->cn && m_Radius.spin == (*radius)->spin
508 			    && ((!m_Radius.scale && !(*radius)->scale) ||
509 				(m_Radius.scale && (*radius)->scale && !strcmp (m_Radius.scale, (*radius)->scale))))
510 				selected = j;
511 			m_RadiiIndex.push_back(i++);
512 			j++;
513 			radius++;
514 		}
515 	g_signal_handler_unblock (RadiusMenu, m_RadiiSignalID);
516 	gtk_combo_box_set_active (GTK_COMBO_BOX (RadiusMenu), selected);
517 	gtk_widget_set_sensitive (SelectEltBtn, m_nElt > 0);
518 	m_Radius.charge = m_Charge;
519 }
520 
Closed()521 void AtomsDlg::Closed ()
522 {
523 	// check if the atoms list is coherent
524 	m_Closing = true;
525 	m_pDoc->CheckAtoms ();
526 }
527 
ReloadData()528 void AtomsDlg::ReloadData ()
529 {
530 	if (m_Closing)
531 		return;
532 	gcr_grid_delete_all (GCR_GRID (m_Grid));
533 	m_Atoms.clear ();
534 	gcr::AtomList* Atoms = m_pDoc->GetAtomList ();
535 	for (list < Atom * >::iterator i = Atoms->begin (); i != Atoms->end (); i++)
536 		m_Atoms[gcr_grid_append_row (GCR_GRID (m_Grid), ((*i)->GetZ ())? Element::Symbol ((*i)->GetZ ()): _("Unknown"),
537 	                                        (*i)->x (), (*i)->y (), (*i)->z ())] = *i;
538 	if (!m_Atoms.size ())
539 		gtk_widget_set_sensitive (DeleteAllBtn, false);
540 }
541 
542 }	//	namespace gcr
543