|
Isis 3.0 Object Programmers' Reference |
Home |
00001 #include "MosaicZoomTool.h" 00002 00003 #include <float.h> 00004 #include <iomanip> 00005 #include <iostream> 00006 00007 #include <QDoubleSpinBox> 00008 #include <QGraphicsSceneMouseEvent> 00009 #include <QHBoxLayout> 00010 #include <QLabel> 00011 #include <QMenu> 00012 #include <QScrollBar> 00013 #include <QToolButton> 00014 00015 #include "IString.h" 00016 #include "MosaicGraphicsView.h" 00017 #include "MosaicSceneWidget.h" 00018 #include "Projection.h" 00019 00020 namespace Isis { 00027 MosaicZoomTool::MosaicZoomTool(MosaicSceneWidget *scene) : MosaicTool(scene) { 00028 p_scaleBox = NULL; 00029 00030 m_zoomInAction = new QAction(this); 00031 m_zoomInAction->setIcon(getIcon("viewmag+.png")); 00032 m_zoomInAction->setText("Zoom In"); 00033 m_zoomInAction->setToolTip("Zoom in on the mosaic scene"); 00034 m_zoomInAction->setShortcut(Qt::Key_Plus); 00035 QString text = 00036 "<b>Function:</b> Zoom in 2X at the center of the active viewport \ 00037 <p><b>Shortcut:</b> +</p> \ 00038 <p><b>Mouse:</b> LeftButton zooms in 2X under pointer</p> \ 00039 <p><b>Modifiers:</b> Shortcuts and mouse clicks can be augmented \ 00040 using the Ctrl or Alt key for 4X and 8X zooms, respectively</p> \ 00041 <p><b>Hint:</b> Left click and drag for a local zoom which scales data \ 00042 in the marquee to the view</p>"; 00043 m_zoomInAction->setWhatsThis(text); 00044 connect(m_zoomInAction, SIGNAL(triggered()), this, SLOT(zoomIn2X())); 00045 00046 m_zoomOutAction = new QAction(this); 00047 m_zoomOutAction->setIcon(getIcon("viewmag-.png")); 00048 m_zoomOutAction->setText("Zoom Out"); 00049 m_zoomOutAction->setToolTip("Zoom out on the mosaic scene"); 00050 m_zoomOutAction->setShortcut(Qt::Key_Minus); 00051 text = 00052 "<b>Function:</b> Zoom out 2X at the center of the view \ 00053 <p><b>Shortcut:</b> +</p> \ 00054 <p><b>Mouse:</b> RightButton zooms out 2X under pointer</p> \ 00055 <p><b>Modifiers:</b> Shortcuts and mouse clicks can be augmented \ 00056 using the Ctrl or Alt key for 4X and 8X zooms, respectively</p> \ 00057 <p><b>Hint:</b> Left click and drag for a local zoom which scales data \ 00058 in the marquee to the view</p>"; 00059 m_zoomOutAction->setWhatsThis(text); 00060 connect(m_zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOut2X())); 00061 00062 m_zoomFitAction = new QAction(this); 00063 m_zoomFitAction->setIcon(getIcon("viewmagfit.png")); 00064 m_zoomFitAction->setText("Fit in View"); 00065 m_zoomFitAction->setToolTip("Zoom to where all of the cubes are visible in " 00066 "the mosaic scene"); 00067 m_zoomFitAction->setShortcut(Qt::Key_Asterisk); 00068 text = 00069 "<b>Function:</b> Fit the entire mosaic inside the view. \ 00070 <p><b>Shortcut:</b> *</p> \ 00071 <p><b>Hint:</b> Many shortcuts for the zoom tool and other tools \ 00072 are easily available on the numeric keypad </p>"; 00073 m_zoomFitAction->setWhatsThis(text); 00074 connect(m_zoomFitAction, SIGNAL(triggered()), this, SLOT(zoomFit())); 00075 } 00076 00077 00083 void MosaicZoomTool::updateResolutionBox() { 00084 if(p_scaleBox) { 00085 // Using these two points we can calculated the scene's width. 00086 QPointF point1 = getWidget()->getView()->mapToScene(0, 0); 00087 QPointF point2 = getWidget()->getView()->mapToScene( 00088 (int)getWidget()->getView()->width(), 0); 00089 double newWidth = point2.x() - point1.x(); 00090 00091 // The scene width divided by the viewport's width gives us the screen res. 00092 p_screenResolution = newWidth / getWidget()->getView()->viewport()->width(); 00093 00094 // Update the text box display 00095 p_scaleBox->setValue(p_screenResolution); 00096 //------------------------------------------------------------------------ 00097 // This sets the up and down arrows (on the text box) so that each time a 00098 // user clicks them, a resonable amount of zoom happens. 00099 //------------------------------------------------------------------------ 00100 p_scaleBox->setSingleStep(p_screenResolution * .05); 00101 } 00102 } 00103 00104 00105 QList<QAction *> MosaicZoomTool::getViewActions() { 00106 QList<QAction *> viewActs; 00107 00108 viewActs.append(m_zoomInAction); 00109 viewActs.append(m_zoomOutAction); 00110 viewActs.append(m_zoomFitAction); 00111 00112 return viewActs; 00113 } 00114 00115 00116 QAction *MosaicZoomTool::getPrimaryAction() { 00117 QAction *action = new QAction(this); 00118 action->setIcon(getIcon("viewmag.png")); 00119 action->setToolTip("Zoom (z)"); 00120 action->setShortcut(Qt::Key_Z); 00121 QString text = 00122 "<b>Function:</b> Zoom in or out of the current cube.<br><br>" 00123 "This tool gives you a <b>click</b> to zoom by 2X and center on the " 00124 "point you clicked on, a <b>right-click</b> to zoom out by 2X and center " 00125 "on the point you clicked on, a <b>click and drag</b> box to best fit " 00126 "the given area into the visible screen, a <b>right-click and drag</b> " 00127 "box to zoom out and center on the center (smaller box means zoom out " 00128 "more), and disables context menus on the mosaic scene." 00129 "<p><b>Shortcut:</b> z</p> "; 00130 action->setWhatsThis(text); 00131 return action; 00132 } 00133 00134 00143 QWidget *MosaicZoomTool::getToolBarWidget() { 00144 QWidget *hbox = new QWidget; 00145 00146 QToolButton *zoomInButton = new QToolButton(hbox); 00147 zoomInButton->setAutoRaise(true); 00148 zoomInButton->setDefaultAction(m_zoomInAction); 00149 zoomInButton->setIconSize(QSize(22, 22)); 00150 00151 QToolButton *zoomOutButton = new QToolButton(hbox); 00152 zoomOutButton->setAutoRaise(true); 00153 zoomOutButton->setDefaultAction(m_zoomOutAction); 00154 zoomOutButton->setIconSize(QSize(22, 22)); 00155 00156 QToolButton *zoomFitButton = new QToolButton(hbox); 00157 zoomFitButton->setAutoRaise(true); 00158 zoomFitButton->setDefaultAction(m_zoomFitAction); 00159 zoomFitButton->setIconSize(QSize(22, 22)); 00160 00161 p_scaleBox = new QDoubleSpinBox(); 00162 p_scaleBox->setRange(DBL_MIN, DBL_MAX); 00163 p_scaleBox->setDecimals(8); 00164 connect(p_scaleBox, SIGNAL(editingFinished()), this, SLOT(zoomManual())); 00165 00166 QLabel *resolutionLabel = new QLabel("Meters per pixel"); 00167 00168 QHBoxLayout *layout = new QHBoxLayout(hbox); 00169 layout->setMargin(0); 00170 layout->addWidget(zoomInButton); 00171 layout->addWidget(zoomOutButton); 00172 00173 //------------------------------------------- 00174 // These two actions are not quite ready yet. 00175 // layout->addWidget(zoomActButton); 00176 //------------------------------------------- 00177 layout->addWidget(zoomFitButton); 00178 layout->addWidget(p_scaleBox); 00179 layout->addWidget(resolutionLabel); 00180 layout->addStretch(1); 00181 hbox->setLayout(layout); 00182 return hbox; 00183 } 00184 00185 00186 void MosaicZoomTool::mouseButtonRelease(QPointF mouseLoc, Qt::MouseButton s) { 00187 if(!isActive()) 00188 return; 00189 00190 if(s == Qt::LeftButton) 00191 zoomIn2X(mouseLoc); 00192 else if(s == Qt::RightButton) 00193 zoomOut2X(mouseLoc); 00194 } 00195 00196 00197 void MosaicZoomTool::mouseWheel(QPointF mouseLoc, int delta) { 00198 static const double sensitivity = 60.0; // this causes factor of 2 changes 00199 double scale = delta / sensitivity; 00200 00201 if(delta < 0) 00202 scale = 1.0 / (-delta / sensitivity); 00203 00204 scale = limitZoomBy(scale); 00205 00206 QPoint screenMouseLoc(getWidget()->getView()->mapFromScene(mouseLoc)); 00207 QPoint screenCenter( 00208 getWidget()->getView()->viewport()->size().width() / 2, 00209 getWidget()->getView()->viewport()->size().height() / 2); 00210 00211 // We're going to do this by zooming on the mouse and then 00212 // undo-ing the center in screen pixels. 00213 zoomBy(scale, mouseLoc); 00214 00215 // The new center screen pixel is: 00216 // center - mouseLoc 00217 QPoint desiredScreenCenter = 00218 screenCenter + (screenCenter - screenMouseLoc); 00219 QPointF newCenterPoint = 00220 getWidget()->getView()->mapToScene(desiredScreenCenter); 00221 getWidget()->getView()->centerOn(newCenterPoint); 00222 } 00223 00224 00229 void MosaicZoomTool::zoomIn2X(QPointF center) { 00230 zoomBy(2.0, center); 00231 } 00232 00233 00238 void MosaicZoomTool::zoomOut2X(QPointF center) { 00239 zoomBy(1.0 / 2.0, center); 00240 } 00241 00242 00247 void MosaicZoomTool::zoomActual(QPointF center) { 00248 zoomBy(1.1, center); 00249 } 00250 00251 00252 double MosaicZoomTool::limitZoomBy(double factor) { 00253 QMatrix matrix = getWidget()->getView()->matrix(); 00254 matrix = matrix.scale(factor, factor).inverted(); 00255 00256 int smallerDimension = getWidget()->getView()->width(); 00257 int largerDimension = getWidget()->getView()->height(); 00258 00259 if(smallerDimension > largerDimension) { 00260 int tmp = smallerDimension; 00261 smallerDimension = largerDimension; 00262 largerDimension = tmp; 00263 } 00264 00265 QPointF point1 = matrix.map(QPointF(0, 0)); 00266 QPointF point2 = matrix.map(QPointF(smallerDimension, 0)); 00267 00268 // If the factor cannot be done, find the one that can 00269 // This max zoom in factor isn't right; I haven't found the number 00270 // that corresponds to the Qt bug(?) causing us to not pan correctly on 00271 // the zoom in. 00272 if((point2.x() - point1.x()) < 1) { 00273 QMatrix origMatrix = getWidget()->getView()->matrix(); 00274 factor = smallerDimension / (origMatrix.m11() * 1.0); 00275 } 00276 00277 point1 = matrix.map(QPointF(0, 0)); 00278 point2 = matrix.map(QPointF(largerDimension, 0)); 00279 00280 if((point2.x() - point1.x()) > 1E10) { 00281 QMatrix origMatrix = getWidget()->getView()->matrix(); 00282 factor = largerDimension / (origMatrix.m11() * 1E10); 00283 } 00284 00285 return factor; 00286 } 00287 00288 00295 void MosaicZoomTool::zoomBy(double factor, QPointF center) { 00296 factor = limitZoomBy(factor); 00297 00298 getWidget()->getView()->scale(factor, factor); 00299 00300 if(!center.isNull()) { 00301 getWidget()->getView()->centerOn(center); 00302 } 00303 00304 updateResolutionBox(); 00305 } 00306 00307 00312 void MosaicZoomTool::zoomFit() { 00313 getWidget()->refit(); 00314 updateResolutionBox(); 00315 } 00316 00317 00322 void MosaicZoomTool::zoomFitWidth() { 00323 00324 } 00325 00326 00332 void MosaicZoomTool::zoomFitHeight() { 00333 00334 } 00335 00336 00346 void MosaicZoomTool::zoomManual() { 00347 if(p_scaleBox) { 00348 double x = p_screenResolution / p_scaleBox->value(); 00349 zoomBy(x); 00350 } 00351 } 00352 00353 00359 void MosaicZoomTool::updateTool() { 00360 if(isActive()) { 00361 getWidget()->setCubesSelectable(false); 00362 getWidget()->getView()->setContextMenuPolicy(Qt::NoContextMenu); 00363 getWidget()->enableRubberBand(true); 00364 } 00365 else { 00366 getWidget()->setCubesSelectable(true); 00367 getWidget()->getView()->setContextMenuPolicy(Qt::DefaultContextMenu); 00368 getWidget()->enableRubberBand(false); 00369 } 00370 00371 updateResolutionBox(); 00372 } 00373 00374 00382 void MosaicZoomTool::rubberBandComplete(QRectF r, Qt::MouseButton s) { 00383 if(!isActive()) 00384 return; 00385 00386 double meters_pixel = 0.0; 00387 00388 //-------------------------------------------------------------------- 00389 // We only user width or height to determine the desired meters/pixel. 00390 // Which ever is larger. 00391 //-------------------------------------------------------------------- 00392 if(r.width() > r.height()) { 00393 meters_pixel = r.width() / getWidget()->getView()->viewport()->width(); 00394 } 00395 else { 00396 meters_pixel = r.height() / getWidget()->getView()->viewport()->height(); 00397 } 00398 00399 // calculate the scale. 00400 double scale = p_screenResolution / meters_pixel; 00401 00402 // zooming in. 00403 if(s == Qt::LeftButton) { 00404 zoomBy(scale, r.center()); 00405 } 00406 00407 // zooming out. 00408 if(s == Qt::RightButton) { 00409 zoomBy(1 / scale, r.center()); 00410 } 00411 00412 updateResolutionBox(); 00413 } 00414 00415 } 00416