placeable_window_proxy.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //
00028 // *****************************************************************************
00029 
00030 #include <mapviz_plugins/placeable_window_proxy.h>
00031 
00032 #include <math.h>
00033 #include <cmath>
00034 
00035 #include <QApplication>
00036 #include <QCursor>
00037 #include <QLine>
00038 #include <QMouseEvent>
00039 #include <QResizeEvent>
00040 #include <QTimerEvent>
00041 #include <QWidget>
00042 
00043 #include <QDebug>
00044 
00045 namespace mapviz_plugins
00046 {
00047 PlaceableWindowProxy::PlaceableWindowProxy()
00048   :
00049   target_(NULL),
00050   visible_(true),
00051   has_cursor_(false),
00052   state_(INACTIVE),
00053   win_resize_timer_(-1)
00054 {
00055 }
00056 
00057 PlaceableWindowProxy::~PlaceableWindowProxy()
00058 {
00059   if (target_)
00060   {
00061     target_->removeEventFilter(this);
00062   }
00063 }
00064 
00065 void PlaceableWindowProxy::setContainer(QWidget *target)
00066 {
00067   if (target_)
00068   {
00069     target_->removeEventFilter(this);
00070   }
00071 
00072   target_ = target;
00073 
00074   if (target_)
00075   {
00076     target_->installEventFilter(this);
00077   }
00078 }
00079 
00080 QRect PlaceableWindowProxy::rect() const
00081 {
00082   return rect_.toRect();
00083 }
00084 
00085 void PlaceableWindowProxy::setRect(const QRect &rect)
00086 {
00087   rect_ = QRectF(rect);
00088   state_ = INACTIVE;
00089 }
00090 
00091 void PlaceableWindowProxy::setVisible(bool visible)
00092 {
00093   if (visible == visible_)
00094   {
00095     return;
00096   }
00097 
00098   visible_ = visible;
00099 
00100   if (!visible_ && state_ != INACTIVE)
00101   {
00102     if (has_cursor_)
00103     {
00104       QApplication::restoreOverrideCursor();
00105       has_cursor_ = false;
00106     }
00107     state_ = INACTIVE;
00108   } 
00109 }
00110 
00111 bool PlaceableWindowProxy::eventFilter(QObject *, QEvent *event)
00112 {
00113   // This should never happen, but doesn't hurt to be defensive.
00114   if (!target_)
00115   {
00116     return false;
00117   }
00118 
00119   if (!visible_)
00120   {
00121     return false;
00122   }
00123 
00124   switch (event->type())
00125   {
00126   case QEvent::MouseButtonPress:
00127     return handleMousePress(static_cast<QMouseEvent*>(event));
00128   case QEvent::MouseButtonRelease:
00129     return handleMouseRelease(static_cast<QMouseEvent*>(event));
00130   case QEvent::MouseMove:
00131     return handleMouseMove(static_cast<QMouseEvent*>(event));
00132   case QEvent::Resize:
00133     return handleResize(static_cast<QResizeEvent*>(event));
00134   default:
00135     return false;
00136   }
00137 }
00138 
00139 bool PlaceableWindowProxy::handleMousePress(QMouseEvent *event)
00140 {
00141   if (!visible_)
00142   {
00143     return false;
00144   }
00145 
00146   if (!rect_.contains(event->pos()))
00147   {
00148     // We don't care about anything outside the rect.
00149      return false;
00150   }
00151 
00152   if (state_ != INACTIVE)
00153   {
00154     // We're already doing something, so we don't want to enter
00155     // another state.  But we also don't want someone else to start
00156     // doing something, so we filter out the press.
00157     return true;
00158   }
00159   
00160   if (event->button() == Qt::LeftButton)
00161   {
00162     start_rect_ = rect_;
00163     start_point_ = event->pos();
00164 #if QT_VERSION >= 0x050000
00165     state_ = getNextState(event->localPos());
00166 #else
00167     state_ = getNextState(event->posF());
00168 #endif
00169     qWarning("changing state to %d", state_);
00170     return true;
00171   }
00172 
00173   // Event if we're not doing anything, we want to present a
00174   // consistent interface that says "this region is belongs to me", so
00175   // we filter out events.
00176   return true;
00177 }
00178 
00179 bool PlaceableWindowProxy::handleMouseRelease(QMouseEvent *event)
00180 {
00181   if (!visible_)
00182   {
00183     return false;
00184   }
00185 
00186   if (state_ == INACTIVE)
00187   {
00188     return false;
00189   }
00190 
00191   if (event->button() == Qt::LeftButton)
00192   {
00193     state_ = INACTIVE;
00194     return true;    
00195   }
00196   
00197   return false;
00198 }
00199 
00200 bool PlaceableWindowProxy::handleMouseMove(QMouseEvent *event)
00201 {
00202   if (!visible_)
00203   {
00204     return false;
00205   }
00206 
00207   if (state_ == INACTIVE)
00208   {
00209 #if QT_VERSION >= 0x050000
00210     if (!rect_.contains(event->localPos()))
00211 #else
00212     if (!rect_.contains(event->posF()))
00213 #endif
00214     {
00215       if (has_cursor_)
00216       {
00217         QApplication::restoreOverrideCursor();
00218         has_cursor_ = false;
00219       }
00220       return false;
00221     }    
00222 
00223     // The mouse cursor is over the rect, so we're going to change the
00224     // cursor to indicate the state the user would enter by clicking.
00225 
00226     Qt::CursorShape shape;
00227 #if QT_VERSION >= 0x050000
00228     switch(getNextState(event->localPos()))
00229 #else
00230     switch(getNextState(event->posF()))
00231 #endif
00232     {
00233     case MOVE_TOP_LEFT:
00234     case MOVE_BOTTOM_RIGHT:
00235       shape = Qt::SizeFDiagCursor;
00236       break;
00237     case MOVE_TOP_RIGHT:
00238     case MOVE_BOTTOM_LEFT:
00239       shape = Qt::SizeBDiagCursor;
00240       break;
00241     default:
00242       shape = Qt::SizeAllCursor;
00243     }
00244 
00245     if (has_cursor_)
00246     {
00247       QApplication::changeOverrideCursor(QCursor(shape));
00248     }
00249     else
00250     {
00251       QApplication::setOverrideCursor(QCursor(shape));
00252       has_cursor_ = true;
00253     }
00254 
00255     return true;
00256   }
00257 
00258 #if QT_VERSION >= 0x050000
00259   QPointF dp = event->localPos() - start_point_;
00260 #else
00261   QPointF dp = event->posF() - start_point_;
00262 #endif
00263 
00264   // todo: enforce minimum size & constrain aspect ratio for resizes.  
00265   if (state_ == MOVE_ALL)
00266   {
00267     rect_ = start_rect_.translated(dp);    
00268   }
00269   else if (state_ == MOVE_TOP_LEFT)
00270   {
00271     rect_= resizeHelper(start_rect_,
00272                         start_rect_.bottomRight(),
00273                         start_rect_.topLeft(),
00274 #if QT_VERSION >= 0x050000
00275                         event->localPos());
00276 #else
00277                         event->posF());
00278 #endif
00279     rect_.moveBottomRight(start_rect_.bottomRight());      
00280   }
00281   else if (state_ == MOVE_BOTTOM_LEFT)
00282   {
00283     rect_= resizeHelper(start_rect_,
00284                         start_rect_.topRight(),
00285                         start_rect_.bottomLeft(),
00286 #if QT_VERSION >= 0x050000
00287                         event->localPos());
00288 #else
00289                         event->posF());
00290 #endif
00291     rect_.moveTopRight(start_rect_.topRight());
00292   }
00293   else if (state_ == MOVE_BOTTOM_RIGHT)
00294   {
00295     rect_= resizeHelper(start_rect_,
00296                         start_rect_.topLeft(),
00297                         start_rect_.bottomRight(),
00298 #if QT_VERSION >= 0x050000
00299                         event->localPos());
00300 #else
00301                         event->posF());
00302 #endif
00303     rect_.moveTopLeft(start_rect_.topLeft());      
00304   }
00305   else if (state_ == MOVE_TOP_RIGHT)
00306   {
00307     rect_= resizeHelper(start_rect_,
00308                         start_rect_.bottomLeft(),
00309                         start_rect_.topRight(),
00310 #if QT_VERSION >= 0x050000
00311                         event->localPos());
00312 #else
00313                         event->posF());
00314 #endif
00315     rect_.moveBottomLeft(start_rect_.bottomLeft());      
00316   }
00317   else
00318   {
00319     qWarning("Unhandled state in PlaceableWindowProxy: %d", state_);
00320   }
00321 
00322   return true;
00323 }
00324 
00325 QRectF PlaceableWindowProxy::resizeHelper(const QRectF &rect,
00326                                           const QPointF &p1,
00327                                           const QPointF &p2,
00328                                           const QPointF &p3) const
00329 {
00330   QPointF v1 = p2 - p1;
00331   QPointF v2 = p3 - p1;
00332 
00333   double d = v1.x()*v2.y() - v1.y()*v2.x();
00334   if (d < 0)
00335   {
00336     double new_width = std::abs(p3.x() - p1.x());
00337     if (new_width < 10)
00338     {
00339       new_width = 10;
00340     }
00341 
00342     double new_height = rect.height() / rect.width() * new_width;
00343     return QRectF(0, 0, new_width, new_height);
00344   }
00345   else
00346   {
00347     double new_height = std::abs(p3.y() - p1.y());
00348     if (new_height < 10)
00349     {
00350       new_height = 10;
00351     }
00352 
00353     double new_width = rect.width() / rect.height() * new_height;
00354     return QRectF(0, 0, new_width, new_height);
00355   }
00356 }
00357 
00358 
00359 bool PlaceableWindowProxy::handleResize(QResizeEvent *event)
00360 {
00361   // We always want to pass the resize event along to other widgets.
00362   return false;
00363 }
00364 
00365 void PlaceableWindowProxy::timerEvent(QTimerEvent *event)
00366 {
00367   if (event->timerId() == win_resize_timer_)
00368   {
00369     killTimer(win_resize_timer_);
00370     win_resize_timer_ = -1;
00371     if (target_)
00372     {
00373       winResize(target_->size());
00374     }
00375   }
00376 }
00377 
00378 void PlaceableWindowProxy::rectResize(int dx, int dy)
00379 {
00380 }
00381 
00382 void PlaceableWindowProxy::winResize(const QSize &size)
00383 {
00384 }
00385 
00386 PlaceableWindowProxy::State PlaceableWindowProxy::getNextState(
00387   const QPointF &pt) const
00388 {
00389   if (!rect_.contains(pt))
00390   {
00391     return INACTIVE;
00392   }
00393 
00394   const double threshold = 10.0;  
00395   double near_left = pt.x() - rect_.left() < threshold;
00396   double near_top = pt.y() - rect_.top() < threshold;
00397   double near_right = rect_.right() - pt.x() < threshold;
00398   double near_bottom = rect_.bottom() - pt.y() < threshold;
00399 
00400   if (near_top && near_left)
00401   {
00402     return MOVE_TOP_LEFT;
00403   }
00404   else if (near_top && near_right)
00405   {
00406     return MOVE_TOP_RIGHT;
00407   }
00408   else if (near_bottom && near_left)
00409   {
00410     return MOVE_BOTTOM_LEFT;
00411   }
00412   else if (near_bottom && near_right)
00413   {
00414     return MOVE_BOTTOM_RIGHT;
00415   }
00416   else
00417   {
00418     return MOVE_ALL;
00419   }
00420 }
00421 }  // namespace mapviz_plugins


mapviz_plugins
Author(s): Marc Alban
autogenerated on Thu Jun 6 2019 18:51:07