Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / sc / source / ui / view / output.cxx
blob7ee1a91bfda7e88264ab49418a0b1a423ff277fb
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/brshitem.hxx>
25 #include <editeng/editdata.hxx>
26 #include <svtools/colorcfg.hxx>
27 #include "svtools/optionsdrawinglayer.hxx"
28 #include <svx/rotmodit.hxx>
29 #include <editeng/shaditem.hxx>
30 #include <editeng/svxfont.hxx>
31 #include <svx/svdoole2.hxx>
32 #include <tools/poly.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/pdfextoutdevdata.hxx>
35 #include <svtools/accessibilityoptions.hxx>
36 #include <svx/framelinkarray.hxx>
37 #include <drawinglayer/geometry/viewinformation2d.hxx>
38 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
41 #include <vcl/lineinfo.hxx>
42 #include <vcl/gradient.hxx>
43 #include <svx/unoapi.hxx>
45 #include "output.hxx"
46 #include "document.hxx"
47 #include "drwlayer.hxx"
48 #include "cell.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>
73 using namespace com::sun::star;
75 // STATIC DATA -----------------------------------------------------------
77 // Farben fuer ChangeTracking "nach Autor" wie im Writer (swmodul1.cxx)
79 #define SC_AUTHORCOLORCOUNT 9
81 static ColorData nAuthorColor[ SC_AUTHORCOLORCOUNT ] = {
82 COL_LIGHTRED, COL_LIGHTBLUE, COL_LIGHTMAGENTA,
83 COL_GREEN, COL_RED, COL_BLUE,
84 COL_BROWN, COL_MAGENTA, COL_CYAN };
87 // Hilfsklasse, fuer die Farbzuordnung,
88 // um nicht mehrfach hintereinander denselben User aus der Liste zu suchen
90 class ScActionColorChanger
92 private:
93 const ScAppOptions& rOpt;
94 const std::set<rtl::OUString>& rUsers;
95 rtl::OUString aLastUserName;
96 size_t nLastUserIndex;
97 ColorData nColor;
99 public:
100 ScActionColorChanger( const ScChangeTrack& rTrack );
101 ~ScActionColorChanger() {}
103 void Update( const ScChangeAction& rAction );
104 ColorData GetColor() const { return nColor; }
107 //------------------------------------------------------------------
109 ScActionColorChanger::ScActionColorChanger( const ScChangeTrack& rTrack ) :
110 rOpt( SC_MOD()->GetAppOptions() ),
111 rUsers( rTrack.GetUserCollection() ),
112 nLastUserIndex( 0 ),
113 nColor( COL_BLACK )
117 void ScActionColorChanger::Update( const ScChangeAction& rAction )
119 ColorData nSetColor;
120 switch (rAction.GetType())
122 case SC_CAT_INSERT_COLS:
123 case SC_CAT_INSERT_ROWS:
124 case SC_CAT_INSERT_TABS:
125 nSetColor = rOpt.GetTrackInsertColor();
126 break;
127 case SC_CAT_DELETE_COLS:
128 case SC_CAT_DELETE_ROWS:
129 case SC_CAT_DELETE_TABS:
130 nSetColor = rOpt.GetTrackDeleteColor();
131 break;
132 case SC_CAT_MOVE:
133 nSetColor = rOpt.GetTrackMoveColor();
134 break;
135 default:
136 nSetColor = rOpt.GetTrackContentColor();
137 break;
139 if ( nSetColor != COL_TRANSPARENT ) // Farbe eingestellt
140 nColor = nSetColor;
141 else // nach Autor
143 if (!aLastUserName.equals(rAction.GetUser()))
145 aLastUserName = rAction.GetUser();
146 std::set<rtl::OUString>::const_iterator it = rUsers.find(aLastUserName);
147 if (it == rUsers.end())
149 // empty string is possible if a name wasn't found while saving a 5.0 file
150 SAL_INFO_IF( aLastUserName.isEmpty(), "sc.ui", "Author not found" );
151 nLastUserIndex = 0;
153 else
155 size_t nPos = std::distance(rUsers.begin(), it);
156 nLastUserIndex = nPos % SC_AUTHORCOLORCOUNT;
159 nColor = nAuthorColor[nLastUserIndex];
163 //==================================================================
165 ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
166 ScTableInfo& rTabInfo, ScDocument* pNewDoc,
167 SCTAB nNewTab, long nNewScrX, long nNewScrY,
168 SCCOL nNewX1, SCROW nNewY1, SCCOL nNewX2, SCROW nNewY2,
169 double nPixelPerTwipsX, double nPixelPerTwipsY,
170 const Fraction* pZoomX, const Fraction* pZoomY ) :
171 mpDev( pNewDev ),
172 mpRefDevice( pNewDev ), // default is output device
173 pFmtDevice( pNewDev ), // default is output device
174 mrTabInfo( rTabInfo ),
175 pRowInfo( rTabInfo.mpRowInfo ),
176 nArrCount( rTabInfo.mnArrCount ),
177 mpDoc( pNewDoc ),
178 nTab( nNewTab ),
179 nScrX( nNewScrX ),
180 nScrY( nNewScrY ),
181 nX1( nNewX1 ),
182 nY1( nNewY1 ),
183 nX2( nNewX2 ),
184 nY2( nNewY2 ),
185 eType( eNewType ),
186 mnPPTX( nPixelPerTwipsX ),
187 mnPPTY( nPixelPerTwipsY ),
188 pEditObj( NULL ),
189 pViewShell( NULL ),
190 pDrawView( NULL ), // #114135#
191 bEditMode( false ),
192 bMetaFile( false ),
193 bSingleGrid( false ),
194 bPagebreakMode( false ),
195 bSolidBackground( false ),
196 mbUseStyleColor( false ),
197 mbForceAutoColor( SC_MOD()->GetAccessOptions().GetIsAutomaticFontColor() ),
198 mbSyntaxMode( false ),
199 pValueColor( NULL ),
200 pTextColor( NULL ),
201 pFormulaColor( NULL ),
202 aGridColor( COL_BLACK ),
203 mbShowNullValues( sal_True ),
204 mbShowFormulas( false ),
205 bShowSpellErrors( false ),
206 bMarkClipped( false ), // sal_False fuer Drucker/Metafile etc.
207 bSnapPixel( false ),
208 bAnyRotated( false ),
209 bAnyClipped( false ),
210 mpTargetPaintWindow(0) // #i74769# use SdrPaintWindow direct
212 if (pZoomX)
213 aZoomX = *pZoomX;
214 else
215 aZoomX = Fraction(1,1);
216 if (pZoomY)
217 aZoomY = *pZoomY;
218 else
219 aZoomY = Fraction(1,1);
221 nVisX1 = nX1;
222 nVisY1 = nY1;
223 nVisX2 = nX2;
224 nVisY2 = nY2;
225 mpDoc->StripHidden( nVisX1, nVisY1, nVisX2, nVisY2, nTab );
227 nScrW = 0;
228 for (SCCOL nX=nVisX1; nX<=nVisX2; nX++)
229 nScrW += pRowInfo[0].pCellInfo[nX+1].nWidth;
231 nMirrorW = nScrW;
233 nScrH = 0;
234 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
235 nScrH += pRowInfo[nArrY].nHeight;
237 bTabProtected = mpDoc->IsTabProtected( nTab );
238 nTabTextDirection = mpDoc->GetEditTextDirection( nTab );
239 bLayoutRTL = mpDoc->IsLayoutRTL( nTab );
242 ScOutputData::~ScOutputData()
244 delete pValueColor;
245 delete pTextColor;
246 delete pFormulaColor;
249 void ScOutputData::SetContentDevice( OutputDevice* pContentDev )
251 // use pContentDev instead of pDev where used
253 if ( mpRefDevice == mpDev )
254 mpRefDevice = pContentDev;
255 if ( pFmtDevice == mpDev )
256 pFmtDevice = pContentDev;
257 mpDev = pContentDev;
260 void ScOutputData::SetMirrorWidth( long nNew )
262 nMirrorW = nNew;
265 void ScOutputData::SetGridColor( const Color& rColor )
267 aGridColor = rColor;
270 void ScOutputData::SetMarkClipped( sal_Bool bSet )
272 bMarkClipped = bSet;
275 void ScOutputData::SetShowNullValues( sal_Bool bSet )
277 mbShowNullValues = bSet;
280 void ScOutputData::SetShowFormulas( sal_Bool bSet )
282 mbShowFormulas = bSet;
285 void ScOutputData::SetShowSpellErrors( sal_Bool bSet )
287 bShowSpellErrors = bSet;
290 void ScOutputData::SetSnapPixel( sal_Bool bSet )
292 bSnapPixel = bSet;
295 void ScOutputData::SetEditCell( SCCOL nCol, SCROW nRow )
297 nEditCol = nCol;
298 nEditRow = nRow;
299 bEditMode = sal_True;
302 void ScOutputData::SetMetaFileMode( sal_Bool bNewMode )
304 bMetaFile = bNewMode;
307 void ScOutputData::SetSingleGrid( sal_Bool bNewMode )
309 bSingleGrid = bNewMode;
312 void ScOutputData::SetSyntaxMode( sal_Bool bNewMode )
314 mbSyntaxMode = bNewMode;
315 if (bNewMode)
316 if (!pValueColor)
318 pValueColor = new Color( COL_LIGHTBLUE );
319 pTextColor = new Color( COL_BLACK );
320 pFormulaColor = new Color( COL_GREEN );
324 void ScOutputData::DrawGrid( sal_Bool bGrid, sal_Bool bPage )
326 SCCOL nX;
327 SCROW nY;
328 long nPosX;
329 long nPosY;
330 SCSIZE nArrY;
331 ScBreakType nBreak = BREAK_NONE;
332 ScBreakType nBreakOld = BREAK_NONE;
334 sal_Bool bSingle;
335 Color aPageColor;
336 Color aManualColor;
338 if (bPagebreakMode)
339 bPage = false; // keine "normalen" Umbrueche ueber volle Breite/Hoehe
341 //! um den einen Pixel sieht das Metafile (oder die Druck-Ausgabe) anders aus
342 //! als die Bildschirmdarstellung, aber wenigstens passen Druck und Metafile zusammen
344 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
345 long nOneX = aOnePixel.Width();
346 long nOneY = aOnePixel.Height();
347 if (bMetaFile)
348 nOneX = nOneY = 1;
350 long nLayoutSign = bLayoutRTL ? -1 : 1;
351 long nSignedOneX = nOneX * nLayoutSign;
353 if ( eType == OUTTYPE_WINDOW )
355 const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
356 aPageColor.SetColor( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor );
357 aManualColor.SetColor( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor );
359 else
361 aPageColor = aGridColor;
362 aManualColor = aGridColor;
365 mpDev->SetLineColor( aGridColor );
366 ScGridMerger aGrid( mpDev, nOneX, nOneY );
369 // Vertikale Linien
372 nPosX = nScrX;
373 if ( bLayoutRTL )
374 nPosX += nMirrorW - nOneX;
376 for (nX=nX1; nX<=nX2; nX++)
378 SCCOL nXplus1 = nX+1;
379 SCCOL nXplus2 = nX+2;
380 sal_uInt16 nWidth = pRowInfo[0].pCellInfo[nXplus1].nWidth;
381 if (nWidth)
383 nPosX += nWidth * nLayoutSign;
385 if ( bPage )
387 // Seitenumbrueche auch in ausgeblendeten suchen
388 SCCOL nCol = nXplus1;
389 while (nCol <= MAXCOL)
391 nBreak = mpDoc->HasColBreak(nCol, nTab);
392 bool bHidden = mpDoc->ColHidden(nCol, nTab);
394 if ( nBreak || !bHidden )
395 break;
396 ++nCol;
399 if (nBreak != nBreakOld)
401 aGrid.Flush();
402 mpDev->SetLineColor( (nBreak & BREAK_MANUAL) ? aManualColor :
403 nBreak ? aPageColor : aGridColor );
404 nBreakOld = nBreak;
408 sal_Bool bDraw = bGrid || nBreakOld; // einfaches Gitter nur wenn eingestellt
410 sal_uInt16 nWidthXplus2 = pRowInfo[0].pCellInfo[nXplus2].nWidth;
411 bSingle = bSingleGrid; //! in Fillinfo holen !!!!!
412 if ( nX<MAXCOL && !bSingle )
414 bSingle = ( nWidthXplus2 == 0 );
415 for (nArrY=1; nArrY+1<nArrCount && !bSingle; nArrY++)
417 if (pRowInfo[nArrY].pCellInfo[nXplus2].bHOverlapped)
418 bSingle = sal_True;
419 if (pRowInfo[nArrY].pCellInfo[nXplus1].bHideGrid)
420 bSingle = sal_True;
424 if (bDraw)
426 if ( nX<MAXCOL && bSingle )
428 SCCOL nVisX = nXplus1;
429 while ( nVisX < MAXCOL && !mpDoc->GetColWidth(nVisX,nTab) )
430 ++nVisX;
432 nPosY = nScrY;
433 long nNextY;
434 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
436 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
437 nNextY = nPosY + pThisRowInfo->nHeight;
439 sal_Bool bHOver = pThisRowInfo->pCellInfo[nXplus1].bHideGrid;
440 if (!bHOver)
442 if (nWidthXplus2)
443 bHOver = pThisRowInfo->pCellInfo[nXplus2].bHOverlapped;
444 else
446 if (nVisX <= nX2)
447 bHOver = pThisRowInfo->pCellInfo[nVisX+1].bHOverlapped;
448 else
449 bHOver = ((ScMergeFlagAttr*)mpDoc->GetAttr(
450 nVisX,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG))
451 ->IsHorOverlapped();
452 if (bHOver)
453 bHOver = ((ScMergeFlagAttr*)mpDoc->GetAttr(
454 nXplus1,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG))
455 ->IsHorOverlapped();
459 if (pThisRowInfo->bChanged && !bHOver)
461 aGrid.AddVerLine( nPosX-nSignedOneX, nPosY, nNextY-nOneY );
463 nPosY = nNextY;
466 else
468 aGrid.AddVerLine( nPosX-nSignedOneX, nScrY, nScrY+nScrH-nOneY );
475 // Horizontale Linien
478 bool bHiddenRow = true;
479 SCROW nHiddenEndRow = -1;
480 nPosY = nScrY;
481 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
483 SCSIZE nArrYplus1 = nArrY+1;
484 nY = pRowInfo[nArrY].nRowNo;
485 SCROW nYplus1 = nY+1;
486 nPosY += pRowInfo[nArrY].nHeight;
488 if (pRowInfo[nArrY].bChanged)
490 if ( bPage )
492 for (SCROW i = nYplus1; i <= MAXROW; ++i)
494 if (i > nHiddenEndRow)
495 bHiddenRow = mpDoc->RowHidden(i, nTab, NULL, &nHiddenEndRow);
496 /* TODO: optimize the row break thing for large hidden
497 * segments where HasRowBreak() has to be called
498 * nevertheless for each row, as a row break is drawn also
499 * for hidden rows, above them. This needed to be done only
500 * once per hidden segment, maybe giving manual breaks
501 * priority. Something like GetNextRowBreak() and
502 * GetNextManualRowBreak(). */
503 nBreak = mpDoc->HasRowBreak(i, nTab);
504 if (!bHiddenRow || nBreak)
505 break;
508 if (nBreakOld != nBreak)
510 aGrid.Flush();
511 mpDev->SetLineColor( (nBreak & BREAK_MANUAL) ? aManualColor :
512 (nBreak) ? aPageColor : aGridColor );
513 nBreakOld = nBreak;
517 sal_Bool bDraw = bGrid || nBreakOld; // einfaches Gitter nur wenn eingestellt
519 sal_Bool bNextYisNextRow = (pRowInfo[nArrYplus1].nRowNo == nYplus1);
520 bSingle = !bNextYisNextRow; // Hidden
521 for (SCCOL i=nX1; i<=nX2 && !bSingle; i++)
523 if (pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped)
524 bSingle = sal_True;
527 if (bDraw)
529 if ( bSingle && nY<MAXROW )
531 SCROW nVisY = pRowInfo[nArrYplus1].nRowNo;
533 nPosX = nScrX;
534 if ( bLayoutRTL )
535 nPosX += nMirrorW - nOneX;
537 long nNextX;
538 for (SCCOL i=nX1; i<=nX2; i++)
540 nNextX = nPosX + pRowInfo[0].pCellInfo[i+1].nWidth * nLayoutSign;
541 if (nNextX != nPosX) // sichtbar
543 sal_Bool bVOver;
544 if ( bNextYisNextRow )
545 bVOver = pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped;
546 else
548 bVOver = ((ScMergeFlagAttr*)mpDoc->GetAttr(
549 i,nYplus1,nTab,ATTR_MERGE_FLAG))
550 ->IsVerOverlapped()
551 && ((ScMergeFlagAttr*)mpDoc->GetAttr(
552 i,nVisY,nTab,ATTR_MERGE_FLAG))
553 ->IsVerOverlapped();
554 //! nVisY aus Array ??
556 if (!bVOver)
558 aGrid.AddHorLine( nPosX, nNextX-nSignedOneX, nPosY-nOneY );
561 nPosX = nNextX;
564 else
566 aGrid.AddHorLine( nScrX, nScrX+nScrW-nOneX, nPosY-nOneY );
573 // ----------------------------------------------------------------------------
575 void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
577 bPagebreakMode = sal_True;
578 if (!pPageData)
579 return; // noch nicht initialisiert -> alles "nicht gedruckt"
581 // gedruckten Bereich markieren
582 // (in FillInfo ist schon alles auf sal_False initialisiert)
584 sal_uInt16 nRangeCount = sal::static_int_cast<sal_uInt16>(pPageData->GetCount());
585 for (sal_uInt16 nPos=0; nPos<nRangeCount; nPos++)
587 ScRange aRange = pPageData->GetData( nPos ).GetPrintRange();
589 SCCOL nStartX = Max( aRange.aStart.Col(), nX1 );
590 SCCOL nEndX = Min( aRange.aEnd.Col(), nX2 );
591 SCROW nStartY = Max( aRange.aStart.Row(), nY1 );
592 SCROW nEndY = Min( aRange.aEnd.Row(), nY2 );
594 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
596 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
597 if ( pThisRowInfo->bChanged && pThisRowInfo->nRowNo >= nStartY &&
598 pThisRowInfo->nRowNo <= nEndY )
600 for (SCCOL nX=nStartX; nX<=nEndX; nX++)
601 pThisRowInfo->pCellInfo[nX+1].bPrinted = sal_True;
607 void ScOutputData::FindRotated()
609 //! nRotMax speichern
610 SCCOL nRotMax = nX2;
611 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
612 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
613 nRotMax = pRowInfo[nRotY].nRotMaxCol;
615 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
617 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
618 if ( pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE &&
619 ( pThisRowInfo->bChanged || pRowInfo[nArrY-1].bChanged ||
620 ( nArrY+1<nArrCount && pRowInfo[nArrY+1].bChanged ) ) )
622 SCROW nY = pThisRowInfo->nRowNo;
624 for (SCCOL nX=0; nX<=nRotMax; nX++)
626 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
627 const ScPatternAttr* pPattern = pInfo->pPatternAttr;
628 const SfxItemSet* pCondSet = pInfo->pConditionSet;
630 if ( !pPattern && !mpDoc->ColHidden(nX, nTab) )
632 pPattern = mpDoc->GetPattern( nX, nY, nTab );
633 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
636 if ( pPattern ) // Spalte nicht ausgeblendet
638 sal_uInt8 nDir = pPattern->GetRotateDir( pCondSet );
639 if (nDir != SC_ROTDIR_NONE)
641 pInfo->nRotateDir = nDir;
642 bAnyRotated = sal_True;
650 // ----------------------------------------------------------------------------
652 static sal_uInt16 lcl_GetRotateDir( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
654 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
655 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
657 sal_uInt16 nRet = SC_ROTDIR_NONE;
659 long nAttrRotate = pPattern->GetRotateVal( pCondSet );
660 if ( nAttrRotate )
662 SvxRotateMode eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
663 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
665 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
666 nRet = SC_ROTDIR_STANDARD;
667 else if ( eRotMode == SVX_ROTATE_MODE_CENTER )
668 nRet = SC_ROTDIR_CENTER;
669 else if ( eRotMode == SVX_ROTATE_MODE_TOP || eRotMode == SVX_ROTATE_MODE_BOTTOM )
671 long nRot180 = nAttrRotate % 18000; // 1/100 Grad
672 if ( nRot180 == 9000 )
673 nRet = SC_ROTDIR_CENTER;
674 else if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nRot180 < 9000 ) ||
675 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nRot180 > 9000 ) )
676 nRet = SC_ROTDIR_LEFT;
677 else
678 nRet = SC_ROTDIR_RIGHT;
682 return nRet;
685 static const SvxBrushItem* lcl_FindBackground( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
687 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
688 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
689 const SvxBrushItem* pBackground = (const SvxBrushItem*)
690 &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
692 sal_uInt16 nDir = lcl_GetRotateDir( pDoc, nCol, nRow, nTab );
694 // CENTER wird wie RIGHT behandelt...
695 if ( nDir == SC_ROTDIR_RIGHT || nDir == SC_ROTDIR_CENTER )
697 // Text geht nach rechts -> Hintergrund von links nehmen
698 while ( nCol > 0 && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
699 pBackground->GetColor().GetTransparency() != 255 )
701 --nCol;
702 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
703 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
704 pBackground = (const SvxBrushItem*)&pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
707 else if ( nDir == SC_ROTDIR_LEFT )
709 // Text geht nach links -> Hintergrund von rechts nehmen
710 while ( nCol < MAXCOL && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
711 pBackground->GetColor().GetTransparency() != 255 )
713 ++nCol;
714 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
715 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
716 pBackground = (const SvxBrushItem*)&pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
720 return pBackground;
723 // ----------------------------------------------------------------------------
725 static sal_Bool lcl_EqualBack( const RowInfo& rFirst, const RowInfo& rOther,
726 SCCOL nX1, SCCOL nX2, sal_Bool bShowProt, sal_Bool bPagebreakMode )
728 if ( rFirst.bChanged != rOther.bChanged ||
729 rFirst.bEmptyBack != rOther.bEmptyBack )
730 return false;
732 SCCOL nX;
733 if ( bShowProt )
735 for ( nX=nX1; nX<=nX2; nX++ )
737 const ScPatternAttr* pPat1 = rFirst.pCellInfo[nX+1].pPatternAttr;
738 const ScPatternAttr* pPat2 = rOther.pCellInfo[nX+1].pPatternAttr;
739 if ( !pPat1 || !pPat2 ||
740 &pPat1->GetItem(ATTR_PROTECTION) != &pPat2->GetItem(ATTR_PROTECTION) )
741 return false;
744 else
746 for ( nX=nX1; nX<=nX2; nX++ )
747 if ( rFirst.pCellInfo[nX+1].pBackground != rOther.pCellInfo[nX+1].pBackground )
748 return false;
751 if ( rFirst.nRotMaxCol != SC_ROTMAX_NONE || rOther.nRotMaxCol != SC_ROTMAX_NONE )
752 for ( nX=nX1; nX<=nX2; nX++ )
753 if ( rFirst.pCellInfo[nX+1].nRotateDir != rOther.pCellInfo[nX+1].nRotateDir )
754 return false;
756 if ( bPagebreakMode )
757 for ( nX=nX1; nX<=nX2; nX++ )
758 if ( rFirst.pCellInfo[nX+1].bPrinted != rOther.pCellInfo[nX+1].bPrinted )
759 return false;
761 for ( nX=nX1; nX<=nX2; nX++ )
763 const Color* pCol1 = rFirst.pCellInfo[nX+1].pColorScale;
764 const Color* pCol2 = rOther.pCellInfo[nX+1].pColorScale;
765 if( (pCol1 && !pCol2) || (!pCol1 && pCol2) )
766 return false;
768 if (pCol1 && (*pCol1 != *pCol2))
769 return false;
771 const ScDataBarInfo* pInfo1 = rFirst.pCellInfo[nX+1].pDataBar;
772 const ScDataBarInfo* pInfo2 = rOther.pCellInfo[nX+1].pDataBar;
774 if( (pInfo1 && !pInfo2) || (!pInfo1 && pInfo2) )
775 return false;
777 if (pInfo1 && (*pInfo1 != *pInfo2))
778 return false;
780 // each cell with an icon set should be painted the same way
781 const ScIconSetInfo* pIconSet1 = rFirst.pCellInfo[nX+1].pIconSet;
782 const ScIconSetInfo* pIconSet2 = rOther.pCellInfo[nX+1].pIconSet;
784 if(pIconSet1 || pIconSet2)
785 return false;
788 return sal_True;
791 void ScOutputData::DrawDocumentBackground()
793 if ( !bSolidBackground )
794 return;
796 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
797 long nOneX = aOnePixel.Width();
798 long nOneY = aOnePixel.Height();
799 Rectangle aRect(nScrX - nOneX, nScrY - nOneY, nScrX + nScrW, nScrY + nScrH);
800 Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
801 mpDev->SetFillColor(aBgColor);
802 mpDev->DrawRect(aRect);
805 namespace {
807 void drawDataBars( const ScDataBarInfo* pOldDataBarInfo, OutputDevice* pDev, const Rectangle& rRect)
809 long nPosZero = 0;
810 Rectangle aPaintRect = rRect;
811 aPaintRect.Top() += 2;
812 aPaintRect.Bottom() -= 2;
813 aPaintRect.Left() += 2;
814 aPaintRect.Right() -= 2;
815 if(pOldDataBarInfo->mnZero)
817 //need to calculate null point in cell
818 long nLength = aPaintRect.Right() - aPaintRect.Left();
819 nPosZero = static_cast<long>(aPaintRect.Left() + nLength*pOldDataBarInfo->mnZero/100.0);
821 else
823 nPosZero = aPaintRect.Left();
826 if(pOldDataBarInfo->mnLength < 0)
828 aPaintRect.Right() = nPosZero;
829 long nLength = nPosZero - aPaintRect.Left();
830 aPaintRect.Left() = nPosZero + static_cast<long>(nLength * pOldDataBarInfo->mnLength/100.0);
832 else if(pOldDataBarInfo->mnLength > 0)
834 aPaintRect.Left() = nPosZero;
835 long nLength = aPaintRect.Right() - nPosZero;
836 aPaintRect.Right() = nPosZero + static_cast<long>(nLength * pOldDataBarInfo->mnLength/100.0);
838 else
839 return;
841 if(pOldDataBarInfo->mbGradient)
843 pDev->SetLineColor(pOldDataBarInfo->maColor);
844 Gradient aGradient(GradientStyle_LINEAR, pOldDataBarInfo->maColor, COL_TRANSPARENT);
846 if(pOldDataBarInfo->mnLength < 0)
847 aGradient.SetAngle(2700);
848 else
849 aGradient.SetAngle(900);
851 pDev->DrawGradient(aPaintRect, aGradient);
853 pDev->SetLineColor();
855 else
857 pDev->SetFillColor(pOldDataBarInfo->maColor);
858 pDev->DrawRect(aPaintRect);
861 //draw axis
862 if(pOldDataBarInfo->mnZero && pOldDataBarInfo->mnZero != 100)
864 Point aPoint1(nPosZero, rRect.Top());
865 Point aPoint2(nPosZero, rRect.Bottom());
866 LineInfo aLineInfo(LINE_DASH, 1);
867 aLineInfo.SetDashCount( 4 );
868 aLineInfo.SetDistance( 3 );
869 aLineInfo.SetDashLen( 3 );
870 pDev->SetFillColor(pOldDataBarInfo->maAxisColor);
871 pDev->SetLineColor(pOldDataBarInfo->maAxisColor);
872 pDev->DrawLine(aPoint1, aPoint2, aLineInfo);
873 pDev->SetLineColor();
874 pDev->SetFillColor();
878 BitmapEx& getIcon( ScIconSetType eType, sal_Int32 nIndex )
880 return ScIconSetFormat::getBitmap( eType, nIndex );
883 void drawIconSets( const ScIconSetInfo* pOldIconSetInfo, OutputDevice* pDev, const Rectangle& rRect )
885 long nSize = 16;
886 ScIconSetType eType = pOldIconSetInfo->eIconSetType;
887 sal_Int32 nIndex = pOldIconSetInfo->nIconIndex;
888 BitmapEx& rIcon = getIcon( eType, nIndex );
889 pDev->DrawBitmapEx( Point( rRect.Left() +2, rRect.Top() + 2 ), Size( nSize, nSize ), rIcon );
892 void drawCells(const Color* pColor, const SvxBrushItem* pBackground, const Color*& pOldColor, const SvxBrushItem*& pOldBackground,
893 Rectangle& rRect, long nPosX, long nSignedOneX, OutputDevice* pDev, const ScDataBarInfo* pDataBarInfo, const ScDataBarInfo*& pOldDataBarInfo,
894 const ScIconSetInfo* pIconSetInfo, const ScIconSetInfo*& pOldIconSetInfo)
897 // need to paint if old color scale has been used and now
898 // we have a different color or a style based background
899 // we can here fall back to pointer comparison
900 if (pOldColor && (pBackground || pOldColor != pColor || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo))
902 rRect.Right() = nPosX-nSignedOneX;
903 if( !pOldColor->GetTransparency() )
905 pDev->SetFillColor( *pOldColor );
906 pDev->DrawRect( rRect );
908 if( pOldDataBarInfo )
909 drawDataBars( pOldDataBarInfo, pDev, rRect );
910 if( pOldIconSetInfo )
911 drawIconSets( pOldIconSetInfo, pDev, rRect );
913 rRect.Left() = nPosX - nSignedOneX;
916 if ( pOldBackground && (pColor ||pBackground != pOldBackground || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo) )
918 rRect.Right() = nPosX-nSignedOneX;
919 if (pOldBackground) // ==0 if hidden
921 Color aBackCol = pOldBackground->GetColor();
922 if ( !aBackCol.GetTransparency() ) //! partial transparency?
924 pDev->SetFillColor( aBackCol );
925 pDev->DrawRect( rRect );
928 if( pOldDataBarInfo )
929 drawDataBars( pOldDataBarInfo, pDev, rRect );
930 if( pOldIconSetInfo )
931 drawIconSets( pOldIconSetInfo, pDev, rRect );
933 rRect.Left() = nPosX - nSignedOneX;
936 if (!pOldBackground && !pOldColor && (pDataBarInfo || pIconSetInfo))
938 rRect.Right() = nPosX -nSignedOneX;
939 rRect.Left() = nPosX - nSignedOneX;
942 if(pColor)
944 // only update pOldColor if the colors changed
945 if (!pOldColor || *pOldColor != *pColor)
946 pOldColor = pColor;
948 pOldBackground = NULL;
950 else if(pBackground)
952 pOldBackground = pBackground;
953 pOldColor = NULL;
956 if(pDataBarInfo)
957 pOldDataBarInfo = pDataBarInfo;
958 else
959 pOldDataBarInfo = NULL;
961 if(pIconSetInfo)
962 pOldIconSetInfo = pIconSetInfo;
963 else
964 pOldIconSetInfo = NULL;
969 void ScOutputData::DrawBackground()
971 FindRotated(); //! von aussen ?
973 Rectangle aRect;
974 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
975 long nOneX = aOnePixel.Width();
976 long nOneY = aOnePixel.Height();
978 if (bMetaFile)
979 nOneX = nOneY = 0;
981 long nLayoutSign = bLayoutRTL ? -1 : 1;
982 long nSignedOneX = nOneX * nLayoutSign;
984 mpDev->SetLineColor();
986 sal_Bool bShowProt = mbSyntaxMode && mpDoc->IsTabProtected(nTab);
987 sal_Bool bDoAll = bShowProt || bPagebreakMode || bSolidBackground;
989 sal_Bool bCellContrast = mbUseStyleColor &&
990 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
992 long nPosY = nScrY;
993 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
995 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
996 long nRowHeight = pThisRowInfo->nHeight;
998 if ( pThisRowInfo->bChanged )
1000 if ( ( ( pThisRowInfo->bEmptyBack ) || mbSyntaxMode ) && !bDoAll )
1002 // nichts
1004 else
1006 // scan for rows with the same background:
1007 SCSIZE nSkip = 0;
1008 while ( nArrY+nSkip+2<nArrCount &&
1009 lcl_EqualBack( *pThisRowInfo, pRowInfo[nArrY+nSkip+1],
1010 nX1, nX2, bShowProt, bPagebreakMode ) )
1012 ++nSkip;
1013 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
1016 long nPosX = nScrX;
1017 if ( bLayoutRTL )
1018 nPosX += nMirrorW - nOneX;
1019 aRect = Rectangle( nPosX, nPosY-nOneY, nPosX, nPosY+nRowHeight-nOneY );
1021 const SvxBrushItem* pOldBackground = NULL;
1022 const SvxBrushItem* pBackground;
1023 const Color* pOldColor = NULL;
1024 const Color* pColor = NULL;
1025 const ScDataBarInfo* pOldDataBarInfo = NULL;
1026 const ScIconSetInfo* pOldIconSetInfo = NULL;
1027 for (SCCOL nX=nX1; nX<=nX2; nX++)
1029 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
1031 if (bCellContrast)
1033 // high contrast for cell borders and backgrounds -> empty background
1034 pBackground = ScGlobal::GetEmptyBrushItem();
1036 else if (bShowProt) // show cell protection in syntax mode
1038 const ScPatternAttr* pP = pInfo->pPatternAttr;
1039 if (pP)
1041 const ScProtectionAttr& rProt = (const ScProtectionAttr&)
1042 pP->GetItem(ATTR_PROTECTION);
1043 if (rProt.GetProtection() || rProt.GetHideCell())
1044 pBackground = ScGlobal::GetProtectedBrushItem();
1045 else
1046 pBackground = ScGlobal::GetEmptyBrushItem();
1048 else
1049 pBackground = NULL;
1051 else
1052 pBackground = pInfo->pBackground;
1054 if ( bPagebreakMode && !pInfo->bPrinted )
1055 pBackground = ScGlobal::GetProtectedBrushItem();
1057 if ( pInfo->nRotateDir > SC_ROTDIR_STANDARD &&
1058 pBackground->GetColor().GetTransparency() != 255 &&
1059 !bCellContrast )
1061 SCROW nY = pRowInfo[nArrY].nRowNo;
1062 pBackground = lcl_FindBackground( mpDoc, nX, nY, nTab );
1065 pColor = pInfo->pColorScale;
1066 const ScDataBarInfo* pDataBarInfo = pInfo->pDataBar;
1067 const ScIconSetInfo* pIconSetInfo = pInfo->pIconSet;
1068 drawCells( pColor, pBackground, pOldColor, pOldBackground, aRect, nPosX, nSignedOneX, mpDev, pDataBarInfo, pOldDataBarInfo, pIconSetInfo, pOldIconSetInfo );
1070 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
1072 drawCells( NULL, NULL, pOldColor, pOldBackground, aRect, nPosX, nSignedOneX, mpDev, NULL, pOldDataBarInfo, NULL, pOldIconSetInfo );
1074 nArrY += nSkip;
1077 nPosY += nRowHeight;
1081 void ScOutputData::DrawShadow()
1083 DrawExtraShadow( false, false, false, false );
1086 void ScOutputData::DrawExtraShadow(sal_Bool bLeft, sal_Bool bTop, sal_Bool bRight, sal_Bool bBottom)
1088 mpDev->SetLineColor();
1090 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1091 sal_Bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1092 Color aAutoTextColor;
1093 if ( bCellContrast )
1094 aAutoTextColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
1096 long nInitPosX = nScrX;
1097 if ( bLayoutRTL )
1099 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1100 long nOneX = aOnePixel.Width();
1101 nInitPosX += nMirrorW - nOneX;
1103 long nLayoutSign = bLayoutRTL ? -1 : 1;
1105 long nPosY = nScrY - pRowInfo[0].nHeight;
1106 for (SCSIZE nArrY=0; nArrY<nArrCount; nArrY++)
1108 sal_Bool bCornerY = ( nArrY == 0 ) || ( nArrY+1 == nArrCount );
1109 sal_Bool bSkipY = ( nArrY==0 && !bTop ) || ( nArrY+1 == nArrCount && !bBottom );
1111 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1112 long nRowHeight = pThisRowInfo->nHeight;
1114 if ( pThisRowInfo->bChanged && !bSkipY )
1116 long nPosX = nInitPosX - pRowInfo[0].pCellInfo[nX1].nWidth * nLayoutSign;
1117 for (SCCOL nArrX=nX1; nArrX<=nX2+2; nArrX++)
1119 sal_Bool bCornerX = ( nArrX==nX1 || nArrX==nX2+2 );
1120 sal_Bool bSkipX = ( nArrX==nX1 && !bLeft ) || ( nArrX==nX2+2 && !bRight );
1122 for (sal_uInt16 nPass=0; nPass<2; nPass++) // horizontal / vertikal
1124 const SvxShadowItem* pAttr = nPass ?
1125 pThisRowInfo->pCellInfo[nArrX].pVShadowOrigin :
1126 pThisRowInfo->pCellInfo[nArrX].pHShadowOrigin;
1127 if ( pAttr && !bSkipX )
1129 ScShadowPart ePart = nPass ?
1130 pThisRowInfo->pCellInfo[nArrX].eVShadowPart :
1131 pThisRowInfo->pCellInfo[nArrX].eHShadowPart;
1133 sal_Bool bDo = sal_True;
1134 if ( (nPass==0 && bCornerX) || (nPass==1 && bCornerY) )
1135 if ( ePart != SC_SHADOW_CORNER )
1136 bDo = false;
1138 if (bDo)
1140 long nThisWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1141 long nMaxWidth = nThisWidth;
1142 if (!nMaxWidth)
1144 //! direction must depend on shadow location
1145 SCCOL nWx = nArrX; // nX+1
1146 while (nWx<nX2 && !pRowInfo[0].pCellInfo[nWx+1].nWidth)
1147 ++nWx;
1148 nMaxWidth = pRowInfo[0].pCellInfo[nWx+1].nWidth;
1151 // rectangle is in logical orientation
1152 Rectangle aRect( nPosX, nPosY,
1153 nPosX + ( nThisWidth - 1 ) * nLayoutSign,
1154 nPosY + pRowInfo[nArrY].nHeight - 1 );
1156 long nSize = pAttr->GetWidth();
1157 long nSizeX = (long)(nSize*mnPPTX);
1158 if (nSizeX >= nMaxWidth) nSizeX = nMaxWidth-1;
1159 long nSizeY = (long)(nSize*mnPPTY);
1160 if (nSizeY >= nRowHeight) nSizeY = nRowHeight-1;
1162 nSizeX *= nLayoutSign; // used only to add to rectangle values
1164 SvxShadowLocation eLoc = pAttr->GetLocation();
1165 if ( bLayoutRTL )
1167 // Shadow location is specified as "visual" (right is always right),
1168 // so the attribute's location value is mirrored here and in FillInfo.
1169 switch (eLoc)
1171 case SVX_SHADOW_BOTTOMRIGHT: eLoc = SVX_SHADOW_BOTTOMLEFT; break;
1172 case SVX_SHADOW_BOTTOMLEFT: eLoc = SVX_SHADOW_BOTTOMRIGHT; break;
1173 case SVX_SHADOW_TOPRIGHT: eLoc = SVX_SHADOW_TOPLEFT; break;
1174 case SVX_SHADOW_TOPLEFT: eLoc = SVX_SHADOW_TOPRIGHT; break;
1175 default:
1177 // added to avoid warnings
1182 if (ePart == SC_SHADOW_HORIZ || ePart == SC_SHADOW_HSTART ||
1183 ePart == SC_SHADOW_CORNER)
1185 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_TOPRIGHT)
1186 aRect.Top() = aRect.Bottom() - nSizeY;
1187 else
1188 aRect.Bottom() = aRect.Top() + nSizeY;
1190 if (ePart == SC_SHADOW_VERT || ePart == SC_SHADOW_VSTART ||
1191 ePart == SC_SHADOW_CORNER)
1193 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_BOTTOMLEFT)
1194 aRect.Left() = aRect.Right() - nSizeX;
1195 else
1196 aRect.Right() = aRect.Left() + nSizeX;
1198 if (ePart == SC_SHADOW_HSTART)
1200 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_BOTTOMLEFT)
1201 aRect.Right() -= nSizeX;
1202 else
1203 aRect.Left() += nSizeX;
1205 if (ePart == SC_SHADOW_VSTART)
1207 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_TOPRIGHT)
1208 aRect.Bottom() -= nSizeY;
1209 else
1210 aRect.Top() += nSizeY;
1213 //! merge rectangles?
1214 mpDev->SetFillColor( bCellContrast ? aAutoTextColor : pAttr->GetColor() );
1215 mpDev->DrawRect( aRect );
1220 nPosX += pRowInfo[0].pCellInfo[nArrX].nWidth * nLayoutSign;
1223 nPosY += nRowHeight;
1228 // Loeschen
1231 void ScOutputData::DrawClear()
1233 Rectangle aRect;
1234 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1235 long nOneX = aOnePixel.Width();
1236 long nOneY = aOnePixel.Height();
1238 // (called only for ScGridWindow)
1239 Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
1241 if (bMetaFile)
1242 nOneX = nOneY = 0;
1244 mpDev->SetLineColor();
1246 mpDev->SetFillColor( aBgColor );
1248 long nPosY = nScrY;
1249 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1251 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1252 long nRowHeight = pThisRowInfo->nHeight;
1254 if ( pThisRowInfo->bChanged )
1256 // scan for more rows which must be painted:
1257 SCSIZE nSkip = 0;
1258 while ( nArrY+nSkip+2<nArrCount && pRowInfo[nArrY+nSkip+1].bChanged )
1260 ++nSkip;
1261 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
1264 aRect = Rectangle( Point( nScrX, nPosY ),
1265 Size( nScrW+1-nOneX, nRowHeight+1-nOneY) );
1266 mpDev->DrawRect( aRect );
1268 nArrY += nSkip;
1270 nPosY += nRowHeight;
1274 namespace {
1276 long lclGetSnappedX( OutputDevice& rDev, long nPosX, bool bSnapPixel )
1278 return (bSnapPixel && nPosX) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( nPosX, 0 ) ) ).Width() : nPosX;
1281 long lclGetSnappedY( OutputDevice& rDev, long nPosY, bool bSnapPixel )
1283 return (bSnapPixel && nPosY) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( 0, nPosY ) ) ).Height() : nPosY;
1286 size_t lclGetArrayColFromCellInfoX( sal_uInt16 nCellInfoX, sal_uInt16 nCellInfoFirstX, sal_uInt16 nCellInfoLastX, bool bRTL )
1288 return static_cast< size_t >( bRTL ? (nCellInfoLastX + 2 - nCellInfoX) : (nCellInfoX - nCellInfoFirstX) );
1292 * Temporarily turn off antialiasing.
1294 class AntiAliasingSwitch
1296 SvtOptionsDrawinglayer maDrawOpt;
1297 bool mbOldSetting;
1298 public:
1299 AntiAliasingSwitch(bool bOn) : mbOldSetting(maDrawOpt.IsAntiAliasing())
1301 maDrawOpt.SetAntiAliasing(bOn);
1304 ~AntiAliasingSwitch()
1306 maDrawOpt.SetAntiAliasing(mbOldSetting);
1312 void ScOutputData::DrawFrame()
1314 // No anti-aliasing for drawing cell borders.
1315 AntiAliasingSwitch aAASwitch(false);
1317 sal_uLong nOldDrawMode = mpDev->GetDrawMode();
1319 Color aSingleColor;
1320 sal_Bool bUseSingleColor = false;
1321 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1322 sal_Bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1324 // if a Calc OLE object is embedded in Draw/Impress, the VCL DrawMode is used
1325 // for display mode / B&W printing. The VCL DrawMode handling doesn't work for lines
1326 // that are drawn with DrawRect, so if the line/background bits are set, the DrawMode
1327 // must be reset and the border colors handled here.
1329 if ( ( nOldDrawMode & DRAWMODE_WHITEFILL ) && ( nOldDrawMode & DRAWMODE_BLACKLINE ) )
1331 mpDev->SetDrawMode( nOldDrawMode & (~DRAWMODE_WHITEFILL) );
1332 aSingleColor.SetColor( COL_BLACK );
1333 bUseSingleColor = sal_True;
1335 else if ( ( nOldDrawMode & DRAWMODE_SETTINGSFILL ) && ( nOldDrawMode & DRAWMODE_SETTINGSLINE ) )
1337 mpDev->SetDrawMode( nOldDrawMode & (~DRAWMODE_SETTINGSFILL) );
1338 aSingleColor = rStyleSettings.GetWindowTextColor(); // same as used in VCL for DRAWMODE_SETTINGSLINE
1339 bUseSingleColor = sal_True;
1341 else if ( bCellContrast )
1343 aSingleColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
1344 bUseSingleColor = sal_True;
1347 const Color* pForceColor = bUseSingleColor ? &aSingleColor : 0;
1349 if (bAnyRotated)
1350 DrawRotatedFrame( pForceColor ); // removes the lines that must not be painted here
1352 long nInitPosX = nScrX;
1353 if ( bLayoutRTL )
1355 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1356 long nOneX = aOnePixel.Width();
1357 nInitPosX += nMirrorW - nOneX;
1359 long nLayoutSign = bLayoutRTL ? -1 : 1;
1362 // *** set column and row sizes of the frame border array ***
1364 svx::frame::Array& rArray = mrTabInfo.maArray;
1365 size_t nColCount = rArray.GetColCount();
1366 size_t nRowCount = rArray.GetRowCount();
1368 // row heights
1370 // row 0 is not visible (dummy for borders from top) - subtract its height from initial position
1371 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit before
1372 long nOldPosY = nScrY - 1 - pRowInfo[ 0 ].nHeight;
1373 long nOldSnapY = lclGetSnappedY( *mpDev, nOldPosY, bSnapPixel );
1374 rArray.SetYOffset( nOldSnapY );
1375 for( size_t nRow = 0; nRow < nRowCount; ++nRow )
1377 long nNewPosY = nOldPosY + pRowInfo[ nRow ].nHeight;
1378 long nNewSnapY = lclGetSnappedY( *mpDev, nNewPosY, bSnapPixel );
1379 rArray.SetRowHeight( nRow, nNewSnapY - nOldSnapY );
1380 nOldPosY = nNewPosY;
1381 nOldSnapY = nNewSnapY;
1384 // column widths
1386 // column nX1 is not visible (dummy for borders from left) - subtract its width from initial position
1387 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit above
1388 long nOldPosX = nInitPosX - nLayoutSign * (1 + pRowInfo[ 0 ].pCellInfo[ nX1 ].nWidth);
1389 long nOldSnapX = lclGetSnappedX( *mpDev, nOldPosX, bSnapPixel );
1390 // set X offset for left-to-right sheets; for right-to-left sheets this is done after for() loop
1391 if( !bLayoutRTL )
1392 rArray.SetXOffset( nOldSnapX );
1393 for( sal_uInt16 nInfoIdx = nX1; nInfoIdx <= nX2 + 2; ++nInfoIdx )
1395 size_t nCol = lclGetArrayColFromCellInfoX( nInfoIdx, nX1, nX2, bLayoutRTL );
1396 long nNewPosX = nOldPosX + pRowInfo[ 0 ].pCellInfo[ nInfoIdx ].nWidth * nLayoutSign;
1397 long nNewSnapX = lclGetSnappedX( *mpDev, nNewPosX, bSnapPixel );
1398 rArray.SetColWidth( nCol, Abs( nNewSnapX - nOldSnapX ) );
1399 nOldPosX = nNewPosX;
1400 nOldSnapX = nNewSnapX;
1402 if( bLayoutRTL )
1403 rArray.SetXOffset( nOldSnapX );
1405 // *** draw the array ***
1407 size_t nFirstCol = 1;
1408 size_t nFirstRow = 1;
1409 size_t nLastCol = nColCount - 2;
1410 size_t nLastRow = nRowCount - 2;
1412 if( mrTabInfo.mbPageMode )
1413 rArray.SetClipRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
1415 // draw only rows with set RowInfo::bChanged flag
1416 size_t nRow1 = nFirstRow;
1417 drawinglayer::processor2d::BaseProcessor2D* pProcessor = CreateProcessor2D();
1418 if (!pProcessor)
1419 return;
1421 while( nRow1 <= nLastRow )
1423 while( (nRow1 <= nLastRow) && !pRowInfo[ nRow1 ].bChanged ) ++nRow1;
1424 if( nRow1 <= nLastRow )
1426 size_t nRow2 = nRow1;
1427 while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
1428 rArray.DrawRange( pProcessor, nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
1429 nRow1 = nRow2 + 1;
1432 if ( pProcessor )
1433 delete pProcessor;
1435 mpDev->SetDrawMode(nOldDrawMode);
1438 // -------------------------------------------------------------------------
1440 // Linie unter der Zelle
1442 static const ::editeng::SvxBorderLine* lcl_FindHorLine( ScDocument* pDoc,
1443 SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nRotDir,
1444 sal_Bool bTopLine )
1446 if ( nRotDir != SC_ROTDIR_LEFT && nRotDir != SC_ROTDIR_RIGHT )
1447 return NULL;
1449 sal_Bool bFound = false;
1450 while (!bFound)
1452 if ( nRotDir == SC_ROTDIR_LEFT )
1454 // Text nach links -> Linie von rechts
1455 if ( nCol < MAXCOL )
1456 ++nCol;
1457 else
1458 return NULL; // war nix
1460 else
1462 // Text nach rechts -> Linie von links
1463 if ( nCol > 0 )
1464 --nCol;
1465 else
1466 return NULL; // war nix
1468 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
1469 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
1470 if ( !pPattern->GetRotateVal( pCondSet ) ||
1471 ((const SvxRotateModeItem&)pPattern->GetItem(
1472 ATTR_ROTATE_MODE, pCondSet)).GetValue() == SVX_ROTATE_MODE_STANDARD )
1473 bFound = sal_True;
1476 if (bTopLine)
1477 --nRow;
1478 const ::editeng::SvxBorderLine* pThisBottom;
1479 if ( ValidRow(nRow) )
1480 pThisBottom = ((const SvxBoxItem*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_BORDER ))->GetBottom();
1481 else
1482 pThisBottom = NULL;
1483 const ::editeng::SvxBorderLine* pNextTop;
1484 if ( nRow < MAXROW )
1485 pNextTop = ((const SvxBoxItem*)pDoc->GetAttr( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
1486 else
1487 pNextTop = NULL;
1489 if ( ScHasPriority( pThisBottom, pNextTop ) )
1490 return pThisBottom;
1491 else
1492 return pNextTop;
1496 static long lcl_getRotate( ScDocument* pDoc, SCTAB nTab, SCCOL nX, SCROW nY )
1498 long nRotate = 0;
1500 const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab );
1501 const SfxItemSet* pCondSet = pDoc->GetCondResult( nX, nY, nTab );
1503 nRotate = pPattern->GetRotateVal( pCondSet );
1505 return nRotate;
1508 void ScOutputData::DrawRotatedFrame( const Color* pForceColor )
1510 //! nRotMax speichern
1511 SCCOL nRotMax = nX2;
1512 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
1513 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
1514 nRotMax = pRowInfo[nRotY].nRotMaxCol;
1516 const ScPatternAttr* pPattern;
1517 const SfxItemSet* pCondSet;
1519 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1520 sal_Bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1522 // color (pForceColor) is determined externally, including DrawMode changes
1524 long nInitPosX = nScrX;
1525 if ( bLayoutRTL )
1527 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1528 long nOneX = aOnePixel.Width();
1529 nInitPosX += nMirrorW - nOneX;
1531 long nLayoutSign = bLayoutRTL ? -1 : 1;
1533 Rectangle aClipRect( Point(nScrX, nScrY), Size(nScrW, nScrH) );
1534 if (bMetaFile)
1536 mpDev->Push();
1537 mpDev->IntersectClipRegion( aClipRect );
1539 else
1540 mpDev->SetClipRegion( Region( aClipRect ) );
1542 svx::frame::Array& rArray = mrTabInfo.maArray;
1543 drawinglayer::processor2d::BaseProcessor2D* pProcessor = CreateProcessor2D( );
1545 long nPosY = nScrY;
1546 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
1548 // Rotated wird auch 1 Zeile ueber/unter Changed gezeichnet, falls Teile
1549 // in die Zeile hineinragen...
1551 RowInfo& rPrevRowInfo = pRowInfo[nArrY-1];
1552 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1553 RowInfo& rNextRowInfo = pRowInfo[nArrY+1];
1555 size_t nRow = static_cast< size_t >( nArrY );
1557 long nRowHeight = rThisRowInfo.nHeight;
1558 if ( rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE &&
1559 ( rThisRowInfo.bChanged || rPrevRowInfo.bChanged ||
1560 ( nArrY+1<nArrCount && rNextRowInfo.bChanged ) ) )
1562 SCROW nY = rThisRowInfo.nRowNo;
1563 long nPosX = 0;
1564 SCCOL nX;
1565 for (nX=0; nX<=nRotMax; nX++)
1567 if (nX==nX1) nPosX = nInitPosX; // calculated individually for preceding positions
1569 sal_uInt16 nArrX = nX + 1;
1571 CellInfo* pInfo = &rThisRowInfo.pCellInfo[nArrX];
1572 long nColWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1573 if ( pInfo->nRotateDir > SC_ROTDIR_STANDARD &&
1574 !pInfo->bHOverlapped && !pInfo->bVOverlapped )
1576 pPattern = pInfo->pPatternAttr;
1577 pCondSet = pInfo->pConditionSet;
1578 if (!pPattern)
1580 pPattern = mpDoc->GetPattern( nX, nY, nTab );
1581 pInfo->pPatternAttr = pPattern;
1582 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
1583 pInfo->pConditionSet = pCondSet;
1586 //! LastPattern etc.
1588 long nAttrRotate = pPattern->GetRotateVal( pCondSet );
1589 SvxRotateMode eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
1590 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
1592 if ( nAttrRotate )
1594 if (nX<nX1) // negative Position berechnen
1596 nPosX = nInitPosX;
1597 SCCOL nCol = nX1;
1598 while (nCol > nX)
1600 --nCol;
1601 nPosX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
1605 // Startposition minus 1, damit auch schraege Hintergruende
1606 // zur Umrandung passen (Umrandung ist auf dem Gitter)
1608 long nTop = nPosY - 1;
1609 long nBottom = nPosY + nRowHeight - 1;
1610 long nTopLeft = nPosX - nLayoutSign;
1611 long nTopRight = nPosX + ( nColWidth - 1 ) * nLayoutSign;
1612 long nBotLeft = nTopLeft;
1613 long nBotRight = nTopRight;
1615 // inclusion of the sign here hasn't been decided yet
1616 // (if not, the extension of the non-rotated background must also be changed)
1617 double nRealOrient = nLayoutSign * nAttrRotate * F_PI18000; // 1/100th degrees
1618 double nCos = cos( nRealOrient );
1619 double nSin = sin( nRealOrient );
1620 //! begrenzen !!!
1621 long nSkew = (long) ( nRowHeight * nCos / nSin );
1623 switch (eRotMode)
1625 case SVX_ROTATE_MODE_BOTTOM:
1626 nTopLeft += nSkew;
1627 nTopRight += nSkew;
1628 break;
1629 case SVX_ROTATE_MODE_CENTER:
1630 nSkew /= 2;
1631 nTopLeft += nSkew;
1632 nTopRight += nSkew;
1633 nBotLeft -= nSkew;
1634 nBotRight -= nSkew;
1635 break;
1636 case SVX_ROTATE_MODE_TOP:
1637 nBotLeft -= nSkew;
1638 nBotRight -= nSkew;
1639 break;
1640 default:
1642 // added to avoid warnings
1646 Point aPoints[4];
1647 aPoints[0] = Point( nTopLeft, nTop );
1648 aPoints[1] = Point( nTopRight, nTop );
1649 aPoints[2] = Point( nBotRight, nBottom );
1650 aPoints[3] = Point( nBotLeft, nBottom );
1652 const SvxBrushItem* pBackground = pInfo->pBackground;
1653 if (!pBackground)
1654 pBackground = (const SvxBrushItem*) &pPattern->GetItem(
1655 ATTR_BACKGROUND, pCondSet );
1656 if (bCellContrast)
1658 // high contrast for cell borders and backgrounds -> empty background
1659 pBackground = ScGlobal::GetEmptyBrushItem();
1661 if(!pInfo->pColorScale)
1663 const Color& rColor = pBackground->GetColor();
1664 if ( rColor.GetTransparency() != 255 )
1666 // draw background only for the changed row itself
1667 // (background doesn't extend into other cells).
1668 // For the borders (rotated and normal), clipping should be
1669 // set if the row isn't changed, but at least the borders
1670 // don't cover the cell contents.
1671 if ( rThisRowInfo.bChanged )
1673 Polygon aPoly( 4, aPoints );
1675 // ohne Pen wird bei DrawPolygon rechts und unten
1676 // ein Pixel weggelassen...
1677 if ( rColor.GetTransparency() == 0 )
1678 mpDev->SetLineColor(rColor);
1679 else
1680 mpDev->SetLineColor();
1681 mpDev->SetFillColor(rColor);
1682 mpDev->DrawPolygon( aPoly );
1686 else
1688 Polygon aPoly( 4, aPoints );
1689 const Color* pColor = pInfo->pColorScale;
1691 // ohne Pen wird bei DrawPolygon rechts und unten
1692 // ein Pixel weggelassen...
1693 if ( pColor->GetTransparency() == 0 )
1694 mpDev->SetLineColor(*pColor);
1695 else
1696 mpDev->SetLineColor();
1697 mpDev->SetFillColor(*pColor);
1698 mpDev->DrawPolygon( aPoly );
1702 svx::frame::Style aTopLine, aBottomLine, aLeftLine, aRightLine;
1704 if ( nX < nX1 || nX > nX2 ) // Attribute in FillInfo nicht gesetzt
1706 //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
1707 const ::editeng::SvxBorderLine* pLeftLine;
1708 const ::editeng::SvxBorderLine* pTopLine;
1709 const ::editeng::SvxBorderLine* pRightLine;
1710 const ::editeng::SvxBorderLine* pBottomLine;
1711 mpDoc->GetBorderLines( nX, nY, nTab,
1712 &pLeftLine, &pTopLine, &pRightLine, &pBottomLine );
1713 aTopLine.Set( pTopLine, mnPPTY );
1714 aBottomLine.Set( pBottomLine, mnPPTY );
1715 aLeftLine.Set( pLeftLine, mnPPTX );
1716 aRightLine.Set( pRightLine, mnPPTX );
1718 else
1720 size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
1721 aTopLine = rArray.GetCellStyleTop( nCol, nRow );
1722 aBottomLine = rArray.GetCellStyleBottom( nCol, nRow );
1723 aLeftLine = rArray.GetCellStyleLeft( nCol, nRow );
1724 aRightLine = rArray.GetCellStyleRight( nCol, nRow );
1725 // in RTL mode the array is already mirrored -> swap back left/right borders
1726 if( bLayoutRTL )
1727 std::swap( aLeftLine, aRightLine );
1730 const svx::frame::Style noStyle;
1731 // Horizontal lines
1732 long nUpperRotate = lcl_getRotate( mpDoc, nTab, nX, nY - 1 );
1733 pProcessor->process( svx::frame::CreateBorderPrimitives(
1734 aPoints[bLayoutRTL?1:0], aPoints[bLayoutRTL?0:1], aTopLine,
1735 svx::frame::Style(),
1736 svx::frame::Style(),
1737 aLeftLine,
1738 svx::frame::Style(),
1739 svx::frame::Style(),
1740 aRightLine,
1741 pForceColor, nUpperRotate, nAttrRotate ) );
1743 long nLowerRotate = lcl_getRotate( mpDoc, nTab, nX, nY + 1 );
1744 pProcessor->process( svx::frame::CreateBorderPrimitives(
1745 aPoints[bLayoutRTL?2:3], aPoints[bLayoutRTL?3:2], aBottomLine,
1746 aLeftLine,
1747 svx::frame::Style(),
1748 svx::frame::Style(),
1749 aRightLine,
1750 svx::frame::Style(),
1751 svx::frame::Style(),
1752 pForceColor, 18000 - nAttrRotate, 18000 - nLowerRotate ) );
1754 // Vertical slanted lines
1755 long nLeftRotate = lcl_getRotate( mpDoc, nTab, nX - 1, nY );
1756 pProcessor->process( svx::frame::CreateBorderPrimitives(
1757 aPoints[0], aPoints[3], aLeftLine,
1758 aTopLine,
1759 svx::frame::Style(),
1760 svx::frame::Style(),
1761 aBottomLine,
1762 svx::frame::Style(),
1763 svx::frame::Style(),
1764 pForceColor, nAttrRotate, nLeftRotate ) );
1766 long nRightRotate = lcl_getRotate( mpDoc, nTab, nX + 1, nY );
1767 pProcessor->process( svx::frame::CreateBorderPrimitives(
1768 aPoints[1], aPoints[2], aRightLine,
1769 svx::frame::Style(),
1770 svx::frame::Style(),
1771 aTopLine,
1772 svx::frame::Style(),
1773 svx::frame::Style(),
1774 aBottomLine,
1775 pForceColor, 18000 - nRightRotate, 18000 - nAttrRotate ) );
1778 nPosX += nColWidth * nLayoutSign;
1781 // erst hinterher im zweiten Schritt die Linien fuer normale Ausgabe loeschen
1783 nX = nX1 > 0 ? (nX1-1) : static_cast<SCCOL>(0);
1784 for (; nX<=nX2+1; nX++) // sichtbarer Teil +- 1
1786 sal_uInt16 nArrX = nX + 1;
1787 CellInfo& rInfo = rThisRowInfo.pCellInfo[nArrX];
1788 if ( rInfo.nRotateDir > SC_ROTDIR_STANDARD &&
1789 !rInfo.bHOverlapped && !rInfo.bVOverlapped )
1791 pPattern = rInfo.pPatternAttr;
1792 pCondSet = rInfo.pConditionSet;
1794 size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
1796 // horizontal: angrenzende Linie verlaengern
1797 // (nur, wenn die gedrehte Zelle eine Umrandung hat)
1798 sal_uInt16 nDir = rInfo.nRotateDir;
1799 if ( rArray.GetCellStyleTop( nCol, nRow ).Prim() )
1801 svx::frame::Style aStyle( lcl_FindHorLine( mpDoc, nX, nY, nTab, nDir, sal_True ), mnPPTY );
1802 rArray.SetCellStyleTop( nCol, nRow, aStyle );
1803 if( nRow > 0 )
1804 rArray.SetCellStyleBottom( nCol, nRow - 1, aStyle );
1806 if ( rArray.GetCellStyleBottom( nCol, nRow ).Prim() )
1808 svx::frame::Style aStyle( lcl_FindHorLine( mpDoc, nX, nY, nTab, nDir, false ), mnPPTY );
1809 rArray.SetCellStyleBottom( nCol, nRow, aStyle );
1810 if( nRow + 1 < rArray.GetRowCount() )
1811 rArray.SetCellStyleTop( nCol, nRow + 1, aStyle );
1814 // always remove vertical borders
1815 if( !rArray.IsMergedOverlappedLeft( nCol, nRow ) )
1817 rArray.SetCellStyleLeft( nCol, nRow, svx::frame::Style() );
1818 if( nCol > 0 )
1819 rArray.SetCellStyleRight( nCol - 1, nRow, svx::frame::Style() );
1821 if( !rArray.IsMergedOverlappedRight( nCol, nRow ) )
1823 rArray.SetCellStyleRight( nCol, nRow, svx::frame::Style() );
1824 if( nCol + 1 < rArray.GetColCount() )
1825 rArray.SetCellStyleLeft( nCol + 1, nRow, svx::frame::Style() );
1828 // remove diagonal borders
1829 rArray.SetCellStyleTLBR( nCol, nRow, svx::frame::Style() );
1830 rArray.SetCellStyleBLTR( nCol, nRow, svx::frame::Style() );
1834 nPosY += nRowHeight;
1837 if ( pProcessor ) delete pProcessor;
1839 if (bMetaFile)
1840 mpDev->Pop();
1841 else
1842 mpDev->SetClipRegion();
1845 drawinglayer::processor2d::BaseProcessor2D* ScOutputData::CreateProcessor2D( )
1847 mpDoc->InitDrawLayer(mpDoc->GetDocumentShell());
1848 ScDrawLayer* pDrawLayer = mpDoc->GetDrawLayer();
1849 if (!pDrawLayer)
1850 return NULL;
1852 basegfx::B2DRange aViewRange;
1853 SdrPage *pDrawPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
1854 const drawinglayer::geometry::ViewInformation2D aNewViewInfos(
1855 basegfx::B2DHomMatrix( ),
1856 mpDev->GetViewTransformation(),
1857 aViewRange,
1858 GetXDrawPageForSdrPage( pDrawPage ),
1859 0.0,
1860 uno::Sequence< beans::PropertyValue >() );
1862 return drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
1863 *mpDev, aNewViewInfos );
1866 // Drucker
1868 PolyPolygon ScOutputData::GetChangedArea()
1870 PolyPolygon aPoly;
1872 Rectangle aDrawingRect;
1873 aDrawingRect.Left() = nScrX;
1874 aDrawingRect.Right() = nScrX+nScrW-1;
1876 sal_Bool bHad = false;
1877 long nPosY = nScrY;
1878 SCSIZE nArrY;
1879 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1881 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1883 if ( pThisRowInfo->bChanged )
1885 if (!bHad)
1887 aDrawingRect.Top() = nPosY;
1888 bHad = sal_True;
1890 aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1892 else if (bHad)
1894 aPoly.Insert( Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1895 bHad = false;
1897 nPosY += pRowInfo[nArrY].nHeight;
1900 if (bHad)
1901 aPoly.Insert( Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1903 return aPoly;
1906 sal_Bool ScOutputData::SetChangedClip()
1908 PolyPolygon aPoly;
1910 Rectangle aDrawingRect;
1911 aDrawingRect.Left() = nScrX;
1912 aDrawingRect.Right() = nScrX+nScrW-1;
1914 sal_Bool bHad = false;
1915 long nPosY = nScrY;
1916 SCSIZE nArrY;
1917 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1919 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1921 if ( pThisRowInfo->bChanged )
1923 if (!bHad)
1925 aDrawingRect.Top() = nPosY;
1926 bHad = sal_True;
1928 aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1930 else if (bHad)
1932 aPoly.Insert( Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1933 bHad = false;
1935 nPosY += pRowInfo[nArrY].nHeight;
1938 if (bHad)
1939 aPoly.Insert( Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1941 sal_Bool bRet = (aPoly.Count() != 0);
1942 if (bRet)
1943 mpDev->SetClipRegion(Region(aPoly));
1944 return bRet;
1947 void ScOutputData::FindChanged()
1949 SCCOL nX;
1950 SCSIZE nArrY;
1952 bool bWasIdleDisabled = mpDoc->IsIdleDisabled();
1953 mpDoc->DisableIdle(true);
1954 for (nArrY=0; nArrY<nArrCount; nArrY++)
1955 pRowInfo[nArrY].bChanged = false;
1957 bool bProgress = false;
1958 for (nArrY=0; nArrY<nArrCount; nArrY++)
1960 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1961 for (nX=nX1; nX<=nX2; nX++)
1963 ScBaseCell* pCell = pThisRowInfo->pCellInfo[nX+1].pCell;
1964 if (!pCell)
1965 continue;
1967 if (pCell->GetCellType() != CELLTYPE_FORMULA)
1968 continue;
1970 ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
1971 if ( !bProgress && pFCell->GetDirty() )
1973 ScProgress::CreateInterpretProgress(mpDoc, true);
1974 bProgress = true;
1976 if (pFCell->IsRunning())
1977 // still being interpreted. Skip it.
1978 continue;
1980 (void)pFCell->GetValue();
1981 if (!pFCell->IsChanged())
1982 // the result hasn't changed. Skip it.
1983 continue;
1985 pThisRowInfo->bChanged = true;
1986 if ( pThisRowInfo->pCellInfo[nX+1].bMerged )
1988 SCSIZE nOverY = nArrY + 1;
1989 while ( nOverY<nArrCount &&
1990 pRowInfo[nOverY].pCellInfo[nX+1].bVOverlapped )
1992 pRowInfo[nOverY].bChanged = true;
1993 ++nOverY;
1998 if ( bProgress )
1999 ScProgress::DeleteInterpretProgress();
2000 mpDoc->DisableIdle( bWasIdleDisabled );
2003 void ScOutputData::DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
2004 SCCOL nRefEndX, SCROW nRefEndY,
2005 const Color& rColor, sal_Bool bHandle )
2007 PutInOrder( nRefStartX, nRefEndX );
2008 PutInOrder( nRefStartY, nRefEndY );
2010 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2011 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
2013 if ( nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
2014 nRefStartY <= nVisY2 && nRefEndY >= nVisY1 )
2016 long nMinX = nScrX;
2017 long nMinY = nScrY;
2018 long nMaxX = nScrX+nScrW-1;
2019 long nMaxY = nScrY+nScrH-1;
2020 if ( bLayoutRTL )
2022 long nTemp = nMinX;
2023 nMinX = nMaxX;
2024 nMaxX = nTemp;
2026 long nLayoutSign = bLayoutRTL ? -1 : 1;
2028 sal_Bool bTop = false;
2029 sal_Bool bBottom = false;
2030 sal_Bool bLeft = false;
2031 sal_Bool bRight = false;
2033 long nPosY = nScrY;
2034 sal_Bool bNoStartY = ( nY1 < nRefStartY );
2035 sal_Bool bNoEndY = false;
2036 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
2038 SCROW nY = pRowInfo[nArrY].nRowNo;
2040 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2042 nMinY = nPosY;
2043 bTop = sal_True;
2045 if ( nY==nRefEndY )
2047 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
2048 bBottom = sal_True;
2050 if ( nY>nRefEndY && bNoEndY )
2052 nMaxY = nPosY-2;
2053 bBottom = sal_True;
2055 bNoStartY = ( nY < nRefStartY );
2056 bNoEndY = ( nY < nRefEndY );
2057 nPosY += pRowInfo[nArrY].nHeight;
2060 long nPosX = nScrX;
2061 if ( bLayoutRTL )
2062 nPosX += nMirrorW - 1; // always in pixels
2064 for (SCCOL nX=nX1; nX<=nX2; nX++)
2066 if ( nX==nRefStartX )
2068 nMinX = nPosX;
2069 bLeft = sal_True;
2071 if ( nX==nRefEndX )
2073 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 2 ) * nLayoutSign;
2074 bRight = sal_True;
2076 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2079 if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2080 nMaxY >= nMinY )
2082 mpDev->SetLineColor( rColor );
2083 if (bTop && bBottom && bLeft && bRight)
2085 mpDev->SetFillColor();
2086 mpDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2088 else
2090 if (bTop)
2091 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
2092 if (bBottom)
2093 mpDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2094 if (bLeft)
2095 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
2096 if (bRight)
2097 mpDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
2099 if ( bHandle && bRight && bBottom )
2101 mpDev->SetLineColor();
2102 mpDev->SetFillColor( rColor );
2103 mpDev->DrawRect( Rectangle( nMaxX-3*nLayoutSign, nMaxY-3, nMaxX+nLayoutSign, nMaxY+1 ) );
2109 void ScOutputData::DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
2110 SCCOL nRefEndX, SCROW nRefEndY,
2111 const Color& rColor, sal_uInt16 nType )
2113 PutInOrder( nRefStartX, nRefEndX );
2114 PutInOrder( nRefStartY, nRefEndY );
2116 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2117 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
2119 if ( nRefStartX <= nVisX2 + 1 && nRefEndX >= nVisX1 &&
2120 nRefStartY <= nVisY2 + 1 && nRefEndY >= nVisY1 ) // +1 because it touches next cells left/top
2122 long nMinX = nScrX;
2123 long nMinY = nScrY;
2124 long nMaxX = nScrX+nScrW-1;
2125 long nMaxY = nScrY+nScrH-1;
2126 if ( bLayoutRTL )
2128 long nTemp = nMinX;
2129 nMinX = nMaxX;
2130 nMaxX = nTemp;
2132 long nLayoutSign = bLayoutRTL ? -1 : 1;
2134 sal_Bool bTop = false;
2135 sal_Bool bBottom = false;
2136 sal_Bool bLeft = false;
2137 sal_Bool bRight = false;
2139 long nPosY = nScrY;
2140 sal_Bool bNoStartY = ( nY1 < nRefStartY );
2141 sal_Bool bNoEndY = false;
2142 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
2144 SCROW nY = pRowInfo[nArrY].nRowNo;
2146 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2148 nMinY = nPosY - 1;
2149 bTop = sal_True;
2151 if ( nY==nRefEndY )
2153 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 1;
2154 bBottom = sal_True;
2156 if ( nY>nRefEndY && bNoEndY )
2158 nMaxY = nPosY - 1;
2159 bBottom = sal_True;
2161 bNoStartY = ( nY < nRefStartY );
2162 bNoEndY = ( nY < nRefEndY );
2163 nPosY += pRowInfo[nArrY].nHeight;
2166 long nPosX = nScrX;
2167 if ( bLayoutRTL )
2168 nPosX += nMirrorW - 1; // always in pixels
2170 for (SCCOL nX=nX1; nX<=nX2+1; nX++)
2172 if ( nX==nRefStartX )
2174 nMinX = nPosX - nLayoutSign;
2175 bLeft = sal_True;
2177 if ( nX==nRefEndX )
2179 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 1 ) * nLayoutSign;
2180 bRight = sal_True;
2182 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2185 if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2186 nMaxY >= nMinY )
2188 if ( nType == SC_CAT_DELETE_ROWS )
2189 bLeft = bRight = bBottom = false; //! dicke Linie ???
2190 else if ( nType == SC_CAT_DELETE_COLS )
2191 bTop = bBottom = bRight = false; //! dicke Linie ???
2193 mpDev->SetLineColor( rColor );
2194 if (bTop && bBottom && bLeft && bRight)
2196 mpDev->SetFillColor();
2197 mpDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2199 else
2201 if (bTop)
2203 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
2204 if ( nType == SC_CAT_DELETE_ROWS )
2205 mpDev->DrawLine( Point( nMinX,nMinY+1 ), Point( nMaxX,nMinY+1 ) );
2207 if (bBottom)
2208 mpDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2209 if (bLeft)
2211 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
2212 if ( nType == SC_CAT_DELETE_COLS )
2213 mpDev->DrawLine( Point( nMinX+nLayoutSign,nMinY ), Point( nMinX+nLayoutSign,nMaxY ) );
2215 if (bRight)
2216 mpDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
2218 if ( bLeft && bTop )
2220 mpDev->SetLineColor();
2221 mpDev->SetFillColor( rColor );
2222 mpDev->DrawRect( Rectangle( nMinX+nLayoutSign, nMinY+1, nMinX+3*nLayoutSign, nMinY+3 ) );
2228 void ScOutputData::DrawChangeTrack()
2230 ScChangeTrack* pTrack = mpDoc->GetChangeTrack();
2231 ScChangeViewSettings* pSettings = mpDoc->GetChangeViewSettings();
2232 if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
2233 return; // nix da oder abgeschaltet
2235 ScActionColorChanger aColorChanger(*pTrack);
2237 // Clipping passiert von aussen
2238 //! ohne Clipping, nur betroffene Zeilen painten ??!??!?
2240 SCCOL nEndX = nX2;
2241 SCROW nEndY = nY2;
2242 if ( nEndX < MAXCOL ) ++nEndX; // auch noch von der naechsten Zelle, weil die Markierung
2243 if ( nEndY < MAXROW ) ++nEndY; // in die jeweils vorhergehende Zelle hineinragt
2244 ScRange aViewRange( nX1, nY1, nTab, nEndX, nEndY, nTab );
2245 const ScChangeAction* pAction = pTrack->GetFirst();
2246 while (pAction)
2248 ScChangeActionType eActionType;
2249 if ( pAction->IsVisible() )
2251 eActionType = pAction->GetType();
2252 const ScBigRange& rBig = pAction->GetBigRange();
2253 if ( rBig.aStart.Tab() == nTab )
2255 ScRange aRange = rBig.MakeRange();
2257 if ( eActionType == SC_CAT_DELETE_ROWS )
2258 aRange.aEnd.SetRow( aRange.aStart.Row() );
2259 else if ( eActionType == SC_CAT_DELETE_COLS )
2260 aRange.aEnd.SetCol( aRange.aStart.Col() );
2262 if ( aRange.Intersects( aViewRange ) &&
2263 ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2265 aColorChanger.Update( *pAction );
2266 Color aColor( aColorChanger.GetColor() );
2267 DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2268 aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2272 if ( eActionType == SC_CAT_MOVE &&
2273 ((const ScChangeActionMove*)pAction)->
2274 GetFromRange().aStart.Tab() == nTab )
2276 ScRange aRange = ((const ScChangeActionMove*)pAction)->
2277 GetFromRange().MakeRange();
2278 if ( aRange.Intersects( aViewRange ) &&
2279 ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2281 aColorChanger.Update( *pAction );
2282 Color aColor( aColorChanger.GetColor() );
2283 DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2284 aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2289 pAction = pAction->GetNext();
2293 //TODO: moggi Need to check if this can't be written simpler
2294 void ScOutputData::DrawNoteMarks()
2297 sal_Bool bFirst = sal_True;
2299 long nInitPosX = nScrX;
2300 if ( bLayoutRTL )
2301 nInitPosX += nMirrorW - 1; // always in pixels
2302 long nLayoutSign = bLayoutRTL ? -1 : 1;
2304 long nPosY = nScrY;
2305 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2307 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2308 if ( pThisRowInfo->bChanged )
2310 long nPosX = nInitPosX;
2311 for (SCCOL nX=nX1; nX<=nX2; nX++)
2313 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2314 sal_Bool bIsMerged = false;
2316 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2318 // find start of merged cell
2319 bIsMerged = sal_True;
2320 SCROW nY = pRowInfo[nArrY].nRowNo;
2321 SCCOL nMergeX = nX;
2322 SCROW nMergeY = nY;
2323 mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2324 // use origin's pCell for NotePtr test below
2327 if ( mpDoc->GetNotes(nTab)->findByAddress(nX, pRowInfo[nArrY].nRowNo) && ( bIsMerged ||
2328 ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2330 if (bFirst)
2332 mpDev->SetLineColor();
2334 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2335 if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2336 mpDev->SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2337 else
2338 mpDev->SetFillColor(COL_LIGHTRED);
2340 bFirst = false;
2343 long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 4 ) * nLayoutSign;
2344 if ( bIsMerged || pInfo->bMerged )
2346 // if merged, add widths of all cells
2347 SCCOL nNextX = nX + 1;
2348 while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2350 nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2351 ++nNextX;
2354 if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2355 mpDev->DrawRect( Rectangle( nMarkX,nPosY,nMarkX+2*nLayoutSign,nPosY+2 ) );
2358 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2361 nPosY += pThisRowInfo->nHeight;
2365 void ScOutputData::AddPDFNotes()
2367 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, mpDev->GetExtOutDevData() );
2368 if ( !pPDFData || !pPDFData->GetIsExportNotes() )
2369 return;
2371 long nInitPosX = nScrX;
2372 if ( bLayoutRTL )
2374 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
2375 long nOneX = aOnePixel.Width();
2376 nInitPosX += nMirrorW - nOneX;
2378 long nLayoutSign = bLayoutRTL ? -1 : 1;
2380 long nPosY = nScrY;
2381 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2383 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2384 if ( pThisRowInfo->bChanged )
2386 long nPosX = nInitPosX;
2387 for (SCCOL nX=nX1; nX<=nX2; nX++)
2389 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2390 sal_Bool bIsMerged = false;
2391 SCROW nY = pRowInfo[nArrY].nRowNo;
2392 SCCOL nMergeX = nX;
2393 SCROW nMergeY = nY;
2395 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2397 // find start of merged cell
2398 bIsMerged = sal_True;
2399 mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2400 // use origin's pCell for NotePtr test below
2403 if ( mpDoc->GetNotes(nTab)->findByAddress(nMergeX, nMergeY) && ( bIsMerged ||
2404 ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2406 long nNoteWidth = (long)( SC_CLIPMARK_SIZE * mnPPTX );
2407 long nNoteHeight = (long)( SC_CLIPMARK_SIZE * mnPPTY );
2409 long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - nNoteWidth ) * nLayoutSign;
2410 if ( bIsMerged || pInfo->bMerged )
2412 // if merged, add widths of all cells
2413 SCCOL nNextX = nX + 1;
2414 while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2416 nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2417 ++nNextX;
2420 if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2422 Rectangle aNoteRect( nMarkX, nPosY, nMarkX+nNoteWidth*nLayoutSign, nPosY+nNoteHeight );
2423 const ScPostIt* pNote = mpDoc->GetNotes(nTab)->findByAddress(nMergeX, nMergeY);
2425 // Note title is the cell address (as on printed note pages)
2426 String aTitle;
2427 ScAddress aAddress( nMergeX, nMergeY, nTab );
2428 aAddress.Format( aTitle, SCA_VALID, mpDoc, mpDoc->GetAddressConvention() );
2430 // Content has to be a simple string without line breaks
2431 String aContent = pNote->GetText();
2432 xub_StrLen nPos;
2433 while ( (nPos=aContent.Search('\n')) != STRING_NOTFOUND )
2434 aContent.SetChar( nPos, ' ' );
2436 vcl::PDFNote aNote;
2437 aNote.Title = aTitle;
2438 aNote.Contents = aContent;
2439 pPDFData->CreateNote( aNoteRect, aNote );
2443 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2446 nPosY += pThisRowInfo->nHeight;
2450 void ScOutputData::DrawClipMarks()
2452 if (!bAnyClipped)
2453 return;
2455 Color aArrowFillCol( COL_LIGHTRED );
2457 sal_uLong nOldDrawMode = mpDev->GetDrawMode();
2458 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2459 if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2461 // use DrawMode to change the arrow's outline color
2462 mpDev->SetDrawMode( nOldDrawMode | DRAWMODE_SETTINGSLINE );
2463 // use text color also for the fill color
2464 aArrowFillCol.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2467 long nInitPosX = nScrX;
2468 if ( bLayoutRTL )
2469 nInitPosX += nMirrorW - 1; // always in pixels
2470 long nLayoutSign = bLayoutRTL ? -1 : 1;
2472 Rectangle aCellRect;
2473 long nPosY = nScrY;
2474 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2476 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2477 if ( pThisRowInfo->bChanged )
2479 SCROW nY = pThisRowInfo->nRowNo;
2480 long nPosX = nInitPosX;
2481 for (SCCOL nX=nX1; nX<=nX2; nX++)
2483 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2484 if (pInfo->nClipMark)
2486 if (pInfo->bHOverlapped || pInfo->bVOverlapped)
2488 // merge origin may be outside of visible area - use document functions
2490 SCCOL nOverX = nX;
2491 SCROW nOverY = nY;
2492 long nStartPosX = nPosX;
2493 long nStartPosY = nPosY;
2495 while ( nOverX > 0 && ( ((const ScMergeFlagAttr*)mpDoc->GetAttr(
2496 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & SC_MF_HOR ) )
2498 --nOverX;
2499 nStartPosX -= nLayoutSign * (long) ( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
2502 while ( nOverY > 0 && ( ((const ScMergeFlagAttr*)mpDoc->GetAttr(
2503 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & SC_MF_VER ) )
2505 --nOverY;
2506 nStartPosY -= nLayoutSign * (long) ( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
2509 long nOutWidth = (long) ( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
2510 long nOutHeight = (long) ( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
2512 const ScMergeAttr* pMerge = (const ScMergeAttr*)
2513 mpDoc->GetAttr( nOverX, nOverY, nTab, ATTR_MERGE );
2514 SCCOL nCountX = pMerge->GetColMerge();
2515 for (SCCOL i=1; i<nCountX; i++)
2516 nOutWidth += (long) ( mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX );
2517 SCROW nCountY = pMerge->GetRowMerge();
2518 nOutHeight += (long) mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY);
2520 if ( bLayoutRTL )
2521 nStartPosX -= nOutWidth - 1;
2522 aCellRect = Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
2524 else
2526 long nOutWidth = pRowInfo[0].pCellInfo[nX+1].nWidth;
2527 long nOutHeight = pThisRowInfo->nHeight;
2529 if ( pInfo->bMerged && pInfo->pPatternAttr )
2531 SCCOL nOverX = nX;
2532 SCROW nOverY = nY;
2533 const ScMergeAttr* pMerge =
2534 (ScMergeAttr*)&pInfo->pPatternAttr->GetItem(ATTR_MERGE);
2535 SCCOL nCountX = pMerge->GetColMerge();
2536 for (SCCOL i=1; i<nCountX; i++)
2537 nOutWidth += (long) ( mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX );
2538 SCROW nCountY = pMerge->GetRowMerge();
2539 nOutHeight += (long) mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY);
2542 long nStartPosX = nPosX;
2543 if ( bLayoutRTL )
2544 nStartPosX -= nOutWidth - 1;
2545 // #i80447# create aCellRect from two points in case nOutWidth is 0
2546 aCellRect = Rectangle( Point( nStartPosX, nPosY ),
2547 Point( nStartPosX+nOutWidth-1, nPosY+nOutHeight-1 ) );
2550 aCellRect.Bottom() -= 1; // don't paint over the cell grid
2551 if ( bLayoutRTL )
2552 aCellRect.Left() += 1;
2553 else
2554 aCellRect.Right() -= 1;
2556 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
2557 Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
2559 if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_RIGHT : SC_CLIPMARK_LEFT ) )
2561 // visually left
2562 Rectangle aMarkRect = aCellRect;
2563 aMarkRect.Right() = aCellRect.Left()+nMarkPixel-1;
2564 SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, true );
2566 if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_LEFT : SC_CLIPMARK_RIGHT ) )
2568 // visually right
2569 Rectangle aMarkRect = aCellRect;
2570 aMarkRect.Left() = aCellRect.Right()-nMarkPixel+1;
2571 SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, false );
2574 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2577 nPosY += pThisRowInfo->nHeight;
2580 mpDev->SetDrawMode(nOldDrawMode);
2585 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */