Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / ui / view / output.cxx
blobf5dedb72f36ad7745d17815578bbb9dd6427561b
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 <iostream>
70 #include <map>
71 #include <memory>
72 #include <utility>
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( nullptr ),
167 pViewShell( nullptr ),
168 pDrawView( nullptr ),
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( nullptr ),
180 pTextColor( nullptr ),
181 pFormulaColor( nullptr ),
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(nullptr), // #i74769# use SdrPaintWindow direct
191 mpSpellCheckCxt(nullptr)
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()
278 bSnapPixel = true;
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(vcl::RenderContext& rRenderContext, 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 // It is a big mess to distinguish when we are using pixels and when logic
328 // units for drawing. Ultimately we want to work only in the logic units,
329 // but until that happens, we need to special-case:
331 // * metafile
332 // * drawing to the screen - everything is internally counted in pixels there
334 // 'Internally' in the above means the pCellInfo[...].nWidth and
335 // pRowInfo[...]->nHeight:
337 // * when bWorksInPixels is true: these are in pixels
338 // * when bWorksInPixels is false: these are in the logic units
340 // This is where all the confusion comes from, ultimately we want them
341 // always in the logic units (100th of millimiters), but we need to get
342 // there gradually (get rid of setting MAP_PIXEL first), otherwise we'd
343 // break all the drawing by one change.
344 // So until that happens, we need to special case.
345 bool bWorksInPixels = bMetaFile;
347 if ( eType == OUTTYPE_WINDOW )
349 bWorksInPixels = true;
350 const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
351 aPageColor.SetColor( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor );
352 aManualColor.SetColor( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor );
354 else
356 aPageColor = aGridColor;
357 aManualColor = aGridColor;
360 long nOneX = 1;
361 long nOneY = 1;
362 if (!bWorksInPixels)
364 Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
365 nOneX = aOnePixel.Width();
366 nOneY = aOnePixel.Height();
369 long nLayoutSign = bLayoutRTL ? -1 : 1;
370 long nSignedOneX = nOneX * nLayoutSign;
372 rRenderContext.SetLineColor(aGridColor);
373 ScGridMerger aGrid(&rRenderContext, nOneX, nOneY);
375 // vertical lines
377 nPosX = nScrX;
378 if ( bLayoutRTL )
379 nPosX += nMirrorW - nOneX;
381 for (nX=nX1; nX<=nX2; nX++)
383 SCCOL nXplus1 = nX+1;
384 SCCOL nXplus2 = nX+2;
385 sal_uInt16 nWidth = pRowInfo[0].pCellInfo[nXplus1].nWidth;
386 if (nWidth)
388 nPosX += nWidth * nLayoutSign;
390 if ( bPage )
392 // Search also in hidden part for page breaks
393 SCCOL nCol = nXplus1;
394 while (nCol <= MAXCOL)
396 nBreak = mpDoc->HasColBreak(nCol, nTab);
397 bool bHidden = mpDoc->ColHidden(nCol, nTab);
399 if ( nBreak || !bHidden )
400 break;
401 ++nCol;
404 if (nBreak != nBreakOld)
406 aGrid.Flush();
407 rRenderContext.SetLineColor( (nBreak & BREAK_MANUAL) ? aManualColor :
408 nBreak ? aPageColor : aGridColor );
409 nBreakOld = nBreak;
413 bool bDraw = bGrid || nBreakOld; // simple grid only if set that way
415 sal_uInt16 nWidthXplus2 = pRowInfo[0].pCellInfo[nXplus2].nWidth;
416 bSingle = bSingleGrid; //! get into Fillinfo !!!!!
417 if ( nX<MAXCOL && !bSingle )
419 bSingle = ( nWidthXplus2 == 0 );
420 for (nArrY=1; nArrY+1<nArrCount && !bSingle; nArrY++)
422 if (pRowInfo[nArrY].pCellInfo[nXplus2].bHOverlapped)
423 bSingle = true;
424 if (pRowInfo[nArrY].pCellInfo[nXplus1].bHideGrid)
425 bSingle = true;
429 if (bDraw)
431 if ( nX<MAXCOL && bSingle )
433 SCCOL nVisX = nXplus1;
434 while ( nVisX < MAXCOL && !mpDoc->GetColWidth(nVisX,nTab) )
435 ++nVisX;
437 nPosY = nScrY;
438 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
440 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
441 const long nNextY = nPosY + pThisRowInfo->nHeight;
443 bool bHOver = pThisRowInfo->pCellInfo[nXplus1].bHideGrid;
444 if (!bHOver)
446 if (nWidthXplus2)
447 bHOver = pThisRowInfo->pCellInfo[nXplus2].bHOverlapped;
448 else
450 if (nVisX <= nX2)
451 bHOver = pThisRowInfo->pCellInfo[nVisX+1].bHOverlapped;
452 else
453 bHOver = static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
454 nVisX,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG))
455 ->IsHorOverlapped();
456 if (bHOver)
457 bHOver = static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
458 nXplus1,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG))
459 ->IsHorOverlapped();
463 if (pThisRowInfo->bChanged && !bHOver)
465 aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nPosY, nNextY-nOneY);
467 nPosY = nNextY;
470 else
472 aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nScrY, nScrY+nScrH-nOneY);
478 // horizontal lines
480 bool bHiddenRow = true;
481 SCROW nHiddenEndRow = -1;
482 nPosY = nScrY;
483 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
485 SCSIZE nArrYplus1 = nArrY+1;
486 nY = pRowInfo[nArrY].nRowNo;
487 SCROW nYplus1 = nY+1;
488 nPosY += pRowInfo[nArrY].nHeight;
490 if (pRowInfo[nArrY].bChanged)
492 if ( bPage )
494 for (SCROW i = nYplus1; i <= MAXROW; ++i)
496 if (i > nHiddenEndRow)
497 bHiddenRow = mpDoc->RowHidden(i, nTab, nullptr, &nHiddenEndRow);
498 /* TODO: optimize the row break thing for large hidden
499 * segments where HasRowBreak() has to be called
500 * nevertheless for each row, as a row break is drawn also
501 * for hidden rows, above them. This needed to be done only
502 * once per hidden segment, maybe giving manual breaks
503 * priority. Something like GetNextRowBreak() and
504 * GetNextManualRowBreak(). */
505 nBreak = mpDoc->HasRowBreak(i, nTab);
506 if (!bHiddenRow || nBreak)
507 break;
510 if (nBreakOld != nBreak)
512 aGrid.Flush();
513 rRenderContext.SetLineColor( (nBreak & BREAK_MANUAL) ? aManualColor :
514 (nBreak) ? aPageColor : aGridColor );
515 nBreakOld = nBreak;
519 bool bDraw = bGrid || nBreakOld; // simple grid only if set so
521 bool bNextYisNextRow = (pRowInfo[nArrYplus1].nRowNo == nYplus1);
522 bSingle = !bNextYisNextRow; // Hidden
523 for (SCCOL i=nX1; i<=nX2 && !bSingle; i++)
525 if (pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped)
526 bSingle = true;
529 if (bDraw)
531 if ( bSingle && nY<MAXROW )
533 SCROW nVisY = pRowInfo[nArrYplus1].nRowNo;
535 nPosX = nScrX;
536 if ( bLayoutRTL )
537 nPosX += nMirrorW - nOneX;
539 for (SCCOL i=nX1; i<=nX2; i++)
541 const long nNextX = nPosX + pRowInfo[0].pCellInfo[i+1].nWidth * nLayoutSign;
542 if (nNextX != nPosX) // visible
544 bool bVOver;
545 if ( bNextYisNextRow )
546 bVOver = pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped;
547 else
549 bVOver = static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
550 i,nYplus1,nTab,ATTR_MERGE_FLAG))
551 ->IsVerOverlapped()
552 && static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
553 i,nVisY,nTab,ATTR_MERGE_FLAG))
554 ->IsVerOverlapped();
555 //! nVisY from Array ??
557 if (!bVOver)
559 aGrid.AddHorLine(bWorksInPixels, nPosX, nNextX-nSignedOneX, nPosY-nOneY);
562 nPosX = nNextX;
565 else
567 aGrid.AddHorLine(bWorksInPixels, nScrX, nScrX+nScrW-nOneX, nPosY-nOneY);
574 void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
576 bPagebreakMode = true;
577 if (!pPageData)
578 return; // not yet initialized -> everything "not printed"
580 // mark printed range
581 // (everything in FillInfo is already initialized to sal_False)
583 sal_uInt16 nRangeCount = sal::static_int_cast<sal_uInt16>(pPageData->GetCount());
584 for (sal_uInt16 nPos=0; nPos<nRangeCount; nPos++)
586 ScRange aRange = pPageData->GetData( nPos ).GetPrintRange();
588 SCCOL nStartX = std::max( aRange.aStart.Col(), nX1 );
589 SCCOL nEndX = std::min( aRange.aEnd.Col(), nX2 );
590 SCROW nStartY = std::max( aRange.aStart.Row(), nY1 );
591 SCROW nEndY = std::min( aRange.aEnd.Row(), nY2 );
593 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
595 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
596 if ( pThisRowInfo->bChanged && pThisRowInfo->nRowNo >= nStartY &&
597 pThisRowInfo->nRowNo <= nEndY )
599 for (SCCOL nX=nStartX; nX<=nEndX; nX++)
600 pThisRowInfo->pCellInfo[nX+1].bPrinted = true;
606 void ScOutputData::FindRotated()
608 //! save nRotMax
609 SCCOL nRotMax = nX2;
610 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
611 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
612 nRotMax = pRowInfo[nRotY].nRotMaxCol;
614 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
616 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
617 if ( pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE &&
618 ( pThisRowInfo->bChanged || pRowInfo[nArrY-1].bChanged ||
619 ( nArrY+1<nArrCount && pRowInfo[nArrY+1].bChanged ) ) )
621 SCROW nY = pThisRowInfo->nRowNo;
623 for (SCCOL nX=0; nX<=nRotMax; nX++)
625 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
626 const ScPatternAttr* pPattern = pInfo->pPatternAttr;
627 const SfxItemSet* pCondSet = pInfo->pConditionSet;
629 if ( !pPattern && !mpDoc->ColHidden(nX, nTab) )
631 pPattern = mpDoc->GetPattern( nX, nY, nTab );
632 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
635 if ( pPattern ) // column isn't hidden
637 sal_uInt8 nDir = pPattern->GetRotateDir( pCondSet );
638 if (nDir != SC_ROTDIR_NONE)
640 pInfo->nRotateDir = nDir;
641 bAnyRotated = true;
649 static sal_uInt16 lcl_GetRotateDir( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
651 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
652 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
654 sal_uInt16 nRet = SC_ROTDIR_NONE;
656 long nAttrRotate = pPattern->GetRotateVal( pCondSet );
657 if ( nAttrRotate )
659 SvxRotateMode eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
660 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
662 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
663 nRet = SC_ROTDIR_STANDARD;
664 else if ( eRotMode == SVX_ROTATE_MODE_CENTER )
665 nRet = SC_ROTDIR_CENTER;
666 else if ( eRotMode == SVX_ROTATE_MODE_TOP || eRotMode == SVX_ROTATE_MODE_BOTTOM )
668 long nRot180 = nAttrRotate % 18000; // 1/100 degree
669 if ( nRot180 == 9000 )
670 nRet = SC_ROTDIR_CENTER;
671 else if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nRot180 < 9000 ) ||
672 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nRot180 > 9000 ) )
673 nRet = SC_ROTDIR_LEFT;
674 else
675 nRet = SC_ROTDIR_RIGHT;
679 return nRet;
682 static const SvxBrushItem* lcl_FindBackground( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
684 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
685 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
686 const SvxBrushItem* pBackground = static_cast<const SvxBrushItem*>(
687 &pPattern->GetItem( ATTR_BACKGROUND, pCondSet ));
689 sal_uInt16 nDir = lcl_GetRotateDir( pDoc, nCol, nRow, nTab );
691 // treat CENTER like RIGHT
692 if ( nDir == SC_ROTDIR_RIGHT || nDir == SC_ROTDIR_CENTER )
694 // text goes to the right -> take background from the left
695 while ( nCol > 0 && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
696 pBackground->GetColor().GetTransparency() != 255 )
698 --nCol;
699 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
700 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
701 pBackground = static_cast<const SvxBrushItem*>(&pPattern->GetItem( ATTR_BACKGROUND, pCondSet ));
704 else if ( nDir == SC_ROTDIR_LEFT )
706 // text goes to the left -> take background from the right
707 while ( nCol < MAXCOL && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
708 pBackground->GetColor().GetTransparency() != 255 )
710 ++nCol;
711 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
712 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
713 pBackground = static_cast<const SvxBrushItem*>(&pPattern->GetItem( ATTR_BACKGROUND, pCondSet ));
717 return pBackground;
720 static bool lcl_EqualBack( const RowInfo& rFirst, const RowInfo& rOther,
721 SCCOL nX1, SCCOL nX2, bool bShowProt, bool bPagebreakMode )
723 if ( rFirst.bChanged != rOther.bChanged ||
724 rFirst.bEmptyBack != rOther.bEmptyBack )
725 return false;
727 SCCOL nX;
728 if ( bShowProt )
730 for ( nX=nX1; nX<=nX2; nX++ )
732 const ScPatternAttr* pPat1 = rFirst.pCellInfo[nX+1].pPatternAttr;
733 const ScPatternAttr* pPat2 = rOther.pCellInfo[nX+1].pPatternAttr;
734 if ( !pPat1 || !pPat2 ||
735 &pPat1->GetItem(ATTR_PROTECTION) != &pPat2->GetItem(ATTR_PROTECTION) )
736 return false;
739 else
741 for ( nX=nX1; nX<=nX2; nX++ )
742 if ( rFirst.pCellInfo[nX+1].pBackground != rOther.pCellInfo[nX+1].pBackground )
743 return false;
746 if ( rFirst.nRotMaxCol != SC_ROTMAX_NONE || rOther.nRotMaxCol != SC_ROTMAX_NONE )
747 for ( nX=nX1; nX<=nX2; nX++ )
748 if ( rFirst.pCellInfo[nX+1].nRotateDir != rOther.pCellInfo[nX+1].nRotateDir )
749 return false;
751 if ( bPagebreakMode )
752 for ( nX=nX1; nX<=nX2; nX++ )
753 if ( rFirst.pCellInfo[nX+1].bPrinted != rOther.pCellInfo[nX+1].bPrinted )
754 return false;
756 for ( nX=nX1; nX<=nX2; nX++ )
758 const Color* pCol1 = rFirst.pCellInfo[nX+1].pColorScale.get();
759 const Color* pCol2 = rOther.pCellInfo[nX+1].pColorScale.get();
760 if( (pCol1 && !pCol2) || (!pCol1 && pCol2) )
761 return false;
763 if (pCol1 && (*pCol1 != *pCol2))
764 return false;
766 const ScDataBarInfo* pInfo1 = rFirst.pCellInfo[nX+1].pDataBar.get();
767 const ScDataBarInfo* pInfo2 = rOther.pCellInfo[nX+1].pDataBar.get();
769 if( (pInfo1 && !pInfo2) || (!pInfo1 && pInfo2) )
770 return false;
772 if (pInfo1 && (*pInfo1 != *pInfo2))
773 return false;
775 // each cell with an icon set should be painted the same way
776 const ScIconSetInfo* pIconSet1 = rFirst.pCellInfo[nX+1].pIconSet.get();
777 const ScIconSetInfo* pIconSet2 = rOther.pCellInfo[nX+1].pIconSet.get();
779 if(pIconSet1 || pIconSet2)
780 return false;
783 return true;
786 void ScOutputData::DrawDocumentBackground()
788 if ( !bSolidBackground )
789 return;
791 Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
792 mpDev->SetLineColor(aBgColor);
793 mpDev->SetFillColor(aBgColor);
795 Point aScreenPos = mpDev->PixelToLogic(Point(nScrX, nScrY));
796 Size aScreenSize = mpDev->PixelToLogic(Size(nScrW - 1,nScrH - 1));
798 mpDev->DrawRect(Rectangle(aScreenPos, aScreenSize));
801 namespace {
803 static const double lclCornerRectTransparency = 40.0;
805 void drawDataBars(vcl::RenderContext& rRenderContext, const ScDataBarInfo* pOldDataBarInfo, const Rectangle& rRect, long nOneX, long nOneY)
807 long nPosZero = 0;
808 Rectangle aPaintRect = rRect;
809 aPaintRect.Top() += 2 * nOneY;
810 aPaintRect.Bottom() -= 2 * nOneY;
811 aPaintRect.Left() += 2 * nOneX;
812 aPaintRect.Right() -= 2 * nOneX;
813 if(pOldDataBarInfo->mnZero)
815 // need to calculate null point in cell
816 long nLength = aPaintRect.Right() - aPaintRect.Left();
817 nPosZero = static_cast<long>(aPaintRect.Left() + nLength*pOldDataBarInfo->mnZero/100.0);
819 else
821 nPosZero = aPaintRect.Left();
824 if(pOldDataBarInfo->mnLength < 0)
826 aPaintRect.Right() = nPosZero;
827 long nLength = nPosZero - aPaintRect.Left();
828 aPaintRect.Left() = nPosZero + static_cast<long>(nLength * pOldDataBarInfo->mnLength/100.0);
830 else if(pOldDataBarInfo->mnLength > 0)
832 aPaintRect.Left() = nPosZero;
833 long nLength = aPaintRect.Right() - nPosZero;
834 aPaintRect.Right() = nPosZero + static_cast<long>(nLength * pOldDataBarInfo->mnLength/100.0);
836 else
837 return;
839 if(pOldDataBarInfo->mbGradient)
841 rRenderContext.SetLineColor(pOldDataBarInfo->maColor);
842 Gradient aGradient(GradientStyle_LINEAR, pOldDataBarInfo->maColor, COL_TRANSPARENT);
844 if(pOldDataBarInfo->mnLength < 0)
845 aGradient.SetAngle(2700);
846 else
847 aGradient.SetAngle(900);
849 rRenderContext.DrawGradient(aPaintRect, aGradient);
851 rRenderContext.SetLineColor();
853 else
855 rRenderContext.SetFillColor(pOldDataBarInfo->maColor);
856 rRenderContext.DrawRect(aPaintRect);
859 //draw axis
860 if(pOldDataBarInfo->mnZero && pOldDataBarInfo->mnZero != 100)
862 Point aPoint1(nPosZero, rRect.Top());
863 Point aPoint2(nPosZero, rRect.Bottom());
864 LineInfo aLineInfo(LINE_DASH, 1);
865 aLineInfo.SetDashCount( 4 );
866 aLineInfo.SetDistance( 3 );
867 aLineInfo.SetDashLen( 3 );
868 rRenderContext.SetFillColor(pOldDataBarInfo->maAxisColor);
869 rRenderContext.SetLineColor(pOldDataBarInfo->maAxisColor);
870 rRenderContext.DrawLine(aPoint1, aPoint2, aLineInfo);
871 rRenderContext.SetLineColor();
872 rRenderContext.SetFillColor();
876 const BitmapEx& getIcon(sc::IconSetBitmapMap & rIconSetBitmapMap, ScIconSetType eType, sal_Int32 nIndex)
878 return ScIconSetFormat::getBitmap(rIconSetBitmapMap, eType, nIndex);
881 void drawIconSets(vcl::RenderContext& rRenderContext, const ScIconSetInfo* pOldIconSetInfo, const Rectangle& rRect, long nOneX, long nOneY,
882 sc::IconSetBitmapMap & rIconSetBitmapMap)
884 //long nSize = 16;
885 ScIconSetType eType = pOldIconSetInfo->eIconSetType;
886 sal_Int32 nIndex = pOldIconSetInfo->nIconIndex;
887 const BitmapEx& rIcon = getIcon(rIconSetBitmapMap, eType, nIndex);
888 long aOrigSize = std::max<long>(0,std::min(rRect.GetSize().getWidth() - 4 * nOneX, rRect.GetSize().getHeight() -4 * nOneY));
889 rRenderContext.DrawBitmapEx( Point( rRect.Left() + 2 * nOneX, rRect.Top() + 2 * nOneY), Size(aOrigSize, aOrigSize), rIcon );
892 void drawCells(vcl::RenderContext& rRenderContext, const Color* pColor, const SvxBrushItem* pBackground, const Color*& pOldColor, const SvxBrushItem*& pOldBackground,
893 Rectangle& rRect, long nPosX, long nLayoutSign, long nOneX, long nOneY, const ScDataBarInfo* pDataBarInfo, const ScDataBarInfo*& pOldDataBarInfo,
894 const ScIconSetInfo* pIconSetInfo, const ScIconSetInfo*& pOldIconSetInfo,
895 sc::IconSetBitmapMap & rIconSetBitmapMap)
897 long nSignedOneX = nOneX * nLayoutSign;
898 // need to paint if old color scale has been used and now
899 // we have a different color or a style based background
900 // we can here fall back to pointer comparison
901 if (pOldColor && (pBackground || pOldColor != pColor || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo))
903 rRect.Right() = nPosX-nSignedOneX;
904 if( !pOldColor->GetTransparency() )
906 rRenderContext.SetFillColor( *pOldColor );
907 rRenderContext.DrawRect( rRect );
909 if( pOldDataBarInfo )
910 drawDataBars(rRenderContext, pOldDataBarInfo, rRect, nOneX, nOneY);
911 if( pOldIconSetInfo )
912 drawIconSets(rRenderContext, pOldIconSetInfo, rRect, nOneX, nOneY, rIconSetBitmapMap);
914 rRect.Left() = nPosX - nSignedOneX;
917 if ( pOldBackground && (pColor ||pBackground != pOldBackground || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo) )
919 rRect.Right() = nPosX-nSignedOneX;
920 if (pOldBackground) // ==0 if hidden
922 Color aBackCol = pOldBackground->GetColor();
923 if ( !aBackCol.GetTransparency() ) //! partial transparency?
925 rRenderContext.SetFillColor( aBackCol );
926 rRenderContext.DrawRect( rRect );
929 if( pOldDataBarInfo )
930 drawDataBars(rRenderContext, pOldDataBarInfo, rRect, nOneX, nOneY);
931 if( pOldIconSetInfo )
932 drawIconSets(rRenderContext, pOldIconSetInfo, rRect, nOneX, nOneY, rIconSetBitmapMap);
934 rRect.Left() = nPosX - nSignedOneX;
937 if (!pOldBackground && !pOldColor && (pDataBarInfo || pIconSetInfo))
939 rRect.Right() = nPosX -nSignedOneX;
940 rRect.Left() = nPosX - nSignedOneX;
943 if(pColor)
945 // only update pOldColor if the colors changed
946 if (!pOldColor || *pOldColor != *pColor)
947 pOldColor = pColor;
949 pOldBackground = nullptr;
951 else if(pBackground)
953 pOldBackground = pBackground;
954 pOldColor = nullptr;
957 if(pDataBarInfo)
958 pOldDataBarInfo = pDataBarInfo;
959 else
960 pOldDataBarInfo = nullptr;
962 if(pIconSetInfo)
963 pOldIconSetInfo = pIconSetInfo;
964 else
965 pOldIconSetInfo = nullptr;
970 void ScOutputData::DrawBackground(vcl::RenderContext& rRenderContext)
972 FindRotated(); //! from the outside?
974 Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
975 long nOneXLogic = aOnePixel.Width();
976 long nOneYLogic = aOnePixel.Height();
978 // See more about bWorksInPixels in ScOutputData::DrawGrid
979 bool bWorksInPixels = false;
980 if (eType == OUTTYPE_WINDOW)
981 bWorksInPixels = true;
983 long nOneX = 1;
984 long nOneY = 1;
985 if (!bWorksInPixels)
987 nOneX = nOneXLogic;
988 nOneY = nOneYLogic;
991 Rectangle aRect;
993 long nLayoutSign = bLayoutRTL ? -1 : 1;
995 rRenderContext.SetLineColor();
997 bool bShowProt = mbSyntaxMode && mpDoc->IsTabProtected(nTab);
998 bool bDoAll = bShowProt || bPagebreakMode || bSolidBackground;
1000 bool bCellContrast = mbUseStyleColor &&
1001 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
1003 long nPosY = nScrY;
1004 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1006 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1007 long nRowHeight = pThisRowInfo->nHeight;
1009 if ( pThisRowInfo->bChanged )
1011 if ( ( ( pThisRowInfo->bEmptyBack ) || mbSyntaxMode ) && !bDoAll )
1013 // nothing
1015 else
1017 // scan for rows with the same background:
1018 SCSIZE nSkip = 0;
1019 while ( nArrY+nSkip+2<nArrCount &&
1020 lcl_EqualBack( *pThisRowInfo, pRowInfo[nArrY+nSkip+1],
1021 nX1, nX2, bShowProt, bPagebreakMode ) )
1023 ++nSkip;
1024 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
1027 long nPosX = nScrX;
1029 if ( bLayoutRTL )
1030 nPosX += nMirrorW - nOneX;
1032 aRect = Rectangle(nPosX, nPosY - nOneY, nPosX, nPosY - nOneY + nRowHeight);
1033 if (bWorksInPixels)
1034 aRect = rRenderContext.PixelToLogic(aRect); // internal data in pixels, but we'll be drawing in logic units
1036 const SvxBrushItem* pOldBackground = nullptr;
1037 const SvxBrushItem* pBackground;
1038 const Color* pOldColor = nullptr;
1039 const ScDataBarInfo* pOldDataBarInfo = nullptr;
1040 const ScIconSetInfo* pOldIconSetInfo = nullptr;
1041 SCCOL nMergedCells = 1;
1042 SCCOL nOldMerged = 0;
1044 for (SCCOL nX=nX1; nX + nMergedCells <= nX2 + 1; nX += nOldMerged)
1046 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+nMergedCells];
1048 nOldMerged = nMergedCells;
1050 if (bCellContrast)
1052 // high contrast for cell borders and backgrounds -> empty background
1053 pBackground = ScGlobal::GetEmptyBrushItem();
1055 else if (bShowProt) // show cell protection in syntax mode
1057 const ScPatternAttr* pP = pInfo->pPatternAttr;
1058 if (pP)
1060 const ScProtectionAttr& rProt = static_cast<const ScProtectionAttr&>(
1061 pP->GetItem(ATTR_PROTECTION));
1062 if (rProt.GetProtection() || rProt.GetHideCell())
1063 pBackground = ScGlobal::GetProtectedBrushItem();
1064 else
1065 pBackground = ScGlobal::GetEmptyBrushItem();
1067 else
1068 pBackground = nullptr;
1070 else
1071 pBackground = pInfo->pBackground;
1073 if ( bPagebreakMode && !pInfo->bPrinted )
1074 pBackground = ScGlobal::GetProtectedBrushItem();
1076 if ( pInfo->nRotateDir > SC_ROTDIR_STANDARD &&
1077 pBackground->GetColor().GetTransparency() != 255 &&
1078 !bCellContrast )
1080 SCROW nY = pRowInfo[nArrY].nRowNo;
1081 pBackground = lcl_FindBackground( mpDoc, nX, nY, nTab );
1084 const Color* pColor = pInfo->pColorScale.get();
1085 const ScDataBarInfo* pDataBarInfo = pInfo->pDataBar.get();
1086 const ScIconSetInfo* pIconSetInfo = pInfo->pIconSet.get();
1088 long nPosXLogic = nPosX;
1089 if (bWorksInPixels)
1090 nPosXLogic = rRenderContext.PixelToLogic(Point(nPosX, 0)).X();
1092 drawCells(rRenderContext, pColor, pBackground, pOldColor, pOldBackground, aRect, nPosXLogic, nLayoutSign, nOneXLogic, nOneYLogic, pDataBarInfo, pOldDataBarInfo, pIconSetInfo, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap());
1094 // extend for all merged cells
1095 nMergedCells = 1;
1096 if (pInfo->bMerged && pInfo->pPatternAttr)
1098 const ScMergeAttr* pMerge =
1099 static_cast<const ScMergeAttr*>(&pInfo->pPatternAttr->GetItem(ATTR_MERGE));
1100 nMergedCells = std::max<SCCOL>(1, pMerge->GetColMerge());
1103 for (SCCOL nMerged = 0; nMerged < nMergedCells; ++nMerged)
1105 SCCOL nCol = nX+nOldMerged+nMerged;
1106 if (nCol > nX2+2)
1107 break;
1108 nPosX += pRowInfo[0].pCellInfo[nCol].nWidth * nLayoutSign;
1112 long nPosXLogic = nPosX;
1113 if (bWorksInPixels)
1114 nPosXLogic = rRenderContext.PixelToLogic(Point(nPosX, 0)).X();
1116 drawCells(rRenderContext, nullptr, nullptr, pOldColor, pOldBackground, aRect, nPosXLogic, nLayoutSign, nOneXLogic, nOneYLogic, nullptr, pOldDataBarInfo, nullptr, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap());
1118 nArrY += nSkip;
1121 nPosY += nRowHeight;
1125 void ScOutputData::DrawShadow()
1127 DrawExtraShadow( false, false, false, false );
1130 void ScOutputData::DrawExtraShadow(bool bLeft, bool bTop, bool bRight, bool bBottom)
1132 mpDev->SetLineColor();
1134 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1135 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1136 Color aAutoTextColor;
1137 if ( bCellContrast )
1138 aAutoTextColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
1140 long nInitPosX = nScrX;
1141 if ( bLayoutRTL )
1143 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1144 long nOneX = aOnePixel.Width();
1145 nInitPosX += nMirrorW - nOneX;
1147 long nLayoutSign = bLayoutRTL ? -1 : 1;
1149 long nPosY = nScrY - pRowInfo[0].nHeight;
1150 for (SCSIZE nArrY=0; nArrY<nArrCount; nArrY++)
1152 bool bCornerY = ( nArrY == 0 ) || ( nArrY+1 == nArrCount );
1153 bool bSkipY = ( nArrY==0 && !bTop ) || ( nArrY+1 == nArrCount && !bBottom );
1155 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1156 long nRowHeight = pThisRowInfo->nHeight;
1158 if ( pThisRowInfo->bChanged && !bSkipY )
1160 long nPosX = nInitPosX - pRowInfo[0].pCellInfo[nX1].nWidth * nLayoutSign;
1161 for (SCCOL nArrX=nX1; nArrX<=nX2+2; nArrX++)
1163 bool bCornerX = ( nArrX==nX1 || nArrX==nX2+2 );
1164 bool bSkipX = ( nArrX==nX1 && !bLeft ) || ( nArrX==nX2+2 && !bRight );
1166 for (sal_uInt16 nPass=0; nPass<2; nPass++) // horizontal / vertical
1168 const SvxShadowItem* pAttr = nPass ?
1169 pThisRowInfo->pCellInfo[nArrX].pVShadowOrigin :
1170 pThisRowInfo->pCellInfo[nArrX].pHShadowOrigin;
1171 if ( pAttr && !bSkipX )
1173 ScShadowPart ePart = nPass ?
1174 pThisRowInfo->pCellInfo[nArrX].eVShadowPart :
1175 pThisRowInfo->pCellInfo[nArrX].eHShadowPart;
1177 bool bDo = true;
1178 if ( (nPass==0 && bCornerX) || (nPass==1 && bCornerY) )
1179 if ( ePart != SC_SHADOW_CORNER )
1180 bDo = false;
1182 if (bDo)
1184 long nThisWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1185 long nMaxWidth = nThisWidth;
1186 if (!nMaxWidth)
1188 //! direction must depend on shadow location
1189 SCCOL nWx = nArrX; // nX+1
1190 while (nWx<nX2 && !pRowInfo[0].pCellInfo[nWx+1].nWidth)
1191 ++nWx;
1192 nMaxWidth = pRowInfo[0].pCellInfo[nWx+1].nWidth;
1195 // rectangle is in logical orientation
1196 Rectangle aRect( nPosX, nPosY,
1197 nPosX + ( nThisWidth - 1 ) * nLayoutSign,
1198 nPosY + pRowInfo[nArrY].nHeight - 1 );
1200 long nSize = pAttr->GetWidth();
1201 long nSizeX = (long)(nSize*mnPPTX);
1202 if (nSizeX >= nMaxWidth) nSizeX = nMaxWidth-1;
1203 long nSizeY = (long)(nSize*mnPPTY);
1204 if (nSizeY >= nRowHeight) nSizeY = nRowHeight-1;
1206 nSizeX *= nLayoutSign; // used only to add to rectangle values
1208 SvxShadowLocation eLoc = pAttr->GetLocation();
1209 if ( bLayoutRTL )
1211 // Shadow location is specified as "visual" (right is always right),
1212 // so the attribute's location value is mirrored here and in FillInfo.
1213 switch (eLoc)
1215 case SVX_SHADOW_BOTTOMRIGHT: eLoc = SVX_SHADOW_BOTTOMLEFT; break;
1216 case SVX_SHADOW_BOTTOMLEFT: eLoc = SVX_SHADOW_BOTTOMRIGHT; break;
1217 case SVX_SHADOW_TOPRIGHT: eLoc = SVX_SHADOW_TOPLEFT; break;
1218 case SVX_SHADOW_TOPLEFT: eLoc = SVX_SHADOW_TOPRIGHT; break;
1219 default:
1221 // added to avoid warnings
1226 if (ePart == SC_SHADOW_HORIZ || ePart == SC_SHADOW_HSTART ||
1227 ePart == SC_SHADOW_CORNER)
1229 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_TOPRIGHT)
1230 aRect.Top() = aRect.Bottom() - nSizeY;
1231 else
1232 aRect.Bottom() = aRect.Top() + nSizeY;
1234 if (ePart == SC_SHADOW_VERT || ePart == SC_SHADOW_VSTART ||
1235 ePart == SC_SHADOW_CORNER)
1237 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_BOTTOMLEFT)
1238 aRect.Left() = aRect.Right() - nSizeX;
1239 else
1240 aRect.Right() = aRect.Left() + nSizeX;
1242 if (ePart == SC_SHADOW_HSTART)
1244 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_BOTTOMLEFT)
1245 aRect.Right() -= nSizeX;
1246 else
1247 aRect.Left() += nSizeX;
1249 if (ePart == SC_SHADOW_VSTART)
1251 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_TOPRIGHT)
1252 aRect.Bottom() -= nSizeY;
1253 else
1254 aRect.Top() += nSizeY;
1257 //! merge rectangles?
1258 mpDev->SetFillColor( bCellContrast ? aAutoTextColor : pAttr->GetColor() );
1259 mpDev->DrawRect( aRect );
1264 nPosX += pRowInfo[0].pCellInfo[nArrX].nWidth * nLayoutSign;
1267 nPosY += nRowHeight;
1271 void ScOutputData::DrawClear()
1273 Rectangle aRect;
1274 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1275 long nOneX = aOnePixel.Width();
1276 long nOneY = aOnePixel.Height();
1278 // (called only for ScGridWindow)
1279 Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
1281 if (bMetaFile)
1282 nOneX = nOneY = 0;
1284 mpDev->SetLineColor();
1286 mpDev->SetFillColor( aBgColor );
1288 long nPosY = nScrY;
1289 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1291 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1292 long nRowHeight = pThisRowInfo->nHeight;
1294 if ( pThisRowInfo->bChanged )
1296 // scan for more rows which must be painted:
1297 SCSIZE nSkip = 0;
1298 while ( nArrY+nSkip+2<nArrCount && pRowInfo[nArrY+nSkip+1].bChanged )
1300 ++nSkip;
1301 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
1304 aRect = Rectangle( Point( nScrX, nPosY ),
1305 Size( nScrW+1-nOneX, nRowHeight+1-nOneY) );
1306 mpDev->DrawRect( aRect );
1308 nArrY += nSkip;
1310 nPosY += nRowHeight;
1314 // Lines
1316 long lclGetSnappedX( OutputDevice& rDev, long nPosX, bool bSnapPixel )
1318 return (bSnapPixel && nPosX) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( nPosX, 0 ) ) ).Width() : nPosX;
1321 long lclGetSnappedY( OutputDevice& rDev, long nPosY, bool bSnapPixel )
1323 return (bSnapPixel && nPosY) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( 0, nPosY ) ) ).Height() : nPosY;
1326 size_t lclGetArrayColFromCellInfoX( sal_uInt16 nCellInfoX, sal_uInt16 nCellInfoFirstX, sal_uInt16 nCellInfoLastX, bool bRTL )
1328 return static_cast< size_t >( bRTL ? (nCellInfoLastX + 2 - nCellInfoX) : (nCellInfoX - nCellInfoFirstX) );
1331 void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)
1333 DrawModeFlags nOldDrawMode = rRenderContext.GetDrawMode();
1335 Color aSingleColor;
1336 bool bUseSingleColor = false;
1337 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1338 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1340 // if a Calc OLE object is embedded in Draw/Impress, the VCL DrawMode is used
1341 // for display mode / B&W printing. The VCL DrawMode handling doesn't work for lines
1342 // that are drawn with DrawRect, so if the line/background bits are set, the DrawMode
1343 // must be reset and the border colors handled here.
1345 if ( ( nOldDrawMode & DrawModeFlags::WhiteFill ) && ( nOldDrawMode & DrawModeFlags::BlackLine ) )
1347 rRenderContext.SetDrawMode( nOldDrawMode & (~DrawModeFlags::WhiteFill) );
1348 aSingleColor.SetColor( COL_BLACK );
1349 bUseSingleColor = true;
1351 else if ( ( nOldDrawMode & DrawModeFlags::SettingsFill ) && ( nOldDrawMode & DrawModeFlags::SettingsLine ) )
1353 rRenderContext.SetDrawMode( nOldDrawMode & (~DrawModeFlags::SettingsFill) );
1354 aSingleColor = rStyleSettings.GetWindowTextColor(); // same as used in VCL for DrawModeFlags::SettingsLine
1355 bUseSingleColor = true;
1357 else if ( bCellContrast )
1359 aSingleColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
1360 bUseSingleColor = true;
1363 const Color* pForceColor = bUseSingleColor ? &aSingleColor : nullptr;
1365 if (bAnyRotated)
1366 DrawRotatedFrame(rRenderContext, pForceColor); // removes the lines that must not be painted here
1368 long nInitPosX = nScrX;
1369 if ( bLayoutRTL )
1371 Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
1372 long nOneX = aOnePixel.Width();
1373 nInitPosX += nMirrorW - nOneX;
1375 long nLayoutSign = bLayoutRTL ? -1 : 1;
1377 // *** set column and row sizes of the frame border array ***
1379 svx::frame::Array& rArray = mrTabInfo.maArray;
1380 size_t nColCount = rArray.GetColCount();
1381 size_t nRowCount = rArray.GetRowCount();
1383 // row heights
1385 // row 0 is not visible (dummy for borders from top) - subtract its height from initial position
1386 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit before
1387 long nOldPosY = nScrY - 1 - pRowInfo[ 0 ].nHeight;
1388 long nOldSnapY = lclGetSnappedY( rRenderContext, nOldPosY, bSnapPixel );
1389 rArray.SetYOffset( nOldSnapY );
1390 for( size_t nRow = 0; nRow < nRowCount; ++nRow )
1392 long nNewPosY = nOldPosY + pRowInfo[ nRow ].nHeight;
1393 long nNewSnapY = lclGetSnappedY( rRenderContext, nNewPosY, bSnapPixel );
1394 rArray.SetRowHeight( nRow, nNewSnapY - nOldSnapY );
1395 nOldPosY = nNewPosY;
1396 nOldSnapY = nNewSnapY;
1399 // column widths
1401 // column nX1 is not visible (dummy for borders from left) - subtract its width from initial position
1402 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit above
1403 long nOldPosX = nInitPosX - nLayoutSign * (1 + pRowInfo[ 0 ].pCellInfo[ nX1 ].nWidth);
1404 long nOldSnapX = lclGetSnappedX( rRenderContext, nOldPosX, bSnapPixel );
1405 // set X offset for left-to-right sheets; for right-to-left sheets this is done after for() loop
1406 if( !bLayoutRTL )
1407 rArray.SetXOffset( nOldSnapX );
1408 for( sal_uInt16 nInfoIdx = nX1; nInfoIdx <= nX2 + 2; ++nInfoIdx )
1410 size_t nCol = lclGetArrayColFromCellInfoX( nInfoIdx, nX1, nX2, bLayoutRTL );
1411 long nNewPosX = nOldPosX + pRowInfo[ 0 ].pCellInfo[ nInfoIdx ].nWidth * nLayoutSign;
1412 long nNewSnapX = lclGetSnappedX( rRenderContext, nNewPosX, bSnapPixel );
1413 rArray.SetColWidth( nCol, std::abs( nNewSnapX - nOldSnapX ) );
1414 nOldPosX = nNewPosX;
1415 nOldSnapX = nNewSnapX;
1417 if( bLayoutRTL )
1418 rArray.SetXOffset( nOldSnapX );
1420 // *** draw the array ***
1422 size_t nFirstCol = 1;
1423 size_t nFirstRow = 1;
1424 size_t nLastCol = nColCount - 2;
1425 size_t nLastRow = nRowCount - 2;
1427 if( mrTabInfo.mbPageMode )
1428 rArray.SetClipRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
1430 // draw only rows with set RowInfo::bChanged flag
1431 size_t nRow1 = nFirstRow;
1432 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D());
1433 if (!pProcessor)
1434 return;
1436 while( nRow1 <= nLastRow )
1438 while( (nRow1 <= nLastRow) && !pRowInfo[ nRow1 ].bChanged ) ++nRow1;
1439 if( nRow1 <= nLastRow )
1441 size_t nRow2 = nRow1;
1442 while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
1443 rArray.DrawRange( pProcessor.get(), nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
1444 nRow1 = nRow2 + 1;
1447 pProcessor.reset();
1449 rRenderContext.SetDrawMode(nOldDrawMode);
1452 // Line below the cell
1454 static const ::editeng::SvxBorderLine* lcl_FindHorLine( ScDocument* pDoc,
1455 SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nRotDir,
1456 bool bTopLine )
1458 if ( nRotDir != SC_ROTDIR_LEFT && nRotDir != SC_ROTDIR_RIGHT )
1459 return nullptr;
1461 bool bFound = false;
1462 while (!bFound)
1464 if ( nRotDir == SC_ROTDIR_LEFT )
1466 // text to the left -> line from the right
1467 if ( nCol < MAXCOL )
1468 ++nCol;
1469 else
1470 return nullptr; // couldn't find it
1472 else
1474 // text to the right -> line from the left
1475 if ( nCol > 0 )
1476 --nCol;
1477 else
1478 return nullptr; // couldn't find it
1480 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
1481 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
1482 if ( !pPattern->GetRotateVal( pCondSet ) ||
1483 static_cast<const SvxRotateModeItem&>(pPattern->GetItem(
1484 ATTR_ROTATE_MODE, pCondSet)).GetValue() == SVX_ROTATE_MODE_STANDARD )
1485 bFound = true;
1488 if (bTopLine)
1489 --nRow;
1490 const ::editeng::SvxBorderLine* pThisBottom;
1491 if ( ValidRow(nRow) )
1492 pThisBottom = static_cast<const SvxBoxItem*>(pDoc->GetAttr( nCol, nRow, nTab, ATTR_BORDER ))->GetBottom();
1493 else
1494 pThisBottom = nullptr;
1495 const ::editeng::SvxBorderLine* pNextTop;
1496 if ( nRow < MAXROW )
1497 pNextTop = static_cast<const SvxBoxItem*>(pDoc->GetAttr( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
1498 else
1499 pNextTop = nullptr;
1501 if ( ScHasPriority( pThisBottom, pNextTop ) )
1502 return pThisBottom;
1503 else
1504 return pNextTop;
1507 static long lcl_getRotate( ScDocument* pDoc, SCTAB nTab, SCCOL nX, SCROW nY )
1509 long nRotate = 0;
1511 const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab );
1512 const SfxItemSet* pCondSet = pDoc->GetCondResult( nX, nY, nTab );
1514 nRotate = pPattern->GetRotateVal( pCondSet );
1516 return nRotate;
1519 void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Color* pForceColor)
1521 //! save nRotMax
1522 SCCOL nRotMax = nX2;
1523 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
1524 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
1525 nRotMax = pRowInfo[nRotY].nRotMaxCol;
1527 const ScPatternAttr* pPattern;
1528 const SfxItemSet* pCondSet;
1530 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1531 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1533 // color (pForceColor) is determined externally, including DrawMode changes
1535 long nInitPosX = nScrX;
1536 if ( bLayoutRTL )
1538 Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
1539 long nOneX = aOnePixel.Width();
1540 nInitPosX += nMirrorW - nOneX;
1542 long nLayoutSign = bLayoutRTL ? -1 : 1;
1544 Rectangle aClipRect( Point(nScrX, nScrY), Size(nScrW, nScrH) );
1545 if (bMetaFile)
1547 rRenderContext.Push();
1548 rRenderContext.IntersectClipRegion( aClipRect );
1550 else
1551 rRenderContext.SetClipRegion( vcl::Region( aClipRect ) );
1553 svx::frame::Array& rArray = mrTabInfo.maArray;
1554 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D( ));
1556 long nPosY = nScrY;
1557 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
1559 // Rotated is also drawn one line above/below Changed if parts extend into the cell
1561 RowInfo& rPrevRowInfo = pRowInfo[nArrY-1];
1562 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1563 RowInfo& rNextRowInfo = pRowInfo[nArrY+1];
1565 size_t nRow = static_cast< size_t >( nArrY );
1567 long nRowHeight = rThisRowInfo.nHeight;
1568 if ( rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE &&
1569 ( rThisRowInfo.bChanged || rPrevRowInfo.bChanged ||
1570 ( nArrY+1<nArrCount && rNextRowInfo.bChanged ) ) )
1572 SCROW nY = rThisRowInfo.nRowNo;
1573 long nPosX = 0;
1574 SCCOL nX;
1575 for (nX=0; nX<=nRotMax; nX++)
1577 if (nX==nX1) nPosX = nInitPosX; // calculated individually for preceding positions
1579 sal_uInt16 nArrX = nX + 1;
1581 CellInfo* pInfo = &rThisRowInfo.pCellInfo[nArrX];
1582 long nColWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1583 if ( pInfo->nRotateDir > SC_ROTDIR_STANDARD &&
1584 !pInfo->bHOverlapped && !pInfo->bVOverlapped )
1586 pPattern = pInfo->pPatternAttr;
1587 pCondSet = pInfo->pConditionSet;
1588 if (!pPattern)
1590 pPattern = mpDoc->GetPattern( nX, nY, nTab );
1591 pInfo->pPatternAttr = pPattern;
1592 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
1593 pInfo->pConditionSet = pCondSet;
1596 //! LastPattern etc.
1598 long nAttrRotate = pPattern->GetRotateVal( pCondSet );
1599 SvxRotateMode eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
1600 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
1602 if ( nAttrRotate )
1604 if (nX<nX1) // compute negative position
1606 nPosX = nInitPosX;
1607 SCCOL nCol = nX1;
1608 while (nCol > nX)
1610 --nCol;
1611 nPosX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
1615 // start position minus 1 so rotated backgrounds suit the border
1616 // (border is on the grid)
1618 long nTop = nPosY - 1;
1619 long nBottom = nPosY + nRowHeight - 1;
1620 long nTopLeft = nPosX - nLayoutSign;
1621 long nTopRight = nPosX + ( nColWidth - 1 ) * nLayoutSign;
1622 long nBotLeft = nTopLeft;
1623 long nBotRight = nTopRight;
1625 // inclusion of the sign here hasn't been decided yet
1626 // (if not, the extension of the non-rotated background must also be changed)
1627 double nRealOrient = nLayoutSign * nAttrRotate * F_PI18000; // 1/100th degrees
1628 double nCos = cos( nRealOrient );
1629 double nSin = sin( nRealOrient );
1630 //! restrict !!!
1631 long nSkew = (long) ( nRowHeight * nCos / nSin );
1633 switch (eRotMode)
1635 case SVX_ROTATE_MODE_BOTTOM:
1636 nTopLeft += nSkew;
1637 nTopRight += nSkew;
1638 break;
1639 case SVX_ROTATE_MODE_CENTER:
1640 nSkew /= 2;
1641 nTopLeft += nSkew;
1642 nTopRight += nSkew;
1643 nBotLeft -= nSkew;
1644 nBotRight -= nSkew;
1645 break;
1646 case SVX_ROTATE_MODE_TOP:
1647 nBotLeft -= nSkew;
1648 nBotRight -= nSkew;
1649 break;
1650 default:
1652 // added to avoid warnings
1656 Point aPoints[4];
1657 aPoints[0] = Point( nTopLeft, nTop );
1658 aPoints[1] = Point( nTopRight, nTop );
1659 aPoints[2] = Point( nBotRight, nBottom );
1660 aPoints[3] = Point( nBotLeft, nBottom );
1662 const SvxBrushItem* pBackground = pInfo->pBackground;
1663 if (!pBackground)
1664 pBackground = static_cast<const SvxBrushItem*>( &pPattern->GetItem(
1665 ATTR_BACKGROUND, pCondSet ));
1666 if (bCellContrast)
1668 // high contrast for cell borders and backgrounds -> empty background
1669 pBackground = ScGlobal::GetEmptyBrushItem();
1671 if(!pInfo->pColorScale)
1673 const Color& rColor = pBackground->GetColor();
1674 if ( rColor.GetTransparency() != 255 )
1676 // draw background only for the changed row itself
1677 // (background doesn't extend into other cells).
1678 // For the borders (rotated and normal), clipping should be
1679 // set if the row isn't changed, but at least the borders
1680 // don't cover the cell contents.
1681 if ( rThisRowInfo.bChanged )
1683 tools::Polygon aPoly( 4, aPoints );
1685 // for DrawPolygon, whitout Pen one pixel is left out
1686 // to the right and below...
1687 if ( rColor.GetTransparency() == 0 )
1688 rRenderContext.SetLineColor(rColor);
1689 else
1690 rRenderContext.SetLineColor();
1691 rRenderContext.SetFillColor(rColor);
1692 rRenderContext.DrawPolygon( aPoly );
1696 else
1698 tools::Polygon aPoly( 4, aPoints );
1699 const Color* pColor = pInfo->pColorScale.get();
1701 // for DrawPolygon, whitout Pen one pixel is left out
1702 // to the right and below...
1703 if ( pColor->GetTransparency() == 0 )
1704 rRenderContext.SetLineColor(*pColor);
1705 else
1706 rRenderContext.SetLineColor();
1707 rRenderContext.SetFillColor(*pColor);
1708 rRenderContext.DrawPolygon( aPoly );
1712 svx::frame::Style aTopLine, aBottomLine, aLeftLine, aRightLine;
1714 if ( nX < nX1 || nX > nX2 ) // Attributes in FillInfo not set
1716 //! consider page borders for printing !!!!!
1717 const ::editeng::SvxBorderLine* pLeftLine;
1718 const ::editeng::SvxBorderLine* pTopLine;
1719 const ::editeng::SvxBorderLine* pRightLine;
1720 const ::editeng::SvxBorderLine* pBottomLine;
1721 mpDoc->GetBorderLines( nX, nY, nTab,
1722 &pLeftLine, &pTopLine, &pRightLine, &pBottomLine );
1723 aTopLine.Set( pTopLine, mnPPTY );
1724 aBottomLine.Set( pBottomLine, mnPPTY );
1725 aLeftLine.Set( pLeftLine, mnPPTX );
1726 aRightLine.Set( pRightLine, mnPPTX );
1728 else
1730 size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
1731 aTopLine = rArray.GetCellStyleTop( nCol, nRow );
1732 aBottomLine = rArray.GetCellStyleBottom( nCol, nRow );
1733 aLeftLine = rArray.GetCellStyleLeft( nCol, nRow );
1734 aRightLine = rArray.GetCellStyleRight( nCol, nRow );
1735 // in RTL mode the array is already mirrored -> swap back left/right borders
1736 if( bLayoutRTL )
1737 std::swap( aLeftLine, aRightLine );
1740 // Horizontal lines
1741 if (aTopLine.Prim() || aTopLine.Secn())
1743 long nUpperRotate = lcl_getRotate( mpDoc, nTab, nX, nY - 1 );
1744 pProcessor->process( svx::frame::CreateBorderPrimitives(
1745 aPoints[bLayoutRTL?1:0], aPoints[bLayoutRTL?0:1], aTopLine,
1746 svx::frame::Style(),
1747 svx::frame::Style(),
1748 aLeftLine,
1749 svx::frame::Style(),
1750 svx::frame::Style(),
1751 aRightLine,
1752 pForceColor, nUpperRotate, nAttrRotate ) );
1755 if (aBottomLine.Prim() || aBottomLine.Secn())
1757 long nLowerRotate = lcl_getRotate( mpDoc, nTab, nX, nY + 1 );
1758 pProcessor->process( svx::frame::CreateBorderPrimitives(
1759 aPoints[bLayoutRTL?2:3], aPoints[bLayoutRTL?3:2], aBottomLine,
1760 aLeftLine,
1761 svx::frame::Style(),
1762 svx::frame::Style(),
1763 aRightLine,
1764 svx::frame::Style(),
1765 svx::frame::Style(),
1766 pForceColor, 18000 - nAttrRotate, 18000 - nLowerRotate ) );
1769 // Vertical slanted lines
1770 if (aLeftLine.Prim() || aLeftLine.Secn())
1772 long nLeftRotate = lcl_getRotate( mpDoc, nTab, nX - 1, nY );
1773 pProcessor->process( svx::frame::CreateBorderPrimitives(
1774 aPoints[0], aPoints[3], aLeftLine,
1775 aTopLine,
1776 svx::frame::Style(),
1777 svx::frame::Style(),
1778 aBottomLine,
1779 svx::frame::Style(),
1780 svx::frame::Style(),
1781 pForceColor, nAttrRotate, nLeftRotate ) );
1784 if (aRightLine.Prim() || aRightLine.Secn())
1786 long nRightRotate = lcl_getRotate( mpDoc, nTab, nX + 1, nY );
1787 pProcessor->process( svx::frame::CreateBorderPrimitives(
1788 aPoints[1], aPoints[2], aRightLine,
1789 svx::frame::Style(),
1790 svx::frame::Style(),
1791 aTopLine,
1792 svx::frame::Style(),
1793 svx::frame::Style(),
1794 aBottomLine,
1795 pForceColor, 18000 - nRightRotate, 18000 - nAttrRotate ) );
1799 nPosX += nColWidth * nLayoutSign;
1802 // delete the lines for normal output only afterwards in the second step
1804 nX = nX1 > 0 ? (nX1-1) : static_cast<SCCOL>(0);
1805 for (; nX<=nX2+1; nX++) // visible part +- 1
1807 sal_uInt16 nArrX = nX + 1;
1808 CellInfo& rInfo = rThisRowInfo.pCellInfo[nArrX];
1809 if ( rInfo.nRotateDir > SC_ROTDIR_STANDARD &&
1810 !rInfo.bHOverlapped && !rInfo.bVOverlapped )
1812 size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
1814 // horizontal: extend adjacent line
1815 // (only when the rotated cell has a border)
1816 sal_uInt16 nDir = rInfo.nRotateDir;
1817 if ( rArray.GetCellStyleTop( nCol, nRow ).Prim() )
1819 svx::frame::Style aStyle( lcl_FindHorLine( mpDoc, nX, nY, nTab, nDir, true ), mnPPTY );
1820 rArray.SetCellStyleTop( nCol, nRow, aStyle );
1821 if( nRow > 0 )
1822 rArray.SetCellStyleBottom( nCol, nRow - 1, aStyle );
1824 if ( rArray.GetCellStyleBottom( nCol, nRow ).Prim() )
1826 svx::frame::Style aStyle( lcl_FindHorLine( mpDoc, nX, nY, nTab, nDir, false ), mnPPTY );
1827 rArray.SetCellStyleBottom( nCol, nRow, aStyle );
1828 if( nRow + 1 < rArray.GetRowCount() )
1829 rArray.SetCellStyleTop( nCol, nRow + 1, aStyle );
1832 // always remove vertical borders
1833 if( !rArray.IsMergedOverlappedLeft( nCol, nRow ) )
1835 rArray.SetCellStyleLeft( nCol, nRow, svx::frame::Style() );
1836 if( nCol > 0 )
1837 rArray.SetCellStyleRight( nCol - 1, nRow, svx::frame::Style() );
1839 if( !rArray.IsMergedOverlappedRight( nCol, nRow ) )
1841 rArray.SetCellStyleRight( nCol, nRow, svx::frame::Style() );
1842 if( nCol + 1 < rArray.GetColCount() )
1843 rArray.SetCellStyleLeft( nCol + 1, nRow, svx::frame::Style() );
1846 // remove diagonal borders
1847 rArray.SetCellStyleTLBR( nCol, nRow, svx::frame::Style() );
1848 rArray.SetCellStyleBLTR( nCol, nRow, svx::frame::Style() );
1852 nPosY += nRowHeight;
1855 pProcessor.reset();
1857 if (bMetaFile)
1858 rRenderContext.Pop();
1859 else
1860 rRenderContext.SetClipRegion();
1863 drawinglayer::processor2d::BaseProcessor2D* ScOutputData::CreateProcessor2D( )
1865 mpDoc->InitDrawLayer(mpDoc->GetDocumentShell());
1866 ScDrawLayer* pDrawLayer = mpDoc->GetDrawLayer();
1867 if (!pDrawLayer)
1868 return nullptr;
1870 basegfx::B2DRange aViewRange;
1871 SdrPage *pDrawPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
1872 const drawinglayer::geometry::ViewInformation2D aNewViewInfos(
1873 basegfx::B2DHomMatrix( ),
1874 mpDev->GetViewTransformation(),
1875 aViewRange,
1876 GetXDrawPageForSdrPage( pDrawPage ),
1877 0.0,
1878 uno::Sequence< beans::PropertyValue >() );
1880 return drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
1881 *mpDev, aNewViewInfos );
1884 // Printer
1886 vcl::Region ScOutputData::GetChangedAreaRegion()
1888 vcl::Region aRegion;
1889 Rectangle aDrawingRect;
1890 bool bHad(false);
1891 long nPosY = nScrY;
1892 SCSIZE nArrY;
1894 aDrawingRect.Left() = nScrX;
1895 aDrawingRect.Right() = nScrX+nScrW-1;
1897 for(nArrY=1; nArrY+1<nArrCount; nArrY++)
1899 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1901 if(pThisRowInfo->bChanged)
1903 if(!bHad)
1905 aDrawingRect.Top() = nPosY;
1906 bHad = true;
1909 aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1911 else if(bHad)
1913 aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1914 bHad = false;
1917 nPosY += pRowInfo[nArrY].nHeight;
1920 if(bHad)
1922 aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1925 return aRegion;
1928 bool ScOutputData::SetChangedClip()
1930 tools::PolyPolygon aPoly;
1932 Rectangle aDrawingRect;
1933 aDrawingRect.Left() = nScrX;
1934 aDrawingRect.Right() = nScrX+nScrW-1;
1936 bool bHad = false;
1937 long nPosY = nScrY;
1938 SCSIZE nArrY;
1939 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1941 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1943 if ( pThisRowInfo->bChanged )
1945 if (!bHad)
1947 aDrawingRect.Top() = nPosY;
1948 bHad = true;
1950 aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1952 else if (bHad)
1954 aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1955 bHad = false;
1957 nPosY += pRowInfo[nArrY].nHeight;
1960 if (bHad)
1961 aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1963 bool bRet = (aPoly.Count() != 0);
1964 if (bRet)
1965 mpDev->SetClipRegion(vcl::Region(aPoly));
1966 return bRet;
1969 void ScOutputData::FindChanged()
1971 SCCOL nX;
1972 SCSIZE nArrY;
1974 bool bWasIdleEnabled = mpDoc->IsIdleEnabled();
1975 mpDoc->EnableIdle(false);
1976 for (nArrY=0; nArrY<nArrCount; nArrY++)
1977 pRowInfo[nArrY].bChanged = false;
1979 bool bProgress = false;
1980 for (nArrY=0; nArrY<nArrCount; nArrY++)
1982 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1983 for (nX=nX1; nX<=nX2; nX++)
1985 const ScRefCellValue& rCell = pThisRowInfo->pCellInfo[nX+1].maCell;
1987 if (rCell.meType != CELLTYPE_FORMULA)
1988 continue;
1990 ScFormulaCell* pFCell = rCell.mpFormula;
1991 if ( !bProgress && pFCell->GetDirty() )
1993 ScProgress::CreateInterpretProgress(mpDoc);
1994 bProgress = true;
1996 if (pFCell->IsRunning())
1997 // still being interpreted. Skip it.
1998 continue;
2000 (void)pFCell->GetValue();
2001 if (!pFCell->IsChanged())
2002 // the result hasn't changed. Skip it.
2003 continue;
2005 pThisRowInfo->bChanged = true;
2006 if ( pThisRowInfo->pCellInfo[nX+1].bMerged )
2008 SCSIZE nOverY = nArrY + 1;
2009 while ( nOverY<nArrCount &&
2010 pRowInfo[nOverY].pCellInfo[nX+1].bVOverlapped )
2012 pRowInfo[nOverY].bChanged = true;
2013 ++nOverY;
2018 if ( bProgress )
2019 ScProgress::DeleteInterpretProgress();
2020 mpDoc->EnableIdle(bWasIdleEnabled);
2023 void ScOutputData::DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
2024 SCCOL nRefEndX, SCROW nRefEndY,
2025 const Color& rColor, bool bHandle )
2027 PutInOrder( nRefStartX, nRefEndX );
2028 PutInOrder( nRefStartY, nRefEndY );
2030 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2031 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
2033 if ( nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
2034 nRefStartY <= nVisY2 && nRefEndY >= nVisY1 )
2036 long nMinX = nScrX;
2037 long nMinY = nScrY;
2038 long nMaxX = nScrX + nScrW - 1;
2039 long nMaxY = nScrY + nScrH - 1;
2040 if ( bLayoutRTL )
2042 long nTemp = nMinX;
2043 nMinX = nMaxX;
2044 nMaxX = nTemp;
2046 long nLayoutSign = bLayoutRTL ? -1 : 1;
2048 bool bTop = false;
2049 bool bBottom = false;
2050 bool bLeft = false;
2051 bool bRight = false;
2053 long nPosY = nScrY;
2054 bool bNoStartY = ( nY1 < nRefStartY );
2055 bool bNoEndY = false;
2056 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
2058 SCROW nY = pRowInfo[nArrY].nRowNo;
2060 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2062 nMinY = nPosY;
2063 bTop = true;
2065 if ( nY==nRefEndY )
2067 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
2068 bBottom = true;
2070 if ( nY>nRefEndY && bNoEndY )
2072 nMaxY = nPosY-2;
2073 bBottom = true;
2075 bNoStartY = ( nY < nRefStartY );
2076 bNoEndY = ( nY < nRefEndY );
2077 nPosY += pRowInfo[nArrY].nHeight;
2080 long nPosX = nScrX;
2081 if ( bLayoutRTL )
2082 nPosX += nMirrorW - 1; // always in pixels
2084 for (SCCOL nX=nX1; nX<=nX2; nX++)
2086 if ( nX==nRefStartX )
2088 nMinX = nPosX;
2089 bLeft = true;
2091 if ( nX==nRefEndX )
2093 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 2 ) * nLayoutSign;
2094 bRight = true;
2096 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2099 if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2100 nMaxY >= nMinY )
2102 mpDev->SetLineColor( rColor );
2103 if (bTop && bBottom && bLeft && bRight)
2105 mpDev->SetFillColor();
2106 mpDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2108 else
2110 if (bTop)
2111 mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMaxX, nMinY ) );
2112 if (bBottom)
2113 mpDev->DrawLine( Point( nMinX, nMaxY ), Point( nMaxX, nMaxY ) );
2114 if (bLeft)
2115 mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMinX, nMaxY ) );
2116 if (bRight)
2117 mpDev->DrawLine( Point( nMaxX, nMinY ), Point( nMaxX, nMaxY ) );
2119 if ( bHandle && bRight && bBottom )
2121 mpDev->SetLineColor( rColor );
2122 mpDev->SetFillColor( rColor );
2124 const sal_Int32 aRadius = 4;
2126 sal_Int32 aRectMaxX1 = nMaxX - nLayoutSign * aRadius;
2127 sal_Int32 aRectMaxX2 = nMaxX + nLayoutSign;
2128 sal_Int32 aRectMinX1 = nMinX - nLayoutSign;
2129 sal_Int32 aRectMinX2 = nMinX + nLayoutSign * aRadius;
2131 sal_Int32 aRectMaxY1 = nMaxY - aRadius;
2132 sal_Int32 aRectMaxY2 = nMaxY + 1;
2133 sal_Int32 aRectMinY1 = nMinY - 1;
2134 sal_Int32 aRectMinY2 = nMinY + aRadius;
2136 // Draw corner rectangles
2137 Rectangle aLowerRight( aRectMaxX1, aRectMaxY1, aRectMaxX2, aRectMaxY2 );
2138 Rectangle aUpperLeft ( aRectMinX1, aRectMinY1, aRectMinX2, aRectMinY2 );
2139 Rectangle aLowerLeft ( aRectMinX1, aRectMaxY1, aRectMinX2, aRectMaxY2 );
2140 Rectangle aUpperRight( aRectMaxX1, aRectMinY1, aRectMaxX2, aRectMinY2 );
2142 mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerRight ) ), lclCornerRectTransparency );
2143 mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperLeft ) ), lclCornerRectTransparency );
2144 mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerLeft ) ), lclCornerRectTransparency );
2145 mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperRight ) ), lclCornerRectTransparency );
2151 void ScOutputData::DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
2152 SCCOL nRefEndX, SCROW nRefEndY,
2153 const Color& rColor, sal_uInt16 nType )
2155 PutInOrder( nRefStartX, nRefEndX );
2156 PutInOrder( nRefStartY, nRefEndY );
2158 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2159 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
2161 if ( nRefStartX <= nVisX2 + 1 && nRefEndX >= nVisX1 &&
2162 nRefStartY <= nVisY2 + 1 && nRefEndY >= nVisY1 ) // +1 because it touches next cells left/top
2164 long nMinX = nScrX;
2165 long nMinY = nScrY;
2166 long nMaxX = nScrX+nScrW-1;
2167 long nMaxY = nScrY+nScrH-1;
2168 if ( bLayoutRTL )
2170 long nTemp = nMinX;
2171 nMinX = nMaxX;
2172 nMaxX = nTemp;
2174 long nLayoutSign = bLayoutRTL ? -1 : 1;
2176 bool bTop = false;
2177 bool bBottom = false;
2178 bool bLeft = false;
2179 bool bRight = false;
2181 long nPosY = nScrY;
2182 bool bNoStartY = ( nY1 < nRefStartY );
2183 bool bNoEndY = false;
2184 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
2186 SCROW nY = pRowInfo[nArrY].nRowNo;
2188 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2190 nMinY = nPosY - 1;
2191 bTop = true;
2193 if ( nY==nRefEndY )
2195 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 1;
2196 bBottom = true;
2198 if ( nY>nRefEndY && bNoEndY )
2200 nMaxY = nPosY - 1;
2201 bBottom = true;
2203 bNoStartY = ( nY < nRefStartY );
2204 bNoEndY = ( nY < nRefEndY );
2205 nPosY += pRowInfo[nArrY].nHeight;
2208 long nPosX = nScrX;
2209 if ( bLayoutRTL )
2210 nPosX += nMirrorW - 1; // always in pixels
2212 for (SCCOL nX=nX1; nX<=nX2+1; nX++)
2214 if ( nX==nRefStartX )
2216 nMinX = nPosX - nLayoutSign;
2217 bLeft = true;
2219 if ( nX==nRefEndX )
2221 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 1 ) * nLayoutSign;
2222 bRight = true;
2224 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2227 if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2228 nMaxY >= nMinY )
2230 if ( nType == SC_CAT_DELETE_ROWS )
2231 bLeft = bRight = bBottom = false; //! thick lines???
2232 else if ( nType == SC_CAT_DELETE_COLS )
2233 bTop = bBottom = bRight = false; //! thick lines???
2235 mpDev->SetLineColor( rColor );
2236 if (bTop && bBottom && bLeft && bRight)
2238 mpDev->SetFillColor();
2239 mpDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2241 else
2243 if (bTop)
2245 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
2246 if ( nType == SC_CAT_DELETE_ROWS )
2247 mpDev->DrawLine( Point( nMinX,nMinY+1 ), Point( nMaxX,nMinY+1 ) );
2249 if (bBottom)
2250 mpDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2251 if (bLeft)
2253 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
2254 if ( nType == SC_CAT_DELETE_COLS )
2255 mpDev->DrawLine( Point( nMinX+nLayoutSign,nMinY ), Point( nMinX+nLayoutSign,nMaxY ) );
2257 if (bRight)
2258 mpDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
2260 if ( bLeft && bTop )
2262 mpDev->SetLineColor();
2263 mpDev->SetFillColor( rColor );
2264 mpDev->DrawRect( Rectangle( nMinX+nLayoutSign, nMinY+1, nMinX+3*nLayoutSign, nMinY+3 ) );
2270 void ScOutputData::DrawChangeTrack()
2272 ScChangeTrack* pTrack = mpDoc->GetChangeTrack();
2273 ScChangeViewSettings* pSettings = mpDoc->GetChangeViewSettings();
2274 if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
2275 return; // nothing there or hidden
2277 ScActionColorChanger aColorChanger(*pTrack);
2279 // clipping happens from the outside
2280 //! without clipping, only paínt affected cells ??!??!?
2282 SCCOL nEndX = nX2;
2283 SCROW nEndY = nY2;
2284 if ( nEndX < MAXCOL ) ++nEndX; // also from the next cell since the mark
2285 if ( nEndY < MAXROW ) ++nEndY; // protrudes from the preceding cell
2286 ScRange aViewRange( nX1, nY1, nTab, nEndX, nEndY, nTab );
2287 const ScChangeAction* pAction = pTrack->GetFirst();
2288 while (pAction)
2290 ScChangeActionType eActionType;
2291 if ( pAction->IsVisible() )
2293 eActionType = pAction->GetType();
2294 const ScBigRange& rBig = pAction->GetBigRange();
2295 if ( rBig.aStart.Tab() == nTab )
2297 ScRange aRange = rBig.MakeRange();
2299 if ( eActionType == SC_CAT_DELETE_ROWS )
2300 aRange.aEnd.SetRow( aRange.aStart.Row() );
2301 else if ( eActionType == SC_CAT_DELETE_COLS )
2302 aRange.aEnd.SetCol( aRange.aStart.Col() );
2304 if ( aRange.Intersects( aViewRange ) &&
2305 ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2307 aColorChanger.Update( *pAction );
2308 Color aColor( aColorChanger.GetColor() );
2309 DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2310 aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2314 if ( eActionType == SC_CAT_MOVE &&
2315 static_cast<const ScChangeActionMove*>(pAction)->
2316 GetFromRange().aStart.Tab() == nTab )
2318 ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)->
2319 GetFromRange().MakeRange();
2320 if ( aRange.Intersects( aViewRange ) &&
2321 ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2323 aColorChanger.Update( *pAction );
2324 Color aColor( aColorChanger.GetColor() );
2325 DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2326 aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2331 pAction = pAction->GetNext();
2335 //TODO: moggi Need to check if this can't be written simpler
2336 void ScOutputData::DrawNoteMarks(vcl::RenderContext& rRenderContext)
2339 bool bFirst = true;
2341 long nInitPosX = nScrX;
2342 if ( bLayoutRTL )
2343 nInitPosX += nMirrorW - 1; // always in pixels
2344 long nLayoutSign = bLayoutRTL ? -1 : 1;
2346 long nPosY = nScrY;
2347 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2349 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2350 if ( pThisRowInfo->bChanged )
2352 long nPosX = nInitPosX;
2353 for (SCCOL nX=nX1; nX<=nX2; nX++)
2355 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2356 bool bIsMerged = false;
2358 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2360 // find start of merged cell
2361 bIsMerged = true;
2362 SCROW nY = pRowInfo[nArrY].nRowNo;
2363 SCCOL nMergeX = nX;
2364 SCROW nMergeY = nY;
2365 mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2366 // use origin's pCell for NotePtr test below
2369 if ( mpDoc->GetNote(nX, pRowInfo[nArrY].nRowNo, nTab) && ( bIsMerged ||
2370 ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2372 if (bFirst)
2374 rRenderContext.SetLineColor(COL_WHITE);
2376 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2377 if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2378 rRenderContext.SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2379 else
2380 rRenderContext.SetFillColor(COL_LIGHTRED);
2382 bFirst = false;
2385 long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 4 ) * nLayoutSign;
2386 if ( bIsMerged || pInfo->bMerged )
2388 // if merged, add widths of all cells
2389 SCCOL nNextX = nX + 1;
2390 while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2392 nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2393 ++nNextX;
2396 if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2397 rRenderContext.DrawRect( Rectangle( nMarkX-5*nLayoutSign,nPosY,nMarkX+1*nLayoutSign,nPosY+6 ) );
2400 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2403 nPosY += pThisRowInfo->nHeight;
2407 void ScOutputData::AddPDFNotes()
2409 vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >( mpDev->GetExtOutDevData() );
2410 if ( !pPDFData || !pPDFData->GetIsExportNotes() )
2411 return;
2413 long nInitPosX = nScrX;
2414 if ( bLayoutRTL )
2416 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
2417 long nOneX = aOnePixel.Width();
2418 nInitPosX += nMirrorW - nOneX;
2420 long nLayoutSign = bLayoutRTL ? -1 : 1;
2422 long nPosY = nScrY;
2423 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2425 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2426 if ( pThisRowInfo->bChanged )
2428 long nPosX = nInitPosX;
2429 for (SCCOL nX=nX1; nX<=nX2; nX++)
2431 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2432 bool bIsMerged = false;
2433 SCROW nY = pRowInfo[nArrY].nRowNo;
2434 SCCOL nMergeX = nX;
2435 SCROW nMergeY = nY;
2437 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2439 // find start of merged cell
2440 bIsMerged = true;
2441 mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2442 // use origin's pCell for NotePtr test below
2445 if ( mpDoc->GetNote(nMergeX, nMergeY, nTab) && ( bIsMerged ||
2446 ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2448 long nNoteWidth = (long)( SC_CLIPMARK_SIZE * mnPPTX );
2449 long nNoteHeight = (long)( SC_CLIPMARK_SIZE * mnPPTY );
2451 long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - nNoteWidth ) * nLayoutSign;
2452 if ( bIsMerged || pInfo->bMerged )
2454 // if merged, add widths of all cells
2455 SCCOL nNextX = nX + 1;
2456 while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2458 nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2459 ++nNextX;
2462 if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2464 Rectangle aNoteRect( nMarkX, nPosY, nMarkX+nNoteWidth*nLayoutSign, nPosY+nNoteHeight );
2465 const ScPostIt* pNote = mpDoc->GetNote(nMergeX, nMergeY, nTab);
2467 // Note title is the cell address (as on printed note pages)
2468 ScAddress aAddress( nMergeX, nMergeY, nTab );
2469 OUString aTitle(aAddress.Format(ScRefFlags::VALID, mpDoc, mpDoc->GetAddressConvention()));
2471 // Content has to be a simple string without line breaks
2472 OUString aContent = pNote->GetText();
2473 aContent = aContent.replaceAll("\n", " ");
2475 vcl::PDFNote aNote;
2476 aNote.Title = aTitle;
2477 aNote.Contents = aContent;
2478 pPDFData->CreateNote( aNoteRect, aNote );
2482 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2485 nPosY += pThisRowInfo->nHeight;
2489 void ScOutputData::DrawClipMarks()
2491 if (!bAnyClipped)
2492 return;
2494 Color aArrowFillCol( COL_LIGHTRED );
2496 DrawModeFlags nOldDrawMode = mpDev->GetDrawMode();
2497 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2498 if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2500 // use DrawMode to change the arrow's outline color
2501 mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::SettingsLine );
2502 // use text color also for the fill color
2503 aArrowFillCol.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2506 long nInitPosX = nScrX;
2507 if ( bLayoutRTL )
2508 nInitPosX += nMirrorW - 1; // always in pixels
2509 long nLayoutSign = bLayoutRTL ? -1 : 1;
2511 Rectangle aCellRect;
2512 long nPosY = nScrY;
2513 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2515 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2516 if ( pThisRowInfo->bChanged )
2518 SCROW nY = pThisRowInfo->nRowNo;
2519 long nPosX = nInitPosX;
2520 for (SCCOL nX=nX1; nX<=nX2; nX++)
2522 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2523 if (pInfo->nClipMark)
2525 if (pInfo->bHOverlapped || pInfo->bVOverlapped)
2527 // merge origin may be outside of visible area - use document functions
2529 SCCOL nOverX = nX;
2530 SCROW nOverY = nY;
2531 long nStartPosX = nPosX;
2532 long nStartPosY = nPosY;
2534 while ( nOverX > 0 && ( static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
2535 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & ScMF::Hor ) )
2537 --nOverX;
2538 nStartPosX -= nLayoutSign * (long) ( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
2541 while ( nOverY > 0 && ( static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
2542 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & ScMF::Ver ) )
2544 --nOverY;
2545 nStartPosY -= nLayoutSign * (long) ( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
2548 long nOutWidth = (long) ( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
2549 long nOutHeight = (long) ( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
2551 const ScMergeAttr* pMerge = static_cast<const ScMergeAttr*>(
2552 mpDoc->GetAttr( nOverX, nOverY, nTab, ATTR_MERGE ));
2553 SCCOL nCountX = pMerge->GetColMerge();
2554 for (SCCOL i=1; i<nCountX; i++)
2555 nOutWidth += (long) ( mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX );
2556 SCROW nCountY = pMerge->GetRowMerge();
2557 nOutHeight += (long) mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY);
2559 if ( bLayoutRTL )
2560 nStartPosX -= nOutWidth - 1;
2561 aCellRect = Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
2563 else
2565 long nOutWidth = pRowInfo[0].pCellInfo[nX+1].nWidth;
2566 long nOutHeight = pThisRowInfo->nHeight;
2568 if ( pInfo->bMerged && pInfo->pPatternAttr )
2570 SCCOL nOverX = nX;
2571 SCROW nOverY = nY;
2572 const ScMergeAttr* pMerge =
2573 static_cast<const ScMergeAttr*>(&pInfo->pPatternAttr->GetItem(ATTR_MERGE));
2574 SCCOL nCountX = pMerge->GetColMerge();
2575 for (SCCOL i=1; i<nCountX; i++)
2576 nOutWidth += (long) ( mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX );
2577 SCROW nCountY = pMerge->GetRowMerge();
2578 nOutHeight += (long) mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY);
2581 long nStartPosX = nPosX;
2582 if ( bLayoutRTL )
2583 nStartPosX -= nOutWidth - 1;
2584 // #i80447# create aCellRect from two points in case nOutWidth is 0
2585 aCellRect = Rectangle( Point( nStartPosX, nPosY ),
2586 Point( nStartPosX+nOutWidth-1, nPosY+nOutHeight-1 ) );
2589 aCellRect.Bottom() -= 1; // don't paint over the cell grid
2590 if ( bLayoutRTL )
2591 aCellRect.Left() += 1;
2592 else
2593 aCellRect.Right() -= 1;
2595 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
2596 Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
2598 if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_RIGHT : SC_CLIPMARK_LEFT ) )
2600 // visually left
2601 Rectangle aMarkRect = aCellRect;
2602 aMarkRect.Right() = aCellRect.Left()+nMarkPixel-1;
2603 SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, true );
2605 if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_LEFT : SC_CLIPMARK_RIGHT ) )
2607 // visually right
2608 Rectangle aMarkRect = aCellRect;
2609 aMarkRect.Left() = aCellRect.Right()-nMarkPixel+1;
2610 SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, false );
2613 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2616 nPosY += pThisRowInfo->nHeight;
2619 mpDev->SetDrawMode(nOldDrawMode);
2622 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */