Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / sidebar / possize / PosSizePropertyPanel.cxx
blob0024a41458db7278b6114fcb31a9e204c1d39a35
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <algorithm>
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>
40 #include <utility>
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>
52 using namespace css;
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")),
90 mpView(nullptr),
91 mlOldWidth(1),
92 mlOldHeight(1),
93 mlRotX(0),
94 mlRotY(0),
95 mePoolUnit(),
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),
113 mbAutoWidth(false),
114 mbAutoHeight(false),
115 mbAdjustEnabled(false),
116 mxSidebar(std::move(xSidebar))
118 Initialize();
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
122 // solution
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()
138 mxFtPosX.reset();
139 mxMtrPosX.reset();
140 mxFtPosY.reset();
141 mxMtrPosY.reset();
142 mxFtWidth.reset();
143 mxMtrWidth.reset();
144 mxFtHeight.reset();
145 mxMtrHeight.reset();
146 mxCbxScale.reset();
147 mxFtAngle.reset();
148 mxMtrAngle.reset();
149 mxDial.reset();
150 mxCtrlDial.reset();
151 mxFtFlip.reset();
152 mxFlipDispatch.reset();
153 mxFlipTbx.reset();
154 mxAlignDispatch.reset();
155 mxAlignDispatch2.reset();
156 mxAlignTbx.reset();
157 mxAlignTbx2.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();
179 namespace
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())
196 return true;
201 return false;
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 ) );
216 //Size : Keep ratio
217 mxCbxScale->connect_toggled( LINK( this, PosSizePropertyPanel, ClickAutoHdl ) );
219 //rotation control
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();
234 if ( pCurSh )
235 mpView = pCurSh->GetDrawView();
236 else
237 mpView = nullptr;
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);
256 if ( ! rxFrame.is())
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)
269 // Nothing to do.
270 return;
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):
284 bShowAngle = true;
285 bShowFlip = true;
286 bShowArrangeTbx2 = true;
287 break;
289 case CombinedEnumContext(Application::WriterVariants, Context::Graphic):
290 bShowFlip = true;
291 bShowAngle = true; // RotGrfFlyFrame: Writer FlyFrames for Graphics now support angle
292 break;
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;
302 bShowAngle = true;
303 bShowFlip = true;
304 break;
306 case CombinedEnumContext(Application::WriterVariants, Context::OLE):
307 bShowEditObject = true;
308 break;
310 case CombinedEnumContext(Application::Calc, Context::OLE):
311 case CombinedEnumContext(Application::DrawImpress, Context::OLE):
312 bShowPosition = true;
313 bShowEditObject = true;
314 break;
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;
325 break;
328 // Position
329 mxFtPosX->set_visible(bShowPosition);
330 mxMtrPosX->set_visible(bShowPosition);
331 mxFtPosY->set_visible(bShowPosition);
332 mxMtrPosY->set_visible(bShowPosition);
334 // Rotation
335 mxFtAngle->set_visible(bShowAngle);
336 mxMtrAngle->set_visible(bShowAngle);
337 mxCtrlDial->set_visible(bShowAngle);
339 // Flip
340 mxFtFlip->set_visible(bShowFlip);
341 mxFlipTbx->set_visible(bShowFlip);
343 // Edit Object
344 mxBtnEditOLEObject->set_visible(bShowEditObject);
346 // Arrange tool bar 2
347 mxArrangeTbx2->set_visible(bShowArrangeTbx2);
349 if (mxSidebar.is())
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 );
364 else
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 );
372 executeSize();
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 );
386 else
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 );
394 executeSize();
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();
460 if ( pCurSh)
462 pCurSh->DoVerb( -1 );
466 namespace
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(
479 sal_uInt16 nSID,
480 SfxItemState eState,
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();
493 if ( pCurSh )
494 mpView = pCurSh->GetDrawView();
495 else
496 mpView = nullptr;
498 if ( mpView == nullptr )
499 return;
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();
507 switch (nSID)
509 case SID_ATTR_TRANSFORM_WIDTH:
510 if ( SfxItemState::DEFAULT == eState )
512 pWidthItem = dynamic_cast< const SfxUInt32Item* >(pState);
514 if(pWidthItem)
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();
522 break;
526 mxMtrWidth->set_text( "" );
527 break;
529 case SID_ATTR_TRANSFORM_HEIGHT:
530 if ( SfxItemState::DEFAULT == eState )
532 pHeightItem = dynamic_cast< const SfxUInt32Item* >(pState);
534 if(pHeightItem)
536 tools::Long nTmp = tools::Long( pHeightItem->GetValue() / maUIScale);
537 SetFieldUnit( *mxMtrHeight, meDlgUnit, true );
538 SetMetricValue( *mxMtrHeight, nTmp, mePoolUnit );
539 limitWidth(*mxMtrHeight);
540 mlOldHeight = nTmp;
541 mxMtrHeight->save_value();
542 break;
546 mxMtrHeight->set_text( "");
547 break;
549 case SID_ATTR_TRANSFORM_POS_X:
550 if(SfxItemState::DEFAULT == eState)
552 const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >(pState);
554 if(pItem)
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();
561 break;
565 mxMtrPosX->set_text( "" );
566 break;
568 case SID_ATTR_TRANSFORM_POS_Y:
569 if(SfxItemState::DEFAULT == eState)
571 const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >(pState);
573 if(pItem)
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();
580 break;
584 mxMtrPosY->set_text( "" );
585 break;
587 case SID_ATTR_TRANSFORM_ROT_X:
588 if (SfxItemState::DEFAULT == eState)
590 const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >(pState);
592 if(pItem)
594 mlRotX = pItem->GetValue();
595 mlRotX = tools::Long( mlRotX / maUIScale );
598 break;
600 case SID_ATTR_TRANSFORM_ROT_Y:
601 if (SfxItemState::DEFAULT == eState)
603 const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >(pState);
605 if(pItem)
607 mlRotY = pItem->GetValue();
608 mlRotY = tools::Long( mlRotY / maUIScale );
611 break;
613 case SID_ATTR_TRANSFORM_PROTECT_POS:
614 if(SfxItemState::DEFAULT == eState)
616 const SfxBoolItem* pItem = dynamic_cast< const SfxBoolItem* >(pState);
618 if(pItem)
620 // record the state of position protect
621 mbPositionProtected = pItem->GetValue();
622 break;
626 mbPositionProtected = false;
627 break;
629 case SID_ATTR_TRANSFORM_PROTECT_SIZE:
630 if(SfxItemState::DEFAULT == eState)
632 const SfxBoolItem* pItem = dynamic_cast< const SfxBoolItem* >(pState);
634 if(pItem)
636 // record the state of size protect
637 mbSizeProtected = pItem->GetValue();
638 break;
642 mbSizeProtected = false;
643 break;
645 case SID_ATTR_TRANSFORM_AUTOWIDTH:
646 if(SfxItemState::DEFAULT == eState)
648 const SfxBoolItem* pItem = dynamic_cast< const SfxBoolItem* >(pState);
650 if(pItem)
652 mbAutoWidth = pItem->GetValue();
655 break;
657 case SID_ATTR_TRANSFORM_AUTOHEIGHT:
658 if(SfxItemState::DEFAULT == eState)
660 const SfxBoolItem* pItem = dynamic_cast< const SfxBoolItem* >(pState);
662 if(pItem)
664 mbAutoHeight = pItem->GetValue();
667 break;
669 case SID_ATTR_TRANSFORM_ANGLE:
670 if (eState >= SfxItemState::DEFAULT)
672 const SdrAngleItem* pItem = dynamic_cast< const SdrAngleItem* >(pState);
674 if(pItem)
676 Degree100 nTmp = NormAngle36000(pItem->GetValue());
678 mxMtrAngle->set_value(nTmp.get(), FieldUnit::DEGREE);
679 mxCtrlDial->SetRotation(nTmp);
681 break;
685 mxMtrAngle->set_text( "" );
686 mxCtrlDial->SetRotation( 0_deg100 );
687 break;
689 case SID_ATTR_METRIC:
691 const Fraction aUIScale(mpView->GetModel().GetUIScale());
692 MetricState(eState, pState, aUIScale);
693 UpdateUIScale(aUIScale);
694 mbFieldMetricOutDated = false;
695 break;
697 default:
698 break;
701 const sal_Int32 nCombinedContext(maContext.GetCombinedContext_DI());
702 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
704 switch (rMarkList.GetMarkCount())
706 case 0:
707 break;
709 case 1:
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);
725 break;
728 default:
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)
743 isNoEdge = false;
744 break;
746 nMarkObj++;
749 if(!isNoEdge)
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);
757 break;
761 if(nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::TextObject))
763 mxFlipTbx->set_sensitive(false);
764 mxFtFlip->set_sensitive(false);
767 DisableControls();
769 // mxCbxScale must synchronized with that on Position and Size tabpage on Shape Properties dialog
770 SvtViewOptions aPageOpt(EViewType::TabPage, "cui/ui/possizetabpage/PositionAndSize");
771 OUString sUserData;
772 css::uno::Any aUserItem = aPageOpt.GetUserItem( USERITEM_NAME );
773 OUString aTemp;
774 if ( aUserItem >>= aTemp )
775 sUserData = 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;
782 switch (nSID)
784 case SID_ATTR_TRANSFORM_POS_X:
785 pControl = mxMtrPosX.get();
786 break;
787 case SID_ATTR_TRANSFORM_POS_Y:
788 pControl = mxMtrPosY.get();
789 break;
790 case SID_ATTR_TRANSFORM_WIDTH:
791 pControl = mxMtrWidth.get();
792 break;
793 case SID_ATTR_TRANSFORM_HEIGHT:
794 pControl = mxMtrHeight.get();
795 break;
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())
809 return;
811 Fraction aUIScale = mpView->GetModel().GetUIScale();
813 // get Width
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 ));
819 // get Height
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 });
838 else
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)
874 return;
875 meDlgUnit = eDlgUnit;
877 if (mxMtrPosX->get_text().isEmpty())
878 bPosXBlank = true;
879 SetFieldUnit( *mxMtrPosX, meDlgUnit, true );
880 if(bPosXBlank)
881 mxMtrPosX->set_text(OUString());
883 if (mxMtrPosY->get_text().isEmpty())
884 bPosYBlank = true;
885 SetFieldUnit( *mxMtrPosY, meDlgUnit, true );
886 if(bPosYBlank)
887 mxMtrPosY->set_text(OUString());
889 SetPosSizeMinMax(rUIScale);
891 if (mxMtrWidth->get_text().isEmpty())
892 bWidthBlank = true;
893 SetFieldUnit( *mxMtrWidth, meDlgUnit, true );
894 if(bWidthBlank)
895 mxMtrWidth->set_text(OUString());
897 if (mxMtrHeight->get_text().isEmpty())
898 bHeightBlank = true;
899 SetFieldUnit( *mxMtrHeight, meDlgUnit, true );
900 if(bHeightBlank)
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());
913 else
915 SfxViewFrame* pFrame = SfxViewFrame::Current();
916 SfxObjectShell* pSh = nullptr;
917 if ( pFrame )
918 pSh = pFrame->GetObjectShell();
919 if ( pSh )
921 SfxModule* pModule = pSh->GetModule();
922 if ( pModule )
924 const SfxPoolItem* pItem = pModule->GetItem( SID_ATTR_METRIC );
925 if ( pItem )
926 eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
928 else
930 SAL_WARN("svx.sidebar", "GetModuleFieldUnit(): no module found");
935 return eUnit;
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);
961 else
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);
976 else
978 if( mbAdjustEnabled )
980 if( mbAutoWidth )
982 mxFtWidth->set_sensitive(false);
983 mxMtrWidth->set_sensitive(false);
984 mxCbxScale->set_sensitive(false);
986 else
988 mxFtWidth->set_sensitive(true);
989 mxMtrWidth->set_sensitive(true);
991 if( mbAutoHeight )
993 mxFtHeight->set_sensitive(false);
994 mxMtrHeight->set_sensitive(false);
995 mxCbxScale->set_sensitive(false);
997 else
999 mxFtHeight->set_sensitive(true);
1000 mxMtrHeight->set_sensitive(true);
1002 if( !mbAutoWidth && !mbAutoHeight )
1003 mxCbxScale->set_sensitive(true);
1005 else
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();
1020 if (!pPV)
1021 return;
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)
1069 return;
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: */