1 #include "seaview.h"
2 #include <FL/Fl_Round_Button.H>
3 #include <FL/Fl_Check_Button.H>
4 #include <ctype.h>
5 #if 10000*FL_MAJOR_VERSION + 100*FL_MINOR_VERSION + FL_PATCH_VERSION >= 10305
6 #include <FL/platform.H>
7 #else
8 #include <FL/x.H>
9 #endif
10 #ifdef WIN32
11 #include <wchar.h>
12 /*extern "C" {
13   int _wsystem(const wchar_t *command );
14 }*/
15 #endif
16 
17 
18 enum position_mask {custom_mask = -1, gblocks_sites, position_1, position_2, position_3, position_12,
19   variable_sites  };
20 const char *position_mask_names[] = {"Gblocks", "First codon pos.", "Second codon pos.",
21 "Third codon pos.", "1st+2nd codon pos.", "Variable sites"};
22 int position_mask_count = sizeof(position_mask_names)/sizeof(char*);
23 
24 /* prototypes of included functions */
25 region *duplicate_region(region *source, const char *name);
26 void free_region(region *reg);
27 region *copy_region(region *from, region *to);
28 int create_full_region(SEA_VIEW *view, const char *name);
29 void save_active_region(SEA_VIEW *view );
30 void hide_region_line(SEA_VIEW *view);
31 int create_codon_position_mask(SEA_VIEW *view, position_mask mask, const char *regname);
32 int rename_current_region(SEA_VIEW *view, const char *name);
33 void delete_region(SEA_VIEW *view, int rang);
34 void activate_region_line(SEA_VIEW *view, int rang);
35 void ajout_segment(region *maregion, int debut, int fin);
36 int suppr_segment(region *maregion, int site, char *line);
37 list_segments *get_segment(region *maregion, int site);
38 void draw_region_line(Fl_Widget *ob, SEA_VIEW *view);
39 const char *site_mask_creation_dialog(SEA_VIEW *view, position_mask *outmask);
40 void regions_menu_callback(Fl_Widget *ob, void *extra);
41 int begin_change_segment(SEA_VIEW *view, int new_site);
42 int continue_change_segment(SEA_VIEW *view, int new_site);
43 void end_change_segment(SEA_VIEW *view);
44 int extend_segment_at_left(SEA_VIEW *view, int new_site);
45 static void delete_in_region_line(SEA_VIEW *view, int numsite, int total);
46 void delete_region_part(SEA_VIEW *view, int numsite, int total);
47 static void insert_in_active_region(SEA_VIEW *view, int numsite, int total);
48 void insert_region_part(SEA_VIEW *view, int numsite, int total);
49 list_regions *parse_regions_from_header(char *header);
50 void draw_region_background(SEA_VIEW *view, int f_seq0, int l_seq0);
51 const char *create_species_set(SEA_VIEW *view, const char *set_name);
52 void species_menu_callback(Fl_Widget *ob, void *extra);
53 int parse_species_sets_from_header(char *header, int **list_species_sets,
54 	char **name_species_sets, int totseqs);
55 
56 
57 extern void adjust_menu_edit_modes(SEA_VIEW *view);
58 int compute_size_params(SEA_VIEW *view, int force_recompute);
59 extern char *create_tmp_filename(void);
60 extern void delete_tmp_filename(const char *base_fname);
61 
62 
duplicate_region(region * source,const char * name)63 region *duplicate_region(region *source, const char *name)
64 {
65 region *destin;
66 list_segments *pseg, *dest_seg, *prev;
67 
68 destin = (region *)calloc(1, sizeof(region));
69 if(destin == NULL) return NULL;
70 if(name != NULL) {
71 	size_t l;
72 	l = strlen(name);
73 	destin->name = (char *)calloc(l+1, 1);
74 	if(destin->name == NULL) return NULL;
75 	memcpy(destin->name, name, l+1);
76 	}
77 if(source == NULL) return destin;
78 pseg = source->list;
79 if(pseg == NULL) return destin;
80 destin->list = (list_segments *)calloc(1, sizeof(list_segments));
81 if(destin->list == NULL) return NULL;
82 *(destin->list) = *pseg;
83 destin->list->next = NULL;
84 pseg = pseg->next;
85 prev = destin->list;
86 while(pseg != NULL) {
87 	dest_seg = (list_segments *)calloc(1, sizeof(list_segments));
88 	if(dest_seg == NULL) return NULL;
89 	*dest_seg = *pseg;
90 	dest_seg->next = NULL;
91 	prev->next = dest_seg;
92 	prev = dest_seg;
93 	pseg = pseg->next;
94 	}
95 destin->hide_when_viewasprots = source->hide_when_viewasprots;
96 return destin;
97 }
98 
99 
free_region(region * reg)100 void free_region(region *reg)
101 {
102 list_segments *pseg, *suiv;
103 if(reg == NULL) return;
104 pseg = reg->list;
105 while(pseg != NULL) {
106 	suiv = pseg->next;
107 	free(pseg);
108 	pseg = suiv;
109 	}
110 if(reg->name != NULL) free(reg->name);
111 free(reg);
112 }
113 
114 
copy_region(region * from,region * to)115 region *copy_region(region *from, region *to)
116 {
117 region *retval;
118 char *name;
119 name = to->name;
120 to->name = NULL;
121 free_region(to);
122 retval = duplicate_region(from, NULL);
123 if(retval ==  NULL) out_of_memory();
124 retval->name = name;
125 return retval;
126 }
127 
128 
create_full_region(SEA_VIEW * view,const char * name)129 int create_full_region(SEA_VIEW *view, const char *name)
130 {
131 list_regions *old, *new_list;
132 region *maregion;
133 /* le nom existe-t-il deja? */
134 old = view->regions;
135 while(old != NULL) {
136 	if(strcmp(name, old->element->name) == 0) return FALSE;
137 	old = old->next;
138 	}
139 maregion = (region *)calloc(1,sizeof(region));
140 if(maregion ==  NULL) out_of_memory();
141 maregion->name = (char *)malloc(strlen(name)+1);
142 if(maregion->name ==  NULL) out_of_memory();
143 strcpy(maregion->name, name);
144 maregion->list = (list_segments *)calloc(1, sizeof(list_segments));
145 if(maregion->list ==  NULL) out_of_memory();
146 maregion->list->debut = 1;
147 maregion->list->fin = view->seq_length;
148 new_list = (list_regions *)calloc(1, sizeof(list_regions));
149 if(new_list ==  NULL) out_of_memory();
150 new_list->element = maregion;
151 /* placer nouvelle region en fin de liste des regions connues */
152 if(view->regions == NULL)
153 	view->regions = new_list;
154 else	{
155 	old = view->regions;
156 	while(old->next != NULL) old = old->next;
157 	old->next = new_list;
158 	}
159 view->active_region = duplicate_region(maregion, name);
160 if(view->active_region == NULL) return TRUE; /*mess no mem serait mieux */
161 Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_file;
162 items[SAVE_REGIONS].activate();
163 view->region_length = view->seq_length;
164 memset(view->region_line, 'X', view->region_length);
165 view->region_line[view->region_length] = 0;
166 compute_size_params(view, TRUE);
167 return TRUE;
168 }
169 
170 
create_variable_mask(SEA_VIEW * view,region * maregion)171 void create_variable_mask(SEA_VIEW *view, region *maregion)
172 {
173   int i, j, in_variable = FALSE;
174   list_segments *segment, *previous;
175   previous = NULL;
176 
177   for(i = 1; i <= view->seq_length; i++) {
178     for (j = 1; j < view->tot_seqs; j++) {
179       if(toupper(view->sequence[j][i-1]) != toupper(view->sequence[0][i-1])) break;
180       }
181     if(j < view->tot_seqs) {
182       if(in_variable) continue;
183       in_variable = TRUE;
184       segment = (list_segments *)calloc(1, sizeof(list_segments));
185       segment->debut = i;
186       if(previous != NULL) previous->next = segment;
187       else maregion->list = segment;
188       previous = segment;
189     }
190     else {
191       if( ! in_variable) continue;
192       in_variable = FALSE;
193       segment->fin = i - 1;
194       for(j = segment->debut; j <= segment->fin; j++) view->region_line[j-1] = 'X';
195       }
196     }
197   if(in_variable) {
198     segment->fin = view->seq_length;
199     for(j = segment->debut; j <= segment->fin; j++) view->region_line[j-1] = 'X';
200     }
201 }
202 
run_gblocks_dialog(int * pb5_val,int * pb4_val,int * pb3_val,int * pb2_val)203 int run_gblocks_dialog(int *pb5_val, int *pb4_val, int *pb3_val, int *pb2_val)
204 {
205   Fl_Widget *o;
206   Fl_Window *w = new Fl_Window(370,100);
207   w->label("Gblocks options dialog");
208   Fl_Box *b = new Fl_Box(5, 5, w->w(), 20, "Options for a less stringent selection:");
209   b->align(FL_ALIGN_LEFT + FL_ALIGN_INSIDE);
210   b->labelfont(FL_TIMES_BOLD);
211   Fl_Check_Button *b4 = new Fl_Check_Button(10,30, 350, 20, "Allow smaller final blocks");
212   Fl_Check_Button *b5 = new Fl_Check_Button(10,50, 350, 20, "Allow gap positions within the final blocks");
213   Fl_Check_Button *b2 = new Fl_Check_Button(10,70, 350, 20, "Allow less strict flanking positions");
214   Fl_Box *box2 = new Fl_Box(5, b2->y() + 20, w->w(), 20, "Option for a more stringent selection:");
215   box2->align(FL_ALIGN_LEFT + FL_ALIGN_INSIDE);
216   box2->labelfont(FL_TIMES_BOLD);
217   Fl_Check_Button *b3 = new Fl_Check_Button(10,box2->y()+20, 350, 20, "Do not allow many contiguous nonconserved positions");
218   Fl_Button *cancel = new Fl_Button(10, b3->y()+30, 50, 20, "Cancel");
219   Fl_Return_Button *ret = new Fl_Return_Button(w->w()-60, cancel->y(), 50, 20, "OK");
220   w->size(w->w(), ret->y()+22);
221   w->end();
222   w->set_non_modal();
223   w->show();
224   while(TRUE) {
225     o = Fl::readqueue();
226     if (!o) Fl::wait();
227     else if(o == cancel || o == w) {
228       return 1;
229     }
230     else if(o == ret)
231       break;
232   }
233   *pb5_val = b5->value(); // -b5=h
234   *pb4_val = b4->value(); // -b4=5
235   *pb3_val = b3->value(); // -b3=4
236   *pb2_val = b2->value(); // -b2=(50% of species)
237   Fl::delete_widget(w);
238   if (o == cancel || o == w) return 1;
239   return 0;
240 }
241 
create_gblocks_mask(SEA_VIEW * view,region * maregion,int no_gui=false,int b5_val=0,int b4_val=0,int b3_val=0,int b2_val=0)242 int create_gblocks_mask(SEA_VIEW *view, region *maregion, int no_gui=false, int b5_val=0, int b4_val=0, int b3_val=0, int b2_val=0)
243 /* return 0 iff OK */
244 {
245   char cmd[500];
246   char base_fname[PATH_MAX], fname[PATH_MAX], *p, *q, *last;
247   int status, segment_count = -1, num, l;
248   FILE *in;
249   list_segments *segment, *previous;
250   void (*alert)(const char*,...) = (no_gui ? Fl::fatal : fl_alert);
251 
252 #ifdef WIN32
253 #define GBLOCKS_NAME "Gblocks.exe"
254 #elif defined(__APPLE__)
255   const char  *GBLOCKS_NAME = (fl_mac_os_version >= 101400 ? "Gblocks_x86_64" : "Gblocks_ppc_i386");
256 #else
257 #define GBLOCKS_NAME "Gblocks"
258 #endif
259   q = get_full_path(GBLOCKS_NAME);
260 
261   if (!q) {
262     alert("Program Gblocks not found."
263 #if !(defined(WIN32) || defined(__APPLE__))
264     "\nTo use Gblocks, download it from http://molevol.cmima.csic.es/castresana/Gblocks.html\n"
265     "and put it in a directory of your PATH"
266 #endif
267     );
268     return 1;
269   }
270 
271   if (!no_gui && run_gblocks_dialog(&b5_val, &b4_val, &b3_val, &b2_val)) return 1;
272   p = create_tmp_filename();
273   if(p == NULL) return 1;
274   strcpy(base_fname, p);
275   sprintf(fname, "%s.fst", base_fname);
276   char **newnames = new char*[view->tot_seqs];
277   for (int i = 0; i < view->tot_seqs; i++) {
278     newnames[i] = new char[15];
279     sprintf(newnames[i], "Seq_%d", i);
280     }
281   status = save_fasta_file(fname, view->sequence, NULL,
282 		      newnames, view->tot_seqs, view->each_length, NULL,
283 			   NULL, 0, FALSE, TRUE);
284   for (int i = 0; i < view->tot_seqs; i++) delete newnames[i];
285   delete[] newnames;
286   if (status) {
287     alert("Cannot write to temporary file %s", fname);
288     delete_tmp_filename(base_fname);
289     return 1;
290     }
291   sprintf(cmd, "\"%s\" \"%s\" -p=s -t=%c", q, fname, view->protein?'p':'d');
292   if (b5_val) strcat(cmd, " -b5=h");
293   if (b4_val) strcat(cmd, " -b4=5");
294   if (b3_val) strcat(cmd, " -b3=4");
295   if (b2_val) sprintf(cmd + strlen(cmd), " -b2=%d", view->tot_seqs/2 + 1);
296 #ifdef WIN32
297   //conversion of utf-8 cmd into a WCHAR string
298   int wlen = MultiByteToWideChar(CP_UTF8, 0, cmd, -1, NULL, 0);
299   WCHAR *wcmd = new WCHAR[wlen];
300   MultiByteToWideChar(CP_UTF8, 0, cmd, -1, wcmd, wlen);
301   //_wsystem(wcmd);
302   PROCESS_INFORMATION pi;
303   STARTUPINFOW si;
304   ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
305   ZeroMemory( &si, sizeof(STARTUPINFOW) );
306   l = CreateProcessW(NULL, wcmd, 0,0,FALSE,CREATE_NO_WINDOW,0,0, &si, &pi);
307   if (l) {
308     while ( WaitForSingleObject(pi.hProcess, 0) != WAIT_OBJECT_0) Fl::wait(0.1);
309   }
310   delete[] wcmd;
311 #else
312   strcat(cmd, " > /dev/null");
313   system(cmd);
314 #endif
315   sprintf(fname, "%s.fst-gb.txts", base_fname);
316   in = fopen(fname, "r");
317   if (in == NULL) status = 1;
318   if (!status) {
319     do {
320       p = fgets(cmd, sizeof(cmd), in);
321       if (p == NULL) { status = 1; break; }
322       }
323     while(strncmp(cmd, "Flank positions of the", 22) != 0);
324     if (p) {
325       sscanf(cmd + 22, "%d", &segment_count);
326       p = fgets(cmd, sizeof(cmd), in);
327       if (p == NULL || segment_count < 0 || strncmp(cmd, "Flanks:", 7) != 0) status = 1;
328       }
329     }
330   if (status == 0 && segment_count == 0) {
331     alert("Gblocks didn't find any block of conserved sites");
332     status = 1;
333     }
334   if (!status) {
335     p = cmd;
336     previous = NULL;
337     for (num = 0; num < segment_count; num++) {
338       q = NULL;
339       p = strchr(p, '[');
340       if (p != NULL) q = strchr(p, ']');
341       if (q == NULL) {
342 	l = strlen(cmd);
343 	memmove(cmd, last, l + 1 - (last - cmd));
344 	l -= (last - cmd);
345 	p = cmd;
346 	fgets(cmd + l, sizeof(cmd) - l, in);
347 	p = strchr(p, '[');
348 	if (p != NULL) q = strchr(p, ']');
349 	if (p == NULL || q == NULL) break;
350       }
351       p++;
352       segment = (list_segments*)calloc(sizeof(list_segments), 1);
353       sscanf(p, "%d", &segment->debut);
354       p = strchr(p, ' ');
355       sscanf(p, "%d", &segment->fin);
356       p = strchr(p, ']');
357       last = p;
358       if (previous) previous->next = segment;
359       else maregion->list = segment;
360       previous = segment;
361       for(int j = segment->debut; j <= segment->fin; j++) view->region_line[j-1] = 'X';
362       }
363     if (num < segment_count) status = 1;
364     maregion->hide_when_viewasprots = FALSE;
365     }
366   if (in) fclose(in);
367   delete_tmp_filename(base_fname);
368   return status;
369 }
370 
371 
create_codon_position_mask(SEA_VIEW * view,position_mask mask,const char * regname)372 int create_codon_position_mask(SEA_VIEW *view, position_mask mask, const char *regname)
373 /* return values:
374  0  no region was created
375  1  OK
376  2  name is already used
377  */
378 {
379   list_regions *old, *new_list;
380   region *maregion;
381   list_segments *segment, *previous;
382   int i;
383   /* le nom existe-t-il deja? */
384   old = view->regions;
385   while (old != NULL) {
386     if(strcmp(regname, old->element->name) == 0) break;
387     old = old->next;
388   }
389   if (old != NULL) {
390     if (mask != gblocks_sites) return 2;
391     int taille, valeur;
392     taille = view->menu_sites->vlength();
393     valeur = taille;
394     while(old->next) {
395       old = old->next;
396       valeur--;
397       }
398     delete_region(view, valeur);
399     }
400   maregion = (region *)calloc(1,sizeof(region));
401   if(maregion ==  NULL) out_of_memory();
402   maregion->name = (char *)malloc(strlen(regname) + 1);
403   if(maregion->name ==  NULL) out_of_memory();
404   strcpy(maregion->name, regname);
405   if(!view->protein) maregion->hide_when_viewasprots = TRUE;
406 
407   memset(view->region_line, '-', view->seq_length);
408   if (mask == gblocks_sites) {
409     if (create_gblocks_mask(view, maregion) ) {
410       free(maregion->name);
411       free(maregion);
412       return 0;
413     }
414   }
415   else if (mask >= position_1 && mask <= position_12) {
416     previous = NULL;
417     for(i = 1; i <= view->seq_length; i += 3) {
418       segment = (list_segments *)calloc(1, sizeof(list_segments));
419       if(mask == position_12) {
420 	segment->debut = i;
421 	segment->fin = i + 1;
422 	view->region_line[i - 1] = 'X';
423 	view->region_line[i] = 'X';
424       }
425       else {
426 	segment->debut = i + mask - position_1;
427 	segment->fin = segment->debut;
428 	view->region_line[i - 1 + mask - position_1] = 'X';
429       }
430       if(previous != NULL) previous->next = segment;
431       else maregion->list = segment;
432       previous = segment;
433       }
434     }
435   else if (mask == variable_sites) create_variable_mask(view, maregion);
436   view->region_length = view->seq_length;
437   view->region_line[view->region_length] = 0;
438 
439   new_list = (list_regions *)calloc(1, sizeof(list_regions));
440   if(new_list ==  NULL) out_of_memory();
441   new_list->element = maregion;
442   /* placer nouvelle region en fin de liste des regions connues */
443   if(view->regions == NULL)
444 	view->regions = new_list;
445   else	{
446 	old = view->regions;
447 	while(old->next != NULL) old = old->next;
448 	old->next = new_list;
449   }
450   view->active_region = duplicate_region(maregion, maregion->name);
451   if(view->active_region == NULL) return TRUE; /*mess no mem serait mieux */
452   Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_file;
453   items[SAVE_REGIONS].activate();
454   compute_size_params(view, TRUE);
455   return 1;
456 }
457 
458 
rename_current_region(SEA_VIEW * view,const char * name)459 int rename_current_region(SEA_VIEW *view, const char *name)
460 {
461 list_regions *old, *new_list;
462 region *maregion;
463 size_t l;
464 char *p;
465 
466 /* le nom existe-t-il deja? */
467 old = view->regions;
468 while(old != NULL) {
469 	if(strcmp(name, old->element->name) == 0) return FALSE;
470 	old = old->next;
471 	}
472 l = strlen(name);
473 p = (char *)calloc(l+1, 1);
474 if(p == NULL) return TRUE; /*mess no mem serait mieux */;
475 save_active_region(view);
476 memcpy(p, name, l+1);
477 free(view->active_region->name);
478 view->active_region->name = p;
479 maregion = duplicate_region(view->active_region, name);
480 if(maregion == NULL) return TRUE; /*mess no mem serait mieux */
481 new_list = (list_regions *)calloc(1, sizeof(list_regions));
482 if(new_list ==  NULL) out_of_memory();
483 new_list->element = maregion;
484 /* placer nouvelle region en fin de liste des regions connues */
485 if(view->regions == NULL)
486 	view->regions = new_list;
487 else	{
488 	old = view->regions;
489 	while(old->next != NULL) old = old->next;
490 	old->next = new_list;
491 	}
492 Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_file;
493 items[SAVE_REGIONS].activate();
494 return TRUE;
495 }
496 
497 
save_active_region(SEA_VIEW * view)498 void save_active_region(SEA_VIEW *view)
499 { /* save changes in current region */
500 list_regions *list;
501 list_segments *act_seg, *mem_seg;
502 int tmp, taille;
503 
504 if(view->menu_sites == NULL) return;
505   tmp = view->menu_sites->value();
506   if(tmp == 0) return;
507   taille = view->menu_sites->vlength();
508 list = view->regions;
509 if(tmp > 1) while( --tmp) list= list->next;
510 /* compare active and region in list */
511 act_seg = list->element->list;
512 mem_seg = view->active_region->list;
513 while ( (act_seg != NULL && mem_seg != NULL) ||
514 		(act_seg == NULL && mem_seg == NULL) ) {
515 	if( act_seg == NULL && mem_seg == NULL )
516 		return;
517 	if(act_seg->debut != mem_seg->debut || act_seg->fin != mem_seg->fin)
518 		break;
519 	act_seg = act_seg->next;
520 	mem_seg = mem_seg->next;
521 	}
522 list->element = copy_region(view->active_region, list->element);
523 if(view->format_for_save == MASE_FORMAT || view->format_for_save == NEXUS_FORMAT) {
524   set_seaview_modified(view, TRUE);
525   }
526 }
527 
528 
hide_region_line(SEA_VIEW * view)529 void hide_region_line(SEA_VIEW *view)
530 {
531 free_region(view->active_region);
532 view->active_region = NULL;
533 Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_file;
534 if (view->tot_sel_seqs == 0) items[SAVE_REGIONS].deactivate();
535 compute_size_params(view, TRUE);
536 }
537 
538 
delete_region(SEA_VIEW * view,int rang)539 void delete_region(SEA_VIEW *view, int rang)
540 {
541 list_regions *list, *previous;
542 region *maregion;
543 list_segments *segment, *next;
544 
545   view->menu_sites->remove(rang-1);
546 list = view->regions;
547 if(rang == 1)
548 	view->regions = list->next;
549 else	{
550 	while( --rang) {
551 		previous = list;
552 		list= list->next;
553 		}
554 	previous->next = list->next;
555 	}
556 maregion = list->element;
557 segment = maregion->list;
558 while(segment != NULL) {
559 	next = segment->next;
560 	free(segment);
561 	segment = next;
562 	}
563 free(maregion->name);
564 free(maregion);
565 free(list);
566 hide_region_line(view);
567 }
568 
569 
activate_region_line(SEA_VIEW * view,int rang)570 void activate_region_line(SEA_VIEW *view, int rang)
571 {
572 list_regions *list;
573 list_segments *segment;
574 list = view->regions;
575 while ( --rang )
576 	list = list->next;
577 if(view->viewasprots && list->element->hide_when_viewasprots) return;
578 if(view->active_region == NULL) {
579 	Fl_Menu_Item *items = (Fl_Menu_Item *)view->menu_file;
580 	items[SAVE_REGIONS].activate();
581 	}
582 view->active_region = duplicate_region(list->element, list->element->name);
583 view->region_length = view->seq_length;
584 memset(view->region_line, '-', view->region_length);
585 view->region_line[view->region_length] = 0;
586 segment = view->active_region->list;
587 while(segment != NULL) {
588 	memset(view->region_line + segment->debut - 1, 'X',
589 		segment->fin - segment->debut + 1);
590 	segment = segment->next;
591 	}
592 }
593 
594 
ajout_segment(region * maregion,int debut,int fin)595 void ajout_segment(region *maregion, int debut, int fin)
596 /* toutes inferferences entre nouveau segment et anciens sont acceptees
597 */
598 {
599 list_segments *psegment, *next, *prev;
600 prev = NULL; psegment = maregion->list;
601 while(psegment != NULL) { /* recherche premier segment apres le nouveau */
602 	if(debut <= psegment->fin + 1) break;
603 	prev = psegment;
604 	psegment = psegment->next;
605 	}
606 if(psegment == NULL || fin < psegment->debut - 1) { /* nouveau sans interference*/
607 	next = (list_segments *)calloc(1, sizeof(list_segments));
608 	if(next ==  NULL) out_of_memory();
609 	next->debut = debut; next->fin = fin; next->next = psegment;
610 	if(prev != NULL) prev->next = next;
611 	else 	maregion->list = next;
612 	return;
613 	}
614 /* nouveau segment interfere avec un(des) autre(s) */
615 psegment->debut = FL_min(debut, psegment->debut);
616 psegment->fin = FL_max(fin, psegment->fin);
617 while(psegment->next != NULL && psegment->fin >= psegment->next->debut - 1) {
618 	psegment->fin = FL_max(psegment->fin, psegment->next->fin);
619 	next = psegment->next->next;
620 	free(psegment->next);
621 	psegment->next = next;
622 	}
623 return;
624 }
625 
626 
suppr_segment(region * maregion,int site,char * line)627 int suppr_segment(region *maregion, int site, char *line)
628 /* suppression du segment entier exact contenant le site site
629 et la ligne-regions ligne est mise a jour avec des - (sauf si line==NULL)
630 valeur rendue TRUE si pas de segment supprime, FALSE si ok.
631 */
632 {
633 list_segments *psegment, *prev, *next;
634 int debut, fin;
635 
636 psegment = maregion->list; prev = NULL;
637 while(psegment != NULL && psegment->fin < site) {
638 	prev = psegment;
639 	psegment = psegment->next;
640 	}
641 if(psegment == NULL || psegment->debut > site) return TRUE;
642 next = psegment->next; debut = psegment->debut; fin = psegment->fin;
643 free(psegment);
644 if(prev != NULL) prev->next = next;
645 else	maregion->list = next;
646 if(line != NULL) memset(line+debut-1, '-', fin-debut+1);
647 return FALSE;
648 }
649 
650 
get_segment(region * maregion,int site)651 list_segments *get_segment(region *maregion, int site)
652 /* rend le segment contenant site ou NULL si site n'est pas dans un segment */
653 {
654 list_segments *psegment;
655 psegment = maregion->list;
656 while(psegment != NULL && psegment->fin < site) {
657 	psegment = psegment->next;
658 	}
659 if(psegment == NULL || psegment->debut > site) return NULL;
660 return psegment;
661 }
662 
663 
draw_region_line(Fl_Widget * ob,SEA_VIEW * view)664 void draw_region_line(Fl_Widget *ob, SEA_VIEW *view)
665 {
666 int offset, x, y, l_line;
667 
668 x = view->x_seq;
669 y = view->y_seq + FL_min(view->tot_lines, view->tot_seqs) * view->line_height;
670 fl_font(ob->labelfont(),ob->labelsize());
671 /* clear the background of the region line */
672 fl_color(ob->color());
673 fl_rectf(x - view->char_width, y - view->line_height + fl_descent(),
674 	(view->tot_sites + 2) * view->char_width, view->line_height);
675 /* write region line */
676 offset= view->first_site - 1;
677 l_line = ( offset + view->tot_sites < view->region_length ?
678 view->tot_sites : view->region_length - offset);
679 if(l_line <= 0) return;
680 fl_color(view->region_color);
681 fl_draw(view->region_line + offset, l_line, x, y);
682 }
683 
684 
site_mask_creation_dialog(SEA_VIEW * view,position_mask * outmask)685 const char *site_mask_creation_dialog(SEA_VIEW *view, position_mask *outmask)
686 {
687   const char *retval;
688   static char custom_name[50];
689   *outmask = custom_mask;
690   Fl_Window *w = new Fl_Window(300,220);
691   w->label("Site set creation dialog");
692   Fl_Input *input = new Fl_Input(180, 20, 100, 20, "Name of custom site set?");
693   input->value("all sites");
694   Fl_Group  *g = new Fl_Group(0,40,w->w(),130);
695   Fl_Round_Button *mask[6];
696   mask[0] = new Fl_Round_Button(30, input->y() + 30, 150, 20, position_mask_names[0]);
697   mask[0]->type(FL_RADIO_BUTTON);
698   mask[1] = new Fl_Round_Button(mask[0]->x(), mask[0]->y() + 20, 150, 20, position_mask_names[1]);
699   mask[1]->type(FL_RADIO_BUTTON);
700   mask[2] = new Fl_Round_Button(mask[0]->x(), mask[1]->y() + 20, 150, 20, position_mask_names[2]);
701   mask[2]->type(FL_RADIO_BUTTON);
702   mask[3] = new Fl_Round_Button(mask[0]->x(), mask[2]->y() + 20, 180, 20, position_mask_names[3]);
703   mask[3]->type(FL_RADIO_BUTTON);
704   mask[4] = new Fl_Round_Button(mask[0]->x(), mask[3]->y() + 20, 120, 20, position_mask_names[4]);
705   mask[4]->type(FL_RADIO_BUTTON);
706   mask[5] = new Fl_Round_Button(mask[0]->x(), mask[4]->y() + 20, 120, 20, position_mask_names[5]);
707   mask[5]->type(FL_RADIO_BUTTON);
708   g->end();
709   if(view->protein) {
710     for(int i = 1; i <= 4; i++) mask[i]->deactivate();
711     }
712   Fl_Return_Button *ok = new Fl_Return_Button(170, mask[5]->y() + mask[5]->h() + 10, 50, 30, "Ok");
713   Fl_Button *cancel = new Fl_Button(ok->x() + ok->w() + 5, ok->y(), 60, 30, "Cancel");
714   w->end();
715   w->set_non_modal();
716   w->show();
717   while(TRUE) {
718 	Fl_Widget *o = Fl::readqueue();
719 	if (!o) Fl::wait();
720 	else if(o == mask[0] || o == mask[1] || o == mask[2] || o == mask[3] || o == mask[4] || o == mask[5]) {
721 	  ((Fl_Round_Button*)o)->setonly();
722 	  ok->take_focus();
723 	  input->deactivate();
724 	  if(o == mask[0]) {*outmask = gblocks_sites;}
725 	  else if(o == mask[1]) {*outmask = position_1;}
726 	  else if(o == mask[2]) {*outmask = position_2;}
727 	  else if(o == mask[3]) {*outmask = position_3;}
728 	  else if(o == mask[4]) {*outmask = position_12;}
729 	  else if(o == mask[5]) {*outmask = variable_sites;}
730 	  retval = position_mask_names[*outmask];
731 	}
732 	else if(o == cancel || o == w) {
733 	  retval = NULL;
734 	  break;
735 	  }
736 	else if(o == ok) {
737 	  if(input->active()) {
738 		strncpy(custom_name, input->value(), sizeof(custom_name) - 1);
739 		retval = custom_name;
740 		}
741 	  break;
742 	  }
743 	}
744   delete w;
745   return retval;
746 }
747 
748 
regions_menu_callback(Fl_Widget * ob,void * extra)749 void regions_menu_callback(Fl_Widget *ob, void *extra)
750 {
751   SEA_VIEW *view;
752   const char *reg_name;
753   position_mask mask;
754   Fl_Menu_ *menu = (Fl_Menu_*)ob;
755   view = (SEA_VIEW *) ob->user_data();
756   int reponse = menu->mvalue() - view->menu_sites->get_menu();
757   int ok;
758   Fl_Menu_Item *items = view->menu_sites->get_menu();
759 
760   if(reponse == 0) { /* create new region */
761 	reg_name = site_mask_creation_dialog(view, &mask);
762 	if(reg_name == NULL) return;
763 	if(mask == custom_mask) ok = create_full_region(view, reg_name);
764 	else {
765 	  int retval = create_codon_position_mask(view, mask, reg_name);
766 	  if (retval == 0) return;
767 	  if (retval == 2) ok = 0; else ok = 1;
768 	  }
769 	if(!ok) {
770 	  fl_alert("This name is already used: %s", reg_name);
771 	  return;
772 	  }
773 	view->DNA_obj->redraw();
774 	items[0].deactivate();
775 	items[1].activate();
776 	items[2].activate();
777 	items[3].activate();
778     view->menu_sites->add(reg_name, regions_menu_callback, NULL, FL_MENU_RADIO);
779     view->menu_sites->value(view->menu_sites->vlength());
780 	}
781   else if(reponse == 1) { /* duplicate current region */
782 	  reg_name = fl_input("New set name?", view->active_region->name);
783 	  if(reg_name == NULL) return;
784 	  if( !rename_current_region(view, reg_name) ) {
785 		  fl_alert("This name is already used: %s",reg_name);
786 		  return;
787 		  }
788 	  view->DNA_obj->redraw();
789     view->menu_sites->add(reg_name, regions_menu_callback, NULL, FL_MENU_RADIO);
790     view->menu_sites->value(view->menu_sites->vlength());
791 	  }
792   else if(reponse == 2) { /* hide current region */
793 	  save_active_region(view);
794 	  hide_region_line(view);
795 	  view->DNA_obj->redraw();
796 	  items[0].activate();
797 	  items[1].deactivate();
798 	  items[2].deactivate();
799 	  items[3].deactivate();
800     view->menu_sites->value(0);
801 	  }
802   else if(reponse == 3) { /* delete current region */
803 	  list_regions *list;
804 	  int valeur, tmp;
805     valeur = view->menu_sites->value();
806     if (!valeur) return;
807 	  tmp = valeur;
808 	  list = view->regions;
809 	  if(tmp > 1) while( --tmp) list= list->next;
810 	  if( fl_choice("Confirm deletion of set:\n%s", "Cancel", "Delete", NULL, list->element->name) ) {
811 		  delete_region(view, valeur);
812 	    view->menu_sites->value(0);
813 		  view->DNA_obj->redraw();
814 		  items[0].activate();
815 		  items[1].deactivate();
816 		  items[2].deactivate();
817 		  items[3].deactivate();
818 		  }
819 	  }
820   else	{ /* choix d'une region courante */
821 	  save_active_region(view);
822 	  int valeur = menu->mvalue() - view->menu_sites->vitem(0) + 1;
823 	  activate_region_line(view, valeur);
824 	  compute_size_params(view, TRUE);
825 	  view->DNA_obj->redraw();
826     view->menu_sites->value(valeur);
827 	  items[0].deactivate();
828 	  items[1].activate();
829 	  items[2].activate();
830 	  items[3].activate();
831 	  }
832 }
833 
834 
835 static int new_debut, new_fin, prev_site;
836 static list_segments *modified_segment;
837 
begin_change_segment(SEA_VIEW * view,int new_site)838 int begin_change_segment(SEA_VIEW *view, int new_site)
839 /*
840 returns TRUE si click sur extremite d'un segment ou entre 2 segments, FALSE sinon et enleve le site clique de la region
841 */
842 {
843 int tmp;
844 modified_segment = get_segment(view->active_region, new_site);
845 if ( modified_segment != NULL && new_site != modified_segment->debut &&
846 	new_site != modified_segment->fin) {
847 	/* enlever un site au milieu d'un segment */
848 	tmp = modified_segment->fin;
849 	modified_segment->fin = new_site - 1;
850 	ajout_segment(view->active_region, new_site+1, tmp);
851 	view->region_line[new_site - 1] ='-';
852 	return FALSE;
853 	}
854 if(modified_segment != NULL) {
855 	new_debut = modified_segment->debut;
856 	new_fin = modified_segment->fin;
857 	}
858 else	{
859 	new_debut = new_fin = new_site;
860 	view->region_line[new_site - 1] ='X';
861 	}
862 prev_site = new_site;
863 return TRUE;
864 }
865 
continue_change_segment(SEA_VIEW * view,int new_site)866 int continue_change_segment(SEA_VIEW *view, int new_site)
867 {
868 int min;
869 char *pos, new_char;
870 list_segments *current_segment;
871 
872 if(new_site == prev_site) return FALSE;
873 current_segment = get_segment(view->active_region, new_site);
874 if( current_segment != NULL && current_segment != modified_segment)return FALSE;
875 pos = view->region_line + new_site - 1;
876 if( *pos == '-' ) new_char = 'X';
877 else	new_char = '-';
878 min = FL_min(prev_site, new_site);
879 memset( view->region_line + min - 1, new_char, abs(prev_site - new_site) + 1 );
880 view->region_line[new_site - 1] = 'X';
881 if(new_char == 'X') {
882 	new_debut = FL_min(new_debut, new_site);
883 	new_fin = FL_max(new_fin, new_site);
884 	}
885 else	{
886 	if(new_site > prev_site)
887 		new_debut = new_site;
888 	else
889 		new_fin = new_site;
890 	}
891 prev_site = new_site;
892 return TRUE;
893 }
894 
895 
end_change_segment(SEA_VIEW * view)896 void end_change_segment(SEA_VIEW *view)
897 {
898 if(modified_segment == NULL ) /* nouveau segment */
899 	ajout_segment(view->active_region, new_debut, new_fin);
900 else 	{
901 	if (new_fin > modified_segment->fin)
902 	/* segment rallonge par sa fin */
903 		ajout_segment(view->active_region, modified_segment->debut,
904  			new_fin);
905 	else if( new_fin < modified_segment->fin )
906 		/*segment raccourci par sa fin */
907 		modified_segment->fin = new_fin;
908 	if (new_debut < modified_segment->debut)
909 		/* segment rallonge par son debut */
910 		ajout_segment(view->active_region, new_debut,
911  			modified_segment->fin);
912 	else if( new_debut > modified_segment->debut )
913 		/* segment raccourci par son debut */
914 		modified_segment->debut = new_debut;
915 	}
916 }
917 
918 
extend_segment_at_left(SEA_VIEW * view,int new_site)919 int extend_segment_at_left(SEA_VIEW *view, int new_site)
920 {
921 list_segments *segment;
922 
923 segment = view->active_region->list;
924 if(segment == NULL || segment->debut > new_site) return TRUE;
925 if(get_segment(view->active_region, new_site) != NULL) return TRUE;
926 while(segment->next != NULL) {
927 	if(segment->next->debut > new_site) break;
928 	segment = segment->next;
929 	}
930 memset(view->region_line + segment->fin, 'X', new_site - segment->fin);
931 ajout_segment(view->active_region, segment->fin, new_site);
932 return FALSE;
933 }
934 
935 
delete_in_region_line(SEA_VIEW * view,int numsite,int total)936 static void delete_in_region_line(SEA_VIEW *view, int numsite, int total)
937 /* delete total sites in pos numsite of view->region_line */
938 {
939 char *site;
940 int l;
941 l = view->region_length;
942 site = view->region_line + numsite - 1;
943 memmove(site - total, site, l - numsite + 2);
944 view->region_length -= total;
945 }
946 
947 
delete_region_part(SEA_VIEW * view,int numsite,int total)948 void delete_region_part(SEA_VIEW *view, int numsite, int total)
949 {
950 int debut, fin, vnumsite, vtotal;
951 list_segments *segment, *previous;
952 list_regions *next_region;
953 list_regions active;
954 
955 if(total >= numsite) total = numsite - 1;
956 if(total == 0) return;
957 if(view->active_region != NULL) delete_in_region_line(view, numsite, total);
958 /* pour toutes les regions en commencant par active_region */
959 if(view->active_region != NULL) {
960 	active.element = view->active_region;
961 	active.next = view->regions;
962 	next_region = &active;
963 	}
964 else
965 	next_region = view->regions;
966 while(next_region != NULL) {
967 	if(view->viewasprots && next_region->element->hide_when_viewasprots) {
968 	  vtotal = total * 3;
969 	  vnumsite = numsite * 3;
970 	}
971 	else {
972 	  vtotal = total;
973 	  vnumsite = numsite;
974 	}
975 	segment = next_region->element->list;
976 	while(segment != NULL) {
977 		debut = segment->debut; fin = segment->fin;
978 		if(debut >= vnumsite) debut -= vtotal;
979 		else if(debut >= vnumsite - vtotal) debut = vnumsite - vtotal;
980 		if(fin >= vnumsite - vtotal) {
981 			fin -= vtotal;
982 			if(fin < debut) {
983 				debut = segment->debut;
984 				segment = segment->next;
985 				suppr_segment(next_region->element, debut,
986 						NULL);
987 				}
988 			else	{
989 				segment->debut = debut;
990 				segment->fin = fin;
991 				segment = segment->next;
992 				}
993 			}
994 		else
995 			segment = segment->next;
996 		}
997 /* il peut etre necessaire de fusionner 2 segments consecutifs */
998 	segment = next_region->element->list;
999 	previous = NULL;
1000 	while(segment != NULL) {
1001 		if(previous != NULL && segment->debut == previous->fin + 1) {
1002 			fin = segment->fin;
1003 			suppr_segment(next_region->element, segment->debut,
1004 					NULL);
1005 			ajout_segment(next_region->element, previous->debut,
1006 					fin);
1007 			segment = previous;
1008 			}
1009 		previous = segment;
1010 		segment = segment->next;
1011 		}
1012 	next_region = next_region->next;
1013 	}
1014 }
1015 
1016 
insert_in_active_region(SEA_VIEW * view,int numsite,int total)1017 static void insert_in_active_region(SEA_VIEW *view, int numsite, int total)
1018 /*
1019 insert total sites in pos numsite of view->region_line and of ->active_region
1020 */
1021 {
1022 char *site, new_char;
1023 list_segments *segment;
1024 
1025 site = view->region_line + numsite - 1;
1026 memmove(site + total, site, view->region_length - numsite + 2);
1027 view->region_length += total;
1028 segment = view->active_region->list;
1029 new_char = '-';
1030 while(segment != NULL) {
1031 	if(segment->debut <= numsite && segment->fin >= numsite) {
1032 		new_char = 'X';
1033 		}
1034 	if(segment->debut > numsite) segment->debut += total;
1035 	if(segment->fin >= numsite) segment->fin += total;
1036 	segment = segment->next;
1037 	}
1038 memset(site, new_char, total);
1039 }
1040 
1041 
insert_region_part(SEA_VIEW * view,int numsite,int total)1042 void insert_region_part(SEA_VIEW *view, int numsite, int total)
1043 /* insert total sites in pos numsite of all known regions */
1044 {
1045 list_segments *segment;
1046 list_regions *next_region;
1047 int vtotal, vnumsite;
1048 
1049 if(total + view->region_length > view->max_seq_length)
1050 	total = view->max_seq_length - view->region_length;
1051 if(total == 0) return;
1052 if(view->active_region != NULL) insert_in_active_region(view, numsite, total);
1053 next_region = view->regions;
1054 while(next_region != NULL) {
1055 	segment = next_region->element->list;
1056 	if(view->viewasprots && next_region->element->hide_when_viewasprots) {
1057 	  vtotal = total * 3;
1058 	  vnumsite = numsite * 3;
1059 	  }
1060 	else {
1061 	  vtotal = total;
1062 	  vnumsite = numsite;
1063 	  }
1064 	while(segment != NULL) {
1065 		if(segment->debut > vnumsite) segment->debut += vtotal;
1066 		if(segment->fin >= vnumsite) segment->fin += vtotal;
1067 		segment = segment->next;
1068 		}
1069 	next_region = next_region->next;
1070 	}
1071 }
1072 
1073 
parse_regions_from_header(char * header)1074 list_regions *parse_regions_from_header(char *header)
1075 /* parse the region information from header lines
1076 and remove it from them
1077 */
1078 {
1079 char *p, reg_name[200], aux[200], separ[5], *i, *j, *new_header,
1080 	*fin_new_header, *old_header;
1081 int nreg, tot_reg, l, *endpoints, l_header;
1082 region *maregion;
1083 list_segments *segment;
1084 list_regions *rlist, *deb_rlist = NULL, *cur_list;
1085 if(header == NULL) return NULL;
1086 old_header = header;
1087 l_header=strlen(header);
1088 if( (new_header = (char *)malloc(l_header+1)) == NULL) out_of_memory();
1089 fin_new_header = new_header;
1090 *new_header = 0;
1091 while (*header!= 0) {
1092 	if(strncmp(header,";;#",3) == 0) {
1093 		p=strchr(header,'=') + 1;
1094 		while(*p == ' ') p++;
1095 		sscanf(p,"%d",&tot_reg);
1096 		endpoints = (int *)malloc(2*tot_reg*sizeof(int));
1097 		if(endpoints==NULL) out_of_memory();
1098 		while(*p != ' ' && *p != '\n') p++;
1099 		while(*p == ' ') p++;
1100 		if( *p == '\n') { /* no region name in file */
1101 			strcpy(reg_name, "regions");
1102 			header = p;
1103 			}
1104 		else	{
1105 			header = strchr(p,'\n');
1106 			memcpy(reg_name, p, header - p);
1107 			l = header - p;
1108 			reg_name[l] = 0;
1109 			while(reg_name[--l]==' ') reg_name[l] = 0;
1110 			}
1111 		header++;
1112 		nreg=0;
1113 		while(nreg <= 2*tot_reg-1) {
1114 			j = (char *)memccpy(aux, header, '\n', sizeof(aux));
1115 			if(j == NULL) goto next_line;
1116 			*(j - 1) = 0;
1117 			strcpy(separ,";, "); j=aux;
1118 			while( (i=strtok(j,separ)) != NULL) {
1119 				sscanf(i,"%d",&l);
1120 				if( nreg > 0 &&
1121 					l <= *(endpoints+nreg-1) - nreg%2 ) {
1122 					fprintf(stderr,
1123 			"Region endpoints are not in increasing order: %d\n",l);
1124 					goto next_line;
1125 					}
1126 				*(endpoints + nreg++) = l;
1127 				j = NULL;
1128 				}
1129 			header = strchr(header,'\n') + 1;
1130 			}
1131 		maregion = (region *)calloc(1,sizeof(region));
1132 		if(maregion ==  NULL) out_of_memory();
1133 		l=strlen(reg_name);
1134 		maregion->name = (char *)malloc(l+1);
1135 		if(maregion->name ==  NULL) out_of_memory();
1136 		strcpy(maregion->name, reg_name);
1137 		for(nreg = 2*tot_reg -1; nreg >= 0; nreg -= 2) {
1138 			segment = (list_segments *)
1139 				malloc(sizeof(list_segments));
1140 			if(segment ==  NULL) out_of_memory();
1141 			segment->fin = endpoints[nreg];
1142 			segment->debut = endpoints[nreg - 1];
1143 			segment->next = maregion->list;
1144 			maregion->list = segment;
1145 			}
1146 		free(endpoints);
1147 		rlist = (list_regions *)malloc(sizeof(list_regions));
1148 		if(rlist ==  NULL) out_of_memory();
1149 		rlist->element = maregion;
1150 		rlist->next = NULL;
1151 		if(deb_rlist == NULL)
1152 			deb_rlist = rlist;
1153 		else	{
1154 			cur_list =  deb_rlist;
1155 			while(cur_list->next != NULL)
1156 				cur_list = cur_list->next;
1157 			cur_list->next = rlist;
1158 			}
1159 		continue;
1160 		}
1161 	else	{
1162 		j=(char *)memccpy(fin_new_header, header, '\n', l_header);
1163 		fin_new_header += (j - fin_new_header);
1164 		}
1165 next_line:
1166 	header = strchr(header,'\n') + 1;
1167 	}
1168 *fin_new_header = 0;
1169 strcpy(old_header, new_header);
1170 free(new_header);
1171 return deb_rlist;
1172 }
1173 
1174 
draw_region_background(SEA_VIEW * view,int f_seq0,int l_seq0)1175 void draw_region_background(SEA_VIEW *view, int f_seq0, int l_seq0)
1176 {
1177 list_segments *segment;
1178 int nb_sites, debut, der_site, h, x, y, w, seqnum, y0;
1179 Fl_Widget *ob = view->DNA_obj;
1180 
1181 if(view->active_region == NULL || view->numb_gc == 1) return;
1182 segment = view->active_region->list;
1183 if(segment == NULL) return;
1184 der_site = view->first_site + view->tot_sites - 1;
1185 if(view->mod_seq == 0) { /* toutes les seqs */
1186 	h = FL_min(view->tot_lines, view->tot_seqs - view->first_seq + 1) *
1187 		view->line_height;
1188 	y0 = view->y_seq - view->line_height + fl_descent();
1189 	f_seq0 = l_seq0 = 0;
1190 	}
1191 else if(view->mod_seq == -1) { /* les seqs selectionnees seulement */
1192 	h = view->line_height;
1193 	y0 = view->y_seq - view->line_height + fl_descent() +
1194 		(f_seq0 + 1 - view->first_seq) * view->line_height;
1195 	}
1196 else	{ /* la seq mod_seq seulement */
1197 	h = view->line_height;
1198 	y0 = view->y_seq - view->line_height + fl_descent() +
1199 		(view->mod_seq - view->first_seq) * view->line_height;
1200 	f_seq0 = l_seq0 = 0;
1201 	}
1202 fl_color(ob->selection_color());
1203 do	{
1204 	if(segment->debut > der_site) break;
1205 	if(segment->fin < view->first_site) continue;
1206 	debut = FL_max(segment->debut, view->first_site);
1207 	nb_sites = FL_min(segment->fin, der_site) - debut + 1;
1208 	x = view->x_seq + (debut - view->first_site) * view->char_width;
1209 	y = y0;
1210 	w = nb_sites * view->char_width;
1211 	for(seqnum = f_seq0; seqnum <= l_seq0; seqnum++) {
1212 		if(view->mod_seq != -1 || view->sel_seqs[seqnum])
1213 			fl_rectf( x, y, w, h);
1214 		y += view->line_height;
1215 		}
1216 	}
1217 while( (segment = segment->next) != NULL );
1218 }
1219 
1220 
create_species_set(SEA_VIEW * view,const char * set_name)1221 const char *create_species_set(SEA_VIEW *view, const char *set_name)
1222 {
1223 int newnumb, i;
1224 if(view->numb_species_sets >= MAX_SPECIES_SETS)
1225 	return "Cannot create more sets";
1226 /* le nom existe-t-il deja? */
1227 for(i=0; i< view->numb_species_sets; i++) {
1228 	if(strcmp(set_name, view->name_species_sets[i]) == 0)
1229 		return "Name already used";
1230 	}
1231 newnumb = view->numb_species_sets + 1;
1232 view->list_species_sets[newnumb-1] = (int *)calloc(view->tot_seqs, sizeof(int));
1233 if(view->list_species_sets[newnumb-1] == NULL)
1234 	return "Not enough memory";
1235 view->name_species_sets[newnumb-1] =
1236 	(char *)calloc(strlen(set_name)+1, sizeof(char));
1237 if(view->name_species_sets[newnumb-1] == NULL)
1238 	return "Not enough memory";
1239 memcpy(view->list_species_sets[newnumb-1], view->sel_seqs,
1240 	view->tot_seqs * sizeof(int) );
1241 strcpy(view->name_species_sets[newnumb-1], set_name);
1242 view->numb_species_sets = newnumb;
1243 return NULL;
1244 }
1245 
1246 
species_menu_callback(Fl_Widget * ob,void * extra)1247 void species_menu_callback(Fl_Widget *ob, void *extra)
1248 {
1249 SEA_VIEW *view;
1250   Fl_Menu_* menu = (Fl_Menu_*)ob;
1251 const char *set_name;
1252 const char *message;
1253 int i, rang, numset, taille;
1254 
1255 view = (SEA_VIEW *)ob->user_data();
1256 int reponse = menu->mvalue() - view->menu_species->get_menu();
1257   taille = view->menu_species->vlength();
1258   rang = view->menu_species->value();
1259 if (reponse == 0) { /* create new set of species */
1260 	if(view->tot_sel_seqs == 0) return;
1261 	set_name = (char *)fl_input("New species set name?", "good seqs");
1262 	if(set_name == NULL) return;
1263 	if( (message = create_species_set(view, set_name) ) != NULL ) {
1264 		fl_alert("%s\n%s", message, set_name);
1265 		return;
1266 		}
1267   view->menu_species->add(set_name, species_menu_callback, NULL, FL_MENU_TOGGLE);
1268   view->menu_species->value(++taille);
1269   view->menu_species->get_menu()->deactivate();
1270   (view->menu_species->get_menu()+1)->activate();
1271 	}
1272 else if(reponse == 1) { /* effacer un set */
1273   Fl_Menu_Item *items = view->menu_species->get_menu();
1274 	items[1].deactivate();
1275 	if(rang == 0) return; /* par securite */
1276 	numset = rang - 1;
1277   view->menu_species->remove(numset);
1278 	items[0].deactivate();
1279 	free(view->list_species_sets[numset]);
1280 	free(view->name_species_sets[numset]);
1281 	memcpy(view->list_species_sets + numset,
1282 		view->list_species_sets + numset + 1,
1283 		(view->numb_species_sets - numset - 1)*sizeof(int *) );
1284 	memcpy(view->name_species_sets + numset,
1285 		view->name_species_sets + numset + 1,
1286 		(view->numb_species_sets - numset - 1)*sizeof(char *) );
1287 	(view->numb_species_sets)--;
1288 	view->tot_sel_seqs = 0;
1289 	memset(view->sel_seqs, 0, view->tot_seqs * sizeof(int));
1290 	view->DNA_obj->redraw();
1291 	}
1292 else	{ /* choix d'un set courant */
1293 	int minvis, maxvis, visible = FALSE, premier = 0;
1294   rang = menu->mvalue() - view->menu_species->vitem(0) + 1;
1295 	memcpy(view->sel_seqs, view->list_species_sets[rang-1],
1296 		view->tot_seqs * sizeof(int) );
1297 	view->tot_sel_seqs = 0;
1298 	minvis = view->first_seq; maxvis = minvis + view->tot_lines - 1;
1299 	for(i=0; i< view->tot_seqs; i++)
1300 		if(view->sel_seqs[i]) {
1301 			++(view->tot_sel_seqs);
1302 			if(!visible) visible = (i+1 >= minvis && i+1 <= maxvis);
1303 			if(premier == 0) premier = i + 1;
1304 			}
1305 	if(premier != 0 && !visible ) {
1306 		int maxi;
1307   		maxi = (int)((Fl_Slider *)view->vertsli)->maximum();
1308 		if(premier > maxi) premier = maxi;
1309 		view->first_seq = premier;
1310 		((Fl_Slider *)view->vertsli)->value(premier);
1311 		}
1312 	view->DNA_obj->redraw();
1313   view->menu_species->value(rang);
1314   (view->menu_species->get_menu()+1)->activate();
1315 	adjust_menu_edit_modes(view);
1316 	}
1317 }
1318 
1319 
vlength_menu(Fl_Menu_ * m,const char * name,const Fl_Menu_Item * init,int clength)1320 vlength_menu::vlength_menu(Fl_Menu_ *m, const char *name, const Fl_Menu_Item *init, int clength)
1321 {
1322   menu_ = m;
1323   offset = clength;
1324   vlen = 0;
1325   val = 0;
1326   items = (Fl_Menu_Item*)malloc((offset+1)*sizeof(Fl_Menu_Item));
1327   memcpy(items, init, offset*sizeof(Fl_Menu_Item));
1328   memset(items + offset, 0, sizeof(Fl_Menu_Item));
1329   rank = menu_->add(name, 0, NULL, items, FL_SUBMENU_POINTER);
1330 }
1331 
add(const char * txt,Fl_Callback * cb,void * data,int flags)1332 void vlength_menu::add(const char *txt, Fl_Callback *cb, void *data, int flags)
1333 {
1334   items = (Fl_Menu_Item*)realloc(items, (offset + vlen + 2)*sizeof(Fl_Menu_Item));
1335   ((Fl_Menu_Item*)(menu_->menu() + rank))->user_data( items );
1336   memset(items + offset + vlen, 0, 2*sizeof(Fl_Menu_Item));
1337   (items + offset + vlen)->label( strdup(txt) );
1338   (items + offset + vlen)->callback(cb, data);
1339   (items + offset + vlen)->flags = flags;
1340   vlen++;
1341 }
1342 
remove(int rank)1343 void vlength_menu::remove(int rank)
1344 {
1345   if (rank >= vlen) return;
1346   free( (void*)vitem(rank)->label() );
1347   memmove(items + offset + rank, items + offset + rank + 1, (vlen - rank)*sizeof(Fl_Menu_Item));
1348   vlen--;
1349 }
1350 
1351 
find_item(const char * txt)1352 Fl_Menu_Item* vlength_menu::find_item(const char* txt)
1353 {
1354   for (int i = 0; i < vlen; i++) {
1355     if (strcmp(vitem(i)->label(), txt) == 0) return vitem(i);
1356     }
1357   return NULL;
1358 }
1359 
value(int v)1360 void vlength_menu::value(int v)
1361 {
1362   if (v) vitem(v - 1)->setonly();
1363   else if (val) vitem(val - 1)->clear();
1364   val = v;
1365 }
1366 
vclear()1367 void vlength_menu::vclear()
1368 {
1369   for (int i = 0; i < vlen; i++) {
1370     free( (void*)(items+offset+i)->label() );
1371   }
1372   vlen = 0;
1373   val = 0;
1374   memset(items + offset, 0, sizeof(Fl_Menu_Item));
1375 }
1376 
~vlength_menu()1377 vlength_menu::~vlength_menu()
1378 {
1379   for (int i = 0; i < vlen; i++) {
1380     free( (void*)(items+offset+i)->label() );
1381     }
1382   free(items);
1383   ((Fl_Menu_Item*)(menu_->menu() + rank))->user_data( NULL );
1384   ((Fl_Menu_Item*)(menu_->menu() + rank))->flags = 0;
1385 }
1386 
parse_species_sets_from_header(char * header,int ** list_species_sets,char ** name_species_sets,int totseqs)1387 int parse_species_sets_from_header(char *header, int **list_species_sets,
1388 	char **name_species_sets, int totseqs)
1389 /* parse the species sets information from header lines
1390 and remove it from them
1391 */
1392 {
1393 char *p, set_name[200], aux[200], separ[5], *i, *j, *new_header,
1394 	*fin_new_header, *old_header;
1395 int numset, tot_spec, l, l_header, num;
1396 if(header == NULL) return 0;
1397 old_header = header;
1398 l_header=strlen(header);
1399 if( (new_header = (char *)malloc(l_header+1)) == NULL) out_of_memory();
1400 fin_new_header = new_header;
1401 *new_header = 0;
1402 numset = -1;
1403 while (*header!= 0) {
1404 	if(strncmp(header,";;@ of species =", 16) == 0) {
1405 		numset++;
1406 		p=strchr(header,'=') + 1;
1407 		while(*p == ' ') p++;
1408 		sscanf(p,"%d",&tot_spec);
1409 		list_species_sets[numset] = (int *)calloc(totseqs, sizeof(int));
1410 		if(list_species_sets[numset]==NULL) out_of_memory();
1411 		while(*p != ' ' && *p != '\n') p++;
1412 		while(*p == ' ') p++;
1413 		if( *p == '\n') { /* no set name in file */
1414 			strcpy(set_name, "species set");
1415 			header = p;
1416 			}
1417 		else	{
1418 			header = strchr(p,'\n');
1419 			memcpy(set_name, p, header - p);
1420 			l = header - p;
1421 			set_name[l] = 0;
1422 			while(set_name[--l]==' ') set_name[l] = 0;
1423 			}
1424 		l = (int) strlen(set_name);
1425 		name_species_sets[numset] = (char *)malloc(l+1);
1426 		if(name_species_sets[numset] == NULL) out_of_memory();
1427 		memcpy(name_species_sets[numset], set_name, l+1);
1428 		header++;
1429 		num = 0;
1430 		while(num < tot_spec) {
1431 			j = (char *)memccpy(aux, header, '\n', sizeof(aux));
1432 			if(j == NULL) goto next_line;
1433 			*(j - 1) = 0;
1434 			strcpy(separ,";, "); j=aux;
1435 			while( (i=strtok(j,separ)) != NULL) {
1436 				sscanf(i,"%d",&l);
1437 				if( l>= 1 && l <= totseqs)
1438 					list_species_sets[numset][l-1] = 1;
1439 				num++;
1440 				j = NULL;
1441 				}
1442 			header = strchr(header,'\n') + 1;
1443 			}
1444 		continue;
1445 		}
1446 	else	{
1447 		j=(char *)memccpy(fin_new_header, header, '\n', l_header);
1448 		fin_new_header += (j - fin_new_header);
1449 		}
1450 next_line:
1451 	header = strchr(header,'\n') + 1;
1452 	}
1453 *fin_new_header = 0;
1454 strcpy(old_header, new_header);
1455 free(new_header);
1456 return numset + 1;
1457 }
1458