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