1 
2 /*
3  *  Ump - Unnamed Math Program
4  *  Copyright (c) 2004-2006 by Mattias Hultgren <mattias_hultgren@tele2.se>
5  *
6  *  See main.cpp
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <gtk/gtk.h>
12 #include <sys/time.h>
13 #include "ump_picturewin.h"
14 #include "main.h"
15 #include "vector.h"
16 #include "picture2gtk.h"
17 #include "math2.h"
18 #include "vartypes.h"
19 
20 GtkWidget *picturewin = 0, *picwin_status, *picwin_combo_trace, *picwin_combo_action,
21           *picwin_label_trace, *picturewin_vbox, *picturewin_menu;
22 guint         pic_statusid;
23 picture2gtk   picbild;
24 math::Picture picbild2;
25 Format        stdformat;
26 Matrix        trace_matrix;
27 
28 int32 SNAP_SIZE = 5;
29 struct SnapInfo
30 {
31 	enum SnapType { Snap_Root, Snap_Minimum, Snap_Maximum, Snap_Intersection };
32 	SnapType snap_type;
33 	int32 x, intersect_with;
34 	floatx fx, fy;
35 	bool calculated;
36 };
37 Vector<SnapInfo> snap_info[10];
38 
39 timeval action_combo_changed;
40 
41 graph_settings act_settings;
42 
43 int32  old_tx, old_ty;
44 int    old_best_match_i = -1;
45 guchar *picwin_rowbuffer = 0, *picwin_colbuffer = 0;
46 int    picwin_rowbuffer_len = 0, picwin_colbuffer_len = 0;
47 
48 bool picwin_first_click_done = false;
49 
50 enum LeftClickAction { LeftClickAction_Zoom, LeftClickAction_FindRoot, LeftClickAction_FindMaximumMinimum,
51                        LeftClickAction_FindIntersection, LeftClickAction_CalcDerivate, LeftClickAction_CalcIntegral,
52                        LeftClickAction_CalcLength };
53 
54 bool picturewin_action_dont_show_dialog = false;
55 
graph_settings()56 graph_settings::graph_settings() throw(error_obj)
57 {
58 	show_code = false;
59 	use_antialiasing = true;
60 
61 	width = 400;
62 	height = 400;
63 	xmin = "-10";
64 	xmax = "10";
65 	ymin = "-10";
66 	ymax = "10";
67 	bgcolor = picture_h::color::WHITE;
68 
69 	grid_on = true;
70 	grid_color = picture_h::color::LIGHT_GRAY;
71 	grid_scale1 = "2";
72 	grid_scale2 = "2";
73 	grid_type = "Rect";
74 
75 	axes_on = true;
76 	axes_color = picture_h::color::BLACK;
77 	scalex = "1";
78 	scaley = "1";
79 	scale_length = 3;
80 
81 	plot_mode = "Connected";
82 	show_active_page_only = true;
83 	active_page = 0;
84 
85 	polar_start = "0";
86 	polar_stop = "2pi";
87 	polar_steps = "40";
88 	par_start = "-10";
89 	par_stop = "10";
90 	par_steps = "40";
91 
92 	for( int i=0; i<10; i++ )
93 	{
94 		func[i].show_this = false;
95 		polar[i].show_this = false;
96 		func[i].entry = "";
97 		polar[i].entry = "";
98 		if( i<5 )
99 		{
100 			par[i].show_this = false;
101 			par[i].entry = "";
102 			par[i].entry2 = "";
103 		}
104 	}
105 	func[0].color = picture_h::color::BLUE;
106 	func[1].color = picture_h::color::RED;
107 	func[2].color = picture_h::color::BLACK;
108 	func[3].color = picture_h::color::DARK_GREEN;
109 	func[4].color = picture_h::color::PINK;
110 	func[5].color = picture_h::color::ORANGE;
111 	func[6].color = ((picture_h::colorrgb) { 159, 0, 255 });
112 	func[7].color = ((picture_h::colorrgb) { 60, 117, 117 });
113 	func[8].color = ((picture_h::colorrgb) { 0, 178, 208 });
114 	func[9].color = ((picture_h::colorrgb) { 156, 103, 131 });
115 
116 	polar[0].color = picture_h::color::BLUE;
117 	polar[1].color = picture_h::color::RED;
118 	polar[2].color = picture_h::color::BLACK;
119 	polar[3].color = picture_h::color::DARK_GREEN;
120 	polar[4].color = picture_h::color::PINK;
121 	polar[5].color = picture_h::color::ORANGE;
122 	polar[6].color = ((picture_h::colorrgb) { 159, 0, 255 });
123 	polar[7].color = ((picture_h::colorrgb) { 60, 117, 117 });
124 	polar[8].color = ((picture_h::colorrgb) { 0, 178, 208 });
125 	polar[9].color = ((picture_h::colorrgb) { 156, 103, 131 });
126 
127 	par[0].color = picture_h::color::BLUE;
128 	par[1].color = picture_h::color::RED;
129 	par[2].color = picture_h::color::BLACK;
130 	par[3].color = picture_h::color::DARK_GREEN;
131 	par[4].color = picture_h::color::PINK;
132 }
133 
134 
135 void picwin_mousedown( const picture2gtk *src, int32 x, int32 y, int32 button );
136 void find_root( int function, floatx guess, Complex &x, Complex &y ) throw(error_obj);
137 bool find_min_or_max( int function, floatx guess, Complex &x, Complex &y ) throw(error_obj);  // true if minimum,  false if maximum
138 void find_intersection( int f1, int f2, floatx guess, Complex &x, Complex &y ) throw(error_obj);
139 
calculate_snap(SnapInfo * snap,int function)140 void calculate_snap( SnapInfo *snap, int function ) throw(error_obj)
141 {
142 	Complex x, y;
143 	error_obj remove_this_snap_point;
144 
145 	switch( snap->snap_type )
146 	{
147 	case SnapInfo::Snap_Root:
148 		find_root( function, snap->fx, x, y );
149 		break;
150 
151 	case SnapInfo::Snap_Maximum:
152 		if( find_min_or_max( function, snap->fx, x, y ) )
153 			snap->snap_type = SnapInfo::Snap_Minimum;
154 		break;
155 
156 	case SnapInfo::Snap_Minimum:
157 		if( find_min_or_max( function, snap->fx, x, y ) == false )
158 			snap->snap_type = SnapInfo::Snap_Maximum;
159 		break;
160 
161 	case SnapInfo::Snap_Intersection:
162 		find_intersection( function, snap->intersect_with, snap->fx, x, y );
163 		break;
164 
165 	default:
166 		printf( "Internal error: unhandled snap_type: %ld\n", snap->snap_type );
167 		throw remove_this_snap_point;
168 	}
169 	if( fabsx( floatx(x.real) - snap->fx ) > ( 1.01*(picbild2.get_right() - picbild2.get_left()) / floatx(picbild2.pic.get_width()) ) )
170 		throw remove_this_snap_point; // there was an extreme point found but not anywhere near here
171 	snap->fx = floatx( x.real );
172 	snap->fy = floatx( y.real );
173 	snap->calculated = true;
174 }
175 
conv_combobox_index_to_function_index(int index)176 int conv_combobox_index_to_function_index(int index)
177 {
178 	if(index < 2)
179 		return -1;
180 
181 	index -= 2;
182 	for( int i=0; i<10; i++ )
183 	{
184 		if( act_settings.func[i].show_this )
185 		{
186 			if( index == 0 )
187 				return i;
188 			index--;
189 		}
190 	}
191 
192 	return -1;
193 }
conv_function_index_to_combobox_index(int index)194 int conv_function_index_to_combobox_index(int index)
195 {
196 	int ret = 1;
197 
198 	if( index < 0  ||  index >= 10 )
199 		return -1;
200 
201 	if( !act_settings.func[index].show_this )
202 		return -1;
203 
204 	for( int i=0; i<index; i++ )
205 	{
206 		if( act_settings.func[i].show_this )
207 			ret++;
208 	}
209 	return ret+2;
210 }
211 
get_x_value(int32 x,int function,SnapInfo * ptr=0)212 floatx get_x_value( int32 x, int function, SnapInfo *ptr = 0 )
213 {
214 	int min_dist = SNAP_SIZE, index = -1;
215 
216 	if( function == -1 )
217 		return floatx(trace_matrix.get_complex( x+1, 1 ).real);
218 
219 	for( int i=0; i<snap_info[function].get_size(); i++ )
220 	{
221 		if( abs(snap_info[function][i]->x -x) < min_dist )
222 		{
223 			if( snap_info[function][i]->calculated == false )
224 			{
225 				try{ calculate_snap( snap_info[function][i], function ); }
226 				catch( ... ) { snap_info[function].remove( i ); i--; continue; } // this snap wasn't calculatable
227 			}                                                                        // let's remove it
228 			min_dist = abs(snap_info[function][i]->x -x);
229 			index = i;
230 		}
231 	}
232 	if( index != -1 )
233 	{
234 		if( ptr != 0 )
235 			*ptr = *snap_info[function][index];
236 		return snap_info[function][index]->fx;
237 	}
238 	return floatx(trace_matrix.get_complex( x+1, 1 ).real);
239 }
get_y_value(int32 x,int function,SnapInfo * ptr=0)240 floatx get_y_value( int32 x, int function, SnapInfo *ptr = 0 )
241 {
242 	int min_dist = SNAP_SIZE, index = -1;
243 
244 	if( function == -1 )
245 		THROW_ERROR( ErrorType_General, "Intern error: Illegal value of function in get_y_value" );
246 
247 	for( int i=0; i<snap_info[function].get_size(); i++ )
248 	{
249 		if( abs(snap_info[function][i]->x -x) < min_dist )
250 		{
251 			if( snap_info[function][i]->calculated == false )
252 			{
253 				try{ calculate_snap( snap_info[function][i], function ); }
254 				catch( ... ) { snap_info[function].remove( i ); i--; continue; } // this snap wasn't calculatable
255 			}                                                                        // let's remove it
256 			min_dist = abs(snap_info[function][i]->x -x);
257 			index = i;
258 		}
259 	}
260 	if( index != -1 )
261 	{
262 		if( ptr != 0 )
263 			*ptr = *snap_info[function][index];
264 		return snap_info[function][index]->fy;
265 	}
266 	return floatx(trace_matrix.get_complex( x+1, function + 2 ).real);
267 }
268 
find_root(int function,floatx guess,Complex & x,Complex & y)269 void find_root( int function, floatx guess, Complex &x, Complex &y ) throw(error_obj)
270 {
271 	math::CodeLine code;
272 	math::Variable tmpvar;
273 	utf8_string str;
274 	char char_str[1000];
275 
276 	snprintf( char_str, 1000, "x = nSolve( y%ld, x, ", function );
277 	str = char_str;
278 	floatx_to_string( guess, str, stdformat);
279 	str.append( ", " );
280 	floatx_to_string( (picbild2.get_right() - picbild2.get_left()) / (floatx(picbild2.pic.get_width()) * 5.0), str, stdformat );
281 	str.append( " )\n" );
282 	if( act_settings.show_code )
283 		(*TEXTVIEW_FUNCTION)( str.c_str() );
284 	code.set_code_line( str.c_str() );
285 	code.calc( 0 );
286 
287 	x = *math::global_varlist.get_pointer( math::global_varlist.get_id("x") )->get_complex();
288 
289 	code.set_code_line( act_settings.func[function].entry.c_str() );
290 	code.calc( &tmpvar );
291 	y = *tmpvar.get_complex();
292 }
293 
find_min_or_max(int function,floatx guess,Complex & x,Complex & y)294 bool find_min_or_max( int function, floatx guess, Complex &x, Complex &y ) throw(error_obj)
295 {
296 	math::CodeLine code;
297 	math::Variable tmpvar;
298 	utf8_string str;
299 	char char_str[500];
300 
301 	snprintf( char_str, 500, "ans = \"nDeriv( y%ld, x, x, ", function );
302 	str = char_str;
303 	floatx_to_string( (picbild2.get_right() - picbild2.get_left()) / (floatx(picbild2.pic.get_width()) * 5.0), str, stdformat );
304 	str.append( " )\"\n" );
305 	if( act_settings.show_code )
306 		(*TEXTVIEW_FUNCTION)( str.c_str() );
307 	code.set_code_line( str.c_str() );
308 	code.calc( 0 );
309 
310 	str = "x = nSolve( ans, x, ";
311 	floatx_to_string( guess, str, stdformat );
312 	str.append( ", " );
313 	floatx_to_string( (picbild2.get_right() - picbild2.get_left()) / (floatx(picbild2.pic.get_width()) * 5.0), str, stdformat);
314 	str.append( " )\n" );
315 	if( act_settings.show_code )
316 		(*TEXTVIEW_FUNCTION)( str.c_str() );
317 	code.set_code_line( str.c_str() );
318 	code.calc( 0 );
319 
320 // saves x,y for the solution
321 	x = *math::global_varlist.get_pointer( math::global_varlist.get_id("x") )->get_complex();
322 	code.set_code_line( act_settings.func[function].entry.c_str() );
323 	code.calc( &tmpvar );
324 	y = *tmpvar.get_complex();
325 
326 	str = "x = nDeriv( ans, x, x , ";
327 	floatx_to_string( (picbild2.get_right() - picbild2.get_left()) / (floatx(picbild2.pic.get_width()) * 5.0), str, stdformat );
328 	str.append( " )\n" );
329 	if( act_settings.show_code )
330 		(*TEXTVIEW_FUNCTION)( str.c_str() );
331 	code.set_code_line( str.c_str() );
332 	code.calc( 0 );
333 
334 	return ( floatx(math::global_varlist.get_pointer( math::global_varlist.get_id("x") )->get_complex()->real) > 0.0);
335 }
336 
find_intersection(int f1,int f2,floatx guess,Complex & x,Complex & y)337 void find_intersection( int f1, int f2, floatx guess, Complex &x, Complex &y ) throw(error_obj)
338 {
339 	char tmp_str[50];
340 	math::Variable tmpvar;
341 	math::CodeLine code;
342 	utf8_string str;
343 
344 	snprintf( tmp_str, 50, "x = nSolve( y%ld + \" - (\" + y%ld + \")\", x, ", f1, f2 );
345 	str = tmp_str;
346 	floatx_to_string( guess, str, stdformat);
347 	str.append( ", " );
348 	floatx_to_string( (picbild2.get_right() - picbild2.get_left()) / (floatx(picbild2.pic.get_width() * 5.0)), str, stdformat);
349 	str.append( " )\n" );
350 	if( act_settings.show_code )
351 		(*TEXTVIEW_FUNCTION)( str.c_str() );
352 	code.set_code_line( str.c_str() );
353 	code.calc( 0 );
354 
355 	x = *math::global_varlist.get_pointer( math::global_varlist.get_id("x") )->get_complex();
356 	code.set_code_line( act_settings.func[f1].entry.c_str() );
357 	code.calc( &tmpvar );
358 	y = *tmpvar.get_complex();
359 }
360 
picwin_reload_combos(int combo_action_entries)361 int picwin_reload_combos(int combo_action_entries)
362 {
363 	if( combo_action_entries != 0 )
364 	{
365 		for( int i=0; i<7; i++ )
366 			gtk_combo_box_remove_text( GTK_COMBO_BOX(picwin_combo_action), 0 );
367 	}
368 
369 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_action), _("Zoom") );
370 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_action), _("Find root") );
371 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_action), _("Find maximum/minimum") );
372 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_action), _("Find intersection") );
373 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_action), _("Calculate derivate") );
374 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_action), _("Calculate integral") );
375 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_action), _("Calculate length") );
376 
377 	gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_action), -1 );
378 
379 
380 	for( ; combo_action_entries > 0; combo_action_entries-- ) // removing all entries
381 		gtk_combo_box_remove_text( GTK_COMBO_BOX(picwin_combo_trace), 0 );
382 
383 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_trace), _("Off") );
384 	gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_trace), _("Auto") );
385 
386 	combo_action_entries = 2;
387 	if( act_settings.active_page == 0  ||  !act_settings.show_active_page_only )
388 	{
389 		char tmp_str[100];
390 		const char *trans = _("Locked on y%ld");
391 
392 		for( int i=0; i<10; i++ )
393 		{
394 			if( act_settings.func[i].show_this )
395 			{
396 				snprintf( tmp_str, 100, trans, i );
397 
398 				gtk_combo_box_append_text( GTK_COMBO_BOX(picwin_combo_trace), tmp_str );
399 				combo_action_entries++;
400 			}
401 		}
402 	}
403 
404 	gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace), 0 );
405 
406 	return combo_action_entries;
407 }
408 
place_marker(float x,float y,picture_h::colorrgb color)409 void place_marker(float x, float y, picture_h::colorrgb color)
410 {
411 	picbild2.pic.line( int32(x)-3, int32(y), int32(x)+3, int32(y), color );
412 	picbild2.pic.line( int32(x), int32(y)-3, int32(x), int32(y)+3, color );
413 
414 	picbild.update_from( picbild2.pic );
415 }
416 
picwin_intersection_show(int32 x)417 void picwin_intersection_show(int32 x)
418 {
419 	GtkWidget *dialog, *label, *align, *vbox;
420 	char tmp_str[50];
421 	utf8_string str;
422 	int second_function,nr;
423 	GtkWidget *radios[10];
424 	Complex tmp_value_x, tmp_value_y;
425 
426 	nr = 0;
427 	for( int i=0; i<10; i++ )
428 	{
429 		if( act_settings.func[i].show_this )
430 			nr++;
431 	}
432 	if( nr < 2 ) // at least 2 functions has to be drawn
433 	{
434 		dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
435 		                                 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
436 		             _("At least 2 functions must be drawn\nto be able to find an intersection") );
437 		gtk_window_set_title( GTK_WINDOW(dialog), _("Find intersection") );
438 		gtk_dialog_run(GTK_DIALOG(dialog));
439 		gtk_widget_destroy(dialog);
440 
441 		return;
442 	}
443 	else if( nr > 2 ) // if it's more than 2, dialog must be shown and user should choose which...
444 	{
445 		dialog = gtk_dialog_new_with_buttons( _("Find intersection"), GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
446 		                                      GTK_STOCK_OK, GTK_RESPONSE_OK, NULL );
447 
448 		align = gtk_alignment_new( 0.0, 0.0, 1.0, 1.0 );
449 		gtk_container_set_border_width( GTK_CONTAINER(align), 5 );
450 		gtk_box_pack_start( GTK_BOX(GTK_DIALOG(dialog)->vbox), align, FALSE, FALSE, 0 );
451 
452 		vbox = gtk_vbox_new( FALSE, 3 );
453 		gtk_container_add( GTK_CONTAINER(align), vbox );
454 
455 		label = gtk_label_new( _("Find intersection between") );
456 		gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5 );
457 		gtk_box_pack_start( GTK_BOX(vbox), label, FALSE, FALSE, 0) ;
458 
459 
460 		snprintf( tmp_str, 50, "y%ld = \"", old_best_match_i );
461 		str = tmp_str;
462 		str.append( act_settings.func[old_best_match_i].entry );
463 		str.append( "\"" );
464 		label = gtk_label_new( str.c_str() );
465 		gtk_misc_set_alignment( GTK_MISC(label), 0.05, 0.5 );
466 		gtk_box_pack_start( GTK_BOX(vbox), label, FALSE, FALSE, 0 );
467 
468 		label = gtk_label_new( _("and") );
469 		gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5 );
470 		gtk_box_pack_start( GTK_BOX(vbox), label, FALSE, FALSE, 0 );
471 
472 		nr = 0;
473 		for(int i=0;i<10;i++)
474 		{
475 			if( act_settings.func[i].show_this  &&  i != old_best_match_i )
476 			{
477 				snprintf( tmp_str, 50, "y%ld = \"", i );
478 				str = tmp_str;
479 				str.append( act_settings.func[i].entry );
480 				str.append( "\"" );
481 
482 				label = gtk_label_new( str.c_str() );
483 
484 				if(nr == 0)
485 				{
486 					radios[0] = gtk_radio_button_new( NULL );
487 					gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(radios[0]), TRUE );
488 				}
489 				else
490 					radios[nr] = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON(radios[0]) );
491 
492 				gtk_container_add( GTK_CONTAINER(radios[nr]), label );
493 
494 				gtk_box_pack_start( GTK_BOX(vbox), radios[nr], FALSE, FALSE, 0 );
495 
496 				nr++;
497 			}
498 		}
499 
500 		gtk_widget_show_all( dialog );
501 
502 		switch( gtk_dialog_run( GTK_DIALOG(dialog) ) )
503 		{
504 		case GTK_RESPONSE_OK:
505 
506 			second_function = 0;
507 			for(int i=0;i<10;i++)
508 			{
509 				if( act_settings.func[i].show_this  &&  i != old_best_match_i )
510 				{
511 					if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(radios[second_function]) ) ==
512 						TRUE )
513 					{
514 						second_function = i;
515 						break;
516 					}
517 					second_function++;
518 				}
519 			}
520 			gtk_widget_destroy(dialog);
521 			break;
522 
523 		default:
524 			gtk_widget_destroy(dialog);
525 			return;
526 		}
527 	}
528 	else // if(nr == 2)
529 	{
530 		for( int i=0; i<10; i++ )
531 		{
532 			if( act_settings.func[i].show_this  &&  i != old_best_match_i )
533 			{
534 				second_function = i;
535 				break;
536 			}
537 		}
538 	}
539 
540 	try
541 	{
542 		find_intersection( old_best_match_i, second_function, get_x_value( x, old_best_match_i ), tmp_value_x, tmp_value_y );
543 
544 		str = _("Intersection found at");
545 		str.append( "\nx = " );
546 		tmp_value_x.append_to_string( str, format );
547 
548 		str.append( "\ny = " );
549 		tmp_value_y.append_to_string( str, format );
550 		if(act_settings.show_code)
551 		{
552 			(*TEXTVIEW_FUNCTION)( str.c_str() );
553 			(*TEXTVIEW_FUNCTION)("\n");
554 		}
555 		place_marker( picbild2.get_float_x_pixel( floatx(tmp_value_x.real) ),
556 		              picbild2.get_float_y_pixel( floatx(tmp_value_y.real)),
557 		              act_settings.func[old_best_match_i].color );
558 
559 
560 		dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
561 		                                 GTK_BUTTONS_OK, str.c_str() );
562 		gtk_window_set_title( GTK_WINDOW(dialog), _("Find intersection") );
563 		gtk_dialog_run( GTK_DIALOG(dialog) );
564 		gtk_widget_destroy(dialog);
565 	}
566 	catch(error_obj error)
567 	{
568 		dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
569 		                                 GTK_BUTTONS_CLOSE, error.msg );
570 		gtk_window_set_title( GTK_WINDOW(dialog), _("Find intersection") );
571 		gtk_dialog_run(GTK_DIALOG(dialog));
572 		gtk_widget_destroy(dialog);
573 	}
574 	catch(...)
575 	{
576 		try{ THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
577 		catch(error_obj error)
578 		{
579 			dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
580 			                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error.msg);
581 			gtk_window_set_title( GTK_WINDOW(dialog), _("Find intersection") );
582 			gtk_dialog_run(GTK_DIALOG(dialog));
583 			gtk_widget_destroy(dialog);
584 		}
585 	}
586 }
587 
picwin_calc_derivate(int32 x)588 void picwin_calc_derivate( int32 x )
589 {
590 	utf8_string str, str2;
591 	math::CodeLine function;
592 	GtkWidget *dialog;
593 
594 	char char_str[1000];
595 
596 	try
597 	{
598 		str = "";
599 		floatx_to_string( get_x_value( x, old_best_match_i ), str, stdformat );
600 		str2 = "";
601 		floatx_to_string( ((floatx(trace_matrix.get_complex( 2, 1 ).real) -
602 		                    floatx(trace_matrix.get_complex( 1, 1 ).real))/2.0), str2, stdformat);
603 		snprintf( char_str, 1000, "x = nDeriv( y%ld, x, %s, %s )", old_best_match_i, str.c_str(), str2.c_str() );
604 
605 		function.set_code_line( char_str );
606 		function.calc( 0 );
607 
608 		str2 = "";
609 		math::global_varlist.get_pointer( math::global_varlist.get_id("x") )->get_complex()->append_to_string( str2, format );
610 
611 		snprintf( char_str, 1000, _("Derivate of y%ld at X=%s is\n%s"), old_best_match_i, str.c_str(), str2.c_str() );
612 
613 		dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
614 		                                 GTK_BUTTONS_OK, char_str );
615 		gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate derivate") );
616 		gtk_dialog_run( GTK_DIALOG(dialog) );
617 		gtk_widget_destroy(dialog);
618 	}
619 	catch(error_obj error)
620 	{
621 		dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
622 		                                 GTK_BUTTONS_CLOSE, error.msg );
623 		gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate derivate") );
624 		gtk_dialog_run(GTK_DIALOG(dialog));
625 		gtk_widget_destroy(dialog);
626 	}
627 	catch(...)
628 	{
629 		try{ THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
630 		catch(error_obj error)
631 		{
632 			dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
633 			                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error.msg);
634 			gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate deriavte") );
635 			gtk_dialog_run(GTK_DIALOG(dialog));
636 			gtk_widget_destroy(dialog);
637 		}
638 	}
639 }
640 
picwin_calc_integral(int32 x)641 void picwin_calc_integral( int32 x )
642 {
643 	static int32 first_x;
644 	static int first_old_best_match_i;
645 	utf8_string str, str2, str3;
646 	math::CodeLine function;
647 	GtkWidget *dialog;
648 	Complex tmp_value_x;
649 	int tmp_old_best_match_i;
650 
651 	char char_str[1000];
652 
653 	try
654 	{
655 		if( picwin_first_click_done )
656 		{
657 			picwin_first_click_done = false;
658 
659 			if( first_old_best_match_i == old_best_match_i )
660 			{
661 				snprintf( char_str, 1000, "x = nInt( y%ld, x, ", old_best_match_i );
662 				str = char_str;
663 				floatx_to_string( get_x_value( first_x, old_best_match_i ), str, stdformat );
664 				str.append( ", " );
665 				floatx_to_string( get_x_value( x, old_best_match_i ), str, stdformat );
666 				snprintf( char_str, 1000, ", %ld )", abs(first_x-x)*10 );
667 				str.append( char_str );
668 
669 				function.set_code_line( str.c_str() );
670 				function.calc( 0 );
671 
672 				tmp_value_x = *math::global_varlist.get_pointer(
673 				                       math::global_varlist.get_id("x") )->get_complex();
674 
675 				snprintf( char_str, 1000, "plot_picture = shade( plot_picture, y%ld, \"0\", x, ", old_best_match_i );
676 				str = char_str;
677 				floatx_to_string( get_x_value( first_x, old_best_match_i ), str, stdformat );
678 				str.append( ", " );
679 				floatx_to_string( get_x_value( x, old_best_match_i ), str, stdformat );
680 				snprintf( char_str, 1000, ", 0, [[ %f, %f, %f ]] )",
681 				          act_settings.func[old_best_match_i].color.red/255.0f,
682 				          act_settings.func[old_best_match_i].color.green/255.0f,
683 				          act_settings.func[old_best_match_i].color.blue/255.0f );
684 				str.append( char_str );
685 				function.set_code_line( str.c_str() );
686 				function.calc( 0 );
687 			}
688 			else
689 			{
690 				snprintf( char_str, 1000, "x = nInt( y%ld + \" - ( \" + y%ld + \" )\", x, ", first_old_best_match_i,
691 				          old_best_match_i );
692 				str = char_str;
693 				floatx_to_string( get_x_value( first_x, first_old_best_match_i ), str, stdformat );
694 				str.append( ", " );
695 				floatx_to_string( get_x_value( x, old_best_match_i ), str, stdformat );
696 				snprintf( char_str, 1000, ", %ld )", abs(first_x-x)*10 );
697 				str.append( char_str );
698 
699 				function.set_code_line( str.c_str() );
700 				function.calc( 0 );
701 
702 				tmp_value_x = *math::global_varlist.get_pointer(
703 				                       math::global_varlist.get_id("x") )->get_complex();
704 
705 				snprintf( char_str, 1000, "plot_picture = shade( plot_picture, y%ld, y%ld, x, ", first_old_best_match_i,
706 				          old_best_match_i );
707 				str = char_str;
708 				floatx_to_string( get_x_value( first_x, first_old_best_match_i ), str, stdformat );
709 				str.append( ", " );
710 				floatx_to_string( get_x_value( x, old_best_match_i ), str, stdformat);
711 				snprintf( char_str, 1000, ", 0, [[ %f, %f, %f ]] )",
712 				          act_settings.func[first_old_best_match_i].color.red/255.0f,
713 				          act_settings.func[first_old_best_match_i].color.green/255.0f,
714 				          act_settings.func[first_old_best_match_i].color.blue/255.0f );
715 				str.append( char_str );
716 				function.set_code_line( str.c_str() );
717 				function.calc( 0 );
718 			}
719 			{
720 				int tmp = gtk_combo_box_get_active( GTK_COMBO_BOX(picwin_combo_trace) );
721 
722 				tmp_old_best_match_i = old_best_match_i;     // saving this because it will be reseted to -1 when
723 				function.set_code_line("show plot_picture"); // redrawing the picture
724 				function.calc( 0 );
725 
726 				gtk_widget_set_sensitive( picwin_combo_trace, TRUE );
727 				gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace), tmp ); // auto-trace
728 				gtk_widget_set_sensitive( picwin_combo_action, TRUE );
729 				gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_action), LeftClickAction_CalcIntegral );
730 
731 				picbild.mousedown_func = picwin_mousedown;
732 			}
733 
734 			str = "";  str2 = "";  str3 = "";
735 			floatx_to_string( get_x_value( first_x, first_old_best_match_i ), str, stdformat );
736 			floatx_to_string( get_x_value( x, tmp_old_best_match_i ), str2, stdformat );
737 			tmp_value_x.append_to_string( str3, format );
738 
739 			snprintf( char_str, 1000, _("Integral from %s to %s is\n%s"), str.c_str(), str2.c_str(), str3.c_str() );
740 
741 			dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
742 			                                 GTK_BUTTONS_OK, char_str );
743 			gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate integral") );
744 			gtk_dialog_run( GTK_DIALOG(dialog) );
745 			gtk_widget_destroy(dialog);
746 		}
747 		else
748 		{
749 			first_x = x;
750 			first_old_best_match_i = old_best_match_i;
751 			picwin_first_click_done = true;
752 
753 			gettimeofday( &action_combo_changed, 0 );
754 			gtk_label_set_text( GTK_LABEL(picwin_status), _("Select end point") );
755 		}
756 	}
757 	catch(error_obj error)
758 	{
759 		dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
760 		                                 GTK_BUTTONS_CLOSE, error.msg );
761 		gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate integral") );
762 		gtk_dialog_run(GTK_DIALOG(dialog));
763 		gtk_widget_destroy(dialog);
764 	}
765 	catch(...)
766 	{
767 		try{ THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
768 		catch(error_obj error)
769 		{
770 			dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
771 			                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error.msg);
772 			gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate integral") );
773 			gtk_dialog_run(GTK_DIALOG(dialog));
774 			gtk_widget_destroy(dialog);
775 		}
776 	}
777 }
778 
779 
picwin_calc_length(int32 x)780 void picwin_calc_length( int32 x )
781 {
782 	static int32 first_x;
783 	static int first_old_best_match_i;
784 	utf8_string str, str2, str3;
785 	math::CodeLine function;
786 	GtkWidget *dialog;
787 	Complex tmp_value_x;
788 
789 	char char_str[1000];
790 
791 	try
792 	{
793 		if( picwin_first_click_done )
794 		{
795 			picwin_first_click_done = false;
796 
797 			if( first_old_best_match_i == old_best_match_i )
798 			{
799 				snprintf( char_str, 1000, "x = nInt( \"sqrt( 1.0 + nDeriv( y%ld, x, x, ", old_best_match_i );
800 				str = char_str;
801 				floatx_to_string( ((floatx(trace_matrix.get_complex( 2, 1 ).real) -
802 				                    floatx(trace_matrix.get_complex( 1, 1 ).real))/10.0), str, stdformat);
803 				str.append( " ) ^2 )\", x, " );
804 				floatx_to_string( get_x_value( first_x, old_best_match_i ), str, stdformat);
805 				str.append( ", " );
806 				floatx_to_string( get_x_value( x, old_best_match_i ), str, stdformat);
807 				snprintf( char_str, 1000, ", %ld )", abs(first_x-x)*10 );
808 				str.append( char_str );
809 
810 				function.set_code_line( str.c_str() );
811 				function.calc( 0 );
812 
813 				tmp_value_x = *math::global_varlist.get_pointer( math::global_varlist.get_id("x") )->get_complex();
814 			}
815 			else
816 			{
817 				error_obj error;
818 				snprintf( error.msg, ERROR_OBJ_MSG_LEN, _("Start and end point must both\nbe at the same function.") );
819 				throw error;
820 			}
821 
822 			str = "";  str2 = "";  str3 = "";
823 			floatx_to_string( get_x_value( first_x, old_best_match_i ), str, stdformat);
824 			floatx_to_string( get_x_value( x, old_best_match_i ), str2, stdformat);
825 			tmp_value_x.append_to_string( str3, format );
826 
827 			snprintf( char_str, 1000, _("The length of y%ld from %s to %s is\n%s"), old_best_match_i, str.c_str(),
828 			                                                                        str2.c_str(), str3.c_str() );
829 
830 			dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
831 							GTK_BUTTONS_OK, char_str );
832 			gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate length") );
833 			gtk_dialog_run( GTK_DIALOG(dialog) );
834 			gtk_widget_destroy(dialog);
835 		}
836 		else
837 		{
838 			first_x = x;
839 			first_old_best_match_i = old_best_match_i;
840 			picwin_first_click_done = true;
841 
842 			gettimeofday( &action_combo_changed, 0 );
843 			gtk_label_set_text( GTK_LABEL(picwin_status), _("Select end point") );
844 		}
845 	}
846 	catch(error_obj error)
847 	{
848 		dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
849 		                                 GTK_BUTTONS_CLOSE, error.msg );
850 		gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate length") );
851 		gtk_dialog_run(GTK_DIALOG(dialog));
852 		gtk_widget_destroy(dialog);
853 	}
854 	catch(...)
855 	{
856 		try{ THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
857 		catch(error_obj error)
858 		{
859 			dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
860 			                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error.msg);
861 			gtk_window_set_title( GTK_WINDOW(dialog), _("Calculate length") );
862 			gtk_dialog_run(GTK_DIALOG(dialog));
863 			gtk_widget_destroy(dialog);
864 		}
865 	}
866 }
867 
picwin_mousedown(const picture2gtk * src,int32 x,int32 y,int32 button)868 void picwin_mousedown( const picture2gtk *src, int32 x, int32 y, int32 button )
869 {
870 	utf8_string str;
871 	floatx xcenter, ycenter, width, height;
872 	math::Variable tmpvar;
873 	char char_str[1000];
874 
875 	if( old_best_match_i != -1 )
876 	{
877 		x = old_tx;
878 		y = old_ty;
879 	}
880 
881 	switch(button)
882 	{
883 	case 1: // left button
884 		if( GTK_WIDGET_IS_SENSITIVE(picwin_combo_trace) == TRUE )
885 		{
886 			switch(gtk_combo_box_get_active( GTK_COMBO_BOX(picwin_combo_action) ))
887 			{
888 			case LeftClickAction_Zoom:
889 
890 				xcenter = picbild2.get_x_value( x );
891 				ycenter = picbild2.get_y_value( y );
892 				width = picbild2.get_right() - picbild2.get_left();
893 				height = picbild2.get_top() - picbild2.get_bottom();
894 				width /= 4.0;
895 				height /= 4.0;
896 
897 				try
898 				{
899 					floatx_to_string( xcenter-width, str, stdformat);
900 					act_settings.xmin = str.c_str();
901 
902 					str = "";
903 					floatx_to_string( xcenter+width, str, stdformat);
904 					act_settings.xmax = str.c_str();
905 
906 					str = "";
907 					floatx_to_string( ycenter-height, str, stdformat);
908 					act_settings.ymin = str.c_str();
909 
910 					str = "";
911 					floatx_to_string( ycenter+height, str, stdformat);
912 					act_settings.ymax = str.c_str();
913 
914 					{
915 						gint tmpint;
916 						tmpint = gtk_combo_box_get_active(GTK_COMBO_BOX(picwin_combo_trace));
917 						picturewin_show( (graph_settings *)(0) );
918 						gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace), tmpint );
919 					}
920 				}
921 				catch(...) { }
922 				break;
923 
924 			case LeftClickAction_FindRoot:
925 				{
926 					GtkWidget *dialog;
927 					Complex tmp_value_x,tmp_value_y;
928 
929 					if( old_best_match_i == -1 )
930 						return;
931 
932 					try
933 					{
934 						find_root( old_best_match_i, get_x_value( x, old_best_match_i ), tmp_value_x, tmp_value_y );
935 
936 						str = "x = ";
937 						tmp_value_x.append_to_string( str, format );
938 						if( act_settings.show_code )
939 						{
940 							(*TEXTVIEW_FUNCTION)( str.c_str() );
941 							(*TEXTVIEW_FUNCTION)( "\n" );
942 						}
943 						place_marker( picbild2.get_float_x_pixel( floatx(tmp_value_x.real) ),
944 						              picbild2.get_float_y_pixel( floatx(tmp_value_y.real)),
945 						              act_settings.func[old_best_match_i].color );
946 
947 						dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
948 						                                 GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
949 						                                 str.c_str() );
950 						gtk_window_set_title( GTK_WINDOW(dialog), _("Find root") );
951 						gtk_dialog_run( GTK_DIALOG(dialog) );
952 						gtk_widget_destroy( dialog );
953 					}
954 					catch(error_obj error)
955 					{
956 						dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
957 						                                 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
958 						                                 error.msg );
959 						gtk_window_set_title( GTK_WINDOW(dialog), _("Find root") );
960 						gtk_dialog_run( GTK_DIALOG(dialog) );
961 						gtk_widget_destroy( dialog );
962 					}
963 					catch(...)
964 					{
965 						try{ THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
966 						catch(error_obj error)
967 						{
968 							dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin),
969 							                                 GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
970 							                                 GTK_BUTTONS_CLOSE, error.msg );
971 							gtk_window_set_title( GTK_WINDOW(dialog), _("Find root") );
972 							gtk_dialog_run( GTK_DIALOG(dialog) );
973 							gtk_widget_destroy( dialog );
974 						}
975 					}
976 				}
977 				break;  // LeftClickAction_FindRoot
978 
979 			case LeftClickAction_FindMaximumMinimum:
980 				{
981 					GtkWidget *dialog;
982 					Complex tmp_value_x,tmp_value_y;
983 
984 					if( old_best_match_i == -1 )
985 						return;
986 
987 					try
988 					{
989 						if( find_min_or_max( old_best_match_i, get_x_value( x, old_best_match_i ),
990 						                               tmp_value_x, tmp_value_y ) )
991 							str = _("Local minimum at");
992 						else
993 							str = _("Local maximum at");
994 
995 						str.append( "\nx = " );
996 						tmp_value_x.append_to_string( str, format );
997 
998 						str.append( "\ny = " );
999 						tmp_value_y.append_to_string( str, format );
1000 						if(act_settings.show_code)
1001 						{
1002 							(*TEXTVIEW_FUNCTION)( str.c_str() );
1003 							(*TEXTVIEW_FUNCTION)( "\n" );
1004 						}
1005 						place_marker( picbild2.get_float_x_pixel( floatx(tmp_value_x.real) ),
1006 						              picbild2.get_float_y_pixel( floatx(tmp_value_y.real)),
1007 						              act_settings.func[old_best_match_i].color );
1008 
1009 						dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
1010 						                                 GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
1011 						                                 str.c_str() );
1012 						gtk_window_set_title( GTK_WINDOW(dialog), _("Find maximum/minimum") );
1013 						gtk_dialog_run( GTK_DIALOG(dialog) );
1014 						gtk_widget_destroy(dialog);
1015 					}
1016 					catch(error_obj error)
1017 					{
1018 						dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin), GTK_DIALOG_MODAL,
1019 						                                 GTK_MESSAGE_ERROR,
1020 						                                 GTK_BUTTONS_CLOSE, error.msg );
1021 						gtk_window_set_title( GTK_WINDOW(dialog), _("Find maximum/minimum") );
1022 						gtk_dialog_run( GTK_DIALOG(dialog) );
1023 						gtk_widget_destroy(dialog);
1024 					}
1025 					catch(...)
1026 					{
1027 						try{ THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
1028 						catch(error_obj error)
1029 						{
1030 							dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin),
1031 							                                 GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
1032 							                                 GTK_BUTTONS_CLOSE, error.msg );
1033 							gtk_window_set_title( GTK_WINDOW(dialog), _("Find maximum/minimum") );
1034 							gtk_dialog_run( GTK_DIALOG(dialog) );
1035 							gtk_widget_destroy(dialog);
1036 						}
1037 					}
1038 				}
1039 				break; // LeftClickAction_FindMaximumMinimum
1040 
1041 			case LeftClickAction_FindIntersection:
1042 				if( old_best_match_i == -1 )
1043 					return;
1044 				picwin_intersection_show( x );
1045 				break;
1046 
1047 			case LeftClickAction_CalcDerivate:
1048 				if( old_best_match_i == -1 )
1049 					return;
1050 				picwin_calc_derivate( x );
1051 				break;
1052 
1053 			case LeftClickAction_CalcIntegral:
1054 				if( old_best_match_i == -1 )
1055 					return;
1056 				picwin_calc_integral( x );
1057 				break;
1058 
1059 			case LeftClickAction_CalcLength:
1060 				if( old_best_match_i == -1 )
1061 					return;
1062 				picwin_calc_length( x );
1063 				break;
1064 			}
1065 		}
1066 		break;
1067 
1068 	case 2: // middle button
1069 		if(GTK_WIDGET_IS_SENSITIVE(picwin_combo_trace) == TRUE)
1070 		{
1071 			switch( gtk_combo_box_get_active(GTK_COMBO_BOX(picwin_combo_trace)) )
1072 			{
1073 			case 0: // off
1074 				gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace), 1 );
1075 				break;
1076 
1077 			case 1: // auto
1078 				if(old_best_match_i != -1)
1079 					gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace),
1080 					                   conv_function_index_to_combobox_index(old_best_match_i) );
1081 				break;
1082 
1083 
1084 			default: // locked
1085 				gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace), 1 );
1086 			}
1087 		}
1088 		break;
1089 
1090 	case 3: // right button
1091 		if(GTK_WIDGET_IS_SENSITIVE(picwin_combo_trace) == TRUE)
1092 		{
1093 			xcenter = picbild2.get_x_value( x );
1094 			ycenter = picbild2.get_y_value( y );
1095 			width = picbild2.get_right() - picbild2.get_left();
1096 			height = picbild2.get_top() - picbild2.get_bottom();
1097 
1098 			try
1099 			{
1100 				str = "";
1101 				floatx_to_string( xcenter-width, str, stdformat);
1102 				act_settings.xmin = str.c_str();
1103 
1104 				str = "";
1105 				floatx_to_string( xcenter+width, str, stdformat);
1106 				act_settings.xmax = str.c_str();
1107 
1108 				str = "";
1109 				floatx_to_string( ycenter-height, str, stdformat);
1110 				act_settings.ymin = str.c_str();
1111 
1112 				str = "";
1113 				floatx_to_string( ycenter+height, str, stdformat);
1114 				act_settings.ymax = str.c_str();
1115 
1116 				{
1117 					gint tmpint;
1118 					tmpint = gtk_combo_box_get_active(GTK_COMBO_BOX(picwin_combo_trace));
1119 					picturewin_show( (graph_settings *)(0) );
1120 					gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace), tmpint );
1121 				}
1122 			}
1123 			catch(...) { }
1124 		}
1125 		break;
1126 	}
1127 }
1128 
1129 
1130 
1131 
picwin_hline(guchar * buffer,int32 width,int32 height,int32 row,picture_h::colorrgb & color)1132 void picwin_hline( guchar *buffer, int32 width, int32 height, int32 row, picture_h::colorrgb &color)
1133 {
1134 	if( row < 0  ||  row >= height  ||  width <= 0  ||  height <= 0  ||  buffer == 0 )
1135 		return;
1136 
1137 	buffer += width*3*row;
1138 	for(;width != 0;width--)
1139 	{
1140 		*buffer++ = guchar(color.red);
1141 		*buffer++ = guchar(color.green);
1142 		*buffer++ = guchar(color.blue);
1143 	}
1144 }
picwin_vline(guchar * buffer,int32 width,int32 height,int32 col,picture_h::colorrgb & color)1145 void picwin_vline( guchar *buffer, int32 width, int32 height, int32 col, picture_h::colorrgb &color)
1146 {
1147 	if( col < 0  ||  col >= width  ||  width <= 0  ||  height <= 0  ||  buffer == 0 )
1148 		return;
1149 
1150 	int rowstride = 3*width - 2;
1151 	buffer += 3*col;
1152 	for(;height != 0;height--, buffer += rowstride)
1153 	{
1154 		*buffer++ = guchar(color.red);
1155 		*buffer++ = guchar(color.green);
1156 		*buffer = guchar(color.blue);
1157 	}
1158 }
1159 
picwin_get_row(const guchar * buffer,int32 width,int32 height,int32 row,guchar * dest)1160 void picwin_get_row( const guchar *buffer, int32 width, int32 height, int32 row, guchar *dest)
1161 {
1162 	if( row < 0  ||  row >= height  ||  width <= 0  ||  height <= 0  ||  buffer == 0 )
1163 		return;
1164 
1165 	register int32 tmp = width*3;
1166 	buffer += tmp*row;
1167 
1168 	memcpy(dest, buffer, tmp);
1169 }
1170 
picwin_set_row(guchar * buffer,int32 width,int32 height,int32 row,const guchar * src)1171 void picwin_set_row( guchar *buffer, int32 width, int32 height, int32 row, const guchar *src)
1172 {
1173 	if( row < 0  ||  row >= height  ||  width <= 0  ||  height <= 0  ||  buffer == 0 )
1174 		return;
1175 
1176 	register int32 tmp = width*3;
1177 	buffer += tmp*row;
1178 
1179 	memcpy(buffer, src, tmp);
1180 }
1181 
picwin_get_col(const guchar * buffer,int32 width,int32 height,int32 col,guchar * dest)1182 void picwin_get_col( const guchar *buffer, int32 width, int32 height, int32 col, guchar *dest)
1183 {
1184 	if( col < 0  ||  col >= width  ||  width <= 0  ||  height <= 0  ||  buffer == 0 )
1185 		return;
1186 
1187 	int rowstride = 3*width - 2;
1188 	buffer += 3*col;
1189 	for(;height != 0;height--, buffer += rowstride)
1190 	{
1191 		*dest++ = *buffer++;
1192 		*dest++ = *buffer++;
1193 		*dest++ = *buffer;
1194 	}
1195 }
1196 
picwin_set_col(guchar * buffer,int32 width,int32 height,int32 col,const guchar * src)1197 void picwin_set_col( guchar *buffer, int32 width, int32 height, int32 col, const guchar *src)
1198 {
1199 	if( col < 0  ||  col >= width  ||  width <= 0  ||  height <= 0  ||  buffer == 0 )
1200 		return;
1201 
1202 	int rowstride = 3*width - 2;
1203 	buffer += 3*col;
1204 	for(;height != 0;height--, buffer += rowstride)
1205 	{
1206 		*buffer++ = *src++;
1207 		*buffer++ = *src++;
1208 		*buffer = *src++;
1209 	}
1210 }
1211 
picwin_remove_old_trace_mark(void)1212 void picwin_remove_old_trace_mark( void )
1213 {
1214 	if( old_best_match_i != -1 )
1215 	{
1216 		if( picwin_rowbuffer_len < picbild2.pic.get_width() )
1217 		{
1218 			delete [] picwin_rowbuffer;
1219 			picwin_rowbuffer = 0;
1220 			picwin_rowbuffer_len = 0;
1221 
1222 			try{
1223 				picwin_rowbuffer = new guchar [ picbild2.pic.get_width()*3 ];
1224 				picwin_rowbuffer_len = picbild2.pic.get_width();
1225 			}catch( ... ) {  return;  }
1226 		}
1227 		if( picwin_colbuffer_len < picbild2.pic.get_height() )
1228 		{
1229 			delete [] picwin_colbuffer;
1230 			picwin_colbuffer = 0;
1231 			picwin_colbuffer_len = 0;
1232 
1233 			try{
1234 				picwin_colbuffer = new guchar [ picbild2.pic.get_height()*3 ];
1235 				picwin_colbuffer_len = picbild2.pic.get_height();
1236 			}catch( ... ) {  return;  }
1237 		}
1238 
1239 		picwin_set_col( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1240 		                picbild2.pic.get_height(), old_tx, picwin_colbuffer );
1241 		picwin_set_row( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1242 		                picbild2.pic.get_height(), old_ty, picwin_rowbuffer );
1243 
1244 		picbild.force_expose_line( old_ty );
1245 		picbild.force_expose_col( old_tx );
1246 
1247 		old_best_match_i = -1;
1248 	}
1249 }
1250 
picwin_mousemove(const picture2gtk * src,int32 x,int32 y)1251 void picwin_mousemove( const picture2gtk *src, int32 x, int32 y )
1252 {
1253 	const uint32 limit_tiden = 3000000;
1254 	uint32 tiden;
1255 	{
1256 		timeval tmp;
1257 		gettimeofday( &tmp ,0 );
1258 
1259 		tiden = 1000000*(tmp.tv_sec - action_combo_changed.tv_sec) + tmp.tv_usec - action_combo_changed.tv_usec;
1260 	}
1261 
1262 	picwin_remove_old_trace_mark();
1263 
1264 	if( GTK_WIDGET_IS_SENSITIVE(picwin_combo_trace) == TRUE  &&
1265 	    gtk_combo_box_get_active( GTK_COMBO_BOX(picwin_combo_trace) ) == 0 ) // no trace
1266 		gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_action), 0 ); // zoom
1267 
1268 	if( x < 0  ||  x >= picbild2.pic.get_width()  ||  y < 0  ||  y >= picbild2.pic.get_height() )
1269 	{
1270 		if( gtk_combo_box_get_active( GTK_COMBO_BOX(picwin_combo_action) ) < 1 )
1271 			gtk_label_set_text( GTK_LABEL(picwin_status), PRG_NAME );
1272 	}
1273 	else
1274 	{
1275 		Complex tmp, best_match;
1276 		floatx y_value;
1277 		int i, best_match_i;
1278 		static utf8_string str;
1279 		Format tmp_format;
1280 
1281 		char char_str[300];
1282 
1283 		tmp_format = format;
1284 		tmp_format.show_trailingzeros = true;
1285 
1286 		if( gtk_combo_box_get_active(GTK_COMBO_BOX(picwin_combo_trace)) != 0 )
1287 		{
1288 			if( act_settings.active_page != 0  &&  act_settings.show_active_page_only )
1289 				goto picwin_no_trace;
1290 
1291 			if( gtk_combo_box_get_active(GTK_COMBO_BOX(picwin_combo_trace)) == 1 )
1292 			{
1293 				y_value = picbild2.get_y_value( y );
1294 				best_match_i = -1;
1295 				for(i=0;i<10;i++) // this loop finds first (if any) non error trace
1296 				{
1297 					if(act_settings.func[i].show_this)
1298 					{
1299 						best_match_i = i;
1300 						best_match = trace_matrix.get_complex( x+1, i+2 );
1301 						if( floatx(best_match.imaginary) == 0.0 )
1302 							break;
1303 					}
1304 				}
1305 				if(best_match_i == -1)
1306 					goto picwin_no_trace;
1307 				for( i++; i<10; i++ )
1308 				{
1309 					if(act_settings.func[i].show_this)
1310 					{
1311 						tmp = trace_matrix.get_complex( x+1, i+2 );
1312 						if(floatx(tmp.imaginary) != 0.0) // skip this
1313 							continue;
1314 						if( fabsx(floatx(tmp.real) - y_value) < fabsx(floatx(best_match.real) - y_value) )
1315 						{
1316 							best_match_i = i;
1317 							best_match = tmp;
1318 						}
1319 					}
1320 				}
1321 			}
1322 			else // this is a locked trace
1323 			{
1324 				best_match_i = conv_combobox_index_to_function_index(
1325 				                    gtk_combo_box_get_active(GTK_COMBO_BOX(picwin_combo_trace)) );
1326 				best_match = trace_matrix.get_complex( x+1, best_match_i+2 );
1327 			}
1328 
1329 			if(floatx(best_match.imaginary) != 0.0)
1330 			{
1331 				if( gtk_combo_box_get_active( GTK_COMBO_BOX(picwin_combo_action) ) < 1  ||  tiden > limit_tiden )
1332 				{
1333 					str = "X=";
1334 					floatx_to_string( get_x_value( x, best_match_i ), str, tmp_format );
1335 					str.append( "  Y=" );
1336 					str.append( _("Error") );
1337 					gtk_label_set_text( GTK_LABEL(picwin_status), str.c_str() );
1338 				}
1339 			}
1340 			else
1341 			{
1342 				if( gtk_combo_box_get_active( GTK_COMBO_BOX(picwin_combo_action) ) < 1  ||  tiden > limit_tiden )
1343 				{
1344 					SnapInfo snappen;
1345 
1346 					snprintf( char_str, 300, "y%ld( ", best_match_i );
1347 					str = char_str;
1348 
1349 					snappen.calculated = false;
1350 					floatx_to_string( get_x_value( x, best_match_i ), str, tmp_format );
1351 					str.append( " ) = " );
1352 					floatx_to_string( get_y_value( x, best_match_i, &snappen ), str, tmp_format );
1353 					if( snappen.calculated )
1354 					{
1355 						str.append( " (" );
1356 						switch( snappen.snap_type )
1357 						{
1358 						case SnapInfo::Snap_Root:
1359 							str.append( _("Root") );
1360 							break;
1361 						case SnapInfo::Snap_Maximum:
1362 							str.append( _("Maximum") );
1363 							break;
1364 						case SnapInfo::Snap_Minimum:
1365 							str.append( _("Minimum") );
1366 							break;
1367 						case SnapInfo::Snap_Intersection:
1368 							snprintf( char_str, 300, _("Intersection with y%ld"),
1369 							          snappen.intersect_with );
1370 							str.append( char_str );
1371 							break;
1372 						}
1373 						str.append( ")" );
1374 					}
1375 					gtk_label_set_text( GTK_LABEL(picwin_status), str.c_str() );
1376 				}
1377 
1378 				try
1379 				{
1380 					int32 tx,ty;
1381 
1382 					if( picwin_rowbuffer_len < picbild2.pic.get_width() )
1383 					{
1384 						delete [] picwin_rowbuffer;
1385 						picwin_rowbuffer = 0;
1386 						picwin_rowbuffer_len = 0;
1387 
1388 						picwin_rowbuffer = new guchar [ picbild2.pic.get_width()*3 ];
1389 						picwin_rowbuffer_len = picbild2.pic.get_width();
1390 					}
1391 					if( picwin_colbuffer_len < picbild2.pic.get_height() )
1392 					{
1393 						delete [] picwin_colbuffer;
1394 						picwin_colbuffer = 0;
1395 						picwin_colbuffer_len = 0;
1396 
1397 						picwin_colbuffer = new guchar [ picbild2.pic.get_height()*3 ];
1398 						picwin_colbuffer_len = picbild2.pic.get_height();
1399 					}
1400 
1401 					tx = picbild2.get_x_pixel( get_x_value( x, best_match_i ) );
1402 
1403 					if( tx != old_tx  ||  best_match_i != old_best_match_i )
1404 					{
1405 						ty = picbild2.get_y_pixel( get_y_value( x, best_match_i ) );
1406 
1407 						if( old_best_match_i != -1 )
1408 						{
1409 							picwin_set_col( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1410 							                picbild2.pic.get_height(), old_tx, picwin_colbuffer );
1411 							picwin_set_row( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1412 							                picbild2.pic.get_height(), old_ty, picwin_rowbuffer );
1413 
1414 							picbild.force_expose_line( old_ty );
1415 							picbild.force_expose_col( old_tx );
1416 						}
1417 						picwin_get_row( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1418 						                picbild2.pic.get_height(), ty, picwin_rowbuffer );
1419 						picwin_get_col( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1420 						                picbild2.pic.get_height(), tx, picwin_colbuffer );
1421 
1422 						picwin_hline( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1423 						              picbild2.pic.get_height(), ty,
1424 						              act_settings.func[best_match_i].color );
1425 						picwin_vline( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1426 						              picbild2.pic.get_height(), tx,
1427 						              act_settings.func[best_match_i].color );
1428 
1429 						picbild.force_expose_line( ty );
1430 						picbild.force_expose_col( tx );
1431 
1432 						old_tx = tx;
1433 						old_ty = ty;
1434 						old_best_match_i = best_match_i;
1435 					}
1436 				}
1437 				catch(error_obj error)
1438 				{
1439 					(*TEXTVIEW_FUNCTION)("\n\nError while updating trace: ");
1440 					(*TEXTVIEW_FUNCTION)(error.msg);
1441 					(*TEXTVIEW_FUNCTION)("\n\n");
1442 				}
1443 				catch(...)
1444 				{
1445 					try{ THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
1446 					catch(error_obj error)
1447 					{
1448 						(*TEXTVIEW_FUNCTION)("\n\nError while updating trace: ");
1449 						(*TEXTVIEW_FUNCTION)(error.msg);
1450 						(*TEXTVIEW_FUNCTION)("\n\n");
1451 					}
1452 				}
1453 			}
1454 		}
1455 		else
1456 		{
1457 picwin_no_trace:
1458 			bool trailingzeros = stdformat.show_trailingzeros;
1459 			stdformat.show_trailingzeros = true;
1460 			str = "X=";
1461 			floatx_to_string( picbild2.get_x_value( x ), str, stdformat);
1462 			str.append( "  Y=" );
1463 			floatx_to_string( picbild2.get_y_value( y ), str, stdformat);
1464 			gtk_label_set_text( GTK_LABEL(picwin_status), str.c_str() );
1465 			stdformat.show_trailingzeros = trailingzeros;
1466 
1467 			if( old_best_match_i != -1 )
1468 			{
1469 				if( picwin_rowbuffer_len < picbild2.pic.get_width() )
1470 				{
1471 					delete [] picwin_rowbuffer;
1472 					picwin_rowbuffer = 0;
1473 					picwin_rowbuffer_len = 0;
1474 
1475 					picwin_rowbuffer = new guchar [ picbild2.pic.get_width()*3 ];
1476 					picwin_rowbuffer_len = picbild2.pic.get_width();
1477 				}
1478 				if( picwin_colbuffer_len < picbild2.pic.get_height() )
1479 				{
1480 					delete [] picwin_colbuffer;
1481 					picwin_colbuffer = 0;
1482 					picwin_colbuffer_len = 0;
1483 
1484 					picwin_colbuffer = new guchar [ picbild2.pic.get_height()*3 ];
1485 					picwin_colbuffer_len = picbild2.pic.get_height();
1486 				}
1487 
1488 				picwin_set_col( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1489 				                picbild2.pic.get_height(), old_tx, picwin_colbuffer );
1490 				picwin_set_row( picbild.get_intern_buffer(), picbild2.pic.get_width(),
1491 				                picbild2.pic.get_height(), old_ty, picwin_rowbuffer );
1492 
1493 				picbild.force_expose_line( old_ty );
1494 				picbild.force_expose_col( old_tx );
1495 
1496 				old_best_match_i = -1;
1497 			}
1498 		}
1499 	}
1500 }
1501 
picwin_mousenop(const picture2gtk * src,int32 x,int32 y,int32 button)1502 void picwin_mousenop(const picture2gtk *src,int32 x,int32 y,int32 button) {  }
1503 
picturewin_save_as(void)1504 void picturewin_save_as(void)
1505 {
1506 	GtkWidget *file_chooser, *tmp, *tmp2, *hbox, *picwin_save_format;
1507 	GtkFileFilter *filter;
1508 
1509 	file_chooser = gtk_file_chooser_dialog_new( dialog_title_save_as,
1510 	                                            GTK_WINDOW(picturewin),
1511 	                                            GTK_FILE_CHOOSER_ACTION_SAVE,
1512 	                                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1513 	                                            GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1514 	                                            NULL );
1515 
1516 
1517 	filter = gtk_file_filter_new();
1518 	gtk_file_filter_add_pattern(filter, "*.pcx");
1519 	gtk_file_filter_add_pattern(filter, "*.ppm");
1520 	gtk_file_filter_set_name(filter, filter_picture_files);
1521 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
1522 
1523 	filter = gtk_file_filter_new();
1524 	gtk_file_filter_add_pattern(filter, "*.pcx");
1525 	gtk_file_filter_set_name(filter, filter_pcx_files);
1526 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
1527 
1528 	filter = gtk_file_filter_new();
1529 	gtk_file_filter_add_pattern(filter, "*.ppm");
1530 	gtk_file_filter_set_name(filter, filter_ppm_files);
1531 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
1532 
1533 	filter = gtk_file_filter_new();
1534 	gtk_file_filter_add_pattern(filter, "*");
1535 	gtk_file_filter_set_name(filter, filter_all_files);
1536 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
1537 
1538 	hbox = gtk_hbox_new(FALSE,0);
1539 	gtk_widget_show( hbox );
1540 
1541 	picwin_save_format = gtk_option_menu_new();
1542 	gtk_widget_show( picwin_save_format );
1543 
1544 	tmp = gtk_menu_new();
1545 	gtk_widget_show( tmp );
1546 
1547 	tmp2 = gtk_menu_item_new_with_label( _("PCX") );
1548 	gtk_widget_show( tmp2 );
1549 	gtk_menu_shell_append(GTK_MENU_SHELL(tmp),tmp2);
1550 
1551 	tmp2 = gtk_menu_item_new_with_label( _("PPM (binary)") );
1552 	gtk_widget_show( tmp2 );
1553 	gtk_menu_shell_append(GTK_MENU_SHELL(tmp),tmp2);
1554 
1555 	tmp2 = gtk_menu_item_new_with_label( _("PPM (text/ascii)") );
1556 	gtk_widget_show( tmp2 );
1557 	gtk_menu_shell_append(GTK_MENU_SHELL(tmp),tmp2);
1558 
1559 	gtk_option_menu_set_menu(GTK_OPTION_MENU(picwin_save_format), tmp);
1560 
1561 	gtk_box_pack_end(GTK_BOX(hbox), picwin_save_format, FALSE, FALSE, 0);
1562 
1563 
1564 	tmp = gtk_label_new( _("File type:") );
1565 	gtk_widget_show( tmp );
1566 	gtk_box_pack_end(GTK_BOX(hbox), tmp, FALSE, FALSE, 0);
1567 
1568 	gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_chooser), hbox);
1569 
1570 	if(gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT)
1571 	{
1572 		gint type;
1573 		char *filename;
1574 
1575 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser));
1576 
1577 		type = gtk_option_menu_get_history(GTK_OPTION_MENU(picwin_save_format));
1578 
1579 		try
1580 		{
1581 			switch(type)
1582 			{
1583 			case 0: // PCX
1584 				picbild2.pic.save_pcx(filename);
1585 				break;
1586 			case 1: // PPM (binary)
1587 				picbild2.pic.save_ppm(filename);
1588 				break;
1589 			case 2: // PPM (ascii)
1590 				picbild2.pic.save_ppm(filename,1);
1591 				break;
1592 			default:
1593 				THROW_ERROR( ErrorType_General, _("Unknown format") );
1594 			}
1595 		}
1596 		catch(error_obj error)
1597 		{
1598 			GtkWidget *dialog;
1599 
1600 			dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin),
1601 			                                 GTK_DIALOG_DESTROY_WITH_PARENT,
1602 			                                 GTK_MESSAGE_ERROR,
1603 			                                 GTK_BUTTONS_CLOSE,
1604 			                                 error.msg );
1605 			gtk_dialog_run( GTK_DIALOG(dialog) );
1606 			gtk_widget_destroy(dialog);
1607 		}
1608 		g_free(filename);
1609 	}
1610 	gtk_widget_destroy(file_chooser);
1611 }
1612 
find_all_snap_points(void)1613 void find_all_snap_points( void )
1614 {
1615 	SnapInfo tmp_snap;
1616 	Complex tmp0[10], tmp1[10], tmp2[10];
1617 	floatx f0, f1, f2;
1618 	bool active[10];
1619 
1620 	tmp_snap.calculated = false;
1621 
1622 	for( int32 x=2; x<act_settings.width; x++ )
1623 	{
1624 /*
1625 struct SnapInfo
1626 {
1627 	enum SnapType { Snap_Root, Snap_Minimum, Snap_Maximum, Snap_Intersection };
1628 	SnapType snap_type;
1629 	int32 x, intersect_with;
1630 	floatx fx, fy;
1631 	bool calculated;
1632 };
1633 */
1634 		for( int i=0; i<10; i++ )
1635 		{
1636 			if( act_settings.func[i].show_this == false )
1637 				continue;
1638 			tmp0[i] = trace_matrix.get_complex( x-1, i+2 );
1639 			tmp1[i] = trace_matrix.get_complex( x,   i+2 );
1640 			tmp2[i] = trace_matrix.get_complex( x+1, i+2 );
1641 		}
1642 
1643 		for( int i=0; i<10; i++ )
1644 		{
1645 			if( act_settings.func[i].show_this == false )
1646 				continue;
1647 			for( int a=i; a<10; a++ )
1648 			{
1649 				if( act_settings.func[a].show_this == false )
1650 				{
1651 					active[a] = false;
1652 					continue;
1653 				}
1654 				active[a] = bool( floatx(tmp0[a].imaginary) == 0.0  &&  floatx(tmp1[a].imaginary) == 0.0  &&
1655 				                  floatx(tmp2[a].imaginary) == 0.0 );
1656 			}
1657 			if( active[i] )
1658 			{
1659 				f0 = floatx(tmp0[i].real);
1660 				f1 = floatx(tmp1[i].real);
1661 				f2 = floatx(tmp2[i].real);
1662 				if( f1 * f2 < 0.0 ) // they have different signs, here might a root be found
1663 				{
1664 					tmp_snap.snap_type = SnapInfo::Snap_Root;
1665 					tmp_snap.x = x;
1666 					tmp_snap.fx = floatx( trace_matrix.get_complex( x, 1 ).real );
1667 					snap_info[i].append( tmp_snap );
1668 				}
1669 				if( f0 <= f1  &&  f2 < f1 )
1670 				{
1671 					tmp_snap.snap_type = SnapInfo::Snap_Maximum;
1672 					tmp_snap.x = x;
1673 					tmp_snap.fx = floatx( trace_matrix.get_complex( x, 1 ).real );
1674 					snap_info[i].append( tmp_snap );
1675 				}
1676 				if( f0 >= f1  &&  f2 > f1 )
1677 				{
1678 					tmp_snap.snap_type = SnapInfo::Snap_Minimum;
1679 					tmp_snap.x = x;
1680 					tmp_snap.fx = floatx( trace_matrix.get_complex( x, 1 ).real );
1681 					snap_info[i].append( tmp_snap );
1682 				}
1683 				for( int a=i; a<10; a++ )
1684 				{
1685 					if( active[a] == false )
1686 						continue;
1687 					if( (f1 < floatx(tmp1[a].real)) ^ (f2 < floatx(tmp2[a].real)) )
1688 					{
1689 						tmp_snap.snap_type = SnapInfo::Snap_Intersection;
1690 						tmp_snap.x = x;
1691 						tmp_snap.fx = floatx( trace_matrix.get_complex( x, 1 ).real );
1692 						tmp_snap.intersect_with = a;
1693 						snap_info[i].append( tmp_snap );
1694 						tmp_snap.intersect_with = i;
1695 						snap_info[a].append( tmp_snap );
1696 					}
1697 				}
1698 			}
1699 		}
1700 	}
1701 }
1702 
1703 
picturewin_show(const graph_settings * settings)1704 void picturewin_show( const graph_settings *settings )
1705 {
1706 	enum IM_HERE { IM_HERE_picture, IM_HERE_funcion, IM_HERE_polar, IM_HERE_par };
1707 	math::CodeLine function;
1708 	utf8_string str;
1709 	picture_h::colorrgb color;
1710 	const Matrix *matr;
1711 	IM_HERE Im_here = IM_HERE_picture;
1712 	int i;
1713 	char char_str[1000];
1714 
1715 	old_best_match_i = -1;
1716 
1717 	try
1718 	{
1719 		for( i=0; i<10; i++ )
1720 			snap_info[i].clear();
1721 
1722 		if(settings != 0)
1723 			act_settings = *settings;
1724 
1725 		snprintf( char_str, 1000, "plot_picture = picture( %ld, %ld, ", act_settings.width, act_settings.height );
1726 		str = char_str;
1727 		str.append( act_settings.xmin ).append( ", " );
1728 		str.append( act_settings.xmax ).append( ", " );
1729 		str.append( act_settings.ymin ).append( ", " );
1730 		str.append( act_settings.ymax );
1731 		snprintf( char_str, 1000, ", [[ %f, %f, %f ]] )\n", act_settings.bgcolor.red/255.0f,
1732 		          act_settings.bgcolor.green/255.0f, act_settings.bgcolor.blue/255.0f );
1733 		str.append( char_str );
1734 		if(act_settings.show_code)
1735 			(*TEXTVIEW_FUNCTION)( str.c_str() );
1736 		function.set_code_line( str.c_str() );
1737 		function.calc( 0 );  // resizing the picture
1738 
1739 		if( act_settings.grid_on )
1740 		{
1741 			snprintf( char_str, 1000, "plot_picture.grid( \"%s\", %s, %s, %s, [[ %f, %f, %f ]] )\n",
1742 			          act_settings.grid_type.c_str(), act_settings.grid_scale1.c_str(),
1743 			          act_settings.grid_scale2.c_str(), (act_settings.use_antialiasing) ? "true" : "false",
1744 			          act_settings.grid_color.red/255.0f, act_settings.grid_color.green/255.0f,
1745 			          act_settings.grid_color.blue/255.0f );
1746 			if(act_settings.show_code)
1747 				(*TEXTVIEW_FUNCTION)( char_str );
1748 			function.set_code_line( char_str );
1749 			function.calc( 0 );  // adding grid
1750 		}
1751 
1752 		if( act_settings.axes_on )
1753 		{
1754 			snprintf( char_str, 1000, "plot_picture.axes( %s, %s, %ld, [[ %f, %f, %f ]] )\n",
1755 			          act_settings.scalex.c_str(), act_settings.scaley.c_str(),
1756 			          act_settings.scale_length, act_settings.axes_color.red/255.0f,
1757 			          act_settings.axes_color.green/255.0f, act_settings.axes_color.blue/255.0f );
1758 			if(act_settings.show_code)
1759 				(*TEXTVIEW_FUNCTION)( char_str );
1760 			function.set_code_line( char_str );
1761 			function.calc( 0 );  // adding axes
1762 		}
1763 
1764 		if(act_settings.active_page == 0  ||  act_settings.show_active_page_only == false) // function-page
1765 		{
1766 			Im_here = IM_HERE_funcion;
1767 			for( i=0; i<10; i++ ) // setting up all functions
1768 			{
1769 				snprintf( char_str, 1000, "y%ld = \"", i );
1770 				str = char_str;
1771 				str.append( act_settings.func[i].entry ).append( "\"\n" );
1772 				if( act_settings.show_code )
1773 					(*TEXTVIEW_FUNCTION)( str.c_str() );
1774 				function.set_code_line( str.c_str() );
1775 				function.calc( 0 );
1776 			}
1777 			str = "plot_x_matrix = table( \"x\", x, dec( ";
1778 			str.append( act_settings.xmin ).append( " ), dec( " );
1779 			str.append( act_settings.xmax );
1780 			snprintf( char_str, 1000, " ), %ld )\n", act_settings.width );
1781 			str.append( char_str );
1782 			if( act_settings.show_code )
1783 				(*TEXTVIEW_FUNCTION)( str.c_str() );
1784 			function.set_code_line( str.c_str() );
1785 			function.calc( 0 ); // calculating the x list
1786 
1787 			trace_matrix.set_size( act_settings.width, 11 );
1788 			trace_matrix.fill( Complex( 0.0, 1.0 ) );
1789 
1790 			matr = math::global_varlist.get_pointer( math::global_varlist.get_id("plot_x_matrix") )->get_matrix();
1791 			for( int i2=0; i2<act_settings.width; i2++ )
1792 				trace_matrix.set_complex(i2+1,1, matr->get_complex(i2+1,1) );
1793 
1794 			for( i=0; i<10; i++ )
1795 			{
1796 				color = act_settings.func[i].color;
1797 				if( act_settings.func[i].show_this )
1798 				{
1799 					snprintf( char_str, 1000, "plot_y_matrix = table( y%ld, x, dec( ", i );
1800 					str = char_str;
1801 					str.append( act_settings.xmin ).append( " ), dec( " );
1802 					str.append( act_settings.xmax );
1803 					snprintf( char_str, 1000, " ), %ld, i )\n", act_settings.width );
1804 					str.append( char_str );
1805 					if( act_settings.show_code )
1806 						(*TEXTVIEW_FUNCTION)( str.c_str() );
1807 					function.set_code_line( str.c_str() );
1808 					function.calc( 0 );  // calculating the y list
1809 
1810 					matr = math::global_varlist.get_pointer(
1811 					                  math::global_varlist.get_id("plot_y_matrix") )->get_matrix();
1812 					for( int i2=0; i2<act_settings.width; i2++ )
1813 						trace_matrix.set_complex(i2+1,i+2, matr->get_complex(i2+1,1) );
1814 
1815 					str = "plot_picture.plot( plot_x_matrix, plot_y_matrix, \"";
1816 					str.append( act_settings.plot_mode );
1817 					snprintf( char_str, 1000, "\", \"Dot\", 0, false, %s, [[ %f, %f, %f ]] )\n",
1818 					          (act_settings.use_antialiasing) ? "true" : "false",
1819 					          color.red/255.0f, color.green/255.0f, color.blue/255.0f );
1820 					str.append( char_str );
1821 					if( act_settings.show_code )
1822 						(*TEXTVIEW_FUNCTION)( str.c_str() );
1823 					function.set_code_line( str.c_str() );
1824 					function.calc( 0 );  // drawing function
1825 				}
1826 			}
1827 			find_all_snap_points();
1828 		}
1829 		if( act_settings.active_page == 1  ||  act_settings.show_active_page_only == false ) // polar-page
1830 		{
1831 			Im_here = IM_HERE_polar;
1832 			bool connected = true;
1833 			if( act_settings.plot_mode == "Dots" )
1834 				connected = false;
1835 			for( i=0; i<10; i++ ) // setting up all functions
1836 			{
1837 				snprintf( char_str, 1000, "r%ld = \"", i );
1838 				str = char_str;
1839 				str.append( act_settings.polar[i].entry ).append( "\"\n" );
1840 				if( act_settings.show_code )
1841 					(*TEXTVIEW_FUNCTION)( str.c_str() );
1842 				function.set_code_line( str.c_str() );
1843 				function.calc( 0 );
1844 			}
1845 			for( i=0; i<10; i++ )
1846 			{
1847 				color = act_settings.polar[i].color;
1848 				if( act_settings.polar[i].show_this )
1849 				{
1850 					snprintf( char_str, 1000, "plot_x_matrix = table( \"r%ld(x)cos x\", x, ", i );
1851 					str = char_str;
1852 					str.append( act_settings.polar_start ).append( ", " );
1853 					str.append( act_settings.polar_stop ).append( ", " );
1854 					str.append( act_settings.polar_steps ).append( ", i )\n" );
1855 					if( act_settings.show_code )
1856 						(*TEXTVIEW_FUNCTION)( str.c_str() );
1857 					function.set_code_line( str.c_str() );
1858 					function.calc( 0 );  // calculating the x list
1859 
1860 					snprintf( char_str, 1000, "plot_y_matrix = table( \"r%ld(x)sin x\", x, ", i );
1861 					str = char_str;
1862 					str.append( act_settings.polar_start ).append( ", " );
1863 					str.append( act_settings.polar_stop ).append( ", " );
1864 					str.append( act_settings.polar_steps ).append( ", i )\n" );
1865 					if( act_settings.show_code )
1866 						(*TEXTVIEW_FUNCTION)( str.c_str() );
1867 					function.set_code_line( str.c_str() );
1868 					function.calc( 0 );  // calculating the x list
1869 
1870 					snprintf( char_str, 1000, "plot_picture.plot( plot_x_matrix, plot_y_matrix, \"%s\", "
1871 					                          "\"Dot\", 0, false, %s, [[ %f, %f, %f ]] )\n",
1872 					          connected ? "Connected" : "Dots",
1873 					          act_settings.use_antialiasing ? "true" : "false",
1874 					          color.red/255.0f, color.green/255.0f, color.blue/255.0f );
1875 					if( act_settings.show_code )
1876 						(*TEXTVIEW_FUNCTION)( char_str );
1877 					function.set_code_line( char_str );
1878 					function.calc( 0 );  // drawing function
1879 				}
1880 			}
1881 		}
1882 		if( act_settings.active_page == 2  ||  act_settings.show_active_page_only == false ) // parameter-page
1883 		{
1884 			Im_here = IM_HERE_par;
1885 			bool connected = (act_settings.plot_mode == "Dots") ? false : true;
1886 
1887 			for( i=0; i<5; i++ ) // setting up all functions
1888 			{
1889 				snprintf( char_str, 1000, "xf%ld = \"", i );
1890 				str = char_str;
1891 				str.append( act_settings.par[i].entry ).append( "\"\n" );
1892 				if( act_settings.show_code )
1893 					(*TEXTVIEW_FUNCTION)( str.c_str() );
1894 				function.set_code_line( str.c_str() );
1895 				function.calc( 0 );
1896 
1897 				snprintf( char_str, 1000, "yf%ld = \"", i );
1898 				str = char_str;
1899 				str.append( act_settings.par[i].entry2 ).append( "\"\n" );
1900 				if( act_settings.show_code )
1901 					(*TEXTVIEW_FUNCTION)( str.c_str() );
1902 				function.set_code_line( str.c_str() );
1903 				function.calc( 0 );
1904 			}
1905 			for( i=0; i<5; i++ )
1906 			{
1907 				color = act_settings.par[i].color;
1908 				if( act_settings.par[i].show_this )
1909 				{
1910 					snprintf( char_str, 1000, "plot_x_matrix = table( xf%ld, x, ", i );
1911 					str = char_str;
1912 					str.append( act_settings.par_start ).append( ", " );
1913 					str.append( act_settings.par_stop ).append( ", " );
1914 					str.append( act_settings.par_steps ).append( ", i )\n" );
1915 					if( act_settings.show_code )
1916 						(*TEXTVIEW_FUNCTION)( str.c_str() );
1917 					function.set_code_line( str.c_str() );
1918 					function.calc( 0 );  // calculating the x list
1919 
1920 					snprintf( char_str, 1000, "plot_y_matrix = table( yf%ld, x, ", i );
1921 					str = char_str;
1922 					str.append( act_settings.par_start ).append( ", " );
1923 					str.append( act_settings.par_stop ).append( ", " );
1924 					str.append( act_settings.par_steps ).append( ", i )\n" );
1925 					if( act_settings.show_code )
1926 						(*TEXTVIEW_FUNCTION)( str.c_str() );
1927 					function.set_code_line( str.c_str() );
1928 					function.calc( 0 );  // calculating the y list
1929 
1930 					snprintf( char_str, 1000, "plot_picture.plot( plot_x_matrix, plot_y_matrix, \"%s\""
1931 					                          ", \"Dot\", 0, false, %s, [[ %f, %f, %f ]] )\n",
1932 					          connected ? "Connected" : "Dots",
1933 					          act_settings.use_antialiasing ? "true" : "false",
1934 					          color.red/255.0f, color.green/255.0f, color.blue/255.0f );
1935 					if( act_settings.show_code )
1936 						(*TEXTVIEW_FUNCTION)( char_str );
1937 					function.set_code_line( char_str );
1938 					function.calc( 0 );  // drawing parameter function
1939 				}
1940 			}
1941 		}
1942 		if( act_settings.show_code )
1943 			(*TEXTVIEW_FUNCTION)("show plot_picture\n\n");
1944 		function.set_code_line("show plot_picture");
1945 		function.calc( 0 );
1946 
1947 		gtk_widget_set_sensitive( picwin_combo_trace, TRUE );
1948 		gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace), 1 ); // auto-trace
1949 		gtk_widget_set_sensitive( picwin_combo_action, TRUE );
1950 		gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_action), 0 ); // zoom
1951 		old_best_match_i = -1;
1952 
1953 		picbild.mousedown_func = picwin_mousedown;
1954 	}
1955 	catch(error_obj error)
1956 	{
1957 		GtkWidget *dialog;
1958 		utf8_string str;
1959 		char tkn[2];
1960 		tkn[1] = '\0';
1961 
1962 		switch( Im_here )
1963 		{
1964 		case IM_HERE_picture:
1965 			str = "When creating plot-picture: ";
1966 			break;
1967 		case IM_HERE_funcion:
1968 			str = "When plotting y";
1969 			tkn[0] = char(i)+'0';
1970 			str.append( tkn );
1971 			str.append( ": " );
1972 			break;
1973 		case IM_HERE_polar:
1974 			str = "When plotting r";
1975 			tkn[0] = char(i)+'0';
1976 			str.append( tkn );
1977 			str.append( ": " );
1978 			break;
1979 		case IM_HERE_par:
1980 			str = "When plotting xf";
1981 			tkn[0] = char(i)+'0';
1982 			str.append( tkn );
1983 			str.append( " yf" );
1984 			str.append( tkn );
1985 			str.append( ": " );
1986 			break;
1987 		}
1988 
1989 		str.append( error.msg );
1990 		dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin),
1991 		                                 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1992 		                                 GTK_BUTTONS_CLOSE, str.c_str() );
1993 		gtk_dialog_run(GTK_DIALOG(dialog));
1994 		gtk_widget_destroy(dialog);
1995 	}
1996 	catch(...)
1997 	{
1998 		try{ THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
1999 		catch(error_obj error)
2000 		{
2001 			GtkWidget *dialog;
2002 
2003 			dialog = gtk_message_dialog_new( GTK_WINDOW(picturewin),
2004 			                                 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
2005 			                                 GTK_BUTTONS_CLOSE, error.msg );
2006 			gtk_dialog_run( GTK_DIALOG(dialog) );
2007 			gtk_widget_destroy(dialog);
2008 		}
2009 	}
2010 }
2011 
picwin_combo_action_changed(GtkComboBox * widget,gpointer user_data)2012 void picwin_combo_action_changed( GtkComboBox *widget, gpointer user_data )
2013 {
2014 	gettimeofday( &action_combo_changed, 0 );
2015 
2016 	switch( gtk_combo_box_get_active( widget ) )
2017 	{
2018 	case LeftClickAction_Zoom:
2019 		gtk_label_set_text( GTK_LABEL(picwin_status), PRG_NAME );
2020 		break;
2021 
2022 	case LeftClickAction_FindRoot:
2023 	case LeftClickAction_FindMaximumMinimum:
2024 	case LeftClickAction_FindIntersection:
2025 		gtk_label_set_text( GTK_LABEL(picwin_status), _("Make a guess") );
2026 		break;
2027 
2028 	case LeftClickAction_CalcDerivate:
2029 		gtk_label_set_text( GTK_LABEL(picwin_status), _("Select point") );
2030 		break;
2031 	case LeftClickAction_CalcIntegral:
2032 	case LeftClickAction_CalcLength:
2033 		gtk_label_set_text( GTK_LABEL(picwin_status), _("Select start point") );
2034 		break;
2035 	}
2036 	picwin_first_click_done = false;
2037 }
2038 
picturewin_build_menu(void)2039 GtkWidget* picturewin_build_menu(void)
2040 {
2041 	GtkActionGroup *actions;
2042 	GtkUIManager *ui_manager;
2043 	GError *error = NULL;
2044 
2045 	static const gchar *menu =
2046 "<ui>"
2047 "  <menubar name='MenuBar'>"
2048 "    <menu action='FileMenu'>"
2049 "      <menuitem action='SaveAs'/>"
2050 "      <separator/>"
2051 "      <menuitem action='Close'/>"
2052 "      <separator/>"
2053 "      <menuitem action='Quit'/>"
2054 "    </menu>"
2055 "  </menubar>"
2056 "</ui>";
2057 	GtkActionEntry entries[] = {
2058 { "FileMenu", NULL,              menu_file },
2059 { "SaveAs",   GTK_STOCK_SAVE_AS, menu_file_save_as, "<shift><ctrl>S", NULL, G_CALLBACK(picturewin_save_as) },
2060 { "Close",    GTK_STOCK_CLOSE,   menu_file_close,   "<ctrl>W",        NULL, G_CALLBACK(picturewin_close) },
2061 { "Quit",     GTK_STOCK_QUIT,    menu_file_quit,    "<ctrl>Q",        NULL, G_CALLBACK(UMP_gtk_quit) }
2062 };
2063 	guint n_entries = G_N_ELEMENTS(entries);
2064 
2065 	actions = gtk_action_group_new("Actions");
2066 	gtk_action_group_add_actions(actions, entries, n_entries, NULL);
2067 	ui_manager = gtk_ui_manager_new();
2068 	gtk_ui_manager_insert_action_group(ui_manager, actions, 0);
2069 	gtk_window_add_accel_group( GTK_WINDOW(picturewin), gtk_ui_manager_get_accel_group(ui_manager) );
2070 	if (!gtk_ui_manager_add_ui_from_string(ui_manager, menu, -1, &error))
2071 	{
2072 		g_message("building menus failed: %s", error->message);
2073 		g_error_free(error);
2074 		return 0;
2075 	}
2076 	gtk_ui_manager_ensure_update(ui_manager);
2077 
2078 
2079 	return gtk_ui_manager_get_widget(ui_manager, "/MenuBar");
2080 }
2081 
picturewin_show(const char * title,const math::Picture & src)2082 void picturewin_show( const char *title, const math::Picture &src )
2083 {
2084 	static int combobox_trace_last_nrofentries;
2085 	GtkWidget *drawarea,*scrolled;
2086 
2087 	old_best_match_i = -1;
2088 
2089 	if(picturewin == 0)
2090 	{
2091 		picturewin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2092 		gtk_window_set_title(GTK_WINDOW(picturewin), title);
2093 		g_signal_connect_swapped( GTK_OBJECT(picturewin), "delete-event",
2094 		                          G_CALLBACK(picturewin_close), NULL);
2095 
2096 		picturewin_vbox = gtk_vbox_new(FALSE,0);
2097 
2098 		if((picturewin_menu = picturewin_build_menu()) == 0)
2099 		{
2100 			gtk_widget_destroy( picturewin );
2101 			picturewin = 0;
2102 			return;
2103 		}
2104 		gtk_box_pack_start(GTK_BOX(picturewin_vbox), picturewin_menu, FALSE, FALSE, 0);
2105 
2106 		{
2107 			GtkWidget *tbox;
2108 			utf8_string str;
2109 
2110 			tbox = gtk_hbox_new(FALSE,2);
2111 
2112 			picwin_label_trace = gtk_label_new( _("Trace action") );
2113 			gtk_box_pack_start(GTK_BOX(tbox), picwin_label_trace, FALSE, FALSE, 2 );
2114 
2115 			picwin_combo_trace = gtk_combo_box_new_text();
2116 			gtk_box_pack_start(GTK_BOX(tbox), picwin_combo_trace, FALSE, FALSE, 2 );
2117 			gtk_label_set_mnemonic_widget( GTK_LABEL(picwin_label_trace), picwin_combo_trace );
2118 
2119 			gtk_widget_set_sensitive(picwin_combo_trace, FALSE);
2120 
2121 
2122 			picwin_combo_action = gtk_combo_box_new_text();
2123 			gtk_box_pack_end(GTK_BOX(tbox), picwin_combo_action, FALSE, FALSE, 2 );
2124 
2125 			combobox_trace_last_nrofentries = picwin_reload_combos( 0 );
2126 
2127 			gtk_widget_set_sensitive(picwin_combo_action, FALSE);
2128 			gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_action), -1 );
2129 			g_signal_connect( GTK_OBJECT(picwin_combo_action), "changed",
2130 			                  G_CALLBACK(picwin_combo_action_changed), gpointer(NULL) );
2131 
2132 			gtk_box_pack_start(GTK_BOX(picturewin_vbox), tbox, FALSE, FALSE, 2 );
2133 		}
2134 
2135 		drawarea = gtk_drawing_area_new();
2136 		picbild.connect_to_drawing_area( drawarea );
2137 
2138 		scrolled = gtk_scrolled_window_new( NULL, NULL );
2139 		gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC,
2140 		                                GTK_POLICY_AUTOMATIC );
2141 
2142 		gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled), drawarea );
2143 
2144 		gtk_box_pack_start( GTK_BOX(picturewin_vbox), scrolled, TRUE, TRUE, 0 );
2145 
2146 		{
2147 			GtkWidget *tbox, *tbar;
2148 			tbox = gtk_hbox_new( FALSE, 0 );
2149 
2150 			picwin_status = gtk_label_new( PRG_NAME );
2151 			gtk_misc_set_alignment( GTK_MISC(picwin_status), 0.0f, 0.5f );
2152 			gtk_box_pack_start( GTK_BOX(tbox), picwin_status, FALSE, FALSE, 0 );
2153 
2154 			tbar = gtk_statusbar_new();
2155 			gtk_box_pack_start( GTK_BOX(tbox), tbar, TRUE, TRUE, 0 );
2156 
2157 			gtk_box_pack_start( GTK_BOX(picturewin_vbox), tbox, FALSE, FALSE, 0 );
2158 		}
2159 
2160 		gtk_container_add( GTK_CONTAINER(picturewin), picturewin_vbox );
2161 
2162 		gtk_window_resize( GTK_WINDOW(picturewin), src.pic.get_width() + 10,
2163 		                   src.pic.get_height() + 90 );
2164 
2165 		gtk_widget_show_all(picturewin);
2166 	}
2167 	else
2168 	{
2169 		gtk_window_set_title( GTK_WINDOW(picturewin), title );
2170 		gtk_window_resize( GTK_WINDOW(picturewin), src.pic.get_width() + 10,
2171 		                   src.pic.get_height() + 90 );
2172 
2173 		gtk_window_present( GTK_WINDOW(picturewin) );
2174 
2175 		gtk_widget_set_sensitive(picwin_combo_trace, FALSE);
2176 		gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_trace), 0 ); // trace off
2177 
2178 		gtk_widget_set_sensitive(picwin_combo_action, FALSE);
2179 		gtk_combo_box_set_active( GTK_COMBO_BOX(picwin_combo_action), -1 ); // no action
2180 
2181 		combobox_trace_last_nrofentries = picwin_reload_combos( combobox_trace_last_nrofentries );
2182 	}
2183 
2184 	picbild2 = src;
2185 	picbild.update_from( src.pic );
2186 
2187 	picbild.mousemove_func = picwin_mousemove;
2188 	picbild.mousedown_func = picwin_mousenop;
2189 	picbild.mouseup_func = picwin_mousenop;
2190 }
2191 
2192 
picturewin_translate(void)2193 void picturewin_translate(void)
2194 {
2195 	if(picturewin != 0)
2196 	{
2197 		GtkWidget *new_menu;
2198 
2199 		gtk_label_set( GTK_LABEL(picwin_label_trace), _("Trace action") );
2200 
2201 
2202 		if(( new_menu = picturewin_build_menu()) == 0 )
2203 			return;
2204 
2205 		gtk_widget_destroy( picturewin_menu );
2206 		picturewin_menu = new_menu;
2207 
2208 		gtk_box_pack_start( GTK_BOX(picturewin_vbox), picturewin_menu, FALSE, FALSE, 0 );
2209 		gtk_box_reorder_child( GTK_BOX(picturewin_vbox), picturewin_menu, 0 );
2210 
2211 		picwin_reload_combos( 12 );
2212 	}
2213 }
2214 
picturewin_close(void)2215 void picturewin_close(void)
2216 {
2217 	if(picturewin != 0)
2218 	{
2219 		gtk_widget_destroy(picturewin);
2220 		picturewin = 0;
2221 	}
2222 }
2223