Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/dialog/pagectrl.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#include <memory>
21
#include <editeng/frmdir.hxx>
22
#include <vcl/canvastools.hxx>
23
#include <vcl/outdev.hxx>
24
#include <vcl/settings.hxx>
25
#include <vcl/themecolors.hxx>
26
#include <tools/color.hxx>
27
#include <tools/fract.hxx>
28
#include <tools/mapunit.hxx>
29
#include <svx/pageitem.hxx>
30
#include <svx/pagectrl.hxx>
31
#include <algorithm>
32
#include <basegfx/matrix/b2dhommatrix.hxx>
33
#include <drawinglayer/geometry/viewinformation2d.hxx>
34
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
35
#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
36
#include <drawinglayer/processor2d/processor2dtools.hxx>
37
#include <basegfx/polygon/b2dpolygontools.hxx>
38
39
0
#define CELL_WIDTH      1600L
40
0
#define CELL_HEIGHT      800L
41
42
SvxPageWindow::SvxPageWindow() :
43
0
    m_nTop(0),
44
0
    m_nBottom(0),
45
0
    m_nLeft(0),
46
0
    m_nRight(0),
47
0
    m_bResetBackground(false),
48
0
    m_bFrameDirection(false),
49
0
    m_nFrameDirection(SvxFrameDirection::Horizontal_LR_TB),
50
0
    m_nHdLeft(0),
51
0
    m_nHdRight(0),
52
0
    m_nHdDist(0),
53
0
    m_nHdHeight(0),
54
0
    m_nFtLeft(0),
55
0
    m_nFtRight(0),
56
0
    m_nFtDist(0),
57
0
    m_nFtHeight(0),
58
0
    m_bFooter(false),
59
0
    m_bHeader(false),
60
0
    m_bTable(false),
61
0
    m_bHorz(false),
62
0
    m_bVert(false),
63
0
    m_eUsage(SvxPageUsage::All)
64
0
{
65
0
}
66
67
SvxPageWindow::~SvxPageWindow()
68
0
{
69
0
}
70
71
void SvxPageWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
72
0
{
73
0
    auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::MAPMODE);
74
0
    rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
75
76
0
    double aXScale = double(m_aWinSize.Width()) / std::max(m_aSize.Width() * 2 + m_aSize.Width() / 8, tools::Long(1));
77
0
    double aYScale = double(m_aWinSize.Height()) / std::max(m_aSize.Height(), tools::Long(1));
78
0
    MapMode aMapMode(rRenderContext.GetMapMode());
79
80
0
    if(aYScale < aXScale)
81
0
    {
82
0
        aMapMode.SetScaleX(aYScale);
83
0
        aMapMode.SetScaleY(aYScale);
84
0
    }
85
0
    else
86
0
    {
87
0
        aMapMode.SetScaleX(aXScale);
88
0
        aMapMode.SetScaleY(aXScale);
89
0
    }
90
0
    rRenderContext.SetMapMode(aMapMode);
91
0
    Size aSz(rRenderContext.PixelToLogic(GetOutputSizePixel()));
92
0
    tools::Long nYPos = (aSz.Height() - m_aSize.Height()) / 2;
93
94
0
    if (m_eUsage == SvxPageUsage::All)
95
0
    {
96
        // all pages are equal -> draw one page
97
0
        if (m_aSize.Width() > m_aSize.Height())
98
0
        {
99
            // Draw Landscape page of the same size
100
0
            double aX = aMapMode.GetScaleX();
101
0
            double aY = aMapMode.GetScaleY();
102
0
            double a2(1.5);
103
0
            aX *= a2;
104
0
            aY *= a2;
105
0
            aMapMode.SetScaleX(aX);
106
0
            aMapMode.SetScaleY(aY);
107
0
            rRenderContext.SetMapMode(aMapMode);
108
0
            aSz = rRenderContext.PixelToLogic(GetOutputSizePixel());
109
0
            nYPos = (aSz.Height() - m_aSize.Height()) / 2;
110
0
            tools::Long nXPos = (aSz.Width() - m_aSize.Width()) / 2;
111
0
            DrawPage(rRenderContext, Point(nXPos,nYPos),false,true);
112
0
        }
113
0
        else
114
            // Portrait
115
0
            DrawPage(rRenderContext, Point((aSz.Width() - m_aSize.Width()) / 2,nYPos),false,true);
116
0
    }
117
0
    else
118
0
    {
119
        // Left and right page are different -> draw two pages if possible
120
0
        DrawPage(rRenderContext, Point(0, nYPos), false,
121
0
                 m_eUsage == SvxPageUsage::Left || m_eUsage == SvxPageUsage::All || m_eUsage == SvxPageUsage::Mirror);
122
0
        DrawPage(rRenderContext, Point(m_aSize.Width() + m_aSize.Width() / 8, nYPos), true,
123
0
                 m_eUsage == SvxPageUsage::Right || m_eUsage == SvxPageUsage::All || m_eUsage == SvxPageUsage::Mirror);
124
0
    }
125
0
}
126
127
void SvxPageWindow::DrawPage(vcl::RenderContext& rRenderContext, const Point& rOrg, const bool bSecond, const bool bEnabled)
128
0
{
129
0
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
130
0
    const Color& rFieldColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
131
0
    const Color& rFieldTextColor = rStyleSettings.GetFieldTextColor();
132
0
    const Color& rDisableColor = rStyleSettings.GetDisableColor();
133
0
    const Color& rDlgColor = rStyleSettings.GetDialogColor();
134
135
    // background
136
0
    if (!bSecond || m_bResetBackground)
137
0
    {
138
0
        rRenderContext.SetLineColor();
139
0
        rRenderContext.SetFillColor(rDlgColor);
140
0
        Size winSize(rRenderContext.GetOutputSize());
141
0
        rRenderContext.DrawRect(tools::Rectangle(Point(0,0), winSize));
142
143
0
        if (m_bResetBackground)
144
0
            m_bResetBackground = false;
145
0
    }
146
0
    rRenderContext.SetLineColor(rFieldTextColor);
147
0
    rRenderContext.SetTextColor(COL_GRAY);
148
149
    // Shadow
150
0
    Size aTempSize = m_aSize;
151
152
    // Page
153
0
    if (!bEnabled)
154
0
    {
155
0
        rRenderContext.SetFillColor(rDisableColor);
156
0
        rRenderContext.DrawRect(tools::Rectangle(rOrg, aTempSize));
157
0
        return;
158
0
    }
159
0
    rRenderContext.SetFillColor(rFieldColor);
160
0
    rRenderContext.DrawRect(tools::Rectangle(rOrg, aTempSize));
161
162
0
    tools::Long nL = m_nLeft;
163
0
    tools::Long nR = m_nRight;
164
165
0
    if (m_eUsage == SvxPageUsage::Mirror && !bSecond)
166
0
    {
167
        // turn for mirrored
168
0
        nL = m_nRight;
169
0
        nR = m_nLeft;
170
0
    }
171
172
0
    tools::Rectangle aRect;
173
174
0
    aRect.SetLeft( rOrg.X() + nL );
175
0
    aRect.SetRight( rOrg.X() + aTempSize.Width() - nR );
176
0
    aRect.SetTop( rOrg.Y() + m_nTop );
177
0
    aRect.SetBottom( rOrg.Y() + aTempSize.Height() - m_nBottom );
178
179
0
    tools::Rectangle aHdRect(aRect);
180
0
    tools::Rectangle aFtRect(aRect);
181
182
0
    if (m_bHeader || m_bFooter)
183
0
    {
184
        // draw PageFill first and on the whole page, no outline
185
0
        rRenderContext.SetLineColor();
186
0
        drawFillAttributes(rRenderContext, maPageFillAttributes, aRect, aRect);
187
0
        rRenderContext.SetLineColor(COL_GRAY);
188
189
0
        if (m_bHeader)
190
0
        {
191
            // show headers if possible
192
0
            aHdRect.AdjustLeft(m_nHdLeft );
193
0
            aHdRect.AdjustRight( -m_nHdRight );
194
0
            aHdRect.SetBottom( aRect.Top() + m_nHdHeight );
195
0
            aRect.AdjustTop(m_nHdHeight + m_nHdDist );
196
197
            // draw header over PageFill, plus outline
198
0
            drawFillAttributes(rRenderContext, maHeaderFillAttributes, aHdRect, aHdRect);
199
0
        }
200
201
0
        if (m_bFooter)
202
0
        {
203
            // show footer if possible
204
0
            aFtRect.AdjustLeft(m_nFtLeft );
205
0
            aFtRect.AdjustRight( -m_nFtRight );
206
0
            aFtRect.SetTop( aRect.Bottom() - m_nFtHeight );
207
0
            aRect.AdjustBottom( -(m_nFtHeight + m_nFtDist) );
208
209
            // draw footer over PageFill, plus outline
210
0
            drawFillAttributes(rRenderContext, maFooterFillAttributes, aFtRect, aFtRect);
211
0
        }
212
213
        // draw page's reduced outline, only outline
214
0
        drawFillAttributes(rRenderContext, drawinglayer::attribute::SdrAllFillAttributesHelperPtr(), aRect, aRect);
215
0
    }
216
0
    else
217
0
    {
218
        // draw PageFill and outline
219
0
        drawFillAttributes(rRenderContext, maPageFillAttributes, aRect, aRect);
220
0
    }
221
222
0
    if (m_bFrameDirection && !m_bTable)
223
0
    {
224
0
        Point aPos;
225
0
        vcl::Font aFont(rRenderContext.GetFont());
226
0
        const Size aSaveSize = aFont.GetFontSize();
227
0
        Size aDrawSize(0,aRect.GetHeight() / 6);
228
0
        aFont.SetFontSize(aDrawSize);
229
0
        rRenderContext.SetFont(aFont);
230
0
        OUString sText(u"ABC"_ustr);
231
0
        Point aMove(1, rRenderContext.GetTextHeight());
232
0
        sal_Unicode cArrow = 0x2193;
233
0
        tools::Long nAWidth = rRenderContext.GetTextWidth(sText.copy(0,1));
234
0
        switch (m_nFrameDirection)
235
0
        {
236
0
        case SvxFrameDirection::Horizontal_LR_TB:
237
0
            aPos = aRect.TopLeft();
238
0
            aPos.AdjustX(rRenderContext.PixelToLogic(Point(1,1)).X() );
239
0
            aMove.setY( 0 );
240
0
            cArrow = 0x2192;
241
0
            break;
242
0
        case SvxFrameDirection::Horizontal_RL_TB:
243
0
            aPos = aRect.TopRight();
244
0
            aPos.AdjustX( -nAWidth );
245
0
            aMove.setY( 0 );
246
0
            aMove.setX( aMove.X() * -1 );
247
0
            cArrow = 0x2190;
248
0
            break;
249
0
        case SvxFrameDirection::Vertical_LR_TB:
250
0
            aPos = aRect.TopLeft();
251
0
            aPos.AdjustX(rRenderContext.PixelToLogic(Point(1,1)).X() );
252
0
            aMove.setX( 0 );
253
0
            break;
254
0
        case SvxFrameDirection::Vertical_RL_TB:
255
0
            aPos = aRect.TopRight();
256
0
            aPos.AdjustX( -nAWidth );
257
0
            aMove.setX( 0 );
258
0
            break;
259
0
        default: break;
260
0
        }
261
0
        sText += OUStringChar(cArrow);
262
0
        for (sal_Int32 i = 0; i < sText.getLength(); i++)
263
0
        {
264
0
            OUString sDraw(sText.copy(i,1));
265
0
            tools::Long nHDiff = 0;
266
0
            tools::Long nCharWidth = rRenderContext.GetTextWidth(sDraw);
267
0
            bool bHorizontal = 0 == aMove.Y();
268
0
            if (!bHorizontal)
269
0
            {
270
0
                nHDiff = (nAWidth - nCharWidth) / 2;
271
0
                aPos.AdjustX(nHDiff );
272
0
            }
273
0
            rRenderContext.DrawText(aPos,sDraw);
274
0
            if (bHorizontal)
275
0
            {
276
0
                aPos.AdjustX(aMove.X() < 0 ? -nCharWidth : nCharWidth );
277
0
            }
278
0
            else
279
0
            {
280
0
                aPos.AdjustX( -nHDiff );
281
0
                aPos.AdjustY(aMove.Y() );
282
0
            }
283
0
        }
284
0
        aFont.SetFontSize(aSaveSize);
285
0
        rRenderContext.SetFont(aFont);
286
287
0
    }
288
0
    if (!m_bTable)
289
0
        return;
290
291
    // Paint Table, if necessary center it
292
0
    rRenderContext.SetLineColor(COL_LIGHTGRAY);
293
294
0
    tools::Long nW = aRect.GetWidth();
295
0
    tools::Long nH = aRect.GetHeight();
296
0
    tools::Long const nTW = CELL_WIDTH * 3;
297
0
    tools::Long const nTH = CELL_HEIGHT * 3;
298
0
    tools::Long _nLeft = m_bHorz ? aRect.Left() + ((nW - nTW) / 2) : aRect.Left();
299
0
    tools::Long _nTop = m_bVert ? aRect.Top() + ((nH - nTH) / 2) : aRect.Top();
300
0
    tools::Rectangle aCellRect(Point(_nLeft, _nTop),Size(CELL_WIDTH, CELL_HEIGHT));
301
302
0
    for (sal_uInt16 i = 0; i < 3; ++i)
303
0
    {
304
0
        aCellRect.SetLeft( _nLeft );
305
0
        aCellRect.SetRight( _nLeft + CELL_WIDTH );
306
0
        if(i > 0)
307
0
            aCellRect.Move(0,CELL_HEIGHT);
308
309
0
        for (sal_uInt16 j = 0; j < 3; ++j)
310
0
        {
311
0
            if (j > 0)
312
0
                aCellRect.Move(CELL_WIDTH,0);
313
0
            rRenderContext.DrawRect(aCellRect);
314
0
        }
315
0
    }
316
0
}
317
318
void SvxPageWindow::drawFillAttributes(vcl::RenderContext& rRenderContext,
319
                                       const drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
320
                                       const tools::Rectangle& rPaintRange,
321
                                       const tools::Rectangle& rDefineRange)
322
0
{
323
0
    const basegfx::B2DRange aPaintRange = vcl::unotools::b2DRectangleFromRectangle(rPaintRange);
324
325
0
    if(aPaintRange.isEmpty() ||
326
0
       basegfx::fTools::equalZero(aPaintRange.getWidth()) ||
327
0
       basegfx::fTools::equalZero(aPaintRange.getHeight()))
328
0
        return;
329
330
0
    const basegfx::B2DRange aDefineRange = vcl::unotools::b2DRectangleFromRectangle(rDefineRange);
331
332
    // prepare primitive sequence
333
0
    drawinglayer::primitive2d::Primitive2DContainer aSequence;
334
335
    // create fill geometry if there is something to fill
336
0
    if (rFillAttributes && rFillAttributes->isUsed())
337
0
    {
338
0
        aSequence = rFillAttributes->getPrimitive2DSequence(aPaintRange, aDefineRange);
339
0
    }
340
341
    // create line geometry if a LineColor is set at the target device
342
0
    if (rRenderContext.IsLineColor())
343
0
    {
344
0
        const drawinglayer::primitive2d::Primitive2DReference xOutline(
345
0
            new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
346
0
                basegfx::utils::createPolygonFromRect(aPaintRange), rRenderContext.GetLineColor().getBColor()));
347
348
0
        aSequence.push_back(xOutline);
349
0
    }
350
351
    // draw that if we have something to draw
352
0
    if (aSequence.empty())
353
0
        return;
354
355
0
    drawinglayer::geometry::ViewInformation2D aViewInformation2D;
356
0
    aViewInformation2D.setViewTransformation(rRenderContext.GetViewTransformation());
357
0
    aViewInformation2D.setViewport(aPaintRange);
358
359
0
    std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
360
0
        drawinglayer::processor2d::createProcessor2DFromOutputDevice(rRenderContext, aViewInformation2D));
361
0
    pProcessor->process(aSequence);
362
0
}
363
364
void SvxPageWindow::EnableFrameDirection(bool bEnable)
365
0
{
366
0
    m_bFrameDirection = bEnable;
367
0
}
368
369
void SvxPageWindow::SetFrameDirection(SvxFrameDirection nDirection)
370
0
{
371
0
    m_nFrameDirection = nDirection;
372
0
}
373
374
void SvxPageWindow::ResetBackground()
375
0
{
376
0
    m_bResetBackground = true;
377
0
}
378
379
void SvxPageWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
380
0
{
381
0
    CustomWidgetController::SetDrawingArea(pDrawingArea);
382
383
0
    OutputDevice& rRefDevice = pDrawingArea->get_ref_device();
384
    // Count in Twips by default
385
0
    auto popIt = rRefDevice.ScopedPush(vcl::PushFlags::MAPMODE);
386
0
    rRefDevice.SetMapMode(MapMode(MapUnit::MapTwip));
387
0
    m_aWinSize = rRefDevice.LogicToPixel(Size(75, 46), MapMode(MapUnit::MapAppFont));
388
0
    pDrawingArea->set_size_request(m_aWinSize.Width(), m_aWinSize.Height());
389
390
0
    m_aWinSize.AdjustHeight( -4 );
391
0
    m_aWinSize.AdjustWidth( -4 );
392
393
0
    m_aWinSize = rRefDevice.PixelToLogic(m_aWinSize);
394
0
}
395
396
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */