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