1 // GTK_APP.CPP
2 
3 // Copyright (C) 2003 Tommi Hassinen.
4 
5 // This package is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 
10 // This package is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 
15 // You should have received a copy of the GNU General Public License
16 // along with this package; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 
19 /*################################################################################################*/
20 
21 #include "gtk_app.h"
22 
23 #include <ghemical/notice.h>
24 
25 #include "gtk_setup_dialog.h"
26 
27 #include <ghemical/utility.h>
28 
29 #ifndef WIN32
30 #include <X11/Xlib.h>	// DisplayString()
31 #endif	// WIN32
32 
33 #include "res_gtk/draw.xpm"
34 #include "res_gtk/erase.xpm"
35 #include "res_gtk/select.xpm"
36 #include "res_gtk/zoom.xpm"
37 #include "res_gtk/clipping.xpm"
38 #include "res_gtk/transl_xy.xpm"
39 #include "res_gtk/transl_z.xpm"
40 #include "res_gtk/orbit_xy.xpm"
41 #include "res_gtk/orbit_z.xpm"
42 #include "res_gtk/rotate_xy.xpm"
43 #include "res_gtk/rotate_z.xpm"
44 #include "res_gtk/measure.xpm"
45 
46 #include "res_gtk/element.xpm"
47 #include "res_gtk/bondtype.xpm"
48 #include "res_gtk/setup.xpm"
49 
50 #include "gtk_wnd.h"
51 
52 #include "local_i18n.h"
53 
54 #include <cstring>
55 #include <sstream>
56 using namespace std;
57 
58 /*################################################################################################*/
59 
60 const char * tb_mousetool_labels[] =
61 #ifdef USE_SHORT_TOOLBAR_LABELS
62 // http://library.gnome.org/devel/glib/stable/glib-I18N.html
63 // what about using Q_() ; tbl_s|d = toolbarlabel_short_d ??? need to cut away the prefix?
64 // 2009-04-16 ; THERE IS NO NEED TO TRANSLATE THESE AT ALL ; just use the translated tooltips...
65 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66 {
67 	"d",		"e",		"s",		"z",		"c",
68 	"t",		"tz",		"o",		"oz",		"r",
69 	"rz",		"m",		NULL
70 };
71 #else	// USE_SHORT_TOOLBAR_LABELS
72 {
73 	"draw\n",	"erase\n",	"select\n",	"zoom\n",	"clip\n",
74 	"trans\nXY",	"trans\nZ",	"orbit\nXY",	"orbit\nZ",	"rotate\nXY",
75 	"rotate\nZ",	"measure\n",	NULL
76 };
77 #endif	// USE_SHORT_TOOLBAR_LABELS
78 
79 const char * tb_shortcut_labels[] =
80 #ifdef USE_SHORT_TOOLBAR_LABELS
81 {
82 	"el",		"bt",		"su",		NULL
83 };
84 #else	// USE_SHORT_TOOLBAR_LABELS
85 {
86 	"element\n",	"bond\ntype",	"setup\n",	NULL
87 };
88 #endif	// USE_SHORT_TOOLBAR_LABELS
89 
90 GtkActionEntry gtk_app::entries1[] =
91 {
92 	{ "FileMenu", NULL, N_("File") },
93 	{ "HelpMenu", NULL, N_("Help") },
94 
95 	{ "New", GTK_STOCK_NEW, N_("New"), NULL, N_("Create a new file."), (GCallback) gtk_app::mainmenu_FileNew },		//<control>N
96 	{ "Open", GTK_STOCK_OPEN, N_("Open"), NULL, N_("Open an existing file."), (GCallback) gtk_app::mainmenu_FileOpen },	//<control>O
97 	{ "SaveAs", GTK_STOCK_OPEN, N_("Save as..."), NULL, N_("Save a file."), (GCallback) gtk_app::mainmenu_FileSaveAs },	//<control>S
98 	{ "Close", GTK_STOCK_QUIT, N_("Close"), NULL, N_("Quit the program."), (GCallback) gtk_app::mainmenu_FileClose },	//<control>C
99 
100 	{ "Help", GTK_STOCK_HELP, N_("Contents"), NULL, N_("View the User's Manual."), (GCallback) gtk_app::mainmenu_HelpHelp },		//<control>H
101 	{ "About", GTK_STOCK_ABOUT, N_("About"), NULL, N_("Information about this program."), (GCallback) gtk_app::mainmenu_HelpAbout },	//<control>A
102 
103 	// the rest are toolbar actions...
104 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
105 
106 	{ "Element", "MY_ELEMENT_ICON", tb_shortcut_labels[0], NULL, N_("Set the current element."), (GCallback) gtk_app::maintb_dial_Element },
107 	{ "BondType", "MY_BONDTYPE_ICON", tb_shortcut_labels[1], NULL, N_("Set the current bondtype."), (GCallback) gtk_app::maintb_dial_BondType },
108 	{ "Setup", "MY_SETUP_ICON", tb_shortcut_labels[2], NULL, N_("Setup or change the comp.chem. method in use."), (GCallback) gtk_app::maintb_dial_Setup }
109 };
110 
111 GtkToggleActionEntry gtk_app::entries2[] =
112 {
113 	{ "Draw", "MY_DRAW_ICON", tb_mousetool_labels[0], NULL, N_("Draw ; add atoms and bonds to the model."), (GCallback) gtk_app::maintb_tool_Draw, FALSE },
114 	{ "Erase", "MY_ERASE_ICON", tb_mousetool_labels[1], NULL, N_("Erase ; remove atoms and bonds from the model."), (GCallback) gtk_app::maintb_tool_Erase, FALSE },
115 	{ "Select", "MY_SELECT_ICON", tb_mousetool_labels[2], NULL, N_("Select ; make selections in the model, and also select objects."), (GCallback) gtk_app::maintb_tool_Select, FALSE },
116 	{ "Zoom", "MY_ZOOM_ICON", tb_mousetool_labels[3], NULL, N_("Zoom ; zoom the view."), (GCallback) gtk_app::maintb_tool_Zoom, FALSE },
117 	{ "Clip", "MY_CLIPPING_ICON", tb_mousetool_labels[4], NULL, N_("Clipping ; set the near and far clipping planes for graphics rendering."), (GCallback) gtk_app::maintb_tool_Clipping, FALSE },
118 	{ "TransXY", "MY_TRANSL_XY_ICON", tb_mousetool_labels[5], NULL, N_("TranslateXY ; translate the camera or a selected object in XY-direction."), (GCallback) gtk_app::maintb_tool_TranslateXY, FALSE },
119 	{ "TransZ", "MY_TRANSL_Z_ICON", tb_mousetool_labels[6], NULL, N_("TranslateZ ; translate the camera or a selected object in Z-direction."), (GCallback) gtk_app::maintb_tool_TranslateZ, FALSE },
120 	{ "OrbXY", "MY_ORBIT_XY_ICON", tb_mousetool_labels[7], NULL, N_("OrbitXY ; orbit the camera or a selected object around the focus point in XY-direction."), (GCallback) gtk_app::maintb_tool_OrbitXY, TRUE },
121 	{ "OrbZ", "MY_ORBIT_Z_ICON", tb_mousetool_labels[8], NULL, N_("OrbitZ ; orbit the camera or a selected object around the focus point in Z-direction."), (GCallback) gtk_app::maintb_tool_OrbitZ, FALSE },
122 	{ "RotXY", "MY_ROTATE_XY_ICON", tb_mousetool_labels[9], NULL, N_("RotateXY ; turn the camera or a selected object in XY-direction."), (GCallback) gtk_app::maintb_tool_RotateXY, FALSE },
123 	{ "RotZ", "MY_ROTATE_Z_ICON", tb_mousetool_labels[10], NULL, N_("RotateZ ; turn the camera or a selected object in Z-direction."), (GCallback) gtk_app::maintb_tool_RotateZ, FALSE },
124 	{ "Measure", "MY_MEASURE_ICON", tb_mousetool_labels[11], NULL, N_("Measure ; measure distances, angles and torsions."), (GCallback) gtk_app::maintb_tool_Measure, FALSE },
125 };
126 
127 const char * gtk_app::ui_description =
128 "<ui>"
129 "  <menubar name='MainMenu'>"
130 "    <menu action='FileMenu'>"
131 "      <menuitem action='New'/>"
132 "      <menuitem action='Open'/>"
133 "      <separator/>"
134 "      <menuitem action='SaveAs'/>"
135 "      <separator/>"
136 "      <menuitem action='Close'/>"
137 "    </menu>"
138 "    <menu action='HelpMenu'>"
139 "      <menuitem action='Help'/>"
140 "      <menuitem action='About'/>"
141 "    </menu>"
142 "  </menubar>"
143 "  <toolbar name='MainTB'>"
144 "    <placeholder name='MainTools'>"
145 "      <separator/>"
146 "      <toolitem name='dr' action='Draw'/>"
147 "      <toolitem name='er' action='Erase'/>"
148 "      <toolitem name='se' action='Select'/>"
149 "      <toolitem name='zm' action='Zoom'/>"
150 "      <toolitem name='cp' action='Clip'/>"
151 "      <toolitem name='tt' action='TransXY'/>"
152 "      <toolitem name='tz' action='TransZ'/>"
153 "      <toolitem name='oo' action='OrbXY'/>"
154 "      <toolitem name='oz' action='OrbZ'/>"
155 "      <toolitem name='rr' action='RotXY'/>"
156 "      <toolitem name='rz' action='RotZ'/>"
157 "      <toolitem name='ms' action='Measure'/>"
158 "      <separator/>"
159 "      <toolitem name='el' action='Element'/>"
160 "      <toolitem name='bt' action='BondType'/>"
161 "      <separator/>"
162 "      <toolitem name='su' action='Setup'/>"
163 "      <separator/>"
164 "    </placeholder>"
165 "  </toolbar>"
166 "</ui>";
167 
168 GtkUIManager * gtk_app::ui_manager = NULL;
169 
170 GtkWidget * gtk_app::main_window = NULL;
171 GtkWidget * gtk_app::main_vbox = NULL;
172 
173 GtkWidget * gtk_app::main_menubar = NULL;
174 GtkWidget * gtk_app::main_toolbar = NULL;
175 
176 GtkWidget * gtk_app::mtb_mtool_draw = NULL;
177 GtkWidget * gtk_app::mtb_mtool_erase = NULL;
178 GtkWidget * gtk_app::mtb_mtool_select = NULL;
179 GtkWidget * gtk_app::mtb_mtool_zoom = NULL;
180 GtkWidget * gtk_app::mtb_mtool_clipping = NULL;
181 GtkWidget * gtk_app::mtb_mtool_translate_xy = NULL;
182 GtkWidget * gtk_app::mtb_mtool_translate_z = NULL;
183 GtkWidget * gtk_app::mtb_mtool_orbit_xy = NULL;
184 GtkWidget * gtk_app::mtb_mtool_orbit_z = NULL;
185 GtkWidget * gtk_app::mtb_mtool_rotate_xy = NULL;
186 GtkWidget * gtk_app::mtb_mtool_rotate_z = NULL;
187 GtkWidget * gtk_app::mtb_mtool_measure = NULL;
188 
189 GtkWidget * gtk_app::paned_widget = NULL;
190 
191 GtkWidget * gtk_app::notebook_widget = NULL;
192 
193 GtkTextBuffer * gtk_app::txt_buffer = NULL;
194 GtkTextMark * gtk_app::end_mark = NULL;
195 
196 GtkWidget * gtk_app::scroll_widget = NULL;
197 GtkWidget * gtk_app::txt_widget = NULL;
198 
199 GtkWidget * gtk_app::pv_view_widget = NULL;
200 GtkWidget * gtk_app::pv_label_widget = NULL;
201 
202 // the views/objects-menu...
203 // ^^^^^^^^^^^^^^^^^^^^^^^^^
204 
205 GtkActionEntry gtk_app::pv_viewsobjs_entries[] =
206 {
207 	{ "viewsobjs_SetCurrent", NULL, N_("Set to Current Object"), NULL, N_("Set this object to Current Object"), (GCallback) gtk_app::viewsobjs_SetCurrent },
208 	{ "viewsobjs_Delete", NULL, N_("Delete Object/View"), NULL, N_("Delete this object or view"), (GCallback) gtk_app::viewsobjs_Delete },
209 };
210 
211 const char * gtk_app::pv_viewsobjs_ui_description =
212 "<ui>"
213 "  <popup name='gpvViewsObjsMenu'>"
214 "    <menuitem action='viewsobjs_SetCurrent'/>"
215 "    <separator/>"
216 "    <menuitem action='viewsobjs_Delete'/>"
217 "  </popup>"
218 "</ui>";
219 
220 // the chains-menu...
221 // ^^^^^^^^^^^^^^^^^^
222 
223 GtkActionEntry gtk_app::pv_chains_entries[] =
224 {
225 	{ "chains_UpdateView", NULL, N_("Update View"), NULL, N_("Rebuild the chains info for this view"), (GCallback) gtk_app::chains_UpdateView },
226 	{ "chains_SelectItem", NULL, N_("Select Item"), NULL, N_("Select/unselect this chain/residue"), (GCallback) gtk_app::chains_SelectItem },
227 };
228 
229 const char * gtk_app::pv_chains_ui_description =
230 "<ui>"
231 "  <popup name='gpvChainsMenu'>"
232 "    <menuitem action='chains_UpdateView'/>"
233 "    <separator/>"
234 "    <menuitem action='chains_SelectItem'/>"
235 "  </popup>"
236 "</ui>";
237 
238 // the atoms-menu...
239 // ^^^^^^^^^^^^^^^^^
240 
241 GtkActionEntry gtk_app::pv_atoms_entries[] =
242 {
243 	{ "atoms_SelectAtom", NULL, N_("Select Atom"), NULL, N_("Select/unselect this atom"), (GCallback) gtk_app::atoms_SelectAtom },
244 };
245 
246 const char * gtk_app::pv_atoms_ui_description =
247 "<ui>"
248 "  <popup name='gpvAtomsMenu'>"
249 "    <menuitem action='atoms_SelectAtom'/>"
250 "  </popup>"
251 "</ui>";
252 
253 // the bonds-menu...
254 // ^^^^^^^^^^^^^^^^^
255 
256 GtkActionEntry gtk_app::pv_bonds_entries[] =
257 {
258 	{ "bonds_SelectBond", NULL, N_("Select Bond"), NULL, N_("Select/unselect this bond"), (GCallback) gtk_app::bonds_SelectBond },
259 };
260 
261 const char * gtk_app::pv_bonds_ui_description =
262 "<ui>"
263 "  <popup name='gpvBondsMenu'>"
264 "    <menuitem action='bonds_SelectBond'/>"
265 "  </popup>"
266 "</ui>";
267 
268 // end of pv-pages.
269 // ^^^^^^^^^^^^^^^^
270 
gtk_app(void)271 gtk_app::gtk_app(void) :
272 	custom_app()
273 {
274 	// register some new stock icons...
275 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
276 
277 	GtkIconFactory * icon_factory = gtk_icon_factory_new();
278 	GtkIconSet * icon_set; GdkPixbuf * pixbuf; GtkIconSource * icon_source;
279 	const int num_icons = 12 + 3;
280 
281 	const char ** icondata[num_icons] =
282 	{
283 		(const char **) draw_xpm,
284 		(const char **) erase_xpm,
285 		(const char **) select_xpm,
286 		(const char **) zoom_xpm,
287 		(const char **) clipping_xpm,
288 		(const char **) transl_xy_xpm,
289 		(const char **) transl_z_xpm,
290 		(const char **) orbit_xy_xpm,
291 		(const char **) orbit_z_xpm,
292 		(const char **) rotate_xy_xpm,
293 		(const char **) rotate_z_xpm,
294 		(const char **) measure_xpm,
295 
296 		(const char **) element_xpm,
297 		(const char **) bondtype_xpm,
298 		(const char **) setup_xpm
299 	};
300 
301 	const char * icon_id[num_icons] =
302 	{
303 		"MY_DRAW_ICON",
304 		"MY_ERASE_ICON",
305 		"MY_SELECT_ICON",
306 		"MY_ZOOM_ICON",
307 		"MY_CLIPPING_ICON",
308 		"MY_TRANSL_XY_ICON",
309 		"MY_TRANSL_Z_ICON",
310 		"MY_ORBIT_XY_ICON",
311 		"MY_ORBIT_Z_ICON",
312 		"MY_ROTATE_XY_ICON",
313 		"MY_ROTATE_Z_ICON",
314 		"MY_MEASURE_ICON",
315 
316 		"MY_ELEMENT_ICON",
317 		"MY_BONDTYPE_ICON",
318 		"MY_SETUP_ICON"
319 	};
320 
321 	for (int ii = 0;ii < num_icons;ii++)
322 	{
323 		pixbuf = gdk_pixbuf_new_from_xpm_data(icondata[ii]);
324 		icon_set = gtk_icon_set_new_from_pixbuf(pixbuf);
325 
326 		icon_source = gtk_icon_source_new();
327 		gtk_icon_source_set_pixbuf(icon_source, pixbuf);
328 		gtk_icon_set_add_source(icon_set, icon_source);
329 		gtk_icon_source_free (icon_source);
330 
331 		gtk_icon_factory_add(icon_factory, icon_id[ii], icon_set);
332 		gtk_icon_set_unref (icon_set);
333 	}
334 
335 	gtk_icon_factory_add_default(icon_factory);
336 
337 	// create the main window...
338 	// ^^^^^^^^^^^^^^^^^^^^^^^^^
339 
340 	main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
341 
342 	gtk_window_set_default_size(GTK_WINDOW(main_window), 845, 640);
343 
344 gchar * tmp_title = g_strconcat(_("Ghemical"), " ", APPVERSION, NULL );
345 gtk_window_set_title(GTK_WINDOW(main_window), tmp_title);
346 free(tmp_title); tmp_title = NULL;
347 
348 	ostringstream icon_fn;
349 	icon_fn << project::appdata_path << DIR_SEPARATOR << APPVERSION << DIR_SEPARATOR << "pixmaps" << DIR_SEPARATOR << "ghemical.png" << ends;
350 	pixbuf = gdk_pixbuf_new_from_file(icon_fn.str().c_str(), NULL);
351 	if (pixbuf == NULL) printf(_("ERROR : Icon loading failed : %s\n"), icon_fn.str().c_str());
352 	else gtk_window_set_icon(GTK_WINDOW(main_window), pixbuf);
353 
354 	gtk_container_set_border_width(GTK_CONTAINER(main_window), 1);
355 
356 	g_signal_connect(G_OBJECT(main_window), "delete_event", G_CALLBACK(gtk_app::DeleteEventHandler), NULL);
357 	g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(gtk_app::DestroyHandler), NULL);
358 
359 	main_vbox = gtk_vbox_new(FALSE, 0);
360 	gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
361 	gtk_container_add(GTK_CONTAINER(main_window), main_vbox);
362 
363 	// add the user interface elements...
364 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
365 
366 	GtkActionGroup * action_group1 = gtk_action_group_new("MainWindowActions");
367 	gtk_action_group_set_translation_domain(action_group1, GETTEXT_PACKAGE);
368 	gtk_action_group_add_actions(action_group1, entries1, G_N_ELEMENTS(entries1), NULL);
369 
370 	GtkActionGroup * action_group2 = gtk_action_group_new("MouseToolToggleActions");
371 	gtk_action_group_set_translation_domain(action_group2, GETTEXT_PACKAGE);
372 	gtk_action_group_add_toggle_actions(action_group2, entries2, G_N_ELEMENTS(entries2), NULL);
373 
374 	ui_manager = gtk_ui_manager_new();
375 	gtk_ui_manager_insert_action_group(ui_manager, action_group1, 0);
376 	gtk_ui_manager_insert_action_group(ui_manager, action_group2, 0);
377 
378 	GError * error = NULL;
379 	if (!gtk_ui_manager_add_ui_from_string(ui_manager, ui_description, -1, & error))
380 	{
381 		g_message(_("ERROR : Building main menu failed : %s"), error->message);
382 		g_error_free(error); exit(EXIT_FAILURE);
383 	}
384 
385 	// todo : tooltips do not appear to the main menu?!?!?
386 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
387 	// but they DO appear in the toolbar??? TOOLTIPS NEEDED FOR I18N!!!
388 	// gedit shows tooltips in the statusbar. at GtkUIManager documentation
389 	// "connect-proxy" -signal is defined which may have something to do with this.
390 
391 	main_menubar = gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
392 	gtk_box_pack_start(GTK_BOX(main_vbox), main_menubar, FALSE, FALSE, 0);
393 
394 	main_toolbar = gtk_ui_manager_get_widget(ui_manager, "/MainTB");
395 	gtk_box_pack_start(GTK_BOX(main_vbox), main_toolbar, FALSE, FALSE, 0);
396 
397 mtb_mtool_draw = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/dr");
398 mtb_mtool_erase = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/er");
399 mtb_mtool_select = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/se");
400 mtb_mtool_zoom = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/zm");
401 mtb_mtool_clipping = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/cp");
402 mtb_mtool_translate_xy = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/tt");
403 mtb_mtool_translate_z = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/tz");
404 mtb_mtool_orbit_xy = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/oo");
405 mtb_mtool_orbit_z = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/oz");
406 mtb_mtool_rotate_xy = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/rr");
407 mtb_mtool_rotate_z = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/rz");
408 mtb_mtool_measure = gtk_ui_manager_get_widget(ui_manager, "/MainTB/MainTools/ms");
409 
410 	paned_widget = gtk_vpaned_new();
411 
412 	notebook_widget = gtk_notebook_new();
413 
414 	txt_widget = gtk_text_view_new();
415 	gtk_text_view_set_editable(GTK_TEXT_VIEW(txt_widget), false);
416 
417 	txt_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_widget));
418 	GtkTextIter txt_iter; gtk_text_buffer_get_end_iter(txt_buffer, & txt_iter);
419 	end_mark = gtk_text_buffer_create_mark(txt_buffer, NULL, & txt_iter, FALSE);	// right_gravity!
420 
421 	scroll_widget = gtk_scrolled_window_new(NULL, NULL);
422 	gtk_container_add(GTK_CONTAINER(scroll_widget), GTK_WIDGET(txt_widget));
423 
424 	gtk_widget_show(txt_widget);
425 
426 	gtk_paned_add1(GTK_PANED(paned_widget), GTK_WIDGET(notebook_widget));
427 	gtk_paned_add2(GTK_PANED(paned_widget), GTK_WIDGET(scroll_widget));
428 
429 	gtk_box_pack_start(GTK_BOX(main_vbox), paned_widget, TRUE, TRUE, 0);
430 
431 	gtk_widget_show(notebook_widget);
432 	gtk_widget_show(scroll_widget);
433 
434 	gtk_widget_show(paned_widget);
435 
436 	InitPV();	// build and show the project_view...
437 
438 	// show the widgets and enter in the main loop.
439 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
440 
441 	gtk_widget_show(main_menubar);
442 	gtk_widget_show(main_toolbar);
443 
444 	gtk_widget_show(main_vbox);
445 	gtk_widget_show(main_window);
446 
447 	// set a new default project.
448 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^
449 
450 	SetNewProject();
451 
452 	// when leaving this stage, the program
453 	// will (soon) enter in the main loop...
454 }
455 
~gtk_app(void)456 gtk_app::~gtk_app(void)
457 {
458 	// need to release memory etc...
459 }
460 
GetAppX(void)461 gtk_app * gtk_app::GetAppX(void)
462 {
463 	base_app * app = base_app::GetAppB();
464 	if (app != NULL) return dynamic_cast<gtk_app *>(app);
465 	else return new gtk_app();
466 }
467 
GetPrjX(void)468 gtk_project * gtk_app::GetPrjX(void)
469 {
470 	project * p = custom_app::GetPrj();
471 	if (!p) return NULL;
472 
473 	gtk_project * gp = dynamic_cast<gtk_project *>(p);
474 	return gp;
475 }
476 
AttachDetachView(base_wcl * wcl)477 void gtk_app::AttachDetachView(base_wcl * wcl)
478 {
479 	// this is a gtk-notebook-related special feature,
480 	// so it will duplicate some functionality from the
481 	// generic implementations (project-class???).
482 
483 	// so also see these:
484 	// ^^^^^^^^^^^^^^^^^^
485 	// project::AddGraphicsClient()
486 	// project::RemoveGraphicsClient()
487 
488 	base_wnd * wndB = wcl->GetWnd();
489 	gtk_wnd * wndX = dynamic_cast<gtk_wnd *>(wndB);
490 
491 	if (wndB == NULL || wndX == NULL)
492 	{
493 		assertion_failed(__FILE__, __LINE__, "no wnd!");
494 	}
495 
496 	bool detached = !wndX->IsDetached();
497 	wndX = NULL;	// no longer needed...
498 
499 	// unlink the old window, and destroy it.
500 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
501 
502 	wcl->UnlinkWnd();
503 
504 	// then create a new window, and link it.
505 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
506 	// determine the window class using the client...
507 
508 	if (dynamic_cast<oglview_wcl *>(wcl) != NULL)
509 	{
510 		GetPrj()->DestroyGraphicsWnd(wndB);
511 		wndB = NULL;
512 
513 		wndB = GetPrj()->CreateGraphicsWnd(detached);
514 	}
515 	else
516 	{
517 		GetPrj()->DestroyPlottingWnd(wndB);
518 		wndB = NULL;
519 
520 		// handle the various plotting wnd types here...
521 
522 		if (dynamic_cast<p1dview_wcl *>(wcl) != NULL)	wndB = GetPrj()->CreatePlot1DWnd(detached);
523 	else	if (dynamic_cast<p2dview_wcl *>(wcl) != NULL)	wndB = GetPrj()->CreatePlot2DWnd(detached);
524 	else	if (dynamic_cast<eldview_wcl *>(wcl) != NULL)	wndB = GetPrj()->CreateEnergyLevelDiagramWnd(detached);
525 	else	if (dynamic_cast<rcpview_wcl *>(wcl) != NULL)	wndB = GetPrj()->CreateReactionCoordinatePlotWnd(detached);
526 	else	if (dynamic_cast<gpcview_wcl *>(wcl) != NULL)	wndB = GetPrj()->CreateGenericProteinChainWnd(detached);
527 		else
528 		{
529 			assertion_failed(__FILE__, __LINE__, "wcl class unknown.");
530 		}
531 	}
532 
533 	wcl->LinkWnd(wndB);
534 
535 	UpdateAllWindowTitles();	// attach/detach status texts...
536 }
537 
SetTransientForMainWnd(GtkWindow * other_window)538 void gtk_app::SetTransientForMainWnd(GtkWindow * other_window)
539 {
540 	gtk_window_set_transient_for(other_window, GTK_WINDOW(main_window));
541 }
542 
AddTabToNB(GtkWidget * widget,GtkWidget * label)543 void gtk_app::AddTabToNB(GtkWidget * widget, GtkWidget * label)
544 {
545 	gtk_notebook_append_page(GTK_NOTEBOOK(notebook_widget), widget, label);
546 
547 	// activate the last page ; makes the new view visible.
548 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
549 
550 	gtk_notebook_set_page(GTK_NOTEBOOK(notebook_widget), -1);
551 }
552 
RemoveTabFromNB(GtkWidget * widget)553 void gtk_app::RemoveTabFromNB(GtkWidget * widget)
554 {
555 	gint page = gtk_notebook_page_num(GTK_NOTEBOOK(notebook_widget), widget);
556 	gtk_notebook_remove_page(GTK_NOTEBOOK(notebook_widget), page);
557 }
558 
SetTabTitleNB(GtkWidget * widget,GtkWidget * label)559 void gtk_app::SetTabTitleNB(GtkWidget * widget, GtkWidget * label)
560 {
561 	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook_widget), widget, label);
562 }
563 
InitPV(void)564 void gtk_app::InitPV(void)
565 {
566 	pv_label_widget = gtk_label_new(_("project view"));
567 
568 	pv_view_widget = gtk_notebook_new();
569 	gtk_widget_set_size_request(pv_view_widget, 640, 400);	// minimum size...
570 
571 	GtkCellRenderer * renderer;
572 	GtkTreeViewColumn * column;
573 
574 	GtkActionGroup * action_group = NULL;
575 	GError * error = NULL;
576 
577 	// "views/objects"-page
578 
579 	pv_viewsobjs_store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
580 	pv_viewsobjs_widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pv_viewsobjs_store));
581 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(pv_viewsobjs_widget), TRUE);		// optional : draw the stripes to background.
582 
583 	renderer = gtk_cell_renderer_text_new();	// ??? (string)
584 	column = gtk_tree_view_column_new_with_attributes(_("Object"), renderer, "text", 0, NULL);
585 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_viewsobjs_widget), column);
586 
587 	renderer = gtk_cell_renderer_text_new();	// ??? (string)
588 	column = gtk_tree_view_column_new_with_attributes(_("Sub-Objects"), renderer, "text", 1, NULL);
589 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_viewsobjs_widget), column);
590 
591 	pv_viewsobjs_label = gtk_label_new(_("Views/Objects"));
592 	pv_viewsobjs_sw = gtk_scrolled_window_new (NULL, NULL);
593 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pv_viewsobjs_sw), GTK_SHADOW_ETCHED_IN);	// optional : ???
594 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pv_viewsobjs_sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
595 	gtk_container_add(GTK_CONTAINER(pv_viewsobjs_sw), pv_viewsobjs_widget);
596 	gtk_notebook_append_page(GTK_NOTEBOOK(pv_view_widget), pv_viewsobjs_sw, pv_viewsobjs_label);
597 action_group = gtk_action_group_new("gpvViewsObjsActions");
598 gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
599 gtk_action_group_add_actions(action_group, pv_viewsobjs_entries, G_N_ELEMENTS(pv_viewsobjs_entries), GTK_WIDGET(pv_view_widget));
600 gtk_ui_manager_insert_action_group(gtk_app::GetUIManager(), action_group, 0);
601 error = NULL;
602 if (!gtk_ui_manager_add_ui_from_string(gtk_app::GetUIManager(), pv_viewsobjs_ui_description, -1, & error))
603 {
604 	g_message(_("ERROR : Building Views/Objects menu in project view failed : %s"), error->message);
605 	g_error_free(error); exit(EXIT_FAILURE);
606 }
607 pv_viewsobjs_menu = gtk_ui_manager_get_widget(gtk_app::GetUIManager(), "/gpvViewsObjsMenu");
608 g_signal_connect_swapped(GTK_OBJECT(pv_viewsobjs_widget), "button_press_event", G_CALLBACK(ViewsObjsPopupHandler), GTK_WIDGET(pv_viewsobjs_widget));
609 	gtk_widget_show(pv_viewsobjs_widget);
610 	gtk_widget_show(pv_viewsobjs_label);
611 	gtk_widget_show(pv_viewsobjs_sw);
612 
613 	// "chains"-page
614 
615 	pv_chains_store = gtk_tree_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
616 	pv_chains_widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pv_chains_store));
617 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(pv_chains_widget), TRUE);		// optional : draw the stripes to background.
618 
619 	renderer = gtk_cell_renderer_text_new();	// chain_info (string)
620 	column = gtk_tree_view_column_new_with_attributes(_("Chain Description"), renderer, "text", 0, NULL);
621 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_chains_widget), column);
622 
623 	renderer = gtk_cell_renderer_text_new();	// res_num (string)
624 	column = gtk_tree_view_column_new_with_attributes(_("Residue Number"), renderer, "text", 1, NULL);
625 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_chains_widget), column);
626 
627 	renderer = gtk_cell_renderer_text_new();	// res_id (string)
628 	column = gtk_tree_view_column_new_with_attributes(_("Residue ID"), renderer, "text", 2, NULL);
629 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_chains_widget), column);
630 
631 	renderer = gtk_cell_renderer_text_new();	// res_state1 (string)
632 	column = gtk_tree_view_column_new_with_attributes(_("Sec-Str State"), renderer, "text", 3, NULL);
633 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_chains_widget), column);
634 
635 	renderer = gtk_cell_renderer_text_new();	// res_state2 (string)
636 	column = gtk_tree_view_column_new_with_attributes(_("Protonation State"), renderer, "text", 4, NULL);
637 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_chains_widget), column);
638 
639 	pv_chains_label = gtk_label_new(_("Chains"));
640 	pv_chains_sw = gtk_scrolled_window_new (NULL, NULL);
641 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pv_chains_sw), GTK_SHADOW_ETCHED_IN);		// optional : ???
642 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pv_chains_sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
643 	gtk_container_add(GTK_CONTAINER(pv_chains_sw), pv_chains_widget);
644 	gtk_notebook_append_page(GTK_NOTEBOOK(pv_view_widget), pv_chains_sw, pv_chains_label);
645 action_group = gtk_action_group_new("gpvChainsActions");
646 gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
647 gtk_action_group_add_actions(action_group, pv_chains_entries, G_N_ELEMENTS(pv_chains_entries), GTK_WIDGET(pv_view_widget));
648 gtk_ui_manager_insert_action_group(gtk_app::GetUIManager(), action_group, 0);
649 error = NULL;
650 if (!gtk_ui_manager_add_ui_from_string(gtk_app::GetUIManager(), pv_chains_ui_description, -1, & error))
651 {
652 	g_message(_("ERROR : Building Chains menu in project view failed : %s"), error->message);
653 	g_error_free(error); exit(EXIT_FAILURE);
654 }
655 pv_chains_menu = gtk_ui_manager_get_widget(gtk_app::GetUIManager(), "/gpvChainsMenu");
656 g_signal_connect_swapped(GTK_OBJECT(pv_chains_widget), "button_press_event", G_CALLBACK(ChainsPopupHandler), GTK_WIDGET(pv_chains_widget));
657 	gtk_widget_show(pv_chains_widget);
658 	gtk_widget_show(pv_chains_label);
659 	gtk_widget_show(pv_chains_sw);
660 
661 	// "atoms"-page
662 
663 	pv_atoms_store = gtk_list_store_new (3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_BOOLEAN);
664 	pv_atoms_widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pv_atoms_store));
665 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(pv_atoms_widget), TRUE);		// optional : draw the stripes to background.
666 
667 	renderer = gtk_cell_renderer_text_new();	// index1
668 	column = gtk_tree_view_column_new_with_attributes(_("Atom Index"), renderer, "text", 0, NULL);
669 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_atoms_widget), column);
670 
671 	renderer = gtk_cell_renderer_text_new();	// element
672 	column = gtk_tree_view_column_new_with_attributes(_("Element"), renderer, "text", 1, NULL);
673 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_atoms_widget), column);
674 
675 	renderer = gtk_cell_renderer_toggle_new();	// locked
676 	g_object_set(renderer, "activatable", TRUE, NULL);
677 	g_signal_connect(GTK_OBJECT(renderer), "toggled", G_CALLBACK(atoms_ToggleLocked), (gpointer *) pv_atoms_store);
678 	column = gtk_tree_view_column_new_with_attributes(_("Locked"), renderer, "active", 2, NULL);
679 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_atoms_widget), column);
680 
681 	pv_atoms_label = gtk_label_new(_("Atoms"));
682 	pv_atoms_sw = gtk_scrolled_window_new (NULL, NULL);
683 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pv_atoms_sw), GTK_SHADOW_ETCHED_IN);		// optional : ???
684 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pv_atoms_sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
685 	gtk_container_add(GTK_CONTAINER(pv_atoms_sw), pv_atoms_widget);
686 	gtk_notebook_append_page(GTK_NOTEBOOK(pv_view_widget), pv_atoms_sw, pv_atoms_label);
687 action_group = gtk_action_group_new("gpvAtomsActions");
688 gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
689 gtk_action_group_add_actions(action_group, pv_atoms_entries, G_N_ELEMENTS(pv_atoms_entries), GTK_WIDGET(pv_view_widget));
690 gtk_ui_manager_insert_action_group(gtk_app::GetUIManager(), action_group, 0);
691 error = NULL;
692 if (!gtk_ui_manager_add_ui_from_string(gtk_app::GetUIManager(), pv_atoms_ui_description, -1, & error))
693 {
694 	g_message(_("ERROR : Building Atoms menu in project view failed : %s"), error->message);
695 	g_error_free(error); exit(EXIT_FAILURE);
696 }
697 pv_atoms_menu = gtk_ui_manager_get_widget(gtk_app::GetUIManager(), "/gpvAtomsMenu");
698 g_signal_connect_swapped(GTK_OBJECT(pv_atoms_widget), "button_press_event", G_CALLBACK(AtomsPopupHandler), GTK_WIDGET(pv_atoms_widget));
699 	gtk_widget_show(pv_atoms_widget);
700 	gtk_widget_show(pv_atoms_label);
701 	gtk_widget_show(pv_atoms_sw);
702 
703 	// "bonds"-page
704 
705 	pv_bonds_store = gtk_list_store_new (3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
706 	pv_bonds_widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pv_bonds_store));
707 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(pv_bonds_widget), TRUE);		// optional : draw the stripes to background.
708 
709 	renderer = gtk_cell_renderer_text_new();	// index1
710 	column = gtk_tree_view_column_new_with_attributes(_("Atom Index #1"), renderer, "text", 0, NULL);
711 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_bonds_widget), column);
712 
713 	renderer = gtk_cell_renderer_text_new();	// index2
714 	column = gtk_tree_view_column_new_with_attributes(_("Atom Index #2"), renderer, "text", 1, NULL);
715 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_bonds_widget), column);
716 
717 	renderer = gtk_cell_renderer_text_new();	// bondtype
718 	column = gtk_tree_view_column_new_with_attributes(_("BondType"), renderer, "text", 2, NULL);
719 	gtk_tree_view_append_column(GTK_TREE_VIEW(pv_bonds_widget), column);
720 
721 	pv_bonds_label = gtk_label_new(_("Bonds"));
722 	pv_bonds_sw = gtk_scrolled_window_new (NULL, NULL);
723 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pv_bonds_sw), GTK_SHADOW_ETCHED_IN);		// optional : ???
724 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pv_bonds_sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
725 	gtk_container_add(GTK_CONTAINER(pv_bonds_sw), pv_bonds_widget);
726 	gtk_notebook_append_page(GTK_NOTEBOOK(pv_view_widget), pv_bonds_sw, pv_bonds_label);
727 action_group = gtk_action_group_new("gpvBondsActions");
728 gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
729 gtk_action_group_add_actions(action_group, pv_bonds_entries, G_N_ELEMENTS(pv_bonds_entries), GTK_WIDGET(pv_view_widget));
730 gtk_ui_manager_insert_action_group(gtk_app::GetUIManager(), action_group, 0);
731 error = NULL;
732 if (!gtk_ui_manager_add_ui_from_string(gtk_app::GetUIManager(), pv_bonds_ui_description, -1, & error))
733 {
734 	g_message(_("ERROR : Building Bonds menu in project view failed : %s"), error->message);
735 	g_error_free(error); exit(EXIT_FAILURE);
736 }
737 pv_bonds_menu = gtk_ui_manager_get_widget(gtk_app::GetUIManager(), "/gpvBondsMenu");
738 g_signal_connect_swapped(GTK_OBJECT(pv_bonds_widget), "button_press_event", G_CALLBACK(BondsPopupHandler), GTK_WIDGET(pv_bonds_widget));
739 	gtk_widget_show(pv_bonds_widget);
740 	gtk_widget_show(pv_bonds_label);
741 	gtk_widget_show(pv_bonds_sw);
742 
743 	// ready...
744 	// ready...
745 	// ready...
746 
747 	gtk_notebook_append_page(GTK_NOTEBOOK(notebook_widget), pv_view_widget, pv_label_widget);
748 
749 	gtk_widget_show(GTK_WIDGET(pv_view_widget));
750 	gtk_widget_show(GTK_WIDGET(pv_label_widget));
751 }
752 
SetNewProject(void)753 void gtk_app::SetNewProject(void)
754 {
755 	if (prj != NULL)
756 	{
757 		prj->ClearAll();
758 		delete prj; prj = NULL;
759 	}
760 
761 	custom_app::SetNewProject();
762 	gtk_project * tmpprj = new gtk_project();
763 
764 	prj = tmpprj;
765 	tmpprj->DoSafeStart();
766 }
767 
DeleteEventHandler(GtkWidget * widget,GdkEvent * event,gpointer data)768 gboolean gtk_app::DeleteEventHandler(GtkWidget * widget, GdkEvent * event, gpointer data)
769 {
770 	if (project::background_job_running) return TRUE;	// protect the model-data during background jobs...
771 
772 	bool quit = sQuestion(_("Are you sure that you\nwant to quit the program?"));
773 	if (quit) return FALSE; else return TRUE;
774 }
775 
DestroyHandler(GtkWidget * widget,gpointer data)776 void gtk_app::DestroyHandler(GtkWidget * widget, gpointer data)
777 {
778 	prj->ClearAll();
779 	delete prj; prj = NULL;
780 
781 	gtk_main_quit();
782 }
783 
784 // Print the message (no problems).
sMessage(const char * msg)785 void gtk_app::sMessage(const char * msg)
786 {
787 	GtkWidget * message_dialog = gtk_message_dialog_new(NULL,
788 	GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", msg);
789 
790 	gtk_dialog_run(GTK_DIALOG(message_dialog));
791 	gtk_widget_destroy(message_dialog);
792 }
793 
794 // Print the message (lower severity).
sWarningMessage(const char * msg)795 void gtk_app::sWarningMessage(const char * msg)
796 {
797 	GtkWidget * message_dialog = gtk_message_dialog_new(NULL,
798 	GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", msg);
799 
800 	gtk_dialog_run(GTK_DIALOG(message_dialog));
801 	gtk_widget_destroy(message_dialog);
802 }
803 
804 // Print the message (higher severity).
sErrorMessage(const char * msg)805 void gtk_app::sErrorMessage(const char * msg)
806 {
807 	GtkWidget * message_dialog = gtk_message_dialog_new(NULL,
808 	GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", msg);
809 
810 	gtk_dialog_run(GTK_DIALOG(message_dialog));
811 	gtk_widget_destroy(message_dialog);
812 }
813 
814 // Print the message and wait for a yes/no response.
sQuestion(const char * msg)815 bool gtk_app::sQuestion(const char * msg)
816 {
817 	GtkWidget * question_dialog = gtk_message_dialog_new(NULL,
818 	GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s", msg);
819 
820 	gint response = gtk_dialog_run(GTK_DIALOG(question_dialog));
821 	gtk_widget_destroy(question_dialog);
822 
823 	switch (response)
824 	{
825 		case GTK_RESPONSE_YES:
826 		return true;
827 
828 		default:
829 		return false;
830 	}
831 }
832 
833 #define MSG_BUFF_SZ	65536
834 
sPrintToLog(const char * msg)835 void gtk_app::sPrintToLog(const char * msg)
836 {
837 	if (strlen(msg) > MSG_BUFF_SZ)
838 	{
839 		cout << _("gtk_app::sPrintToLog() : message is too long!") << endl;
840 		return;
841 	}
842 
843 	static char msgbuff[MSG_BUFF_SZ];
844 	strcpy(msgbuff, msg);
845 
846 	GtkTextIter txt_iter;
847 	gtk_text_buffer_get_iter_at_mark(txt_buffer, & txt_iter, end_mark);
848 
849 	gtk_text_buffer_insert(txt_buffer, & txt_iter, msgbuff, -1);
850 
851 	gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(txt_widget), end_mark);
852 
853 	cout << "PrintToLog : " << msg;
854 }
855 
Message(const char * msg)856 void gtk_app::Message(const char * msg)
857 {
858 	sMessage(msg);
859 }
860 
WarningMessage(const char * msg)861 void gtk_app::WarningMessage(const char * msg)
862 {
863 	sWarningMessage(msg);
864 }
865 
ErrorMessage(const char * msg)866 void gtk_app::ErrorMessage(const char * msg)
867 {
868 	sErrorMessage(msg);
869 }
870 
Question(const char * msg)871 bool gtk_app::Question(const char * msg)
872 {
873 	return sQuestion(msg);
874 }
875 
PrintToLog(const char * msg)876 void gtk_app::PrintToLog(const char * msg)
877 {
878 	sPrintToLog(msg);
879 }
880 
UpdateAllWindowTitles(void)881 void gtk_app::UpdateAllWindowTitles(void)
882 {
883 	list<pv_viewsobjs_record *>::iterator it = pv_viewsobjs_data.begin();
884 	while (it != pv_viewsobjs_data.end())
885 	{
886 		if ((* it)->refV2 != NULL)
887 		{
888 			base_wcl * wcl = (* it)->refV2;
889 
890 			ostringstream vts;	// view title stream (in PV)
891 			ostringstream wts;	// window title stream
892 
893 			oglview_wcl * oglwcl = dynamic_cast<oglview_wcl *>(wcl);
894 			if (oglwcl != NULL)
895 			{
896 				gtk_wnd * wnd = dynamic_cast<gtk_wnd *>(oglwcl->GetWnd());
897 
898 				vts << _("window ") << oglwcl->my_wnd_number;
899 				vts << (wnd->IsDetached() ? _(" (detached)") : _(" (attached)")) << ends;
900 
901 				wts << _("cam ") << oglwcl->GetCCam()->GetCCamI() << " ";
902 				wts << _("wnd ") << oglwcl->my_wnd_number;
903 				wts << (wnd->IsDetached() ? _(" (detached)") : "") << ends;
904 
905 				oglwcl->SetTitle(wts.str().c_str());
906 			}
907 			else
908 			{
909 				// it's a plotting client...
910 				// ^^^^^^^^^^^^^^^^^^^^^^^^^
911 
912 				bool has_name = false;
913 
914 				if (dynamic_cast<ac_stor_wcl *>(wcl) != NULL)
915 				{
916 					if (dynamic_cast<p1dview_wcl *>(wcl) != NULL)
917 					{
918 						if (dynamic_cast<rcpview_wcl *>(wcl) != NULL)
919 						{
920 							has_name = true;
921 							vts << _("RC plot view") << ends;
922 							wts << _("RC plot view") << ends;
923 						}
924 						else
925 						{
926 							has_name = true;
927 							vts << _("1D plot view") << ends;
928 							wts << _("1D plot view") << ends;
929 						}
930 					}
931 					else if (dynamic_cast<p2dview_wcl *>(wcl) != NULL)
932 					{
933 						has_name = true;
934 						vts << _("2D plot view") << ends;
935 						wts << _("2D plot view") << ends;
936 					}
937 				}
938 				else if (dynamic_cast<eldview_wcl *>(wcl) != NULL)
939 				{
940 					has_name = true;
941 					vts << _("energy-level diagram view") << ends;
942 					wts << _("energy-level diagram view") << ends;
943 				}
944 				else if (dynamic_cast<gpcview_wcl *>(wcl) != NULL)
945 				{
946 					has_name = true;
947 					vts << _("generic protein chain view") << ends;
948 					wts << _("generic protein chain view") << ends;
949 				}
950 
951 				if (!has_name)
952 				{
953 					vts << _("<unknown view>") << ends;
954 					wts << _("<unknown view>") << ends;
955 				}
956 
957 				wcl->SetTitle(wts.str().c_str());
958 			}
959 
960 			gtk_tree_store_set(pv_viewsobjs_store, & (* it)->iter, 0, vts.str().c_str(), 1, FALSE, -1);
961 		}
962 
963 		it++;
964 	}
965 }
966 
CameraAdded(custom_camera * p1)967 void gtk_app::CameraAdded(custom_camera * p1)
968 {
969 	pv_viewsobjs_record * vo_rec = new pv_viewsobjs_record;
970 
971 	vo_rec->owner = NULL;
972 	vo_rec->refV1 = p1;
973 	vo_rec->refV2 = NULL;
974 	vo_rec->refO = NULL;
975 
976 	gtk_tree_store_append(pv_viewsobjs_store, & vo_rec->iter, NULL);
977 	pv_viewsobjs_data.push_back(vo_rec);
978 
979 	ostringstream name;
980 	name << _("camera ") << p1->GetCCamI() << ends;
981 	const char * name_str = name.str().c_str();
982 
983 	gtk_tree_store_set(pv_viewsobjs_store, & vo_rec->iter, 0, name_str, 1, FALSE, -1);
984 }
985 
CameraRemoved(custom_camera * p1)986 void gtk_app::CameraRemoved(custom_camera * p1)
987 {
988 	list<pv_viewsobjs_record *>::iterator it = pv_viewsobjs_data.begin();
989 	while (it != pv_viewsobjs_data.end()) { if ((* it)->refV1 == (ogl_dummy_object *) p1) break; else it++; }
990 
991 	if (it == pv_viewsobjs_data.end())
992 	{
993 		assertion_failed(__FILE__, __LINE__, "object not found.");
994 	}
995 
996 	gtk_tree_store_remove(pv_viewsobjs_store, & (* it)->iter);
997 
998 	pv_viewsobjs_data.erase(it);
999 	delete (* it);
1000 }
1001 
LightAdded(ogl_light * p1)1002 void gtk_app::LightAdded(ogl_light * p1)
1003 {
1004 	bool is_local_light = (p1->owner != NULL);
1005 	if (is_local_light)
1006 	{
1007 		list<pv_viewsobjs_record *>::iterator it = pv_viewsobjs_data.begin();
1008 		while (it != pv_viewsobjs_data.end()) { if ((* it)->refV1 == (ogl_dummy_object *) p1->owner) break; else it++; }
1009 
1010 		if (it == pv_viewsobjs_data.end())
1011 		{
1012 			assertion_failed(__FILE__, __LINE__, "owner not found.");
1013 		}
1014 
1015 		custom_camera * ccam = dynamic_cast<custom_camera *>(p1->owner);
1016 		if (!ccam)
1017 		{
1018 			assertion_failed(__FILE__, __LINE__, "ccam cast failed.");
1019 		}
1020 
1021 		pv_viewsobjs_record * vo_rec = new pv_viewsobjs_record;
1022 
1023 		vo_rec->owner = ccam;
1024 		vo_rec->refV1 = p1;
1025 		vo_rec->refV2 = NULL;
1026 		vo_rec->refO = NULL;
1027 
1028 		gtk_tree_store_append(pv_viewsobjs_store, & vo_rec->iter, & (* it)->iter);
1029 		pv_viewsobjs_data.push_back(vo_rec);
1030 
1031 		const char * object_name = p1->GetObjectName();
1032 
1033 		gtk_tree_store_set(pv_viewsobjs_store, & vo_rec->iter, 0, object_name, 1, FALSE, -1);
1034 
1035 		// expand the newly created row...
1036 
1037 		GtkTreePath * path = gtk_tree_model_get_path(GTK_TREE_MODEL(pv_viewsobjs_store), & vo_rec->iter);
1038 		gtk_tree_view_expand_to_path(GTK_TREE_VIEW(pv_viewsobjs_widget), path);
1039 		gtk_tree_path_free(path);
1040 	}
1041 	else
1042 	{
1043 		pv_viewsobjs_record * vo_rec = new pv_viewsobjs_record;
1044 
1045 		vo_rec->owner = NULL;
1046 		vo_rec->refV1 = p1;
1047 		vo_rec->refV2 = NULL;
1048 		vo_rec->refO = NULL;
1049 
1050 		gtk_tree_store_append(pv_viewsobjs_store, & vo_rec->iter, NULL);
1051 		pv_viewsobjs_data.push_back(vo_rec);
1052 
1053 		const char * object_name = p1->GetObjectName();
1054 
1055 		gtk_tree_store_set(pv_viewsobjs_store, & vo_rec->iter, 0, object_name, 1, FALSE, -1);
1056 	}
1057 }
1058 
LightRemoved(ogl_light * p1)1059 void gtk_app::LightRemoved(ogl_light * p1)
1060 {
1061 	list<pv_viewsobjs_record *>::iterator it = pv_viewsobjs_data.begin();
1062 	while (it != pv_viewsobjs_data.end()) { if ((* it)->refV1 == (ogl_dummy_object *) p1) break; else it++; }
1063 
1064 	if (it == pv_viewsobjs_data.end())
1065 	{
1066 		assertion_failed(__FILE__, __LINE__, "object not found.");
1067 	}
1068 
1069 	gtk_tree_store_remove(pv_viewsobjs_store, & (* it)->iter);
1070 
1071 	pv_viewsobjs_data.erase(it);
1072 	delete (* it);
1073 }
1074 
GraphicsClientAdded(oglview_wcl * p1)1075 void gtk_app::GraphicsClientAdded(oglview_wcl * p1)
1076 {
1077 	list<pv_viewsobjs_record *>::iterator it = pv_viewsobjs_data.begin();
1078 	while (it != pv_viewsobjs_data.end()) { if ((* it)->refV1 == (ogl_dummy_object *) p1->GetCam()) break; else it++; }
1079 
1080 	if (it == pv_viewsobjs_data.end())
1081 	{
1082 		assertion_failed(__FILE__, __LINE__, "camera not found.");
1083 	}
1084 
1085 	custom_camera * ccam = dynamic_cast<custom_camera *>(p1->GetCam());
1086 	if (!ccam)
1087 	{
1088 		assertion_failed(__FILE__, __LINE__, "ccam cast failed.");
1089 	}
1090 
1091 	pv_viewsobjs_record * vo_rec = new pv_viewsobjs_record;
1092 
1093 	vo_rec->owner = ccam;
1094 	vo_rec->refV1 = NULL;
1095 	vo_rec->refV2 = p1;
1096 	vo_rec->refO = NULL;
1097 
1098 	gtk_tree_store_append(pv_viewsobjs_store, & vo_rec->iter, & (* it)->iter);
1099 	pv_viewsobjs_data.push_back(vo_rec);
1100 
1101 	const char * object_name = "a graphics client ; THIS IS NEVER DISPLAYED?";
1102 
1103 	gtk_tree_store_set(pv_viewsobjs_store, & vo_rec->iter, 0, object_name, 1, FALSE, -1);
1104 
1105 	// expand the newly created row...
1106 
1107 	GtkTreePath * path = gtk_tree_model_get_path(GTK_TREE_MODEL(pv_viewsobjs_store), & vo_rec->iter);
1108 	gtk_tree_view_expand_to_path(GTK_TREE_VIEW(pv_viewsobjs_widget), path);
1109 	gtk_tree_path_free(path);
1110 }
1111 
GraphicsClientRemoved(oglview_wcl * p1)1112 void gtk_app::GraphicsClientRemoved(oglview_wcl * p1)
1113 {
1114 	list<pv_viewsobjs_record *>::iterator it = pv_viewsobjs_data.begin();
1115 	while (it != pv_viewsobjs_data.end()) { if ((* it)->refV2 == (base_wcl *) p1) break; else it++; }
1116 
1117 	if (it == pv_viewsobjs_data.end())
1118 	{
1119 		assertion_failed(__FILE__, __LINE__, "object not found.");
1120 	}
1121 
1122 	gtk_tree_store_remove(pv_viewsobjs_store, & (* it)->iter);
1123 
1124 	pv_viewsobjs_data.erase(it);
1125 	delete (* it);
1126 }
1127 
PlottingClientAdded(base_wcl * p1)1128 void gtk_app::PlottingClientAdded(base_wcl * p1)
1129 {
1130 //cout << "called gtk_app::PlottingClientAdded()" << endl;
1131 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1132 	pv_viewsobjs_record * vo_rec = new pv_viewsobjs_record;
1133 
1134 	vo_rec->owner = NULL;
1135 	vo_rec->refV1 = NULL;
1136 	vo_rec->refV2 = p1;
1137 	vo_rec->refO = NULL;
1138 
1139 	gtk_tree_store_append(pv_viewsobjs_store, & vo_rec->iter, NULL);
1140 	pv_viewsobjs_data.push_back(vo_rec);
1141 
1142 	const char * object_name = "a plotting client ; THIS IS NEVER DISPLAYED?";
1143 
1144 	gtk_tree_store_set(pv_viewsobjs_store, & vo_rec->iter, 0, object_name, 1, FALSE, -1);
1145 }
1146 
PlottingClientRemoved(base_wcl * p1)1147 void gtk_app::PlottingClientRemoved(base_wcl * p1)
1148 {
1149 //cout << "called gtk_app::PlottingClientRemoved()" << endl;
1150 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1151 	list<pv_viewsobjs_record *>::iterator it = pv_viewsobjs_data.begin();
1152 	while (it != pv_viewsobjs_data.end()) { if ((* it)->refV2 == (base_wcl *) p1) break; else it++; }
1153 
1154 	if (it == pv_viewsobjs_data.end())
1155 	{
1156 		assertion_failed(__FILE__, __LINE__, "object not found.");
1157 	}
1158 
1159 	gtk_tree_store_remove(pv_viewsobjs_store, & (* it)->iter);
1160 
1161 	pv_viewsobjs_data.erase(it);
1162 	delete (* it);
1163 }
1164 
ObjectAdded(ogl_smart_object * p1)1165 void gtk_app::ObjectAdded(ogl_smart_object * p1)
1166 {
1167 	pv_viewsobjs_record * vo_rec = new pv_viewsobjs_record;
1168 
1169 	vo_rec->owner = NULL;
1170 	vo_rec->refV1 = NULL;
1171 	vo_rec->refV2 = NULL;
1172 	vo_rec->refO = p1;
1173 
1174 	gtk_tree_store_append(pv_viewsobjs_store, & vo_rec->iter, NULL);
1175 	pv_viewsobjs_data.push_back(vo_rec);
1176 
1177 	const char * object_name = p1->GetObjectName();
1178 
1179 	gtk_tree_store_set(pv_viewsobjs_store, & vo_rec->iter, 0, object_name, 1, FALSE, -1);
1180 }
1181 
ObjectRemoved(ogl_smart_object * p1)1182 void gtk_app::ObjectRemoved(ogl_smart_object * p1)
1183 {
1184 	list<pv_viewsobjs_record *>::iterator it = pv_viewsobjs_data.begin();
1185 	while (it != pv_viewsobjs_data.end()) { if ((* it)->refO == p1) break; else it++; }
1186 
1187 	if (it == pv_viewsobjs_data.end())
1188 	{
1189 		assertion_failed(__FILE__, __LINE__, "object_not_found.");
1190 	}
1191 
1192 	gtk_tree_store_remove(pv_viewsobjs_store, & (* it)->iter);
1193 
1194 	pv_viewsobjs_data.erase(it);
1195 	delete (* it);
1196 }
1197 
ViewsObjsPopupHandler(GtkWidget * widget,GdkEvent * event)1198 gint gtk_app::ViewsObjsPopupHandler(GtkWidget * widget, GdkEvent * event)
1199 {
1200 	if (project::background_job_running) return TRUE;	// protect the model-data during background jobs...
1201 
1202 	if (event->type == GDK_BUTTON_PRESS)
1203 	{
1204 		GdkEventButton * event_button = (GdkEventButton *) event;
1205 		if (event_button->button == 3)
1206 		{
1207 			GtkMenu * menu = GTK_MENU(gtk_app::GetAppX()->pv_viewsobjs_menu);
1208 			gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event_button->button, event_button->time);
1209 			return TRUE;
1210 		}
1211 	}
1212 
1213 	return FALSE;
1214 }
1215 
viewsobjs_SetCurrent(GtkWidget * widget,gpointer data)1216 void gtk_app::viewsobjs_SetCurrent(GtkWidget * widget, gpointer data)
1217 {
1218 	gtk_app * app = gtk_app::GetAppX();
1219 
1220 // assume that tsel is in mode GTK_SELECTION_SINGLE (as it seems to be); this is the simplest case...
1221 // here the equivalence test of GtkTreeIter is a bit uncertain... need to test any other records???
1222 
1223 	GtkTreeSelection * tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(app->pv_viewsobjs_widget));
1224 	GtkTreeModel * tm = gtk_tree_view_get_model(GTK_TREE_VIEW(app->pv_viewsobjs_widget));
1225 	GtkTreeIter iter;
1226 
1227 	bool has_item = gtk_tree_selection_get_selected(tsel, & tm, & iter);
1228 	if (has_item)
1229 	{
1230 		list<pv_viewsobjs_record *>::iterator it = app->pv_viewsobjs_data.begin();
1231 		while (it != app->pv_viewsobjs_data.end()) { if ((* it)->iter.user_data == iter.user_data) break; else it++; }
1232 
1233 		if (it == app->pv_viewsobjs_data.end())
1234 		{
1235 			cout << "ERROR : gtk_app::viewsobjs_SetCurrent() failed." << endl;
1236 			exit(EXIT_FAILURE);
1237 		}
1238 
1239 		bool is_light = ((* it)->refV1 != NULL && dynamic_cast<ogl_light *>((* it)->refV1) != NULL);
1240 		bool is_obj = ((* it)->refO != NULL);
1241 
1242 		if (is_light)
1243 		{
1244 			gtk_app::GetPrjX()->selected_object = (* it)->refV1;
1245 
1246 			ostringstream mstr;
1247 			mstr << _("Object ") << gtk_app::GetPrjX()->selected_object->GetObjectName() << _(" is set to current object.") << endl << ends;
1248 			gtk_app::GetPrjX()->PrintToLog(mstr.str().c_str());
1249 		}
1250 		else if (is_obj)
1251 		{
1252 			gtk_app::GetPrjX()->selected_object = (* it)->refO;
1253 
1254 			ostringstream mstr;
1255 			mstr << _("Object ") << gtk_app::GetPrjX()->selected_object->GetObjectName() << _(" is set to current object.") << endl << ends;
1256 			gtk_app::GetPrjX()->PrintToLog(mstr.str().c_str());
1257 		}
1258 		else gtk_app::GetPrjX()->Message(_("Sorry, this operation is not yet implemented."));
1259 	}
1260 }
1261 
viewsobjs_Delete(GtkWidget *,gpointer data)1262 void gtk_app::viewsobjs_Delete(GtkWidget *, gpointer data)
1263 {
1264 	gtk_app * app = gtk_app::GetAppX();
1265 
1266 // assume that tsel is in mode GTK_SELECTION_SINGLE (as it seems to be); this is the simplest case...
1267 // here the equivalence test of GtkTreeIter is a bit uncertain... need to test any other records???
1268 
1269 	GtkTreeSelection * tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(app->pv_viewsobjs_widget));
1270 	GtkTreeModel * tm = gtk_tree_view_get_model(GTK_TREE_VIEW(app->pv_viewsobjs_widget));
1271 	GtkTreeIter iter;
1272 
1273 	bool has_item = gtk_tree_selection_get_selected(tsel, & tm, & iter);
1274 	if (has_item)
1275 	{
1276 		list<pv_viewsobjs_record *>::iterator it = app->pv_viewsobjs_data.begin();
1277 		while (it != app->pv_viewsobjs_data.end()) { if ((* it)->iter.user_data == iter.user_data) break; else it++; }
1278 
1279 		if (it == app->pv_viewsobjs_data.end())
1280 		{
1281 			assertion_failed(__FILE__, __LINE__, "object not found.");
1282 		}
1283 
1284 		bool is_light = ((* it)->refV1 != NULL && dynamic_cast<ogl_light *>((* it)->refV1) != NULL);
1285 		bool is_view = ((* it)->refV2 != NULL);
1286 		bool is_obj = ((* it)->refO != NULL);
1287 
1288 		if (is_light)
1289 		{
1290 			ostringstream mstr;
1291 			mstr << _("Object ") << (* it)->refV1->GetObjectName() << _(" is deleted.") << endl << ends;
1292 			gtk_app::GetPrjX()->PrintToLog(mstr.str().c_str());
1293 
1294 			if (project::selected_object == (* it)->refV1) project::selected_object = NULL;
1295 			base_app::GetAppB()->RemoveLight((* it)->refV1);
1296 
1297 			gtk_app::GetPrjX()->UpdateAllGraphicsViews();
1298 		}
1299 		else if (is_view)
1300 		{
1301 			base_wcl * wcl = (* it)->refV2;
1302 			oglview_wcl * oglwcl = dynamic_cast<oglview_wcl *>(wcl);
1303 
1304 			if (oglwcl != NULL)
1305 			{
1306 				gtk_app::GetPrjX()->RemoveGraphicsClient(oglwcl, false);
1307 			}
1308 			else
1309 			{
1310 				gtk_app::GetPrjX()->RemovePlottingClient(wcl);
1311 			}
1312 		}
1313 		else if (is_obj)
1314 		{
1315 			ostringstream mstr;
1316 			mstr << _("Object ") << (* it)->refO->GetObjectName() << _(" is deleted.") << endl << ends;
1317 			gtk_app::GetPrjX()->PrintToLog(mstr.str().c_str());
1318 
1319 			if (project::selected_object == (* it)->refO) project::selected_object = NULL;
1320 			gtk_app::GetPrjX()->RemoveObject((* it)->refO);
1321 
1322 			gtk_app::GetPrjX()->UpdateAllGraphicsViews();
1323 		}
1324 		else gtk_app::GetPrjX()->Message(_("Sorry, this operation is not yet implemented."));
1325 	}
1326 }
1327 
BuildChainsView(void)1328 void gtk_app::BuildChainsView(void)
1329 {
1330 	if (pv_chains_data.size() != 0)
1331 	{
1332 		ClearChainsView();
1333 	}
1334 
1335 	if (gtk_app::GetPrjX()->GetCI() != NULL)
1336 	{
1337 		vector<chn_info> & ci_vector = (* gtk_app::GetPrjX()->GetCI());
1338 
1339 		for (i32u n1 = 0;n1 < ci_vector.size();n1++)
1340 		{
1341 			pv_chains_record * c_rec1 = new pv_chains_record;
1342 			c_rec1->c_r_ind = (n1 << 16) + 0xFFFF; gtk_tree_store_append(pv_chains_store, & c_rec1->iter, NULL);
1343 
1344 			pv_chains_data.push_back(c_rec1);
1345 
1346 			ostringstream cis;
1347 
1348 		//	if (ci_vector[n1].description...	// this is not implemented at the moment...
1349 
1350 			// show chain index 1,2,3,... to user ; it is 0,1,2,... internally!
1351 			// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1352 
1353 			cis << _("chain #") << (n1 + 1) << " (";
1354 
1355 			switch (ci_vector[n1].GetType())
1356 			{
1357 				case chn_info::amino_acid:	cis << "AA"; break;
1358 				case chn_info::nucleic_acid:	cis << "NA"; break;
1359 				default:			cis << "??";
1360 			}
1361 			cis << _(" chain).") << ends;
1362 
1363 			gtk_tree_store_set(pv_chains_store, & c_rec1->iter, 0, cis.str().c_str(), 1, FALSE, 2, FALSE, 3, FALSE, 4, FALSE, -1);
1364 
1365 			const char * seq1_buff = ci_vector[n1].GetSequence1();
1366 			for (i32s n2 = 0;n2 < ci_vector[n1].GetLength();n2++)
1367 			{
1368 				pv_chains_record * c_rec2 = new pv_chains_record;
1369 				c_rec2->c_r_ind = (n1 << 16) + n2; gtk_tree_store_append(pv_chains_store, & c_rec2->iter, & c_rec1->iter);
1370 
1371 				pv_chains_data.push_back(c_rec2);
1372 
1373 				// show residue index 1,2,3,... to user ; it is 0,1,2,... internally!
1374 				// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1375 
1376 				ostringstream rns;
1377 				rns << (n2 + 1) << ends;
1378 
1379 				char res_id[8] = "?";
1380 				res_id[0] = seq1_buff[n2];
1381 
1382 				gtk_tree_store_set(pv_chains_store, & c_rec2->iter, 0, FALSE, 1, rns.str().c_str(), 2, res_id, 3, "???", 4, "???", -1);
1383 			}
1384 		}
1385 	}
1386 }
1387 
ClearChainsView(void)1388 void gtk_app::ClearChainsView(void)
1389 {
1390 	list<pv_chains_record *>::iterator it;
1391 
1392 	it = pv_chains_data.begin();		// first remove the residue records...
1393 	while (it != pv_chains_data.end())	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1394 	{
1395 		if (((* it)->c_r_ind & 0xFFFF) != 0xFFFF)
1396 		{
1397 			gtk_tree_store_remove(pv_chains_store, & (* it)->iter);
1398 
1399 			delete (* it);
1400 			pv_chains_data.erase(it);
1401 
1402 			it = pv_chains_data.begin();
1403 		}
1404 
1405 		it++;
1406 	}
1407 
1408 	it = pv_chains_data.begin();		// ...and then the chain records!
1409 	while (it != pv_chains_data.end())	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1410 	{
1411 		gtk_tree_store_remove(pv_chains_store, & (* it)->iter);
1412 
1413 		delete (* it);
1414 		pv_chains_data.erase(it);
1415 
1416 		it = pv_chains_data.begin();
1417 	}
1418 }
1419 
ChainsPopupHandler(GtkWidget * widget,GdkEvent * event)1420 gint gtk_app::ChainsPopupHandler(GtkWidget * widget, GdkEvent * event)
1421 {
1422 	if (project::background_job_running) return TRUE;	// protect the model-data during background jobs...
1423 
1424 	if (event->type == GDK_BUTTON_PRESS)
1425 	{
1426 		GdkEventButton * event_button = (GdkEventButton *) event;
1427 		if (event_button->button == 3)
1428 		{
1429 			GtkMenu * menu = GTK_MENU(gtk_app::GetAppX()->pv_chains_menu);
1430 			gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event_button->button, event_button->time);
1431 			return TRUE;
1432 		}
1433 	}
1434 
1435 	return FALSE;
1436 }
1437 
chains_UpdateView(GtkWidget *,gpointer data)1438 void gtk_app::chains_UpdateView(GtkWidget *, gpointer data)
1439 {
1440 	gtk_app * app = gtk_app::GetAppX();
1441 
1442 	// update the data only if it's necessary ; there might be some extra info stored in the chains data!
1443 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1444 
1445 	if (gtk_app::GetPrjX()->GetCI() == NULL)
1446 	{
1447 		gtk_app::GetPrjX()->UpdateChains();
1448 	}
1449 }
1450 
chains_SelectItem(GtkWidget *,gpointer data)1451 void gtk_app::chains_SelectItem(GtkWidget *, gpointer data)
1452 {
1453 	gtk_app * app = gtk_app::GetAppX();
1454 
1455 // assume that tsel is in mode GTK_SELECTION_SINGLE (as it seems to be); this is the simplest case...
1456 // here the equivalence test of GtkTreeIter is a bit uncertain... need to test any other records???
1457 
1458 	GtkTreeSelection * tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(app->pv_chains_widget));
1459 	GtkTreeModel * tm = gtk_tree_view_get_model(GTK_TREE_VIEW(app->pv_chains_widget));
1460 	GtkTreeIter iter;
1461 
1462 	bool has_item = gtk_tree_selection_get_selected(tsel, & tm, & iter);
1463 	if (has_item)
1464 	{
1465 		list<pv_chains_record *>::iterator it = app->pv_chains_data.begin();
1466 		while (it != app->pv_chains_data.end()) { if ((* it)->iter.user_data == iter.user_data) break; else it++; }
1467 
1468 		if (it == app->pv_chains_data.end())
1469 		{
1470 			assertion_failed(__FILE__, __LINE__, "object not found.");
1471 		}
1472 
1473 		i32s c_ind = ((* it)->c_r_ind >> 16);
1474 		i32s r_ind = ((* it)->c_r_ind & 0xFFFF);
1475 
1476 		iter_al c_rng[2]; gtk_app::GetPrjX()->GetRange(1, c_ind, c_rng);
1477 
1478 		if (r_ind == 0xFFFF)	// select chain
1479 		{
1480 			for (iter_al iter = c_rng[0]; iter != c_rng[1];iter++)
1481 			{
1482 				(* iter).flags |= ATOMFLAG_USER_SELECTED;
1483 			}
1484 		}
1485 		else			// select residue
1486 		{
1487 			iter_al r_rng[2]; gtk_app::GetPrjX()->GetRange(2, c_rng, r_ind, r_rng);
1488 
1489 			for (iter_al iter = r_rng[0]; iter != r_rng[1];iter++)
1490 			{
1491 				(* iter).flags |= ATOMFLAG_USER_SELECTED;
1492 			}
1493 		}
1494 
1495 		gtk_app::GetPrjX()->UpdateAllGraphicsViews();
1496 	}
1497 }
1498 
AtomAdded(atom * p1)1499 void gtk_app::AtomAdded(atom * p1)
1500 {
1501 	pv_atoms_record * a_rec = new pv_atoms_record;
1502 	a_rec->ref = p1; gtk_list_store_append(pv_atoms_store, & a_rec->iter);
1503 
1504 	pv_atoms_data.push_back(a_rec);
1505 
1506 	AtomUpdateItem(p1);
1507 }
1508 
AtomUpdateItem(atom * p1)1509 void gtk_app::AtomUpdateItem(atom * p1)
1510 {
1511 	list<pv_atoms_record *>::iterator it = pv_atoms_data.begin();
1512 	while (it != pv_atoms_data.end()) { if ((* it)->ref == p1) break; else it++; }
1513 
1514 	if (it == pv_atoms_data.end())
1515 	{
1516 		assertion_failed(__FILE__, __LINE__, "object not found.");
1517 	}
1518 
1519 	// show atom index 1,2,3,... to user ; it is 0,1,2,... internally!
1520 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1521 
1522 	const i32s atmi = (p1->index + 1);
1523 	const char * ele = p1->el.GetSymbol();
1524 	const bool locked = p1->flags & ATOMFLAG_USER_LOCKED;
1525 
1526 	gtk_list_store_set(pv_atoms_store, & (* it)->iter, 0, atmi, 1, ele, 2, locked, -1);
1527 }
1528 
AtomRemoved(atom * p1)1529 void gtk_app::AtomRemoved(atom * p1)
1530 {
1531 	list<pv_atoms_record *>::iterator it = pv_atoms_data.begin();
1532 	while (it != pv_atoms_data.end()) { if ((* it)->ref == p1) break; else it++; }
1533 
1534 	if (it == pv_atoms_data.end())
1535 	{
1536 		assertion_failed(__FILE__, __LINE__, "object not found.");
1537 	}
1538 
1539 	gtk_list_store_remove(pv_atoms_store, & (* it)->iter);
1540 
1541 	delete (* it);
1542 	pv_atoms_data.erase(it);
1543 }
1544 
AtomsPopupHandler(GtkWidget * widget,GdkEvent * event)1545 gint gtk_app::AtomsPopupHandler(GtkWidget * widget, GdkEvent * event)
1546 {
1547 	if (project::background_job_running) return TRUE;	// protect the model-data during background jobs...
1548 
1549 	if (event->type == GDK_BUTTON_PRESS)
1550 	{
1551 		GdkEventButton * event_button = (GdkEventButton *) event;
1552 		if (event_button->button == 3)
1553 		{
1554 			GtkMenu * menu = GTK_MENU(gtk_app::GetAppX()->pv_atoms_menu);
1555 			gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event_button->button, event_button->time);
1556 			return TRUE;
1557 		}
1558 	}
1559 
1560 	return FALSE;
1561 }
1562 
atoms_SelectAtom(GtkWidget *,gpointer data)1563 void gtk_app::atoms_SelectAtom(GtkWidget *, gpointer data)
1564 {
1565 	gtk_app * app = gtk_app::GetAppX();
1566 
1567 // assume that tsel is in mode GTK_SELECTION_SINGLE (as it seems to be); this is the simplest case...
1568 // here the equivalence test of GtkTreeIter is a bit uncertain... need to test any other records???
1569 
1570 	GtkTreeSelection * tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(app->pv_atoms_widget));
1571 	GtkTreeModel * tm = gtk_tree_view_get_model(GTK_TREE_VIEW(app->pv_atoms_widget));
1572 	GtkTreeIter iter;
1573 
1574 	bool has_item = gtk_tree_selection_get_selected(tsel, & tm, & iter);
1575 	if (has_item)
1576 	{
1577 		list<pv_atoms_record *>::iterator it = app->pv_atoms_data.begin();
1578 		while (it != app->pv_atoms_data.end()) { if ((* it)->iter.user_data == iter.user_data) break; else it++; }
1579 
1580 		if (it == app->pv_atoms_data.end())
1581 		{
1582 			assertion_failed(__FILE__, __LINE__, "object not found.");
1583 		}
1584 
1585 		(* it)->ref->flags ^= ATOMFLAG_USER_SELECTED;
1586 		gtk_app::GetPrjX()->UpdateAllGraphicsViews();
1587 	}
1588 }
1589 
atoms_ToggleLocked(GtkWidget * widget,gchar * path,gpointer * data)1590 gint gtk_app::atoms_ToggleLocked(GtkWidget * widget, gchar * path, gpointer * data)
1591 {
1592 	gtk_app * app = gtk_app::GetAppX();
1593 
1594 	GtkTreeIter iter;
1595 	if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(data), &iter, path))
1596 	{
1597 		assertion_failed(__FILE__, __LINE__, "iter search failed.");
1598 	}
1599 
1600 	list<pv_atoms_record *>::iterator it = app->pv_atoms_data.begin();
1601 	while (it != app->pv_atoms_data.end())
1602 	{
1603 		if ((* it)->iter.user_data == iter.user_data) break;
1604 		else it++;
1605 	}
1606 
1607 	if (it == app->pv_atoms_data.end())
1608 	{
1609 		assertion_failed(__FILE__, __LINE__, "object not found.");
1610 	}
1611 
1612 	atom * p1 = (* it)->ref;
1613 	p1->SetLocked(!(p1->GetLocked()));
1614 	gtk_list_store_set(GTK_LIST_STORE(data), &iter, 2, p1->GetLocked(), -1);
1615 
1616 	app->AtomUpdateItem(p1);	// make the list show the updated information...
1617 
1618 	printf(_("Atom locking changed : %s\n"), p1->GetLocked() ? _("yes") : _("no"));
1619 	return FALSE;
1620 }
1621 
BondAdded(bond * p1)1622 void gtk_app::BondAdded(bond * p1)
1623 {
1624 	pv_bonds_record * b_rec = new pv_bonds_record;
1625 	b_rec->ref = p1; gtk_list_store_append(pv_bonds_store, & b_rec->iter);
1626 
1627 	pv_bonds_data.push_back(b_rec);
1628 
1629 	BondUpdateItem(p1);
1630 }
1631 
BondUpdateItem(bond * p1)1632 void gtk_app::BondUpdateItem(bond * p1)
1633 {
1634 	list<pv_bonds_record *>::iterator it = pv_bonds_data.begin();
1635 	while (it != pv_bonds_data.end()) { if ((* it)->ref == p1) break; else it++; }
1636 
1637 	if (it == pv_bonds_data.end())
1638 	{
1639 		assertion_failed(__FILE__, __LINE__, "object not found.");
1640 	}
1641 
1642 	const char * bt_strings[4] =
1643 	{
1644 		_("Conjugated"),
1645 		_("Single"),
1646 		_("Double"),
1647 		_("Triple")
1648 	};
1649 
1650 	// show atom index 1,2,3,... to user ; it is 0,1,2,... internally!
1651 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1652 
1653 	const i32s atmi1 = (p1->atmr[0]->index + 1);
1654 	const i32s atmi2 = (p1->atmr[1]->index + 1);
1655 	const char * btype = bt_strings[p1->bt.GetValue()];
1656 
1657 	gtk_list_store_set(pv_bonds_store, & (* it)->iter, 0, atmi1, 1, atmi2, 2, btype, -1);
1658 }
1659 
BondRemoved(bond * p1)1660 void gtk_app::BondRemoved(bond * p1)
1661 {
1662 	list<pv_bonds_record *>::iterator it = pv_bonds_data.begin();
1663 	while (it != pv_bonds_data.end()) { if ((* it)->ref == p1) break; else it++; }
1664 
1665 	if (it == pv_bonds_data.end())
1666 	{
1667 		assertion_failed(__FILE__, __LINE__, "object not found.");
1668 	}
1669 
1670 	gtk_list_store_remove(pv_bonds_store, & (* it)->iter);
1671 
1672 	delete (* it);
1673 	pv_bonds_data.erase(it);
1674 }
1675 
BondsPopupHandler(GtkWidget * widget,GdkEvent * event)1676 gint gtk_app::BondsPopupHandler(GtkWidget * widget, GdkEvent * event)
1677 {
1678 	if (project::background_job_running) return TRUE;	// protect the model-data during background jobs...
1679 
1680 	if (event->type == GDK_BUTTON_PRESS)
1681 	{
1682 		GdkEventButton * event_button = (GdkEventButton *) event;
1683 		if (event_button->button == 3)
1684 		{
1685 			GtkMenu * menu = GTK_MENU(gtk_app::GetAppX()->pv_bonds_menu);
1686 			gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event_button->button, event_button->time);
1687 			return TRUE;
1688 		}
1689 	}
1690 
1691 	return FALSE;
1692 }
1693 
bonds_SelectBond(GtkWidget *,gpointer data)1694 void gtk_app::bonds_SelectBond(GtkWidget *, gpointer data)
1695 {
1696 	gtk_app * app = gtk_app::GetAppX();
1697 
1698 // assume that tsel is in mode GTK_SELECTION_SINGLE (as it seems to be); this is the simplest case...
1699 // here the equivalence test of GtkTreeIter is a bit uncertain... need to test any other records???
1700 
1701 	GtkTreeSelection * tsel = gtk_tree_view_get_selection(GTK_TREE_VIEW(app->pv_bonds_widget));
1702 	GtkTreeModel * tm = gtk_tree_view_get_model(GTK_TREE_VIEW(app->pv_bonds_widget));
1703 	GtkTreeIter iter;
1704 
1705 	bool has_item = gtk_tree_selection_get_selected(tsel, & tm, & iter);
1706 	if (has_item)
1707 	{
1708 		list<pv_bonds_record *>::iterator it = app->pv_bonds_data.begin();
1709 		while (it != app->pv_bonds_data.end()) { if ((* it)->iter.user_data == iter.user_data) break; else it++; }
1710 
1711 		if (it == app->pv_bonds_data.end())
1712 		{
1713 			assertion_failed(__FILE__, __LINE__, "object not found.");
1714 		}
1715 
1716 		bool both_selected = (((* it)->ref->atmr[0]->flags & ATOMFLAG_USER_SELECTED) && ((* it)->ref->atmr[1]->flags & ATOMFLAG_USER_SELECTED));
1717 		if (!both_selected)	// select...
1718 		{
1719 			(* it)->ref->atmr[0]->flags |= ATOMFLAG_USER_SELECTED;
1720 			(* it)->ref->atmr[1]->flags |= ATOMFLAG_USER_SELECTED;
1721 		}
1722 		else			// un-select...
1723 		{
1724 			(* it)->ref->atmr[0]->flags &= (~ATOMFLAG_USER_SELECTED);
1725 			(* it)->ref->atmr[1]->flags &= (~ATOMFLAG_USER_SELECTED);
1726 		}
1727 
1728 		gtk_app::GetPrjX()->UpdateAllGraphicsViews();
1729 	}
1730 }
1731 
1732 // the toolbar-button callbacks start here ; the toolbar-button callbacks start here
1733 // the toolbar-button callbacks start here ; the toolbar-button callbacks start here
1734 // the toolbar-button callbacks start here ; the toolbar-button callbacks start here
1735 
1736 static int toggle_event_ignore_counter = 0;
HandleToggleButtons(custom_app::mtool old_mt)1737 void gtk_app::HandleToggleButtons(custom_app::mtool old_mt)
1738 {
1739 	// a static event counter is set up and used so that a cascade of button events is prevented.
1740 	// the same thing could be done by disabling/enabling the callbacks in GTK, but this is simpler.
1741 
1742 	gboolean state = TRUE;
1743 	if (old_mt != current_mouse_tool) state = FALSE;
1744 
1745 	if (old_mt == custom_app::mtDraw)
1746 	{
1747 		toggle_event_ignore_counter++;
1748 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_draw), state);
1749 	}
1750 
1751 	if (old_mt == custom_app::mtErase)
1752 	{
1753 		toggle_event_ignore_counter++;
1754 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_erase), state);
1755 	}
1756 
1757 	if (old_mt == custom_app::mtSelect)
1758 	{
1759 		toggle_event_ignore_counter++;
1760 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_select), state);
1761 	}
1762 
1763 	if (old_mt == custom_app::mtZoom)
1764 	{
1765 		toggle_event_ignore_counter++;
1766 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_zoom), state);
1767 	}
1768 
1769 	if (old_mt == custom_app::mtClipping)
1770 	{
1771 		toggle_event_ignore_counter++;
1772 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_clipping), state);
1773 	}
1774 
1775 	if (old_mt == custom_app::mtTranslateXY)
1776 	{
1777 		toggle_event_ignore_counter++;
1778 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_translate_xy), state);
1779 	}
1780 
1781 	if (old_mt == custom_app::mtTranslateZ)
1782 	{
1783 		toggle_event_ignore_counter++;
1784 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_translate_z), state);
1785 	}
1786 
1787 	if (old_mt == custom_app::mtOrbitXY)
1788 	{
1789 		toggle_event_ignore_counter++;
1790 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_orbit_xy), state);
1791 	}
1792 
1793 	if (old_mt == custom_app::mtOrbitZ)
1794 	{
1795 		toggle_event_ignore_counter++;
1796 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_orbit_z), state);
1797 	}
1798 
1799 	if (old_mt == custom_app::mtRotateXY)
1800 	{
1801 		toggle_event_ignore_counter++;
1802 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_rotate_xy), state);
1803 	}
1804 
1805 	if (old_mt == custom_app::mtRotateZ)
1806 	{
1807 		toggle_event_ignore_counter++;
1808 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_rotate_z), state);
1809 	}
1810 
1811 	if (old_mt == custom_app::mtMeasure)
1812 	{
1813 		toggle_event_ignore_counter++;
1814 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_measure), state);
1815 	}
1816 }
1817 
maintb_tool_Draw(gpointer p1,guint p2,GtkWidget * p3)1818 void gtk_app::maintb_tool_Draw(gpointer p1, guint p2, GtkWidget * p3)
1819 {
1820 	if (toggle_event_ignore_counter > 0)
1821 	{
1822 		cout << "DEBUG : draw skipped ; counter = " << toggle_event_ignore_counter << endl;
1823 		toggle_event_ignore_counter--;
1824 	}
1825 	else
1826 	{
1827 		cout << "DEBUG : draw state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_draw)) << endl;
1828 
1829 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1830 		custom_app::current_mouse_tool = custom_app::mtDraw;
1831 		HandleToggleButtons(old_mt);
1832 	}
1833 }
1834 
maintb_tool_Erase(gpointer,guint,GtkWidget *)1835 void gtk_app::maintb_tool_Erase(gpointer, guint, GtkWidget *)
1836 {
1837 	if (toggle_event_ignore_counter > 0)
1838 	{
1839 		cout << "DEBUG : erase skipped ; counter = " << toggle_event_ignore_counter << endl;
1840 		toggle_event_ignore_counter--;
1841 	}
1842 	else
1843 	{
1844 		cout << "DEBUG : erase state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_erase)) << endl;
1845 
1846 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1847 		custom_app::current_mouse_tool = custom_app::mtErase;
1848 		HandleToggleButtons(old_mt);
1849 	}
1850 }
1851 
maintb_tool_Select(gpointer,guint,GtkWidget *)1852 void gtk_app::maintb_tool_Select(gpointer, guint, GtkWidget *)
1853 {
1854 	if (toggle_event_ignore_counter > 0)
1855 	{
1856 		cout << "DEBUG : select skipped ; counter = " << toggle_event_ignore_counter << endl;
1857 		toggle_event_ignore_counter--;
1858 	}
1859 	else
1860 	{
1861 		cout << "DEBUG : select state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_select)) << endl;
1862 
1863 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1864 		custom_app::current_mouse_tool = custom_app::mtSelect;
1865 		HandleToggleButtons(old_mt);
1866 	}
1867 }
1868 
maintb_tool_Zoom(gpointer,guint,GtkWidget *)1869 void gtk_app::maintb_tool_Zoom(gpointer, guint, GtkWidget *)
1870 {
1871 	if (toggle_event_ignore_counter > 0)
1872 	{
1873 		cout << "DEBUG : zoom skipped ; counter = " << toggle_event_ignore_counter << endl;
1874 		toggle_event_ignore_counter--;
1875 	}
1876 	else
1877 	{
1878 		cout << "DEBUG : zoom state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_zoom)) << endl;
1879 
1880 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1881 		custom_app::current_mouse_tool = custom_app::mtZoom;
1882 		HandleToggleButtons(old_mt);
1883 	}
1884 }
1885 
maintb_tool_Clipping(gpointer,guint,GtkWidget *)1886 void gtk_app::maintb_tool_Clipping(gpointer, guint, GtkWidget *)
1887 {
1888 	if (toggle_event_ignore_counter > 0)
1889 	{
1890 		cout << "DEBUG : clipping skipped ; counter = " << toggle_event_ignore_counter << endl;
1891 		toggle_event_ignore_counter--;
1892 	}
1893 	else
1894 	{
1895 		cout << "DEBUG : clipping state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_clipping)) << endl;
1896 
1897 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1898 		custom_app::current_mouse_tool = custom_app::mtClipping;
1899 		HandleToggleButtons(old_mt);
1900 	}
1901 }
1902 
maintb_tool_TranslateXY(gpointer,guint,GtkWidget *)1903 void gtk_app::maintb_tool_TranslateXY(gpointer, guint, GtkWidget *)
1904 {
1905 	if (toggle_event_ignore_counter > 0)
1906 	{
1907 		cout << "DEBUG : transl_xy skipped ; counter = " << toggle_event_ignore_counter << endl;
1908 		toggle_event_ignore_counter--;
1909 	}
1910 	else
1911 	{
1912 		cout << "DEBUG : transl_xy state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_translate_xy)) << endl;
1913 
1914 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1915 		custom_app::current_mouse_tool = custom_app::mtTranslateXY;
1916 		HandleToggleButtons(old_mt);
1917 	}
1918 }
1919 
maintb_tool_TranslateZ(gpointer,guint,GtkWidget *)1920 void gtk_app::maintb_tool_TranslateZ(gpointer, guint, GtkWidget *)
1921 {
1922 	if (toggle_event_ignore_counter > 0)
1923 	{
1924 		cout << "DEBUG : transl_z skipped ; counter = " << toggle_event_ignore_counter << endl;
1925 		toggle_event_ignore_counter--;
1926 	}
1927 	else
1928 	{
1929 		cout << "DEBUG : transl_z state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_translate_z)) << endl;
1930 
1931 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1932 		custom_app::current_mouse_tool = custom_app::mtTranslateZ;
1933 		HandleToggleButtons(old_mt);
1934 	}
1935 }
1936 
maintb_tool_OrbitXY(gpointer,guint,GtkWidget *)1937 void gtk_app::maintb_tool_OrbitXY(gpointer, guint, GtkWidget *)
1938 {
1939 	if (toggle_event_ignore_counter > 0)
1940 	{
1941 		cout << "DEBUG : orbit_xy skipped ; counter = " << toggle_event_ignore_counter << endl;
1942 		toggle_event_ignore_counter--;
1943 	}
1944 	else
1945 	{
1946 		cout << "DEBUG : orbit_xy state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_orbit_xy)) << endl;
1947 
1948 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1949 		custom_app::current_mouse_tool = custom_app::mtOrbitXY;
1950 		HandleToggleButtons(old_mt);
1951 	}
1952 }
1953 
maintb_tool_OrbitZ(gpointer,guint,GtkWidget *)1954 void gtk_app::maintb_tool_OrbitZ(gpointer, guint, GtkWidget *)
1955 {
1956 	if (toggle_event_ignore_counter > 0)
1957 	{
1958 		cout << "DEBUG : orbit_z skipped ; counter = " << toggle_event_ignore_counter << endl;
1959 		toggle_event_ignore_counter--;
1960 	}
1961 	else
1962 	{
1963 		cout << "DEBUG : orbit_z state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_orbit_z)) << endl;
1964 
1965 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1966 		custom_app::current_mouse_tool = custom_app::mtOrbitZ;
1967 		HandleToggleButtons(old_mt);
1968 	}
1969 }
1970 
maintb_tool_RotateXY(gpointer,guint,GtkWidget *)1971 void gtk_app::maintb_tool_RotateXY(gpointer, guint, GtkWidget *)
1972 {
1973 	if (toggle_event_ignore_counter > 0)
1974 	{
1975 		cout << "DEBUG : rotate_xy skipped ; counter = " << toggle_event_ignore_counter << endl;
1976 		toggle_event_ignore_counter--;
1977 	}
1978 	else
1979 	{
1980 		cout << "DEBUG : rotate_xy state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_rotate_xy)) << endl;
1981 
1982 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
1983 		custom_app::current_mouse_tool = custom_app::mtRotateXY;
1984 		HandleToggleButtons(old_mt);
1985 	}
1986 }
1987 
maintb_tool_RotateZ(gpointer,guint,GtkWidget *)1988 void gtk_app::maintb_tool_RotateZ(gpointer, guint, GtkWidget *)
1989 {
1990 	if (toggle_event_ignore_counter > 0)
1991 	{
1992 		cout << "DEBUG : rotate_z skipped ; counter = " << toggle_event_ignore_counter << endl;
1993 		toggle_event_ignore_counter--;
1994 	}
1995 	else
1996 	{
1997 		cout << "DEBUG : rotate_z state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_rotate_z)) << endl;
1998 
1999 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
2000 		custom_app::current_mouse_tool = custom_app::mtRotateZ;
2001 		HandleToggleButtons(old_mt);
2002 	}
2003 }
2004 
maintb_tool_Measure(gpointer,guint,GtkWidget *)2005 void gtk_app::maintb_tool_Measure(gpointer, guint, GtkWidget *)
2006 {
2007 	if (toggle_event_ignore_counter > 0)
2008 	{
2009 		cout << "DEBUG : measure skipped ; counter = " << toggle_event_ignore_counter << endl;
2010 		toggle_event_ignore_counter--;
2011 	}
2012 	else
2013 	{
2014 		cout << "DEBUG : measure state is " << gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(mtb_mtool_measure)) << endl;
2015 
2016 		custom_app::mtool old_mt = custom_app::current_mouse_tool;
2017 		custom_app::current_mouse_tool = custom_app::mtMeasure;
2018 		HandleToggleButtons(old_mt);
2019 	}
2020 }
2021 
maintb_dial_Element(gpointer,guint,GtkWidget *)2022 void gtk_app::maintb_dial_Element(gpointer, guint, GtkWidget *)
2023 {
2024 	new gtk_element_dialog();		// will call delete itself...
2025 }
2026 
maintb_dial_BondType(gpointer,guint,GtkWidget *)2027 void gtk_app::maintb_dial_BondType(gpointer, guint, GtkWidget *)
2028 {
2029 	new gtk_bondtype_dialog();		// will call delete itself...
2030 }
2031 
maintb_dial_Setup(gpointer,guint,GtkWidget *)2032 void gtk_app::maintb_dial_Setup(gpointer, guint, GtkWidget *)
2033 {
2034 	if (project::background_job_running) return;	// protect the model-data during background jobs...
2035 
2036 	new gtk_setup_dialog(GetPrjX());	// will call delete itself...
2037 }
2038 
2039 // the main-menu callbacks start here ; the main-menu callbacks start here
2040 // the main-menu callbacks start here ; the main-menu callbacks start here
2041 // the main-menu callbacks start here ; the main-menu callbacks start here
2042 
mainmenu_FileNew(gpointer,guint,GtkWidget *)2043 void gtk_app::mainmenu_FileNew(gpointer, guint, GtkWidget *)
2044 {
2045 	if (project::background_job_running) return;	// protect the model-data during background jobs...
2046 
2047 	GetAppX()->SetNewProject();
2048 }
2049 
mainmenu_FileOpen(gpointer,guint,GtkWidget *)2050 void gtk_app::mainmenu_FileOpen(gpointer, guint, GtkWidget *)
2051 {
2052 	if (project::background_job_running) return;	// protect the model-data during background jobs...
2053 
2054 	new gtk_file_open_dialog(GetPrjX());	// will call delete itself...
2055 }
2056 
mainmenu_FileSaveAs(gpointer,guint,GtkWidget *)2057 void gtk_app::mainmenu_FileSaveAs(gpointer, guint, GtkWidget *)
2058 {
2059 	if (project::background_job_running) return;	// protect the model-data during background jobs...
2060 
2061 	new gtk_file_save_dialog(GetPrjX());	// will call delete itself...
2062 }
2063 
mainmenu_FileClose(gpointer,guint,GtkWidget *)2064 void gtk_app::mainmenu_FileClose(gpointer, guint, GtkWidget *)
2065 {
2066 	if (project::background_job_running) return;	// protect the model-data during background jobs...
2067 
2068 	// gtk_signal_emit_by_name(GTK_OBJECT(main_window), "delete_event");
2069 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2070 	// the above is an "elegant" solution but it segfaults ; why???
2071 	// in below the same stuff is done "manually".
2072 
2073 	if (!DeleteEventHandler(NULL, NULL, NULL)) gtk_widget_destroy(main_window);
2074 }
2075 
mainmenu_HelpHelp(gpointer,guint,GtkWidget *)2076 void gtk_app::mainmenu_HelpHelp(gpointer, guint, GtkWidget *)
2077 {
2078 	ostringstream str; str << "xdg-open ";
2079 	str << project::appdata_path << DIR_SEPARATOR;
2080 	str << project::appversion << DIR_SEPARATOR;
2081 	str << "user-docs/index.html &" << ends;
2082 
2083 	cout << _("Displaying the User's Manual using the following command:") << endl;
2084 	cout << str.str().c_str() << endl;
2085 
2086 	system(str.str().c_str());
2087 }
2088 
mainmenu_HelpAbout(gpointer,guint,GtkWidget *)2089 void gtk_app::mainmenu_HelpAbout(gpointer, guint, GtkWidget *)
2090 {
2091 	ostringstream about_str;
2092 
2093 	about_str << _("Ghemical-") << APPVERSION << _(" released on ") << APPRELEASEDATE << endl;
2094 	about_str << " " << endl;
2095 	about_str << _("For more information please visit:") << endl;
2096 	about_str << WEBSITE << endl;
2097 	about_str << " " << endl;
2098 
2099 	// leave some lines out to keep the dialog size smaller...
2100 	for (i32s n1 = 0;n1 < 16;n1++) about_str << get_copyright_notice_line(n1) << endl;
2101 
2102 	about_str << " " << endl;
2103 	about_str << _("Authors:") << endl;
2104 	about_str << "\t\t" << "Tommi Hassinen" << endl;
2105 	about_str << "\t\t" << "Geoff Hutchison" << endl;
2106 	about_str << "\t\t" << "Mike Cruz" << endl;
2107 	about_str << "\t\t" << "Michael Banck" << endl;
2108 	about_str << "\t\t" << "Christopher Rowley" << endl;
2109 	about_str << "\t\t" << "Jean Brefort" << endl;
2110 	about_str << "\t\t" << "Daniel Leidert" << endl;
2111 	about_str << "\t\t" << "Vlado Peshov" << endl;
2112 
2113 	about_str << ends;
2114 
2115 	static char about[2048];
2116 	strcpy(about, about_str.str().c_str());
2117 
2118 	prj->Message(about);
2119 }
2120 
2121 /*################################################################################################*/
2122 
2123 // eof
2124