1 #include "seaview.h"
2 #include <ctype.h>
3 #include <FL/Fl_Multiline_Input.H>
4 
5 #define ISSEQCHAR(c) (isalpha(c) || c=='-' || c=='*' )
6 
7 typedef struct {
8 	SEA_VIEW *view;
9 	Fl_Input *seq_name_field;
10 	Fl_Input *seq_field;
11 	} view_name_struct;
12 
13 /* included prototypes */
14 void clear_callback(Fl_Widget *ob, void *data);
15 void refresh_callback(Fl_Widget *ob, void *data);
16 void remove_gaps_callback(Fl_Widget *ob, void *data);
17 void remove_numbers_callback(Fl_Widget *ob, void *data);
18 void to_upcase_callback(Fl_Widget *ob, void *data);
19 void load_seq_callback(void *data);
20 void load_seq_dialog(SEA_VIEW *view);
21 char complement_base(char old);
22 void edit_comments_dialog(SEA_VIEW *view);
23 void edit_sequence_dialog(SEA_VIEW *view);
24 int load_sequence_for_edit(struct editseq *editdata);
25 char *renumber_seq(char *seq);
26 void renumber_callback(Fl_Widget *ob, void *data);
27 void edit_sequence_callback(struct editseq *editdata);
28 void update_comments_callback(void *data);
29 int load_comments(SEA_VIEW *view, Fl_Input *input, Fl_Widget *name);
30 char *cre_consensus(SEA_VIEW *view, char *newname);
31 Fl_Widget *cre_adjusted_button(int x, int y, int *w, int h,
32 	const char *label);
33 
34 
35 /* external prototypes */
36 extern void hide_window_callback(Fl_Widget *ob, void *data);
37 extern void allonge_seqs(char **seq, int totseqs, int maxlen, int *eachlength,
38 	int tot_comment_lines, char **comment_line, char **pregion_line);
39 extern int compute_wid_names(SEA_VIEW *view, int totseqs);
40 extern int compute_size_params(SEA_VIEW *view, int force_recompute);
41 extern int calc_max_seq_length(int seq_length, int tot_seqs);
42 
43 
clear_callback(Fl_Widget * ob,void * data)44 void clear_callback(Fl_Widget *ob, void *data)
45 {
46 Fl_Input *seq_input, *seq_name_input;
47 seq_name_input = ((view_name_struct *)data)->seq_name_field;
48 seq_input = ((view_name_struct *)data)->seq_field;
49 seq_input->value("");
50 if(seq_name_input != NULL) seq_name_input->value("");
51 }
52 
53 
refresh_callback(Fl_Widget * ob,void * data)54 void refresh_callback(Fl_Widget *ob, void *data)
55 {
56 Fl_Input *seq_input;
57 seq_input = ((view_name_struct *)data)->seq_field;
58 seq_input->redraw();
59 }
60 
61 
remove_gaps_callback(Fl_Widget * ob,void * data)62 void remove_gaps_callback(Fl_Widget *ob, void *data)
63 {
64 Fl_Input *seq_input;
65 char *old_seq, *new_seq, *p, *q;
66 size_t lseq;
67 
68 seq_input = (Fl_Input *)data;
69 old_seq = (char *)seq_input->value();
70 lseq = strlen(old_seq);
71 new_seq = (char *)malloc(lseq+1);
72 if(new_seq == NULL) return;
73 p = old_seq; q = new_seq;
74 while(*p != 0) {
75 	if(*p != '-' ) *(q++) = *p;
76 	p++;
77 	}
78 *q = 0;
79 seq_input->value(new_seq);
80 }
81 
82 
remove_numbers_callback(Fl_Widget * ob,void * data)83 void remove_numbers_callback(Fl_Widget *ob, void *data)
84 {
85 Fl_Input *seq_input;
86 char *old_seq, *new_seq, *p, *q;
87 size_t lseq;
88 
89 seq_input = (Fl_Input *)data;
90 old_seq = (char *)seq_input->value();
91 lseq = strlen(old_seq);
92 new_seq = (char *)malloc(lseq+1);
93 if(new_seq == NULL) return;
94 p = old_seq; q = new_seq;
95 while(*p != 0) {
96 	if( ! isdigit(*p) ) *(q++) = *p;
97 	p++;
98 	}
99 *q = 0;
100 seq_input->value(new_seq);
101 }
102 
103 
to_upcase_callback(Fl_Widget * ob,void * data)104 void to_upcase_callback(Fl_Widget *ob, void *data)
105 {
106 Fl_Input *seq_input = (Fl_Input *)data;
107 char *old_seq = (char *)seq_input->value();
108 int lseq = strlen(old_seq);
109 char *new_seq = (char *)malloc(lseq+1);
110 if(new_seq == NULL) return;
111 char *p = old_seq;
112 char *q = new_seq - 1;
113 do *(++q) = toupper(*(p++)); while(*q != 0);
114 seq_input->value(new_seq);
115 }
116 
117 
load_seq_callback(void * data)118 void load_seq_callback(void *data)
119 {
120 Fl_Input *seq_name_input, *seq_input;
121 SEA_VIEW *view;
122 char *name, *newseq, *tmp, *p, *q;
123 int lenseq;
124 
125 seq_name_input = ((view_name_struct *)data)->seq_name_field;
126 view = ((view_name_struct *)data)->view;
127 seq_input = ((view_name_struct *)data)->seq_field;
128 name = (char *)seq_name_input->value();
129 if(strlen(name) == 0) {
130 	fl_alert(
131 		"`Seq. name' field is empty\nPlease enter a sequence name");
132 	return;
133 	}
134 tmp = (char *)seq_input->value();
135 lenseq = (int)strlen(tmp);
136 newseq = (char *)malloc(lenseq+1);
137 if(newseq == NULL) {
138 	fl_alert("Not enough memory");
139 	return;
140 	}
141 p = tmp; q = newseq; lenseq = 0;
142 while(*p != 0) {
143 	if(*p != ' ' && *p != '\n' && *p != '\t') {
144 		if(view->allow_lower) *(q++) = (*p);
145 		else *(q++) = toupper(*p);
146 		lenseq++;
147 		}
148 	p++;
149 	}
150 *q = 0;
151 add_seq_to_align(view, name, newseq, lenseq);
152 free(newseq);
153 }
154 
155 
cre_adjusted_button(int x,int y,int * w,int h,const char * label)156 Fl_Widget *cre_adjusted_button(int x, int y, int *w, int h,
157 	const char *label)
158 {
159 Fl_Button *obj;
160 const int lsize = FL_NORMAL_SIZE;
161 fl_font(FL_HELVETICA, lsize);
162 // *w = (int) ( fl_width(label) + 2 * fl_width("R") + 0.5 );
163 *w = (int) ( fl_width(label) + 10 + 0.5 );
164 obj = new Fl_Button(x, y, *w, h, label);
165 obj->labelsize(lsize);
166 obj->labelfont(FL_HELVETICA);
167 return (Fl_Widget *)obj;
168 }
169 
170 
load_seq_dialog(SEA_VIEW * view)171 void load_seq_dialog(SEA_VIEW *view)
172 {
173   Fl_Window *load_form;
174   Fl_Input *seq_input, *seq_name_input;
175   view_name_struct view_name;
176   Fl_Widget *cancel, *add, *obj;
177   int fin, width;
178   load_form = new Fl_Window(490,530);
179   load_form->box(FL_FLAT_BOX);
180   load_form->label("Sequence Loading");
181 
182   int curr_y = 5;
183   fin = 5;
184   Fl_Group *top = new Fl_Group(fin,curr_y,load_form->w() - 2 * fin, 25);
185   static char label[] = "Seq. name:";
186   fl_font(FL_HELVETICA, FL_NORMAL_SIZE);
187   width = (int)fl_width(label) + 4 * 2;
188   Fl_Box *name_box = new Fl_Box(FL_UP_BOX,
189 	  fin, top->y(), width, top->h(), label);
190   name_box->labelsize(FL_NORMAL_SIZE);
191   name_box->box(FL_NO_BOX);
192   fin += width + 5;
193 
194   seq_name_input = new Fl_Input(fin,top->y(),100,top->h(),"");
195   seq_name_input->type(FL_NORMAL_INPUT);
196   fin += seq_name_input->w() + 5;
197 
198   add = cre_adjusted_button(fin,top->y(),&width,top->h(),
199 	  "Add to alignment");
200   fin += width + 5;
201 
202   cancel = cre_adjusted_button(fin,top->y(),&width,top->h(),
203 	  "Cancel");
204   ((Fl_Button *)cancel)->shortcut(FL_COMMAND | 'w');
205   fin += width;
206 
207   top->resizable(NULL);
208   top->size(fin - top->x(), top->h());
209   top->end();
210 
211   curr_y += top->h() + 15;
212   seq_input = new Fl_Input(top->x(), curr_y, load_form->w() - 2 * top->x(), 450,
213 #if defined(__APPLE__)
214 	    ""
215 #elif defined(WIN32)
216 	    "Type sequence or paste it with CRTL-V in panel below"
217 #else
218 	    "Type or paste sequence with middle mouse button in panel below"
219 #endif
220 	    );
221   seq_input->type(FL_MULTILINE_INPUT);
222   seq_input->align(FL_ALIGN_TOP);
223   seq_input->textfont(FL_COURIER);
224   seq_input->textsize(12);
225   fin = top->x();
226   curr_y += seq_input->h() + 5;
227   Fl_Group *bottom = new Fl_Group(fin, curr_y, top->w(), top->h() );
228   obj = cre_adjusted_button(fin, curr_y, &width, bottom->h(), "Refresh");
229   obj->callback(refresh_callback, &view_name);
230   fin += width + 5;
231 
232   obj = cre_adjusted_button(fin, curr_y, &width, bottom->h(), "Clear");
233   obj->callback(clear_callback, &view_name);
234   fin += width + 5;
235 
236   obj = cre_adjusted_button(fin, curr_y, &width, bottom->h(),
237 	"Remove gaps");
238   obj->callback(remove_gaps_callback, seq_input);
239   fin += width + 5;
240 
241   obj = cre_adjusted_button(fin,curr_y,&width,bottom->h(),
242 	"Remove numbers");
243   obj->callback(remove_numbers_callback, seq_input);
244   fin += width + 5;
245 
246   obj = cre_adjusted_button(fin, curr_y, &width, bottom->h(),
247 	"to UPPER");
248   obj->callback(to_upcase_callback, seq_input);
249   fin += width;
250 
251   bottom->resizable(NULL);
252   bottom->size(fin - bottom->x(), bottom->h());
253   bottom->end();
254 
255   load_form->resizable(seq_input);
256 
257   view_name.seq_name_field = seq_name_input;
258   view_name.seq_field = seq_input;
259   load_form->end();
260   load_form->position((Fl::w() - load_form->w())/2, (Fl::h() - load_form->h())/2);
261   seq_name_input->value("");
262   seq_input->value("");
263   view_name.view = view;
264 #if defined(__APPLE__)
265 	seq_input->value("\n\n\n\n\n\nType sequence or paste it with cmd-V\n\n\n");
266 	seq_input->position(seq_input->size(), 0);
267 #endif
268   seq_input->take_focus();
269   load_form->show();
270 #ifndef MICRO
271   load_form->hotspot(load_form);
272 #endif
273   while (TRUE) {
274     obj = Fl::readqueue();
275     if (!obj) Fl::wait();
276     else if(obj == add || obj == cancel || obj == load_form) {
277       if (obj == add) {
278 	load_seq_callback(&view_name);
279       }
280       delete load_form;
281       break;
282     }
283   }
284 }
285 
286 
add_seq_to_align(SEA_VIEW * view,char * newname,char * newseq,int lenseq,bool no_gui)287 int add_seq_to_align(SEA_VIEW *view, char *newname, char *newseq, int lenseq, bool no_gui)
288 /* returns 0 if failed or the rank of newly added sequence
289 */
290 {
291 int num, *newsel, numset;
292 char **newcol;
293 static char defname[]="newfile";
294 char **new_s, **new_n, **new_c;
295 
296 if(view->tot_seqs == 0) {
297 	view->max_seq_length = lenseq;//the true value is set later in init_dna_scroller
298 	}
299 num = view->tot_seqs + 1;
300 if(view->sequence != NULL) new_s = (char **)realloc(view->sequence, num * sizeof(char *));
301 else new_s = (char **)malloc(num * sizeof(char *));
302 if(new_s != NULL) view->sequence = new_s;
303 if(view->comments != NULL) {
304 	new_c = (char **)realloc(view->comments, num * sizeof(char *));
305 	if(new_c != NULL) view->comments = new_c;
306 	else goto nomem;
307 	}
308 else view->comments = (char **)calloc(num, sizeof(char *));
309 if(view->seqname != NULL) new_n = (char **)realloc(view->seqname, num * sizeof(char *));
310 else new_n = (char **)malloc(num * sizeof(char *));
311 if(new_n != NULL) view->seqname = new_n;
312 
313 if(new_s == NULL || new_n == NULL) goto nomem;
314 if(lenseq > view->max_seq_length) {
315   view->max_seq_length = calc_max_seq_length(lenseq, view->tot_seqs);
316   allonge_seqs(view->sequence, view->tot_seqs, view->max_seq_length, view->each_length,
317 	       view->tot_comment_lines, view->comment_line, &view->region_line);
318   if (!no_gui) {
319     for (int i = 0; i < view->tot_seqs; i++) free(view->col_rank[i]);
320     free(view->col_rank);
321     view->col_rank = prepcolranks(view->sequence, view->tot_seqs, view->max_seq_length, view->each_length,
322 		 ( view->protein ? get_color_for_aa : get_color_for_base ),
323 		 view->numb_gc, view->allow_lower);
324     }
325   }
326 if( (view->seqname[num-1] = (char *)malloc(strlen(newname)+1)) == NULL)
327 	goto nomem;
328 strcpy(view->seqname[num-1], newname);
329 if(view->comments != NULL) {
330 	view->comments[num-1] = NULL;
331 	}
332 if( (view->sequence[num-1] = (char *)malloc(view->max_seq_length + 1)) == NULL)
333 	goto nomem;
334 memcpy(view->sequence[num-1], newseq, lenseq+1);
335 if(view->masename == NULL && !no_gui) {
336 	newname = (char *) fl_input("Name of the new alignment?", "");
337 	if(newname == NULL) newname = defname;
338 	}
339 else newname = view->masename;
340 if (view->tot_seqs == 0 && !no_gui) {
341 	init_dna_scroller(view, 1, newname, is_a_protein_seq(newseq), NULL);
342 	set_seaview_modified(view, TRUE);
343 	view->DNA_obj->redraw();
344 	((Fl_Menu_Item*)view->menu_file + SAVE_AS)->activate();
345 	return 1;
346 	}
347 if( (newsel = (int *)malloc(num*sizeof(int))) == NULL) goto nomem;
348 memcpy(newsel, view->each_length, (num-1)*sizeof(int) );
349 free(view->each_length);
350 view->each_length = newsel;
351 view->each_length[num-1] = lenseq;
352 if (lenseq > view->seq_length && !no_gui) {
353 	double x; int l;
354 	view->seq_length = lenseq;
355 	x = ( (double) view->tot_sites ) / ( view->seq_length + 3 );
356 	if(x>1) x=1;
357 	((Fl_Slider*)view->horsli)->slider_size(x);
358 	l = view->seq_length - view->tot_sites+3;
359 	if(l<1) l=1;
360 	((Fl_Slider*)view->horsli)->bounds(1,l);
361 	}
362 if(view->numb_dnacolors > 1 && !no_gui) {
363 	if( (newcol = (char **)malloc(num*sizeof(char *))) == NULL)
364 		goto nomem;
365 	memcpy(newcol, view->col_rank, (num-1)*sizeof(char *) );
366   char **tmpcol = prepcolranks(view->sequence+num-1, 1,
367 		view->max_seq_length,
368 		view->each_length+num-1,
369 		( view->protein ? get_color_for_aa : get_color_for_base ),
370 		view->numb_gc, view->allow_lower);
371 	if(tmpcol == NULL) out_of_memory();
372   newcol[num-1] = tmpcol[0];
373   free(tmpcol);
374 	free(view->col_rank);
375 	view->col_rank = newcol;
376 	}
377 if( (newsel = (int *)malloc(num*sizeof(int))) == NULL) goto nomem;
378   if (!no_gui) {
379     memcpy(newsel, view->sel_seqs, (num-1)*sizeof(int) );
380     free(view->sel_seqs);
381     view->sel_seqs = newsel;
382     view->sel_seqs[num-1] = FALSE;
383   }
384 for(numset = 0; numset < view->numb_species_sets; numset++) {
385 	if( (newsel = (int *)malloc(num*sizeof(int))) == NULL) goto nomem;
386 	memcpy(newsel, view->list_species_sets[numset], (num-1)*sizeof(int) );
387 	free(view->list_species_sets[numset]);
388 	view->list_species_sets[numset] = newsel;
389 	view->list_species_sets[numset][num-1] = FALSE;
390 	}
391 view->tot_seqs = num;
392 view->cursor_seq = num;
393 view->cursor_site = 1;
394 view->first_site = 1;
395   if (no_gui) return num;
396 if(strlen(view->seqname[num - 1]) > (unsigned)view->wid_names) {
397   view->wid_names = compute_wid_names(view, num);
398   compute_size_params(view, TRUE);
399 }
400 set_seaview_modified(view, TRUE);
401 ((Fl_Slider*)view->horsli)->value(1);
402 set_tot_lines(view, view->tot_lines);
403 view->first_seq = FL_max(num - view->tot_lines + 1, 1);
404 ((Fl_Slider*)view->vertsli)->value(view->first_seq);
405 view->DNA_obj->redraw();
406 view->vertsli->redraw();
407 view->horsli->redraw();
408 return num;
409 nomem:
410   void (*alert)(const char *,...) = no_gui ? Fl::fatal : fl_alert;
411   alert("Not enough memory\nto create the new sequence %s", newname);
412 return 0;
413 }
414 
415 
complement_base(char old)416 char complement_base(char old)
417 {
418 static char bases[] = "ACGTURYMWSKVHDBacgturymwskvhdb";
419 static char complement[] = "TGCAAYRKWSMBDHVtgcaayrkwsmbdhv";
420 char *p;
421 if( (p = strchr(bases, old)) != NULL )
422 	return complement[ p - bases ];
423 else
424 	return old;
425 }
426 
427 
edit_comments_dialog(SEA_VIEW * view)428 void edit_comments_dialog(SEA_VIEW *view)
429 {
430   Fl_Window *comments_form;
431   Fl_Input *comments_input;
432   Fl_Widget *comments_name;
433   view_name_struct comments_data;
434   Fl_Widget *o, *cancel, *apply;
435 
436   Fl_Widget *obj;
437   int fin, width;
438   comments_form = new Fl_Window(490,530);
439   comments_form->label("Comments Editing");
440   comments_form->box(FL_FLAT_BOX);
441 
442   Fl_Group *top_group = new Fl_Group(5,5,comments_form->w() - 10, 25);
443   fin = 5;
444   apply = cre_adjusted_button(fin,5,&width,25, "Apply");
445   fin += width + 5;
446 
447   cancel = cre_adjusted_button(fin,5,&width,25,"Cancel");
448   ((Fl_Button *)cancel)->shortcut(FL_COMMAND | 'w');
449   fin += width + 5;
450 
451   obj = cre_adjusted_button(fin,5,&width,25,"Refresh");
452   obj->callback(refresh_callback, &comments_data);
453   fin += width + 5;
454 
455   comments_name = new Fl_Box(FL_DOWN_BOX, fin, 5,
456 	  top_group->x() +top_group->w() - fin, 25, "");
457   comments_name->align(FL_ALIGN_LEFT | FL_ALIGN_CLIP | FL_ALIGN_INSIDE);
458   comments_name->labelfont(FL_COURIER);
459   comments_name->labelsize(FL_NORMAL_SIZE);
460 
461   top_group->resizable(comments_name);
462   top_group->end();
463 
464   comments_input = new Fl_Input(5,35,top_group->w(),
465 		  comments_form->h() - 5 - 35, "");
466   comments_input->type(FL_MULTILINE_INPUT);
467   comments_input->textfont(FL_COURIER);
468   comments_input->textsize(12);
469   comments_data.seq_field = comments_input;
470   comments_form->resizable(comments_input);
471   comments_form->end();
472   comments_form->position( (Fl::w() - comments_form->w())/2,
473 	  (Fl::h() - comments_form->h())/2 );
474   comments_data.view = view;
475   if(load_comments(view, comments_input, comments_name)) {
476 	delete comments_form;
477 	fl_alert("Not enough memory");
478 	return;
479 	}
480   comments_input->take_focus();
481   comments_form->show();
482 #ifndef MICRO
483 	comments_form->hotspot(comments_form);
484 #endif
485   while (TRUE) {
486     o = Fl::readqueue();
487     if (!o) Fl::wait();
488     else if (o == apply || o == cancel || o == comments_form) {
489       if (o == apply) {
490 	update_comments_callback(&comments_data);
491 	}
492       delete comments_form;
493       break;
494       }
495     }
496 }
497 
498 
499 struct editseq {
500 	Fl_Multiline_Input *input;
501 	Fl_Widget *name;
502 	SEA_VIEW *view;
503 	int seqnum;
504 	};
505 
506 
edit_sequence_dialog(SEA_VIEW * view)507 void edit_sequence_dialog(SEA_VIEW *view)
508 {
509 struct editseq *editdata;
510 int fin, width, num;
511 Fl_Window *form;
512 Fl_Widget *obj, *apply, *cancel;
513 
514 for(num = 0; num <view->tot_seqs; num++) { if(view->sel_seqs[num]) break; }
515 if(num >= view->tot_seqs) return;
516 editdata = (struct editseq *)malloc(sizeof(struct editseq));
517 if(editdata == NULL) return;
518 editdata->seqnum = num;
519 editdata->view = view;
520 form = new Fl_Window(770,530);
521 form->label("Sequence Editing");
522 form->box(FL_FLAT_BOX);
523 form->user_data(editdata);
524 
525 Fl_Group *top_group = new Fl_Group(5,5,form->w() - 10, 25);
526 fin = 5;
527 apply = cre_adjusted_button(fin,5,&width,25, "Apply");
528 fin += width + 5;
529 
530 obj = cre_adjusted_button(fin,5,&width,25,"Renumber");
531 obj->callback(renumber_callback, 0);
532 fin += width + 5;
533 
534 cancel = cre_adjusted_button(fin,5,&width,25,"Cancel");
535 ((Fl_Button *)cancel)->shortcut(FL_COMMAND | 'w');
536 fin += width + 5;
537 
538 editdata->name = new Fl_Box(FL_DOWN_BOX, fin, 5,
539 	top_group->x() +top_group->w() - fin, 25, "");
540 editdata->name->align(FL_ALIGN_LEFT | FL_ALIGN_CLIP | FL_ALIGN_INSIDE);
541 editdata->name->labelfont(FL_COURIER);
542 editdata->name->labelsize(FL_NORMAL_SIZE);
543 
544 top_group->resizable(editdata->name);
545 top_group->end();
546 
547 editdata->input = new Fl_Multiline_Input(5,35,top_group->w(),
548 		form->h() - 5 - 35, "");
549 editdata->input->type(FL_MULTILINE_INPUT);
550 editdata->input->textfont(FL_COURIER);
551 editdata->input->textsize(12);
552 form->resizable(editdata->input);
553 form->end();
554 form->position( (Fl::w() - form->w())/2,
555 		(Fl::h() - form->h())/2 );
556 
557 if(load_sequence_for_edit(editdata)) {
558   free(editdata);
559 	delete form;
560 	fl_alert("Not enough memory");
561 	return;
562 	}
563 form->show();
564 #ifndef MICRO
565 form->hotspot(form);
566 #endif
567 editdata->input->take_focus();
568   while (TRUE) {
569     obj = Fl::readqueue();
570     if (!obj) Fl::wait();
571     else if(obj == apply || obj == cancel || obj == form) {
572       if (obj == apply) {
573 	edit_sequence_callback(editdata);
574       }
575       free(editdata);
576       delete form;
577       break;
578     }
579   }
580 }
581 
582 
load_sequence_for_edit(struct editseq * editdata)583 int load_sequence_for_edit(struct editseq *editdata)
584 {
585 char *temp;
586 
587 editdata->name->label(editdata->view->seqname[editdata->seqnum]);
588 editdata->name->redraw();
589 
590 temp = renumber_seq(editdata->view->sequence[editdata->seqnum]);
591 if(temp == NULL) return TRUE;
592 editdata->input->value(temp);
593 free(temp);
594 editdata->input->position(0);
595 return FALSE;
596 }
597 
598 
renumber_seq(char * seq)599 char *renumber_seq(char *seq)
600 {
601 int l, nl, pos;
602 char *p, *q, *temp;
603 const int w = 100;
604 
605 p = seq - 1;
606 l = 0;
607 while(*(++p) != 0) {
608 	if(ISSEQCHAR(*p)) l++;
609 	}
610 nl = l / w + 2;
611 temp = (char *)malloc(l + 7 * nl + 100);
612 if(temp == NULL) return NULL;
613 p = seq - 1;
614 q = temp;
615 pos = 0;
616 while(*(++p) != 0) {
617 	if( ! ISSEQCHAR(*p)) continue;
618 	*q++ = *p; pos++;
619 	if(pos % w == 0) {
620 		sprintf(q, "%6d\n", pos);
621 		q += strlen(q);
622 		}
623 	}
624 strcpy(q, "\n");
625 return temp;
626 }
627 
628 
renumber_callback(Fl_Widget * ob,void * data)629 void renumber_callback(Fl_Widget *ob, void *data)
630 {
631 char *temp;
632 struct editseq *editdata = (struct editseq *)ob->window()->user_data();
633 
634 temp = renumber_seq((char *)editdata->input->value());
635 if(temp == NULL) return;
636 editdata->input->value(temp);
637 free(temp);
638 }
639 
640 
edit_sequence_callback(struct editseq * editdata)641 void edit_sequence_callback(struct editseq *editdata)
642 {
643 char *p, *newseq, *q, **newcolseq;
644 SEA_VIEW *view;
645 int num, l;
646 
647 view = editdata->view;
648 num = editdata->seqnum;
649 
650 l = strlen( editdata->input->value() );
651 newseq = (char *)malloc(l + 1);
652 if(newseq == NULL) return;
653 q = newseq;
654 p = (char *)editdata->input->value() - 1;
655 while(*(++p) !=  0) {
656 	if( ! ISSEQCHAR(*p) ) continue;
657 	*(q++) = *p;
658 	}
659 *q = 0;
660 l = strlen(newseq);
661   if (l > view->max_seq_length) {
662     view->max_seq_length = calc_max_seq_length(l, view->tot_seqs);
663     allonge_seqs(view->sequence, view->tot_seqs, view->max_seq_length, view->each_length,
664 		 view->tot_comment_lines, view->comment_line, &view->region_line);
665     for (int i = 0; i < view->tot_seqs; i++) free(view->col_rank[i]);
666     free(view->col_rank);
667     view->col_rank = prepcolranks(view->sequence, view->tot_seqs, view->max_seq_length, view->each_length,
668 				  ( view->protein ? get_color_for_aa : get_color_for_base ),
669 				  view->numb_gc, view->allow_lower);
670   }
671 if(view->numb_gc > 1) {
672 	newcolseq = prepcolranks(&newseq, 1,
673 		view->max_seq_length, &l,
674 		( view->protein ? get_color_for_aa : get_color_for_base ),
675 		view->numb_gc, view->allow_lower);
676 	if(newcolseq == NULL) return;
677 	free(view->col_rank[num]);
678 	view->col_rank[num] = newcolseq[0];
679 	free(newcolseq);
680 	}
681 strcpy(view->sequence[num], newseq); free(newseq);
682 view->each_length[num] = l;
683 set_seaview_modified(view, TRUE);
684 if(l > view->seq_length) {
685 	double x;
686 	view->seq_length = l;
687 	x = ( (double) view->tot_sites ) / ( view->seq_length + 3 );
688 	if(x>1) x=1;
689 	((Fl_Slider*)view->horsli)->slider_size(x);
690 	l = view->seq_length - view->tot_sites+3;
691 	if(l<1) l=1;
692 	((Fl_Slider*)view->horsli)->bounds(1,l);
693 	}
694 else view->mod_seq = num;
695 view->DNA_obj->redraw();
696 }
697 
698 
update_comments_callback(void * data)699 void update_comments_callback(void *data)
700 {
701 Fl_Input *comments_input;
702 SEA_VIEW *view;
703 int num, l, num_l;
704 char *temp, *p, *q, *r;
705 
706 view = ((view_name_struct *)data)->view;
707 if(view->comments == NULL) {
708 	view->comments = (char **)calloc(view->tot_seqs , sizeof(char *));
709 	if(view->comments == NULL) return;
710 	}
711 comments_input = ((view_name_struct *)data)->seq_field;
712 num = comments_input->argument();
713 num_l = 0;
714 p = (char *)comments_input->value(); l =strlen(p);
715 q = p;
716 while( (q = strchr(q, '\n')) != NULL) {
717 	q++; num_l++;
718 	}
719 if(p[l - 1] != '\n') num_l++;
720 temp = (char *)malloc(l + num_l + 1);
721 if(temp == NULL) {
722 	fl_alert("Not enough memory");
723 	return;
724 	}
725 r = temp;
726 do	{
727 	q = strchr(p, '\n'); if(q == NULL) q = strchr(p, 0) - 1;
728 	*(r++) = ';';
729 	memcpy(r, p, q - p + 1); r += q - p + 1;
730 	p = q + 1;
731 	}
732 while( *p != 0);
733 if( *(r - 1) != '\n') *(r++) = '\n';
734 *r = 0;
735 if(view->comments[num] != NULL) free(view->comments[num]);
736 view->comments[num] = temp;
737 set_seaview_modified(view, TRUE);
738 }
739 
740 
load_comments(SEA_VIEW * view,Fl_Input * input,Fl_Widget * name)741 int load_comments(SEA_VIEW *view, Fl_Input *input, Fl_Widget *name)
742 {
743 int num;
744 char *temp, *p, *q, *r;
745 
746 for(num = 0; num <view->tot_seqs; num++)
747 	if(view->sel_seqs[num]) break;
748 input->argument( num);
749 name->label(view->seqname[num]);
750 name->redraw();
751 if( view->comments == NULL || view->comments[num] == NULL) {
752 	input->value("");
753 	return FALSE;
754 	}
755 temp = (char *)malloc(strlen(view->comments[num]) + 1);
756 if( temp == NULL) return TRUE;
757 r = temp; p = view->comments[num];
758 do	{
759 	q = strchr(p, '\n');
760 	memcpy(r, p + 1, q - p); r += q - p;
761 	p = q + 1;
762 	}
763 while( *p != 0);
764 *r = 0;
765 input->value(temp);
766 free(temp);
767 input->position(0);
768 return FALSE;
769 }
770 
771 static int *sort_f_transmit;
772 
sort_f(const void * v1,const void * v2)773 static int sort_f(const void *v1, const void *v2) {
774   int i1 = *(int*)v1;
775   int i2 = *(int*)v2;
776   return sort_f_transmit[i2] - sort_f_transmit[i1];
777 }
778 
calc_iupac_consensus(int * freqs,float minval)779 char calc_iupac_consensus(int *freqs, float minval) {
780   // order for freqs[1-16]: ACGTUMRWSYKVHDBN
781   // code for nucleotide sets: 4 bits representing A,C,G,T=U
782   // then coded_set[i-1] is the integer value of the set of count freq[i]
783   static int coded_set[16] = {1,2,4,8,8,3,5,9,6,10,12,7,11,13,14,15};
784   static char set_to_iupac[18] = {".ACMGRSVTWYHKDBN"};
785   int sorted_freqs[16];
786   freqs[16] += freqs[0]; // add count of non-IUPAC characters to count of N
787   for (int i = 0; i < 16; i++) sorted_freqs[i] = i+1;
788   sort_f_transmit = freqs;
789   // sort residue counts in decreasing order
790   qsort(sorted_freqs, 16, sizeof(int), sort_f);
791   int cumul = 0;
792   int set = 0;
793   // walk through residue counts in decreasing order until cumulated counts exceeds minval
794   for (int rank = 0; rank < 16; rank++) {
795     int residue = sorted_freqs[rank]; // the next most frequent residue
796     cumul += freqs[residue]; // summed frequencies till here
797     set |= coded_set[residue - 1]; // the set of all counted residues till here
798     // residues of equal frequencies are pooled together
799     if (rank < 15 && freqs[residue] == freqs[sorted_freqs[rank+1]]) continue;
800     if (cumul >= minval ) break;
801   }
802   if (set == 8 && sorted_freqs[0] == 5) return 'U';
803   return set_to_iupac[set];
804 }
805 
806 
calc_site_consensus(int * freqs,int dernier,int threshold,char * residues,char unknown,int total,int protein,int allowgaps,int iupac)807 char calc_site_consensus(int *freqs, int dernier, int threshold, char *residues, char unknown, int total,
808 						 int protein, int allowgaps, int iupac)
809 {
810 	char retval;
811 	int maxi = 0, num, kind, last;
812 	maxi = freqs[1];
813 	kind = 1;
814 	if(protein) last = dernier;
815 	else last = 5;
816 	for(num = 2; num < last; num++) {
817 		if(freqs[num] > maxi) {
818 			maxi = freqs[num];
819 			kind = num;
820 			}
821 		}
822   if (!protein && !iupac) {
823     total -= freqs[16];//DNA: don't count uninformative N's for frequency calculation
824     if(total == 0) return 'N';
825   }
826   float minval = total * (threshold / 100.);
827 	if (allowgaps) {
828 		num = dernier - 1; // check if '-' has the highest freq
829 		if (freqs[num] > maxi) {
830                   return freqs[num] > minval ? '-' : unknown;
831 		}
832 	}
833 	if (iupac && !protein ) { // for DNA/RNA with IUPAC codes
834           retval = calc_iupac_consensus(freqs, minval);
835           }
836 	else {
837 		if( maxi >= minval )
838 			retval = residues[kind - 1];
839 		else
840 			retval = unknown;
841 		}
842 	return retval;
843 }
844 
845 
cre_consensus(SEA_VIEW * view,char * newname)846 char *cre_consensus(SEA_VIEW *view, char *newname)
847 {
848 char *newseq, *p, *residues, unknown;
849 int pos, num, total, kind, dernier, vu;
850 static char dna_residues[]="ACGTUMRWSYKVHDBN-";
851 static const char prot_residues[] = "EDQNHRKILMVAPSGTFYWC-";
852 static int freqs[30];
853 
854 newseq = (char *)malloc(view->seq_length + 1);
855 if(newseq == NULL) return NULL;
856 if(view->protein) {
857 	residues = (char *)prot_residues;
858 	unknown = 'X';
859 	}
860 else	{
861 	residues = (char *)dna_residues;
862 	unknown = 'N';
863 	}
864 dernier = strlen(residues) + 1;
865 
866 for (pos = 0; pos < view->seq_length; pos++) {
867 	vu = total = 0; memset(freqs, 0, dernier * sizeof(int));
868 	for(num = 0; num < view->tot_seqs; num++) {
869 		if( !view->sel_seqs[num] ) continue;
870 		if(pos >= view->each_length[num]) continue;
871 		vu++;
872 		if(view->sequence[num][pos] == '-' && ! view->consensus_allowgaps) continue;
873 		total++;
874 		p = strchr(residues, toupper(view->sequence[num][pos]));
875 		if(p == NULL) kind = 0;
876 		else kind = p - residues + 1;
877 		++(freqs[kind]);
878 		}
879 	if(vu == 0) break;
880 	if(total == 0)
881 		newseq[pos] = '-';
882 	else	{
883 		newseq[pos] = calc_site_consensus(freqs, dernier, view->consensus_threshold, residues, unknown,
884 										  total, view->protein, view->consensus_allowgaps, view->consensus_allowiupac);
885 		}
886 	newseq[pos + 1] = 0;
887 	}
888 sprintf(newname, "Consensus%d", view->consensus_threshold);
889 return newseq;
890 }
891