/* -*- 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 <sal/config.h>
#include <algorithm>
#include "PosSizePropertyPanel.hxx"
#include <sal/log.hxx>
#include <svx/svxids.hrc>
#include <sfx2/dispatch.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/module.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/weldutils.hxx>
#include <svx/dialcontrol.hxx>
#include <svx/dialmgr.hxx>
#include <svx/rectenum.hxx>
#include <svx/sdangitm.hxx>
#include <unotools/viewoptions.hxx>
#include <unotools/localedatawrapper.hxx>
#include <utility>
#include <vcl/canvastools.hxx>
#include <vcl/fieldvalues.hxx>
#include <svl/intitem.hxx>
#include <svx/strings.hrc>
#include <svx/svdpagv.hxx>
#include <svx/svdview.hxx>
#include <svx/transfrmhelper.hxx>
#include <boost/property_tree/ptree.hpp>
#include <svtools/unitconv.hxx>
#include <bitmaps.hlst>
using namespace css;
using namespace css::uno;
constexpr OUString USERITEM_NAME = u
"FitItem" _ustr;
namespace svx::sidebar {
PosSizePropertyPanel::PosSizePropertyPanel(
weld::Widget* pParent,
const css::uno::Reference<css::frame::XFrame>& rxFrame,
SfxBindings* pBindings,
css::uno::Reference<css::ui::XSidebar> xSidebar)
: PanelLayout(pParent, u
"PosSizePropertyPanel" _ustr, u
"svx/ui/sidebarpossize.ui" _us
tr),
m_aRatioTop(ConnectorType::Top),
m_aRatioBottom(ConnectorType::Bottom),
mxFtPosX(m_xBuilder->weld_label(u"horizontallabel" _ustr)),
mxMtrPosX(m_xBuilder->weld_metric_spin_button(u"horizontalpos" _ustr, FieldUnit::CM)),
mxFtPosY(m_xBuilder->weld_label(u"verticallabel" _ustr)),
mxMtrPosY(m_xBuilder->weld_metric_spin_button(u"verticalpos" _ustr, FieldUnit::CM)),
mxFtWidth(m_xBuilder->weld_label(u"widthlabel" _ustr)),
mxMtrWidth(m_xBuilder->weld_metric_spin_button(u"selectwidth" _ustr, FieldUnit::CM)),
mxFtHeight(m_xBuilder->weld_label(u"heightlabel" _ustr)),
mxMtrHeight(m_xBuilder->weld_metric_spin_button(u"selectheight" _ustr, FieldUnit::CM))
, mxCbxScale(m_xBuilder->weld_check_button(u"ratio" _ustr))
, m_xCbxScaleImg(m_xBuilder->weld_image(u"imRatio" _ustr))
, m_xImgRatioTop(new weld::CustomWeld(*m_xBuilder, u"daRatioTop" _ustr, m_aRatioTop))
, m_xImgRatioBottom(new weld::CustomWeld(*m_xBuilder, u"daRatioBottom" _ustr, m_aRatioBottom))
, mxFtAngle(m_xBuilder->weld_label(u"rotationlabel" _ustr))
, mxMtrAngle(m_xBuilder->weld_metric_spin_button(u"rotation" _ustr, FieldUnit::DEGREE)),
mxCtrlDial(new DialControl),
mxDial(new weld::CustomWeld(*m_xBuilder, u"orientationcontrol" _ustr, *mxCtrlDial)),
mxFtFlip(m_xBuilder->weld_label(u"fliplabel" _ustr)),
mxFlipTbx(m_xBuilder->weld_toolbar(u"selectrotationtype" _ustr)),
mxFlipDispatch(new ToolbarUnoDispatcher(*mxFlipTbx, *m_xBuilder, rxFrame)),
mxArrangeTbx(m_xBuilder->weld_toolbar(u"arrangetoolbar" _ustr)),
mxArrangeDispatch(new ToolbarUnoDispatcher(*mxArrangeTbx, *m_xBuilder, rxFrame)),
mxArrangeTbx2(m_xBuilder->weld_toolbar(u"arrangetoolbar2" _ustr)),
mxArrangeDispatch2(new ToolbarUnoDispatcher(*mxArrangeTbx2, *m_xBuilder, rxFrame)),
mxAlignTbx(m_xBuilder->weld_toolbar(u"aligntoolbar" _ustr)),
mxAlignDispatch(new ToolbarUnoDispatcher(*mxAlignTbx, *m_xBuilder, rxFrame)),
mxAlignTbx2(m_xBuilder->weld_toolbar(u"aligntoolbar2" _ustr)),
mxAlignDispatch2(new ToolbarUnoDispatcher(*mxAlignTbx2, *m_xBuilder, rxFrame)),
mxBtnEditOLEObject(m_xBuilder->weld_button(u"btnEditObject" _ustr)),
mpView(nullptr),
mlOldWidth(1),
mlOldHeight(1),
mlRotX(0),
mlRotY(0),
mePoolUnit(),
meDlgUnit(FieldUnit::INCH), // #i124409# init with fallback default
mbFieldMetricOutDated(true ),
maTransfPosXControl(SID_ATTR_TRANSFORM_POS_X, *pBindings, *this ),
maTransfPosYControl(SID_ATTR_TRANSFORM_POS_Y, *pBindings, *this ),
maTransfWidthControl(SID_ATTR_TRANSFORM_WIDTH, *pBindings, *this ),
maTransfHeightControl(SID_ATTR_TRANSFORM_HEIGHT, *pBindings, *this ),
maSvxAngleControl( SID_ATTR_TRANSFORM_ANGLE, *pBindings, *this ),
maRotXControl(SID_ATTR_TRANSFORM_ROT_X, *pBindings, *this ),
maRotYControl(SID_ATTR_TRANSFORM_ROT_Y, *pBindings, *this ),
maProPosControl(SID_ATTR_TRANSFORM_PROTECT_POS, *pBindings, *this ),
maProSizeControl(SID_ATTR_TRANSFORM_PROTECT_SIZE, *pBindings, *this ),
maAutoWidthControl(SID_ATTR_TRANSFORM_AUTOWIDTH, *pBindings, *this ),
maAutoHeightControl(SID_ATTR_TRANSFORM_AUTOHEIGHT, *pBindings, *this ),
m_aMetricCtl(SID_ATTR_METRIC, *pBindings, *this ),
mpBindings(pBindings),
mbSizeProtected(false ),
mbPositionProtected(false ),
mbAutoWidth(false ),
mbAutoHeight(false ),
mbAdjustEnabled(false ),
mbMtrPosXBlanked(false ),
mbMtrPosYBlanked(false ),
mbMtrWidthBlanked(false ),
mbMtrHeightBlanked(false ),
mbMtrAngleBlanked(false ),
mxSidebar(std::move(xSidebar))
{
Initialize();
// A guesstimate of the longest label in the various sidebar panes to use
// to get this pane's contents to align with them, for lack of a better
// solution
auto nWidth = mxFtWidth->get_preferred_size().Width();
OUString sLabel = mxFtWidth->get_label();
mxFtWidth->set_label(SvxResId(RID_SVXSTR_TRANSPARENCY));
nWidth = std::max(nWidth, mxFtWidth->get_preferred_size().Width());;
mxFtWidth->set_label(sLabel);
mxFtWidth->set_size_request(nWidth, -1);
// vertical alignment = fill makes the drawingarea expand the associated spinedits so we have to size it here
const sal_Int16 aHeight
= static_cast <sal_Int16>(std::max(int (mxCbxScale->get_preferred_size().getHeight() / 2
- mxMtrWidth->get_preferred_size().getHeight() / 2),
12));
const sal_Int16 aWidth
= static_cast <sal_Int16>(mxCbxScale->get_preferred_size().getWidth() / 2);
m_xImgRatioTop->set_size_request(aWidth, aHeight);
m_xImgRatioBottom->set_size_request(aWidth, aHeight);
//init needed for gtk3
m_xCbxScaleImg->set_from_icon_name(mxCbxScale->get_active() ? RID_SVXBMP_LOCKED
: RID_SVXBMP_UNLOCKED);
mpBindings->Update( SID_ATTR_METRIC );
mpBindings->Update( SID_ATTR_TRANSFORM_WIDTH );
mpBindings->Update( SID_ATTR_TRANSFORM_HEIGHT );
mpBindings->Update( SID_ATTR_TRANSFORM_PROTECT_SIZE );
}
PosSizePropertyPanel::~PosSizePropertyPanel()
{
mxFtPosX.reset();
mxMtrPosX.reset();
mxFtPosY.reset();
mxMtrPosY.reset();
mxFtWidth.reset();
mxMtrWidth.reset();
mxFtHeight.reset();
mxMtrHeight.reset();
mxCbxScale.reset();
mxFtAngle.reset();
mxMtrAngle.reset();
mxDial.reset();
mxCtrlDial.reset();
mxFtFlip.reset();
mxFlipDispatch.reset();
mxFlipTbx.reset();
mxAlignDispatch.reset();
mxAlignDispatch2.reset();
mxAlignTbx.reset();
mxAlignTbx2.reset();
mxArrangeDispatch.reset();
mxArrangeDispatch2.reset();
mxArrangeTbx.reset();
mxArrangeTbx2.reset();
mxBtnEditOLEObject.reset();
maTransfPosXControl.dispose();
maTransfPosYControl.dispose();
maTransfWidthControl.dispose();
maTransfHeightControl.dispose();
maSvxAngleControl.dispose();
maRotXControl.dispose();
maRotYControl.dispose();
maProPosControl.dispose();
maProSizeControl.dispose();
maAutoWidthControl.dispose();
maAutoHeightControl.dispose();
m_aMetricCtl.dispose();
}
namespace
{
bool hasText(const SdrView& rSdrView)
{
const SdrMarkList& rMarkList = rSdrView.GetMarkedObjectList();
if (1 == rMarkList.GetMarkCount())
{
const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
const SdrObjKind eKind(pObj->GetObjIdentifier());
if ((pObj->GetObjInventor() == SdrInventor::Default ) && (SdrObjKind::Text == eKind || SdrObjKind::TitleText == eKind || SdrObjKind::OutlineText == eKind))
{
const SdrTextObj* pSdrTextObj = DynCastSdrTextObj(pObj);
if (pSdrTextObj && pSdrTextObj->HasText())
{
return true ;
}
}
}
return false ;
}
} // end of anonymous namespace
void PosSizePropertyPanel::Initialize()
{
//Position : Horizontal / Vertical
mxMtrPosX->connect_value_changed( LINK( this , PosSizePropertyPanel, ChangePosXHdl ) );
mxMtrPosY->connect_value_changed( LINK( this , PosSizePropertyPanel, ChangePosYHdl ) );
//Size : Width / Height
mxMtrWidth->connect_value_changed( LINK( this , PosSizePropertyPanel, ChangeWidthHdl ) );
mxMtrHeight->connect_value_changed( LINK( this , PosSizePropertyPanel, ChangeHeightHdl ) );
//Size : Keep ratio
mxCbxScale->connect_toggled( LINK( this , PosSizePropertyPanel, ClickAutoHdl ) );
//rotation control
mxCtrlDial->SetLinkedField(mxMtrAngle.get(), 2);
mxCtrlDial->SetModifyHdl(LINK( this , PosSizePropertyPanel, RotationHdl));
//use same logic as DialControl_Impl::SetSize
weld::DrawingArea* pDrawingArea = mxCtrlDial->GetDrawingArea();
int nDim = (std::min<int >(pDrawingArea->get_approximate_digit_width() * 6,
pDrawingArea->get_text_height() * 3) - 1) | 1;
Size aSize(nDim, nDim);
pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
mxCtrlDial->Init(aSize);
mxBtnEditOLEObject->connect_clicked( LINK( this , PosSizePropertyPanel, ClickObjectEditHdl ) );
SfxViewShell* pCurSh = SfxViewShell::Current();
if ( pCurSh )
mpView = pCurSh->GetDrawView();
else
mpView = nullptr;
if ( mpView != nullptr )
{
maUIScale = mpView->GetModel().GetUIScale();
mbAdjustEnabled = hasText(*mpView);
}
mePoolUnit = maTransfWidthControl.GetCoreMetric();
}
std::unique_ptr<PanelLayout> PosSizePropertyPanel::Create (
weld::Widget* pParent,
const css::uno::Reference<css::frame::XFrame>& rxFrame,
SfxBindings* pBindings,
const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
{
if (pParent == nullptr)
throw lang::IllegalArgumentException(u"no parent Window given to PosSizePropertyPanel::Create" _ustr, nullptr, 0);
if ( ! rxFrame.is())
throw lang::IllegalArgumentException(u"no XFrame given to PosSizePropertyPanel::Create" _ustr, nullptr, 1);
if (pBindings == nullptr)
throw lang::IllegalArgumentException(u"no SfxBindings given to PosSizePropertyPanel::Create" _ustr, nullptr, 2);
return std::make_unique<PosSizePropertyPanel>(pParent, rxFrame, pBindings, rxSidebar);
}
void PosSizePropertyPanel::HandleContextChange(
const vcl::EnumContext& rContext)
{
if (maContext == rContext)
{
// Nothing to do.
return ;
}
maContext = rContext;
bool bShowPosition = false ;
bool bShowAngle = false ;
bool bShowFlip = false ;
bool bShowEditObject = false ;
bool bShowArrangeTbx2 = false ;
switch (maContext.GetCombinedContext_DI())
{
case CombinedEnumContext(Application::WriterVariants, Context::Draw):
bShowAngle = true ;
bShowFlip = true ;
bShowArrangeTbx2 = true ;
break ;
case CombinedEnumContext(Application::WriterVariants, Context::Graphic):
bShowFlip = true ;
bShowAngle = true ; // RotGrfFlyFrame: Writer FlyFrames for Graphics now support angle
break ;
case CombinedEnumContext(Application::Calc, Context::Draw):
case CombinedEnumContext(Application::Calc, Context::DrawLine):
case CombinedEnumContext(Application::Calc, Context::Graphic):
case CombinedEnumContext(Application::DrawImpress, Context::Draw):
case CombinedEnumContext(Application::DrawImpress, Context::DrawLine):
case CombinedEnumContext(Application::DrawImpress, Context::TextObject):
case CombinedEnumContext(Application::DrawImpress, Context::Graphic):
bShowPosition = true ;
bShowAngle = true ;
bShowFlip = true ;
break ;
case CombinedEnumContext(Application::WriterVariants, Context::OLE):
bShowEditObject = true ;
break ;
case CombinedEnumContext(Application::Calc, Context::OLE):
case CombinedEnumContext(Application::DrawImpress, Context::OLE):
bShowPosition = true ;
bShowEditObject = true ;
break ;
case CombinedEnumContext(Application::Calc, Context::Chart):
case CombinedEnumContext(Application::Calc, Context::Form):
case CombinedEnumContext(Application::Calc, Context::Media):
case CombinedEnumContext(Application::Calc, Context::MultiObject):
case CombinedEnumContext(Application::DrawImpress, Context::Media):
case CombinedEnumContext(Application::DrawImpress, Context::Form):
case CombinedEnumContext(Application::DrawImpress, Context::ThreeDObject):
case CombinedEnumContext(Application::DrawImpress, Context::MultiObject):
bShowPosition = true ;
break ;
}
// Position
mxFtPosX->set_visible(bShowPosition);
mxMtrPosX->set_visible(bShowPosition);
mxFtPosY->set_visible(bShowPosition);
mxMtrPosY->set_visible(bShowPosition);
// Rotation
mxFtAngle->set_visible(bShowAngle);
mxMtrAngle->set_visible(bShowAngle);
mxCtrlDial->set_visible(bShowAngle);
// Flip
mxFtFlip->set_visible(bShowFlip);
mxFlipTbx->set_visible(bShowFlip);
// Edit Object
mxBtnEditOLEObject->set_visible(bShowEditObject);
// Arrange tool bar 2
mxArrangeTbx2->set_visible(bShowArrangeTbx2);
if (mxSidebar.is())
mxSidebar->requestLayout();
}
IMPL_LINK_NOARG( PosSizePropertyPanel, ChangeWidthHdl, weld::MetricSpinButton&, void )
{
if ( mxCbxScale->get_active() &&
mxCbxScale->get_sensitive() )
{
tools::Long nHeight = static_cast <tools::Long >( (static_cast <double >(mlOldHeight) * static_cast <double >(mxMtrWidth->get_value(FieldUnit::NONE))) / static_cast <double >(mlOldWidth) );
if ( nHeight <= mxMtrHeight->get_max( FieldUnit::NONE ) )
{
mxMtrHeight->set_value( nHeight, FieldUnit::NONE );
}
else
{
nHeight = static_cast <tools::Long >(mxMtrHeight->get_max( FieldUnit::NONE ));
mxMtrHeight->set_value(nHeight, FieldUnit::NONE);
const tools::Long nWidth = static_cast <tools::Long >( (static_cast <double >(mlOldWidth) * static_cast <double >(nHeight)) / static_cast <double >(mlOldHeight) );
mxMtrWidth->set_value( nWidth, FieldUnit::NONE );
}
}
executeSize();
}
IMPL_LINK_NOARG( PosSizePropertyPanel, ChangeHeightHdl, weld::MetricSpinButton&, void )
{
if ( mxCbxScale->get_active() &&
mxCbxScale->get_sensitive() )
{
tools::Long nWidth = static_cast <tools::Long >( (static_cast <double >(mlOldWidth) * static_cast <double >(mxMtrHeight->get_value(FieldUnit::NONE))) / static_cast <double >(mlOldHeight) );
if ( nWidth <= mxMtrWidth->get_max( FieldUnit::NONE ) )
{
mxMtrWidth->set_value( nWidth, FieldUnit::NONE );
}
else
{
nWidth = static_cast <tools::Long >(mxMtrWidth->get_max( FieldUnit::NONE ));
mxMtrWidth->set_value( nWidth, FieldUnit::NONE );
const tools::Long nHeight = static_cast <tools::Long >( (static_cast <double >(mlOldHeight) * static_cast <double >(nWidth)) / static_cast <double >(mlOldWidth) );
mxMtrHeight->set_value( nHeight, FieldUnit::NONE );
}
}
executeSize();
}
IMPL_LINK_NOARG( PosSizePropertyPanel, ChangePosXHdl, weld::MetricSpinButton&, void )
{
if ( mxMtrPosX->get_value_changed_from_saved())
{
tools::Long lX = GetCoreValue( *mxMtrPosX, mePoolUnit );
Fraction aUIScale = mpView->GetModel().GetUIScale();
lX = tools::Long ( lX * aUIScale );
SfxInt32Item aPosXItem( SID_ATTR_TRANSFORM_POS_X,static_cast <sal_uInt32>(lX));
GetBindings()->GetDispatcher()->ExecuteList(
SID_ATTR_TRANSFORM, SfxCallMode::RECORD, { &aPosXItem });
}
}
IMPL_LINK_NOARG( PosSizePropertyPanel, ChangePosYHdl, weld::MetricSpinButton&, void )
{
if ( mxMtrPosY->get_value_changed_from_saved() )
{
tools::Long lY = GetCoreValue( *mxMtrPosY, mePoolUnit );
Fraction aUIScale = mpView->GetModel().GetUIScale();
lY = tools::Long ( lY * aUIScale );
SfxInt32Item aPosYItem( SID_ATTR_TRANSFORM_POS_Y,static_cast <sal_uInt32>(lY));
GetBindings()->GetDispatcher()->ExecuteList(
SID_ATTR_TRANSFORM, SfxCallMode::RECORD, { &aPosYItem });
}
}
IMPL_LINK_NOARG( PosSizePropertyPanel, ClickAutoHdl, weld::Toggleable&, void )
{
m_xCbxScaleImg->set_from_icon_name(mxCbxScale->get_active() ? RID_SVXBMP_LOCKED : RID_SVXBMP_UNLOCKED);
if ( mxCbxScale->get_active() )
{
mlOldWidth = std::max(GetCoreValue(*mxMtrWidth, mePoolUnit), SAL_CONST_INT64(1));
mlOldHeight = std::max(GetCoreValue(*mxMtrHeight, mePoolUnit), SAL_CONST_INT64(1));
}
// mxCbxScale must synchronized with that on Position and Size tabpage on Shape Properties dialog
SvtViewOptions aPageOpt(EViewType::TabPage, u"cui/ui/possizetabpage/PositionAndSize" _ustr);
aPageOpt.SetUserItem( USERITEM_NAME, css::uno::Any( OUString::number( int (mxCbxScale->get_active()) ) ) );
}
IMPL_LINK_NOARG( PosSizePropertyPanel, RotationHdl, DialControl&, void )
{
Degree100 nTmp = mxCtrlDial->GetRotation();
// #i123993# Need to take UIScale into account when executing rotations
const double fUIScale(mpView ? double (mpView->GetModel().GetUIScale()) : 1.0);
SdrAngleItem aAngleItem( SID_ATTR_TRANSFORM_ANGLE, nTmp);
SfxInt32Item aRotXItem( SID_ATTR_TRANSFORM_ROT_X, basegfx::fround(mlRotX * fUIScale));
SfxInt32Item aRotYItem( SID_ATTR_TRANSFORM_ROT_Y, basegfx::fround(mlRotY * fUIScale));
GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
SfxCallMode::RECORD, { &aAngleItem, &aRotXItem, &aRotYItem });
}
IMPL_STATIC_LINK_NOARG( PosSizePropertyPanel, ClickObjectEditHdl, weld::Button&, void )
{
SfxViewShell* pCurSh = SfxViewShell::Current();
if ( pCurSh)
{
pCurSh->DoVerb( -1 );
}
}
namespace
{
void limitWidth(weld::MetricSpinButton& rMetricSpinButton)
{
// space is limited in the sidebar, so limit MetricSpinButtons to a width of 7 digits
const int nMaxDigits = 7;
weld::SpinButton& rSpinButton = rMetricSpinButton.get_widget();
rSpinButton.set_width_chars(std::min(rSpinButton.get_width_chars(), nMaxDigits));
}
}
void PosSizePropertyPanel::NotifyItemUpdate(
sal_uInt16 nSID,
SfxItemState eState,
const SfxPoolItem* pState)
{
mxFtAngle->set_sensitive(true );
mxMtrAngle->set_sensitive(true );
mxDial->set_sensitive(true );
mxFtFlip->set_sensitive(true );
mxFlipTbx->set_sensitive(true );
const SfxUInt32Item* pWidthItem;
const SfxUInt32Item* pHeightItem;
SfxViewShell* pCurSh = SfxViewShell::Current();
if ( pCurSh )
mpView = pCurSh->GetDrawView();
else
mpView = nullptr;
if ( mpView == nullptr )
return ;
mbAdjustEnabled = hasText(*mpView);
// Pool unit and dialog unit may have changed, make sure that we
// have the current values.
mePoolUnit = maTransfWidthControl.GetCoreMetric();
switch (nSID)
{
case SID_ATTR_TRANSFORM_WIDTH:
if ( SfxItemState::DEFAULT == eState )
{
pWidthItem = dynamic_cast < const SfxUInt32Item* >(pState);
if (pWidthItem)
{
tools::Long lOldWidth1 = tools::Long ( pWidthItem->GetValue() / maUIScale );
SetFieldUnit( *mxMtrWidth, meDlgUnit, true );
SetMetricValue( *mxMtrWidth, lOldWidth1, mePoolUnit );
limitWidth(*mxMtrWidth);
mlOldWidth = lOldWidth1;
mxMtrWidth->save_value();
if (mbMtrWidthBlanked)
{
mxMtrWidth->reformat();
mbMtrWidthBlanked = false ;
}
break ;
}
}
mbMtrWidthBlanked = true ;
break ;
case SID_ATTR_TRANSFORM_HEIGHT:
if ( SfxItemState::DEFAULT == eState )
{
pHeightItem = dynamic_cast < const SfxUInt32Item* >(pState);
if (pHeightItem)
{
tools::Long nTmp = tools::Long ( pHeightItem->GetValue() / maUIScale);
SetFieldUnit( *mxMtrHeight, meDlgUnit, true );
SetMetricValue( *mxMtrHeight, nTmp, mePoolUnit );
limitWidth(*mxMtrHeight);
mlOldHeight = nTmp;
mxMtrHeight->save_value();
if (mbMtrHeightBlanked)
{
mxMtrHeight->reformat();
mbMtrHeightBlanked = false ;
}
break ;
}
}
mbMtrHeightBlanked = true ;
break ;
case SID_ATTR_TRANSFORM_POS_X:
if (SfxItemState::DEFAULT == eState)
{
const SfxInt32Item* pItem = dynamic_cast < const SfxInt32Item* >(pState);
if (pItem)
{
tools::Long nTmp = tools::Long (pItem->GetValue() / maUIScale);
SetFieldUnit( *mxMtrPosX, meDlgUnit, true );
SetMetricValue( *mxMtrPosX, nTmp, mePoolUnit );
limitWidth(*mxMtrPosX);
mxMtrPosX->save_value();
if (mbMtrPosXBlanked)
{
mxMtrPosX->reformat();
mbMtrPosXBlanked = false ;
}
break ;
}
}
mbMtrPosXBlanked = true ;
break ;
case SID_ATTR_TRANSFORM_POS_Y:
if (SfxItemState::DEFAULT == eState)
{
const SfxInt32Item* pItem = dynamic_cast < const SfxInt32Item* >(pState);
if (pItem)
{
tools::Long nTmp = tools::Long (pItem->GetValue() / maUIScale);
SetFieldUnit( *mxMtrPosY, meDlgUnit, true );
SetMetricValue( *mxMtrPosY, nTmp, mePoolUnit );
limitWidth(*mxMtrPosY);
mxMtrPosY->save_value();
if (mbMtrPosYBlanked)
{
mxMtrPosY->reformat();
mbMtrPosYBlanked = false ;
}
break ;
}
}
mbMtrPosYBlanked = true ;
break ;
case SID_ATTR_TRANSFORM_ROT_X:
if (SfxItemState::DEFAULT == eState)
{
const SfxInt32Item* pItem = dynamic_cast < const SfxInt32Item* >(pState);
if (pItem)
{
mlRotX = pItem->GetValue();
mlRotX = tools::Long ( mlRotX / maUIScale );
}
}
break ;
case SID_ATTR_TRANSFORM_ROT_Y:
if (SfxItemState::DEFAULT == eState)
{
const SfxInt32Item* pItem = dynamic_cast < const SfxInt32Item* >(pState);
if (pItem)
{
mlRotY = pItem->GetValue();
mlRotY = tools::Long ( mlRotY / maUIScale );
}
}
break ;
case SID_ATTR_TRANSFORM_PROTECT_POS:
if (SfxItemState::DEFAULT == eState)
{
const SfxBoolItem* pItem = dynamic_cast < const SfxBoolItem* >(pState);
if (pItem)
{
// record the state of position protect
mbPositionProtected = pItem->GetValue();
break ;
}
}
mbPositionProtected = false ;
break ;
case SID_ATTR_TRANSFORM_PROTECT_SIZE:
if (SfxItemState::DEFAULT == eState)
{
const SfxBoolItem* pItem = dynamic_cast < const SfxBoolItem* >(pState);
if (pItem)
{
// record the state of size protect
mbSizeProtected = pItem->GetValue();
break ;
}
}
mbSizeProtected = false ;
break ;
case SID_ATTR_TRANSFORM_AUTOWIDTH:
if (SfxItemState::DEFAULT == eState)
{
const SfxBoolItem* pItem = dynamic_cast < const SfxBoolItem* >(pState);
if (pItem)
{
mbAutoWidth = pItem->GetValue();
}
}
break ;
case SID_ATTR_TRANSFORM_AUTOHEIGHT:
if (SfxItemState::DEFAULT == eState)
{
const SfxBoolItem* pItem = dynamic_cast < const SfxBoolItem* >(pState);
if (pItem)
{
mbAutoHeight = pItem->GetValue();
}
}
break ;
case SID_ATTR_TRANSFORM_ANGLE:
if (eState >= SfxItemState::DEFAULT )
{
const SdrAngleItem* pItem = dynamic_cast < const SdrAngleItem* >(pState);
if (pItem)
{
Degree100 nTmp = NormAngle36000(pItem->GetValue());
mxMtrAngle->set_value(nTmp.get(), FieldUnit::DEGREE);
mxCtrlDial->SetRotation(nTmp);
if (mbMtrAngleBlanked)
{
mxMtrAngle->reformat();
mbMtrAngleBlanked = false ;
}
break ;
}
}
mbMtrAngleBlanked = true ;
mxCtrlDial->SetRotation( 0_deg100 );
break ;
case SID_ATTR_METRIC:
{
const Fraction aUIScale(mpView->GetModel().GetUIScale());
MetricState(eState, pState, aUIScale);
UpdateUIScale(aUIScale);
mbFieldMetricOutDated = false ;
break ;
}
default :
break ;
}
const sal_Int32 nCombinedContext(maContext.GetCombinedContext_DI());
const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
switch (rMarkList.GetMarkCount())
{
case 0:
break ;
case 1:
{
const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
const SdrObjKind eKind(pObj->GetObjIdentifier());
if (((nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::Draw)
|| nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::TextObject)
) && SdrObjKind::Edge == eKind)
|| SdrObjKind::Caption == eKind)
{
mxFtAngle->set_sensitive(false );
mxMtrAngle->set_sensitive(false );
mxDial->set_sensitive(false );
mxFlipTbx->set_sensitive(false );
mxFtFlip->set_sensitive(false );
}
break ;
}
default :
{
sal_uInt16 nMarkObj = 0;
bool isNoEdge = true ;
while (isNoEdge && rMarkList.GetMark(nMarkObj))
{
const SdrObject* pObj = rMarkList.GetMark(nMarkObj)->GetMarkedSdrObj();
const SdrObjKind eKind(pObj->GetObjIdentifier());
if (((nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::Draw)
|| nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::TextObject)
) && SdrObjKind::Edge == eKind)
|| SdrObjKind::Caption == eKind)
{
isNoEdge = false ;
break ;
}
nMarkObj++;
}
if (!isNoEdge)
{
mxFtAngle->set_sensitive(false );
mxMtrAngle->set_sensitive(false );
mxDial->set_sensitive(false );
mxFlipTbx->set_sensitive(false );
mxFtFlip->set_sensitive(false );
}
break ;
}
}
if (nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::TextObject))
{
mxFlipTbx->set_sensitive(false );
mxFtFlip->set_sensitive(false );
}
DisableControls();
// mxCbxScale must synchronized with that on Position and Size tabpage on Shape Properties dialog
SvtViewOptions aPageOpt(EViewType::TabPage, u"cui/ui/possizetabpage/PositionAndSize" _ustr);
OUString sUserData;
css::uno::Any aUserItem = aPageOpt.GetUserItem( USERITEM_NAME );
OUString aTemp;
if ( aUserItem >>= aTemp )
sUserData = aTemp;
mxCbxScale->set_active(static_cast <bool >(sUserData.toInt32()));
m_xCbxScaleImg->set_from_icon_name(mxCbxScale->get_active() ? RID_SVXBMP_LOCKED : RID_SVXBMP_UNLOCKED);
}
void PosSizePropertyPanel::GetControlState(const sal_uInt16 nSID, boost::property_tree::ptree& rState)
{
weld::MetricSpinButton* pControl = nullptr;
switch (nSID)
{
case SID_ATTR_TRANSFORM_POS_X:
pControl = mxMtrPosX.get();
break ;
case SID_ATTR_TRANSFORM_POS_Y:
pControl = mxMtrPosY.get();
break ;
case SID_ATTR_TRANSFORM_WIDTH:
pControl = mxMtrWidth.get();
break ;
case SID_ATTR_TRANSFORM_HEIGHT:
pControl = mxMtrHeight.get();
break ;
}
if (pControl && !pControl->get_text().isEmpty())
{
OUString sValue = Application::GetSettings().GetNeutralLocaleDataWrapper().
getNum(pControl->get_value(pControl->get_unit()), pControl->get_digits(), false , false );
rState.put(pControl->get_buildable_name().toUtf8().getStr(), sValue.toUtf8().getStr());
}
}
void PosSizePropertyPanel::executeSize()
{
if ( !mxMtrWidth->get_value_changed_from_saved() && !mxMtrHeight->get_value_changed_from_saved())
return ;
Fraction aUIScale = mpView->GetModel().GetUIScale();
// get Width
double nWidth = static_cast <double >(mxMtrWidth->get_value(FieldUnit::MM_100TH));
tools::Long lWidth = tools::Long (nWidth * static_cast <double >(aUIScale));
lWidth = OutputDevice::LogicToLogic( lWidth, MapUnit::Map100thMM, mePoolUnit );
lWidth = static_cast <tools::Long >(mxMtrWidth->denormalize( lWidth ));
// get Height
double nHeight = static_cast <double >(mxMtrHeight->get_value(FieldUnit::MM_100TH));
tools::Long lHeight = tools::Long (nHeight * static_cast <double >(aUIScale));
lHeight = OutputDevice::LogicToLogic( lHeight, MapUnit::Map100thMM, mePoolUnit );
lHeight = static_cast <tools::Long >(mxMtrHeight->denormalize( lHeight ));
// put Width & Height to itemset
SfxUInt32Item aWidthItem( SID_ATTR_TRANSFORM_WIDTH, static_cast <sal_uInt32>(lWidth));
SfxUInt32Item aHeightItem( SID_ATTR_TRANSFORM_HEIGHT, static_cast <sal_uInt32>(lHeight));
SfxUInt16Item aPointItem (SID_ATTR_TRANSFORM_SIZE_POINT, sal_uInt16(RectPoint::LT));
const sal_Int32 nCombinedContext(maContext.GetCombinedContext_DI());
if ( nCombinedContext == CombinedEnumContext(Application::WriterVariants, Context::Graphic)
|| nCombinedContext == CombinedEnumContext(Application::WriterVariants, Context::OLE)
)
{
GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
SfxCallMode::RECORD, { &aWidthItem, &aHeightItem, &aPointItem });
}
else
{
if ( (mxMtrWidth->get_value_changed_from_saved()) && (mxMtrHeight->get_value_changed_from_saved()))
GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
SfxCallMode::RECORD, { &aWidthItem, &aHeightItem, &aPointItem });
else if ( mxMtrWidth->get_value_changed_from_saved())
GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
SfxCallMode::RECORD, { &aWidthItem, &aPointItem });
else if ( mxMtrHeight->get_value_changed_from_saved())
GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
SfxCallMode::RECORD, { &aHeightItem, &aPointItem });
}
}
void PosSizePropertyPanel::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
{
if (meDlgUnit != GetCurrentUnit(SfxItemState::DEFAULT , nullptr))
{
mpBindings->Update( SID_ATTR_METRIC );
}
PanelLayout::DumpAsPropertyTree(rJsonWriter);
}
void PosSizePropertyPanel::MetricState(SfxItemState eState, const SfxPoolItem* pState, const Fraction& rUIScale)
{
bool bPosXBlank = false ;
bool bPosYBlank = false ;
bool bWidthBlank = false ;
bool bHeightBlank = false ;
// #i124409# use the given Item to get the correct UI unit and initialize it
// and the Fields using it
FieldUnit eDlgUnit = GetCurrentUnit(eState, pState);
mbFieldMetricOutDated |= (eDlgUnit != meDlgUnit || maUIScale != rUIScale);
if (!mbFieldMetricOutDated)
return ;
meDlgUnit = eDlgUnit;
if (mxMtrPosX->get_text().isEmpty())
bPosXBlank = true ;
SetFieldUnit( *mxMtrPosX, meDlgUnit, true );
if (bPosXBlank)
{
mbMtrPosXBlanked = true ;
}
if (mxMtrPosY->get_text().isEmpty())
bPosYBlank = true ;
SetFieldUnit( *mxMtrPosY, meDlgUnit, true );
if (bPosYBlank)
{
mbMtrPosYBlanked = true ;
}
SetPosSizeMinMax(rUIScale);
if (mxMtrWidth->get_text().isEmpty())
bWidthBlank = true ;
SetFieldUnit( *mxMtrWidth, meDlgUnit, true );
if (bWidthBlank)
{
mbMtrWidthBlanked = true ;
}
if (mxMtrHeight->get_text().isEmpty())
bHeightBlank = true ;
SetFieldUnit( *mxMtrHeight, meDlgUnit, true );
if (bHeightBlank)
{
mbMtrHeightBlanked = true ;
}
}
FieldUnit PosSizePropertyPanel::GetCurrentUnit( SfxItemState eState, const SfxPoolItem* pState )
{
FieldUnit eUnit = FieldUnit::NONE;
if ( pState && eState >= SfxItemState::DEFAULT )
{
eUnit = static_cast <FieldUnit>(static_cast <const SfxUInt16Item*>(pState)->GetValue());
}
else
{
SfxViewFrame* pFrame = SfxViewFrame::Current();
SfxObjectShell* pSh = nullptr;
if ( pFrame )
pSh = pFrame->GetObjectShell();
if ( pSh )
{
SfxModule* pModule = pSh->GetModule();
if ( pModule )
{
eUnit = pModule->GetFieldUnit();
}
else
{
SAL_WARN("svx.sidebar" , "GetModuleFieldUnit(): no module found" );
}
}
}
return eUnit;
}
void PosSizePropertyPanel::DisableControls()
{
const bool bZeroDimension = mlOldWidth == 0 || mlOldHeight == 0;
if ( mbPositionProtected )
{
// the position is protected("Position protect" option in modal dialog is checked),
// disable all the Position controls in sidebar
mxFtPosX->set_sensitive(false );
mxMtrPosX->set_sensitive(false );
mxFtPosY->set_sensitive(false );
mxMtrPosY->set_sensitive(false );
mxFtAngle->set_sensitive(false );
mxMtrAngle->set_sensitive(false );
mxDial->set_sensitive(false );
mxFtFlip->set_sensitive(false );
mxFlipTbx->set_sensitive(false );
mxFtWidth->set_sensitive(false );
mxMtrWidth->set_sensitive(false );
mxFtHeight->set_sensitive(false );
mxMtrHeight->set_sensitive(false );
mxCbxScale->set_sensitive(false );
}
else
{
mxFtPosX->set_sensitive(true );
mxMtrPosX->set_sensitive(true );
mxFtPosY->set_sensitive(true );
mxMtrPosY->set_sensitive(true );
if ( mbSizeProtected )
{
mxFtWidth->set_sensitive(false );
mxMtrWidth->set_sensitive(false );
mxFtHeight->set_sensitive(false );
mxMtrHeight->set_sensitive(false );
mxCbxScale->set_sensitive(false );
}
else
{
if ( mbAdjustEnabled )
{
if ( mbAutoWidth )
{
mxFtWidth->set_sensitive(false );
mxMtrWidth->set_sensitive(false );
mxCbxScale->set_sensitive(false );
}
else
{
mxFtWidth->set_sensitive(true );
mxMtrWidth->set_sensitive(true );
}
if ( mbAutoHeight )
{
mxFtHeight->set_sensitive(false );
mxMtrHeight->set_sensitive(false );
mxCbxScale->set_sensitive(false );
}
else
{
mxFtHeight->set_sensitive(true );
mxMtrHeight->set_sensitive(true );
}
if ( !mbAutoWidth && !mbAutoHeight )
mxCbxScale->set_sensitive(true );
}
else
{
mxFtWidth->set_sensitive(true );
mxMtrWidth->set_sensitive(true );
mxFtHeight->set_sensitive(true );
mxMtrHeight->set_sensitive(true );
mxCbxScale->set_sensitive(true );
}
}
}
// tdf#150743 Disable Keep ratio if there is zero width/height
if (bZeroDimension)
mxCbxScale->set_sensitive(false );
}
void PosSizePropertyPanel::SetPosSizeMinMax(const Fraction& rUIScale)
{
SdrPageView* pPV = mpView->GetSdrPageView();
if (!pPV)
return ;
tools::Rectangle aTmpRect(mpView->GetAllMarkedRect());
pPV->LogicToPagePos(aTmpRect);
maRect = vcl::unotools::b2DRectangleFromRectangle(aTmpRect);
tools::Rectangle aTmpRect2(mpView->GetWorkArea());
pPV->LogicToPagePos(aTmpRect2);
maWorkArea = vcl::unotools::b2DRectangleFromRectangle(aTmpRect2);
TransfrmHelper::ScaleRect(maWorkArea, rUIScale);
TransfrmHelper::ScaleRect(maRect, rUIScale);
const sal_uInt16 nDigits(mxMtrPosX->get_digits());
TransfrmHelper::ConvertRect( maWorkArea, nDigits, mePoolUnit, meDlgUnit );
TransfrmHelper::ConvertRect( maRect, nDigits, mePoolUnit, meDlgUnit );
double fLeft(maWorkArea.getMinX());
double fTop(maWorkArea.getMinY());
double fRight(maWorkArea.getMaxX());
double fBottom(maWorkArea.getMaxY());
// seems that sidebar defaults to top left reference point
// and there's no way to set it to something else
fRight -= maRect.getWidth();
fBottom -= maRect.getHeight();
const double fMaxLong(static_cast <double >(vcl::ConvertValue( LONG_MAX, 0, MapUnit::Map100thMM, meDlgUnit ) - 1));
fLeft = std::clamp(fLeft, -fMaxLong, fMaxLong);
fRight = std::clamp(fRight, -fMaxLong, fMaxLong);
fTop = std::clamp(fTop, - fMaxLong, fMaxLong);
fBottom = std::clamp(fBottom, -fMaxLong, fMaxLong);
mxMtrPosX->set_range(basegfx::fround64(fLeft), basegfx::fround64(fRight), FieldUnit::NONE);
limitWidth(*mxMtrPosX);
mxMtrPosY->set_range(basegfx::fround64(fTop), basegfx::fround64(fBottom), FieldUnit::NONE);
limitWidth(*mxMtrPosY);
double fMaxWidth = maWorkArea.getWidth() - (maRect.getWidth() - fLeft);
double fMaxHeight = maWorkArea.getHeight() - (maRect.getHeight() - fTop);
mxMtrWidth->set_max(std::min<sal_Int64>(INT_MAX, basegfx::fround64(fMaxWidth*100)), FieldUnit::NONE);
limitWidth(*mxMtrWidth);
mxMtrHeight->set_max(std::min<sal_Int64>(INT_MAX, basegfx::fround64(fMaxHeight*100)), FieldUnit::NONE);
limitWidth(*mxMtrHeight);
}
void PosSizePropertyPanel::UpdateUIScale(const Fraction& rUIScale)
{
if (maUIScale == rUIScale)
return ;
// UI scale has changed.
// Remember the new UI scale.
maUIScale = rUIScale;
// The content of the position and size boxes is only updated when item changes are notified.
// Request such notifications without changing the actual item values.
GetBindings()->Invalidate(SID_ATTR_TRANSFORM_POS_X, true );
GetBindings()->Invalidate(SID_ATTR_TRANSFORM_POS_Y, true );
GetBindings()->Invalidate(SID_ATTR_TRANSFORM_WIDTH, true );
GetBindings()->Invalidate(SID_ATTR_TRANSFORM_HEIGHT, true );
}
} // end of namespace svx::sidebar
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 C=92 H=96 G=93
¤ Dauer der Verarbeitung: 0.10 Sekunden
¤
*© Formatika GbR, Deutschland