1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
24 #include "PosSizePropertyPanel.hxx"
25 #include <sal/log.hxx>
26 #include <svx/svxids.hrc>
27 #include <sfx2/dispatch.hxx>
28 #include <sfx2/bindings.hxx>
29 #include <sfx2/module.hxx>
30 #include <sfx2/viewsh.hxx>
31 #include <sfx2/objsh.hxx>
32 #include <sfx2/viewfrm.hxx>
33 #include <sfx2/weldutils.hxx>
34 #include <svx/dialcontrol.hxx>
35 #include <svx/dialmgr.hxx>
36 #include <svx/rectenum.hxx>
37 #include <svx/sdangitm.hxx>
38 #include <unotools/viewoptions.hxx>
39 #include <unotools/localedatawrapper.hxx>
41 #include <vcl/canvastools.hxx>
42 #include <vcl/fieldvalues.hxx>
43 #include <svl/intitem.hxx>
44 #include <svx/strings.hrc>
45 #include <svx/svdpagv.hxx>
46 #include <svx/svdview.hxx>
47 #include <svx/transfrmhelper.hxx>
48 #include <boost/property_tree/ptree.hpp>
50 #include <svtools/unitconv.hxx>
53 using namespace css::uno
;
55 constexpr OUStringLiteral USERITEM_NAME
= u
"FitItem";
57 namespace svx::sidebar
{
59 PosSizePropertyPanel::PosSizePropertyPanel(
60 weld::Widget
* pParent
,
61 const css::uno::Reference
<css::frame::XFrame
>& rxFrame
,
62 SfxBindings
* pBindings
,
63 css::uno::Reference
<css::ui::XSidebar
> xSidebar
)
64 : PanelLayout(pParent
, "PosSizePropertyPanel", "svx/ui/sidebarpossize.ui"),
65 mxFtPosX(m_xBuilder
->weld_label("horizontallabel")),
66 mxMtrPosX(m_xBuilder
->weld_metric_spin_button("horizontalpos", FieldUnit::CM
)),
67 mxFtPosY(m_xBuilder
->weld_label("verticallabel")),
68 mxMtrPosY(m_xBuilder
->weld_metric_spin_button("verticalpos", FieldUnit::CM
)),
69 mxFtWidth(m_xBuilder
->weld_label("widthlabel")),
70 mxMtrWidth(m_xBuilder
->weld_metric_spin_button("selectwidth", FieldUnit::CM
)),
71 mxFtHeight(m_xBuilder
->weld_label("heightlabel")),
72 mxMtrHeight(m_xBuilder
->weld_metric_spin_button("selectheight", FieldUnit::CM
)),
73 mxCbxScale(m_xBuilder
->weld_check_button("ratio")),
74 mxFtAngle(m_xBuilder
->weld_label("rotationlabel")),
75 mxMtrAngle(m_xBuilder
->weld_metric_spin_button("rotation", FieldUnit::DEGREE
)),
76 mxCtrlDial(new DialControl
),
77 mxDial(new weld::CustomWeld(*m_xBuilder
, "orientationcontrol", *mxCtrlDial
)),
78 mxFtFlip(m_xBuilder
->weld_label("fliplabel")),
79 mxFlipTbx(m_xBuilder
->weld_toolbar("selectrotationtype")),
80 mxFlipDispatch(new ToolbarUnoDispatcher(*mxFlipTbx
, *m_xBuilder
, rxFrame
)),
81 mxArrangeTbx(m_xBuilder
->weld_toolbar("arrangetoolbar")),
82 mxArrangeDispatch(new ToolbarUnoDispatcher(*mxArrangeTbx
, *m_xBuilder
, rxFrame
)),
83 mxArrangeTbx2(m_xBuilder
->weld_toolbar("arrangetoolbar2")),
84 mxArrangeDispatch2(new ToolbarUnoDispatcher(*mxArrangeTbx2
, *m_xBuilder
, rxFrame
)),
85 mxAlignTbx(m_xBuilder
->weld_toolbar("aligntoolbar")),
86 mxAlignDispatch(new ToolbarUnoDispatcher(*mxAlignTbx
, *m_xBuilder
, rxFrame
)),
87 mxAlignTbx2(m_xBuilder
->weld_toolbar("aligntoolbar2")),
88 mxAlignDispatch2(new ToolbarUnoDispatcher(*mxAlignTbx2
, *m_xBuilder
, rxFrame
)),
89 mxBtnEditOLEObject(m_xBuilder
->weld_button("btnEditObject")),
96 meDlgUnit(FieldUnit::INCH
), // #i124409# init with fallback default
97 mbFieldMetricOutDated(true),
98 maTransfPosXControl(SID_ATTR_TRANSFORM_POS_X
, *pBindings
, *this),
99 maTransfPosYControl(SID_ATTR_TRANSFORM_POS_Y
, *pBindings
, *this),
100 maTransfWidthControl(SID_ATTR_TRANSFORM_WIDTH
, *pBindings
, *this),
101 maTransfHeightControl(SID_ATTR_TRANSFORM_HEIGHT
, *pBindings
, *this),
102 maSvxAngleControl( SID_ATTR_TRANSFORM_ANGLE
, *pBindings
, *this),
103 maRotXControl(SID_ATTR_TRANSFORM_ROT_X
, *pBindings
, *this),
104 maRotYControl(SID_ATTR_TRANSFORM_ROT_Y
, *pBindings
, *this),
105 maProPosControl(SID_ATTR_TRANSFORM_PROTECT_POS
, *pBindings
, *this),
106 maProSizeControl(SID_ATTR_TRANSFORM_PROTECT_SIZE
, *pBindings
, *this),
107 maAutoWidthControl(SID_ATTR_TRANSFORM_AUTOWIDTH
, *pBindings
, *this),
108 maAutoHeightControl(SID_ATTR_TRANSFORM_AUTOHEIGHT
, *pBindings
, *this),
109 m_aMetricCtl(SID_ATTR_METRIC
, *pBindings
, *this),
110 mpBindings(pBindings
),
111 mbSizeProtected(false),
112 mbPositionProtected(false),
115 mbAdjustEnabled(false),
116 mxSidebar(std::move(xSidebar
))
120 // A guesstimate of the longest label in the various sidebar panes to use
121 // to get this pane's contents to align with them, for lack of a better
123 auto nWidth
= mxFtWidth
->get_preferred_size().Width();
124 OUString sLabel
= mxFtWidth
->get_label();
125 mxFtWidth
->set_label(SvxResId(RID_SVXSTR_TRANSPARENCY
));
126 nWidth
= std::max(nWidth
, mxFtWidth
->get_preferred_size().Width());;
127 mxFtWidth
->set_label(sLabel
);
128 mxFtWidth
->set_size_request(nWidth
, -1);
130 mpBindings
->Update( SID_ATTR_METRIC
);
131 mpBindings
->Update( SID_ATTR_TRANSFORM_WIDTH
);
132 mpBindings
->Update( SID_ATTR_TRANSFORM_HEIGHT
);
133 mpBindings
->Update( SID_ATTR_TRANSFORM_PROTECT_SIZE
);
136 PosSizePropertyPanel::~PosSizePropertyPanel()
152 mxFlipDispatch
.reset();
154 mxAlignDispatch
.reset();
155 mxAlignDispatch2
.reset();
158 mxArrangeDispatch
.reset();
159 mxArrangeDispatch2
.reset();
160 mxArrangeTbx
.reset();
161 mxArrangeTbx2
.reset();
162 mxBtnEditOLEObject
.reset();
164 maTransfPosXControl
.dispose();
165 maTransfPosYControl
.dispose();
166 maTransfWidthControl
.dispose();
167 maTransfHeightControl
.dispose();
169 maSvxAngleControl
.dispose();
170 maRotXControl
.dispose();
171 maRotYControl
.dispose();
172 maProPosControl
.dispose();
173 maProSizeControl
.dispose();
174 maAutoWidthControl
.dispose();
175 maAutoHeightControl
.dispose();
176 m_aMetricCtl
.dispose();
181 bool hasText(const SdrView
& rSdrView
)
183 const SdrMarkList
& rMarkList
= rSdrView
.GetMarkedObjectList();
185 if(1 == rMarkList
.GetMarkCount())
187 const SdrObject
* pObj
= rMarkList
.GetMark(0)->GetMarkedSdrObj();
188 const SdrObjKind
eKind(pObj
->GetObjIdentifier());
190 if((pObj
->GetObjInventor() == SdrInventor::Default
) && (SdrObjKind::Text
== eKind
|| SdrObjKind::TitleText
== eKind
|| SdrObjKind::OutlineText
== eKind
))
192 const SdrTextObj
* pSdrTextObj
= DynCastSdrTextObj(pObj
);
194 if(pSdrTextObj
&& pSdrTextObj
->HasText())
203 } // end of anonymous namespace
206 void PosSizePropertyPanel::Initialize()
208 //Position : Horizontal / Vertical
209 mxMtrPosX
->connect_value_changed( LINK( this, PosSizePropertyPanel
, ChangePosXHdl
) );
210 mxMtrPosY
->connect_value_changed( LINK( this, PosSizePropertyPanel
, ChangePosYHdl
) );
212 //Size : Width / Height
213 mxMtrWidth
->connect_value_changed( LINK( this, PosSizePropertyPanel
, ChangeWidthHdl
) );
214 mxMtrHeight
->connect_value_changed( LINK( this, PosSizePropertyPanel
, ChangeHeightHdl
) );
217 mxCbxScale
->connect_toggled( LINK( this, PosSizePropertyPanel
, ClickAutoHdl
) );
220 mxCtrlDial
->SetLinkedField(mxMtrAngle
.get(), 2);
221 mxCtrlDial
->SetModifyHdl(LINK( this, PosSizePropertyPanel
, RotationHdl
));
223 //use same logic as DialControl_Impl::SetSize
224 weld::DrawingArea
* pDrawingArea
= mxCtrlDial
->GetDrawingArea();
225 int nDim
= (std::min
<int>(pDrawingArea
->get_approximate_digit_width() * 6,
226 pDrawingArea
->get_text_height() * 3) - 1) | 1;
227 Size
aSize(nDim
, nDim
);
228 pDrawingArea
->set_size_request(aSize
.Width(), aSize
.Height());
229 mxCtrlDial
->Init(aSize
);
231 mxBtnEditOLEObject
->connect_clicked( LINK( this, PosSizePropertyPanel
, ClickObjectEditHdl
) );
233 SfxViewShell
* pCurSh
= SfxViewShell::Current();
235 mpView
= pCurSh
->GetDrawView();
239 if ( mpView
!= nullptr )
241 maUIScale
= mpView
->GetModel().GetUIScale();
242 mbAdjustEnabled
= hasText(*mpView
);
245 mePoolUnit
= maTransfWidthControl
.GetCoreMetric();
248 std::unique_ptr
<PanelLayout
> PosSizePropertyPanel::Create (
249 weld::Widget
* pParent
,
250 const css::uno::Reference
<css::frame::XFrame
>& rxFrame
,
251 SfxBindings
* pBindings
,
252 const css::uno::Reference
<css::ui::XSidebar
>& rxSidebar
)
254 if (pParent
== nullptr)
255 throw lang::IllegalArgumentException("no parent Window given to PosSizePropertyPanel::Create", nullptr, 0);
257 throw lang::IllegalArgumentException("no XFrame given to PosSizePropertyPanel::Create", nullptr, 1);
258 if (pBindings
== nullptr)
259 throw lang::IllegalArgumentException("no SfxBindings given to PosSizePropertyPanel::Create", nullptr, 2);
261 return std::make_unique
<PosSizePropertyPanel
>(pParent
, rxFrame
, pBindings
, rxSidebar
);
264 void PosSizePropertyPanel::HandleContextChange(
265 const vcl::EnumContext
& rContext
)
267 if (maContext
== rContext
)
273 maContext
= rContext
;
275 bool bShowPosition
= false;
276 bool bShowAngle
= false;
277 bool bShowFlip
= false;
278 bool bShowEditObject
= false;
279 bool bShowArrangeTbx2
= false;
281 switch (maContext
.GetCombinedContext_DI())
283 case CombinedEnumContext(Application::WriterVariants
, Context::Draw
):
286 bShowArrangeTbx2
= true;
289 case CombinedEnumContext(Application::WriterVariants
, Context::Graphic
):
291 bShowAngle
= true; // RotGrfFlyFrame: Writer FlyFrames for Graphics now support angle
294 case CombinedEnumContext(Application::Calc
, Context::Draw
):
295 case CombinedEnumContext(Application::Calc
, Context::DrawLine
):
296 case CombinedEnumContext(Application::Calc
, Context::Graphic
):
297 case CombinedEnumContext(Application::DrawImpress
, Context::Draw
):
298 case CombinedEnumContext(Application::DrawImpress
, Context::DrawLine
):
299 case CombinedEnumContext(Application::DrawImpress
, Context::TextObject
):
300 case CombinedEnumContext(Application::DrawImpress
, Context::Graphic
):
301 bShowPosition
= true;
306 case CombinedEnumContext(Application::WriterVariants
, Context::OLE
):
307 bShowEditObject
= true;
310 case CombinedEnumContext(Application::Calc
, Context::OLE
):
311 case CombinedEnumContext(Application::DrawImpress
, Context::OLE
):
312 bShowPosition
= true;
313 bShowEditObject
= true;
316 case CombinedEnumContext(Application::Calc
, Context::Chart
):
317 case CombinedEnumContext(Application::Calc
, Context::Form
):
318 case CombinedEnumContext(Application::Calc
, Context::Media
):
319 case CombinedEnumContext(Application::Calc
, Context::MultiObject
):
320 case CombinedEnumContext(Application::DrawImpress
, Context::Media
):
321 case CombinedEnumContext(Application::DrawImpress
, Context::Form
):
322 case CombinedEnumContext(Application::DrawImpress
, Context::ThreeDObject
):
323 case CombinedEnumContext(Application::DrawImpress
, Context::MultiObject
):
324 bShowPosition
= true;
329 mxFtPosX
->set_visible(bShowPosition
);
330 mxMtrPosX
->set_visible(bShowPosition
);
331 mxFtPosY
->set_visible(bShowPosition
);
332 mxMtrPosY
->set_visible(bShowPosition
);
335 mxFtAngle
->set_visible(bShowAngle
);
336 mxMtrAngle
->set_visible(bShowAngle
);
337 mxCtrlDial
->set_visible(bShowAngle
);
340 mxFtFlip
->set_visible(bShowFlip
);
341 mxFlipTbx
->set_visible(bShowFlip
);
344 mxBtnEditOLEObject
->set_visible(bShowEditObject
);
346 // Arrange tool bar 2
347 mxArrangeTbx2
->set_visible(bShowArrangeTbx2
);
350 mxSidebar
->requestLayout();
354 IMPL_LINK_NOARG( PosSizePropertyPanel
, ChangeWidthHdl
, weld::MetricSpinButton
&, void )
356 if( mxCbxScale
->get_active() &&
357 mxCbxScale
->get_sensitive() )
359 tools::Long nHeight
= static_cast<tools::Long
>( (static_cast<double>(mlOldHeight
) * static_cast<double>(mxMtrWidth
->get_value(FieldUnit::NONE
))) / static_cast<double>(mlOldWidth
) );
360 if( nHeight
<= mxMtrHeight
->get_max( FieldUnit::NONE
) )
362 mxMtrHeight
->set_value( nHeight
, FieldUnit::NONE
);
366 nHeight
= static_cast<tools::Long
>(mxMtrHeight
->get_max( FieldUnit::NONE
));
367 mxMtrHeight
->set_value(nHeight
, FieldUnit::NONE
);
368 const tools::Long nWidth
= static_cast<tools::Long
>( (static_cast<double>(mlOldWidth
) * static_cast<double>(nHeight
)) / static_cast<double>(mlOldHeight
) );
369 mxMtrWidth
->set_value( nWidth
, FieldUnit::NONE
);
376 IMPL_LINK_NOARG( PosSizePropertyPanel
, ChangeHeightHdl
, weld::MetricSpinButton
&, void )
378 if( mxCbxScale
->get_active() &&
379 mxCbxScale
->get_sensitive() )
381 tools::Long nWidth
= static_cast<tools::Long
>( (static_cast<double>(mlOldWidth
) * static_cast<double>(mxMtrHeight
->get_value(FieldUnit::NONE
))) / static_cast<double>(mlOldHeight
) );
382 if( nWidth
<= mxMtrWidth
->get_max( FieldUnit::NONE
) )
384 mxMtrWidth
->set_value( nWidth
, FieldUnit::NONE
);
388 nWidth
= static_cast<tools::Long
>(mxMtrWidth
->get_max( FieldUnit::NONE
));
389 mxMtrWidth
->set_value( nWidth
, FieldUnit::NONE
);
390 const tools::Long nHeight
= static_cast<tools::Long
>( (static_cast<double>(mlOldHeight
) * static_cast<double>(nWidth
)) / static_cast<double>(mlOldWidth
) );
391 mxMtrHeight
->set_value( nHeight
, FieldUnit::NONE
);
398 IMPL_LINK_NOARG( PosSizePropertyPanel
, ChangePosXHdl
, weld::MetricSpinButton
&, void )
400 if ( mxMtrPosX
->get_value_changed_from_saved())
402 tools::Long lX
= GetCoreValue( *mxMtrPosX
, mePoolUnit
);
404 Fraction aUIScale
= mpView
->GetModel().GetUIScale();
405 lX
= tools::Long( lX
* aUIScale
);
407 SfxInt32Item
aPosXItem( SID_ATTR_TRANSFORM_POS_X
,static_cast<sal_uInt32
>(lX
));
409 GetBindings()->GetDispatcher()->ExecuteList(
410 SID_ATTR_TRANSFORM
, SfxCallMode::RECORD
, { &aPosXItem
});
414 IMPL_LINK_NOARG( PosSizePropertyPanel
, ChangePosYHdl
, weld::MetricSpinButton
&, void )
416 if ( mxMtrPosY
->get_value_changed_from_saved() )
418 tools::Long lY
= GetCoreValue( *mxMtrPosY
, mePoolUnit
);
420 Fraction aUIScale
= mpView
->GetModel().GetUIScale();
421 lY
= tools::Long( lY
* aUIScale
);
423 SfxInt32Item
aPosYItem( SID_ATTR_TRANSFORM_POS_Y
,static_cast<sal_uInt32
>(lY
));
425 GetBindings()->GetDispatcher()->ExecuteList(
426 SID_ATTR_TRANSFORM
, SfxCallMode::RECORD
, { &aPosYItem
});
430 IMPL_LINK_NOARG( PosSizePropertyPanel
, ClickAutoHdl
, weld::Toggleable
&, void )
432 if ( mxCbxScale
->get_active() )
434 mlOldWidth
= std::max(GetCoreValue(*mxMtrWidth
, mePoolUnit
), SAL_CONST_INT64(1));
435 mlOldHeight
= std::max(GetCoreValue(*mxMtrHeight
, mePoolUnit
), SAL_CONST_INT64(1));
438 // mxCbxScale must synchronized with that on Position and Size tabpage on Shape Properties dialog
439 SvtViewOptions
aPageOpt(EViewType::TabPage
, "cui/ui/possizetabpage/PositionAndSize");
440 aPageOpt
.SetUserItem( USERITEM_NAME
, css::uno::Any( OUString::number( int(mxCbxScale
->get_active()) ) ) );
443 IMPL_LINK_NOARG( PosSizePropertyPanel
, RotationHdl
, DialControl
&, void )
445 Degree100 nTmp
= mxCtrlDial
->GetRotation();
447 // #i123993# Need to take UIScale into account when executing rotations
448 const double fUIScale(mpView
? double(mpView
->GetModel().GetUIScale()) : 1.0);
449 SdrAngleItem
aAngleItem( SID_ATTR_TRANSFORM_ANGLE
, nTmp
);
450 SfxInt32Item
aRotXItem( SID_ATTR_TRANSFORM_ROT_X
, basegfx::fround(mlRotX
* fUIScale
));
451 SfxInt32Item
aRotYItem( SID_ATTR_TRANSFORM_ROT_Y
, basegfx::fround(mlRotY
* fUIScale
));
453 GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM
,
454 SfxCallMode::RECORD
, { &aAngleItem
, &aRotXItem
, &aRotYItem
});
457 IMPL_STATIC_LINK_NOARG( PosSizePropertyPanel
, ClickObjectEditHdl
, weld::Button
&, void )
459 SfxViewShell
* pCurSh
= SfxViewShell::Current();
462 pCurSh
->DoVerb( -1 );
468 void limitWidth(weld::MetricSpinButton
& rMetricSpinButton
)
470 // space is limited in the sidebar, so limit MetricSpinButtons to a width of 7 digits
471 const int nMaxDigits
= 7;
473 weld::SpinButton
& rSpinButton
= rMetricSpinButton
.get_widget();
474 rSpinButton
.set_width_chars(std::min(rSpinButton
.get_width_chars(), nMaxDigits
));
478 void PosSizePropertyPanel::NotifyItemUpdate(
481 const SfxPoolItem
* pState
)
483 mxFtAngle
->set_sensitive(true);
484 mxMtrAngle
->set_sensitive(true);
485 mxDial
->set_sensitive(true);
486 mxFtFlip
->set_sensitive(true);
487 mxFlipTbx
->set_sensitive(true);
489 const SfxUInt32Item
* pWidthItem
;
490 const SfxUInt32Item
* pHeightItem
;
492 SfxViewShell
* pCurSh
= SfxViewShell::Current();
494 mpView
= pCurSh
->GetDrawView();
498 if ( mpView
== nullptr )
501 mbAdjustEnabled
= hasText(*mpView
);
503 // Pool unit and dialog unit may have changed, make sure that we
504 // have the current values.
505 mePoolUnit
= maTransfWidthControl
.GetCoreMetric();
509 case SID_ATTR_TRANSFORM_WIDTH
:
510 if ( SfxItemState::DEFAULT
== eState
)
512 pWidthItem
= dynamic_cast< const SfxUInt32Item
* >(pState
);
516 tools::Long lOldWidth1
= tools::Long( pWidthItem
->GetValue() / maUIScale
);
517 SetFieldUnit( *mxMtrWidth
, meDlgUnit
, true );
518 SetMetricValue( *mxMtrWidth
, lOldWidth1
, mePoolUnit
);
519 limitWidth(*mxMtrWidth
);
520 mlOldWidth
= lOldWidth1
;
521 mxMtrWidth
->save_value();
526 mxMtrWidth
->set_text( "" );
529 case SID_ATTR_TRANSFORM_HEIGHT
:
530 if ( SfxItemState::DEFAULT
== eState
)
532 pHeightItem
= dynamic_cast< const SfxUInt32Item
* >(pState
);
536 tools::Long nTmp
= tools::Long( pHeightItem
->GetValue() / maUIScale
);
537 SetFieldUnit( *mxMtrHeight
, meDlgUnit
, true );
538 SetMetricValue( *mxMtrHeight
, nTmp
, mePoolUnit
);
539 limitWidth(*mxMtrHeight
);
541 mxMtrHeight
->save_value();
546 mxMtrHeight
->set_text( "");
549 case SID_ATTR_TRANSFORM_POS_X
:
550 if(SfxItemState::DEFAULT
== eState
)
552 const SfxInt32Item
* pItem
= dynamic_cast< const SfxInt32Item
* >(pState
);
556 tools::Long nTmp
= tools::Long(pItem
->GetValue() / maUIScale
);
557 SetFieldUnit( *mxMtrPosX
, meDlgUnit
, true );
558 SetMetricValue( *mxMtrPosX
, nTmp
, mePoolUnit
);
559 limitWidth(*mxMtrPosX
);
560 mxMtrPosX
->save_value();
565 mxMtrPosX
->set_text( "" );
568 case SID_ATTR_TRANSFORM_POS_Y
:
569 if(SfxItemState::DEFAULT
== eState
)
571 const SfxInt32Item
* pItem
= dynamic_cast< const SfxInt32Item
* >(pState
);
575 tools::Long nTmp
= tools::Long(pItem
->GetValue() / maUIScale
);
576 SetFieldUnit( *mxMtrPosY
, meDlgUnit
, true );
577 SetMetricValue( *mxMtrPosY
, nTmp
, mePoolUnit
);
578 limitWidth(*mxMtrPosY
);
579 mxMtrPosY
->save_value();
584 mxMtrPosY
->set_text( "" );
587 case SID_ATTR_TRANSFORM_ROT_X
:
588 if (SfxItemState::DEFAULT
== eState
)
590 const SfxInt32Item
* pItem
= dynamic_cast< const SfxInt32Item
* >(pState
);
594 mlRotX
= pItem
->GetValue();
595 mlRotX
= tools::Long( mlRotX
/ maUIScale
);
600 case SID_ATTR_TRANSFORM_ROT_Y
:
601 if (SfxItemState::DEFAULT
== eState
)
603 const SfxInt32Item
* pItem
= dynamic_cast< const SfxInt32Item
* >(pState
);
607 mlRotY
= pItem
->GetValue();
608 mlRotY
= tools::Long( mlRotY
/ maUIScale
);
613 case SID_ATTR_TRANSFORM_PROTECT_POS
:
614 if(SfxItemState::DEFAULT
== eState
)
616 const SfxBoolItem
* pItem
= dynamic_cast< const SfxBoolItem
* >(pState
);
620 // record the state of position protect
621 mbPositionProtected
= pItem
->GetValue();
626 mbPositionProtected
= false;
629 case SID_ATTR_TRANSFORM_PROTECT_SIZE
:
630 if(SfxItemState::DEFAULT
== eState
)
632 const SfxBoolItem
* pItem
= dynamic_cast< const SfxBoolItem
* >(pState
);
636 // record the state of size protect
637 mbSizeProtected
= pItem
->GetValue();
642 mbSizeProtected
= false;
645 case SID_ATTR_TRANSFORM_AUTOWIDTH
:
646 if(SfxItemState::DEFAULT
== eState
)
648 const SfxBoolItem
* pItem
= dynamic_cast< const SfxBoolItem
* >(pState
);
652 mbAutoWidth
= pItem
->GetValue();
657 case SID_ATTR_TRANSFORM_AUTOHEIGHT
:
658 if(SfxItemState::DEFAULT
== eState
)
660 const SfxBoolItem
* pItem
= dynamic_cast< const SfxBoolItem
* >(pState
);
664 mbAutoHeight
= pItem
->GetValue();
669 case SID_ATTR_TRANSFORM_ANGLE
:
670 if (eState
>= SfxItemState::DEFAULT
)
672 const SdrAngleItem
* pItem
= dynamic_cast< const SdrAngleItem
* >(pState
);
676 Degree100 nTmp
= NormAngle36000(pItem
->GetValue());
678 mxMtrAngle
->set_value(nTmp
.get(), FieldUnit::DEGREE
);
679 mxCtrlDial
->SetRotation(nTmp
);
685 mxMtrAngle
->set_text( "" );
686 mxCtrlDial
->SetRotation( 0_deg100
);
689 case SID_ATTR_METRIC
:
691 const Fraction
aUIScale(mpView
->GetModel().GetUIScale());
692 MetricState(eState
, pState
, aUIScale
);
693 UpdateUIScale(aUIScale
);
694 mbFieldMetricOutDated
= false;
701 const sal_Int32
nCombinedContext(maContext
.GetCombinedContext_DI());
702 const SdrMarkList
& rMarkList
= mpView
->GetMarkedObjectList();
704 switch (rMarkList
.GetMarkCount())
711 const SdrObject
* pObj
= rMarkList
.GetMark(0)->GetMarkedSdrObj();
712 const SdrObjKind
eKind(pObj
->GetObjIdentifier());
714 if(((nCombinedContext
== CombinedEnumContext(Application::DrawImpress
, Context::Draw
)
715 || nCombinedContext
== CombinedEnumContext(Application::DrawImpress
, Context::TextObject
)
716 ) && SdrObjKind::Edge
== eKind
)
717 || SdrObjKind::Caption
== eKind
)
719 mxFtAngle
->set_sensitive(false);
720 mxMtrAngle
->set_sensitive(false);
721 mxDial
->set_sensitive(false);
722 mxFlipTbx
->set_sensitive(false);
723 mxFtFlip
->set_sensitive(false);
730 sal_uInt16 nMarkObj
= 0;
731 bool isNoEdge
= true;
733 while(isNoEdge
&& rMarkList
.GetMark(nMarkObj
))
735 const SdrObject
* pObj
= rMarkList
.GetMark(nMarkObj
)->GetMarkedSdrObj();
736 const SdrObjKind
eKind(pObj
->GetObjIdentifier());
738 if(((nCombinedContext
== CombinedEnumContext(Application::DrawImpress
, Context::Draw
)
739 || nCombinedContext
== CombinedEnumContext(Application::DrawImpress
, Context::TextObject
)
740 ) && SdrObjKind::Edge
== eKind
)
741 || SdrObjKind::Caption
== eKind
)
751 mxFtAngle
->set_sensitive(false);
752 mxMtrAngle
->set_sensitive(false);
753 mxDial
->set_sensitive(false);
754 mxFlipTbx
->set_sensitive(false);
755 mxFtFlip
->set_sensitive(false);
761 if(nCombinedContext
== CombinedEnumContext(Application::DrawImpress
, Context::TextObject
))
763 mxFlipTbx
->set_sensitive(false);
764 mxFtFlip
->set_sensitive(false);
769 // mxCbxScale must synchronized with that on Position and Size tabpage on Shape Properties dialog
770 SvtViewOptions
aPageOpt(EViewType::TabPage
, "cui/ui/possizetabpage/PositionAndSize");
772 css::uno::Any aUserItem
= aPageOpt
.GetUserItem( USERITEM_NAME
);
774 if ( aUserItem
>>= aTemp
)
776 mxCbxScale
->set_active(static_cast<bool>(sUserData
.toInt32()));
779 void PosSizePropertyPanel::GetControlState(const sal_uInt16 nSID
, boost::property_tree::ptree
& rState
)
781 weld::MetricSpinButton
* pControl
= nullptr;
784 case SID_ATTR_TRANSFORM_POS_X
:
785 pControl
= mxMtrPosX
.get();
787 case SID_ATTR_TRANSFORM_POS_Y
:
788 pControl
= mxMtrPosY
.get();
790 case SID_ATTR_TRANSFORM_WIDTH
:
791 pControl
= mxMtrWidth
.get();
793 case SID_ATTR_TRANSFORM_HEIGHT
:
794 pControl
= mxMtrHeight
.get();
798 if (pControl
&& !pControl
->get_text().isEmpty())
800 OUString sValue
= Application::GetSettings().GetNeutralLocaleDataWrapper().
801 getNum(pControl
->get_value(pControl
->get_unit()), pControl
->get_digits(), false, false);
802 rState
.put(pControl
->get_buildable_name().toUtf8().getStr(), sValue
.toUtf8().getStr());
806 void PosSizePropertyPanel::executeSize()
808 if ( !mxMtrWidth
->get_value_changed_from_saved() && !mxMtrHeight
->get_value_changed_from_saved())
811 Fraction aUIScale
= mpView
->GetModel().GetUIScale();
814 double nWidth
= static_cast<double>(mxMtrWidth
->get_value(FieldUnit::MM_100TH
));
815 tools::Long lWidth
= tools::Long(nWidth
* static_cast<double>(aUIScale
));
816 lWidth
= OutputDevice::LogicToLogic( lWidth
, MapUnit::Map100thMM
, mePoolUnit
);
817 lWidth
= static_cast<tools::Long
>(mxMtrWidth
->denormalize( lWidth
));
820 double nHeight
= static_cast<double>(mxMtrHeight
->get_value(FieldUnit::MM_100TH
));
821 tools::Long lHeight
= tools::Long(nHeight
* static_cast<double>(aUIScale
));
822 lHeight
= OutputDevice::LogicToLogic( lHeight
, MapUnit::Map100thMM
, mePoolUnit
);
823 lHeight
= static_cast<tools::Long
>(mxMtrHeight
->denormalize( lHeight
));
825 // put Width & Height to itemset
826 SfxUInt32Item
aWidthItem( SID_ATTR_TRANSFORM_WIDTH
, static_cast<sal_uInt32
>(lWidth
));
827 SfxUInt32Item
aHeightItem( SID_ATTR_TRANSFORM_HEIGHT
, static_cast<sal_uInt32
>(lHeight
));
828 SfxUInt16Item
aPointItem (SID_ATTR_TRANSFORM_SIZE_POINT
, sal_uInt16(RectPoint::LT
));
829 const sal_Int32
nCombinedContext(maContext
.GetCombinedContext_DI());
831 if( nCombinedContext
== CombinedEnumContext(Application::WriterVariants
, Context::Graphic
)
832 || nCombinedContext
== CombinedEnumContext(Application::WriterVariants
, Context::OLE
)
835 GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM
,
836 SfxCallMode::RECORD
, { &aWidthItem
, &aHeightItem
, &aPointItem
});
840 if ( (mxMtrWidth
->get_value_changed_from_saved()) && (mxMtrHeight
->get_value_changed_from_saved()))
841 GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM
,
842 SfxCallMode::RECORD
, { &aWidthItem
, &aHeightItem
, &aPointItem
});
843 else if( mxMtrWidth
->get_value_changed_from_saved())
844 GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM
,
845 SfxCallMode::RECORD
, { &aWidthItem
, &aPointItem
});
846 else if ( mxMtrHeight
->get_value_changed_from_saved())
847 GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM
,
848 SfxCallMode::RECORD
, { &aHeightItem
, &aPointItem
});
852 void PosSizePropertyPanel::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
854 if (meDlgUnit
!= GetCurrentUnit(SfxItemState::DEFAULT
, nullptr))
856 mpBindings
->Update( SID_ATTR_METRIC
);
859 PanelLayout::DumpAsPropertyTree(rJsonWriter
);
862 void PosSizePropertyPanel::MetricState(SfxItemState eState
, const SfxPoolItem
* pState
, const Fraction
& rUIScale
)
864 bool bPosXBlank
= false;
865 bool bPosYBlank
= false;
866 bool bWidthBlank
= false;
867 bool bHeightBlank
= false;
869 // #i124409# use the given Item to get the correct UI unit and initialize it
870 // and the Fields using it
871 FieldUnit eDlgUnit
= GetCurrentUnit(eState
, pState
);
872 mbFieldMetricOutDated
|= (eDlgUnit
!= meDlgUnit
|| maUIScale
!= rUIScale
);
873 if (!mbFieldMetricOutDated
)
875 meDlgUnit
= eDlgUnit
;
877 if (mxMtrPosX
->get_text().isEmpty())
879 SetFieldUnit( *mxMtrPosX
, meDlgUnit
, true );
881 mxMtrPosX
->set_text(OUString());
883 if (mxMtrPosY
->get_text().isEmpty())
885 SetFieldUnit( *mxMtrPosY
, meDlgUnit
, true );
887 mxMtrPosY
->set_text(OUString());
889 SetPosSizeMinMax(rUIScale
);
891 if (mxMtrWidth
->get_text().isEmpty())
893 SetFieldUnit( *mxMtrWidth
, meDlgUnit
, true );
895 mxMtrWidth
->set_text(OUString());
897 if (mxMtrHeight
->get_text().isEmpty())
899 SetFieldUnit( *mxMtrHeight
, meDlgUnit
, true );
901 mxMtrHeight
->set_text(OUString());
905 FieldUnit
PosSizePropertyPanel::GetCurrentUnit( SfxItemState eState
, const SfxPoolItem
* pState
)
907 FieldUnit eUnit
= FieldUnit::NONE
;
909 if ( pState
&& eState
>= SfxItemState::DEFAULT
)
911 eUnit
= static_cast<FieldUnit
>(static_cast<const SfxUInt16Item
*>(pState
)->GetValue());
915 SfxViewFrame
* pFrame
= SfxViewFrame::Current();
916 SfxObjectShell
* pSh
= nullptr;
918 pSh
= pFrame
->GetObjectShell();
921 SfxModule
* pModule
= pSh
->GetModule();
924 const SfxPoolItem
* pItem
= pModule
->GetItem( SID_ATTR_METRIC
);
926 eUnit
= static_cast<FieldUnit
>(static_cast<const SfxUInt16Item
*>(pItem
)->GetValue());
930 SAL_WARN("svx.sidebar", "GetModuleFieldUnit(): no module found");
939 void PosSizePropertyPanel::DisableControls()
941 if( mbPositionProtected
)
943 // the position is protected("Position protect" option in modal dialog is checked),
944 // disable all the Position controls in sidebar
945 mxFtPosX
->set_sensitive(false);
946 mxMtrPosX
->set_sensitive(false);
947 mxFtPosY
->set_sensitive(false);
948 mxMtrPosY
->set_sensitive(false);
949 mxFtAngle
->set_sensitive(false);
950 mxMtrAngle
->set_sensitive(false);
951 mxDial
->set_sensitive(false);
952 mxFtFlip
->set_sensitive(false);
953 mxFlipTbx
->set_sensitive(false);
955 mxFtWidth
->set_sensitive(false);
956 mxMtrWidth
->set_sensitive(false);
957 mxFtHeight
->set_sensitive(false);
958 mxMtrHeight
->set_sensitive(false);
959 mxCbxScale
->set_sensitive(false);
963 mxFtPosX
->set_sensitive(true);
964 mxMtrPosX
->set_sensitive(true);
965 mxFtPosY
->set_sensitive(true);
966 mxMtrPosY
->set_sensitive(true);
968 if( mbSizeProtected
)
970 mxFtWidth
->set_sensitive(false);
971 mxMtrWidth
->set_sensitive(false);
972 mxFtHeight
->set_sensitive(false);
973 mxMtrHeight
->set_sensitive(false);
974 mxCbxScale
->set_sensitive(false);
978 if( mbAdjustEnabled
)
982 mxFtWidth
->set_sensitive(false);
983 mxMtrWidth
->set_sensitive(false);
984 mxCbxScale
->set_sensitive(false);
988 mxFtWidth
->set_sensitive(true);
989 mxMtrWidth
->set_sensitive(true);
993 mxFtHeight
->set_sensitive(false);
994 mxMtrHeight
->set_sensitive(false);
995 mxCbxScale
->set_sensitive(false);
999 mxFtHeight
->set_sensitive(true);
1000 mxMtrHeight
->set_sensitive(true);
1002 if( !mbAutoWidth
&& !mbAutoHeight
)
1003 mxCbxScale
->set_sensitive(true);
1007 mxFtWidth
->set_sensitive(true);
1008 mxMtrWidth
->set_sensitive(true);
1009 mxFtHeight
->set_sensitive(true);
1010 mxMtrHeight
->set_sensitive(true);
1011 mxCbxScale
->set_sensitive(true);
1017 void PosSizePropertyPanel::SetPosSizeMinMax(const Fraction
& rUIScale
)
1019 SdrPageView
* pPV
= mpView
->GetSdrPageView();
1022 tools::Rectangle
aTmpRect(mpView
->GetAllMarkedRect());
1023 pPV
->LogicToPagePos(aTmpRect
);
1024 maRect
= vcl::unotools::b2DRectangleFromRectangle(aTmpRect
);
1026 tools::Rectangle
aTmpRect2(mpView
->GetWorkArea());
1027 pPV
->LogicToPagePos(aTmpRect2
);
1028 maWorkArea
= vcl::unotools::b2DRectangleFromRectangle(aTmpRect2
);
1030 TransfrmHelper::ScaleRect(maWorkArea
, rUIScale
);
1031 TransfrmHelper::ScaleRect(maRect
, rUIScale
);
1033 const sal_uInt16
nDigits(mxMtrPosX
->get_digits());
1034 TransfrmHelper::ConvertRect( maWorkArea
, nDigits
, mePoolUnit
, meDlgUnit
);
1035 TransfrmHelper::ConvertRect( maRect
, nDigits
, mePoolUnit
, meDlgUnit
);
1037 double fLeft(maWorkArea
.getMinX());
1038 double fTop(maWorkArea
.getMinY());
1039 double fRight(maWorkArea
.getMaxX());
1040 double fBottom(maWorkArea
.getMaxY());
1042 // seems that sidebar defaults to top left reference point
1043 // and there's no way to set it to something else
1044 fRight
-= maRect
.getWidth();
1045 fBottom
-= maRect
.getHeight();
1047 const double fMaxLong(static_cast<double>(vcl::ConvertValue( LONG_MAX
, 0, MapUnit::Map100thMM
, meDlgUnit
) - 1));
1048 fLeft
= std::clamp(fLeft
, -fMaxLong
, fMaxLong
);
1049 fRight
= std::clamp(fRight
, -fMaxLong
, fMaxLong
);
1050 fTop
= std::clamp(fTop
, - fMaxLong
, fMaxLong
);
1051 fBottom
= std::clamp(fBottom
, -fMaxLong
, fMaxLong
);
1053 mxMtrPosX
->set_range(basegfx::fround64(fLeft
), basegfx::fround64(fRight
), FieldUnit::NONE
);
1054 limitWidth(*mxMtrPosX
);
1055 mxMtrPosY
->set_range(basegfx::fround64(fTop
), basegfx::fround64(fBottom
), FieldUnit::NONE
);
1056 limitWidth(*mxMtrPosY
);
1058 double fMaxWidth
= maWorkArea
.getWidth() - (maRect
.getWidth() - fLeft
);
1059 double fMaxHeight
= maWorkArea
.getHeight() - (maRect
.getHeight() - fTop
);
1060 mxMtrWidth
->set_max(std::min
<sal_Int64
>(INT_MAX
, basegfx::fround64(fMaxWidth
*100)), FieldUnit::NONE
);
1061 limitWidth(*mxMtrWidth
);
1062 mxMtrHeight
->set_max(std::min
<sal_Int64
>(INT_MAX
, basegfx::fround64(fMaxHeight
*100)), FieldUnit::NONE
);
1063 limitWidth(*mxMtrHeight
);
1066 void PosSizePropertyPanel::UpdateUIScale(const Fraction
& rUIScale
)
1068 if (maUIScale
== rUIScale
)
1071 // UI scale has changed.
1073 // Remember the new UI scale.
1074 maUIScale
= rUIScale
;
1076 // The content of the position and size boxes is only updated when item changes are notified.
1077 // Request such notifications without changing the actual item values.
1078 GetBindings()->Invalidate(SID_ATTR_TRANSFORM_POS_X
, true);
1079 GetBindings()->Invalidate(SID_ATTR_TRANSFORM_POS_Y
, true);
1080 GetBindings()->Invalidate(SID_ATTR_TRANSFORM_WIDTH
, true);
1081 GetBindings()->Invalidate(SID_ATTR_TRANSFORM_HEIGHT
, true);
1085 } // end of namespace svx::sidebar
1087 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */