Lumiera  0.pre.03
»edit your freedom«
ZoomWindow Class Reference

#include "stage/model/zoom-window.hpp"

Description

A component to ensure uniform handling of zoom scale and visible interval on the timeline.

Changes through the mutator functions are validated and harmonised to meet the internal invariants; a change listener is possibly notified to pick up the new settings.

A ZoomWindow...

  • is a #visible TimeSpan
  • which is completely inside an #overalSpan
  • and is rendered at a scale factor #px_per_sec
  • 0 < px_per_sec <= ZOOM_MAX_RESOLUTION
  • zoom operations are applied around an anchorPoint

Definition at line 222 of file zoom-window.hpp.

Public Member Functions

 ZoomWindow (uint pxWidth, TimeSpan timeline=TimeSpan{Time::ZERO, DEFAULT_CANVAS})
 
 ZoomWindow (TimeSpan timeline=TimeSpan{Time::ZERO, DEFAULT_CANVAS})
 
template<class FUN >
void attachChangeNotification (FUN &&trigger)
 Attach a λ or functor to be triggered on each actual change. More...
 
void calibrateExtension (uint pxWidth)
 Define the extension of the window in pixels. More...
 
void detachChangeNotification ()
 
void expandVisibleRange (TimeSpan target)
 the »reverse zoom operation«: zoom out such as to bring the current window at the designated time span. More...
 
void navHistory ()
 
void nudgeMetric (int steps)
 scale up or down on a 2-logarithmic scale. More...
 
void nudgeVisiblePos (int64_t steps)
 scroll by increments of half window size, possibly expanding. More...
 
void offsetVisiblePos (Offset offset)
 scroll by arbitrary offset, possibly expanding canvas. More...
 
TimeSpan overallSpan () const
 
Rat px_per_sec () const
 
uint pxWidth () const
 
void setMetric (Rat px_per_sec)
 explicitly set the zoom factor, defined as pixel per second More...
 
void setOverallDuration (Duration duration)
 
void setOverallRange (TimeSpan range)
 redefine the overall canvas range. More...
 
void setOverallStart (TimeValue start)
 
void setRanges (TimeSpan overall, TimeSpan visible)
 Set both the overall canvas, as well as the visible part within that canvas. More...
 
void setVisibleDuration (Duration duration)
 explicitly set the duration of the visible window range, working around the relative anchor point; possibly expand canvas. More...
 
void setVisiblePos (Time posToShow)
 scroll the window to bring the denoted position in sight, retaining the current zoom factor, possibly expanding canvas.
 
void setVisiblePos (Rat percentage)
 scroll to reveal position designated relative to overall canvas
 
void setVisiblePos (double percentage)
 
void setVisibleRange (TimeSpan newWindow)
 explicitly set the visible window, possibly expanding the canvas to fit. More...
 
void setVisibleStart (TimeValue start)
 
TimeSpan visible () const
 

Private Member Functions

void adaptWindowToPixels (uint pxWidth)
 
FSecs anchorPoint () const
 The anchor point or centre for zooming operations applied to the visible window. More...
 
void anchorWindowAtPosition (FSecs canvasOffset)
 
Rat conformMetricToWindow (uint pxWidth)
 
void conformToBounds (Rat changedMetric)
 
void conformWindowToCanvas ()
 
void conformWindowToMetric (Rat changedMetric)
 this is the centrepiece of the whole zoom metric logic... More...
 
void conformWindowToMetricLimits (uint pxWidth)
 The zoom metric factor must not become "poisonous". More...
 
void ensureInvariants (uint px=0)
 Procedure to (re)establish the invariants. More...
 
void establishWindowDuration (Duration duration)
 
void fireChangeNotification ()
 
void mutateCanvas (TimeSpan canvas)
 
void mutateDuration (FSecs duration, uint px=0)
 
void mutateRanges (TimeSpan canvas, TimeSpan window)
 
void mutateScale (Rat changedMetric)
 
void mutateWindow (TimeSpan window)
 
Rat optimiseMetric (uint pxWidth, FSecs dur, Rat rawMetric)
 Reform the effective metric in all dangerous corner cases. More...
 
void placeWindowRelativeToAnchor (FSecs duration)
 
Rat relativeAnchor () const
 define at which proportion to the visible window's duration the anchor should be placed More...
 
- Private Member Functions inherited from NonCopyable
 NonCopyable (NonCopyable const &)=delete
 
NonCopyableoperator= (NonCopyable const &)=delete
 

Static Private Member Functions

static FSecs addSafe (FSecs t1, FSecs t2)
 Calculate sum (or difference) of possibly large time durations, avoiding integer wrap-around. More...
 
static int64_t calcPixelsForDurationAtScale (Rat zoomFactor, FSecs duration)
 calculate rational_cast<uint> (zoomFactor * duration) More...
 
static Rat detox (Rat poison)
 Check and possibly sanitise a rational number to avoid internal numeric overflow. More...
 
static void ENSURE_matchesExpectedPixWidth (Rat zoomFactor, FSecs duration, uint pxWidth)
 Assertion helper: resulting pxWidth matches expectations.
 
static TimeSpan ensureNonEmpty (TimeSpan const &span)
 
static Rat establishMetric (uint pxWidth, Time startWin, Time afterWin)
 
static FSecs maxSaneWinExtension (uint pxWidth)
 window size beyond that limit would lead to numerically dangerous zoom factors (pixel/duration)
 
static Rat parabolicAnchorRule (Rat posFactor)
 A counter movement rule to place an anchor point, based on a percentage factor. More...
 
static FSecs scaleSafe (FSecs duration, Rat factor)
 Scale a possibly large time duration by a rational factor, while attempting to avoid integer wrap-around. More...
 

Private Attributes

TimeVar afterAll_
 
TimeVar afterWin_
 
std::function< void()> changeSignal_ {}
 
Rat px_per_sec_
 
TimeVar startAll_
 
TimeVar startWin_
 

Member Function Documentation

◆ calibrateExtension()

void calibrateExtension ( uint  pxWidth)
inline

Define the extension of the window in pixels.

The existing logical scale factor is retained, meaning that the logical duration of the actually visible window is adjusted alongside to match the new given pixel size, if necessary, also the canvas is expanded to fit.

Note
all other manipulations will always retain this value

Definition at line 287 of file zoom-window.hpp.

References ZoomWindow::adaptWindowToPixels().

+ Here is the call graph for this function:

◆ setMetric()

void setMetric ( Rat  px_per_sec)
inline

explicitly set the zoom factor, defined as pixel per second

Note
the given factor will be capped to remain below a maximal zoom of 2px per µ-tick; also the window may not be expanded beyond the current overall canvas size

Definition at line 300 of file zoom-window.hpp.

Referenced by ZoomWindow::nudgeMetric().

+ Here is the caller graph for this function:

◆ nudgeMetric()

void nudgeMetric ( int  steps)
inline

scale up or down on a 2-logarithmic scale.

Each step either doubles or halves the zoom level, and the visible window is adjusted accordingly, using the current anchorPoint as centre for scaling.

Note
the zoom factor is limited to be between 2px per µ-tick and showing the full canvas

Definition at line 315 of file zoom-window.hpp.

References ZoomWindow::setMetric().

+ Here is the call graph for this function:

◆ setRanges()

void setRanges ( TimeSpan  overall,
TimeSpan  visible 
)
inline

Set both the overall canvas, as well as the visible part within that canvas.

Given values will possibly be adjusted to retain overall consistency, according to the following rules:

  • all ranges are non empty and properly oriented
  • the extension in pixels will always be retained
  • zoom factor is only allowed to range between showing the full canvas and a maximum factor (2 pixel per µ-tick)
  • the visible window will always be within the canvas area

Definition at line 335 of file zoom-window.hpp.

References ZoomWindow::mutateRanges().

+ Here is the call graph for this function:

◆ setOverallRange()

void setOverallRange ( TimeSpan  range)
inline

redefine the overall canvas range.

Note
the currently visible window may be shifted or capped to fit within the new range, which may also change the zoom factor, while the overall pixel width is always retained unaltered

Definition at line 349 of file zoom-window.hpp.

References ZoomWindow::mutateCanvas(), and ZoomWindow::mutateWindow().

+ Here is the call graph for this function:

◆ setVisibleRange()

void setVisibleRange ( TimeSpan  newWindow)
inline

explicitly set the visible window, possibly expanding the canvas to fit.

Typically used to zoom into a user selected range.

Definition at line 382 of file zoom-window.hpp.

References ZoomWindow::mutateWindow().

+ Here is the call graph for this function:

◆ expandVisibleRange()

void expandVisibleRange ( TimeSpan  target)
inline

the »reverse zoom operation«: zoom out such as to bring the current window at the designated time span.

Typically the user selects a sub-range, and the current view is then collapsed accordingly to fit into that range. As a side effect, the canvas may be expanded significantly.

Definition at line 396 of file zoom-window.hpp.

References stage::model::anonymous_namespace{zoom-window.hpp}::_FSecs().

+ Here is the call graph for this function:

◆ setVisibleDuration()

void setVisibleDuration ( Duration  duration)
inline

explicitly set the duration of the visible window range, working around the relative anchor point; possibly expand canvas.

Remarks
the anchor point is based on the relative position of the window within canvas — however, other than for scaling, the canvas will possibly be expanded and the given duration will thus always be realised.

Definition at line 420 of file zoom-window.hpp.

References stage::model::anonymous_namespace{zoom-window.hpp}::_FSecs(), and ZoomWindow::mutateDuration().

Referenced by ZoomWindow_test::safeguard_reversed_intervals().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ offsetVisiblePos()

void offsetVisiblePos ( Offset  offset)
inline

scroll by arbitrary offset, possibly expanding canvas.

Definition at line 428 of file zoom-window.hpp.

References ZoomWindow::mutateWindow().

+ Here is the call graph for this function:

◆ nudgeVisiblePos()

void nudgeVisiblePos ( int64_t  steps)
inline

scroll by increments of half window size, possibly expanding.

Definition at line 436 of file zoom-window.hpp.

◆ attachChangeNotification()

void attachChangeNotification ( FUN &&  trigger)
inline

Attach a λ or functor to be triggered on each actual change.

Definition at line 485 of file zoom-window.hpp.

◆ detox()

static Rat detox ( Rat  poison)
inlinestaticprivate

Check and possibly sanitise a rational number to avoid internal numeric overflow.

Fractional arithmetics can be insidious, due to the frequent re-normalisation; seemingly "harmless" numbers with a large denominator can cause numeric wrap-around. As safeguard, by introducing a tiny error, problematic numbers can be re-quantised to smaller denominators; moreover, large numbers must be limit checked.

Remarks
Both the denominator and the numerator must be kept below a toxic limit, which is defined by the ability to multiply with Time::Scale without wrap-around. This heuristic is based on the actual computations done with the zoom factor and is thus specific to the ZoomWindow implementation. To sanitise, the denominator is reduced logarithmically (bit-shift) sufficiently and then used as new quantiser, thus ensuring that both denominator (=quantiser) and numerator are below limit.
Warning
the rational number must not be too large overall; this heuristic will fail on fractions with very large numerator and small denominator — however, for the ZoomWindow, this case is not relevant, since the zoom factor is limited, and other usages of rational numbers can be range checked explicitly.
Note
the check is based on the 2-logarithm of numerator and denominator, which is pretty much the fastest possibility (even a simple comparison would have to do the same). Values below threshold are simply passed-through.
Todo:
this utility function could be factored out into a FSecs or RSec class //////////////////TICKET #1262

Definition at line 529 of file zoom-window.hpp.

◆ scaleSafe()

static FSecs scaleSafe ( FSecs  duration,
Rat  factor 
)
inlinestaticprivate

Scale a possibly large time duration by a rational factor, while attempting to avoid integer wrap-around.

In the typical use-case, the multiplication can be just computed precisely and safe, but at least we check the limits. In the danger and boundary zone, a slight error is introduced to allow cancelling out a common factor, so that the result can be just constructed without any further dangerous computation. Obviously this is only a heuristic, yet adequate within the framework of ZoomWindow, where the end result is pixel aligned anyway.

Todo:
this utility function could be factored out into a FSecs or RSec class //////////////////TICKET #1262

Descriptor for a Strategy to reduce the numbers to keep them in domain. After cross-wise cancelling out one part in each factor, the result can be constructed without any further multiplication. To achieve that, a slight error is introduced into one of the four participating numbers

< factor one is safe and will not be changed

< the counterpart of f1 is used as quantiser and cancelled out

< the diagonal counterpart of u is scaled to u and cancelled

< the counterpart of #q is re-quantised to u; it acts as limit

< Strategy will be applied to the inverse 1/x

Definition at line 547 of file zoom-window.hpp.

Referenced by ZoomWindow::anchorPoint(), and ZoomWindow::placeWindowRelativeToAnchor().

+ Here is the caller graph for this function:

◆ addSafe()

static FSecs addSafe ( FSecs  t1,
FSecs  t2 
)
inlinestaticprivate

Calculate sum (or difference) of possibly large time durations, avoiding integer wrap-around.

Again, this is a heuristics, based on re-quantisation to a smaller common denominator.

Returns
exact result if representable, otherwise approximation
Note
result is capped to MAX_TIMESPAN when exceeding domain
Todo:
this utility function could be factored out into a FSecs or RSec class //////////////////TICKET #1262

Definition at line 645 of file zoom-window.hpp.

◆ calcPixelsForDurationAtScale()

static int64_t calcPixelsForDurationAtScale ( Rat  zoomFactor,
FSecs  duration 
)
inlinestaticprivate

calculate rational_cast<uint> (zoomFactor * duration)

Remarks
indirect calculation to avoid overflow on large durations

Definition at line 721 of file zoom-window.hpp.

◆ optimiseMetric()

Rat optimiseMetric ( uint  pxWidth,
FSecs  dur,
Rat  rawMetric 
)
inlineprivate

Reform the effective metric in all dangerous corner cases.

Ensure the metric value is not »poisonous« and can be multiplied even with Time::SCALE without numeric wrap-around.

Note
this function introduces a slight error to simplify the numbers; then the result is optimised to conform to pxWith and duration

Definition at line 752 of file zoom-window.hpp.

◆ conformWindowToMetric()

void conformWindowToMetric ( Rat  changedMetric)
inlineprivate

this is the centrepiece of the whole zoom metric logic...

Note
control flow for every scale adjustment passes here

Definition at line 813 of file zoom-window.hpp.

◆ conformWindowToMetricLimits()

void conformWindowToMetricLimits ( uint  pxWidth)
inlineprivate

The zoom metric factor must not become "poisonous".

This leads to a minimum possible zoom factor for a given pixWidth, thereby effectively limiting the maximum window extension. This constraint is enforced by reducing the current window size.

Definition at line 856 of file zoom-window.hpp.

References ZoomWindow::maxSaneWinExtension(), and ZoomWindow::placeWindowRelativeToAnchor().

Referenced by ZoomWindow::mutateRanges(), and ZoomWindow::mutateWindow().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ensureInvariants()

void ensureInvariants ( uint  px = 0)
inlineprivate

Procedure to (re)establish the invariants.

Adjustments should be done first to windows, then to the metric, using conformWindowToMetric(). Then this function shall be called and will first shift and possibly cap the window, then reestablish the metric and possibly increase the canvas to keep ensure the ZOOM_MAX_RESOLUTION is not exceeded. These steps ensure overall pixel size remains stable.

Definition at line 931 of file zoom-window.hpp.

Referenced by ZoomWindow::mutateCanvas(), and ZoomWindow::mutateRanges().

+ Here is the caller graph for this function:

◆ mutateCanvas()

void mutateCanvas ( TimeSpan  canvas)
inlineprivate

set a different overall canvas range, possibly set window and metrics to fit

Definition at line 946 of file zoom-window.hpp.

References ZoomWindow::ensureInvariants().

Referenced by ZoomWindow::setOverallRange().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutateWindow()

void mutateWindow ( TimeSpan  window)
inlineprivate

change Window TimeSpan, possibly also outside of the current canvas, which is then expanded; validate and adjust all params accordingly

Definition at line 957 of file zoom-window.hpp.

References ZoomWindow::conformWindowToMetricLimits().

Referenced by ZoomWindow::offsetVisiblePos(), ZoomWindow::setOverallRange(), and ZoomWindow::setVisibleRange().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutateRanges()

void mutateRanges ( TimeSpan  canvas,
TimeSpan  window 
)
inlineprivate

change canvas and window position in one call, then validate and adjust to maintain invariants

Definition at line 971 of file zoom-window.hpp.

References ZoomWindow::conformWindowToMetricLimits(), and ZoomWindow::ensureInvariants().

Referenced by ZoomWindow::setRanges().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutateScale()

void mutateScale ( Rat  changedMetric)
inlineprivate

adjust Window to match given scale, validate and adjust all params

Definition at line 986 of file zoom-window.hpp.

◆ mutateDuration()

void mutateDuration ( FSecs  duration,
uint  px = 0 
)
inlineprivate

change visible duration centred around anchor point, validate and adjust all params

Definition at line 999 of file zoom-window.hpp.

Referenced by ZoomWindow::setVisibleDuration().

+ Here is the caller graph for this function:

◆ adaptWindowToPixels()

void adaptWindowToPixels ( uint  pxWidth)
inlineprivate

resize window to span the given pixel with, validate and adjust all other params

Definition at line 1016 of file zoom-window.hpp.

Referenced by ZoomWindow::calibrateExtension().

+ Here is the caller graph for this function:

◆ anchorWindowAtPosition()

void anchorWindowAtPosition ( FSecs  canvasOffset)
inlineprivate

relocate window anchored at a position relative to canvas, also placing the anchor position relative within the window in accordance with the position relative to canvas. Window will enclose the given position, possibly extending canvas to fit, afterwards reestablishing all invariants.

Definition at line 1032 of file zoom-window.hpp.

Referenced by ZoomWindow::setVisiblePos().

+ Here is the caller graph for this function:

◆ placeWindowRelativeToAnchor()

void placeWindowRelativeToAnchor ( FSecs  duration)
inlineprivate

similar operation as anchorWindowAtPosition(), but based on the current window position and without relocation, rather intended for changing the scale

Definition at line 1053 of file zoom-window.hpp.

References ZoomWindow::anchorPoint(), Time::MAX, ZoomWindow::relativeAnchor(), and ZoomWindow::scaleSafe().

Referenced by ZoomWindow::conformWindowToMetricLimits().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ anchorPoint()

FSecs anchorPoint ( ) const
inlineprivate

The anchor point or centre for zooming operations applied to the visible window.

Returns
where the visible window should currently be anchored
Remarks
this point can sometimes be outside the current visible window, but any further zooming/scaling/scrolling operation should bring it back into sight. Moreover, the function relativeAnchor() defines the position where this anchor point should be placed relative to the visible window.
Todo:
10/2022 we use a numerical rule currently, but that could be contextual state, like e.g. the current position of the play head or edit cursor or mouse.

Definition at line 1084 of file zoom-window.hpp.

References ZoomWindow::relativeAnchor(), and ZoomWindow::scaleSafe().

Referenced by ZoomWindow::placeWindowRelativeToAnchor().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ relativeAnchor()

Rat relativeAnchor ( ) const
inlineprivate

define at which proportion to the visible window's duration the anchor should be placed

Returns
a fraction 0 ... 1, where 0 means at start and 1 means after end.
Note
as of 10/2022 we use a numerical rule to place the anchor point in accordance to the current visible window's position within the overall timeline; if it's close to the beginning, the anchor point is also rather to the beginning...

Definition at line 1097 of file zoom-window.hpp.

Referenced by ZoomWindow::anchorPoint(), and ZoomWindow::placeWindowRelativeToAnchor().

+ Here is the caller graph for this function:

◆ parabolicAnchorRule()

static Rat parabolicAnchorRule ( Rat  posFactor)
inlinestaticprivate

A counter movement rule to place an anchor point, based on a percentage factor.

Used to define the anchor point within the window, depending on the window's position relative to the overall canvas. Implemented using a cubic parabola, which moves quick away from the boundaries, while hovering most of the time in the middle area.

Returns
factor effectively between 0 ... 1 (inclusive)
Warning
in case of a "poisonous" input the calculation may go astray; yet results are limited at least...

Definition at line 1119 of file zoom-window.hpp.

+ Inheritance diagram for ZoomWindow:
+ Collaboration diagram for ZoomWindow:

The documentation for this class was generated from the following file: