KiCad PCB EDA Suite
Loading...
Searching...
No Matches
zoom_controller.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5 * Copyright (C) 2013-2015 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * @author Tomasz Wlostowski <[email protected]>
9 * @author Maciej Suminski <[email protected]>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 */
24
26
27#include <trace_helpers.h>
28
29#include <wx/log.h>
30
31#include <algorithm>
32#include <cmath>
33
34using namespace KIGFX;
35
36
37// Bounds the zoom of a single event however many notches it reports
38static constexpr double MAX_MERGED_NOTCHES = 10.0;
39
40
41// Notches carried by one wheel event, where aWheelDelta is the rotation of a single notch
42// A zero aWheelDelta means the rotation is a scroll distance, so the event counts as one notch
43static double notchCount( int aRotation, int aWheelDelta )
44{
45 if( aWheelDelta <= 0 )
46 return 1.0;
47
48 return std::clamp( std::abs( double( aRotation ) ) / aWheelDelta, 1.0, MAX_MERGED_NOTCHES );
49}
50
51
57{
58public:
60 {
61 return ACCELERATING_ZOOM_CONTROLLER::CLOCK::now();
62 }
63};
64
65
67 double aScale, const TIMEOUT& aAccTimeout, TIMESTAMP_PROVIDER* aTimestampProv ) :
68 m_accTimeout( aAccTimeout ),
69 m_scale( aScale )
70{
71 if( aTimestampProv )
72 {
73 m_timestampProv = aTimestampProv;
74 }
75 else
76 {
77 m_ownTimestampProv = std::make_unique<SIMPLE_TIMESTAMPER>();
79 }
80
81 m_prevTimestamp = m_timestampProv->GetTimestamp();
82}
83
84
85double ACCELERATING_ZOOM_CONTROLLER::GetScaleForRotation( int aRotation, int aWheelDelta )
86{
87 // The minimal step value when changing the current zoom level
88 const double minStep = 1.05;
89
90 const auto timestamp = m_timestampProv->GetTimestamp();
91 auto timeDiff = std::chrono::duration_cast<TIMEOUT>( timestamp - m_prevTimestamp );
92
93 m_prevTimestamp = timestamp;
94
95 wxLogTrace( traceZoomScroll,
96 wxString::Format( "Rot %d, time diff: %ldms", aRotation, (long)timeDiff.count() ) );
97
98 double zoomScale;
99
100 // Set scaling speed depending on scroll wheel event interval
101 if( timeDiff < m_accTimeout
102 && ( (aRotation > 0) == m_prevRotationPositive ) )
103 {
104 zoomScale = ( 2.05 * m_scale / 5.0 ) - timeDiff / m_accTimeout;
105
106 // be sure zoomScale value is significant
107 zoomScale = std::max( zoomScale, minStep );
108
109 if( aRotation < 0 )
110 zoomScale = 1.0 / zoomScale;
111 }
112 else
113 {
114 zoomScale = ( aRotation > 0 ) ? minStep : 1 / minStep;
115 }
116 m_prevRotationPositive = aRotation > 0;
117
118 if( notchCount( aRotation, aWheelDelta ) > 1.0 )
119 zoomScale = std::pow( zoomScale, notchCount( aRotation, aWheelDelta ) );
120
121 wxLogTrace( traceZoomScroll, wxString::Format( " Zoom factor: %f", zoomScale ) );
122
123 return zoomScale;
124}
125
126#ifdef __MINGW32__
127// For some reason, this is needed to avoid a link issue
128// (undefined reference to ACCELERATING_ZOOM_CONTROLLER::DEFAULT_TIMEOUT
129// and GAL_API CONSTANT_ZOOM_CONTROLLER::MSW_SCALE)
132#endif
133
134
136{
137}
138
139
140double CONSTANT_ZOOM_CONTROLLER::GetScaleForRotation( int aRotation, int aWheelDelta )
141{
142 wxLogTrace( traceZoomScroll, wxString::Format( "Rot %d", aRotation ) );
143
144 // One notch is worth at most 100 units, and each further notch of a merged event zooms by it again
145 const double stepCap = aWheelDelta > 0 ? std::min( aWheelDelta, 100 ) : 100;
146 const double oneStep = std::min( std::abs( double( aRotation ) ), stepCap );
147 const double factor = std::pow( 1.0 + oneStep * m_scale, notchCount( aRotation, aWheelDelta ) );
148 const double zoom_scale = aRotation > 0 ? factor : 1.0 / factor;
149
150 wxLogTrace( traceZoomScroll, wxString::Format( " Zoom factor: %f", zoom_scale ) );
151
152 return zoom_scale;
153}
A interface that provides timestamps for events.
double GetScaleForRotation(int aRotation, int aWheelDelta=0) override
Get the scale factor produced by a given mousewheel rotation.
std::chrono::time_point< CLOCK > TIME_PT
The type of the time stamps.
std::chrono::milliseconds TIMEOUT
The type of the acceleration timeout.
static constexpr TIMEOUT DEFAULT_TIMEOUT
The default timeout, after which a another scroll will not be accelerated.
TIME_PT m_prevTimestamp
The timestamp of the previous event.
TIMEOUT m_accTimeout
The timeout value.
bool m_prevRotationPositive
Previous rotation was positive.
double m_scale
A multiplier for the minimum zoom step size.
TIMESTAMP_PROVIDER * m_timestampProv
The timestamp provider to use (might be provided externally).
ACCELERATING_ZOOM_CONTROLLER(double aScale=DEFAULT_ACCELERATION_SCALE, const TIMEOUT &aAccTimeout=DEFAULT_TIMEOUT, TIMESTAMP_PROVIDER *aTimestampProv=nullptr)
std::unique_ptr< TIMESTAMP_PROVIDER > m_ownTimestampProv
Any provider owned by this class (the default one, if used).
double m_scale
The scale factor set by the constructor.
double GetScaleForRotation(int aRotation, int aWheelDelta=0) override
Get the scale factor produced by a given mousewheel rotation.
static constexpr double MSW_SCALE
A suitable (magic) scale factor for Windows systems.
A very simple timestamper that uses the KIGFX::ACCELERATING_ZOOM_CONTROLLER::CLOCK to provide a times...
ACCELERATING_ZOOM_CONTROLLER::TIME_PT GetTimestamp() override
#define GAL_API
Definition gal.h:27
const wxChar *const traceZoomScroll
Flag to enable debug output of zoom-scrolling calculations in KIGFX::ZOOM_CONTROLLER and derivatives.
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:30
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
wxLogTrace helper definitions.
static double notchCount(int aRotation, int aWheelDelta)
static constexpr double MAX_MERGED_NOTCHES
ZOOM_CONTROLLER class definition.