예제 #1
5
void GuiFormCtrl::onMouseDown(const GuiEvent &event)
{
   Point2I localClick = globalToLocalCoord(event.mousePoint);

   // If we're clicking in the header then resize
   if(localClick.y < mThumbSize.y)
   {
      mouseLock();
      mDepressed = true;
      mMouseMovingWin = mCanMove;

      //update
      setUpdate();
   }

   mOrigBounds = getBounds();

   mMouseDownPosition = event.mousePoint;

   if (mMouseMovingWin )
   {
      mouseLock();
   }
   else
   {
      GuiControl *ctrl = findHitControl(localClick);
      if (ctrl && ctrl != this)
         ctrl->onMouseDown(event);
   }
}
예제 #2
0
bool GuiRolloutCtrl::_onMouseUp( const GuiEvent &event, bool lockedMouse )
{
   Point2I localPoint = globalToLocalCoord( event.mousePoint );
   if( mCanCollapse && mHeader.pointInRect( localPoint ) && !mIsAnimating && ( !lockedMouse || isMouseLocked() ) )
   {
      // If Ctrl/Cmd-clicking a header, collapse all sibling GuiRolloutCtrls.
      
      if(    ( mAutoCollapseSiblings && !mIsExpanded && !( event.modifier & SI_PRIMARY_CTRL )
          || ( !mAutoCollapseSiblings && event.modifier & SI_PRIMARY_CTRL ) ) )
      {
         for( SimSet::iterator iter = getParent()->begin(); iter != getParent()->end(); ++ iter )
         {
            GuiRolloutCtrl* ctrl = dynamic_cast< GuiRolloutCtrl* >( *iter );
            if( ctrl && ctrl != this && ctrl->mCanCollapse )
               ctrl->instantCollapse();
         }
         
         if( !mIsExpanded )
            expand();
      }
      else
      {
         // Toggle expansion.
         
         toggleExpanded( false );
      }
      
      return true;
   }
   
   return false;
}
예제 #3
0
void GuiInspectorField::onRightMouseUp( const GuiEvent &event )
{
   if ( mCaptionRect.pointInRect( globalToLocalCoord( event.mousePoint ) ) ) 
      Con::executef( mInspector, "onFieldRightClick", getIdString() );
   else
      Parent::onMouseDown( event );
}
예제 #4
0
bool GuiTabBookCtrl::onMouseDownEditor(const GuiEvent &event, Point2I offset)
{
   bool handled = false;
   Point2I localMouse = globalToLocalCoord( event.mousePoint );

   if( mTabRect.pointInRect( localMouse ) )
   {
      GuiTabPageCtrl *tab = findHitTab( localMouse );
      if( tab != NULL )
      {
         selectPage( tab );
         handled = true;
      }
   }

#ifdef TORQUE_TOOLS
   // This shouldn't be called if it's not design time, but check just incase
   if ( GuiControl::smDesignTime )
   {
      // If we clicked in the editor and our addset is the tab book
      // ctrl, select the child ctrl so we can edit it's properties
      GuiEditCtrl* edit = GuiControl::smEditorHandle;
      if( edit  && ( edit->getAddSet() == this ) && mActivePage != NULL )
         edit->select( mActivePage );
   }
#endif

   // Return whether we handled this or not.
   return handled;

}
void ArrayCtrl::onMouseMove(const Event &event)
{
   Point2I pt = globalToLocalCoord(event.ptMouse);
   pt.x -= headerDim.x; pt.y -= headerDim.y;
   Point2I cell((pt.x < 0 ? -1 : pt.x / cellSize.x), (pt.y < 0 ? -1 : pt.y / cellSize.y));
   if(cell.x != mouseOverCell.x || cell.y != mouseOverCell.y)
   {
      if(mouseOverCell.x != -1)
      {
         setUpdateRegion( Point2I(mouseOverCell.x * cellSize.x + headerDim.x,
                           mouseOverCell.y * cellSize.y + headerDim.y), cellSize );
      }
      
      if(cell.x >= 0 && cell.x < size.x && cell.y >= 0 && cell.y < size.y)
      {
         setUpdateRegion( Point2I(cell.x * cellSize.x + headerDim.x,
                           cell.y * cellSize.y + headerDim.y), cellSize );
         mouseOverCell = cell;
      }
      else
         mouseOverCell.set(-1,-1);
         
      //set the state over flag
      stateOver = ((mouseOverCell.x != -1) && (mouseOverCell.y != -1));
   }
}
예제 #6
0
void GuiInspectorField::onRightMouseUp( const GuiEvent &event )
{
   if ( mCaptionRect.pointInRect( globalToLocalCoord( event.mousePoint ) ) ) 
   { mInspector->onFieldRightClick_callback( getIdString() ); }
   else
   { Parent::onMouseDown( event ); }
}
예제 #7
0
void GuiGradientCtrl::onMouseDown(const GuiEvent &event)
{
   if (!mActive)
      return;
   
   mouseLock(this);
   
   if (mProfile->mCanKeyFocus)
      setFirstResponder();
	
	if (mActive) 
      onAction();

	Point2I extent = getRoot()->getExtent();
   Point2I resolution = getRoot()->getExtent();
   GFXTexHandle bb( resolution.x, 
                    resolution.y, 
                    GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__) );
   
   Point2I tmpPt( event.mousePoint.x, event.mousePoint.y );
   GFXTarget *targ = GFX->getActiveRenderTarget();
   targ->resolveTo( bb );
   GBitmap bmp( bb.getWidth(), bb.getHeight() );
   bb.copyToBmp( &bmp );
   ColorI tmp;
   bmp.getColor( event.mousePoint.x, event.mousePoint.y, tmp );
	
	addColorRange( globalToLocalCoord(event.mousePoint), ColorF(tmp) );
   
   mMouseDown = true;
}
Int32 FearGuiScrollCtrl::getMouseCursorTag(void)
{
   if (! root) return 0;
   Point2I cursorPos = root->getCursorPos();
   
   // handle state depressed
   if (isDepressed())
   {
      switch (getCurHitRegion())
      {
         case SimGui::ScrollCtrl::VertThumb:
         case SimGui::ScrollCtrl::HorizThumb:
            return IDBMP_CURSOR_GRAB;
         
         default:
            return IDBMP_CURSOR_HAND;
      }
   }
   
   switch (findHitRegion(globalToLocalCoord(cursorPos)))
   {
      case SimGui::ScrollCtrl::VertThumb:
      case SimGui::ScrollCtrl::HorizThumb:
         return IDBMP_CURSOR_OPENHAND;
         
      default:
         return IDBMP_CURSOR_HAND;
   }
}
예제 #9
0
F32 GuiSliderCtrl::_getThumbValue( const GuiEvent& event )
{
   Point2I curMousePos = globalToLocalCoord( event.mousePoint );

   F32 value;
   if( getWidth() >= getHeight() )
      value = F32( curMousePos.x - mShiftPoint ) / F32( getWidth() - mShiftExtent ) * ( mRange.y - mRange.x ) + mRange.x;
   else
      value = F32( curMousePos.y ) / F32( getHeight() ) * ( mRange.y - mRange.x ) + mRange.x;

   if(value > mRange.y )
      value = mRange.y;
   else if( value < mRange.x )
      value = mRange.x;

   if( mSnap || ( event.modifier & SI_SHIFT && mTicks >= 1 ) )
   {
      // If the shift key is held, snap to the nearest tick, if any are being drawn

      F32 tickStep = ( mRange.y - mRange.x ) / F32( mTicks + 1 );

      F32 tickSteps = (value - mRange.x ) / tickStep;
      S32 actualTick = S32( tickSteps + 0.5 );

      value = actualTick * tickStep + mRange.x;
      AssertFatal( value <= mRange.y && value >= mRange.x, "Error, out of bounds value generated from shift-snap of slider" );
   }

   return value;
}
예제 #10
0
void GuiRolloutCtrl::onRightMouseUp( const GuiEvent& event )
{
   Parent::onRightMouseUp( event );
   
   Point2I localMouse = globalToLocalCoord( event.mousePoint );
   if( mHeader.pointInRect( localMouse ) )
      onHeaderRightClick_callback();
}
예제 #11
0
void GuiTabBookCtrl::onRightMouseUp( const GuiEvent& event )
{
   Point2I localMouse = globalToLocalCoord( event.mousePoint );
   if( mTabRect.pointInRect( localMouse ) )
   {
      GuiTabPageCtrl* tab = findHitTab( localMouse );
      if( tab )
         onTabRightClick_callback( tab->getText(), getPageNum( tab ) );
   }
}
예제 #12
0
void GuiFormCtrl::onMouseMove(const GuiEvent &event)
{
   Point2I localMove = globalToLocalCoord(event.mousePoint);

   // If we're clicking in the header then resize
   mMouseOver = (localMove.y < mThumbSize.y);
   if(isMouseLocked())
      mDepressed = mMouseOver;

}
예제 #13
0
void FGChatMenu::onRender(GFXSurface *sfc, Point2I offset, const Box2I &)
{
   if (! mMenuName[0]) return;
   ChatMenu *menu = dynamic_cast<ChatMenu *>(manager->findObject(mMenuName));
   if (! menu) return;
   
   Point2I curDrawPoint(offset.x + 3, offset.y + 1);
   if(menu->getMode() == ChatMenu::Inactive || !menu->curMenu)
   {
      sfc->drawText_p(hFont, &curDrawPoint, "Menu inactive");
      return;
   }
   ChatMenu::Node *parent = menu->curMenu->parent;
   char buf[1024];

   if(!parent)
   {
      sfc->drawText_p(hFont, &curDrawPoint, "Root Menu:");
   }
   else
   {
      int lastPt = 1023;
      while(parent)
      {
         int len = strlen(parent->heading) + 1;
         if(len < lastPt)
         {
            lastPt -= len;
            strncpy(buf + lastPt, parent->heading, len + 1);
            buf[lastPt + len] = ':';
         }
         parent = parent->parent;
      }
      buf[1023] = 0;
      sfc->drawText_p(hFont, &curDrawPoint, buf + lastPt);
   }
   curDrawPoint.y += hFont->getHeight();
   
   Point2I cursorPos = root->getCursorPos();
   Point2I pt = globalToLocalCoord(cursorPos);
   
   ChatMenu::Node *walk = menu->curMenu;
   while(walk)
   {
      sprintf(buf, "%c: %s", walk->key, walk->heading);
      GFXFont *font;
      if (pt.x < 0 || pt.x >= extent.x) font = hFont;
      else if (pt.y >= curDrawPoint.y - offset.y && pt.y < curDrawPoint.y - offset.y + hFont->getHeight()) font = hFontHL;
      else font = hFont;
      sfc->drawText_p(font, &curDrawPoint, buf);
      walk->y_offset = curDrawPoint.y - offset.y;
      curDrawPoint.y += hFont->getHeight();
      walk = walk->nextSibling;
   }
}
예제 #14
0
void GuiInspectorField::onMouseDown( const GuiEvent &event )
{
   if ( mCaptionRect.pointInRect( globalToLocalCoord( event.mousePoint ) ) )  
   {
      if ( mEdit )
         //mEdit->onMouseDown( event );
         mInspector->setHighlightField( this );
   }
   else
      Parent::onMouseDown( event );
}
예제 #15
0
void GuiTabPageCtrl::onMouseDown(const GuiEvent &event)
{
   setUpdate();
   Point2I localPoint = globalToLocalCoord( event.mousePoint );

   GuiControl *ctrl = findHitControl(localPoint);
   if (ctrl && ctrl != this)
   {
      ctrl->onMouseDown(event);
   }
}
예제 #16
0
void GuiRectHandles::onMouseDown(const GuiEvent &event)
{
   // The handles range from 0-1, so scale to fit within the
   // control's bounds.
   const Point2I& extent = getExtent();
   Point2I pos(extent.x*mHandleRect.point.x, extent.y*mHandleRect.point.y);
   Point2I size(extent.x*mHandleRect.extent.x, extent.y*mHandleRect.extent.y);
   RectI box(pos, size);

   Point2I localMousePoint = globalToLocalCoord(event.mousePoint);

   // Check if mouse is within handle rect
   if(!box.pointInRect(localMousePoint))
   {
      mHitHandle = 0;
      return;
   }

   Point2I normalizedMouse = localMousePoint - pos;
   Point2I halfSize = size / 2;
   S32 halfHandleSize = mHandleSize / 2;
   if(normalizedMouse.y < mHandleSize)
   {
      // Top handles
      if(normalizedMouse.x < mHandleSize)
         mHitHandle = 1;
      else if(normalizedMouse.x >= (size.x-mHandleSize))
         mHitHandle = 3;
      else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
         mHitHandle = 2;
   }
   else if(normalizedMouse.y >= (size.y-mHandleSize))
   {
      // Bottom handles
      if(normalizedMouse.x < mHandleSize)
         mHitHandle = 7;
      else if(normalizedMouse.x >= (size.x-mHandleSize))
         mHitHandle = 5;
      else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
         mHitHandle = 6;
   }
   else if(normalizedMouse.y >= (halfSize.y-halfHandleSize) && normalizedMouse.y < (halfSize.y+halfHandleSize))
   {
      // Middle handles
      if(normalizedMouse.x < mHandleSize)
         mHitHandle = 8;
      else if(normalizedMouse.x >= (size.x-mHandleSize))
         mHitHandle = 4;
      else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
         mHitHandle = 9;
   }

   mHitPoint = localMousePoint;
}
예제 #17
0
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::onMouseDragged(const GuiEvent &event)
{
   if ((mActive && mMouseDown) || (mActive && (mDisplayMode == pDropperBackground)))
   {
      // Update the picker cross position
      if (mDisplayMode != pPallet)
         setSelectorPos(globalToLocalCoord(event.mousePoint));
   }

   if( !mActionOnMove )
      execAltConsoleCallback();
}
void MenuDisplayCtrl::onRender(GFXSurface *sfc, Point2I offset, const Box2I &)
{
   // temporary menu stuff:
   SimObject *obj = manager->findObject("CurServerMenu");
   ChatMenu *menu = NULL;
   if(obj)
      menu = dynamic_cast<ChatMenu *>(obj);
   if(!menu)
      return;
      
   Point2I curDrawPoint(offset.x, offset.y);

   char buf[1024];

   if(!menu->curMenu || !(menu->curMenu->parent))
      sfc->drawText_p(hFont, &curDrawPoint, menu->heading);
   else if(menu->curMenu)
   {
      ChatMenu::Node *parent = menu->curMenu->parent;
      int lastPt = 1023;
      while(parent)
      {
         int len = strlen(parent->heading) + 1;
         if(len < lastPt)
         {
            lastPt -= len;
            strncpy(buf + lastPt, parent->heading, len + 1);
            buf[lastPt + len] = ':';
         }
         parent = parent->parent;
      }
      buf[1023] = 0;
      sfc->drawText_p(hFont, &curDrawPoint, buf + lastPt);
   }
   
   Point2I cursorPos = root->getCursorPos();
   Point2I pt = globalToLocalCoord(cursorPos);
   
   curDrawPoint.y += hFont->getHeight();
   ChatMenu::Node *walk = menu->curMenu;
   while(walk)
   {
      sprintf(buf, "%c: %s", walk->key, walk->heading);
      GFXFont *font;
      if (pt.x < 0 || pt.x >= extent.x) font = hFont;
      else if (pt.y >= curDrawPoint.y - offset.y && pt.y < curDrawPoint.y - offset.y + hFont->getHeight()) font = hFontHL;
      else font = hFont;
      sfc->drawText_p(font, &curDrawPoint, buf);
      walk->y_offset = curDrawPoint.y - offset.y;
      curDrawPoint.y += hFont->getHeight();
      walk = walk->nextSibling;
   }
}
예제 #19
0
void GuiTabBookCtrl::onMouseMove(const GuiEvent &event)
{
   Point2I localMouse = globalToLocalCoord( event.mousePoint );
   if( mTabRect.pointInRect( localMouse ) )
   {
      GuiTabPageCtrl *tab = findHitTab( localMouse );
      if( tab != NULL && mHoverTab != tab )
         mHoverTab = tab;
      else if ( !tab )
         mHoverTab = NULL;
   }
   Parent::onMouseMove( event );
}
예제 #20
0
void ArrayCtrl::onMouseDown(const Event &event)
{
   if(!active)
   {
      Parent::onMouseDown(event);
      return;
   }
   Point2I pt = globalToLocalCoord(event.ptMouse);
   pt.x -= headerDim.x; pt.y -= headerDim.y;
   Point2I cell((pt.x < 0 ? -1 : pt.x / cellSize.x), (pt.y < 0 ? -1 : pt.y / cellSize.y));
   if(cell.x >= 0 && cell.x < size.x && cell.y >= 0 && cell.y < size.y)
      cellSelected(cell);
   Parent::onMouseDown(event);
}
void GuiSplitContainer::onMouseDragged( const GuiEvent &event )
{
   GuiContainer *firstPanel = dynamic_cast<GuiContainer*>(at(0));
   GuiContainer *secondPanel = dynamic_cast<GuiContainer*>(at(1));

   // This function will constrain the panels to their minExtents and update the mSplitPoint
   if ( mDragging && firstPanel && secondPanel )
   {
      RectI clientRect = getClientRect();
      Point2I newDragPos = globalToLocalCoord( event.mousePoint );

      solvePanelConstraints(newDragPos, firstPanel, secondPanel, clientRect);
   }
}
예제 #22
0
void GuiFormCtrl::onMouseUp(const GuiEvent &event)
{
   // Make sure we only get events we ought to be getting...
   if (! mActive)
      return; 

   mouseUnlock();
   setUpdate();

   Point2I localClick = globalToLocalCoord(event.mousePoint);

   // If we're clicking in the header then resize
   //if(localClick.y < mThumbSize.y && mDepressed)
   //   setCollapsed(!mCollapsed);
}
예제 #23
0
void GuiPaneControl::onMouseDown(const GuiEvent &event)
{
   if(!mCollapsable)
      return;

   Point2I localClick = globalToLocalCoord(event.mousePoint);

   // If we're clicking in the header then resize
   if(localClick.y < mThumbSize.y)
   {
      mouseLock();
      mDepressed = true;

      //update
      setUpdate();
   }
}
void GuiSplitContainer::getCursor( GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent )
{
   GuiCanvas *rootCtrl = getRoot();
   if ( !rootCtrl )
      return;

   S32 desiredCursor = 0;
   RectI splitRect = getSplitRect();

   // Figure out which cursor we want if we need one
   if ( mOrientation == Horizontal )
      desiredCursor = PlatformCursorController::curResizeHorz;
   else if ( mOrientation == Vertical )
      desiredCursor = PlatformCursorController::curResizeVert;

   PlatformWindow *platformWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
   AssertFatal( platformWindow != NULL,"GuiControl without owning platform window!  This should not be possible." );

   PlatformCursorController *cusrorController = platformWindow->getCursorController();
   AssertFatal( cusrorController != NULL,"PlatformWindow without an owned CursorController!" );

   // Check to see if we need one or just the default...

   Point2I localPoint = Point2I( globalToLocalCoord( lastGuiEvent.mousePoint ) );
   if ( splitRect.pointInRect( localPoint ) || mDragging  )
   {
      // Do we need to change it or is it already set?
      if ( rootCtrl->mCursorChanged != desiredCursor )
      {
         // We've already changed the cursor, so set it back
         if ( rootCtrl->mCursorChanged != -1 )
            cusrorController->popCursor();

         // Now change the cursor shape
         cusrorController->pushCursor( desiredCursor );
         rootCtrl->mCursorChanged = desiredCursor;
      }
   }
   else if ( rootCtrl->mCursorChanged != -1 )
   {
      // Just the default
      cusrorController->popCursor();
      rootCtrl->mCursorChanged = -1;
   }
}
예제 #25
0
void GuiSliderCtrl::onMouseDown(const GuiEvent &event)
{
   if ( !mActive || !mAwake || !mVisible )
      return;

   mouseLock();
   setFirstResponder();
   mDepressed = true;

   Point2I curMousePos = globalToLocalCoord( event.mousePoint );
   F32 value;
   if (getWidth() >= getHeight())
      value = F32(curMousePos.x-mShiftPoint) / F32(getWidth()-mShiftExtent)*(mRange.y-mRange.x) + mRange.x;
   else
      value = F32(curMousePos.y) / F32(getHeight())*(mRange.y-mRange.x) + mRange.x;
   
   _updateThumb( value, mSnap || ( event.modifier & SI_SHIFT ) );
}
예제 #26
0
void GuiTabBookCtrl::onMouseDown(const GuiEvent &event)
{
   mDraggingTab = false;
   mDraggingTabRect = false;
   Point2I localMouse = globalToLocalCoord( event.mousePoint );
   if( mTabRect.pointInRect( localMouse ) )
   {
      GuiTabPageCtrl *tab = findHitTab( localMouse );
      if( tab != NULL )
      {
         selectPage( tab );
         mDraggingTab = mAllowReorder;
      }
      else
      {
         mDraggingTabRect = true;
      }
   }
}
예제 #27
0
void GuiTabBookCtrl::onMouseDragged(const GuiEvent &event)
{
   Parent::onMouseDragged( event );

   if ( !mDraggingTab )
       return;

   GuiTabPageCtrl *selectedPage = NULL;
   if ( mSelectedPageNum != -1 )
      selectedPage = mPages[mSelectedPageNum].Page;

   if ( !selectedPage )
       return;

   Point2I localMouse = globalToLocalCoord( event.mousePoint );
   if( mTabRect.pointInRect( localMouse ) )
   {
      GuiTabPageCtrl *tab = findHitTab( localMouse );
      if( tab != NULL && tab != selectedPage )
      {
         S32 targetIndex = -1;
         for( S32 i = 0; i < mPages.size(); i++ )
         {
            if( mPages[i].Page == tab )
            {
               targetIndex = i;
               break;
            }
         }

         if ( targetIndex > mSelectedPageNum )
         {
            reOrder( tab, selectedPage );
         }
         else
         {
            reOrder( selectedPage, tab );
         }
      }
   }
}
예제 #28
0
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::onMouseDown(const GuiEvent &event)
{
   if (!mActive)
      return;
   
   if (mDisplayMode == pDropperBackground)
      return;

   mouseLock(this);
   
   if (mProfile->mCanKeyFocus)
      setFirstResponder();
	
	if (mActive && (mDisplayMode != pDropperBackground)) 
      onAction();

   // Update the picker cross position
   if (mDisplayMode != pPallet)
      setSelectorPos(globalToLocalCoord(event.mousePoint)); 
   
   mMouseDown = true;
}
void MenuDisplayCtrl::onMouseDown(const SimGui::Event &event)
{
   //make sure we have an active menu
   ChatMenu *menu = dynamic_cast<ChatMenu *>(manager->findObject("CurServerMenu"));
   if (! menu) return;
   
   if(menu->getMode() == ChatMenu::Inactive || !menu->curMenu) return;
   
   Point2I pt = globalToLocalCoord(event.ptMouse);
   ChatMenu::Node *walk = menu->curMenu;
   while (walk)
   {
      if (pt.y >= walk->y_offset && pt.y < walk->y_offset + hFont->getHeight())
      {
         if (walk->key != 0)
         {
            menu->processKey(walk->key);
         }
         break;
      }
      walk = walk->nextSibling;
   }
}            
예제 #30
0
S32 GuiGameListMenuCtrl::getRow(Point2I globalPoint)
{
   Point2I localPoint = globalToLocalCoord(globalPoint);
   GuiGameListMenuProfile * profile = (GuiGameListMenuProfile *) mProfile;

   F32 xScale = (float) getWidth() / profile->getRowWidth();

   S32 rowHeight = profile->getRowHeight();
   Point2I currentOffset(0, 0);
   Point2I hitAreaUpperLeft = profile->mHitAreaUpperLeft;
   hitAreaUpperLeft.x *= xScale;
   Point2I hitAreaLowerRight = profile->mHitAreaLowerRight;
   hitAreaLowerRight.x *= xScale;

   Point2I upperLeft, lowerRight;
   for (Vector<Row *>::iterator row = mRows.begin(); row < mRows.end(); ++row)
   {
      if (row != mRows.begin())
      {
         // rows other than the first can have padding above them
         currentOffset.y += (*row)->mHeightPad;
      }

      upperLeft = currentOffset + hitAreaUpperLeft;
      lowerRight = currentOffset + hitAreaLowerRight;

      if ((upperLeft.x <= localPoint.x) && (localPoint.x < lowerRight.x) &&
         (upperLeft.y <= localPoint.y) && (localPoint.y < lowerRight.y))
      {
         return row - mRows.begin();
      }

      currentOffset.y += rowHeight;
   }

   return NO_ROW;
}