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 "globals.h"
11 #include <config.h>
12 #include <gtk/gtk.h>
13 #include <string.h>
14 #include "gtk12compat.h"
15 #include "debug.h"
16 #include "analyzer.h"
17 #include "currenttime.h"
18 
gtkwave_strrev(char * p)19 static void gtkwave_strrev(char *p)
20 {
21 char *q = p;
22 while(q && *q) ++q;
23 for(--q; p < q; ++p, --q)
24         *p = *p ^ *q,
25         *q = *p ^ *q,
26         *p = *p ^ *q;
27 }
28 
29 
make_bijective_marker_id_string(char * buf,unsigned int value)30 char *make_bijective_marker_id_string(char *buf, unsigned int value)
31 {
32 char *pnt = buf;
33 
34 value++; /* bijective values start at one */
35 while (value)
36         {
37         value--;
38         *(pnt++) = (char)('A' + value % ('Z'-'A'+1));
39         value = value / ('Z'-'A'+1);
40         }
41 
42 *pnt = 0;
43 gtkwave_strrev(buf);
44 return(buf);
45 }
46 
47 
bijective_marker_id_string_hash(const char * so)48 unsigned int bijective_marker_id_string_hash(const char *so)
49 {
50 unsigned int val=0;
51 int i;
52 int len = strlen(so);
53 char sn[16];
54 char *s = sn;
55 
56 strcpy(sn, so);
57 gtkwave_strrev(sn);
58 
59 s += len;
60 for(i=0;i<len;i++)
61         {
62 	char c = toupper(*(--s));
63 	if((c < 'A') || (c > 'Z')) break;
64         val *= ('Z'-'A'+1);
65         val += ((unsigned char)c) - ('A' - 1);
66         }
67 
68 val--; /* bijective values start at one so decrement */
69 return(val);
70 }
71 
72 
bijective_marker_id_string_len(const char * s)73 unsigned int bijective_marker_id_string_len(const char *s)
74 {
75 int len = 0;
76 
77 while(*s)
78 	{
79 	char c = toupper(*s);
80 	if((c >= 'A') && (c <= 'Z'))
81 		{
82 		len++;
83 		s++;
84 		continue;
85 		}
86 		else
87 		{
88 		break;
89 		}
90 	}
91 
92 return(len);
93 }
94 
95 
str_change_callback(GtkWidget * entry,gpointer which)96 static void str_change_callback(GtkWidget *entry, gpointer which)
97 {
98 G_CONST_RETURN gchar *entry_text;
99 int i;
100 uint32_t hashmask =  WAVE_NUM_NAMED_MARKERS;
101 hashmask |= hashmask >> 1;
102 hashmask |= hashmask >> 2;
103 hashmask |= hashmask >> 4;
104 hashmask |= hashmask >> 8;
105 hashmask |= hashmask >> 16;
106 
107 i = ((int) (((intptr_t) which) & hashmask)) % WAVE_NUM_NAMED_MARKERS;
108 GLOBALS->dirty_markerbox_c_1 = 1;
109 
110 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
111 if(entry_text && strlen(entry_text))
112 	{
113 	if(GLOBALS->shadow_marker_names[i])
114 		{
115 		free_2(GLOBALS->shadow_marker_names[i]);
116 		}
117 
118 	GLOBALS->shadow_marker_names[i] = strdup_2(entry_text);
119 	}
120 	else
121 	{
122 	if(GLOBALS->shadow_marker_names[i])
123 		{
124 		free_2(GLOBALS->shadow_marker_names[i]);
125 		GLOBALS->shadow_marker_names[i] = NULL;
126 		}
127 	}
128 }
129 
str_enter_callback(GtkWidget * entry,gpointer which)130 static void str_enter_callback(GtkWidget *entry, gpointer which)
131 {
132 G_CONST_RETURN gchar *entry_text;
133 int i;
134 uint32_t hashmask =  WAVE_NUM_NAMED_MARKERS;
135 hashmask |= hashmask >> 1;
136 hashmask |= hashmask >> 2;
137 hashmask |= hashmask >> 4;
138 hashmask |= hashmask >> 8;
139 hashmask |= hashmask >> 16;
140 
141 i = ((int) (((intptr_t) which) & hashmask)) % WAVE_NUM_NAMED_MARKERS;
142 GLOBALS->dirty_markerbox_c_1 = 1;
143 
144 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
145 if(entry_text && strlen(entry_text))
146 	{
147 	if(GLOBALS->shadow_marker_names[i])
148 		{
149 		free_2(GLOBALS->shadow_marker_names[i]);
150 		}
151 
152 	GLOBALS->shadow_marker_names[i] = strdup_2(entry_text);
153 	gtk_entry_select_region (GTK_ENTRY (entry),
154                              0, GTK_ENTRY(entry)->text_length);
155 
156 	}
157 	else
158 	{
159 	if(GLOBALS->shadow_marker_names[i])
160 		{
161 		free_2(GLOBALS->shadow_marker_names[i]);
162 		GLOBALS->shadow_marker_names[i] = NULL;
163 		}
164 	}
165 }
166 
167 
change_callback(GtkWidget * widget,gpointer which)168 static void change_callback(GtkWidget *widget, gpointer which)
169 {
170 (void)widget;
171 
172 GtkWidget *entry;
173 TimeType temp;
174 G_CONST_RETURN gchar *entry_text;
175 char buf[49];
176 int i;
177 int ent_idx;
178 uint32_t hashmask =  WAVE_NUM_NAMED_MARKERS;
179 hashmask |= hashmask >> 1;
180 hashmask |= hashmask >> 2;
181 hashmask |= hashmask >> 4;
182 hashmask |= hashmask >> 8;
183 hashmask |= hashmask >> 16;
184 
185 ent_idx = ((int) (((intptr_t) which) & hashmask)) % WAVE_NUM_NAMED_MARKERS;
186 
187 entry=GLOBALS->entries_markerbox_c_1[ent_idx];
188 
189 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
190 entry_text = entry_text ? entry_text : "";
191 if(!strlen(entry_text)) goto failure;
192 if(entry_text[0] != '-')
193 	{
194 	if(!isdigit((int)(unsigned char)entry_text[0])) goto failure;
195 	}
196 
197 temp=unformat_time(entry_text, GLOBALS->time_dimension);
198 temp -= GLOBALS->global_time_offset;
199 if((temp<GLOBALS->tims.start)||(temp>GLOBALS->tims.last)) goto failure;
200 
201 for(i=0;i<WAVE_NUM_NAMED_MARKERS;i++)
202         {
203         if(temp==GLOBALS->shadow_markers_markerbox_c_1[i])
204 		{
205 		if(i!=ent_idx)
206 			{
207 			GLOBALS->shadow_markers_markerbox_c_1[ent_idx] = -1;
208 			}
209 		goto failure;
210 		}
211         }
212 
213 reformat_time_simple(buf, temp + GLOBALS->global_time_offset, GLOBALS->time_dimension);
214 
215 GLOBALS->shadow_markers_markerbox_c_1[ent_idx]=temp;
216 GLOBALS->dirty_markerbox_c_1=1;
217 
218 failure:
219 return;
220 }
221 
enter_callback(GtkWidget * widget,gpointer which)222 static void enter_callback(GtkWidget *widget, gpointer which)
223 {
224 (void)widget;
225 
226 GtkWidget *entry;
227 /* TimeType *modify; */ /* scan-build */
228 TimeType temp;
229 G_CONST_RETURN gchar *entry_text;
230 char buf[49];
231 int i;
232 int ent_idx;
233 uint32_t hashmask =  WAVE_NUM_NAMED_MARKERS;
234 hashmask |= hashmask >> 1;
235 hashmask |= hashmask >> 2;
236 hashmask |= hashmask >> 4;
237 hashmask |= hashmask >> 8;
238 hashmask |= hashmask >> 16;
239 
240 ent_idx = ((int) (((intptr_t) which) & hashmask)) % WAVE_NUM_NAMED_MARKERS;
241 
242 entry=GLOBALS->entries_markerbox_c_1[ent_idx];
243 
244 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
245 entry_text = entry_text ? entry_text : "";
246 if(!strlen(entry_text)) goto failure;
247 
248 temp=unformat_time(entry_text, GLOBALS->time_dimension);
249 temp -= GLOBALS->global_time_offset;
250 if((temp<GLOBALS->tims.start)||(temp>GLOBALS->tims.last)) goto failure;
251 
252 for(i=0;i<WAVE_NUM_NAMED_MARKERS;i++)
253         {
254         if(temp==GLOBALS->shadow_markers_markerbox_c_1[i]) goto failure;
255         }
256 
257 reformat_time_simple(buf, temp +  GLOBALS->global_time_offset, GLOBALS->time_dimension);
258 gtk_entry_set_text (GTK_ENTRY (entry), buf);
259 
260 GLOBALS->shadow_markers_markerbox_c_1[ent_idx]=temp;
261 GLOBALS->dirty_markerbox_c_1=1;
262 gtk_entry_select_region (GTK_ENTRY (entry),
263 			     0, GTK_ENTRY(entry)->text_length);
264 return;
265 
266 failure:
267 /* modify=(TimeType *)which; */ /* scan-build */
268 if(GLOBALS->shadow_markers_markerbox_c_1[ent_idx]==-1)
269 	{
270 	sprintf(buf,"<None>");
271 	}
272 	else
273 	{
274 	reformat_time_simple(buf, GLOBALS->shadow_markers_markerbox_c_1[ent_idx] + GLOBALS->global_time_offset, GLOBALS->time_dimension);
275 	}
276 gtk_entry_set_text (GTK_ENTRY (entry), buf);
277 }
278 
ok_callback(GtkWidget * widget,GtkWidget * nothing)279 static void ok_callback(GtkWidget *widget, GtkWidget *nothing)
280 {
281 (void)widget;
282 (void)nothing;
283 
284 if(GLOBALS->dirty_markerbox_c_1)
285 	{
286 	int i;
287 	for(i=0;i<WAVE_NUM_NAMED_MARKERS;i++)
288 		{
289 		GLOBALS->named_markers[i]=GLOBALS->shadow_markers_markerbox_c_1[i];
290 		if(GLOBALS->marker_names[i]) free_2(GLOBALS->marker_names[i]);
291 		GLOBALS->marker_names[i] = GLOBALS->shadow_marker_names[i];
292 		GLOBALS->shadow_marker_names[i] = NULL;
293 		}
294         MaxSignalLength();
295         signalarea_configure_event(GLOBALS->signalarea, NULL);
296         wavearea_configure_event(GLOBALS->wavearea, NULL);
297 	}
298 
299   wave_gtk_grab_remove(GLOBALS->window_markerbox_c_4);
300   gtk_widget_destroy(GLOBALS->window_markerbox_c_4);
301   GLOBALS->window_markerbox_c_4 = NULL;
302 
303   GLOBALS->cleanup_markerbox_c_4();
304 }
305 
destroy_callback(GtkWidget * widget,GtkWidget * nothing)306 static void destroy_callback(GtkWidget *widget, GtkWidget *nothing)
307 {
308 (void)widget;
309 (void)nothing;
310 
311 int i;
312   for(i=0;i<WAVE_NUM_NAMED_MARKERS;i++)
313 	{
314 	if(GLOBALS->marker_names[i]) free_2(GLOBALS->marker_names[i]);
315   	GLOBALS->marker_names[i] = GLOBALS->shadow_marker_names[i];
316   	GLOBALS->shadow_marker_names[i] = NULL;
317 	}
318 
319   wave_gtk_grab_remove(GLOBALS->window_markerbox_c_4);
320   gtk_widget_destroy(GLOBALS->window_markerbox_c_4);
321   GLOBALS->window_markerbox_c_4 = NULL;
322 }
323 
markerbox(char * title,GtkSignalFunc func)324 void markerbox(char *title, GtkSignalFunc func)
325 {
326     GtkWidget *entry;
327     GtkWidget *vbox, *hbox, *vbox_g, *label;
328     GtkWidget *button1, *button2, *scrolled_win, *frame, *separator;
329     GtkWidget *table;
330     char labtitle[16];
331     int i;
332 
333     GLOBALS->cleanup_markerbox_c_4=func;
334     GLOBALS->dirty_markerbox_c_1=0;
335 
336     for(i=0;i<WAVE_NUM_NAMED_MARKERS;i++)
337 	{
338 	GLOBALS->shadow_markers_markerbox_c_1[i] = GLOBALS->named_markers[i];
339 	GLOBALS->shadow_marker_names[i] = strdup_2(GLOBALS->marker_names[i]);
340 	}
341 
342     /* fix problem where ungrab doesn't occur if button pressed + simultaneous accelerator key occurs */
343     if(GLOBALS->in_button_press_wavewindow_c_1) { gdk_pointer_ungrab(GDK_CURRENT_TIME); }
344 
345     /* create a new modal window */
346     GLOBALS->window_markerbox_c_4 = gtk_window_new(GLOBALS->disable_window_manager ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
347     install_focus_cb(GLOBALS->window_markerbox_c_4, ((char *)&GLOBALS->window_markerbox_c_4) - ((char *)GLOBALS));
348 
349     gtk_window_set_title(GTK_WINDOW (GLOBALS->window_markerbox_c_4), title);
350     gtkwave_signal_connect(GTK_OBJECT (GLOBALS->window_markerbox_c_4), "delete_event",(GtkSignalFunc) destroy_callback, NULL);
351 
352     vbox = gtk_vbox_new (FALSE, 0);
353     gtk_widget_show (vbox);
354 
355     vbox_g = gtk_vbox_new (FALSE, 0);
356     gtk_widget_show (vbox_g);
357 
358     table = gtk_table_new (256, 1, FALSE);
359     gtk_widget_show (table);
360 
361     gtk_table_attach (GTK_TABLE (table), vbox, 0, 1, 0, 255,
362                         GTK_FILL | GTK_EXPAND,
363                         GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
364 
365     frame = gtk_frame_new (NULL);
366     gtk_container_border_width (GTK_CONTAINER (frame), 3);
367     gtk_widget_show(frame);
368 
369     scrolled_win = gtk_scrolled_window_new (NULL, NULL);
370     gtk_widget_set_usize( GTK_WIDGET (scrolled_win), 400, 300);
371     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
372                                       GTK_POLICY_AUTOMATIC,
373                                       GTK_POLICY_AUTOMATIC);
374     gtk_widget_show(scrolled_win);
375     gtk_container_add (GTK_CONTAINER (frame), scrolled_win);
376     gtk_container_add (GTK_CONTAINER (vbox), frame);
377 
378     for(i=0;i<WAVE_NUM_NAMED_MARKERS;i++)
379     {
380     char buf[49];
381 
382     if(i)
383 	{
384     	separator = gtk_hseparator_new ();
385         gtk_widget_show (separator);
386         gtk_box_pack_start (GTK_BOX (vbox_g), separator, TRUE, TRUE, 0);
387 	}
388 
389 
390     make_bijective_marker_id_string(labtitle, i);
391     label=gtk_label_new(labtitle);
392     gtk_widget_show (label);
393     gtk_box_pack_start (GTK_BOX (vbox_g), label, TRUE, TRUE, 0);
394 
395     hbox = gtk_hbox_new(FALSE, 0);
396     gtk_widget_show (hbox);
397 
398     GLOBALS->entries_markerbox_c_1[i]=entry = gtk_entry_new_with_max_length (48);
399     gtkwave_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(enter_callback), (void *)((intptr_t) i));
400     gtkwave_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(change_callback), (void *)((intptr_t) i));
401     if(GLOBALS->shadow_markers_markerbox_c_1[i]==-1)
402 	{
403 	sprintf(buf,"<None>");
404 	}
405 	else
406 	{
407 	reformat_time_simple(buf, GLOBALS->shadow_markers_markerbox_c_1[i] + GLOBALS->global_time_offset, GLOBALS->time_dimension);
408 	}
409 
410     gtk_entry_set_text (GTK_ENTRY (entry), buf);
411     gtk_widget_show (entry);
412     gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
413 
414     /* string part */
415     entry = gtk_entry_new_with_max_length (48);
416     if(GLOBALS->shadow_marker_names[i]) gtk_entry_set_text (GTK_ENTRY (entry), GLOBALS->shadow_marker_names[i]);
417     gtk_widget_show (entry);
418     gtkwave_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(str_enter_callback), (void *)((intptr_t) i));
419     gtkwave_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(str_change_callback), (void *)((intptr_t) i));
420 
421     gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
422 
423 
424     gtk_box_pack_start (GTK_BOX (vbox_g), hbox, TRUE, TRUE, 0);
425     }
426 
427     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_win), vbox_g);
428 
429     hbox = gtk_hbox_new (FALSE, 1);
430     gtk_widget_show (hbox);
431 
432     gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, 255, 256,
433                         GTK_FILL | GTK_EXPAND,
434                         GTK_FILL | GTK_EXPAND | GTK_SHRINK, 1, 1);
435 
436     button1 = gtk_button_new_with_label ("OK");
437     gtk_widget_set_usize(button1, 100, -1);
438     gtkwave_signal_connect(GTK_OBJECT (button1), "clicked", GTK_SIGNAL_FUNC(ok_callback), NULL);
439     gtk_widget_show (button1);
440     gtk_container_add (GTK_CONTAINER (hbox), button1);
441     GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT);
442     gtkwave_signal_connect_object (GTK_OBJECT (button1), "realize", (GtkSignalFunc) gtk_widget_grab_default, GTK_OBJECT (button1));
443 
444 
445     button2 = gtk_button_new_with_label ("Cancel");
446     gtk_widget_set_usize(button2, 100, -1);
447     gtkwave_signal_connect(GTK_OBJECT (button2), "clicked", GTK_SIGNAL_FUNC(destroy_callback), NULL);
448     GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT);
449     gtk_widget_show (button2);
450     gtk_container_add (GTK_CONTAINER (hbox), button2);
451 
452     gtk_container_add (GTK_CONTAINER (GLOBALS->window_markerbox_c_4), table); /* need this table to keep ok/cancel buttons from stretching! */
453     gtk_widget_show(GLOBALS->window_markerbox_c_4);
454     wave_gtk_grab_add(GLOBALS->window_markerbox_c_4);
455 }
456 
457