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