# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = alg qui .
+INPUT = alg qui qui/seqbrowser .
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
--- /dev/null
+#include "alg/glseqbrowser.hpp"
+#include "mussa_exceptions.hpp"
+
+#include <iostream>
+#include <stdexcept>
+
+using namespace std;
+
+GlSeqBrowser::GlSeqBrowser()
+ : border(25),
+ max_ortho(400.0, 0.0, 600.0, 0.0),
+ cur_ortho(max_ortho),
+ viewport_size(600, 400),
+ viewport_center(0),
+ zoom_level(2),
+ color_mapper(),
+ track_container()
+{
+}
+
+GlSeqBrowser::GlSeqBrowser(const GlSeqBrowser& gt)
+ : border(gt.border),
+ max_ortho(gt.max_ortho),
+ cur_ortho(gt.cur_ortho),
+ viewport_size(gt.viewport_size),
+ viewport_center(gt.viewport_center),
+ zoom_level(gt.zoom_level),
+ color_mapper(gt.color_mapper),
+ track_container(gt.track_container)
+{
+}
+
+void GlSeqBrowser::initializeGL()
+{
+ glEnable(GL_DEPTH_TEST);
+ glClearColor(1.0, 1.0, 1.0, 0.0);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glShadeModel(GL_FLAT);
+}
+
+void GlSeqBrowser::resizeGL(int width, int height)
+{
+ viewport_size.x = width;
+ viewport_size.y = height;
+ glViewport(0, 0, (GLsizei)width, (GLsizei)height);
+ //update_layout();
+}
+
+void GlSeqBrowser::paintGL() const
+{
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(cur_ortho.left, cur_ortho.right,
+ cur_ortho.bottom, cur_ortho.top,
+ -50.0, 50);
+
+ draw();
+
+ glPopMatrix();
+ glFlush();
+}
+
+void GlSeqBrowser::processSelection(GLuint hits, GLuint buffer[], GLuint bufsize)
+{
+ GLuint *ptr;
+ GLuint names;
+ GLuint consumed_names = 0;
+ float z1;
+ float z2;
+ GLuint objtype;
+ GLuint objid;
+ GLuint path_index = 0;
+ GLuint pair_key_0 = 0;
+ GLuint pair_key_1 = 0;
+
+ selectedPaths.clear();
+ selectedTracks.clear();
+
+ std::cout << "hits = " << hits << std::endl;
+ ptr = (GLuint *) buffer;
+ if (hits > 0)
+ selectedMode = true;
+ for (GLuint i=0; i < hits; ++i)
+ {
+ if ((i + 5) > bufsize) {
+ std::clog << "*** selection overflow***" << std::endl;
+ } else {
+ consumed_names = 0;
+ names = *ptr++;
+ z1 = ((float)*ptr++)/0x7fffffff;
+ z2 = ((float)*ptr++)/0x7fffffff;
+ objtype = *ptr++; ++consumed_names;
+ switch (objtype) {
+ case MussaSegment:
+ path_index = *ptr++; ++consumed_names;
+ pair_key_0 = *ptr++; ++consumed_names;
+ pair_key_1 = *ptr++; ++consumed_names;
+ if (path_index < path_segments.size()) {
+ segment_key k(pair_key_0, pair_key_1);
+ pair_segment_map::iterator psm_i;
+ psm_i = path_segments[path_index].find(k);
+ if (psm_i != path_segments[path_index].end()) {
+ Segment &seg = psm_i->second;
+ selectedPaths.insert(seg.path_ids.begin(), seg.path_ids.end());
+ }
+ // else something else is wrong
+ } else {
+ // something wasn't right
+ clog << "invalid path_index " << path_index
+ << " should have been [0,"<<path_segments.size()
+ << ") " << endl;
+ }
+ break;
+ case MussaTrack:
+ objid = *ptr++; ++consumed_names;
+ selectedTracks.insert(objid);
+ break;
+ default:
+ cout << "unknown type " << objtype << " ";
+ for(; consumed_names < names; ++consumed_names) {
+ cout << consumed_names << "," << *ptr++ << " ";
+ }
+ cout << endl;
+ break;
+ }
+ }
+ }
+}
+
+void GlSeqBrowser::selectRegion(int top, int left, int bottom, int right)
+{
+ GLfloat x_scale = cur_ortho.width()/((float)viewport_size.x);
+ GLfloat y_scale = cur_ortho.height()/((float)viewport_size.y);
+ GLfloat x_left = cur_ortho.left + (left*x_scale);
+ GLfloat x_right = right * x_scale;
+
+ if (top > bottom) {
+ // woah, someone gave us a rectangle with the origin in the lower left
+ int temp = top;
+ bottom = top;
+ top = temp;
+ }
+ // swap the orientation of canvas coordinates
+ GLfloat y_top = cur_ortho.top-(bottom*y_scale);
+ GLfloat y_bottom = cur_ortho.top - top * y_scale;
+ selectedRegion = rect<float>(y_top, x_left, y_bottom, x_right);
+
+ // hopefully this will make a buffer big enough to receive
+ // everything being selected
+ //const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
+ //const GLuint select_buf_size = 1 + 5 * (pathz_count + sequences.size());
+ const GLuint select_buf_size = 500000;
+ GLuint selectBuf[select_buf_size];
+ glSelectBuffer(select_buf_size, selectBuf);
+ GLint hits;
+
+ (void)glRenderMode(GL_SELECT);
+ glPushMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(x_left, x_right, y_top, y_bottom, -50.0, 50.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ draw();
+
+ glFlush();
+ glPopMatrix();
+ hits = glRenderMode(GL_RENDER);
+ processSelection(hits, selectBuf, select_buf_size);
+}
+
+float GlSeqBrowser::left() const
+{
+ return max_ortho.left;
+}
+
+float GlSeqBrowser::right() const
+{
+ return max_ortho.right;
+}
+
+void GlSeqBrowser::setViewportCenter(float x)
+{
+ update_viewport(x, zoom_level);
+ viewport_center = x;
+}
+
+float GlSeqBrowser::viewportLeft() const
+{
+ return cur_ortho.left;
+}
+
+float GlSeqBrowser::viewportCenter() const
+{
+ return viewport_center;
+}
+
+float GlSeqBrowser::viewportRight() const
+{
+ return cur_ortho.right;
+}
+
+float GlSeqBrowser::viewportHeight() const
+{
+ return cur_ortho.top - cur_ortho.bottom;
+}
+
+float GlSeqBrowser::viewportWidth() const
+{
+ return cur_ortho.right - cur_ortho.left;
+}
+
+void GlSeqBrowser::setZoom(int new_zoom)
+{
+ update_viewport(viewport_center, new_zoom);
+ zoom_level = new_zoom;
+}
+
+int GlSeqBrowser::zoom() const
+{
+ return zoom_level;
+}
+
+void GlSeqBrowser::setColorMapper(AnnotationColors& cm)
+{
+ color_mapper = cm;
+}
+
+AnnotationColors& GlSeqBrowser::colorMapper()
+{
+ return color_mapper;
+}
+
+void GlSeqBrowser::clear()
+{
+ clear_links();
+ path_segments.clear();
+ track_container.clear();
+}
+
+void GlSeqBrowser::push_sequence(const Sequence &s)
+{
+ GlSequence gs(s, color_mapper);
+ push_sequence(gs);
+}
+
+void GlSeqBrowser::push_sequence(GlSequence &gs)
+{
+ clear_links();
+ pathid = 0;
+ track_container.push_back(gs);
+ update_layout();
+ if (track_container.size() > 1)
+ path_segments.push_back(pair_segment_map());
+}
+
+const std::vector<GlSequence>& GlSeqBrowser::sequences() const
+{
+ return track_container;
+}
+
+void GlSeqBrowser::clear_links()
+{
+ path_segment_map_vector::iterator psmv_i;
+ for(psmv_i = path_segments.begin();
+ psmv_i != path_segments.end();
+ ++psmv_i)
+ {
+ psmv_i->clear();
+ }
+}
+
+void
+GlSeqBrowser::link(const vector<int>& path, const vector<bool>& rc, int length)
+{
+ if (path.size() < 2) {
+ // should i throw an error instead?
+ return;
+ }
+ if (path.size() != rc.size()) {
+ throw runtime_error("path and reverse compliment must be the same length");
+ }
+ vector<int>::const_iterator path_i = path.begin();
+ vector<bool>::const_iterator rc_i = rc.begin();
+ int track_i = 0;
+ int prev_x = *path_i; ++path_i;
+ bool prev_rc = *rc_i; ++rc_i;
+ while (path_i != path.end() and rc_i != rc.end())
+ {
+ segment_key p(prev_x, *path_i);
+ pair_segment_map::iterator found_segment = path_segments[track_i].find(p);
+ if (found_segment == path_segments[track_i].end()) {
+ // not already found
+ float y1 = track_container[track_i].y();
+ y1 -= track_container[track_i].height()/2;
+ float y2 = track_container[track_i+1].y();
+ y2 += track_container[track_i+1].height()/2;
+
+ Segment s(prev_x, y1, *path_i, y2, prev_rc);
+ s.path_ids.insert(pathid);
+ path_segments[track_i][p] = s;
+ } else {
+ //found
+ found_segment->second.path_ids.insert(pathid);
+ }
+ prev_x = *path_i;
+ prev_rc = *rc_i;
+ ++track_i;
+ ++path_i;
+ ++rc_i;
+ }
+ // pathid is reset by push_sequence
+ ++pathid;
+}
+
+void GlSeqBrowser::update_viewport(float center, int new_zoom)
+{
+ float max_width = max_ortho.width();
+ // division by zero is a major bummer
+ if (new_zoom < 1) {
+ new_zoom = 1;
+ }
+ float new_max_width = max_width / new_zoom;
+ cur_ortho.left = center-new_max_width;
+ cur_ortho.right = center+new_max_width;
+}
+
+void GlSeqBrowser::update_layout()
+{
+ typedef std::vector<GlSequence>::iterator glseq_itor_type;
+ float available_height = (float)cur_ortho.top - 2 * (float)border;
+ float max_base_pairs = 0;
+ size_t track_count = track_container.size();
+
+ if (track_count > 1) {
+ // we have several sequences
+ float track_spacing = available_height / (track_count-1);
+ float y = available_height + (float)border;
+ for(glseq_itor_type seq_i = track_container.begin();
+ seq_i != track_container.end();
+ ++seq_i, y-=track_spacing)
+ {
+ seq_i->setX(0);
+ seq_i->setY(y);
+ if (seq_i->length() > max_base_pairs)
+ max_base_pairs = seq_i->length();
+ }
+ } else if (track_count == 1) {
+ // center the single track
+ glseq_itor_type seq_i = track_container.begin();
+ seq_i->setX(0);
+ seq_i->setY(viewport_size.x /2);
+ max_base_pairs = seq_i->length();
+ } else {
+ // nothing to do as we're empty
+ return;
+ }
+ max_ortho.right = max_base_pairs + border;
+ max_ortho.left = -border;
+ max_ortho.top = viewport_size.x;
+ max_ortho.bottom = 0;
+ cur_ortho = max_ortho;
+ viewport_center = (cur_ortho.width()/2) + cur_ortho.left;
+}
+
+void GlSeqBrowser::draw() const
+{
+ glMatrixMode(GL_MODELVIEW);
+ glInitNames();
+ glPushName(MussaSegment);
+ draw_segments();
+ glLoadName(MussaTrack);
+ draw_tracks();
+ glPopName();
+ // a selection shouldn't have a glName associated with it
+ draw_selection();
+}
+
+void GlSeqBrowser::draw_selection() const
+{
+ // draw selection box
+ glEnable(GL_BLEND);
+ glDepthMask(GL_FALSE);
+ if (selectedMode) {
+ glColor4f(0.6, 0.6, 0.6, 0.9);
+ glRectf(selectedRegion.left, selectedRegion.top,
+ selectedRegion.right, selectedRegion.bottom);
+ }
+ glDepthMask(GL_TRUE);
+ glDisable(GL_BLEND);
+}
+
+void GlSeqBrowser::draw_tracks() const
+{
+ for(size_t track_i = 0; track_i != track_container.size(); ++track_i)
+ {
+ glPushName(track_i);
+ track_container[track_i].draw(cur_ortho.left, cur_ortho.right);
+ glPopName();
+ }
+}
+
+void GlSeqBrowser::draw_segments() const
+{
+ glLineWidth(0.1);
+ // each vector contains path_segment_maps of all the connections
+ // between this track and the next
+ path_segment_map_vector::const_iterator psmv_i;
+ for(psmv_i = path_segments.begin();
+ psmv_i != path_segments.end();
+ ++psmv_i)
+ {
+ path_segment_map_vector::difference_type path_index;
+ path_index = psmv_i - path_segments.begin();
+ // these maps contain the pair index (used so we dont keep drawing the
+ // same segment) and the actual segment structure.
+ pair_segment_map::const_iterator psm_i;
+ for(psm_i = psmv_i->begin();
+ psm_i != psmv_i->end();
+ ++psm_i)
+ {
+ // grab the index into our segment map
+ const segment_key& key = psm_i->first;
+ // the second element of our map pair is a segment
+ const Segment &s = psm_i->second;
+ // need to do something so we can detect our selection
+ vector<int> selected;
+ set_intersection(selectedPaths.begin(), selectedPaths.end(),
+ s.path_ids.begin(), s.path_ids.end(),
+ back_inserter(selected));
+
+ if (not s.reversed) {
+ if (selectedPaths.size() == 0 or selected.size() > 0) {
+ glColor3f(1.0, 0.0, 0.0);
+ } else {
+ glColor3f(1.0, 0.8, 0.8);
+ }
+ } else {
+ if (selectedPaths.size() == 0 or selected.size() > 0) {
+ glColor3f(0.0, 0.0, 1.0);
+ } else {
+ glColor3f(0.8, 0.8, 1.0);
+ }
+ }
+ // save the multipart name for our segment
+ glPushName(path_index); glPushName(key.first); glPushName(key.second);
+ glBegin(GL_LINES);
+ glVertex3f(s.start.x, s.start.y, -1);
+ glVertex3f(s.end.x, s.end.y, -1);
+ glEnd();
+ // clear the names
+ glPopName(); glPopName(); glPopName();
+ }
+ }
+}
--- /dev/null
+#ifndef _GLTRACKS_H_
+#define _GLTRACKS_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "alg/annotation_colors.hpp"
+#include "alg/sequence.hpp"
+#include "alg/glsequence.hpp"
+
+//! Manage rendering a collection of glSequences
+class GlSeqBrowser
+{
+public:
+ GlSeqBrowser();
+ GlSeqBrowser(const GlSeqBrowser&);
+
+ //! setup the opengl canvas
+ void initializeGL();
+ //! called when our screen canvas is resized
+ void resizeGL(int width, int height);
+ //! render our scene
+ void paintGL() const;
+
+ //! select a region (using canvas coordinates)
+ void GlSeqBrowser::selectRegion(int top, int left, int bottom, int right);
+
+ //! max world left coordinate
+ float left() const;
+ //! max world right coordinate
+ float right() const;
+
+ void setViewportCenter(float x);
+ float viewportLeft() const;
+ float viewportCenter() const;
+ float viewportRight() const;
+ float viewportHeight() const;
+ float viewportWidth() const;
+
+ void setZoom(int zoom_level);
+ int zoom() const;
+
+ void setColorMapper(AnnotationColors& cm);
+ AnnotationColors& colorMapper();
+
+ //! clear our tracks and connections
+ void clear();
+
+ //! add a sequence to the back of our track container
+ void push_sequence(const Sequence &s);
+ //! add a glsequence to the back of our track container
+ void push_sequence(GlSequence &s);
+ //! return our track container
+ const std::vector<GlSequence>& sequences() const;
+
+ //! clear all the line segments between all the sequences
+ void clear_links();
+ //! define a path
+ void link(const std::vector<int>& path, const std::vector<bool>& isRC, int length);
+
+ //! Provide a logical name for a type discriminator for our glName stack
+ enum FeatureType { MussaTrack, MussaSegment };
+
+ //! a useful point class
+ template<class T> struct point {
+ T x;
+ T y;
+
+ point(T x_, T y_):x(x_), y(y_) {}
+ };
+
+ //! a useful rectangle, where 0,0 is in the lower left
+ template<class T> struct rect {
+ T top;
+ T left;
+ T bottom;
+ T right;
+
+ rect() {}
+ rect(T t, T l, T b, T r) : top(t), left(l), bottom(b), right(r) {}
+ T width() { return right - left; }
+ T height() { return top - bottom; }
+ };
+
+ struct Segment
+ {
+ point<float> start;
+ point<float> end;
+ bool reversed;
+ std::set<int> path_ids;
+
+ Segment() : start(0.0, 0.0), end(0.0, 0.0) {}
+ Segment(float x1, float y1, float x2, float y2, bool isRC)
+ : start(x1, y1), end(x2, y2), reversed(isRC) {}
+ };
+
+ //! data structure holding our line segments
+ /*! the vector is of size track_container.size()-1
+ * it's indexed by the pair x1, x2 (the two x coordinates between
+ * the two tracks
+ */
+ typedef std::pair<int, int> segment_key;
+ typedef std::map<segment_key, Segment> pair_segment_map;
+ typedef std::vector<pair_segment_map> path_segment_map_vector;
+ path_segment_map_vector path_segments;
+private:
+ //! recalculate the viewable world
+ /*! depending on the size of our canvas, our zoom level and
+ * how far we've been offset
+ */
+ void update_viewport(float center, int new_zoom);
+
+ //! determine where all the tracks should be placed
+ void update_layout();
+
+ //! convert opengl selections into the list of paths we should highlight
+ void processSelection(GLuint hits, GLuint buffer[], GLuint bufsize);
+
+ //! master scene drawing function
+ /*! draw is broken out for the opengl selection code
+ */
+ void draw() const;
+ //! draw glsequence tracks
+ void draw_tracks() const;
+ //! draw line segments between tracks
+ void draw_segments() const;
+ //! draw selection box
+ void draw_selection() const;
+
+ //! number of pixels to reserve around the edges of our canvas
+ const int border;
+ //! the maximum dimensions that our scene is taking up (world coord)
+ rect<float> max_ortho;
+ //! the current viewable region (world coord)
+ rect<float> cur_ortho;
+ //! how many pixels our viewport is (screen coord)
+ point<int> viewport_size;
+ //! the center of our current viewport (world coord) (used for scrollbar)
+ float viewport_center;
+ int zoom_level;
+ AnnotationColors color_mapper;
+ //! container of all the GlSequences loaded into our scene
+ std::vector<GlSequence> track_container;
+ //! counter for each path added to us via connect
+ int pathid;
+
+protected:
+ //! where to draw our box
+ rect<float> selectedRegion;
+ //! true if we have a selection
+ bool selectedMode;
+ //! indicate which paths are selected
+ std::set<int> selectedPaths;
+ //! which track is selected (it only makes sense to have one track selected).
+ std::set<int> selectedTracks;
+
+};
+#endif
+++ /dev/null
-#include "alg/gltracks.hpp"
-#include "mussa_exceptions.hpp"
-
-#include <iostream>
-#include <stdexcept>
-
-using namespace std;
-
-GlTracks::GlTracks()
- : border(25),
- max_ortho(400.0, 0.0, 600.0, 0.0),
- cur_ortho(max_ortho),
- viewport_size(600, 400),
- viewport_center(0),
- zoom_level(2),
- color_mapper(),
- track_container()
-{
-}
-
-GlTracks::GlTracks(const GlTracks& gt)
- : border(gt.border),
- max_ortho(gt.max_ortho),
- cur_ortho(gt.cur_ortho),
- viewport_size(gt.viewport_size),
- viewport_center(gt.viewport_center),
- zoom_level(gt.zoom_level),
- color_mapper(gt.color_mapper),
- track_container(gt.track_container)
-{
-}
-
-void GlTracks::initializeGL()
-{
- glEnable(GL_DEPTH_TEST);
- glClearColor(1.0, 1.0, 1.0, 0.0);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glShadeModel(GL_FLAT);
-}
-
-void GlTracks::resizeGL(int width, int height)
-{
- viewport_size.x = width;
- viewport_size.y = height;
- glViewport(0, 0, (GLsizei)width, (GLsizei)height);
- //update_layout();
-}
-
-void GlTracks::paintGL() const
-{
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-
- glPushMatrix();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(cur_ortho.left, cur_ortho.right,
- cur_ortho.bottom, cur_ortho.top,
- -50.0, 50);
-
- draw();
-
- glPopMatrix();
- glFlush();
-}
-
-void GlTracks::processSelection(GLuint hits, GLuint buffer[], GLuint bufsize)
-{
- GLuint *ptr;
- GLuint names;
- GLuint consumed_names = 0;
- float z1;
- float z2;
- GLuint objtype;
- GLuint objid;
- GLuint path_index = 0;
- GLuint pair_key_0 = 0;
- GLuint pair_key_1 = 0;
-
- selectedPaths.clear();
- selectedTracks.clear();
-
- std::cout << "hits = " << hits << std::endl;
- ptr = (GLuint *) buffer;
- if (hits > 0)
- selectedMode = true;
- for (GLuint i=0; i < hits; ++i)
- {
- if ((i + 5) > bufsize) {
- std::clog << "*** selection overflow***" << std::endl;
- } else {
- consumed_names = 0;
- names = *ptr++;
- z1 = ((float)*ptr++)/0x7fffffff;
- z2 = ((float)*ptr++)/0x7fffffff;
- objtype = *ptr++; ++consumed_names;
- switch (objtype) {
- case MussaSegment:
- path_index = *ptr++; ++consumed_names;
- pair_key_0 = *ptr++; ++consumed_names;
- pair_key_1 = *ptr++; ++consumed_names;
- if (path_index < path_segments.size()) {
- segment_key k(pair_key_0, pair_key_1);
- pair_segment_map::iterator psm_i;
- psm_i = path_segments[path_index].find(k);
- if (psm_i != path_segments[path_index].end()) {
- Segment &seg = psm_i->second;
- selectedPaths.insert(seg.path_ids.begin(), seg.path_ids.end());
- }
- // else something else is wrong
- } else {
- // something wasn't right
- clog << "invalid path_index " << path_index
- << " should have been [0,"<<path_segments.size()
- << ") " << endl;
- }
- break;
- case MussaTrack:
- objid = *ptr++; ++consumed_names;
- selectedTracks.insert(objid);
- break;
- default:
- cout << "unknown type " << objtype << " ";
- for(; consumed_names < names; ++consumed_names) {
- cout << consumed_names << "," << *ptr++ << " ";
- }
- cout << endl;
- break;
- }
- }
- }
-}
-
-void GlTracks::selectRegion(int top, int left, int bottom, int right)
-{
- GLfloat x_scale = cur_ortho.width()/((float)viewport_size.x);
- GLfloat y_scale = cur_ortho.height()/((float)viewport_size.y);
- GLfloat x_left = cur_ortho.left + (left*x_scale);
- GLfloat x_right = right * x_scale;
-
- if (top > bottom) {
- // woah, someone gave us a rectangle with the origin in the lower left
- int temp = top;
- bottom = top;
- top = temp;
- }
- // swap the orientation of canvas coordinates
- GLfloat y_top = cur_ortho.top-(bottom*y_scale);
- GLfloat y_bottom = cur_ortho.top - top * y_scale;
- selectedRegion = rect<float>(y_top, x_left, y_bottom, x_right);
-
- // hopefully this will make a buffer big enough to receive
- // everything being selected
- //const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
- //const GLuint select_buf_size = 1 + 5 * (pathz_count + tracks.size());
- const GLuint select_buf_size = 500000;
- GLuint selectBuf[select_buf_size];
- glSelectBuffer(select_buf_size, selectBuf);
- GLint hits;
-
- (void)glRenderMode(GL_SELECT);
- glPushMatrix();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(x_left, x_right, y_top, y_bottom, -50.0, 50.0);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- draw();
-
- glFlush();
- glPopMatrix();
- hits = glRenderMode(GL_RENDER);
- processSelection(hits, selectBuf, select_buf_size);
-}
-
-float GlTracks::left() const
-{
- return max_ortho.left;
-}
-
-float GlTracks::right() const
-{
- return max_ortho.right;
-}
-
-void GlTracks::setViewportCenter(float x)
-{
- update_viewport(x, zoom_level);
- viewport_center = x;
-}
-
-float GlTracks::viewportLeft() const
-{
- return cur_ortho.left;
-}
-
-float GlTracks::viewportCenter() const
-{
- return viewport_center;
-}
-
-float GlTracks::viewportRight() const
-{
- return cur_ortho.right;
-}
-
-float GlTracks::viewportHeight() const
-{
- return cur_ortho.top - cur_ortho.bottom;
-}
-
-float GlTracks::viewportWidth() const
-{
- return cur_ortho.right - cur_ortho.left;
-}
-
-void GlTracks::setZoom(int new_zoom)
-{
- update_viewport(viewport_center, new_zoom);
- zoom_level = new_zoom;
-}
-
-int GlTracks::zoom() const
-{
- return zoom_level;
-}
-
-void GlTracks::setColorMapper(AnnotationColors& cm)
-{
- color_mapper = cm;
-}
-
-AnnotationColors& GlTracks::colorMapper()
-{
- return color_mapper;
-}
-
-void GlTracks::clear()
-{
- clear_links();
- path_segments.clear();
- track_container.clear();
-}
-
-void GlTracks::push_sequence(const Sequence &s)
-{
- GlSequence gs(s, color_mapper);
- push_sequence(gs);
-}
-
-void GlTracks::push_sequence(GlSequence &gs)
-{
- clear_links();
- pathid = 0;
- track_container.push_back(gs);
- update_layout();
- if (track_container.size() > 1)
- path_segments.push_back(pair_segment_map());
-}
-
-const std::vector<GlSequence>& GlTracks::tracks() const
-{
- return track_container;
-}
-
-void GlTracks::clear_links()
-{
- path_segment_map_vector::iterator psmv_i;
- for(psmv_i = path_segments.begin();
- psmv_i != path_segments.end();
- ++psmv_i)
- {
- psmv_i->clear();
- }
-}
-
-void
-GlTracks::link(vector<int> path, vector<bool> rc, int length)
-{
- if (path.size() < 2) {
- // should i throw an error instead?
- return;
- }
- if (path.size() != rc.size()) {
- throw runtime_error("path and reverse compliment must be the same length");
- }
- vector<int>::iterator path_i = path.begin();
- vector<bool>::iterator rc_i = rc.begin();
- int track_i = 0;
- int prev_x = *path_i; ++path_i;
- bool prev_rc = *rc_i; ++rc_i;
- while (path_i != path.end() and rc_i != rc.end())
- {
- segment_key p(prev_x, *path_i);
- pair_segment_map::iterator found_segment = path_segments[track_i].find(p);
- if (found_segment == path_segments[track_i].end()) {
- // not already found
- float y1 = track_container[track_i].y();
- y1 -= track_container[track_i].height()/2;
- float y2 = track_container[track_i+1].y();
- y2 += track_container[track_i+1].height()/2;
-
- Segment s(prev_x, y1, *path_i, y2, prev_rc);
- s.path_ids.insert(pathid);
- path_segments[track_i][p] = s;
- } else {
- //found
- found_segment->second.path_ids.insert(pathid);
- }
- prev_x = *path_i;
- prev_rc = *rc_i;
- ++track_i;
- ++path_i;
- ++rc_i;
- }
- // pathid is reset by push_sequence
- ++pathid;
-}
-
-void GlTracks::update_viewport(float center, int new_zoom)
-{
- float max_width = max_ortho.width();
- // division by zero is a major bummer
- if (new_zoom < 1) {
- new_zoom = 1;
- }
- float new_max_width = max_width / new_zoom;
- cur_ortho.left = center-new_max_width;
- cur_ortho.right = center+new_max_width;
-}
-
-void GlTracks::update_layout()
-{
- typedef std::vector<GlSequence>::iterator glseq_itor_type;
- float available_height = (float)cur_ortho.top - 2 * (float)border;
- float max_base_pairs = 0;
- size_t track_count = track_container.size();
-
- if (track_count > 1) {
- // we have several tracks
- float track_spacing = available_height / (track_count-1);
- float y = available_height + (float)border;
- for(glseq_itor_type seq_i = track_container.begin();
- seq_i != track_container.end();
- ++seq_i, y-=track_spacing)
- {
- seq_i->setX(0);
- seq_i->setY(y);
- if (seq_i->length() > max_base_pairs)
- max_base_pairs = seq_i->length();
- }
- } else if (track_count == 1) {
- // center the single track
- glseq_itor_type seq_i = track_container.begin();
- seq_i->setX(0);
- seq_i->setY(viewport_size.x /2);
- max_base_pairs = seq_i->length();
- } else {
- // nothing to do as we're empty
- return;
- }
- max_ortho.right = max_base_pairs + border;
- max_ortho.left = -border;
- max_ortho.top = viewport_size.x;
- max_ortho.bottom = 0;
- cur_ortho = max_ortho;
- viewport_center = (cur_ortho.width()/2) + cur_ortho.left;
-}
-
-void GlTracks::draw() const
-{
- glMatrixMode(GL_MODELVIEW);
- glInitNames();
- glPushName(MussaSegment);
- draw_segments();
- glLoadName(MussaTrack);
- draw_tracks();
- glPopName();
- // a selection shouldn't have a glName associated with it
- draw_selection();
-}
-
-void GlTracks::draw_selection() const
-{
- // draw selection box
- glEnable(GL_BLEND);
- glDepthMask(GL_FALSE);
- if (selectedMode) {
- glColor4f(0.6, 0.6, 0.6, 0.9);
- glRectf(selectedRegion.left, selectedRegion.top,
- selectedRegion.right, selectedRegion.bottom);
- }
- glDepthMask(GL_TRUE);
- glDisable(GL_BLEND);
-}
-
-void GlTracks::draw_tracks() const
-{
- for(size_t track_i = 0; track_i != track_container.size(); ++track_i)
- {
- glPushName(track_i);
- track_container[track_i].draw(cur_ortho.left, cur_ortho.right);
- glPopName();
- }
-}
-
-void GlTracks::draw_segments() const
-{
- glLineWidth(0.1);
- // each vector contains path_segment_maps of all the connections
- // between this track and the next
- path_segment_map_vector::const_iterator psmv_i;
- for(psmv_i = path_segments.begin();
- psmv_i != path_segments.end();
- ++psmv_i)
- {
- path_segment_map_vector::difference_type path_index;
- path_index = psmv_i - path_segments.begin();
- // these maps contain the pair index (used so we dont keep drawing the
- // same segment) and the actual segment structure.
- pair_segment_map::const_iterator psm_i;
- for(psm_i = psmv_i->begin();
- psm_i != psmv_i->end();
- ++psm_i)
- {
- // grab the index into our segment map
- const segment_key& key = psm_i->first;
- // the second element of our map pair is a segment
- const Segment &s = psm_i->second;
- // need to do something so we can detect our selection
- vector<int> selected;
- set_intersection(selectedPaths.begin(), selectedPaths.end(),
- s.path_ids.begin(), s.path_ids.end(),
- back_inserter(selected));
-
- if (not s.reversed) {
- if (selectedPaths.size() == 0 or selected.size() > 0) {
- glColor3f(1.0, 0.0, 0.0);
- } else {
- glColor3f(1.0, 0.8, 0.8);
- }
- } else {
- if (selectedPaths.size() == 0 or selected.size() > 0) {
- glColor3f(0.0, 0.0, 1.0);
- } else {
- glColor3f(0.8, 0.8, 1.0);
- }
- }
- // save the multipart name for our segment
- glPushName(path_index); glPushName(key.first); glPushName(key.second);
- glBegin(GL_LINES);
- glVertex3f(s.start.x, s.start.y, -1);
- glVertex3f(s.end.x, s.end.y, -1);
- glEnd();
- // clear the names
- glPopName(); glPopName(); glPopName();
- }
- }
-}
+++ /dev/null
-#ifndef _GLTRACKS_H_
-#define _GLTRACKS_H_
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "alg/annotation_colors.hpp"
-#include "alg/sequence.hpp"
-#include "alg/glsequence.hpp"
-
-//! Manage rendering a collection of glSequences
-class GlTracks
-{
-public:
- GlTracks();
- GlTracks(const GlTracks&);
-
- //! setup the opengl canvas
- void initializeGL();
- //! called when our screen canvas is resized
- void resizeGL(int width, int height);
- //! render our scene
- void paintGL() const;
-
- //! select a region (using canvas coordinates)
- void GlTracks::selectRegion(int top, int left, int bottom, int right);
-
- //! max world left coordinate
- float left() const;
- //! max world right coordinate
- float right() const;
-
- void setViewportCenter(float x);
- float viewportLeft() const;
- float viewportCenter() const;
- float viewportRight() const;
- float viewportHeight() const;
- float viewportWidth() const;
-
- void setZoom(int zoom_level);
- int zoom() const;
-
- void setColorMapper(AnnotationColors& cm);
- AnnotationColors& colorMapper();
-
- //! clear our tracks and connections
- void clear();
-
- //! add a sequence to the back of our track container
- void push_sequence(const Sequence &s);
- //! add a glsequence to the back of our track container
- void push_sequence(GlSequence &s);
- //! return our track container
- const std::vector<GlSequence>& tracks() const;
-
- //! clear all the line segments between all the sequences
- void clear_links();
- //! define a path
- void link(std::vector<int> path, std::vector<bool> isRC, int length);
-
- //! Provide a logical name for a type discriminator for our glName stack
- enum FeatureType { MussaTrack, MussaSegment };
-
- //! a useful point class
- template<class T> struct point {
- T x;
- T y;
-
- point(T x_, T y_):x(x_), y(y_) {}
- };
-
- //! a useful rectangle, where 0,0 is in the lower left
- template<class T> struct rect {
- T top;
- T left;
- T bottom;
- T right;
-
- rect() {}
- rect(T t, T l, T b, T r) : top(t), left(l), bottom(b), right(r) {}
- T width() { return right - left; }
- T height() { return top - bottom; }
- };
-
- struct Segment
- {
- point<float> start;
- point<float> end;
- bool reversed;
- std::set<int> path_ids;
-
- Segment() : start(0.0, 0.0), end(0.0, 0.0) {}
- Segment(float x1, float y1, float x2, float y2, bool isRC)
- : start(x1, y1), end(x2, y2), reversed(isRC) {}
- };
-
- //! data structure holding our line segments
- /*! the vector is of size track_container.size()-1
- * it's indexed by the pair x1, x2 (the two x coordinates between
- * the two tracks
- */
- typedef std::pair<int, int> segment_key;
- typedef std::map<segment_key, Segment> pair_segment_map;
- typedef std::vector<pair_segment_map> path_segment_map_vector;
- path_segment_map_vector path_segments;
-private:
- //! recalculate the viewable world
- /*! depending on the size of our canvas, our zoom level and
- * how far we've been offset
- */
- void update_viewport(float center, int new_zoom);
-
- //! determine where all the tracks should be placed
- void update_layout();
-
- //! convert opengl selections into the list of paths we should highlight
- void processSelection(GLuint hits, GLuint buffer[], GLuint bufsize);
-
- //! master scene drawing function
- /*! draw is broken out for the opengl selection code
- */
- void draw() const;
- //! draw glsequence tracks
- void draw_tracks() const;
- //! draw line segments between tracks
- void draw_segments() const;
- //! draw selection box
- void draw_selection() const;
-
- //! number of pixels to reserve around the edges of our canvas
- const int border;
- //! the maximum dimensions that our scene is taking up (world coord)
- rect<float> max_ortho;
- //! the current viewable region (world coord)
- rect<float> cur_ortho;
- //! how many pixels our viewport is (screen coord)
- point<int> viewport_size;
- //! the center of our current viewport (world coord) (used for scrollbar)
- float viewport_center;
- int zoom_level;
- AnnotationColors color_mapper;
- //! container of all the GlSequences loaded into our scene
- std::vector<GlSequence> track_container;
- //! counter for each path added to us via connect
- int pathid;
-
-protected:
- //! where to draw our box
- rect<float> selectedRegion;
- //! true if we have a selection
- bool selectedMode;
- //! indicate which paths are selected
- std::set<int> selectedPaths;
- //! which track is selected (it only makes sense to have one track selected).
- std::set<int> selectedTracks;
-
-};
-#endif
MUSSA_ALG_OBJ := $(MUSSA_ALG_SRC:.cpp=$(OBJEXT))
GLSOURCES.cpp := glsequence.cpp \
- gltracks.cpp
+ glseqbrowser.cpp
MUSSA_ALG_GL_SRC := $(addprefix $(CURDIR), $(GLSOURCES.cpp))
MUSSA_ALG_GL_OBJ := $(MUSSA_ALG_GL_SRC:.cpp=$(OBJEXT))
test_conserved_path.cpp \
test_flp.cpp \
test_glsequence.cpp \
- test_gltracks.cpp \
+ test_glseqbrowser.cpp \
test_color.cpp \
test_main.cpp \
test_mussa.cpp \
BOOST_CHECK_EQUAL( ac.lookup("bleem", "a"), black);
}
+// can we assign a color?
+BOOST_AUTO_TEST_CASE( annotation_color_assignment )
+{
+ Color black(0.0, 0.0, 0.0);
+ Color white(1.0, 1.0, 1.0);
+ Color red(1.0, 0.0, 0.0);
+
+ AnnotationColors ac1;
+ ac1.setColor(white);
+ ac1.appendTypeColor("bleem", black);
+ ac1.appendInstanceColor("bleem", "a", red);
+
+ AnnotationColors ac2;
+ BOOST_CHECK_EQUAL( ac2.color(), black );
+ ac2 = ac1;
+ BOOST_CHECK_EQUAL( ac2.color(), white );
+ BOOST_CHECK_EQUAL( ac2.typeColor("bleem"), ac1.typeColor("bleem") );
+ BOOST_CHECK_EQUAL( ac2.lookup("bleem","a"), ac1.lookup("bleem","a") );
+}
--- /dev/null
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/assign/std/vector.hpp>
+using namespace boost::assign;
+
+#include <string>
+#include <list>
+#include <vector>
+
+#include "alg/annotation_colors.hpp"
+#include "alg/glseqbrowser.hpp"
+#include "alg/sequence.hpp"
+
+using namespace std;
+
+BOOST_AUTO_TEST_CASE ( gltracks_connect )
+{
+ string s0("AAGGCCTT");
+ string s1("TTGGCCAA");
+ string s2("GATTACAA");
+ Sequence seq0(s0);
+ Sequence seq1(s1);
+ Sequence seq2(s2);
+
+ GlSeqBrowser gt;
+ gt.push_sequence(seq0);
+ gt.push_sequence(seq1);
+ gt.push_sequence(seq2);
+
+ // make up some sample data
+ vector<bool> rc;
+ rc += false, false, false;
+ vector<int> path;
+ path += 1,1,1; gt.link(path, rc, 1);
+ path.clear(); path += 1,1,3; gt.link(path, rc, 1);
+ path.clear(); path += 2,3,3; gt.link(path, rc, 1);
+ path.clear(); path += 3,3,3; gt.link(path, rc, 1);
+
+ BOOST_CHECK_EQUAL( gt.path_segments.size(), 2 );
+ GlSeqBrowser::segment_key p(1, 1);
+ GlSeqBrowser::pair_segment_map::iterator psm_i = gt.path_segments[0].find(p);
+ BOOST_CHECK( psm_i != gt.path_segments[0].end() );
+ BOOST_CHECK_EQUAL( psm_i->second.path_ids.size(), 2 );
+
+ gt.clear();
+ BOOST_CHECK_EQUAL( gt.path_segments.size(), 0 );
+}
+
+++ /dev/null
-#include <boost/test/auto_unit_test.hpp>
-#include <boost/assign/std/vector.hpp>
-using namespace boost::assign;
-
-#include <string>
-#include <list>
-#include <vector>
-
-#include "alg/annotation_colors.hpp"
-#include "alg/gltracks.hpp"
-#include "alg/sequence.hpp"
-
-using namespace std;
-
-BOOST_AUTO_TEST_CASE ( gltracks_connect )
-{
- string s0("AAGGCCTT");
- string s1("TTGGCCAA");
- string s2("GATTACAA");
- Sequence seq0(s0);
- Sequence seq1(s1);
- Sequence seq2(s2);
-
- GlTracks gt;
- gt.push_sequence(seq0);
- gt.push_sequence(seq1);
- gt.push_sequence(seq2);
-
- // make up some sample data
- vector<bool> rc;
- rc += false, false, false;
- vector<int> path;
- path += 1,1,1; gt.link(path, rc, 1);
- path.clear(); path += 1,1,3; gt.link(path, rc, 1);
- path.clear(); path += 2,3,3; gt.link(path, rc, 1);
- path.clear(); path += 3,3,3; gt.link(path, rc, 1);
-
- BOOST_CHECK_EQUAL( gt.path_segments.size(), 2 );
- GlTracks::segment_key p(1, 1);
- GlTracks::pair_segment_map::iterator psm_i = gt.path_segments[0].find(p);
- BOOST_CHECK( psm_i != gt.path_segments[0].end() );
- BOOST_CHECK_EQUAL( psm_i->second.path_ids.size(), 2 );
-
- gt.clear();
- BOOST_CHECK_EQUAL( gt.path_segments.size(), 0 );
-}
-
#include <QApplication>
-#include "qui/PathWindow.hpp"
+#include "qui/MussaWindow.hpp"
#include "alg/parse_options.hpp"
int main(int argc, char **argv)
return 1;
}
- PathWindow win(analysis);
+ MussaWindow win(analysis);
win.show();
app.exec();
return 0;
# Input
HEADERS += mussa_exceptions.hpp \
- qui/PathWidget.hpp \
- qui/PathWindow.hpp \
- qui/PathScene.hpp \
- qui/PathSidebar.hpp \
- qui/ScrollableScene.hpp \
- qui/SequenceDescription.hpp \
+ qui/MussaWindow.hpp \
qui/ThresholdWidget.hpp \
qui/ImageScaler.hpp \
qui/ImageSaveDialog.hpp \
+ qui/seqbrowser/SequenceBrowserWidget.hpp \
+ qui/seqbrowser/SequenceBrowser.hpp \
+ qui/seqbrowser/SequenceBrowserSidebar.hpp \
+ qui/seqbrowser/ScrollableSequenceBrowser.hpp \
+ qui/seqbrowser/SequenceDescription.hpp \
alg/annotation_colors.hpp \
alg/color.hpp \
alg/conserved_path.hpp \
alg/flp.hpp \
alg/glsequence.hpp \
- alg/gltracks.hpp \
+ alg/glseqbrowser.hpp \
alg/mussa.hpp \
alg/nway_paths.hpp \
alg/parse_options.hpp \
alg/sequence.hpp
SOURCES += mussagl.cpp \
- qui/PathWidget.cpp \
- qui/PathWindow.cpp \
- qui/PathScene.cpp \
- qui/PathSidebar.cpp \
- qui/ScrollableScene.cpp \
- qui/SequenceDescription.cpp \
+ qui/MussaWindow.cpp \
qui/ThresholdWidget.cpp \
qui/ImageScaler.cpp \
qui/ImageSaveDialog.cpp \
+ qui/seqbrowser/SequenceBrowserWidget.cpp \
+ qui/seqbrowser/SequenceBrowser.cpp \
+ qui/seqbrowser/SequenceBrowserSidebar.cpp \
+ qui/seqbrowser/ScrollableSequenceBrowser.cpp \
+ qui/seqbrowser/SequenceDescription.cpp \
alg/annotation_colors.cpp \
alg/color.cpp \
alg/conserved_path.cpp \
alg/flp.cpp \
alg/flp_seqcomp.cpp \
alg/glsequence.cpp \
- alg/gltracks.cpp \
+ alg/glseqbrowser.cpp \
alg/mussa.cpp \
alg/nway_entropy.cpp \
alg/nway_other.cpp \
--- /dev/null
+#include <QAction>
+#include <QDir>
+#include <QFileDialog>
+#include <QHBoxLayout>
+#include <QIcon>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QScrollBar>
+#include <QStatusBar>
+#include <QString>
+#include <QWhatsThis>
+
+#include "qui/MussaWindow.hpp"
+#include "mussa_exceptions.hpp"
+
+#include <iostream>
+
+using namespace std;
+
+MussaWindow::MussaWindow(Mussa *analysis_, QWidget *parent) :
+ QMainWindow(parent),
+ analysis(analysis_),
+ browser(this),
+ mussaViewTB("Path Views"),
+ zoomBox(),
+ threshold(),
+ closeAction(0) // initialize one of the pointers to null as a saftey flag
+{
+ setupActions();
+ setupMainMenu();
+
+ //This next setWhatsThis function prevents
+ // a segfault when using WhatsThis feature with
+ // opengl widget.
+ //scene->setWhatsThis(tr("Mussa in OpenGL!"));
+ setCentralWidget(&browser);
+
+ mussaViewTB.addAction(toggleMotifsAction);
+
+ zoomBox.setWhatsThis("zoom magnification factor");
+ zoomBox.setRange(2,1000);
+ mussaViewTB.addWidget(&zoomBox);
+ connect(&zoomBox, SIGNAL(valueChanged(int)),
+ &browser, SLOT(setZoom(int)));
+
+ threshold.setRange(19, 30);
+ threshold.setThreshold(19);
+ //scene->setClipPlane(20);
+ // FIXME: for when we get the paths drawn at the appropriate depth
+ //connect(&threshold, SIGNAL(thresholdChanged(int)),
+ // this, SLOT(setClipPlane(int)));
+ connect(&threshold, SIGNAL(thresholdChanged(int)),
+ this, SLOT(setSoftThreshold(int)));
+ mussaViewTB.addWidget(&threshold);
+
+ addToolBar(&mussaViewTB);
+
+ statusBar()->showMessage("Welcome to mussa", 2000);
+ updateAnalysis();
+}
+
+void MussaWindow::setupActions()
+{
+ // we really don't want to run this more than once.
+ assert (closeAction == 0);
+
+ // the ever popular about box
+ aboutAction = new QAction(tr("&About"), this);
+ connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
+ aboutAction->setIcon(QIcon("icons/info.png"));
+
+ // add exit
+ closeAction = new QAction(tr("&Close"), this);
+ closeAction->setStatusTip(tr("Close this window"));
+ connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
+ closeAction->setIcon(QIcon("icons/exit.png"));
+
+ createNewAnalysisAction = new QAction(tr("Define Analysis"), this);
+ connect(createNewAnalysisAction, SIGNAL(triggered()),
+ this, SLOT(createNewAnalysis()));
+ createNewAnalysisAction->setIcon(QIcon("icons/filenew.png"));
+
+ createSubAnalysisAction = new QAction(tr("Define SubAnalysis"), this);
+ connect(createSubAnalysisAction, SIGNAL(triggered()),
+ this, SLOT(createSubAnalysis()));
+
+ loadMotifListAction = new QAction(tr("Load Motif List"), this);
+ connect(loadMotifListAction, SIGNAL(triggered()),
+ this, SLOT(loadMotifList()));
+
+ loadMupaAction = new QAction(tr("Load Mussa Parameters"), this);
+ connect(loadMupaAction, SIGNAL(triggered()),
+ this, SLOT(loadMupa()));
+
+ loadSavedAnalysisAction = new QAction(tr("Load &Analysis"), this);
+ connect(loadSavedAnalysisAction, SIGNAL(triggered()),
+ this, SLOT(loadSavedAnalysis()));
+ loadSavedAnalysisAction->setIcon(QIcon("icons/fileopen.png"));
+
+ saveMotifListAction = new QAction(tr("Save Motifs"), this);
+ connect(saveMotifListAction, SIGNAL(triggered()),
+ this, SLOT(saveMotifList()));
+ saveMotifListAction->setIcon(QIcon("icons/filesave.png"));
+
+ showMussaViewToolbarAction = new QAction(tr("Show Toolbar"), this);
+ connect(showMussaViewToolbarAction, SIGNAL(triggered()),
+ this, SLOT(showMussaToolbar()));
+ showMussaViewToolbarAction->setCheckable(true);
+ showMussaViewToolbarAction->setChecked(true);
+
+ toggleMotifsAction = new QAction(tr("Toggle Motifs"), this);
+ connect(toggleMotifsAction, SIGNAL(triggered()),
+ this, SLOT(toggleMotifs()));
+ toggleMotifsAction->setCheckable(true);
+ toggleMotifsAction->setIcon(QIcon("icons/motif_icon.png"));
+ toggleMotifsAction->setWhatsThis(tr("Toggle motif annotations on/off\n\n"
+ "You can load motif annotations via "
+ "'File->Load Motif List' menu option."));
+
+ whatsThisAction = QWhatsThis::createAction(this);
+ whatsThisAction->setIcon(QIcon("icons/help.png"));
+
+ //Save pixel map action
+ saveBrowserPixmapAction = new QAction(tr("Save to image..."), this);
+ connect(saveBrowserPixmapAction, (SIGNAL(triggered())),
+ &browser, SLOT(promptSaveBrowserPixmap()));
+ saveBrowserPixmapAction->setIcon(QIcon("icons/image2.png"));
+}
+
+void MussaWindow::setupMainMenu()
+{
+ // we need to run setupActions first
+ assert (closeAction != 0);
+
+ QMenu *newMenu;
+ newMenu = menuBar()->addMenu(tr("&File"));
+ newMenu->addAction(createNewAnalysisAction);
+ newMenu->addAction(loadMupaAction);
+ newMenu->addAction(loadSavedAnalysisAction);
+ newMenu->addAction(createSubAnalysisAction);
+ newMenu->addSeparator();
+ newMenu->addAction(loadMotifListAction);
+ newMenu->addAction(saveMotifListAction);
+ newMenu->addSeparator();
+ newMenu->addAction(saveBrowserPixmapAction);
+ newMenu->addSeparator();
+ newMenu->addAction(closeAction);
+
+ newMenu = menuBar()->addMenu(tr("&View"));
+ newMenu->addAction(showMussaViewToolbarAction);
+
+ newMenu = menuBar()->addMenu(tr("&Help"));
+ newMenu->addAction(whatsThisAction);
+ newMenu->addSeparator();
+ newMenu->addAction(aboutAction);
+}
+
+void MussaWindow::about()
+{
+ QMessageBox::about(this, tr("About mussa"),
+ tr("Welcome to Multiple Species Sequence Analysis\n"
+ "(c) 2005-2006 California Institute of Technology\n"
+ "Tristan De Buysscher, Diane Trout\n"));
+}
+
+void MussaWindow::createNewAnalysis()
+{
+ NotImplementedBox();
+}
+
+void MussaWindow::createSubAnalysis()
+{
+ NotImplementedBox();
+}
+
+
+void MussaWindow::loadMotifList()
+{
+ QString caption("Load a motif list");
+ QString filter("Motif list(*.txt *.mtl)");
+ QString path = QFileDialog::getOpenFileName(this,
+ caption,
+ QDir::currentPath(),
+ filter);
+ // user hit cancel?
+ if (path.isNull())
+ return;
+ // try to load safely
+ try {
+ analysis->load_motifs(path.toStdString());
+ } catch (runtime_error e) {
+ QString msg("Unable to load ");
+ msg += path;
+ msg += "\n";
+ msg += e.what();
+ QMessageBox::warning(this, "Load Motifs", msg);
+ }
+ assert (analysis != 0);
+}
+
+void MussaWindow::saveMotifList()
+{
+ NotImplementedBox();
+}
+
+void MussaWindow::loadMupa()
+{
+ QString caption("Load a mussa parameter file");
+ QString filter("Mussa Parameters (*.mupa)");
+ QString mupa_path = QFileDialog::getOpenFileName(this,
+ caption,
+ QDir::currentPath(),
+ filter);
+ // user hit cancel?
+ if (mupa_path.isNull())
+ return;
+ // try to load safely
+ try {
+ Mussa *m = new Mussa;
+ m->load_mupa_file(mupa_path.toStdString());
+ m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
+ // only switch mussas if we loaded without error
+ delete analysis;
+ analysis = m;
+ updateAnalysis();
+ } catch (mussa_load_error e) {
+ QString msg("Unable to load ");
+ msg += mupa_path;
+ msg += "\n";
+ msg += e.what();
+ QMessageBox::warning(this, "Load Parameter", msg);
+ }
+ assert (analysis != 0);
+}
+
+void MussaWindow::loadSavedAnalysis()
+{
+ QString caption("Load a previously run analysis");
+ QString muway_dir = QFileDialog::getExistingDirectory(this,
+ caption,
+ QDir::currentPath());
+ // user hit cancel?
+ if (muway_dir.isNull())
+ return;
+ // try to safely load
+ try {
+ Mussa *m = new Mussa;
+ m->load(muway_dir.toStdString());
+ // only switch mussas if we loaded without error
+ delete analysis;
+ analysis = m;
+ updateAnalysis();
+ } catch (mussa_load_error e) {
+ QString msg("Unable to load ");
+ msg += muway_dir;
+ msg += "\n";
+ msg += e.what();
+ QMessageBox::warning(this, "Load Parameter", msg);
+ }
+ assert (analysis != 0);
+}
+
+void MussaWindow::setSoftThreshold(int threshold)
+{
+ if (analysis->get_soft_thres() != threshold) {
+ analysis->set_soft_thres(threshold);
+ analysis->nway();
+ updateLinks();
+ update();
+ }
+}
+
+void MussaWindow::showMussaToolbar()
+{
+ if (mussaViewTB.isVisible())
+ mussaViewTB.hide();
+ else
+ mussaViewTB.show();
+}
+
+void MussaWindow::toggleMotifs()
+{
+ NotImplementedBox();
+}
+
+void MussaWindow::NotImplementedBox()
+{
+ QMessageBox::warning(this, QObject::tr("mussa"), QObject::tr("Not implemented yet"));
+}
+
+void MussaWindow::updateAnalysis()
+{
+ cout << "analysis updated" << endl;
+ browser.clear();
+ const vector<Sequence>& seqs = analysis->sequences();
+ browser.setSequences(seqs, analysis->colorMapper());
+ updateLinks();
+}
+
+void MussaWindow::updateLinks()
+{
+ browser.clear_links();
+ bool reversed = false;
+ const NwayPaths& nway = analysis->paths();
+
+ typedef list<ExtendedConservedPath> conserved_paths;
+ typedef conserved_paths::const_iterator const_conserved_paths_itor;
+ for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
+ path_itor != nway.refined_pathz.end();
+ ++path_itor)
+ {
+ // since we were drawing to the start of a window, and opengl lines
+ // are centered around the two connecting points our lines were slightly
+ // offset. the idea of window_offset is to adjust them to the
+ // right for forward compliment or left for reverse compliment
+ // FIXME: figure out how to unit test these computations
+ //GLfloat window_offset = (path_itor->window_size)/2.0;
+
+ size_t track_len = path_itor->track_indexes.size();
+ vector<int> normalized_path;
+ normalized_path.reserve(track_len);
+ vector<bool> rc_flags(false, track_len);
+ for (size_t track_i=0; track_i != track_len; ++track_i)
+ {
+ int x = path_itor->track_indexes[track_i];
+ // at some point when we modify the pathz data structure to keep
+ // track of the score we can put grab the depth here.
+ //
+ // are we reverse complimented?
+ if ( x>=0) {
+ reversed = false;
+ } else {
+ reversed = true;
+ x = -x; // make positive
+ }
+ normalized_path.push_back(x);
+ rc_flags.push_back(reversed);
+ }
+ browser.link(normalized_path, rc_flags, path_itor->window_size);
+ }
+ browser.update();
+}
+
--- /dev/null
+#ifndef _MUSSAWINDOW_H_
+#define _MUSSAWINDOW_H_
+
+#include <QMainWindow>
+#include <QPixmap>
+#include <QSpinBox>
+#include <QToolBar>
+
+#include "qui/seqbrowser/SequenceBrowserWidget.hpp"
+#include "qui/ThresholdWidget.hpp"
+
+class QAction;
+class Mussa;
+
+class MussaWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MussaWindow(Mussa* analysis=0, QWidget *parent=0);
+
+public slots:
+ //! display an about box, contemplating the politics of the author list
+ void about();
+
+ //! \defgroup AnalysisFunctions Components related to running analyses
+ //\@{
+ //! open a window to collect the information needed to create a new analysis
+ void createNewAnalysis();
+ //! launch a sub analysis
+ void createSubAnalysis();
+ //\@}
+
+ //! \defgroup MotifHandling Handling of motif lists
+ //\@{
+ //! load motifs
+ void loadMotifList();
+ void saveMotifList();
+ void toggleMotifs();
+ //\@}
+
+ //! load a mussa parameter file (which specifies an analysis to run)
+ void loadMupa();
+ //! load a previously run analysis
+ void loadSavedAnalysis();
+ //! set the soft threshold used by the Nway_Path algorithm
+ void setSoftThreshold(int thres);
+
+ void showMussaToolbar();
+
+protected:
+ Mussa *analysis;
+ // display our wonderful mussa output
+ SequenceBrowserWidget browser;
+ QToolBar mussaViewTB;
+ QSpinBox zoomBox;
+ ThresholdWidget threshold;
+
+ QAction *aboutAction;
+ QAction *closeAction;
+ QAction *createNewAnalysisAction;
+ QAction *createSubAnalysisAction;
+ QAction *loadMotifListAction;
+ QAction *loadMupaAction;
+ QAction *loadSavedAnalysisAction;
+ QAction *saveMotifListAction;
+ QAction *showMussaViewToolbarAction;
+ QAction *toggleMotifsAction;
+ QAction *whatsThisAction;
+ QAction *saveBrowserPixmapAction;
+
+ //! initialze the actions
+ void setupActions();
+ //! initialize this windows menu object
+ void setupMainMenu();
+ //! stub function to fill in QActions
+ void NotImplementedBox();
+ //! update the SequenceBrowser with our analysis
+ void updateAnalysis();
+ //! update the view of conserved windows
+ void updateLinks();
+};
+
+#endif
+++ /dev/null
-#include <QDir>
-#include <QFileDialog>
-#include <QMessageBox>
-#include <QMouseEvent>
-#include <QRubberBand>
-#include <QRect>
-#include <QString>
-#include <iostream>
-#include <set>
-
-#include <GL/gl.h>
-#include <math.h>
-
-#include "qui/PathScene.hpp"
-#include "alg/glsequence.hpp"
-#include "mussa_exceptions.hpp"
-
-using namespace std;
-
-PathScene::PathScene(QWidget *parent)
- : QGLWidget(parent),
- rubberBand(0),
- drawingBand(false)
-{
-}
-
-QSize PathScene::sizeHint() const
-{
- //return QSize((int)GlTracks::viewportHeight(), (int)GlTracks::viewportWidth());
- return QSize(600, 400);
-}
-
-void PathScene::setViewportCenter(float x)
-{
- const float epsilon = 1e-10;
- float center = GlTracks::viewportCenter();
- float difference = fabsf(x - center);
- float abs_x = fabsf(x);
- center = fabsf(center);
-
- // the difference < epsilon * val is one of the recommended tests
- // for float equality.
- // of course since we're looking for not equals, we need to toss a
- // not at the beginning
- if (not (difference < epsilon * abs_x or difference < epsilon * center))
- {
- GlTracks::setViewportCenter(x);
- emit viewportChanged();
- update();
- }
-}
-
-void PathScene::setZoom(int new_zoom)
-{
- if (new_zoom != GlTracks::zoom()) {
- GlTracks::setZoom(new_zoom);
- emit viewportChanged();
- update();
- }
-}
-
-void PathScene::setClipPlane(int )
-{
-/*
- if (clipZ != (double) newZ){
- clipZ = (double) newZ;
- update();
- }
-*/
-}
-
-void PathScene::clear()
-{
- GlTracks::clear();
- emit tracksChanged();
-}
-
-void PathScene::push_sequence(const Sequence &s)
-{
- GlTracks::push_sequence(s);
- emit tracksChanged();
-}
-
-void PathScene::push_sequence(GlSequence &gs)
-{
- GlTracks::push_sequence(gs);
- emit tracksChanged();
-}
-
-////////////////////
-// Rendering code
-void PathScene::initializeGL()
-{
- GlTracks::initializeGL();
-}
-
-void PathScene::resizeGL(int width, int height)
-{
- GlTracks::resizeGL(width, height);
-}
-
-void PathScene::paintGL()
-{
- GlTracks::paintGL();
-}
-
-void PathScene::mousePressEvent( QMouseEvent *e)
-{
- drawingBand = true;
-
- selectedMode = false;
- bandOrigin = e->pos();
- if (!rubberBand)
- rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
-
- rubberBand->setGeometry(QRect(bandOrigin, QSize()));
- rubberBand->show();
-}
-
-void PathScene::mouseMoveEvent( QMouseEvent *e)
-{
- if (drawingBand)
- rubberBand->setGeometry(QRect(bandOrigin, e->pos()).normalized());
-}
-
-void PathScene::mouseReleaseEvent( QMouseEvent *e)
-{
- drawingBand = false;
- rubberBand->hide();
- QRect r = QRect(bandOrigin, e->pos()).normalized();
- bandOrigin = r.topLeft();
-
- selectRegion(r.top(), r.left(), r.bottom(), r.right());
-}
+++ /dev/null
-#ifndef _PATHSCENE_H_
-#define _PATHSCENE_H_
-
-#include <QGLWidget>
-#include <QRectF>
-#include <QPoint>
-#include <vector>
-#include <GL/gl.h>
-
-#include "alg/mussa.hpp"
-#include "alg/glsequence.hpp"
-#include "alg/gltracks.hpp"
-
-class QMouseEvent;
-class QRubberBand;
-
-/*! \brief Render mussa sequences and paths
- */
-class PathScene: public QGLWidget, public GlTracks
-{
- Q_OBJECT
-
-public:
- PathScene(QWidget *parent=0);
-
- QSize sizeHint() const;
-
- void clear();
- void push_sequence(const Sequence &s);
- void push_sequence(GlSequence &);
-
-public slots:
- void setClipPlane(int z);
- //! set the center of the current viewport
- void setViewportCenter(float x);
- //! set our magnification level
- void setZoom(int);
-
-signals:
- //! emited when someone adds to our list of tracks
- void tracksChanged();
- void viewportChanged();
-
-private:
- void initializeGL();
- void resizeGL(int height, int width);
- void paintGL();
-
- //! \defgroup Selection
- QRubberBand *rubberBand;
- QPoint bandOrigin;
- bool drawingBand;
- void mousePressEvent(QMouseEvent *);
- void mouseMoveEvent(QMouseEvent *);
- void mouseReleaseEvent(QMouseEvent *);
-};
-#endif
+++ /dev/null
-#include "qui/PathSidebar.hpp"
-#include "alg/glsequence.hpp"
-
-using namespace std;
-
-PathSidebar::PathSidebar(QWidget* parent)
- : QWidget(parent)
-{
- setLayout(&layout);
-}
-
-void PathSidebar::updateSidebar(PathScene& scene)
-{
- for (vector<SequenceDescription *>::iterator desc_i = descriptions.begin();
- desc_i != descriptions.end();
- ++desc_i)
- {
- layout.removeWidget(*desc_i);
- }
- descriptions.clear();
- cout << "sidebar " << scene.tracks().size() << endl;
- for (vector<GlSequence>::const_iterator track_i = scene.tracks().begin();
- track_i != scene.tracks().end();
- ++track_i)
- {
- cout << " " << track_i->sequence().length() << endl;
- SequenceDescription *desc = new SequenceDescription(this);
- //disc->setName(track_i->sequence().name());
- desc->setLength(track_i->sequence().length());
- //desc->setPosition(track_i->sequence().length());
- descriptions.push_back(desc);
- layout.addWidget(desc);
- }
- setLayout(&layout);
-}
+++ /dev/null
-#ifndef _PATH_SIDEBAR_H
-#define _PATH_SIDEBAR_H
-
-#include <vector>
-
-#include <QVBoxLayout>
-#include <QWidget>
-#include "qui/PathScene.hpp"
-#include "qui/SequenceDescription.hpp"
-
-//! store a collection of sequence descriptions for the PathWidget
-class PathSidebar : public QWidget
-{
-public:
- PathSidebar(QWidget *parent = 0);
-
- void updateSidebar(PathScene& scene);
- QVBoxLayout layout;
- std::vector<SequenceDescription *> descriptions;
-};
-#endif
+++ /dev/null
-#include <iostream>
-
-#include <QLabel>
-#include <QScrollBar>
-#include <QSpacerItem>
-#include <QSplitter>
-#include <QVBoxLayout>
-#include <QWidget>
-
-#include "qui/PathScene.hpp"
-#include "qui/PathWidget.hpp"
-#include "qui/ScrollableScene.hpp"
-#include "qui/SequenceDescription.hpp"
-#include "alg/glsequence.hpp"
-
-#include <math.h>
-using namespace std;
-
-PathWidget::PathWidget(QWidget *parent)
- : QSplitter(parent),
- scrollable_scene(parent)
-{
- setOrientation(Qt::Horizontal);
-
- addWidget(&left_sidebar);
- addWidget(&scrollable_scene);
- addWidget(&right_sidebar);
-
- connect(&scrollable_scene.scene(), SIGNAL(viewportChanged()),
- this, SLOT(updatePosition()));
-}
-
-void PathWidget::updateTracks()
-{
- left_sidebar.updateSidebar(scrollable_scene.scene());
- right_sidebar.updateSidebar(scrollable_scene.scene());
- updatePosition();
-}
-
-void PathWidget::updatePosition()
-{
- const PathScene& scene = scrollable_scene.scene();
- const vector<GlSequence> &tracks = scene.tracks();
- vector<SequenceDescription *> left = left_sidebar.descriptions;
- vector<SequenceDescription *> right = right_sidebar.descriptions;
- for(size_t i = 0; i != tracks.size() and i != right.size(); ++i)
- {
- left[i]->setPosition(tracks[i].leftbase(scene.viewportLeft()));
- right[i]->setPosition(tracks[i].rightbase(scene.viewportRight()));
- }
-}
+++ /dev/null
-#ifndef _PATH_WIDGET_H_
-#define _PATH_WIDGET_H_
-
-#include <QSplitter>
-
-#include "qui/ScrollableScene.hpp"
-#include "qui/PathSidebar.hpp"
-
-class PathWidget : public QSplitter
-{
- Q_OBJECT
-
-public:
- PathWidget(QWidget *parent=0);
-
- PathScene& scene() { return scrollable_scene.scene(); }
-
-public slots:
- //! when a scene changes its tracks lets update some of our meta info
- void updateTracks();
- void updatePosition();
-
-private:
- ScrollableScene scrollable_scene;
- PathSidebar left_sidebar;
- PathSidebar right_sidebar;
-};
-#endif
+++ /dev/null
-#include <QAction>
-#include <QDir>
-#include <QFileDialog>
-#include <QHBoxLayout>
-#include <QIcon>
-#include <QMenuBar>
-#include <QMessageBox>
-#include <QScrollBar>
-#include <QStatusBar>
-#include <QString>
-#include <QWhatsThis>
-
-#include "qui/PathScene.hpp"
-#include "qui/PathWindow.hpp"
-#include "qui/ImageSaveDialog.hpp"
-#include "mussa_exceptions.hpp"
-
-#include <iostream>
-
-using namespace std;
-
-PathWindow::PathWindow(Mussa *analysis_, QWidget *parent) :
- QMainWindow(parent),
- analysis(analysis_),
- path_view(this),
- mussaViewTB("Path Views"),
- zoomBox(),
- threshold(),
- closeAction(0) // initialize one of the pointers to null as a saftey flag
-{
- setupActions();
- setupMainMenu();
-
- //This next setWhatsThis function prevents
- // a segfault when using WhatsThis feature with
- // opengl widget.
- //scene->setWhatsThis(tr("Mussa in OpenGL!"));
- setCentralWidget(&path_view);
-
- mussaViewTB.addAction(toggleMotifsAction);
-
- zoomBox.setWhatsThis("zoom magnification factor");
- zoomBox.setRange(2,1000);
- mussaViewTB.addWidget(&zoomBox);
- connect(&zoomBox, SIGNAL(valueChanged(int)),
- &path_view.scene(), SLOT(setZoom(int)));
-
- threshold.setRange(19, 30);
- threshold.setThreshold(19);
- //scene->setClipPlane(20);
- // FIXME: for when we get the paths drawn at the appropriate depth
- //connect(&threshold, SIGNAL(thresholdChanged(int)),
- // this, SLOT(setClipPlane(int)));
- connect(&threshold, SIGNAL(thresholdChanged(int)),
- this, SLOT(setSoftThreshold(int)));
- mussaViewTB.addWidget(&threshold);
-
- addToolBar(&mussaViewTB);
-
- statusBar()->showMessage("Welcome to mussa", 2000);
- updateAnalysis();
-}
-
-void PathWindow::setupActions()
-{
- // we really don't want to run this more than once.
- assert (closeAction == 0);
-
- // the ever popular about box
- aboutAction = new QAction(tr("&About"), this);
- connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
- aboutAction->setIcon(QIcon("icons/info.png"));
-
- // add exit
- closeAction = new QAction(tr("&Close"), this);
- closeAction->setStatusTip(tr("Close this window"));
- connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
- closeAction->setIcon(QIcon("icons/exit.png"));
-
- createNewAnalysisAction = new QAction(tr("Define Analysis"), this);
- connect(createNewAnalysisAction, SIGNAL(triggered()),
- this, SLOT(createNewAnalysis()));
- createNewAnalysisAction->setIcon(QIcon("icons/filenew.png"));
-
- createSubAnalysisAction = new QAction(tr("Define SubAnalysis"), this);
- connect(createSubAnalysisAction, SIGNAL(triggered()),
- this, SLOT(createSubAnalysis()));
-
- loadMotifListAction = new QAction(tr("Load Motif List"), this);
- connect(loadMotifListAction, SIGNAL(triggered()),
- this, SLOT(loadMotifList()));
-
- loadMupaAction = new QAction(tr("Load Mussa Parameters"), this);
- connect(loadMupaAction, SIGNAL(triggered()),
- this, SLOT(loadMupa()));
-
- loadSavedAnalysisAction = new QAction(tr("Load &Analysis"), this);
- connect(loadSavedAnalysisAction, SIGNAL(triggered()),
- this, SLOT(loadSavedAnalysis()));
- loadSavedAnalysisAction->setIcon(QIcon("icons/fileopen.png"));
-
- saveMotifListAction = new QAction(tr("Save Motifs"), this);
- connect(saveMotifListAction, SIGNAL(triggered()),
- this, SLOT(saveMotifList()));
- saveMotifListAction->setIcon(QIcon("icons/filesave.png"));
-
- showMussaViewToolbarAction = new QAction(tr("Show Toolbar"), this);
- connect(showMussaViewToolbarAction, SIGNAL(triggered()),
- this, SLOT(showMussaToolbar()));
- showMussaViewToolbarAction->setCheckable(true);
- showMussaViewToolbarAction->setChecked(true);
-
- toggleMotifsAction = new QAction(tr("Toggle Motifs"), this);
- connect(toggleMotifsAction, SIGNAL(triggered()),
- this, SLOT(toggleMotifs()));
- toggleMotifsAction->setCheckable(true);
- toggleMotifsAction->setIcon(QIcon("icons/motif_icon.png"));
- toggleMotifsAction->setWhatsThis(tr("Toggle motif annotations on/off\n\n"
- "You can load motif annotations via "
- "'File->Load Motif List' menu option."));
-
- whatsThisAction = QWhatsThis::createAction(this);
- whatsThisAction->setIcon(QIcon("icons/help.png"));
-
- //Save pixel map action
- saveOpenGlPixmapAction = new QAction(tr("Save to image..."), this);
- connect(saveOpenGlPixmapAction, (SIGNAL(triggered())),
- this, SLOT(promptSaveOpenGlPixmap()));
- saveOpenGlPixmapAction->setIcon(QIcon("icons/image2.png"));
-}
-
-void PathWindow::setupMainMenu()
-{
- // we need to run setupActions first
- assert (closeAction != 0);
-
- QMenu *newMenu;
- newMenu = menuBar()->addMenu(tr("&File"));
- newMenu->addAction(createNewAnalysisAction);
- newMenu->addAction(loadMupaAction);
- newMenu->addAction(loadSavedAnalysisAction);
- newMenu->addAction(createSubAnalysisAction);
- newMenu->addSeparator();
- newMenu->addAction(loadMotifListAction);
- newMenu->addAction(saveMotifListAction);
- newMenu->addSeparator();
- newMenu->addAction(saveOpenGlPixmapAction);
- newMenu->addSeparator();
- newMenu->addAction(closeAction);
-
- newMenu = menuBar()->addMenu(tr("&View"));
- newMenu->addAction(showMussaViewToolbarAction);
-
- newMenu = menuBar()->addMenu(tr("&Help"));
- newMenu->addAction(whatsThisAction);
- newMenu->addSeparator();
- newMenu->addAction(aboutAction);
-}
-
-void PathWindow::about()
-{
- QMessageBox::about(this, tr("About mussa"),
- tr("Welcome to Multiple Species Sequence Analysis\n"
- "(c) 2005-2006 California Institute of Technology\n"
- "Tristan De Buysscher, Diane Trout\n"));
-}
-
-void PathWindow::createNewAnalysis()
-{
- NotImplementedBox();
-}
-
-void PathWindow::createSubAnalysis()
-{
- NotImplementedBox();
-}
-
-
-void PathWindow::loadMotifList()
-{
- QString caption("Load a motif list");
- QString filter("Motif list(*.txt *.mtl)");
- QString path = QFileDialog::getOpenFileName(this,
- caption,
- QDir::currentPath(),
- filter);
- // user hit cancel?
- if (path.isNull())
- return;
- // try to load safely
- try {
- analysis->load_motifs(path.toStdString());
- } catch (runtime_error e) {
- QString msg("Unable to load ");
- msg += path;
- msg += "\n";
- msg += e.what();
- QMessageBox::warning(this, "Load Motifs", msg);
- }
- assert (analysis != 0);
-}
-
-void PathWindow::saveMotifList()
-{
- NotImplementedBox();
-}
-
-void PathWindow::loadMupa()
-{
- QString caption("Load a mussa parameter file");
- QString filter("Mussa Parameters (*.mupa)");
- QString mupa_path = QFileDialog::getOpenFileName(this,
- caption,
- QDir::currentPath(),
- filter);
- // user hit cancel?
- if (mupa_path.isNull())
- return;
- // try to load safely
- try {
- Mussa *m = new Mussa;
- m->load_mupa_file(mupa_path.toStdString());
- m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
- // only switch mussas if we loaded without error
- delete analysis;
- analysis = m;
- updateAnalysis();
- } catch (mussa_load_error e) {
- QString msg("Unable to load ");
- msg += mupa_path;
- msg += "\n";
- msg += e.what();
- QMessageBox::warning(this, "Load Parameter", msg);
- }
- assert (analysis != 0);
-}
-
-void PathWindow::loadSavedAnalysis()
-{
- QString caption("Load a previously run analysis");
- QString muway_dir = QFileDialog::getExistingDirectory(this,
- caption,
- QDir::currentPath());
- // user hit cancel?
- if (muway_dir.isNull())
- return;
- // try to safely load
- try {
- Mussa *m = new Mussa;
- m->load(muway_dir.toStdString());
- // only switch mussas if we loaded without error
- delete analysis;
- analysis = m;
- updateAnalysis();
- } catch (mussa_load_error e) {
- QString msg("Unable to load ");
- msg += muway_dir;
- msg += "\n";
- msg += e.what();
- QMessageBox::warning(this, "Load Parameter", msg);
- }
- assert (analysis != 0);
-}
-
-void PathWindow::setSoftThreshold(int threshold)
-{
- if (analysis->get_soft_thres() != threshold) {
- analysis->set_soft_thres(threshold);
- analysis->nway();
- updateLinks();
- update();
- }
-}
-
-void PathWindow::showMussaToolbar()
-{
- if (mussaViewTB.isVisible())
- mussaViewTB.hide();
- else
- mussaViewTB.show();
-}
-
-void PathWindow::toggleMotifs()
-{
- NotImplementedBox();
-}
-
-void PathWindow::NotImplementedBox()
-{
- QMessageBox::warning(this, QObject::tr("mussa"), QObject::tr("Not implemented yet"));
-}
-
-void PathWindow::promptSaveOpenGlPixmap()
-{
- QSize size;
- size = path_view.scene().size();
- //Image Save Dialog
- ImageSaveDialog imageSaveDialog(&path_view.scene(), this);
- imageSaveDialog.setSize(size.width(), size.height());
- int result = imageSaveDialog.exec();
- cout << "Result: " << result << "\n";
-}
-
-void PathWindow::updateAnalysis()
-{
- cout << "analysis updated" << endl;
- path_view.scene().clear();
- path_view.scene().setColorMapper(analysis->colorMapper());
- const vector<Sequence>& seqs = analysis->sequences();
- for(vector<Sequence>::const_iterator seq_i = seqs.begin();
- seq_i != seqs.end();
- ++seq_i)
- {
- GlSequence *gs= new GlSequence(*seq_i, analysis->colorMapper());
- path_view.scene().push_sequence(*gs);
- }
- updateLinks();
- path_view.updateTracks();
-}
-
-void PathWindow::updateLinks()
-{
- path_view.scene().clear_links();
- bool reversed = false;
- const NwayPaths& nway = analysis->paths();
-
- typedef list<ExtendedConservedPath> conserved_paths;
- typedef conserved_paths::const_iterator const_conserved_paths_itor;
- for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
- path_itor != nway.refined_pathz.end();
- ++path_itor)
- {
- // since we were drawing to the start of a window, and opengl lines
- // are centered around the two connecting points our lines were slightly
- // offset. the idea of window_offset is to adjust them to the
- // right for forward compliment or left for reverse compliment
- // FIXME: figure out how to unit test these computations
- //GLfloat window_offset = (path_itor->window_size)/2.0;
-
- size_t track_len = path_itor->track_indexes.size();
- vector<int> normalized_path;
- normalized_path.reserve(track_len);
- vector<bool> rc_flags(false, track_len);
- for (size_t track_i=0; track_i != track_len; ++track_i)
- {
- int x = path_itor->track_indexes[track_i];
- // at some point when we modify the pathz data structure to keep
- // track of the score we can put grab the depth here.
- //
- // are we reverse complimented?
- if ( x>=0) {
- reversed = false;
- } else {
- reversed = true;
- x = -x; // make positive
- }
- normalized_path.push_back(x);
- rc_flags.push_back(reversed);
- }
- path_view.scene().link(normalized_path, rc_flags, path_itor->window_size);
- }
- path_view.scene().update();
-}
-
+++ /dev/null
-#ifndef _PATHWINDOW_H_
-#define _PATHWINDOW_H_
-
-
-
-#include <QMainWindow>
-#include <QPixmap>
-#include <QSpinBox>
-#include <QToolBar>
-
-#include "qui/PathWidget.hpp"
-#include "qui/ThresholdWidget.hpp"
-
-class QAction;
-class Mussa;
-
-class PathWindow : public QMainWindow
-{
- Q_OBJECT
-
-public:
- PathWindow(Mussa* analysis=0, QWidget *parent=0);
-
-public slots:
- //! display an about box, contemplating the politics of the author list
- void about();
-
- //! \defgroup AnalysisFunctions Components related to running analyses
- //\@{
- //! open a window to collect the information needed to create a new analysis
- void createNewAnalysis();
- //! launch a sub analysis
- void createSubAnalysis();
- //\@}
-
- //! \defgroup MotifHandling Handling of motif lists
- //\@{
- //! load motifs
- void loadMotifList();
- void saveMotifList();
- void toggleMotifs();
- //\@}
-
- //! load a mussa parameter file (which specifies an analysis to run)
- void loadMupa();
- //! load a previously run analysis
- void loadSavedAnalysis();
- //! set the soft threshold used by the Nway_Path algorithm
- void setSoftThreshold(int thres);
-
- void showMussaToolbar();
-
- void promptSaveOpenGlPixmap();
-
-protected:
- Mussa *analysis;
- // display our wonderful mussa output
- PathWidget path_view;
- QToolBar mussaViewTB;
- QSpinBox zoomBox;
- ThresholdWidget threshold;
-
- QAction *aboutAction;
- QAction *closeAction;
- QAction *createNewAnalysisAction;
- QAction *createSubAnalysisAction;
- QAction *loadMotifListAction;
- QAction *loadMupaAction;
- QAction *loadSavedAnalysisAction;
- QAction *saveMotifListAction;
- QAction *showMussaViewToolbarAction;
- QAction *toggleMotifsAction;
- QAction *whatsThisAction;
- QAction *saveOpenGlPixmapAction;
-
- //! initialze the actions
- void setupActions();
- //! initialize this windows menu object
- void setupMainMenu();
- //! stub function to fill in QActions
- void NotImplementedBox();
- //! update the PathScene with our analysis
- void updateAnalysis();
- //! update the view of conserved windows
- void updateLinks();
-};
-
-#endif
+++ /dev/null
-
-#include <QVBoxLayout>
-
-#include "qui/ScrollableScene.hpp"
-
-ScrollableScene::ScrollableScene(QWidget *parent) :
- QWidget(parent),
- viewportBar(Qt::Horizontal)
-{
- // construct central opengl widget
- QVBoxLayout *layout = new QVBoxLayout;
-
- layout->addWidget(&path_scene);
- layout->addWidget(&viewportBar);
-
- connect(&viewportBar, SIGNAL(valueChanged(int)),
- this, SLOT(setViewportCenter(int)));
- connect(&path_scene, SIGNAL(viewportChanged()),
- this, SLOT(updateScrollBar()));
-
- setLayout(layout);
-
- // sets range & scale
- updateScrollBar();
-}
-
-void ScrollableScene::updateScrollBar()
-{
- float max_right = path_scene.right();
- float max_left = path_scene.left();
- float max_range = max_right - max_left;
- float cur_left = path_scene.viewportLeft();
- float cur_right = path_scene.viewportRight();
- float cur_center = ((cur_right-cur_left)/2)+cur_left;
- // set range to min
- thumb = (int)cur_center;
- viewportBar.setRange((int)max_left, (int)max_right);
- viewportBar.setValue(thumb);
-}
-
-void ScrollableScene::setViewportCenter(int x)
-{
- if (x != thumb) {
- thumb = x;
- path_scene.setViewportCenter(thumb);
- }
-}
-
+++ /dev/null
-#ifndef _SCROLLABLE_SCENE_H_
-#define _SCROLLABLE_SCENE_H_
-
-#include <QScrollBar>
-#include <QWidget>
-#include "qui/PathScene.hpp"
-
-class ScrollableScene : public QWidget
-{
- Q_OBJECT
-
-public:
- ScrollableScene(QWidget *parent=0);
- PathScene path_scene;
-
- PathScene& scene() { return path_scene; }
-public slots:
- //! update the scrollbar with current viewport information
- void updateScrollBar();
- //! update scene with the properly scalled scrollbar offset
- void setViewportCenter(int x);
-
-private:
- QScrollBar viewportBar;
- int thumb;
-
- float range;
- float scale;
-};
-
-#endif
+++ /dev/null
-#include "qui/SequenceDescription.hpp"
-
-#include <QVBoxLayout>
-
-using namespace std;
-
-SequenceDescription::SequenceDescription(QWidget *parent)
- : QWidget(parent)
-{
- createWidget();
-}
-
-SequenceDescription::SequenceDescription(string& name, float length,
- QWidget *parent)
- : QWidget(parent)
-{
- setName(name);
- setLength(length);
- createWidget();
-}
-
-void SequenceDescription::createWidget()
-{
- QLayout *layout = new QVBoxLayout;
- layout->setSpacing(2);
- layout->addWidget(&name_label);
- layout->addWidget(&length_label);
- layout->addWidget(&position_label);
- setLayout(layout);
-}
-
-void SequenceDescription::setLength(float length)
-{
- QString s;
- if (length > 1000) {
- length /= 1000;
- s.setNum(length, 'f', 2);
- s += "kb";
- } else {
- s.setNum(length);
- s += "b";
- }
- length_label.setText(s);
-}
-
+++ /dev/null
-#ifndef _SEQUENCE_DESCRIPTION_H
-#define _SEQUENCE_DESCRIPTION_H
-
-#include <string>
-
-#include <QString>
-#include <QLabel>
-#include <QWidget>
-
-class SequenceDescription : public QWidget
-{
- Q_OBJECT
-
-public:
- SequenceDescription(QWidget *parent=0);
- SequenceDescription(std::string& name, float length, QWidget *parent=0);
-
- void setName(std::string& name) { name_label.setText(name.c_str()); }
- void setLength(float length);
- void setPosition(int pos) { QString s; position_label.setText(s.setNum(pos));}
-
-private:
- QLabel name_label;
- QLabel length_label;
- QLabel position_label;
-
- void createWidget();
-};
-#endif
--- /dev/null
+#include <QVBoxLayout>
+
+#include "qui/seqbrowser/ScrollableSequenceBrowser.hpp"
+
+ScrollableSequenceBrowser::ScrollableSequenceBrowser(QWidget *parent) :
+ QWidget(parent),
+ viewportBar(Qt::Horizontal)
+{
+ // construct central opengl widget
+ QVBoxLayout *layout = new QVBoxLayout;
+
+ layout->addWidget(&sequence_browser);
+ layout->addWidget(&viewportBar);
+
+ connect(&viewportBar, SIGNAL(valueChanged(int)),
+ this, SLOT(setViewportCenter(int)));
+ connect(&sequence_browser, SIGNAL(viewportChanged()),
+ this, SLOT(updateScrollBar()));
+
+ setLayout(layout);
+
+ // sets range & scale
+ updateScrollBar();
+}
+
+void ScrollableSequenceBrowser::updateScrollBar()
+{
+ float max_right = sequence_browser.right();
+ float max_left = sequence_browser.left();
+ float max_range = max_right - max_left;
+ float cur_left = sequence_browser.viewportLeft();
+ float cur_right = sequence_browser.viewportRight();
+ float cur_center = ((cur_right-cur_left)/2)+cur_left;
+ // set range to min
+ thumb = (int)cur_center;
+ viewportBar.setRange((int)max_left, (int)max_right);
+ viewportBar.setValue(thumb);
+}
+
+void ScrollableSequenceBrowser::setViewportCenter(int x)
+{
+ if (x != thumb) {
+ thumb = x;
+ sequence_browser.setViewportCenter(thumb);
+ }
+}
+
--- /dev/null
+#ifndef _SCROLLABLE_SEQUENCE_BROWSER_H_
+#define _SCROLLABLE_SEQUENCE_BROWSER_H_
+
+#include <QScrollBar>
+#include <QWidget>
+#include "qui/seqbrowser/SequenceBrowser.hpp"
+
+class ScrollableSequenceBrowser : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ScrollableSequenceBrowser(QWidget *parent=0);
+ SequenceBrowser sequence_browser;
+
+ SequenceBrowser& browser() { return sequence_browser; }
+ const SequenceBrowser& browser() const { return sequence_browser; }
+public slots:
+ //! update the scrollbar with current viewport information
+ void updateScrollBar();
+ //! update scene with the properly scalled scrollbar offset
+ void setViewportCenter(int x);
+
+private:
+ QScrollBar viewportBar;
+ int thumb;
+
+ float range;
+ float scale;
+};
+
+#endif
--- /dev/null
+#include <QDir>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QMouseEvent>
+#include <QRubberBand>
+#include <QRect>
+#include <QString>
+#include <iostream>
+#include <set>
+
+#include <GL/gl.h>
+#include <math.h>
+
+#include "qui/seqbrowser/SequenceBrowser.hpp"
+#include "mussa_exceptions.hpp"
+
+using namespace std;
+
+SequenceBrowser::SequenceBrowser(QWidget *parent)
+ : QGLWidget(parent),
+ rubberBand(0),
+ drawingBand(false)
+{
+}
+
+QSize SequenceBrowser::sizeHint() const
+{
+ //return QSize((int)GlSeqBrowser::viewportHeight(), (int)GlSeqBrowser::viewportWidth());
+ return QSize(600, 400);
+}
+
+void SequenceBrowser::setViewportCenter(float x)
+{
+ const float epsilon = 1e-10;
+ float center = GlSeqBrowser::viewportCenter();
+ float difference = fabsf(x - center);
+ float abs_x = fabsf(x);
+ center = fabsf(center);
+
+ // the difference < epsilon * val is one of the recommended tests
+ // for float equality.
+ // of course since we're looking for not equals, we need to toss a
+ // not at the beginning
+ if (not (difference < epsilon * abs_x or difference < epsilon * center))
+ {
+ GlSeqBrowser::setViewportCenter(x);
+ emit viewportChanged();
+ update();
+ }
+}
+
+void SequenceBrowser::setZoom(int new_zoom)
+{
+ if (new_zoom != GlSeqBrowser::zoom()) {
+ GlSeqBrowser::setZoom(new_zoom);
+ emit viewportChanged();
+ update();
+ }
+}
+
+void SequenceBrowser::setClipPlane(int )
+{
+/*
+ if (clipZ != (double) newZ){
+ clipZ = (double) newZ;
+ update();
+ }
+*/
+}
+
+void SequenceBrowser::clear()
+{
+ GlSeqBrowser::clear();
+ emit tracksChanged();
+}
+
+void SequenceBrowser::push_sequence(const Sequence &s)
+{
+ GlSeqBrowser::push_sequence(s);
+ emit tracksChanged();
+}
+
+void SequenceBrowser::push_sequence(GlSequence &gs)
+{
+ GlSeqBrowser::push_sequence(gs);
+ emit tracksChanged();
+}
+
+////////////////////
+// Rendering code
+void SequenceBrowser::initializeGL()
+{
+ GlSeqBrowser::initializeGL();
+}
+
+void SequenceBrowser::resizeGL(int width, int height)
+{
+ GlSeqBrowser::resizeGL(width, height);
+}
+
+void SequenceBrowser::paintGL()
+{
+ GlSeqBrowser::paintGL();
+}
+
+void SequenceBrowser::mousePressEvent( QMouseEvent *e)
+{
+ drawingBand = true;
+
+ selectedMode = false;
+ bandOrigin = e->pos();
+ if (!rubberBand)
+ rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
+
+ rubberBand->setGeometry(QRect(bandOrigin, QSize()));
+ rubberBand->show();
+}
+
+void SequenceBrowser::mouseMoveEvent( QMouseEvent *e)
+{
+ if (drawingBand)
+ rubberBand->setGeometry(QRect(bandOrigin, e->pos()).normalized());
+}
+
+void SequenceBrowser::mouseReleaseEvent( QMouseEvent *e)
+{
+ drawingBand = false;
+ rubberBand->hide();
+ QRect r = QRect(bandOrigin, e->pos()).normalized();
+ bandOrigin = r.topLeft();
+
+ selectRegion(r.top(), r.left(), r.bottom(), r.right());
+}
--- /dev/null
+#ifndef _PATHSCENE_H_
+#define _PATHSCENE_H_
+
+#include <QGLWidget>
+#include <QRectF>
+#include <QPoint>
+#include <vector>
+#include <GL/gl.h>
+
+#include "alg/mussa.hpp"
+#include "alg/glsequence.hpp"
+#include "alg/glseqbrowser.hpp"
+
+class QMouseEvent;
+class QRubberBand;
+
+/*! \brief Render mussa sequences and paths
+ */
+class SequenceBrowser: public QGLWidget, public GlSeqBrowser
+{
+ Q_OBJECT
+
+public:
+ SequenceBrowser(QWidget *parent=0);
+
+ QSize sizeHint() const;
+
+ void clear();
+ void push_sequence(const Sequence &s);
+ void push_sequence(GlSequence &);
+
+public slots:
+ void setClipPlane(int z);
+ //! set the center of the current viewport
+ void setViewportCenter(float x);
+ //! set our magnification level
+ void setZoom(int);
+
+signals:
+ //! emited when someone adds to our list of tracks
+ void tracksChanged();
+ void viewportChanged();
+
+private:
+ void initializeGL();
+ void resizeGL(int height, int width);
+ void paintGL();
+
+ //! \defgroup Selection
+ QRubberBand *rubberBand;
+ QPoint bandOrigin;
+ bool drawingBand;
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+};
+#endif
--- /dev/null
+#include "qui/seqbrowser/SequenceBrowserSidebar.hpp"
+
+using namespace std;
+
+SequenceBrowserSidebar::SequenceBrowserSidebar(QWidget* parent)
+ : QWidget(parent)
+{
+ setLayout(&layout);
+}
+
+void SequenceBrowserSidebar::clear()
+{
+ for (vector<SequenceDescription *>::iterator desc_i = descriptions.begin();
+ desc_i != descriptions.end();
+ ++desc_i)
+ {
+ layout.removeWidget(*desc_i);
+ }
+ descriptions.clear();
+}
+
+void SequenceBrowserSidebar::setSequences(vector<GlSequence>& sequences)
+{
+ clear();
+ for (vector<GlSequence>::const_iterator track_i = sequences.begin();
+ track_i != sequences.end();
+ ++track_i)
+ {
+ SequenceDescription *desc = new SequenceDescription(this);
+ //disc->setName(track_i->sequence().name());
+ desc->setLength(track_i->sequence().length());
+ //desc->setPosition(track_i->sequence().length());
+ descriptions.push_back(desc);
+ layout.addWidget(desc);
+ }
+ setLayout(&layout);
+}
--- /dev/null
+#ifndef _SEQUENCE_BROWSER_SIDEBAR_H
+#define _SEQUENCE_BROWSER_SIDEBAR_H
+
+#include <vector>
+
+#include <QVBoxLayout>
+#include <QWidget>
+#include "qui/seqbrowser/SequenceBrowser.hpp"
+#include "qui/seqbrowser/SequenceDescription.hpp"
+#include "alg/glsequence.hpp"
+
+//! store a collection of sequence descriptions for the SequenceBrowserWidget
+class SequenceBrowserSidebar : public QWidget
+{
+ Q_OBJECT
+
+public:
+ enum SidebarSide { Left, Right };
+
+ SequenceBrowserSidebar(QWidget *parent = 0);
+
+ //! clear our list of descriptions
+ void clear();
+ void setSequences(std::vector<GlSequence>& );
+
+ std::vector<SequenceDescription *> descriptions;
+public slots:
+ //! update the reported sequence position for each of our sequences
+ /*! for example when the right side is at position 3000 call
+ * iterate over each sequence and get its rightbase pair value
+ */
+ //void updatePositionValues(float left, float right);
+
+private:
+ QVBoxLayout layout;
+ //! for updating positions we need to know which side we're on
+ //SidebarSide sidebar_side;
+};
+#endif
--- /dev/null
+#include <iostream>
+
+#include <QLabel>
+#include <QScrollBar>
+#include <QSpacerItem>
+#include <QSplitter>
+#include <QVBoxLayout>
+#include <QWidget>
+
+#include "qui/seqbrowser/SequenceBrowserWidget.hpp"
+#include "qui/seqbrowser/SequenceBrowser.hpp"
+#include "qui/seqbrowser/ScrollableSequenceBrowser.hpp"
+#include "qui/seqbrowser/SequenceDescription.hpp"
+#include "qui/ImageSaveDialog.hpp"
+
+#include "alg/glsequence.hpp"
+
+#include <math.h>
+using namespace std;
+
+SequenceBrowserWidget::SequenceBrowserWidget(QWidget *parent)
+ : QSplitter(parent),
+ scrollable_browser(parent)
+{
+ setOrientation(Qt::Horizontal);
+
+ addWidget(&left_sidebar);
+ addWidget(&scrollable_browser);
+ addWidget(&right_sidebar);
+
+ connect(&scrollable_browser.browser(), SIGNAL(viewportChanged()),
+ this, SLOT(updatePosition()));
+}
+
+void SequenceBrowserWidget::clear()
+{
+ converted_sequences.clear();
+ scrollable_browser.browser().clear();
+ left_sidebar.clear();
+ right_sidebar.clear();
+}
+
+void SequenceBrowserWidget::setSequences(const std::vector<Sequence>& sequences,
+ AnnotationColors& cm)
+{
+ SequenceBrowser& browser = scrollable_browser.browser();
+ clear();
+ for(vector<Sequence>::const_iterator seq_i = sequences.begin();
+ seq_i != sequences.end();
+ ++seq_i)
+ {
+ GlSequence *gs= new GlSequence(*seq_i, cm);
+ converted_sequences.push_back(*gs);
+ browser.push_sequence(*gs);
+ }
+ left_sidebar.setSequences(converted_sequences);
+ right_sidebar.setSequences(converted_sequences);
+ updatePosition();
+}
+
+void SequenceBrowserWidget::setSequences(std::vector<GlSequence>& sequences)
+{
+ SequenceBrowser& browser = scrollable_browser.browser();
+ clear();
+ for(vector<GlSequence>::iterator seq_i = sequences.begin();
+ seq_i != sequences.end();
+ ++seq_i)
+ {
+ browser.push_sequence(*seq_i);
+ }
+ left_sidebar.setSequences(sequences);
+ right_sidebar.setSequences(sequences);
+ updatePosition();
+}
+
+const vector<GlSequence>& SequenceBrowserWidget::sequences() const
+{
+ return scrollable_browser.browser().sequences();
+}
+
+void SequenceBrowserWidget::clear_links()
+{
+ scrollable_browser.browser().clear_links();
+}
+
+void SequenceBrowserWidget::link(const std::vector<int>& path,
+ const std::vector<bool>& isRC,
+ int length)
+{
+ scrollable_browser.browser().link(path, isRC, length);
+}
+
+/* This could theoretically be pushed down to some set
+ * of signals and slots connecting SequenceDescriptions and
+ * some signal emitted by the browser's viewportChanged code
+ * but evertime I tried to figure it out, I got confused about
+ * how the descriptions in one of the sidebars was supposed to know
+ * if it was mapping the rightbase or the leftbase.
+ * And so though this could be better the typical use cases
+ * can just talk to the SequenceBrowserWidget for rendering
+ * or mussa output
+ */
+void SequenceBrowserWidget::updatePosition()
+{
+ const SequenceBrowser& browser = scrollable_browser.browser();
+ const vector<GlSequence> &sequences = browser.sequences();
+ vector<SequenceDescription *> left = left_sidebar.descriptions;
+ vector<SequenceDescription *> right = right_sidebar.descriptions;
+ for(size_t i = 0; i != sequences.size() and i != right.size(); ++i)
+ {
+ left[i]->setPosition(sequences[i].leftbase(browser.viewportLeft()));
+ right[i]->setPosition(sequences[i].rightbase(browser.viewportRight()));
+ }
+}
+
+void SequenceBrowserWidget::promptSaveBrowserPixmap()
+{
+ QSize size;
+ size = scrollable_browser.browser().size();
+ //Image Save Dialog
+ ImageSaveDialog imageSaveDialog(&scrollable_browser.browser(), this);
+ imageSaveDialog.setSize(size.width(), size.height());
+ int result = imageSaveDialog.exec();
+ cout << "Result: " << result << "\n";
+}
+
+void SequenceBrowserWidget::setZoom(int z)
+{
+ scrollable_browser.browser().setZoom(z);
+}
--- /dev/null
+#ifndef _PATH_WIDGET_H_
+#define _PATH_WIDGET_H_
+
+#include <vector>
+
+#include <QSplitter>
+
+#include "alg/sequence.hpp"
+#include "alg/glsequence.hpp"
+#include "qui/seqbrowser/ScrollableSequenceBrowser.hpp"
+#include "qui/seqbrowser/SequenceBrowserSidebar.hpp"
+
+//! the master widget that makes a useful Sequence Browser
+class SequenceBrowserWidget : public QSplitter
+{
+ Q_OBJECT
+
+public:
+ SequenceBrowserWidget(QWidget *parent=0);
+
+ //SequenceBrowser& browser() { return scrollable_browser.browser(); }
+
+ //! reset all of our stored data back to the empty state
+ void clear();
+
+ /* Attach sequences to our browser, its best to attach them all
+ * at once, as otherwise the Sidebar has some rendering trouble
+ * as it draw and redraws the SequenceDescriptions in the various
+ * positions.
+ */
+ //void push_sequences(std::vector<Sequence>& sequences);
+ void setSequences(const std::vector<Sequence>& sequences, AnnotationColors& cm);
+ void setSequences(std::vector<GlSequence>& sequences);
+ const std::vector<GlSequence>& sequences() const;
+
+ //! reset just the links we're displaying
+ void clear_links();
+ //! set per species links
+ void link(const std::vector<int> &path, const std::vector<bool>& isRC, int length);
+
+public slots:
+ //! set the zoom level of our browser
+ void setZoom(int);
+
+ void updatePosition();
+ //! ask the user where to save an image of the current browser view
+ void promptSaveBrowserPixmap();
+
+private:
+ ScrollableSequenceBrowser scrollable_browser;
+ SequenceBrowserSidebar left_sidebar;
+ SequenceBrowserSidebar right_sidebar;
+
+ //! sequences created by a setSequences(vector<Sequences>) call
+ /*! I need to save them so i can free them to avoid a memory leak
+ */
+ std::vector<GlSequence> converted_sequences;
+};
+#endif
--- /dev/null
+#include <QVBoxLayout>
+
+#include "qui/seqbrowser/SequenceDescription.hpp"
+
+using namespace std;
+
+SequenceDescription::SequenceDescription(QWidget *parent)
+ : QWidget(parent)
+{
+ createWidget();
+}
+
+SequenceDescription::SequenceDescription(string& name, float length,
+ QWidget *parent)
+ : QWidget(parent)
+{
+ setName(name);
+ setLength(length);
+ createWidget();
+}
+
+void SequenceDescription::createWidget()
+{
+ QLayout *layout = new QVBoxLayout;
+ layout->setSpacing(2);
+ layout->addWidget(&name_label);
+ layout->addWidget(&length_label);
+ layout->addWidget(&position_label);
+ setLayout(layout);
+}
+
+void SequenceDescription::setLength(float length)
+{
+ QString s;
+ if (length > 1000) {
+ length /= 1000;
+ s.setNum(length, 'f', 2);
+ s += "kb";
+ } else {
+ s.setNum(length);
+ s += "b";
+ }
+ length_label.setText(s);
+}
+
--- /dev/null
+#ifndef _SEQUENCE_DESCRIPTION_H
+#define _SEQUENCE_DESCRIPTION_H
+
+#include <string>
+
+#include <QString>
+#include <QLabel>
+#include <QWidget>
+
+class SequenceDescription : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SequenceDescription(QWidget *parent=0);
+ SequenceDescription(std::string& name, float length, QWidget *parent=0);
+
+ void setName(std::string& name) { name_label.setText(name.c_str()); }
+ void setLength(float length);
+ void setPosition(int pos) { QString s; position_label.setText(s.setNum(pos));}
+
+private:
+ QLabel name_label;
+ QLabel length_label;
+ QLabel position_label;
+
+ void createWidget();
+};
+#endif