/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// The header row must be drawn also when the inner rectangle is not visible, // that is why there is no return value anymore. // When it is far away, then lcl_DrawOneFrame is not even called.
}
staticvoid lcl_DrawOneFrame( vcl::RenderContext* pDev, const tools::Rectangle& rInnerPixel, const OUString& rTitle, const Color& rColor, bool bTextBelow, double nPPTX, double nPPTY, const Fraction& rZoomY, const ScDocument& rDoc, ScViewData& rButtonViewData, bool bLayoutRTL )
{ // rButtonViewData is only used to set the button size,
// use ScPatternAttr::GetFont only for font size
vcl::Font aAttrFont;
rDoc.getCellAttributeHelper().getDefaultCellAttribute().fillFontOnly(aAttrFont, pDev, &rZoomY);
// everything else from application font
vcl::Font aAppFont = pDev->GetSettings().GetStyleSettings().GetAppFont();
aAppFont.SetFontSize( aAttrFont.GetFontSize() );
bool ScGridWindow::NeedLOKCursorInvalidation(const tools::Rectangle& rCursorRect, const Fraction aScaleX, const Fraction aScaleY)
{ // Don't see the need for a map as there will be only a few zoom levels // and as of now X and Y zooms in online are the same. for (auto& rEntry : maLOKLastCursor)
{ if (aScaleX == rEntry.aScaleX && aScaleY == rEntry.aScaleY)
{ if (rCursorRect == rEntry.aRect) returnfalse; // No change
void ScGridWindow::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect )
{
ScDocument& rDoc = mrViewData.GetDocument(); if ( rDoc.IsInInterpreter() )
{ // Via Reschedule, interpreted cells do not trigger Invalidate again, // otherwise for instance an error box would never appear (bug 36381). // Later, through bNeedsRepaint everything is painted again. if ( bNeedsRepaint )
{ //! Merge Rectangle?
aRepaintPixel = tools::Rectangle(); // multiple -> paint all
} else
{
bNeedsRepaint = true;
aRepaintPixel = LogicToPixel(rRect); // only affected ranges
} return;
}
// #i117893# If GetSizePixel needs to call the resize handler, the resulting nested Paint call // (possibly for a larger rectangle) has to be allowed. Call GetSizePixel before setting bIsInPaint.
GetSizePixel();
// let's ignore the normal Draw() attempts when doing the tiled rendering, // all the rendering should go through PaintTile() in that case. // TODO revisit if we can actually turn this into an assert(), and clean // up the callers if (comphelper::LibreOfficeKit::isActive()) return;
if ( bTextWysiwyg )
{ // use printer for text formatting
OutputDevice* pFmtDev = rDoc.GetPrinter();
pFmtDev->SetMapMode( mrViewData.GetLogicMode(eWhich) );
aOutputData.SetFmtDevice( pFmtDev );
} elseif ( aZoomX != aZoomY && mrViewData.IsOle() )
{ // #i45033# For OLE inplace editing with different zoom factors, // use a virtual device with 1/100th mm as text formatting reference
// If something was inverted during the Paint (selection changed from Basic Macro) // then this is now mixed up and has to be repainted
OSL_ENSURE(nPaintCount, "Wrong nPaintCount");
--nPaintCount; if (!nPaintCount)
CheckNeedsRepaint();
// Flag drawn formula cells "unchanged".
rDoc.ResetChanged(ScRange(nX1, nY1, nTab, nX2, nY2, nTab));
rDoc.PrepareFormulaCalc();
}
namespace {
class SuppressEditViewMessagesGuard
{ public:
SuppressEditViewMessagesGuard(EditView& rEditView) :
mrEditView(rEditView),
mbOrigSuppressFlag(rEditView.IsSuppressLOKMessages())
{ if (!mbOrigSuppressFlag)
mrEditView.SuppressLOKMessages(true);
}
~SuppressEditViewMessagesGuard()
{ if (mrEditView.IsSuppressLOKMessages() != mbOrigSuppressFlag)
mrEditView.SuppressLOKMessages(mbOrigSuppressFlag);
}
/** * Used to store the necessary information about the (combined-)tile * area relevant to coordinate transformations in RTL mode.
*/ class ScLokRTLContext
{ public:
ScLokRTLContext(const ScOutputData& rOutputData, const tools::Long nTileDeviceOriginPixelX):
mrOutputData(rOutputData),
mnTileDevOriginX(nTileDeviceOriginPixelX)
{}
/** * Converts from document x pixel position to the * corresponding pixel position w.r.t the tile device origin.
*/
tools::Long docToTilePos(tools::Long nPosX) const
{
tools::Long nMirrorX = (-2 * mnTileDevOriginX) + mrOutputData.GetScrW(); return nMirrorX - 1 - nPosX;
}
const svtools::ColorConfig& rColorCfg = pScMod->GetColorConfig();
Color aGridColor( rColorCfg.GetColorValue( svtools::CALCGRID ).nColor ); if ( aGridColor == COL_TRANSPARENT )
{ // use view options' grid color only if color config has "automatic" color
aGridColor = rOpts.GetGridColor();
}
// define drawing layer map mode and paint rectangle
MapMode aDrawMode = GetDrawMapMode(); if (bIsTiledRendering)
{ // FIXME this shouldn't be necessary once we change the entire Calc to // work in the logic coordinates (ideally 100ths of mm - so that it is // the same as editeng and drawinglayer), and get rid of all the // SetMapMode's and other unnecessary fun we have with pixels // See also ScGridWindow::GetDrawMapMode() for the rest of this hack
aDrawMode.SetOrigin(PixelToLogic(Point(nScrX, nScrY), aDrawMode));
}
tools::Rectangle aDrawingRectLogic; bool bLayoutRTL = rDoc.IsLayoutRTL( nTab ); bool bLokRTL = bLayoutRTL && bIsTiledRendering;
std::unique_ptr<ScLokRTLContext> pLokRTLCtxt(
bLokRTL ? new ScLokRTLContext(aOutputData, o3tl::convert(aOriginalMode.GetOrigin().X(), o3tl::Length::twip, o3tl::Length::px)) :
nullptr);
{ // get drawing pixel rect
tools::Rectangle aDrawingRectPixel(
bLokRTL ? Point(-(nScrX + aOutputData.GetScrW()), nScrY) : Point(nScrX, nScrY),
Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
// get logic positions
aDrawingRectLogic = PixelToLogic(aDrawingRectPixel, aDrawMode);
}
bool bInPlaceEditing = bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo());
vcl::Cursor* pInPlaceCrsr = nullptr; bool bInPlaceVisCursor = false; if (bInPlaceEditing)
{ // toggle the cursor off if it's on to ensure the cursor invert // background logic remains valid after the background is cleared on // the next cursor flash
pInPlaceCrsr = pEditView->GetCursor();
bInPlaceVisCursor = pInPlaceCrsr && pInPlaceCrsr->IsVisible(); if (bInPlaceVisCursor)
pInPlaceCrsr->Hide();
}
OutputDevice* pContentDev = &rDevice; // device for document content, used by overlay manager
SdrPaintWindow* pTargetPaintWindow = nullptr; // #i74769# work with SdrPaintWindow directly
if(pDrawView)
{ // #i74769# Use new BeginDrawLayers() interface
vcl::Region aDrawingRegion(aDrawingRectLogic);
pTargetPaintWindow = pDrawView->BeginDrawLayers(pContentDev, aDrawingRegion);
OSL_ENSURE(pTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)");
if (!bIsTiledRendering)
{ // #i74769# get target device from SdrPaintWindow, this may be the prerender // device now, too.
pContentDev = &(pTargetPaintWindow->GetTargetOutputDevice());
aOutputData.SetContentDevice(pContentDev);
}
}
pContentDev->SetMapMode(aCurrentMapMode);
}
}
// app-background / document edge (area) (Pixel) if ( !bIsTiledRendering && ( nX2 == rDoc.MaxCol() || nY2 == rDoc.MaxRow() ) )
{ // save MapMode and set to pixel
MapMode aCurrentMapMode(pContentDev->GetMapMode());
pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
tools::Rectangle aPixRect( Point(), GetOutputSizePixel() );
pContentDev->SetFillColor( rColorCfg.GetColorValue(svtools::APPBACKGROUND).nColor );
pContentDev->SetLineColor(); if ( nX2==rDoc.MaxCol() )
{
tools::Rectangle aDrawRect( aPixRect ); if ( bLayoutRTL )
aDrawRect.SetRight( nScrX - 1 ); else
aDrawRect.SetLeft( nScrX + aOutputData.GetScrW() ); if (aDrawRect.Right() >= aDrawRect.Left())
pContentDev->DrawRect( aDrawRect );
} if ( nY2==rDoc.MaxRow() )
{
tools::Rectangle aDrawRect( aPixRect );
aDrawRect.SetTop( nScrY + aOutputData.GetScrH() ); if ( nX2==rDoc.MaxCol() )
{ // no double painting of the corner if ( bLayoutRTL )
aDrawRect.SetLeft( nScrX ); else
aDrawRect.SetRight( nScrX + aOutputData.GetScrW() - 1 );
} if (aDrawRect.Bottom() >= aDrawRect.Top())
pContentDev->DrawRect( aDrawRect );
}
if (bGridFirst && (bGrid || bPage))
{ // Draw lines in background color cover over lok client grid lines in merged cell areas if bNoBackgroundAndGrid is set. if (bNoBackgroundAndGrid)
aOutputData.DrawGrid(*pContentDev, false/* bGrid */, false /* bPage */, true /* bMergeCover */); else
aOutputData.DrawGrid(*pContentDev, bGrid, bPage);
}
//tdf#128258 - draw a dotted line before hidden columns/rows
DrawHiddenIndicator(nX1,nY1,nX2,nY2, *pContentDev);
if ( bPageMode )
{ // DrawPagePreview draws complete lines/page numbers, must always be clipped if ( aOutputData.SetChangedClip() )
{
DrawPagePreview(nX1,nY1,nX2,nY2, *pContentDev);
pContentDev->SetClipRegion();
}
}
// Show Note Mark if ( rOpts.GetOption( VOPT_NOTES ) )
aOutputData.DrawNoteMarks(*pContentDev);
if ( rOpts.GetOption( VOPT_FORMULAS_MARKS ) )
aOutputData.DrawFormulaMarks(*pContentDev);
if ( !bLogicText )
aOutputData.DrawStrings(); // in pixel MapMode
// edit cells and printer-metrics text must be before the buttons // (DataPilot buttons contain labels in UI font)
pContentDev->SetMapMode(mrViewData.GetLogicMode(eWhich)); if ( bLogicText )
aOutputData.DrawStrings(true); // in logic MapMode if bLogicText is set
aOutputData.DrawEdit(true);
// the buttons are painted in absolute coordinates if (bIsTiledRendering)
{ // Tiled offset nScrX, nScrY
MapMode aMap( MapUnit::MapPixel );
Point aOrigin(o3tl::convert(aOriginalMode.GetOrigin(), o3tl::Length::twip, o3tl::Length::px));
aOrigin.Move(nScrX, nScrY);
aMap.SetOrigin(aOrigin);
pContentDev->SetMapMode(aMap);
} else
pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
if(pDrawView)
{ // #i74769# work with SdrPaintWindow directly
pDrawView->EndDrawLayers(*pTargetPaintWindow, true);
}
pContentDev->SetMapMode(aCurrentMapMode);
}
}
// in place editing - lok case if (bIsTiledRendering)
{
ScTabViewShell* pThisViewShell = mrViewData.GetViewShell();
ViewShellList aCurrentDocViewList = LOKEditViewHistory::GetSortedViewsForDoc(pThisViewShell->GetDocId());
tools::Rectangle aTileRectPx(Point(nScrX, nScrY), Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
for (SfxViewShell* pVS: aCurrentDocViewList)
{ auto pTabViewShell = dynamic_cast<ScTabViewShell*>(pVS); if (!pTabViewShell) continue;
if (!(bOtherEditMode
&& ( nCol2 >= nX1 && nCol1 <= nX2 && nRow2 >= nY1 && nRow1 <= nY2 )
&& rOtherViewData.GetRefTabNo() == nTab)) continue; // only views where in place editing is occurring need to be rendered
EditView* pOtherEditView = rOtherViewData.GetEditView(eOtherWhich); if (!pOtherEditView) continue;
// edit rectangle / background
Point aStart = mrViewData.GetScrPos( nCol1, nRow1, eOtherWhich );
Point aEnd = mrViewData.GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
tools::Rectangle aEditRectPx(aStart, aEnd); if (bLokRTL)
{ // Transform the cell range X coordinates such that the edit cell area is // horizontally mirrored w.r.t the (combined-)tile.
aStart.setX(pLokRTLCtxt->docToTilePos(aStart.X()));
aEnd.setX(pLokRTLCtxt->docToTilePos(aEnd.X()));
}
tools::Rectangle aBackground(aStart, aEnd); if (bLokRTL)
aBackground.Normalize();
tools::Rectangle aBGAbs(aBackground);
// Need to draw the background in absolute coords.
Point aOriginTw = aOriginalMode.GetOrigin();
Point aOriginAbsTw = aOriginTw + o3tl::toTwips(aTileRectPx.GetPos(), o3tl::Length::px);
Point aOriginAbsPx = o3tl::convert(aOriginAbsTw, o3tl::Length::twip, o3tl::Length::px);
aBackground += aOriginAbsPx;
rDevice.SetMapMode(aDrawMode);
// keep into account the zoom factor
Point aNewOrigin(o3tl::convert(aOriginAbsTw, o3tl::Length::twip, o3tl::Length::mm100));
aNewOrigin = aNewOrigin.scale(
aDrawMode.GetScaleX().GetDenominator(), aDrawMode.GetScaleX().GetNumerator(),
aDrawMode.GetScaleY().GetDenominator(), aDrawMode.GetScaleY().GetNumerator());
// paint text const tools::Rectangle aOrigOutputArea(pOtherEditView->GetOutputArea()); // Not in pixels.
tools::Rectangle aNewOutputArea; // compute output area for view with a different zoom level wrt the view used for painting if (!(mrViewData.GetZoomX() == rOtherViewData.GetZoomX() &&
mrViewData.GetZoomY() == rOtherViewData.GetZoomY()))
{
Point aOtherStart = rOtherViewData.GetScrPos( nCol1, nRow1, eOtherWhich );
Point aOtherEnd = rOtherViewData.GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
tools::Rectangle aOtherEditRect(
o3tl::convert(tools::Rectangle(aOtherStart, aOtherEnd), o3tl::Length::px,
aOrigOutputAreaUnit));
aNewOutputArea = tools::Rectangle(sides[0], sides[1], sides[2], sides[3]);
aNewOutputArea += aOriginAbsPx;
} // compute output area for RTL case if (bLokRTL)
{ if (aNewOutputArea.IsEmpty())
{ // same zoom level as view used for painting
aNewOutputArea = rDevice.LogicToPixel(aOrigOutputArea);
} // a small workaround for getting text position matching cursor position horizontally. const tools::Long nCursorGapPx = 2; // Transform the cell range X coordinates such that the edit cell area is // horizontally mirrored w.r.t the (combined-)tile.
aNewOutputArea = tools::Rectangle(
pLokRTLCtxt->docToTilePos(aNewOutputArea.Left() - aOriginAbsPx.X()) + aOriginAbsPx.X(),
aNewOutputArea.Top(),
pLokRTLCtxt->docToTilePos(aNewOutputArea.Right() - aOriginAbsPx.X()) + aOriginAbsPx.X() + nCursorGapPx,
aNewOutputArea.Bottom());
aNewOutputArea.Normalize();
}
if (aNewOutputArea.IsEmpty())
{ // same zoom level and not RTL: no need to change the output area before painting
pOtherEditView->Paint(rDevice.PixelToLogic(aTileRectPx), &rDevice);
} else
{ // EditView has an 'output area' which is used to clip the 'paint area' we provide below. // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin // attached to the EditView, so we have to change its mapmode too (temporarily). We save the // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
rOtherWin.SetMapMode(rDevice.GetMapMode());
// Avoid sending wrong cursor/selection messages by the 'other' view, as the output-area is going // to be tweaked temporarily to match the current view's zoom.
SuppressEditViewMessagesGuard aGuard(*pOtherEditView);
// EditView will do the cursor notifications correctly if we're in // print-twips messaging mode. if (pTabViewShell == pThisViewShell
&& !comphelper::LibreOfficeKit::isCompatFlagSet(
comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
{ // Now we need to get relative cursor position within the editview. // This is for sending the pixel-aligned twips position of the cursor to the specific views with // the same given zoom level.
tools::Rectangle aCursorRect = pEditView->GetEditCursor();
Point aCursPos = o3tl::toTwips(aCursorRect.TopLeft(), o3tl::Length::mm100);
aBGAbs.AdjustLeft(1);
aBGAbs.AdjustTop(1);
aCursorRect = GetOutDev()->PixelToLogic(aBGAbs, aMM);
aCursorRect.setWidth(0);
aCursorRect.Move(aCursPos.getX(), 0); // Sends view cursor position to views of all matching zooms if needed (avoids duplicates).
InvalidateLOKViewCursor(aCursorRect, aMM.GetScaleX(), aMM.GetScaleY());
}
// Rollback the mapmode and 'output area'.
rOtherWin.SetMapMode(aOrigMapMode);
pOtherEditView->SetOutputArea(aOrigOutputArea);
}
rDevice.SetMapMode(MapMode(MapUnit::MapPixel));
}
}
// In-place editing - when the user is typing, we need to paint the text // using the editeng. // It's being done after EndDrawLayers() to get it outside the overlay // buffer and on top of everything. if (bInPlaceEditing && !bIsTiledRendering && bInPlaceVisCursor)
pInPlaceCrsr->Show();
if (mrViewData.HasEditView(eWhich))
{ // set MapMode for text edit
rDevice.SetMapMode(mrViewData.GetLogicMode());
} else
rDevice.SetMapMode(aDrawMode);
if (bPage && bInitialPageBreaks)
SetupInitialPageBreaks(rDoc, nTab);
}
void ScGridWindow::SetupInitialPageBreaks(const ScDocument& rDoc, SCTAB nTab)
{ // tdf#124983, if option LibreOfficeDev Calc/View/Visual Aids/Page breaks // is enabled, breaks should be visible. If the document is opened the first // time, the breaks are not calculated yet, so for this initialization // a timer will be triggered here.
std::set<SCCOL> aColBreaks;
std::set<SCROW> aRowBreaks;
rDoc.GetAllColBreaks(aColBreaks, nTab, true, false);
rDoc.GetAllRowBreaks(aRowBreaks, nTab, true, false); if (aColBreaks.empty() || aRowBreaks.empty())
{
maShowPageBreaksTimer.SetPriority(TaskPriority::DEFAULT_IDLE);
maShowPageBreaksTimer.Start();
}
bInitialPageBreaks = false;
}
void ScGridWindow::resetCachedViewGridOffsets() const
{ if (mpLOKDrawView) if (SdrPageView* pPageView = mpLOKDrawView->GetSdrPageView())
pPageView->resetGridOffsetsOfAllPageWindows();
}
void ScGridWindow::PaintTile( VirtualDevice& rDevice, int nOutputWidth, int nOutputHeight, int nTilePosX, int nTilePosY,
tools::Long nTileWidth, tools::Long nTileHeight,
SCCOL nTiledRenderingAreaEndCol, SCROW nTiledRenderingAreaEndRow )
{
Fraction origZoomX = mrViewData.GetZoomX();
Fraction origZoomY = mrViewData.GetZoomY();
// Output size is in pixels while tile position and size are in logical units (twips).
// Assumption: always paint the whole sheet i.e. "visible" range is always // from (0,0) to last data position.
// Tile geometry is independent of the zoom level, but the output size is // dependent of the zoom level. Determine the correct zoom level before // we start.
// FIXME the painting works using a mixture of drawing with coordinates in // pixels and in logic coordinates; it should be cleaned up to use logic // coords only, and avoid all the SetMapMode()'s. // Similarly to Writer, we should set the mapmode once on the rDevice, and // not care about any zoom settings.
// page break zoom, and aLogicMode in ScViewData // FIXME: there are issues when SetZoom is called conditionally.
mrViewData.SetZoom(aFracX, aFracY, true); if (bChangeZoom)
{ if (ScDrawView* pDrawView = mrViewData.GetScDrawView())
pDrawView->resetGridOffsetsForAllSdrPageViews();
}
// Checkout -> 'rDoc.ExtendMerge' ... if we miss merged cells.
// Origin must be the offset of the first col and row // containing our top-left pixel. const MapMode aOriginalMode = rDevice.GetMapMode();
MapMode aAbsMode = aOriginalMode; const Point aOrigin(-nTopLeftTileColOrigin, -nTopLeftTileRowOrigin);
aAbsMode.SetOrigin(aOrigin);
rDevice.SetMapMode(aAbsMode);
// setup the SdrPage so that drawinglayer works correctly
ScDrawLayer* pModel = rDoc.GetDrawLayer(); if (pModel)
{ bool bPrintTwipsMsgs = comphelper::LibreOfficeKit::isCompatFlagSet(
comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs); if (!mpLOKDrawView)
{
mpLOKDrawView.reset(bPrintTwipsMsgs ? new ScLOKDrawView(
&rDevice,
mrViewData) : new FmFormView(
*pModel,
&rDevice));
}
void ScGridWindow::LogicInvalidatePart(const tools::Rectangle* pRectangle, int nPart)
{
tools::Rectangle aRectangle;
tools::Rectangle* pResultRectangle; if (!pRectangle)
pResultRectangle = nullptr; else
{
aRectangle = *pRectangle; // When dragging shapes the map mode is disabled. if (IsMapModeEnabled())
{ if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
{
aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip);
}
} else
aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip));
pResultRectangle = &aRectangle;
}
// Trim invalidation rectangle overlapping negative X region in RTL mode. if (pResultRectangle && pResultRectangle->Left() < 0
&& mrViewData.GetDocument().IsLayoutRTL(mrViewData.GetTabNo()))
{
pResultRectangle->SetLeft(0); if (pResultRectangle->Right() < 0)
pResultRectangle->SetRight(0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.