Files
odfstudio/cui/source/tabpages/tpshadow.cxx
T
Armin Le Grand (collabora) 760394bbad Remove XFillAttrSetItem and XLineAttrSetItem
Both are derived from SfxSetItem which means they contain
a SfxItemSet themselves. That leads to problems since at
their construction time a SfxItemPool has to be known and
it *should* not be different to the one of the ItemSet
that Item gets added later - that leads to the 2nd class
of problems.

In the long therm we should get rid of all SfxSetItems.
This change simplifies already some stuff, including that
the standard Items for DrawObjects reduces by two (and
more due to containing a whole ItemSet) and e.g. the
problem that these Items had to be converted to hard
attributes in the done fixes for copy/pasting Slides.

Signed-off-by: Armin Le Grand (collabora) <Armin.LeGrand@collabora.com>
Change-Id: I8b1c6cabdaa43ed6062811b5508ab3dece47a755
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/6795
Reviewed-by: Armin Le Grand <armin.legrand@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit e67458a9b769fe7a3a7ee0739ed6d5c46dbc0692)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211734
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-10-08 08:56:42 +02:00

518 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 <svx/colorbox.hxx>
#include <svx/svxids.hrc>
#include <svtools/unitconv.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xflclit.hxx>
#include <svx/xflgrit.hxx>
#include <svx/xflhtit.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/sdmetitm.hxx>
#include <svx/sdooitm.hxx>
#include <svx/sdprcitm.hxx>
#include <svx/sdshcitm.hxx>
#include <svx/sdshitm.hxx>
#include <svx/sdshtitm.hxx>
#include <svx/sdsxyitm.hxx>
#include <svx/drawitem.hxx>
#include <svx/xfltrit.hxx>
#include <vcl/weld/Builder.hxx>
#include <cuitabarea.hxx>
#include <svx/dlgutil.hxx>
#include <vcl/weld/Dialog.hxx>
#include <cuitabline.hxx>
using namespace com::sun::star;
const WhichRangesContainer SvxShadowTabPage::pShadowRanges(svl::Items<
SDRATTR_SHADOWCOLOR, SDRATTR_SHADOWTRANSPARENCE,
SDRATTR_SHADOWBLUR, SDRATTR_SHADOWBLUR,
SID_ATTR_FILL_SHADOW, SID_ATTR_FILL_SHADOW,
SID_ATTR_SHADOW_BLUR, SID_ATTR_SHADOW_BLUR,
SID_ATTR_SHADOW_TRANSPARENCE, SID_ATTR_SHADOW_YDISTANCE
>);
SvxShadowTabPage::SvxShadowTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs)
: SvxTabPage(pPage, pController, u"cui/ui/shadowtabpage.ui"_ustr, u"ShadowTabPage"_ustr, rInAttrs)
, m_rOutAttrs(rInAttrs)
, m_pnColorListState(nullptr)
, m_nPageType(PageType::Area)
, m_nDlgType(0)
, m_aFillAttributeSet(rInAttrs.getPool(), WhichRangesContainer(XATTR_FILL_FIRST, XATTR_FILL_LAST))
, m_aCtlPosition(this)
, m_xTsbShowShadow(m_xBuilder->weld_check_button(u"TSB_SHOW_SHADOW"_ustr))
, m_xGridShadow(m_xBuilder->weld_widget(u"gridSHADOW"_ustr))
, m_xMtrDistance(m_xBuilder->weld_metric_spin_button(u"MTR_FLD_DISTANCE"_ustr, FieldUnit::CM))
, m_xLbShadowColor(new ColorListBox(m_xBuilder->weld_menu_button(u"LB_SHADOW_COLOR"_ustr),
[this]{ return GetDialogController()->getDialog(); }))
, m_xMtrTransparent(m_xBuilder->weld_metric_spin_button(u"MTR_SHADOW_TRANSPARENT"_ustr, FieldUnit::PERCENT))
, m_xLbShadowBlurMetric(m_xBuilder->weld_metric_spin_button(u"LB_SHADOW_BLUR"_ustr, FieldUnit::POINT))
, m_xCtlPosition(new weld::CustomWeld(*m_xBuilder, u"CTL_POSITION"_ustr, m_aCtlPosition))
, m_xCtlXRectPreview(new weld::CustomWeld(*m_xBuilder, u"CTL_COLOR_PREVIEW"_ustr, m_aCtlXRectPreview))
{
// this page needs ExchangeSupport
SetExchangeSupport();
// adjust metric
FieldUnit eFUnit = GetModuleFieldUnit( rInAttrs );
switch ( eFUnit )
{
case FieldUnit::M:
case FieldUnit::KM:
eFUnit = FieldUnit::MM;
break;
default: ;//prevent warning
}
SetFieldUnit( *m_xMtrDistance, eFUnit );
// determine PoolUnit
SfxItemPool* pPool = m_rOutAttrs.GetPool();
assert(pPool && "Where is the pool?");
m_ePoolUnit = pPool->GetMetric( SDRATTR_SHADOWXDIST );
// setting the output device
drawing::FillStyle eXFS = drawing::FillStyle_SOLID;
if( m_rOutAttrs.GetItemState( XATTR_FILLSTYLE ) != SfxItemState::INVALID )
{
eXFS = m_rOutAttrs.Get( GetWhich( XATTR_FILLSTYLE ) ).GetValue();
switch( eXFS )
{
case drawing::FillStyle_SOLID:
if( SfxItemState::INVALID != m_rOutAttrs.GetItemState( XATTR_FILLCOLOR ) )
{
m_aFillAttributeSet.Put( m_rOutAttrs.Get( XATTR_FILLCOLOR ) );
}
break;
case drawing::FillStyle_GRADIENT:
if( SfxItemState::INVALID != m_rOutAttrs.GetItemState( XATTR_FILLGRADIENT ) )
{
m_aFillAttributeSet.Put( m_rOutAttrs.Get( XATTR_FILLGRADIENT ) );
}
break;
case drawing::FillStyle_HATCH:
if( SfxItemState::INVALID != m_rOutAttrs.GetItemState( XATTR_FILLHATCH ) )
{
m_aFillAttributeSet.Put( m_rOutAttrs.Get( XATTR_FILLHATCH ) );
}
break;
case drawing::FillStyle_BITMAP:
{
if( SfxItemState::INVALID != m_rOutAttrs.GetItemState( XATTR_FILLBITMAP ) )
{
m_aFillAttributeSet.Put( m_rOutAttrs.Get( XATTR_FILLBITMAP ) );
}
}
break;
case drawing::FillStyle_NONE : break;
default: break;
}
}
else
{
m_aFillAttributeSet.Put( XFillColorItem( OUString(), COL_LIGHTRED ) );
}
if(drawing::FillStyle_NONE == eXFS)
{
// #i96350#
// fallback to solid fillmode when no fill mode is provided to have
// a reasonable shadow preview. The used color will be a set one or
// the default (currently blue8)
eXFS = drawing::FillStyle_SOLID;
}
m_aFillAttributeSet.Put( XFillStyleItem( eXFS ) );
m_aCtlXRectPreview.SetRectangleAttributes(m_aFillAttributeSet);
m_xTsbShowShadow->connect_toggled(LINK( this, SvxShadowTabPage, ClickShadowHdl_Impl));
m_xLbShadowColor->SetSelectHdl( LINK( this, SvxShadowTabPage, SelectShadowHdl_Impl ) );
Link<weld::MetricSpinButton&,void> aLink = LINK( this, SvxShadowTabPage, ModifyShadowHdl_Impl );
m_xLbShadowBlurMetric->connect_value_changed(aLink);
m_xMtrTransparent->connect_value_changed(aLink);
m_xMtrDistance->connect_value_changed(aLink);
}
SvxShadowTabPage::~SvxShadowTabPage()
{
m_xCtlXRectPreview.reset();
m_xLbShadowColor.reset();
m_xCtlPosition.reset();
m_xLbShadowBlurMetric.reset();
}
void SvxShadowTabPage::ActivatePage( const SfxItemSet& rSet )
{
const SfxUInt16Item* pPageTypeItem = rSet.GetItem<SfxUInt16Item>(SID_PAGE_TYPE, false);
if (pPageTypeItem)
SetPageType(static_cast<PageType>(pPageTypeItem->GetValue()));
if( m_nDlgType != 0 )
return;
if( !m_pColorList.is() )
return;
// ColorList
if( *m_pnColorListState & ChangeType::CHANGED ||
*m_pnColorListState & ChangeType::MODIFIED )
{
if( *m_pnColorListState & ChangeType::CHANGED )
{
SvxAreaTabDialog* pArea = dynamic_cast<SvxAreaTabDialog*>(GetDialogController());
if( pArea )
{
m_pColorList = pArea->GetNewColorList();
}
else
{
SvxLineTabDialog* pLine = dynamic_cast<SvxLineTabDialog*>(GetDialogController());
if( pLine )
m_pColorList = pLine->GetNewColorList();
}
}
SfxItemSet rAttribs( rSet );
// rSet contains shadow attributes too, but we want
// to use it for updating rectangle attributes only,
// so set the shadow to none here
SdrOnOffItem aItem( makeSdrShadowItem( false ));
rAttribs.Put( aItem );
m_aCtlXRectPreview.SetRectangleAttributes( rAttribs );
ModifyShadowHdl_Impl( *m_xMtrTransparent );
}
m_nPageType = PageType::Shadow;
}
DeactivateRC SvxShadowTabPage::DeactivatePage( SfxItemSet* _pSet )
{
if( _pSet )
FillItemSet( _pSet );
return DeactivateRC::LeavePage;
}
bool SvxShadowTabPage::FillItemSet( SfxItemSet* rAttrs )
{
bool bModified = false;
const SfxPoolItem* pOld = nullptr;
if (m_xTsbShowShadow->get_state_changed_from_saved())
{
TriState eState = m_xTsbShowShadow->get_state();
assert(eState != TRISTATE_INDET);
// given how m_xTsbShowShadow is set up and saved in Reset(),
// eState == TRISTATE_INDET would imply
// !IsValueChangedFromSaved()
SdrOnOffItem aItem( makeSdrShadowItem(eState == TRISTATE_TRUE) );
pOld = GetOldItem( *rAttrs, SDRATTR_SHADOW );
if ( !pOld || !( *static_cast<const SdrOnOffItem*>(pOld) == aItem ) )
{
rAttrs->Put( aItem );
bModified = true;
}
}
// shadow removal
// a bit intricate inquiry whether there was something changed,
// as the items can't be displayed directly on controls
sal_Int32 nX = 0, nY = 0;
sal_Int32 nXY = GetCoreValue( *m_xMtrDistance, m_ePoolUnit );
switch (m_aCtlPosition.GetActualRP())
{
case RectPoint::LT: nX = nY = -nXY; break;
case RectPoint::MT: nY = -nXY; break;
case RectPoint::RT: nX = nXY; nY = -nXY; break;
case RectPoint::LM: nX = -nXY; break;
case RectPoint::RM: nX = nXY; break;
case RectPoint::LB: nX = -nXY; nY = nXY; break;
case RectPoint::MB: nY = nXY; break;
case RectPoint::RB: nX = nY = nXY; break;
case RectPoint::MM: break;
}
// If the values of the shadow distances==SfxItemState::INVALID and the displayed
// string in the respective MetricField=="", then the comparison of the old
// and the new distance values would return a wrong result because in such a
// case the new distance values would match the default values of the MetricField !!!!
if ( !m_xMtrDistance->get_text().isEmpty() ||
m_rOutAttrs.GetItemState( SDRATTR_SHADOWXDIST ) != SfxItemState::INVALID ||
m_rOutAttrs.GetItemState( SDRATTR_SHADOWYDIST ) != SfxItemState::INVALID )
{
sal_Int32 nOldX = 9876543; // impossible value, so DontCare
sal_Int32 nOldY = 9876543;
if( m_rOutAttrs.GetItemState( SDRATTR_SHADOWXDIST ) != SfxItemState::INVALID &&
m_rOutAttrs.GetItemState( SDRATTR_SHADOWYDIST ) != SfxItemState::INVALID )
{
nOldX = m_rOutAttrs.Get( SDRATTR_SHADOWXDIST ).GetValue();
nOldY = m_rOutAttrs.Get( SDRATTR_SHADOWYDIST ).GetValue();
}
SdrMetricItem aXItem( makeSdrShadowXDistItem(nX) );
pOld = GetOldItem( *rAttrs, SDRATTR_SHADOWXDIST );
if ( nX != nOldX &&
( !pOld || !( *static_cast<const SdrMetricItem*>(pOld) == aXItem ) ) )
{
rAttrs->Put( aXItem );
bModified = true;
}
SdrMetricItem aYItem( makeSdrShadowYDistItem(nY) );
pOld = GetOldItem( *rAttrs, SDRATTR_SHADOWYDIST );
if ( nY != nOldY &&
( !pOld || !( *static_cast<const SdrMetricItem*>(pOld) == aYItem ) ) )
{
rAttrs->Put( aYItem );
bModified = true;
}
}
// ShadowColor
{
XColorItem aItem(makeSdrShadowColorItem(m_xLbShadowColor->GetSelectEntryColor()));
pOld = GetOldItem( *rAttrs, SDRATTR_SHADOWCOLOR );
if ( !pOld || !( *static_cast<const XColorItem*>(pOld) == aItem ) )
{
rAttrs->Put( aItem );
bModified = true;
}
}
// transparency
sal_uInt16 nVal = static_cast<sal_uInt16>(m_xMtrTransparent->get_value(FieldUnit::PERCENT));
if (m_xMtrTransparent->get_value_changed_from_saved())
{
SdrPercentItem aItem( makeSdrShadowTransparenceItem(nVal) );
pOld = GetOldItem( *rAttrs, SDRATTR_SHADOWTRANSPARENCE );
if ( !pOld || !( *static_cast<const SdrPercentItem*>(pOld) == aItem ) )
{
rAttrs->Put( aItem );
bModified = true;
}
}
if (m_xLbShadowBlurMetric->get_value_changed_from_saved())
{
SdrMetricItem aItem(SDRATTR_SHADOWBLUR, m_xLbShadowBlurMetric->get_value(FieldUnit::MM_100TH));
pOld = GetOldItem( *rAttrs, SDRATTR_SHADOWBLUR );
if ( !pOld || !( *static_cast<const SdrMetricItem*>(pOld) == aItem ) )
{
rAttrs->Put( aItem );
bModified = true;
}
}
rAttrs->Put (CntUInt16Item(SID_PAGE_TYPE, static_cast<sal_uInt16>(m_nPageType)));
return bModified;
}
void SvxShadowTabPage::Reset( const SfxItemSet* rAttrs )
{
// all objects can have a shadow
// at the moment there are only 8 possible positions where a shadow can be set
// has a shadow been set?
if( rAttrs->GetItemState( SDRATTR_SHADOW ) != SfxItemState::INVALID )
{
if( rAttrs->Get( SDRATTR_SHADOW ).GetValue() )
m_xTsbShowShadow->set_state(TRISTATE_TRUE);
else
{
m_xTsbShowShadow->set_state(TRISTATE_FALSE);
}
}
else
m_xTsbShowShadow->set_state(TRISTATE_INDET);
// distance (only 8 possible positions),
// so there is only one item evaluated
if( rAttrs->GetItemState( SDRATTR_SHADOWXDIST ) != SfxItemState::INVALID &&
rAttrs->GetItemState( SDRATTR_SHADOWYDIST ) != SfxItemState::INVALID )
{
sal_Int32 nX = rAttrs->Get( SDRATTR_SHADOWXDIST ).GetValue();
sal_Int32 nY = rAttrs->Get( SDRATTR_SHADOWYDIST ).GetValue();
if( nX != 0 )
SetMetricValue( *m_xMtrDistance, nX < 0 ? -nX : nX, m_ePoolUnit );
else
SetMetricValue( *m_xMtrDistance, nY < 0 ? -nY : nY, m_ePoolUnit );
// setting the shadow control
if ( nX < 0 && nY < 0 ) m_aCtlPosition.SetActualRP( RectPoint::LT );
else if( nX == 0 && nY < 0 ) m_aCtlPosition.SetActualRP( RectPoint::MT );
else if( nX > 0 && nY < 0 ) m_aCtlPosition.SetActualRP( RectPoint::RT );
else if( nX < 0 && nY == 0 ) m_aCtlPosition.SetActualRP( RectPoint::LM );
// there's no center point anymore
else if( nX == 0 && nY == 0 ) m_aCtlPosition.SetActualRP( RectPoint::RB );
else if( nX > 0 && nY == 0 ) m_aCtlPosition.SetActualRP( RectPoint::RM );
else if( nX < 0 && nY > 0 ) m_aCtlPosition.SetActualRP( RectPoint::LB );
else if( nX == 0 && nY > 0 ) m_aCtlPosition.SetActualRP( RectPoint::MB );
else if( nX > 0 && nY > 0 ) m_aCtlPosition.SetActualRP( RectPoint::RB );
}
else
{
// determine default-distance
SfxItemPool* pPool = m_rOutAttrs.GetPool();
{
sal_Int32 n = pPool->GetUserOrPoolDefaultItem(SDRATTR_SHADOWXDIST).GetValue();
if (n == 0)
n = pPool->GetUserOrPoolDefaultItem(SDRATTR_SHADOWYDIST).GetValue();
SetMetricValue(*m_xMtrDistance, std::abs(n), m_ePoolUnit);
}
// Tristate, e. g. multiple objects have been marked of which some have a shadow and some don't.
// The text (which shall be displayed) of the MetricFields is set to "" and serves as an
// identification in the method FillItemSet for the fact that the distance value was NOT changed !!!!
m_xMtrDistance->set_text( u""_ustr );
m_aCtlPosition.SetActualRP( RectPoint::MM );
}
m_aCtlPosition.SaveValue();
if( rAttrs->GetItemState( SDRATTR_SHADOWCOLOR ) != SfxItemState::INVALID )
{
m_xLbShadowColor->SelectEntry( rAttrs->Get( SDRATTR_SHADOWCOLOR ).GetColorValue() );
}
else
m_xLbShadowColor->SetNoSelection();
if( rAttrs->GetItemState( SDRATTR_SHADOWTRANSPARENCE ) != SfxItemState::INVALID )
{
sal_uInt16 nTransp = rAttrs->Get( SDRATTR_SHADOWTRANSPARENCE ).GetValue();
m_xMtrTransparent->set_value(nTransp, FieldUnit::PERCENT);
}
else
m_xMtrTransparent->set_text(u""_ustr);
if( rAttrs->GetItemState( SDRATTR_SHADOWBLUR ) != SfxItemState::INVALID )
{
sal_uInt16 nBlur = rAttrs->Get( SDRATTR_SHADOWBLUR ).GetValue();
m_xLbShadowBlurMetric->set_value(nBlur, FieldUnit::MM_100TH);
}
else
m_xLbShadowBlurMetric->set_text(u""_ustr);
//aCtlPosition
m_xMtrDistance->save_value();
m_xLbShadowColor->SaveValue();
m_xTsbShowShadow->save_state();
m_xLbShadowBlurMetric->save_value();
// #66832# This field was not saved, but used to determine changes.
// Why? Seems to be the error.
// It IS the error.
m_xMtrTransparent->save_value();
ClickShadowHdl_Impl(*m_xTsbShowShadow);
ModifyShadowHdl_Impl(*m_xMtrTransparent);
}
std::unique_ptr<SfxTabPage> SvxShadowTabPage::Create( weld::Container* pPage, weld::DialogController* pController,
const SfxItemSet* rAttrs )
{
return std::make_unique<SvxShadowTabPage>(pPage, pController, *rAttrs);
}
IMPL_LINK_NOARG(SvxShadowTabPage, ClickShadowHdl_Impl, weld::Toggleable&, void)
{
if (m_xTsbShowShadow->get_state() == TRISTATE_FALSE)
{
m_xGridShadow->set_sensitive(false);
m_xCtlPosition->set_sensitive(false);
}
else
{
m_xGridShadow->set_sensitive(true);
m_xCtlPosition->set_sensitive(true);
}
m_aCtlPosition.Invalidate();
ModifyShadowHdl_Impl(*m_xMtrTransparent);
}
IMPL_LINK_NOARG(SvxShadowTabPage, SelectShadowHdl_Impl, ColorListBox&, void)
{
ModifyShadowHdl_Impl(*m_xMtrTransparent);
}
IMPL_LINK_NOARG(SvxShadowTabPage, ModifyShadowHdl_Impl, weld::MetricSpinButton&, void)
{
if (m_xTsbShowShadow->get_state() == TRISTATE_TRUE)
m_aFillAttributeSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
else
m_aFillAttributeSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
m_aFillAttributeSet.Put( XFillColorItem( OUString(), m_xLbShadowColor->GetSelectEntryColor() ) );
sal_uInt16 nVal = static_cast<sal_uInt16>(m_xMtrTransparent->get_value(FieldUnit::PERCENT));
m_aFillAttributeSet.Put( XFillTransparenceItem( nVal ) );
// shadow removal
sal_Int32 nX = 0, nY = 0;
sal_Int32 nXY = GetCoreValue( *m_xMtrDistance, m_ePoolUnit );
switch( m_aCtlPosition.GetActualRP() )
{
case RectPoint::LT: nX = nY = -nXY; break;
case RectPoint::MT: nY = -nXY; break;
case RectPoint::RT: nX = nXY; nY = -nXY; break;
case RectPoint::LM: nX = -nXY; break;
case RectPoint::RM: nX = nXY; break;
case RectPoint::LB: nX = -nXY; nY = nXY; break;
case RectPoint::MB: nY = nXY; break;
case RectPoint::RB: nX = nY = nXY; break;
case RectPoint::MM: break;
}
m_aCtlXRectPreview.SetShadowPosition(Point(nX, nY));
m_aCtlXRectPreview.SetShadowAttributes(m_aFillAttributeSet);
m_aCtlXRectPreview.Invalidate();
}
void SvxShadowTabPage::PointChanged( weld::DrawingArea*, RectPoint )
{
// repaint shadow
ModifyShadowHdl_Impl( *m_xMtrTransparent );
}
void SvxShadowTabPage::PageCreated(const SfxAllItemSet& aSet)
{
const SvxColorListItem* pColorListItem = aSet.GetItem<SvxColorListItem>(SID_COLOR_TABLE, false);
const SfxUInt16Item* pPageTypeItem = aSet.GetItem<SfxUInt16Item>(SID_PAGE_TYPE, false);
const SfxUInt16Item* pDlgTypeItem = aSet.GetItem<SfxUInt16Item>(SID_DLG_TYPE, false);
if (pColorListItem)
SetColorList(pColorListItem->GetColorList());
if (pPageTypeItem)
SetPageType(static_cast<PageType>(pPageTypeItem->GetValue()));
if (pDlgTypeItem)
SetDlgType(pDlgTypeItem->GetValue());
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */