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