<|start_filename|>ZMJGanttChart/Classes/ZMJScrollView.h<|end_filename|>
//
//  ZMJScrollView.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/19.
//  Copyright © 2018年 Jason. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "Define.h"
#import "Borders.h"
#import "ZMJCell.h"
#import "Gridlines.h"
#import "ReuseQueue.h"

@interface ZMJScrollView : UIScrollView
@property (nonatomic, strong) NSMutableArray<NSNumber *> *columnRecords; // number -> CGFloat
@property (nonatomic, strong) NSMutableArray<NSNumber *> *rowRecords;    // number -> CGFloat

@property (nonatomic, copy) TouchHandler touchesBegan;
@property (nonatomic, copy) TouchHandler touchesEnded;
@property (nonatomic, copy) TouchHandler touchesCancelled;

@property (nonatomic, assign) LayoutAttributes layoutAttributes;
@property (nonatomic, assign, readwrite) State state;

@property (nonatomic, strong) ReusableCollection<ZMJCell *>  *visibleCells;
@property (nonatomic, strong) ReusableCollection<Gridline *> *visibleVerticalGridlines;
@property (nonatomic, strong) ReusableCollection<Gridline *> *visibleHorizontalGridlines;
@property (nonatomic, strong) ReusableCollection<Border *>   *visibleBorders;

@property (nonatomic, assign) BOOL hasDisplayedContent;

- (void)resetReusableObjects;
@end


<|start_filename|>Example/ZMJGanttChart/ZMJViewController.h<|end_filename|>
//
//  ZMJViewController.h
//  ZMJGanttChart
//
//  Created by keshiim on 01/19/2018.
//  Copyright (c) 2018 keshiim. All rights reserved.
//

@import UIKit;

@interface ZMJViewController : UIViewController

@end


<|start_filename|>ZMJGanttChart/Classes/SpreadsheetView+Layout.h<|end_filename|>
//
//  SpreadsheetView+Layout.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/24.
//

#import "SpreadsheetView.h"
#import "ZMJScrollView.h"
#import "ZMJLayoutEngine.h"

@interface SpreadsheetView (Layout)

- (LayoutAttributes)layoutAttributeForCornerView;
- (LayoutAttributes)layoutAttributeForColumnHeaderView;
- (LayoutAttributes)layoutAttributeForRowHeaderView;
- (LayoutAttributes)layoutAttributeForTableView;
- (ZMJLayoutProperties *)resetLayoutProperties;

- (void)resetContentSize:(ZMJScrollView *)scrollView;
- (void)resetScrollViewFrame;
- (void)resetOverlayViewContentSize:(UIEdgeInsets)contentInset;
- (void)resetScrollViewArrangement;
- (NSInteger)findIndex:(NSArray<NSNumber *> *)records offset:(CGFloat)offset;

@end


<|start_filename|>ZMJGanttChart/Classes/Location.h<|end_filename|>
//
//  Location.h
//  Pods
//
//  Created by Jason on 2018/1/19.
//

#import <Foundation/Foundation.h>

@interface Location : NSObject <NSCopying>
@property (nonatomic, assign) NSInteger row;
@property (nonatomic, assign) NSInteger column;

- (instancetype)initWithRow:(NSInteger)row column:(NSInteger)column;
+ (instancetype)locationWithRow:(NSInteger)row column:(NSInteger)column;
+ (instancetype)indexPath:(NSIndexPath *)indexPath;

@end


<|start_filename|>ZMJGanttChart/Classes/SpreadsheetViewDataSource.h<|end_filename|>
//
//  SpreadsheetViewDataSource.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/24.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@class ZMJCell;
@class ZMJCellRange;
@class SpreadsheetView;

/// Implement this protocol to provide data to an `SpreadsheetView`.
@protocol SpreadsheetViewDataSource  <NSObject>
@required
/// Asks your data source object for the number of columns in the spreadsheet view.
///
/// - Parameter spreadsheetView: The spreadsheet view requesting this information.
/// - Returns: The number of columns in `spreadsheetView`.
- (NSInteger)numberOfColumns:(SpreadsheetView *)spreadsheetView;

/// Asks the number of rows in spreadsheet view.
///
/// - Parameter spreadsheetView: The spreadsheet view requesting this information.
/// - Returns: The number of rows in `spreadsheetView`.
- (NSInteger)numberOfRows:(SpreadsheetView *)spreadsheetView;

/// Asks the data source for the width to use for a row in a specified location.
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view requesting this information.
///   - column: The index of the column.
/// - Returns: A nonnegative floating-point value that specifies the width (in points) that column should be.
- (CGFloat)spreadsheetView:(SpreadsheetView *)spreadsheetView widthForColumn:(NSInteger)column;

/// Asks the data source for the height to use for a row in a specified location.
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view requesting this information.
///   - row: The index of the row.
/// - Returns: A nonnegative floating-point value that specifies the height (in points) that row should be.
- (CGFloat)spreadsheetView:(SpreadsheetView *)spreadsheetView heightForRow:(NSInteger)row;

/// Asks your data source object for the view that corresponds to the specified cell in the spreadsheetView.
/// The cell that is returned must be retrieved from a call to `dequeueReusableCell(withReuseIdentifier:for:)`
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view requesting this information.
///   - indexPath: The location of the cell
/// - Returns: A cell object to be displayed at the location.
///   If you return nil from this method, the blank cell will be displayed by default.
- (ZMJCell *)spreadsheetView:(SpreadsheetView *)spreadsheetView cellForItemAt:(NSIndexPath *)indexPath;

@optional
/// Asks your data source object for the array of cell ranges that indicate the range of merged cells in the spreadsheetView.
///
/// - Parameter spreadsheetView: The spreadsheet view requesting this information.
/// - Returns: An array of the cell ranges indicating the range of merged cells.
- (NSArray<ZMJCellRange *> *)mergedCells:(SpreadsheetView *)spreadsheetView;

/// Asks your data source object for the number of columns to be frozen as a fixed column header in the spreadsheetView.
///
/// - Parameter spreadsheetView: The spreadsheet view requesting this information.
/// - Returns: The number of columns to be frozen
- (NSInteger)frozenColumns:(SpreadsheetView *)spreadsheetView;

/// Asks your data source object for the number of rows to be frozen as a fixed row header in the spreadsheetView.
///
/// - Parameter spreadsheetView: The spreadsheet view requesting this information.
/// - Returns: The number of rows to be frozen
- (NSInteger)frozenRows:(SpreadsheetView *)spreadsheetView;
@end


<|start_filename|>ZMJGanttChart/Classes/NSIndexPath+column.h<|end_filename|>
//
//  NSIndexPath+column.h
//  Pods
//
//  Created by Jason on 2018/1/19.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface NSIndexPath (column)
@property (nonatomic, assign) NSInteger column;

+ (instancetype)indexPathWithRow:(NSInteger)row column:(NSInteger)column;
@end


<|start_filename|>ZMJGanttChart/Classes/Borders.h<|end_filename|>
//
//  Borders.h
//  Pods
//
//  Created by Jason on 2018/1/19.
//

#import <Foundation/Foundation.h>
#import "Define.h"

@class BorderStyle;
@interface Borders : NSObject
@property (nonatomic, strong) BorderStyle *top;
@property (nonatomic, strong) BorderStyle *bottom;
@property (nonatomic, strong) BorderStyle *left;
@property (nonatomic, strong) BorderStyle *right;

- (instancetype)initWithTop:(BorderStyle *)top bottom:(BorderStyle *)bottom left:(BorderStyle *)left right:(BorderStyle *)right;
+ (instancetype)all:(BorderStyle *)style;
@end

@interface BorderStyle : NSObject
@property (nonatomic, assign) CGFloat  width;
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, assign) BorderStyle_Enum border_enum;

- (instancetype)initWithStyle:(BorderStyle_Enum)style_enum width:(CGFloat)widith color:(UIColor *)color;
+ (instancetype)borderStyleNone;
@end

@interface Borders ()
@property (nonatomic, assign) BOOL hasBorders;
@end

@interface Border: UIView
@property (nonatomic, strong) Borders *borders;
@end


<|start_filename|>ZMJGanttChart/Classes/ZMJCell.h<|end_filename|>
//
//  ZMJCell.h
//  Pods
//
//  Created by Jason on 2018/1/19.
//

#import <UIKit/UIKit.h>
#import "Gridlines.h"
#import "Borders.h"

@interface ZMJCell : UIView

@property (nonatomic, strong, readonly) UIView *contentView;
@property (nonatomic, strong) UIView *backgroundView;
@property (nonatomic, strong) UIView *selectedBackgroundView;

@property (nonatomic, assign, getter=isHighlighted) BOOL highlighted;
@property (nonatomic, assign, getter=isSelected)    BOOL selected;

@property (nonatomic, strong) Gridlines *gridlines;
@property (nonatomic, strong) Gridlines *grids;

@property (nonatomic, strong) Borders *borders;
@property (nonatomic, assign) BOOL hasBorder;

@property (nonatomic, copy  ) NSString *reuseIdentifier;
@property (nonatomic, strong) NSIndexPath *indexPath;

- (NSComparisonResult)compare:(ZMJCell *)aValue;
- (void)prepareForReuse;

- (void)setSelected:(BOOL)selected animated:(BOOL)animated;
@end

@interface BlankCell: ZMJCell
@end


<|start_filename|>ZMJGanttChart/Classes/SpreadsheetViewDelegate.h<|end_filename|>
//
//  SpreadsheetViewDelegate.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/24.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@class SpreadsheetView;

/// The `SpreadsheetViewDelegate` protocol defines methods that allow you to manage the selection and
/// highlighting of cells in a spreadsheet view and to perform actions on those cells.
/// The methods of this protocol are all optional.
@protocol SpreadsheetViewDelegate <NSObject>
@optional
/// Asks the delegate if the cell should be highlighted during tracking.
/// - Note: As touch events arrive, the spreadsheet view highlights cells in anticipation of the user selecting them.
///   As it processes those touch events, the collection view calls this method to ask your delegate if a given cell should be highlighted.
///   It calls this method only in response to user interactions and does not call it if you programmatically set the highlighting on a cell.
///
///   If you do not implement this method, the default return value is `true`.
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view object that is asking about the highlight change.
///   - indexPath: The index path of the cell to be highlighted.
/// - Returns: `true` if the item should be highlighted or `false` if it should not.
- (BOOL)spreadsheetView:(SpreadsheetView *)spreadsheetView shouldHighlightItemAt:(NSIndexPath *)indexPath;

/// Tells the delegate that the cell at the specified index path was highlighted.
/// - Note: The spreadsheet view calls this method only in response to user interactions and does not call it
///   if you programmatically set the highlighting on a cell.
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view object that is notifying you of the highlight change.
///   - indexPath: The index path of the cell that was highlighted.
- (void)spreadsheetView:(SpreadsheetView *)spreadsheetView didHighlightItemAt:(NSIndexPath *)indexPath;

/// Tells the delegate that the highlight was removed from the cell at the specified index path.
/// - Note: The spreadsheet view calls this method only in response to user interactions and does not call it
///   if you programmatically change the highlighting on a cell.
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view object that is notifying you of the highlight change.
///   - indexPath: The index path of the cell that had its highlight removed.
- (void)spreadsheetView:(SpreadsheetView *)spreadsheetView didUnhighlightItemAt:(NSIndexPath *)indexPath;

/// Asks the delegate if the specified cell should be selected.
/// - Note: The spreadsheet view calls this method when the user tries to select an item in the collection view.
///   It does not call this method when you programmatically set the selection.
///
///   If you do not implement this method, the default return value is `true`.
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view object that is asking whether the selection should change.
///   - indexPath: The index path of the cell to be selected.
/// - Returns: `true` if the item should be selected or `false` if it should not.
- (BOOL)spreadsheetView:(SpreadsheetView *)spreadsheetView shouldSelectItemAt:(NSIndexPath *)indexPath;

/// Asks the delegate if the specified item should be deselected.
/// - Note: The spreadsheet view calls this method when the user tries to deselect a cell in the spreadsheet view.
///   It does not call this method when you programmatically deselect items.
///
///   If you do not implement this method, the default return value is `true`.
///
///   This method is called when the user taps on an already-selected item in multi-select mode
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view object that is asking whether the selection should change.
///   - indexPath: The index path of the cell to be deselected.
/// - Returns: `true` if the cell should be deselected or `false` if it should not.
- (BOOL)spreadsheetView:(SpreadsheetView *)spreadsheetView shouldDeselectItemAt:(NSIndexPath *)indexPath;

/// Tells the delegate that the cell at the specified index path was selected.
/// - Note: The spreadsheet view calls this method when the user successfully selects a cell in the spreadsheet view.
///   It does not call this method when you programmatically set the selection.
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view object that is notifying you of the selection change.
///   - indexPath: The index path of the cell that was selected.
- (void)spreadsheetView:(SpreadsheetView *)spreadsheetView didSelectItemAt:(NSIndexPath *)indexPath;

/// Tells the delegate that the cell at the specified path was deselected.
/// - Note: The spreadsheet view calls this method when the user successfully deselects an item in the spreadsheet view.
///   It does not call this method when you programmatically deselect items.
///
/// - Parameters:
///   - spreadsheetView: The spreadsheet view object that is notifying you of the selection change.
///   - indexPath: The index path of the cell that was deselected.
- (void)spreadsheetView:(SpreadsheetView *)spreadsheetView didDeselectItemAt:(NSIndexPath *)indexPath;
@end


<|start_filename|>ZMJGanttChart/Classes/Gridlines.h<|end_filename|>
//
//  Gridlines.h
//  Pods
//
//  Created by Jason on 2018/1/19.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Define.h"

@class GridStyle;
@interface Gridlines : NSObject
@property (nonatomic, strong) GridStyle *top;
@property (nonatomic, strong) GridStyle *bottom;
@property (nonatomic, strong) GridStyle *left;
@property (nonatomic, strong) GridStyle *right;

- (instancetype)initWithTop:(GridStyle *)top bottom:(GridStyle *)bottom left:(GridStyle *)left right:(GridStyle *)right;
+ (instancetype)all:(GridStyle *)style;
@end

@interface GridStyle : NSObject
/**
 style : default, none, solid
 */
@property (nonatomic, assign) GridStyle_Enum styleEnum;

/**
 when style = GridStyle_solid, width & color needed
 */
@property (nonatomic, assign) CGFloat width;
@property (nonatomic, strong) UIColor *color;

- (instancetype)initWithStyle:(GridStyle_Enum)style_enum width:(CGFloat)widith color:(UIColor *)color;
+ (instancetype)borderStyleNone;
+ (instancetype)style:(GridStyle_Enum)style_enum width:(CGFloat)widith color:(UIColor *)color;
@end


@interface ZMJGridLayout : NSObject  <NSCopying>
@property (nonatomic, assign) CGFloat gridWidth;
@property (nonatomic, copy  ) UIColor*gridColor;
@property (nonatomic, assign) CGPoint origin;
@property (nonatomic, assign) CGFloat length;
@property (nonatomic, assign) RectEdge edge;
@property (nonatomic, assign) CGFloat priority;

- (instancetype)initWithGridWidth:(CGFloat)gridWidth gridColor:(UIColor *)gridColor origin:(CGPoint)origin length:(CGFloat)length edge:(RectEdge)edge priority:(CGFloat)priority;

+ (instancetype)gridLayoutWithGridWidth:(CGFloat)gridWidth gridColor:(UIColor *)gridColor origin:(CGPoint)origin length:(CGFloat)length edge:(RectEdge)edge priority:(CGFloat)priority;
@end


@interface Gridline : CALayer
@property (nonatomic, strong) UIColor *color;
@end


<|start_filename|>Example/ZMJGanttChart/ZMJAppDelegate.h<|end_filename|>
//
//  ZMJAppDelegate.h
//  ZMJGanttChart
//
//  Created by keshiim on 01/19/2018.
//  Copyright (c) 2018 keshiim. All rights reserved.
//

@import UIKit;

@interface ZMJAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end


<|start_filename|>Example/ZMJSchedule/ZMJCells.h<|end_filename|>
//
//  ZMJCells.h
//  ZMJSchedule
//
//  Created by Jason on 2018/2/6.
//  Copyright © 2018年 keshiim. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <ZMJGanttChart/ZMJGanttChart.h>

@interface DateCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface DayTitleCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface TimeTitleCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface TimeCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface ScheduleCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UIColor *color;
@end


<|start_filename|>ZMJGanttChart/Classes/SpreadsheetView+UIViewHierarchy.h<|end_filename|>
//
//  SpreadsheetView+UIViewHierarchy.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/25.
//

#import "SpreadsheetView.h"

@interface SpreadsheetView (UIViewHierarchy)

@end


<|start_filename|>ZMJGanttChart/Classes/ZMJGanttChart.h<|end_filename|>
//
//  ZMJGanttChat.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/29.
//

#ifndef ZMJGanttChart_h
#define ZMJGanttChart_h

#import "Define.h"

#import "NSDictionary+WBGAdd.h"
#import "NSArray+WBGAddition.h"
#import "Address.h"
#import "Borders.h"
#import "CircualrScrolling.h"
#import "Gridlines.h"
#import "Location.h"
#import "NSArray+BinarySearch.h"
#import "NSIndexPath+column.h"
#import "ReuseQueue.h"
#import "ZMJCell.h"
#import "ZMJCellRange.h"
#import "ZMJLayoutEngine.h"
#import "ZMJScrollView.h"
#import "SpreadsheetViewDelegate.h"
#import "SpreadsheetViewDataSource.h"
#import "SpreadsheetView.h"
#import "SpreadsheetView+Layout.h"
#import "SpreadsheetView+CirclularScrolling.h"
#import "SpreadsheetView+Touches.h"
#import "SpreadsheetView+UIViewHierarchy.h"
#import "SpreadsheetView+UISnapshotting.h"
#import "SpreadsheetView+UIScrollView.h"
#import "SpreadsheetView+UIScrollViewDelegate.h"
#endif /* ZMJGanttChart_h */


<|start_filename|>ZMJGanttChart/Classes/NSArray+WBGAddition.h<|end_filename|>
//
//  NSArray+WBGAddition.h
//  Trader
//
//  Created by <NAME> on 1/23/16.
//
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSArray<__covariant ObjectType> (WBGAddition)


# pragma mark - Blocks
/**
 *  把一个数组给map成另外一个数组
 *
 *  @param block 输入一个self里的东西 返回一个需要被map成的东西
 *  可以返回nil, 返回nil的话这个东西就像是被过滤掉了
 *
 *  @return 被map成的另外一个array
 */
- (NSArray *)wbg_map:(id __nullable (^)(ObjectType stuff))block __attribute__((warn_unused_result));
- (NSArray *)wbg_mapWithIndex:(id __nullable (^)(ObjectType stuff,
                                                 NSUInteger index))block __attribute__((warn_unused_result));

/// 比[- NSArray wbg_map]安全, array是nil的时候返回@[]
+ (NSArray *)wbg_map:(NSArray<ObjectType> *)array
             inBlock:(id __nullable (^)(ObjectType stuff))block;

/// 比[- NSArray wbg_mapWithIndex]安全, array是nil的时候返回@[]
+ (NSArray *)wbg_mapWithIndex:(NSArray<ObjectType> *)array
                      inBlock:(id __nullable (^)(ObjectType stuff,
                                                 NSUInteger index))block __attribute__((warn_unused_result));

typedef void(^WBGMultiMapReturn)(id __nullable returnedStuff);

/// 和map一样 不过可以把一个对象map成好几个东西 呼叫returnBlock把需要return的东西传过来
- (NSArray *)wbg_multiMap:(void (^)(ObjectType stuff, WBGMultiMapReturn returnBlock))block __attribute__((warn_unused_result));

/// 和map一样 不过可以把一个对象map成好几个东西 呼叫returnBlock把需要return的东西传过来
- (NSArray *)wbg_multiMapWithIndex:(void (^)(ObjectType stuff, WBGMultiMapReturn returnBlock,
                                             NSUInteger index))block __attribute__((warn_unused_result));


/**
 *  把一个数组过滤一下
 *
 *  @param block 顾虑的block  传进来数组里的每个东西 返回no的话这个元素就被过滤掉了
 *
 *  @return 过滤之后的数组
 */
- (NSArray<ObjectType> *)wbg_filter:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));
- (NSArray<ObjectType> *)wbg_filterWithIndex:(BOOL (^)(ObjectType stuff,
                                                       NSUInteger index))block __attribute__((warn_unused_result));

+ (NSArray<ObjectType> *)wbg_filter:(NSArray<ObjectType> *)array
                            inBlock:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));

+ (NSArray<ObjectType> *)wbg_filterWithIndex:(NSArray<ObjectType> *)array
                                     inBlock:(BOOL (^)(ObjectType stuff,
                                                       NSUInteger index))block __attribute__((warn_unused_result));


/**
 *  reject是反着的filter
 *
 *  @param block  传进来数组里的每个东西 返回YES的话这个元素就被过滤掉了
 *
 *  @return 过滤之后的数组
 */
- (NSArray<ObjectType> *)wbg_reject:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));
- (NSArray<ObjectType> *)wbg_rejectWithIndex:(BOOL (^)(ObjectType stuff,
                                                       NSUInteger index))block __attribute__((warn_unused_result));

+ (NSArray<ObjectType> *)wbg_reject:(NSArray<ObjectType> *)array
inBlock:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));

+ (NSArray<ObjectType> *)wbg_rejectWithIndex:(NSArray<ObjectType> *)array
inBlock:(BOOL (^)(ObjectType stuff,
                  NSUInteger index))block __attribute__((warn_unused_result));


# pragma mark - Reduce
/**
 reduce

 @param first first value to be passed to `prev`
 @param block reduces `prev` and `curr` and returns next prev
 @return last value returned by `block`
 */
- (nullable id)wbg_reduce:(nullable id)first with:(nullable id (^)(_Nullable id prev, ObjectType curr))block __attribute__((warn_unused_result));


/**
 reduce with first value being `nil`

 @param block reduces `prev` and `curr` and returns next prev
 @return last value returned by `block`
 */
- (nullable id)wbg_reduce:(nullable id (^)(_Nullable id prev, ObjectType curr))block __attribute__((warn_unused_result));


/**
 reduce with index
 
 @param first first value to be passed to `prev`
 @param block reduces `prev` and `curr` and returns next prev
 @return last value returned by `block`
 */
- (nullable id)wbg_reduce:(nullable id)first withIndex:(nullable id (^)(_Nullable id prev, ObjectType curr, NSUInteger idx))block __attribute__((warn_unused_result));


/**
 reduce with index
 
 @param block reduces `prev` and `curr` and returns next prev
 @return last value returned by `block`
 */
- (nullable id)wbg_reduceWithIndex:(nullable id (^)(_Nullable id prev, ObjectType curr, NSUInteger idx))block __attribute__((warn_unused_result));

/**
 reduce with CGFloat as type - most commonly reduced type
 */
- (CGFloat)wbg_reduceCGFloat:(CGFloat)first with:(CGFloat (^)(CGFloat prev, ObjectType curr))block;

/**
 reduce with double as type
 */
- (CGFloat)wbg_reduceDouble:(double)first with:(double (^)(double prev, ObjectType curr))block;

/**
 reduce with NSInteger as type
 */
- (CGFloat)wbg_reduceNSInteger:(NSInteger)first with:(NSInteger (^)(NSInteger prev, ObjectType curr))block;

/**
 apply - equivalent to -[NSArray makeObjectsPerformSelector:]

 @param block the block to perform
 */
- (void)wbg_apply:(void (^)(ObjectType stuff))block;

# pragma mark - QueryFirst

/**
 和过滤一个意思 不过只得第一个元素

 @param block 过滤的block  传进来数组里的每个东西 返回no的话这个元素就被过滤掉了 返回yes的话就停了
 @return 过滤得到的第一个东西
 */
- (ObjectType)wbg_queryFirst:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));
- (ObjectType)wbg_queryFirstWithIndex:(BOOL (^)(ObjectType stuff,
                                                NSUInteger index))block __attribute__((warn_unused_result));

/**
 找第一个满足block的index 找不到的话return NSNotFound
 */
- (NSUInteger)wbg_indexOf:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));

/**
 和queryFirst一个意思 不过反着搜索

 @param block 过滤的block  传进来数组里的每个东西 返回no的话这个元素就被过滤掉了 返回yes的话就停了
 @return 过滤得到的第一个东西
 */
- (ObjectType)wbg_queryLast:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));

/**
 带着index的queryLast
 
 @param block 过滤的block  传进来数组里的每个东西 返回no的话这个元素就被过滤掉了 返回yes的话就停了
 @return 过滤得到的第一个东西
 */
- (ObjectType)wbg_queryLastWithIndex:(BOOL (^)(ObjectType stuff,
                                               NSUInteger index))block __attribute__((warn_unused_result));

# pragma mark - Any

/**
 任意一个object符合block
 */
- (BOOL)wbg_any:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));

/**
 任意一个object符合block
 */
- (BOOL)wbg_anyWithIndex:(BOOL (^)(ObjectType stuff,
                                   NSUInteger index))block __attribute__((warn_unused_result));

# pragma mark - All

/**
 所有object符合block
 */
- (BOOL)wbg_all:(BOOL (^)(ObjectType stuff))block __attribute__((warn_unused_result));

/**
 所有object符合block
 */
- (BOOL)wbg_allWithIndex:(BOOL (^)(ObjectType stuff,
                                   NSUInteger index))block __attribute__((warn_unused_result));


# pragma mark - For..In

/**
 for ii in 0..count: { ... }

 @param count count, returns @[] for count <= 0
 @param block build your stuff in this block, return nullable
 @return the stuffs you built in `block`
 */
+ (NSArray<ObjectType> *)wbg_forIn:(NSInteger)count block:(ObjectType __nullable (^)(NSUInteger index))block /* __attribute__((warn_unused_result)) */;

/// similar to `for ii in range: ...`
+ (NSArray<ObjectType> *)wbg_forInRange:(NSRange)range block:(ObjectType __nullable (^)(NSUInteger index))block __attribute__((warn_unused_result));


# pragma mark - 去重
- (NSArray<ObjectType> *)wbg_arrayByRemovingDuplicate __attribute__((warn_unused_result));

# pragma mark - Get
- (nullable ObjectType)wbg_safeObjectAtIndex:(NSInteger)index __attribute__((warn_unused_result));
- (NSArray<ObjectType> *)wbg_getObjectsWithRange:(NSRange)range __attribute__((warn_unused_result));
/**
 *  @param indexNumber index作为NSNumber, 取integerValue. 不是NSNumber返回nil
 */
- (nullable ObjectType)wbg_safeObjectAtIndexNumber:(NSNumber *)indexNumber __attribute__((warn_unused_result));

# pragma mark - Delete
- (NSArray<ObjectType> *)wbg_arrayByRemovingObject:(ObjectType)object __attribute__((warn_unused_result));
- (NSArray<ObjectType> *)wbg_arrayByRemovingObjectsFromArray:(NSArray<ObjectType> *)array __attribute__((warn_unused_result));
- (NSArray<ObjectType> *)wbg_arrayByPopFirst __attribute__((warn_unused_result));
- (NSArray<ObjectType> *)wbg_arrayByPopLast __attribute__((warn_unused_result));

- (NSArray<ObjectType> *)wbg_safeArrayByRemovingObjectAtIndex:(NSUInteger)index __attribute__((warn_unused_result));

# pragma mark - Append
- (NSArray<ObjectType> *)wbg_arrayByAddingObject:(ObjectType)anObject __attribute__((warn_unused_result));

# pragma mark - Replace
- (NSArray<ObjectType> *)wbg_arrayByReplacingObject:(ObjectType)object with:(ObjectType)newObject __attribute__((warn_unused_result));
- (NSArray<ObjectType> *)wbg_arrayByReplacingObjectAtIndex:(NSUInteger)idx with:(ObjectType)newObject __attribute__((warn_unused_result));

# pragma mark - Join

/**
 效果参考-[NSArray componentsJoinedByString:]
 */
- (NSArray *)wbg_arrayByJoiningWithObject:(id)object copyObject:(BOOL)copyObject __attribute__((warn_unused_result));

# pragma mark - Merge
+ (NSArray<ObjectType> *)wbg_arrayByMergingArray:(NSArray<ObjectType> *)oneArray withArray:(NSArray<ObjectType> *)anotherArray copyItems:(BOOL)copyItems removeDuplicate:(BOOL)removeDuplicate __attribute__((warn_unused_result));


/**
 merge many arrays
 
 @note this method does not copy items in array, and does not remove duplicate
 @note this method simply skips non nill but non NSArray typed objects in argument list
 
 @param oneArray an array to be merged
 @return merged array
 */
+ (NSArray<ObjectType> *)wbg_arrayByMerging:(NSArray<ObjectType> *)oneArray, ... NS_REQUIRES_NIL_TERMINATION __attribute__((warn_unused_result));


/**
 merge self with many arrays
 
 @note this method does not copy items in array, and does not remove duplicate
 @note this method simply skips non nill but non NSArray typed objects in argument list
 
 @param oneArray the first array to be merged
 @return merged array
 */
- (NSArray<ObjectType> *)wbg_arrayByMerging:(NSArray<ObjectType> *)oneArray, ... NS_REQUIRES_NIL_TERMINATION __attribute__((warn_unused_result));


# pragma mark - Set Like Operations

/**
 @return [item for item in self if item in otherArray]
 */
- (NSArray<ObjectType> *)wbg_arrayByIntersectingWithArray:(NSArray<ObjectType> *)otherArray;

# pragma mark - Prepend
- (NSArray *)wbg_arrayByPrependingObject:(id)object __attribute__((warn_unused_result));

- (NSArray *)wbg_arrayByPrependingObjectsFromArray:(NSArray<id> *)array __attribute__((warn_unused_result));

# pragma mark - Reverse
- (NSArray<ObjectType> *)wbg_arrayByReverse;



/**
 求两个同类型数组的交集

 @param otherArray 另一数组
 @return 交集数组
 */
- (NSArray<ObjectType> *)wbg_interSectWithArray:(NSArray<ObjectType> *)otherArray ;



/**
 求两个数组的差集

 @param otherArray 另一数组
 @return 差集数组
 */
- (NSArray<ObjectType> *)wbg_minuWithArray:(NSArray<ObjectType> *)otherArray ;

@end

NS_ASSUME_NONNULL_END


<|start_filename|>ZMJGanttChart/Classes/ZMJLayoutEngine.h<|end_filename|>
//
//  ZMJLayoutEngine.h
//  Pods
//
//  Created by Jason on 2018/1/19.
//

#import <Foundation/Foundation.h>
#import "ZMJScrollView.h"
#import "Define.h"

@class ZMJCellRange;
@class Location;
@class ZMJScrollView;
@class SpreadsheetView;
#pragma mark - Class interface
@interface ZMJLayoutProperties: NSObject
@property (nonatomic, assign) NSInteger numberOfColumns;
@property (nonatomic, assign) NSInteger numberOfRows;
@property (nonatomic, assign) NSInteger frozenColumns;
@property (nonatomic, assign) NSInteger frozenRows;

@property (nonatomic, assign) CGFloat frozenColumnWidth;
@property (nonatomic, assign) CGFloat frozenRowHeight;
@property (nonatomic, assign) CGFloat columnWidth;
@property (nonatomic, assign) CGFloat rowHeight;

@property (nonatomic, strong) NSMutableArray<NSNumber *> *columnWidthCache; //number -> CGFloat
@property (nonatomic, strong) NSMutableArray<NSNumber *> *rowHeightCache;   //number -> CGFloat

@property (nonatomic, strong) NSMutableArray<ZMJCellRange *> *mergedCells;
@property (nonatomic, strong) NSMutableDictionary<Location *, ZMJCellRange *> *mergedCellLayouts;

- (instancetype)initWithNumberOfColumns:(NSInteger)numberOfColumns
                           numberOfRows:(NSInteger)numberOfRows
                          frozenColumns:(NSInteger)frozenColumns
                             frozenRows:(NSInteger)frozenRows
                      frozenColumnWidth:(CGFloat)frozenColumnWidth
                        frozenRowHeight:(CGFloat)frozenRowHeight
                            columnWidth:(CGFloat)columnWidth
                              rowHeight:(CGFloat)rowHeight
                       columnWidthCache:(NSArray<NSNumber *> *)columnWidthCache
                         rowHeightCache:(NSArray<NSNumber *> *)rowHeightCache
                            mergedCells:(NSArray<ZMJCellRange *> *)mergedCells
                      mergedCellLayouts:(NSDictionary<Location *, ZMJCellRange *> *)mergedCellLayouts;
@end


@interface ZMJLayoutEngine : NSObject
- (instancetype)initWithSpreadsheetView:(SpreadsheetView *)spreadsheetView scrollView:(ZMJScrollView *)scrollView;
+ (instancetype)spreadsheetView:(SpreadsheetView *)spreadsheetView scrollView:(ZMJScrollView *)scrollView;

- (void)layout;
@end



<|start_filename|>ZMJGanttChart/Classes/SpreadsheetView+UISnapshotting.h<|end_filename|>
//
//  SpreadsheetView+UISnapshotting.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/25.
//

#import "SpreadsheetView.h"

@interface SpreadsheetView (UISnapshotting)

@end


<|start_filename|>ZMJGanttChart/Classes/ReuseQueue.h<|end_filename|>
//
//  ReuseQueue.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/19.
//  Copyright © 2018年 Jason. All rights reserved.
//

#import <Foundation/Foundation.h>

#define LOCK(...) [_lock lock]; \
__VA_ARGS__; \
[_lock unlock];

@class Address;

@interface ReuseQueue<__covariant Reusable> : NSObject
- (void)enqueue:(Reusable)reusableObject;
- (Reusable)dequeue;
- (Reusable)dequeueOrCreate:(Class)clazz;
@end

@interface ReusableCollection<__covariant Reusable> : NSObject <NSFastEnumeration>
@property (nonatomic, strong, readonly) NSArray<Reusable> *array;
@property (nonatomic, strong, readonly) NSMutableDictionary<Address *, Reusable> *pairs;
@property (nonatomic, strong) NSMutableOrderedSet<Address *>     *addresses;

- (BOOL)contains:(Address *)member;
- (void)insert:(Address *)newMember;
- (void)substract:(NSOrderedSet<Address *> *)other;

- (Reusable)objectForKeyedSubscript:(Address *)key;
- (void)removeObjectForKey:(Address *)aKey;
- (void)setObject:(Reusable)obj forKeyedSubscript:(Address *)key;

@end


<|start_filename|>ZMJGanttChart/Classes/CircualrScrolling.h<|end_filename|>
//
//  CircualrScrolling.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/22.
//

#import <Foundation/Foundation.h>
#import "Define.h"
@protocol CircularScrollingConfiguration;

@class Configuration;
@class Options;
@class CircualrScrolling;
@class CircularScrollingConfigurationBuilder;

#pragma mark - Protocol

@protocol CircularScrollingConfiguration
- (Options *)options;
@end

typedef NS_OPTIONS(NSUInteger, CircularScrollingConfigurationState) {
    ZMJCircularScrolling_none         = 0,
    
    ZMJCircularScrolling_horizontally = 1 << 0,
    ZMJCircularScrolling_horizontally_rowHeaderStartsFirstColumn = 1 << 1,
    ZMJCircularScrolling_horizontally_columnHeaderNotRepeated    = 1 << 2,
    ZMJCircularScrolling_horizontally_columnHeaderNotRepeated_rowHeaderStartsFirstColumn = 1 << 3,
    
    ZMJCircularScrolling_vertically = 1 << 4,
    ZMJCircularScrolling_vertically_columnHeaderStartsFirstRow = 1 << 5,
    ZMJCircularScrolling_vertically_rowHeaderNotRepeated = 1 << 6,
    ZMJCircularScrolling_vertically_rowHeaderNotRepeated_columnHeaderStartsFirstRow = 1 << 7,
    
    ZMJCircularScrolling_both = 1 << 8,
    ZMJCircularScrolling_both_rowHeaderStartsFirstColumn = 1 << 9,
    ZMJCircularScrolling_both_columnHeaderStartsFirstRow = 1 << 10,
    ZMJCircularScrolling_both_rowHeaderStartsFirstColumn_rowHeaderNotRepeated = 1 << 11,
    ZMJCircularScrolling_both_columnHeaderStartsFirstRow_columnHeaderNotRepeated = 1 << 12,
    
    ZMJCircularScrolling_both_columnHeaderNotRepeated = 1 << 13,
    ZMJCircularScrolling_both_columnHeaderNotRepeated_rowHeaderStartsFirstColumn = 1 << 14,
    ZMJCircularScrolling_both_columnHeaderNotRepeated_columnHeaderStartsFirstRow = 1 << 15,
    ZMJCircularScrolling_both_columnHeaderNotRepeated_rowHeaderNotRepeated = 1 << 16,
    ZMJCircularScrolling_both_columnHeaderNotRepeated_rowHeaderNotRepeated_rowHeaderStartsFirstColumn = 1 << 17,
    ZMJCircularScrolling_both_columnHeaderNotRepeated_rowHeaderNotRepeated_columnHeaderStartsFirstRow = 1 << 18,
    
    ZMJCircularScrolling_both_rowHeaderNotRepeated = 1 << 19,
    ZMJCircularScrolling_both_rowHeaderNotRepeated_rowHeaderStartsFirstColumn = 1 << 20,
    ZMJCircularScrolling_both_rowHeaderNotRepeated_columnHeaderStartsFirstRow = 1 << 21,
    ZMJCircularScrolling_both_rowHeaderNotRepeated_columnHeaderNotRepeated = 1 << 22,
    ZMJCircularScrolling_both_rowHeaderNotRepeated_columnHeaderNotRepeated_rowHeaderStartsFirstColumn = 1 << 23,
    ZMJCircularScrolling_both_rowHeaderNotRepeated_columnHeaderNotRepeated_columnHeaderStartsFirstRow = 1 << 24,
};

#pragma mark - Class
@interface CircularScrollingConfigurationBuilder: NSObject <CircularScrollingConfiguration>
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCircularScrollingState:(CircularScrollingConfigurationState)state;
+ (instancetype)configurationBuilderWithCircularScrollingState:(CircularScrollingConfigurationState)state;

@property (nonatomic, assign) CircularScrollingConfigurationState state;
@end

@interface Configuration: NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)instance;

@property (nonatomic, strong) CircularScrollingConfigurationBuilder         *none;
@property (nonatomic, strong) CircularScrollingConfigurationBuilder *horizontally;
@property (nonatomic, strong) CircularScrollingConfigurationBuilder   *vertically;
@property (nonatomic, strong) CircularScrollingConfigurationBuilder         *both;
@end

@interface Options : NSObject
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithDirection:(ZMJDirection)direction headerStyle:(ZMJHeaderStyle)headerStyle tableStyle:(ZMJTableStyle)tableStyle;
+ (instancetype)optionsWithDirection:(ZMJDirection)direction headerStyle:(ZMJHeaderStyle)headerStyle tableStyle:(ZMJTableStyle)tableStyle;

@property (nonatomic, assign) ZMJDirection   direction;
@property (nonatomic, assign) ZMJHeaderStyle headerStyle;
@property (nonatomic, assign) ZMJTableStyle  tableStyle;
@end

@interface CircualrScrolling : NSObject
@end



<|start_filename|>ZMJGanttChart/Classes/SpreadsheetView+CirclularScrolling.h<|end_filename|>
//
//  SpreadsheetView+CirclularScrolling.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/24.
//

#import "SpreadsheetView.h"

@interface SpreadsheetView (CirclularScrolling)
- (void)scrollToHorizontalCenter;
- (void)scrollToVerticalCenter;
- (void)recenterHorizontallyIfNecessary;
- (void)recenterVerticallyIfNecessary;
- (CircularScrollScalingFactor)determineCircularScrollScalingFactor;
- (NSInteger)determineHorizontalCircularScrollScalingFactor;
- (NSInteger)determineVerticalCircularScrollScalingFactor;
- (CGPoint)calculateCenterOffset;
@end


<|start_filename|>ZMJGanttChart/Classes/Address.h<|end_filename|>
//
//  Address.h
//  Pods
//
//  Created by Jason on 2018/1/19.
//

#import <Foundation/Foundation.h>

@interface Address : NSObject <NSCopying>
@property (nonatomic, assign) NSInteger row;
@property (nonatomic, assign) NSInteger column;
@property (nonatomic, assign) NSInteger rowIndex;
@property (nonatomic, assign) NSInteger columnIndex;

- (instancetype)initWithRow:(NSInteger)row column:(NSInteger)column rowIndex:(NSInteger)rowIndex columnIndex:(NSInteger)columnIndex;
+ (instancetype)addressWithRow:(NSInteger)row column:(NSInteger)column rowIndex:(NSInteger)rowIndex columnIndex:(NSInteger)columnIndex;
@end


<|start_filename|>Example/ZMJGanttChart/ZMJCells.h<|end_filename|>
//
//  ZMJCells.h
//  ZMJGanttChart_Example
//
//  Created by Jason on 2018/1/29.
//  Copyright © 2018年 keshiim. All rights reserved.
//

#import "UIKit/UIKit.h"
#import <ZMJGanttChart/ZMJGanttChart.h>

@interface ZMJHeaderCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface ZMJTextCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface ZMJTaskCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface ZMJChartBarCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UIView  *colorBarView;
@property (nonatomic, strong) UIColor *color;
@end


<|start_filename|>Example/ZMJGanttList/ZMJCells.h<|end_filename|>
//
//  ZMJCells.h
//  ZMJGanttList
//
//  Created by Jason on 2018/2/26.
//  Copyright © 2018年 keshiim. All rights reserved.
//

#import <ZMJGanttChart/ZMJGanttChart.h>

@interface ZMJHeaderCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface ZMJTaskCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

typedef NS_ENUM(NSInteger, ZMJDashlineDirection) {
    ZMJDashlineDirectionNone = 0,
    ZMJDashlineDirectionLeft ,
    ZMJDashlineDirectionRight,
};
@interface ZMJChartBarCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UIView  *colorBarView;
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, assign) ZMJDashlineDirection direction;
@end


<|start_filename|>ZMJGanttChart/Classes/SpreadsheetView+UIScrollView.h<|end_filename|>
//
//  SpreadsheetView+UIScrollView.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/25.
//

#import "SpreadsheetView.h"

@interface SpreadsheetView (UIScrollView)
@property (nonatomic, assign) CGPoint contentOffset;
@property (nonatomic, assign) UIEdgeInsets scrollIndicatorInsets;
@property (nonatomic, assign, readonly) CGSize contentSize;
@property (nonatomic, assign) UIEdgeInsets contentInset;

#ifdef __IPHONE_11_0
@property (nonatomic, assign, readonly) UIEdgeInsets adjustedContentInset;
#endif


- (void)flashScrollIndicators;
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;
@end


<|start_filename|>Example/ZMJGanttChart/ClassData/ZMJCells.h<|end_filename|>
//
//  ZMJCells.h
//  ZMJClassData
//
//  Created by Jason on 2018/2/5.
//  Copyright © 2018年 keshiim. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <ZMJGanttChart/ZMJGanttChart.h>

@interface HeaderCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UILabel *sortArrow;
@end

@interface TextCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end


<|start_filename|>ZMJGanttChart/Classes/Define.h<|end_filename|>
//
//  Define.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/23.
//

#ifndef Define_h
#define Define_h
#import <UIKit/UIKit.h>
#define IOS_VERSION_11_OR_LATER (([[[UIDevice currentDevice] systemVersion] floatValue] >=11.0)? (YES):(NO))


typedef void(^TouchHandler)(NSSet<UITouch *> *touches, UIEvent *event);

typedef struct ZMJState {
    CGRect  frame;
    CGSize  contentSize;
    CGPoint contentOffset;
} State;

typedef NS_OPTIONS(NSUInteger, ZMJScrollPosition) {
    // The vertical positions are mutually exclusive to each other, but are bitwise or-able with the horizontal scroll positions.
    // Combining positions from the same grouping (horizontal or vertical) will result in an NSInvalidArgumentException.
    ScrollPosition_top                 = 1 << 0,
    ScrollPosition_centeredVertiically = 1 << 1,
    ScrollPosition_bottom              = 1 << 2,
    
    // Likewise, the horizontal positions are mutually exclusive to each other.
    ScrollPosition_left                = 1 << 3,
    ScrollPosition_centeredHorizontally= 1 << 4,
    ScrollPosition_right               = 1 << 5,
};


typedef NS_ENUM(NSInteger, GridStyle_Enum) {
    GridStyle_default = 0,
    GridStyle_none,
    GridStyle_solid,
};

typedef NS_ENUM(NSInteger, BorderStyle_Enum) {
    BorderStyle_None,
    BorderStyle_solid,
};

#pragma mark - Defines
typedef struct ZMJDirect {
    CGFloat left;
    CGFloat right;
    CGFloat top;
    CGFloat bottom;
    BOOL notNull;
} Direct;

#define DirectZero ((Direct){0, 0, 0, 0, NO})

typedef struct ZMJRectEdge {
    //top || bottom
    Direct top;
    Direct bottom;
    
    //left || right
    Direct left;
    Direct right;
    BOOL notNull;
} RectEdge;


/**
RectEdgeDirection
 - RectEdgeDirectionUp: 0
 - RectEdgeDirectionDown: 1
 - RectEdgeDirectionLeft: 2
 - RectEdgeDirectionRight: 3
 */
typedef NS_ENUM(NSUInteger, RectEdgeDirection) {
    RectEdgeDirectionUp = 0,
    RectEdgeDirectionDown,
    RectEdgeDirectionLeft,
    RectEdgeDirectionRight,
};

/**
 DescriptionRectEdgeMake
 @param direction RectEdgeDirection
 @param top       Direct.top
 @param left      Direct.left
 @param bottom    Direct.bottom
 @param right     Direct.right
 @return create   RectEdge with direction
 */
static inline RectEdge
RectEdgeMake(RectEdgeDirection direction, CGFloat top, CGFloat left, CGFloat bottom, CGFloat right)
{
    RectEdge edge;
    BOOL notnull = NO;
    if (direction == RectEdgeDirectionUp) {
        Direct d_top;
        d_top.top   = top;
        d_top.left  = left;
        d_top.bottom= bottom;
        d_top.right = right;
        d_top.notNull = YES;
        edge.top    = d_top;
        edge.bottom = DirectZero;
        edge.left   = DirectZero;
        edge.right  = DirectZero;
        notnull = YES;
    }
    if (direction == RectEdgeDirectionLeft) {
        Direct d_left;
        d_left.top   = top;
        d_left.left  = left;
        d_left.bottom= bottom;
        d_left.right = right;
        d_left.notNull = YES;
        edge.left   = d_left;
        edge.bottom = DirectZero;
        edge.top    = DirectZero;
        edge.right  = DirectZero;
        notnull = YES;
    }
    if (direction == RectEdgeDirectionRight) {
        Direct d_right;
        d_right.top   = top;
        d_right.left  = left;
        d_right.bottom= bottom;
        d_right.right = right;
        d_right.notNull = YES;
        edge.right  = d_right;
        edge.bottom = DirectZero;
        edge.left   = DirectZero;
        edge.top    = DirectZero;
        notnull = YES;
    }
    if (direction == RectEdgeDirectionDown) {
        Direct d_bottom;
        d_bottom.top   = top;
        d_bottom.left  = left;
        d_bottom.bottom= bottom;
        d_bottom.right = right;
        d_bottom.notNull = YES;
        edge.bottom = d_bottom;
        edge.top    = DirectZero;
        edge.left   = DirectZero;
        edge.right  = DirectZero;
        notnull = YES;
    }
    edge.notNull = notnull;
    return edge;
}

static inline BOOL
RectEdgeEqualToRectEdge(RectEdge rectEdge1, RectEdge rectEdge2)
{
    return
    rectEdge1.top.top == rectEdge2.top.top &&
    rectEdge1.top.left == rectEdge2.top.left &&
    rectEdge1.top.right == rectEdge2.top.right &&
    rectEdge1.top.bottom == rectEdge2.top.bottom &&
    
    rectEdge1.bottom.top == rectEdge2.bottom.top &&
    rectEdge1.bottom.left == rectEdge2.bottom.left &&
    rectEdge1.bottom.right == rectEdge2.bottom.right &&
    rectEdge1.bottom.bottom == rectEdge2.bottom.bottom &&
    
    rectEdge1.left.top == rectEdge2.left.top &&
    rectEdge1.left.left == rectEdge2.left.left &&
    rectEdge1.left.right == rectEdge2.left.right &&
    rectEdge1.left.bottom == rectEdge2.left.bottom &&
    
    rectEdge1.right.top == rectEdge2.right.top &&
    rectEdge1.right.left == rectEdge2.right.left &&
    rectEdge1.right.right == rectEdge2.right.right &&
    rectEdge1.right.bottom == rectEdge2.right.bottom;
}

static inline NSString *
RectEdgeDescription(RectEdge rectEdge)
{
    if (rectEdge.notNull == YES) {
        if (rectEdge.top.notNull == YES) {
            return [NSString stringWithFormat:@"Top: t:%ld,l:%ld,b:%ld,r:%ld",
                    (long)rectEdge.top.top,
                    (long)rectEdge.top.left,
                    (long)rectEdge.top.bottom,
                    (long)rectEdge.top.right];
        }
        if (rectEdge.bottom.notNull == YES) {
            return [NSString stringWithFormat:@"Bottom: t:%ld,l:%ld,b:%ld,r:%ld",
                    (long)rectEdge.bottom.top,
                    (long)rectEdge.bottom.left,
                    (long)rectEdge.bottom.bottom,
                    (long)rectEdge.bottom.right];
        }
        if (rectEdge.left.notNull == YES) {
            return [NSString stringWithFormat:@"Left: t:%ld,l:%ld,b:%ld,r:%ld",
                    (long)rectEdge.left.top,
                    (long)rectEdge.left.left,
                    (long)rectEdge.left.bottom,
                    (long)rectEdge.left.right];
        }
        if (rectEdge.right.notNull == YES) {
            return [NSString stringWithFormat:@"Right: t:%ld,l:%ld,b:%ld,r:%ld",
                    (long)rectEdge.right.top,
                    (long)rectEdge.right.left,
                    (long)rectEdge.right.bottom,
                    (long)rectEdge.right.right];
        }
    }
    return @"null";
}

typedef struct ZMJLayoutAttributes {
    NSInteger startColumn;
    NSInteger startRow;
    NSInteger numberOfColumns;
    NSInteger numberOfRows;
    NSInteger columnCount;
    NSInteger rowCount;
    CGPoint insets;
} LayoutAttributes;

typedef NS_OPTIONS(NSUInteger, ZMJDirection) {
    Direction_vertically   = 1 << 0,
    Direction_horizontally = 1 << 1,
    Direction_both         = Direction_vertically | Direction_horizontally,
};

typedef NS_OPTIONS(NSUInteger, ZMJTableStyle) {
    TableStyle_columnHeaderNotRepeated  = 1 << 0,
    TableStyle_rowHeaderNotRepeated     = 1 << 1,
};

typedef NS_ENUM(NSUInteger, ZMJHeaderStyle) {
    HeaderStyle_none,
    HeaderStyle_columnHeaderStartsFirstRow,
    HeaderStyle_rowHeaderStartsFirstColumn,
};


#endif /* Define_h */


<|start_filename|>Example/ZMJGanttList/ZMJTask.h<|end_filename|>
//
//  ZMJTask.h
//  ZMJGanttList
//
//  Created by Jason on 2018/2/27.
//  Copyright © 2018年 keshiim. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface ZMJTask : NSObject
/// lol
@property (copy, nonatomic) NSString * taskName;

/// 任务描述 - description
@property (copy, nonatomic) NSString * taskDesc;

/// 发起人
@property (strong, nonatomic) NSString *createdByUser;

/// 发起时间
@property (copy, nonatomic) NSString * createdAt;

/// start
@property (copy, nonatomic) NSDate * startDate;
/// due
@property (copy, nonatomic) NSDate * dueDate;

+ (instancetype)taskWithName:(NSString *)taskName startDate:(NSDate *)startDate endDate:(NSDate *)endDate;
@end


<|start_filename|>ZMJGanttChart/Classes/SpreadsheetView+Touches.h<|end_filename|>
//
//  SpreadsheetView+Touches.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/24.
//

#import "SpreadsheetView.h"

@interface SpreadsheetView (Touches)
- (void)touchesBegan:(NSSet<UITouch *> *)touches event:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches event:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches event:(UIEvent *)event;

- (void)restorePreviousSelection;
- (void)clearCurrentTouch;


@end


<|start_filename|>Example/Pods/Target Support Files/ZMJGanttChart-iOS9.3/ZMJGanttChart-iOS9.3-umbrella.h<|end_filename|>
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif

#import "Address.h"
#import "Borders.h"
#import "CircualrScrolling.h"
#import "Define.h"
#import "Gridlines.h"
#import "Location.h"
#import "NSArray+BinarySearch.h"
#import "NSArray+WBGAddition.h"
#import "NSDictionary+WBGAdd.h"
#import "NSIndexPath+column.h"
#import "ReuseQueue.h"
#import "SpreadsheetView+CirclularScrolling.h"
#import "SpreadsheetView+Layout.h"
#import "SpreadsheetView+Touches.h"
#import "SpreadsheetView+UIScrollView.h"
#import "SpreadsheetView+UIScrollViewDelegate.h"
#import "SpreadsheetView+UISnapshotting.h"
#import "SpreadsheetView+UIViewHierarchy.h"
#import "SpreadsheetView.h"
#import "SpreadsheetViewDataSource.h"
#import "SpreadsheetViewDelegate.h"
#import "ZMJCell.h"
#import "ZMJCellRange.h"
#import "ZMJGanttChart.h"
#import "ZMJLayoutEngine.h"
#import "ZMJScrollView.h"

FOUNDATION_EXPORT double ZMJGanttChartVersionNumber;
FOUNDATION_EXPORT const unsigned char ZMJGanttChartVersionString[];



<|start_filename|>Example/ZMJTimeable/ZMJCells.h<|end_filename|>
//
//  ZMJCells.h
//  ZMJTimeable
//
//  Created by Jason on 2018/2/5.
//  Copyright © 2018年 keshiim. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <ZMJGanttChart/ZMJGanttChart.h>

@interface HourCell : ZMJCell
@property (nonatomic, strong) UILabel *label;
@end

@interface ChannelCell: ZMJCell
@property (nonatomic, strong) UILabel  *label;
@property (nonatomic, strong) NSString *channel;
@end

@interface SlotCell: ZMJCell
@property (weak, nonatomic) IBOutlet UILabel *minutesLabel;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *tableHighlightLabel;

@property (nonatomic, assign) NSInteger minutes;
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *tableHighlight;

@end

@interface MyBlankCell: BlankCell

@end


<|start_filename|>ZMJGanttChart/Classes/ZMJCellRange.h<|end_filename|>
//
//  ZMJCellRange.h
//  Pods
//
//  Created by Jason on 2018/1/19.
//

#import <Foundation/Foundation.h>
#import "Location.h"

@interface ZMJCellRange : NSObject

@property (nonatomic, strong, readonly) Location *from;
@property (nonatomic, strong, readonly) Location *to;

@property (nonatomic, assign, readonly) NSInteger columnCount;
@property (nonatomic, assign, readonly) NSInteger rowCount;

@property (nonatomic, assign) CGSize size;

+ (instancetype)cellRangeFrom:(Location *)from to:(Location *)to;

- (instancetype)initFromRow:(NSInteger)fromRow fromColumn:(NSInteger)fromColumn toRow:(NSInteger)toRow toColumn:(NSInteger)toColumn;
- (instancetype)initFromIndex:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath;

- (BOOL)containsIndexPath:(NSIndexPath *)indexPath;
- (BOOL)containsCellRange:(ZMJCellRange *)cellRange;
@end


<|start_filename|>ZMJGanttChart/Classes/NSDictionary+WBGAdd.h<|end_filename|>
//
//  NSDictionary+WBGAdd.h
//  WBGNetworkingDemo
//
//  Created by LiMing on 16/7/6.
//  Copyright © 2016年 LiMing. All rights reserved.
//

#import <Foundation/Foundation.h>

#ifndef WBG_WARN_RESULT_UNUSED
#define WBG_WARN_RESULT_UNUSED __attribute__((warn_unused_result))
#endif

NS_ASSUME_NONNULL_BEGIN

// 1.扩展NSDictionary+YYAdd的方法应用范围
// 2.支持通过多级路径访问NSDictionary中的数值, 如:路径"report/0/id"，表示返回关键字为"report"下的0号位置的"id"字段

@interface NSDictionary<KeyType, ObjectType> (WBGAdd)

typedef void(^WBGDictionaryReturnBlock)(KeyType key, ObjectType obj);

// 扩展YYKit
- (nullable NSDictionary *)dictionaryValueForKey:(NSString *)key default:(nullable NSDictionary *)def;
- (nullable NSArray *)arrayValueForKey:(NSString *)key default:(nullable NSArray *)def;
- (nullable NSDate *)dateValueForKey:(NSString *)key default:(nullable NSDate *)def;
- (nullable id)blockValueForKey:(NSString *)key default:(nullable id)def;

/// match * for kind == nil
- (nullable ObjectType)valueForKey:(NSString *)key ofKind:(nullable Class)kind default:(nullable id)def;

// 多级路径匹配

- (BOOL)boolValueForPath:(NSString *)path default:(BOOL)def;

- (char)charValueForPath:(NSString *)path default:(char)def;
- (unsigned char)unsignedCharValueForPath:(NSString *)path default:(unsigned char)def;

- (short)shortValueForPath:(NSString *)path default:(short)def;
- (unsigned short)unsignedShortValueForPath:(NSString *)path default:(unsigned short)def;

- (int)intValueForPath:(NSString *)path default:(int)def;
- (unsigned int)unsignedIntValueForPath:(NSString *)path default:(unsigned int)def;

- (long)longValueForPath:(NSString *)path default:(long)def;
- (unsigned long)unsignedLongValueForPath:(NSString *)path default:(unsigned long)def;

- (long long)longLongValueForPath:(NSString *)path default:(long long)def;
- (unsigned long long)unsignedLongLongValueForPath:(NSString *)path default:(unsigned long long)def;

- (float)floatValueForPath:(NSString *)path default:(float)def;
- (double)doubleValueForPath:(NSString *)path default:(double)def;

- (NSInteger)integerValueForPath:(NSString *)path default:(NSInteger)def;
- (NSUInteger)unsignedIntegerValueForPath:(NSString *)path default:(NSUInteger)def;

- (nullable NSNumber *)numberValueForPath:(NSString *)path default:(nullable NSNumber *)def;
- (nullable NSString *)stringValueForPath:(NSString *)path default:(nullable NSString *)def;

- (nullable NSDictionary *)dictionaryValueForPath:(NSString *)path default:(nullable NSDictionary *)def;
- (nullable NSArray *)arrayValueForPath:(NSString *)path default:(nullable NSArray *)def;

- (nullable NSDate *)dateValueForPath:(NSString *)path default:(nullable NSDate *)def;
- (nullable id)blockValueForPath:(NSString *)path default:(nullable id)def;

// 缺省默认值
- (nonnull NSDictionary *)dictionaryValueForPath:(NSString *)path;  // 默认值为@{}
- (nonnull NSArray *)arrayValueForPath:(NSString *)path;            // 默认值为@[]
- (nonnull NSString *)stringValueForPath:(NSString *)path;          // 默认值为@""
- (nonnull NSDictionary *)dictionaryValueForKey:(NSString *)key;    // 默认值为@{}
- (nonnull NSArray *)arrayValueForKey:(NSString *)key;              // 默认值为@[]
- (nonnull NSString *)stringValueForKey:(NSString *)key;            // 默认值为@""


# pragma mark - Array Like

- (NSDictionary *)wbg_map:(void (^)(KeyType key, ObjectType obj, WBGDictionaryReturnBlock returnBlock))block WBG_WARN_RESULT_UNUSED;

- (NSDictionary<KeyType, ObjectType> *)wbg_filter:(BOOL (^)(KeyType key, ObjectType obj))block WBG_WARN_RESULT_UNUSED;

+ (NSDictionary<KeyType, ObjectType> *)wbg_forIn:(NSInteger)count block:(void (^)(NSInteger idx, WBGDictionaryReturnBlock returnBlock))block WBG_WARN_RESULT_UNUSED;

/**
 把一个字典map成array

 @param block 用这个block把key和obj加工成要放到数组里的东西
 @return map完了之后的数组
 */
- (NSArray<id> *)wbg_toArray:(id (^)(KeyType key, ObjectType obj))block WBG_WARN_RESULT_UNUSED;

/**
 给一个字典append上一个key value

 @param anObject anObject
 @param aKey aKey
 @return 新append过的字典
 */
- (NSDictionary<KeyType, ObjectType> *)wbg_dictionaryBySettingObject:(ObjectType)anObject forKey:(KeyType <NSCopying>)aKey WBG_WARN_RESULT_UNUSED;

/**
 把字典里所有NSNull都去掉

 @return 新📙
 */
@property (nonatomic, readonly, nonnull) NSDictionary<KeyType, ObjectType> *wbg_dictionaryByRemovingNSNull;

@end

@interface NSMutableDictionary<KeyType, ObjectType> (WBGAdd)

/// If 'anObject' or 'aKey' is nil or NSNull, then ignore this operation
- (void)setSafeObject:(ObjectType)anObject forKey:(KeyType)aKey;

/// If integer == defaultValue, then ignore this operation
/// dict[aKey] = string(integer)
- (void)setSafeInteger:(NSInteger)integer forKey:(KeyType)aKey defaultValue:(NSInteger)defaultValue;

/// use milliseconds as date value
- (void)setSafeDate:(NSDate *)date forKey:(KeyType)aKey;

/**
 设小数

 @param precision 精确到小数点后几位
 */
- (void)setDouble:(double)aDouble precision:(NSUInteger)precision forKey:(KeyType)aKey;

@end

NS_ASSUME_NONNULL_END


<|start_filename|>ZMJGanttChart/Classes/NSArray+BinarySearch.h<|end_filename|>
//
//  NSArray+BinarySearch.h
//  ZMJGanttChart
//
//  Created by Jason on 2018/1/19.
//

#import <Foundation/Foundation.h>

@interface NSArray<__covariant ObjectType> (BinarySearch)

- (NSInteger)insertionIndexOfObject:(ObjectType)element;

@end
