tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / view / output.cxx
blobddf3dd5e0b789b9da59244c08115d8ebd2022995
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 <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>
46 #include <output.hxx>
47 #include <document.hxx>
48 #include <drwlayer.hxx>
49 #include <formulacell.hxx>
50 #include <attrib.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>
59 #include <scmod.hxx>
60 #include <appoptio.hxx>
61 #include <postit.hxx>
62 #include <validat.hxx>
63 #include <detfunc.hxx>
64 #include <editutil.hxx>
66 #include <SparklineRenderer.hxx>
67 #include <colorscale.hxx>
69 #include <math.h>
70 #include <memory>
72 using namespace com::sun::star;
74 // Static Data
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() ),
90 nLastUserIndex( 0 ),
91 nColor( COL_BLACK )
95 void ScActionColorChanger::Update( const ScChangeAction& rAction )
97 Color nSetColor;
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();
104 break;
105 case SC_CAT_DELETE_COLS:
106 case SC_CAT_DELETE_ROWS:
107 case SC_CAT_DELETE_TABS:
108 nSetColor = rOpt.GetTrackDeleteColor();
109 break;
110 case SC_CAT_MOVE:
111 nSetColor = rOpt.GetTrackMoveColor();
112 break;
113 default:
114 nSetColor = rOpt.GetTrackContentColor();
115 break;
117 if ( nSetColor != COL_TRANSPARENT ) // color assigned
118 nColor = nSetColor;
119 else // by author
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" );
129 nLastUserIndex = 0;
131 else
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 ),
148 mpDev( 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 ),
154 mpDoc( pNewDoc ),
155 nTab( nNewTab ),
156 nScrX( nNewScrX ),
157 nScrY( nNewScrY ),
158 nX1( nNewX1 ),
159 nY1( nNewY1 ),
160 nX2( nNewX2 ),
161 nY2( nNewY2 ),
162 eType( eNewType ),
163 mnPPTX( nPixelPerTwipsX ),
164 mnPPTY( nPixelPerTwipsY ),
165 pViewShell( nullptr ),
166 pDrawView( nullptr ),
167 bEditMode( false ),
168 nEditCol( 0 ),
169 nEditRow( 0 ),
170 bMetaFile( false ),
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.
181 bSnapPixel( false ),
182 bAnyClipped( false ),
183 bVertical(false),
184 mpTargetPaintWindow(nullptr), // #i74769# use SdrPaintWindow direct
185 mpSpellCheckCxt(nullptr)
187 if (pZoomX)
188 aZoomX = *pZoomX;
189 else
190 aZoomX = Fraction(1,1);
191 if (pZoomY)
192 aZoomY = *pZoomY;
193 else
194 aZoomY = Fraction(1,1);
196 nVisX1 = nX1;
197 nVisY1 = nY1;
198 nVisX2 = nX2;
199 nVisY2 = nY2;
200 mpDoc->StripHidden( nVisX1, nVisY1, nVisX2, nVisY2, nTab );
202 nScrW = 0;
203 for (SCCOL nX=nVisX1; nX<=nVisX2; nX++)
204 nScrW += pRowInfo[0].basicCellInfo(nX).nWidth;
206 nMirrorW = nScrW;
208 nScrH = 0;
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
216 SetCellRotations();
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;
237 mpDev = pContentDev;
240 void ScOutputData::SetMirrorWidth( tools::Long nNew )
242 nMirrorW = nNew;
245 void ScOutputData::SetGridColor( const Color& rColor )
247 aGridColor = rColor;
250 void ScOutputData::SetMarkClipped( bool bSet )
252 bMarkClipped = 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()
274 bSnapPixel = true;
277 void ScOutputData::SetEditCell( SCCOL nCol, SCROW nRow )
279 nEditCol = nCol;
280 nEditRow = nRow;
281 bEditMode = true;
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());
305 if (pPDF)
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);
313 bReopenTag = true;
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);
322 bReopenTag = true;
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);
332 bReopenTag = true;
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);
343 bReopenTag = true;
348 return bReopenTag;
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.
356 SCCOL nX;
357 SCROW nY;
358 tools::Long nPosX;
359 tools::Long nPosY;
360 SCSIZE nArrY;
361 ScBreakType nBreak = ScBreakType::NONE;
362 ScBreakType nBreakOld = ScBreakType::NONE;
364 bool bDashed = false;
365 Color aPageColor;
366 Color aManualColor;
368 if (bPagebreakMode)
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:
375 // * metafile
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;
399 else
401 aPageColor = aGridColor;
402 aManualColor = aGridColor;
405 tools::Long nOneX = 1;
406 tools::Long nOneY = 1;
407 if (!bWorksInPixels)
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);
421 // vertical lines
423 nPosX = nScrX;
424 if ( bLayoutRTL )
425 nPosX += nMirrorW - nOneX;
427 for (nX=nX1; nX<=nX2; nX++)
429 sal_uInt16 nWidth = pRowInfo[0].basicCellInfo(nX).nWidth;
430 if (nWidth)
432 nPosX += nWidth * nLayoutSign;
434 if ( bPage )
436 // Search also in hidden part for page breaks
437 SCCOL nCol = nX + 1;
438 while (nCol <= mpDoc->MaxCol())
440 nBreak = mpDoc->HasColBreak(nCol, nTab);
441 bool bHidden = mpDoc->ColHidden(nCol, nTab);
443 if ( nBreak != ScBreakType::NONE || !bHidden )
444 break;
445 ++nCol;
448 if (nBreak != nBreakOld)
450 aGrid.Flush();
452 if (static_cast<int>(nBreak))
454 rRenderContext.SetLineColor( (nBreak & ScBreakType::Manual) ? aManualColor :
455 aPageColor );
456 bDashed = true;
458 else
460 rRenderContext.SetLineColor(bMergeCover ? aSheetBGColor : aGridColor);
461 bDashed = false;
464 nBreakOld = nBreak;
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)
478 bSingle = true;
479 if (pRowInfo[nArrY].cellInfo(nX).bHideGrid)
480 bSingle = true;
484 if (bDraw)
486 if ( nX<mpDoc->MaxCol() && bSingle )
488 SCCOL nVisX = nX + 1;
489 while ( nVisX < mpDoc->MaxCol() && !mpDoc->GetColWidth(nVisX,nTab) )
490 ++nVisX;
492 nPosY = nScrY;
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;
499 if (!bHOver)
501 if (nWidthXplus1)
502 bHOver = pThisRowInfo->cellInfo(nX+1).bHOverlapped;
503 else
505 if (nVisX <= nX2)
506 bHOver = pThisRowInfo->cellInfo(nVisX).bHOverlapped;
507 else
508 bHOver = mpDoc->GetAttr(
509 nVisX,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG)
510 ->IsHorOverlapped();
511 if (bHOver)
512 bHOver = mpDoc->GetAttr(
513 nX + 1,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG)
514 ->IsHorOverlapped();
518 if ((pThisRowInfo->bChanged && !bHOver && !bMergeCover) || (bHOver && bMergeCover))
520 aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nPosY, nNextY-nOneY, bDashed);
522 nPosY = nNextY;
525 else if (!bMergeCover)
527 aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nScrY, nScrY+nScrH-nOneY, bDashed);
533 // horizontal lines
535 bool bHiddenRow = true;
536 SCROW nHiddenEndRow = -1;
537 nPosY = nScrY;
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)
547 if ( bPage )
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)
562 break;
565 if (nBreakOld != nBreak)
567 aGrid.Flush();
569 if (static_cast<int>(nBreak))
571 rRenderContext.SetLineColor( (nBreak & ScBreakType::Manual) ? aManualColor :
572 aPageColor );
573 bDashed = true;
575 else
577 rRenderContext.SetLineColor(bMergeCover ? aSheetBGColor : aGridColor);
578 bDashed = false;
581 nBreakOld = nBreak;
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)
592 bSingle = true;
595 if (bDraw)
597 if ( bSingle && nY<mpDoc->MaxRow() )
599 SCROW nVisY = pRowInfo[nArrYplus1].nRowNo;
601 nPosX = nScrX;
602 if ( bLayoutRTL )
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
610 bool bVOver;
611 if ( bNextYisNextRow )
612 bVOver = pRowInfo[nArrYplus1].cellInfo(i).bVOverlapped;
613 else
615 bVOver = mpDoc->GetAttr(
616 i,nYplus1,nTab,ATTR_MERGE_FLAG)
617 ->IsVerOverlapped()
618 && mpDoc->GetAttr(
619 i,nVisY,nTab,ATTR_MERGE_FLAG)
620 ->IsVerOverlapped();
621 //! nVisY from Array ??
624 if ((!bVOver && !bMergeCover) || (bVOver && bMergeCover))
626 aGrid.AddHorLine(bWorksInPixels, nPosX, nNextX-nSignedOneX, nPosY-nOneY, bDashed);
629 nPosX = nNextX;
632 else if (!bMergeCover)
634 aGrid.AddHorLine(bWorksInPixels, nScrX, nScrX+nScrW-nOneX, nPosY-nOneY, bDashed);
641 void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
643 bPagebreakMode = true;
644 if (!pPageData)
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()
675 //! save nRotMax
676 SCCOL nRotMax = nX2;
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 );
741 if ( nAttrRotate )
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;
758 else
759 nRet = ScRotateDir::Right;
763 return nRet;
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 )
782 --nCol;
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 )
794 ++nCol;
795 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
796 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
797 pBackground = &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
801 return pBackground;
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 )
809 return false;
811 SCCOL nX;
812 if ( bShowProt )
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) ) )
820 return false;
823 else
825 for ( nX=nX1; nX<=nX2; nX++ )
826 if ( !SfxPoolItem::areSame(rFirst.cellInfo(nX).maBackground.getItem(), rOther.cellInfo(nX).maBackground.getItem() ) )
827 return false;
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 )
833 return false;
835 if ( bPagebreakMode )
836 for ( nX=nX1; nX<=nX2; nX++ )
837 if ( rFirst.cellInfo(nX).bPrinted != rOther.cellInfo(nX).bPrinted )
838 return false;
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) )
845 return false;
847 if (pCol1 && (*pCol1 != *pCol2))
848 return false;
850 const ScDataBarInfo* pInfo1 = rFirst.cellInfo(nX).pDataBar;
851 const ScDataBarInfo* pInfo2 = rOther.cellInfo(nX).pDataBar;
853 if( (pInfo1 && !pInfo2) || (!pInfo1 && pInfo2) )
854 return false;
856 if (pInfo1 && (*pInfo1 != *pInfo2))
857 return false;
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)
864 return false;
867 return true;
870 void ScOutputData::DrawDocumentBackground()
872 if ( !bSolidBackground )
873 return;
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));
885 namespace {
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);
903 else
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) );
920 else
921 return;
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);
931 else
932 aGradient.SetAngle(900_deg10);
934 rRenderContext.DrawGradient(aPaintRect, aGradient);
936 rRenderContext.SetLineColor();
938 else
940 rRenderContext.SetFillColor(pOldDataBarInfo->maColor);
941 rRenderContext.DrawRect(aPaintRect);
944 //draw axis
945 if(!(pOldDataBarInfo->mnZero && pOldDataBarInfo->mnZero != 100))
946 return;
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();
982 else
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 );
1049 if(pColor)
1051 // only update pOldColor if the colors changed
1052 if (!pOldColor || *pOldColor != *pColor)
1053 pOldColor = pColor;
1055 pOldBackground = nullptr;
1057 else if(pBackground)
1059 pOldBackground = pBackground;
1060 pOldColor.reset();
1063 if(pDataBarInfo)
1064 pOldDataBarInfo = pDataBarInfo;
1065 else
1066 pOldDataBarInfo = nullptr;
1068 if(pIconSetInfo)
1069 pOldIconSetInfo = pIconSetInfo;
1070 else
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)
1094 nOneX = nOneXLogic;
1095 nOneY = nOneYLogic;
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 )
1126 // nothing
1128 else
1130 if (bTaggedPDF)
1131 pPDF->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement);
1133 // scan for rows with the same background:
1134 SCSIZE nSkip = 0;
1135 while ( nArrY+nSkip+2<nArrCount &&
1136 lcl_EqualBack( *pThisRowInfo, pRowInfo[nArrY+nSkip+1],
1137 nX1, nX2, bShowProt, bPagebreakMode ) )
1139 ++nSkip;
1140 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
1143 tools::Long nPosX = nScrX;
1145 if ( bLayoutRTL )
1146 nPosX += nMirrorW - nOneX;
1148 aRect = tools::Rectangle(nPosX, nPosY - nOneY, nPosX, nPosY - nOneY + nRowHeight);
1149 if (bWorksInPixels)
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
1168 nMergedCols = 1;
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;
1179 if (nCol > nX2+2)
1180 break;
1181 nNewPosX += pRowInfo[0].basicCellInfo(nCol-1).nWidth * nLayoutSign;
1184 if (nNewPosX == nPosX)
1185 continue; // Zero width, no need to draw.
1187 if (bCellContrast)
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;
1195 if (pP)
1197 const ScProtectionAttr& rProt = pP->GetItem(ATTR_PROTECTION);
1198 if (rProt.GetProtection() || rProt.GetHideCell())
1199 pBackground = pProtectedBackground.get();
1200 else
1201 pBackground = ScGlobal::GetEmptyBrushItem();
1203 else
1204 pBackground = nullptr;
1206 else
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() &&
1214 !bCellContrast )
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;
1225 if (bWorksInPixels)
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());
1230 nPosX = nNewPosX;
1233 tools::Long nPosXLogic = nPosX;
1234 if (bWorksInPixels)
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());
1239 nArrY += nSkip;
1241 if (bTaggedPDF)
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;
1268 if ( bLayoutRTL )
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 )
1300 if (bTaggedPDF)
1301 pPDF->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement);
1303 ScShadowPart ePart = nPass ?
1304 pThisRowInfo->cellInfo(nCol).eVShadowPart :
1305 pThisRowInfo->cellInfo(nCol).eHShadowPart;
1307 bool bDo = true;
1308 if ( (nPass==0 && bCornerX) || (nPass==1 && bCornerY) )
1309 if ( ePart != SC_SHADOW_CORNER )
1310 bDo = false;
1312 if (bDo)
1314 tools::Long nThisWidth = pRowInfo[0].basicCellInfo(nCol).nWidth;
1315 tools::Long nMaxWidth = nThisWidth;
1316 if (!nMaxWidth)
1318 //! direction must depend on shadow location
1319 SCCOL nWx = nCol+1;
1320 while (nWx<nX2 && !pRowInfo[0].basicCellInfo(nWx).nWidth)
1321 ++nWx;
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();
1339 if ( bLayoutRTL )
1341 // Shadow location is specified as "visual" (right is always right),
1342 // so the attribute's location value is mirrored here and in FillInfo.
1343 switch (eLoc)
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;
1349 default:
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 );
1361 else
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 );
1369 else
1370 aRect.SetRight( aRect.Left() + nSizeX );
1372 if (ePart == SC_SHADOW_HSTART)
1374 if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::BottomLeft)
1375 aRect.AdjustRight( -nSizeX );
1376 else
1377 aRect.AdjustLeft(nSizeX );
1379 if (ePart == SC_SHADOW_VSTART)
1381 if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::TopRight)
1382 aRect.AdjustBottom( -nSizeY );
1383 else
1384 aRect.AdjustTop(nSizeY );
1387 //! merge rectangles?
1388 mpDev->SetFillColor( bCellContrast ? aAutoTextColor : pAttr->GetColor() );
1389 mpDev->DrawRect( aRect );
1391 if (bTaggedPDF)
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);
1414 if (bMetaFile)
1415 nOneX = nOneY = 0;
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:
1430 SCSIZE nSkip = 0;
1431 while ( nArrY+nSkip+2<nArrCount && pRowInfo[nArrY+nSkip+1].bChanged )
1433 ++nSkip;
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 );
1441 nArrY += nSkip;
1443 nPosY += nRowHeight;
1447 // Lines
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();
1463 if (bTaggedPDF)
1464 pPDF->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement);
1466 DrawModeFlags nOldDrawMode = rRenderContext.GetDrawMode();
1468 Color aSingleColor;
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;
1504 if ( bLayoutRTL )
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();
1518 // row heights
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;
1534 // column widths
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
1541 if( !bLayoutRTL )
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;
1552 if( bLayoutRTL )
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());
1568 if (!pProcessor)
1569 return;
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);
1580 nRow1 = nRow2 + 1;
1583 pProcessor.reset();
1585 rRenderContext.SetDrawMode(nOldDrawMode);
1587 if (bTaggedPDF)
1588 pPDF->EndStructureElement();
1591 void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext)
1593 //! save nRotMax
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;
1606 if ( bLayoutRTL )
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) );
1615 if (bMetaFile)
1617 rRenderContext.Push();
1618 rRenderContext.IntersectClipRegion( aClipRect );
1620 else
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;
1640 SCCOL nX;
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;
1652 if (!pPattern)
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();
1666 if (nAttrRotate)
1668 if (nX < nX1) // compute negative position
1670 nPosX = nInitPosX;
1671 SCCOL nCol = nX1;
1672 while (nCol > nX)
1674 --nCol;
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);
1694 //! restrict !!!
1695 tools::Long nSkew = static_cast<tools::Long>(nRowHeight * nCos / nSin);
1697 switch (eRotMode)
1699 case SVX_ROTATE_MODE_BOTTOM:
1700 nTopLeft += nSkew;
1701 nTopRight += nSkew;
1702 break;
1703 case SVX_ROTATE_MODE_CENTER:
1704 nSkew /= 2;
1705 nTopLeft += nSkew;
1706 nTopRight += nSkew;
1707 nBotLeft -= nSkew;
1708 nBotRight -= nSkew;
1709 break;
1710 case SVX_ROTATE_MODE_TOP:
1711 nBotLeft -= nSkew;
1712 nBotRight -= nSkew;
1713 break;
1714 default:
1716 // added to avoid warnings
1720 Point aPoints[4];
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()));
1727 if (!pBackground)
1728 pBackground = &pPattern->GetItem(ATTR_BACKGROUND, pCondSet);
1729 if (bCellContrast)
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);
1752 else
1753 rRenderContext.SetLineColor();
1754 rRenderContext.SetFillColor(rColor);
1755 rRenderContext.DrawPolygon(aPoly);
1759 else
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);
1768 else
1769 rRenderContext.SetLineColor();
1770 rRenderContext.SetFillColor(*pColor);
1771 rRenderContext.DrawPolygon(aPoly);
1776 nPosX += nColWidth * nLayoutSign;
1779 nPosY += nRowHeight;
1782 pProcessor.reset();
1784 if (bMetaFile)
1785 rRenderContext.Pop();
1786 else
1787 rRenderContext.SetClipRegion();
1790 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> ScOutputData::CreateProcessor2D( )
1792 mpDoc->InitDrawLayer(mpDoc->GetDocumentShell());
1793 ScDrawLayer* pDrawLayer = mpDoc->GetDrawLayer();
1794 if (!pDrawLayer)
1795 return nullptr;
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 );
1808 // Printer
1810 vcl::Region ScOutputData::GetChangedAreaRegion()
1812 vcl::Region aRegion;
1813 tools::Rectangle aDrawingRect;
1814 bool bHad(false);
1815 tools::Long nPosY = nScrY;
1816 SCSIZE nArrY;
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)
1827 if(!bHad)
1829 aDrawingRect.SetTop( nPosY );
1830 bHad = true;
1833 aDrawingRect.SetBottom( nPosY + pRowInfo[nArrY].nHeight - 1 );
1835 else if(bHad)
1837 aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1838 bHad = false;
1841 nPosY += pRowInfo[nArrY].nHeight;
1844 if(bHad)
1846 aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1849 return aRegion;
1852 bool ScOutputData::SetChangedClip()
1854 tools::PolyPolygon aPoly;
1856 tools::Rectangle aDrawingRect;
1857 aDrawingRect.SetLeft( nScrX );
1858 aDrawingRect.SetRight( nScrX+nScrW-1 );
1860 bool bHad = false;
1861 tools::Long nPosY = nScrY;
1862 SCSIZE nArrY;
1863 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1865 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1867 if ( pThisRowInfo->bChanged )
1869 if (!bHad)
1871 aDrawingRect.SetTop( nPosY );
1872 bHad = true;
1874 aDrawingRect.SetBottom( nPosY + pRowInfo[nArrY].nHeight - 1 );
1876 else if (bHad)
1878 aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1879 bHad = false;
1881 nPosY += pRowInfo[nArrY].nHeight;
1884 if (bHad)
1885 aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1887 bool bRet = (aPoly.Count() != 0);
1888 if (bRet)
1889 mpDev->SetClipRegion(vcl::Region(aPoly));
1890 return bRet;
1893 void ScOutputData::FindChanged()
1895 SCCOL nX;
1896 SCSIZE nArrY;
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)
1916 continue;
1918 ScFormulaCell* pFCell = rCell.getFormula();
1919 if (pFCell->IsRunning())
1920 // still being interpreted. Skip it.
1921 continue;
1923 bool bDirty = pFCell->GetDirty();
1924 bAnyChanged = bAnyChanged || pFCell->IsChanged();
1926 if (bDirty)
1928 if (!bAnyDirty)
1930 ScProgress::CreateInterpretProgress(mpDoc);
1931 bAnyDirty = true;
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());
1942 if (pData)
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)
1954 if (bAnyDirty)
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)
1965 continue;
1967 ScFormulaCell* pFCell = rCell.getFormula();
1968 if (pFCell->IsRunning())
1969 // still being interpreted. Skip it.
1970 continue;
1972 if (!pFCell->IsChanged())
1973 // the result hasn't changed. Skip it.
1974 continue;
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;
1984 ++nOverY;
1990 if (bAnyDirty)
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;
2015 if ( bLayoutRTL )
2016 std::swap( nMinX, nMaxX );
2017 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
2019 bool bTop = false;
2020 bool bBottom = false;
2021 bool bLeft = 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) )
2033 nMinY = nPosY;
2034 bTop = true;
2036 if ( nY==nRefEndY )
2038 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
2039 bBottom = true;
2041 if ( nY>nRefEndY && bNoEndY )
2043 nMaxY = nPosY-2;
2044 bBottom = true;
2046 bNoStartY = ( nY < nRefStartY );
2047 bNoEndY = ( nY < nRefEndY );
2048 nPosY += pRowInfo[nArrY].nHeight;
2051 tools::Long nPosX = nScrX;
2052 if ( bLayoutRTL )
2053 nPosX += nMirrorW - 1; // always in pixels
2055 for (SCCOL nX=nX1; nX<=nX2; nX++)
2057 if ( nX==nRefStartX )
2059 nMinX = nPosX;
2060 bLeft = true;
2062 if ( nX==nRefEndX )
2064 nMaxX = nPosX + ( pRowInfo[0].basicCellInfo(nX).nWidth - 2 ) * nLayoutSign;
2065 bRight = true;
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,
2074 nMinY / mnPPTY,
2075 ( nMaxX - nMinX ) / mnPPTX,
2076 ( nMaxY - nMinY ) / mnPPTY,
2077 nTab,
2078 rColor );
2082 return aResult;
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) )
2099 return;
2101 tools::Long nMinX = nScrX;
2102 tools::Long nMinY = nScrY;
2103 tools::Long nMaxX = nScrX + nScrW - 1;
2104 tools::Long nMaxY = nScrY + nScrH - 1;
2105 if ( bLayoutRTL )
2106 std::swap( nMinX, nMaxX );
2107 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
2109 bool bTop = false;
2110 bool bBottom = false;
2111 bool bLeft = 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) )
2123 nMinY = nPosY;
2124 bTop = true;
2126 if ( nY==nRefEndY )
2128 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
2129 bBottom = true;
2131 if ( nY>nRefEndY && bNoEndY )
2133 nMaxY = nPosY-2;
2134 bBottom = true;
2136 bNoStartY = ( nY < nRefStartY );
2137 bNoEndY = ( nY < nRefEndY );
2138 nPosY += pRowInfo[nArrY].nHeight;
2141 tools::Long nPosX = nScrX;
2142 if ( bLayoutRTL )
2143 nPosX += nMirrorW - 1; // always in pixels
2145 for (SCCOL nX=nX1; nX<=nX2; nX++)
2147 if ( nX==nRefStartX )
2149 nMinX = nPosX;
2150 bLeft = true;
2152 if ( nX==nRefEndX )
2154 nMaxX = nPosX + ( pRowInfo[0].basicCellInfo(nX).nWidth - 2 ) * nLayoutSign;
2155 bRight = true;
2157 nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2160 if ( nMaxX * nLayoutSign < nMinX * nLayoutSign || nMaxY < nMinY )
2161 return;
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() )
2171 if (bTop)
2172 mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMaxX, nMinY ) );
2173 if (bBottom)
2174 mpDev->DrawLine( Point( nMinX, nMaxY ), Point( nMaxX, nMaxY ) );
2175 if (bLeft)
2176 mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMinX, nMaxY ) );
2177 if (bRight)
2178 mpDev->DrawLine( Point( nMaxX, nMinY ), Point( nMaxX, nMaxY ) );
2180 if ( !bHandle || !bRight || !bBottom || comphelper::LibreOfficeKit::isActive() )
2181 return;
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
2222 return;
2224 tools::Long nMinX = nScrX;
2225 tools::Long nMinY = nScrY;
2226 tools::Long nMaxX = nScrX+nScrW-1;
2227 tools::Long nMaxY = nScrY+nScrH-1;
2228 if ( bLayoutRTL )
2229 std::swap( nMinX, nMaxX );
2230 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
2232 bool bTop = false;
2233 bool bBottom = false;
2234 bool bLeft = 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) )
2246 nMinY = nPosY - 1;
2247 bTop = true;
2249 if ( nY==nRefEndY )
2251 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 1;
2252 bBottom = true;
2254 if ( nY>nRefEndY && bNoEndY )
2256 nMaxY = nPosY - 1;
2257 bBottom = true;
2259 bNoStartY = ( nY < nRefStartY );
2260 bNoEndY = ( nY < nRefEndY );
2261 nPosY += pRowInfo[nArrY].nHeight;
2264 tools::Long nPosX = nScrX;
2265 if ( bLayoutRTL )
2266 nPosX += nMirrorW - 1; // always in pixels
2268 for (SCCOL nX=nX1; nX<=nX2+1; nX++)
2270 if ( nX==nRefStartX )
2272 nMinX = nPosX - nLayoutSign;
2273 bLeft = true;
2275 if ( nX==nRefEndX )
2277 nMaxX = nPosX + ( pRowInfo[0].basicCellInfo(nX).nWidth - 1 ) * nLayoutSign;
2278 bRight = true;
2280 nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2283 if ( nMaxX * nLayoutSign < nMinX * nLayoutSign || nMaxY < nMinY )
2284 return;
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 ) );
2297 else
2299 if (bTop)
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 ) );
2305 if (bBottom)
2306 mpDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2307 if (bLeft)
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 ) );
2313 if (bRight)
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 ??!??!?
2336 SCCOL nEndX = nX2;
2337 SCROW nEndY = nY2;
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();
2342 while (pAction)
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)
2403 nOneX = nOneXLogic;
2404 nOneY = nOneYLogic;
2407 tools::Long nInitPosX = nScrX;
2408 if ( bLayoutRTL )
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
2427 bIsMerged = true;
2428 SCROW nY = pRowInfo[nArrY].nRowNo;
2429 SCCOL nMergeX = nX;
2430 SCROW nMergeY = nY;
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())
2463 return;
2465 tools::Long nInitPosX = nScrX;
2466 if ( bLayoutRTL )
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
2485 bIsMerged = true;
2486 SCROW nY = pRowInfo[nArrY].nRowNo;
2487 SCCOL nMergeX = nX;
2488 SCROW nMergeY = nY;
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 );
2501 else
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;
2512 ++nNextX;
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();
2518 if (nSize < 1)
2520 const double fSize(rRenderContext.GetDPIScaleFactor() * aZoomX * 3 + 3);
2521 nSize = static_cast<sal_Int16>(fSize);
2523 Point aPoints[3];
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)
2543 bool bFirst = true;
2545 tools::Long nInitPosX = nScrX;
2546 if ( bLayoutRTL )
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))
2563 if (bFirst)
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 );
2570 else
2571 rRenderContext.SetFillColor(COL_LIGHTBLUE);
2573 bFirst = false;
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++)
2582 bool bVOver;
2583 if (pRowInfo[nNextY + 1].nRowNo == (pRowInfo[nNextY].nRowNo + 1)) {
2584 bVOver = pRowInfo[nNextY].cellInfo(nX).bVOverlapped;
2585 } else {
2586 bVOver = mpDoc->GetAttr(nX,nNextY,nTab,ATTR_MERGE_FLAG)->IsVerOverlapped();
2588 if (!bVOver) break;
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);
2595 Point aPoints[3];
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() )
2617 return;
2619 tools::Long nInitPosX = nScrX;
2620 if ( bLayoutRTL )
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;
2640 SCCOL nMergeX = nX;
2641 SCROW nMergeY = nY;
2643 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2645 // find start of merged cell
2646 bIsMerged = true;
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;
2666 ++nNextX;
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();
2686 if (!bShowCaption)
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);
2695 if (!bShowCaption)
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()
2711 if (!bAnyClipped)
2712 return;
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;
2721 if ( bLayoutRTL )
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
2743 SCCOL nOverX = nX;
2744 SCROW nOverY = nY;
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 ) )
2751 --nOverX;
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 ) )
2758 --nOverY;
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);
2772 if ( bLayoutRTL )
2773 nStartPosX -= nOutWidth - 1;
2774 aCellRect = tools::Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
2776 else
2778 tools::Long nOutWidth = pRowInfo[0].basicCellInfo(nX).nWidth;
2779 tools::Long nOutHeight = pThisRowInfo->nHeight;
2781 if ( pInfo->bMerged && pInfo->pPatternAttr )
2783 SCCOL nOverX = nX;
2784 SCROW nOverY = nY;
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;
2795 if ( bLayoutRTL )
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
2803 if ( bLayoutRTL )
2804 aCellRect.AdjustLeft(1 );
2805 else
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() :
2813 COL_AUTO;
2814 if ( aColor == COL_AUTO ? bIsDarkBackground : aColor.IsDark() )
2815 mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::WhiteLine );
2816 else
2817 mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::BlackLine );
2819 if (bVertical)
2821 if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Bottom : ScClipMark::Top))
2823 // visually 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))
2830 // visually bottom
2831 tools::Rectangle aMarkRect = aCellRect;
2832 aMarkRect.SetTop(aCellRect.Bottom() + nMarkPixel + 1);
2833 SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, false,
2834 true);
2837 else
2839 if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Right : ScClipMark::Left))
2841 // visually left
2842 tools::Rectangle aMarkRect = aCellRect;
2843 aMarkRect.SetRight(aCellRect.Left() + nMarkPixel - 1);
2844 SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, true,
2845 false);
2847 if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Left : ScClipMark::Right))
2849 // visually right
2850 tools::Rectangle aMarkRect = aCellRect;
2851 aMarkRect.SetLeft(aCellRect.Right() - nMarkPixel + 1);
2852 SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, false,
2853 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: */