simplify zoom code
[mussa.git] / qui / seqbrowser / SequenceBrowser.cpp
index 00885dd256e20fd2997c92ce26339888f4d74c74..4e1fbcd74421572b0b587bbe5fd1fc508b33f141 100644 (file)
@@ -1,14 +1,16 @@
+#include <QApplication>
+#include <QClipboard>
 #include <QDir>
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QMouseEvent>
+#include <QWheelEvent>
 #include <QRubberBand>
 #include <QRect>
 #include <QString>
 #include <iostream>
 #include <set>
 
-#include <GL/gl.h>
 #include <math.h>
 
 #include "qui/seqbrowser/SequenceBrowser.hpp"
@@ -19,14 +21,75 @@ using namespace std;
 SequenceBrowser::SequenceBrowser(QWidget *parent)
   : QGLWidget(parent),
     rubberBand(0),
-    drawingBand(false)
+    popupMenu(0),
+    copySelectedSequenceAsFastaAction(0),
+    copySelectedSequenceAsStringAction(0),
+    editSequencePropertiesAction(0),
+    clearSelectionAction(0)
 { 
+  popupMenu = new QMenu(this);
+  copySelectedSequenceAsFastaAction = new QAction(tr("&Copy as Fasta"), this);
+  connect(copySelectedSequenceAsFastaAction, SIGNAL(triggered()), 
+          this, SLOT(copySelectedSequenceAsFasta()));
+  popupMenu->addAction(copySelectedSequenceAsFastaAction);
+
+  copySelectedSequenceAsStringAction = new QAction(tr("&Copy Sequence"), this);
+  copySelectedSequenceAsStringAction->setShortcut(Qt::CTRL | Qt::Key_C);
+  connect(copySelectedSequenceAsStringAction, SIGNAL(triggered()), 
+          this, SLOT(copySelectedSequenceAsString()));
+  popupMenu->addAction(copySelectedSequenceAsStringAction);
+
+  // connect edit properties action
+  editSequencePropertiesAction = new QAction(tr("Sequence &Properties"), this);
+  connect(editSequencePropertiesAction, SIGNAL(triggered()), 
+          this, SLOT(editSequenceProperties()));
+          
+  clearSelectionAction = new QAction(tr("Clear Selection"), this);
+  clearSelectionAction->setShortcut(Qt::Key_Escape);
+  connect(clearSelectionAction, SIGNAL(triggered()), 
+          this, SLOT(clearSelection()));
+  this->addAction(clearSelectionAction);          
+  
+}
+
+SequenceBrowser::SequenceBrowser(const SequenceBrowser& sb, QWidget *parent)
+  : QGLWidget(parent),
+    GlSeqBrowser(sb),
+    rubberBand(sb.rubberBand),
+    popupMenu(sb.popupMenu),
+    copySelectedSequenceAsFastaAction(sb.copySelectedSequenceAsFastaAction),
+    copySelectedSequenceAsStringAction(sb.copySelectedSequenceAsStringAction),
+    editSequencePropertiesAction(sb.editSequencePropertiesAction),
+    clearSelectionAction(sb.clearSelectionAction)
+{
+  resize(sb.width(), sb.height());
+  setZoom(sb.zoom());
+  paintGL();
+}
+
+QMenu *SequenceBrowser::getPopupMenu()
+{
+  return popupMenu;
+}
+
+QAction *SequenceBrowser::getCopySelectedSequenceAsFastaAction()
+{
+  return copySelectedSequenceAsFastaAction;
+}
+
+QAction *SequenceBrowser::getCopySelectedSequenceAsStringAction()
+{
+  return copySelectedSequenceAsStringAction;
+}
+
+QAction *SequenceBrowser::getEditSequencePropertiesAction()
+{
+  return editSequencePropertiesAction;
 }
 
 QSize SequenceBrowser::sizeHint() const
 {
-  //return QSize((int)GlSeqBrowser::viewportHeight(), (int)GlSeqBrowser::viewportWidth());
-  return QSize(600, 400);
+  return QSize(viewportPixelWidth(), viewportPixelHeight());
 }
 
 void SequenceBrowser::setViewportCenter(float x)
@@ -49,7 +112,7 @@ void SequenceBrowser::setViewportCenter(float x)
   }
 }
 
-void SequenceBrowser::setZoom(int new_zoom)
+void SequenceBrowser::setZoom(double new_zoom)
 {
   if (new_zoom != GlSeqBrowser::zoom()) {
     GlSeqBrowser::setZoom(new_zoom);
@@ -68,19 +131,62 @@ void SequenceBrowser::setClipPlane(int )
 */
 }
 
+void SequenceBrowser::copySelectedSequenceAsFasta()
+{
+  // get fasta data
+  std::string buffer;
+  size_t base_pairs_copied = copySelectedTracksAsFasta(buffer);
+
+  // get reference to clipboard
+  QClipboard *clipboard = QApplication::clipboard();
+  clipboard->setText(buffer.c_str());
+  emit basepairsCopied(base_pairs_copied);
+}
+
+void SequenceBrowser::copySelectedSequenceAsString()
+{
+  // get fasta data
+  std::string buffer;
+  size_t base_pairs_copied = copySelectedTracksAsString(buffer);
+
+  // get reference to clipboard
+  QClipboard *clipboard = QApplication::clipboard();
+  clipboard->setText(buffer.c_str());
+  emit basepairsCopied(base_pairs_copied);
+}
+
 void SequenceBrowser::clear()
 {
   GlSeqBrowser::clear();
   emit tracksChanged();
 }
 
-void SequenceBrowser::push_sequence(const Sequence &s)
+void SequenceBrowser::displayContextMenu(const QPoint& point)
+{
+  popupMenu->popup(point);
+}
+
+void SequenceBrowser::editSequenceProperties()
+{
+  // if there's a previous window, disconnect its signal
+  if (properties) {
+    disconnect(properties.get(), SIGNAL(propertiesChanged()),
+               this, SLOT(updateGL()));
+  }
+  PropertiesWindowRef new_properties(new PropertiesWindow(track_container));
+  properties = new_properties;
+  connect(properties.get(), SIGNAL(propertiesChanged()),
+          this, SLOT(updateGL()));
+  properties->show();
+}
+
+void SequenceBrowser::push_sequence(boost::shared_ptr<Sequence> s)
 {
   GlSeqBrowser::push_sequence(s);
   emit tracksChanged();
 }
 
-void SequenceBrowser::push_sequence(GlSequence &gs)
+void SequenceBrowser::push_sequence(boost::shared_ptr<GlSequence> gs)
 {
   GlSeqBrowser::push_sequence(gs);
   emit tracksChanged();
@@ -106,31 +212,96 @@ void SequenceBrowser::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();
+  switch(e->button()) {
+    case Qt::LeftButton:
+      startSelecting(e);
+      e->accept();
+      break;
+   default:
+      e->ignore();
+      break;
+  }
 }
 
-void SequenceBrowser::mouseMoveEvent( QMouseEvent *e)
+void SequenceBrowser::mouseMoveEvent( QMouseEvent *e )
 {
-  if (drawingBand)
+  if (rubberBand and rubberBand->isVisible()) {
     rubberBand->setGeometry(QRect(bandOrigin, e->pos()).normalized());
+    e->accept();
+  } else {
+    e->ignore();
+  }
 }
 
 void SequenceBrowser::mouseReleaseEvent( QMouseEvent *e)
 {
-  drawingBand = false;
-  if (rubberBand != 0) {
+  switch(e->button()) {
+    case Qt::LeftButton:
+      stopSelecting(e);
+      break;
+   case Qt::RightButton:
+      // ok so selectedMode and drawing mode should probably be combinded
+      // into a single state variable.
+      if (rubberBand and 
+          not rubberBand->isVisible() and
+          selectedCanvasRegion.contains(e->pos())) {
+        displayContextMenu(e->globalPos());
+      }
+      break;
+   default:
+      e->ignore();
+      return;
+      break;
+  }
+  e->accept();
+}
+
+void SequenceBrowser::startSelecting(QMouseEvent *e)
+{
+  if (!rubberBand)
+    rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
+
+  if (not rubberBand->isVisible()) {
+    bandOrigin = e->pos();
+    rubberBand->setGeometry(QRect(bandOrigin, QSize()));
+    rubberBand->show();
+  }
+}
+
+void SequenceBrowser::stopSelecting(QMouseEvent *e)
+{
+  if (rubberBand and rubberBand->isVisible()) {
     rubberBand->hide();
+    selectedMode = false;
     QRect r = QRect(bandOrigin, e->pos()).normalized();
     bandOrigin = r.topLeft();
   
     selectRegion(r.top(), r.left(), r.bottom(), r.right());
+    selectedCanvasRegion = r;
+  }
+}
+
+void SequenceBrowser::wheelEvent(QWheelEvent *e)
+{
+  e->accept();
+  double cur_zoom = GlSeqBrowser::zoom();
+  
+  // Normalize so one turn of the mouse wheel
+  // is equal to 1 step.
+  const int normalize_tick = 120;
+  // arbitrary scaling factor that seems to "work"
+  const int scaling = 50;
+  int num_steps = e->delta() / normalize_tick;
+
+  cur_zoom = pow(10, log10(cur_zoom) - ((double)num_steps/scaling));
+  emit mouseWheelZoom(cur_zoom);
+}
+
+void SequenceBrowser::clearSelection()
+{
+  GlSeqBrowser::clearSelection();
+  if (rubberBand and rubberBand->isVisible()) {
+    rubberBand->hide();
   }
+  updateGL();
 }