Skip to content

Commit

Permalink
Implementation of TimedEventCoveringTypeComplex based on https://gi…
Browse files Browse the repository at this point in the history
  • Loading branch information
gklka committed Dec 1, 2016
1 parent 2631eac commit 03af9a2
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 92 deletions.
4 changes: 3 additions & 1 deletion Calendar.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@
ORGANIZATIONNAME = "Julien Martin";
TargetAttributes = {
72B5D8ED180D73E0004ADB86 = {
DevelopmentTeam = RSMX8QUE69;
DevelopmentTeam = 9L2H2A796T;
};
};
};
Expand Down Expand Up @@ -757,6 +757,7 @@
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = 9L2H2A796T;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "CalendarDemo/Calendar-Prefix.pch";
INFOPLIST_FILE = "$(SRCROOT)/CalendarDemo/Calendar-Info.plist";
Expand All @@ -777,6 +778,7 @@
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = 9L2H2A796T;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "CalendarDemo/Calendar-Prefix.pch";
INFOPLIST_FILE = "$(SRCROOT)/CalendarDemo/Calendar-Info.plist";
Expand Down
15 changes: 0 additions & 15 deletions CalendarLib/MGCTimedEventsViewLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,6 @@ typedef enum : NSUInteger
@end


// Helper cluster objects for `TimedEventCoveringTypeComplex` layout calculations
@interface MGCEventCellLayoutAttributesCluster : NSObject

@property (nonatomic, strong) NSMutableArray<MGCEventCellLayoutAttributes *> *contents; // attributes sorted by time
@property (nonatomic) NSUInteger columnSize; // the maxmimum number of attributes which have covering points at the same time


/**
Refresh the `columnSize` property's value
*/
- (void)calculateColumnSize;

@end


// This collection view layout is responsible for the layout of event views in the timed-events part
// of the day planner view.
@interface MGCTimedEventsViewLayout : UICollectionViewLayout
Expand Down
137 changes: 61 additions & 76 deletions CalendarLib/MGCTimedEventsViewLayout.m
Original file line number Diff line number Diff line change
Expand Up @@ -74,48 +74,6 @@ @interface MGCTimedEventsViewLayout()
@end


@implementation MGCEventCellLayoutAttributesCluster

- (instancetype)init {
if (self = [super init]) {
self.columnSize = 0;
}
return self;
}

// public
- (NSMutableArray<MGCEventCellLayoutAttributes *> *)contents
{
if (!_contents) {
_contents = [NSMutableArray new];
}

return _contents;
}

// public
- (void)calculateColumnSize
{
for (NSInteger i = 0; i < self.contents.count; i++) {
MGCEventCellLayoutAttributes *attribs1 = [self.contents objectAtIndex:i];
NSUInteger numberOfCoveredAttribs = 0;

for (NSInteger j = 0; j < self.contents.count; j++) {
MGCEventCellLayoutAttributes *attribs2 = [self.contents objectAtIndex:j];

if (CGRectIntersectsRect(attribs1.frame, attribs2.frame)) {
numberOfCoveredAttribs += 1;
}
}

if (numberOfCoveredAttribs > self.columnSize) {
self.columnSize = numberOfCoveredAttribs;
}
}
}
@end


@implementation MGCTimedEventsViewLayout

- (instancetype)init {
Expand Down Expand Up @@ -292,16 +250,16 @@ - (NSArray*)adjustLayoutForOverlappingCells:(NSArray*)attributes inSection:(NSUI

} else if (self.coveringType == TimedEventCoveringTypeComplex) {

// #1 Create clusters
// Create clusters - groups of rectangles which don't have common parts with other groups
NSMutableArray *uninspectedAttributes = [adjustedAttributes mutableCopy];
NSMutableArray<MGCEventCellLayoutAttributesCluster *> *clusters = [NSMutableArray new];
NSMutableArray<NSMutableArray<MGCEventCellLayoutAttributes *> *> *clusters = [NSMutableArray new];

while (uninspectedAttributes.count > 0) {
MGCEventCellLayoutAttributes *attrib = [uninspectedAttributes firstObject];
MGCEventCellLayoutAttributesCluster *destinationCluster;
NSMutableArray<MGCEventCellLayoutAttributes *> *destinationCluster;

for (MGCEventCellLayoutAttributesCluster *cluster in clusters) {
for (MGCEventCellLayoutAttributes *clusteredAttrib in cluster.contents) {
for (NSMutableArray<MGCEventCellLayoutAttributes *> *cluster in clusters) {
for (MGCEventCellLayoutAttributes *clusteredAttrib in cluster) {
if (CGRectIntersectsRect(clusteredAttrib.frame, attrib.frame)) {
destinationCluster = cluster;
break;
Expand All @@ -310,48 +268,75 @@ - (NSArray*)adjustLayoutForOverlappingCells:(NSArray*)attributes inSection:(NSUI
}

if (destinationCluster) {
[destinationCluster.contents addObject:attrib];
[destinationCluster addObject:attrib];
} else {
MGCEventCellLayoutAttributesCluster *cluster = [MGCEventCellLayoutAttributesCluster new];
[cluster.contents addObject:attrib];
NSMutableArray<MGCEventCellLayoutAttributes *> *cluster = [NSMutableArray new];
[cluster addObject:attrib];
[clusters addObject:cluster];
}

[uninspectedAttributes removeObject:attrib];
}

// #2 Determine cluster sizes
for (MGCEventCellLayoutAttributesCluster *cluster in clusters) {
[cluster calculateColumnSize];
// Distribute rectangles evenly in clusters
for (NSMutableArray<MGCEventCellLayoutAttributes *> *cluster in clusters) {
[self expandCellsToMaxWidthInCluster:cluster];
}

// #3 Determine base offsets
NSMutableArray *adjustedAttributes = [NSMutableArray new];
// Gather all the attributes and return them
NSMutableArray *attributes = [NSMutableArray new];
for (NSMutableArray<MGCEventCellLayoutAttributes *> *cluster in clusters) {
[attributes addObjectsFromArray:cluster];
}

CGFloat totalWidth = (self.dayColumnSize.width - 1.);
return attributes;
}

return @[];
}

for (MGCEventCellLayoutAttributesCluster *cluster in clusters) {
CGFloat colWidth = totalWidth / cluster.columnSize;
CGFloat x = section * self.dayColumnSize.width; // + groupOffset;

for (NSInteger i = 0; i < cluster.contents.count; i++) {
MGCEventCellLayoutAttributes *clusteredAttrib = [cluster.contents objectAtIndex:i];

for (NSInteger j = 0; j < i; j++) {
MGCEventCellLayoutAttributes *adjustedAttrib = [cluster.contents objectAtIndex:j];
if (!CGRectIntersectsRect(clusteredAttrib.frame, adjustedAttrib.frame)) {
x = adjustedAttrib.frame.origin.x;
}
}

clusteredAttrib.frame = MGCAlignedRectMake(x, clusteredAttrib.frame.origin.y, colWidth, clusteredAttrib.frame.size.height);
x += colWidth;

[adjustedAttributes addObject:clusteredAttrib];
- (void)expandCellsToMaxWidthInCluster:(NSMutableArray<MGCEventCellLayoutAttributes *> *)cluster
{
// Expand the attributes to maximum possible width
NSMutableArray<NSMutableArray<MGCEventCellLayoutAttributes *> *> *columns = [NSMutableArray new];
[columns addObject:[NSMutableArray new]];
for (MGCEventCellLayoutAttributes *attribs in cluster) {
BOOL isPlaced = NO;
for (NSMutableArray<MGCEventCellLayoutAttributes *> *column in columns) {
if (column.count == 0) {
[column addObject:attribs];
isPlaced = YES;
} else if (!CGRectIntersectsRect(attribs.frame, [column lastObject].frame)) {
[column addObject:attribs];
isPlaced = YES;
break;
}
}

return adjustedAttributes;
if (!isPlaced) {
NSMutableArray<MGCEventCellLayoutAttributes *> *column = [NSMutableArray new];
[column addObject:attribs];
[columns addObject:column];
}
}

// Calculate left and right position for all the attributes, get the maxRowCount by looking in all columns
NSInteger maxRowCount = 0;
for (NSMutableArray<MGCEventCellLayoutAttributes *> *column in columns) {
maxRowCount = fmax(maxRowCount, column.count);
}
for (NSInteger i = 0; i < maxRowCount; i++) {
// Set the x position of the rect
NSInteger j = 0;
for (NSMutableArray<MGCEventCellLayoutAttributes *> *column in columns) {
if (column.count >= i + 1) {
MGCEventCellLayoutAttributes *attribs = [column objectAtIndex:i];
attribs.frame = MGCAlignedRectMake(attribs.frame.origin.x + j * attribs.frame.size.width / columns.count,
attribs.frame.origin.y,
attribs.frame.size.width / columns.count,
attribs.frame.size.height);
}
j++;
}
}
}

Expand Down

0 comments on commit 03af9a2

Please sign in to comment.