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