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

Generated on Thu Jul 1 06:09:05 2010 for Second Life Viewer by  doxygen 1.4.7