1 /*
2  * Copyright (c) Tony Bybell 1999-2016.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  */
9 
10 #include <config.h>
11 #include "globals.h"
12 #include "pixmaps.h"
13 #include "currenttime.h"
14 #include "debug.h"
15 
16 
fix_wavehadj(void)17 void fix_wavehadj(void)
18 {
19 GtkAdjustment *hadj;
20 gfloat pageinc;
21 
22 hadj=GTK_ADJUSTMENT(GLOBALS->wave_hslider);
23 hadj->lower=GLOBALS->tims.first;
24 hadj->upper=GLOBALS->tims.last+2.0;
25 
26 pageinc=(gfloat)(((gdouble)GLOBALS->wavewidth)*GLOBALS->nspx);
27 hadj->page_size=hadj->page_increment=(pageinc>=1.0)?pageinc:1.0;
28 
29 /* hadj->step_increment=(GLOBALS->nspx>=1.0)?GLOBALS->nspx:1.0; */
30 
31 hadj->step_increment = pageinc / 10.0;
32 if(hadj->step_increment < 1.0) hadj->step_increment = 1.0;
33 
34 if(hadj->page_size >= (hadj->upper-hadj->lower)) hadj->value=hadj->lower;
35 if(hadj->value+hadj->page_size>hadj->upper)
36 	{
37 	hadj->value=hadj->upper-hadj->page_size;
38 	if(hadj->value<hadj->lower)
39 		hadj->value=hadj->lower;
40 	}
41 }
42 
service_zoom_left(GtkWidget * text,gpointer data)43 void service_zoom_left(GtkWidget *text, gpointer data)
44 {
45 (void)text;
46 (void)data;
47 
48 GtkAdjustment *hadj;
49 
50 if(GLOBALS->helpbox_is_active)
51         {
52         help_text_bold("\n\nZoom To Start");
53         help_text(
54 		" is used to jump scroll to the trace's beginning."
55         );
56         return;
57         }
58 
59 hadj=GTK_ADJUSTMENT(GLOBALS->wave_hslider);
60 hadj->value=GLOBALS->tims.timecache=GLOBALS->tims.first;
61 time_update();
62 }
63 
service_zoom_right(GtkWidget * text,gpointer data)64 void service_zoom_right(GtkWidget *text, gpointer data)
65 {
66 (void)text;
67 (void)data;
68 
69 GtkAdjustment *hadj;
70 TimeType ntinc;
71 
72 if(GLOBALS->helpbox_is_active)
73         {
74         help_text_bold("\n\nZoom To End");
75         help_text(
76 		" is used to jump scroll to the trace's end."
77         );
78         return;
79         }
80 
81 ntinc=(TimeType)(((gdouble)GLOBALS->wavewidth)*GLOBALS->nspx);
82 
83 GLOBALS->tims.timecache=GLOBALS->tims.last-ntinc+1;
84         if(GLOBALS->tims.timecache<GLOBALS->tims.first) GLOBALS->tims.timecache=GLOBALS->tims.first;
85 
86 hadj=GTK_ADJUSTMENT(GLOBALS->wave_hslider);
87 hadj->value=GLOBALS->tims.timecache;
88 time_update();
89 }
90 
service_zoom_out(GtkWidget * text,gpointer data)91 void service_zoom_out(GtkWidget *text, gpointer data)
92 {
93 (void)text;
94 (void)data;
95 
96 TimeType middle=0, width;
97 
98 if(GLOBALS->helpbox_is_active)
99         {
100         help_text_bold("\n\nZoom Out");
101         help_text(
102 		" is used to decrease the zoom factor around the marker."
103 #ifdef WAVE_USE_GTK2
104 		" Alt + Scrollwheel Up also hits this button in non-alternative wheel mode."
105 #endif
106         );
107         return;
108         }
109 
110 if(GLOBALS->do_zoom_center)
111 	{
112 	if((GLOBALS->tims.marker<0)||(GLOBALS->tims.marker<GLOBALS->tims.first)||(GLOBALS->tims.marker>GLOBALS->tims.last))
113 		{
114 		if(GLOBALS->tims.end>GLOBALS->tims.last) GLOBALS->tims.end=GLOBALS->tims.last;
115 		middle=(GLOBALS->tims.start/2)+(GLOBALS->tims.end/2);
116 		if((GLOBALS->tims.start&1)&&(GLOBALS->tims.end&1)) middle++;
117 		}
118 		else
119 		{
120 		middle=GLOBALS->tims.marker;
121 		}
122 	}
123 
124 GLOBALS->tims.prevzoom=GLOBALS->tims.zoom;
125 
126 GLOBALS->tims.zoom--;
127 calczoom(GLOBALS->tims.zoom);
128 
129 if(GLOBALS->do_zoom_center)
130 	{
131 	width=(TimeType)(((gdouble)GLOBALS->wavewidth)*GLOBALS->nspx);
132 	GLOBALS->tims.start=time_trunc(middle-(width/2));
133         if(GLOBALS->tims.start+width>GLOBALS->tims.last) GLOBALS->tims.start=time_trunc(GLOBALS->tims.last-width);
134 	if(GLOBALS->tims.start<GLOBALS->tims.first) GLOBALS->tims.start=GLOBALS->tims.first;
135 	GTK_ADJUSTMENT(GLOBALS->wave_hslider)->value=GLOBALS->tims.timecache=GLOBALS->tims.start;
136 	}
137 	else
138 	{
139 	GLOBALS->tims.timecache=0;
140 	}
141 
142 fix_wavehadj();
143 
144 gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "changed"); /* force zoom update */
145 gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "value_changed"); /* force zoom update */
146 
147 DEBUG(printf("Zoombuttons out\n"));
148 }
149 
service_zoom_in(GtkWidget * text,gpointer data)150 void service_zoom_in(GtkWidget *text, gpointer data)
151 {
152 (void)text;
153 (void)data;
154 
155 if(GLOBALS->helpbox_is_active)
156         {
157         help_text_bold("\n\nZoom In");
158         help_text(
159                 " is used to increase the zoom factor around the marker."
160 #ifdef WAVE_USE_GTK2
161 		" Alt + Scrollwheel Down also hits this button in non-alternative wheel mode."
162 #endif
163         );
164         return;
165         }
166 
167 if(GLOBALS->tims.zoom<0)		/* otherwise it's ridiculous and can cause */
168 	{		/* overflow problems in the scope          */
169 	TimeType middle=0, width;
170 
171 	if(GLOBALS->do_zoom_center)
172 		{
173 		if((GLOBALS->tims.marker<0)||(GLOBALS->tims.marker<GLOBALS->tims.first)||(GLOBALS->tims.marker>GLOBALS->tims.last))
174 			{
175 			if(GLOBALS->tims.end>GLOBALS->tims.last) GLOBALS->tims.end=GLOBALS->tims.last;
176 			middle=(GLOBALS->tims.start/2)+(GLOBALS->tims.end/2);
177 			if((GLOBALS->tims.start&1)&&(GLOBALS->tims.end&1)) middle++;
178 			}
179 			else
180 			{
181 			middle=GLOBALS->tims.marker;
182 			}
183 		}
184 
185 	GLOBALS->tims.prevzoom=GLOBALS->tims.zoom;
186 
187 	GLOBALS->tims.zoom++;
188 	calczoom(GLOBALS->tims.zoom);
189 
190 	if(GLOBALS->do_zoom_center)
191 		{
192 		width=(TimeType)(((gdouble)GLOBALS->wavewidth)*GLOBALS->nspx);
193 		GLOBALS->tims.start=time_trunc(middle-(width/2));
194 	        if(GLOBALS->tims.start+width>GLOBALS->tims.last) GLOBALS->tims.start=time_trunc(GLOBALS->tims.last-width);
195 		if(GLOBALS->tims.start<GLOBALS->tims.first) GLOBALS->tims.start=GLOBALS->tims.first;
196 		GTK_ADJUSTMENT(GLOBALS->wave_hslider)->value=GLOBALS->tims.timecache=GLOBALS->tims.start;
197 		}
198 		else
199 		{
200 		GLOBALS->tims.timecache=0;
201 		}
202 
203 	fix_wavehadj();
204 
205 	gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "changed"); /* force zoom update */
206 	gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "value_changed"); /* force zoom update */
207 
208 	DEBUG(printf("Zoombuttons in\n"));
209 	}
210 }
211 
service_zoom_undo(GtkWidget * text,gpointer data)212 void service_zoom_undo(GtkWidget *text, gpointer data)
213 {
214 (void)text;
215 (void)data;
216 
217 gdouble temp;
218 
219 if(GLOBALS->helpbox_is_active)
220         {
221         help_text_bold("\n\nZoom Undo");
222         help_text(
223                 " is used to revert to the previous zoom value used.  Undo"
224 		" only works one level deep."
225         );
226         return;
227         }
228 
229 
230 temp=GLOBALS->tims.zoom;
231 GLOBALS->tims.zoom=GLOBALS->tims.prevzoom;
232 GLOBALS->tims.prevzoom=temp;
233 GLOBALS->tims.timecache=0;
234 calczoom(GLOBALS->tims.zoom);
235 fix_wavehadj();
236 
237 gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "changed"); /* force zoom update */
238 gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "value_changed"); /* force zoom update */
239 
240 DEBUG(printf("Zoombuttons Undo\n"));
241 }
242 
service_zoom_fit(GtkWidget * text,gpointer data)243 void service_zoom_fit(GtkWidget *text, gpointer data)
244 {
245 (void)text;
246 (void)data;
247 
248 gdouble estimated;
249 int fixedwidth;
250 
251 if(GLOBALS->helpbox_is_active)
252         {
253         help_text_bold("\n\nZoom Best Fit");
254         help_text(
255 		" attempts a \"best fit\" to get the whole trace onscreen."
256 		"  Note that the trace may be more or less than a whole screen since"
257 		" this isn't a \"perfect fit.\" Also, if the middle button baseline"
258 		" marker is nailed down, the zoom instead of getting the whole trace"
259 		" onscreen will use the part of the trace between the primary"
260 		" marker and the baseline marker."
261         );
262         return;
263         }
264 
265 if((GLOBALS->tims.baseline>=0)&&(GLOBALS->tims.marker>=0))
266 	{
267 	service_dragzoom(GLOBALS->tims.baseline, GLOBALS->tims.marker); /* new semantics added to zoom between the two */
268 	}
269 	else
270 	{
271 	if(GLOBALS->wavewidth>4) { fixedwidth=GLOBALS->wavewidth-4; } else { fixedwidth=GLOBALS->wavewidth; }
272 	estimated=-log(((gdouble)(GLOBALS->tims.last-GLOBALS->tims.first+1))/((gdouble)fixedwidth)*((gdouble)200.0))/log(GLOBALS->zoombase);
273 	if(estimated>((gdouble)(0.0))) estimated=((gdouble)(0.0));
274 
275 	GLOBALS->tims.prevzoom=GLOBALS->tims.zoom;
276 	GLOBALS->tims.timecache=0;
277 
278 	calczoom(estimated);
279 	GLOBALS->tims.zoom=estimated;
280 
281 	fix_wavehadj();
282 
283 	gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "changed"); /* force zoom update */
284 	gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "value_changed"); /* force zoom update */
285 	}
286 
287 DEBUG(printf("Zoombuttons Fit\n"));
288 }
289 
service_zoom_full(GtkWidget * text,gpointer data)290 void service_zoom_full(GtkWidget *text, gpointer data)
291 {
292 (void)text;
293 (void)data;
294 
295 gdouble estimated;
296 int fixedwidth;
297 
298 if(GLOBALS->helpbox_is_active)
299         {
300         help_text_bold("\n\nZoom Full");
301         help_text(
302 		" attempts a \"best fit\" to get the whole trace onscreen."
303 		"  Note that the trace may be more or less than a whole screen since"
304 		" this isn't a \"perfect fit.\""
305         );
306         return;
307         }
308 
309 if(GLOBALS->wavewidth>4) { fixedwidth=GLOBALS->wavewidth-4; } else { fixedwidth=GLOBALS->wavewidth; }
310 estimated=-log(((gdouble)(GLOBALS->tims.last-GLOBALS->tims.first+1))/((gdouble)fixedwidth)*((gdouble)200.0))/log(GLOBALS->zoombase);
311 if(estimated>((gdouble)(0.0))) estimated=((gdouble)(0.0));
312 
313 GLOBALS->tims.prevzoom=GLOBALS->tims.zoom;
314 GLOBALS->tims.timecache=0;
315 
316 calczoom(estimated);
317 GLOBALS->tims.zoom=estimated;
318 
319 fix_wavehadj();
320 
321 gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "changed"); /* force zoom update */
322 gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "value_changed"); /* force zoom update */
323 
324 DEBUG(printf("Zoombuttons Full\n"));
325 }
326 
327 
service_dragzoom(TimeType time1,TimeType time2)328 void service_dragzoom(TimeType time1, TimeType time2)	/* the function you've been waiting for... */
329 {
330 gdouble estimated;
331 int fixedwidth;
332 TimeType temp;
333 GtkAdjustment *hadj;
334 Trptr t;
335 int dragzoom_ok = 1;
336 
337 if(time2<time1)
338 	{
339 	temp=time1;
340 	time1=time2;
341 	time2=temp;
342 	}
343 
344 if(GLOBALS->dragzoom_threshold)
345 	{
346 	TimeType tdelta = time2 - time1;
347 	gdouble x = tdelta * GLOBALS->pxns;
348 	if(x<GLOBALS->dragzoom_threshold)
349 		{
350 		dragzoom_ok = 0;
351 		}
352 	}
353 
354 if((time2>time1)&&(dragzoom_ok))	/* ensure at least 1 tick and dragzoom_threshold if set */
355 	{
356 	if(GLOBALS->wavewidth>4) { fixedwidth=GLOBALS->wavewidth-4; } else { fixedwidth=GLOBALS->wavewidth; }
357 	estimated=-log(((gdouble)(time2-time1+1))/((gdouble)fixedwidth)*((gdouble)200.0))/log(GLOBALS->zoombase);
358 	if(estimated>((gdouble)(0.0))) estimated=((gdouble)(0.0));
359 
360 	GLOBALS->tims.prevzoom=GLOBALS->tims.zoom;
361 	GLOBALS->tims.timecache=GLOBALS->tims.laststart=GLOBALS->tims.start=time_trunc(time1);
362 
363         for(t=GLOBALS->traces.first;t;t=t->t_next) /* have to nuke string refs so printout is ok! */
364                 {
365                 if(t->asciivalue) { free_2(t->asciivalue); t->asciivalue=NULL; }
366                 }
367 
368         for(t=GLOBALS->traces.buffer;t;t=t->t_next)
369                 {
370                 if(t->asciivalue) { free_2(t->asciivalue); t->asciivalue=NULL; }
371                 }
372 
373 	if(!((GLOBALS->tims.baseline>=0)&&(GLOBALS->tims.marker>=0)))
374 		{
375 	        update_markertime(GLOBALS->tims.marker=-1);
376 		}
377         GLOBALS->signalwindow_width_dirty=1;
378         MaxSignalLength();
379 
380 
381         hadj=GTK_ADJUSTMENT(GLOBALS->wave_hslider);
382         hadj->value=time1;
383 
384 	calczoom(estimated);
385 	GLOBALS->tims.zoom=estimated;
386 
387 	fix_wavehadj();
388 
389 	gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "changed"); /* force zoom update */
390 	gtk_signal_emit_by_name (GTK_OBJECT (GTK_ADJUSTMENT(GLOBALS->wave_hslider)), "value_changed"); /* force zoom update */
391 
392 	DEBUG(printf("Drag Zoom\n"));
393 	}
394 }
395 
396 /* Create actual buttons */
397 GtkWidget *
create_zoom_buttons(void)398 create_zoom_buttons (void)
399 {
400 GtkWidget *table;
401 GtkWidget *table2;
402 GtkWidget *frame;
403 GtkWidget *main_vbox;
404 GtkWidget *b1;
405 GtkWidget *b2;
406 GtkWidget *b3;
407 GtkWidget *b4;
408 GtkWidget *b5;
409 GtkWidget *b6;
410 GtkWidget *pixmapzout, *pixmapzin, *pixmapzfit, *pixmapzundo;
411 GtkWidget *pixmapzleft, *pixmapzright;
412 
413 GtkTooltips *tooltips;
414 
415 tooltips=gtk_tooltips_new_2();
416 gtk_tooltips_set_delay_2(tooltips,1500);
417 
418 pixmapzin=gtk_pixmap_new(GLOBALS->zoomin_pixmap, GLOBALS->zoomin_mask);
419 gtk_widget_show(pixmapzin);
420 pixmapzout=gtk_pixmap_new(GLOBALS->zoomout_pixmap, GLOBALS->zoomout_mask);
421 gtk_widget_show(pixmapzout);
422 pixmapzfit=gtk_pixmap_new(GLOBALS->zoomfit_pixmap, GLOBALS->zoomfit_mask);
423 gtk_widget_show(pixmapzfit);
424 pixmapzundo=gtk_pixmap_new(GLOBALS->zoomundo_pixmap, GLOBALS->zoomundo_mask);
425 gtk_widget_show(pixmapzundo);
426 
427 pixmapzleft=gtk_pixmap_new(GLOBALS->zoom_larrow_pixmap, GLOBALS->zoom_larrow_mask);
428 gtk_widget_show(pixmapzleft);
429 pixmapzright=gtk_pixmap_new(GLOBALS->zoom_rarrow_pixmap, GLOBALS->zoom_rarrow_mask);
430 gtk_widget_show(pixmapzright);
431 
432 
433 /* Create a table to hold the text widget and scrollbars */
434 table = gtk_table_new (1, 1, FALSE);
435 
436 main_vbox = gtk_vbox_new (FALSE, 1);
437 gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
438 gtk_container_add (GTK_CONTAINER (table), main_vbox);
439 
440 frame = gtk_frame_new ("Zoom ");
441 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
442 gtk_widget_show (frame);
443 gtk_widget_show (main_vbox);
444 
445 table2 = gtk_table_new (2, 3, FALSE);
446 
447 b1 = gtk_button_new();
448 gtk_container_add(GTK_CONTAINER(b1), pixmapzin);
449 gtk_table_attach (GTK_TABLE (table2), b1, 0, 1, 0, 1,
450 		      	GTK_FILL | GTK_EXPAND,
451 		      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
452 gtk_signal_connect_object (GTK_OBJECT (b1), "clicked", GTK_SIGNAL_FUNC(service_zoom_out), GTK_OBJECT (table2));
453 gtk_tooltips_set_tip_2(tooltips, b1, "Zoom Out", NULL);
454 gtk_widget_show(b1);
455 
456 b2 = gtk_button_new();
457 gtk_container_add(GTK_CONTAINER(b2), pixmapzout);
458 gtk_table_attach (GTK_TABLE (table2), b2, 0, 1, 1, 2,
459 		      	GTK_FILL | GTK_EXPAND,
460 		      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
461 gtk_signal_connect_object (GTK_OBJECT (b2), "clicked", GTK_SIGNAL_FUNC(service_zoom_in), GTK_OBJECT (table2));
462 gtk_tooltips_set_tip_2(tooltips, b2, "Zoom In", NULL);
463 gtk_widget_show(b2);
464 
465 b3 = gtk_button_new();
466 gtk_container_add(GTK_CONTAINER(b3), pixmapzfit);
467 gtk_table_attach (GTK_TABLE (table2), b3, 1, 2, 0, 1,
468 		      	GTK_FILL | GTK_EXPAND,
469 		      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
470 gtk_signal_connect_object (GTK_OBJECT (b3), "clicked", GTK_SIGNAL_FUNC(service_zoom_fit), GTK_OBJECT (table2));
471 gtk_tooltips_set_tip_2(tooltips, b3, "Zoom Best Fit", NULL);
472 gtk_widget_show(b3);
473 
474 b4 = gtk_button_new();
475 gtk_container_add(GTK_CONTAINER(b4), pixmapzundo);
476 gtk_table_attach (GTK_TABLE (table2), b4, 1, 2, 1, 2,
477 		      	GTK_FILL | GTK_EXPAND,
478 		      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
479 gtk_signal_connect_object (GTK_OBJECT (b4), "clicked", GTK_SIGNAL_FUNC(service_zoom_undo), GTK_OBJECT (table2));
480 gtk_tooltips_set_tip_2(tooltips, b4, "Undo Last Zoom", NULL);
481 gtk_widget_show(b4);
482 
483 b5 = gtk_button_new();
484 gtk_container_add(GTK_CONTAINER(b5), pixmapzleft);
485 gtk_table_attach (GTK_TABLE (table2), b5, 2, 3, 0, 1,
486 		      	GTK_FILL | GTK_EXPAND,
487 		      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
488 gtk_signal_connect_object (GTK_OBJECT (b5), "clicked", GTK_SIGNAL_FUNC(service_zoom_left), GTK_OBJECT (table2));
489 gtk_tooltips_set_tip_2(tooltips, b5, "Zoom To Start", NULL);
490 gtk_widget_show(b5);
491 
492 b6 = gtk_button_new();
493 gtk_container_add(GTK_CONTAINER(b6), pixmapzright);
494 gtk_table_attach (GTK_TABLE (table2), b6, 2, 3, 1, 2,
495 		      	GTK_FILL | GTK_EXPAND,
496 		      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
497 gtk_signal_connect_object (GTK_OBJECT (b6), "clicked", GTK_SIGNAL_FUNC(service_zoom_right), GTK_OBJECT (table2));
498 gtk_tooltips_set_tip_2(tooltips, b6, "Zoom To End", NULL);
499 gtk_widget_show(b6);
500 
501 
502 gtk_container_add (GTK_CONTAINER (frame), table2);
503 
504 gtk_widget_show(table2);
505 
506 return table;
507 }
508 
509