Logo Search packages:      
Sourcecode: abiword version File versions

ap_TopRuler.cpp

/* AbiWord
 * Copyright (C) 1998-2000 AbiSource, Inc.
 * Copyright (C) 2001 Tomas Frydrych
 * Copyright (C) 2002 Dom Lachowicz
 * Copyright (C) 2004 Hubert Figuiere
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#include <string.h>
#include <stdio.h>

#include "ut_types.h"
#include "ut_assert.h"
#include "ut_debugmsg.h"
#include "ut_string.h"
#include "ut_timer.h"
#include "ap_TopRuler.h"
#include "gr_Graphics.h"
#include "ap_Ruler.h"
#include "ap_Prefs.h"
#include "xap_Frame.h"
#include "fv_View.h"
#include "ap_FrameData.h"
#include "ap_StatusBar.h"
#include "ap_Strings.h"
#include "ut_string_class.h"
#include "fp_TableContainer.h"

#include "pp_AttrProp.h"
#include "pd_Document.h"
#include "gr_Painter.h"

enum TABINDEX
  {
    tr_TABINDEX_NEW  = -1,
    tr_TABINDEX_NONE = -2
  };

const static UT_uint32 s_tr_AUTOSCROLL_PIXELS   = 25;
const static UT_uint32 s_tr_AUTOSCROLL_INTERVAL = 300; // miliseconds

/*****************************************************************/
UT_uint32 AP_TopRuler::s_iFixedHeight = 32;
UT_uint32 AP_TopRuler::s_iFixedWidth = 32;

AP_TopRuler::AP_TopRuler(XAP_Frame * pFrame)
#if XAP_DONTUSE_XOR
      : m_guideCache(NULL),
      m_otherGuideCache(NULL)
#endif
{
      m_pFrame = pFrame;
      m_pView = NULL;
      m_pScrollObj = NULL;
      m_pG = NULL;
      //m_iHeight = 0;
      m_iWidth = 0;
      m_iLeftRulerWidth = 0;
      m_xScrollOffset = 0;
      m_xScrollLimit = 0;
      m_bValidMouseClick = false;
      m_draggingWhat = DW_NOTHING;
      m_iDefaultTabType = FL_TAB_LEFT;
      m_pAutoScrollTimer = NULL;

      m_bGuide = false;
      m_xGuide = 0;

      const XML_Char * szRulerUnits;
      if (pFrame->getApp()->getPrefsValue(AP_PREF_KEY_RulerUnits,&szRulerUnits))
            m_dim = UT_determineDimension(szRulerUnits);
      else
            m_dim = DIM_IN;

      // set the default to be the fixed size
      m_iHeight = s_iFixedHeight;

      // install top_ruler_prefs_listener as this lister for this func
      pFrame->getApp()->getPrefs()->addListener( AP_TopRuler::_prefsListener, static_cast<void *>(this ));
      m_iCellContainerLeftPos = 0;
      m_draggingCell = 0;
      m_lidTopRuler = 0;
      m_bIsHidden = false;
      UT_DEBUGMSG(("Created TopRuler %x \n",this));
}

AP_TopRuler::~AP_TopRuler(void)
{
      if(m_pView) 
      {
      // don't receive anymore scroll messages
            m_pView->removeScrollListener(m_pScrollObj);

      // no more view messages
            m_pView->removeListener(m_lidTopRuler);
      }
      // no more prefs
      m_pFrame->getApp()->getPrefs()->removeListener( AP_TopRuler::_prefsListener, static_cast<void *>(this ));
      if(!m_bIsHidden)
      {

      //UT_DEBUGMSG(("AP_TopRuler::~AP_TopRuler (this=%p scroll=%p)\n", this, m_pScrollObj));

            DELETEP(m_pScrollObj);
            DELETEP(m_pAutoScrollTimer);
      }
      if(m_pView)
      {
            FV_View * pView = static_cast<FV_View *>(m_pView);
            pView->setTopRuler(NULL);
      }
      m_pView = NULL;
      m_pG = NULL;
      xxx_UT_DEBUGMSG(("Deleting TopRuler %x \n",this));
}

/*****************************************************************/

void AP_TopRuler::setView(AV_View* pView, UT_uint32 iZoom)
{
      this->setView(pView);

      UT_return_if_fail (m_pG);
      m_pG->setZoomPercentage(iZoom);

    // TODO this dimension shouldn't be hard coded.
      m_minColumnWidth = UT_convertToLogicalUnits("0.5in");
      static_cast<FV_View *>(pView)->setTopRuler(this);
}

void AP_TopRuler::setZoom(UT_uint32 iZoom)
{
      UT_return_if_fail (m_pG);
      m_pG->setZoomPercentage(iZoom);

    // TODO this dimension shouldn't be hard coded.
      m_minColumnWidth = UT_convertToLogicalUnits("0.5in");

}
void AP_TopRuler::setViewHidden(AV_View *pView)
{
      if(m_pView != NULL)
      {
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            return;
      }
      m_pView = pView;
      m_bIsHidden = true;
}

void AP_TopRuler::setView(AV_View * pView)
{
      if (m_pView && (m_pView != pView))
      {
            // view is changing.  since this TopRuler class is bound to
            // the actual on-screen widgets, we reuse it as documents
            // change in the frame rather than recreating it with each
            // view (as we do with some of the other objects).

            DELETEP(m_pScrollObj);
      }

      m_pView = pView;
      static_cast<FV_View *>(pView)->setTopRuler(this);

      // create an AV_ScrollObj to receive send*ScrollEvents()

      m_pScrollObj = new AV_ScrollObj(this,_scrollFuncX,_scrollFuncY);
      UT_return_if_fail (m_pScrollObj);
      m_pView->addScrollListener(m_pScrollObj);

      // Register the TopRuler as a ViewListeners on the View.
      // This lets us receive notify events as the user interacts
      // with the document (cmdCharMotion, etc).  This will let
      // us update the display as we move from block to block and
      // from column to column.

      m_pView->addListener(static_cast<AV_Listener *>(this),&m_lidTopRuler);
}

void AP_TopRuler::_refreshView(void)
{
      setView(m_pView);
}

/*! parameter is in device units
 */
void AP_TopRuler::setOffsetLeftRuler(UT_uint32 iLeftRulerWidth)
{
      // we assume that the TopRuler spans the LeftRuler and
      // the DocumentWindow.  The width of the LeftRuler gives
      // us the right edge of the fixed region -- the portion
      // that should not be scrolled on an horizontal scroll.
      // We allow for the LeftRuler to be zero (if/when we
      // support a UI to turn it on and off.

      m_iLeftRulerWidth = iLeftRulerWidth;
}

void AP_TopRuler::setHeight(UT_uint32 iHeight)
{
      m_iHeight = iHeight;
}

UT_uint32 AP_TopRuler::getHeight(void) const
{
      if (m_pG == NULL) {
            return 0;
      }
      return m_pG->tlu(m_iHeight);
}

void AP_TopRuler::setWidth(UT_uint32 iWidth)
{
      m_iWidth = iWidth;
}

UT_uint32 AP_TopRuler::getWidth(void) const
{
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView == NULL)
      {
            return 0;
      }
      GR_Graphics * pG = pView->getGraphics();
      if ((m_pG == NULL) && (pG== NULL)) 
      {
            return 0;
      }
      else if(isHidden())
      {
            return pView->getWindowWidth();
      }
      return m_pG->tlu(m_iWidth);
}

/*****************************************************************/

bool AP_TopRuler::notify(AV_View * pView, const AV_ChangeMask mask)
{
      // Handle AV_Listener events on the view.
      if(isHidden())
      {
            return true;
      }
      UT_ASSERT_HARMLESS(pView==m_pView);
      xxx_UT_DEBUGMSG(("AP_TopRuler::notify [view %p][mask %p]\n",pView,mask));

      // if the column containing the caret has changed or any
      // properties on the section (like the number of columns
      // or the margins) or on the block (like the paragraph
      // indents), then we redraw the ruler.
//#bidi
      if (mask & (AV_CHG_COLUMN | AV_CHG_FMTSECTION | AV_CHG_FMTBLOCK | AV_CHG_HDRFTR ))
      {
            UT_Rect pClipRect;
            pClipRect.top = 0;
            pClipRect.left = m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth));
            FV_View * pView = static_cast<FV_View *>(m_pView);
            if(pView->getViewMode() != VIEW_PRINT)
            {
                  pClipRect.left = 0;
            }

            pClipRect.height = getHeight();
            pClipRect.width = getWidth();
            draw(&pClipRect);
      }

      return true;
}

/*****************************************************************/

void AP_TopRuler::_scrollFuncX(void * pData, UT_sint32 xoff, UT_sint32 xlimit)
{
      // static callback referenced by an AV_ScrollObj() for the ruler
      UT_return_if_fail (pData);

      AP_TopRuler * pTopRuler = (AP_TopRuler *)(pData);

      // let non-static member function do all the work.

      pTopRuler->scrollRuler(xoff,xlimit);
}

void AP_TopRuler::_scrollFuncY(void * /*pData*/, UT_sint32 /*yoff*/, UT_sint32 /*ylimit*/)
{
      // static callback referenced by an AV_ScrollObj() for the ruler
      // we don't care about vertical scrolling.
}

/*****************************************************************/

void AP_TopRuler::scrollRuler(UT_sint32 xoff, UT_sint32 xlimit)
{
      // scroll the window while excluding the portion
      // lining up with the LeftRuler.

      if (xlimit > 0)
            m_xScrollLimit = xlimit;

      if (xoff > m_xScrollLimit)
            xoff = m_xScrollLimit;

      UT_sint32 dx = xoff-  m_xScrollOffset;
      if (!dx)
            return;

      UT_sint32 xFixed = m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth));
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView->getViewMode() != VIEW_PRINT)
      {
            xFixed = m_pG->tlu(s_iFixedWidth);
      }

      UT_sint32 width = getWidth() - xFixed;
      UT_sint32 height = m_pG->tlu(s_iFixedHeight);
      UT_sint32 y_dest = 0;
      UT_sint32 y_src = 0;
      UT_sint32 x_dest = xFixed;
      UT_sint32 x_src = xFixed;

      UT_Rect rClip;
      rClip.top = y_src;
      rClip.height = height;

      if (dx > 0)
      {
            x_src += dx;
            width += -dx;
            // fudge factor of 10
            rClip.left = x_dest + width - m_pG->tlu(10);
            rClip.width = dx + m_pG->tlu(10);
      }
      else if (dx < 0)
      {
            x_dest += -dx;
            width += dx;
            rClip.left = x_src;
            rClip.width = -dx + m_pG->tlu(10);
      }

      m_pG->scroll(x_dest,y_dest,x_src,y_src,width,height);
      m_xScrollOffset = xoff;
      draw(&rClip);
}

/*****************************************************************/

void AP_TopRuler::draw(const UT_Rect * pCR, AP_TopRulerInfo * pUseInfo)
{
      if (!m_pG)
            return;

      UT_Rect r;
      UT_Rect * pClipRect = NULL;
      
      if (pCR)
      {
            r.left   = pCR->left;
            r.top    = pCR->top;
            r.width  = pCR->width;
            r.height = pCR->height;
            pClipRect = &r;
            m_pG->setClipRect(pClipRect);
      }

      /* if you get one of these two asserts then you forgot to call setWidth() or setHeight() */
      UT_ASSERT_HARMLESS(m_iHeight);
      UT_ASSERT_HARMLESS(m_iWidth);

      // draw the background

      GR_Painter painter(m_pG);
      painter.fillRect(GR_Graphics::CLR3D_Background,0,0,getWidth (),getHeight ());

      // draw the foreground

      _draw(pClipRect,pUseInfo);

      if (pClipRect)
            m_pG->setClipRect(NULL);
}

void AP_TopRuler::_drawBar(const UT_Rect * pClipRect, AP_TopRulerInfo * pInfo,
                                       GR_Graphics::GR_Color3D clr3d, UT_sint32 x, UT_sint32 w)
{
      // Draw ruler bar (white or dark-gray) over [x,x+w)
      // where x is in page-relative coordinates.  we need
      // to compensate for fixed portion, the page-view margin,
      // and the scroll.

      UT_uint32 yTop = m_pG->tlu(s_iFixedHeight)/4;
      UT_uint32 yBar = m_pG->tlu(s_iFixedHeight)/2;
      UT_sint32 xFixed = static_cast<UT_sint32>(m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));

      // convert page-relative coordinates into absolute coordinates.
      UT_sint32 ixMargin = pInfo->m_xPageViewMargin;
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView == NULL)
            return;

      if(pView->getPoint() == 0)
            return;

      if(pView->getViewMode() != VIEW_PRINT)
      {
            ixMargin = 0;
            xFixed = m_pG->tlu(s_iFixedWidth);
      }
      UT_sint32 xAbsLeft = xFixed + ixMargin + x - m_xScrollOffset;
      UT_sint32 xAbsRight = xAbsLeft + w;


      // we need to do our own clipping for the fixed area

      if (xAbsLeft < xFixed)              // need to shorten what we draw
            xAbsLeft = xFixed;

      // draw whatever is left

      if (xAbsRight > xAbsLeft)
      {
            UT_Rect r(xAbsLeft,yTop,(xAbsRight-xAbsLeft),yBar);
            if (!pClipRect || r.intersectsRect(pClipRect)) {
                  GR_Painter painter(m_pG);
                  painter.fillRect(clr3d,r);
            }
      }
}

void AP_TopRuler::_drawTickMark(const UT_Rect * pClipRect,
                                                AP_TopRulerInfo * /* pInfo */, ap_RulerTicks &tick,
                                                GR_Graphics::GR_Color3D clr3d, GR_Font * pFont,
                                                UT_sint32 k, UT_sint32 xTick)
{
      UT_sint32 yTop = m_pG->tlu(s_iFixedHeight)/4;
      UT_sint32 yBar = m_pG->tlu(s_iFixedHeight)/2;

      GR_Painter painter(m_pG);

      if (pClipRect)
      {
            // do quick and crude check for visibility.
            // we know that everything that we draw will
            // be vertically within the bar.  horizontally
            // it will either be a single line or a small
            // font -- let's assume that a 3 digit centered
            // string will be less than 100 pixels.
      }

      if (k % tick.tickLabel)
      {
            // draw the ticks
            UT_uint32 h = ((k % tick.tickLong) ? m_pG->tlu(2) : m_pG->tlu(6));
            UT_sint32 y = yTop + (yBar-h)/2;
            m_pG->setColor3D(clr3d);
            painter.drawLine(xTick,y,xTick,y+h);
      }
      else if (pFont)
      {
            // draw the number
            m_pG->setColor3D(clr3d);
            m_pG->setFont(pFont);
//
// The graphics class works in logical units almost exclusively.
//
            UT_uint32 iFontHeight = m_pG->getFontAscent();

            UT_uint32 n = k / tick.tickLabel * tick.tickScale;

            if (n == 0)                               // we never draw the zero on the
                  return;                                   // origin

            char buf[6];
            UT_UCSChar span[6];
            UT_GrowBufElement charWidths[6];
            UT_ASSERT_HARMLESS(n < 10000);

            sprintf(buf, "%d", n);
            UT_UCS4_strcpy_char(span, buf);
            UT_uint32 len = strlen(buf);

            UT_sint32 w = m_pG->measureString(span, 0, len, charWidths) * 100 / m_pG->getZoomPercentage();

//                UT_sint32 yDU = s_iFixedHeight/4 + 
//                        (s_iFixedHeight/2 - s_iFixedHeight*m_pG->getZoomPercentage()/(4*100))/2;

            // The following code works perfectly on UNIX
                UT_sint32 yDU = 2*s_iFixedHeight/3;
            UT_sint32 yLU = m_pG->tlu(yDU);
            yLU = yLU - iFontHeight;
            xxx_UT_DEBUGMSG(("s_iFixedHeight %d yDU %d yLU %d \n",s_iFixedHeight,yDU,yLU));
            //
            // FIXME HACK for Windows! There is something wrong with
            // here. Thi sis Tomas's code which works for Windows
            // but not Unix
            //
#ifdef WIN32
// the call to drawChars will scale y and x by the zoom factor 
// -- in reality the y is
// constant because the height of the whole ruler bar is a constant and 
// similarly
// w is a constant because the font does not scale              
// working the offset in device units and converting it to layout units only at
// the end significantly reduces the rounding errors            
            iFontHeight = m_pG->getFontHeight();
                yDU = s_iFixedHeight/4 +
                        (s_iFixedHeight/2 - iFontHeight*m_pG->getDeviceResolution()/m_pG->getResolution())/2;
                yLU = m_pG->tlu(yDU);                                 
#endif
               painter.drawChars(span, 0, len, xTick - w/2, yLU); 
      }
}

void AP_TopRuler::_drawTicks(const UT_Rect * pClipRect,
                                           AP_TopRulerInfo * pInfo, ap_RulerTicks &tick,
                                           GR_Graphics::GR_Color3D clr3d, GR_Font * pFont,
                                           UT_sint32 xOrigin, UT_sint32 xFrom, UT_sint32 xTo)
{
      // draw tick marks over the ruler bar.
      // xOrigin gives the page-relative x-coordinate of zero.
      // xFrom gives the page-relative x-coordinate of where we should begin drawing.
      // xTo gives the page-relative x-coordinate of where we should end drawing.
      // if xTo is less than xFrom we draw with values increasing to the left.

      UT_ASSERT_HARMLESS(xFrom != xTo);
      UT_ASSERT_HARMLESS(xFrom >= 0);
      UT_ASSERT_HARMLESS(xTo >= 0);

      UT_sint32 xFixed = static_cast<UT_sint32>(m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView->getViewMode() != VIEW_PRINT)
      {
            xFixed = m_pG->tlu(s_iFixedWidth);
      }


      // convert page-relative coordinates into absolute coordinates.

      UT_sint32 xAbsOrigin = xFixed + pInfo->m_xPageViewMargin + xOrigin - m_xScrollOffset;
      UT_sint32 xAbsFrom   = xFixed + pInfo->m_xPageViewMargin + xFrom   - m_xScrollOffset;
      UT_sint32 xAbsTo     = xFixed + pInfo->m_xPageViewMargin + xTo     - m_xScrollOffset;

      // we need to do our own clipping for the fixed area
      //UT_DEBUGMSG(("xAbsFrom %d, xAbsTo %d\n",xAbsFrom,xAbsTo));

      if (xAbsFrom < xFixed)
            xAbsFrom = xFixed;
      if (xAbsTo < xFixed)
            xAbsTo = xFixed;
      if (xAbsFrom == xAbsTo)
            return;                                         // everything clipped

      if (xAbsTo > xAbsFrom)
      {
            // draw increasing numbers to the right
            //if(pView->getViewMode() == VIEW_NORMAL)
            //{
            //    xAbsOrigin -= m_pG->tlu(s_iFixedWidth);
            //}
            UT_sint32 k=0;
            while (1)
            {
                  UT_ASSERT(k < 10000);
                  UT_sint32 xTick = xAbsOrigin + k*tick.tickUnit/tick.tickUnitScale;
                  if (xTick > xAbsTo)
                        break;

                  if (xTick >= xAbsFrom)
                  {
                        _drawTickMark(pClipRect,pInfo,tick,clr3d,pFont,k,xTick);
                  }
                  k++;
            }
      }
      else
      {
            // draw increasing numbers to the left

            UT_sint32 k=0;
            while (1)
            {
                  UT_ASSERT(k < 10000);
                  UT_sint32 xTick = xAbsOrigin - k*tick.tickUnit/tick.tickUnitScale;
                  if (xTick < xAbsTo)
                        break;
                  if (xTick <= xAbsFrom)
                        _drawTickMark(pClipRect,pInfo,tick,clr3d,pFont,k,xTick);
                  k++;
            }
      }
}

/*****************************************************************/

void AP_TopRuler::_getParagraphMarkerXCenters(AP_TopRulerInfo * pInfo,
                                                                    UT_sint32 * pLeft, UT_sint32 * pRight, UT_sint32 * pFirstLine)
{
      UT_sint32 xAbsLeft;
      UT_sint32 xAbsRight;

      FV_View * pView = (static_cast<FV_View *>(m_pView));
      fl_BlockLayout *pBlock = pView->getCurrentBlock();
      
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);

/*    if(bRTL)
      {
            xAbsRight = _getFirstPixelInColumn(pInfo,pInfo->m_iCurrentColumn);
            xAbsLeft = xAbsRight - pInfo->u.c.m_xColumnWidth;
      }
      else  */
      {
            xAbsLeft = _getFirstPixelInColumn(pInfo,pInfo->m_iCurrentColumn);
            xAbsRight = xAbsLeft + pInfo->u.c.m_xColumnWidth;
      }

      AP_TopRulerTableInfo *pTInfo = NULL;
      if(pInfo->m_mode == AP_TopRulerInfo::TRI_MODE_TABLE)
      {
            if(pInfo->m_vecTableColInfo->getItemCount() > 0 && pInfo->m_iCurCell < pInfo->m_vecTableColInfo->getItemCount())
            {
                  pTInfo = static_cast<AP_TopRulerTableInfo *>(pInfo->m_vecTableColInfo->getNthItem(pInfo->m_iCurCell));
            }
            else
            {
                  pTInfo = NULL;
            }
      }
      m_iCellContainerLeftPos = xAbsLeft;
      if (pLeft)
      {
            if(pTInfo == NULL)
            {
                  *pLeft = xAbsLeft + pInfo->m_xrLeftIndent;
            }
            else
            {
                  *pLeft = xAbsLeft + pTInfo->m_iLeftCellPos + pTInfo->m_iLeftSpacing + pInfo->m_xrLeftIndent;
//
// m_iLeftCellPos is the absolute value of the position of the left side of the cell relative
// to the left column.
//
// What we want is the position relative to the container holding the cell
                  fp_Container *pCon = pTInfo->m_pCell->getContainer();
                  if(pCon)
                  {
                        pCon = pCon->getContainer();
                        UT_sint32 ioff_x = 0;
                        while(pCon && !pCon->isColumnType())
                        {
                              ioff_x += pCon->getX();
                              pCon = static_cast<fp_Container *>(pCon->getContainer());
                        }                       
                        m_iCellContainerLeftPos += ioff_x;
                  }
            }
      }

      if (pRight)
      {
            if(pTInfo == NULL)
            {
                  *pRight = xAbsRight - pInfo->m_xrRightIndent;
            }
            else
            {
                  *pRight = xAbsLeft + pTInfo->m_iRightCellPos - pTInfo->m_iRightSpacing - pInfo->m_xrRightIndent;  
            }
      }
      if (pFirstLine)
      {
            if(pTInfo == NULL)
            {
                  if(bRTL)
                        *pFirstLine = xAbsRight - pInfo->m_xrRightIndent - pInfo->m_xrFirstLineIndent;
                  else
                        *pFirstLine = xAbsLeft + pInfo->m_xrLeftIndent + pInfo->m_xrFirstLineIndent;
            }
            else
            {
                  if(bRTL)
                        *pFirstLine = xAbsLeft + pTInfo->m_iRightCellPos - pTInfo->m_iRightSpacing - pInfo->m_xrFirstLineIndent - pInfo->m_xrRightIndent;
                  else
                        *pFirstLine = xAbsLeft + pTInfo->m_iLeftCellPos + pTInfo->m_iLeftSpacing + pInfo->m_xrFirstLineIndent  + pInfo->m_xrLeftIndent;
            }
      }
}

bool AP_TopRuler::_isInBottomBoxOfLeftIndent(UT_uint32 y)
{
      // return true if in the lower box of the left-indent pair

      UT_uint32 yTop = m_pG->tlu(s_iFixedHeight)/4;
      UT_uint32 yBar = m_pG->tlu(s_iFixedHeight)/2;
      UT_uint32 yBottom = yTop + yBar;

      return (y > yBottom);
}

void AP_TopRuler::_getParagraphMarkerRects(AP_TopRulerInfo * /* pInfo */,
                                                               UT_sint32 leftCenter,
                                                               UT_sint32 rightCenter,
                                                               UT_sint32 firstLineCenter,
                                                               UT_Rect * prLeftIndent,
                                                               UT_Rect * prRightIndent,
                                                               UT_Rect * prFirstLineIndent)
{
      UT_uint32 yTop = m_pG->tlu(s_iFixedHeight)/4;
      UT_uint32 yBar = m_pG->tlu(s_iFixedHeight)/2;
      UT_uint32 yBottom = yTop + yBar;
      UT_sint32 hs = m_pG->tlu(5);                          // halfSize
      UT_sint32 fs = hs * 2 + m_pG->tlu(1);             // fullSize
      UT_sint32 ls, rs;                   // the sizes of left and right markers

      FV_View * pView = (static_cast<FV_View *>(m_pView));
      fl_BlockLayout * pBlock = pView->getCurrentBlock();
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);

      if(bRTL)
      {
            ls = m_pG->tlu(9);
            rs = m_pG->tlu(15);
      }
      else
      {
            ls = m_pG->tlu(15);
            rs = m_pG->tlu(9);
      }
      if (prLeftIndent)
            prLeftIndent->set(leftCenter - hs, yBottom - m_pG->tlu(8), fs, ls);

      if (prFirstLineIndent)
            prFirstLineIndent->set(firstLineCenter - hs, yTop - m_pG->tlu(1), fs, m_pG->tlu(9));

      if (prRightIndent)
            prRightIndent->set(rightCenter - hs, yBottom - m_pG->tlu(8), fs, rs);
}

void AP_TopRuler::_drawParagraphProperties(const UT_Rect * pClipRect,
                                                               AP_TopRulerInfo * pInfo,
                                                               bool bDrawAll)
{
      UT_sint32 leftCenter, rightCenter, firstLineCenter;
      UT_Rect rLeftIndent, rRightIndent, rFirstLineIndent;

      _getParagraphMarkerXCenters(pInfo,&leftCenter,&rightCenter,&firstLineCenter);
      _getParagraphMarkerRects(pInfo,
                                           leftCenter, rightCenter, firstLineCenter,
                                           &rLeftIndent, &rRightIndent, &rFirstLineIndent);

      FV_View * pView = (static_cast<FV_View *>(m_pView));
      fl_BlockLayout * pBlock = pView->getCurrentBlock();
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);
      
      xxx_UT_DEBUGMSG(("ap_TopRulerDrawPara: bRTL = %d \n",bRTL));
      if (m_draggingWhat == DW_LEFTINDENTWITHFIRST)
      {
            if(bRTL)
            {
                  _drawRightIndentMarker(rLeftIndent, false); // draw hollow version at old location
                  _drawFirstLineIndentMarker(rFirstLineIndent, false);
                  _drawRightIndentMarker(m_draggingRect, true);   // draw sculpted version at mouse
                  _drawFirstLineIndentMarker(m_dragging2Rect, true);
            }
            else
            {
                  _drawLeftIndentMarker(rLeftIndent, false); // draw hollow version at old location
                  _drawFirstLineIndentMarker(rFirstLineIndent, false);
                  _drawLeftIndentMarker(m_draggingRect, true);    // draw sculpted version at mouse
                  _drawFirstLineIndentMarker(m_dragging2Rect, true);
            }
      }
      else if (bDrawAll)
      {
            if (!pClipRect || rLeftIndent.intersectsRect(pClipRect))
                  _drawLeftIndentMarker(rLeftIndent, true); // draw sculpted version at current location
            if (!pClipRect || rFirstLineIndent.intersectsRect(pClipRect))
                  _drawFirstLineIndentMarker(rFirstLineIndent, true);
      }

      if (m_draggingWhat == DW_LEFTINDENT)
      {
            if(bRTL)
            {
                  _drawRightIndentMarker(rLeftIndent, false); // draw hollow version at old location
                  _drawRightIndentMarker(m_draggingRect, true);   // draw sculpted version at mouse
            }
            else
            {
                  _drawLeftIndentMarker(rLeftIndent, false); // draw hollow version at old location
                  _drawLeftIndentMarker(m_draggingRect, true);    // draw sculpted version at mouse
            }
      }
      else if (bDrawAll)
      {
            if (!pClipRect || rLeftIndent.intersectsRect(pClipRect))
                  _drawLeftIndentMarker(rLeftIndent, true); // draw sculpted version at current location
      }

      if (m_draggingWhat == DW_RIGHTINDENT)
      {
            if(bRTL)
            {
                  _drawLeftIndentMarker(rRightIndent, false);
                  _drawLeftIndentMarker(m_draggingRect, true);
            }
            else
            {
                  _drawRightIndentMarker(rRightIndent, false);
                  _drawRightIndentMarker(m_draggingRect, true);
            }
      }
      else if (bDrawAll)
      {
            if (!pClipRect || rRightIndent.intersectsRect(pClipRect))
                  _drawRightIndentMarker(rRightIndent, true);
      }

      if (m_draggingWhat == DW_FIRSTLINEINDENT)
      {
            _drawFirstLineIndentMarker(rFirstLineIndent, false);
            _drawFirstLineIndentMarker(m_draggingRect, true);
      }
      else if (bDrawAll)
      {
            if (!pClipRect || rFirstLineIndent.intersectsRect(pClipRect))
                  _drawFirstLineIndentMarker(rFirstLineIndent, true);
      }
}


/*****************************************************************/

void AP_TopRuler::_getTabToggleRect(UT_Rect * prToggle)
{
      if (prToggle) {
            UT_sint32 l,xFixed = static_cast<UT_sint32>(m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
            FV_View * pView = static_cast<FV_View *>(m_pView);
            if(pView->getViewMode() != VIEW_PRINT)
                  xFixed = m_pG->tlu(s_iFixedWidth);
            
            l = (xFixed - m_pG->tlu(17))/2;
            
            UT_sint32 t = (m_pG->tlu(s_iFixedHeight) - m_pG->tlu(17))/2;
            prToggle->set(t, l, m_pG->tlu(17), m_pG->tlu(17));
      }
}

void AP_TopRuler::_getTabStopRect(AP_TopRulerInfo * /* pInfo */,
                                                       UT_sint32 anchor,
                                                       UT_Rect * pRect)
{
      if (pRect) {
            UT_uint32 yTop = m_pG->tlu(s_iFixedHeight)/4;
            UT_uint32 yBar = m_pG->tlu(s_iFixedHeight)/2;
            UT_uint32 yBottom = yTop + yBar;
            UT_sint32 hs = m_pG->tlu(4);                          // halfSize
            UT_sint32 fs = hs * 2 + m_pG->tlu(2);                 // fullSize
            
            pRect->set(anchor - hs, yBottom - m_pG->tlu(6), fs, m_pG->tlu(6));
      }
}

/*****************************************************************/

void AP_TopRuler::_getTabStopXAnchor(AP_TopRulerInfo * pInfo,
                                                            UT_sint32 k,
                                                            UT_sint32 * pTab,
                                                            eTabType & iType,
                                                            eTabLeader & iLeader)
{
      UT_sint32 xAbsLeft = _getFirstPixelInColumn(pInfo,pInfo->m_iCurrentColumn);

      UT_sint32 iPosition;

      if (k == tr_TABINDEX_NEW)
      {
            // this is a new tab
            iPosition = m_dragStart;
            iType = m_draggingTabType;
            iLeader = FL_LEADER_NONE;
      }
      else
      {
            // look it up in the document
            UT_ASSERT_HARMLESS(k<pInfo->m_iTabStops);

            fl_TabStop TabInfo;
            bool bRes = pInfo->m_pfnEnumTabStops(pInfo->m_pVoidEnumTabStopsData,
                                                                        k, &TabInfo);
            UT_ASSERT_HARMLESS(bRes);
            iPosition = TabInfo.getPosition();
            iType = TabInfo.getType();
            iLeader = TabInfo.getLeader();
      }

      if (pTab)
      {
            fl_BlockLayout * pBlock = (static_cast<FV_View *>(m_pView))->getCurrentBlock();
      if(pBlock && pBlock->getDominantDirection() == UT_BIDI_RTL)
      {
            UT_sint32 xAbsRight = xAbsLeft + pInfo->u.c.m_xColumnWidth;
            *pTab = xAbsRight - iPosition;
      }
      else
            *pTab = xAbsLeft + iPosition;
      }
}

void AP_TopRuler::_drawTabProperties(const UT_Rect * pClipRect,
                                                               AP_TopRulerInfo * pInfo,
                                                               bool bDrawAll)
{
      UT_sint32 anchor;
      UT_Rect rect;
      eTabType iType;
      eTabLeader iLeader;

      if (m_draggingWhat == DW_TABSTOP)
      {
            // just deal with the tab being moved

            _getTabStopXAnchor(pInfo, m_draggingTab, &anchor, iType, iLeader);
            _getTabStopRect(pInfo, anchor, &rect);

            _drawTabStop(rect, m_draggingTabType, false);
            UT_uint32 xFixed = static_cast<UT_sint32>(m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
            FV_View * pView = static_cast<FV_View *>(m_pView);
            if(pView->getViewMode() != VIEW_PRINT)
            {
                  xFixed = m_pG->tlu(s_iFixedWidth);
            }
            if (m_draggingRect.left + m_draggingRect.width > static_cast<UT_sint32>(xFixed))
                  _drawTabStop(m_draggingRect, m_draggingTabType, true);
      }

      /*
            NOTE: even during tab drags, we might need to draw other tabs
            that got revealed after being obscured by the dragged tab
      */

      if (bDrawAll)
      {
            // loop over all explicit tabs

            UT_sint32 xAbsLeft = _getFirstPixelInColumn(pInfo,pInfo->m_iCurrentColumn);
            UT_sint32 left = xAbsLeft + pInfo->m_xrLeftIndent;

            for (UT_sint32 i = 0; i < pInfo->m_iTabStops; i++)
            {
                  if ((m_draggingWhat == DW_TABSTOP) &&
                        (m_draggingTab == static_cast<UT_sint32>(i)))
                        continue;

                  _getTabStopXAnchor(pInfo, i, &anchor, iType, iLeader);
                  _getTabStopRect(pInfo, anchor, &rect);

                  if (left < anchor)
                        left = anchor;

                  if (!pClipRect || rect.intersectsRect(pClipRect))
                        _drawTabStop(rect, iType, true);
            }

            if (m_draggingWhat != DW_TABSTOP)
            {
                  // draw trailing default tabs

                  UT_sint32 xAbsRight = xAbsLeft + pInfo->u.c.m_xColumnWidth;
                  UT_uint32 yTop = m_pG->tlu(s_iFixedHeight)/4;
                  UT_uint32 yBar = m_pG->tlu(s_iFixedHeight)/2;
                  UT_uint32 yBottom = yTop + yBar;

                  m_pG->setColor3D(GR_Graphics::CLR3D_BevelDown);

                  // UT_ASSERT_HARMLESS(pInfo->m_iDefaultTabInterval > 0);
                  if (pInfo->m_iDefaultTabInterval > 0)                 // prevent infinite loop -- just in case
                  {
                        UT_sint32 iPos = xAbsLeft;
                        GR_Painter painter(m_pG);
                        for (;iPos < xAbsRight; iPos += pInfo->m_iDefaultTabInterval)
                        {
                              if (iPos <= left)
                                    continue;

                              painter.drawLine(iPos, yBottom + m_pG->tlu(1), iPos, yBottom + m_pG->tlu(4));
                        }
                  }
            }
      }
}

UT_sint32 AP_TopRuler::_findTabStop(AP_TopRulerInfo * pInfo,
                                                      UT_uint32 x, UT_uint32 y,
                                                      UT_sint32 &anchor, eTabType & iType, eTabLeader & iLeader)
{
      // hit-test all the existing tabs
      // return the index of the one found

      UT_Rect rect;

      for (UT_sint32 i = 0; i < pInfo->m_iTabStops; i++)
      {
            _getTabStopXAnchor(pInfo, i, &anchor, iType, iLeader);
            _getTabStopRect(pInfo, anchor, &rect);

            if (rect.containsPoint(x,y))
                  return i;
      }

      return tr_TABINDEX_NONE;
}

void AP_TopRuler::_getTabZoneRect(AP_TopRulerInfo * pInfo, UT_Rect &rZone)
{
      // this is the zone where clicking will get you a new tab
      // this is basically anywhere in the ruler bar, inside the current column

      UT_uint32 yTop = m_pG->tlu(s_iFixedHeight)/4;
      UT_uint32 yBar = m_pG->tlu(s_iFixedHeight)/2;
      UT_sint32 xAbsLeft = _getFirstPixelInColumn(pInfo,0);
      UT_sint32 xAbsRight = xAbsLeft + pInfo->u.c.m_xColumnWidth;

      rZone.set(xAbsLeft, yTop, xAbsRight-xAbsLeft, yBar);
}

const char * AP_TopRuler::_getTabStopString(AP_TopRulerInfo * pInfo, UT_sint32 k)
{
      // return pointer to static buffer -- use it quickly.

      fl_TabStop TabInfo;

      bool bRes = pInfo->m_pfnEnumTabStops(pInfo->m_pVoidEnumTabStopsData,
                                                                  k, &TabInfo);
      UT_return_val_if_fail (bRes, NULL);

      const char* pStart = &pInfo->m_pszTabStops[TabInfo.getOffset()];
      const char* pEnd = pStart;
      while (*pEnd && (*pEnd != ','))
      {
            pEnd++;
      }

      UT_uint32 iLen = pEnd - pStart;
      UT_return_val_if_fail (iLen<20, NULL);

      static char buf[20];

      strncpy(buf, pStart, iLen);
      buf[iLen]=0;

      return buf;
}

/*****************************************************************/

UT_sint32 AP_TopRuler::_getColumnMarkerXRightEnd(AP_TopRulerInfo * pInfo, UT_uint32 kCol)
{
      // return the right edge of the gap following this column
      // (this is equal to the left edge of the start of the
      // next column)

      return _getFirstPixelInColumn(pInfo,kCol+1);
}

void AP_TopRuler::_getColumnMarkerRect(AP_TopRulerInfo * pInfo, UT_uint32 /* kCol */,
                                                         UT_sint32 xRight, UT_Rect * prCol)
{
      UT_uint32 yTop = m_pG->tlu(s_iFixedHeight)/4;

      UT_sint32 xAbsLeft = _getFirstPixelInColumn(pInfo,0);
      UT_sint32 xAbsRight = xAbsLeft + pInfo->u.c.m_xColumnWidth;
      UT_sint32 xAbsRightGap = xAbsRight + pInfo->u.c.m_xColumnGap;
      UT_sint32 xdelta = xRight - xAbsRightGap;
      prCol->set(xAbsRight-xdelta, yTop- m_pG->tlu(5), pInfo->u.c.m_xColumnGap + 2*xdelta + m_pG->tlu(1), m_pG->tlu(11));
}

void AP_TopRuler::_drawColumnProperties(const UT_Rect * pClipRect,
                                                            AP_TopRulerInfo * pInfo,
                                                            UT_uint32 kCol)
{
      UT_Rect rCol;

      _getColumnMarkerRect(pInfo,kCol,_getColumnMarkerXRightEnd(pInfo,kCol),&rCol);

      if ( (m_draggingWhat == DW_COLUMNGAP) || (m_draggingWhat == DW_COLUMNGAPLEFTSIDE) )
      {
            _drawColumnGapMarker(m_draggingRect);
      }
      else
      {
            if (!pClipRect || rCol.intersectsRect(pClipRect))
                  _drawColumnGapMarker(rCol);
      }
}

/*****************************************************************/

void AP_TopRuler::_getMarginMarkerRects(AP_TopRulerInfo * pInfo, UT_Rect &rLeft, UT_Rect &rRight)
{
      // we play some games with where the right margin is
      // drawn.  this compensates for an odd pixel roundoff
      // due to our (current) restriction that all columns
      // and gaps are the same size.  rather than compute
      // from the right of the paper, we compute the right
      // edge of the last column.

      UT_sint32 xAbsLeft,xAbsRight;

      bool bRTL;
      XAP_App::getApp()->getPrefsValueBool(static_cast<const XML_Char *>(AP_PREF_KEY_DefaultDirectionRtl), &bRTL);

      if(bRTL)
      {
            xAbsRight = _getFirstPixelInColumn(pInfo,0) + pInfo->u.c.m_xColumnWidth;
            xAbsLeft = _getFirstPixelInColumn(pInfo, pInfo->m_iNumColumns - 1);
      }
      else
      {
            xAbsLeft = _getFirstPixelInColumn(pInfo,0);
            xAbsRight = _getFirstPixelInColumn(pInfo, pInfo->m_iNumColumns - 1) + pInfo->u.c.m_xColumnWidth;
      }

      UT_uint32 yTop = m_pG->tlu(s_iFixedHeight) / 4;
      UT_sint32 hs = m_pG->tlu(3);                          // halfSize
      UT_sint32 fs = hs * 2;              // fullSize

      // we want the width to be 1 pixel more than 2*hs, cause you can "center" an odd number of pixels better
      rLeft.set(xAbsLeft - hs, yTop - fs, fs + m_pG->tlu(1), fs);
      rRight.set(xAbsRight - hs, yTop - fs, fs + m_pG->tlu(1), fs);
}

void AP_TopRuler::_drawMarginProperties(const UT_Rect * /* pClipRect */,
                                                            AP_TopRulerInfo * pInfo, GR_Graphics::GR_Color3D clr)
{
      UT_Rect rLeft, rRight;

      _getMarginMarkerRects(pInfo,rLeft,rRight);

      GR_Painter painter(m_pG);

      painter.fillRect(GR_Graphics::CLR3D_Background, rLeft);

      m_pG->setColor3D(GR_Graphics::CLR3D_Foreground);
      painter.drawLine( rLeft.left,  rLeft.top, rLeft.left + rLeft.width, rLeft.top);
      painter.drawLine( rLeft.left + rLeft.width,  rLeft.top, rLeft.left + rLeft.width, rLeft.top + rLeft.height);
      painter.drawLine( rLeft.left + rLeft.width,  rLeft.top + rLeft.height, rLeft.left, rLeft.top + rLeft.height);
      painter.drawLine( rLeft.left,  rLeft.top + rLeft.height, rLeft.left, rLeft.top);
      m_pG->setColor3D(GR_Graphics::CLR3D_BevelUp);
      painter.drawLine( rLeft.left + m_pG->tlu(1), rLeft.top + m_pG->tlu(1), rLeft.left + rLeft.width - m_pG->tlu(2), rLeft.top + m_pG->tlu(1));
      painter.drawLine( rLeft.left + m_pG->tlu(1), rLeft.top + m_pG->tlu(1), rLeft.left + m_pG->tlu(1), rLeft.top + rLeft.height - m_pG->tlu(2));
      painter.fillRect(GR_Graphics::CLR3D_Background, rRight);

      m_pG->setColor3D(GR_Graphics::CLR3D_Foreground);
      painter.drawLine( rRight.left,  rRight.top, rRight.left + rRight.width, rRight.top);
      painter.drawLine( rRight.left + rRight.width,  rRight.top, rRight.left + rRight.width, rRight.top + rRight.height);
      painter.drawLine( rRight.left + rRight.width,  rRight.top + rRight.height, rRight.left, rRight.top + rRight.height);
      painter.drawLine( rRight.left,  rRight.top + rRight.height, rRight.left, rRight.top);
      m_pG->setColor3D(GR_Graphics::CLR3D_BevelUp);
      painter.drawLine( rRight.left + m_pG->tlu(1), rRight.top + m_pG->tlu(1), rRight.left + rRight.width - m_pG->tlu(2), rRight.top + m_pG->tlu(1));
      painter.drawLine( rRight.left + m_pG->tlu(1), rRight.top + m_pG->tlu(1), rRight.left + m_pG->tlu(1), rRight.top + rRight.height - m_pG->tlu(2));
}

/*****************************************************************/

void AP_TopRuler::_draw(const UT_Rect * pClipRect, AP_TopRulerInfo * pUseInfo)
{
      UT_sint32 sum;
      UT_uint32 k;

      FV_View * pView = static_cast<FV_View *>(m_pView);

      // ask the view for paper/margin/column/table/caret
      // details at the current insertion point.

      AP_TopRulerInfo infoLocal;
      AP_TopRulerInfo * pInfo;
      if(pView== NULL)
            return;

      if(pView->getPoint() == 0)
            return;

      if (pUseInfo)
            // if we are given an info arg, use it
            pInfo = pUseInfo;
      else
      {
            // otherwise we calculate our own.
            if(pView->getPoint() == 0)
            {
                  return;
            }
            pInfo = &infoLocal;
            if(pView->getDocument() == NULL)
            {
                  return;
            }
            if(pView->getDocument()->isPieceTableChanging())
            {
                  return;
            }
            pView->getTopRulerInfo(pInfo);
      }

      // draw the tab toggle inside the fixed area in the left-hand corner
      _drawTabToggle(pClipRect, false);

      // TODO for now assume we are in column display mode.

      // draw the dark-gray and white bar across the
      // width of the paper.  we adjust the x coords
      // by 1 to keep a light-gray bar between the
      // dark-gray bars (margins & gaps) and the white
      // bars (columns).

      // draw a dark-gray bar over the left margin

      bool bRTL;
      XAP_App::getApp()->getPrefsValueBool(static_cast<const XML_Char *>(AP_PREF_KEY_DefaultDirectionRtl), &bRTL);

    UT_sint32 xAbsRight = pInfo->u.c.m_xaLeftMargin + (pInfo->u.c.m_xColumnWidth + pInfo->u.c.m_xColumnGap) * pInfo->m_iNumColumns - pInfo->u.c.m_xColumnGap;

    if(bRTL)
    {
            sum = xAbsRight;
            _drawBar(pClipRect,pInfo,GR_Graphics::CLR3D_BevelDown,sum+ m_pG->tlu(1),pInfo->u.c.m_xaRightMargin- m_pG->tlu(1));
            //sum -= pInfo->u.c.m_xColumnWidth;
    }
    else
      {
            UT_sint32 width = pInfo->u.c.m_xaLeftMargin;
            if(pView->getViewMode() != VIEW_PRINT)
            {
                  width -= m_pG->tlu(s_iFixedWidth);
            }

            _drawBar(pClipRect,pInfo,GR_Graphics::CLR3D_BevelDown, m_pG->tlu(0+1), width- m_pG->tlu(1));
            sum = width;
      }


      for (k=0; k<pInfo->m_iNumColumns; k++)
      {
            // draw white bar over this column
            if(bRTL)
                  sum -= pInfo->u.c.m_xColumnWidth;

            _drawBar(pClipRect,pInfo, GR_Graphics::CLR3D_Highlight, sum+ m_pG->tlu(1), pInfo->u.c.m_xColumnWidth- m_pG->tlu(1));

            if(!bRTL)
                  sum += pInfo->u.c.m_xColumnWidth;

            // if another column after this one, draw dark gray-gap

            if (k+1 < pInfo->m_iNumColumns)
            {
                  if(bRTL)
                        sum -= pInfo->u.c.m_xColumnGap;

                  _drawBar(pClipRect,pInfo, GR_Graphics::CLR3D_BevelDown, sum+ m_pG->tlu(1), pInfo->u.c.m_xColumnGap- m_pG->tlu(1));

                  if(!bRTL)
                        sum += pInfo->u.c.m_xColumnGap;
            }
      }

      // draw dark-gray right margin
      if(bRTL)
      {
            sum -= pInfo->u.c.m_xaLeftMargin;
            _drawBar(pClipRect,pInfo, GR_Graphics::CLR3D_BevelDown, sum+ m_pG->tlu(1),pInfo->u.c.m_xaLeftMargin- m_pG->tlu(1));
      }
      else
            _drawBar(pClipRect,pInfo, GR_Graphics::CLR3D_BevelDown, sum+ m_pG->tlu(1),pInfo->u.c.m_xaRightMargin- m_pG->tlu(1));

      // now draw tick marks on the bar, using the selected system of units.

      ap_RulerTicks tick(m_pG,m_dim);
      GR_Font * pFont = m_pG->getGUIFont();

      // find the origin for the tick marks.  this is the left-edge of the
      // column that we are in.  everything to the left of this x-value will
      // be drawn on a negative scale to the left relative to here.  everything
      // to the right of this x-value will be drawn on a positive scale to the
      // right.
      UT_sint32 xTickOrigin = 0;

      if(bRTL)
      {
          xTickOrigin = xAbsRight;
            if (pInfo->m_iCurrentColumn > 0)
                  xTickOrigin -= pInfo->m_iCurrentColumn * (pInfo->u.c.m_xColumnWidth + pInfo->u.c.m_xColumnGap);
      }
      else
      {     //do not remove!!!
            xTickOrigin = pInfo->u.c.m_xaLeftMargin;
            if(pView->getViewMode() != VIEW_PRINT)
            {
                  xTickOrigin -= m_pG->tlu(s_iFixedWidth);
            }

            if (pInfo->m_iCurrentColumn > 0)
                  xTickOrigin += pInfo->m_iCurrentColumn * (pInfo->u.c.m_xColumnWidth + pInfo->u.c.m_xColumnGap);
    }

      sum = 0;

      // draw negative ticks over left margin.
      if(bRTL)
      {
            sum = xTickOrigin + pInfo->u.c.m_xaRightMargin;
            if(pInfo->u.c.m_xaRightMargin)
                  _drawTicks(pClipRect,pInfo,tick,GR_Graphics::CLR3D_Foreground,pFont,xTickOrigin,xTickOrigin,sum);
            sum -= pInfo->u.c.m_xaRightMargin;
      }
      else
      {     //do not remove!!!
            if(pInfo->u.c.m_xaLeftMargin)
                  _drawTicks(pClipRect,pInfo,tick,GR_Graphics::CLR3D_Foreground,pFont,xTickOrigin, pInfo->u.c.m_xaLeftMargin,sum);
            sum += pInfo->u.c.m_xaLeftMargin;
      }

      if(pView->getViewMode() != VIEW_PRINT)
            sum -= m_pG->tlu(s_iFixedWidth);

      for (k=0; k<pInfo->m_iNumColumns; k++)
      {
            // draw positive or negative ticks on this column.
            if (k < pInfo->m_iCurrentColumn)
                  if(bRTL)
                  {
                        _drawTicks(pClipRect,pInfo,tick,GR_Graphics::CLR3D_Foreground,pFont,xTickOrigin, sum-pInfo->u.c.m_xColumnWidth, sum);
                        sum -= pInfo->u.c.m_xColumnWidth;
                  }
                  else
                  {
                        _drawTicks(pClipRect,pInfo,tick,GR_Graphics::CLR3D_Foreground,pFont,xTickOrigin, sum+pInfo->u.c.m_xColumnWidth, sum);
                        sum += pInfo->u.c.m_xColumnWidth;
                  }
            else
                  if(bRTL)
                  {
                        _drawTicks(pClipRect,pInfo,tick,GR_Graphics::CLR3D_Foreground,pFont,xTickOrigin, sum, sum-pInfo->u.c.m_xColumnWidth);
                        sum -= pInfo->u.c.m_xColumnWidth;
                  }
                  else
                  {
                        _drawTicks(pClipRect,pInfo,tick,GR_Graphics::CLR3D_Foreground,pFont,xTickOrigin, sum, sum+pInfo->u.c.m_xColumnWidth);
                        sum += pInfo->u.c.m_xColumnWidth;
                  }

            // if another column after this one, skip over the gap
            // (we don't draw ticks on the gap itself).

            if (k+1 < pInfo->m_iNumColumns)
                  if(bRTL)
                        sum -= pInfo->u.c.m_xColumnGap;
                  else
                        sum += pInfo->u.c.m_xColumnGap;
      }

      // draw ticks over the right margin
      if(bRTL)
      {
            if(pInfo->u.c.m_xaLeftMargin)
            {
                  _drawTicks(pClipRect,pInfo,tick,GR_Graphics::CLR3D_Foreground,pFont,xTickOrigin, pInfo->u.c.m_xaLeftMargin, 0);
                  //UT_DEBUGMSG(("drawn left margin\n"));
            }
      }
      else if(pInfo->u.c.m_xaRightMargin)
      {
            _drawTicks(pClipRect,pInfo,tick,GR_Graphics::CLR3D_Foreground,pFont,xTickOrigin, sum, sum+pInfo->u.c.m_xaRightMargin);
      }

      // draw the various widgets for the:
      //
      // current section properties {left-margin, right-margin};
      // the current column properties {column-gap};
      // and the current paragraph properties {left-indent, right-indent, first-left-indent}.

      _drawMarginProperties(pClipRect, pInfo, GR_Graphics::CLR3D_Foreground);
      if (pInfo->m_iNumColumns > 1)
            _drawColumnProperties(pClipRect,pInfo,0);
      _drawCellProperties(pClipRect, pInfo,true);

      // draw the Tab properties
      _drawTabProperties(pClipRect,pInfo,true);
      // draw the paragraph properties {left-indent, right-indent, first-left-indent}.
      _drawParagraphProperties(pClipRect,pInfo,true); 
}

/*****************************************************************/

void AP_TopRuler::_xorGuide(bool bClear)
{
      GR_Graphics * pG = (static_cast<FV_View *>(m_pView))->getGraphics();
      UT_return_if_fail (pG);
      UT_uint32 xFixed = static_cast<UT_sint32>(pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView->getViewMode() != VIEW_PRINT)
      {
            xFixed = 0;
      }

      UT_sint32 x = m_draggingCenter - xFixed;

      // when dragging the column gap, we draw lines on both
      // sides of the gap.

      UT_sint32 xOther = m_draggingRect.left - xFixed;


      // TODO we need to query the document window to see what the actual
      // TODO background color is so that we can compose the proper color so
      // TODO that we can XOR on it and be guaranteed that it will show up.

#if XAP_DONTUSE_XOR
      UT_RGBColor clrBlack(0,0,0);
      pG->setColor(clrBlack);
#else
      UT_RGBColor clrWhite(255,255,255);
      pG->setColor(clrWhite);
#endif

      UT_sint32 h = m_pView->getWindowHeight();

      GR_Painter painter(pG);

      if (m_bGuide)
      {
            if (!bClear && (x == m_xGuide))
                  return;           // avoid flicker

            // erase old guide
#if XAP_DONTUSE_XOR
            if (m_guideCache) {
                  painter.drawImage(m_guideCache, m_guideCacheRect.left, m_guideCacheRect.top);
                  DELETEP(m_guideCache);
            }
            if ( (m_draggingWhat == DW_COLUMNGAP) || (m_draggingWhat == DW_COLUMNGAPLEFTSIDE) ) {
                  if (m_otherGuideCache) {
                        painter.drawImage(m_otherGuideCache, m_otherGuideCacheRect.left, m_otherGuideCacheRect.top);
                        DELETEP(m_otherGuideCache);
                  }
            }
#else
            painter.xorLine(m_xGuide, 0, m_xGuide, h);
            if ( (m_draggingWhat == DW_COLUMNGAP) || (m_draggingWhat == DW_COLUMNGAPLEFTSIDE) )
                  painter.xorLine(m_xOtherGuide, 0, m_xOtherGuide, h);
#endif
            m_bGuide = false;
      }

      if (!bClear)
      {
            UT_ASSERT_HARMLESS(m_bValidMouseClick);

      
#if XAP_DONTUSE_XOR
            m_guideCacheRect.left = x - pG->tlu(1);
            m_guideCacheRect.top = 0;
            m_guideCacheRect.width = pG->tlu(3);
            m_guideCacheRect.height = h;
            DELETEP(m_guideCache);        // make sure it is deleted. we could leak it here
            m_guideCache = painter.genImageFromRectangle(m_guideCacheRect);
            painter.drawLine(x, 0, x, h);
            
            if ( (m_draggingWhat == DW_COLUMNGAP) || (m_draggingWhat == DW_COLUMNGAPLEFTSIDE) ) {
                  m_otherGuideCacheRect.left = xOther - pG->tlu(1);
                  m_otherGuideCacheRect.top = 0;
                  m_otherGuideCacheRect.width = pG->tlu(3);
                  m_otherGuideCacheRect.height = h;
                  DELETEP(m_otherGuideCache);         // make sure it is deleted. we could leak it here
                  m_otherGuideCache = painter.genImageFromRectangle(m_otherGuideCacheRect);
                  painter.drawLine(xOther, 0, xOther, h);
            }
#else
            painter.xorLine(x, 0, x, h);
            if ( (m_draggingWhat == DW_COLUMNGAP) || (m_draggingWhat == DW_COLUMNGAPLEFTSIDE) )
                  painter.xorLine(xOther, 0, xOther, h);
#endif
            // remember this for next time
            m_xGuide = x;
            m_xOtherGuide = xOther;
            m_bGuide = true;
      }
}

/*****************************************************************/

/*!
 * Returns true if the mouse is over a previously defined tab marker or a
 * paragraph control
\param x location of mouse
\param y location of mouse
*/
bool AP_TopRuler::isMouseOverTab(UT_uint32 x, UT_uint32 y)
{
      // incremental loader segfault protection
      if (!m_pView)
            return false;
      if(m_pView->getPoint() == 0)
      {
            return false;
      }
//
// Piecetable changes means the document is changing as we look. Bail out until it stablizes.
//
      PD_Document * pDoc = static_cast<FV_View *>(m_pView)->getDocument();
      if(pDoc->isPieceTableChanging())
      {
            return false;
      }
// Sevior: Look to cache this.
      // first hit-test against the tab toggle control
      (static_cast<FV_View *>(m_pView))->getTopRulerInfo(&m_infoCache);
      //UT_sint32 xFixed = static_cast<UT_sint32>(m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
      //UT_sint32 xStartPixel = xFixed + static_cast<UT_sint32>(m_infoCache.m_xPageViewMargin);

      UT_Rect rToggle;

      if (m_draggingWhat != DW_NOTHING)
            return false;

      if ( static_cast<FV_View*>(m_pView)->getViewMode() == VIEW_WEB )
        return false;

      _getTabToggleRect(&rToggle);
      if (rToggle.containsPoint(x,y))
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_EXCHANGE);
            XAP_String_Id baseTabName = AP_STRING_ID_TabToggleLeftTab-1;
            _displayStatusMessage(baseTabName + m_iDefaultTabType);
            return true;
      }

      UT_sint32 anchor;
      eTabType iType;
      eTabLeader iLeader;
      ap_RulerTicks tick(m_pG,m_dim);
      UT_sint32 iTab = _findTabStop(&m_infoCache, x, m_pG->tlu(s_iFixedHeight)/2 + m_pG->tlu(s_iFixedHeight)/4 - 3, anchor, iType, iLeader);

      UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
    UT_sint32 xrel;

      UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
      bool bRTLglobal;
      XAP_App::getApp()->getPrefsValueBool(static_cast<const XML_Char *>(AP_PREF_KEY_DefaultDirectionRtl), &bRTLglobal);

      fl_BlockLayout * pBL = (static_cast<FV_View *>(m_pView))->getCurrentBlock();
      UT_return_val_if_fail(pBL,false);
      
      bool bRTLpara = pBL->getDominantDirection() == UT_BIDI_RTL;
      if(bRTLpara)
            xrel = xAbsRight - anchor;
      else
            xrel = anchor - xAbsLeft;

      if (iTab >= 0)
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_LEFTRIGHT);
            _displayStatusMessage(AP_STRING_ID_TabStopStatus, tick, xrel);
            return true;
      }

      // next hit-test against the paragraph widgets

      UT_sint32 leftIndentCenter, rightIndentCenter, firstLineIndentCenter;
      UT_Rect rLeftIndent, rRightIndent, rFirstLineIndent;
      _getParagraphMarkerXCenters(&m_infoCache,&leftIndentCenter,&rightIndentCenter,&firstLineIndentCenter);
      _getParagraphMarkerRects(&m_infoCache,
                                           leftIndentCenter, rightIndentCenter, firstLineIndentCenter,
                                           &rLeftIndent, &rRightIndent, &rFirstLineIndent);
      if (rLeftIndent.containsPoint(x,y))
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_LEFTRIGHT);

            if(bRTLpara)
                  xrel = xAbsRight - rLeftIndent.left;
            else
                  xrel = rLeftIndent.left - xAbsLeft;

            _displayStatusMessage(AP_STRING_ID_LeftIndentStatus, tick,  xrel);
            return true;
      }

      if (rRightIndent.containsPoint(x,y))
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_LEFTRIGHT);

            if(bRTLpara)
                  xrel = xAbsRight - rRightIndent.left;
            else
                  xrel = rRightIndent.left - xAbsLeft;

            _displayStatusMessage(AP_STRING_ID_RightIndentStatus, tick, xrel);
            return true;
      }

      if (rFirstLineIndent.containsPoint(x,y))
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_LEFTRIGHT);

            if(bRTLpara)
                  xrel = xAbsRight - rFirstLineIndent.left;
            else
                  xrel = rFirstLineIndent.left - xAbsLeft;

            _displayStatusMessage(AP_STRING_ID_FirstLineIndentStatus, tick, xrel);
            return true;
      }

      // next check the column gap

      if (m_infoCache.m_iNumColumns > 1)
      {
            UT_Rect rCol;
            _getColumnMarkerRect(&m_infoCache,0,_getColumnMarkerXRightEnd(&m_infoCache,0),&rCol);
            if (rCol.containsPoint(x,y))
            {
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_LEFTRIGHT);
                  _displayStatusMessage(AP_STRING_ID_ColumnGapStatus, tick, 0);
                  return true;
            }
      }

      // next check page margins

      UT_Rect rLeftMargin, rRightMargin;
      _getMarginMarkerRects(&m_infoCache,rLeftMargin,rRightMargin);
      if (rLeftMargin.containsPoint(x,y))
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_LEFTRIGHT);
            _displayStatusMessage(AP_STRING_ID_LeftMarginStatus, tick, m_infoCache.u.c.m_xaLeftMargin);
            return true;
      }
      if (rRightMargin.containsPoint(x,y))
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_LEFTRIGHT);
            _displayStatusMessage(AP_STRING_ID_RightMarginStatus, tick, m_infoCache.u.c.m_xaRightMargin);
            return true;
      }

// Now the Cells

      UT_Rect rCell;
      if(m_infoCache.m_vecTableColInfo)
      {
            UT_sint32 nCells =  m_infoCache.m_vecTableColInfo->getItemCount();
            UT_sint32 iCell =0;
            for(iCell = 0; iCell <= nCells; iCell++)
            {
                  _getCellMarkerRect(&m_infoCache,static_cast<UT_uint32>(iCell), &rCell);
                  if(rCell.containsPoint(x,y))
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_LEFTRIGHT);
                        if(iCell < nCells)
                  {
                        _displayStatusMessage(AP_STRING_ID_ColumnStatus, iCell, "");
                  }
                  else
                  {
                        _displayStatusMessage(AP_STRING_ID_ColumnStatus, iCell, "");
                  }
                        return true;
                  }
            }
      }


      AP_FrameData * pFrameData = static_cast<AP_FrameData *>(m_pFrame->getFrameData());
      if(m_pFrame->getFrameMode() == XAP_NormalFrame)
      {
            pFrameData->m_pStatusBar->setStatusMessage("");
      }
      return false;
}

void AP_TopRuler::_getCellMarkerRect(AP_TopRulerInfo * pInfo, UT_sint32 kCell, 
                                                   UT_Rect * prCell)
{
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(!pView)
      {
            return;
      }

      if(pInfo->m_vecTableColInfo)
      {
            UT_sint32 nCells = pInfo->m_vecTableColInfo->getItemCount();
            if(kCell < nCells)
            {
                  AP_TopRulerTableInfo * pCellInfo = static_cast<AP_TopRulerTableInfo *>(pInfo->m_vecTableColInfo->getNthItem(kCell));

                  UT_sint32 xAbsLeft = _getFirstPixelInColumn(pInfo,pInfo->m_iCurrentColumn);
                  UT_sint32 pos = xAbsLeft + pCellInfo->m_iLeftCellPos;
                  UT_sint32 ileft = pView->getGraphics()->tlu(s_iFixedHeight)/4;
                  prCell->set(pos-ileft,ileft,pView->getGraphics()->tlu(s_iFixedHeight)/2,pView->getGraphics()->tlu(s_iFixedHeight)/2); // left/top/width/height
            }
            else if(nCells > 0)
            {
                  AP_TopRulerTableInfo * pCellInfo = static_cast<AP_TopRulerTableInfo *>(pInfo->m_vecTableColInfo->getNthItem(nCells-1));

                  UT_sint32 xAbsLeft = _getFirstPixelInColumn(pInfo,pInfo->m_iCurrentColumn);
                  UT_sint32 pos = xAbsLeft + pCellInfo->m_iRightCellPos;
                  UT_sint32 ileft = pView->getGraphics()->tlu(s_iFixedHeight)/4;
                  prCell->set(pos-ileft,ileft,pView->getGraphics()->tlu(s_iFixedHeight)/2,pView->getGraphics()->tlu(s_iFixedHeight)/2); // left/top/width/height
            }
      }

}

/*!
 * This draws a cell marker as either a hollow square or a bevelled square.
 * The hollow square is to show the original location during a drag.
 * pUp should be true to draw the bevelled square.
 */
void AP_TopRuler::_drawCellMark(UT_Rect * prDrag, bool bUp)
{
//
// Draw square inside
//
      if(m_pG == NULL)
            return;

      GR_Painter painter(m_pG);

      UT_sint32 left = prDrag->left + m_pG->tlu(2);
      UT_sint32 right = left + prDrag->width -m_pG->tlu(4);
      UT_sint32 top = prDrag->top + m_pG->tlu(2);
      UT_sint32 bot = top + prDrag->height - m_pG->tlu(4);
      m_pG->setColor3D(GR_Graphics::CLR3D_Foreground);
      painter.drawLine(left,top,left,bot);
      painter.drawLine(left,bot,right,bot);
      painter.drawLine(right,bot,right,top);
      painter.drawLine(right,top,left,top);
      if(bUp)
      {
//
// Draw a bevel up
//
            m_pG->setColor3D(GR_Graphics::CLR3D_BevelUp);
            left += m_pG->tlu(1);
            top += m_pG->tlu(1);
            right -= m_pG->tlu(1);
            bot -= m_pG->tlu(1);
            painter.drawLine(left,top,left,bot);
            painter.drawLine(right,top,left,top);
//
// Fill with Background?? color
//
            left += m_pG->tlu(1);
            top += m_pG->tlu(1);
            painter.fillRect(GR_Graphics::CLR3D_Background,left,top,right-left+m_pG->tlu(1),bot-top+m_pG->tlu(1));
      }
}

void AP_TopRuler::_drawCellProperties(const UT_Rect * pClipRect,
                                                        AP_TopRulerInfo * pInfo,
                                                        UT_uint32 kCell, bool bDrawAll)
{
      if(m_pG == NULL)
            return;

      if (m_draggingWhat == DW_CELLMARK)
      {
//
// Just deal with the cell being dragged.
//
            UT_uint32 xFixed = static_cast<UT_uint32>(m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
            FV_View * pView = static_cast<FV_View *>(m_pView);
            if(pView->getViewMode() != VIEW_PRINT)
            {
                  xFixed = m_pG->tlu(s_iFixedWidth);
            }
            if (m_draggingRect.left + m_draggingRect.width > static_cast<UT_sint32>(xFixed))
                  _drawCellMark(&m_draggingRect,true);
      }

      /*
            NOTE: even during cell drags, we might need to draw other column marks
            that got revealed after being obscured by the dragged column
      */
      UT_Rect rCell;
            // loop over all explicit cells
      if (bDrawAll)
      {
            // loop over all explicit cells
            for (UT_sint32 i = 0; i <= pInfo->m_iCells; i++)
            {
                  if ((m_draggingWhat == DW_CELLMARK) &&
                        (m_draggingCell == static_cast<UT_sint32>(i)))
                        continue;
                  _getCellMarkerRect(pInfo, i, &rCell);

                  if (!pClipRect || rCell.intersectsRect(pClipRect))
                  {
                        _drawCellGap(pInfo, i);
                        _drawCellMark(&rCell,true);
                  }
            }
      }
}
/*!
 * Draw all the cell locations.
 */
void AP_TopRuler::_drawCellProperties(const UT_Rect * pClipRect,
                                                        AP_TopRulerInfo * pInfo, bool bDrawAll)
{
      if(m_pG == NULL)
      {
            return;
      }
      if(pInfo->m_mode != AP_TopRulerInfo::TRI_MODE_TABLE)
      {
            return;
      }
      UT_Rect rCell;
      if (m_draggingWhat == DW_CELLMARK)
      {
//
// Deal with the cell being dragged.
//
// First draw a boring box at the old position.
//
            _getCellMarkerRect(pInfo,  m_draggingCell, &rCell);
            if (!pClipRect || rCell.intersectsRect(pClipRect))
            {
                  _drawCellGap(pInfo, m_draggingCell);
                  _drawCellMark(&rCell,false);
            }
//
// Now draw a nice bevelled cell at the dragging position.
//
            UT_uint32 xFixed = static_cast<UT_sint32>(m_pG->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
            FV_View * pView = static_cast<FV_View *>(m_pView);
            if(pView->getViewMode() != VIEW_PRINT)
            {
                  xFixed = m_pG->tlu(s_iFixedWidth);
            }
            if (m_draggingRect.left + m_draggingRect.width > static_cast<UT_sint32>(xFixed))
                  _drawCellMark(&m_draggingRect,true);
      }
      if(!bDrawAll)
      {
            return;
      }
      
      for (UT_sint32 i = 0; i <= pInfo->m_iCells; i++)
      {
            if( m_draggingCell == static_cast<UT_sint32>(i) && (m_draggingWhat == DW_CELLMARK))
            {
                  continue;
            }
            _getCellMarkerRect(pInfo, i, &rCell);
            if (!pClipRect || rCell.intersectsRect(pClipRect))
            {
                  _drawCellGap(pInfo, i);
                  _drawCellMark(&rCell,true);
            }
      }
}

/*!
 * Draw the gap between active regions for tables.
 */
void AP_TopRuler::_drawCellGap(AP_TopRulerInfo * pInfo, UT_sint32 iCell)
{
      if(m_pG == NULL)
            return;

      UT_Rect lCell, cCell, rCell;
      UT_sint32 left,right,top,height;
      if(pInfo->m_vecTableColInfo)
      {
            UT_sint32 nCells = pInfo->m_vecTableColInfo->getItemCount();
            if(nCells == 0)
                  return;

            if(iCell < nCells)
            {
                  AP_TopRulerTableInfo * pCellInfo = static_cast<AP_TopRulerTableInfo *>(pInfo->m_vecTableColInfo->getNthItem(iCell));
                  UT_sint32 xAbsLeft = _getFirstPixelInColumn(pInfo,pInfo->m_iCurrentColumn);
                  if(iCell == 0)
                  {
                        left = xAbsLeft + pCellInfo->m_iLeftCellPos -  pCellInfo->m_iLeftSpacing;
                  }
                  else
                  {
                        AP_TopRulerTableInfo * pPI = static_cast<AP_TopRulerTableInfo *>(pInfo->m_vecTableColInfo->getNthItem(iCell-1));
                        left = xAbsLeft +  pCellInfo->m_iLeftCellPos - pPI->m_iRightSpacing;
                  }
                  right = xAbsLeft + pCellInfo->m_iLeftCellPos + pCellInfo->m_iLeftSpacing;
            }
            else
            {
                  AP_TopRulerTableInfo * pCellInfo = static_cast<AP_TopRulerTableInfo *>(pInfo->m_vecTableColInfo->getNthItem(nCells-1));
                  UT_sint32 xAbsLeft = _getFirstPixelInColumn(pInfo,pInfo->m_iCurrentColumn);
                  right = xAbsLeft + pCellInfo->m_iRightCellPos;
                  left = right - pCellInfo->m_iRightSpacing;
                  right +=  pCellInfo->m_iRightSpacing;
            }
            top = m_pG->tlu(s_iFixedHeight) / 4;
            height =  m_pG->tlu(s_iFixedHeight) / 2;
            
            GR_Painter painter(m_pG);

            if(cCell.width >= 0)
            {     
                  lCell.set(left, top, m_pG->tlu(1), height);
                  cCell.set(left + m_pG->tlu(1), top, right - left - m_pG->tlu(2), height);
                  rCell.set(right - m_pG->tlu(1), top, m_pG->tlu(1), height);
                  
                  painter.fillRect(GR_Graphics::CLR3D_Background, lCell);
                  if (cCell.width > 0)
                        painter.fillRect(GR_Graphics::CLR3D_BevelDown, cCell);
                  painter.fillRect(GR_Graphics::CLR3D_Background, rCell);
            }
      }
}

UT_sint32 AP_TopRuler::setTableLineDrag(PT_DocPosition pos, UT_sint32 x, UT_sint32 & iFixed)
{
      m_bValidMouseClick = false;
      m_draggingWhat = DW_NOTHING;
      m_bEventIgnored = false;
      FV_View * pView = (static_cast<FV_View *>(m_pView));
      UT_sint32 y = pView->getGraphics()->tlu(s_iFixedHeight)/2;
      if(pView->getDocument()->isPieceTableChanging())
      {
            return 0;
      }
      pView->getTopRulerInfo(pos,&m_infoCache);
      if(m_pG)
            draw(NULL, &m_infoCache);

      iFixed = static_cast<UT_sint32>(pView->getGraphics()->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));

      if(pView->getViewMode() != VIEW_PRINT)
            iFixed = 0;
      if(pView->getViewMode() == VIEW_PRINT)
            x += iFixed;

      // Set this in case we never get a mouse motion event
    UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
      UT_sint32 xrel;

    UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
      fl_BlockLayout * pBlock = pView->getCurrentBlock();
    bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);
      
      xxx_UT_DEBUGMSG(("setTableLineDrag: x = %d \n",x));
      if(bRTL)
            xrel = xAbsRight - static_cast<UT_sint32>(x);
      else
            xrel = static_cast<UT_sint32>(x) - xAbsLeft;

    ap_RulerTicks tick(m_pG,m_dim);
    UT_sint32 xgrid = tick.snapPixelToGrid(xrel);

      if(bRTL)
          m_draggingCenter = xAbsRight - xgrid;
      else
          m_draggingCenter = xAbsLeft + xgrid;

      xxx_UT_DEBUGMSG(("mousePress: m_draggingCenter (1) %d\n", m_draggingCenter));
      m_oldX = xgrid; // used to determine if delta is zero on a mouse release

// Now hit test against the cell containers to find the right cell to drag.

      if(m_infoCache.m_mode == AP_TopRulerInfo::TRI_MODE_TABLE)
      {
            UT_sint32 i = 0;
            bool bFound = false;
            UT_Rect rCell;
            for(i=0; i<= m_infoCache.m_iCells && !bFound; i++)
            {
                  _getCellMarkerRect(&m_infoCache, i, &rCell);
                  xxx_UT_DEBUGMSG(("setTableLine: cell %d left %d \n",i,rCell.left));
                  if(rCell.containsPoint(x,y))
                  {
                        bFound = true;
                        
                        // determine the range in which this cell marker can be dragged
                        UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
                        // WARNING KILL UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
                        UT_sint32 xExtraMargin = 3; // keep an extra margin 3 pixels; there must be some space left to enter text in
                        if (i == 0)
                        {
                              AP_TopRulerTableInfo * pCurrentCellInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(i));
                              
                              m_iMinCellPos = 0;
                              m_iMaxCellPos = xAbsLeft + pCurrentCellInfo->m_iRightCellPos - pCurrentCellInfo->m_iRightSpacing - pCurrentCellInfo->m_iLeftSpacing - xExtraMargin;
                        }
                        else if (i == m_infoCache.m_iCells)
                        {
                              AP_TopRulerTableInfo * pPrevCellInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(i-1));
                              
                              m_iMinCellPos = xAbsLeft + pPrevCellInfo->m_iLeftCellPos + pPrevCellInfo->m_iLeftSpacing + pPrevCellInfo->m_iRightSpacing + xExtraMargin;
                              m_iMaxCellPos = 99999999;
                        }
                        else
                        {
                              AP_TopRulerTableInfo * pPrevCellInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(i-1));
                              AP_TopRulerTableInfo * pCurrentCellInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(i));
                              
                              m_iMinCellPos = xAbsLeft + pPrevCellInfo->m_iLeftCellPos + pPrevCellInfo->m_iLeftSpacing + pPrevCellInfo->m_iRightSpacing + xExtraMargin;
                              m_iMaxCellPos = xAbsLeft + pCurrentCellInfo->m_iRightCellPos - pCurrentCellInfo->m_iRightSpacing - pCurrentCellInfo->m_iLeftSpacing - xExtraMargin;
//                            m_iMaxCellPos = 999999999;
                        }

                        break;
                  }
            }
            if(bFound)
            {
                  UT_DEBUGMSG(("hit Cell marker %d \n",i));
                  m_bValidMouseClick = true;
                  m_draggingWhat = DW_CELLMARK;
                  m_bBeforeFirstMotion = true;
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  }
                  m_draggingCell = i;
                  return y;
            }
      }
      return 0;
}

void AP_TopRuler::mousePress(EV_EditModifierState /* ems */,
                                           EV_EditMouseButton emb , UT_uint32 x, UT_uint32 y)
{
      //UT_DEBUGMSG(("mousePress: [ems 0x%08lx][emb 0x%08lx][x %ld][y %ld]\n",ems,emb,x,y));

      // get the complete state of what should be on the ruler at the time of the grab.
      // we assume that nothing in the document can change during our grab unless we
      // change it.

      m_bValidMouseClick = false;
      m_draggingWhat = DW_NOTHING;
      m_bEventIgnored = false;

      FV_View * pView = (static_cast<FV_View *>(m_pView));
    if(pView->getDocument()->isPieceTableChanging())
      {
            return;
      }
      pView->getTopRulerInfo(&m_infoCache);

      // Set this in case we never get a mouse motion event
    UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
      UT_sint32 xrel;

    UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
      fl_BlockLayout *pBlock = pView->getCurrentBlock();
      
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);

      if(bRTL)
            xrel = xAbsRight - static_cast<UT_sint32>(x);
      else
            xrel = static_cast<UT_sint32>(x) - xAbsLeft;

    ap_RulerTicks tick(m_pG,m_dim);
    UT_sint32 xgrid = tick.snapPixelToGrid(xrel);

      if(bRTL)
          m_draggingCenter = xAbsRight - xgrid;
      else
          m_draggingCenter = xAbsLeft + xgrid;

      xxx_UT_DEBUGMSG(("mousePress: m_draggingCenter (1) %d\n", m_draggingCenter));
      m_oldX = xgrid; // used to determine if delta is zero on a mouse release

      // first hit-test against the tab toggle control

      UT_Rect rToggle;
      _getTabToggleRect(&rToggle);
      if (rToggle.containsPoint(x,y))
      {
        // do nothing in this view mode
        if ( pView->getViewMode () == VIEW_WEB )
          return ;

            int currentTabType = m_iDefaultTabType;
            if(emb == EV_EMB_BUTTON1)
            {
                  currentTabType = ++currentTabType >= __FL_TAB_MAX ? FL_TAB_NONE+1 : currentTabType;
            }
            else
            {
                  currentTabType = --currentTabType <= FL_TAB_NONE ? __FL_TAB_MAX-1 :  currentTabType;
            }
            m_iDefaultTabType = static_cast<eTabType>(currentTabType);
            _drawTabToggle(NULL, true);
            XAP_String_Id baseTabName = AP_STRING_ID_TabToggleLeftTab-1;
            _displayStatusMessage(baseTabName + m_iDefaultTabType);
            m_bValidMouseClick = true;
            m_draggingWhat = DW_TABTOGGLE;
            return;
      }

      // next hit-test against the tabs

      UT_sint32 anchor;
      eTabType iType;
      eTabLeader iLeader;
      UT_sint32 iTab = _findTabStop(&m_infoCache, x, m_pG->tlu(s_iFixedHeight/2 + s_iFixedHeight/4 - 3), anchor, iType, iLeader);
      if (iTab >= 0)
      {
            if(emb == EV_EMB_BUTTON1)
            {
                  //UT_DEBUGMSG(("hit tab %ld  x=%d y=%d \n",iTab,x,y));
                  m_bValidMouseClick = true;
                  m_draggingWhat = DW_TABSTOP;
                  m_draggingTab = iTab;
                  m_draggingTabType = iType;
                  m_draggingTabLeader = iLeader;
                  m_dragStart = 0;
                  m_bBeforeFirstMotion = true;
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
            }
//
// if not button 1 delete the tabstop
//
            else
            {
//
// Rebuild the tab setting minus the found tab
//
                  UT_String buf;
                  UT_sint32 j;
                  for (j = 0; j < m_infoCache.m_iTabStops; j++)
                  {
                        if ((j == iTab))
                              continue;

                        if (!buf.empty())
                              buf += ",";

                        buf += _getTabStopString(&m_infoCache, j);
                  }

                  const XML_Char * properties[3];
                  properties[0] = "tabstops";
                  properties[1] = static_cast<const XML_Char *>(buf.c_str());
                  properties[2] = 0;
                  UT_DEBUGMSG(("TopRuler: Tab Stop [%s]\n",properties[1]));
                  m_draggingWhat = DW_NOTHING;
                  pView->setBlockFormat(properties);
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
            }

            return;
      }

      // next hit-test against the paragraph widgets

      UT_sint32 leftIndentCenter, rightIndentCenter, firstLineIndentCenter;
      UT_Rect rLeftIndent, rRightIndent, rFirstLineIndent;
      _getParagraphMarkerXCenters(&m_infoCache,&leftIndentCenter,&rightIndentCenter,&firstLineIndentCenter);
      _getParagraphMarkerRects(&m_infoCache,
                                           leftIndentCenter, rightIndentCenter, firstLineIndentCenter,
                                           &rLeftIndent, &rRightIndent, &rFirstLineIndent);
      if (rLeftIndent.containsPoint(x,y))
      {
            UT_DEBUGMSG(("hit left indent block x= %d y=%d \n",x,y));
            m_bValidMouseClick = true;

            /*
                  in RTL paragraphs we will throw right indent events for this box
                  the code which handles these events then ensure that we do in fact
                  modify the left margin
            */
            if(bRTL)
                  m_draggingWhat = DW_RIGHTINDENT;
            else
                  m_draggingWhat = ((_isInBottomBoxOfLeftIndent(y)) ? DW_LEFTINDENTWITHFIRST : DW_LEFTINDENT);

            m_bBeforeFirstMotion = true;
            m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
            return;
      }
      if (rRightIndent.containsPoint(x,y))
      {
            UT_DEBUGMSG(("hit right indent block x=%d y=%d \n",x,y));
            m_bValidMouseClick = true;

            /*
                  in RTL paragraphs we will throw left indent events for this box
                  the code which handles these events then ensure that we do in fact
                  modify the right margin
            */
            if(bRTL)
                  m_draggingWhat = _isInBottomBoxOfLeftIndent(y) ? DW_LEFTINDENTWITHFIRST : DW_LEFTINDENT;
            else
                  m_draggingWhat = DW_RIGHTINDENT;

            m_bBeforeFirstMotion = true;
            m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
            return;
      }
      if (rFirstLineIndent.containsPoint(x,y))
      {
            UT_DEBUGMSG(("hit first-line-indent block x= %d y= %d \n",x,y));
            m_bValidMouseClick = true;
            m_draggingWhat = DW_FIRSTLINEINDENT;
            m_bBeforeFirstMotion = true;
            m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
            return;
      }

      // next check the column gap

      if (m_infoCache.m_iNumColumns > 1)
      {
            UT_Rect rCol;
            _getColumnMarkerRect(&m_infoCache,0,_getColumnMarkerXRightEnd(&m_infoCache,0),&rCol);
            if (rCol.containsPoint(x,y))
            {
                  //UT_DEBUGMSG(("hit in column gap block\n"));
                  m_bValidMouseClick = true;
                  m_draggingWhat = ((static_cast<UT_sint32>(x) > (rCol.left+(rCol.width/2))) ? DW_COLUMNGAP : DW_COLUMNGAPLEFTSIDE);
                  m_bBeforeFirstMotion = true;
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  return;
            }
      }

      // next check page margins

      UT_Rect rLeftMargin, rRightMargin;
      _getMarginMarkerRects(&m_infoCache,rLeftMargin,rRightMargin);
      if (rLeftMargin.containsPoint(x,y))
      {
            UT_DEBUGMSG(("hit left margin block\n"));
            m_bValidMouseClick = true;
            m_bBeforeFirstMotion = true;
            m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
            m_draggingWhat = DW_LEFTMARGIN;
            return;
      }
      if (rRightMargin.containsPoint(x,y))
      {
            UT_DEBUGMSG(("hit right margin block\n"));
            m_bValidMouseClick = true;
            m_draggingWhat = DW_RIGHTMARGIN;
            m_bBeforeFirstMotion = true;
            m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
            return;
      }

// Now hit test against the cell containers if we're in a Table context.

      if(m_infoCache.m_mode == AP_TopRulerInfo::TRI_MODE_TABLE)
      {
            UT_sint32 i = 0;
            bool bFound = false;
            UT_Rect rCell;
            for(i=0; i<= m_infoCache.m_iCells && !bFound; i++)
            {
                  _getCellMarkerRect(&m_infoCache, i, &rCell);
                  if(rCell.containsPoint(x,y))
                  {
                        bFound = true;
                        
                        // determine the range in which this cell marker can be dragged
                        UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
                        UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
                        UT_sint32 xExtraMargin = 3; // keep an extra margin 3 pixels; there must be some space left to enter text in
                        if (i == 0)
                        {
                              AP_TopRulerTableInfo * pCurrentCellInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(i));
                              
//                            m_iMinCellPos = xAbsLeft;
                              m_iMinCellPos = 0;
                              m_iMaxCellPos = xAbsLeft + pCurrentCellInfo->m_iRightCellPos - pCurrentCellInfo->m_iRightSpacing - pCurrentCellInfo->m_iLeftSpacing - xExtraMargin;
                        }
                        else if (i == m_infoCache.m_iCells)
                        {
                              AP_TopRulerTableInfo * pPrevCellInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(i-1));
                              
                              m_iMinCellPos = xAbsLeft + pPrevCellInfo->m_iLeftCellPos + pPrevCellInfo->m_iLeftSpacing + pPrevCellInfo->m_iRightSpacing + xExtraMargin;
                              if((m_infoCache.m_iCurrentColumn + 1) == m_infoCache.m_iNumColumns)
                              {
                                    m_iMaxCellPos = xAbsRight + m_infoCache.u.c.m_xaRightMargin;
                              }
                              else
                              {
                                    m_iMaxCellPos = xAbsRight;
                              }
                        }
                        else
                        {
                              AP_TopRulerTableInfo * pPrevCellInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(i-1));
                              AP_TopRulerTableInfo * pCurrentCellInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(i));
                              
                              m_iMinCellPos = xAbsLeft + pPrevCellInfo->m_iLeftCellPos + pPrevCellInfo->m_iLeftSpacing + pPrevCellInfo->m_iRightSpacing + xExtraMargin;
                              m_iMaxCellPos = xAbsLeft + pCurrentCellInfo->m_iRightCellPos - pCurrentCellInfo->m_iRightSpacing - pCurrentCellInfo->m_iLeftSpacing - xExtraMargin;
                        }

                        break;
                  }
            }
            if(bFound)
            {
                  UT_DEBUGMSG(("hit Cell marker %d \n",i));
                  m_bValidMouseClick = true;
                  m_draggingWhat = DW_CELLMARK;
                  m_bBeforeFirstMotion = true;
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  m_draggingCell = i;
                  return;
            }
      }
      // finally, if nothing else, try to create a new tab

      UT_Rect rZone;
      _getTabZoneRect(&m_infoCache,rZone);
      if (rZone.containsPoint(x,y))
      {
            UT_DEBUGMSG(("hit new tab\n"));
            m_bValidMouseClick = true;
            m_draggingWhat = DW_TABSTOP;
            m_draggingTab = tr_TABINDEX_NEW;
            m_draggingTabType = m_iDefaultTabType;
            m_draggingTabLeader = FL_LEADER_NONE;
            m_bBeforeFirstMotion = true;

            // this is a new widget, so it needs more work to get started
            m_dragStart = xgrid;

            double dgrid = tick.scalePixelDistanceToUnits(xrel);
            UT_DEBUGMSG(("SettingTabStop: %s\n",m_pG->invertDimension(tick.dimType,dgrid)));

            UT_sint32 oldDraggingCenter = m_draggingCenter;
            UT_Rect oldDraggingRect = m_draggingRect;

            if(bRTL)
                  m_draggingCenter = xAbsRight - xgrid;
            else
                  m_draggingCenter = xAbsLeft + xgrid;

            UT_DEBUGMSG(("m_draggingCenter = %d\n",m_draggingCenter));

            _getTabStopRect(&m_infoCache,m_draggingCenter,&m_draggingRect);
            if (!m_bBeforeFirstMotion && (m_draggingCenter != oldDraggingCenter))
                  draw(&oldDraggingRect,&m_infoCache);
            _drawTabProperties(NULL,&m_infoCache,false);
            _xorGuide();

            m_bBeforeFirstMotion = false;

            // Since this is a new tab, it may be a simple click and not
            // a drag. Set m_oldX to a negative number so that
            // mouseMotion() is fooled.
            m_oldX = -1;
            m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
      }
}

/*****************************************************************/

void AP_TopRuler::mouseRelease(EV_EditModifierState ems, EV_EditMouseButton /* emb */, UT_sint32 x, UT_sint32 y)
{
      if (m_bValidMouseClick && m_draggingWhat == DW_TABTOGGLE)
      {
            m_draggingWhat = DW_NOTHING;
            m_bValidMouseClick = false;
            return;
      }

      if (!m_bValidMouseClick || (m_bEventIgnored && m_draggingWhat != DW_TABSTOP))
      {
            m_draggingWhat = DW_NOTHING;
            m_bValidMouseClick = false;
            if(m_pG)
            {
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
            }
            return;
      }

      m_bValidMouseClick = false;

      // if they drag vertically off the ruler, we ignore the whole thing.

      if ((y < 0) || (y > static_cast<UT_sint32>(getHeight ())))
      {
            _ignoreEvent(true);
            m_draggingWhat = DW_NOTHING;
            if(m_pG)
            {
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
            }
            return;
      }

      // mouse up was in the ruler portion of the window, or horizontally
      // off - we cannot ignore it.
      // i'd like to assert that we can just use the data computed in the
      // last mouseMotion() since the Release must be at the same spot or
      // we'd have received another Motion before the release.  therefore,
      // we use the last value of m_draggingCenter that we computed.

      // also, we do not do any drawing here.  we assume that whatever change
      // that we make to the document will cause a notify event to come back
      // to us and cause a full draw.

      //UT_DEBUGMSG(("mouseRelease: [ems 0x%08lx][emb 0x%08lx][x %ld][y %ld]\n",ems,emb,x,y));
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView == NULL)
      {
            return;
      }
      ap_RulerTicks tick(pView->getGraphics(),m_dim);
      UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);

    UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
      UT_sint32 xgrid;


      bool bRTLglobal;
      XAP_App::getApp()->getPrefsValueBool(static_cast<const XML_Char *>(AP_PREF_KEY_DefaultDirectionRtl), &bRTLglobal);

      fl_BlockLayout *pBlock = (static_cast<FV_View *>(m_pView))->getCurrentBlock();
      
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);


      if(bRTL)
            xgrid = tick.snapPixelToGrid(xAbsRight - static_cast<UT_sint32>(x));
      else
            xgrid = tick.snapPixelToGrid(static_cast<UT_sint32>(x) - xAbsLeft);


      _xorGuide (true);
      if (xgrid == m_oldX && (!pView->getDragTableLine())  ) // Not moved - clicked and released
      {
            UT_DEBUGMSG(("release only\n"));
            m_draggingWhat = DW_NOTHING;
            if(m_pG)
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
            return;
      }

      AP_TopRulerTableInfo *pTInfo = NULL;
      if(m_infoCache.m_mode == AP_TopRulerInfo::TRI_MODE_TABLE)
      {
            pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(m_infoCache.m_iCurCell));
            xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn) 
                  + pTInfo->m_iLeftCellPos + pTInfo->m_iLeftSpacing;
            xAbsRight =  _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn) 
                  + pTInfo->m_iRightCellPos - pTInfo->m_iRightSpacing;
      }
      bool isInFrame = pView->isInFrame(pView->getPoint());

      switch (m_draggingWhat)
      {
      case DW_NOTHING:
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            if(m_pG)
            {
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
            }
            return;

      case DW_LEFTMARGIN:
            {

                  // margins do not require any special bidi treatement; right
                  // edge of the page is always a right edge of the page ...

                  UT_sint32 xFixed = static_cast<UT_sint32>(pView->getGraphics()->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
                  FV_View * pView = static_cast<FV_View *>(m_pView);
                  if(pView->getViewMode() != VIEW_PRINT)
                  {
                        xFixed = 0;
                  }

                  UT_sint32 xAbsLeft;
                  double dxrel;

                  xAbsLeft = xFixed + m_infoCache.m_xPageViewMargin - m_xScrollOffset;

                  dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);
                  if((m_infoCache.m_mode != AP_TopRulerInfo::TRI_MODE_FRAME) && !isInFrame)
                  {
                        const XML_Char * properties[3];
                        properties[0] = "page-margin-left";
                        properties[1] = pView->getGraphics()->invertDimension(tick.dimType,dxrel);
                        properties[2] = 0;
                        UT_DEBUGMSG(("TopRuler: page-margin-left [%s]\n",properties[1]));

                        _xorGuide(true);
                        m_draggingWhat = DW_NOTHING;
                        pView->setSectionFormat(properties);
                  }
                  else
                  {
                        fl_FrameLayout * pFrame = pView->getFrameLayout();
                        if(pFrame)
                        {
                              const PP_AttrProp* pSectionAP = NULL;
                              pFrame->getAP(pSectionAP);
                              const XML_Char * pszXpos = NULL;
                              const XML_Char * pszWidth = NULL;
                              UT_sint32 iX;
                              UT_sint32 iWidth;
                              if(!pSectionAP || !pSectionAP->getProperty("xpos",pszXpos))
                              {
                                    UT_DEBUGMSG(("No xpos defined for Frame !\n"));
                                    UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
                                    return;
                              }
                              else
                              {
                                    iX = UT_convertToLogicalUnits(pszXpos);
                              }
                              if(!pSectionAP || !pSectionAP->getProperty("frame-width",pszWidth))
                              {
                                    UT_DEBUGMSG(("No Width defined for Frame !\n"));
                                    UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
                                    return;
                              }
                              else
                              {
                                    iWidth = UT_convertToLogicalUnits(pszWidth);
                              }
                              UT_sint32 diff = xgrid - m_oldX;
                              iX += diff;
                              iWidth -= diff;
                              if(iWidth < 0)
                              {
                                    iWidth = -iWidth;
                              }
                              UT_String sXpos("");
                              UT_String sWidth("");
                              double dX = static_cast<double>(iX)/static_cast<double>(UT_LAYOUT_RESOLUTION);
                              sXpos = UT_formatDimensionedValue(dX,"in", NULL);
                              double dWidth = static_cast<double>(iWidth)/static_cast<double>(UT_LAYOUT_RESOLUTION);
                              sWidth = UT_formatDimensionedValue(dWidth,"in", NULL);
                              const XML_Char * props[6] = {"frame-width",sWidth.c_str(),
                                                "xpos",sXpos.c_str(),
                                                NULL,NULL};
                              pView->setFrameFormat(props);
                        }
                        else
                        {
                              return;
                        }
                  }
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
                  return;
            }
      case DW_RIGHTMARGIN:
            {
                  if((m_infoCache.m_mode != AP_TopRulerInfo::TRI_MODE_FRAME) && !isInFrame)
                  {
                        UT_sint32 xAbsRight;
                        
                        if(bRTLglobal)
                              xAbsRight = _getFirstPixelInColumn(&m_infoCache, 0)
                                    + m_infoCache.u.c.m_xColumnWidth + m_infoCache.u.c.m_xaRightMargin;
                        else
                              xAbsRight = _getFirstPixelInColumn(&m_infoCache, m_infoCache.m_iNumColumns - 1)
                                    + m_infoCache.u.c.m_xColumnWidth + m_infoCache.u.c.m_xaRightMargin;

                        double dxrel = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter);

                        const XML_Char * properties[3];
                        properties[0] = "page-margin-right";
                        properties[1] = pView->getGraphics()->invertDimension(tick.dimType,dxrel);
                        properties[2] = 0;
                        UT_DEBUGMSG(("TopRuler: page-margin-right [%s] (x %d, xAbsRight %d)\n",properties[1], x, xAbsRight));
                        FV_View *pView = static_cast<FV_View *>(m_pView);

                        pView->setSectionFormat(properties);
                  }
                  else
                  {
                        if(m_pView == NULL)
                        {
                              return;
                        }
                        FV_View * pView = static_cast<FV_View *>(m_pView);
                        fl_FrameLayout * pFrame = pView->getFrameLayout();
                        if(pFrame)
                        {
                              const PP_AttrProp* pSectionAP = NULL;
                              pFrame->getAP(pSectionAP);
                              const XML_Char * pszWidth = NULL;
                              UT_sint32 iWidth;
                              if(!pSectionAP || !pSectionAP->getProperty("frame-width",pszWidth))
                              {
                                    UT_DEBUGMSG(("No Width defined for Frame !\n"));
                                    UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
                                    return;
                              }
                              else
                              {
                                    iWidth = UT_convertToLogicalUnits(pszWidth);
                              }
                              UT_sint32 diff = xgrid - m_oldX;
                              iWidth += diff;
                              if(iWidth < 0)
                              {
                                    iWidth = -iWidth;
                              }
                              UT_String sWidth("");
                              double dWidth = static_cast<double>(iWidth)/static_cast<double>(UT_LAYOUT_RESOLUTION);
                              sWidth = UT_formatDimensionedValue(dWidth,"in", NULL);
                              const XML_Char * props[4] = {"frame-width",sWidth.c_str(),
                                                NULL,NULL};
                              pView->setFrameFormat(props);
                        }
                        else
                        {
                              return;
                        }
                  }
                  _xorGuide(true);
                  m_draggingWhat = DW_NOTHING;
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
                  return;
            }

      case DW_COLUMNGAP:
      case DW_COLUMNGAPLEFTSIDE:
            {
                  double dxrel = tick.scalePixelDistanceToUnits(m_draggingRect.width);

                  const XML_Char * properties[3];
                  properties[0] = "column-gap";
                  properties[1] = pView->getGraphics()->invertDimension(tick.dimType,dxrel);
                  properties[2] = 0;
                  UT_DEBUGMSG(("TopRuler: ColumnGap [%s]\n",properties[1]));

                  m_draggingWhat = DW_NOTHING;
            FV_View *pView = static_cast<FV_View *>(m_pView);
            pView->setSectionFormat(properties);
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
            }
            return;

      case DW_LEFTINDENT:
            {
                  // we are dragging only the left-indent and not the first-line.
                  // so, when we drop the left-indent, we need to reset the first-line
                  // so that the absolute position of the first-line has not changed.
                  // first-line is stored in relative terms, so we need to update it.

                  if(pTInfo)
                  {
                        xAbsRight = _getFirstPixelInColumn(&m_infoCache, 0)
                                    + pTInfo->m_iRightCellPos;
                  }


                  FV_View * pView = static_cast<FV_View *>(m_pView);

                  const XML_Char * properties[5];
            double dxrel;
            double dxrel2;
            UT_sint32 xdelta;

                  // in rtl block we drag the right indent
                  xxx_UT_DEBUGMSG(("DW_LEFTINDENT (release): m_draggingCenter %d\n", m_draggingCenter));
                  if(bRTL)
                  {
                        dxrel = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter);
                        xdelta = (xAbsRight - m_draggingCenter) - m_infoCache.m_xrRightIndent;
                        properties[0] = "margin-right";
                  }
                  else
                  {
                        dxrel  = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);
                        xdelta = (m_draggingCenter-xAbsLeft) - m_infoCache.m_xrLeftIndent;
                        properties[0] = "margin-left";
                  }

                  dxrel2 = tick.scalePixelDistanceToUnits(m_infoCache.m_xrFirstLineIndent - xdelta);

                  // invertDimension() returns pointer to static buffer, so
                  // we need to copy these for later use.
                  char buf1[50];
                  strcpy(buf1,pView->getGraphics()->invertDimension(tick.dimType,dxrel));
                  char buf2[50];
                  strcpy(buf2,pView->getGraphics()->invertDimension(tick.dimType,dxrel2));

                  properties[1] = buf1;
                  properties[2] = "text-indent";
                  properties[3] = buf2;
                  properties[4] = 0;
                  xxx_UT_DEBUGMSG(("TopRuler: LeftIndent [%s] TextIndent [%s] (xAbsRight %d, dxrel %f, m_draggingCenter %d)\n",
                                           properties[1],properties[3],xAbsRight, dxrel,m_draggingCenter));

                  m_draggingWhat = DW_NOTHING;

                  pView->setBlockFormat(properties);
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
            }
            return;

      case DW_LEFTINDENTWITHFIRST:
            {
                  // we are dragging both the left-indent and first-line in sync
                  // so that we do not change the first-line-indent relative to
                  // the paragraph.  since first-line-indent is stored in the
                  // document in relative coordinates, we don't need to do anything.
                  double dxrel;
                  const XML_Char * properties[3];
                  FV_View * pView = static_cast<FV_View *>(m_pView);

                  // in rtl block we drag the right margin, of course :-);
                  xxx_UT_DEBUGMSG(("DW_LEFTINDENTWITHFIRST (release): m_draggingCenter %d\n", m_draggingCenter));
                  if(bRTL)
                  {
                        dxrel = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter);
                        properties[0] = "margin-right";
                  }
                  else
                  {
                        dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);
                        properties[0] = "margin-left";
                  }

                  properties[1] = pView->getGraphics()->invertDimension(tick.dimType,dxrel);
                  properties[2] = 0;
                  UT_DEBUGMSG(("TopRuler: LeftIndent [%s]\n",properties[1]));

                  m_draggingWhat = DW_NOTHING;
                  pView->setBlockFormat(properties);
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
            }
            return;

      case DW_RIGHTINDENT:
            {

                  double dxrel;
                  FV_View * pView = static_cast<FV_View *>(m_pView);
                  const XML_Char * properties[3];

                  // in rtl block we drag the left indent
                  xxx_UT_DEBUGMSG(("DW_RIGHTINDENT (release): m_draggingCenter %d\n", m_draggingCenter));
                  if(bRTL)
                  {
                        dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);
                        properties[0] = "margin-left";
                  }
                  else
                  {
                        dxrel = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter);
                        properties[0] = "margin-right";
                  }

                  // invertDimension() returns pointer to static buffer, so
                  // we need to copy these for later use.
                  char buf1[50];
                  strcpy(buf1,pView->getGraphics()->invertDimension(tick.dimType,dxrel));

                  properties[1] = buf1;
                  properties[2] = 0;
                  UT_DEBUGMSG(("TopRuler: RightIndent [%s]\n",properties[1]));


                  m_draggingWhat = DW_NOTHING;
                  pView->setBlockFormat(properties);
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
            }
            return;

      case DW_FIRSTLINEINDENT:
            {
                  double dxrel;
                  FV_View * pView = static_cast<FV_View *>(m_pView);

                  if(bRTL)
                        dxrel = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter-m_infoCache.m_xrRightIndent);
                  else
                        dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter-xAbsLeft-m_infoCache.m_xrLeftIndent);


                  const XML_Char * properties[3];
                  properties[0] = "text-indent";
                  properties[1] = pView->getGraphics()->invertDimension(tick.dimType,dxrel);
                  properties[2] = 0;
                  UT_DEBUGMSG(("TopRuler: FirstLineIndent [%s]\n",properties[1]));

                  m_draggingWhat = DW_NOTHING;
                  pView->setBlockFormat(properties);
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
            }
            return;

      case DW_TABSTOP:
            {
                  UT_sint32 anchor;
                  eTabType iType;
                  eTabLeader iLeader;
            UT_sint32 xrel;

                  fl_BlockLayout *pBlock = (static_cast<FV_View *>(m_pView))->getCurrentBlock();
      
                  bool bRTL = false;

                  if(pBlock)
                        bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);


                  if(bRTL)
                        xrel = xAbsRight - xgrid;
                  else
                        xrel = xgrid + xAbsLeft;

                  UT_sint32 iTab = _findTabStop(&m_infoCache, xrel, pView->getGraphics()->tlu(s_iFixedHeight)/2 + pView->getGraphics()->tlu(s_iFixedHeight)/4 - 3, anchor, iType, iLeader);

                  UT_DEBUGMSG (("iTab: %i, m_draggingTab: %i\n", iTab, m_draggingTab));

                  if (iTab >= 0 && iTab != m_draggingTab)
                  {
                        UT_DEBUGMSG (("This tab was released over an existing tab. It will be deleted.\n"));
                        _setTabStops(tick, m_draggingTab, iLeader, true); // true for the last arg will cause this to be deleted
                  }
                  else
                  {
                        _setTabStops(tick, iTab,  m_draggingTabLeader, false);
                  }
                  m_draggingWhat = DW_NOTHING;
                  FV_View * pView = static_cast<FV_View *>(m_pView);
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
                  return;
            }

      case DW_CELLMARK:
            {
            double dxrel;
            UT_sint32 xdelta;
                  UT_sint32 iCell;
                  UT_sint32 nCells;
                  AP_TopRulerTableInfo *pTInfo = NULL;
                  if(m_infoCache.m_mode == AP_TopRulerInfo::TRI_MODE_TABLE)
                  {
                        iCell =  m_infoCache.m_iCurCell;
                        nCells = m_infoCache.m_vecTableColInfo->getItemCount();
                        pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(iCell));
                  }
                  else
                  {
                        m_draggingWhat = DW_NOTHING;
                        FV_View * pView = static_cast<FV_View *>(m_pView);
                        notify(pView, AV_CHG_HDRFTR);
                        if(m_pG)
                        {
                              m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                        }
                        return;
                  }                       
                  xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn); 
                  xxx_UT_DEBUGMSG(("DW_CELLMARK (release): m_draggingCenter %d\n", m_draggingCenter));
                  dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);
                  xdelta = m_draggingCenter - pTInfo->m_iLeftCellPos ;
                  UT_String sCellPos = pView->getGraphics()->invertDimension(tick.dimType,dxrel);
                  xxx_UT_DEBUGMSG(("cellPos dragged to position %s from left column edge difference in pixels %d \n",sCellPos.c_str(),xdelta));
                  UT_String sColWidths;
                  UT_sint32 i;
                  bool bDragRightMost = false;
                  bool bDragLeftMost = false;
                  UT_sint32 leftDrag = -100000;
                  UT_sint32 rightDrag = -100000;
                  if(ems == EV_EMS_SHIFT)
                  {
//
// shift-drag-release keep the width of the table constant
//
                        if(m_draggingCell == static_cast<UT_sint32>(m_infoCache.m_vecTableColInfo->getItemCount()))
                        {
                              bDragRightMost = true;
                        }
                        else
                        {
                              pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(m_draggingCell));
                              leftDrag = pTInfo->m_iLeftCellPos ;
                        }
                        
                        for(i=1; i <= static_cast<UT_sint32>(m_infoCache.m_vecFullTable->getItemCount());i++)
                        {
                              UT_sint32 left =0;
                              UT_sint32 right = 0;
                        
                        //
                              pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecFullTable->getNthItem(i-1));
                              bool bOnDraggingRight = false;
                              UT_DEBUGMSG(("ap_TopRuler: leftDrag %d i %d pTInfo->m_iLeftCellPos %d \n",leftDrag,i,pTInfo->m_iLeftCellPos));
                              if(leftDrag != pTInfo->m_iLeftCellPos)
                                    left = pTInfo->m_iLeftCellPos + xAbsLeft + pTInfo->m_iLeftSpacing;
                              else
                                    left =  m_draggingCenter;
                              if(i < static_cast<UT_sint32>(m_infoCache.m_vecFullTable->getItemCount()))
                              {
                                    pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecFullTable->getNthItem(i));
                                    bOnDraggingRight = (leftDrag == pTInfo->m_iLeftCellPos);
                              }
//
// Now set the right marker
//
                              if(i != static_cast<UT_sint32>(m_infoCache.m_vecFullTable->getItemCount()) && !bOnDraggingRight)
                              {
                                    pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecFullTable->getNthItem(i));
                                    right = pTInfo->m_iLeftCellPos + xAbsLeft + pTInfo->m_iLeftSpacing;
                              }
                              else if(i == static_cast<UT_sint32>(m_infoCache.m_vecFullTable->getItemCount()) && !bDragRightMost)
                              {
                                    pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecFullTable->getNthItem(i-1));
                                    right = pTInfo->m_iRightCellPos + xAbsLeft - pTInfo->m_iLeftSpacing;
                              }
                              else if(i == static_cast<UT_sint32>(m_infoCache.m_vecFullTable->getItemCount()) && bDragRightMost )
                              {
                                    right = m_draggingCenter;
                              }
                              else
                                    right = m_draggingCenter;
                              
                              xxx_UT_DEBUGMSG(("SEVIOR i %d iCell %d left %d right %d \n",i,m_draggingCell,left,right));
                              UT_sint32 width = right - left;
                              if(width > 0)
                              {
                                    dxrel = tick.scalePixelDistanceToUnits(width);
                              }
                              else
                              {
                                    width = pTInfo->m_iRightCellPos - pTInfo->m_iLeftCellPos - pTInfo->m_iLeftSpacing - pTInfo->m_iRightSpacing;
                                    dxrel = tick.scalePixelDistanceToUnits(width);
                              }
                              UT_String sTmp = pView->getGraphics()->invertDimension(tick.dimType,dxrel);
                              sColWidths += sTmp;
                              sColWidths += '/';
                        }
                  }
                  else
                  {
//
// Just change the width of the cell to the left of marker unless is the
// first cell
//
                        UT_sint32 iNumCells =  static_cast<UT_sint32>(m_infoCache.m_vecFullTable->getItemCount());
                        if(m_draggingCell == 0)
                        {
                              bDragLeftMost = true;
                        }
                        else if(m_draggingCell == iNumCells)
                        {
                              bDragRightMost = true;
                              pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(m_draggingCell-1));
                              rightDrag = pTInfo->m_iRightCellPos;
                              UT_DEBUGMSG(("rightDrag %d \n",rightDrag));
                        }
                        else
                        {
                              pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecTableColInfo->getNthItem(m_draggingCell-1));
                              rightDrag = pTInfo->m_iRightCellPos;
                        }
                        if(!bDragLeftMost)
                        {
                              for(i=1; i <= iNumCells ;i++)
                              {
                                    UT_sint32 left =0;
                                    UT_sint32 right = 0;
                                    UT_sint32 width = 0;
                        //
                                    pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecFullTable->getNthItem(i-1));
                                    UT_DEBUGMSG(("ap_TopRuler: rightDrag %d i %d pTInfo->m_iRightCellPos %d \n",rightDrag,i,pTInfo->m_iRightCellPos));
                                    if(abs(rightDrag - pTInfo->m_iRightCellPos) >10)
                                    {
                                          left = pTInfo->m_iLeftCellPos + xAbsLeft + pTInfo->m_iLeftSpacing;
                                          if(i < iNumCells)
                                          {
                                                pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecFullTable->getNthItem(i));
                                                right = pTInfo->m_iLeftCellPos + xAbsLeft + pTInfo->m_iLeftSpacing;
                                          }
                                          else
                                          {
                                                right = pTInfo->m_iRightCellPos + xAbsLeft + pTInfo->m_iRightSpacing;
                                          }
                                          width = right - left;
                                          if(width < 5*pTInfo->m_iLeftSpacing)
                                          {
                                                width = 5*pTInfo->m_iLeftSpacing;
                                          }
                                    }
                                    else
                                    {
                                          right =  m_draggingCenter;
                                          left = pTInfo->m_iLeftCellPos + xAbsLeft + pTInfo->m_iLeftSpacing;
                                          width = right - left;
                                          if(width < 5*pTInfo->m_iLeftSpacing)
                                          {
                                                width = 5*pTInfo->m_iLeftSpacing;
                                          }
                                    }
                                    dxrel = tick.scalePixelDistanceToUnits(width);
                                    UT_String sTmp = pView->getGraphics()->invertDimension(tick.dimType,dxrel);
                                    sColWidths += sTmp;
                                    sColWidths += '/';
                              }

                        }
                        xxx_UT_DEBUGMSG(("SEVIOR: COlumn Width string = %s \n",sColWidths.c_str()));
                  }
                  m_draggingWhat = DW_NOTHING;
                  FV_View * pView = static_cast<FV_View *>(m_pView);
                  const XML_Char * props[3] = {NULL,NULL,NULL};
                  if(!bDragLeftMost)
                  {
                        props[0] = "table-column-props";
                        props[1] = sColWidths.c_str();
                  }
                  else
                  {
                        if(m_pG == NULL)
                        {
                              m_iCellContainerLeftPos = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
                        }
                        UT_sint32 leftCol =  m_draggingCenter - m_iCellContainerLeftPos;
                        xxx_UT_DEBUGMSG(("ap_TopRuler - set Left most leftCol %d dragging center %d M-iCellContainerLeftPos %d \n",leftCol,m_draggingCenter,  m_iCellContainerLeftPos));
                        double dLeft = tick.scalePixelDistanceToUnits(leftCol);
                        sCellPos = pView->getGraphics()->invertDimension(tick.dimType,dLeft);
                        props[0] = "table-column-leftpos";
                        props[1] = sCellPos.c_str();
                  }

//
// Now do manipulations to find the position of the table we're about to 
// change.
//
                  if(pTInfo == NULL)
                  {
                        pTInfo = static_cast<AP_TopRulerTableInfo *>(m_infoCache.m_vecFullTable->getNthItem(0));
                  }
                  fp_CellContainer * pCell = pTInfo->m_pCell;
                  fl_SectionLayout * pSL = pCell->getSectionLayout();
                  fl_BlockLayout * pBL = static_cast<fl_BlockLayout *>(pSL->getFirstLayout());
                  PT_DocPosition pos = pBL->getPosition();
                  pView->setTableFormat(pos,props);
                  if(pView->getDragTableLine() && !pView->isInTable())
                  {
                        pView->setPoint(pos);
                  }
                  notify(pView, AV_CHG_HDRFTR);
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
                  }
                  return;
            }
      default:
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            if(m_pG)
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
            return;
      }
}

void AP_TopRuler::_setTabStops(ap_RulerTicks tick, UT_sint32 iTab, eTabLeader iLeader, bool bDelete)
{
      UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
    UT_sint32 xrel;
      fl_BlockLayout *pBlock = (static_cast<FV_View *>(m_pView))->getCurrentBlock();
      
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);


      UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;

      if(bRTL)
            xrel = xAbsRight - m_draggingCenter;
      else
            xrel = m_draggingCenter-xAbsLeft;

      double dxrel = tick.scalePixelDistanceToUnits(xrel);

      UT_String buf;

      // first add the new tab settings

      if (!bDelete)
      {
            char * sz = NULL, sz1[2];
            sz1[0] = static_cast<char>(iLeader) + '0'; sz1[1] = 0;

            switch(m_draggingTabType)
            {
                  case FL_TAB_LEFT:       sz = "L";   break;
                  case FL_TAB_RIGHT:            sz = "R";   break;
                  case FL_TAB_CENTER:           sz = "C";   break;
                  case FL_TAB_DECIMAL:    sz = "D";   break;
                  case FL_TAB_BAR:        sz = "B";   break;
                  default:
                        sz = "";
            }
            buf += m_pG->invertDimension(tick.dimType,dxrel);
            buf += "/";
            buf += sz;
            buf += sz1;
      }

      // then append all the remaining tabstops, if any

      for (UT_sint32 i = 0; i < m_infoCache.m_iTabStops; i++)
      {
            if ((i == iTab) || (i == m_draggingTab))
                  continue;

            if (!buf.empty())
                  buf += ",";

            buf += _getTabStopString(&m_infoCache, i);
      }

      const XML_Char * properties[3];
      properties[0] = "tabstops";
      properties[1] = static_cast<const XML_Char *>(buf.c_str());
      properties[2] = 0;
      UT_DEBUGMSG(("TopRuler: Tab Stop [%s]\n",properties[1]));

      m_draggingWhat = DW_NOTHING;
      (static_cast<FV_View *>(m_pView))->setBlockFormat(properties);
}

/*****************************************************************/

void AP_TopRuler::mouseMotion(EV_EditModifierState ems, UT_sint32 x, UT_sint32 y)
{
      // The X and Y that are passed to this function are x and y on the screen, not on the ruler.
//    if(m_pG == NULL)
//    {
//          return;
//    }
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView && pView->isLayoutFilling())
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_WAIT);
            return;
      }
      if(pView == NULL)
      {
            return;
      }
      if (!m_bValidMouseClick && (m_pG != NULL))
      {
            m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
            return;
      }

      m_bEventIgnored = false;

      xxx_UT_DEBUGMSG(("mouseMotion: [ems 0x%08lx][x %ld][y %ld]\n",ems,x,y));

      // if they drag vertically off the ruler, we ignore the whole thing.

      if (m_pG && ((y < 0) || (y > static_cast<UT_sint32>(getHeight ()))))
      {
            if(!m_bEventIgnored)
            {
                  _ignoreEvent(false);
                  m_bEventIgnored = true;
            }
            if(m_pG)
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
            return;
      }


      // the following segment of code used to test whether the mouse was on the ruler horizontally
      // now it makes sure the values are sane, disregarding mouse area
      // for example, it will not let a left indent be moved to a place before the end of the left page view margin

      UT_sint32 xFixed = static_cast<UT_sint32>(pView->getGraphics()->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));

      if(pView->getViewMode() != VIEW_PRINT)
            xFixed = pView->getGraphics()->tlu(s_iFixedWidth);

      UT_sint32 xStartPixel = xFixed + static_cast<UT_sint32>(m_infoCache.m_xPageViewMargin);
      UT_sint32 xAbsRight;    // NB !!! this variable is used by the page margins and
                                          // refers to the very right edge of the page; it is not
                                          // a right edge of the rightmost column.

      bool bRTLglobal;
      XAP_App::getApp()->getPrefsValueBool(static_cast<const XML_Char *>(AP_PREF_KEY_DefaultDirectionRtl), &bRTLglobal);

      fl_BlockLayout *pBlock = (static_cast<FV_View *>(m_pView))->getCurrentBlock();
      
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);

      
      if(bRTLglobal)
            xAbsRight = _getFirstPixelInColumn(&m_infoCache, 0) +
                  m_infoCache.u.c.m_xColumnWidth + m_infoCache.u.c.m_xaRightMargin;
      else
            xAbsRight = _getFirstPixelInColumn(&m_infoCache, m_infoCache.m_iNumColumns - 1) +
                  m_infoCache.u.c.m_xColumnWidth + m_infoCache.u.c.m_xaRightMargin;

      //UT_DEBUGMSG(("mouseMotion: xAbsRight %d\n", xAbsRight));
      ap_RulerTicks tick(pView->getGraphics(),m_dim);
      // now to test if we are on the view, and scroll if the mouse isn't

      if ((x < xFixed || x > static_cast<UT_sint32>(getWidth())) && m_draggingWhat != DW_TABTOGGLE)
      {
            // set m_aScrollDirection here instead of in the timer creation block because there is a change,
            // though small, that the direction will change immediately with no on-ruler in-between state.
            // the user could have the mouse to the left of the ruler, bring it up onto the toolbar, go to the
            // right of the window, and bring it down to the right of the ruler. i'm crazy! :-)))
            if (x < xFixed)
                  m_aScrollDirection = 'L';
            else
                  m_aScrollDirection = 'R';

            if (!m_pAutoScrollTimer)
            {
                  // the timer DOESNT exist, it's NOT already being taken care of, we are the FIRST mouse motion event
                  // off the ruler since the last time it was on the ruler and we have MAJOR SELF-ESTEEM PROBLEMS!!!
                  if(m_pG)
                  {
                        m_pAutoScrollTimer = UT_Timer::static_constructor(_autoScroll, this, m_pG);
                        if (m_pAutoScrollTimer)
                              m_pAutoScrollTimer->set(s_tr_AUTOSCROLL_INTERVAL);
                  }
            }

            if (m_aScrollDirection == 'L')
                  x = xFixed + 1;
            else
                  x = getWidth () - 10;

            if(m_pG)
                  draw(NULL, &m_infoCache);
      }

      // by now, if the cursor if off the ruler we will have created a timer and set it and returned.
      // so, the cursor is on the ruler. make sure that any timer for autoscroll is stopped.
      else if (m_pAutoScrollTimer)
      {
            m_pAutoScrollTimer->stop();
            DELETEP(m_pAutoScrollTimer);
            m_pAutoScrollTimer = NULL;
            if(m_pG)
                  draw(NULL, &m_infoCache);
            _xorGuide(true);
      }

      // make sure the item is within the page...
      if (x + m_xScrollOffset < xStartPixel)
            x = xStartPixel - m_xScrollOffset;
      // Aiiiiaag... xAbsRight is a screen coordinate. I figured this out the hard way.
      else if (x > xAbsRight)
            x = xAbsRight;

      // if we are this far along, the mouse motion is significant
      // we cannot ignore it.

      switch (m_draggingWhat)
      {
      case DW_NOTHING:
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            return;

      case DW_TABTOGGLE:
            return;

      case DW_LEFTMARGIN:
            {
            if(m_pG)
        {   
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
            }
            UT_sint32 oldDragCenter = m_draggingCenter;
            UT_sint32 xAbsLeft = xFixed + m_infoCache.m_xPageViewMargin - m_xScrollOffset;

            UT_sint32 iAbsLeft;
            UT_sint32 iAbsRight;
            UT_sint32 iIndentShift;
            UT_sint32 iRightIndentPos;
            UT_sint32 iFirstIndentL, iFirstIndentR;

            UT_sint32 xAbsRight;

            if(bRTLglobal)
            {
                  xAbsRight = _getFirstPixelInColumn(&m_infoCache,0) + m_infoCache.u.c.m_xColumnWidth;
                  iFirstIndentL = 0;
                  iFirstIndentR = m_infoCache.m_xrFirstLineIndent;
              iAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iNumColumns - 1);
            }
            else
            {
                  iFirstIndentL = m_infoCache.m_xrFirstLineIndent;
                  iFirstIndentR = 0;
              iAbsLeft = _getFirstPixelInColumn(&m_infoCache,0);
            }

            m_draggingCenter = tick.snapPixelToGrid(x);


          iAbsRight = iAbsLeft + m_infoCache.u.c.m_xColumnWidth;
            iIndentShift = UT_MAX(0,UT_MAX(m_infoCache.m_xrLeftIndent,m_infoCache.m_xrLeftIndent + iFirstIndentL));
        iRightIndentPos = iAbsRight - UT_MAX(0,m_infoCache.m_xrRightIndent + iFirstIndentR) - iIndentShift;

        if(iRightIndentPos - m_draggingCenter < m_minColumnWidth)
            {
            m_draggingCenter = iRightIndentPos - m_minColumnWidth;
            }

        iIndentShift = UT_MIN(0,UT_MIN(m_infoCache.m_xrLeftIndent,m_infoCache.m_xrLeftIndent + iFirstIndentL));

        m_draggingCenter = UT_MAX(m_draggingCenter, xAbsLeft - iIndentShift);

            if(m_draggingCenter == oldDragCenter)
            {
                  // Position not changing so finish here.

                  return;
            }

            UT_sint32 newMargin = m_draggingCenter - xAbsLeft;
            UT_sint32 deltaLeftMargin = newMargin - m_infoCache.u.c.m_xaLeftMargin;
            UT_sint32 newColumnWidth = m_infoCache.u.c.m_xColumnWidth - deltaLeftMargin / static_cast<UT_sint32>(m_infoCache.m_iNumColumns);
            if(iFirstIndentL + m_infoCache.m_xrLeftIndent > m_infoCache.m_xrLeftIndent)
            {
                  if(iFirstIndentL + m_infoCache.m_xrLeftIndent > 0)
                  {
                        newColumnWidth -= iFirstIndentL + m_infoCache.m_xrLeftIndent;
                  }
            }
            else if(m_infoCache.m_xrLeftIndent > 0)
            {
                  newColumnWidth -= m_infoCache.m_xrLeftIndent;
            }
            if(newColumnWidth < m_minColumnWidth)
            {
                  x -= (m_minColumnWidth - newColumnWidth) * static_cast<UT_sint32>(m_infoCache.m_iNumColumns);

                  m_draggingCenter = tick.snapPixelToGrid(x);

                  newMargin = m_draggingCenter - xAbsLeft;
                  deltaLeftMargin = newMargin - m_infoCache.u.c.m_xaLeftMargin;
                  m_infoCache.u.c.m_xaLeftMargin += deltaLeftMargin;
                  m_infoCache.u.c.m_xColumnWidth -= deltaLeftMargin / static_cast<UT_sint32>(m_infoCache.m_iNumColumns);
                  draw(NULL, &m_infoCache);
                  m_infoCache.u.c.m_xaLeftMargin -= deltaLeftMargin;
                  m_infoCache.u.c.m_xColumnWidth += deltaLeftMargin / static_cast<UT_sint32>(m_infoCache.m_iNumColumns);
            }

            _xorGuide();
            m_bBeforeFirstMotion = false;

            // Display in margin in status bar.
        double dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);
            _displayStatusMessage(AP_STRING_ID_LeftMarginStatus, tick, dxrel);

            }
            return;

      case DW_RIGHTMARGIN:
            {
            if(m_pG)
        {   
                  m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
            }
            UT_sint32 oldDragCenter = m_draggingCenter;

            UT_sint32 iFirstIndentL, iFirstIndentR;

            if(bRTLglobal)
            {
                  iFirstIndentR = m_infoCache.m_xrFirstLineIndent;
                  iFirstIndentL = 0;
            }
            else
            {
                  iFirstIndentR = 0;
                  iFirstIndentL = m_infoCache.m_xrFirstLineIndent;
            }

        UT_sint32 iRightShift = UT_MAX(0,UT_MAX(m_infoCache.m_xrRightIndent,m_infoCache.m_xrRightIndent + iFirstIndentR));
        UT_sint32 iLeftShift = UT_MAX(0,UT_MAX(m_infoCache.m_xrLeftIndent,m_infoCache.m_xrLeftIndent + iFirstIndentL));
        UT_sint32 newMargin;
        UT_sint32 deltaRightMargin;
        UT_sint32 newColumnWidth;

        x = UT_MIN(x,xAbsRight + UT_MIN(0,m_infoCache.m_xrRightIndent + iFirstIndentR));
        while(1)
            {
            newMargin = xAbsRight - x;
            deltaRightMargin = newMargin - m_infoCache.u.c.m_xaRightMargin;
            newColumnWidth = m_infoCache.u.c.m_xColumnWidth - deltaRightMargin / static_cast<UT_sint32>(m_infoCache.m_iNumColumns);

            if(newColumnWidth - iRightShift - iLeftShift < m_minColumnWidth){
                x += (m_minColumnWidth - (newColumnWidth - iRightShift - iLeftShift)) * static_cast<UT_sint32>(m_infoCache.m_iNumColumns);
            }
                  else
                        break;
        }
            m_draggingCenter = tick.snapPixelToGrid(x);

            // Position not changing so finish here.
            if(m_draggingCenter == oldDragCenter)
                  return;

            m_infoCache.u.c.m_xaRightMargin += deltaRightMargin;
            m_infoCache.u.c.m_xColumnWidth -= deltaRightMargin / static_cast<UT_sint32>(m_infoCache.m_iNumColumns);

            draw(NULL, &m_infoCache);
            m_infoCache.u.c.m_xaRightMargin -= deltaRightMargin;
            m_infoCache.u.c.m_xColumnWidth += deltaRightMargin / static_cast<UT_sint32>(m_infoCache.m_iNumColumns);
            _xorGuide();
            m_bBeforeFirstMotion = false;

            // Display in margin in status bar.

            double dxrel = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter);

            _displayStatusMessage(AP_STRING_ID_RightMarginStatus, tick, dxrel);
            }
            return;

      case DW_COLUMNGAP:
      case DW_COLUMNGAPLEFTSIDE:
            {
                  if(m_pG)
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,0);
                  UT_sint32 xAbsRight2 = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
                  UT_sint32 xAbsRightGap = xAbsRight2 + m_infoCache.u.c.m_xColumnGap;
                  UT_sint32 xAbsMidPoint = (xAbsRight2 + xAbsRightGap)/2;
                  UT_sint32 xrel;

                  if(m_draggingWhat == DW_COLUMNGAP)
                  {
                        UT_sint32 xAbsLowerLimit = xAbsMidPoint + tick.snapPixelToGrid((UT_sint32)(tick.dragDelta/tick.tickUnitScale));
                        if (static_cast<UT_sint32>(x) < xAbsLowerLimit)
                              x = static_cast<UT_uint32>(xAbsLowerLimit);
                        xrel = static_cast<UT_sint32>(x) - xAbsRight2;
                  }
                  else
                  {
                        UT_sint32 xAbsUpperLimit = xAbsMidPoint - tick.snapPixelToGrid((UT_sint32)(tick.dragDelta/tick.tickUnitScale));
                        if (static_cast<UT_sint32>(x) > xAbsUpperLimit)
                              x = static_cast<UT_uint32>(xAbsUpperLimit);
                        xrel = xAbsRightGap - static_cast<UT_sint32>(x);
                  }

                  UT_sint32 xgrid = tick.snapPixelToGrid(xrel);

                  // Check the column width.

                  UT_sint32 columnWidth = xAbsRightGap - xgrid - xAbsLeft;
                  UT_DEBUGMSG(("[Column width %ld]\n",columnWidth));

                  if(columnWidth < m_minColumnWidth)
                  {
                        xgrid -= m_minColumnWidth - columnWidth;
                  }

                  UT_sint32 oldDraggingCenter = m_draggingCenter;
                  UT_Rect oldDraggingRect = m_draggingRect;
                  m_draggingCenter = xAbsRight2 + xgrid;
                  _getColumnMarkerRect(&m_infoCache,0,m_draggingCenter,&m_draggingRect);


                  UT_DEBUGMSG(("Gap: [x %ld][xAbsRight %ld][xrel %ld][xgrid %ld][width %ld]\n",x,xAbsRight2,xrel,xgrid,m_draggingRect.width));


                  if (!m_bBeforeFirstMotion && (m_draggingCenter != oldDraggingCenter))
                        draw(((oldDraggingRect.width > m_draggingRect.width ) ? &oldDraggingRect : &m_draggingRect),
                               &m_infoCache);
                  _drawColumnProperties(NULL,&m_infoCache,0);
                  _xorGuide();

                  double dgrid = tick.scalePixelDistanceToUnits(m_draggingRect.width);
                  _displayStatusMessage(AP_STRING_ID_ColumnGapStatus, tick, dgrid);

            }
            m_bBeforeFirstMotion = false;
            return;

      case DW_LEFTINDENT:
            {
                  // we are dragging the left-indent box **without** the
                  // first-line-indent.  this keeps the same absolute
                  // location for the first-line, but means that we need
                  // to update it (since it is stored in relative to the
                  // paragraph in the document).
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  }
                  UT_sint32 xAbsLeft, xrel;
                  UT_sint32 xAbsRight;
                  UT_sint32 oldDraggingCenter = m_draggingCenter;
                  xxx_UT_DEBUGMSG(("DW_LEFTINDENT (motion), m_draggingCenter (1) %d\n", m_draggingCenter));

                  if(bRTL)
                  {
                        xAbsRight = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn) + m_infoCache.u.c.m_xColumnWidth;
                        xrel = xAbsRight - static_cast<UT_sint32>(x);
                  }
                  else
                  {
                        xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
                        xrel = static_cast<UT_sint32>(x) - xAbsLeft;
                  }

                  UT_sint32 xgrid = tick.snapPixelToGrid(xrel);
                  double dgrid = tick.scalePixelDistanceToUnits(xrel);
                  UT_DEBUGMSG(("SettingLeftIndent: %s\n",pView->getGraphics()->invertDimension(tick.dimType,dgrid)));
                  UT_Rect oldDraggingRect = m_draggingRect;

                  UT_sint32 iRightPos;

                  if(bRTL)
                  {
                        m_draggingCenter = xAbsRight - xgrid;
                        iRightPos = xAbsRight - m_infoCache.u.c.m_xColumnWidth + m_infoCache.m_xrLeftIndent;
                  }
                  else
                  {
                        m_draggingCenter = xAbsLeft + xgrid;
                  iRightPos = m_infoCache.u.c.m_xColumnWidth + xAbsLeft - m_infoCache.m_xrRightIndent;
                  }


                  xxx_UT_DEBUGMSG(("DW_LEFTINDENT (motion) (2): m_draggingCenter %d, iRightPos %d, m_minColumnWidth %d\n",m_draggingCenter,iRightPos,m_minColumnWidth));
                  if(bRTL)
                  {
                  if(m_draggingCenter - iRightPos < m_minColumnWidth)
                              m_draggingCenter = iRightPos + m_minColumnWidth;
            }
                  else
                  {

                        if(iRightPos - m_draggingCenter < m_minColumnWidth)
                  m_draggingCenter = iRightPos - m_minColumnWidth;
                  }


                  xxx_UT_DEBUGMSG(("DW_LEFTINDENT (motion) (3): m_draggingCenter %d, iRightPos %d, m_minColumnWidth %d\n",m_draggingCenter,iRightPos,m_minColumnWidth));

                  _getParagraphMarkerRects(&m_infoCache,m_draggingCenter,0,0,&m_draggingRect,NULL,NULL);
                  if (!m_bBeforeFirstMotion && (m_draggingCenter != oldDraggingCenter))
                        draw(&oldDraggingRect,&m_infoCache);
                  _drawParagraphProperties(NULL,&m_infoCache,false);
                  _xorGuide();

                double dxrel;
                UT_sint32 xdelta;

                  if(bRTL)
                  {
                        dxrel  = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter);
                        xdelta = (xAbsRight - m_draggingCenter) - m_infoCache.m_xrRightIndent;
                  }
                  else
                  {
                        dxrel  = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);
                        xdelta = (m_draggingCenter-xAbsLeft) - m_infoCache.m_xrLeftIndent;
                  }

                  double dxrel2 = tick.scalePixelDistanceToUnits(m_infoCache.m_xrFirstLineIndent - xdelta);

                  if(bRTL)
                        _displayStatusMessage(AP_STRING_ID_RightIndentStatus, tick, dxrel, dxrel2);
                  else
                        _displayStatusMessage(AP_STRING_ID_LeftIndentTextIndentStatus, tick, dxrel, dxrel2);

            }
            m_bBeforeFirstMotion = false;
            return;

      case DW_LEFTINDENTWITHFIRST:
            {
                  // we are dragging the left-indent box with the
                  // first-line-indent in sync -- this keeps a constant
                  // first-line-indent (since it is stored in relative
                  // terms.
                  if(m_pG)
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);

                  UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
                  UT_sint32 xrel, xgrid, xgridTagAlong;

            UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;

            if(bRTL)
            {
                        xrel = xAbsRight - static_cast<UT_sint32>(x);
                        xgrid = tick.snapPixelToGrid(xrel);
                xgridTagAlong = xgrid + m_infoCache.m_xrFirstLineIndent;
            }
            else
                  {
                        xrel = static_cast<UT_sint32>(x) - xAbsLeft;
                        xgrid = tick.snapPixelToGrid(xrel);
                        xgridTagAlong = xgrid + m_infoCache.m_xrFirstLineIndent;
                  }


                  double dgrid = tick.scalePixelDistanceToUnits(xrel);
                  UT_DEBUGMSG(("SettingLeftIndent: %s\n",pView->getGraphics()->invertDimension(tick.dimType,dgrid)));
                  UT_sint32 oldDraggingCenter = m_draggingCenter;
                  UT_sint32 oldDragging2Center = m_dragging2Center;
                  UT_Rect oldDraggingRect = m_draggingRect;
                  UT_Rect oldDragging2Rect = m_dragging2Rect;

                  UT_sint32 iRightIndentPos;
            UT_sint32 iFirstIndentShift = UT_MAX(0,m_infoCache.m_xrFirstLineIndent);

                  if(bRTL)
                  {
                        m_draggingCenter  = xAbsRight - xgrid;
                        m_dragging2Center = xAbsRight - xgridTagAlong;
                  iRightIndentPos = xAbsRight - m_infoCache.u.c.m_xColumnWidth + m_infoCache.m_xrLeftIndent + iFirstIndentShift;
                  }
                  else
                  {
                        m_draggingCenter  = xAbsLeft + xgrid;
                        m_dragging2Center = xAbsLeft + xgridTagAlong;
                  iRightIndentPos = xAbsLeft + m_infoCache.u.c.m_xColumnWidth - m_infoCache.m_xrRightIndent - iFirstIndentShift;
                  }


                  // Prevent the first-line indent from being dragged off the page
                  if(bRTL)
                  {
                        if (m_dragging2Center > xAbsRight)
                        {
                              m_dragging2Center = oldDragging2Center;
                              m_draggingCenter = oldDraggingCenter;
                              return;
                        }

                  }
                  else
                  {

                        if (m_dragging2Center < xFixed + static_cast<UT_sint32>(m_infoCache.m_xPageViewMargin))
                        {
                              m_dragging2Center = oldDragging2Center;
                              m_draggingCenter = oldDraggingCenter;
                              return;
                        }
                  }


                  xxx_UT_DEBUGMSG(("m_draggingCenter %d, iRightIndentPos %d, m_minColumnWidth %d\n",m_draggingCenter,iRightIndentPos,m_minColumnWidth));

                  if(bRTL)
                  {
                  if(m_draggingCenter - iRightIndentPos < m_minColumnWidth)
                  {
                        m_draggingCenter = iRightIndentPos + m_minColumnWidth;
                  m_dragging2Center = m_draggingCenter - xgridTagAlong + xgrid;
                  }
                  }
                  else
                  {
                        if(iRightIndentPos - m_draggingCenter < m_minColumnWidth)
                        {
                        m_draggingCenter = iRightIndentPos - m_minColumnWidth;
                  m_dragging2Center = m_draggingCenter + xgridTagAlong - xgrid;
                        }
                  }

                  _getParagraphMarkerRects(&m_infoCache,
                                                       m_draggingCenter,0,m_dragging2Center,
                                                       &m_draggingRect,NULL,&m_dragging2Rect);
                  if (!m_bBeforeFirstMotion && (m_draggingCenter != oldDraggingCenter))
                  {
                        draw(&oldDraggingRect,&m_infoCache);
                        draw(&oldDragging2Rect,&m_infoCache);
                  }
                  _drawParagraphProperties(NULL,&m_infoCache,false);
                  _xorGuide();

                  double dxrel;

                  if(bRTL)
                        dxrel = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter);
                  else
                        dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);

                  _displayStatusMessage(AP_STRING_ID_LeftIndentStatus, tick, dxrel);
            }
            m_bBeforeFirstMotion = false;
            return;

      case DW_RIGHTINDENT:
            {
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  }
                  UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
                  UT_sint32 xAbsRight2 = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
                  UT_sint32 xrel;
                  if(bRTL)
                  {
                        xrel = static_cast<UT_sint32>(x) - xAbsLeft;
                  }
                  else
                  {

                        xrel = xAbsRight2 - static_cast<UT_sint32>(x);
                  }

                  UT_sint32 xgrid = tick.snapPixelToGrid(xrel);
                  double dgrid = tick.scalePixelDistanceToUnits(xrel);
                  UT_DEBUGMSG(("SettingRightIndent: %s\n",pView->getGraphics()->invertDimension(tick.dimType,dgrid)));
                  UT_sint32 oldDraggingCenter = m_draggingCenter;
                  UT_Rect oldDraggingRect = m_draggingRect;
                  UT_sint32 iLeftIndentPos;

                  if(bRTL)
                  {
                        m_draggingCenter = xAbsLeft + xgrid;
                        iLeftIndentPos = xAbsRight2 - UT_MAX(m_infoCache.m_xrRightIndent,m_infoCache.m_xrRightIndent);
                  }
                  else
                  {
                        m_draggingCenter = xAbsRight2 - xgrid;
                        iLeftIndentPos = xAbsLeft + UT_MAX(m_infoCache.m_xrLeftIndent,m_infoCache.m_xrLeftIndent + m_infoCache.m_xrFirstLineIndent);
                  }

                  UT_DEBUGMSG(("DW_RIGHTINDENT (motion) m_draggingCenter %d, iLeftIndentPos %d, m_minColumnWidth %d\n",m_draggingCenter,iLeftIndentPos,m_minColumnWidth));
                  if(bRTL)
                  {
                        if(static_cast<UT_sint32>(iLeftIndentPos) - static_cast<UT_sint32>(m_draggingCenter) < static_cast<UT_sint32>(m_minColumnWidth))
                              m_draggingCenter = iLeftIndentPos - m_minColumnWidth;
            }
                  else
                  {

                  if(m_draggingCenter - iLeftIndentPos < m_minColumnWidth)
                      m_draggingCenter = iLeftIndentPos + m_minColumnWidth;
                  }

                  UT_DEBUGMSG(("DW_RIGHTINDENT (motion) (2) m_draggingCenter %d, iLeftIndentPos %d, m_minColumnWidth %d\n",m_draggingCenter,iLeftIndentPos,m_minColumnWidth));

                  _getParagraphMarkerRects(&m_infoCache,0,m_draggingCenter,0,NULL,&m_draggingRect,NULL);
                  if (!m_bBeforeFirstMotion && (m_draggingCenter != oldDraggingCenter))
                        draw(&oldDraggingRect,&m_infoCache);
                  _drawParagraphProperties(NULL,&m_infoCache,false);
                  _xorGuide();

                  double dxrel;

                  if(bRTL)
                        dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft);
                  else
                        dxrel = tick.scalePixelDistanceToUnits(xAbsRight2 - m_draggingCenter);

                  if(bRTL)
                        _displayStatusMessage(AP_STRING_ID_LeftIndentStatus, tick, dxrel);
                  else
                        _displayStatusMessage(AP_STRING_ID_RightIndentStatus, tick, dxrel);
            }
            m_bBeforeFirstMotion = false;
            return;

      case DW_FIRSTLINEINDENT:
            {
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  }
                  UT_sint32 xAbsLeft = _getFirstPixelInColumn(&m_infoCache,m_infoCache.m_iCurrentColumn);
                  UT_sint32 xrel;
            UT_sint32 xrel2;

                  UT_sint32 xAbsRight = xAbsLeft + m_infoCache.u.c.m_xColumnWidth;
                  if(bRTL)
                  {
                        xrel = xAbsRight - static_cast<UT_sint32>(x);
                        xrel2 = xrel - m_infoCache.m_xrRightIndent;
                  }
                  else
                  {
                        // first-line-indent is relative to the left-indent
                        // not the left edge of the column.
                        xrel = static_cast<UT_sint32>(x) - xAbsLeft;
                        xrel2 = xrel - m_infoCache.m_xrLeftIndent;
                  }

                  UT_sint32 xgrid = tick.snapPixelToGrid(xrel2);
//                double dgrid = tick.scalePixelDistanceToUnits(xrel2);
                  xxx_UT_DEBUGMSG(("SettingFirstLineIndent: %s\n",pView->getGraphics()->invertDimension(tick.dimType,dgrid)));
                  UT_sint32 oldDraggingCenter = m_draggingCenter;
                  UT_Rect oldDraggingRect = m_draggingRect;

            UT_sint32 iRightIndentPos;

                  if(bRTL)
                  {
                        m_draggingCenter = xAbsRight - m_infoCache.m_xrRightIndent - xgrid;
                        iRightIndentPos = xAbsRight - m_infoCache.u.c.m_xColumnWidth + m_infoCache.m_xrLeftIndent;
                  }
                  else
                  {
                        m_draggingCenter = xAbsLeft + m_infoCache.m_xrLeftIndent + xgrid;
                        iRightIndentPos = xAbsLeft + m_infoCache.u.c.m_xColumnWidth - m_infoCache.m_xrRightIndent;
            }

                  xxx_UT_DEBUGMSG(("m_draggingCenter %d, iRightIndentPos %d, m_minColumnWidth %d\n",m_draggingCenter,iRightIndentPos,m_minColumnWidth));
                  if(bRTL)
                  {
                  if(m_draggingCenter - iRightIndentPos < m_minColumnWidth)
                              m_draggingCenter = iRightIndentPos + m_minColumnWidth;
            }
                  else
                  {

                        if(iRightIndentPos - m_draggingCenter < m_minColumnWidth)
                  m_draggingCenter = iRightIndentPos - m_minColumnWidth;
                  }

                  _getParagraphMarkerRects(&m_infoCache,0,0,m_draggingCenter,NULL,NULL,&m_draggingRect);
                  if (!m_bBeforeFirstMotion && (m_draggingCenter != oldDraggingCenter))
                        draw(&oldDraggingRect,&m_infoCache);
                  _drawParagraphProperties(NULL,&m_infoCache,false);
                  xxx_UT_DEBUGMSG(("FirstLineIndent: r [%ld %ld %ld %ld]]n",
                                     m_draggingRect.left,m_draggingRect.top,m_draggingRect.width,m_draggingRect.height));
                  _xorGuide();

                  double dxrel;

                  if(bRTL)
                        dxrel = tick.scalePixelDistanceToUnits(xAbsRight - m_draggingCenter - m_infoCache.m_xrRightIndent);
                  else
                        dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xAbsLeft - m_infoCache.m_xrLeftIndent);

                  _displayStatusMessage(AP_STRING_ID_FirstLineIndentStatus, tick, dxrel);
            }
            m_bBeforeFirstMotion = false;
            return;

      case DW_TABSTOP:
            {
                  if(m_pG)
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  if (x < xStartPixel - m_xScrollOffset + m_infoCache.u.c.m_xaLeftMargin)
                        x = xStartPixel - m_xScrollOffset + m_infoCache.u.c.m_xaLeftMargin;
                  else if (x > xAbsRight - m_infoCache.u.c.m_xaRightMargin)
                        x = xAbsRight - m_infoCache.u.c.m_xaRightMargin;

                  UT_sint32 xrel = static_cast<UT_sint32>(x) - xStartPixel - 1; // TODO why is the -1 necessary? w/o it problems arise.
                  UT_sint32 xgrid = tick.snapPixelToGrid(xrel);
                  UT_sint32 oldDraggingCenter = m_draggingCenter;
                  UT_Rect oldDraggingRect = m_draggingRect;
                  m_draggingCenter = xStartPixel + xgrid;
                  _getTabStopRect(&m_infoCache,m_draggingCenter,&m_draggingRect);
                  if (!m_bBeforeFirstMotion && (m_draggingCenter != oldDraggingCenter))
                        draw(&oldDraggingRect,&m_infoCache);
                  _drawTabProperties(NULL,&m_infoCache,false);
                  _xorGuide();

                  double dxrel = tick.scalePixelDistanceToUnits(m_draggingCenter - xStartPixel);
                  _displayStatusMessage(AP_STRING_ID_TabStopStatus, tick, dxrel);
            }
            m_bBeforeFirstMotion = false;
            return;

      case DW_CELLMARK:
            {
                  if(m_pG)
                  {
                        m_pG->setCursor(GR_Graphics::GR_CURSOR_GRAB);
                  }
                  if (x < xStartPixel - m_xScrollOffset)
                  {
                        x = xStartPixel - m_xScrollOffset;
                  }
                  else if (x > xAbsRight)
                  {
                        x = xAbsRight;
                  }
                  UT_sint32 xrel = static_cast<UT_sint32>(x) - xStartPixel - 1; // TODO why is the -1 necessary? w/o it problems arise.
                  UT_DEBUGMSG(("MovingCellMark: %s\n",pView->getGraphics()->invertDimension(tick.dimType,tick.scalePixelDistanceToUnits(xrel))));
                  UT_sint32 oldDraggingCenter = m_draggingCenter;
                  UT_Rect oldDraggingRect = m_draggingRect;
                  m_draggingCenter = xStartPixel + xrel;
                  
                  // disalow that a cell marker is dragged over other cell markers
                  if (m_draggingCenter < m_iMinCellPos)
                              m_draggingCenter = m_iMinCellPos;
                  if (m_draggingCenter > m_iMaxCellPos)
                              m_draggingCenter = m_iMaxCellPos;
//
// set the dragging cell marker rectangle here
//
                  UT_sint32 ileft = pView->getGraphics()->tlu(s_iFixedHeight)/4;
                  m_draggingRect.set(m_draggingCenter-ileft,ileft,pView->getGraphics()->tlu(s_iFixedHeight)/2,pView->getGraphics()->tlu(s_iFixedHeight)/2); // left/top/width/height

                  if (!m_bBeforeFirstMotion && (m_draggingCenter != oldDraggingCenter))
                        draw(&oldDraggingRect,&m_infoCache);
                  _drawCellProperties(NULL,&m_infoCache,false);
                  _xorGuide();
            }
            m_bBeforeFirstMotion = false;
            return;

      default:
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            return;
      }
}

/*****************************************************************/

double AP_TopRuler::_getUnitsFromRulerLeft(UT_sint32 xColRel, ap_RulerTicks & tick)
{
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView == NULL)
      {
            return 0;
      }
      UT_sint32 xFixed = static_cast<UT_sint32>(pView->getGraphics()->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
      if(pView->getViewMode() != VIEW_PRINT)
      {
            xFixed = 0;
      }

      UT_sint32 xAbsLeft = xFixed + m_infoCache.m_xPageViewMargin - m_xScrollOffset;
      return tick.scalePixelDistanceToUnits(xColRel - xAbsLeft) * tick.tickUnitScale /  tick.tickUnit * tick.dBasicUnit;
}

UT_sint32 AP_TopRuler::_getFirstPixelInColumn(AP_TopRulerInfo * pInfo, UT_uint32 kCol)
{
      // return absolute pixel value for the first pixel in this column.
      FV_View * pView = static_cast<FV_View *>(m_pView);
      if(pView == NULL)
            return 0;

      UT_sint32 xFixed = static_cast<UT_sint32>(pView->getGraphics()->tlu(UT_MAX(m_iLeftRulerWidth,s_iFixedWidth)));
      UT_sint32 xOrigin = pInfo->u.c.m_xaLeftMargin
            + kCol * (pInfo->u.c.m_xColumnWidth + pInfo->u.c.m_xColumnGap);
      UT_sint32 ixMargin = pInfo->m_xPageViewMargin;
      if(pView->getViewMode() != VIEW_PRINT)
      {
            ixMargin = 0;
            xFixed = 0;
      }
      UT_sint32 xAbsLeft = xFixed + ixMargin + xOrigin - m_xScrollOffset;

      bool bRTL;
      XAP_App::getApp()->getPrefsValueBool(static_cast<const XML_Char *>(AP_PREF_KEY_DefaultDirectionRtl), &bRTL);

      if(bRTL)
      {
            UT_sint32 xAbsRight = xFixed + pInfo->m_xPageViewMargin + pInfo->u.c.m_xaLeftMargin
                        + pInfo->m_iNumColumns * (pInfo->u.c.m_xColumnWidth + pInfo->u.c.m_xColumnGap)
                        /*- pInfo->u.c.m_xColumnGap*/ - m_xScrollOffset
                        - (kCol + 1) * (pInfo->u.c.m_xColumnWidth + pInfo->u.c.m_xColumnGap);
            return xAbsRight;
      }
      else

      return xAbsLeft;
}

void AP_TopRuler::_ignoreEvent(bool bDone)
{
      // user released the mouse off of the ruler.  we need to treat
      // this as a cancel.  so we need to put everything back the
      // way it was on the ruler.

      // clear the guide line

      _xorGuide(true);
      FV_View *pView = static_cast<FV_View *>(m_pView);
      // Clear messages from status bar.

      AP_FrameData * pFrameData = static_cast<AP_FrameData *>(m_pFrame->getFrameData());
      if(m_pFrame->getFrameMode() == XAP_NormalFrame)
            pFrameData->m_pStatusBar->setStatusMessage("");

      // erase the widget that we are dragging.   remember what we
      // are dragging, clear it, and then restore it at the bottom.

      DraggingWhat dw = m_draggingWhat;
      m_draggingWhat = DW_NOTHING;

      if (!m_bBeforeFirstMotion || (bDone && (dw==DW_TABSTOP)))
      {
            // erase the widget we are dragging by invalidating
            // the region that's under it and letting it repaint.
            // to avoid flashing, we only do this once.
            draw(&m_draggingRect, &m_infoCache);
            if (dw == DW_LEFTINDENTWITHFIRST)
                  draw(&m_dragging2Rect, &m_infoCache);
            m_bBeforeFirstMotion = true;
      }

      // redraw the widget we are dragging at its original location

      switch (dw)
      {
      case DW_TABTOGGLE:
            break;
      case DW_LEFTMARGIN:
      case DW_RIGHTMARGIN:
            if(m_pG)
                  draw(NULL, &m_infoCache);
            break;

      case DW_COLUMNGAP:
      case DW_COLUMNGAPLEFTSIDE:
            if(m_pG)
                  _drawColumnProperties(NULL,&m_infoCache,0);
            break;

      case DW_LEFTINDENT:
      case DW_RIGHTINDENT:
      case DW_FIRSTLINEINDENT:
      case DW_LEFTINDENTWITHFIRST:
            if(m_pG)
                  _drawParagraphProperties(NULL,&m_infoCache,true);
            break;

      case DW_TABSTOP:
            // tabs are different.  instead of restoring the control when
            // dragged off, we delete it.
            //
            // during the drag, this is visually indicated by leaving the
            // ghost in place (since the delete hasn't happened yet).
            // the actual delete is done on mouseup.
            if (bDone)
            {
                  // delete the tab
                  m_draggingWhat = dw;
                  ap_RulerTicks tick(pView->getGraphics(),m_dim);
                  _setTabStops(tick, tr_TABINDEX_NONE, FL_LEADER_NONE, true);
            }
            break;

      case DW_CELLMARK:
            if(m_pG)
            {
                  _drawCellProperties(NULL,&m_infoCache,true);
            }
            break;
            
      case DW_NOTHING:
      default:
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            break;
      }

      m_draggingWhat = dw;
      return;
}

static void _computeEffects(bool bFilled,
                                          GR_Graphics::GR_Color3D & clr3dBorder,
                                          GR_Graphics::GR_Color3D & clr3dBevel)
{
      if (bFilled)
      {
            clr3dBorder = GR_Graphics::CLR3D_Foreground;
            clr3dBevel =  GR_Graphics::CLR3D_BevelUp;
      }
      else
      {
            clr3dBorder = GR_Graphics::CLR3D_BevelDown;
            clr3dBevel  = GR_Graphics::CLR3D_Background;
      }
}

void AP_TopRuler::_drawLeftIndentMarker(UT_Rect & rect, bool bFilled)
{
      GR_Graphics::GR_Color3D clr3dBorder, clr3dBevel;
      _computeEffects(bFilled,clr3dBorder,clr3dBevel);

      UT_sint32 l = rect.left;
      UT_sint32 t = rect.top;

      //FV_View * pView = (static_cast<FV_View *>(m_pView));
      fl_BlockLayout *pBlock = (static_cast<FV_View *>(m_pView))->getCurrentBlock();
      
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);

      GR_Painter painter(m_pG);

      if(bRTL)
      {
            // fill in the body

            m_pG->setColor3D(GR_Graphics::CLR3D_Background);
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(7),  l+m_pG->tlu(10), t+m_pG->tlu(7) );
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(6),  l+m_pG->tlu(10), t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(5),  l+m_pG->tlu(10), t+m_pG->tlu(5) );
            painter.drawLine( l+m_pG->tlu(3),   t+m_pG->tlu(4),  l+m_pG->tlu(9),  t+m_pG->tlu(4) );
            painter.drawLine( l+m_pG->tlu(4),   t+m_pG->tlu(3),  l+m_pG->tlu(8), t+m_pG->tlu(3) );
            painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(2),  l+m_pG->tlu(7), t+m_pG->tlu(2) );

            // draw 3d highlights

            m_pG->setColor3D(clr3dBevel);
            painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(1),  l,    t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(5),  l+m_pG->tlu(1),  t+m_pG->tlu(7) );

            // draw border

            m_pG->setColor3D(clr3dBorder);
            painter.drawLine( l+m_pG->tlu(5),   t,    l+m_pG->tlu(11), t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(5),   t,    l- m_pG->tlu(1), t+m_pG->tlu(6) );
            
            painter.drawLine( l,     t+m_pG->tlu(5),  l,    t+m_pG->tlu(8) );
            painter.drawLine( l+m_pG->tlu(10),  t+m_pG->tlu(5),  l+m_pG->tlu(10), t+m_pG->tlu(8) );
            painter.drawLine( l,     t+m_pG->tlu(8),  l+m_pG->tlu(10), t+m_pG->tlu(8) );

      }
      else
      {
            // fill in the body

            m_pG->setColor3D(GR_Graphics::CLR3D_Background);
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(13), l+m_pG->tlu(10), t+m_pG->tlu(13));
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(12), l+m_pG->tlu(10), t+m_pG->tlu(12));
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(11), l+m_pG->tlu(10), t+m_pG->tlu(11));
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(10), l+m_pG->tlu(10), t+m_pG->tlu(10));
            painter.drawLine( l+m_pG->tlu(9),   t+m_pG->tlu(9),  l+m_pG->tlu(10), t+m_pG->tlu(9) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(7),  l+m_pG->tlu(10), t+m_pG->tlu(7) );
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(6),  l+m_pG->tlu(10), t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(5),  l+m_pG->tlu(10), t+m_pG->tlu(5) );
            painter.drawLine( l+m_pG->tlu(3),   t+m_pG->tlu(4),  l+m_pG->tlu(9),  t+m_pG->tlu(4) );
            painter.drawLine( l+m_pG->tlu(4),   t+m_pG->tlu(3),  l+m_pG->tlu(8), t+m_pG->tlu(3) );
            painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(2),  l+m_pG->tlu(7), t+m_pG->tlu(2) );

            // draw 3d highlights

            m_pG->setColor3D(clr3dBevel);
            painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(1),  l,    t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(5),  l+m_pG->tlu(1),  t+m_pG->tlu(7) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(9),  l+m_pG->tlu(9),  t+m_pG->tlu(9) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(9),  l+m_pG->tlu(1),  t+m_pG->tlu(13));

            // draw border

            m_pG->setColor3D(clr3dBorder);
            painter.drawLine( l+m_pG->tlu(5),   t,    l+m_pG->tlu(11), t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(5),   t,    l- m_pG->tlu(1), t+m_pG->tlu(6) );
            
            painter.drawLine( l,     t+m_pG->tlu(5),  l,    t+m_pG->tlu(14));
            painter.drawLine( l+m_pG->tlu(10),  t+m_pG->tlu(5),  l+m_pG->tlu(10), t+m_pG->tlu(14));
            painter.drawLine( l,     t+m_pG->tlu(14), l+m_pG->tlu(10), t+m_pG->tlu(14));
            painter.drawLine( l,     t+m_pG->tlu(8),  l+m_pG->tlu(10), t+m_pG->tlu(8) );
    }
}

void AP_TopRuler::_drawRightIndentMarker(UT_Rect & rect, bool bFilled)
{
      GR_Graphics::GR_Color3D clr3dBorder, clr3dBevel;
      _computeEffects(bFilled,clr3dBorder,clr3dBevel);

      UT_sint32 l = rect.left;
      UT_sint32 t = rect.top;

      //FV_View * pView = (static_cast<FV_View *>(m_pView));
      fl_BlockLayout *pBlock = (static_cast<FV_View *>(m_pView))->getCurrentBlock();
      
      bool bRTL = false;

      if(pBlock)
            bRTL = (pBlock->getDominantDirection() == UT_BIDI_RTL);

      GR_Painter painter(m_pG);

      if(bRTL)
      {
            // fill in the body

            m_pG->setColor3D(GR_Graphics::CLR3D_Background);
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(13), l+m_pG->tlu(10), t+m_pG->tlu(13));
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(12), l+m_pG->tlu(10), t+m_pG->tlu(12));
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(11), l+m_pG->tlu(10), t+m_pG->tlu(11));
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(10), l+m_pG->tlu(10), t+m_pG->tlu(10));
            painter.drawLine( l+m_pG->tlu(9),   t+m_pG->tlu(9),  l+m_pG->tlu(10), t+m_pG->tlu(9) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(7),  l+m_pG->tlu(10), t+m_pG->tlu(7) );
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(6),  l+m_pG->tlu(10), t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(5),  l+m_pG->tlu(10), t+m_pG->tlu(5) );
            painter.drawLine( l+m_pG->tlu(3),   t+m_pG->tlu(4),  l+m_pG->tlu(9),  t+m_pG->tlu(4) );
            painter.drawLine( l+m_pG->tlu(4),   t+m_pG->tlu(3),  l+m_pG->tlu(8), t+m_pG->tlu(3) );
            painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(2),  l+m_pG->tlu(7), t+m_pG->tlu(2) );

            // draw 3d highlights

            m_pG->setColor3D(clr3dBevel);
            painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(1),  l,    t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(5),  l+m_pG->tlu(1),  t+m_pG->tlu(7) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(9),  l+m_pG->tlu(9),  t+m_pG->tlu(9) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(9),  l+m_pG->tlu(1),  t+m_pG->tlu(13));

            // draw border

            m_pG->setColor3D(clr3dBorder);
            painter.drawLine( l+m_pG->tlu(5),   t,    l+m_pG->tlu(11), t+m_pG->tlu(6));
            painter.drawLine( l+m_pG->tlu(5),   t,    l- m_pG->tlu(1), t+m_pG->tlu(6));
            
            painter.drawLine( l,     t+m_pG->tlu(5),  l,    t+m_pG->tlu(14));
            painter.drawLine( l+m_pG->tlu(10),  t+m_pG->tlu(5),  l+m_pG->tlu(10), t+m_pG->tlu(14));
            painter.drawLine( l,     t+m_pG->tlu(14), l+m_pG->tlu(10), t+m_pG->tlu(14));
            painter.drawLine( l,     t+m_pG->tlu(8),  l+m_pG->tlu(10), t+m_pG->tlu(8) );
      }
      else
      {
            // fill in the body

            m_pG->setColor3D(GR_Graphics::CLR3D_Background);
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(7),  l+m_pG->tlu(10), t+m_pG->tlu(7) );
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(6),  l+m_pG->tlu(10), t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(5),  l+m_pG->tlu(10), t+m_pG->tlu(5) );
            painter.drawLine( l+m_pG->tlu(3),   t+m_pG->tlu(4),  l+m_pG->tlu(9),  t+m_pG->tlu(4) );
            painter.drawLine( l+m_pG->tlu(4),   t+m_pG->tlu(3),  l+m_pG->tlu(8), t+m_pG->tlu(3) );
            painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(2),  l+m_pG->tlu(7), t+m_pG->tlu(2) );

            // draw 3d highlights

            m_pG->setColor3D(clr3dBevel);
            painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(1),  l,    t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(5),  l+m_pG->tlu(1),  t+m_pG->tlu(7) );

            // draw border

            m_pG->setColor3D(clr3dBorder);
            painter.drawLine( l+m_pG->tlu(5),   t,    l+m_pG->tlu(11), t+m_pG->tlu(6) );
            painter.drawLine( l+m_pG->tlu(5),   t,    l- m_pG->tlu(1), t+m_pG->tlu(6) );
            
            painter.drawLine( l,     t+m_pG->tlu(5),  l,    t+m_pG->tlu(8) );
            painter.drawLine( l+m_pG->tlu(10),  t+m_pG->tlu(5),  l+m_pG->tlu(10), t+m_pG->tlu(8) );
            painter.drawLine( l,     t+m_pG->tlu(8),  l+m_pG->tlu(10), t+m_pG->tlu(8) );
    }
}

void AP_TopRuler::_drawFirstLineIndentMarker(UT_Rect & rect, bool bFilled)
{
      GR_Graphics::GR_Color3D clr3dBorder, clr3dBevel;
      _computeEffects(bFilled,clr3dBorder,clr3dBevel);

      UT_sint32 l = rect.left;
      UT_sint32 t = rect.top;

      GR_Painter painter(m_pG);

      // fill in the body

      m_pG->setColor3D(GR_Graphics::CLR3D_Background);
      painter.drawLine( l+m_pG->tlu(9),   t+m_pG->tlu(1),  l+m_pG->tlu(10), t+m_pG->tlu(1) );
      painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(2),  l+m_pG->tlu(10), t+m_pG->tlu(2) );
      painter.drawLine( l+m_pG->tlu(2),   t+m_pG->tlu(3),  l+m_pG->tlu(10), t+m_pG->tlu(3) );
      painter.drawLine( l+m_pG->tlu(3),   t+m_pG->tlu(4),  l+m_pG->tlu(9),  t+m_pG->tlu(4) );
      painter.drawLine( l+m_pG->tlu(4),   t+m_pG->tlu(5),  l+m_pG->tlu(8),  t+m_pG->tlu(5) );
      painter.drawLine( l+m_pG->tlu(5),   t+m_pG->tlu(6),  l+m_pG->tlu(7),  t+m_pG->tlu(6) );

      // draw 3d highlights

      m_pG->setColor3D(clr3dBevel);
      painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(1),  l+m_pG->tlu(9),  t+m_pG->tlu(1) );
      painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(2),  l+m_pG->tlu(1),  t+m_pG->tlu(4) );
      painter.drawLine( l+m_pG->tlu(1),   t+m_pG->tlu(3),  l+m_pG->tlu(6),  t+m_pG->tlu(8) );

      // draw border

      m_pG->setColor3D(clr3dBorder);
      painter.drawLine( l+m_pG->tlu(10),  t+m_pG->tlu(3),  l+m_pG->tlu(4),  t+m_pG->tlu(9));
      painter.drawLine( l,     t+m_pG->tlu(3),  l+m_pG->tlu(6),  t+m_pG->tlu(9));
      
      painter.drawLine( l,     t,    l,    t+m_pG->tlu(3));
      painter.drawLine( l+m_pG->tlu(10),  t,    l+m_pG->tlu(10), t+m_pG->tlu(3));
      painter.drawLine( l,     t,    l+m_pG->tlu(10), t);

}

void AP_TopRuler::_drawTabToggle(const UT_Rect * pClipRect, bool bErase)
{
      // draw in normal and print layout modes, not online
      if(static_cast<FV_View*>(m_pView)->getViewMode() == VIEW_WEB)
        return;

      UT_Rect rect;
      _getTabToggleRect(&rect);

      GR_Painter painter(m_pG);

      if (!pClipRect || rect.intersectsRect(pClipRect) || bErase)
      {
            UT_sint32 left = rect.left;
            UT_sint32 right = rect.left + rect.width - m_pG->tlu(1);
            UT_sint32 top = rect.top;
            UT_sint32 bot = rect.top + rect.height - m_pG->tlu(1);

            // first draw the frame

            m_pG->setColor3D(GR_Graphics::CLR3D_BevelDown);
            painter.drawLine(left,top,right,top);
            painter.drawLine(left,top,left,bot);
            painter.drawLine(left,bot,right,bot);
            painter.drawLine(right,top,right,bot);
            
            m_pG->setColor3D(GR_Graphics::CLR3D_BevelUp);
            painter.drawLine( left + m_pG->tlu(1), top + m_pG->tlu(1), right - m_pG->tlu(1), top + m_pG->tlu(1));
            painter.drawLine( left + m_pG->tlu(1), top + m_pG->tlu(1), left + m_pG->tlu(1), bot - m_pG->tlu(1));
            painter.drawLine( left, bot + m_pG->tlu(1), right, bot + m_pG->tlu(1));

            // now draw the default tab style

            rect.set(left + m_pG->tlu(4), top + m_pG->tlu(6), m_pG->tlu(10), m_pG->tlu(9));

            // fill first if needed

            if (bErase)
                  painter.fillRect(GR_Graphics::CLR3D_Background, rect);

            if          (m_iDefaultTabType == FL_TAB_LEFT)  rect.left -= m_pG->tlu(2);
            else if (m_iDefaultTabType == FL_TAB_RIGHT)     rect.left += m_pG->tlu(2);

            _drawTabStop(rect, m_iDefaultTabType, true);
      }
}

void AP_TopRuler::_drawTabStop(UT_Rect & rect, eTabType iType, bool bFilled)
{
      GR_Graphics::GR_Color3D clr3d;
      if (bFilled)
            clr3d = GR_Graphics::CLR3D_Foreground;
      else
            clr3d = GR_Graphics::CLR3D_Background;

      UT_sint32 l = rect.left;
      UT_sint32 t = rect.top;
      UT_sint32 r = rect.left + rect.width;

      GR_Painter painter (m_pG);

      // stroke the vertical first
      painter.fillRect(clr3d, l+m_pG->tlu(4),   t,    m_pG->tlu(2),    m_pG->tlu(4));
      if (iType == FL_TAB_DECIMAL)
      {
            // add the dot
            painter.fillRect(clr3d, l+ m_pG->tlu(7),   t+ m_pG->tlu(1),    m_pG->tlu(2),   m_pG->tlu(2));
      }

      // figure out the bottom
      switch (iType)
      {
            case FL_TAB_LEFT:
                  l += m_pG->tlu(4);
                  break;

            case FL_TAB_BAR:
                  l += m_pG->tlu(4);
                  r = l+ m_pG->tlu(2);
                  break;
                  // fall through

            case FL_TAB_RIGHT:
                  r -= m_pG->tlu(4);
                  break;

            case FL_TAB_CENTER:
            case FL_TAB_DECIMAL:
                  l += m_pG->tlu(1);
                  r -= m_pG->tlu(1);
                  break;

            default:
                  UT_ASSERT_HARMLESS(UT_TODO);
                  break;
      }

      painter.fillRect(clr3d, l,     t+ m_pG->tlu(4),  r-l,  m_pG->tlu(2));
}

void AP_TopRuler::_drawColumnGapMarker(UT_Rect & rect)
{
      GR_Graphics::GR_Color3D clr3dBorder, clr3dBevel;
      _computeEffects(true,clr3dBorder,clr3dBevel);

      UT_sint32 l = rect.left;
      UT_sint32 t = rect.top;
      UT_sint32 w = rect.width;
      UT_sint32 w2 = w/2 - m_pG->tlu(1);

      GR_Painter painter(m_pG);

      // fill in the body

      m_pG->setColor3D(GR_Graphics::CLR3D_Background);
      painter.drawLine(l+ m_pG->tlu(2),   t+ m_pG->tlu(1),  l+w- m_pG->tlu(1),   t+ m_pG->tlu(1) );
      painter.drawLine(l+ m_pG->tlu(2),   t+ m_pG->tlu(2),  l+w- m_pG->tlu(1),   t+ m_pG->tlu(2) );
      painter.drawLine(l+ m_pG->tlu(2),   t+ m_pG->tlu(3),  l+w- m_pG->tlu(1),   t+ m_pG->tlu(3) );
      painter.drawLine(l+ m_pG->tlu(2),   t+ m_pG->tlu(4),  l+w- m_pG->tlu(1),   t+ m_pG->tlu(4) );
      painter.drawLine(l+ m_pG->tlu(2),   t+ m_pG->tlu(3),  l+ m_pG->tlu(2),     t+ m_pG->tlu(8) );
      painter.drawLine(l+ m_pG->tlu(3),   t+ m_pG->tlu(3),  l+ m_pG->tlu(3),     t+ m_pG->tlu(7) );
      painter.drawLine(l+ m_pG->tlu(4),   t+ m_pG->tlu(3),  l+ m_pG->tlu(4),     t+ m_pG->tlu(6) );
      painter.drawLine(l+w- m_pG->tlu(2), t+ m_pG->tlu(3),  l+w- m_pG->tlu(2),   t+ m_pG->tlu(9) );
      painter.drawLine(l+w- m_pG->tlu(3), t+ m_pG->tlu(3),  l+w- m_pG->tlu(3),   t+ m_pG->tlu(8) );
      painter.drawLine(l+w- m_pG->tlu(4), t+ m_pG->tlu(3),  l+w- m_pG->tlu(4),   t+ m_pG->tlu(7) );
      painter.drawLine(l+w- m_pG->tlu(5), t+ m_pG->tlu(3),  l+w- m_pG->tlu(5),   t+ m_pG->tlu(6) );

      // draw 3d highlights

      m_pG->setColor3D(clr3dBevel);
      painter.drawLine(l+m_pG->tlu(1),   t+m_pG->tlu(1),  l+w2,    t+m_pG->tlu(1) );
      painter.drawLine(l+w2+m_pG->tlu(1),t+m_pG->tlu(1),  l+w-m_pG->tlu(1),   t+m_pG->tlu(1) );
      painter.drawLine(l+m_pG->tlu(1),   t+m_pG->tlu(1),  l+m_pG->tlu(1),     t+m_pG->tlu(10));
      painter.drawLine(l+w2+m_pG->tlu(1),t+m_pG->tlu(1),  l+w2+m_pG->tlu(1),  t+m_pG->tlu(5) );

      // draw border

      m_pG->setColor3D(clr3dBorder);
      painter.drawLine(l,     t,    l+w,     t   );
      painter.drawLine(l,     t,    l,       t+ m_pG->tlu(11));
      painter.drawLine(l+w- m_pG->tlu(1), t,    l+w- m_pG->tlu(1),   t+ m_pG->tlu(11));
      painter.drawLine(l,     t+ m_pG->tlu(10), l+ m_pG->tlu(5),     t+ m_pG->tlu(5));
      painter.drawLine(l+w- m_pG->tlu(1), t+ m_pG->tlu(10), l+w- m_pG->tlu(6),   t+ m_pG->tlu(5));
      painter.drawLine(l+ m_pG->tlu(5),   t+ m_pG->tlu(5),  l+w- m_pG->tlu(5),   t+ m_pG->tlu(5));
}

/*static*/ void AP_TopRuler::_prefsListener( XAP_App * /*pApp*/, XAP_Prefs *pPrefs, UT_StringPtrMap * /*phChanges*/, void *data )
{
      AP_TopRuler *pTopRuler = static_cast<AP_TopRuler *>(data);
      UT_return_if_fail ( data && pPrefs );

      const XML_Char *pszBuffer;
      pPrefs->getPrefsValue(static_cast<const XML_Char *>(AP_PREF_KEY_RulerUnits), &pszBuffer );

      // or should I just default to inches or something?
      UT_Dimension dim = UT_determineDimension( pszBuffer, DIM_none );
      UT_ASSERT_HARMLESS( dim != DIM_none );

      if ( dim != pTopRuler->getDimension() )
            pTopRuler->setDimension( dim );
}

void AP_TopRuler::setDimension( UT_Dimension newdim )
{
      m_dim = newdim;
      draw( static_cast<const UT_Rect *>(0) );
}

void AP_TopRuler::_displayStatusMessage(XAP_String_Id messageID, const ap_RulerTicks &tick, double dValue)
{
      const XML_Char * pText = m_pG->invertDimension(tick.dimType, dValue);
      UT_String pzMessageFormat;
      m_pFrame->getApp()->getStringSet()->getValue(messageID, XAP_App::getApp()->getDefaultEncoding(),pzMessageFormat);
      UT_String temp(UT_String_sprintf(pzMessageFormat.c_str(), pText));

      AP_FrameData * pFrameData = static_cast<AP_FrameData *>(m_pFrame->getFrameData());
      if(m_pFrame->getFrameMode() == XAP_NormalFrame)
            pFrameData->m_pStatusBar->setStatusMessage(temp.c_str());
}

void AP_TopRuler::_displayStatusMessage(XAP_String_Id messageID, const ap_RulerTicks &tick, double dValue1, double dValue2)
{
      const XML_Char * pText = m_pG->invertDimension(tick.dimType, dValue1);
      char buf1[100];
      strcpy(buf1, pText);
      pText = m_pG->invertDimension(tick.dimType, dValue2);

      UT_String pzMessageFormat;
      m_pFrame->getApp()->getStringSet()->getValue(messageID, XAP_App::getApp()->getDefaultEncoding(), pzMessageFormat);
      UT_String temp(UT_String_sprintf(pzMessageFormat.c_str(), buf1, pText));

      AP_FrameData * pFrameData = static_cast<AP_FrameData *>(m_pFrame->getFrameData());
      if(m_pFrame->getFrameMode() == XAP_NormalFrame)
            pFrameData->m_pStatusBar->setStatusMessage(temp.c_str());
}

void AP_TopRuler::_displayStatusMessage(XAP_String_Id FormatMessageID, UT_sint32 iCol, const char * /*format*/)
{
      UT_String pzMessageFormat;
      m_pFrame->getApp()->getStringSet()->getValue(FormatMessageID, XAP_App::getApp()->getDefaultEncoding(), pzMessageFormat);
      static UT_String sCell;
      UT_String_sprintf(sCell,pzMessageFormat.c_str(),iCol);

      AP_FrameData * pFrameData = static_cast<AP_FrameData *>(m_pFrame->getFrameData());
      if(m_pFrame->getFrameMode() == XAP_NormalFrame)
            pFrameData->m_pStatusBar->setStatusMessage(sCell.c_str());
}


void AP_TopRuler::_displayStatusMessage(XAP_String_Id FormatMessageID)
{
      UT_String pzMessageFormat;
      m_pFrame->getApp()->getStringSet()->getValue(FormatMessageID, XAP_App::getApp()->getDefaultEncoding(),pzMessageFormat);

      AP_FrameData * pFrameData = static_cast<AP_FrameData *>(m_pFrame->getFrameData());
      if(m_pFrame->getFrameMode() == XAP_NormalFrame)
            pFrameData->m_pStatusBar->setStatusMessage(pzMessageFormat.c_str());
}

/* lambda */ void AP_TopRuler::_autoScroll(UT_Worker * pWorker)
{
      // this is a static callback method and does not have a 'this' pointer.
      AP_TopRuler * pRuler = static_cast<AP_TopRuler *>(pWorker->getInstanceData());
      UT_return_if_fail (pRuler);

      pRuler->_xorGuide(true);

      UT_sint32 newXScrollOffset = pRuler->m_xScrollOffset;
      if (pRuler->m_aScrollDirection == 'L')
        newXScrollOffset = pRuler->m_xScrollOffset - pRuler->m_pG->tlu(s_tr_AUTOSCROLL_PIXELS);
      else if (pRuler->m_aScrollDirection == 'R')
        newXScrollOffset = pRuler->m_xScrollOffset + pRuler->m_pG->tlu(s_tr_AUTOSCROLL_PIXELS);
      else
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);

      if (newXScrollOffset >= 0)
                  pRuler->m_pView->sendHorizontalScrollEvent(newXScrollOffset); // YAY it works!!

      // IT'S A TRICK!!!
      UT_sint32 fakeY = pRuler->m_pG->tlu(s_iFixedHeight)/2 + pRuler->m_pG->tlu(s_iFixedHeight)/4 - pRuler->m_pG->tlu(3);
      if (pRuler->m_aScrollDirection == 'L')
            pRuler->mouseMotion(0, 0, fakeY); // it wants to see something < xFixed and 0 is gonna be
      else
            pRuler->mouseMotion(0, static_cast<UT_sint32>(pRuler->getWidth ()) + 1, fakeY); // getWidth ()+1 will be greater than getWidth ()
}


Generated by  Doxygen 1.6.0   Back to index