@@ -73,6 +73,36 @@ public static IProjection<int, TimeRange> Create(IProjection<int, TimeRange> tim
7373 return ( IProjection < int , TimeRange > ) instance ;
7474 }
7575
76+ /// <summary>
77+ /// Create a <see cref="ResourceTimeRange"/> projection that is clipped to a
78+ /// <see cref="VisibleDomainRegionContainer"/>.
79+ /// See also <seealso cref="IVisibleDomainSensitiveProjection"/>.
80+ /// </summary>
81+ /// <param name="resourceTimeRangeProjection">
82+ /// Original projection.
83+ /// </param>
84+ /// <returns>
85+ /// A visible domain sensitive projection.
86+ /// </returns>
87+ public static IProjection < int , ResourceTimeRange > Create ( IProjection < int , ResourceTimeRange > resourceTimeRangeProjection )
88+ {
89+ Guard . NotNull ( resourceTimeRangeProjection , nameof ( resourceTimeRangeProjection ) ) ;
90+
91+ var typeArgs = new [ ]
92+ {
93+ resourceTimeRangeProjection . GetType ( ) ,
94+ } ;
95+
96+ var constructorArgs = new object [ ]
97+ {
98+ resourceTimeRangeProjection ,
99+ } ;
100+
101+ var type = typeof ( ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator < > ) . MakeGenericType ( typeArgs ) ;
102+ var instance = Activator . CreateInstance ( type , constructorArgs ) ;
103+ return ( IProjection < int , ResourceTimeRange > ) instance ;
104+ }
105+
76106 /// <summary>
77107 /// Creates a new percent projection that is defined by the current viewport.
78108 /// </summary>
@@ -101,6 +131,34 @@ public static IProjection<int, TimeRange> CreatePercent(IProjection<int, TimeRan
101131 return ( IProjection < int , TimeRange > ) instance ;
102132 }
103133
134+ /// <summary>
135+ /// Creates a new percent projection that is defined by the current viewport.
136+ /// </summary>
137+ /// <param name="resourceTimeRangeColumn">
138+ /// Original projection.
139+ /// </param>
140+ /// <returns>
141+ /// A viewport sensitive projection.
142+ /// </returns>
143+ public static IProjection < int , ResourceTimeRange > CreatePercent ( IProjection < int , ResourceTimeRange > resourceTimeRangeColumn )
144+ {
145+ Guard . NotNull ( resourceTimeRangeColumn , nameof ( resourceTimeRangeColumn ) ) ;
146+
147+ var typeArgs = new [ ]
148+ {
149+ resourceTimeRangeColumn . GetType ( ) ,
150+ } ;
151+
152+ var constructorArgs = new object [ ]
153+ {
154+ resourceTimeRangeColumn ,
155+ } ;
156+
157+ var type = typeof ( ClipTimeToVisibleResourceTimeRangePercentColumnGenerator < > ) . MakeGenericType ( typeArgs ) ;
158+ var instance = Activator . CreateInstance ( type , constructorArgs ) ;
159+ return ( IProjection < int , ResourceTimeRange > ) instance ;
160+ }
161+
104162 [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Microsoft.Performance" , "CA1811:AvoidUncalledPrivateCode" ) ]
105163 private struct ClipTimeToVisibleTimestampDomainColumnGenerator < TGenerator >
106164 : IProjection < int , Timestamp > ,
@@ -228,6 +286,72 @@ public bool NotifyVisibleDomainChanged(IVisibleDomainRegion visibleDomain)
228286 public bool DependsOnVisibleDomain => true ;
229287 }
230288
289+ [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Microsoft.Performance" , "CA1811:AvoidUncalledPrivateCode" ) ]
290+ private struct ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator < TGenerator >
291+ : IProjection < int , ResourceTimeRange > ,
292+ IVisibleDomainSensitiveProjection
293+ where TGenerator : IProjection < int , ResourceTimeRange >
294+ {
295+ internal TGenerator Generator { get ; }
296+
297+ internal VisibleDomainRegionContainer VisibleDomainContainer { get ; }
298+
299+ public ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator ( TGenerator resourceTimeRangeGenerator )
300+ {
301+ this . Generator = resourceTimeRangeGenerator ;
302+ this . VisibleDomainContainer = new VisibleDomainRegionContainer ( ) ;
303+ }
304+
305+ // IProjection<int, Timestamp>
306+ public ResourceTimeRange this [ int value ]
307+ {
308+ get
309+ {
310+ TimeRange visibleDomain = this . VisibleDomainContainer . VisibleDomain ;
311+
312+ ResourceTimeRange resourceTimeRange = this . Generator [ value ] ;
313+
314+ resourceTimeRange . StartTime = ClipTimestampToVisibleDomain ( resourceTimeRange . StartTime , visibleDomain ) ;
315+ resourceTimeRange . EndTime = ClipTimestampToVisibleDomain ( resourceTimeRange . EndTime , visibleDomain ) ;
316+
317+ return resourceTimeRange ;
318+ }
319+ }
320+
321+ public Type SourceType
322+ {
323+ get
324+ {
325+ return typeof ( int ) ;
326+ }
327+ }
328+
329+ public Type ResultType
330+ {
331+ get
332+ {
333+ return typeof ( ResourceTimeRange ) ;
334+ }
335+ }
336+
337+ public object Clone ( )
338+ {
339+ var result = new ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator < TGenerator > (
340+ VisibleDomainSensitiveProjection . CloneIfVisibleDomainSensitive ( this . Generator ) ) ;
341+ return result ;
342+ }
343+
344+
345+ public bool NotifyVisibleDomainChanged ( IVisibleDomainRegion visibleDomain )
346+ {
347+ this . VisibleDomainContainer . VisibleDomainRegion = visibleDomain ;
348+ VisibleDomainSensitiveProjection . NotifyVisibleDomainChanged ( this . Generator , visibleDomain ) ;
349+ return true ;
350+ }
351+
352+ public bool DependsOnVisibleDomain => true ;
353+ }
354+
231355 private struct ClipTimeToVisibleTimeRangePercentColumnGenerator < TGenerator >
232356 : IProjection < int , TimeRange > ,
233357 IVisibleDomainSensitiveProjection ,
@@ -319,6 +443,98 @@ public string Format(string format, object arg, IFormatProvider formatProvider)
319443 }
320444 }
321445 }
446+
447+ private struct ClipTimeToVisibleResourceTimeRangePercentColumnGenerator < TGenerator >
448+ : IProjection < int , ResourceTimeRange > ,
449+ IVisibleDomainSensitiveProjection ,
450+ IFormatProvider
451+ where TGenerator : IProjection < int , ResourceTimeRange >
452+ {
453+ private readonly ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator < TGenerator > resourceTimeRangeColumnGenerator ;
454+
455+ // IFormatProvider returns an object - cannot return 'this' struct.
456+ // So implement ICustomFormatter in a private class and return that object.
457+ //
458+ private readonly ClipTimeToVisibleResourceTimeRangePercentFormatProvider customFormatter ;
459+
460+ public ClipTimeToVisibleResourceTimeRangePercentColumnGenerator ( TGenerator timeRangeGenerator )
461+ {
462+ var internalGenerator = new ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator < TGenerator > ( timeRangeGenerator ) ;
463+ this . resourceTimeRangeColumnGenerator = internalGenerator ;
464+
465+ this . customFormatter =
466+ new ClipTimeToVisibleResourceTimeRangePercentFormatProvider ( ( ) => internalGenerator . VisibleDomainContainer . VisibleDomain . Duration ) ;
467+ }
468+
469+ public ResourceTimeRange this [ int value ] => this . resourceTimeRangeColumnGenerator [ value ] ;
470+
471+ public Type SourceType => typeof ( int ) ;
472+
473+ public Type ResultType => typeof ( ResourceTimeRange ) ;
474+
475+ public bool DependsOnVisibleDomain => true ;
476+
477+ public object GetFormat ( Type formatType )
478+ {
479+ return ( formatType == typeof ( ResourceTimeRange ) ||
480+ formatType == typeof ( TimestampDelta ) ) ? this . customFormatter : null ;
481+ }
482+
483+ public object Clone ( )
484+ {
485+ var result = new ClipTimeToVisibleResourceTimeRangePercentColumnGenerator < TGenerator > (
486+ VisibleDomainSensitiveProjection . CloneIfVisibleDomainSensitive ( this . resourceTimeRangeColumnGenerator . Generator ) ) ;
487+ return result ;
488+ }
489+
490+ public bool NotifyVisibleDomainChanged ( IVisibleDomainRegion visibleDomain )
491+ {
492+ this . resourceTimeRangeColumnGenerator . NotifyVisibleDomainChanged ( visibleDomain ) ;
493+ return true ;
494+ }
495+
496+ private class ClipTimeToVisibleResourceTimeRangePercentFormatProvider
497+ : ICustomFormatter
498+ {
499+ private readonly Func < TimestampDelta > getVisibleDomainDuration ;
500+
501+ public ClipTimeToVisibleResourceTimeRangePercentFormatProvider ( Func < TimestampDelta > getVisibleDomainDuration )
502+ {
503+ Guard . NotNull ( getVisibleDomainDuration , nameof ( getVisibleDomainDuration ) ) ;
504+
505+ this . getVisibleDomainDuration = getVisibleDomainDuration ;
506+ }
507+
508+ public string Format ( string format , object arg , IFormatProvider formatProvider )
509+ {
510+ if ( arg == null )
511+ {
512+ return string . Empty ;
513+ }
514+
515+ TimestampDelta numerator ;
516+ if ( arg is ResourceTimeRange )
517+ {
518+ numerator = ( ( ResourceTimeRange ) arg ) . Duration ;
519+ }
520+ else if ( arg is TimestampDelta )
521+ {
522+ numerator = ( TimestampDelta ) arg ;
523+ }
524+ else
525+ {
526+ throw new FormatException ( ) ;
527+ }
528+
529+ TimestampDelta visibleDomainDuration = getVisibleDomainDuration ( ) ;
530+ double percent = ( visibleDomainDuration != TimestampDelta . Zero ) ?
531+ ( 100.0 * ( ( double ) numerator . ToNanoseconds ) / ( visibleDomainDuration . ToNanoseconds ) ) :
532+ 100.0 ;
533+
534+ return percent . ToString ( format , formatProvider ) ;
535+ }
536+ }
537+ }
322538 }
323539 }
324540}
0 commit comments