1
0
Fork 0
libreoffice/svx/source/dialog/pagenumberlistbox.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

433 lines
19 KiB
C++

/* -*- 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 .
*/
#include <editeng/brushitem.hxx>
#include <editeng/numitem.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <svtools/colorcfg.hxx>
#include <svx/dialmgr.hxx>
#include <svx/numberingpreview.hxx>
#include <svx/pagenumberlistbox.hxx>
#include <vcl/graph.hxx>
#include <vcl/metric.hxx>
#include <vcl/virdev.hxx>
#include <numberingtype.hrc>
#include <com/sun/star/style/NumberingType.hpp>
SvxPageNumberListBox::SvxPageNumberListBox(std::unique_ptr<weld::ComboBox> pControl)
: m_xControl(std::move(pControl))
{
m_xControl->set_size_request(150, -1);
for (size_t i = 0; i < SAL_N_ELEMENTS(RID_SVXSTRARY_NUMBERINGTYPE); ++i)
{
sal_uInt16 nData = RID_SVXSTRARY_NUMBERINGTYPE[i].second;
switch (nData)
{
// String list array is also used in Writer and contains strings
// for Bullet and Graphics, ignore those here.
case css::style::NumberingType::CHAR_SPECIAL:
case css::style::NumberingType::BITMAP:
case css::style::NumberingType::BITMAP | LINK_TOKEN:
break;
default:
{
OUString aStr = SvxResId(RID_SVXSTRARY_NUMBERINGTYPE[i].first);
m_xControl->append(OUString::number(nData), aStr);
break;
}
}
}
}
SvxNumberingPreview::SvxNumberingPreview()
: m_pActNum(nullptr)
, m_bPosition(false)
, m_nActLevel(SAL_MAX_UINT16)
{
}
static tools::Long lcl_DrawGraphic(VirtualDevice& rVDev, const SvxNumberFormat& rFmt,
tools::Long nXStart, tools::Long nYMiddle, tools::Long nDivision)
{
const SvxBrushItem* pBrushItem = rFmt.GetBrush();
tools::Long nRet = 0;
if (pBrushItem)
{
const Graphic* pGrf = pBrushItem->GetGraphic();
if (pGrf)
{
Size aGSize(rFmt.GetGraphicSize());
aGSize.setWidth(aGSize.Width() / nDivision);
nRet = aGSize.Width();
aGSize.setHeight(aGSize.Height() / nDivision);
pGrf->Draw(rVDev, Point(nXStart, nYMiddle - (aGSize.Height() / 2)),
rVDev.PixelToLogic(aGSize));
}
}
return nRet;
}
static tools::Long lcl_DrawBullet(VirtualDevice* pVDev, const SvxNumberFormat& rFmt,
tools::Long nXStart, tools::Long nYStart, const Size& rSize)
{
vcl::Font aTmpFont(pVDev->GetFont());
// via Uno it's possible that no font has been set!
vcl::Font aFont(rFmt.GetBulletFont() ? *rFmt.GetBulletFont() : aTmpFont);
Size aTmpSize(rSize);
aTmpSize.setWidth(aTmpSize.Width() * (rFmt.GetBulletRelSize()));
aTmpSize.setWidth(aTmpSize.Width() / 100);
aTmpSize.setHeight(aTmpSize.Height() * (rFmt.GetBulletRelSize()));
aTmpSize.setHeight(aTmpSize.Height() / 100);
// in case of a height of zero it is drawn in original height
if (!aTmpSize.Height())
aTmpSize.setHeight(1);
aFont.SetFontSize(aTmpSize);
aFont.SetTransparent(true);
Color aBulletColor = rFmt.GetBulletColor();
if (aBulletColor == COL_AUTO)
aBulletColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK;
else if (pVDev->GetBackgroundColor().IsDark() == aBulletColor.IsDark())
aBulletColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK;
aFont.SetColor(aBulletColor);
pVDev->SetFont(aFont);
sal_UCS4 cChar = rFmt.GetBulletChar();
OUString aText(&cChar, 1);
tools::Long nY = nYStart;
nY -= ((aTmpSize.Height() - rSize.Height()) / 2);
pVDev->DrawText(Point(nXStart, nY), aText);
tools::Long nRet = pVDev->GetTextWidth(aText);
pVDev->SetFont(aTmpFont);
return nRet;
}
// paint preview of numeration
void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext,
const ::tools::Rectangle& /*rRect*/)
{
Size aSize(rRenderContext.PixelToLogic(GetOutputSizePixel()));
// Use default document and font colors to create preview
const Color aBackColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
const Color aTextColor = svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
ScopedVclPtrInstance<VirtualDevice> pVDev(rRenderContext);
pVDev->EnableRTL(rRenderContext.IsRTLEnabled());
pVDev->SetMapMode(rRenderContext.GetMapMode());
pVDev->SetOutputSize(aSize);
Color aLineColor(COL_LIGHTGRAY);
if (aLineColor == aBackColor)
aLineColor.Invert();
pVDev->SetLineColor(aLineColor);
pVDev->SetFillColor(aBackColor);
pVDev->SetBackground(Wallpaper(aBackColor));
pVDev->DrawWallpaper(pVDev->GetOutputRectPixel(), pVDev->GetBackground());
if (m_pActNum)
{
tools::Long nWidthRelation = 30; // chapter dialog
// height per level
tools::Long nXStep
= aSize.Width() / (m_pActNum->GetLevelCount() > 1 ? 3 * m_pActNum->GetLevelCount() : 3);
if (m_pActNum->GetLevelCount() < 10)
nXStep /= 2;
tools::Long nYStart = 4;
// the whole height mustn't be used for a single level
tools::Long nYStep = (aSize.Height() - 6)
/ (m_pActNum->GetLevelCount() > 1 ? m_pActNum->GetLevelCount() : 5);
m_aStdFont = OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS,
MsLangId::getConfiguredSystemLanguage(),
GetDefaultFontFlags::OnlyOne);
m_aStdFont.SetColor(aTextColor);
m_aStdFont.SetFillColor(aBackColor);
tools::Long nFontHeight = nYStep * 6 / 10;
if (m_bPosition)
nFontHeight = nYStep * 15 / 10;
m_aStdFont.SetFontSize(Size(0, nFontHeight));
SvxNodeNum aNum;
sal_uInt16 nPreNum = m_pActNum->GetLevel(0).GetStart();
if (m_bPosition)
{
// When bPosition == true, draw the preview used in the Writer's "Position" tab
// This is not used in Impress/Draw
tools::Long nLineHeight = nFontHeight * 8 / 7;
sal_uInt8 nStart = 0;
while (!(m_nActLevel & (1 << nStart)))
{
nStart++;
}
if (nStart)
nStart--;
sal_uInt8 nEnd = std::min(sal_uInt8(nStart + 3), sal_uInt8(m_pActNum->GetLevelCount()));
for (sal_uInt8 nLevel = nStart; nLevel < nEnd; ++nLevel)
{
const SvxNumberFormat& rFmt = m_pActNum->GetLevel(nLevel);
aNum.GetLevelVal()[nLevel] = rFmt.GetStart();
tools::Long nXStart(0);
short nTextOffset(0);
tools::Long nNumberXPos(0);
if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION)
{
nXStart = rFmt.GetAbsLSpace() / nWidthRelation;
nTextOffset = rFmt.GetCharTextDistance() / nWidthRelation;
nNumberXPos = nXStart;
tools::Long nFirstLineOffset = (-rFmt.GetFirstLineOffset()) / nWidthRelation;
if (nFirstLineOffset <= nNumberXPos)
nNumberXPos = nNumberXPos - nFirstLineOffset;
else
nNumberXPos = 0;
// in draw this is valid
if (nTextOffset < 0)
nNumberXPos = nNumberXPos + nTextOffset;
}
else if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT)
{
const tools::Long nTmpNumberXPos(
(rFmt.GetIndentAt() + rFmt.GetFirstLineIndent()) / nWidthRelation);
if (nTmpNumberXPos < 0)
{
nNumberXPos = 0;
}
else
{
nNumberXPos = nTmpNumberXPos;
}
}
tools::Long nBulletWidth = 0;
if (SVX_NUM_BITMAP == (rFmt.GetNumberingType() & (~LINK_TOKEN)))
{
tools::Long nYMiddle = nYStart + (nFontHeight / 2);
nBulletWidth = rFmt.IsShowSymbol() ? lcl_DrawGraphic(*pVDev, rFmt, nNumberXPos,
nYMiddle, nWidthRelation)
: 0;
}
else if (SVX_NUM_CHAR_SPECIAL == rFmt.GetNumberingType())
{
nBulletWidth = rFmt.IsShowSymbol()
? lcl_DrawBullet(pVDev.get(), rFmt, nNumberXPos, nYStart,
m_aStdFont.GetFontSize())
: 0;
}
else
{
pVDev->SetFont(m_aStdFont);
aNum.SetLevel(nLevel);
if (m_pActNum->IsContinuousNumbering())
aNum.GetLevelVal()[nLevel] = nPreNum;
OUString aText(m_pActNum->MakeNumString(aNum));
vcl::Font aSaveFont = pVDev->GetFont();
vcl::Font aColorFont(aSaveFont);
Color aTmpBulletColor = rFmt.GetBulletColor();
if (aTmpBulletColor == COL_AUTO)
aTmpBulletColor
= pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK;
else if (pVDev->GetBackgroundColor().IsDark() == aTmpBulletColor.IsDark())
aTmpBulletColor
= pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK;
aColorFont.SetColor(aTmpBulletColor);
pVDev->SetFont(aColorFont);
pVDev->DrawText(Point(nNumberXPos, nYStart), aText);
pVDev->SetFont(aSaveFont);
nBulletWidth = pVDev->GetTextWidth(aText);
nPreNum++;
}
if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
&& rFmt.GetLabelFollowedBy() == SvxNumberFormat::SPACE)
{
pVDev->SetFont(m_aStdFont);
OUString aText(' ');
pVDev->DrawText(Point(nNumberXPos, nYStart), aText);
nBulletWidth = nBulletWidth + pVDev->GetTextWidth(aText);
}
tools::Long nTextXPos(0);
if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION)
{
nTextXPos = nXStart;
if (nTextOffset < 0)
nTextXPos = nTextXPos + nTextOffset;
if (nNumberXPos + nBulletWidth + nTextOffset > nTextXPos)
nTextXPos = nNumberXPos + nBulletWidth + nTextOffset;
}
else if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT)
{
switch (rFmt.GetLabelFollowedBy())
{
case SvxNumberFormat::LISTTAB:
{
nTextXPos = rFmt.GetListtabPos() / nWidthRelation;
if (nTextXPos < nNumberXPos + nBulletWidth)
{
nTextXPos = nNumberXPos + nBulletWidth;
}
}
break;
case SvxNumberFormat::SPACE:
case SvxNumberFormat::NOTHING:
case SvxNumberFormat::NEWLINE:
{
nTextXPos = nNumberXPos + nBulletWidth;
}
break;
}
nXStart = rFmt.GetIndentAt() / nWidthRelation;
}
::tools::Rectangle aRect1(Point(nTextXPos, nYStart + nFontHeight / 2),
Size(aSize.Width() / 2, 2));
pVDev->SetFillColor(aBackColor);
pVDev->DrawRect(aRect1);
::tools::Rectangle aRect2(Point(nXStart, nYStart + nLineHeight + nFontHeight / 2),
Size(aSize.Width() / 2, 2));
pVDev->DrawRect(aRect2);
nYStart += 2 * nLineHeight;
}
}
else
{
// When bPosition == false, draw the preview used in Writer's "Customize" tab
// and in Impress' "Bullets and Numbering" dialog
//#i5153# painting gray or black rectangles as 'normal' numbering text
tools::Long nWidth = pVDev->GetTextWidth(u"Preview"_ustr);
tools::Long nTextHeight = pVDev->GetTextHeight();
tools::Long nRectHeight = nTextHeight * 2 / 3;
tools::Long nTopOffset = nTextHeight - nRectHeight;
Color aSelRectColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK;
for (sal_uInt16 nLevel = 0; nLevel < m_pActNum->GetLevelCount();
++nLevel, nYStart = nYStart + nYStep)
{
const SvxNumberFormat& rFmt = m_pActNum->GetLevel(nLevel);
aNum.GetLevelVal()[nLevel] = rFmt.GetStart();
tools::Long nXStart(0);
pVDev->SetFillColor(aBackColor);
if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION)
{
nXStart = rFmt.GetAbsLSpace() / nWidthRelation;
}
else if (rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT)
{
const tools::Long nTmpXStart((rFmt.GetIndentAt() + rFmt.GetFirstLineIndent())
/ nWidthRelation);
if (nTmpXStart < 0)
{
nXStart = 0;
}
else
{
nXStart = nTmpXStart;
}
}
nXStart /= 2;
nXStart += 2;
tools::Long nTextOffset = 2 * nXStep;
if (SVX_NUM_BITMAP == (rFmt.GetNumberingType() & (~LINK_TOKEN)))
{
if (rFmt.IsShowSymbol())
{
tools::Long nYMiddle = nYStart + (nFontHeight / 2);
nTextOffset
= lcl_DrawGraphic(*pVDev, rFmt, nXStart, nYMiddle, nWidthRelation);
nTextOffset = nTextOffset + nXStep;
}
}
else if (SVX_NUM_CHAR_SPECIAL == rFmt.GetNumberingType())
{
if (rFmt.IsShowSymbol())
{
nTextOffset = lcl_DrawBullet(pVDev.get(), rFmt, nXStart, nYStart,
m_aStdFont.GetFontSize());
nTextOffset = nTextOffset + nXStep;
}
}
else
{
vcl::Font aFont(m_aStdFont);
Size aTmpSize(m_aStdFont.GetFontSize());
if (m_pActNum->IsFeatureSupported(SvxNumRuleFlags::BULLET_REL_SIZE))
{
aTmpSize.setWidth(aTmpSize.Width() * (rFmt.GetBulletRelSize()));
aTmpSize.setWidth(aTmpSize.Width() / 100);
aTmpSize.setHeight(aTmpSize.Height() * (rFmt.GetBulletRelSize()));
aTmpSize.setHeight(aTmpSize.Height() / 100);
}
if (!aTmpSize.Height())
aTmpSize.setHeight(1);
aFont.SetFontSize(aTmpSize);
Color aTmpBulletColor = rFmt.GetBulletColor();
if (aTmpBulletColor == COL_AUTO)
aTmpBulletColor
= pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK;
else if (pVDev->GetBackgroundColor().IsDark() == aTmpBulletColor.IsDark())
aTmpBulletColor
= pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK;
aFont.SetColor(aTmpBulletColor);
pVDev->SetFont(aFont);
aNum.SetLevel(nLevel);
if (m_pActNum->IsContinuousNumbering())
aNum.GetLevelVal()[nLevel] = nPreNum;
OUString aText(m_pActNum->MakeNumString(aNum));
tools::Long nY = nYStart;
nY -= (pVDev->GetTextHeight() - nTextHeight
- pVDev->GetFontMetric().GetDescent());
pVDev->DrawText(Point(nXStart, nY), aText);
nTextOffset = pVDev->GetTextWidth(aText);
nTextOffset = nTextOffset + nXStep;
nPreNum++;
pVDev->SetFont(m_aStdFont);
}
//#i5153# the selected rectangle(s) should be black
if (0 != (m_nActLevel & (1 << nLevel)))
{
pVDev->SetFillColor(aSelRectColor);
pVDev->SetLineColor(aSelRectColor);
}
else
{
//#i5153# unselected levels are gray
pVDev->SetFillColor(aLineColor);
pVDev->SetLineColor(aLineColor);
}
::tools::Rectangle aRect1(Point(nXStart + nTextOffset, nYStart + nTopOffset),
Size(nWidth, nRectHeight));
pVDev->DrawRect(aRect1);
}
}
}
rRenderContext.DrawOutDev(Point(), aSize, Point(), aSize, *pVDev);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */