1 /*
2 * Copyright (c) Tony Bybell 2005-2014.
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 <gtk/gtk.h>
13 #include "gtk12compat.h"
14 #include "symbol.h"
15 #include "translate.h"
16 #include "debug.h"
17
18
19 #ifdef _MSC_VER
20 #define strcasecmp _stricmp
21 #endif
22
23 /************************ splay ************************/
24
xl_splay(char * i,xl_Tree * t)25 xl_Tree * xl_splay (char *i, xl_Tree * t) {
26 /* Simple top down splay, not requiring i to be in the tree t. */
27 /* What it does is described above. */
28 xl_Tree N, *l, *r, *y;
29 int dir;
30
31 if (t == NULL) return t;
32 N.left = N.right = NULL;
33 l = r = &N;
34
35 for (;;) {
36 dir = strcasecmp(i, t->item);
37 if (dir < 0) {
38 if (t->left == NULL) break;
39 if (strcasecmp(i, t->left->item)<0) {
40 y = t->left; /* rotate right */
41 t->left = y->right;
42 y->right = t;
43 t = y;
44 if (t->left == NULL) break;
45 }
46 r->left = t; /* link right */
47 r = t;
48 t = t->left;
49 } else if (dir > 0) {
50 if (t->right == NULL) break;
51 if (strcasecmp(i, t->right->item)>0) {
52 y = t->right; /* rotate left */
53 t->right = y->left;
54 y->left = t;
55 t = y;
56 if (t->right == NULL) break;
57 }
58 l->right = t; /* link left */
59 l = t;
60 t = t->right;
61 } else {
62 break;
63 }
64 }
65 l->right = t->left; /* assemble */
66 r->left = t->right;
67 t->left = N.right;
68 t->right = N.left;
69 return t;
70 }
71
72
xl_insert(char * i,xl_Tree * t,char * trans)73 xl_Tree * xl_insert(char *i, xl_Tree * t, char *trans) {
74 /* Insert i into the tree t, unless it's already there. */
75 /* Return a pointer to the resulting tree. */
76 xl_Tree * n;
77 int dir;
78
79 n = (xl_Tree *) calloc_2(1, sizeof (xl_Tree));
80 if (n == NULL) {
81 fprintf(stderr, "xl_insert: ran out of memory, exiting.\n");
82 exit(255);
83 }
84 n->item = strcpy(malloc_2(strlen(i)+1), i);
85 if(trans) n->trans = strcpy(malloc_2(strlen(trans)+1), trans);
86
87 if (t == NULL) {
88 n->left = n->right = NULL;
89 return n;
90 }
91 t = xl_splay(i,t);
92 dir = strcasecmp(i,t->item);
93 if (dir<0) {
94 n->left = t->left;
95 n->right = t;
96 t->left = NULL;
97 return n;
98 } else if (dir>0) {
99 n->right = t->right;
100 n->left = t;
101 t->right = NULL;
102 return n;
103 } else { /* We get here if it's already in the tree */
104 /* Don't add it again */
105 if(n->trans) free_2(n->trans);
106 free_2(n->item);
107 free_2(n);
108 return t;
109 }
110 }
111
xl_delete(char * i,xl_Tree * t)112 xl_Tree * xl_delete(char *i, xl_Tree * t) {
113 /* Deletes i from the tree if it's there. */
114 /* Return a pointer to the resulting tree. */
115 xl_Tree * x;
116 if (t==NULL) return NULL;
117 t = xl_splay(i,t);
118 if (strcmp(i, t->item) == 0) { /* found it */
119 if (t->left == NULL) {
120 x = t->right;
121 } else {
122 x = xl_splay(i, t->left);
123 x->right = t->right;
124 }
125 if(t->trans) free_2(t->trans);
126 free_2(t->item);
127 free_2(t);
128 return x;
129 }
130 return t; /* It wasn't there */
131 }
132
133
134 /************************ splay ************************/
135
136
init_filetrans_data(void)137 void init_filetrans_data(void)
138 {
139 int i;
140
141 if(!GLOBALS->filesel_filter) { GLOBALS->filesel_filter = calloc_2(FILE_FILTER_MAX+1, sizeof(char *)); }
142 if(!GLOBALS->xl_file_filter) { GLOBALS->xl_file_filter = calloc_2(FILE_FILTER_MAX+1, sizeof(struct xl_tree_node *)); }
143
144 for(i=0;i<FILE_FILTER_MAX+1;i++)
145 {
146 GLOBALS->filesel_filter[i] = NULL;
147 GLOBALS->xl_file_filter[i] = NULL;
148 }
149 }
150
regen_display(void)151 static void regen_display(void)
152 {
153 GLOBALS->signalwindow_width_dirty=1;
154 MaxSignalLength();
155 signalarea_configure_event(GLOBALS->signalarea, NULL);
156 wavearea_configure_event(GLOBALS->wavearea, NULL);
157 }
158
159
remove_file_filter_2(xl_Tree * t)160 static void remove_file_filter_2(xl_Tree *t)
161 {
162 if(t->left) remove_file_filter_2(t->left);
163 if(t->right) remove_file_filter_2(t->right);
164 if(t->item) free_2(t->item);
165 if(t->trans) free_2(t->trans);
166 free_2(t);
167 }
168
remove_file_filter(int which,int regen)169 static void remove_file_filter(int which, int regen)
170 {
171 if(GLOBALS->xl_file_filter[which])
172 {
173 remove_file_filter_2(GLOBALS->xl_file_filter[which]);
174 GLOBALS->xl_file_filter[which] = NULL;
175 }
176
177 if(regen)
178 {
179 regen_display();
180 }
181 }
182
load_file_filter(int which,char * name)183 static void load_file_filter(int which, char *name)
184 {
185 FILE *f = fopen(name, "rb");
186 if(!f)
187 {
188 status_text("Could not open filter file!\n");
189 return;
190 }
191
192 remove_file_filter(which, 0); /* should never happen from GUI, but possible from save files or other weirdness */
193
194 while(!feof(f))
195 {
196 char *s = fgetmalloc(f);
197 if(s)
198 {
199 char *lhs = s;
200
201 while(*lhs && isspace((int)(unsigned char)*lhs)) lhs++;
202 if(lhs)
203 {
204 char *rhs = lhs;
205
206 if(*lhs != '#') /* ignore comments */
207 {
208 while(*rhs && !isspace((int)(unsigned char)*rhs)) rhs++;
209 if(*rhs)
210 {
211 char *xlt = rhs+1;
212 *rhs = 0;
213
214 while(*xlt && isspace((int)(unsigned char)*xlt)) xlt++;
215 if(*xlt)
216 {
217 GLOBALS->xl_file_filter[which] = xl_insert(lhs, GLOBALS->xl_file_filter[which], xlt);
218 }
219 }
220 }
221 }
222
223 free_2(s);
224 }
225 }
226
227 fclose(f);
228 }
229
230
load_enums_filter(int which,char * name)231 static void load_enums_filter(int which, char *name)
232 {
233 int argc;
234 char **spl = zSplitTclList(name, &argc);
235 int i;
236
237 if((!spl)||(!argc)||(argc&1))
238 {
239 status_text("Malformed enums list!\n");
240 return;
241 }
242
243 remove_file_filter(which, 0); /* should never happen from GUI, but possible from save files or other weirdness */
244
245 for(i=0;i<argc;i+=2)
246 {
247 char *lhs = spl[i];
248 char *xlt = spl[i+1];
249
250 GLOBALS->xl_file_filter[which] = xl_insert(lhs, GLOBALS->xl_file_filter[which], xlt);
251 }
252 free_2(spl);
253 }
254
255
install_file_filter(int which)256 int install_file_filter(int which)
257 {
258 int found = 0;
259
260 if((which<0)||(which>=(FILE_FILTER_MAX+1)))
261 {
262 which = 0;
263 }
264
265 if(GLOBALS->traces.first)
266 {
267 Trptr t = GLOBALS->traces.first;
268 while(t)
269 {
270 if(t->flags&TR_HIGHLIGHT)
271 {
272 if(!(t->flags&(TR_BLANK|TR_ANALOG_BLANK_STRETCH)))
273 {
274 t->f_filter = which;
275 t->p_filter = 0;
276 if(!which)
277 {
278 t->flags &= (~(TR_FTRANSLATED|TR_PTRANSLATED|TR_ANALOGMASK));
279 }
280 else
281 {
282 t->flags &= (~(TR_ANALOGMASK));
283 t->flags |= TR_FTRANSLATED;
284 }
285 found++;
286 }
287 }
288 t=t->t_next;
289 }
290 }
291
292 if(found)
293 {
294 regen_display();
295 }
296
297 return(found);
298 }
299
300 /************************************************************************/
301
302
303
destroy_callback(GtkWidget * widget,GtkWidget * nothing)304 static void destroy_callback(GtkWidget *widget, GtkWidget *nothing)
305 {
306 (void)widget;
307 (void)nothing;
308
309 GLOBALS->is_active_translate_c_5=0;
310 gtk_widget_destroy(GLOBALS->window_translate_c_11);
311 GLOBALS->window_translate_c_11 = NULL;
312 }
313
ok_callback(GtkWidget * widget,GtkWidget * nothing)314 static void ok_callback(GtkWidget *widget, GtkWidget *nothing)
315 {
316 install_file_filter(GLOBALS->current_filter_translate_c_2);
317 destroy_callback(widget, nothing);
318 }
319
select_row_callback(GtkWidget * widget,gint row,gint column,GdkEventButton * event,gpointer data)320 static void select_row_callback(GtkWidget *widget, gint row, gint column,
321 GdkEventButton *event, gpointer data)
322 {
323 (void)widget;
324 (void)row;
325 (void)column;
326 (void)event;
327 (void)data;
328
329 GLOBALS->current_filter_translate_c_2 = row + 1;
330 }
331
unselect_row_callback(GtkWidget * widget,gint row,gint column,GdkEventButton * event,gpointer data)332 static void unselect_row_callback(GtkWidget *widget, gint row, gint column,
333 GdkEventButton *event, gpointer data)
334 {
335 (void)widget;
336 (void)row;
337 (void)column;
338 (void)event;
339 (void)data;
340
341 GLOBALS->current_filter_translate_c_2 = 0; /* none */
342 }
343
344
add_filter_callback_2(GtkWidget * widget,GtkWidget * nothing)345 static void add_filter_callback_2(GtkWidget *widget, GtkWidget *nothing)
346 {
347 (void)widget;
348 (void)nothing;
349
350 int i;
351 GtkCList *cl;
352
353 if(!GLOBALS->filesel_ok) { return; }
354
355 if(*GLOBALS->fileselbox_text)
356 {
357 for(i=0;i<GLOBALS->num_file_filters;i++)
358 {
359 if(GLOBALS->filesel_filter[i])
360 {
361 if(!strcmp(GLOBALS->filesel_filter[i], *GLOBALS->fileselbox_text))
362 {
363 status_text("Filter already imported.\n");
364 if(GLOBALS->is_active_translate_c_5) gdk_window_raise(GLOBALS->window_translate_c_11->window);
365 return;
366 }
367 }
368 }
369 }
370
371 GLOBALS->num_file_filters++;
372 load_file_filter(GLOBALS->num_file_filters, *GLOBALS->fileselbox_text);
373 if(GLOBALS->xl_file_filter[GLOBALS->num_file_filters] && (*GLOBALS->fileselbox_text /* scan-build */))
374 {
375 if(GLOBALS->filesel_filter[GLOBALS->num_file_filters]) free_2(GLOBALS->filesel_filter[GLOBALS->num_file_filters]);
376 GLOBALS->filesel_filter[GLOBALS->num_file_filters] = malloc_2(strlen(*GLOBALS->fileselbox_text) + 1);
377 strcpy(GLOBALS->filesel_filter[GLOBALS->num_file_filters], *GLOBALS->fileselbox_text);
378
379 cl=GTK_CLIST(GLOBALS->clist_translate_c_4);
380 gtk_clist_freeze(cl);
381 gtk_clist_append(cl,(gchar **)&(GLOBALS->filesel_filter[GLOBALS->num_file_filters]));
382
383 gtk_clist_set_column_width(cl,0,gtk_clist_optimal_column_width(cl,0));
384 gtk_clist_thaw(cl);
385 }
386 else
387 {
388 GLOBALS->num_file_filters--;
389 }
390
391 if(GLOBALS->is_active_translate_c_5) gdk_window_raise(GLOBALS->window_translate_c_11->window);
392 }
393
add_filter_callback(GtkWidget * widget,GtkWidget * nothing)394 static void add_filter_callback(GtkWidget *widget, GtkWidget *nothing)
395 {
396 (void)widget;
397 (void)nothing;
398
399 if(GLOBALS->num_file_filters == FILE_FILTER_MAX)
400 {
401 status_text("Max number of file filters installed already.\n");
402 return;
403 }
404
405 fileselbox("Select Filter File",&GLOBALS->fcurr_translate_c_2,GTK_SIGNAL_FUNC(add_filter_callback_2), GTK_SIGNAL_FUNC(NULL),NULL, 0);
406 }
407
408 /*
409 * mainline..
410 */
trans_searchbox(char * title)411 void trans_searchbox(char *title)
412 {
413 int i;
414
415 GtkWidget *scrolled_win;
416 GtkWidget *vbox1, *hbox, *hbox0;
417 GtkWidget *button1, *button5, *button6;
418 gchar *titles[]={"Filter Select"};
419 GtkWidget *frame2, *frameh, *frameh0;
420 GtkWidget *table;
421 GtkTooltips *tooltips;
422
423 if(GLOBALS->is_active_translate_c_5)
424 {
425 gdk_window_raise(GLOBALS->window_translate_c_11->window);
426 return;
427 }
428
429 GLOBALS->is_active_translate_c_5=1;
430 GLOBALS->current_filter_translate_c_2 = 0;
431
432 /* create a new modal window */
433 GLOBALS->window_translate_c_11 = gtk_window_new(GLOBALS->disable_window_manager ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
434 install_focus_cb(GLOBALS->window_translate_c_11, ((char *)&GLOBALS->window_translate_c_11) - ((char *)GLOBALS));
435
436 gtk_window_set_title(GTK_WINDOW (GLOBALS->window_translate_c_11), title);
437 gtkwave_signal_connect(GTK_OBJECT (GLOBALS->window_translate_c_11), "delete_event",(GtkSignalFunc) destroy_callback, NULL);
438
439 tooltips=gtk_tooltips_new_2();
440
441 table = gtk_table_new (256, 1, FALSE);
442 gtk_widget_show (table);
443
444 vbox1 = gtk_vbox_new (FALSE, 0);
445 gtk_container_border_width (GTK_CONTAINER (vbox1), 3);
446 gtk_widget_show (vbox1);
447
448
449 frame2 = gtk_frame_new (NULL);
450 gtk_container_border_width (GTK_CONTAINER (frame2), 3);
451 gtk_widget_show(frame2);
452
453 gtk_table_attach (GTK_TABLE (table), frame2, 0, 1, 0, 254,
454 GTK_FILL | GTK_EXPAND,
455 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
456
457 GLOBALS->clist_translate_c_4=gtk_clist_new_with_titles(1,titles);
458 gtk_clist_column_titles_passive(GTK_CLIST(GLOBALS->clist_translate_c_4));
459
460 gtk_clist_set_selection_mode(GTK_CLIST(GLOBALS->clist_translate_c_4), GTK_SELECTION_EXTENDED);
461 gtkwave_signal_connect_object (GTK_OBJECT (GLOBALS->clist_translate_c_4), "select_row",GTK_SIGNAL_FUNC(select_row_callback),NULL);
462 gtkwave_signal_connect_object (GTK_OBJECT (GLOBALS->clist_translate_c_4), "unselect_row",GTK_SIGNAL_FUNC(unselect_row_callback),NULL);
463
464 for(i=0;i<GLOBALS->num_file_filters;i++)
465 {
466 gtk_clist_append(GTK_CLIST(GLOBALS->clist_translate_c_4),(gchar **)&(GLOBALS->filesel_filter[i+1]));
467 }
468 gtk_clist_set_column_width(GTK_CLIST(GLOBALS->clist_translate_c_4),0,gtk_clist_optimal_column_width(GTK_CLIST(GLOBALS->clist_translate_c_4),0));
469
470 gtk_widget_show (GLOBALS->clist_translate_c_4);
471
472 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
473 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
474 GTK_POLICY_AUTOMATIC,
475 GTK_POLICY_AUTOMATIC);
476 gtk_widget_set_usize( GTK_WIDGET (scrolled_win), -1, 300);
477 gtk_widget_show(scrolled_win);
478
479 /* gtk_scrolled_window_add_with_viewport doesn't seen to work right here.. */
480 gtk_container_add (GTK_CONTAINER (scrolled_win), GLOBALS->clist_translate_c_4);
481
482 gtk_container_add (GTK_CONTAINER (frame2), scrolled_win);
483
484
485 frameh0 = gtk_frame_new (NULL);
486 gtk_container_border_width (GTK_CONTAINER (frameh0), 3);
487 gtk_widget_show(frameh0);
488 gtk_table_attach (GTK_TABLE (table), frameh0, 0, 1, 254, 255,
489 GTK_FILL | GTK_EXPAND,
490 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
491
492
493 hbox0 = gtk_hbox_new (FALSE, 1);
494 gtk_widget_show (hbox0);
495
496 button6 = gtk_button_new_with_label (" Add Filter to List ");
497 gtk_container_border_width (GTK_CONTAINER (button6), 3);
498 gtkwave_signal_connect_object (GTK_OBJECT (button6), "clicked",GTK_SIGNAL_FUNC(add_filter_callback),GTK_OBJECT (GLOBALS->window_translate_c_11));
499 gtk_widget_show (button6);
500 gtk_tooltips_set_tip_2(tooltips, button6,
501 "Bring up a file requester to add a filter to the filter select window.",NULL);
502
503 gtk_box_pack_start (GTK_BOX (hbox0), button6, TRUE, FALSE, 0);
504 gtk_container_add (GTK_CONTAINER (frameh0), hbox0);
505
506 frameh = gtk_frame_new (NULL);
507 gtk_container_border_width (GTK_CONTAINER (frameh), 3);
508 gtk_widget_show(frameh);
509 gtk_table_attach (GTK_TABLE (table), frameh, 0, 1, 255, 256,
510 GTK_FILL | GTK_EXPAND,
511 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
512
513
514 hbox = gtk_hbox_new (FALSE, 1);
515 gtk_widget_show (hbox);
516
517 button1 = gtk_button_new_with_label (" OK ");
518 gtk_container_border_width (GTK_CONTAINER (button1), 3);
519 gtkwave_signal_connect_object (GTK_OBJECT (button1), "clicked",GTK_SIGNAL_FUNC(ok_callback),GTK_OBJECT (GLOBALS->window_translate_c_11));
520 gtk_widget_show (button1);
521 gtk_tooltips_set_tip_2(tooltips, button1,
522 "Add selected signals to end of the display on the main window.",NULL);
523
524 gtk_box_pack_start (GTK_BOX (hbox), button1, TRUE, FALSE, 0);
525
526 button5 = gtk_button_new_with_label (" Cancel ");
527 gtk_container_border_width (GTK_CONTAINER (button5), 3);
528 gtkwave_signal_connect_object (GTK_OBJECT (button5), "clicked",GTK_SIGNAL_FUNC(destroy_callback),GTK_OBJECT (GLOBALS->window_translate_c_11));
529 gtk_tooltips_set_tip_2(tooltips, button5,
530 "Do nothing and return to the main window.",NULL);
531 gtk_widget_show (button5);
532 gtk_box_pack_start (GTK_BOX (hbox), button5, TRUE, FALSE, 0);
533
534 gtk_container_add (GTK_CONTAINER (frameh), hbox);
535 gtk_container_add (GTK_CONTAINER (GLOBALS->window_translate_c_11), table);
536
537 gtk_widget_set_usize(GTK_WIDGET(GLOBALS->window_translate_c_11), 400, 400);
538 gtk_widget_show(GLOBALS->window_translate_c_11);
539 }
540
541
542 /*
543 * currently only called by parsewavline+tcl
544 */
set_current_translate_generic(char * name,int typ)545 static void set_current_translate_generic(char *name, int typ)
546 {
547 int i;
548
549 if(typ)
550 {
551 for(i=1;i<GLOBALS->num_file_filters+1;i++)
552 {
553 if(!strcmp(GLOBALS->filesel_filter[i], name)) { GLOBALS->current_translate_file = i; return; }
554 }
555
556 if(!strcmp(WAVE_TCL_INSTALLED_FILTER, name))
557 {
558 GLOBALS->current_translate_file = 0; return;
559 }
560 }
561
562 if(GLOBALS->num_file_filters < FILE_FILTER_MAX)
563 {
564 GLOBALS->num_file_filters++;
565
566 if(typ)
567 {
568 load_file_filter(GLOBALS->num_file_filters, name);
569 }
570 else
571 {
572 load_enums_filter(GLOBALS->num_file_filters, name);
573 }
574
575 if(!GLOBALS->xl_file_filter[GLOBALS->num_file_filters])
576 {
577 GLOBALS->num_file_filters--;
578 GLOBALS->current_translate_file = 0;
579 }
580 else
581 {
582 if(GLOBALS->filesel_filter[GLOBALS->num_file_filters]) free_2(GLOBALS->filesel_filter[GLOBALS->num_file_filters]);
583
584 if(!typ)
585 {
586 name = WAVE_TCL_INSTALLED_FILTER;
587 }
588
589 GLOBALS->filesel_filter[GLOBALS->num_file_filters] = malloc_2(strlen(name) + 1);
590 strcpy(GLOBALS->filesel_filter[GLOBALS->num_file_filters], name);
591 GLOBALS->current_translate_file = GLOBALS->num_file_filters;
592 }
593 }
594 }
595
596
set_current_translate_file(char * name)597 void set_current_translate_file(char *name)
598 {
599 set_current_translate_generic(name, 1); /* use file, not enums */
600 }
601
set_current_translate_enums(char * lst)602 void set_current_translate_enums(char *lst)
603 {
604 set_current_translate_generic(lst, 0); /* use enums */
605 }
606
607
608