1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 #include <svl/eitem.hxx>
22 #include <svl/stritem.hxx>
23 #include <dialmgr.hxx>
24 #include <svx/dlgutil.hxx>
25 #include <editeng/sizeitem.hxx>
26 #include <editeng/brushitem.hxx>
27 #include <grfpage.hxx>
28 #include <svx/grfcrop.hxx>
29 #include <rtl/ustring.hxx>
30 #include <tools/debug.hxx>
31 #include <tools/fract.hxx>
32 #include <svx/svxids.hrc>
33 #include <strings.hrc>
34 #include <vcl/fieldvalues.hxx>
35 #include <vcl/settings.hxx>
36 #include <vcl/svapp.hxx>
37 #include <svtools/unitconv.hxx>
38 #include <svtools/optionsdrawinglayer.hxx>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <basegfx/polygon/b2dpolygontools.hxx>
41 #include <o3tl/unit_conversion.hxx>
42 
43 constexpr auto CM_1_TO_TWIP = o3tl::convert(1, o3tl::Length::cm, o3tl::Length::twip); // 567
44 
45 
lcl_GetValue(const weld::MetricSpinButton & rMetric,FieldUnit eUnit)46 static int lcl_GetValue(const weld::MetricSpinButton& rMetric, FieldUnit eUnit)
47 {
48     return rMetric.denormalize(rMetric.get_value(eUnit));
49 }
50 
51 /*--------------------------------------------------------------------
52     description: crop graphic
53  --------------------------------------------------------------------*/
54 
SvxGrfCropPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rSet)55 SvxGrfCropPage::SvxGrfCropPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rSet)
56     : SfxTabPage(pPage, pController, "cui/ui/croppage.ui", "CropPage", &rSet)
57     , nOldWidth(0)
58     , nOldHeight(0)
59     , bSetOrigSize(false)
60     , m_xCropFrame(m_xBuilder->weld_widget("cropframe"))
61     , m_xZoomConstRB(m_xBuilder->weld_radio_button("keepscale"))
62     , m_xSizeConstRB(m_xBuilder->weld_radio_button("keepsize"))
63     , m_xLeftMF(m_xBuilder->weld_metric_spin_button("left", FieldUnit::CM))
64     , m_xRightMF(m_xBuilder->weld_metric_spin_button("right", FieldUnit::CM))
65     , m_xTopMF(m_xBuilder->weld_metric_spin_button("top", FieldUnit::CM))
66     , m_xBottomMF(m_xBuilder->weld_metric_spin_button("bottom", FieldUnit::CM))
67     , m_xScaleFrame(m_xBuilder->weld_widget("scaleframe"))
68     , m_xWidthZoomMF(m_xBuilder->weld_metric_spin_button("widthzoom", FieldUnit::PERCENT))
69     , m_xHeightZoomMF(m_xBuilder->weld_metric_spin_button("heightzoom", FieldUnit::PERCENT))
70     , m_xSizeFrame(m_xBuilder->weld_widget("sizeframe"))
71     , m_xWidthMF(m_xBuilder->weld_metric_spin_button("width", FieldUnit::CM))
72     , m_xHeightMF(m_xBuilder->weld_metric_spin_button("height", FieldUnit::CM))
73     , m_xOrigSizeGrid(m_xBuilder->weld_widget("origsizegrid"))
74     , m_xOrigSizeFT(m_xBuilder->weld_label("origsizeft"))
75     , m_xOrigSizePB(m_xBuilder->weld_button("origsize"))
76     , m_xExampleWN(new weld::CustomWeld(*m_xBuilder, "preview", m_aExampleWN))
77 {
78     SetExchangeSupport();
79 
80     // set the correct metric
81     const FieldUnit eMetric = GetModuleFieldUnit( rSet );
82 
83     SetFieldUnit( *m_xWidthMF, eMetric );
84     SetFieldUnit( *m_xHeightMF, eMetric );
85     SetFieldUnit( *m_xLeftMF, eMetric );
86     SetFieldUnit( *m_xRightMF, eMetric );
87     SetFieldUnit( *m_xTopMF , eMetric );
88     SetFieldUnit( *m_xBottomMF, eMetric );
89 
90     Link<weld::MetricSpinButton&,void> aLk = LINK(this, SvxGrfCropPage, SizeHdl);
91     m_xWidthMF->connect_value_changed( aLk );
92     m_xHeightMF->connect_value_changed( aLk );
93 
94     aLk = LINK(this, SvxGrfCropPage, ZoomHdl);
95     m_xWidthZoomMF->connect_value_changed( aLk );
96     m_xHeightZoomMF->connect_value_changed( aLk );
97 
98     aLk = LINK(this, SvxGrfCropPage, CropModifyHdl);
99     m_xLeftMF->connect_value_changed( aLk );
100     m_xRightMF->connect_value_changed( aLk );
101     m_xTopMF->connect_value_changed( aLk );
102     m_xBottomMF->connect_value_changed( aLk );
103 
104     m_xOrigSizePB->connect_clicked(LINK(this, SvxGrfCropPage, OrigSizeHdl));
105 }
106 
~SvxGrfCropPage()107 SvxGrfCropPage::~SvxGrfCropPage()
108 {
109     m_xExampleWN.reset();
110 }
111 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)112 std::unique_ptr<SfxTabPage> SvxGrfCropPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rSet)
113 {
114     return std::make_unique<SvxGrfCropPage>(pPage, pController, *rSet);
115 }
116 
Reset(const SfxItemSet * rSet)117 void SvxGrfCropPage::Reset( const SfxItemSet *rSet )
118 {
119     const SfxPoolItem* pItem;
120     const SfxItemPool& rPool = *rSet->GetPool();
121 
122     if(SfxItemState::SET == rSet->GetItemState( rPool.GetWhich(
123                                     SID_ATTR_GRAF_KEEP_ZOOM ), true, &pItem ))
124     {
125         if( static_cast<const SfxBoolItem*>(pItem)->GetValue() )
126             m_xZoomConstRB->set_active(true);
127         else
128             m_xSizeConstRB->set_active(true);
129         m_xZoomConstRB->save_state();
130     }
131 
132     sal_uInt16 nW = rPool.GetWhich( SID_ATTR_GRAF_CROP );
133     if( SfxItemState::SET == rSet->GetItemState( nW, true, &pItem))
134     {
135         FieldUnit eUnit = MapToFieldUnit( rSet->GetPool()->GetMetric( nW ));
136 
137         const SvxGrfCrop* pCrop = static_cast<const SvxGrfCrop*>(pItem);
138 
139         m_aExampleWN.SetLeft(pCrop->GetLeft());
140         m_aExampleWN.SetRight(pCrop->GetRight());
141         m_aExampleWN.SetTop(pCrop->GetTop());
142         m_aExampleWN.SetBottom(pCrop->GetBottom());
143 
144         m_xLeftMF->set_value( m_xLeftMF->normalize( pCrop->GetLeft()), eUnit );
145         m_xRightMF->set_value( m_xRightMF->normalize( pCrop->GetRight()), eUnit );
146         m_xTopMF->set_value( m_xTopMF->normalize( pCrop->GetTop()), eUnit );
147         m_xBottomMF->set_value( m_xBottomMF->normalize( pCrop->GetBottom()), eUnit );
148     }
149     else
150     {
151         m_xLeftMF->set_value(0, FieldUnit::NONE);
152         m_xRightMF->set_value(0, FieldUnit::NONE);
153         m_xTopMF->set_value(0, FieldUnit::NONE);
154         m_xBottomMF->set_value(0, FieldUnit::NONE);
155     }
156 
157     m_xLeftMF->save_value();
158     m_xRightMF->save_value();
159     m_xTopMF->save_value();
160     m_xBottomMF->save_value();
161 
162     nW = rPool.GetWhich( SID_ATTR_PAGE_SIZE );
163     if ( SfxItemState::SET == rSet->GetItemState( nW, false, &pItem ) )
164     {
165         // orientation and size from the PageItem
166         FieldUnit eUnit = MapToFieldUnit( rSet->GetPool()->GetMetric( nW ));
167 
168         aPageSize = static_cast<const SvxSizeItem*>(pItem)->GetSize();
169 
170         auto nMin = m_xWidthMF->normalize( 23 );
171         auto nMax = m_xHeightMF->normalize(aPageSize.Height());
172         m_xHeightMF->set_range(nMin, nMax, eUnit);
173         nMax = m_xWidthMF->normalize(aPageSize.Width());
174         m_xWidthMF->set_range(nMin, nMax, eUnit);
175     }
176     else
177     {
178         aPageSize = OutputDevice::LogicToLogic(
179                         Size( CM_1_TO_TWIP,  CM_1_TO_TWIP ),
180                         MapMode( MapUnit::MapTwip ),
181                         MapMode( rSet->GetPool()->GetMetric( nW ) ) );
182     }
183 
184     bool bFound = false;
185     if( SfxItemState::SET == rSet->GetItemState( SID_ATTR_GRAF_GRAPHIC, false, &pItem ) )
186     {
187         OUString referer;
188         SfxStringItem const * it = static_cast<SfxStringItem const *>(
189             rSet->GetItem(SID_REFERER));
190         if (it != nullptr) {
191             referer = it->GetValue();
192         }
193         const Graphic* pGrf = static_cast<const SvxBrushItem*>(pItem)->GetGraphic(referer);
194         if( pGrf )
195         {
196             aOrigSize = GetGrfOrigSize( *pGrf );
197             if (pGrf->GetType() == GraphicType::Bitmap && aOrigSize.Width() && aOrigSize.Height())
198             {
199                 aOrigPixelSize = pGrf->GetSizePixel();
200             }
201 
202             if( aOrigSize.Width() && aOrigSize.Height() )
203             {
204                 CalcMinMaxBorder();
205                 m_aExampleWN.SetGraphic( *pGrf );
206                 m_aExampleWN.SetFrameSize( aOrigSize );
207 
208                 bFound = true;
209                 if( !static_cast<const SvxBrushItem*>(pItem)->GetGraphicLink().isEmpty() )
210                     aGraphicName = static_cast<const SvxBrushItem*>(pItem)->GetGraphicLink();
211             }
212         }
213     }
214 
215     GraphicHasChanged( bFound );
216     ActivatePage( *rSet );
217 }
218 
FillItemSet(SfxItemSet * rSet)219 bool SvxGrfCropPage::FillItemSet(SfxItemSet *rSet)
220 {
221     const SfxItemPool& rPool = *rSet->GetPool();
222     bool bModified = false;
223     if( m_xWidthMF->get_value_changed_from_saved() ||
224         m_xHeightMF->get_value_changed_from_saved() )
225     {
226         sal_uInt16 nW = rPool.GetWhich( SID_ATTR_GRAF_FRMSIZE );
227         FieldUnit eUnit = MapToFieldUnit( rSet->GetPool()->GetMetric( nW ));
228 
229         std::shared_ptr<SvxSizeItem> aSz(std::make_shared<SvxSizeItem>(nW));
230 
231         // size could already have been set from another page
232         const SfxItemSet* pExSet = GetDialogExampleSet();
233         const SfxPoolItem* pItem = nullptr;
234         if( pExSet && SfxItemState::SET ==pExSet->GetItemState( nW, false, &pItem ) )
235         {
236             aSz.reset(static_cast< SvxSizeItem*>(pItem->Clone()));
237         }
238         else
239         {
240             aSz.reset(static_cast< SvxSizeItem*>(GetItemSet().Get(nW).Clone()));
241         }
242 
243         Size aTmpSz( aSz->GetSize() );
244         if( m_xWidthMF->get_value_changed_from_saved() )
245             aTmpSz.setWidth( lcl_GetValue( *m_xWidthMF, eUnit ) );
246         if( m_xHeightMF->get_value_changed_from_saved() )
247             aTmpSz.setHeight( lcl_GetValue( *m_xHeightMF, eUnit ) );
248         aSz->SetSize( aTmpSz );
249         m_xWidthMF->save_value();
250         m_xHeightMF->save_value();
251 
252         bModified |= nullptr != rSet->Put( *aSz );
253 
254         if( bSetOrigSize )
255         {
256             bModified |= nullptr != rSet->Put( SvxSizeItem( rPool.GetWhich(
257                         SID_ATTR_GRAF_FRMSIZE_PERCENT ), Size( 0, 0 )) );
258         }
259     }
260     if( m_xLeftMF->get_value_changed_from_saved() || m_xRightMF->get_value_changed_from_saved() ||
261         m_xTopMF->get_value_changed_from_saved()  || m_xBottomMF->get_value_changed_from_saved() )
262     {
263         sal_uInt16 nW = rPool.GetWhich( SID_ATTR_GRAF_CROP );
264         FieldUnit eUnit = MapToFieldUnit( rSet->GetPool()->GetMetric( nW ));
265         std::unique_ptr<SvxGrfCrop> pNew(static_cast<SvxGrfCrop*>(rSet->Get( nW ).Clone()));
266 
267         pNew->SetLeft( lcl_GetValue( *m_xLeftMF, eUnit ) );
268         pNew->SetRight( lcl_GetValue( *m_xRightMF, eUnit ) );
269         pNew->SetTop( lcl_GetValue( *m_xTopMF, eUnit ) );
270         pNew->SetBottom( lcl_GetValue( *m_xBottomMF, eUnit ) );
271         bModified |= nullptr != rSet->Put( *pNew );
272     }
273 
274     if( m_xZoomConstRB->get_state_changed_from_saved() )
275     {
276         bModified |= nullptr != rSet->Put( SfxBoolItem( rPool.GetWhich(
277                     SID_ATTR_GRAF_KEEP_ZOOM), m_xZoomConstRB->get_active() ) );
278     }
279 
280     return bModified;
281 }
282 
ActivatePage(const SfxItemSet & rSet)283 void SvxGrfCropPage::ActivatePage(const SfxItemSet& rSet)
284 {
285 #ifdef DBG_UTIL
286     SfxItemPool* pPool = GetItemSet().GetPool();
287     DBG_ASSERT( pPool, "Where is the pool?" );
288 #endif
289 
290     bSetOrigSize = false;
291 
292     // Size
293     Size aSize;
294     const SfxPoolItem* pItem;
295     if( SfxItemState::SET == rSet.GetItemState( SID_ATTR_GRAF_FRMSIZE, false, &pItem ) )
296         aSize = static_cast<const SvxSizeItem*>(pItem)->GetSize();
297 
298     nOldWidth = aSize.Width();
299     nOldHeight = aSize.Height();
300 
301     auto nWidth = m_xWidthMF->normalize(nOldWidth);
302     auto nHeight = m_xHeightMF->normalize(nOldHeight);
303 
304     if (nWidth != m_xWidthMF->get_value(FieldUnit::TWIP))
305         m_xWidthMF->set_value(nWidth, FieldUnit::TWIP);
306     m_xWidthMF->save_value();
307 
308     if (nHeight != m_xHeightMF->get_value(FieldUnit::TWIP))
309         m_xHeightMF->set_value(nHeight, FieldUnit::TWIP);
310     m_xHeightMF->save_value();
311 
312     if( SfxItemState::SET == rSet.GetItemState( SID_ATTR_GRAF_GRAPHIC, false, &pItem ) )
313     {
314         const SvxBrushItem& rBrush = *static_cast<const SvxBrushItem*>(pItem);
315         if( !rBrush.GetGraphicLink().isEmpty() &&
316             aGraphicName != rBrush.GetGraphicLink() )
317             aGraphicName = rBrush.GetGraphicLink();
318 
319         OUString referer;
320         SfxStringItem const * it = static_cast<SfxStringItem const *>(
321             rSet.GetItem(SID_REFERER));
322         if (it != nullptr) {
323             referer = it->GetValue();
324         }
325         const Graphic* pGrf = rBrush.GetGraphic(referer);
326         if( pGrf )
327         {
328             m_aExampleWN.SetGraphic( *pGrf );
329             aOrigSize = GetGrfOrigSize( *pGrf );
330             if (pGrf->GetType() == GraphicType::Bitmap && aOrigSize.Width() > 1 && aOrigSize.Height() > 1) {
331                 aOrigPixelSize = pGrf->GetSizePixel();
332             }
333             m_aExampleWN.SetFrameSize(aOrigSize);
334             GraphicHasChanged( aOrigSize.Width() && aOrigSize.Height() );
335             CalcMinMaxBorder();
336         }
337         else
338             GraphicHasChanged( false );
339     }
340 
341     CalcZoom();
342 }
343 
DeactivatePage(SfxItemSet * _pSet)344 DeactivateRC SvxGrfCropPage::DeactivatePage(SfxItemSet *_pSet)
345 {
346     if ( _pSet )
347         FillItemSet( _pSet );
348     return DeactivateRC::LeavePage;
349 }
350 
351 /*--------------------------------------------------------------------
352     description: scale changed, adjust size
353  --------------------------------------------------------------------*/
354 
IMPL_LINK(SvxGrfCropPage,ZoomHdl,weld::MetricSpinButton &,rField,void)355 IMPL_LINK( SvxGrfCropPage, ZoomHdl, weld::MetricSpinButton&, rField, void )
356 {
357     SfxItemPool* pPool = GetItemSet().GetPool();
358     DBG_ASSERT( pPool, "Where is the pool?" );
359     FieldUnit eUnit = MapToFieldUnit( pPool->GetMetric( pPool->GetWhich(
360                                                     SID_ATTR_GRAF_CROP ) ) );
361 
362     if (&rField == m_xWidthZoomMF.get())
363     {
364         tools::Long nLRBorders = lcl_GetValue(*m_xLeftMF, eUnit)
365                          +lcl_GetValue(*m_xRightMF, eUnit);
366         m_xWidthMF->set_value( m_xWidthMF->normalize(
367             ((aOrigSize.Width() - nLRBorders) * rField.get_value(FieldUnit::NONE))/100),
368             eUnit);
369     }
370     else
371     {
372         tools::Long nULBorders = lcl_GetValue(*m_xTopMF, eUnit)
373                          +lcl_GetValue(*m_xBottomMF, eUnit);
374         m_xHeightMF->set_value( m_xHeightMF->normalize(
375             ((aOrigSize.Height() - nULBorders ) * rField.get_value(FieldUnit::NONE))/100) ,
376             eUnit );
377     }
378 }
379 
380 /*--------------------------------------------------------------------
381     description: change size, adjust scale
382  --------------------------------------------------------------------*/
383 
IMPL_LINK(SvxGrfCropPage,SizeHdl,weld::MetricSpinButton &,rField,void)384 IMPL_LINK( SvxGrfCropPage, SizeHdl, weld::MetricSpinButton&, rField, void )
385 {
386     SfxItemPool* pPool = GetItemSet().GetPool();
387     DBG_ASSERT( pPool, "Where is the pool?" );
388     FieldUnit eUnit = MapToFieldUnit( pPool->GetMetric( pPool->GetWhich(
389                                                     SID_ATTR_GRAF_CROP ) ) );
390 
391     Size aSize( lcl_GetValue(*m_xWidthMF, eUnit),
392                 lcl_GetValue(*m_xHeightMF, eUnit) );
393 
394     if(&rField == m_xWidthMF.get())
395     {
396         tools::Long nWidth = aOrigSize.Width() -
397                 ( lcl_GetValue(*m_xLeftMF, eUnit) +
398                   lcl_GetValue(*m_xRightMF, eUnit) );
399         if(!nWidth)
400             nWidth++;
401         sal_uInt16 nZoom = static_cast<sal_uInt16>( aSize.Width() * 100 / nWidth);
402         m_xWidthZoomMF->set_value(nZoom, FieldUnit::NONE);
403     }
404     else
405     {
406         tools::Long nHeight = aOrigSize.Height() -
407                 ( lcl_GetValue(*m_xTopMF, eUnit) +
408                   lcl_GetValue(*m_xBottomMF, eUnit));
409         if(!nHeight)
410             nHeight++;
411         sal_uInt16 nZoom = static_cast<sal_uInt16>( aSize.Height() * 100 / nHeight);
412         m_xHeightZoomMF->set_value(nZoom, FieldUnit::NONE);
413     }
414 }
415 
416 /*--------------------------------------------------------------------
417     description: evaluate border
418  --------------------------------------------------------------------*/
419 
IMPL_LINK(SvxGrfCropPage,CropModifyHdl,weld::MetricSpinButton &,rField,void)420 IMPL_LINK( SvxGrfCropPage, CropModifyHdl, weld::MetricSpinButton&, rField, void )
421 {
422     SfxItemPool* pPool = GetItemSet().GetPool();
423     DBG_ASSERT( pPool, "Where is the pool?" );
424     FieldUnit eUnit = MapToFieldUnit( pPool->GetMetric( pPool->GetWhich(
425                                                     SID_ATTR_GRAF_CROP ) ) );
426 
427     bool bZoom = m_xZoomConstRB->get_active();
428     if (&rField == m_xLeftMF.get() || &rField == m_xRightMF.get())
429     {
430         tools::Long nLeft = lcl_GetValue( *m_xLeftMF, eUnit );
431         tools::Long nRight = lcl_GetValue( *m_xRightMF, eUnit );
432         tools::Long nWidthZoom = static_cast<tools::Long>(m_xWidthZoomMF->get_value(FieldUnit::NONE));
433         if (bZoom && nWidthZoom != 0 && ( ( ( aOrigSize.Width() - (nLeft + nRight )) * nWidthZoom )
434                             / 100 >= aPageSize.Width() ) )
435         {
436             if (&rField == m_xLeftMF.get())
437             {
438                 nLeft = aOrigSize.Width() -
439                             ( aPageSize.Width() * 100 / nWidthZoom + nRight );
440                 m_xLeftMF->set_value( m_xLeftMF->normalize( nLeft ), eUnit );
441             }
442             else
443             {
444                 nRight = aOrigSize.Width() -
445                             ( aPageSize.Width() * 100 / nWidthZoom + nLeft );
446                 m_xRightMF->set_value( m_xRightMF->normalize( nRight ), eUnit );
447             }
448         }
449         if (AllSettings::GetLayoutRTL())
450         {
451             m_aExampleWN.SetLeft(nRight);
452             m_aExampleWN.SetRight(nLeft);
453         }
454         else
455         {
456             m_aExampleWN.SetLeft(nLeft);
457             m_aExampleWN.SetRight(nRight);
458         }
459         if(bZoom)
460         {
461             // scale stays, recompute width
462             ZoomHdl(*m_xWidthZoomMF);
463         }
464     }
465     else
466     {
467         tools::Long nTop = lcl_GetValue( *m_xTopMF, eUnit );
468         tools::Long nBottom = lcl_GetValue( *m_xBottomMF, eUnit );
469         tools::Long nHeightZoom = static_cast<tools::Long>(m_xHeightZoomMF->get_value(FieldUnit::NONE));
470         if(bZoom && ( ( ( aOrigSize.Height() - (nTop + nBottom )) * nHeightZoom)
471                                             / 100 >= aPageSize.Height()))
472         {
473             assert(nHeightZoom && "div-by-zero");
474             if(&rField == m_xTopMF.get())
475             {
476                 nTop = aOrigSize.Height() -
477                             ( aPageSize.Height() * 100 / nHeightZoom + nBottom);
478                 m_xTopMF->set_value( m_xWidthMF->normalize( nTop ), eUnit );
479             }
480             else
481             {
482                 nBottom = aOrigSize.Height() -
483                             ( aPageSize.Height() * 100 / nHeightZoom + nTop);
484                 m_xBottomMF->set_value( m_xWidthMF->normalize( nBottom ), eUnit );
485             }
486         }
487         m_aExampleWN.SetTop( nTop );
488         m_aExampleWN.SetBottom( nBottom );
489         if(bZoom)
490         {
491             // scale stays, recompute height
492             ZoomHdl(*m_xHeightZoomMF);
493         }
494     }
495     m_aExampleWN.Invalidate();
496     // size and border changed -> recompute scale
497     if(!bZoom)
498         CalcZoom();
499     CalcMinMaxBorder();
500 }
501 /*--------------------------------------------------------------------
502     description: set original size
503  --------------------------------------------------------------------*/
504 
IMPL_LINK_NOARG(SvxGrfCropPage,OrigSizeHdl,weld::Button &,void)505 IMPL_LINK_NOARG(SvxGrfCropPage, OrigSizeHdl, weld::Button&, void)
506 {
507     SfxItemPool* pPool = GetItemSet().GetPool();
508     DBG_ASSERT( pPool, "Where is the pool?" );
509     FieldUnit eUnit = MapToFieldUnit( pPool->GetMetric( pPool->GetWhich(
510                                                     SID_ATTR_GRAF_CROP ) ) );
511 
512     tools::Long nWidth = aOrigSize.Width() -
513         lcl_GetValue( *m_xLeftMF, eUnit ) -
514         lcl_GetValue( *m_xRightMF, eUnit );
515     m_xWidthMF->set_value( m_xWidthMF->normalize( nWidth ), eUnit );
516     tools::Long nHeight = aOrigSize.Height() -
517         lcl_GetValue( *m_xTopMF, eUnit ) -
518         lcl_GetValue( *m_xBottomMF, eUnit );
519     m_xHeightMF->set_value( m_xHeightMF->normalize( nHeight ), eUnit );
520     m_xWidthZoomMF->set_value(100, FieldUnit::NONE);
521     m_xHeightZoomMF->set_value(100, FieldUnit::NONE);
522     bSetOrigSize = true;
523 }
524 /*--------------------------------------------------------------------
525     description: compute scale
526  --------------------------------------------------------------------*/
527 
CalcZoom()528 void SvxGrfCropPage::CalcZoom()
529 {
530     SfxItemPool* pPool = GetItemSet().GetPool();
531     DBG_ASSERT( pPool, "Where is the pool?" );
532     FieldUnit eUnit = MapToFieldUnit( pPool->GetMetric( pPool->GetWhich(
533                                                     SID_ATTR_GRAF_CROP ) ) );
534 
535     tools::Long nWidth = lcl_GetValue( *m_xWidthMF, eUnit );
536     tools::Long nHeight = lcl_GetValue( *m_xHeightMF, eUnit );
537     tools::Long nLRBorders = lcl_GetValue( *m_xLeftMF, eUnit ) +
538                       lcl_GetValue( *m_xRightMF, eUnit );
539     tools::Long nULBorders = lcl_GetValue( *m_xTopMF, eUnit ) +
540                       lcl_GetValue( *m_xBottomMF, eUnit );
541     sal_uInt16 nZoom = 0;
542     tools::Long nDen;
543     if( (nDen = aOrigSize.Width() - nLRBorders) > 0)
544         nZoom = static_cast<sal_uInt16>((( nWidth  * 1000 / nDen )+5)/10);
545     m_xWidthZoomMF->set_value(nZoom, FieldUnit::NONE);
546     if( (nDen = aOrigSize.Height() - nULBorders) > 0)
547         nZoom = static_cast<sal_uInt16>((( nHeight * 1000 / nDen )+5)/10);
548     else
549         nZoom = 0;
550     m_xHeightZoomMF->set_value(nZoom, FieldUnit::NONE);
551 }
552 
553 /*--------------------------------------------------------------------
554     description: set minimum/maximum values for the margins
555  --------------------------------------------------------------------*/
556 
CalcMinMaxBorder()557 void SvxGrfCropPage::CalcMinMaxBorder()
558 {
559     SfxItemPool* pPool = GetItemSet().GetPool();
560     DBG_ASSERT( pPool, "Where is the pool?" );
561     FieldUnit eUnit = MapToFieldUnit( pPool->GetMetric( pPool->GetWhich(
562                                                     SID_ATTR_GRAF_CROP ) ) );
563     tools::Long nR = lcl_GetValue(*m_xRightMF, eUnit );
564     tools::Long nMinWidth = (aOrigSize.Width() * 10) /11;
565     tools::Long nMin = nMinWidth - (nR >= 0 ? nR : 0);
566     m_xLeftMF->set_max( m_xLeftMF->normalize(nMin), eUnit );
567 
568     tools::Long nL = lcl_GetValue(*m_xLeftMF, eUnit );
569     nMin = nMinWidth - (nL >= 0 ? nL : 0);
570     m_xRightMF->set_max( m_xRightMF->normalize(nMin), eUnit );
571 
572     tools::Long nUp  = lcl_GetValue( *m_xTopMF, eUnit );
573     tools::Long nMinHeight = (aOrigSize.Height() * 10) /11;
574     nMin = nMinHeight - (nUp >= 0 ? nUp : 0);
575     m_xBottomMF->set_max( m_xBottomMF->normalize(nMin), eUnit );
576 
577     tools::Long nLow = lcl_GetValue(*m_xBottomMF, eUnit );
578     nMin = nMinHeight - (nLow >= 0 ? nLow : 0);
579     m_xTopMF->set_max( m_xTopMF->normalize(nMin), eUnit );
580 }
581 /*--------------------------------------------------------------------
582     description:   set spinsize to 1/20 of the original size,
583                    fill FixedText with the original size
584  --------------------------------------------------------------------*/
585 
GraphicHasChanged(bool bFound)586 void SvxGrfCropPage::GraphicHasChanged( bool bFound )
587 {
588     if( bFound )
589     {
590         SfxItemPool* pPool = GetItemSet().GetPool();
591         DBG_ASSERT( pPool, "Where is the pool?" );
592         FieldUnit eUnit = MapToFieldUnit( pPool->GetMetric( pPool->GetWhich(
593                                                     SID_ATTR_GRAF_CROP ) ));
594 
595         sal_Int64 nSpin = m_xLeftMF->normalize(aOrigSize.Width()) / 20;
596         nSpin = vcl::ConvertValue( nSpin, aOrigSize.Width(), 0,
597                                                eUnit, m_xLeftMF->get_unit());
598 
599         // if the margin is too big, it is set to 1/3 on both pages
600         tools::Long nR = lcl_GetValue( *m_xRightMF, eUnit );
601         tools::Long nL = lcl_GetValue( *m_xLeftMF, eUnit );
602         if((nL + nR) < - aOrigSize.Width())
603         {
604             tools::Long nVal = aOrigSize.Width() / -3;
605             m_xRightMF->set_value( m_xRightMF->normalize( nVal ), eUnit );
606             m_xLeftMF->set_value( m_xLeftMF->normalize( nVal ), eUnit );
607             m_aExampleWN.SetLeft(nVal);
608             m_aExampleWN.SetRight(nVal);
609         }
610         tools::Long nUp  = lcl_GetValue(*m_xTopMF, eUnit );
611         tools::Long nLow = lcl_GetValue(*m_xBottomMF, eUnit );
612         if((nUp + nLow) < - aOrigSize.Height())
613         {
614             tools::Long nVal = aOrigSize.Height() / -3;
615             m_xTopMF->set_value( m_xTopMF->normalize( nVal ), eUnit );
616             m_xBottomMF->set_value( m_xBottomMF->normalize( nVal ), eUnit );
617             m_aExampleWN.SetTop(nVal);
618             m_aExampleWN.SetBottom(nVal);
619         }
620 
621         m_xLeftMF->set_increments(nSpin, nSpin * 10, FieldUnit::NONE);
622         m_xRightMF->set_increments(nSpin, nSpin * 10, FieldUnit::NONE);
623         nSpin = m_xTopMF->normalize(aOrigSize.Height()) / 20;
624         nSpin = vcl::ConvertValue( nSpin, aOrigSize.Width(), 0,
625                                                eUnit, m_xLeftMF->get_unit() );
626         m_xTopMF->set_increments(nSpin, nSpin * 10, FieldUnit::NONE);
627         m_xBottomMF->set_increments(nSpin, nSpin * 10, FieldUnit::NONE);
628 
629         // display original size
630         const FieldUnit eMetric = GetModuleFieldUnit( GetItemSet() );
631 
632         OUString sTemp;
633         {
634             std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "cui/ui/spinbox.ui"));
635             std::unique_ptr<weld::Dialog> xTopLevel(xBuilder->weld_dialog("SpinDialog"));
636             std::unique_ptr<weld::MetricSpinButton> xFld(xBuilder->weld_metric_spin_button("spin", FieldUnit::CM));
637             SetFieldUnit( *xFld, eMetric );
638             xFld->set_digits(m_xWidthMF->get_digits());
639             xFld->set_max(INT_MAX - 1, FieldUnit::NONE);
640 
641             xFld->set_value(xFld->normalize(aOrigSize.Width()), eUnit);
642             sTemp = xFld->get_text();
643             xFld->set_value(xFld->normalize(aOrigSize.Height()), eUnit);
644             // multiplication sign (U+00D7)
645             sTemp += u"\u00D7" + xFld->get_text();
646         }
647 
648         if ( aOrigPixelSize.Width() && aOrigPixelSize.Height() ) {
649              sal_Int32 ax = 0.5 + aOrigPixelSize.Width() /
650                  o3tl::convert<double>(aOrigSize.Width(), o3tl::Length::twip,
651                                                           o3tl::Length::in);
652              sal_Int32 ay = 0.5 + aOrigPixelSize.Height() /
653                  o3tl::convert<double>(aOrigSize.Height(), o3tl::Length::twip,
654                                                            o3tl::Length::in);
655              OUString sPPI = OUString::number(ax);
656              if (abs(ax - ay) > 1) {
657                 sPPI += u"\u00D7" + OUString::number(ay);
658              }
659              sTemp += " " + CuiResId(RID_SVXSTR_PPI).replaceAll("%1", sPPI);
660         }
661         m_xOrigSizeFT->set_label(sTemp);
662     }
663 
664     m_xCropFrame->set_sensitive(bFound);
665     m_xScaleFrame->set_sensitive(bFound);
666     m_xSizeFrame->set_sensitive(bFound);
667     m_xOrigSizeGrid->set_sensitive(bFound);
668     m_xZoomConstRB->set_sensitive(bFound);
669 }
670 
GetGrfOrigSize(const Graphic & rGrf)671 Size SvxGrfCropPage::GetGrfOrigSize(const Graphic& rGrf)
672 {
673     const MapMode aMapTwip( MapUnit::MapTwip );
674     Size aSize( rGrf.GetPrefSize() );
675     if( MapUnit::MapPixel == rGrf.GetPrefMapMode().GetMapUnit() )
676         aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMapTwip);
677     else
678         aSize = OutputDevice::LogicToLogic( aSize,
679                                         rGrf.GetPrefMapMode(), aMapTwip );
680     return aSize;
681 }
682 
683 /*****************************************************************/
684 
SvxCropExample()685 SvxCropExample::SvxCropExample()
686     : m_aTopLeft(0, 0)
687     , m_aBottomRight(0, 0)
688 {
689 }
690 
SetDrawingArea(weld::DrawingArea * pDrawingArea)691 void SvxCropExample::SetDrawingArea(weld::DrawingArea* pDrawingArea)
692 {
693     CustomWidgetController::SetDrawingArea(pDrawingArea);
694     OutputDevice& rDevice = pDrawingArea->get_ref_device();
695     Size aSize(rDevice.LogicToPixel(Size(78, 78), MapMode(MapUnit::MapAppFont)));
696     pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
697 
698     m_aMapMode = rDevice.GetMapMode();
699     m_aFrameSize = OutputDevice::LogicToLogic(
700                             Size(CM_1_TO_TWIP / 2, CM_1_TO_TWIP / 2),
701                             MapMode(MapUnit::MapTwip), m_aMapMode);
702 }
703 
Paint(vcl::RenderContext & rRenderContext,const::tools::Rectangle &)704 void SvxCropExample::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle&)
705 {
706     rRenderContext.Push(PushFlags::MAPMODE);
707     rRenderContext.SetMapMode(m_aMapMode);
708 
709     // Win BG
710     const Size aWinSize(rRenderContext.PixelToLogic(GetOutputSizePixel()));
711     rRenderContext.SetLineColor();
712     rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor());
713     rRenderContext.DrawRect(::tools::Rectangle(Point(), aWinSize));
714 
715     // use AA, the Graphic may be a metafile/svg and would then look ugly
716     rRenderContext.SetAntialiasing(AntialiasingFlags::Enable);
717 
718     // draw Graphic
719     ::tools::Rectangle aRect(
720         Point((aWinSize.Width() - m_aFrameSize.Width())/2, (aWinSize.Height() - m_aFrameSize.Height())/2),
721         m_aFrameSize);
722     m_aGrf.Draw(rRenderContext, aRect.TopLeft(), aRect.GetSize());
723 
724     // Remove one more case that uses XOR paint (RasterOp::Invert).
725     // Get colors and logic DashLength from settings, use equal to
726     // PolygonMarkerPrimitive2D, may be changed to that primitive later.
727     // Use this to guarantee good visibility - that was the purpose of
728     // the former used XOR paint.
729     const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
730     const Color aColA(aSvtOptionsDrawinglayer.GetStripeColorA().getBColor());
731     const Color aColB(aSvtOptionsDrawinglayer.GetStripeColorB().getBColor());
732     const double fStripeLength(aSvtOptionsDrawinglayer.GetStripeLength());
733     const basegfx::B2DVector aDashVector(rRenderContext.GetInverseViewTransformation() * basegfx::B2DVector(fStripeLength, 0.0));
734     const double fLogicDashLength(aDashVector.getX());
735 
736     // apply current crop settings
737     aRect.AdjustLeft(m_aTopLeft.Y());
738     aRect.AdjustTop(m_aTopLeft.X());
739     aRect.AdjustRight(-m_aBottomRight.Y());
740     aRect.AdjustBottom(-m_aBottomRight.X());
741 
742     // apply dash with direct paint callbacks
743     basegfx::utils::applyLineDashing(
744         basegfx::utils::createPolygonFromRect(
745             basegfx::B2DRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom())),
746         std::vector< double >(2, fLogicDashLength),
747         [&aColA,&rRenderContext](const basegfx::B2DPolygon& rSnippet)
748         {
749             rRenderContext.SetLineColor(aColA);
750             rRenderContext.DrawPolyLine(rSnippet);
751         },
752         [&aColB,&rRenderContext](const basegfx::B2DPolygon& rSnippet)
753         {
754             rRenderContext.SetLineColor(aColB);
755             rRenderContext.DrawPolyLine(rSnippet);
756         },
757         2.0 * fLogicDashLength);
758 
759     rRenderContext.Pop();
760 }
761 
Resize()762 void SvxCropExample::Resize()
763 {
764     SetFrameSize(m_aFrameSize);
765 }
766 
SetFrameSize(const Size & rSz)767 void SvxCropExample::SetFrameSize( const Size& rSz )
768 {
769     m_aFrameSize = rSz;
770     if (!m_aFrameSize.Width())
771         m_aFrameSize.setWidth( 1 );
772     if (!m_aFrameSize.Height())
773         m_aFrameSize.setHeight( 1 );
774     Size aWinSize( GetOutputSizePixel() );
775     Fraction aXScale( aWinSize.Width() * 4, m_aFrameSize.Width() * 5 );
776     Fraction aYScale( aWinSize.Height() * 4, m_aFrameSize.Height() * 5 );
777 
778     if( aYScale < aXScale )
779         aXScale = aYScale;
780 
781     m_aMapMode.SetScaleX(aXScale);
782     m_aMapMode.SetScaleY(aXScale);
783 
784     Invalidate();
785 }
786 
787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
788