#ifndef ZoomManager_H
#define ZoomManager_H
#include <list>
#include <deque>
#include <utility>
#include <algorithm>
#include <boost\tuple\tuple.hpp>
template < class ViewT >
class ZoomManager
{
private:
class ZoomRect : private boost::tuple< double, double, double, double >
{
typedef enum
{
eXMin = 0,
eXMax = 1,
eYMin = 2,
eYMax = 3
} Offsets;
public:
ZoomRect( double xMin = 0.0, double xMax = 100.0, double yMin = 0.0, double yMax = 100.0 )
{
SetRect( xMin, xMax, yMin, yMax );
}
void GetRect( double & xMin, double & xMax, double & yMin, double & yMax ) const
{
xMin = get< eXMin >();
xMax = get< eXMax >();
yMin = get< eYMin >();
yMax = get< eYMax >();
}
void GetRect( double & xMin, double & xMax ) const
{
xMin = get< eXMin >();
xMax = get< eXMax >();
}
void SetRect( double xMin, double xMax, double yMin, double yMax )
{
get< eXMin >() = xMin;
get< eXMax >() = xMax;
get< eYMin >() = yMin;
get< eYMax >() = yMax;
}
double GetXMin() const { return get< eXMin >(); }
double GetXMax() const { return get< eXMax >(); }
double GetYMin() const { return get< eYMin >(); }
double GetYMax() const { return get< eYMax >(); }
};
public:
typedef enum
{
ePanFull = 0,
ePanLine = 1,
ePanPage = 2,
} PanMode;
public:
ZoomManager( ViewT * pView = 0 )
: mZoomDepth( -1 )
{
AddLink( pView );
}
virtual ~ZoomManager() {}
// Attributes
public:
int GetZoomDepth() const { return mZoomDepth; }
void SetZoomDepth( int depth )
{
mZoomDepth = depth;
if ( mZoomDepth > 0 )
{
// Pop the zoom stack until new depth is reached
while ( mStack.size() > size_t( mZoomDepth ) )
mStack.pop_back();
}
}
void GetZoomXY( double & xMin, double & xMax, double & yMin, double & yMax ) const
{
GetZoomRect().GetRect( xMin, xMax, yMin, yMax );
}
void GetZoomX( double & xMin, double & xMax ) const
{
GetZoomRect().GetRect( xMin, xMax );
}
void GetZoomY( double & yMin, double & yMax ) const
{
double dummy;
GetZoomRect().GetRect( dummy, dummy, yMin, yMax );
}
// Get / Set the default rectangle for fully zoomed-out state
void GetDefaultZoom( double & xMin, double & xMax, double & yMin, double & yMax ) const
{
xMin = mDefaultRect.GetXMin();
xMax = mDefaultRect.GetXMax();
yMin = mDefaultRect.GetYMin();
yMax = mDefaultRect.GetYMax();
}
void SetDefaultZoom( double xMin, double xMax, double yMin = 0.0, double yMax = 100.0 )
{
mDefaultRect.SetRect( xMin, xMax, yMin, yMax );
}
// Operations
public:
// Adds a link to the plot; returns true if successful, false if already linked
bool AddLink( ViewT * pView )
{
bool bResult = false;
if ( pView )
{
Links::iterator it = std::find( mLinks.begin(), mLinks.end(), pView );
if ( it == mLinks.end() )
{
mLinks.push_back( pView );
bResult = true;
}
}
return bResult;
}
// Removes a link to the plot; returns true if found, false if not
bool RemoveLink( ViewT * pView )
{
bool bResult = false;
Links::iterator it = std::find( mLinks.begin(), mLinks.end(), pView );
if ( it != mLinks.end() )
{
mLinks.erase( it );
bResult = true;
}
return bResult;
}
// Zooms X while autoscaling Y
void ZoomX( double xMin, double xMax )
{
PushZoom( ZoomRect( xMin, xMax ) );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax );
}
}
// Zooms Y leaving X unchanged
void ZoomY( double yMin, double yMax )
{
double xMin;
double xMax;
GetZoomX( xMin, xMax );
PushZoom( ZoomRect( xMin, xMax, yMin, yMax ) );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Zooms both x and y axes
void ZoomXY( double xMin, double xMax, double yMin, double yMax )
{
PushZoom( ZoomRect( xMin, xMax, yMin, yMax ) );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Zooms out to previous X zoom
void ZoomOutX()
{
double xMin;
double xMax;
PopZoom().GetRect( xMin, xMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax );
}
}
// Zooms out to previous Y zoom
void ZoomOutY()
{
// Same as ZoomOutXY for now
double xMin;
double xMax;
double yMin;
double yMax;
PopZoom().GetRect( xMin, xMax, yMin, yMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Zooms out to previous X-Y zoom
void ZoomOutXY()
{
double xMin;
double xMax;
double yMin;
double yMax;
PopZoom().GetRect( xMin, xMax, yMin, yMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Resets the zoom rectangle to defaults (zoom x, autoscale y)
void ZoomResetX()
{
mStack.clear();
double xMin;
double xMax;
mDefaultRect.GetRect( xMin, xMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax );
}
}
// Resets the X-Y zoom rectangle to the default
void ZoomResetXY()
{
mStack.clear();
double xMin;
double xMax;
double yMin;
double yMax;
mDefaultRect.GetRect( xMin, xMax, yMin, yMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Pans completely to the left or by a line or page, while
// keeping the zoom level the same
void PanLeft( PanMode mode )
{
ZoomRect rect = GetZoomRect();
double xMin = rect.GetXMin();
double xMax = rect.GetXMax();
double width = xMax - xMin;
switch( mode )
{
case ePanFull:
{
xMin = mDefaultRect.GetXMin();
xMax = xMin + width;
break;
}
case ePanPage:
{
if ( xMin - width >= mDefaultRect.GetXMin() )
{
xMin -= width;
xMax -= width;
}
else
{
xMin = mDefaultRect.GetXMin();
xMax = xMin + width;
}
break;
}
case ePanLine:
{
width /= 8;
if ( xMin - width >= mDefaultRect.GetXMin() )
{
xMin -= width;
xMax -= width;
}
else
{
xMin = mDefaultRect.GetXMin();
xMax = xMin + width * 8;
}
break;
}
}
PopZoom();
ZoomX( xMin, xMax );
}
// Pans completely to the right or by a line or page, while
// keeping the zoom level the same
void PanRight( PanMode mode )
{
ZoomRect rect = GetZoomRect();
double xMin = rect.GetXMin();
double xMax = rect.GetXMax();
double width = xMax - xMin;
switch( mode )
{
case ePanFull:
{
xMax = mDefaultRect.GetXMax();
xMin = xMax - width;
break;
}
case ePanPage:
{
if ( xMax + width <= mDefaultRect.GetXMax() )
{
xMin += width;
xMax += width;
}
else
{
xMax = mDefaultRect.GetXMax();
xMin = xMax - width;
}
break;
}
case ePanLine:
{
width /= 8;
if ( xMax + width <= mDefaultRect.GetXMax() )
{
xMin += width;
xMax += width;
}
else
{
xMax = mDefaultRect.GetXMax();
xMin = xMax - width * 8;
}
break;
}
}
PopZoom();
ZoomX( xMin, xMax );
}
void PanTo( double xPct, double yPct = 0.0 )
{
// TODO: add support for y panning
if ( xPct <= -1.0 )
PanLeft( ePanFull );
else if ( xPct >= 1.0 )
PanRight( ePanFull );
else
{
ZoomRect rect = GetZoomRect();
double xMin = rect.GetXMin();
double xMax = rect.GetXMax();
double width = xMax - xMin;
double xMinDef = mDefaultRect.GetXMin();
double xMaxDef = mDefaultRect.GetXMax();
xMin = xMinDef + xPct * 0.875 * (xMaxDef - xMinDef);
xMax = xMin + width;
if ( xMax > xMaxDef )
{
xMax = xMaxDef;
xMin = xMax - width;
}
PopZoom();
ZoomX( xMin, xMax );
}
}
protected:
// Pushes the ZoomRect onto the zoom stack while managing stack depth
void PushZoom( const ZoomRect & zoomRect )
{
// If zoom depth is zero, there's no stack so nothing to save
if ( mZoomDepth == 0 )
return;
// Save it
mStack.push_front( zoomRect );
// Remove the bottom-most entry if the stack is too large
if ( mZoomDepth > 0 && mStack.size() > size_t( mZoomDepth ) )
mStack.pop_back();
}
// Pops the ZoomRect from the zoom stack
const ZoomRect & PopZoom()
{
// Remove the current level
if ( !mStack.empty() )
mStack.pop_front();
return GetZoomRect();
}
// Retrieves a reference to the current zoom rectangle
const ZoomRect & GetZoomRect() const
{
if ( mStack.empty() )
return mDefaultRect;
else
return mStack.front();
}
protected:
typedef std::list< ViewT * > Links;
Links mLinks;
typedef std::deque< ZoomRect > Stack;
Stack mStack;
int mZoomDepth;
ZoomRect mDefaultRect;
};
#endif // ZoomManager_H
#ifndef ZoomManager_H
#define ZoomManager_H
#include <list>
#include <deque>
#include <utility>
#include <algorithm>
#include <boost\tuple\tuple.hpp>
template < class ViewT >
class ZoomManager
{
private:
class ZoomRect : private boost::tuple< double, double, double, double >
{
typedef enum
{
eXMin = 0,
eXMax = 1,
eYMin = 2,
eYMax = 3
} Offsets;
public:
ZoomRect( double xMin = 0.0, double xMax = 100.0, double yMin = 0.0, double yMax = 100.0 )
{
SetRect( xMin, xMax, yMin, yMax );
}
void GetRect( double & xMin, double & xMax, double & yMin, double & yMax ) const
{
xMin = get< eXMin >();
xMax = get< eXMax >();
yMin = get< eYMin >();
yMax = get< eYMax >();
}
void GetRect( double & xMin, double & xMax ) const
{
xMin = get< eXMin >();
xMax = get< eXMax >();
}
void SetRect( double xMin, double xMax, double yMin, double yMax )
{
get< eXMin >() = xMin;
get< eXMax >() = xMax;
get< eYMin >() = yMin;
get< eYMax >() = yMax;
}
double GetXMin() const { return get< eXMin >(); }
double GetXMax() const { return get< eXMax >(); }
double GetYMin() const { return get< eYMin >(); }
double GetYMax() const { return get< eYMax >(); }
};
public:
typedef enum
{
ePanFull = 0,
ePanLine = 1,
ePanPage = 2,
} PanMode;
public:
ZoomManager( ViewT * pView = 0 )
: mZoomDepth( -1 )
{
AddLink( pView );
}
virtual ~ZoomManager() {}
// Attributes
public:
int GetZoomDepth() const { return mZoomDepth; }
void SetZoomDepth( int depth )
{
mZoomDepth = depth;
if ( mZoomDepth > 0 )
{
// Pop the zoom stack until new depth is reached
while ( mStack.size() > size_t( mZoomDepth ) )
mStack.pop_back();
}
}
void GetZoomXY( double & xMin, double & xMax, double & yMin, double & yMax ) const
{
GetZoomRect().GetRect( xMin, xMax, yMin, yMax );
}
void GetZoomX( double & xMin, double & xMax ) const
{
GetZoomRect().GetRect( xMin, xMax );
}
void GetZoomY( double & yMin, double & yMax ) const
{
double dummy;
GetZoomRect().GetRect( dummy, dummy, yMin, yMax );
}
// Get / Set the default rectangle for fully zoomed-out state
void GetDefaultZoom( double & xMin, double & xMax, double & yMin, double & yMax ) const
{
xMin = mDefaultRect.GetXMin();
xMax = mDefaultRect.GetXMax();
yMin = mDefaultRect.GetYMin();
yMax = mDefaultRect.GetYMax();
}
void SetDefaultZoom( double xMin, double xMax, double yMin = 0.0, double yMax = 100.0 )
{
mDefaultRect.SetRect( xMin, xMax, yMin, yMax );
}
// Operations
public:
// Adds a link to the plot; returns true if successful, false if already linked
bool AddLink( ViewT * pView )
{
bool bResult = false;
if ( pView )
{
Links::iterator it = std::find( mLinks.begin(), mLinks.end(), pView );
if ( it == mLinks.end() )
{
mLinks.push_back( pView );
bResult = true;
}
}
return bResult;
}
// Removes a link to the plot; returns true if found, false if not
bool RemoveLink( ViewT * pView )
{
bool bResult = false;
Links::iterator it = std::find( mLinks.begin(), mLinks.end(), pView );
if ( it != mLinks.end() )
{
mLinks.erase( it );
bResult = true;
}
return bResult;
}
// Zooms X while autoscaling Y
void ZoomX( double xMin, double xMax )
{
PushZoom( ZoomRect( xMin, xMax ) );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax );
}
}
// Zooms Y leaving X unchanged
void ZoomY( double yMin, double yMax )
{
double xMin;
double xMax;
GetZoomX( xMin, xMax );
PushZoom( ZoomRect( xMin, xMax, yMin, yMax ) );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Zooms both x and y axes
void ZoomXY( double xMin, double xMax, double yMin, double yMax )
{
PushZoom( ZoomRect( xMin, xMax, yMin, yMax ) );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Zooms out to previous X zoom
void ZoomOutX()
{
double xMin;
double xMax;
PopZoom().GetRect( xMin, xMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax );
}
}
// Zooms out to previous Y zoom
void ZoomOutY()
{
// Same as ZoomOutXY for now
double xMin;
double xMax;
double yMin;
double yMax;
PopZoom().GetRect( xMin, xMax, yMin, yMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Zooms out to previous X-Y zoom
void ZoomOutXY()
{
double xMin;
double xMax;
double yMin;
double yMax;
PopZoom().GetRect( xMin, xMax, yMin, yMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Resets the zoom rectangle to defaults (zoom x, autoscale y)
void ZoomResetX()
{
mStack.clear();
double xMin;
double xMax;
mDefaultRect.GetRect( xMin, xMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax );
}
}
// Resets the X-Y zoom rectangle to the default
void ZoomResetXY()
{
mStack.clear();
double xMin;
double xMax;
double yMin;
double yMax;
mDefaultRect.GetRect( xMin, xMax, yMin, yMax );
Links::iterator it = mLinks.begin();
Links::iterator eIt = mLinks.end();
while ( it != eIt )
{
ViewT * pView = *it++;
if ( pView )
pView->ZoomTo( xMin, xMax, yMin, yMax );
}
}
// Pans completely to the left or by a line or page, while
// keeping the zoom level the same
void PanLeft( PanMode mode )
{
ZoomRect rect = GetZoomRect();
double xMin = rect.GetXMin();
double xMax = rect.GetXMax();
double width = xMax - xMin;
switch( mode )
{
case ePanFull:
{
xMin = mDefaultRect.GetXMin();
xMax = xMin + width;
break;
}
case ePanPage:
{
if ( xMin - width >= mDefaultRect.GetXMin() )
{
xMin -= width;
xMax -= width;
}
else
{
xMin = mDefaultRect.GetXMin();
xMax = xMin + width;
}
break;
}
case ePanLine:
{
width /= 8;
if ( xMin - width >= mDefaultRect.GetXMin() )
{
xMin -= width;
xMax -= width;
}
else
{
xMin = mDefaultRect.GetXMin();
xMax = xMin + width * 8;
}
break;
}
}
PopZoom();
ZoomX( xMin, xMax );
}
// Pans completely to the right or by a line or page, while
// keeping the zoom level the same
void PanRight( PanMode mode )
{
ZoomRect rect = GetZoomRect();
double xMin = rect.GetXMin();
double xMax = rect.GetXMax();
double width = xMax - xMin;
switch( mode )
{
case ePanFull:
{
xMax = mDefaultRect.GetXMax();
xMin = xMax - width;
break;
}
case ePanPage:
{
if ( xMax + width <= mDefaultRect.GetXMax() )
{
xMin += width;
xMax += width;
}
else
{
xMax = mDefaultRect.GetXMax();
xMin = xMax - width;
}
break;
}
case ePanLine:
{
width /= 8;
if ( xMax + width <= mDefaultRect.GetXMax() )
{
xMin += width;
xMax += width;
}
else
{
xMax = mDefaultRect.GetXMax();
xMin = xMax - width * 8;
}
break;
}
}
PopZoom();
ZoomX( xMin, xMax );
}
void PanTo( double xPct, double yPct = 0.0 )
{
// TODO: add support for y panning
if ( xPct <= -1.0 )
PanLeft( ePanFull );
else if ( xPct >= 1.0 )
PanRight( ePanFull );
else
{
ZoomRect rect = GetZoomRect();
double xMin = rect.GetXMin();
double xMax = rect.GetXMax();
double width = xMax - xMin;
double xMinDef = mDefaultRect.GetXMin();
double xMaxDef = mDefaultRect.GetXMax();
xMin = xMinDef + xPct * 0.875 * (xMaxDef - xMinDef);
xMax = xMin + width;
if ( xMax > xMaxDef )
{
xMax = xMaxDef;
xMin = xMax - width;
}
PopZoom();
ZoomX( xMin, xMax );
}
}
protected:
// Pushes the ZoomRect onto the zoom stack while managing stack depth
void PushZoom( const ZoomRect & zoomRect )
{
// If zoom depth is zero, there's no stack so nothing to save
if ( mZoomDepth == 0 )
return;
// Save it
mStack.push_front( zoomRect );
// Remove the bottom-most entry if the stack is too large
if ( mZoomDepth > 0 && mStack.size() > size_t( mZoomDepth ) )
mStack.pop_back();
}
// Pops the ZoomRect from the zoom stack
const ZoomRect & PopZoom()
{
// Remove the current level
if ( !mStack.empty() )
mStack.pop_front();
return GetZoomRect();
}
// Retrieves a reference to the current zoom rectangle
const ZoomRect & GetZoomRect() const
{
if ( mStack.empty() )
return mDefaultRect;
else
return mStack.front();
}
protected:
typedef std::list< ViewT * > Links;
Links mLinks;
typedef std::deque< ZoomRect > Stack;
Stack mStack;
int mZoomDepth;
ZoomRect mDefaultRect;
};
#endif // ZoomManager_H
To copy to clipboard, switch view to plain text mode
Bookmarks