5f17b328b54610b19ffa4288c17f54e098bb4505
[mussa.git] / mussa_gui_conn_view.cc
1 #include "mussa_gui_conn_view.hh"
2
3
4
5 void
6 ConnView::setup(string name, int sq_num, int win_len,
7                 vector<Sequence> *some_seqs,
8                 Nway_Paths *some_paths)
9 {
10   int i, i2, seq_length;
11   Sequence a_seq;
12   motif blank_motif;
13   annot_color new_annot;
14
15
16   ana_name = name;
17   seq_num = sq_num;
18   window = win_len;
19   S = some_seqs;
20   P = some_paths;
21
22   cout << "num of paths = " << some_paths->refined_pathz.size() << endl;
23
24   cout << "x()=" << x() << " y()=" << y() << " w()=" << w() << " h()=" << h();
25   cout << endl;
26
27   max_seq_len = 0;
28   for(i = 0; i < seq_num; ++i)
29   {
30     a_seq = (*S)[i];
31     cout << a_seq.len() << endl;
32     seq_length = a_seq.len();
33     seq_lens.push_back(seq_length);
34     if (seq_length > max_seq_len)
35       max_seq_len = seq_length;
36     if (seq_length < 1000)
37       seq_scales.push_back(1);
38     else if (seq_length < 1000000)
39       seq_scales.push_back(2);
40     else
41       seq_scales.push_back(3);
42   }
43
44   name_pad = 80;
45   y_pad = 20;
46
47   x_scale_factor = (float) max_seq_len / (w() - name_pad);
48   cout << "scale factor is " << x_scale_factor << endl;
49   y_seq_incre = (h()-(y_pad*2)) / (seq_num - 1);
50
51
52   drag_start = -1000;
53   drag_end = -1000;
54   ref_seq_num = 0;
55
56   dragging = false;
57   selected = false;
58
59   highlight.clear();
60   show_bars = false;
61   show_lines = false;
62   bar_interval = max_seq_len / 20;
63   line_interval = max_seq_len / 20;
64   ref_seq_num = 0;
65
66
67   some_motifs.clear();
68   for(i = 0; i < 5; ++i)
69   {
70     blank_motif = new_blank_motif();
71     some_motifs.push_back(blank_motif);
72   }
73
74   // find all unique annotation type ids
75   some_annots.clear();
76   vector<annot_color>::iterator annot_type_i;
77   list<annot>::iterator annot_i;
78
79   // loop thru all sequences
80   for(i2 = 0; i2 < seq_num; i2++)
81   {
82     cout << "ConnView: annotation loop\n";
83     // loop thru all annotation entries in this sequence
84     for(annot_i = (*S)[i2].annots.begin(); annot_i != (*S)[i2].annots.end(); ++annot_i)
85     {
86       cout << annot_i->start << ", " << annot_i->end << " : ";
87       cout << annot_i->name << "  " << annot_i->type << endl;
88       // loop thru annotation types
89       annot_type_i = some_annots.begin();
90       bool type_unfound = true;
91       while ((annot_type_i != some_annots.end()) && type_unfound)
92       {
93         if (annot_i->type == annot_type_i->type)
94           type_unfound = false;  // stop search if found
95         ++annot_type_i;
96       }
97       //if unfound, then add to list
98       if (type_unfound)
99       {
100         new_annot = new_blank_annot();
101         new_annot.type = annot_i->type;
102         some_annots.push_back(new_annot);
103       } 
104     }
105   }
106 }
107
108
109 void
110 ConnView::scale_paths()
111 {
112   vector<int> a_path;
113   list<vector<int> >::iterator pathz_i;
114   int i2;
115
116
117   scaled_pathz.clear();
118
119   for(pathz_i = P->refined_pathz.begin(); pathz_i != P->refined_pathz.end(); ++pathz_i)
120   {
121     a_path = *pathz_i;
122     for(i2 = 0; i2 <= seq_num; i2++)
123       a_path[i2] = (int) (a_path[i2] / x_scale_factor);
124     scaled_pathz.push_back(a_path);
125   }
126 }
127
128 void
129 ConnView::toggle_bars()
130 {
131   show_bars = !show_bars;
132   redraw();
133 }
134
135 void
136 ConnView::set_bar_interval(int new_bar_len)
137 {
138   bar_interval = new_bar_len;
139   cout << "bar interval = " << bar_interval << endl;
140   redraw();
141 }
142
143 void
144 ConnView::toggle_lines()
145 {
146   show_lines = !show_lines;
147   redraw();
148 }
149
150 void
151 ConnView::set_line_interval(int new_line_len)
152 {
153   line_interval = new_line_len;
154   cout << "line interval = " << line_interval << endl;
155   redraw();
156 }
157
158
159 void
160 ConnView::draw()
161 {
162   // this is temporary - check if new motifs have been added
163   check_new_motifs();
164
165   // clear drawing area and set background to white
166   fl_color(FL_WHITE);
167   fl_rectf(x(), y(), w(), h());
168
169
170   // draw the scale indicators if they are on
171   // put into own method soon...
172   int i, div_num, x_loc; 
173   float div_len_scaled;
174
175   if (show_bars)
176   {
177     div_num = max_seq_len / bar_interval;
178     div_len_scaled = ((float) bar_interval) / x_scale_factor;
179     fl_color(230,230,230);
180     for(i = 0; i <= div_num; i+=2)
181     {
182       x_loc = (int)(i * div_len_scaled+x());
183       fl_rectf(x_loc, y(), (int) div_len_scaled, h());
184     }
185   }
186
187   if (show_lines)
188   {  
189     div_num = max_seq_len / line_interval;
190     div_len_scaled = ((float) line_interval) / x_scale_factor;
191     fl_color(0,0,0);
192     fl_line_style(FL_SOLID, 1, NULL);
193     for(i = 0; i <= div_num; i++)
194     {
195       x_loc = (int)(i * div_len_scaled+x());
196       fl_line(x_loc, y(), x_loc, h()+y());
197     }
198   }
199
200
201   // divide up the space with some light blue lines
202   fl_color(150,200,255);
203   fl_line_style(FL_SOLID, 2, NULL);
204   fl_rect(x(), y(), w(), h());
205   fl_line(w()+x()-name_pad, y(), w()+x()-name_pad, h()+y());
206
207   draw_paths();
208
209   // white out any overdraw from path area into name/info area
210   fl_color(FL_WHITE);
211   fl_rectf(w()+x()-name_pad, y(), w()+x(), h());
212
213   draw_sequence_stuff();
214
215   // draw selection box
216   /*
217   if (selected)
218   {
219     fl_color(FL_BLACK);
220     fl_line_style(FL_SOLID, 1, NULL);
221     fl_rect(drag_start,(ref_seq_num*y_seq_incre)+y(),drag_end-drag_start,
222             16);
223   }
224   */
225 }
226
227
228 void
229 ConnView::draw_paths()
230 {
231   list<vector<int> >::iterator i;
232   int i2, i3, y_loc, x_loc, x_start, x_end;
233   vector<int> a_path;
234   list<bool>::iterator highlight_i;
235   int window_size;
236   bool rc_color;
237   int path_start, path_end;
238   //Sequence a_seq;
239
240
241   // determine which paths to highlight
242   highlight.clear();
243   for(i = scaled_pathz.begin(); i != scaled_pathz.end(); ++i)
244   {
245     a_path = *i;
246     // determine if path falls within the selected region and mark it for
247     // highlighted color
248     path_start = abs(a_path[ref_seq_num+1]);
249     path_end = path_start + a_path[0];
250     if ( ( (path_start >= drag_start-x()) && (path_end <= drag_end-x())  ) ||
251          ( (path_start < drag_start-x())  && (path_end > drag_end-x())   ) ||
252          ( (path_start < drag_start-x())  && (path_end > drag_start-x()) ) ||
253          ( (path_start < drag_end-x())    && (path_end > drag_end-x())   )    )
254       highlight.push_back(true);
255     else
256       highlight.push_back(false);
257   }
258
259   fl_line_style(FL_SOLID, 1, NULL);
260   // draw non-highlight paths (ie not in the selection box)
261   highlight_i = highlight.begin();
262   for(i = scaled_pathz.begin(); i != scaled_pathz.end(); ++i)
263   {
264     a_path = *i;
265     y_loc = y()+y_pad;
266
267     // get window size to determine line width
268     window_size = a_path[0];
269     // make sure width is at least 1  - might be zero to my slack rounding
270     if (window_size == 0)
271       window_size = 1;
272
273     if (!(*highlight_i))
274       for(i2 = 1; i2 < seq_num; i2++)
275       {
276         // RC case handling
277         // ugh, an xor...only want blue if one of the nodes is rc
278         if ( ((a_path[i2] < 0) || (a_path[i2+1] < 0)) &&
279              !((a_path[i2] < 0) && (a_path[i2+1] < 0)) )
280           fl_color(200,200,255);
281         else
282           fl_color(255,200,200);
283           
284         fl_line_style(FL_SOLID, 1, NULL);
285         fl_polygon((int)abs(a_path[i2])+x(), y_loc + 3,
286                    (int)abs(a_path[i2])+window_size+x(), y_loc + 3,
287                    (int)abs(a_path[i2+1])+window_size+x(), y_loc + y_seq_incre - 3,
288                    (int)abs(a_path[i2+1])+x(), y_loc + y_seq_incre - 3);
289
290         y_loc += y_seq_incre;
291       }
292     ++highlight_i;
293   }
294
295   // draw highlighted paths (ie in or partially in selection)
296   // drawing these separately and after other paths so they are on top
297   highlight_i = highlight.begin();
298   for(i = scaled_pathz.begin(); i != scaled_pathz.end(); ++i)
299   {
300     a_path = *i;
301     y_loc = y()+y_pad;
302
303     // get window size to determine line width
304     window_size = a_path[0];
305     // make sure width is at least 1  - might be zero to my slack rounding
306     if (window_size == 0)
307       window_size = 1;
308
309     if (*highlight_i)
310       for(i2 = 1; i2 < seq_num; i2++)
311       {
312         // RC case handling
313         // ugh, an xor...only want blue if one of the nodes is rc
314         if ( ((a_path[i2] < 0) || (a_path[i2+1] < 0)) &&
315              !((a_path[i2] < 0) && (a_path[i2+1] < 0)) )
316           fl_color(FL_BLUE);
317         else
318           fl_color(FL_RED);
319           
320         fl_polygon((int)abs(a_path[i2])+x(), y_loc + 3,
321                    (int)abs(a_path[i2])+window_size+x(), y_loc + 3,
322                    (int)abs(a_path[i2+1])+window_size+x(), y_loc + y_seq_incre - 3,
323                    (int)abs(a_path[i2+1])+x(), y_loc + y_seq_incre - 3);
324
325         y_loc += y_seq_incre;
326       }
327     ++highlight_i;
328   }
329 }
330
331 /*
332   list<vector<int> >::iterator i;
333   int window_size;
334   bool rc_color;
335   int path_start, path_end;
336   Sequence a_seq;
337   vector<int> a_path;
338 */
339
340 void
341 ConnView::draw_sequence_stuff()
342 {
343   int i2, i3, y_loc, y_offset, x_loc, x_start, x_end, mv_offset;
344   list<annot>::iterator annot_i;
345   string species_name, seq_length;
346   stringstream raw_length;
347
348
349   // draw sequence representation lines
350   fl_font(FL_COURIER, 14);
351   //fl_color(FL_BLACK);
352   fl_color(80,80,80);
353   fl_line_style(FL_SOLID, 7, NULL);
354   y_loc = y()+y_pad;
355   y_offset = 5;
356   for(i2 = 0; i2 < seq_num; i2++)
357   {
358     if (i2 == seq_num - 1)
359       y_offset = -10;
360     x_loc = (int)(seq_lens[i2] / x_scale_factor) + x();
361     //report_float("seq scaled len", x_loc);
362     fl_line(x(),y_loc,x_loc,y_loc);
363
364     species_name = (*S)[i2].species;
365     fl_draw(species_name.c_str(), x()+w()-name_pad+5, y_loc+y_offset);
366
367     // funkiness to figure out which genomic scale to report size in
368     if (seq_scales[i2] == 1)
369       raw_length << setprecision(3) << seq_lens[i2] << " bp";
370     else if (seq_scales[i2] == 2)
371       raw_length << setprecision(3) << seq_lens[i2] / 1000.0 << " Kb";
372     else if (seq_scales[i2] == 3)
373       raw_length << setprecision(3) << seq_lens[i2] /1000000.0<< " Mb";
374     seq_length = raw_length.str();
375     fl_draw(seq_length.c_str(), x()+w()-name_pad+5, y_loc+y_offset+15);
376     raw_length.str("");
377
378     y_loc += y_seq_incre;
379   }
380
381   //fl_line(x(),y()+y_pad/2,w()-name_pad,y()+y_pad/2);
382   //fl_line(x(),y()+h()-y_pad/2,w()-name_pad,y()+h()-y_pad/2);
383
384   // draw annotations
385   vector<annot_color>::iterator annot_type_i;
386
387   fl_color(FL_GREEN);
388   fl_line_style(FL_SOLID, 3, NULL);
389   y_loc = y()+y_pad;
390   for(i2 = 0; i2 < seq_num; i2++)
391   {
392     // loop thru all annotation entries
393     for(annot_i = (*S)[i2].annots.begin(); annot_i != (*S)[i2].annots.end(); ++annot_i)
394     {
395       fl_line_style(FL_SOLID, 3, NULL);
396       mv_offset = 0;
397
398       // loop thru annotation types to determine color
399       annot_type_i = some_annots.begin();
400       bool type_unfound = true;
401       while ((annot_type_i != some_annots.end()) && type_unfound)
402       {
403         if (annot_i->type == annot_type_i->type)
404         {  
405           fl_color(annot_type_i->color);
406           type_unfound = false;
407         }
408         else
409           fl_color(FL_GREEN);
410         ++annot_type_i;
411       }
412
413       // calculate scaled start and end, and draw
414       x_start = (int)(annot_i->start / x_scale_factor) + x();
415       x_end = (int)(annot_i->end / x_scale_factor) + x();
416       fl_line(x_start,y_loc+mv_offset,x_end,y_loc+mv_offset);
417     }
418     y_loc += y_seq_incre;
419   }
420
421
422   // draw motifs found
423   vector<motif>::iterator motif_i;
424   vector<int> some_motif_locs;
425   vector<int>::iterator i_locs;
426   int scale_len, motif_len;
427
428   fl_color(255,0,255);
429   fl_line_style(FL_SOLID, 9, NULL);
430   motif_i = some_motifs.begin();
431   while (motif_i != some_motifs.end())
432   {
433     fl_color(motif_i->color);
434     motif_len = motif_i->seq.length();
435     scale_len = (int) (motif_len / x_scale_factor);
436     if (scale_len == 0)
437       scale_len = 1;
438     y_loc = y()+y_pad;
439     if (!motif_i->locations.empty())
440     for(i2 = 0; i2 < seq_num; i2++)
441     {
442       some_motif_locs = (*motif_i).locations[i2];
443
444       i_locs = some_motif_locs.begin();
445       while (i_locs != some_motif_locs.end())
446       {
447         x_start = (int)(*i_locs / x_scale_factor) + x();
448         fl_line(x_start,y_loc,x_start+scale_len,y_loc);
449         ++i_locs;
450       }
451     y_loc += y_seq_incre;      
452     }
453     ++motif_i;
454   }
455 }
456
457
458 void
459 ConnView::resize(int new_x, int new_y, int new_w, int new_h)
460 {
461
462   x(new_x);
463   y(new_y);
464   w(new_w);
465   h(new_h);
466
467   x_scale_factor = (float) max_seq_len / (w() - name_pad);
468   cout << "scale factor is " << x_scale_factor << endl;
469   y_seq_incre = (h()-(2*y_pad)) / (seq_num - 1);
470
471   scale_paths();
472 }
473
474
475 void
476 ConnView::reporter(string var, int value)
477 {
478   cout << var << " : " << value << endl;
479 }
480
481
482 void
483 ConnView::report_float(string var, float value)
484 {
485   cout << var << " : " << value << endl;
486 }
487
488 int
489 ConnView::handle(int e)
490 {
491   int return_value;
492   float y_calc_tmp;
493
494   // this empty string needs to be put on cout, otherwise the -O optimize
495   // compile option seems to throw this function away with the following:
496   // gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
497   cout << "";
498
499   // why do I need a -O for this module?  Well, originally I just used the 
500   // same compile flags for all modules.  I changed that.  However, on debian
501   // systems I need the -O otherwise the behavior I observe on redhat machines
502   // with above compiler happens if I don't have that empty cout.  WTF
503
504   switch(e)
505   {
506   case FL_PUSH:
507     if (Fl::event_button3())
508     {
509       spawnSeq();
510       return_value = 1;
511     }
512     else if (Fl::event_button2())
513     {
514       find_motifs();
515       return_value = 1;
516     }
517     break;
518   case FL_DRAG:
519     if (!dragging)
520     {
521       drag_start = Fl::event_x();
522       y_drag_start = (float) Fl::event_y();
523       ref_seq_num = (int) (round ( (y_drag_start/y_seq_incre) ) ); 
524       dragging = true;
525       selected = false;
526       return_value = 1;
527     }
528     fl_line_style(FL_SOLID, 1, NULL);
529     fl_overlay_rect(drag_start, (ref_seq_num*y_seq_incre)+y(),
530                     Fl::event_x()-drag_start, 16);
531     
532     break;
533   case FL_RELEASE:
534     if (dragging)
535     {
536       drag_end = Fl::event_x();
537       dragging = false;
538       selected = true;
539       redraw();
540       return_value = 1;
541     }
542     break;
543   default:
544     return_value = Fl_Widget::handle(e);
545   }
546
547   return return_value;
548 }
549
550
551
552 void
553 ConnView::check_new_motifs()
554 {
555   vector<motif>::iterator i;
556   int i2;
557   vector<int> some_motif_locs;
558   vector<int>::iterator i_locs;
559
560   i = some_motifs.begin();
561   while (i != some_motifs.end())
562   {
563     if (i->dirty)
564     {
565       cout << i->seq << " is new\n";
566       i->locations.clear();
567       //i_locs = i->locations;
568       for(i2 = 0; i2 < seq_num; i2++)
569       {
570         some_motif_locs = (*S)[i2].find_motif(i->seq);
571         (*i).locations.push_back(some_motif_locs);
572
573         
574         i_locs = some_motif_locs.begin();
575         while (i_locs != some_motif_locs.end())
576         {
577           cout << *i_locs << " ";
578           ++i_locs;
579         }
580         cout << endl;
581         
582       }
583
584       i->dirty = false;
585     }
586     ++i;
587   }
588 }
589
590
591 void
592 ConnView::spawnSeq()
593 {
594   list<vector<int> > selected_paths;
595   list<vector<int> >::iterator pathz_i;
596   int i2, i3, y_loc, x_loc, x_start, x_end;
597   vector<int> a_path;
598   list<bool>::iterator highlight_i;
599   int y_max;
600   string window_name;
601
602
603   if (selected)
604   {
605     // make new list of connections that are highlighted
606     selected_paths.clear();
607     highlight_i = highlight.begin();
608     for(pathz_i = P->refined_pathz.begin(); pathz_i != P->refined_pathz.end(); ++pathz_i)
609     {
610       if (*highlight_i)
611       {
612         a_path = *pathz_i;
613         selected_paths.push_back(a_path);
614       }
615       ++highlight_i;
616     }
617
618     // give 50 pixels of height per sequence
619     y_max = seq_num * 50;
620     window_name = "Mussa Sequence: " + ana_name;
621
622     a_seq_win = new SeqWindow(800, y_max, (const char*) window_name.c_str(),
623                               seq_num,
624                               S, selected_paths, seq_lens, &some_motifs);
625   }
626 }
627
628
629 void
630 ConnView::find_motifs()
631 {
632   motif_find_window = new MotifWindow(300, 300, "Motifs", &some_motifs);
633 }
634
635 void
636 ConnView::annot_win()
637 {
638   annot_color_window = new AnnotWindow(300, 300, "Annotations", &some_annots);
639 }
640
641 // @!@! special hacked in color coding for the myf5/6 region annots
642
643 /*
644       if (annot_i->type == "mvista")
645       {
646         fl_color(255,230,0);
647         fl_line_style(FL_SOLID, 8, NULL);
648         mv_offset = -4;
649       }
650       else if (annot_i->type == "reg")
651       {
652         fl_line_style(FL_SOLID, 10, NULL);
653         mv_offset = -8;
654
655         if (annot_i->name == "CNS")
656           fl_color(255,150,0);
657         else if (annot_i->name == "ELA")
658           fl_color(0,200,120);
659         else if (annot_i->name == "ES")
660           fl_color(0,200,200);
661         else if (annot_i->name == "NA")
662           fl_color(120,120,120);
663         else if (annot_i->name == "EA")
664         {
665           fl_line_style(FL_SOLID, 7, NULL);
666           mv_offset = -13;
667           fl_color(0,200,120);
668         }
669         else if (annot_i->name == "VS")
670         {
671           fl_line_style(FL_SOLID, 7, NULL);
672           mv_offset = -6;
673           fl_color(255,255,0);
674         }
675         else if (annot_i->name == "SP")
676         {
677           fl_line_style(FL_SOLID, 7, NULL);
678           mv_offset = -13;
679           fl_color(255,230,150);
680         }
681         else if (annot_i->name == "L")
682         {
683           fl_line_style(FL_SOLID, 7, NULL);
684           mv_offset = -6;
685           fl_color(0,0,100);
686         }
687         else if (annot_i->name == "TCM")
688           fl_color(0,130,230);
689       }
690 */