1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <scitems.hxx>
21 #include <editeng/brushitem.hxx>
22 #include <svtools/colorcfg.hxx>
23 #include <svx/rotmodit.hxx>
24 #include <svx/svdocapt.hxx>
25 #include <editeng/shaditem.hxx>
26 #include <editeng/svxfont.hxx>
27 #include <tools/poly.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/pdfextoutdevdata.hxx>
30 #include <svx/framelinkarray.hxx>
31 #include <drawinglayer/geometry/viewinformation2d.hxx>
32 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
33 #include <drawinglayer/processor2d/processor2dtools.hxx>
34 #include <officecfg/Office/Common.hxx>
35 #include <officecfg/Office/Calc.hxx>
36 #include <vcl/lineinfo.hxx>
37 #include <vcl/gradient.hxx>
38 #include <vcl/settings.hxx>
39 #include <vcl/pdf/PDFNote.hxx>
40 #include <svx/unoapi.hxx>
41 #include <sal/log.hxx>
42 #include <comphelper/lok.hxx>
43 #include <o3tl/unit_conversion.hxx>
44 #include <basegfx/matrix/b2dhommatrix.hxx>
47 #include <document.hxx>
48 #include <drwlayer.hxx>
49 #include <formulacell.hxx>
51 #include <patattr.hxx>
52 #include <progress.hxx>
53 #include <pagedata.hxx>
54 #include <chgtrack.hxx>
55 #include <chgviset.hxx>
56 #include <viewutil.hxx>
57 #include <gridmerg.hxx>
58 #include <fillinfo.hxx>
60 #include <appoptio.hxx>
62 #include <validat.hxx>
63 #include <detfunc.hxx>
64 #include <editutil.hxx>
66 #include <SparklineRenderer.hxx>
67 #include <colorscale.hxx>
72 using namespace com::sun::star
;
76 // color for ChangeTracking "by author" as in the writer (swmodul1.cxx)
78 #define SC_AUTHORCOLORCOUNT 9
80 const Color nAuthorColor
[ SC_AUTHORCOLORCOUNT
] = {
81 COL_LIGHTRED
, COL_LIGHTBLUE
, COL_LIGHTMAGENTA
,
82 COL_GREEN
, COL_RED
, COL_BLUE
,
83 COL_BROWN
, COL_MAGENTA
, COL_CYAN
};
85 // Helper class for color assignment to avoid repeated lookups for the same user
87 ScActionColorChanger::ScActionColorChanger( const ScChangeTrack
& rTrack
) :
88 rOpt( ScModule::get()->GetAppOptions() ),
89 rUsers( rTrack
.GetUserCollection() ),
95 void ScActionColorChanger::Update( const ScChangeAction
& rAction
)
98 switch (rAction
.GetType())
100 case SC_CAT_INSERT_COLS
:
101 case SC_CAT_INSERT_ROWS
:
102 case SC_CAT_INSERT_TABS
:
103 nSetColor
= rOpt
.GetTrackInsertColor();
105 case SC_CAT_DELETE_COLS
:
106 case SC_CAT_DELETE_ROWS
:
107 case SC_CAT_DELETE_TABS
:
108 nSetColor
= rOpt
.GetTrackDeleteColor();
111 nSetColor
= rOpt
.GetTrackMoveColor();
114 nSetColor
= rOpt
.GetTrackContentColor();
117 if ( nSetColor
!= COL_TRANSPARENT
) // color assigned
121 if (aLastUserName
!= rAction
.GetUser())
123 aLastUserName
= rAction
.GetUser();
124 std::set
<OUString
>::const_iterator it
= rUsers
.find(aLastUserName
);
125 if (it
== rUsers
.end())
127 // empty string is possible if a name wasn't found while saving a 5.0 file
128 SAL_INFO_IF( aLastUserName
.isEmpty(), "sc.ui", "Author not found" );
133 size_t nPos
= std::distance(rUsers
.begin(), it
);
134 nLastUserIndex
= nPos
% SC_AUTHORCOLORCOUNT
;
137 nColor
= nAuthorColor
[nLastUserIndex
];
141 ScOutputData::ScOutputData( OutputDevice
* pNewDev
, ScOutputType eNewType
,
142 ScTableInfo
& rTabInfo
, ScDocument
* pNewDoc
,
143 SCTAB nNewTab
, tools::Long nNewScrX
, tools::Long nNewScrY
,
144 SCCOL nNewX1
, SCROW nNewY1
, SCCOL nNewX2
, SCROW nNewY2
,
145 double nPixelPerTwipsX
, double nPixelPerTwipsY
,
146 const Fraction
* pZoomX
, const Fraction
* pZoomY
) :
147 mpOriginalTargetDevice( pNewDev
),
149 mpRefDevice( pNewDev
), // default is output device
150 pFmtDevice( pNewDev
), // default is output device
151 mrTabInfo( rTabInfo
),
152 pRowInfo( rTabInfo
.mpRowInfo
.get() ),
153 nArrCount( rTabInfo
.mnArrCount
),
163 mnPPTX( nPixelPerTwipsX
),
164 mnPPTY( nPixelPerTwipsY
),
165 pViewShell( nullptr ),
166 pDrawView( nullptr ),
171 bPagebreakMode( false ),
172 bSolidBackground( false ),
173 mbUseStyleColor( false ),
174 mbForceAutoColor( officecfg::Office::Common::Accessibility::IsAutomaticFontColor::get() ),
175 mbSyntaxMode( false ),
176 aGridColor( COL_BLACK
),
177 mbShowNullValues( true ),
178 mbShowFormulas( false ),
179 bShowSpellErrors( false ),
180 bMarkClipped( false ), // sal_False for printer/metafile etc.
182 bAnyClipped( false ),
184 mpTargetPaintWindow(nullptr), // #i74769# use SdrPaintWindow direct
185 mpSpellCheckCxt(nullptr)
190 aZoomX
= Fraction(1,1);
194 aZoomY
= Fraction(1,1);
200 mpDoc
->StripHidden( nVisX1
, nVisY1
, nVisX2
, nVisY2
, nTab
);
203 for (SCCOL nX
=nVisX1
; nX
<=nVisX2
; nX
++)
204 nScrW
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
;
209 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
210 nScrH
+= pRowInfo
[nArrY
].nHeight
;
212 bTabProtected
= mpDoc
->IsTabProtected( nTab
);
213 bLayoutRTL
= mpDoc
->IsLayoutRTL( nTab
);
215 // always needed, so call at the end of the constructor
217 InitOutputEditEngine();
220 ScOutputData::~ScOutputData()
224 void ScOutputData::SetSpellCheckContext( const sc::SpellCheckContext
* pCxt
)
226 mpSpellCheckCxt
= pCxt
;
229 void ScOutputData::SetContentDevice( OutputDevice
* pContentDev
)
231 // use pContentDev instead of pDev where used
233 if ( mpRefDevice
== mpDev
)
234 mpRefDevice
= pContentDev
;
235 if ( pFmtDevice
== mpDev
)
236 pFmtDevice
= pContentDev
;
240 void ScOutputData::SetMirrorWidth( tools::Long nNew
)
245 void ScOutputData::SetGridColor( const Color
& rColor
)
250 void ScOutputData::SetMarkClipped( bool bSet
)
255 void ScOutputData::SetShowNullValues( bool bSet
)
257 mbShowNullValues
= bSet
;
260 void ScOutputData::SetShowFormulas( bool bSet
)
262 mbShowFormulas
= bSet
;
265 void ScOutputData::SetShowSpellErrors( bool bSet
)
267 bShowSpellErrors
= bSet
;
268 // reset EditEngine because it depends on bShowSpellErrors
269 mxOutputEditEngine
.reset();
272 void ScOutputData::SetSnapPixel()
277 void ScOutputData::SetEditCell( SCCOL nCol
, SCROW nRow
)
284 void ScOutputData::SetMetaFileMode( bool bNewMode
)
286 bMetaFile
= bNewMode
;
289 void ScOutputData::SetSyntaxMode( bool bNewMode
)
291 mbSyntaxMode
= bNewMode
;
292 if ( bNewMode
&& !mxValueColor
)
294 const svtools::ColorConfig
& rColorCfg
= ScModule::get()->GetColorConfig();
295 mxValueColor
= rColorCfg
.GetColorValue( svtools::CALCVALUE
).nColor
;
296 mxTextColor
= rColorCfg
.GetColorValue( svtools::CALCTEXT
).nColor
;
297 mxFormulaColor
= rColorCfg
.GetColorValue( svtools::CALCFORMULA
).nColor
;
301 bool ScOutputData::ReopenPDFStructureElement(vcl::PDFWriter::StructElement aType
, SCROW nRow
, SCCOL nCol
)
303 bool bReopenTag
= false;
304 vcl::PDFExtOutDevData
* pPDF
= dynamic_cast<vcl::PDFExtOutDevData
*>(mpDev
->GetExtOutDevData());
307 if (aType
== vcl::PDFWriter::Part
) // Worksheet
309 if (pPDF
->GetScPDFState()->m_WorksheetId
!= -1)
311 sal_Int32 nId
= pPDF
->GetScPDFState()->m_WorksheetId
;
312 pPDF
->BeginStructureElement(nId
);
316 else if (aType
== vcl::PDFWriter::Table
)
318 if (pPDF
->GetScPDFState()->m_TableId
!= -1)
320 sal_Int32 nId
= pPDF
->GetScPDFState()->m_TableId
;
321 pPDF
->BeginStructureElement(nId
);
325 else if (aType
== vcl::PDFWriter::TableRow
)
327 const auto aIter
= pPDF
->GetScPDFState()->m_TableRowMap
.find(nRow
);
328 if (aIter
!= pPDF
->GetScPDFState()->m_TableRowMap
.end() && nRow
== aIter
->first
)
330 sal_Int32 nId
= (*aIter
).second
;
331 pPDF
->BeginStructureElement(nId
);
335 else if (aType
== vcl::PDFWriter::TableData
)
337 const std::pair
<SCROW
, SCCOL
> keyToFind
= std::make_pair(nRow
, nCol
);
338 const auto aIter
= pPDF
->GetScPDFState()->m_TableDataMap
.find(keyToFind
);
339 if (aIter
!= pPDF
->GetScPDFState()->m_TableDataMap
.end() && keyToFind
== aIter
->first
)
341 sal_Int32 nId
= (*aIter
).second
;
342 pPDF
->BeginStructureElement(nId
);
351 void ScOutputData::DrawGrid(vcl::RenderContext
& rRenderContext
, bool bGrid
, bool bPage
, bool bMergeCover
)
353 // bMergeCover : Draw lines in sheet bgcolor to cover lok client grid lines in merged cell areas.
354 // When scNoGridBackground is set in lok mode, bMergeCover is set to true and bGrid to false.
361 ScBreakType nBreak
= ScBreakType::NONE
;
362 ScBreakType nBreakOld
= ScBreakType::NONE
;
364 bool bDashed
= false;
369 bPage
= false; // no "normal" breaks over the whole width/height
371 // It is a big mess to distinguish when we are using pixels and when logic
372 // units for drawing. Ultimately we want to work only in the logic units,
373 // but until that happens, we need to special-case:
376 // * drawing to the screen - everything is internally counted in pixels there
378 // 'Internally' in the above means the pCellInfo[...].nWidth and
379 // pRowInfo[...]->nHeight:
381 // * when bWorksInPixels is true: these are in pixels
382 // * when bWorksInPixels is false: these are in the logic units
384 // This is where all the confusion comes from, ultimately we want them
385 // always in the logic units (100th of millimeters), but we need to get
386 // there gradually (get rid of setting MapUnit::MapPixel first), otherwise we'd
387 // break all the drawing by one change.
388 // So until that happens, we need to special case.
389 bool bWorksInPixels
= bMetaFile
;
390 const svtools::ColorConfig
& rColorCfg
= ScModule::get()->GetColorConfig();
391 Color aSheetBGColor
= rColorCfg
.GetColorValue(::svtools::DOCCOLOR
).nColor
;
393 if ( eType
== OUTTYPE_WINDOW
)
395 bWorksInPixels
= true;
396 aPageColor
= rColorCfg
.GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC
).nColor
;
397 aManualColor
= rColorCfg
.GetColorValue(svtools::CALCPAGEBREAKMANUAL
).nColor
;
401 aPageColor
= aGridColor
;
402 aManualColor
= aGridColor
;
405 tools::Long nOneX
= 1;
406 tools::Long nOneY
= 1;
409 Size aOnePixel
= rRenderContext
.PixelToLogic(Size(1,1));
410 nOneX
= aOnePixel
.Width();
411 nOneY
= aOnePixel
.Height();
414 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
415 tools::Long nSignedOneX
= nOneX
* nLayoutSign
;
417 rRenderContext
.SetLineColor(bMergeCover
? aSheetBGColor
: aGridColor
);
419 ScGridMerger
aGrid(&rRenderContext
, nOneX
, nOneY
);
425 nPosX
+= nMirrorW
- nOneX
;
427 for (nX
=nX1
; nX
<=nX2
; nX
++)
429 sal_uInt16 nWidth
= pRowInfo
[0].basicCellInfo(nX
).nWidth
;
432 nPosX
+= nWidth
* nLayoutSign
;
436 // Search also in hidden part for page breaks
438 while (nCol
<= mpDoc
->MaxCol())
440 nBreak
= mpDoc
->HasColBreak(nCol
, nTab
);
441 bool bHidden
= mpDoc
->ColHidden(nCol
, nTab
);
443 if ( nBreak
!= ScBreakType::NONE
|| !bHidden
)
448 if (nBreak
!= nBreakOld
)
452 if (static_cast<int>(nBreak
))
454 rRenderContext
.SetLineColor( (nBreak
& ScBreakType::Manual
) ? aManualColor
:
460 rRenderContext
.SetLineColor(bMergeCover
? aSheetBGColor
: aGridColor
);
468 bool bDraw
= bGrid
|| nBreakOld
!= ScBreakType::NONE
|| bMergeCover
; // simple grid only if set that way
470 sal_uInt16 nWidthXplus1
= pRowInfo
[0].basicCellInfo(nX
+1).nWidth
;
471 bool bSingle
= false; //! get into Fillinfo !!!!!
472 if ( nX
<mpDoc
->MaxCol() )
474 bSingle
= ( nWidthXplus1
== 0 );
475 for (nArrY
=1; nArrY
+1<nArrCount
&& !bSingle
; nArrY
++)
477 if (pRowInfo
[nArrY
].cellInfo(nX
+1).bHOverlapped
)
479 if (pRowInfo
[nArrY
].cellInfo(nX
).bHideGrid
)
486 if ( nX
<mpDoc
->MaxCol() && bSingle
)
488 SCCOL nVisX
= nX
+ 1;
489 while ( nVisX
< mpDoc
->MaxCol() && !mpDoc
->GetColWidth(nVisX
,nTab
) )
493 for (nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
495 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
496 const tools::Long nNextY
= nPosY
+ pThisRowInfo
->nHeight
;
498 bool bHOver
= pThisRowInfo
->cellInfo(nX
).bHideGrid
;
502 bHOver
= pThisRowInfo
->cellInfo(nX
+1).bHOverlapped
;
506 bHOver
= pThisRowInfo
->cellInfo(nVisX
).bHOverlapped
;
508 bHOver
= mpDoc
->GetAttr(
509 nVisX
,pThisRowInfo
->nRowNo
,nTab
,ATTR_MERGE_FLAG
)
512 bHOver
= mpDoc
->GetAttr(
513 nX
+ 1,pThisRowInfo
->nRowNo
,nTab
,ATTR_MERGE_FLAG
)
518 if ((pThisRowInfo
->bChanged
&& !bHOver
&& !bMergeCover
) || (bHOver
&& bMergeCover
))
520 aGrid
.AddVerLine(bWorksInPixels
, nPosX
-nSignedOneX
, nPosY
, nNextY
-nOneY
, bDashed
);
525 else if (!bMergeCover
)
527 aGrid
.AddVerLine(bWorksInPixels
, nPosX
-nSignedOneX
, nScrY
, nScrY
+nScrH
-nOneY
, bDashed
);
535 bool bHiddenRow
= true;
536 SCROW nHiddenEndRow
= -1;
538 for (nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
540 SCSIZE nArrYplus1
= nArrY
+1;
541 nY
= pRowInfo
[nArrY
].nRowNo
;
542 SCROW nYplus1
= nY
+1;
543 nPosY
+= pRowInfo
[nArrY
].nHeight
;
545 if (pRowInfo
[nArrY
].bChanged
)
549 for (SCROW i
= nYplus1
; i
<= mpDoc
->MaxRow(); ++i
)
551 if (i
> nHiddenEndRow
)
552 bHiddenRow
= mpDoc
->RowHidden(i
, nTab
, nullptr, &nHiddenEndRow
);
553 /* TODO: optimize the row break thing for large hidden
554 * segments where HasRowBreak() has to be called
555 * nevertheless for each row, as a row break is drawn also
556 * for hidden rows, above them. This needed to be done only
557 * once per hidden segment, maybe giving manual breaks
558 * priority. Something like GetNextRowBreak() and
559 * GetNextManualRowBreak(). */
560 nBreak
= mpDoc
->HasRowBreak(i
, nTab
);
561 if (!bHiddenRow
|| nBreak
!= ScBreakType::NONE
)
565 if (nBreakOld
!= nBreak
)
569 if (static_cast<int>(nBreak
))
571 rRenderContext
.SetLineColor( (nBreak
& ScBreakType::Manual
) ? aManualColor
:
577 rRenderContext
.SetLineColor(bMergeCover
? aSheetBGColor
: aGridColor
);
585 bool bDraw
= bGrid
|| nBreakOld
!= ScBreakType::NONE
|| bMergeCover
; // simple grid only if set so
587 bool bNextYisNextRow
= (pRowInfo
[nArrYplus1
].nRowNo
== nYplus1
);
588 bool bSingle
= !bNextYisNextRow
; // Hidden
589 for (SCCOL i
=nX1
; i
<=nX2
&& !bSingle
; i
++)
591 if (pRowInfo
[nArrYplus1
].cellInfo(i
).bVOverlapped
)
597 if ( bSingle
&& nY
<mpDoc
->MaxRow() )
599 SCROW nVisY
= pRowInfo
[nArrYplus1
].nRowNo
;
603 nPosX
+= nMirrorW
- nOneX
;
605 for (SCCOL i
=nX1
; i
<=nX2
; i
++)
607 const tools::Long nNextX
= nPosX
+ pRowInfo
[0].basicCellInfo(i
).nWidth
* nLayoutSign
;
608 if (nNextX
!= nPosX
) // visible
611 if ( bNextYisNextRow
)
612 bVOver
= pRowInfo
[nArrYplus1
].cellInfo(i
).bVOverlapped
;
615 bVOver
= mpDoc
->GetAttr(
616 i
,nYplus1
,nTab
,ATTR_MERGE_FLAG
)
619 i
,nVisY
,nTab
,ATTR_MERGE_FLAG
)
621 //! nVisY from Array ??
624 if ((!bVOver
&& !bMergeCover
) || (bVOver
&& bMergeCover
))
626 aGrid
.AddHorLine(bWorksInPixels
, nPosX
, nNextX
-nSignedOneX
, nPosY
-nOneY
, bDashed
);
632 else if (!bMergeCover
)
634 aGrid
.AddHorLine(bWorksInPixels
, nScrX
, nScrX
+nScrW
-nOneX
, nPosY
-nOneY
, bDashed
);
641 void ScOutputData::SetPagebreakMode( ScPageBreakData
* pPageData
)
643 bPagebreakMode
= true;
645 return; // not yet initialized -> everything "not printed"
647 // mark printed range
648 // (everything in FillInfo is already initialized to sal_False)
650 sal_uInt16 nRangeCount
= sal::static_int_cast
<sal_uInt16
>(pPageData
->GetCount());
651 for (sal_uInt16 nPos
=0; nPos
<nRangeCount
; nPos
++)
653 ScRange aRange
= pPageData
->GetData( nPos
).GetPrintRange();
655 SCCOL nStartX
= std::max( aRange
.aStart
.Col(), nX1
);
656 SCCOL nEndX
= std::min( aRange
.aEnd
.Col(), nX2
);
657 SCROW nStartY
= std::max( aRange
.aStart
.Row(), nY1
);
658 SCROW nEndY
= std::min( aRange
.aEnd
.Row(), nY2
);
660 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
662 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
663 if ( pThisRowInfo
->bChanged
&& pThisRowInfo
->nRowNo
>= nStartY
&&
664 pThisRowInfo
->nRowNo
<= nEndY
)
666 for (SCCOL nX
=nStartX
; nX
<=nEndX
; nX
++)
667 pThisRowInfo
->cellInfo(nX
).bPrinted
= true;
673 void ScOutputData::SetCellRotations()
677 for (SCSIZE nRotY
=0; nRotY
<nArrCount
; nRotY
++)
678 if (pRowInfo
[nRotY
].nRotMaxCol
!= SC_ROTMAX_NONE
&& pRowInfo
[nRotY
].nRotMaxCol
> nRotMax
)
679 nRotMax
= pRowInfo
[nRotY
].nRotMaxCol
;
681 for (SCSIZE nArrY
=1; nArrY
<nArrCount
; nArrY
++)
683 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
684 if ( pThisRowInfo
->nRotMaxCol
!= SC_ROTMAX_NONE
&&
685 ( pThisRowInfo
->bChanged
|| pRowInfo
[nArrY
-1].bChanged
||
686 ( nArrY
+1<nArrCount
&& pRowInfo
[nArrY
+1].bChanged
) ) )
688 SCROW nY
= pThisRowInfo
->nRowNo
;
690 for (SCCOL nX
=0; nX
<=nRotMax
; nX
++)
692 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
);
693 const ScPatternAttr
* pPattern
= pInfo
->pPatternAttr
;
694 const SfxItemSet
* pCondSet
= pInfo
->pConditionSet
;
696 if ( !pPattern
&& !mpDoc
->ColHidden(nX
, nTab
) )
698 pPattern
= mpDoc
->GetPattern( nX
, nY
, nTab
);
699 pCondSet
= mpDoc
->GetCondResult( nX
, nY
, nTab
);
702 if ( pPattern
) // column isn't hidden
704 ScRotateDir nDir
= pPattern
->GetRotateDir( pCondSet
);
705 if (nDir
!= ScRotateDir::NONE
)
707 // Needed for ScCellInfo internal decisions (bg fill, ...)
708 pInfo
->nRotateDir
= nDir
;
710 // create target coordinates
711 const SCCOL
nTargetX(nX
- nVisX1
+ 1);
712 const SCROW
nTargetY(nY
- nVisY1
+ 1);
714 // Check for values - below in SetCellRotation these will
715 // be converted to size_t and thus may not be negative
716 if(nTargetX
>= 0 && nTargetY
>= 0)
718 // add rotation info to Array information
719 const Degree100
nAttrRotate(pPattern
->GetRotateVal(pCondSet
));
720 const SvxRotateMode
eRotMode(pPattern
->GetItem(ATTR_ROTATE_MODE
, pCondSet
).GetValue());
721 const double fOrient((bLayoutRTL
? -1.0 : 1.0) * toRadians(nAttrRotate
)); // 1/100th degrees -> [0..2PI]
722 svx::frame::Array
& rArray
= mrTabInfo
.maArray
;
724 rArray
.SetCellRotation(nTargetX
, nTargetY
, eRotMode
, fOrient
);
733 static ScRotateDir
lcl_GetRotateDir( const ScDocument
* pDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
735 const ScPatternAttr
* pPattern
= pDoc
->GetPattern( nCol
, nRow
, nTab
);
736 const SfxItemSet
* pCondSet
= pDoc
->GetCondResult( nCol
, nRow
, nTab
);
738 ScRotateDir nRet
= ScRotateDir::NONE
;
740 Degree100 nAttrRotate
= pPattern
->GetRotateVal( pCondSet
);
743 SvxRotateMode eRotMode
=
744 pPattern
->GetItem(ATTR_ROTATE_MODE
, pCondSet
).GetValue();
746 if ( eRotMode
== SVX_ROTATE_MODE_STANDARD
)
747 nRet
= ScRotateDir::Standard
;
748 else if ( eRotMode
== SVX_ROTATE_MODE_CENTER
)
749 nRet
= ScRotateDir::Center
;
750 else if ( eRotMode
== SVX_ROTATE_MODE_TOP
|| eRotMode
== SVX_ROTATE_MODE_BOTTOM
)
752 tools::Long nRot180
= nAttrRotate
.get() % 18000; // 1/100 degree
753 if ( nRot180
== 9000 )
754 nRet
= ScRotateDir::Center
;
755 else if ( ( eRotMode
== SVX_ROTATE_MODE_TOP
&& nRot180
< 9000 ) ||
756 ( eRotMode
== SVX_ROTATE_MODE_BOTTOM
&& nRot180
> 9000 ) )
757 nRet
= ScRotateDir::Left
;
759 nRet
= ScRotateDir::Right
;
766 static const SvxBrushItem
* lcl_FindBackground( const ScDocument
* pDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
768 const ScPatternAttr
* pPattern
= pDoc
->GetPattern( nCol
, nRow
, nTab
);
769 const SfxItemSet
* pCondSet
= pDoc
->GetCondResult( nCol
, nRow
, nTab
);
770 const SvxBrushItem
* pBackground
=
771 &pPattern
->GetItem( ATTR_BACKGROUND
, pCondSet
);
773 ScRotateDir nDir
= lcl_GetRotateDir( pDoc
, nCol
, nRow
, nTab
);
775 // treat CENTER like RIGHT
776 if ( nDir
== ScRotateDir::Right
|| nDir
== ScRotateDir::Center
)
778 // text goes to the right -> take background from the left
779 while ( nCol
> 0 && lcl_GetRotateDir( pDoc
, nCol
, nRow
, nTab
) == nDir
&&
780 pBackground
->GetColor().GetAlpha() != 0 )
783 pPattern
= pDoc
->GetPattern( nCol
, nRow
, nTab
);
784 pCondSet
= pDoc
->GetCondResult( nCol
, nRow
, nTab
);
785 pBackground
= &pPattern
->GetItem( ATTR_BACKGROUND
, pCondSet
);
788 else if ( nDir
== ScRotateDir::Left
)
790 // text goes to the left -> take background from the right
791 while ( nCol
< pDoc
->MaxCol() && lcl_GetRotateDir( pDoc
, nCol
, nRow
, nTab
) == nDir
&&
792 pBackground
->GetColor().GetAlpha() != 0 )
795 pPattern
= pDoc
->GetPattern( nCol
, nRow
, nTab
);
796 pCondSet
= pDoc
->GetCondResult( nCol
, nRow
, nTab
);
797 pBackground
= &pPattern
->GetItem( ATTR_BACKGROUND
, pCondSet
);
804 static bool lcl_EqualBack( const RowInfo
& rFirst
, const RowInfo
& rOther
,
805 SCCOL nX1
, SCCOL nX2
, bool bShowProt
, bool bPagebreakMode
)
807 if ( rFirst
.bChanged
!= rOther
.bChanged
||
808 rFirst
.bEmptyBack
!= rOther
.bEmptyBack
)
814 for ( nX
=nX1
; nX
<=nX2
; nX
++ )
816 const ScPatternAttr
* pPat1
= rFirst
.cellInfo(nX
).pPatternAttr
;
817 const ScPatternAttr
* pPat2
= rOther
.cellInfo(nX
).pPatternAttr
;
818 if ( !pPat1
|| !pPat2
||
819 !SfxPoolItem::areSame(pPat1
->GetItem(ATTR_PROTECTION
), pPat2
->GetItem(ATTR_PROTECTION
) ) )
825 for ( nX
=nX1
; nX
<=nX2
; nX
++ )
826 if ( !SfxPoolItem::areSame(rFirst
.cellInfo(nX
).maBackground
.getItem(), rOther
.cellInfo(nX
).maBackground
.getItem() ) )
830 if ( rFirst
.nRotMaxCol
!= SC_ROTMAX_NONE
|| rOther
.nRotMaxCol
!= SC_ROTMAX_NONE
)
831 for ( nX
=nX1
; nX
<=nX2
; nX
++ )
832 if ( rFirst
.cellInfo(nX
).nRotateDir
!= rOther
.cellInfo(nX
).nRotateDir
)
835 if ( bPagebreakMode
)
836 for ( nX
=nX1
; nX
<=nX2
; nX
++ )
837 if ( rFirst
.cellInfo(nX
).bPrinted
!= rOther
.cellInfo(nX
).bPrinted
)
840 for ( nX
=nX1
; nX
<=nX2
; nX
++ )
842 std::optional
<Color
> const & pCol1
= rFirst
.cellInfo(nX
).mxColorScale
;
843 std::optional
<Color
> const & pCol2
= rOther
.cellInfo(nX
).mxColorScale
;
844 if( (pCol1
&& !pCol2
) || (!pCol1
&& pCol2
) )
847 if (pCol1
&& (*pCol1
!= *pCol2
))
850 const ScDataBarInfo
* pInfo1
= rFirst
.cellInfo(nX
).pDataBar
;
851 const ScDataBarInfo
* pInfo2
= rOther
.cellInfo(nX
).pDataBar
;
853 if( (pInfo1
&& !pInfo2
) || (!pInfo1
&& pInfo2
) )
856 if (pInfo1
&& (*pInfo1
!= *pInfo2
))
859 // each cell with an icon set should be painted the same way
860 const ScIconSetInfo
* pIconSet1
= rFirst
.cellInfo(nX
).pIconSet
;
861 const ScIconSetInfo
* pIconSet2
= rOther
.cellInfo(nX
).pIconSet
;
863 if(pIconSet1
|| pIconSet2
)
870 void ScOutputData::DrawDocumentBackground()
872 if ( !bSolidBackground
)
875 Color
aBgColor(ScModule::get()->GetColorConfig().GetColorValue(svtools::DOCCOLOR
).nColor
);
876 mpDev
->SetLineColor(aBgColor
);
877 mpDev
->SetFillColor(aBgColor
);
879 Point aScreenPos
= mpDev
->PixelToLogic(Point(nScrX
, nScrY
));
880 Size aScreenSize
= mpDev
->PixelToLogic(Size(nScrW
- 1,nScrH
- 1));
882 mpDev
->DrawRect(tools::Rectangle(aScreenPos
, aScreenSize
));
887 const double lclCornerRectTransparency
= 40.0;
889 void drawDataBars(vcl::RenderContext
& rRenderContext
, const ScDataBarInfo
* pOldDataBarInfo
, const tools::Rectangle
& rRect
, tools::Long nOneX
, tools::Long nOneY
)
891 tools::Long nPosZero
= 0;
892 tools::Rectangle aPaintRect
= rRect
;
893 aPaintRect
.AdjustTop(2 * nOneY
);
894 aPaintRect
.AdjustBottom( -(2 * nOneY
) );
895 aPaintRect
.AdjustLeft( 2 * nOneX
);
896 aPaintRect
.AdjustRight( -(2 * nOneX
) );
897 if(pOldDataBarInfo
->mnZero
)
899 // need to calculate null point in cell
900 tools::Long nLength
= aPaintRect
.Right() - aPaintRect
.Left();
901 nPosZero
= static_cast<tools::Long
>(aPaintRect
.Left() + nLength
*pOldDataBarInfo
->mnZero
/100.0);
905 nPosZero
= aPaintRect
.Left();
908 if(pOldDataBarInfo
->mnLength
< 0)
910 aPaintRect
.SetRight( nPosZero
);
911 tools::Long nLength
= nPosZero
- aPaintRect
.Left();
912 aPaintRect
.SetLeft( nPosZero
+ static_cast<tools::Long
>(nLength
* pOldDataBarInfo
->mnLength
/100.0) );
914 else if(pOldDataBarInfo
->mnLength
> 0)
916 aPaintRect
.SetLeft( nPosZero
);
917 tools::Long nLength
= aPaintRect
.Right() - nPosZero
;
918 aPaintRect
.SetRight( nPosZero
+ static_cast<tools::Long
>(nLength
* pOldDataBarInfo
->mnLength
/100.0) );
923 if(pOldDataBarInfo
->mbGradient
)
925 rRenderContext
.SetLineColor(pOldDataBarInfo
->maColor
);
926 Gradient
aGradient(css::awt::GradientStyle_LINEAR
, pOldDataBarInfo
->maColor
, COL_TRANSPARENT
);
927 aGradient
.SetSteps(255);
929 if(pOldDataBarInfo
->mnLength
< 0)
930 aGradient
.SetAngle(2700_deg10
);
932 aGradient
.SetAngle(900_deg10
);
934 rRenderContext
.DrawGradient(aPaintRect
, aGradient
);
936 rRenderContext
.SetLineColor();
940 rRenderContext
.SetFillColor(pOldDataBarInfo
->maColor
);
941 rRenderContext
.DrawRect(aPaintRect
);
945 if(!(pOldDataBarInfo
->mnZero
&& pOldDataBarInfo
->mnZero
!= 100))
948 Point
aPoint1(nPosZero
, rRect
.Top());
949 Point
aPoint2(nPosZero
, rRect
.Bottom());
950 LineInfo
aLineInfo(LineStyle::Dash
, 1);
951 aLineInfo
.SetDashCount( 4 );
952 aLineInfo
.SetDistance( 3 );
953 aLineInfo
.SetDashLen( 3 );
954 rRenderContext
.SetFillColor(pOldDataBarInfo
->maAxisColor
);
955 rRenderContext
.SetLineColor(pOldDataBarInfo
->maAxisColor
);
956 rRenderContext
.DrawLine(aPoint1
, aPoint2
, aLineInfo
);
957 rRenderContext
.SetLineColor();
958 rRenderContext
.SetFillColor();
961 const BitmapEx
& getIcon(sc::IconSetBitmapMap
& rIconSetBitmapMap
, ScIconSetType eType
, sal_Int32 nIndex
)
963 return ScIconSetFormat::getBitmap(rIconSetBitmapMap
, eType
, nIndex
);
966 void drawIconSets(vcl::RenderContext
& rRenderContext
, const ScIconSetInfo
* pOldIconSetInfo
, const tools::Rectangle
& rRect
, tools::Long nOneX
, tools::Long nOneY
,
967 sc::IconSetBitmapMap
& rIconSetBitmapMap
)
969 ScIconSetType eType
= pOldIconSetInfo
->eIconSetType
;
970 sal_Int32 nIndex
= pOldIconSetInfo
->nIconIndex
;
971 const BitmapEx
& rIcon
= getIcon(rIconSetBitmapMap
, eType
, nIndex
);
973 tools::Long aHeight
= o3tl::convert(10, o3tl::Length::pt
, o3tl::Length::mm100
);
975 if (pOldIconSetInfo
->mnHeight
)
977 if (comphelper::LibreOfficeKit::isActive())
979 aHeight
= rRenderContext
.LogicToPixel(Size(0, pOldIconSetInfo
->mnHeight
), MapMode(MapUnit::MapTwip
)).Height();
980 aHeight
*= comphelper::LibreOfficeKit::getDPIScale();
984 aHeight
= o3tl::convert(pOldIconSetInfo
->mnHeight
, o3tl::Length::twip
, o3tl::Length::mm100
);
988 Size aSize
= rIcon
.GetSizePixel();
989 double fRatio
= static_cast<double>(aSize
.Width()) / aSize
.Height();
990 tools::Long aWidth
= fRatio
* aHeight
;
992 rRenderContext
.Push();
993 rRenderContext
.SetClipRegion(vcl::Region(rRect
));
994 rRenderContext
.DrawBitmapEx(Point(rRect
.Left() + 2 * nOneX
, rRect
.Bottom() - 2 * nOneY
- aHeight
), Size(aWidth
, aHeight
), rIcon
);
995 rRenderContext
.Pop();
998 void drawCells(vcl::RenderContext
& rRenderContext
, std::optional
<Color
> const & pColor
, const SvxBrushItem
* pBackground
, std::optional
<Color
>& pOldColor
, const SvxBrushItem
*& pOldBackground
,
999 tools::Rectangle
& rRect
, tools::Long nPosX
, tools::Long nLayoutSign
, tools::Long nOneX
, tools::Long nOneY
, const ScDataBarInfo
* pDataBarInfo
, const ScDataBarInfo
*& pOldDataBarInfo
,
1000 const ScIconSetInfo
* pIconSetInfo
, const ScIconSetInfo
*& pOldIconSetInfo
,
1001 sc::IconSetBitmapMap
& rIconSetBitmapMap
)
1003 tools::Long nSignedOneX
= nOneX
* nLayoutSign
;
1004 // need to paint if old color scale has been used and now
1005 // we have a different color or a style based background
1006 // we can here fall back to pointer comparison
1007 if (pOldColor
&& (pBackground
|| pOldColor
!= pColor
|| pOldDataBarInfo
|| pDataBarInfo
|| pIconSetInfo
|| pOldIconSetInfo
))
1009 rRect
.SetRight( nPosX
-nSignedOneX
);
1010 if( !pOldColor
->IsTransparent() )
1012 rRenderContext
.SetFillColor( *pOldColor
);
1013 rRenderContext
.DrawRect( rRect
);
1015 if( pOldDataBarInfo
)
1016 drawDataBars(rRenderContext
, pOldDataBarInfo
, rRect
, nOneX
, nOneY
);
1017 if( pOldIconSetInfo
)
1018 drawIconSets(rRenderContext
, pOldIconSetInfo
, rRect
, nOneX
, nOneY
, rIconSetBitmapMap
);
1020 rRect
.SetLeft( nPosX
- nSignedOneX
);
1023 if ( pOldBackground
&& (pColor
|| !SfxPoolItem::areSame(pBackground
, pOldBackground
) || pOldDataBarInfo
|| pDataBarInfo
|| pIconSetInfo
|| pOldIconSetInfo
) )
1025 rRect
.SetRight( nPosX
-nSignedOneX
);
1026 if (pOldBackground
) // ==0 if hidden
1028 Color aBackCol
= pOldBackground
->GetColor();
1029 if ( !aBackCol
.IsTransparent() ) //! partial transparency?
1031 rRenderContext
.SetFillColor( aBackCol
);
1032 rRenderContext
.DrawRect( rRect
);
1035 if( pOldDataBarInfo
)
1036 drawDataBars(rRenderContext
, pOldDataBarInfo
, rRect
, nOneX
, nOneY
);
1037 if( pOldIconSetInfo
)
1038 drawIconSets(rRenderContext
, pOldIconSetInfo
, rRect
, nOneX
, nOneY
, rIconSetBitmapMap
);
1040 rRect
.SetLeft( nPosX
- nSignedOneX
);
1043 if (!pOldBackground
&& !pOldColor
&& (pDataBarInfo
|| pIconSetInfo
))
1045 rRect
.SetRight( nPosX
-nSignedOneX
);
1046 rRect
.SetLeft( nPosX
- nSignedOneX
);
1051 // only update pOldColor if the colors changed
1052 if (!pOldColor
|| *pOldColor
!= *pColor
)
1055 pOldBackground
= nullptr;
1057 else if(pBackground
)
1059 pOldBackground
= pBackground
;
1064 pOldDataBarInfo
= pDataBarInfo
;
1066 pOldDataBarInfo
= nullptr;
1069 pOldIconSetInfo
= pIconSetInfo
;
1071 pOldIconSetInfo
= nullptr;
1076 void ScOutputData::DrawBackground(vcl::RenderContext
& rRenderContext
)
1078 vcl::PDFExtOutDevData
* pPDF
= dynamic_cast<vcl::PDFExtOutDevData
*>(mpDev
->GetExtOutDevData());
1079 bool bTaggedPDF
= pPDF
&& pPDF
->GetIsExportTaggedPDF();
1081 Size aOnePixel
= rRenderContext
.PixelToLogic(Size(1,1));
1082 tools::Long nOneXLogic
= aOnePixel
.Width();
1083 tools::Long nOneYLogic
= aOnePixel
.Height();
1085 // See more about bWorksInPixels in ScOutputData::DrawGrid
1086 bool bWorksInPixels
= false;
1087 if (eType
== OUTTYPE_WINDOW
)
1088 bWorksInPixels
= true;
1090 tools::Long nOneX
= 1;
1091 tools::Long nOneY
= 1;
1092 if (!bWorksInPixels
)
1098 tools::Rectangle aRect
;
1100 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1102 rRenderContext
.SetLineColor();
1104 bool bShowProt
= mbSyntaxMode
&& mpDoc
->IsTabProtected(nTab
);
1105 bool bDoAll
= bShowProt
|| bPagebreakMode
|| bSolidBackground
;
1107 bool bCellContrast
= mbUseStyleColor
&&
1108 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
1110 tools::Long nPosY
= nScrY
;
1112 const svtools::ColorConfig
& rColorCfg
= ScModule::get()->GetColorConfig();
1113 Color
aProtectedColor( rColorCfg
.GetColorValue( svtools::CALCPROTECTEDBACKGROUND
).nColor
);
1114 auto pProtectedBackground
= std::make_shared
<SvxBrushItem
>( aProtectedColor
, ATTR_BACKGROUND
);
1116 // iterate through the rows to show
1117 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
1119 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1120 tools::Long nRowHeight
= pThisRowInfo
->nHeight
;
1122 if ( pThisRowInfo
->bChanged
)
1124 if ( ( ( pThisRowInfo
->bEmptyBack
) || mbSyntaxMode
) && !bDoAll
)
1131 pPDF
->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement
);
1133 // scan for rows with the same background:
1135 while ( nArrY
+nSkip
+2<nArrCount
&&
1136 lcl_EqualBack( *pThisRowInfo
, pRowInfo
[nArrY
+nSkip
+1],
1137 nX1
, nX2
, bShowProt
, bPagebreakMode
) )
1140 nRowHeight
+= pRowInfo
[nArrY
+nSkip
].nHeight
; // after incrementing
1143 tools::Long nPosX
= nScrX
;
1146 nPosX
+= nMirrorW
- nOneX
;
1148 aRect
= tools::Rectangle(nPosX
, nPosY
- nOneY
, nPosX
, nPosY
- nOneY
+ nRowHeight
);
1150 aRect
= rRenderContext
.PixelToLogic(aRect
); // internal data in pixels, but we'll be drawing in logic units
1152 const SvxBrushItem
* pOldBackground
= nullptr;
1153 const SvxBrushItem
* pBackground
= nullptr;
1154 std::optional
<Color
> pOldColor
;
1155 const ScDataBarInfo
* pOldDataBarInfo
= nullptr;
1156 const ScIconSetInfo
* pOldIconSetInfo
= nullptr;
1157 SCCOL nMergedCols
= 1;
1158 SCCOL nOldMerged
= 0;
1160 for (SCCOL nX
=nX1
; nX
+ nMergedCols
<= nX2
+ 1; nX
+= nOldMerged
)
1162 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
-1+nMergedCols
);
1164 nOldMerged
= nMergedCols
;
1166 tools::Long nNewPosX
= nPosX
;
1167 // extend for all merged cells
1169 if (pInfo
->bMerged
&& pInfo
->pPatternAttr
)
1171 const ScMergeAttr
* pMerge
=
1172 &pInfo
->pPatternAttr
->GetItem(ATTR_MERGE
);
1173 nMergedCols
= std::max
<SCCOL
>(1, pMerge
->GetColMerge());
1176 for (SCCOL nMerged
= 0; nMerged
< nMergedCols
; ++nMerged
)
1178 SCCOL nCol
= nX
+nOldMerged
+nMerged
;
1181 nNewPosX
+= pRowInfo
[0].basicCellInfo(nCol
-1).nWidth
* nLayoutSign
;
1184 if (nNewPosX
== nPosX
)
1185 continue; // Zero width, no need to draw.
1189 // high contrast for cell borders and backgrounds -> empty background
1190 pBackground
= ScGlobal::GetEmptyBrushItem();
1192 else if (bShowProt
) // show cell protection in syntax mode
1194 const ScPatternAttr
* pP
= pInfo
->pPatternAttr
;
1197 const ScProtectionAttr
& rProt
= pP
->GetItem(ATTR_PROTECTION
);
1198 if (rProt
.GetProtection() || rProt
.GetHideCell())
1199 pBackground
= pProtectedBackground
.get();
1201 pBackground
= ScGlobal::GetEmptyBrushItem();
1204 pBackground
= nullptr;
1207 pBackground
= static_cast<const SvxBrushItem
*>(pInfo
->maBackground
.getItem());
1209 if ( bPagebreakMode
&& !pInfo
->bPrinted
)
1210 pBackground
= pProtectedBackground
.get();
1212 if ( pInfo
->nRotateDir
> ScRotateDir::Standard
&&
1213 !pBackground
->GetColor().IsFullyTransparent() &&
1216 SCROW nY
= pRowInfo
[nArrY
].nRowNo
;
1217 pBackground
= lcl_FindBackground( mpDoc
, nX
, nY
, nTab
);
1220 std::optional
<Color
> const & pColor
= pInfo
->mxColorScale
;
1221 const ScDataBarInfo
* pDataBarInfo
= pInfo
->pDataBar
;
1222 const ScIconSetInfo
* pIconSetInfo
= pInfo
->pIconSet
;
1224 tools::Long nPosXLogic
= nPosX
;
1226 nPosXLogic
= rRenderContext
.PixelToLogic(Point(nPosX
, 0)).X();
1228 drawCells(rRenderContext
, pColor
, pBackground
, pOldColor
, pOldBackground
, aRect
, nPosXLogic
, nLayoutSign
, nOneXLogic
, nOneYLogic
, pDataBarInfo
, pOldDataBarInfo
, pIconSetInfo
, pOldIconSetInfo
, mpDoc
->GetIconSetBitmapMap());
1233 tools::Long nPosXLogic
= nPosX
;
1235 nPosXLogic
= rRenderContext
.PixelToLogic(Point(nPosX
, 0)).X();
1237 drawCells(rRenderContext
, std::optional
<Color
>(), nullptr, pOldColor
, pOldBackground
, aRect
, nPosXLogic
, nLayoutSign
, nOneXLogic
, nOneYLogic
, nullptr, pOldDataBarInfo
, nullptr, pOldIconSetInfo
, mpDoc
->GetIconSetBitmapMap());
1242 pPDF
->EndStructureElement();
1245 nPosY
+= nRowHeight
;
1249 void ScOutputData::DrawShadow()
1251 DrawExtraShadow( false, false, false, false );
1254 void ScOutputData::DrawExtraShadow(bool bLeft
, bool bTop
, bool bRight
, bool bBottom
)
1256 vcl::PDFExtOutDevData
* pPDF
= dynamic_cast<vcl::PDFExtOutDevData
*>(mpDev
->GetExtOutDevData());
1257 bool bTaggedPDF
= pPDF
&& pPDF
->GetIsExportTaggedPDF();
1259 mpDev
->SetLineColor();
1261 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1262 bool bCellContrast
= mbUseStyleColor
&& rStyleSettings
.GetHighContrastMode();
1263 Color aAutoTextColor
;
1264 if ( bCellContrast
)
1265 aAutoTextColor
= ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR
).nColor
;
1267 tools::Long nInitPosX
= nScrX
;
1270 Size aOnePixel
= mpDev
->PixelToLogic(Size(1,1));
1271 tools::Long nOneX
= aOnePixel
.Width();
1272 nInitPosX
+= nMirrorW
- nOneX
;
1274 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1276 tools::Long nPosY
= nScrY
- pRowInfo
[0].nHeight
;
1277 for (SCSIZE nArrY
=0; nArrY
<nArrCount
; nArrY
++)
1279 bool bCornerY
= ( nArrY
== 0 ) || ( nArrY
+1 == nArrCount
);
1280 bool bSkipY
= ( nArrY
==0 && !bTop
) || ( nArrY
+1 == nArrCount
&& !bBottom
);
1282 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1283 tools::Long nRowHeight
= pThisRowInfo
->nHeight
;
1285 if ( pThisRowInfo
->bChanged
&& !bSkipY
)
1287 tools::Long nPosX
= nInitPosX
- pRowInfo
[0].basicCellInfo(nX1
-1).nWidth
* nLayoutSign
;
1288 for (SCCOL nCol
=nX1
-1; nCol
<=nX2
+1; nCol
++)
1290 bool bCornerX
= ( nCol
==nX1
-1 || nCol
==nX2
+1 );
1291 bool bSkipX
= ( nCol
==nX1
-1 && !bLeft
) || ( nCol
==nX2
+1 && !bRight
);
1293 for (sal_uInt16 nPass
=0; nPass
<2; nPass
++) // horizontal / vertical
1295 const SvxShadowItem
* pAttr
= nPass
?
1296 pThisRowInfo
->cellInfo(nCol
).pVShadowOrigin
:
1297 pThisRowInfo
->cellInfo(nCol
).pHShadowOrigin
;
1298 if ( pAttr
&& !bSkipX
)
1301 pPDF
->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement
);
1303 ScShadowPart ePart
= nPass
?
1304 pThisRowInfo
->cellInfo(nCol
).eVShadowPart
:
1305 pThisRowInfo
->cellInfo(nCol
).eHShadowPart
;
1308 if ( (nPass
==0 && bCornerX
) || (nPass
==1 && bCornerY
) )
1309 if ( ePart
!= SC_SHADOW_CORNER
)
1314 tools::Long nThisWidth
= pRowInfo
[0].basicCellInfo(nCol
).nWidth
;
1315 tools::Long nMaxWidth
= nThisWidth
;
1318 //! direction must depend on shadow location
1320 while (nWx
<nX2
&& !pRowInfo
[0].basicCellInfo(nWx
).nWidth
)
1322 nMaxWidth
= pRowInfo
[0].basicCellInfo(nWx
).nWidth
;
1325 // rectangle is in logical orientation
1326 tools::Rectangle
aRect( nPosX
, nPosY
,
1327 nPosX
+ ( nThisWidth
- 1 ) * nLayoutSign
,
1328 nPosY
+ pRowInfo
[nArrY
].nHeight
- 1 );
1330 tools::Long nSize
= pAttr
->GetWidth();
1331 tools::Long nSizeX
= static_cast<tools::Long
>(nSize
*mnPPTX
);
1332 if (nSizeX
>= nMaxWidth
) nSizeX
= nMaxWidth
-1;
1333 tools::Long nSizeY
= static_cast<tools::Long
>(nSize
*mnPPTY
);
1334 if (nSizeY
>= nRowHeight
) nSizeY
= nRowHeight
-1;
1336 nSizeX
*= nLayoutSign
; // used only to add to rectangle values
1338 SvxShadowLocation eLoc
= pAttr
->GetLocation();
1341 // Shadow location is specified as "visual" (right is always right),
1342 // so the attribute's location value is mirrored here and in FillInfo.
1345 case SvxShadowLocation::BottomRight
: eLoc
= SvxShadowLocation::BottomLeft
; break;
1346 case SvxShadowLocation::BottomLeft
: eLoc
= SvxShadowLocation::BottomRight
; break;
1347 case SvxShadowLocation::TopRight
: eLoc
= SvxShadowLocation::TopLeft
; break;
1348 case SvxShadowLocation::TopLeft
: eLoc
= SvxShadowLocation::TopRight
; break;
1351 // added to avoid warnings
1356 if (ePart
== SC_SHADOW_HORIZ
|| ePart
== SC_SHADOW_HSTART
||
1357 ePart
== SC_SHADOW_CORNER
)
1359 if (eLoc
== SvxShadowLocation::TopLeft
|| eLoc
== SvxShadowLocation::TopRight
)
1360 aRect
.SetTop( aRect
.Bottom() - nSizeY
);
1362 aRect
.SetBottom( aRect
.Top() + nSizeY
);
1364 if (ePart
== SC_SHADOW_VERT
|| ePart
== SC_SHADOW_VSTART
||
1365 ePart
== SC_SHADOW_CORNER
)
1367 if (eLoc
== SvxShadowLocation::TopLeft
|| eLoc
== SvxShadowLocation::BottomLeft
)
1368 aRect
.SetLeft( aRect
.Right() - nSizeX
);
1370 aRect
.SetRight( aRect
.Left() + nSizeX
);
1372 if (ePart
== SC_SHADOW_HSTART
)
1374 if (eLoc
== SvxShadowLocation::TopLeft
|| eLoc
== SvxShadowLocation::BottomLeft
)
1375 aRect
.AdjustRight( -nSizeX
);
1377 aRect
.AdjustLeft(nSizeX
);
1379 if (ePart
== SC_SHADOW_VSTART
)
1381 if (eLoc
== SvxShadowLocation::TopLeft
|| eLoc
== SvxShadowLocation::TopRight
)
1382 aRect
.AdjustBottom( -nSizeY
);
1384 aRect
.AdjustTop(nSizeY
);
1387 //! merge rectangles?
1388 mpDev
->SetFillColor( bCellContrast
? aAutoTextColor
: pAttr
->GetColor() );
1389 mpDev
->DrawRect( aRect
);
1392 pPDF
->EndStructureElement();
1397 nPosX
+= pRowInfo
[0].basicCellInfo(nCol
).nWidth
* nLayoutSign
;
1400 nPosY
+= nRowHeight
;
1404 void ScOutputData::DrawClear()
1406 tools::Rectangle aRect
;
1407 Size aOnePixel
= mpDev
->PixelToLogic(Size(1,1));
1408 tools::Long nOneX
= aOnePixel
.Width();
1409 tools::Long nOneY
= aOnePixel
.Height();
1411 // (called only for ScGridWindow)
1412 Color
aBgColor(ScModule::get()->GetColorConfig().GetColorValue(svtools::DOCCOLOR
).nColor
);
1417 mpDev
->SetLineColor();
1419 mpDev
->SetFillColor( aBgColor
);
1421 tools::Long nPosY
= nScrY
;
1422 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
1424 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1425 tools::Long nRowHeight
= pThisRowInfo
->nHeight
;
1427 if ( pThisRowInfo
->bChanged
)
1429 // scan for more rows which must be painted:
1431 while ( nArrY
+nSkip
+2<nArrCount
&& pRowInfo
[nArrY
+nSkip
+1].bChanged
)
1434 nRowHeight
+= pRowInfo
[nArrY
+nSkip
].nHeight
; // after incrementing
1437 aRect
= tools::Rectangle( Point( nScrX
, nPosY
),
1438 Size( nScrW
+1-nOneX
, nRowHeight
+1-nOneY
) );
1439 mpDev
->DrawRect( aRect
);
1443 nPosY
+= nRowHeight
;
1449 static tools::Long
lclGetSnappedX( const OutputDevice
& rDev
, tools::Long nPosX
, bool bSnapPixel
)
1451 return (bSnapPixel
&& nPosX
) ? rDev
.PixelToLogic( rDev
.LogicToPixel( Size( nPosX
, 0 ) ) ).Width() : nPosX
;
1454 static tools::Long
lclGetSnappedY( const OutputDevice
& rDev
, tools::Long nPosY
, bool bSnapPixel
)
1456 return (bSnapPixel
&& nPosY
) ? rDev
.PixelToLogic( rDev
.LogicToPixel( Size( 0, nPosY
) ) ).Height() : nPosY
;
1459 void ScOutputData::DrawFrame(vcl::RenderContext
& rRenderContext
)
1461 vcl::PDFExtOutDevData
* pPDF
= dynamic_cast<vcl::PDFExtOutDevData
*>(mpDev
->GetExtOutDevData());
1462 bool bTaggedPDF
= pPDF
&& pPDF
->GetIsExportTaggedPDF();
1464 pPDF
->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement
);
1466 DrawModeFlags nOldDrawMode
= rRenderContext
.GetDrawMode();
1469 bool bUseSingleColor
= false;
1470 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1471 bool bCellContrast
= mbUseStyleColor
&& rStyleSettings
.GetHighContrastMode();
1473 // if a Calc OLE object is embedded in Draw/Impress, the VCL DrawMode is used
1474 // for display mode / B&W printing. The VCL DrawMode handling doesn't work for lines
1475 // that are drawn with DrawRect, so if the line/background bits are set, the DrawMode
1476 // must be reset and the border colors handled here.
1478 if ( ( nOldDrawMode
& DrawModeFlags::WhiteFill
) && ( nOldDrawMode
& DrawModeFlags::BlackLine
) )
1480 rRenderContext
.SetDrawMode( nOldDrawMode
& (~DrawModeFlags::WhiteFill
) );
1481 aSingleColor
= COL_BLACK
;
1482 bUseSingleColor
= true;
1484 else if ( ( nOldDrawMode
& DrawModeFlags::SettingsFill
) && ( nOldDrawMode
& DrawModeFlags::SettingsLine
) )
1486 rRenderContext
.SetDrawMode( nOldDrawMode
& (~DrawModeFlags::SettingsFill
) );
1487 aSingleColor
= rStyleSettings
.GetWindowTextColor(); // same as used in VCL for DrawModeFlags::SettingsLine
1488 bUseSingleColor
= true;
1490 else if ( bCellContrast
)
1492 aSingleColor
= ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR
).nColor
;
1493 bUseSingleColor
= true;
1496 const Color
* pForceColor
= bUseSingleColor
? &aSingleColor
: nullptr;
1498 if (mrTabInfo
.maArray
.HasCellRotation())
1500 DrawRotatedFrame(rRenderContext
); // removes the lines that must not be painted here
1503 tools::Long nInitPosX
= nScrX
;
1506 Size aOnePixel
= rRenderContext
.PixelToLogic(Size(1,1));
1507 tools::Long nOneX
= aOnePixel
.Width();
1508 nInitPosX
+= nMirrorW
- nOneX
;
1510 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1512 // *** set column and row sizes of the frame border array ***
1514 svx::frame::Array
& rArray
= mrTabInfo
.maArray
;
1515 size_t nColCount
= rArray
.GetColCount();
1516 size_t nRowCount
= rArray
.GetRowCount();
1520 // row 0 is not visible (dummy for borders from top) - subtract its height from initial position
1521 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit before
1522 tools::Long nOldPosY
= nScrY
- 1 - pRowInfo
[ 0 ].nHeight
;
1523 tools::Long nOldSnapY
= lclGetSnappedY( rRenderContext
, nOldPosY
, bSnapPixel
);
1524 rArray
.SetYOffset( nOldSnapY
);
1525 for( size_t nRow
= 0; nRow
< nRowCount
; ++nRow
)
1527 tools::Long nNewPosY
= nOldPosY
+ pRowInfo
[ nRow
].nHeight
;
1528 tools::Long nNewSnapY
= lclGetSnappedY( rRenderContext
, nNewPosY
, bSnapPixel
);
1529 rArray
.SetRowHeight( nRow
, nNewSnapY
- nOldSnapY
);
1530 nOldPosY
= nNewPosY
;
1531 nOldSnapY
= nNewSnapY
;
1536 // column nX1-1 is not visible (dummy for borders from left) - subtract its width from initial position
1537 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit above
1538 tools::Long nOldPosX
= nInitPosX
- nLayoutSign
* (1 + pRowInfo
[ 0 ].basicCellInfo( nX1
- 1 ).nWidth
);
1539 tools::Long nOldSnapX
= lclGetSnappedX( rRenderContext
, nOldPosX
, bSnapPixel
);
1540 // set X offset for left-to-right sheets; for right-to-left sheets this is done after for() loop
1542 rArray
.SetXOffset( nOldSnapX
);
1543 for( SCCOL nCol
= nX1
- 1; nCol
<= nX2
+ 1; ++nCol
)
1545 size_t nArrCol
= bLayoutRTL
? nX2
+ 1 - nCol
: nCol
- (nX1
- 1);
1546 tools::Long nNewPosX
= nOldPosX
+ pRowInfo
[ 0 ].basicCellInfo( nCol
).nWidth
* nLayoutSign
;
1547 tools::Long nNewSnapX
= lclGetSnappedX( rRenderContext
, nNewPosX
, bSnapPixel
);
1548 rArray
.SetColWidth( nArrCol
, std::abs( nNewSnapX
- nOldSnapX
) );
1549 nOldPosX
= nNewPosX
;
1550 nOldSnapX
= nNewSnapX
;
1553 rArray
.SetXOffset( nOldSnapX
);
1555 // *** draw the array ***
1557 size_t nFirstCol
= 1;
1558 size_t nFirstRow
= 1;
1559 size_t nLastCol
= nColCount
- 2;
1560 size_t nLastRow
= nRowCount
- 2;
1562 if( mrTabInfo
.mbPageMode
)
1563 rArray
.SetClipRange( nFirstCol
, nFirstRow
, nLastCol
, nLastRow
);
1565 // draw only rows with set RowInfo::bChanged flag
1566 size_t nRow1
= nFirstRow
;
1567 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor(CreateProcessor2D());
1570 while( nRow1
<= nLastRow
)
1572 while( (nRow1
<= nLastRow
) && !pRowInfo
[ nRow1
].bChanged
) ++nRow1
;
1573 if( nRow1
<= nLastRow
)
1575 size_t nRow2
= nRow1
;
1576 while( (nRow2
+ 1 <= nLastRow
) && pRowInfo
[ nRow2
+ 1 ].bChanged
) ++nRow2
;
1577 auto xPrimitive
= rArray
.CreateB2DPrimitiveRange(
1578 nFirstCol
, nRow1
, nLastCol
, nRow2
, pForceColor
);
1579 pProcessor
->process(xPrimitive
);
1585 rRenderContext
.SetDrawMode(nOldDrawMode
);
1588 pPDF
->EndStructureElement();
1591 void ScOutputData::DrawRotatedFrame(vcl::RenderContext
& rRenderContext
)
1594 SCCOL nRotMax
= nX2
;
1595 for (SCSIZE nRotY
=0; nRotY
<nArrCount
; nRotY
++)
1596 if (pRowInfo
[nRotY
].nRotMaxCol
!= SC_ROTMAX_NONE
&& pRowInfo
[nRotY
].nRotMaxCol
> nRotMax
)
1597 nRotMax
= pRowInfo
[nRotY
].nRotMaxCol
;
1599 const ScPatternAttr
* pPattern
;
1600 const SfxItemSet
* pCondSet
;
1602 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1603 bool bCellContrast
= mbUseStyleColor
&& rStyleSettings
.GetHighContrastMode();
1605 tools::Long nInitPosX
= nScrX
;
1608 Size aOnePixel
= rRenderContext
.PixelToLogic(Size(1,1));
1609 tools::Long nOneX
= aOnePixel
.Width();
1610 nInitPosX
+= nMirrorW
- nOneX
;
1612 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1614 tools::Rectangle
aClipRect( Point(nScrX
, nScrY
), Size(nScrW
, nScrH
) );
1617 rRenderContext
.Push();
1618 rRenderContext
.IntersectClipRegion( aClipRect
);
1621 rRenderContext
.SetClipRegion( vcl::Region( aClipRect
) );
1623 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor(CreateProcessor2D( ));
1624 tools::Long nPosY
= nScrY
;
1625 for (SCSIZE nArrY
=1; nArrY
<nArrCount
; nArrY
++)
1627 // Rotated is also drawn one line above/below Changed if parts extend into the cell
1629 RowInfo
& rPrevRowInfo
= pRowInfo
[nArrY
-1];
1630 RowInfo
& rThisRowInfo
= pRowInfo
[nArrY
];
1631 RowInfo
& rNextRowInfo
= pRowInfo
[nArrY
+1];
1633 tools::Long nRowHeight
= rThisRowInfo
.nHeight
;
1634 if ( rThisRowInfo
.nRotMaxCol
!= SC_ROTMAX_NONE
&&
1635 ( rThisRowInfo
.bChanged
|| rPrevRowInfo
.bChanged
||
1636 ( nArrY
+1<nArrCount
&& rNextRowInfo
.bChanged
) ) )
1638 SCROW nY
= rThisRowInfo
.nRowNo
;
1639 tools::Long nPosX
= 0;
1641 for (nX
=0; nX
<=nRotMax
; nX
++)
1643 if (nX
==nX1
) nPosX
= nInitPosX
; // calculated individually for preceding positions
1645 ScCellInfo
* pInfo
= &rThisRowInfo
.cellInfo(nX
);
1646 tools::Long nColWidth
= pRowInfo
[0].basicCellInfo(nX
).nWidth
;
1647 if ( pInfo
->nRotateDir
> ScRotateDir::Standard
&&
1648 !pInfo
->bHOverlapped
&& !pInfo
->bVOverlapped
)
1650 pPattern
= pInfo
->pPatternAttr
;
1651 pCondSet
= pInfo
->pConditionSet
;
1654 pPattern
= mpDoc
->GetPattern( nX
, nY
, nTab
);
1655 pInfo
->pPatternAttr
= pPattern
;
1656 pCondSet
= mpDoc
->GetCondResult( nX
, nY
, nTab
);
1657 pInfo
->pConditionSet
= pCondSet
;
1660 //! LastPattern etc.
1662 Degree100 nAttrRotate
= pPattern
->GetRotateVal( pCondSet
);
1663 SvxRotateMode eRotMode
=
1664 pPattern
->GetItem(ATTR_ROTATE_MODE
, pCondSet
).GetValue();
1668 if (nX
< nX1
) // compute negative position
1675 nPosX
-= nLayoutSign
* static_cast<tools::Long
>(pRowInfo
[0].basicCellInfo(nCol
).nWidth
);
1679 // start position minus 1 so rotated backgrounds suit the border
1680 // (border is on the grid)
1682 tools::Long nTop
= nPosY
- 1;
1683 tools::Long nBottom
= nPosY
+ nRowHeight
- 1;
1684 tools::Long nTopLeft
= nPosX
- nLayoutSign
;
1685 tools::Long nTopRight
= nPosX
+ (nColWidth
- 1) * nLayoutSign
;
1686 tools::Long nBotLeft
= nTopLeft
;
1687 tools::Long nBotRight
= nTopRight
;
1689 // inclusion of the sign here hasn't been decided yet
1690 // (if not, the extension of the non-rotated background must also be changed)
1691 double nRealOrient
= nLayoutSign
* toRadians(nAttrRotate
); // 1/100th degrees
1692 double nCos
= cos(nRealOrient
);
1693 double nSin
= sin(nRealOrient
);
1695 tools::Long nSkew
= static_cast<tools::Long
>(nRowHeight
* nCos
/ nSin
);
1699 case SVX_ROTATE_MODE_BOTTOM
:
1703 case SVX_ROTATE_MODE_CENTER
:
1710 case SVX_ROTATE_MODE_TOP
:
1716 // added to avoid warnings
1721 aPoints
[0] = Point(nTopLeft
, nTop
);
1722 aPoints
[1] = Point(nTopRight
, nTop
);
1723 aPoints
[2] = Point(nBotRight
, nBottom
);
1724 aPoints
[3] = Point(nBotLeft
, nBottom
);
1726 const SvxBrushItem
* pBackground(static_cast<const SvxBrushItem
*>(pInfo
->maBackground
.getItem()));
1728 pBackground
= &pPattern
->GetItem(ATTR_BACKGROUND
, pCondSet
);
1731 // high contrast for cell borders and backgrounds -> empty background
1732 pBackground
= ScGlobal::GetEmptyBrushItem();
1734 if (!pInfo
->mxColorScale
)
1736 const Color
& rColor
= pBackground
->GetColor();
1737 if (rColor
.GetAlpha() != 0)
1739 // draw background only for the changed row itself
1740 // (background doesn't extend into other cells).
1741 // For the borders (rotated and normal), clipping should be
1742 // set if the row isn't changed, but at least the borders
1743 // don't cover the cell contents.
1744 if (rThisRowInfo
.bChanged
)
1746 tools::Polygon
aPoly(4, aPoints
);
1748 // for DrawPolygon, without Pen one pixel is left out
1749 // to the right and below...
1750 if (!rColor
.IsTransparent())
1751 rRenderContext
.SetLineColor(rColor
);
1753 rRenderContext
.SetLineColor();
1754 rRenderContext
.SetFillColor(rColor
);
1755 rRenderContext
.DrawPolygon(aPoly
);
1761 tools::Polygon
aPoly(4, aPoints
);
1762 std::optional
<Color
> const & pColor
= pInfo
->mxColorScale
;
1764 // for DrawPolygon, without Pen one pixel is left out
1765 // to the right and below...
1766 if (!pColor
->IsTransparent())
1767 rRenderContext
.SetLineColor(*pColor
);
1769 rRenderContext
.SetLineColor();
1770 rRenderContext
.SetFillColor(*pColor
);
1771 rRenderContext
.DrawPolygon(aPoly
);
1776 nPosX
+= nColWidth
* nLayoutSign
;
1779 nPosY
+= nRowHeight
;
1785 rRenderContext
.Pop();
1787 rRenderContext
.SetClipRegion();
1790 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> ScOutputData::CreateProcessor2D( )
1792 mpDoc
->InitDrawLayer(mpDoc
->GetDocumentShell());
1793 ScDrawLayer
* pDrawLayer
= mpDoc
->GetDrawLayer();
1797 basegfx::B2DRange aViewRange
;
1798 SdrPage
*pDrawPage
= pDrawLayer
->GetPage( static_cast< sal_uInt16
>( nTab
) );
1799 drawinglayer::geometry::ViewInformation2D aNewViewInfos
;
1800 aNewViewInfos
.setViewTransformation(mpDev
->GetViewTransformation());
1801 aNewViewInfos
.setViewport(aViewRange
);
1802 aNewViewInfos
.setVisualizedPage(GetXDrawPageForSdrPage( pDrawPage
));
1804 return drawinglayer::processor2d::createProcessor2DFromOutputDevice(
1805 *mpDev
, aNewViewInfos
);
1810 vcl::Region
ScOutputData::GetChangedAreaRegion()
1812 vcl::Region aRegion
;
1813 tools::Rectangle aDrawingRect
;
1815 tools::Long nPosY
= nScrY
;
1818 aDrawingRect
.SetLeft( nScrX
);
1819 aDrawingRect
.SetRight( nScrX
+nScrW
-1 );
1821 for(nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
1823 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1825 if(pThisRowInfo
->bChanged
)
1829 aDrawingRect
.SetTop( nPosY
);
1833 aDrawingRect
.SetBottom( nPosY
+ pRowInfo
[nArrY
].nHeight
- 1 );
1837 aRegion
.Union(mpDev
->PixelToLogic(aDrawingRect
));
1841 nPosY
+= pRowInfo
[nArrY
].nHeight
;
1846 aRegion
.Union(mpDev
->PixelToLogic(aDrawingRect
));
1852 bool ScOutputData::SetChangedClip()
1854 tools::PolyPolygon aPoly
;
1856 tools::Rectangle aDrawingRect
;
1857 aDrawingRect
.SetLeft( nScrX
);
1858 aDrawingRect
.SetRight( nScrX
+nScrW
-1 );
1861 tools::Long nPosY
= nScrY
;
1863 for (nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
1865 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1867 if ( pThisRowInfo
->bChanged
)
1871 aDrawingRect
.SetTop( nPosY
);
1874 aDrawingRect
.SetBottom( nPosY
+ pRowInfo
[nArrY
].nHeight
- 1 );
1878 aPoly
.Insert( tools::Polygon( mpDev
->PixelToLogic(aDrawingRect
) ) );
1881 nPosY
+= pRowInfo
[nArrY
].nHeight
;
1885 aPoly
.Insert( tools::Polygon( mpDev
->PixelToLogic(aDrawingRect
) ) );
1887 bool bRet
= (aPoly
.Count() != 0);
1889 mpDev
->SetClipRegion(vcl::Region(aPoly
));
1893 void ScOutputData::FindChanged()
1898 bool bWasIdleEnabled
= mpDoc
->IsIdleEnabled();
1899 mpDoc
->EnableIdle(false);
1900 for (nArrY
=0; nArrY
<nArrCount
; nArrY
++)
1901 pRowInfo
[nArrY
].bChanged
= false;
1903 SCCOL nCol1
= mpDoc
->MaxCol(), nCol2
= 0;
1904 SCROW nRow1
= mpDoc
->MaxRow(), nRow2
= 0;
1905 bool bAnyDirty
= false;
1906 bool bAnyChanged
= false;
1908 for (nArrY
=0; nArrY
<nArrCount
; nArrY
++)
1910 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1911 for (nX
=nX1
; nX
<=nX2
; nX
++)
1913 const ScRefCellValue
& rCell
= pThisRowInfo
->cellInfo(nX
).maCell
;
1915 if (rCell
.getType() != CELLTYPE_FORMULA
)
1918 ScFormulaCell
* pFCell
= rCell
.getFormula();
1919 if (pFCell
->IsRunning())
1920 // still being interpreted. Skip it.
1923 bool bDirty
= pFCell
->GetDirty();
1924 bAnyChanged
= bAnyChanged
|| pFCell
->IsChanged();
1930 ScProgress::CreateInterpretProgress(mpDoc
);
1934 ScAddress
& rPos(pFCell
->aPos
);
1935 nCol1
= std::min(rPos
.Col(), nCol1
);
1936 nCol2
= std::max(rPos
.Col(), nCol2
);
1937 nRow1
= std::min(rPos
.Row(), nRow1
);
1938 nRow2
= std::max(rPos
.Row(), nRow2
);
1940 const SfxUInt32Item
* pItem
= mpDoc
->GetAttr(rPos
, ATTR_VALIDDATA
);
1941 const ScValidationData
* pData
= mpDoc
->GetValidationEntry(pItem
->GetValue());
1944 ScRefCellValue
aCell(*mpDoc
, rPos
);
1945 if (pData
->IsDataValid(aCell
, rPos
))
1946 ScDetectiveFunc(*mpDoc
, rPos
.Tab()).DeleteCirclesAt(rPos
.Col(), rPos
.Row());
1952 if (bAnyDirty
|| bAnyChanged
)
1955 mpDoc
->EnsureFormulaCellResults(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
), true);
1957 for (nArrY
=0; nArrY
<nArrCount
; nArrY
++)
1959 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1960 for (nX
=nX1
; nX
<=nX2
; nX
++)
1962 const ScRefCellValue
& rCell
= pThisRowInfo
->cellInfo(nX
).maCell
;
1964 if (rCell
.getType() != CELLTYPE_FORMULA
)
1967 ScFormulaCell
* pFCell
= rCell
.getFormula();
1968 if (pFCell
->IsRunning())
1969 // still being interpreted. Skip it.
1972 if (!pFCell
->IsChanged())
1973 // the result hasn't changed. Skip it.
1976 pThisRowInfo
->bChanged
= true;
1977 if ( pThisRowInfo
->cellInfo(nX
).bMerged
)
1979 SCSIZE nOverY
= nArrY
+ 1;
1980 while ( nOverY
<nArrCount
&&
1981 pRowInfo
[nOverY
].cellInfo(nX
).bVOverlapped
)
1983 pRowInfo
[nOverY
].bChanged
= true;
1991 ScProgress::DeleteInterpretProgress();
1994 mpDoc
->EnableIdle(bWasIdleEnabled
);
1997 ReferenceMark
ScOutputData::FillReferenceMark( SCCOL nRefStartX
, SCROW nRefStartY
,
1998 SCCOL nRefEndX
, SCROW nRefEndY
, const Color
& rColor
)
2000 ReferenceMark aResult
;
2002 PutInOrder( nRefStartX
, nRefEndX
);
2003 PutInOrder( nRefStartY
, nRefEndY
);
2005 if ( nRefStartX
== nRefEndX
&& nRefStartY
== nRefEndY
)
2006 mpDoc
->ExtendMerge( nRefStartX
, nRefStartY
, nRefEndX
, nRefEndY
, nTab
);
2008 if ( nRefStartX
<= nVisX2
&& nRefEndX
>= nVisX1
&&
2009 nRefStartY
<= nVisY2
&& nRefEndY
>= nVisY1
)
2011 tools::Long nMinX
= nScrX
;
2012 tools::Long nMinY
= nScrY
;
2013 tools::Long nMaxX
= nScrX
+ nScrW
- 1;
2014 tools::Long nMaxY
= nScrY
+ nScrH
- 1;
2016 std::swap( nMinX
, nMaxX
);
2017 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2020 bool bBottom
= false;
2022 bool bRight
= false;
2024 tools::Long nPosY
= nScrY
;
2025 bool bNoStartY
= ( nY1
< nRefStartY
);
2026 bool bNoEndY
= false;
2027 for (SCSIZE nArrY
=1; nArrY
<nArrCount
; nArrY
++) // loop to end for bNoEndY check
2029 SCROW nY
= pRowInfo
[nArrY
].nRowNo
;
2031 if ( nY
==nRefStartY
|| (nY
>nRefStartY
&& bNoStartY
) )
2038 nMaxY
= nPosY
+ pRowInfo
[nArrY
].nHeight
- 2;
2041 if ( nY
>nRefEndY
&& bNoEndY
)
2046 bNoStartY
= ( nY
< nRefStartY
);
2047 bNoEndY
= ( nY
< nRefEndY
);
2048 nPosY
+= pRowInfo
[nArrY
].nHeight
;
2051 tools::Long nPosX
= nScrX
;
2053 nPosX
+= nMirrorW
- 1; // always in pixels
2055 for (SCCOL nX
=nX1
; nX
<=nX2
; nX
++)
2057 if ( nX
==nRefStartX
)
2064 nMaxX
= nPosX
+ ( pRowInfo
[0].basicCellInfo(nX
).nWidth
- 2 ) * nLayoutSign
;
2067 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2070 if (bTop
&& bBottom
&& bLeft
&& bRight
)
2072 // mnPPT[XY] already has the factor aZoom[XY] in it.
2073 aResult
= ReferenceMark( nMinX
/ mnPPTX
,
2075 ( nMaxX
- nMinX
) / mnPPTX
,
2076 ( nMaxY
- nMinY
) / mnPPTY
,
2085 void ScOutputData::DrawRefMark( SCCOL nRefStartX
, SCROW nRefStartY
,
2086 SCCOL nRefEndX
, SCROW nRefEndY
,
2087 const Color
& rColor
, bool bHandle
)
2089 PutInOrder( nRefStartX
, nRefEndX
);
2090 PutInOrder( nRefStartY
, nRefEndY
);
2092 if ( nRefStartX
== nRefEndX
&& nRefStartY
== nRefEndY
)
2093 mpDoc
->ExtendMerge( nRefStartX
, nRefStartY
, nRefEndX
, nRefEndY
, nTab
);
2094 else if (mpDoc
->HasAttrib(nRefEndX
, nRefEndY
, nTab
, HasAttrFlags::Merged
))
2095 mpDoc
->ExtendMerge(nRefEndX
, nRefEndY
, nRefEndX
, nRefEndY
, nTab
);
2097 if ( !(nRefStartX
<= nVisX2
&& nRefEndX
>= nVisX1
&&
2098 nRefStartY
<= nVisY2
&& nRefEndY
>= nVisY1
) )
2101 tools::Long nMinX
= nScrX
;
2102 tools::Long nMinY
= nScrY
;
2103 tools::Long nMaxX
= nScrX
+ nScrW
- 1;
2104 tools::Long nMaxY
= nScrY
+ nScrH
- 1;
2106 std::swap( nMinX
, nMaxX
);
2107 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2110 bool bBottom
= false;
2112 bool bRight
= false;
2114 tools::Long nPosY
= nScrY
;
2115 bool bNoStartY
= ( nY1
< nRefStartY
);
2116 bool bNoEndY
= false;
2117 for (SCSIZE nArrY
=1; nArrY
<nArrCount
; nArrY
++) // loop to end for bNoEndY check
2119 SCROW nY
= pRowInfo
[nArrY
].nRowNo
;
2121 if ( nY
==nRefStartY
|| (nY
>nRefStartY
&& bNoStartY
) )
2128 nMaxY
= nPosY
+ pRowInfo
[nArrY
].nHeight
- 2;
2131 if ( nY
>nRefEndY
&& bNoEndY
)
2136 bNoStartY
= ( nY
< nRefStartY
);
2137 bNoEndY
= ( nY
< nRefEndY
);
2138 nPosY
+= pRowInfo
[nArrY
].nHeight
;
2141 tools::Long nPosX
= nScrX
;
2143 nPosX
+= nMirrorW
- 1; // always in pixels
2145 for (SCCOL nX
=nX1
; nX
<=nX2
; nX
++)
2147 if ( nX
==nRefStartX
)
2154 nMaxX
= nPosX
+ ( pRowInfo
[0].basicCellInfo(nX
).nWidth
- 2 ) * nLayoutSign
;
2157 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2160 if ( nMaxX
* nLayoutSign
< nMinX
* nLayoutSign
|| nMaxY
< nMinY
)
2163 mpDev
->SetLineColor( rColor
);
2164 if (bTop
&& bBottom
&& bLeft
&& bRight
&& !comphelper::LibreOfficeKit::isActive() )
2166 mpDev
->SetFillColor();
2167 mpDev
->DrawRect( tools::Rectangle( nMinX
, nMinY
, nMaxX
, nMaxY
) );
2169 else if ( !comphelper::LibreOfficeKit::isActive() )
2172 mpDev
->DrawLine( Point( nMinX
, nMinY
), Point( nMaxX
, nMinY
) );
2174 mpDev
->DrawLine( Point( nMinX
, nMaxY
), Point( nMaxX
, nMaxY
) );
2176 mpDev
->DrawLine( Point( nMinX
, nMinY
), Point( nMinX
, nMaxY
) );
2178 mpDev
->DrawLine( Point( nMaxX
, nMinY
), Point( nMaxX
, nMaxY
) );
2180 if ( !bHandle
|| !bRight
|| !bBottom
|| comphelper::LibreOfficeKit::isActive() )
2183 mpDev
->SetLineColor( rColor
);
2184 mpDev
->SetFillColor( rColor
);
2186 const sal_Int32 aRadius
= 4;
2188 sal_Int32 aRectMaxX1
= nMaxX
- nLayoutSign
* aRadius
;
2189 sal_Int32 aRectMaxX2
= nMaxX
+ nLayoutSign
;
2190 sal_Int32 aRectMinX1
= nMinX
- nLayoutSign
;
2191 sal_Int32 aRectMinX2
= nMinX
+ nLayoutSign
* aRadius
;
2193 sal_Int32 aRectMaxY1
= nMaxY
- aRadius
;
2194 sal_Int32 aRectMaxY2
= nMaxY
+ 1;
2195 sal_Int32 aRectMinY1
= nMinY
- 1;
2196 sal_Int32 aRectMinY2
= nMinY
+ aRadius
;
2198 // Draw corner rectangles
2199 tools::Rectangle
aLowerRight( aRectMaxX1
, aRectMaxY1
, aRectMaxX2
, aRectMaxY2
);
2200 tools::Rectangle
aUpperLeft ( aRectMinX1
, aRectMinY1
, aRectMinX2
, aRectMinY2
);
2201 tools::Rectangle
aLowerLeft ( aRectMinX1
, aRectMaxY1
, aRectMinX2
, aRectMaxY2
);
2202 tools::Rectangle
aUpperRight( aRectMaxX1
, aRectMinY1
, aRectMaxX2
, aRectMinY2
);
2204 mpDev
->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerRight
) ), lclCornerRectTransparency
);
2205 mpDev
->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperLeft
) ), lclCornerRectTransparency
);
2206 mpDev
->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerLeft
) ), lclCornerRectTransparency
);
2207 mpDev
->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperRight
) ), lclCornerRectTransparency
);
2210 void ScOutputData::DrawOneChange( SCCOL nRefStartX
, SCROW nRefStartY
,
2211 SCCOL nRefEndX
, SCROW nRefEndY
,
2212 const Color
& rColor
, sal_uInt16 nType
)
2214 PutInOrder( nRefStartX
, nRefEndX
);
2215 PutInOrder( nRefStartY
, nRefEndY
);
2217 if ( nRefStartX
== nRefEndX
&& nRefStartY
== nRefEndY
)
2218 mpDoc
->ExtendMerge( nRefStartX
, nRefStartY
, nRefEndX
, nRefEndY
, nTab
);
2220 if ( !(nRefStartX
<= nVisX2
+ 1 && nRefEndX
>= nVisX1
&&
2221 nRefStartY
<= nVisY2
+ 1 && nRefEndY
>= nVisY1
) ) // +1 because it touches next cells left/top
2224 tools::Long nMinX
= nScrX
;
2225 tools::Long nMinY
= nScrY
;
2226 tools::Long nMaxX
= nScrX
+nScrW
-1;
2227 tools::Long nMaxY
= nScrY
+nScrH
-1;
2229 std::swap( nMinX
, nMaxX
);
2230 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2233 bool bBottom
= false;
2235 bool bRight
= false;
2237 tools::Long nPosY
= nScrY
;
2238 bool bNoStartY
= ( nY1
< nRefStartY
);
2239 bool bNoEndY
= false;
2240 for (SCSIZE nArrY
=1; nArrY
<nArrCount
; nArrY
++) // loop to end for bNoEndY check
2242 SCROW nY
= pRowInfo
[nArrY
].nRowNo
;
2244 if ( nY
==nRefStartY
|| (nY
>nRefStartY
&& bNoStartY
) )
2251 nMaxY
= nPosY
+ pRowInfo
[nArrY
].nHeight
- 1;
2254 if ( nY
>nRefEndY
&& bNoEndY
)
2259 bNoStartY
= ( nY
< nRefStartY
);
2260 bNoEndY
= ( nY
< nRefEndY
);
2261 nPosY
+= pRowInfo
[nArrY
].nHeight
;
2264 tools::Long nPosX
= nScrX
;
2266 nPosX
+= nMirrorW
- 1; // always in pixels
2268 for (SCCOL nX
=nX1
; nX
<=nX2
+1; nX
++)
2270 if ( nX
==nRefStartX
)
2272 nMinX
= nPosX
- nLayoutSign
;
2277 nMaxX
= nPosX
+ ( pRowInfo
[0].basicCellInfo(nX
).nWidth
- 1 ) * nLayoutSign
;
2280 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2283 if ( nMaxX
* nLayoutSign
< nMinX
* nLayoutSign
|| nMaxY
< nMinY
)
2286 if ( nType
== SC_CAT_DELETE_ROWS
)
2287 bLeft
= bRight
= bBottom
= false; //! thick lines???
2288 else if ( nType
== SC_CAT_DELETE_COLS
)
2289 bTop
= bBottom
= bRight
= false; //! thick lines???
2291 mpDev
->SetLineColor( rColor
);
2292 if (bTop
&& bBottom
&& bLeft
&& bRight
)
2294 mpDev
->SetFillColor();
2295 mpDev
->DrawRect( tools::Rectangle( nMinX
, nMinY
, nMaxX
, nMaxY
) );
2301 mpDev
->DrawLine( Point( nMinX
,nMinY
), Point( nMaxX
,nMinY
) );
2302 if ( nType
== SC_CAT_DELETE_ROWS
)
2303 mpDev
->DrawLine( Point( nMinX
,nMinY
+1 ), Point( nMaxX
,nMinY
+1 ) );
2306 mpDev
->DrawLine( Point( nMinX
,nMaxY
), Point( nMaxX
,nMaxY
) );
2309 mpDev
->DrawLine( Point( nMinX
,nMinY
), Point( nMinX
,nMaxY
) );
2310 if ( nType
== SC_CAT_DELETE_COLS
)
2311 mpDev
->DrawLine( Point( nMinX
+nLayoutSign
,nMinY
), Point( nMinX
+nLayoutSign
,nMaxY
) );
2314 mpDev
->DrawLine( Point( nMaxX
,nMinY
), Point( nMaxX
,nMaxY
) );
2316 if ( bLeft
&& bTop
)
2318 mpDev
->SetLineColor();
2319 mpDev
->SetFillColor( rColor
);
2320 mpDev
->DrawRect( tools::Rectangle( nMinX
+nLayoutSign
, nMinY
+1, nMinX
+3*nLayoutSign
, nMinY
+3 ) );
2324 void ScOutputData::DrawChangeTrack()
2326 ScChangeTrack
* pTrack
= mpDoc
->GetChangeTrack();
2327 ScChangeViewSettings
* pSettings
= mpDoc
->GetChangeViewSettings();
2328 if ( !pTrack
|| !pTrack
->GetFirst() || !pSettings
|| !pSettings
->ShowChanges() )
2329 return; // nothing there or hidden
2331 ScActionColorChanger
aColorChanger(*pTrack
);
2333 // clipping happens from the outside
2334 //! without clipping, only paint affected cells ??!??!?
2338 if ( nEndX
< mpDoc
->MaxCol() ) ++nEndX
; // also from the next cell since the mark
2339 if ( nEndY
< mpDoc
->MaxRow() ) ++nEndY
; // protrudes from the preceding cell
2340 ScRange
aViewRange( nX1
, nY1
, nTab
, nEndX
, nEndY
, nTab
);
2341 const ScChangeAction
* pAction
= pTrack
->GetFirst();
2344 if ( pAction
->IsVisible() )
2346 ScChangeActionType eActionType
= pAction
->GetType();
2347 const ScBigRange
& rBig
= pAction
->GetBigRange();
2348 if ( rBig
.aStart
.Tab() == nTab
)
2350 ScRange aRange
= rBig
.MakeRange( *mpDoc
);
2352 if ( eActionType
== SC_CAT_DELETE_ROWS
)
2353 aRange
.aEnd
.SetRow( aRange
.aStart
.Row() );
2354 else if ( eActionType
== SC_CAT_DELETE_COLS
)
2355 aRange
.aEnd
.SetCol( aRange
.aStart
.Col() );
2357 if ( aRange
.Intersects( aViewRange
) &&
2358 ScViewUtil::IsActionShown( *pAction
, *pSettings
, *mpDoc
) )
2360 aColorChanger
.Update( *pAction
);
2361 Color
aColor( aColorChanger
.GetColor() );
2362 DrawOneChange( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
2363 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(), aColor
, sal::static_int_cast
<sal_uInt16
>(eActionType
) );
2367 if ( eActionType
== SC_CAT_MOVE
&&
2368 static_cast<const ScChangeActionMove
*>(pAction
)->
2369 GetFromRange().aStart
.Tab() == nTab
)
2371 ScRange aRange
= static_cast<const ScChangeActionMove
*>(pAction
)->
2372 GetFromRange().MakeRange( *mpDoc
);
2373 if ( aRange
.Intersects( aViewRange
) &&
2374 ScViewUtil::IsActionShown( *pAction
, *pSettings
, *mpDoc
) )
2376 aColorChanger
.Update( *pAction
);
2377 Color
aColor( aColorChanger
.GetColor() );
2378 DrawOneChange( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
2379 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(), aColor
, sal::static_int_cast
<sal_uInt16
>(eActionType
) );
2384 pAction
= pAction
->GetNext();
2388 void ScOutputData::DrawSparklines(vcl::RenderContext
& rRenderContext
)
2390 Size aOnePixel
= rRenderContext
.PixelToLogic(Size(1,1));
2391 tools::Long nOneXLogic
= aOnePixel
.Width();
2392 tools::Long nOneYLogic
= aOnePixel
.Height();
2394 // See more about bWorksInPixels in ScOutputData::DrawGrid
2395 bool bWorksInPixels
= false;
2396 if (eType
== OUTTYPE_WINDOW
)
2397 bWorksInPixels
= true;
2399 tools::Long nOneX
= 1;
2400 tools::Long nOneY
= 1;
2401 if (!bWorksInPixels
)
2407 tools::Long nInitPosX
= nScrX
;
2409 nInitPosX
+= nMirrorW
- 1; // always in pixels
2410 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2412 tools::Long nPosY
= nScrY
;
2413 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
2415 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
2416 if ( pThisRowInfo
->bChanged
)
2418 tools::Long nPosX
= nInitPosX
;
2419 for (SCCOL nX
=nX1
; nX
<=nX2
; nX
++)
2421 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
);
2422 bool bIsMerged
= false;
2424 if ( nX
==nX1
&& pInfo
->bHOverlapped
&& !pInfo
->bVOverlapped
)
2426 // find start of merged cell
2428 SCROW nY
= pRowInfo
[nArrY
].nRowNo
;
2431 mpDoc
->ExtendOverlapped( nMergeX
, nMergeY
, nX
, nY
, nTab
);
2434 std::shared_ptr
<sc::Sparkline
> pSparkline
;
2435 ScAddress
aCurrentAddress(nX
, pRowInfo
[nArrY
].nRowNo
, nTab
);
2437 if (!mpDoc
->ColHidden(nX
, nTab
) && (pSparkline
= mpDoc
->GetSparkline(aCurrentAddress
))
2438 && (bIsMerged
|| (!pInfo
->bHOverlapped
&& !pInfo
->bVOverlapped
)))
2440 const tools::Long nWidth
= pRowInfo
[0].basicCellInfo(nX
).nWidth
;
2441 const tools::Long nHeight
= pThisRowInfo
->nHeight
;
2443 Point
aPoint(nPosX
, nPosY
);
2444 Size
aSize(nWidth
, nHeight
);
2446 sc::SparklineRenderer
renderer(*mpDoc
);
2447 renderer
.render(pSparkline
, rRenderContext
, tools::Rectangle(aPoint
, aSize
), nOneX
, nOneY
, double(aZoomX
), double(aZoomY
));
2450 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2453 nPosY
+= pThisRowInfo
->nHeight
;
2458 //TODO: moggi Need to check if this can't be written simpler
2459 void ScOutputData::DrawNoteMarks(vcl::RenderContext
& rRenderContext
)
2461 // cool#6911 draw the note indicator browser-side instead
2462 if (comphelper::LibreOfficeKit::isActive())
2465 tools::Long nInitPosX
= nScrX
;
2467 nInitPosX
+= nMirrorW
- 1; // always in pixels
2468 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2470 tools::Long nPosY
= nScrY
- 1;
2471 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
2473 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
2474 if ( pThisRowInfo
->bChanged
)
2476 tools::Long nPosX
= nInitPosX
;
2477 for (SCCOL nX
=nX1
; nX
<=nX2
; nX
++)
2479 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
);
2480 bool bIsMerged
= false;
2482 if ( nX
==nX1
&& pInfo
->bHOverlapped
&& !pInfo
->bVOverlapped
)
2484 // find start of merged cell
2486 SCROW nY
= pRowInfo
[nArrY
].nRowNo
;
2489 mpDoc
->ExtendOverlapped( nMergeX
, nMergeY
, nX
, nY
, nTab
);
2492 if (!mpDoc
->ColHidden(nX
, nTab
) && mpDoc
->GetNote(nX
, pRowInfo
[nArrY
].nRowNo
, nTab
)
2493 && (bIsMerged
|| (!pInfo
->bHOverlapped
&& !pInfo
->bVOverlapped
)))
2495 ScModule
* mod
= ScModule::get();
2496 rRenderContext
.SetLineColor(mod
->GetColorConfig().GetColorValue(svtools::CALCGRID
).nColor
);
2498 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2499 if ( mbUseStyleColor
&& rStyleSettings
.GetHighContrastMode() )
2500 rRenderContext
.SetFillColor( mod
->GetColorConfig().GetColorValue(svtools::FONTCOLOR
).nColor
);
2502 rRenderContext
.SetFillColor( mod
->GetColorConfig().GetColorValue(svtools::CALCCOMMENTS
).nColor
);
2504 tools::Long nMarkX
= nPosX
+ ( pRowInfo
[0].basicCellInfo(nX
).nWidth
- 1) * nLayoutSign
;
2505 if ( bIsMerged
|| pInfo
->bMerged
)
2507 // if merged, add widths of all cells
2508 SCCOL nNextX
= nX
+ 1;
2509 while ( nNextX
<= nX2
+ 1 && pThisRowInfo
->cellInfo(nNextX
).bHOverlapped
)
2511 nMarkX
+= pRowInfo
[0].basicCellInfo(nNextX
).nWidth
* nLayoutSign
;
2515 // DPI/ZOOM 100/100 => 6, 100/50 => 4.5, 100/150 => 7.5
2516 // DPI/ZOOM 150/100 => 7.5, 150/50 => 6, 150/150 => 9
2517 sal_Int16 nSize
= officecfg::Office::Calc::Content::Display::NoteIndicator::get();
2520 const double fSize(rRenderContext
.GetDPIScaleFactor() * aZoomX
* 3 + 3);
2521 nSize
= static_cast<sal_Int16
>(fSize
);
2524 aPoints
[0] = Point(nMarkX
, nPosY
);
2525 aPoints
[0].setX( bLayoutRTL
? aPoints
[0].X() + nSize
: aPoints
[0].X() - nSize
);
2526 aPoints
[1] = Point(nMarkX
, nPosY
);
2527 aPoints
[2] = Point(nMarkX
, nPosY
+ nSize
);
2528 tools::Polygon
aPoly(3, aPoints
);
2530 if ( bLayoutRTL
? ( nMarkX
>= 0 ) : ( nMarkX
< nScrX
+nScrW
) )
2531 rRenderContext
.DrawPolygon(aPoly
);
2534 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2537 nPosY
+= pThisRowInfo
->nHeight
;
2541 void ScOutputData::DrawFormulaMarks(vcl::RenderContext
& rRenderContext
)
2545 tools::Long nInitPosX
= nScrX
;
2547 nInitPosX
+= nMirrorW
- 1; // always in pixels
2548 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2550 tools::Long nPosY
= nScrY
;
2551 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
2553 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
2554 if ( pThisRowInfo
->bChanged
)
2556 tools::Long nPosX
= nInitPosX
;
2557 for (SCCOL nX
=nX1
; nX
<=nX2
; nX
++)
2559 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
);
2560 if (!mpDoc
->ColHidden(nX
, nTab
) && !mpDoc
->GetFormula(nX
, pRowInfo
[nArrY
].nRowNo
, nTab
).isEmpty()
2561 && (!pInfo
->bHOverlapped
&& !pInfo
->bVOverlapped
))
2565 rRenderContext
.SetLineColor(COL_WHITE
);
2567 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2568 if ( mbUseStyleColor
&& rStyleSettings
.GetHighContrastMode() )
2569 rRenderContext
.SetFillColor( ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR
).nColor
);
2571 rRenderContext
.SetFillColor(COL_LIGHTBLUE
);
2576 tools::Long nMarkX
= nPosX
;
2577 tools::Long nMarkY
= nPosY
+ pThisRowInfo
->nHeight
- 2;
2578 if ( pInfo
->bMerged
)
2580 for (SCSIZE nNextY
=nArrY
+1; nNextY
+1<nArrCount
; nNextY
++)
2583 if (pRowInfo
[nNextY
+ 1].nRowNo
== (pRowInfo
[nNextY
].nRowNo
+ 1)) {
2584 bVOver
= pRowInfo
[nNextY
].cellInfo(nX
).bVOverlapped
;
2586 bVOver
= mpDoc
->GetAttr(nX
,nNextY
,nTab
,ATTR_MERGE_FLAG
)->IsVerOverlapped();
2589 nMarkY
+= pRowInfo
[nNextY
].nHeight
;
2592 // DPI/ZOOM 100/100 => 10, 100/50 => 7, 100/150 => 13
2593 // DPI/ZOOM 150/100 => 13, 150/50 => 8.5, 150/150 => 17.5
2594 const double nSize( rRenderContext
.GetDPIScaleFactor() * aZoomX
* 6 + 4);
2596 aPoints
[0] = Point(nMarkX
, nMarkY
);
2597 aPoints
[0].setX( bLayoutRTL
? aPoints
[0].X() - nSize
: aPoints
[0].X() + nSize
);
2598 aPoints
[1] = Point(nMarkX
, nMarkY
);
2599 aPoints
[2] = Point(nMarkX
, nMarkY
- nSize
);
2600 tools::Polygon
aPoly(3, aPoints
);
2602 if ( bLayoutRTL
? ( nMarkX
>= 0 ) : ( nMarkX
< nScrX
+nScrW
) )
2603 rRenderContext
.DrawPolygon(aPoly
);
2606 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2609 nPosY
+= pThisRowInfo
->nHeight
;
2613 void ScOutputData::AddPDFNotes()
2615 vcl::PDFExtOutDevData
* pPDFData
= dynamic_cast< vcl::PDFExtOutDevData
* >( mpDev
->GetExtOutDevData() );
2616 if ( !pPDFData
|| !pPDFData
->GetIsExportNotes() )
2619 tools::Long nInitPosX
= nScrX
;
2622 Size aOnePixel
= mpDev
->PixelToLogic(Size(1,1));
2623 tools::Long nOneX
= aOnePixel
.Width();
2624 nInitPosX
+= nMirrorW
- nOneX
;
2626 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2628 tools::Long nPosY
= nScrY
;
2629 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
2631 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
2632 if ( pThisRowInfo
->bChanged
)
2634 tools::Long nPosX
= nInitPosX
;
2635 for (SCCOL nX
=nX1
; nX
<=nX2
; nX
++)
2637 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
);
2638 bool bIsMerged
= false;
2639 SCROW nY
= pRowInfo
[nArrY
].nRowNo
;
2643 if ( nX
==nX1
&& pInfo
->bHOverlapped
&& !pInfo
->bVOverlapped
)
2645 // find start of merged cell
2647 mpDoc
->ExtendOverlapped( nMergeX
, nMergeY
, nX
, nY
, nTab
);
2648 // use origin's pCell for NotePtr test below
2651 ScPostIt
* pNote
= mpDoc
->GetNote(nMergeX
, nMergeY
, nTab
);
2653 if ( pNote
&& ( bIsMerged
|| ( !pInfo
->bHOverlapped
&& !pInfo
->bVOverlapped
) ) )
2655 tools::Long nNoteWidth
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* mnPPTX
);
2656 tools::Long nNoteHeight
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* mnPPTY
);
2658 tools::Long nMarkX
= nPosX
+ ( pRowInfo
[0].basicCellInfo(nX
).nWidth
- nNoteWidth
) * nLayoutSign
;
2659 if ( bIsMerged
|| pInfo
->bMerged
)
2661 // if merged, add widths of all cells
2662 SCCOL nNextX
= nX
+ 1;
2663 while ( nNextX
<= nX2
+ 1 && pThisRowInfo
->cellInfo(nNextX
).bHOverlapped
)
2665 nMarkX
+= pRowInfo
[0].basicCellInfo(nNextX
).nWidth
* nLayoutSign
;
2669 if ( bLayoutRTL
? ( nMarkX
>= 0 ) : ( nMarkX
< nScrX
+nScrW
) )
2671 tools::Rectangle
aNoteRect( nMarkX
, nPosY
, nMarkX
+nNoteWidth
*nLayoutSign
, nPosY
+nNoteHeight
);
2673 vcl::pdf::PDFNote aNote
;
2675 // Note title is the cell address (as on printed note pages)
2676 ScAddress
aAddress( nMergeX
, nMergeY
, nTab
);
2677 aNote
.maTitle
= aAddress
.Format(ScRefFlags::VALID
, mpDoc
, mpDoc
->GetAddressConvention());
2679 // Content has to be a simple string without line breaks
2680 OUString aContent
= pNote
->GetText();
2681 aNote
.maContents
= aContent
.replaceAll("\n", " ");
2683 // If the caption is hidden, we need to show it to get its rectangle,
2684 // then hide it again because it is also hidden in the file.
2685 bool bShowCaption
= pNote
->IsCaptionShown();
2687 pNote
->ShowCaption(aAddress
, true);
2689 SdrCaptionObj
* pCaption
= pNote
->GetCaption();
2690 tools::Rectangle
aCaptionRect(pCaption
->GetLogicRect());
2691 Point
aPoint(aCaptionRect
.getX() + nScrX
, aCaptionRect
.getY() + nScrY
);
2692 Size
aSize(aCaptionRect
.GetWidth(), aCaptionRect
.GetHeight());
2693 tools::Rectangle
aPopupRect(aPoint
, aSize
);
2696 pNote
->ShowCaption(aAddress
, false);
2698 pPDFData
->CreateNote(aNoteRect
, aNote
, aPopupRect
);
2702 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2705 nPosY
+= pThisRowInfo
->nHeight
;
2709 void ScOutputData::DrawClipMarks()
2714 ScModule
* mod
= ScModule::get();
2715 Color
aArrowFillCol(mod
->GetColorConfig().GetColorValue(svtools::CALCTEXTOVERFLOW
).nColor
);
2716 const bool bIsDarkBackground
= mod
->GetColorConfig().GetColorValue(svtools::DOCCOLOR
).nColor
.IsDark();
2718 DrawModeFlags nOldDrawMode
= mpDev
->GetDrawMode();
2720 tools::Long nInitPosX
= nScrX
;
2722 nInitPosX
+= nMirrorW
- 1; // always in pixels
2723 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2725 tools::Rectangle aCellRect
;
2726 tools::Long nPosY
= nScrY
;
2727 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
2729 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
2730 if ( pThisRowInfo
->bChanged
)
2732 SCROW nY
= pThisRowInfo
->nRowNo
;
2733 tools::Long nPosX
= nInitPosX
;
2734 for (SCCOL nX
=nX1
; nX
<=nX2
; nX
++)
2736 ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
);
2737 if (pInfo
->nClipMark
!= ScClipMark::NONE
)
2739 if (pInfo
->bHOverlapped
|| pInfo
->bVOverlapped
)
2741 // merge origin may be outside of visible area - use document functions
2745 tools::Long nStartPosX
= nPosX
;
2746 tools::Long nStartPosY
= nPosY
;
2748 while ( nOverX
> 0 && ( mpDoc
->GetAttr(
2749 nOverX
, nOverY
, nTab
, ATTR_MERGE_FLAG
)->GetValue() & ScMF::Hor
) )
2752 nStartPosX
-= nLayoutSign
* static_cast<tools::Long
>( mpDoc
->GetColWidth(nOverX
,nTab
) * mnPPTX
);
2755 while ( nOverY
> 0 && ( mpDoc
->GetAttr(
2756 nOverX
, nOverY
, nTab
, ATTR_MERGE_FLAG
)->GetValue() & ScMF::Ver
) )
2759 nStartPosY
-= nLayoutSign
* static_cast<tools::Long
>( mpDoc
->GetRowHeight(nOverY
,nTab
) * mnPPTY
);
2762 tools::Long nOutWidth
= static_cast<tools::Long
>( mpDoc
->GetColWidth(nOverX
,nTab
) * mnPPTX
);
2763 tools::Long nOutHeight
= static_cast<tools::Long
>( mpDoc
->GetRowHeight(nOverY
,nTab
) * mnPPTY
);
2765 const ScMergeAttr
* pMerge
= mpDoc
->GetAttr( nOverX
, nOverY
, nTab
, ATTR_MERGE
);
2766 SCCOL nCountX
= pMerge
->GetColMerge();
2767 for (SCCOL i
=1; i
<nCountX
; i
++)
2768 nOutWidth
+= mpDoc
->GetColWidth(nOverX
+i
,nTab
) * mnPPTX
;
2769 SCROW nCountY
= pMerge
->GetRowMerge();
2770 nOutHeight
+= mpDoc
->GetScaledRowHeight( nOverY
+1, nOverY
+nCountY
-1, nTab
, mnPPTY
);
2773 nStartPosX
-= nOutWidth
- 1;
2774 aCellRect
= tools::Rectangle( Point( nStartPosX
, nStartPosY
), Size( nOutWidth
, nOutHeight
) );
2778 tools::Long nOutWidth
= pRowInfo
[0].basicCellInfo(nX
).nWidth
;
2779 tools::Long nOutHeight
= pThisRowInfo
->nHeight
;
2781 if ( pInfo
->bMerged
&& pInfo
->pPatternAttr
)
2785 const ScMergeAttr
* pMerge
=
2786 &pInfo
->pPatternAttr
->GetItem(ATTR_MERGE
);
2787 SCCOL nCountX
= pMerge
->GetColMerge();
2788 for (SCCOL i
=1; i
<nCountX
; i
++)
2789 nOutWidth
+= mpDoc
->GetColWidth(nOverX
+i
,nTab
) * mnPPTX
;
2790 SCROW nCountY
= pMerge
->GetRowMerge();
2791 nOutHeight
+= mpDoc
->GetScaledRowHeight( nOverY
+1, nOverY
+nCountY
-1, nTab
, mnPPTY
);
2794 tools::Long nStartPosX
= nPosX
;
2796 nStartPosX
-= nOutWidth
- 1;
2797 // #i80447# create aCellRect from two points in case nOutWidth is 0
2798 aCellRect
= tools::Rectangle( Point( nStartPosX
, nPosY
),
2799 Point( nStartPosX
+nOutWidth
-1, nPosY
+nOutHeight
-1 ) );
2802 aCellRect
.AdjustBottom( -1 ); // don't paint over the cell grid
2804 aCellRect
.AdjustLeft(1 );
2806 aCellRect
.AdjustRight( -1 );
2808 tools::Long nMarkPixel
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* mnPPTX
);
2809 Size
aMarkSize( nMarkPixel
, (nMarkPixel
-1)*2 );
2811 const Color aColor
= pInfo
->maBackground
?
2812 static_cast<const SvxBrushItem
*>(pInfo
->maBackground
.getItem())->GetColor() :
2814 if ( aColor
== COL_AUTO
? bIsDarkBackground
: aColor
.IsDark() )
2815 mpDev
->SetDrawMode( nOldDrawMode
| DrawModeFlags::WhiteLine
);
2817 mpDev
->SetDrawMode( nOldDrawMode
| DrawModeFlags::BlackLine
);
2821 if (pInfo
->nClipMark
& (bLayoutRTL
? ScClipMark::Bottom
: ScClipMark::Top
))
2824 tools::Rectangle aMarkRect
= aCellRect
;
2825 aMarkRect
.SetBottom(aCellRect
.Top() + nMarkPixel
- 1);
2826 SvxFont::DrawArrow(*mpDev
, aMarkRect
, aMarkSize
, aArrowFillCol
, true, true);
2828 if (pInfo
->nClipMark
& (bLayoutRTL
? ScClipMark::Top
: ScClipMark::Bottom
))
2831 tools::Rectangle aMarkRect
= aCellRect
;
2832 aMarkRect
.SetTop(aCellRect
.Bottom() + nMarkPixel
+ 1);
2833 SvxFont::DrawArrow(*mpDev
, aMarkRect
, aMarkSize
, aArrowFillCol
, false,
2839 if (pInfo
->nClipMark
& (bLayoutRTL
? ScClipMark::Right
: ScClipMark::Left
))
2842 tools::Rectangle aMarkRect
= aCellRect
;
2843 aMarkRect
.SetRight(aCellRect
.Left() + nMarkPixel
- 1);
2844 SvxFont::DrawArrow(*mpDev
, aMarkRect
, aMarkSize
, aArrowFillCol
, true,
2847 if (pInfo
->nClipMark
& (bLayoutRTL
? ScClipMark::Left
: ScClipMark::Right
))
2850 tools::Rectangle aMarkRect
= aCellRect
;
2851 aMarkRect
.SetLeft(aCellRect
.Right() - nMarkPixel
+ 1);
2852 SvxFont::DrawArrow(*mpDev
, aMarkRect
, aMarkSize
, aArrowFillCol
, false,
2857 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2860 nPosY
+= pThisRowInfo
->nHeight
;
2863 mpDev
->SetDrawMode(nOldDrawMode
);
2866 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */