LibreOffice Module sc (master)  1
tbzoomsliderctrl.cxx
Go to the documentation of this file.
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 #include <tbzoomsliderctrl.hxx>
21 #include <vcl/event.hxx>
22 #include <vcl/image.hxx>
23 #include <vcl/toolbox.hxx>
24 #include <vcl/virdev.hxx>
25 #include <svx/zoomslideritem.hxx>
26 #include <iterator>
27 #include <set>
28 #include <bitmaps.hlst>
29 
30 #include <com/sun/star/frame/XFrame.hpp>
31 #include <com/sun/star/frame/XDispatchProvider.hpp>
32 
33 // class ScZoomSliderControl ---------------------------------------
34 
36 
38  sal_uInt16 nSlotId,
39  ToolBoxItemId nId,
40  ToolBox& rTbx )
41  :SfxToolBoxControl( nSlotId, nId, rTbx )
42 {
43  rTbx.Invalidate();
44 }
45 
47 {
48 
49 }
50 
52  const SfxPoolItem* pState )
53 {
55  ToolBox& rTbx = GetToolBox();
56  ScZoomSliderWnd* pBox = static_cast<ScZoomSliderWnd*>(rTbx.GetItemWindow( nId ));
57  OSL_ENSURE( pBox ,"Control not found!" );
58 
59  if ( SfxItemState::DEFAULT != eState || pState->IsVoidItem() )
60  {
61  SvxZoomSliderItem aZoomSliderItem( 100 );
62  pBox->Disable();
63  pBox->UpdateFromItem( &aZoomSliderItem );
64  }
65  else
66  {
67  pBox->Enable();
68  OSL_ENSURE( dynamic_cast<const SvxZoomSliderItem*>( pState) != nullptr, "invalid item type" );
69  const SvxZoomSliderItem* pZoomSliderItem = dynamic_cast< const SvxZoomSliderItem* >( pState );
70 
71  OSL_ENSURE( pZoomSliderItem, "Sc::ScZoomSliderControl::StateChanged(), wrong item type!" );
72  if( pZoomSliderItem )
73  pBox->UpdateFromItem( pZoomSliderItem );
74  }
75 }
76 
78 {
79  // #i98000# Don't try to get a value via SfxViewFrame::Current here.
80  // The view's value is always notified via StateChanged later.
81  VclPtrInstance<ScZoomSliderWnd> xSlider( pParent,
82  css::uno::Reference< css::frame::XDispatchProvider >( m_xFrame->getController(),
83  css::uno::UNO_QUERY ), 100 );
84  return xSlider;
85 }
86 
87 constexpr sal_uInt16 gnSliderCenter(100);
88 
97 const tools::Long nSnappingEpsilon = 5; // snapping epsilon in pixels
98 const tools::Long nSnappingPointsMinDist = nSnappingEpsilon; // minimum distance of two adjacent snapping points
99 
100 sal_uInt16 ScZoomSlider::Offset2Zoom( tools::Long nOffset ) const
101 {
102  Size aSliderWindowSize = GetOutputSizePixel();
103  const tools::Long nControlWidth = aSliderWindowSize.Width();
104  sal_uInt16 nRet = 0;
105 
106  if( nOffset < nSliderXOffset )
107  return mnMinZoom;
108  if( nOffset > nControlWidth - nSliderXOffset )
109  return mnMaxZoom;
110 
111  // check for snapping points:
112  auto aSnappingPointIter = std::find_if(maSnappingPointOffsets.begin(), maSnappingPointOffsets.end(),
113  [nOffset](const tools::Long nCurrent) { return std::abs(nCurrent - nOffset) < nSnappingEpsilon; });
114  if (aSnappingPointIter != maSnappingPointOffsets.end())
115  {
116  nOffset = *aSnappingPointIter;
117  auto nCount = static_cast<sal_uInt16>(std::distance(maSnappingPointOffsets.begin(), aSnappingPointIter));
118  nRet = maSnappingPointZooms[ nCount ];
119  }
120 
121  if( 0 == nRet )
122  {
123  if( nOffset < nControlWidth / 2 )
124  {
125  // first half of slider
126  const tools::Long nFirstHalfRange = gnSliderCenter - mnMinZoom;
127  const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
128  const tools::Long nZoomPerSliderPixel = (1000 * nFirstHalfRange) / nHalfSliderWidth;
129  const tools::Long nOffsetToSliderLeft = nOffset - nSliderXOffset;
130  nRet = mnMinZoom + sal_uInt16( nOffsetToSliderLeft * nZoomPerSliderPixel / 1000 );
131  }
132  else
133  {
134  // second half of slider
135  const tools::Long nSecondHalfRange = mnMaxZoom - gnSliderCenter;
136  const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
137  const tools::Long nZoomPerSliderPixel = 1000 * nSecondHalfRange / nHalfSliderWidth;
138  const tools::Long nOffsetToSliderCenter = nOffset - nControlWidth/2;
139  nRet = gnSliderCenter + sal_uInt16( nOffsetToSliderCenter * nZoomPerSliderPixel / 1000 );
140  }
141  }
142 
143  if( nRet < mnMinZoom )
144  return mnMinZoom;
145 
146  else if( nRet > mnMaxZoom )
147  return mnMaxZoom;
148 
149  return nRet;
150 }
151 
152 tools::Long ScZoomSlider::Zoom2Offset( sal_uInt16 nCurrentZoom ) const
153 {
154  Size aSliderWindowSize = GetOutputSizePixel();
155  const tools::Long nControlWidth = aSliderWindowSize.Width();
156  tools::Long nRect = nSliderXOffset;
157 
158  const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
159  if( nCurrentZoom <= gnSliderCenter )
160  {
161  nCurrentZoom = nCurrentZoom - mnMinZoom;
162  const tools::Long nFirstHalfRange = gnSliderCenter - mnMinZoom;
163  const tools::Long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nFirstHalfRange;
164  const tools::Long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
165  nRect += nOffset;
166  }
167  else
168  {
169  nCurrentZoom = nCurrentZoom - gnSliderCenter;
170  const tools::Long nSecondHalfRange = mnMaxZoom - gnSliderCenter;
171  const tools::Long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nSecondHalfRange;
172  const tools::Long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
173  nRect += nHalfSliderWidth + nOffset;
174  }
175  return nRect;
176 }
177 
179  const css::uno::Reference< css::frame::XDispatchProvider >& rDispatchProvider,
180  sal_uInt16 nCurrentZoom ):
181  InterimItemWindow(pParent, "modules/scalc/ui/zoombox.ui", "ZoomBox"),
182  mxWidget(new ScZoomSlider(rDispatchProvider, nCurrentZoom)),
183  mxWeld(new weld::CustomWeld(*m_xBuilder, "zoom", *mxWidget))
184 {
185  Size aLogicalSize( 115, 40 );
186  Size aSliderSize = LogicToPixel(aLogicalSize, MapMode(MapUnit::Map10thMM));
187  Size aPreferredSize(aSliderSize.Width() * nSliderWidth-1, aSliderSize.Height() + nSliderHeight);
188  mxWidget->GetDrawingArea()->set_size_request(aPreferredSize.Width(), aPreferredSize.Height());
189  mxWidget->SetOutputSizePixel(aPreferredSize);
190  SetSizePixel(aPreferredSize);
191 }
192 
194 {
195  disposeOnce();
196 }
197 
199 {
200  mxWeld.reset();
201  mxWidget.reset();
203 }
204 
205 ScZoomSlider::ScZoomSlider(const css::uno::Reference< css::frame::XDispatchProvider>& rDispatchProvider,
206  sal_uInt16 nCurrentZoom)
207  : mnCurrentZoom( nCurrentZoom ),
208  mnMinZoom( 10 ),
209  mnMaxZoom( 400 ),
210  mbOmitPaint( false ),
211  m_xDispatchProvider(rDispatchProvider)
212 {
213  maSliderButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERBUTTON);
214  maIncreaseButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERINCREASE);
215  maDecreaseButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERDECREASE);
216 }
217 
218 
220 {
221  Size aSliderWindowSize = GetOutputSizePixel();
222 
223  const Point aPoint = rMEvt.GetPosPixel();
224 
225  const tools::Long nButtonLeftOffset = ( nSliderXOffset - nIncDecWidth )/2;
226  const tools::Long nButtonRightOffset = ( nSliderXOffset + nIncDecWidth )/2;
227 
228  const tools::Long nOldZoom = mnCurrentZoom;
229 
230  // click to - button
231  if ( aPoint.X() >= nButtonLeftOffset && aPoint.X() <= nButtonRightOffset )
232  {
234  }
235  // click to + button
236  else if ( aPoint.X() >= aSliderWindowSize.Width() - nSliderXOffset + nButtonLeftOffset &&
237  aPoint.X() <= aSliderWindowSize.Width() - nSliderXOffset + nButtonRightOffset )
238  {
240  }
241  else if( aPoint.X() >= nSliderXOffset && aPoint.X() <= aSliderWindowSize.Width() - nSliderXOffset )
242  {
243  mnCurrentZoom = Offset2Zoom( aPoint.X() );
244  }
245 
246  if( mnCurrentZoom < mnMinZoom )
248  else if( mnCurrentZoom > mnMaxZoom )
250 
251  if( nOldZoom == mnCurrentZoom )
252  return true;
253 
254  tools::Rectangle aRect( Point( 0, 0 ), aSliderWindowSize );
255 
256  Invalidate(aRect);
257  mbOmitPaint = true;
258 
259  SvxZoomSliderItem aZoomSliderItem( mnCurrentZoom );
260 
261  css::uno::Any a;
262  aZoomSliderItem.QueryValue( a );
263 
264  css::uno::Sequence< css::beans::PropertyValue > aArgs( 1 );
265  aArgs[0].Name = "ScalingFactor";
266  aArgs[0].Value = a;
267 
268  SfxToolBoxControl::Dispatch( m_xDispatchProvider, ".uno:ScalingFactor", aArgs );
269 
270  mbOmitPaint = false;
271 
272  return true;
273 }
274 
276 {
277  Size aSliderWindowSize = GetOutputSizePixel();
278  const tools::Long nControlWidth = aSliderWindowSize.Width();
279  const short nButtons = rMEvt.GetButtons();
280 
281  // check mouse move with button pressed
282  if ( 1 == nButtons )
283  {
284  const Point aPoint = rMEvt.GetPosPixel();
285 
286  if ( aPoint.X() >= nSliderXOffset && aPoint.X() <= nControlWidth - nSliderXOffset )
287  {
288  mnCurrentZoom = Offset2Zoom( aPoint.X() );
289 
290  tools::Rectangle aRect(Point(0, 0), aSliderWindowSize);
291  Invalidate(aRect);
292 
293  mbOmitPaint = true; // optimization: paint before executing command,
294 
295  // commit state change
296  SvxZoomSliderItem aZoomSliderItem( mnCurrentZoom );
297 
298  css::uno::Any a;
299  aZoomSliderItem.QueryValue( a );
300 
301  css::uno::Sequence< css::beans::PropertyValue > aArgs( 1 );
302  aArgs[0].Name = "ScalingFactor";
303  aArgs[0].Value = a;
304 
305  SfxToolBoxControl::Dispatch( m_xDispatchProvider, ".uno:ScalingFactor", aArgs );
306 
307  mbOmitPaint = false;
308  }
309  }
310 
311  return false;
312 }
313 
315 {
316  mxWidget->UpdateFromItem(pZoomSliderItem);
317 }
318 
320 {
321  if( pZoomSliderItem )
322  {
323  mnCurrentZoom = pZoomSliderItem->GetValue();
324  mnMinZoom = pZoomSliderItem->GetMinZoom();
325  mnMaxZoom = pZoomSliderItem->GetMaxZoom();
326 
327  OSL_ENSURE( mnMinZoom <= mnCurrentZoom &&
331  "Looks like the zoom slider item is corrupted" );
332  const css::uno::Sequence < sal_Int32 >& rSnappingPoints = pZoomSliderItem->GetSnappingPoints();
333  maSnappingPointOffsets.clear();
334  maSnappingPointZooms.clear();
335 
336  // get all snapping points:
337  std::set< sal_uInt16 > aTmpSnappingPoints;
338  std::transform(rSnappingPoints.begin(), rSnappingPoints.end(), std::inserter(aTmpSnappingPoints, aTmpSnappingPoints.end()),
339  [](const sal_Int32 nSnappingPoint) -> sal_uInt16 { return static_cast<sal_uInt16>(nSnappingPoint); });
340 
341  // remove snapping points that are too close to each other:
342  tools::Long nLastOffset = 0;
343 
344  for ( const sal_uInt16 nCurrent : aTmpSnappingPoints )
345  {
346  const tools::Long nCurrentOffset = Zoom2Offset( nCurrent );
347 
348  if ( nCurrentOffset - nLastOffset >= nSnappingPointsMinDist )
349  {
350  maSnappingPointOffsets.push_back( nCurrentOffset );
351  maSnappingPointZooms.push_back( nCurrent );
352  nLastOffset = nCurrentOffset;
353  }
354  }
355  }
356 
357  Size aSliderWindowSize = GetOutputSizePixel();
358  tools::Rectangle aRect(Point(0, 0), aSliderWindowSize);
359 
360  if ( !mbOmitPaint )
361  Invalidate(aRect);
362 }
363 
364 void ScZoomSlider::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
365 {
366  DoPaint(rRenderContext);
367 }
368 
370 {
371  if (mbOmitPaint)
372  return;
373 
374  Size aSliderWindowSize(GetOutputSizePixel());
375  tools::Rectangle aRect(Point(0, 0), aSliderWindowSize);
376 
377  ScopedVclPtrInstance< VirtualDevice > pVDev(rRenderContext);
378  pVDev->SetOutputSizePixel(aSliderWindowSize);
379 
380  tools::Rectangle aSlider = aRect;
381 
382  aSlider.AdjustTop((aSliderWindowSize.Height() - nSliderHeight) / 2 - 1 );
383  aSlider.SetBottom( aSlider.Top() + nSliderHeight );
384  aSlider.AdjustLeft(nSliderXOffset );
385  aSlider.AdjustRight( -nSliderXOffset );
386 
387  tools::Rectangle aFirstLine(aSlider);
388  aFirstLine.SetBottom( aFirstLine.Top() );
389 
390  tools::Rectangle aSecondLine(aSlider);
391  aSecondLine.SetTop( aSecondLine.Bottom() );
392 
393  tools::Rectangle aLeft(aSlider);
394  aLeft.SetRight( aLeft.Left() );
395 
396  tools::Rectangle aRight(aSlider);
397  aRight.SetLeft( aRight.Right() );
398 
399  // draw VirtualDevice's background color
400  Color aStartColor = rRenderContext.GetSettings().GetStyleSettings().GetFaceColor();
401  Color aEndColor = rRenderContext.GetSettings().GetStyleSettings().GetFaceColor();
402 
403  if (aEndColor.IsDark())
404  aStartColor = aEndColor;
405 
406  Gradient aGradient;
407  aGradient.SetAngle(0_deg10);
408  aGradient.SetStyle(GradientStyle::Linear);
409 
410  aGradient.SetStartColor(aStartColor);
411  aGradient.SetEndColor(aEndColor);
412  pVDev->DrawGradient(aRect, aGradient);
413 
414  // draw slider
415  pVDev->SetLineColor(COL_WHITE);
416  pVDev->DrawRect(aSecondLine);
417  pVDev->DrawRect(aRight);
418 
419  pVDev->SetLineColor(COL_GRAY);
420  pVDev->DrawRect(aFirstLine);
421  pVDev->DrawRect(aLeft);
422 
423  // draw snapping points:
424  for (const auto& rSnappingPointOffset : maSnappingPointOffsets)
425  {
426  pVDev->SetLineColor(COL_GRAY);
427  tools::Rectangle aSnapping(aRect);
428  aSnapping.SetBottom( aSlider.Top() );
429  aSnapping.SetTop( aSnapping.Bottom() - nSnappingHeight );
430  aSnapping.AdjustLeft(rSnappingPointOffset );
431  aSnapping.SetRight( aSnapping.Left() );
432  pVDev->DrawRect(aSnapping);
433 
436  pVDev->DrawRect(aSnapping);
437  }
438 
439  // draw slider button
440  Point aImagePoint = aRect.TopLeft();
441  aImagePoint.AdjustX(Zoom2Offset(mnCurrentZoom) );
442  aImagePoint.AdjustX( -(nButtonWidth / 2) );
443  aImagePoint.AdjustY( (aSliderWindowSize.Height() - nButtonHeight) / 2 );
444  pVDev->DrawImage(aImagePoint, maSliderButton);
445 
446  // draw decrease button
447  aImagePoint = aRect.TopLeft();
448  aImagePoint.AdjustX((nSliderXOffset - nIncDecWidth) / 2 );
449  aImagePoint.AdjustY((aSliderWindowSize.Height() - nIncDecHeight) / 2 );
450  pVDev->DrawImage(aImagePoint, maDecreaseButton);
451 
452  // draw increase button
453  aImagePoint.setX( aRect.Left() + aSliderWindowSize.Width() - nIncDecWidth - (nSliderXOffset - nIncDecWidth) / 2 );
454  pVDev->DrawImage(aImagePoint, maIncreaseButton);
455 
456  rRenderContext.DrawOutDev(Point(0, 0), aSliderWindowSize, Point(0, 0), aSliderWindowSize, *pVDev);
457 }
458 
459 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SetEndColor(const Color &rColor)
std::unique_ptr< weld::CustomWeld > mxWeld
void DoPaint(vcl::RenderContext &rRenderContext)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
const tools::Long nSliderHeight
vcl::Window * GetItemWindow(ToolBoxItemId nItemId) const
ToolBox & GetToolBox() const
constexpr tools::Long Left() const
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
constexpr sal_uInt16 gnSliderCenter(100)
virtual ~ScZoomSliderWnd() override
long Long
const StyleSettings & GetStyleSettings() const
const Color & GetFaceColor() const
const tools::Long nButtonHeight
css::uno::Reference< css::lang::XComponent > m_xFrame
virtual void SetSizePixel(const Size &rNewSize)
sal_Int16 nId
virtual bool MouseButtonDown(const MouseEvent &rMEvt) override
sal_uInt16 GetMaxZoom() const
css::uno::Reference< css::frame::XDispatchProvider > m_xDispatchProvider
Size const & GetOutputSizePixel() const
constexpr tools::Long Width() const
const tools::Long nIncDecHeight
void Enable(bool bEnable=true, bool bChild=true)
sal_uInt16 GetButtons() const
tools::Long Zoom2Offset(sal_uInt16 nZoom) const
std::vector< tools::Long > maSnappingPointOffsets
int nCount
virtual VclPtr< InterimItemWindow > CreateItemWindow(vcl::Window *pParent) override
void SetStartColor(const Color &rColor)
const tools::Long nSliderWidth
const tools::Long nSliderXOffset
virtual bool MouseMove(const MouseEvent &rMEvt) override
std::vector< sal_uInt16 > maSnappingPointZooms
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
virtual bool IsVoidItem() const
const tools::Long nSnappingEpsilon
constexpr void SetLeft(tools::Long v)
ScZoomSliderWnd(vcl::Window *pParent, const css::uno::Reference< css::frame::XDispatchProvider > &rDispatchProvider, sal_uInt16 nCurrentZoom)
virtual bool QueryValue(css::uno::Any &rVal, sal_uInt8 nMemberId=0) const override
Point LogicToPixel(const Point &rLogicPt) const
ScZoomSliderControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox &rTbx)
uno_Any a
std::unique_ptr< ScZoomSlider > mxWidget
bool IsDark() const
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
constexpr tools::Long Right() const
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_GRAY
constexpr tools::Long Top() const
const tools::Long nIncDecWidth
constexpr void SetRight(tools::Long v)
const AllSettings & GetSettings() const
constexpr void SetBottom(tools::Long v)
virtual void dispose() override
SFX_IMPL_TOOLBOX_CONTROL(ScZoomSliderControl, SvxZoomSliderItem)
ScZoomSlider(const css::uno::Reference< css::frame::XDispatchProvider > &rDispatchProvider, sal_uInt16 nCurrentZoom)
constexpr void SetTop(tools::Long v)
void Disable(bool bChild=true)
constexpr Point TopLeft() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
constexpr tools::Long Bottom() const
virtual ~ScZoomSliderControl() override
void SetAngle(Degree10 nAngle)
sal_uInt16 Offset2Zoom(tools::Long nOffset) const
const tools::Long nSnappingPointsMinDist
SfxItemState
constexpr tools::Long Height() const
void UpdateFromItem(const SvxZoomSliderItem *pZoomSliderItem)
virtual void dispose() override
virtual void StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem *pState) override
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
ToolBoxItemId GetId() const
sal_uInt16 mnMaxZoom
const Point & GetPosPixel() const
const tools::Long nButtonWidth
sal_uInt16 mnCurrentZoom
sal_uInt16 mnMinZoom
void UpdateFromItem(const SvxZoomSliderItem *pZoomSliderItem)
sal_uInt16 GetMinZoom() const
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
void SetStyle(GradientStyle eStyle)
const tools::Long nSnappingHeight
const css::uno::Sequence< sal_Int32 > & GetSnappingPoints() const
void Dispatch(const OUString &aCommand, css::uno::Sequence< css::beans::PropertyValue > const &aArgs)
SAL_DLLPRIVATE void DrawOutDev(const Point &, const Size &, const Point &, const Size &, const Printer &)=delete