llresizehandle.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include "llresizehandle.h"
00035 
00036 #include "llfocusmgr.h"
00037 #include "llmath.h"
00038 #include "llui.h"
00039 #include "llmenugl.h"
00040 #include "llcontrol.h"
00041 #include "llfloater.h"
00042 #include "llwindow.h"
00043 
00044 const S32 RESIZE_BORDER_WIDTH = 3;
00045 
00046 LLResizeHandle::LLResizeHandle( const LLString& name, const LLRect& rect, S32 min_width, S32 min_height, ECorner corner )
00047         :
00048         LLView( name, rect, TRUE ),
00049         mDragLastScreenX( 0 ),
00050         mDragLastScreenY( 0 ),
00051         mLastMouseScreenX( 0 ),
00052         mLastMouseScreenY( 0 ),
00053         mImage( NULL ),
00054         mMinWidth( min_width ),
00055         mMinHeight( min_height ),
00056         mCorner( corner )
00057 {
00058         setSaveToXML(false);
00059 
00060         if( RIGHT_BOTTOM == mCorner)
00061         {
00062                 mImage = LLUI::sImageProvider->getUIImage("UIImgResizeBottomRightUUID");
00063         }
00064 
00065         switch( mCorner )
00066         {
00067         case LEFT_TOP:          setFollows( FOLLOWS_LEFT | FOLLOWS_TOP );               break;
00068         case LEFT_BOTTOM:       setFollows( FOLLOWS_LEFT | FOLLOWS_BOTTOM );    break;
00069         case RIGHT_TOP:         setFollows( FOLLOWS_RIGHT | FOLLOWS_TOP );              break;
00070         case RIGHT_BOTTOM:      setFollows( FOLLOWS_RIGHT | FOLLOWS_BOTTOM );   break;
00071         }
00072 
00073         // decorator object, don't serialize
00074         setSaveToXML(FALSE);
00075 }
00076 
00077 BOOL LLResizeHandle::handleMouseDown(S32 x, S32 y, MASK mask)
00078 {
00079         BOOL handled = FALSE;
00080         if( pointInHandle(x, y) )
00081         {
00082                 handled = TRUE;
00083                 // Route future Mouse messages here preemptively.  (Release on mouse up.)
00084                 // No handler needed for focus lost since this clas has no state that depends on it.
00085                 gFocusMgr.setMouseCapture( this );
00086 
00087                 localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
00088                 mLastMouseScreenX = mDragLastScreenX;
00089                 mLastMouseScreenY = mDragLastScreenY;
00090         }
00091 
00092         return handled;
00093 }
00094 
00095 
00096 BOOL LLResizeHandle::handleMouseUp(S32 x, S32 y, MASK mask)
00097 {
00098         BOOL    handled = FALSE;
00099 
00100         if( hasMouseCapture() )
00101         {
00102                 // Release the mouse
00103                 gFocusMgr.setMouseCapture( NULL );
00104                 handled = TRUE;
00105         }
00106         else if( pointInHandle(x, y) )
00107         {
00108                 handled = TRUE;
00109         }
00110 
00111         return handled;
00112 }
00113 
00114 
00115 BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
00116 {
00117         BOOL    handled = FALSE;
00118 
00119         // We only handle the click if the click both started and ended within us
00120         if( hasMouseCapture() )
00121         {
00122                 // Make sure the mouse in still over the application.  We don't want to make the parent
00123                 // so big that we can't see the resize handle any more.
00124         
00125                 S32 screen_x;
00126                 S32 screen_y;
00127                 localPointToScreen(x, y, &screen_x, &screen_y);
00128                 const LLRect valid_rect = getRootView()->getRect();
00129                 screen_x = llclamp( screen_x, valid_rect.mLeft, valid_rect.mRight );
00130                 screen_y = llclamp( screen_y, valid_rect.mBottom, valid_rect.mTop );
00131 
00132                 LLView* resizing_view = getParent();
00133                 if( resizing_view )
00134                 {
00135                         // Resize the parent
00136                         LLRect orig_rect = resizing_view->getRect();
00137                         LLRect scaled_rect = orig_rect;
00138                         S32 delta_x = screen_x - mDragLastScreenX;
00139                         S32 delta_y = screen_y - mDragLastScreenY;
00140                         LLCoordGL mouse_dir;
00141                         // use hysteresis on mouse motion to preserve user intent when mouse stops moving
00142                         mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX;
00143                         mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY;
00144                         mLastMouseScreenX = screen_x;
00145                         mLastMouseScreenY = screen_y;
00146                         mLastMouseDir = mouse_dir;
00147 
00148                         S32 x_multiple = 1;
00149                         S32 y_multiple = 1;
00150                         switch( mCorner )
00151                         {
00152                         case LEFT_TOP:
00153                                 x_multiple = -1; 
00154                                 y_multiple =  1;        
00155                                 break;
00156                         case LEFT_BOTTOM:       
00157                                 x_multiple = -1; 
00158                                 y_multiple = -1;        
00159                                 break;
00160                         case RIGHT_TOP:         
00161                                 x_multiple =  1; 
00162                                 y_multiple =  1;        
00163                                 break;
00164                         case RIGHT_BOTTOM:      
00165                                 x_multiple =  1; 
00166                                 y_multiple = -1;        
00167                                 break;
00168                         }
00169 
00170                         S32 new_width = orig_rect.getWidth() + x_multiple * delta_x;
00171                         if( new_width < mMinWidth )
00172                         {
00173                                 new_width = mMinWidth;
00174                                 delta_x = x_multiple * (mMinWidth - orig_rect.getWidth());
00175                         }
00176 
00177                         S32 new_height = orig_rect.getHeight() + y_multiple * delta_y;
00178                         if( new_height < mMinHeight )
00179                         {
00180                                 new_height = mMinHeight;
00181                                 delta_y = y_multiple * (mMinHeight - orig_rect.getHeight());
00182                         }
00183 
00184                         switch( mCorner )
00185                         {
00186                         case LEFT_TOP:          
00187                                 scaled_rect.translate(delta_x, 0);                      
00188                                 break;
00189                         case LEFT_BOTTOM:       
00190                                 scaled_rect.translate(delta_x, delta_y);        
00191                                 break;
00192                         case RIGHT_TOP:         
00193                                 break;
00194                         case RIGHT_BOTTOM:      
00195                                 scaled_rect.translate(0, delta_y);                      
00196                                 break;
00197                         }
00198 
00199                         // temporarily set new parent rect
00200                         scaled_rect.mRight = scaled_rect.mLeft + new_width;
00201                         scaled_rect.mTop = scaled_rect.mBottom + new_height;
00202                         resizing_view->setRect(scaled_rect);
00203 
00204                         LLView* snap_view = NULL;
00205                         LLView* test_view = NULL;
00206 
00207                         // now do snapping
00208                         switch(mCorner)
00209                         {
00210                         case LEFT_TOP:          
00211                                 snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
00212                                 test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
00213                                 if (!snap_view)
00214                                 {
00215                                         snap_view = test_view;
00216                                 }
00217                                 break;
00218                         case LEFT_BOTTOM:       
00219                                 snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
00220                                 test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
00221                                 if (!snap_view)
00222                                 {
00223                                         snap_view = test_view;
00224                                 }
00225                                 break;
00226                         case RIGHT_TOP:         
00227                                 snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
00228                                 test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
00229                                 if (!snap_view)
00230                                 {
00231                                         snap_view = test_view;
00232                                 }
00233                                 break;
00234                         case RIGHT_BOTTOM:      
00235                                 snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
00236                                 test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
00237                                 if (!snap_view)
00238                                 {
00239                                         snap_view = test_view;
00240                                 }
00241                                 break;
00242                         }
00243 
00244                         // register "snap" behavior with snapped view
00245                         resizing_view->snappedTo(snap_view);
00246 
00247                         // reset parent rect
00248                         resizing_view->setRect(orig_rect);
00249 
00250                         // translate and scale to new shape
00251                         resizing_view->userSetShape(scaled_rect);
00252                         
00253                         // update last valid mouse cursor position based on resized view's actual size
00254                         LLRect new_rect = resizing_view->getRect();
00255                         switch(mCorner)
00256                         {
00257                         case LEFT_TOP:
00258                                 mDragLastScreenX += new_rect.mLeft - orig_rect.mLeft;
00259                                 mDragLastScreenY += new_rect.mTop - orig_rect.mTop;
00260                                 break;
00261                         case LEFT_BOTTOM:
00262                                 mDragLastScreenX += new_rect.mLeft - orig_rect.mLeft;
00263                                 mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom;
00264                                 break;
00265                         case RIGHT_TOP:
00266                                 mDragLastScreenX += new_rect.mRight - orig_rect.mRight;
00267                                 mDragLastScreenY += new_rect.mTop - orig_rect.mTop;
00268                                 break;
00269                         case RIGHT_BOTTOM:
00270                                 mDragLastScreenX += new_rect.mRight - orig_rect.mRight;
00271                                 mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom;
00272                                 break;
00273                         default:
00274                                 break;
00275                         }
00276                 }
00277 
00278                 handled = TRUE;
00279         }
00280         else // don't have mouse capture
00281         {
00282                 if( pointInHandle( x, y ) )
00283                 {
00284                         handled = TRUE;
00285                 }
00286         }
00287 
00288         if( handled )
00289         {
00290                 switch( mCorner )
00291                 {
00292                 case RIGHT_BOTTOM:
00293                 case LEFT_TOP:  
00294                         getWindow()->setCursor(UI_CURSOR_SIZENWSE); 
00295                         break;
00296                 case LEFT_BOTTOM:
00297                 case RIGHT_TOP: 
00298                         getWindow()->setCursor(UI_CURSOR_SIZENESW); 
00299                         break;
00300                 }
00301         }
00302 
00303         return handled;
00304 } // end handleHover
00305 
00306 
00307 // assumes GL state is set for 2D
00308 void LLResizeHandle::draw()
00309 {
00310         if( mImage.notNull() && getVisible() && (RIGHT_BOTTOM == mCorner) ) 
00311         {
00312                 mImage->draw(0, 0);
00313         }
00314 }
00315 
00316 
00317 BOOL LLResizeHandle::pointInHandle( S32 x, S32 y )
00318 {
00319         if( pointInView(x, y) )
00320         {
00321                 const S32 TOP_BORDER = (getRect().getHeight() - RESIZE_BORDER_WIDTH);
00322                 const S32 RIGHT_BORDER = (getRect().getWidth() - RESIZE_BORDER_WIDTH);
00323 
00324                 switch( mCorner )
00325                 {
00326                 case LEFT_TOP:          return (x <= RESIZE_BORDER_WIDTH) || (y >= TOP_BORDER);
00327                 case LEFT_BOTTOM:       return (x <= RESIZE_BORDER_WIDTH) || (y <= RESIZE_BORDER_WIDTH);
00328                 case RIGHT_TOP:         return (x >= RIGHT_BORDER) || (y >= TOP_BORDER);
00329                 case RIGHT_BOTTOM:      return TRUE;
00330                 }
00331         }
00332         return FALSE;
00333 }

Generated on Fri May 16 08:32:56 2008 for SecondLife by  doxygen 1.5.5