fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / view / output.cxx
blob2b04c0f04e043649d406a5d243bd09511724a02b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/embed/EmbedMisc.hpp>
22 #include "scitems.hxx"
23 #include <editeng/boxitem.hxx>
24 #include <editeng/brushitem.hxx>
25 #include <editeng/editdata.hxx>
26 #include <svtools/colorcfg.hxx>
27 #include <svx/rotmodit.hxx>
28 #include <editeng/shaditem.hxx>
29 #include <editeng/svxfont.hxx>
30 #include <svx/svdoole2.hxx>
31 #include <tools/poly.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/pdfextoutdevdata.hxx>
34 #include <svtools/accessibilityoptions.hxx>
35 #include <svx/framelinkarray.hxx>
36 #include <drawinglayer/geometry/viewinformation2d.hxx>
37 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
38 #include <basegfx/matrix/b2dhommatrix.hxx>
39 #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
40 #include <vcl/lineinfo.hxx>
41 #include <vcl/gradient.hxx>
42 #include <vcl/settings.hxx>
43 #include <svx/unoapi.hxx>
45 #include "output.hxx"
46 #include "document.hxx"
47 #include "drwlayer.hxx"
48 #include "formulacell.hxx"
49 #include "attrib.hxx"
50 #include "patattr.hxx"
51 #include "docpool.hxx"
52 #include "tabvwsh.hxx"
53 #include "progress.hxx"
54 #include "pagedata.hxx"
55 #include "chgtrack.hxx"
56 #include "chgviset.hxx"
57 #include "viewutil.hxx"
58 #include "gridmerg.hxx"
59 #include "invmerge.hxx"
60 #include "fillinfo.hxx"
61 #include "scmod.hxx"
62 #include "appoptio.hxx"
63 #include "postit.hxx"
65 #include "scresid.hxx"
66 #include "colorscale.hxx"
68 #include <math.h>
69 #include <map>
70 #include <utility>
71 #include <iostream>
72 #include <boost/scoped_ptr.hpp>
74 using namespace com::sun::star;
76 // Static Data
78 // color for ChangeTracking "by author" as in the writer (swmodul1.cxx)
80 #define SC_AUTHORCOLORCOUNT 9
82 static const ColorData nAuthorColor[ SC_AUTHORCOLORCOUNT ] = {
83 COL_LIGHTRED, COL_LIGHTBLUE, COL_LIGHTMAGENTA,
84 COL_GREEN, COL_RED, COL_BLUE,
85 COL_BROWN, COL_MAGENTA, COL_CYAN };
87 // Helper class for color assignment to avoid repeated lookups for the same user
89 ScActionColorChanger::ScActionColorChanger( const ScChangeTrack& rTrack ) :
90 rOpt( SC_MOD()->GetAppOptions() ),
91 rUsers( rTrack.GetUserCollection() ),
92 nLastUserIndex( 0 ),
93 nColor( COL_BLACK )
97 void ScActionColorChanger::Update( const ScChangeAction& rAction )
99 ColorData nSetColor;
100 switch (rAction.GetType())
102 case SC_CAT_INSERT_COLS:
103 case SC_CAT_INSERT_ROWS:
104 case SC_CAT_INSERT_TABS:
105 nSetColor = rOpt.GetTrackInsertColor();
106 break;
107 case SC_CAT_DELETE_COLS:
108 case SC_CAT_DELETE_ROWS:
109 case SC_CAT_DELETE_TABS:
110 nSetColor = rOpt.GetTrackDeleteColor();
111 break;
112 case SC_CAT_MOVE:
113 nSetColor = rOpt.GetTrackMoveColor();
114 break;
115 default:
116 nSetColor = rOpt.GetTrackContentColor();
117 break;
119 if ( nSetColor != COL_TRANSPARENT ) // color assigned
120 nColor = nSetColor;
121 else // by author
123 if (!aLastUserName.equals(rAction.GetUser()))
125 aLastUserName = rAction.GetUser();
126 std::set<OUString>::const_iterator it = rUsers.find(aLastUserName);
127 if (it == rUsers.end())
129 // empty string is possible if a name wasn't found while saving a 5.0 file
130 SAL_INFO_IF( aLastUserName.isEmpty(), "sc.ui", "Author not found" );
131 nLastUserIndex = 0;
133 else
135 size_t nPos = std::distance(rUsers.begin(), it);
136 nLastUserIndex = nPos % SC_AUTHORCOLORCOUNT;
139 nColor = nAuthorColor[nLastUserIndex];
143 ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
144 ScTableInfo& rTabInfo, ScDocument* pNewDoc,
145 SCTAB nNewTab, long nNewScrX, long nNewScrY,
146 SCCOL nNewX1, SCROW nNewY1, SCCOL nNewX2, SCROW nNewY2,
147 double nPixelPerTwipsX, double nPixelPerTwipsY,
148 const Fraction* pZoomX, const Fraction* pZoomY ) :
149 mpDev( pNewDev ),
150 mpRefDevice( pNewDev ), // default is output device
151 pFmtDevice( pNewDev ), // default is output device
152 mrTabInfo( rTabInfo ),
153 pRowInfo( rTabInfo.mpRowInfo ),
154 nArrCount( rTabInfo.mnArrCount ),
155 mpDoc( pNewDoc ),
156 nTab( nNewTab ),
157 nScrX( nNewScrX ),
158 nScrY( nNewScrY ),
159 nX1( nNewX1 ),
160 nY1( nNewY1 ),
161 nX2( nNewX2 ),
162 nY2( nNewY2 ),
163 eType( eNewType ),
164 mnPPTX( nPixelPerTwipsX ),
165 mnPPTY( nPixelPerTwipsY ),
166 pEditObj( NULL ),
167 pViewShell( NULL ),
168 pDrawView( NULL ), // #114135#
169 bEditMode( false ),
170 nEditCol( 0 ),
171 nEditRow( 0 ),
172 bMetaFile( false ),
173 bSingleGrid( false ),
174 bPagebreakMode( false ),
175 bSolidBackground( false ),
176 mbUseStyleColor( false ),
177 mbForceAutoColor( SC_MOD()->GetAccessOptions().GetIsAutomaticFontColor() ),
178 mbSyntaxMode( false ),
179 pValueColor( NULL ),
180 pTextColor( NULL ),
181 pFormulaColor( NULL ),
182 aGridColor( COL_BLACK ),
183 mbShowNullValues( true ),
184 mbShowFormulas( false ),
185 bShowSpellErrors( false ),
186 bMarkClipped( false ), // sal_False for printer/metafile etc.
187 bSnapPixel( false ),
188 bAnyRotated( false ),
189 bAnyClipped( false ),
190 mpTargetPaintWindow(NULL), // #i74769# use SdrPaintWindow direct
191 mpSpellCheckCxt(NULL)
193 if (pZoomX)
194 aZoomX = *pZoomX;
195 else
196 aZoomX = Fraction(1,1);
197 if (pZoomY)
198 aZoomY = *pZoomY;
199 else
200 aZoomY = Fraction(1,1);
202 nVisX1 = nX1;
203 nVisY1 = nY1;
204 nVisX2 = nX2;
205 nVisY2 = nY2;
206 mpDoc->StripHidden( nVisX1, nVisY1, nVisX2, nVisY2, nTab );
208 nScrW = 0;
209 for (SCCOL nX=nVisX1; nX<=nVisX2; nX++)
210 nScrW += pRowInfo[0].pCellInfo[nX+1].nWidth;
212 nMirrorW = nScrW;
214 nScrH = 0;
215 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
216 nScrH += pRowInfo[nArrY].nHeight;
218 bTabProtected = mpDoc->IsTabProtected( nTab );
219 nTabTextDirection = mpDoc->GetEditTextDirection( nTab );
220 bLayoutRTL = mpDoc->IsLayoutRTL( nTab );
223 ScOutputData::~ScOutputData()
225 delete pValueColor;
226 delete pTextColor;
227 delete pFormulaColor;
230 void ScOutputData::SetSpellCheckContext( const sc::SpellCheckContext* pCxt )
232 mpSpellCheckCxt = pCxt;
235 void ScOutputData::SetContentDevice( OutputDevice* pContentDev )
237 // use pContentDev instead of pDev where used
239 if ( mpRefDevice == mpDev )
240 mpRefDevice = pContentDev;
241 if ( pFmtDevice == mpDev )
242 pFmtDevice = pContentDev;
243 mpDev = pContentDev;
246 void ScOutputData::SetMirrorWidth( long nNew )
248 nMirrorW = nNew;
251 void ScOutputData::SetGridColor( const Color& rColor )
253 aGridColor = rColor;
256 void ScOutputData::SetMarkClipped( bool bSet )
258 bMarkClipped = bSet;
261 void ScOutputData::SetShowNullValues( bool bSet )
263 mbShowNullValues = bSet;
266 void ScOutputData::SetShowFormulas( bool bSet )
268 mbShowFormulas = bSet;
271 void ScOutputData::SetShowSpellErrors( bool bSet )
273 bShowSpellErrors = bSet;
276 void ScOutputData::SetSnapPixel( bool bSet )
278 bSnapPixel = bSet;
281 void ScOutputData::SetEditCell( SCCOL nCol, SCROW nRow )
283 nEditCol = nCol;
284 nEditRow = nRow;
285 bEditMode = true;
288 void ScOutputData::SetMetaFileMode( bool bNewMode )
290 bMetaFile = bNewMode;
293 void ScOutputData::SetSingleGrid( bool bNewMode )
295 bSingleGrid = bNewMode;
298 void ScOutputData::SetSyntaxMode( bool bNewMode )
300 mbSyntaxMode = bNewMode;
301 if (bNewMode)
302 if (!pValueColor)
304 pValueColor = new Color( COL_LIGHTBLUE );
305 pTextColor = new Color( COL_BLACK );
306 pFormulaColor = new Color( COL_GREEN );
310 void ScOutputData::DrawGrid( bool bGrid, bool bPage )
312 SCCOL nX;
313 SCROW nY;
314 long nPosX;
315 long nPosY;
316 SCSIZE nArrY;
317 ScBreakType nBreak = BREAK_NONE;
318 ScBreakType nBreakOld = BREAK_NONE;
320 bool bSingle;
321 Color aPageColor;
322 Color aManualColor;
324 if (bPagebreakMode)
325 bPage = false; // no "normal" breaks over the whole width/height
327 //! um den einen Pixel sieht das Metafile (oder die Druck-Ausgabe) anders aus
328 //! als die Bildschirmdarstellung, aber wenigstens passen Druck und Metafile zusammen
330 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
331 long nOneX = aOnePixel.Width();
332 long nOneY = aOnePixel.Height();
333 if (bMetaFile)
334 nOneX = nOneY = 1;
336 long nLayoutSign = bLayoutRTL ? -1 : 1;
337 long nSignedOneX = nOneX * nLayoutSign;
339 if ( eType == OUTTYPE_WINDOW )
341 const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
342 aPageColor.SetColor( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor );
343 aManualColor.SetColor( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor );
345 else
347 aPageColor = aGridColor;
348 aManualColor = aGridColor;
351 mpDev->SetLineColor( aGridColor );
352 ScGridMerger aGrid( mpDev, nOneX, nOneY );
354 // vertical lines
356 nPosX = nScrX;
357 if ( bLayoutRTL )
358 nPosX += nMirrorW - nOneX;
360 for (nX=nX1; nX<=nX2; nX++)
362 SCCOL nXplus1 = nX+1;
363 SCCOL nXplus2 = nX+2;
364 sal_uInt16 nWidth = pRowInfo[0].pCellInfo[nXplus1].nWidth;
365 if (nWidth)
367 nPosX += nWidth * nLayoutSign;
369 if ( bPage )
371 // Seitenumbrueche auch in ausgeblendeten suchen
372 SCCOL nCol = nXplus1;
373 while (nCol <= MAXCOL)
375 nBreak = mpDoc->HasColBreak(nCol, nTab);
376 bool bHidden = mpDoc->ColHidden(nCol, nTab);
378 if ( nBreak || !bHidden )
379 break;
380 ++nCol;
383 if (nBreak != nBreakOld)
385 aGrid.Flush();
386 mpDev->SetLineColor( (nBreak & BREAK_MANUAL) ? aManualColor :
387 nBreak ? aPageColor : aGridColor );
388 nBreakOld = nBreak;
392 bool bDraw = bGrid || nBreakOld; // simple grid only if set that way
394 sal_uInt16 nWidthXplus2 = pRowInfo[0].pCellInfo[nXplus2].nWidth;
395 bSingle = bSingleGrid; //! get into Fillinfo !!!!!
396 if ( nX<MAXCOL && !bSingle )
398 bSingle = ( nWidthXplus2 == 0 );
399 for (nArrY=1; nArrY+1<nArrCount && !bSingle; nArrY++)
401 if (pRowInfo[nArrY].pCellInfo[nXplus2].bHOverlapped)
402 bSingle = true;
403 if (pRowInfo[nArrY].pCellInfo[nXplus1].bHideGrid)
404 bSingle = true;
408 if (bDraw)
410 if ( nX<MAXCOL && bSingle )
412 SCCOL nVisX = nXplus1;
413 while ( nVisX < MAXCOL && !mpDoc->GetColWidth(nVisX,nTab) )
414 ++nVisX;
416 nPosY = nScrY;
417 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
419 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
420 const long nNextY = nPosY + pThisRowInfo->nHeight;
422 bool bHOver = pThisRowInfo->pCellInfo[nXplus1].bHideGrid;
423 if (!bHOver)
425 if (nWidthXplus2)
426 bHOver = pThisRowInfo->pCellInfo[nXplus2].bHOverlapped;
427 else
429 if (nVisX <= nX2)
430 bHOver = pThisRowInfo->pCellInfo[nVisX+1].bHOverlapped;
431 else
432 bHOver = static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
433 nVisX,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG))
434 ->IsHorOverlapped();
435 if (bHOver)
436 bHOver = static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
437 nXplus1,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG))
438 ->IsHorOverlapped();
442 if (pThisRowInfo->bChanged && !bHOver)
444 aGrid.AddVerLine( nPosX-nSignedOneX, nPosY, nNextY-nOneY );
446 nPosY = nNextY;
449 else
451 aGrid.AddVerLine( nPosX-nSignedOneX, nScrY, nScrY+nScrH-nOneY );
457 // horizontal lines
459 bool bHiddenRow = true;
460 SCROW nHiddenEndRow = -1;
461 nPosY = nScrY;
462 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
464 SCSIZE nArrYplus1 = nArrY+1;
465 nY = pRowInfo[nArrY].nRowNo;
466 SCROW nYplus1 = nY+1;
467 nPosY += pRowInfo[nArrY].nHeight;
469 if (pRowInfo[nArrY].bChanged)
471 if ( bPage )
473 for (SCROW i = nYplus1; i <= MAXROW; ++i)
475 if (i > nHiddenEndRow)
476 bHiddenRow = mpDoc->RowHidden(i, nTab, NULL, &nHiddenEndRow);
477 /* TODO: optimize the row break thing for large hidden
478 * segments where HasRowBreak() has to be called
479 * nevertheless for each row, as a row break is drawn also
480 * for hidden rows, above them. This needed to be done only
481 * once per hidden segment, maybe giving manual breaks
482 * priority. Something like GetNextRowBreak() and
483 * GetNextManualRowBreak(). */
484 nBreak = mpDoc->HasRowBreak(i, nTab);
485 if (!bHiddenRow || nBreak)
486 break;
489 if (nBreakOld != nBreak)
491 aGrid.Flush();
492 mpDev->SetLineColor( (nBreak & BREAK_MANUAL) ? aManualColor :
493 (nBreak) ? aPageColor : aGridColor );
494 nBreakOld = nBreak;
498 bool bDraw = bGrid || nBreakOld; // simple grid only if set so
500 bool bNextYisNextRow = (pRowInfo[nArrYplus1].nRowNo == nYplus1);
501 bSingle = !bNextYisNextRow; // Hidden
502 for (SCCOL i=nX1; i<=nX2 && !bSingle; i++)
504 if (pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped)
505 bSingle = true;
508 if (bDraw)
510 if ( bSingle && nY<MAXROW )
512 SCROW nVisY = pRowInfo[nArrYplus1].nRowNo;
514 nPosX = nScrX;
515 if ( bLayoutRTL )
516 nPosX += nMirrorW - nOneX;
518 for (SCCOL i=nX1; i<=nX2; i++)
520 const long nNextX = nPosX + pRowInfo[0].pCellInfo[i+1].nWidth * nLayoutSign;
521 if (nNextX != nPosX) // visible
523 bool bVOver;
524 if ( bNextYisNextRow )
525 bVOver = pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped;
526 else
528 bVOver = static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
529 i,nYplus1,nTab,ATTR_MERGE_FLAG))
530 ->IsVerOverlapped()
531 && static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
532 i,nVisY,nTab,ATTR_MERGE_FLAG))
533 ->IsVerOverlapped();
534 //! nVisY from Array ??
536 if (!bVOver)
538 aGrid.AddHorLine( nPosX, nNextX-nSignedOneX, nPosY-nOneY );
541 nPosX = nNextX;
544 else
546 aGrid.AddHorLine( nScrX, nScrX+nScrW-nOneX, nPosY-nOneY );
553 void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
555 bPagebreakMode = true;
556 if (!pPageData)
557 return; // not yet initialized -> everything "not printed"
559 // mark printed range
560 // (everything in FillInfo is already initialized to sal_False)
562 sal_uInt16 nRangeCount = sal::static_int_cast<sal_uInt16>(pPageData->GetCount());
563 for (sal_uInt16 nPos=0; nPos<nRangeCount; nPos++)
565 ScRange aRange = pPageData->GetData( nPos ).GetPrintRange();
567 SCCOL nStartX = std::max( aRange.aStart.Col(), nX1 );
568 SCCOL nEndX = std::min( aRange.aEnd.Col(), nX2 );
569 SCROW nStartY = std::max( aRange.aStart.Row(), nY1 );
570 SCROW nEndY = std::min( aRange.aEnd.Row(), nY2 );
572 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
574 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
575 if ( pThisRowInfo->bChanged && pThisRowInfo->nRowNo >= nStartY &&
576 pThisRowInfo->nRowNo <= nEndY )
578 for (SCCOL nX=nStartX; nX<=nEndX; nX++)
579 pThisRowInfo->pCellInfo[nX+1].bPrinted = true;
585 void ScOutputData::FindRotated()
587 //! save nRotMax
588 SCCOL nRotMax = nX2;
589 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
590 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
591 nRotMax = pRowInfo[nRotY].nRotMaxCol;
593 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
595 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
596 if ( pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE &&
597 ( pThisRowInfo->bChanged || pRowInfo[nArrY-1].bChanged ||
598 ( nArrY+1<nArrCount && pRowInfo[nArrY+1].bChanged ) ) )
600 SCROW nY = pThisRowInfo->nRowNo;
602 for (SCCOL nX=0; nX<=nRotMax; nX++)
604 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
605 const ScPatternAttr* pPattern = pInfo->pPatternAttr;
606 const SfxItemSet* pCondSet = pInfo->pConditionSet;
608 if ( !pPattern && !mpDoc->ColHidden(nX, nTab) )
610 pPattern = mpDoc->GetPattern( nX, nY, nTab );
611 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
614 if ( pPattern ) // column isn't hidden
616 sal_uInt8 nDir = pPattern->GetRotateDir( pCondSet );
617 if (nDir != SC_ROTDIR_NONE)
619 pInfo->nRotateDir = nDir;
620 bAnyRotated = true;
628 static sal_uInt16 lcl_GetRotateDir( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
630 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
631 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
633 sal_uInt16 nRet = SC_ROTDIR_NONE;
635 long nAttrRotate = pPattern->GetRotateVal( pCondSet );
636 if ( nAttrRotate )
638 SvxRotateMode eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
639 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
641 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
642 nRet = SC_ROTDIR_STANDARD;
643 else if ( eRotMode == SVX_ROTATE_MODE_CENTER )
644 nRet = SC_ROTDIR_CENTER;
645 else if ( eRotMode == SVX_ROTATE_MODE_TOP || eRotMode == SVX_ROTATE_MODE_BOTTOM )
647 long nRot180 = nAttrRotate % 18000; // 1/100 degree
648 if ( nRot180 == 9000 )
649 nRet = SC_ROTDIR_CENTER;
650 else if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nRot180 < 9000 ) ||
651 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nRot180 > 9000 ) )
652 nRet = SC_ROTDIR_LEFT;
653 else
654 nRet = SC_ROTDIR_RIGHT;
658 return nRet;
661 static const SvxBrushItem* lcl_FindBackground( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
663 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
664 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
665 const SvxBrushItem* pBackground = static_cast<const SvxBrushItem*>(
666 &pPattern->GetItem( ATTR_BACKGROUND, pCondSet ));
668 sal_uInt16 nDir = lcl_GetRotateDir( pDoc, nCol, nRow, nTab );
670 // treat CENTER like RIGHT
671 if ( nDir == SC_ROTDIR_RIGHT || nDir == SC_ROTDIR_CENTER )
673 // text goes to the right -> take background from the left
674 while ( nCol > 0 && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
675 pBackground->GetColor().GetTransparency() != 255 )
677 --nCol;
678 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
679 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
680 pBackground = static_cast<const SvxBrushItem*>(&pPattern->GetItem( ATTR_BACKGROUND, pCondSet ));
683 else if ( nDir == SC_ROTDIR_LEFT )
685 // text goes to the left -> take background from the right
686 while ( nCol < MAXCOL && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
687 pBackground->GetColor().GetTransparency() != 255 )
689 ++nCol;
690 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
691 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
692 pBackground = static_cast<const SvxBrushItem*>(&pPattern->GetItem( ATTR_BACKGROUND, pCondSet ));
696 return pBackground;
699 static bool lcl_EqualBack( const RowInfo& rFirst, const RowInfo& rOther,
700 SCCOL nX1, SCCOL nX2, bool bShowProt, bool bPagebreakMode )
702 if ( rFirst.bChanged != rOther.bChanged ||
703 rFirst.bEmptyBack != rOther.bEmptyBack )
704 return false;
706 SCCOL nX;
707 if ( bShowProt )
709 for ( nX=nX1; nX<=nX2; nX++ )
711 const ScPatternAttr* pPat1 = rFirst.pCellInfo[nX+1].pPatternAttr;
712 const ScPatternAttr* pPat2 = rOther.pCellInfo[nX+1].pPatternAttr;
713 if ( !pPat1 || !pPat2 ||
714 &pPat1->GetItem(ATTR_PROTECTION) != &pPat2->GetItem(ATTR_PROTECTION) )
715 return false;
718 else
720 for ( nX=nX1; nX<=nX2; nX++ )
721 if ( rFirst.pCellInfo[nX+1].pBackground != rOther.pCellInfo[nX+1].pBackground )
722 return false;
725 if ( rFirst.nRotMaxCol != SC_ROTMAX_NONE || rOther.nRotMaxCol != SC_ROTMAX_NONE )
726 for ( nX=nX1; nX<=nX2; nX++ )
727 if ( rFirst.pCellInfo[nX+1].nRotateDir != rOther.pCellInfo[nX+1].nRotateDir )
728 return false;
730 if ( bPagebreakMode )
731 for ( nX=nX1; nX<=nX2; nX++ )
732 if ( rFirst.pCellInfo[nX+1].bPrinted != rOther.pCellInfo[nX+1].bPrinted )
733 return false;
735 for ( nX=nX1; nX<=nX2; nX++ )
737 const Color* pCol1 = rFirst.pCellInfo[nX+1].pColorScale.get();
738 const Color* pCol2 = rOther.pCellInfo[nX+1].pColorScale.get();
739 if( (pCol1 && !pCol2) || (!pCol1 && pCol2) )
740 return false;
742 if (pCol1 && (*pCol1 != *pCol2))
743 return false;
745 const ScDataBarInfo* pInfo1 = rFirst.pCellInfo[nX+1].pDataBar.get();
746 const ScDataBarInfo* pInfo2 = rOther.pCellInfo[nX+1].pDataBar.get();
748 if( (pInfo1 && !pInfo2) || (!pInfo1 && pInfo2) )
749 return false;
751 if (pInfo1 && (*pInfo1 != *pInfo2))
752 return false;
754 // each cell with an icon set should be painted the same way
755 const ScIconSetInfo* pIconSet1 = rFirst.pCellInfo[nX+1].pIconSet.get();
756 const ScIconSetInfo* pIconSet2 = rOther.pCellInfo[nX+1].pIconSet.get();
758 if(pIconSet1 || pIconSet2)
759 return false;
762 return true;
765 void ScOutputData::DrawDocumentBackground()
767 if ( !bSolidBackground )
768 return;
770 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
771 long nOneX = aOnePixel.Width();
772 long nOneY = aOnePixel.Height();
773 Rectangle aRect(nScrX - nOneX, nScrY - nOneY, nScrX + nScrW, nScrY + nScrH);
774 Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
775 mpDev->SetFillColor(aBgColor);
776 mpDev->DrawRect(aRect);
779 namespace {
781 static const double lclCornerRectTransparency = 40.0;
783 void drawDataBars( const ScDataBarInfo* pOldDataBarInfo, vcl::RenderContext* pDev, const Rectangle& rRect)
785 long nPosZero = 0;
786 Rectangle aPaintRect = rRect;
787 aPaintRect.Top() += 2;
788 aPaintRect.Bottom() -= 2;
789 aPaintRect.Left() += 2;
790 aPaintRect.Right() -= 2;
791 if(pOldDataBarInfo->mnZero)
793 // need to calculate null point in cell
794 long nLength = aPaintRect.Right() - aPaintRect.Left();
795 nPosZero = static_cast<long>(aPaintRect.Left() + nLength*pOldDataBarInfo->mnZero/100.0);
797 else
799 nPosZero = aPaintRect.Left();
802 if(pOldDataBarInfo->mnLength < 0)
804 aPaintRect.Right() = nPosZero;
805 long nLength = nPosZero - aPaintRect.Left();
806 aPaintRect.Left() = nPosZero + static_cast<long>(nLength * pOldDataBarInfo->mnLength/100.0);
808 else if(pOldDataBarInfo->mnLength > 0)
810 aPaintRect.Left() = nPosZero;
811 long nLength = aPaintRect.Right() - nPosZero;
812 aPaintRect.Right() = nPosZero + static_cast<long>(nLength * pOldDataBarInfo->mnLength/100.0);
814 else
815 return;
817 if(pOldDataBarInfo->mbGradient)
819 pDev->SetLineColor(pOldDataBarInfo->maColor);
820 Gradient aGradient(GradientStyle_LINEAR, pOldDataBarInfo->maColor, COL_TRANSPARENT);
822 if(pOldDataBarInfo->mnLength < 0)
823 aGradient.SetAngle(2700);
824 else
825 aGradient.SetAngle(900);
827 pDev->DrawGradient(aPaintRect, aGradient);
829 pDev->SetLineColor();
831 else
833 pDev->SetFillColor(pOldDataBarInfo->maColor);
834 pDev->DrawRect(aPaintRect);
837 //draw axis
838 if(pOldDataBarInfo->mnZero && pOldDataBarInfo->mnZero != 100)
840 Point aPoint1(nPosZero, rRect.Top());
841 Point aPoint2(nPosZero, rRect.Bottom());
842 LineInfo aLineInfo(LINE_DASH, 1);
843 aLineInfo.SetDashCount( 4 );
844 aLineInfo.SetDistance( 3 );
845 aLineInfo.SetDashLen( 3 );
846 pDev->SetFillColor(pOldDataBarInfo->maAxisColor);
847 pDev->SetLineColor(pOldDataBarInfo->maAxisColor);
848 pDev->DrawLine(aPoint1, aPoint2, aLineInfo);
849 pDev->SetLineColor();
850 pDev->SetFillColor();
854 BitmapEx& getIcon( ScIconSetType eType, sal_Int32 nIndex )
856 return ScIconSetFormat::getBitmap( eType, nIndex );
859 void drawIconSets( const ScIconSetInfo* pOldIconSetInfo, vcl::RenderContext* pDev, const Rectangle& rRect )
861 //long nSize = 16;
862 ScIconSetType eType = pOldIconSetInfo->eIconSetType;
863 sal_Int32 nIndex = pOldIconSetInfo->nIconIndex;
864 BitmapEx& rIcon = getIcon( eType, nIndex );
865 long aOrigSize = std::max<long>(0,std::min(rRect.GetSize().getWidth() - 4, rRect.GetSize().getHeight() -4));
866 pDev->DrawBitmapEx( Point( rRect.Left() +2, rRect.Top() + 2 ), Size(aOrigSize, aOrigSize), rIcon );
869 void drawCells(const Color* pColor, const SvxBrushItem* pBackground, const Color*& pOldColor, const SvxBrushItem*& pOldBackground,
870 Rectangle& rRect, long nPosX, long nSignedOneX, vcl::RenderContext* pDev, const ScDataBarInfo* pDataBarInfo, const ScDataBarInfo*& pOldDataBarInfo,
871 const ScIconSetInfo* pIconSetInfo, const ScIconSetInfo*& pOldIconSetInfo)
874 // need to paint if old color scale has been used and now
875 // we have a different color or a style based background
876 // we can here fall back to pointer comparison
877 if (pOldColor && (pBackground || pOldColor != pColor || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo))
879 rRect.Right() = nPosX-nSignedOneX;
880 if( !pOldColor->GetTransparency() )
882 pDev->SetFillColor( *pOldColor );
883 pDev->DrawRect( rRect );
885 if( pOldDataBarInfo )
886 drawDataBars( pOldDataBarInfo, pDev, rRect );
887 if( pOldIconSetInfo )
888 drawIconSets( pOldIconSetInfo, pDev, rRect );
890 rRect.Left() = nPosX - nSignedOneX;
893 if ( pOldBackground && (pColor ||pBackground != pOldBackground || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo) )
895 rRect.Right() = nPosX-nSignedOneX;
896 if (pOldBackground) // ==0 if hidden
898 Color aBackCol = pOldBackground->GetColor();
899 if ( !aBackCol.GetTransparency() ) //! partial transparency?
901 pDev->SetFillColor( aBackCol );
902 pDev->DrawRect( rRect );
905 if( pOldDataBarInfo )
906 drawDataBars( pOldDataBarInfo, pDev, rRect );
907 if( pOldIconSetInfo )
908 drawIconSets( pOldIconSetInfo, pDev, rRect );
910 rRect.Left() = nPosX - nSignedOneX;
913 if (!pOldBackground && !pOldColor && (pDataBarInfo || pIconSetInfo))
915 rRect.Right() = nPosX -nSignedOneX;
916 rRect.Left() = nPosX - nSignedOneX;
919 if(pColor)
921 // only update pOldColor if the colors changed
922 if (!pOldColor || *pOldColor != *pColor)
923 pOldColor = pColor;
925 pOldBackground = NULL;
927 else if(pBackground)
929 pOldBackground = pBackground;
930 pOldColor = NULL;
933 if(pDataBarInfo)
934 pOldDataBarInfo = pDataBarInfo;
935 else
936 pOldDataBarInfo = NULL;
938 if(pIconSetInfo)
939 pOldIconSetInfo = pIconSetInfo;
940 else
941 pOldIconSetInfo = NULL;
946 void ScOutputData::DrawBackground()
948 FindRotated(); //! from the outside?
950 Rectangle aRect;
951 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
952 long nOneX = aOnePixel.Width();
953 long nOneY = aOnePixel.Height();
955 if (bMetaFile)
956 nOneX = nOneY = 0;
958 long nLayoutSign = bLayoutRTL ? -1 : 1;
959 long nSignedOneX = nOneX * nLayoutSign;
961 mpDev->SetLineColor();
963 bool bShowProt = mbSyntaxMode && mpDoc->IsTabProtected(nTab);
964 bool bDoAll = bShowProt || bPagebreakMode || bSolidBackground;
966 bool bCellContrast = mbUseStyleColor &&
967 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
969 long nPosY = nScrY;
970 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
972 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
973 long nRowHeight = pThisRowInfo->nHeight;
975 if ( pThisRowInfo->bChanged )
977 if ( ( ( pThisRowInfo->bEmptyBack ) || mbSyntaxMode ) && !bDoAll )
979 // nothing
981 else
983 // scan for rows with the same background:
984 SCSIZE nSkip = 0;
985 while ( nArrY+nSkip+2<nArrCount &&
986 lcl_EqualBack( *pThisRowInfo, pRowInfo[nArrY+nSkip+1],
987 nX1, nX2, bShowProt, bPagebreakMode ) )
989 ++nSkip;
990 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
993 long nPosX = nScrX;
994 if ( bLayoutRTL )
995 nPosX += nMirrorW - nOneX;
996 aRect = Rectangle( nPosX, nPosY-nOneY, nPosX, nPosY+nRowHeight-nOneY );
998 const SvxBrushItem* pOldBackground = NULL;
999 const SvxBrushItem* pBackground;
1000 const Color* pOldColor = NULL;
1001 const ScDataBarInfo* pOldDataBarInfo = NULL;
1002 const ScIconSetInfo* pOldIconSetInfo = NULL;
1003 SCCOL nMergedCells = 1;
1004 SCCOL nOldMerged = 0;
1006 for (SCCOL nX=nX1; nX + nMergedCells <= nX2 + 1; nX += nOldMerged)
1008 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+nMergedCells];
1010 nOldMerged = nMergedCells;
1012 if (bCellContrast)
1014 // high contrast for cell borders and backgrounds -> empty background
1015 pBackground = ScGlobal::GetEmptyBrushItem();
1017 else if (bShowProt) // show cell protection in syntax mode
1019 const ScPatternAttr* pP = pInfo->pPatternAttr;
1020 if (pP)
1022 const ScProtectionAttr& rProt = static_cast<const ScProtectionAttr&>(
1023 pP->GetItem(ATTR_PROTECTION));
1024 if (rProt.GetProtection() || rProt.GetHideCell())
1025 pBackground = ScGlobal::GetProtectedBrushItem();
1026 else
1027 pBackground = ScGlobal::GetEmptyBrushItem();
1029 else
1030 pBackground = NULL;
1032 else
1033 pBackground = pInfo->pBackground;
1035 if ( bPagebreakMode && !pInfo->bPrinted )
1036 pBackground = ScGlobal::GetProtectedBrushItem();
1038 if ( pInfo->nRotateDir > SC_ROTDIR_STANDARD &&
1039 pBackground->GetColor().GetTransparency() != 255 &&
1040 !bCellContrast )
1042 SCROW nY = pRowInfo[nArrY].nRowNo;
1043 pBackground = lcl_FindBackground( mpDoc, nX, nY, nTab );
1046 const Color* pColor = pInfo->pColorScale.get();
1047 const ScDataBarInfo* pDataBarInfo = pInfo->pDataBar.get();
1048 const ScIconSetInfo* pIconSetInfo = pInfo->pIconSet.get();
1049 drawCells( pColor, pBackground, pOldColor, pOldBackground, aRect, nPosX, nSignedOneX, mpDev, pDataBarInfo, pOldDataBarInfo, pIconSetInfo, pOldIconSetInfo );
1051 // extend for all merged cells
1052 nMergedCells = 1;
1053 if (pInfo->bMerged && pInfo->pPatternAttr)
1055 const ScMergeAttr* pMerge =
1056 static_cast<const ScMergeAttr*>(&pInfo->pPatternAttr->GetItem(ATTR_MERGE));
1057 nMergedCells = std::max<SCCOL>(1, pMerge->GetColMerge());
1060 for (SCCOL nMerged = 0; nMerged < nMergedCells; ++nMerged)
1062 SCCOL nCol = nX+nOldMerged+nMerged;
1063 if (nCol > nX2+2)
1064 break;
1065 nPosX += pRowInfo[0].pCellInfo[nCol].nWidth * nLayoutSign;
1068 drawCells( NULL, NULL, pOldColor, pOldBackground, aRect, nPosX, nSignedOneX, mpDev, NULL, pOldDataBarInfo, NULL, pOldIconSetInfo );
1070 nArrY += nSkip;
1073 nPosY += nRowHeight;
1077 void ScOutputData::DrawShadow()
1079 DrawExtraShadow( false, false, false, false );
1082 void ScOutputData::DrawExtraShadow(bool bLeft, bool bTop, bool bRight, bool bBottom)
1084 mpDev->SetLineColor();
1086 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1087 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1088 Color aAutoTextColor;
1089 if ( bCellContrast )
1090 aAutoTextColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
1092 long nInitPosX = nScrX;
1093 if ( bLayoutRTL )
1095 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1096 long nOneX = aOnePixel.Width();
1097 nInitPosX += nMirrorW - nOneX;
1099 long nLayoutSign = bLayoutRTL ? -1 : 1;
1101 long nPosY = nScrY - pRowInfo[0].nHeight;
1102 for (SCSIZE nArrY=0; nArrY<nArrCount; nArrY++)
1104 bool bCornerY = ( nArrY == 0 ) || ( nArrY+1 == nArrCount );
1105 bool bSkipY = ( nArrY==0 && !bTop ) || ( nArrY+1 == nArrCount && !bBottom );
1107 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1108 long nRowHeight = pThisRowInfo->nHeight;
1110 if ( pThisRowInfo->bChanged && !bSkipY )
1112 long nPosX = nInitPosX - pRowInfo[0].pCellInfo[nX1].nWidth * nLayoutSign;
1113 for (SCCOL nArrX=nX1; nArrX<=nX2+2; nArrX++)
1115 bool bCornerX = ( nArrX==nX1 || nArrX==nX2+2 );
1116 bool bSkipX = ( nArrX==nX1 && !bLeft ) || ( nArrX==nX2+2 && !bRight );
1118 for (sal_uInt16 nPass=0; nPass<2; nPass++) // horizontal / vertical
1120 const SvxShadowItem* pAttr = nPass ?
1121 pThisRowInfo->pCellInfo[nArrX].pVShadowOrigin :
1122 pThisRowInfo->pCellInfo[nArrX].pHShadowOrigin;
1123 if ( pAttr && !bSkipX )
1125 ScShadowPart ePart = nPass ?
1126 pThisRowInfo->pCellInfo[nArrX].eVShadowPart :
1127 pThisRowInfo->pCellInfo[nArrX].eHShadowPart;
1129 bool bDo = true;
1130 if ( (nPass==0 && bCornerX) || (nPass==1 && bCornerY) )
1131 if ( ePart != SC_SHADOW_CORNER )
1132 bDo = false;
1134 if (bDo)
1136 long nThisWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1137 long nMaxWidth = nThisWidth;
1138 if (!nMaxWidth)
1140 //! direction must depend on shadow location
1141 SCCOL nWx = nArrX; // nX+1
1142 while (nWx<nX2 && !pRowInfo[0].pCellInfo[nWx+1].nWidth)
1143 ++nWx;
1144 nMaxWidth = pRowInfo[0].pCellInfo[nWx+1].nWidth;
1147 // rectangle is in logical orientation
1148 Rectangle aRect( nPosX, nPosY,
1149 nPosX + ( nThisWidth - 1 ) * nLayoutSign,
1150 nPosY + pRowInfo[nArrY].nHeight - 1 );
1152 long nSize = pAttr->GetWidth();
1153 long nSizeX = (long)(nSize*mnPPTX);
1154 if (nSizeX >= nMaxWidth) nSizeX = nMaxWidth-1;
1155 long nSizeY = (long)(nSize*mnPPTY);
1156 if (nSizeY >= nRowHeight) nSizeY = nRowHeight-1;
1158 nSizeX *= nLayoutSign; // used only to add to rectangle values
1160 SvxShadowLocation eLoc = pAttr->GetLocation();
1161 if ( bLayoutRTL )
1163 // Shadow location is specified as "visual" (right is always right),
1164 // so the attribute's location value is mirrored here and in FillInfo.
1165 switch (eLoc)
1167 case SVX_SHADOW_BOTTOMRIGHT: eLoc = SVX_SHADOW_BOTTOMLEFT; break;
1168 case SVX_SHADOW_BOTTOMLEFT: eLoc = SVX_SHADOW_BOTTOMRIGHT; break;
1169 case SVX_SHADOW_TOPRIGHT: eLoc = SVX_SHADOW_TOPLEFT; break;
1170 case SVX_SHADOW_TOPLEFT: eLoc = SVX_SHADOW_TOPRIGHT; break;
1171 default:
1173 // added to avoid warnings
1178 if (ePart == SC_SHADOW_HORIZ || ePart == SC_SHADOW_HSTART ||
1179 ePart == SC_SHADOW_CORNER)
1181 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_TOPRIGHT)
1182 aRect.Top() = aRect.Bottom() - nSizeY;
1183 else
1184 aRect.Bottom() = aRect.Top() + nSizeY;
1186 if (ePart == SC_SHADOW_VERT || ePart == SC_SHADOW_VSTART ||
1187 ePart == SC_SHADOW_CORNER)
1189 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_BOTTOMLEFT)
1190 aRect.Left() = aRect.Right() - nSizeX;
1191 else
1192 aRect.Right() = aRect.Left() + nSizeX;
1194 if (ePart == SC_SHADOW_HSTART)
1196 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_BOTTOMLEFT)
1197 aRect.Right() -= nSizeX;
1198 else
1199 aRect.Left() += nSizeX;
1201 if (ePart == SC_SHADOW_VSTART)
1203 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_TOPRIGHT)
1204 aRect.Bottom() -= nSizeY;
1205 else
1206 aRect.Top() += nSizeY;
1209 //! merge rectangles?
1210 mpDev->SetFillColor( bCellContrast ? aAutoTextColor : pAttr->GetColor() );
1211 mpDev->DrawRect( aRect );
1216 nPosX += pRowInfo[0].pCellInfo[nArrX].nWidth * nLayoutSign;
1219 nPosY += nRowHeight;
1223 void ScOutputData::DrawClear()
1225 Rectangle aRect;
1226 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1227 long nOneX = aOnePixel.Width();
1228 long nOneY = aOnePixel.Height();
1230 // (called only for ScGridWindow)
1231 Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
1233 if (bMetaFile)
1234 nOneX = nOneY = 0;
1236 mpDev->SetLineColor();
1238 mpDev->SetFillColor( aBgColor );
1240 long nPosY = nScrY;
1241 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1243 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1244 long nRowHeight = pThisRowInfo->nHeight;
1246 if ( pThisRowInfo->bChanged )
1248 // scan for more rows which must be painted:
1249 SCSIZE nSkip = 0;
1250 while ( nArrY+nSkip+2<nArrCount && pRowInfo[nArrY+nSkip+1].bChanged )
1252 ++nSkip;
1253 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
1256 aRect = Rectangle( Point( nScrX, nPosY ),
1257 Size( nScrW+1-nOneX, nRowHeight+1-nOneY) );
1258 mpDev->DrawRect( aRect );
1260 nArrY += nSkip;
1262 nPosY += nRowHeight;
1266 // Lines
1268 long lclGetSnappedX( OutputDevice& rDev, long nPosX, bool bSnapPixel )
1270 return (bSnapPixel && nPosX) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( nPosX, 0 ) ) ).Width() : nPosX;
1273 long lclGetSnappedY( OutputDevice& rDev, long nPosY, bool bSnapPixel )
1275 return (bSnapPixel && nPosY) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( 0, nPosY ) ) ).Height() : nPosY;
1278 size_t lclGetArrayColFromCellInfoX( sal_uInt16 nCellInfoX, sal_uInt16 nCellInfoFirstX, sal_uInt16 nCellInfoLastX, bool bRTL )
1280 return static_cast< size_t >( bRTL ? (nCellInfoLastX + 2 - nCellInfoX) : (nCellInfoX - nCellInfoFirstX) );
1283 void ScOutputData::DrawFrame()
1285 DrawModeFlags nOldDrawMode = mpDev->GetDrawMode();
1287 Color aSingleColor;
1288 bool bUseSingleColor = false;
1289 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1290 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1292 // if a Calc OLE object is embedded in Draw/Impress, the VCL DrawMode is used
1293 // for display mode / B&W printing. The VCL DrawMode handling doesn't work for lines
1294 // that are drawn with DrawRect, so if the line/background bits are set, the DrawMode
1295 // must be reset and the border colors handled here.
1297 if ( ( nOldDrawMode & DrawModeFlags::WhiteFill ) && ( nOldDrawMode & DrawModeFlags::BlackLine ) )
1299 mpDev->SetDrawMode( nOldDrawMode & (~DrawModeFlags::WhiteFill) );
1300 aSingleColor.SetColor( COL_BLACK );
1301 bUseSingleColor = true;
1303 else if ( ( nOldDrawMode & DrawModeFlags::SettingsFill ) && ( nOldDrawMode & DrawModeFlags::SettingsLine ) )
1305 mpDev->SetDrawMode( nOldDrawMode & (~DrawModeFlags::SettingsFill) );
1306 aSingleColor = rStyleSettings.GetWindowTextColor(); // same as used in VCL for DrawModeFlags::SettingsLine
1307 bUseSingleColor = true;
1309 else if ( bCellContrast )
1311 aSingleColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
1312 bUseSingleColor = true;
1315 const Color* pForceColor = bUseSingleColor ? &aSingleColor : 0;
1317 if (bAnyRotated)
1318 DrawRotatedFrame( pForceColor ); // removes the lines that must not be painted here
1320 long nInitPosX = nScrX;
1321 if ( bLayoutRTL )
1323 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1324 long nOneX = aOnePixel.Width();
1325 nInitPosX += nMirrorW - nOneX;
1327 long nLayoutSign = bLayoutRTL ? -1 : 1;
1329 // *** set column and row sizes of the frame border array ***
1331 svx::frame::Array& rArray = mrTabInfo.maArray;
1332 size_t nColCount = rArray.GetColCount();
1333 size_t nRowCount = rArray.GetRowCount();
1335 // row heights
1337 // row 0 is not visible (dummy for borders from top) - subtract its height from initial position
1338 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit before
1339 long nOldPosY = nScrY - 1 - pRowInfo[ 0 ].nHeight;
1340 long nOldSnapY = lclGetSnappedY( *mpDev, nOldPosY, bSnapPixel );
1341 rArray.SetYOffset( nOldSnapY );
1342 for( size_t nRow = 0; nRow < nRowCount; ++nRow )
1344 long nNewPosY = nOldPosY + pRowInfo[ nRow ].nHeight;
1345 long nNewSnapY = lclGetSnappedY( *mpDev, nNewPosY, bSnapPixel );
1346 rArray.SetRowHeight( nRow, nNewSnapY - nOldSnapY );
1347 nOldPosY = nNewPosY;
1348 nOldSnapY = nNewSnapY;
1351 // column widths
1353 // column nX1 is not visible (dummy for borders from left) - subtract its width from initial position
1354 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit above
1355 long nOldPosX = nInitPosX - nLayoutSign * (1 + pRowInfo[ 0 ].pCellInfo[ nX1 ].nWidth);
1356 long nOldSnapX = lclGetSnappedX( *mpDev, nOldPosX, bSnapPixel );
1357 // set X offset for left-to-right sheets; for right-to-left sheets this is done after for() loop
1358 if( !bLayoutRTL )
1359 rArray.SetXOffset( nOldSnapX );
1360 for( sal_uInt16 nInfoIdx = nX1; nInfoIdx <= nX2 + 2; ++nInfoIdx )
1362 size_t nCol = lclGetArrayColFromCellInfoX( nInfoIdx, nX1, nX2, bLayoutRTL );
1363 long nNewPosX = nOldPosX + pRowInfo[ 0 ].pCellInfo[ nInfoIdx ].nWidth * nLayoutSign;
1364 long nNewSnapX = lclGetSnappedX( *mpDev, nNewPosX, bSnapPixel );
1365 rArray.SetColWidth( nCol, std::abs( nNewSnapX - nOldSnapX ) );
1366 nOldPosX = nNewPosX;
1367 nOldSnapX = nNewSnapX;
1369 if( bLayoutRTL )
1370 rArray.SetXOffset( nOldSnapX );
1372 // *** draw the array ***
1374 size_t nFirstCol = 1;
1375 size_t nFirstRow = 1;
1376 size_t nLastCol = nColCount - 2;
1377 size_t nLastRow = nRowCount - 2;
1379 if( mrTabInfo.mbPageMode )
1380 rArray.SetClipRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
1382 // draw only rows with set RowInfo::bChanged flag
1383 size_t nRow1 = nFirstRow;
1384 boost::scoped_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D());
1385 if (!pProcessor)
1386 return;
1388 while( nRow1 <= nLastRow )
1390 while( (nRow1 <= nLastRow) && !pRowInfo[ nRow1 ].bChanged ) ++nRow1;
1391 if( nRow1 <= nLastRow )
1393 size_t nRow2 = nRow1;
1394 while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
1395 rArray.DrawRange( pProcessor.get(), nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
1396 nRow1 = nRow2 + 1;
1399 pProcessor.reset();
1401 mpDev->SetDrawMode(nOldDrawMode);
1404 // Line below the cell
1406 static const ::editeng::SvxBorderLine* lcl_FindHorLine( ScDocument* pDoc,
1407 SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nRotDir,
1408 bool bTopLine )
1410 if ( nRotDir != SC_ROTDIR_LEFT && nRotDir != SC_ROTDIR_RIGHT )
1411 return NULL;
1413 bool bFound = false;
1414 while (!bFound)
1416 if ( nRotDir == SC_ROTDIR_LEFT )
1418 // text to the left -> line from the right
1419 if ( nCol < MAXCOL )
1420 ++nCol;
1421 else
1422 return NULL; // couldn't find it
1424 else
1426 // text to the right -> line from the left
1427 if ( nCol > 0 )
1428 --nCol;
1429 else
1430 return NULL; // couldn't find it
1432 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
1433 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
1434 if ( !pPattern->GetRotateVal( pCondSet ) ||
1435 static_cast<const SvxRotateModeItem&>(pPattern->GetItem(
1436 ATTR_ROTATE_MODE, pCondSet)).GetValue() == SVX_ROTATE_MODE_STANDARD )
1437 bFound = true;
1440 if (bTopLine)
1441 --nRow;
1442 const ::editeng::SvxBorderLine* pThisBottom;
1443 if ( ValidRow(nRow) )
1444 pThisBottom = static_cast<const SvxBoxItem*>(pDoc->GetAttr( nCol, nRow, nTab, ATTR_BORDER ))->GetBottom();
1445 else
1446 pThisBottom = NULL;
1447 const ::editeng::SvxBorderLine* pNextTop;
1448 if ( nRow < MAXROW )
1449 pNextTop = static_cast<const SvxBoxItem*>(pDoc->GetAttr( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
1450 else
1451 pNextTop = NULL;
1453 if ( ScHasPriority( pThisBottom, pNextTop ) )
1454 return pThisBottom;
1455 else
1456 return pNextTop;
1459 static long lcl_getRotate( ScDocument* pDoc, SCTAB nTab, SCCOL nX, SCROW nY )
1461 long nRotate = 0;
1463 const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab );
1464 const SfxItemSet* pCondSet = pDoc->GetCondResult( nX, nY, nTab );
1466 nRotate = pPattern->GetRotateVal( pCondSet );
1468 return nRotate;
1471 void ScOutputData::DrawRotatedFrame( const Color* pForceColor )
1473 //! save nRotMax
1474 SCCOL nRotMax = nX2;
1475 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
1476 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
1477 nRotMax = pRowInfo[nRotY].nRotMaxCol;
1479 const ScPatternAttr* pPattern;
1480 const SfxItemSet* pCondSet;
1482 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1483 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1485 // color (pForceColor) is determined externally, including DrawMode changes
1487 long nInitPosX = nScrX;
1488 if ( bLayoutRTL )
1490 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1491 long nOneX = aOnePixel.Width();
1492 nInitPosX += nMirrorW - nOneX;
1494 long nLayoutSign = bLayoutRTL ? -1 : 1;
1496 Rectangle aClipRect( Point(nScrX, nScrY), Size(nScrW, nScrH) );
1497 if (bMetaFile)
1499 mpDev->Push();
1500 mpDev->IntersectClipRegion( aClipRect );
1502 else
1503 mpDev->SetClipRegion( vcl::Region( aClipRect ) );
1505 svx::frame::Array& rArray = mrTabInfo.maArray;
1506 boost::scoped_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D( ));
1508 long nPosY = nScrY;
1509 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
1511 // Rotated is also drawn one line above/below Changed if parts extend into the cell
1513 RowInfo& rPrevRowInfo = pRowInfo[nArrY-1];
1514 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1515 RowInfo& rNextRowInfo = pRowInfo[nArrY+1];
1517 size_t nRow = static_cast< size_t >( nArrY );
1519 long nRowHeight = rThisRowInfo.nHeight;
1520 if ( rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE &&
1521 ( rThisRowInfo.bChanged || rPrevRowInfo.bChanged ||
1522 ( nArrY+1<nArrCount && rNextRowInfo.bChanged ) ) )
1524 SCROW nY = rThisRowInfo.nRowNo;
1525 long nPosX = 0;
1526 SCCOL nX;
1527 for (nX=0; nX<=nRotMax; nX++)
1529 if (nX==nX1) nPosX = nInitPosX; // calculated individually for preceding positions
1531 sal_uInt16 nArrX = nX + 1;
1533 CellInfo* pInfo = &rThisRowInfo.pCellInfo[nArrX];
1534 long nColWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1535 if ( pInfo->nRotateDir > SC_ROTDIR_STANDARD &&
1536 !pInfo->bHOverlapped && !pInfo->bVOverlapped )
1538 pPattern = pInfo->pPatternAttr;
1539 pCondSet = pInfo->pConditionSet;
1540 if (!pPattern)
1542 pPattern = mpDoc->GetPattern( nX, nY, nTab );
1543 pInfo->pPatternAttr = pPattern;
1544 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
1545 pInfo->pConditionSet = pCondSet;
1548 //! LastPattern etc.
1550 long nAttrRotate = pPattern->GetRotateVal( pCondSet );
1551 SvxRotateMode eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
1552 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
1554 if ( nAttrRotate )
1556 if (nX<nX1) // compute negative position
1558 nPosX = nInitPosX;
1559 SCCOL nCol = nX1;
1560 while (nCol > nX)
1562 --nCol;
1563 nPosX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
1567 // start position minus 1 so rotated backgrounds suit the border
1568 // (border is on the grid)
1570 long nTop = nPosY - 1;
1571 long nBottom = nPosY + nRowHeight - 1;
1572 long nTopLeft = nPosX - nLayoutSign;
1573 long nTopRight = nPosX + ( nColWidth - 1 ) * nLayoutSign;
1574 long nBotLeft = nTopLeft;
1575 long nBotRight = nTopRight;
1577 // inclusion of the sign here hasn't been decided yet
1578 // (if not, the extension of the non-rotated background must also be changed)
1579 double nRealOrient = nLayoutSign * nAttrRotate * F_PI18000; // 1/100th degrees
1580 double nCos = cos( nRealOrient );
1581 double nSin = sin( nRealOrient );
1582 //! restrict !!!
1583 long nSkew = (long) ( nRowHeight * nCos / nSin );
1585 switch (eRotMode)
1587 case SVX_ROTATE_MODE_BOTTOM:
1588 nTopLeft += nSkew;
1589 nTopRight += nSkew;
1590 break;
1591 case SVX_ROTATE_MODE_CENTER:
1592 nSkew /= 2;
1593 nTopLeft += nSkew;
1594 nTopRight += nSkew;
1595 nBotLeft -= nSkew;
1596 nBotRight -= nSkew;
1597 break;
1598 case SVX_ROTATE_MODE_TOP:
1599 nBotLeft -= nSkew;
1600 nBotRight -= nSkew;
1601 break;
1602 default:
1604 // added to avoid warnings
1608 Point aPoints[4];
1609 aPoints[0] = Point( nTopLeft, nTop );
1610 aPoints[1] = Point( nTopRight, nTop );
1611 aPoints[2] = Point( nBotRight, nBottom );
1612 aPoints[3] = Point( nBotLeft, nBottom );
1614 const SvxBrushItem* pBackground = pInfo->pBackground;
1615 if (!pBackground)
1616 pBackground = static_cast<const SvxBrushItem*>( &pPattern->GetItem(
1617 ATTR_BACKGROUND, pCondSet ));
1618 if (bCellContrast)
1620 // high contrast for cell borders and backgrounds -> empty background
1621 pBackground = ScGlobal::GetEmptyBrushItem();
1623 if(!pInfo->pColorScale)
1625 const Color& rColor = pBackground->GetColor();
1626 if ( rColor.GetTransparency() != 255 )
1628 // draw background only for the changed row itself
1629 // (background doesn't extend into other cells).
1630 // For the borders (rotated and normal), clipping should be
1631 // set if the row isn't changed, but at least the borders
1632 // don't cover the cell contents.
1633 if ( rThisRowInfo.bChanged )
1635 Polygon aPoly( 4, aPoints );
1637 // ohne Pen wird bei DrawPolygon rechts und unten
1638 // ein Pixel weggelassen...
1639 if ( rColor.GetTransparency() == 0 )
1640 mpDev->SetLineColor(rColor);
1641 else
1642 mpDev->SetLineColor();
1643 mpDev->SetFillColor(rColor);
1644 mpDev->DrawPolygon( aPoly );
1648 else
1650 Polygon aPoly( 4, aPoints );
1651 const Color* pColor = pInfo->pColorScale.get();
1653 // ohne Pen wird bei DrawPolygon rechts und unten
1654 // ein Pixel weggelassen...
1655 if ( pColor->GetTransparency() == 0 )
1656 mpDev->SetLineColor(*pColor);
1657 else
1658 mpDev->SetLineColor();
1659 mpDev->SetFillColor(*pColor);
1660 mpDev->DrawPolygon( aPoly );
1664 svx::frame::Style aTopLine, aBottomLine, aLeftLine, aRightLine;
1666 if ( nX < nX1 || nX > nX2 ) // Attribute in FillInfo nicht gesetzt
1668 //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
1669 const ::editeng::SvxBorderLine* pLeftLine;
1670 const ::editeng::SvxBorderLine* pTopLine;
1671 const ::editeng::SvxBorderLine* pRightLine;
1672 const ::editeng::SvxBorderLine* pBottomLine;
1673 mpDoc->GetBorderLines( nX, nY, nTab,
1674 &pLeftLine, &pTopLine, &pRightLine, &pBottomLine );
1675 aTopLine.Set( pTopLine, mnPPTY );
1676 aBottomLine.Set( pBottomLine, mnPPTY );
1677 aLeftLine.Set( pLeftLine, mnPPTX );
1678 aRightLine.Set( pRightLine, mnPPTX );
1680 else
1682 size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
1683 aTopLine = rArray.GetCellStyleTop( nCol, nRow );
1684 aBottomLine = rArray.GetCellStyleBottom( nCol, nRow );
1685 aLeftLine = rArray.GetCellStyleLeft( nCol, nRow );
1686 aRightLine = rArray.GetCellStyleRight( nCol, nRow );
1687 // in RTL mode the array is already mirrored -> swap back left/right borders
1688 if( bLayoutRTL )
1689 std::swap( aLeftLine, aRightLine );
1692 // Horizontal lines
1693 if (aTopLine.Prim() || aTopLine.Secn())
1695 long nUpperRotate = lcl_getRotate( mpDoc, nTab, nX, nY - 1 );
1696 pProcessor->process( svx::frame::CreateBorderPrimitives(
1697 aPoints[bLayoutRTL?1:0], aPoints[bLayoutRTL?0:1], aTopLine,
1698 svx::frame::Style(),
1699 svx::frame::Style(),
1700 aLeftLine,
1701 svx::frame::Style(),
1702 svx::frame::Style(),
1703 aRightLine,
1704 pForceColor, nUpperRotate, nAttrRotate ) );
1707 if (aBottomLine.Prim() || aBottomLine.Secn())
1709 long nLowerRotate = lcl_getRotate( mpDoc, nTab, nX, nY + 1 );
1710 pProcessor->process( svx::frame::CreateBorderPrimitives(
1711 aPoints[bLayoutRTL?2:3], aPoints[bLayoutRTL?3:2], aBottomLine,
1712 aLeftLine,
1713 svx::frame::Style(),
1714 svx::frame::Style(),
1715 aRightLine,
1716 svx::frame::Style(),
1717 svx::frame::Style(),
1718 pForceColor, 18000 - nAttrRotate, 18000 - nLowerRotate ) );
1721 // Vertical slanted lines
1722 if (aLeftLine.Prim() || aLeftLine.Secn())
1724 long nLeftRotate = lcl_getRotate( mpDoc, nTab, nX - 1, nY );
1725 pProcessor->process( svx::frame::CreateBorderPrimitives(
1726 aPoints[0], aPoints[3], aLeftLine,
1727 aTopLine,
1728 svx::frame::Style(),
1729 svx::frame::Style(),
1730 aBottomLine,
1731 svx::frame::Style(),
1732 svx::frame::Style(),
1733 pForceColor, nAttrRotate, nLeftRotate ) );
1736 if (aRightLine.Prim() || aRightLine.Secn())
1738 long nRightRotate = lcl_getRotate( mpDoc, nTab, nX + 1, nY );
1739 pProcessor->process( svx::frame::CreateBorderPrimitives(
1740 aPoints[1], aPoints[2], aRightLine,
1741 svx::frame::Style(),
1742 svx::frame::Style(),
1743 aTopLine,
1744 svx::frame::Style(),
1745 svx::frame::Style(),
1746 aBottomLine,
1747 pForceColor, 18000 - nRightRotate, 18000 - nAttrRotate ) );
1751 nPosX += nColWidth * nLayoutSign;
1754 // erst hinterher im zweiten Schritt die Linien fuer normale Ausgabe loeschen
1756 nX = nX1 > 0 ? (nX1-1) : static_cast<SCCOL>(0);
1757 for (; nX<=nX2+1; nX++) // sichtbarer Teil +- 1
1759 sal_uInt16 nArrX = nX + 1;
1760 CellInfo& rInfo = rThisRowInfo.pCellInfo[nArrX];
1761 if ( rInfo.nRotateDir > SC_ROTDIR_STANDARD &&
1762 !rInfo.bHOverlapped && !rInfo.bVOverlapped )
1764 size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
1766 // horizontal: angrenzende Linie verlaengern
1767 // (nur, wenn die gedrehte Zelle eine Umrandung hat)
1768 sal_uInt16 nDir = rInfo.nRotateDir;
1769 if ( rArray.GetCellStyleTop( nCol, nRow ).Prim() )
1771 svx::frame::Style aStyle( lcl_FindHorLine( mpDoc, nX, nY, nTab, nDir, true ), mnPPTY );
1772 rArray.SetCellStyleTop( nCol, nRow, aStyle );
1773 if( nRow > 0 )
1774 rArray.SetCellStyleBottom( nCol, nRow - 1, aStyle );
1776 if ( rArray.GetCellStyleBottom( nCol, nRow ).Prim() )
1778 svx::frame::Style aStyle( lcl_FindHorLine( mpDoc, nX, nY, nTab, nDir, false ), mnPPTY );
1779 rArray.SetCellStyleBottom( nCol, nRow, aStyle );
1780 if( nRow + 1 < rArray.GetRowCount() )
1781 rArray.SetCellStyleTop( nCol, nRow + 1, aStyle );
1784 // always remove vertical borders
1785 if( !rArray.IsMergedOverlappedLeft( nCol, nRow ) )
1787 rArray.SetCellStyleLeft( nCol, nRow, svx::frame::Style() );
1788 if( nCol > 0 )
1789 rArray.SetCellStyleRight( nCol - 1, nRow, svx::frame::Style() );
1791 if( !rArray.IsMergedOverlappedRight( nCol, nRow ) )
1793 rArray.SetCellStyleRight( nCol, nRow, svx::frame::Style() );
1794 if( nCol + 1 < rArray.GetColCount() )
1795 rArray.SetCellStyleLeft( nCol + 1, nRow, svx::frame::Style() );
1798 // remove diagonal borders
1799 rArray.SetCellStyleTLBR( nCol, nRow, svx::frame::Style() );
1800 rArray.SetCellStyleBLTR( nCol, nRow, svx::frame::Style() );
1804 nPosY += nRowHeight;
1807 pProcessor.reset();
1809 if (bMetaFile)
1810 mpDev->Pop();
1811 else
1812 mpDev->SetClipRegion();
1815 drawinglayer::processor2d::BaseProcessor2D* ScOutputData::CreateProcessor2D( )
1817 mpDoc->InitDrawLayer(mpDoc->GetDocumentShell());
1818 ScDrawLayer* pDrawLayer = mpDoc->GetDrawLayer();
1819 if (!pDrawLayer)
1820 return NULL;
1822 basegfx::B2DRange aViewRange;
1823 SdrPage *pDrawPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
1824 const drawinglayer::geometry::ViewInformation2D aNewViewInfos(
1825 basegfx::B2DHomMatrix( ),
1826 mpDev->GetViewTransformation(),
1827 aViewRange,
1828 GetXDrawPageForSdrPage( pDrawPage ),
1829 0.0,
1830 uno::Sequence< beans::PropertyValue >() );
1832 return drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
1833 *mpDev, aNewViewInfos );
1836 // Printer
1838 vcl::Region ScOutputData::GetChangedAreaRegion()
1840 vcl::Region aRegion;
1841 Rectangle aDrawingRect;
1842 bool bHad(false);
1843 long nPosY = nScrY;
1844 SCSIZE nArrY;
1846 aDrawingRect.Left() = nScrX;
1847 aDrawingRect.Right() = nScrX+nScrW-1;
1849 for(nArrY=1; nArrY+1<nArrCount; nArrY++)
1851 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1853 if(pThisRowInfo->bChanged)
1855 if(!bHad)
1857 aDrawingRect.Top() = nPosY;
1858 bHad = true;
1861 aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1863 else if(bHad)
1865 aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1866 bHad = false;
1869 nPosY += pRowInfo[nArrY].nHeight;
1872 if(bHad)
1874 aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1877 return aRegion;
1880 bool ScOutputData::SetChangedClip()
1882 tools::PolyPolygon aPoly;
1884 Rectangle aDrawingRect;
1885 aDrawingRect.Left() = nScrX;
1886 aDrawingRect.Right() = nScrX+nScrW-1;
1888 bool bHad = false;
1889 long nPosY = nScrY;
1890 SCSIZE nArrY;
1891 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1893 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1895 if ( pThisRowInfo->bChanged )
1897 if (!bHad)
1899 aDrawingRect.Top() = nPosY;
1900 bHad = true;
1902 aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1904 else if (bHad)
1906 aPoly.Insert( Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1907 bHad = false;
1909 nPosY += pRowInfo[nArrY].nHeight;
1912 if (bHad)
1913 aPoly.Insert( Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1915 bool bRet = (aPoly.Count() != 0);
1916 if (bRet)
1917 mpDev->SetClipRegion(vcl::Region(aPoly));
1918 return bRet;
1921 void ScOutputData::FindChanged()
1923 SCCOL nX;
1924 SCSIZE nArrY;
1926 bool bWasIdleEnabled = mpDoc->IsIdleEnabled();
1927 mpDoc->EnableIdle(false);
1928 for (nArrY=0; nArrY<nArrCount; nArrY++)
1929 pRowInfo[nArrY].bChanged = false;
1931 bool bProgress = false;
1932 for (nArrY=0; nArrY<nArrCount; nArrY++)
1934 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1935 for (nX=nX1; nX<=nX2; nX++)
1937 const ScRefCellValue& rCell = pThisRowInfo->pCellInfo[nX+1].maCell;
1939 if (rCell.meType != CELLTYPE_FORMULA)
1940 continue;
1942 ScFormulaCell* pFCell = rCell.mpFormula;
1943 if ( !bProgress && pFCell->GetDirty() )
1945 ScProgress::CreateInterpretProgress(mpDoc, true);
1946 bProgress = true;
1948 if (pFCell->IsRunning())
1949 // still being interpreted. Skip it.
1950 continue;
1952 (void)pFCell->GetValue();
1953 if (!pFCell->IsChanged())
1954 // the result hasn't changed. Skip it.
1955 continue;
1957 pThisRowInfo->bChanged = true;
1958 if ( pThisRowInfo->pCellInfo[nX+1].bMerged )
1960 SCSIZE nOverY = nArrY + 1;
1961 while ( nOverY<nArrCount &&
1962 pRowInfo[nOverY].pCellInfo[nX+1].bVOverlapped )
1964 pRowInfo[nOverY].bChanged = true;
1965 ++nOverY;
1970 if ( bProgress )
1971 ScProgress::DeleteInterpretProgress();
1972 mpDoc->EnableIdle(bWasIdleEnabled);
1975 void ScOutputData::DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
1976 SCCOL nRefEndX, SCROW nRefEndY,
1977 const Color& rColor, bool bHandle )
1979 PutInOrder( nRefStartX, nRefEndX );
1980 PutInOrder( nRefStartY, nRefEndY );
1982 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
1983 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
1985 if ( nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
1986 nRefStartY <= nVisY2 && nRefEndY >= nVisY1 )
1988 long nMinX = nScrX;
1989 long nMinY = nScrY;
1990 long nMaxX = nScrX + nScrW - 1;
1991 long nMaxY = nScrY + nScrH - 1;
1992 if ( bLayoutRTL )
1994 long nTemp = nMinX;
1995 nMinX = nMaxX;
1996 nMaxX = nTemp;
1998 long nLayoutSign = bLayoutRTL ? -1 : 1;
2000 bool bTop = false;
2001 bool bBottom = false;
2002 bool bLeft = false;
2003 bool bRight = false;
2005 long nPosY = nScrY;
2006 bool bNoStartY = ( nY1 < nRefStartY );
2007 bool bNoEndY = false;
2008 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
2010 SCROW nY = pRowInfo[nArrY].nRowNo;
2012 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2014 nMinY = nPosY;
2015 bTop = true;
2017 if ( nY==nRefEndY )
2019 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
2020 bBottom = true;
2022 if ( nY>nRefEndY && bNoEndY )
2024 nMaxY = nPosY-2;
2025 bBottom = true;
2027 bNoStartY = ( nY < nRefStartY );
2028 bNoEndY = ( nY < nRefEndY );
2029 nPosY += pRowInfo[nArrY].nHeight;
2032 long nPosX = nScrX;
2033 if ( bLayoutRTL )
2034 nPosX += nMirrorW - 1; // always in pixels
2036 for (SCCOL nX=nX1; nX<=nX2; nX++)
2038 if ( nX==nRefStartX )
2040 nMinX = nPosX;
2041 bLeft = true;
2043 if ( nX==nRefEndX )
2045 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 2 ) * nLayoutSign;
2046 bRight = true;
2048 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2051 if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2052 nMaxY >= nMinY )
2054 mpDev->SetLineColor( rColor );
2055 if (bTop && bBottom && bLeft && bRight)
2057 mpDev->SetFillColor();
2058 mpDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2060 else
2062 if (bTop)
2063 mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMaxX, nMinY ) );
2064 if (bBottom)
2065 mpDev->DrawLine( Point( nMinX, nMaxY ), Point( nMaxX, nMaxY ) );
2066 if (bLeft)
2067 mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMinX, nMaxY ) );
2068 if (bRight)
2069 mpDev->DrawLine( Point( nMaxX, nMinY ), Point( nMaxX, nMaxY ) );
2071 if ( bHandle && bRight && bBottom )
2073 mpDev->SetLineColor( rColor );
2074 mpDev->SetFillColor( rColor );
2076 const sal_Int32 aRadius = 4;
2078 sal_Int32 aRectMaxX1 = nMaxX - nLayoutSign * aRadius;
2079 sal_Int32 aRectMaxX2 = nMaxX + nLayoutSign;
2080 sal_Int32 aRectMinX1 = nMinX - nLayoutSign;
2081 sal_Int32 aRectMinX2 = nMinX + nLayoutSign * aRadius;
2083 sal_Int32 aRectMaxY1 = nMaxY - aRadius;
2084 sal_Int32 aRectMaxY2 = nMaxY + 1;
2085 sal_Int32 aRectMinY1 = nMinY - 1;
2086 sal_Int32 aRectMinY2 = nMinY + aRadius;
2088 // Draw corner rectangles
2089 Rectangle aLowerRight( aRectMaxX1, aRectMaxY1, aRectMaxX2, aRectMaxY2 );
2090 Rectangle aUpperLeft ( aRectMinX1, aRectMinY1, aRectMinX2, aRectMinY2 );
2091 Rectangle aLowerLeft ( aRectMinX1, aRectMaxY1, aRectMinX2, aRectMaxY2 );
2092 Rectangle aUpperRight( aRectMaxX1, aRectMinY1, aRectMaxX2, aRectMinY2 );
2094 mpDev->DrawTransparent( tools::PolyPolygon( Polygon( aLowerRight ) ), lclCornerRectTransparency );
2095 mpDev->DrawTransparent( tools::PolyPolygon( Polygon( aUpperLeft ) ), lclCornerRectTransparency );
2096 mpDev->DrawTransparent( tools::PolyPolygon( Polygon( aLowerLeft ) ), lclCornerRectTransparency );
2097 mpDev->DrawTransparent( tools::PolyPolygon( Polygon( aUpperRight ) ), lclCornerRectTransparency );
2103 void ScOutputData::DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
2104 SCCOL nRefEndX, SCROW nRefEndY,
2105 const Color& rColor, sal_uInt16 nType )
2107 PutInOrder( nRefStartX, nRefEndX );
2108 PutInOrder( nRefStartY, nRefEndY );
2110 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2111 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
2113 if ( nRefStartX <= nVisX2 + 1 && nRefEndX >= nVisX1 &&
2114 nRefStartY <= nVisY2 + 1 && nRefEndY >= nVisY1 ) // +1 because it touches next cells left/top
2116 long nMinX = nScrX;
2117 long nMinY = nScrY;
2118 long nMaxX = nScrX+nScrW-1;
2119 long nMaxY = nScrY+nScrH-1;
2120 if ( bLayoutRTL )
2122 long nTemp = nMinX;
2123 nMinX = nMaxX;
2124 nMaxX = nTemp;
2126 long nLayoutSign = bLayoutRTL ? -1 : 1;
2128 bool bTop = false;
2129 bool bBottom = false;
2130 bool bLeft = false;
2131 bool bRight = false;
2133 long nPosY = nScrY;
2134 bool bNoStartY = ( nY1 < nRefStartY );
2135 bool bNoEndY = false;
2136 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
2138 SCROW nY = pRowInfo[nArrY].nRowNo;
2140 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2142 nMinY = nPosY - 1;
2143 bTop = true;
2145 if ( nY==nRefEndY )
2147 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 1;
2148 bBottom = true;
2150 if ( nY>nRefEndY && bNoEndY )
2152 nMaxY = nPosY - 1;
2153 bBottom = true;
2155 bNoStartY = ( nY < nRefStartY );
2156 bNoEndY = ( nY < nRefEndY );
2157 nPosY += pRowInfo[nArrY].nHeight;
2160 long nPosX = nScrX;
2161 if ( bLayoutRTL )
2162 nPosX += nMirrorW - 1; // always in pixels
2164 for (SCCOL nX=nX1; nX<=nX2+1; nX++)
2166 if ( nX==nRefStartX )
2168 nMinX = nPosX - nLayoutSign;
2169 bLeft = true;
2171 if ( nX==nRefEndX )
2173 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 1 ) * nLayoutSign;
2174 bRight = true;
2176 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2179 if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2180 nMaxY >= nMinY )
2182 if ( nType == SC_CAT_DELETE_ROWS )
2183 bLeft = bRight = bBottom = false; //! thick lines???
2184 else if ( nType == SC_CAT_DELETE_COLS )
2185 bTop = bBottom = bRight = false; //! thick lines???
2187 mpDev->SetLineColor( rColor );
2188 if (bTop && bBottom && bLeft && bRight)
2190 mpDev->SetFillColor();
2191 mpDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2193 else
2195 if (bTop)
2197 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
2198 if ( nType == SC_CAT_DELETE_ROWS )
2199 mpDev->DrawLine( Point( nMinX,nMinY+1 ), Point( nMaxX,nMinY+1 ) );
2201 if (bBottom)
2202 mpDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2203 if (bLeft)
2205 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
2206 if ( nType == SC_CAT_DELETE_COLS )
2207 mpDev->DrawLine( Point( nMinX+nLayoutSign,nMinY ), Point( nMinX+nLayoutSign,nMaxY ) );
2209 if (bRight)
2210 mpDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
2212 if ( bLeft && bTop )
2214 mpDev->SetLineColor();
2215 mpDev->SetFillColor( rColor );
2216 mpDev->DrawRect( Rectangle( nMinX+nLayoutSign, nMinY+1, nMinX+3*nLayoutSign, nMinY+3 ) );
2222 void ScOutputData::DrawChangeTrack()
2224 ScChangeTrack* pTrack = mpDoc->GetChangeTrack();
2225 ScChangeViewSettings* pSettings = mpDoc->GetChangeViewSettings();
2226 if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
2227 return; // nix da oder abgeschaltet
2229 ScActionColorChanger aColorChanger(*pTrack);
2231 // Clipping passiert von aussen
2232 //! ohne Clipping, nur betroffene Zeilen painten ??!??!?
2234 SCCOL nEndX = nX2;
2235 SCROW nEndY = nY2;
2236 if ( nEndX < MAXCOL ) ++nEndX; // auch noch von der naechsten Zelle, weil die Markierung
2237 if ( nEndY < MAXROW ) ++nEndY; // in die jeweils vorhergehende Zelle hineinragt
2238 ScRange aViewRange( nX1, nY1, nTab, nEndX, nEndY, nTab );
2239 const ScChangeAction* pAction = pTrack->GetFirst();
2240 while (pAction)
2242 ScChangeActionType eActionType;
2243 if ( pAction->IsVisible() )
2245 eActionType = pAction->GetType();
2246 const ScBigRange& rBig = pAction->GetBigRange();
2247 if ( rBig.aStart.Tab() == nTab )
2249 ScRange aRange = rBig.MakeRange();
2251 if ( eActionType == SC_CAT_DELETE_ROWS )
2252 aRange.aEnd.SetRow( aRange.aStart.Row() );
2253 else if ( eActionType == SC_CAT_DELETE_COLS )
2254 aRange.aEnd.SetCol( aRange.aStart.Col() );
2256 if ( aRange.Intersects( aViewRange ) &&
2257 ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2259 aColorChanger.Update( *pAction );
2260 Color aColor( aColorChanger.GetColor() );
2261 DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2262 aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2266 if ( eActionType == SC_CAT_MOVE &&
2267 static_cast<const ScChangeActionMove*>(pAction)->
2268 GetFromRange().aStart.Tab() == nTab )
2270 ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)->
2271 GetFromRange().MakeRange();
2272 if ( aRange.Intersects( aViewRange ) &&
2273 ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2275 aColorChanger.Update( *pAction );
2276 Color aColor( aColorChanger.GetColor() );
2277 DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2278 aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2283 pAction = pAction->GetNext();
2287 //TODO: moggi Need to check if this can't be written simpler
2288 void ScOutputData::DrawNoteMarks()
2291 bool bFirst = true;
2293 long nInitPosX = nScrX;
2294 if ( bLayoutRTL )
2295 nInitPosX += nMirrorW - 1; // always in pixels
2296 long nLayoutSign = bLayoutRTL ? -1 : 1;
2298 long nPosY = nScrY;
2299 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2301 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2302 if ( pThisRowInfo->bChanged )
2304 long nPosX = nInitPosX;
2305 for (SCCOL nX=nX1; nX<=nX2; nX++)
2307 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2308 bool bIsMerged = false;
2310 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2312 // find start of merged cell
2313 bIsMerged = true;
2314 SCROW nY = pRowInfo[nArrY].nRowNo;
2315 SCCOL nMergeX = nX;
2316 SCROW nMergeY = nY;
2317 mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2318 // use origin's pCell for NotePtr test below
2321 if ( mpDoc->GetNote(nX, pRowInfo[nArrY].nRowNo, nTab) && ( bIsMerged ||
2322 ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2324 if (bFirst)
2326 mpDev->SetLineColor(COL_WHITE);
2328 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2329 if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2330 mpDev->SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2331 else
2332 mpDev->SetFillColor(COL_LIGHTRED);
2334 bFirst = false;
2337 long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 4 ) * nLayoutSign;
2338 if ( bIsMerged || pInfo->bMerged )
2340 // if merged, add widths of all cells
2341 SCCOL nNextX = nX + 1;
2342 while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2344 nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2345 ++nNextX;
2348 if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2349 mpDev->DrawRect( Rectangle( nMarkX-5*nLayoutSign,nPosY,nMarkX+1*nLayoutSign,nPosY+6 ) );
2352 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2355 nPosY += pThisRowInfo->nHeight;
2359 void ScOutputData::AddPDFNotes()
2361 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, mpDev->GetExtOutDevData() );
2362 if ( !pPDFData || !pPDFData->GetIsExportNotes() )
2363 return;
2365 long nInitPosX = nScrX;
2366 if ( bLayoutRTL )
2368 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
2369 long nOneX = aOnePixel.Width();
2370 nInitPosX += nMirrorW - nOneX;
2372 long nLayoutSign = bLayoutRTL ? -1 : 1;
2374 long nPosY = nScrY;
2375 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2377 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2378 if ( pThisRowInfo->bChanged )
2380 long nPosX = nInitPosX;
2381 for (SCCOL nX=nX1; nX<=nX2; nX++)
2383 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2384 bool bIsMerged = false;
2385 SCROW nY = pRowInfo[nArrY].nRowNo;
2386 SCCOL nMergeX = nX;
2387 SCROW nMergeY = nY;
2389 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2391 // find start of merged cell
2392 bIsMerged = true;
2393 mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2394 // use origin's pCell for NotePtr test below
2397 if ( mpDoc->GetNote(nMergeX, nMergeY, nTab) && ( bIsMerged ||
2398 ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2400 long nNoteWidth = (long)( SC_CLIPMARK_SIZE * mnPPTX );
2401 long nNoteHeight = (long)( SC_CLIPMARK_SIZE * mnPPTY );
2403 long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - nNoteWidth ) * nLayoutSign;
2404 if ( bIsMerged || pInfo->bMerged )
2406 // if merged, add widths of all cells
2407 SCCOL nNextX = nX + 1;
2408 while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2410 nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2411 ++nNextX;
2414 if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2416 Rectangle aNoteRect( nMarkX, nPosY, nMarkX+nNoteWidth*nLayoutSign, nPosY+nNoteHeight );
2417 const ScPostIt* pNote = mpDoc->GetNote(nMergeX, nMergeY, nTab);
2419 // Note title is the cell address (as on printed note pages)
2420 ScAddress aAddress( nMergeX, nMergeY, nTab );
2421 OUString aTitle(aAddress.Format(SCA_VALID, mpDoc, mpDoc->GetAddressConvention()));
2423 // Content has to be a simple string without line breaks
2424 OUString aContent = pNote->GetText();
2425 aContent = aContent.replaceAll("\n", " ");
2427 vcl::PDFNote aNote;
2428 aNote.Title = aTitle;
2429 aNote.Contents = aContent;
2430 pPDFData->CreateNote( aNoteRect, aNote );
2434 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2437 nPosY += pThisRowInfo->nHeight;
2441 void ScOutputData::DrawClipMarks()
2443 if (!bAnyClipped)
2444 return;
2446 Color aArrowFillCol( COL_LIGHTRED );
2448 DrawModeFlags nOldDrawMode = mpDev->GetDrawMode();
2449 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2450 if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2452 // use DrawMode to change the arrow's outline color
2453 mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::SettingsLine );
2454 // use text color also for the fill color
2455 aArrowFillCol.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2458 long nInitPosX = nScrX;
2459 if ( bLayoutRTL )
2460 nInitPosX += nMirrorW - 1; // always in pixels
2461 long nLayoutSign = bLayoutRTL ? -1 : 1;
2463 Rectangle aCellRect;
2464 long nPosY = nScrY;
2465 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2467 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2468 if ( pThisRowInfo->bChanged )
2470 SCROW nY = pThisRowInfo->nRowNo;
2471 long nPosX = nInitPosX;
2472 for (SCCOL nX=nX1; nX<=nX2; nX++)
2474 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2475 if (pInfo->nClipMark)
2477 if (pInfo->bHOverlapped || pInfo->bVOverlapped)
2479 // merge origin may be outside of visible area - use document functions
2481 SCCOL nOverX = nX;
2482 SCROW nOverY = nY;
2483 long nStartPosX = nPosX;
2484 long nStartPosY = nPosY;
2486 while ( nOverX > 0 && ( static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
2487 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & SC_MF_HOR ) )
2489 --nOverX;
2490 nStartPosX -= nLayoutSign * (long) ( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
2493 while ( nOverY > 0 && ( static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
2494 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & SC_MF_VER ) )
2496 --nOverY;
2497 nStartPosY -= nLayoutSign * (long) ( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
2500 long nOutWidth = (long) ( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
2501 long nOutHeight = (long) ( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
2503 const ScMergeAttr* pMerge = static_cast<const ScMergeAttr*>(
2504 mpDoc->GetAttr( nOverX, nOverY, nTab, ATTR_MERGE ));
2505 SCCOL nCountX = pMerge->GetColMerge();
2506 for (SCCOL i=1; i<nCountX; i++)
2507 nOutWidth += (long) ( mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX );
2508 SCROW nCountY = pMerge->GetRowMerge();
2509 nOutHeight += (long) mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY);
2511 if ( bLayoutRTL )
2512 nStartPosX -= nOutWidth - 1;
2513 aCellRect = Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
2515 else
2517 long nOutWidth = pRowInfo[0].pCellInfo[nX+1].nWidth;
2518 long nOutHeight = pThisRowInfo->nHeight;
2520 if ( pInfo->bMerged && pInfo->pPatternAttr )
2522 SCCOL nOverX = nX;
2523 SCROW nOverY = nY;
2524 const ScMergeAttr* pMerge =
2525 static_cast<const ScMergeAttr*>(&pInfo->pPatternAttr->GetItem(ATTR_MERGE));
2526 SCCOL nCountX = pMerge->GetColMerge();
2527 for (SCCOL i=1; i<nCountX; i++)
2528 nOutWidth += (long) ( mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX );
2529 SCROW nCountY = pMerge->GetRowMerge();
2530 nOutHeight += (long) mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY);
2533 long nStartPosX = nPosX;
2534 if ( bLayoutRTL )
2535 nStartPosX -= nOutWidth - 1;
2536 // #i80447# create aCellRect from two points in case nOutWidth is 0
2537 aCellRect = Rectangle( Point( nStartPosX, nPosY ),
2538 Point( nStartPosX+nOutWidth-1, nPosY+nOutHeight-1 ) );
2541 aCellRect.Bottom() -= 1; // don't paint over the cell grid
2542 if ( bLayoutRTL )
2543 aCellRect.Left() += 1;
2544 else
2545 aCellRect.Right() -= 1;
2547 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
2548 Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
2550 if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_RIGHT : SC_CLIPMARK_LEFT ) )
2552 // visually left
2553 Rectangle aMarkRect = aCellRect;
2554 aMarkRect.Right() = aCellRect.Left()+nMarkPixel-1;
2555 SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, true );
2557 if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_LEFT : SC_CLIPMARK_RIGHT ) )
2559 // visually right
2560 Rectangle aMarkRect = aCellRect;
2561 aMarkRect.Left() = aCellRect.Right()-nMarkPixel+1;
2562 SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, false );
2565 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2568 nPosY += pThisRowInfo->nHeight;
2571 mpDev->SetDrawMode(nOldDrawMode);
2574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */