blob: a9169e1519dd00259eff0248b2becff4c1df0fe0 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
// INCLUDE ---------------------------------------------------------------
#include <sfx2/dispatch.hxx>
#include <vcl/help.hxx>
#include <tools/poly.hxx>
#include <svtools/colorcfg.hxx>
#include "scresid.hxx"
#include "sc.hrc"
#include "tabvwsh.hxx"
#include "hdrcont.hxx"
#include "scmod.hxx" // Optionen
#include "inputopt.hxx" // Optionen
#include "gridmerg.hxx"
#include "document.hxx"
// -----------------------------------------------------------------------
#define SC_DRAG_MIN 2
// passes in paint
// (selection left/right must be first because the continuous lines
// are partly overwritten later)
#define SC_HDRPAINT_SEL_RIGHT 0
#define SC_HDRPAINT_SEL_LEFT 1
#define SC_HDRPAINT_TOP 2
#define SC_HDRPAINT_SEL_TOP 3
#define SC_HDRPAINT_SEL_BOTTOM 4
#define SC_HDRPAINT_BOTTOM 5
#define SC_HDRPAINT_TEXT 6
#define SC_HDRPAINT_COUNT 7
//==================================================================
ScHeaderControl::ScHeaderControl( Window* pParent, SelectionEngine* pSelectionEngine,
SCCOLROW nNewSize, sal_uInt16 nNewFlags ) :
Window ( pParent ),
pSelEngine ( pSelectionEngine ),
nFlags ( nNewFlags ),
bVertical ( (nNewFlags & HDR_VERTICAL) != 0 ),
nSize ( nNewSize ),
nMarkStart ( 0 ),
nMarkEnd ( 0 ),
bMarkRange ( sal_False ),
bDragging ( sal_False ),
bIgnoreMove ( sal_False )
{
// --- RTL --- no default mirroring for this window, the spreadsheet itself
// is also not mirrored
// #107811# mirror the vertical window for correct border drawing
// #106948# table layout depends on sheet format, not UI setting, so the
// borders of the vertical window have to be handled manually, too.
EnableRTL( sal_False );
aNormFont = GetFont();
aNormFont.SetTransparent( sal_True ); //! WEIGHT_NORMAL hart setzen ???
aBoldFont = aNormFont;
aBoldFont.SetWeight( WEIGHT_BOLD );
SetFont(aBoldFont);
bBoldSet = sal_True;
Size aSize = LogicToPixel( Size(
GetTextWidth( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("8888")) ),
GetTextHeight() ) );
aSize.Width() += 4; // Platz fuer hervorgehobene Umrandung
aSize.Height() += 3;
SetSizePixel( aSize );
nWidth = nSmallWidth = aSize.Width();
nBigWidth = LogicToPixel( Size( GetTextWidth(
String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("8888888")) ), 0 ) ).Width() + 5;
SetBackground(); // sonst Probleme auf OS/2 !?!?!
}
void ScHeaderControl::SetWidth( long nNew )
{
DBG_ASSERT( bVertical, "SetDigits nur fuer Zeilenkoepfe erlaubt" );
if ( nNew != nWidth )
{
Size aSize( nNew, GetSizePixel().Height() ); // Hoehe nicht aendern
SetSizePixel( aSize );
nWidth = nNew;
Invalidate(); // neu zentrieren
}
}
ScHeaderControl::~ScHeaderControl()
{
}
void ScHeaderControl::DoPaint( SCCOLROW nStart, SCCOLROW nEnd )
{
sal_Bool bLayoutRTL = IsLayoutRTL();
long nLayoutSign = bLayoutRTL ? -1 : 1;
Rectangle aRect( Point(0,0), GetOutputSizePixel() );
if ( bVertical )
{
aRect.Top() = GetScrPos( nStart )-nLayoutSign; // extra pixel for line at top of selection
aRect.Bottom() = GetScrPos( nEnd+1 )-nLayoutSign;
}
else
{
aRect.Left() = GetScrPos( nStart )-nLayoutSign; // extra pixel for line left of selection
aRect.Right() = GetScrPos( nEnd+1 )-nLayoutSign;
}
Invalidate(aRect);
}
void ScHeaderControl::SetMark( sal_Bool bNewSet, SCCOLROW nNewStart, SCCOLROW nNewEnd )
{
sal_Bool bEnabled = SC_MOD()->GetInputOptions().GetMarkHeader(); //! cachen?
if (!bEnabled)
bNewSet = sal_False;
// Variablen setzen
sal_Bool bOldSet = bMarkRange;
SCCOLROW nOldStart = nMarkStart;
SCCOLROW nOldEnd = nMarkEnd;
PutInOrder( nNewStart, nNewEnd );
bMarkRange = bNewSet;
nMarkStart = nNewStart;
nMarkEnd = nNewEnd;
// Paint
if ( bNewSet )
{
if ( bOldSet )
{
if ( nNewStart == nOldStart )
{
if ( nNewEnd != nOldEnd )
DoPaint( Min( nNewEnd, nOldEnd ) + 1, Max( nNewEnd, nOldEnd ) );
// sonst nix
}
else if ( nNewEnd == nOldEnd )
DoPaint( Min( nNewStart, nOldStart ), Max( nNewStart, nOldStart ) - 1 );
else if ( nNewStart > nOldEnd || nNewEnd < nOldStart )
{
// zwei Bereiche...
DoPaint( nOldStart, nOldEnd );
DoPaint( nNewStart, nNewEnd );
}
else // irgendwie ueberlappend... (kommt eh nicht oft vor)
DoPaint( Min( nNewStart, nOldStart ), Max( nNewEnd, nOldEnd ) );
}
else
DoPaint( nNewStart, nNewEnd ); // komplett neu
}
else if ( bOldSet )
DoPaint( nOldStart, nOldEnd ); // komplett aufheben
// sonst war nix, is nix
}
long ScHeaderControl::GetScrPos( SCCOLROW nEntryNo )
{
long nScrPos;
long nMax = ( bVertical ? GetOutputSizePixel().Height() : GetOutputSizePixel().Width() ) + 1;
if (nEntryNo >= nSize)
nScrPos = nMax;
else
{
nScrPos = 0;
for (SCCOLROW i=GetPos(); i<nEntryNo && nScrPos<nMax; i++)
{
sal_uInt16 nAdd = GetEntrySize(i);
if (nAdd)
nScrPos += nAdd;
else
{
SCCOLROW nHidden = GetHiddenCount(i);
if (nHidden > 0)
i += nHidden - 1;
}
}
}
if ( IsLayoutRTL() )
nScrPos = nMax - nScrPos - 2;
return nScrPos;
}
// draw a rectangle across the window's width/height, with the outer part in a lighter color
void ScHeaderControl::DrawShadedRect( long nStart, long nEnd, const Color& rBaseColor )
{
Color aWhite( COL_WHITE );
Color aInner( rBaseColor ); // highlight color, unchanged
Color aCenter( rBaseColor );
aCenter.Merge( aWhite, 0xd0 ); // lighten up a bit
Color aOuter( rBaseColor );
aOuter.Merge( aWhite, 0xa0 ); // lighten up more
if ( IsMirrored() )
std::swap( aInner, aOuter ); // just swap colors instead of positions
Size aWinSize = GetSizePixel();
long nBarSize = bVertical ? aWinSize.Width() : aWinSize.Height();
long nCenterPos = (nBarSize / 2) - 1;
SetLineColor();
SetFillColor( aOuter );
if (bVertical)
DrawRect( Rectangle( 0, nStart, nCenterPos-1, nEnd ) );
else
DrawRect( Rectangle( nStart, 0, nEnd, nCenterPos-1 ) );
SetFillColor( aCenter );
if (bVertical)
DrawRect( Rectangle( nCenterPos, nStart, nCenterPos, nEnd ) );
else
DrawRect( Rectangle( nStart, nCenterPos, nEnd, nCenterPos ) );
SetFillColor( aInner );
if (bVertical)
DrawRect( Rectangle( nCenterPos+1, nStart, nBarSize-1, nEnd ) );
else
DrawRect( Rectangle( nStart, nCenterPos+1, nEnd, nBarSize-1 ) );
}
//
// Paint
//
void ScHeaderControl::Paint( const Rectangle& rRect )
{
// fuer VCL ist es wichtig, wenig Aufrufe zu haben, darum werden die aeusseren
// Linien zusammengefasst
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
sal_Bool bHighContrast = rStyleSettings.GetHighContrastMode();
sal_Bool bDark = rStyleSettings.GetFaceColor().IsDark();
// Use the same distinction for bDark as in Window::DrawSelectionBackground
Color aTextColor = rStyleSettings.GetButtonTextColor();
Color aSelTextColor = rStyleSettings.GetHighlightTextColor();
aNormFont.SetColor( aTextColor );
if ( bHighContrast )
aBoldFont.SetColor( aTextColor );
else
aBoldFont.SetColor( aSelTextColor );
SetTextColor( ( bBoldSet && !bHighContrast ) ? aSelTextColor : aTextColor );
Color aBlack( COL_BLACK );
Color aSelLineColor = rStyleSettings.GetHighlightColor();
aSelLineColor.Merge( aBlack, 0xe0 ); // darken just a little bit
sal_Bool bLayoutRTL = IsLayoutRTL();
long nLayoutSign = bLayoutRTL ? -1 : 1;
sal_Bool bMirrored = IsMirrored();
// const FunctionSet* pFuncSet = pSelEngine->GetFunctionSet();
String aString;
sal_uInt16 nBarSize;
Point aScrPos;
Size aTextSize;
// Size aSize = GetOutputSizePixel();
if (bVertical)
nBarSize = (sal_uInt16) GetSizePixel().Width();
else
nBarSize = (sal_uInt16) GetSizePixel().Height();
SCCOLROW nPos = GetPos();
long nPStart = bVertical ? rRect.Top() : rRect.Left();
long nPEnd = bVertical ? rRect.Bottom() : rRect.Right();
long nTransStart = nPEnd + 1;
long nTransEnd = 0;
long nInitScrPos = 0;
if ( bLayoutRTL )
{
long nTemp = nPStart; // swap nPStart / nPEnd
nPStart = nPEnd;
nPEnd = nTemp;
nTemp = nTransStart; // swap nTransStart / nTransEnd
nTransStart = nTransEnd;
nTransEnd = nTemp;
if ( bVertical ) // start loops from the end
nInitScrPos = GetSizePixel().Height() - 1;
else
nInitScrPos = GetSizePixel().Width() - 1;
}
// aeussere Linien komplett durchzeichnen
// Zuerst Ende der letzten Zelle finden
// long nLineEnd = -1;
long nLineEnd = nInitScrPos - nLayoutSign;
for (SCCOLROW i=nPos; i<nSize; i++)
{
sal_uInt16 nSizePix = GetEntrySize( i );
if (nSizePix)
{
nLineEnd += nSizePix * nLayoutSign;
if ( bMarkRange && i >= nMarkStart && i <= nMarkEnd )
{
long nLineStart = nLineEnd - ( nSizePix - 1 ) * nLayoutSign;
if ( nLineStart * nLayoutSign < nTransStart * nLayoutSign )
nTransStart = nLineStart;
if ( nLineEnd * nLayoutSign > nTransEnd * nLayoutSign )
nTransEnd = nLineEnd;
}
if ( nLineEnd * nLayoutSign > nPEnd * nLayoutSign )
{
nLineEnd = nPEnd;
break;
}
}
else
{
SCCOLROW nHidden = GetHiddenCount(i);
if (nHidden > 0)
i += nHidden - 1;
}
}
// background is different for entry area and behind the entries
Rectangle aFillRect;
SetLineColor();
if ( nLineEnd * nLayoutSign >= nInitScrPos * nLayoutSign )
{
if ( bHighContrast )
{
// high contrast: single-color background
SetFillColor( rStyleSettings.GetFaceColor() );
if ( bVertical )
aFillRect = Rectangle( 0, nInitScrPos, nBarSize-1, nLineEnd );
else
aFillRect = Rectangle( nInitScrPos, 0, nLineEnd, nBarSize-1 );
DrawRect( aFillRect );
}
else
{
// normal: 3-part background
DrawShadedRect( nInitScrPos, nLineEnd, rStyleSettings.GetFaceColor() );
}
}
if ( nLineEnd * nLayoutSign < nPEnd * nLayoutSign )
{
SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::APPBACKGROUND).nColor );
if ( bVertical )
aFillRect = Rectangle( 0, nLineEnd+nLayoutSign, nBarSize-1, nPEnd );
else
aFillRect = Rectangle( nLineEnd+nLayoutSign, 0, nPEnd, nBarSize-1 );
DrawRect( aFillRect );
}
if ( nLineEnd * nLayoutSign >= nPStart * nLayoutSign )
{
if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign )
{
if ( bHighContrast )
{
if ( bDark )
{
// solid grey background for dark face color is drawn before lines
SetLineColor();
SetFillColor( COL_LIGHTGRAY );
if (bVertical)
DrawRect( Rectangle( 0, nTransStart, nBarSize-1, nTransEnd ) );
else
DrawRect( Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 ) );
}
}
else
{
// background for selection
DrawShadedRect( nTransStart, nTransEnd, rStyleSettings.GetHighlightColor() );
}
}
#if 0
// 3D border is no longer used
SetLineColor( rStyleSettings.GetLightColor() );
if (bVertical)
DrawLine( Point( 0, nPStart ), Point( 0, nLineEnd ) );
else
DrawLine( Point( nPStart, 0 ), Point( nLineEnd, 0 ) );
#endif
SetLineColor( rStyleSettings.GetDarkShadowColor() );
if (bVertical)
{
long nDarkPos = bMirrored ? 0 : nBarSize-1;
DrawLine( Point( nDarkPos, nPStart ), Point( nDarkPos, nLineEnd ) );
}
else
DrawLine( Point( nPStart, nBarSize-1 ), Point( nLineEnd, nBarSize-1 ) );
// line in different color for selection
if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && !bHighContrast )
{
SetLineColor( aSelLineColor );
if (bVertical)
{
long nDarkPos = bMirrored ? 0 : nBarSize-1;
DrawLine( Point( nDarkPos, nTransStart ), Point( nDarkPos, nTransEnd ) );
}
else
DrawLine( Point( nTransStart, nBarSize-1 ), Point( nTransEnd, nBarSize-1 ) );
}
}
//
// loop through entries several times to avoid changing the line color too often
// and to allow merging of lines
//
ScGridMerger aGrid( this, 1, 1 );
// start at SC_HDRPAINT_BOTTOM instead of 0 - selection doesn't get different
// borders, light border at top isn't used anymore
// use SC_HDRPAINT_SEL_BOTTOM for different color
for (sal_uInt16 nPass = SC_HDRPAINT_SEL_BOTTOM; nPass < SC_HDRPAINT_COUNT; nPass++)
{
// set line color etc. before entry loop
switch ( nPass )
{
case SC_HDRPAINT_SEL_BOTTOM:
// same as non-selected for high contrast
SetLineColor( bHighContrast ? rStyleSettings.GetDarkShadowColor() : aSelLineColor );
break;
case SC_HDRPAINT_BOTTOM:
SetLineColor( rStyleSettings.GetDarkShadowColor() );
break;
case SC_HDRPAINT_TEXT:
// DrawSelectionBackground is used only for high contrast on light background
if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && bHighContrast && !bDark )
{
// Transparent selection background is drawn after lines, before text.
// #109814# Use DrawSelectionBackground to make sure there is a visible
// difference. The case of a dark face color, where DrawSelectionBackground
// would just paint over the lines, is handled separately (bDark).
// Otherwise, GetHighlightColor is used with 80% transparency.
// The window's background color (SetBackground) has to be the background
// of the cell area, for the contrast comparison in DrawSelectionBackground.
Rectangle aTransRect;
if (bVertical)
aTransRect = Rectangle( 0, nTransStart, nBarSize-1, nTransEnd );
else
aTransRect = Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 );
SetBackground( Color( rStyleSettings.GetFaceColor() ) );
DrawSelectionBackground( aTransRect, 0, sal_True, sal_False, sal_False );
SetBackground();
}
break;
}
SCCOLROW nCount=0;
long nScrPos=nInitScrPos;
do
{
if (bVertical)
aScrPos = Point( 0, nScrPos );
else
aScrPos = Point( nScrPos, 0 );
SCCOLROW nEntryNo = nCount + nPos;
if ( nEntryNo >= nSize ) // MAXCOL/MAXROW
nScrPos = nPEnd + nLayoutSign; // beyond nPEnd -> stop
else
{
sal_uInt16 nSizePix = GetEntrySize( nEntryNo );
if (nSizePix == 0)
{
SCCOLROW nHidden = GetHiddenCount(nEntryNo);
if (nHidden > 0)
nCount += nHidden - 1;
}
else if ((nScrPos+nSizePix*nLayoutSign)*nLayoutSign >= nPStart*nLayoutSign)
{
Point aEndPos(aScrPos);
if (bVertical)
aEndPos = Point( aScrPos.X()+nBarSize-1, aScrPos.Y()+(nSizePix-1)*nLayoutSign );
else
aEndPos = Point( aScrPos.X()+(nSizePix-1)*nLayoutSign, aScrPos.Y()+nBarSize-1 );
sal_Bool bMark = bMarkRange && nEntryNo >= nMarkStart && nEntryNo <= nMarkEnd;
sal_Bool bNextToMark = bMarkRange && nEntryNo + 1 >= nMarkStart && nEntryNo <= nMarkEnd;
switch ( nPass )
{
case SC_HDRPAINT_SEL_BOTTOM:
case SC_HDRPAINT_BOTTOM:
if ( nPass == ( bNextToMark ? SC_HDRPAINT_SEL_BOTTOM : SC_HDRPAINT_BOTTOM ) )
{
if (bVertical)
aGrid.AddHorLine( aScrPos.X(), aEndPos.X(), aEndPos.Y() );
else
aGrid.AddVerLine( aEndPos.X(), aScrPos.Y(), aEndPos.Y() );
// thick bottom for hidden rows
// (drawn directly, without aGrid)
if ( nEntryNo+1 < nSize )
if ( GetEntrySize(nEntryNo+1)==0 )
{
if (bVertical)
DrawLine( Point(aScrPos.X(),aEndPos.Y()-nLayoutSign),
Point(aEndPos.X(),aEndPos.Y()-nLayoutSign) );
else
DrawLine( Point(aEndPos.X()-nLayoutSign,aScrPos.Y()),
Point(aEndPos.X()-nLayoutSign,aEndPos.Y()) );
}
}
break;
case SC_HDRPAINT_TEXT:
if ( nSizePix > 1 ) // minimal check for small columns/rows
{
if ( bMark != bBoldSet )
{
if (bMark)
SetFont(aBoldFont);
else
SetFont(aNormFont);
bBoldSet = bMark;
}
aString = GetEntryText( nEntryNo );
aTextSize.Width() = GetTextWidth( aString );
aTextSize.Height() = GetTextHeight();
Point aTxtPos(aScrPos);
if (bVertical)
{
aTxtPos.X() += (nBarSize-aTextSize.Width())/2;
aTxtPos.Y() += (nSizePix*nLayoutSign-aTextSize.Height())/2;
if ( bMirrored )
aTxtPos.X() += 1; // dark border is left instead of right
}
else
{
aTxtPos.X() += (nSizePix*nLayoutSign-aTextSize.Width()+1)/2;
aTxtPos.Y() += (nBarSize-aTextSize.Height())/2;
}
DrawText( aTxtPos, aString );
}
break;
}
// bei Selektion der ganzen Zeile/Spalte:
// InvertRect( Rectangle( aScrPos, aEndPos ) );
}
nScrPos += nSizePix * nLayoutSign; // also if before the visible area
}
++nCount;
}
while ( nScrPos * nLayoutSign <= nPEnd * nLayoutSign );
aGrid.Flush();
}
}
//
// Maus - Handling
//
SCCOLROW ScHeaderControl::GetMousePos( const MouseEvent& rMEvt, sal_Bool& rBorder )
{
sal_Bool bFound=sal_False;
SCCOLROW nCount = 1;
SCCOLROW nPos = GetPos();
SCCOLROW nHitNo = nPos;
long nScrPos;
long nMousePos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
long nDif;
Size aSize = GetOutputSizePixel();
long nWinSize = bVertical ? aSize.Height() : aSize.Width();
sal_Bool bLayoutRTL = IsLayoutRTL();
long nLayoutSign = bLayoutRTL ? -1 : 1;
long nEndPos = bLayoutRTL ? -1 : nWinSize;
nScrPos = GetScrPos( nPos ) - nLayoutSign;
do
{
SCCOLROW nEntryNo = nCount + nPos;
// nScrPos = GetScrPos( nEntryNo ) - 1;
if (nEntryNo > nSize)
nScrPos = nEndPos + nLayoutSign;
else
nScrPos += GetEntrySize( nEntryNo - 1 ) * nLayoutSign; //! GetHiddenCount() ??
nDif = nMousePos - nScrPos;
if (nDif >= -2 && nDif <= 2 && nCount > 0)
{
bFound=sal_True;
nHitNo=nEntryNo-1;
}
else if (nDif * nLayoutSign >= 0 && nEntryNo < nSize)
nHitNo = nEntryNo;
++nCount;
}
while ( nScrPos * nLayoutSign < nEndPos * nLayoutSign && nDif * nLayoutSign > 0 );
rBorder = bFound;
return nHitNo;
}
bool ScHeaderControl::IsSelectionAllowed(SCCOLROW nPos) const
{
ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
if (!pViewSh)
return false;
ScViewData* pViewData = pViewSh->GetViewData();
sal_uInt16 nTab = pViewData->GetTabNo();
ScDocument* pDoc = pViewData->GetDocument();
const ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
bool bSelectAllowed = true;
if ( pProtect && pProtect->isProtected() )
{
// This sheet is protected. Check if a context menu is allowed on this cell.
bool bCellsProtected = false;
if (bVertical)
{
// row header
SCROW nRPos = static_cast<SCROW>(nPos);
bCellsProtected = pDoc->HasAttrib(0, nRPos, nTab, MAXCOL, nRPos, nTab, HASATTR_PROTECTED);
}
else
{
// column header
SCCOL nCPos = static_cast<SCCOL>(nPos);
bCellsProtected = pDoc->HasAttrib(nCPos, 0, nTab, nCPos, MAXROW, nTab, HASATTR_PROTECTED);
}
bool bSelProtected = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
if (bCellsProtected)
bSelectAllowed = bSelProtected;
else
bSelectAllowed = bSelUnprotected;
}
return bSelectAllowed;
}
void ScHeaderControl::MouseButtonDown( const MouseEvent& rMEvt )
{
if (IsDisabled())
return;
bIgnoreMove = sal_False;
SelectWindow();
sal_Bool bFound;
SCCOLROW nHitNo = GetMousePos( rMEvt, bFound );
if (!IsSelectionAllowed(nHitNo))
return;
if ( bFound && rMEvt.IsLeft() && ResizeAllowed() )
{
nDragNo = nHitNo;
sal_uInt16 nClicks = rMEvt.GetClicks();
if ( nClicks && nClicks%2==0 )
{
SetEntrySize( nDragNo, HDR_SIZE_OPTIMUM );
SetPointer( Pointer( POINTER_ARROW ) );
}
else
{
if (bVertical)
nDragStart = rMEvt.GetPosPixel().Y();
else
nDragStart = rMEvt.GetPosPixel().X();
nDragPos = nDragStart;
ShowDragHelp();
DrawInvert( nDragPos );
// CaptureMouse();
StartTracking();
bDragging = sal_True;
bDragMoved = sal_False;
}
}
else if (rMEvt.IsLeft())
{
pSelEngine->SetWindow( this );
Point aPoint;
Rectangle aVis( aPoint,GetOutputSizePixel() );
if (bVertical)
aVis.Left() = LONG_MIN, aVis.Right() = LONG_MAX;
else
aVis.Top() = LONG_MIN, aVis.Bottom() = LONG_MAX;
pSelEngine->SetVisibleArea( aVis );
SetMarking( sal_True ); // muss vor SelMouseButtonDown sein
pSelEngine->SelMouseButtonDown( rMEvt );
// #74215# In column/row headers a simple click already is a selection.
// -> Call SelMouseMove to ensure CreateAnchor is called (and DestroyAnchor
// if the next click is somewhere else with Control key).
pSelEngine->SelMouseMove( rMEvt );
if (IsMouseCaptured())
{
// Tracking statt CaptureMouse, damit sauber abgebrochen werden kann
//! Irgendwann sollte die SelectionEngine selber StartTracking rufen!?!
ReleaseMouse();
StartTracking();
}
}
}
void ScHeaderControl::MouseButtonUp( const MouseEvent& rMEvt )
{
if ( IsDisabled() )
return;
SetMarking( sal_False );
bIgnoreMove = sal_False;
// sal_Bool bFound;
// SCCOLROW nHitNo = GetMousePos( rMEvt, bFound );
if ( bDragging )
{
DrawInvert( nDragPos );
ReleaseMouse();
bDragging = sal_False;
long nScrPos = GetScrPos( nDragNo );
long nMousePos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
sal_Bool bLayoutRTL = IsLayoutRTL();
long nNewWidth = bLayoutRTL ? ( nScrPos - nMousePos + 1 )
: ( nMousePos + 2 - nScrPos );
if ( nNewWidth < 0 /* && !IsSelected(nDragNo) */ )
{
SCCOLROW nStart = 0;
SCCOLROW nEnd = nDragNo;
while (nNewWidth < 0)
{
nStart = nDragNo;
if (nDragNo>0)
{
--nDragNo;
nNewWidth += GetEntrySize( nDragNo ); //! GetHiddenCount() ???
}
else
nNewWidth = 0;
}
HideEntries( nStart, nEnd );
}
else
{
if (nNewWidth<0) nNewWidth=0;
if (bDragMoved)
SetEntrySize( nDragNo, (sal_uInt16) nNewWidth );
}
}
else
{
pSelEngine->SelMouseButtonUp( rMEvt );
ReleaseMouse();
}
}
void ScHeaderControl::MouseMove( const MouseEvent& rMEvt )
{
if ( IsDisabled() )
{
SetPointer( Pointer( POINTER_ARROW ) );
return;
}
sal_Bool bFound;
(void)GetMousePos( rMEvt, bFound );
if ( bDragging )
{
long nNewPos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
if ( nNewPos != nDragPos )
{
DrawInvert( nDragPos );
nDragPos = nNewPos;
ShowDragHelp();
DrawInvert( nDragPos );
if (nDragPos <= nDragStart-SC_DRAG_MIN || nDragPos >= nDragStart+SC_DRAG_MIN)
bDragMoved = sal_True;
}
}
else
{
if ( bFound && rMEvt.GetButtons()==0 && ResizeAllowed() )
SetPointer( Pointer( bVertical ? POINTER_VSIZEBAR : POINTER_HSIZEBAR ) );
else
SetPointer( Pointer( POINTER_ARROW ) );
if (!bIgnoreMove)
pSelEngine->SelMouseMove( rMEvt );
}
}
void ScHeaderControl::Tracking( const TrackingEvent& rTEvt )
{
// Weil die SelectionEngine kein Tracking kennt, die Events nur auf
// die verschiedenen MouseHandler verteilen...
if ( rTEvt.IsTrackingCanceled() )
StopMarking();
else if ( rTEvt.IsTrackingEnded() )
MouseButtonUp( rTEvt.GetMouseEvent() );
else
MouseMove( rTEvt.GetMouseEvent() );
}
void ScHeaderControl::Command( const CommandEvent& rCEvt )
{
sal_uInt16 nCmd = rCEvt.GetCommand();
if ( nCmd == COMMAND_CONTEXTMENU )
{
StopMarking(); // Selektion / Dragging beenden
// Popup ausfuehren
ScTabViewShell* pViewSh = PTR_CAST( ScTabViewShell,
SfxViewShell::Current() );
if ( pViewSh )
{
if ( rCEvt.IsMouseEvent() )
{
// #i18735# select the column/row under the mouse pointer
ScViewData* pViewData = pViewSh->GetViewData();
SelectWindow(); // also deselects drawing objects, stops draw text edit
if ( pViewData->HasEditView( pViewData->GetActivePart() ) )
SC_MOD()->InputEnterHandler(); // always end edit mode
MouseEvent aMEvt( rCEvt.GetMousePosPixel() );
sal_Bool bBorder;
SCCOLROW nPos = GetMousePos( aMEvt, bBorder );
if (!IsSelectionAllowed(nPos))
// Selecting this cell is not allowed, neither is context menu.
return;
SCTAB nTab = pViewData->GetTabNo();
ScRange aNewRange;
if ( bVertical )
aNewRange = ScRange( 0, sal::static_int_cast<SCROW>(nPos), nTab,
MAXCOL, sal::static_int_cast<SCROW>(nPos), nTab );
else
aNewRange = ScRange( sal::static_int_cast<SCCOL>(nPos), 0, nTab,
sal::static_int_cast<SCCOL>(nPos), MAXROW, nTab );
// see if any part of the range is already selected
sal_Bool bSelected = sal_False;
ScRangeList aRanges;
pViewData->GetMarkData().FillRangeListWithMarks( &aRanges, sal_False );
sal_uLong nRangeCount = aRanges.Count();
for (sal_uLong i=0; i<nRangeCount && !bSelected; i++)
if ( aRanges.GetObject(i)->Intersects( aNewRange ) )
bSelected = sal_True;
// select the range if no part of it was selected
if ( !bSelected )
pViewSh->MarkRange( aNewRange );
}
ScResId aResId( bVertical ? RID_POPUP_ROWHEADER : RID_POPUP_COLHEADER );
pViewSh->GetDispatcher()->ExecutePopup( aResId );
}
}
else if ( nCmd == COMMAND_STARTDRAG )
{
pSelEngine->Command( rCEvt );
}
}
void ScHeaderControl::StopMarking()
{
if ( bDragging )
{
DrawInvert( nDragPos );
bDragging = sal_False;
}
SetMarking( sal_False );
bIgnoreMove = sal_True;
// #86260# don't call pSelEngine->Reset, so selection across the parts of
// a split/frozen view is possible
ReleaseMouse();
}
void ScHeaderControl::ShowDragHelp()
{
if (Help::IsQuickHelpEnabled())
{
long nScrPos = GetScrPos( nDragNo );
sal_Bool bLayoutRTL = IsLayoutRTL();
long nVal = bLayoutRTL ? ( nScrPos - nDragPos + 1 )
: ( nDragPos + 2 - nScrPos );
String aHelpStr = GetDragHelp( nVal );
Point aPos = OutputToScreenPixel( Point(0,0) );
Size aSize = GetSizePixel();
Point aMousePos = OutputToScreenPixel(GetPointerPosPixel());
Rectangle aRect;
sal_uInt16 nAlign;
if (!bVertical)
{
// oberhalb
aRect.Left() = aMousePos.X();
aRect.Top() = aPos.Y() - 4;
nAlign = QUICKHELP_BOTTOM|QUICKHELP_CENTER;
}
else
{
// rechts oben
aRect.Left() = aPos.X() + aSize.Width() + 8;
aRect.Top() = aMousePos.Y() - 2;
nAlign = QUICKHELP_LEFT|QUICKHELP_BOTTOM;
}
aRect.Right() = aRect.Left();
aRect.Bottom() = aRect.Top();
Help::ShowQuickHelp(this, aRect, aHelpStr, nAlign);
}
}
void ScHeaderControl::RequestHelp( const HelpEvent& rHEvt )
{
// Wenn eigene QuickHelp angezeigt wird, nicht durch RequestHelp
// wieder wegnehmen lassen
sal_Bool bOwn = bDragging && Help::IsQuickHelpEnabled();
if (!bOwn)
Window::RequestHelp(rHEvt);
}
// -----------------------------------------------------------------------
// Dummys fuer virtuelle Methoden
// -----------------------------------------------------------------------
SCCOLROW ScHeaderControl::GetHiddenCount( SCCOLROW nEntryNo )
{
SCCOLROW nHidden = 0;
while ( nEntryNo < nSize && GetEntrySize( nEntryNo ) == 0 )
{
++nEntryNo;
++nHidden;
}
return nHidden;
}
sal_Bool ScHeaderControl::IsLayoutRTL()
{
return sal_False;
}
sal_Bool ScHeaderControl::IsMirrored()
{
return sal_False;
}
sal_Bool ScHeaderControl::IsDisabled()
{
return sal_False;
}
sal_Bool ScHeaderControl::ResizeAllowed()
{
return sal_True;
}
void ScHeaderControl::SelectWindow()
{
}
void ScHeaderControl::DrawInvert( long /* nDragPos */ )
{
}
String ScHeaderControl::GetDragHelp( long /* nVal */ )
{
return EMPTY_STRING;
}
void ScHeaderControl::SetMarking( sal_Bool /* bSet */ )
{
}