Mercurial > dwindows
comparison ios/dw.m @ 2765:f734185664cc
iOS: Initial tree view implementation for iOS.
Still needs a lot of work, callbacks not implemented.
Root node needs to be hidden from view.
author | bsmith@81767d24-ef19-dc11-ae90-00e081727c95 |
---|---|
date | Thu, 07 Apr 2022 21:54:35 +0000 |
parents | 4c602db2d2cf |
children | 9b9bc2c2bbad |
comparison
equal
deleted
inserted
replaced
2764:4c602db2d2cf | 2765:f734185664cc |
---|---|
2 * Dynamic Windows: | 2 * Dynamic Windows: |
3 * A GTK like implementation of the iOS GUI | 3 * A GTK like implementation of the iOS GUI |
4 * | 4 * |
5 * (C) 2011-2022 Brian Smith <brian@dbsoft.org> | 5 * (C) 2011-2022 Brian Smith <brian@dbsoft.org> |
6 * (C) 2011-2021 Mark Hessling <mark@rexx.org> | 6 * (C) 2011-2021 Mark Hessling <mark@rexx.org> |
7 * (C) 2017 Ralph Shane (Base tree view implementation) | |
7 * | 8 * |
8 * Requires 13.0 or later. | 9 * Requires 13.0 or later. |
9 * clang -g -o dwtest -D__IOS__ -I. dwtest.c ios/dw.m -framework UIKit -framework WebKit -framework Foundation -framework UserNotifications | 10 * clang -g -o dwtest -D__IOS__ -I. dwtest.c ios/dw.m -framework UIKit -framework WebKit -framework Foundation -framework UserNotifications |
10 */ | 11 */ |
11 #import <Foundation/Foundation.h> | 12 #import <Foundation/Foundation.h> |
1597 @end | 1598 @end |
1598 | 1599 |
1599 #define _DW_BUTTON_TYPE_NORMAL 0 | 1600 #define _DW_BUTTON_TYPE_NORMAL 0 |
1600 #define _DW_BUTTON_TYPE_CHECK 1 | 1601 #define _DW_BUTTON_TYPE_CHECK 1 |
1601 #define _DW_BUTTON_TYPE_RADIO 2 | 1602 #define _DW_BUTTON_TYPE_RADIO 2 |
1603 #define _DW_BUTTON_TYPE_TREE 3 | |
1602 | 1604 |
1603 /* Subclass for a button type */ | 1605 /* Subclass for a button type */ |
1604 @interface DWButton : UIButton | 1606 @interface DWButton : UIButton |
1605 { | 1607 { |
1606 void *userdata; | 1608 void *userdata; |
1607 DWBox *parent; | 1609 DWBox *parent; |
1608 int type, checkstate; | 1610 int type, checkstate; |
1609 } | 1611 } |
1612 @property(nonatomic, strong) void(^didCheckedChanged)(BOOL checked); | |
1610 -(void *)userdata; | 1613 -(void *)userdata; |
1611 -(void)setUserdata:(void *)input; | 1614 -(void)setUserdata:(void *)input; |
1612 -(void)buttonClicked:(id)sender; | 1615 -(void)buttonClicked:(id)sender; |
1613 -(void)setParent:(DWBox *)input; | 1616 -(void)setParent:(DWBox *)input; |
1614 -(DWBox *)parent; | 1617 -(DWBox *)parent; |
1622 -(void *)userdata { return userdata; } | 1625 -(void *)userdata { return userdata; } |
1623 -(void)setUserdata:(void *)input { userdata = input; } | 1626 -(void)setUserdata:(void *)input { userdata = input; } |
1624 -(void)buttonClicked:(id)sender | 1627 -(void)buttonClicked:(id)sender |
1625 { | 1628 { |
1626 /* Toggle the button */ | 1629 /* Toggle the button */ |
1627 if(type == _DW_BUTTON_TYPE_CHECK) | 1630 if(type == _DW_BUTTON_TYPE_CHECK || type == _DW_BUTTON_TYPE_TREE) |
1628 [self setCheckState:(checkstate ? FALSE : TRUE)]; | 1631 [self setCheckState:(checkstate ? FALSE : TRUE)]; |
1629 else if(type == _DW_BUTTON_TYPE_RADIO) | 1632 else if(type == _DW_BUTTON_TYPE_RADIO) |
1630 [self setCheckState:TRUE]; | 1633 [self setCheckState:TRUE]; |
1631 | 1634 |
1632 _dw_event_handler(self, nil, _DW_EVENT_CLICKED); | 1635 _dw_event_handler(self, nil, _DW_EVENT_CLICKED); |
1654 } | 1657 } |
1655 } | 1658 } |
1656 } | 1659 } |
1657 } | 1660 } |
1658 } | 1661 } |
1662 if(_didCheckedChanged) | |
1663 _didCheckedChanged(checkstate); | |
1659 } | 1664 } |
1660 -(void)setParent:(DWBox *)input { parent = input; } | 1665 -(void)setParent:(DWBox *)input { parent = input; } |
1661 -(DWBox *)parent { return parent; } | 1666 -(DWBox *)parent { return parent; } |
1662 -(int)type { return type; } | 1667 -(int)type { return type; } |
1663 -(void)setType:(int)input | 1668 -(void)setType:(int)input |
1688 { | 1693 { |
1689 if(checkstate) | 1694 if(checkstate) |
1690 imagename = @"largecircle.fill.circle"; | 1695 imagename = @"largecircle.fill.circle"; |
1691 else | 1696 else |
1692 imagename = @"circle"; | 1697 imagename = @"circle"; |
1698 } | |
1699 break; | |
1700 case _DW_BUTTON_TYPE_TREE: | |
1701 { | |
1702 if(checkstate) | |
1703 imagename = @"chevron.down"; | |
1704 else | |
1705 imagename = @"chevron.forward"; | |
1693 } | 1706 } |
1694 break; | 1707 break; |
1695 } | 1708 } |
1696 if(imagename) | 1709 if(imagename) |
1697 { | 1710 { |
2641 { | 2654 { |
2642 if([self allowsMultipleSelection]) | 2655 if([self allowsMultipleSelection]) |
2643 [self tableView:tableView didSelectRowAtIndexPath:indexPath]; | 2656 [self tableView:tableView didSelectRowAtIndexPath:indexPath]; |
2644 } | 2657 } |
2645 -(void)dealloc { UserData *root = userdata; _dw_remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | 2658 -(void)dealloc { UserData *root = userdata; _dw_remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } |
2659 @end | |
2660 | |
2661 /* Custom tree view subclasses: DWTree, DWTreeItem, DWTreeViewCell, DWTreeViewCellDelegate */ | |
2662 @interface DWTreeItem : NSObject | |
2663 @property(nonatomic, strong) UIImage *icon; | |
2664 @property(nonatomic, strong) NSString *title; | |
2665 @property(nonatomic, assign) void *data; | |
2666 @property(nonatomic, weak) DWTreeItem *parent; | |
2667 @property(nonatomic, retain, readonly) NSMutableArray<DWTreeItem *> *children; | |
2668 @property(nonatomic, assign, readonly) NSUInteger levelDepth; | |
2669 @property(nonatomic, assign, readonly) BOOL isRoot; | |
2670 @property(nonatomic, assign, readonly) BOOL hasChildren; | |
2671 @property(nonatomic, assign) BOOL expanded; | |
2672 -(instancetype)initWithIcon:(UIImage *)icon Title:(NSString *)title andData:(void *)itemdata; | |
2673 -(void)insertChildAfter:(DWTreeItem *)treeItem; | |
2674 -(void)appendChild:(DWTreeItem *)newChild; | |
2675 -(void)removeFromParent; | |
2676 -(void)moveToDestination:(DWTreeItem *)destination; | |
2677 -(BOOL)containsTreeItem:(DWTreeItem *)treeItem; | |
2678 -(NSArray<DWTreeItem *> *)visibleNodes; | |
2679 @end | |
2680 | |
2681 @implementation DWTreeItem | |
2682 { | |
2683 NSArray *_flattenedTreeCache; | |
2684 } | |
2685 -(void)dealloc { NSLog(@"DWTreeItem \"%@\" dealloc", self.title); [_title release]; [_icon release]; [super dealloc]; } | |
2686 -(instancetype)initWithIcon:(UIImage *)icon Title:(NSString *)title andData:(void *)itemdata | |
2687 { | |
2688 if(self = [super init]) | |
2689 { | |
2690 _title = [title retain]; | |
2691 _icon = [icon retain]; | |
2692 _data = itemdata; | |
2693 _children = [[NSMutableArray alloc] initWithCapacity:1]; | |
2694 } | |
2695 return self; | |
2696 } | |
2697 -(NSString *)title | |
2698 { | |
2699 if(_title) | |
2700 return _title; | |
2701 return self.description; | |
2702 } | |
2703 -(UIImage *)icon | |
2704 { | |
2705 if(_icon) | |
2706 return _icon; | |
2707 return nil; | |
2708 } | |
2709 -(NSArray<DWTreeItem *> *)visibleNodes | |
2710 { | |
2711 NSMutableArray *allElements = [[NSMutableArray alloc] init]; | |
2712 [allElements addObject:self]; | |
2713 if(_expanded) | |
2714 { | |
2715 for (DWTreeItem *child in _children) | |
2716 [allElements addObjectsFromArray:[child visibleNodes]]; | |
2717 } | |
2718 return allElements; | |
2719 } | |
2720 -(void)insertChildAfter:(DWTreeItem *)treeItem | |
2721 { | |
2722 DWTreeItem *parent = self.parent; | |
2723 NSUInteger index = [parent.children indexOfObject:self]; | |
2724 if(index == NSNotFound) | |
2725 index = [parent.children count]; | |
2726 treeItem.parent = parent; | |
2727 [parent.children insertObject:treeItem atIndex:(index+1)]; | |
2728 } | |
2729 -(void)appendChild:(DWTreeItem *)newChild | |
2730 { | |
2731 newChild.parent = self; | |
2732 [_children addObject:newChild]; | |
2733 } | |
2734 -(void)removeFromParent | |
2735 { | |
2736 DWTreeItem *parent = self.parent; | |
2737 if(parent) | |
2738 { | |
2739 [parent.children removeObject:self]; | |
2740 self.parent = nil; | |
2741 } | |
2742 } | |
2743 -(void)moveToDestination:(DWTreeItem *)destination | |
2744 { | |
2745 NSAssert([self containsTreeItem:destination]==NO, @"[self containsTreeItem:destination] something went wrong!"); | |
2746 if(self == destination || destination == nil) | |
2747 return; | |
2748 [self removeFromParent]; | |
2749 | |
2750 [destination insertChildAfter:self]; | |
2751 } | |
2752 -(BOOL)containsTreeItem:(DWTreeItem *)treeItem | |
2753 { | |
2754 DWTreeItem *parent = treeItem.parent; | |
2755 if(parent == nil) | |
2756 return NO; | |
2757 if(self == parent) | |
2758 return YES; | |
2759 return [self containsTreeItem:parent]; | |
2760 } | |
2761 -(NSUInteger)levelDepth | |
2762 { | |
2763 NSUInteger cnt = 0; | |
2764 if(_parent != nil) | |
2765 { | |
2766 cnt += 1; | |
2767 cnt += [_parent levelDepth]; | |
2768 } | |
2769 return cnt; | |
2770 } | |
2771 -(BOOL)isRoot { return (!_parent); } | |
2772 -(BOOL)hasChildren { return (_children.count > 0); } | |
2773 @end | |
2774 | |
2775 @class DWTreeViewCell; | |
2776 @protocol DWTreeViewCellDelegate <NSObject> | |
2777 //@optional | |
2778 - (BOOL) queryExpandableInTreeViewCell:(DWTreeViewCell *)treeViewCell; | |
2779 - (void) treeViewCell:(DWTreeViewCell *)treeViewCell expanded:(BOOL)expanded; | |
2780 @end | |
2781 | |
2782 @interface DWTreeViewCell : UITableViewCell | |
2783 @property(nonatomic, strong) UILabel *titleLabel; | |
2784 @property(nonatomic) NSUInteger level; | |
2785 @property(nonatomic) BOOL expanded; | |
2786 @property(nonatomic) BOOL isFolder; | |
2787 @property(nonatomic, assign) id <DWTreeViewCellDelegate> delegate; | |
2788 -(instancetype)initWithStyle:(UITableViewCellStyle)style | |
2789 reuseIdentifier:(NSString *)reuseIdentifier | |
2790 level:(NSUInteger)level | |
2791 expanded:(BOOL)expanded; | |
2792 @end | |
2793 | |
2794 CGRect DWRectInflate(CGRect rect, CGFloat dx, CGFloat dy) | |
2795 { | |
2796 return CGRectMake(rect.origin.x-dx, rect.origin.y-dy, rect.size.width+2*dx, rect.size.height+2*dy); | |
2797 } | |
2798 | |
2799 static CGFloat IMG_HEIGHT_WIDTH = 20; | |
2800 static CGFloat XOFFSET = 3; | |
2801 | |
2802 @implementation DWTreeViewCell | |
2803 { | |
2804 DWButton *_arrowImageButton; | |
2805 UIImageView *_itemImage; | |
2806 } | |
2807 -(id)initWithStyle:(UITableViewCellStyle)style | |
2808 reuseIdentifier:(NSString *)reuseIdentifier | |
2809 level:(NSUInteger)level | |
2810 expanded:(BOOL)expanded | |
2811 { | |
2812 self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; | |
2813 | |
2814 if(self) | |
2815 { | |
2816 _level = level; | |
2817 _expanded = expanded; | |
2818 | |
2819 UIView *content = self.contentView; | |
2820 | |
2821 UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; | |
2822 titleLabel.lineBreakMode = NSLineBreakByWordWrapping; | |
2823 titleLabel.numberOfLines = 0; | |
2824 titleLabel.textAlignment = NSTextAlignmentLeft; | |
2825 [content addSubview:titleLabel]; | |
2826 _titleLabel = titleLabel; | |
2827 | |
2828 UIImageView *itemImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, IMG_HEIGHT_WIDTH, IMG_HEIGHT_WIDTH)]; | |
2829 [content addSubview:itemImage]; | |
2830 _itemImage = itemImage; | |
2831 | |
2832 DWButton *arrowImageButton = [[DWButton alloc] initWithFrame:CGRectMake(0, 0, IMG_HEIGHT_WIDTH, IMG_HEIGHT_WIDTH)]; | |
2833 [arrowImageButton setType:_DW_BUTTON_TYPE_TREE]; | |
2834 [arrowImageButton setDidCheckedChanged:^(BOOL checked) { | |
2835 _expanded = checked; | |
2836 if([_delegate respondsToSelector:@selector(treeViewCell:expanded:)]) | |
2837 [_delegate treeViewCell:self expanded:checked]; | |
2838 }]; | |
2839 [arrowImageButton setCheckState:_expanded]; | |
2840 [content addSubview:arrowImageButton]; | |
2841 _arrowImageButton = arrowImageButton; | |
2842 } | |
2843 return self; | |
2844 } | |
2845 #pragma mark - | |
2846 #pragma mark Other overrides | |
2847 -(void)layoutSubviews | |
2848 { | |
2849 [super layoutSubviews]; | |
2850 | |
2851 CGSize size = self.contentView.bounds.size; | |
2852 CGFloat stepSize = size.height; | |
2853 CGRect rc = CGRectMake(_level * stepSize, 0, stepSize, stepSize); | |
2854 _arrowImageButton.frame = DWRectInflate(rc, -XOFFSET, -XOFFSET); | |
2855 | |
2856 rc = CGRectMake((_level + 1) * stepSize, 0, stepSize, stepSize); | |
2857 _itemImage.frame = DWRectInflate(rc, -XOFFSET, -XOFFSET); | |
2858 _titleLabel.frame = CGRectMake((_level + 2) * stepSize, 0, size.width - (_level + 3) * stepSize, stepSize); | |
2859 } | |
2860 @end | |
2861 | |
2862 @class DWTree; | |
2863 | |
2864 @protocol DWTreeViewDelegate <NSObject> | |
2865 @required | |
2866 -(NSInteger)numberOfRowsInTreeView:(DWTree *)treeView; | |
2867 -(DWTreeItem *)treeView:(DWTree *)treeView treeItemForRow:(NSInteger)row; | |
2868 -(NSInteger)treeView:(DWTree *)treeView rowForTreeItem:(DWTreeItem *)treeItem; | |
2869 -(void)treeView:(DWTree *)treeView removeTreeItem:(DWTreeItem *)treeItem; | |
2870 -(void)treeView:(DWTree *)treeView moveTreeItem:(DWTreeItem *)treeItem to:(DWTreeItem *)to; | |
2871 -(void)treeView:(DWTree *)treeView addTreeItem:(DWTreeItem *)treeItem; | |
2872 //@optional | |
2873 -(void)treeView:(DWTree *)treeView didSelectForTreeItem:(DWTreeItem *)treeItem; | |
2874 -(BOOL)treeView:(DWTree *)treeView queryExpandableInTreeItem:(DWTreeItem *)treeItem; | |
2875 -(void)treeView:(DWTree *)treeView treeItem:(DWTreeItem *)treeItem expanded:(BOOL)expanded; | |
2876 @optional | |
2877 -(BOOL)treeView:(DWTree *)treeView canEditTreeItem:(DWTreeItem *)treeItem; | |
2878 -(BOOL)treeView:(DWTree *)treeView canMoveTreeItem:(DWTreeItem *)treeItem; | |
2879 @end | |
2880 | |
2881 @interface DWTree : UITableView | |
2882 @property(nonatomic, strong) UIFont *font; | |
2883 @property(nonatomic, strong) DWTreeItem *treeItem; | |
2884 @property(nonatomic, weak) id<DWTreeViewDelegate> treeViewDelegate; | |
2885 -(instancetype)initWithFrame:(CGRect)frame; | |
2886 -(void)insertTreeItem:(DWTreeItem *)treeItem; | |
2887 @end | |
2888 | |
2889 @interface DWTree () <UITableViewDataSource, UITableViewDelegate, DWTreeViewCellDelegate, DWTreeViewDelegate> | |
2890 @end | |
2891 | |
2892 @implementation DWTree | |
2893 { | |
2894 DWTreeItem *_rootNode; | |
2895 DWTreeItem *_selectedNode; | |
2896 } | |
2897 -(instancetype)initWithFrame:(CGRect)frame | |
2898 { | |
2899 if(self = [super initWithFrame:frame]) | |
2900 { | |
2901 self.delegate=self; | |
2902 self.dataSource=self; | |
2903 _treeViewDelegate=self; | |
2904 self.separatorStyle= UITableViewCellSeparatorStyleNone; | |
2905 _font = [UIFont systemFontOfSize:16]; | |
2906 _rootNode = [[[DWTreeItem alloc] initWithIcon:nil Title:@"@Root" andData:NULL] retain]; | |
2907 _rootNode.expanded = YES; | |
2908 } | |
2909 return self; | |
2910 } | |
2911 -(void)dealloc { [_rootNode release]; [super dealloc]; } | |
2912 -(void)insertTreeItem:(DWTreeItem *)treeItem | |
2913 { | |
2914 DWTreeItem *targetNode = nil; | |
2915 | |
2916 NSArray<DWTreeViewCell *> *cells = [self visibleCells]; | |
2917 | |
2918 // Target the selected tree node first if any | |
2919 for(DWTreeViewCell *cell in cells) | |
2920 { | |
2921 DWTreeItem *iter = [self treeItemForTreeViewCell:cell]; | |
2922 if(iter == _selectedNode) | |
2923 { | |
2924 targetNode = iter; | |
2925 break; | |
2926 } | |
2927 } | |
2928 // Otherwise target first visible node if any | |
2929 if(targetNode == nil && [cells count]) | |
2930 targetNode = [self treeItemForTreeViewCell:cells[0]]; | |
2931 // Finally put it on the root level | |
2932 if(targetNode == nil) | |
2933 targetNode = _rootNode; | |
2934 // If target is still nil something went horrible wrong | |
2935 NSAssert(targetNode, @"targetNode == nil, something went wrong!"); | |
2936 [targetNode insertChildAfter:treeItem]; | |
2937 | |
2938 if([_treeViewDelegate respondsToSelector:@selector(treeView:addTreeItem:)]) | |
2939 [_treeViewDelegate treeView:self addTreeItem:treeItem]; | |
2940 | |
2941 [self reloadData]; | |
2942 [self resetSelection:NO]; | |
2943 } | |
2944 -(void)setFont:(UIFont *)font | |
2945 { | |
2946 _font = font; | |
2947 [self reloadData]; | |
2948 [self resetSelection:NO]; | |
2949 } | |
2950 -(void)resetSelection:(BOOL)delay | |
2951 { | |
2952 NSInteger row = NSNotFound; | |
2953 if([_treeViewDelegate respondsToSelector:@selector(treeView:rowForTreeItem:)]) | |
2954 row = [_treeViewDelegate treeView:self rowForTreeItem:_selectedNode]; | |
2955 if(row != NSNotFound) | |
2956 { | |
2957 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0]; | |
2958 dispatch_block_t run = ^ { | |
2959 [self selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; | |
2960 }; | |
2961 if(delay) | |
2962 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), run); | |
2963 else | |
2964 run(); | |
2965 } | |
2966 } | |
2967 #pragma mark - DWTreeViewDelegate | |
2968 -(NSInteger)numberOfRowsInTreeView:(DWTree *)treeView { return [_rootNode visibleNodes].count; } | |
2969 -(void)treeView:(DWTree *)treeView addTreeItem:(DWTreeItem *)treeItem {} | |
2970 -(void)treeView:(DWTree *)treeView didSelectForTreeItem:(DWTreeItem *)treeItem {} | |
2971 -(void)treeView:(DWTree *)treeView moveTreeItem:(DWTreeItem *)treeItem to:(DWTreeItem *)to {} | |
2972 -(BOOL)treeView:(DWTree *)treeView queryExpandableInTreeItem:(DWTreeItem *)treeItem { return YES; } | |
2973 -(void)treeView:(DWTree *)treeView removeTreeItem:(DWTreeItem *)treeItem {} | |
2974 -(NSInteger)treeView:(DWTree *)treeView rowForTreeItem:(DWTreeItem *)treeItem { return [[_rootNode visibleNodes] indexOfObject:treeItem]; } | |
2975 -(void)treeView:(DWTree *)treeView treeItem:(DWTreeItem *)treeItem expanded:(BOOL)expanded {} | |
2976 - (DWTreeItem *)treeView:(DWTree *)treeView treeItemForRow:(NSInteger)row { return [[_rootNode visibleNodes] objectAtIndex:row]; } | |
2977 #pragma mark - UITableViewDataSource | |
2978 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } | |
2979 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section | |
2980 { | |
2981 NSInteger count = 0; | |
2982 if([_treeViewDelegate respondsToSelector:@selector(numberOfRowsInTreeView:)]) | |
2983 count = [_treeViewDelegate numberOfRowsInTreeView:self]; | |
2984 return count; | |
2985 } | |
2986 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath | |
2987 { | |
2988 static NSString *CellIdentifier = @"Cell"; | |
2989 | |
2990 DWTreeItem *treeItem = [self treeItemForIndexPath:indexPath]; | |
2991 DWTreeViewCell *cell = [[DWTreeViewCell alloc] initWithStyle:UITableViewCellStyleDefault | |
2992 reuseIdentifier:CellIdentifier | |
2993 level:[treeItem levelDepth] | |
2994 expanded:treeItem.expanded]; | |
2995 cell.titleLabel.text = treeItem.title; | |
2996 cell.imageView.image = treeItem.icon; | |
2997 cell.titleLabel.font = _font; | |
2998 //cell.selectionStyle = UITableViewCellSelectionStyleNone; | |
2999 cell.delegate = self; | |
3000 return cell; | |
3001 } | |
3002 -(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath | |
3003 { | |
3004 DWTreeItem *treeItem = [self treeItemForIndexPath:indexPath]; | |
3005 if([_treeViewDelegate respondsToSelector:@selector(treeView:canEditTreeItem:)]) | |
3006 return [_treeViewDelegate treeView:self canEditTreeItem:treeItem]; | |
3007 else | |
3008 return (treeItem.isRoot == NO); | |
3009 } | |
3010 -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath | |
3011 { | |
3012 DWTreeItem *treeItem = [self treeItemForIndexPath:indexPath]; | |
3013 if(editingStyle == UITableViewCellEditingStyleDelete) | |
3014 { | |
3015 [treeItem removeFromParent]; | |
3016 if([_treeViewDelegate respondsToSelector:@selector(treeView:removeTreeItem:)]) | |
3017 [_treeViewDelegate treeView:self removeTreeItem:treeItem]; | |
3018 if(treeItem.expanded && treeItem.hasChildren) | |
3019 [self reloadData]; | |
3020 else | |
3021 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; | |
3022 [self resetSelection:YES]; | |
3023 } else if (editingStyle == UITableViewCellEditingStyleInsert) { | |
3024 // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view | |
3025 } | |
3026 } | |
3027 -(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath | |
3028 { | |
3029 if([fromIndexPath isEqual:toIndexPath]) | |
3030 return; | |
3031 DWTreeItem *srcNode = [self treeItemForIndexPath:fromIndexPath]; | |
3032 DWTreeItem *targetNode = [self treeItemForIndexPath:toIndexPath]; | |
3033 [srcNode moveToDestination:targetNode]; | |
3034 | |
3035 if([_treeViewDelegate respondsToSelector:@selector(treeView:moveTreeItem:to:)]) | |
3036 [_treeViewDelegate treeView:self moveTreeItem:srcNode to:targetNode]; | |
3037 | |
3038 [self reloadData]; | |
3039 [self resetSelection:NO]; | |
3040 } | |
3041 -(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath | |
3042 { | |
3043 DWTreeItem *treeItem = [self treeItemForIndexPath:indexPath]; | |
3044 if([_treeViewDelegate respondsToSelector:@selector(treeView:canMoveTreeItem:)]) | |
3045 return [_treeViewDelegate treeView:self canMoveTreeItem:treeItem]; | |
3046 else | |
3047 return (treeItem.isRoot == NO); | |
3048 } | |
3049 #pragma mark - DWTableViewDelegate | |
3050 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath | |
3051 { | |
3052 DWTreeItem *treeItem = [self treeItemForIndexPath:indexPath]; | |
3053 if([_treeViewDelegate respondsToSelector:@selector(treeView:didSelectForTreeItem:)]) | |
3054 [_treeViewDelegate treeView:self didSelectForTreeItem:treeItem]; | |
3055 _selectedNode = treeItem; | |
3056 } | |
3057 -(NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath | |
3058 { | |
3059 DWTreeItem *srcNode = [self treeItemForIndexPath:sourceIndexPath]; | |
3060 DWTreeItem *targetNode = [self treeItemForIndexPath:proposedDestinationIndexPath]; | |
3061 if([srcNode containsTreeItem:targetNode] || srcNode==targetNode) | |
3062 return sourceIndexPath; | |
3063 // NSLog(@"Moving to target node \"%@\"", targetNode.title); | |
3064 return proposedDestinationIndexPath; | |
3065 } | |
3066 #pragma mark - DWTreeViewCellDelegate | |
3067 -(BOOL)queryExpandableInTreeViewCell:(DWTreeViewCell *)treeViewCell | |
3068 { | |
3069 BOOL allow = YES; | |
3070 if([_treeViewDelegate respondsToSelector:@selector(treeView:queryExpandableInTreeItem:)]) | |
3071 { | |
3072 DWTreeItem *treeItem = [self treeItemForTreeViewCell:treeViewCell]; | |
3073 allow = [_treeViewDelegate treeView:self queryExpandableInTreeItem:treeItem]; | |
3074 } | |
3075 return allow; | |
3076 } | |
3077 -(void)treeViewCell:(DWTreeViewCell *)treeViewCell expanded:(BOOL)expanded | |
3078 { | |
3079 DWTreeItem *treeItem = [self treeItemForTreeViewCell:treeViewCell]; | |
3080 treeItem.expanded = expanded; | |
3081 if(treeItem.hasChildren) | |
3082 { | |
3083 [self reloadData]; | |
3084 [self resetSelection:NO]; | |
3085 } | |
3086 if([_treeViewDelegate respondsToSelector:@selector(treeView:treeItem:expanded:)]) | |
3087 [_treeViewDelegate treeView:self treeItem:treeItem expanded:expanded]; | |
3088 } | |
3089 #pragma mark - retrieve TreeItem object from special cell | |
3090 -(DWTreeItem *)treeItemForTreeViewCell:(DWTreeViewCell *)treeViewCell | |
3091 { | |
3092 NSIndexPath *indexPath = [self indexPathForCell:treeViewCell]; | |
3093 return [self treeItemForIndexPath:indexPath]; | |
3094 } | |
3095 -(DWTreeItem *)treeItemForIndexPath:(NSIndexPath *)indexPath | |
3096 { | |
3097 DWTreeItem *treeItem = nil; | |
3098 if([_treeViewDelegate respondsToSelector:@selector(treeView:treeItemForRow:)]) | |
3099 treeItem = [_treeViewDelegate treeView:self treeItemForRow:indexPath.row]; | |
3100 NSAssert(treeItem, @"Can't get the Tree Node data"); | |
3101 return treeItem; | |
3102 } | |
2646 @end | 3103 @end |
2647 | 3104 |
2648 /* Subclass for a Calendar type */ | 3105 /* Subclass for a Calendar type */ |
2649 @interface DWCalendar : UIDatePicker | 3106 @interface DWCalendar : UIDatePicker |
2650 { | 3107 { |
6080 * id: An ID to be used for getting the resource from the | 6537 * id: An ID to be used for getting the resource from the |
6081 * resource file. | 6538 * resource file. |
6082 * Returns: | 6539 * Returns: |
6083 * A handle to a tree window or NULL on failure. | 6540 * A handle to a tree window or NULL on failure. |
6084 */ | 6541 */ |
6085 HWND API dw_tree_new(ULONG cid) | 6542 DW_FUNCTION_DEFINITION(dw_tree_new, HWND, ULONG cid) |
6086 { | 6543 DW_FUNCTION_ADD_PARAM1(cid) |
6087 /* TODO: Implement tree for iOS if possible */ | 6544 DW_FUNCTION_RETURN(dw_tree_new, HWND) |
6088 return 0; | 6545 DW_FUNCTION_RESTORE_PARAM1(cid, ULONG) |
6546 { | |
6547 DW_FUNCTION_INIT; | |
6548 DWTree *tree = [[[DWTree alloc] init] retain]; | |
6549 [tree setTag:cid]; | |
6550 [tree autorelease]; | |
6551 DW_FUNCTION_RETURN_THIS(tree); | |
6089 } | 6552 } |
6090 | 6553 |
6091 /* | 6554 /* |
6092 * Inserts an item into a tree window (widget) after another item. | 6555 * Inserts an item into a tree window (widget) after another item. |
6093 * Parameters: | 6556 * Parameters: |
6098 * parent: Parent handle or 0 if root. | 6561 * parent: Parent handle or 0 if root. |
6099 * itemdata: Item specific data. | 6562 * itemdata: Item specific data. |
6100 * Returns: | 6563 * Returns: |
6101 * A handle to a tree item or NULL on failure. | 6564 * A handle to a tree item or NULL on failure. |
6102 */ | 6565 */ |
6103 HTREEITEM API dw_tree_insert_after(HWND handle, HTREEITEM item, const char *title, HICN icon, HTREEITEM parent, void *itemdata) | 6566 DW_FUNCTION_DEFINITION(dw_tree_insert_after, HTREEITEM, HWND handle, HTREEITEM item, const char *title, HICN icon, HTREEITEM parent, void *itemdata) |
6104 { | 6567 DW_FUNCTION_ADD_PARAM6(handle, item, title, icon, parent, itemdata) |
6105 /* TODO: Implement tree for iOS if possible */ | 6568 DW_FUNCTION_RETURN(dw_tree_insert_after, HTREEITEM) |
6106 return 0; | 6569 DW_FUNCTION_RESTORE_PARAM6(handle, HWND, item, HTREEITEM, title, char *, icon, HICN, parent, HTREEITEM, itemdata, void *) |
6570 { | |
6571 DW_FUNCTION_INIT; | |
6572 DWTree *tree = handle; | |
6573 DWTreeItem *treeparent = item ? item : parent; | |
6574 DWTreeItem *treeitem = [[[DWTreeItem alloc] initWithIcon:icon | |
6575 Title:[NSString stringWithUTF8String:(title ? title : "")] | |
6576 andData:itemdata] retain]; | |
6577 if(treeparent) | |
6578 { | |
6579 if(item) | |
6580 [treeparent insertChildAfter:treeitem]; | |
6581 else | |
6582 [treeparent appendChild:treeitem]; | |
6583 } | |
6584 else | |
6585 [tree insertTreeItem:treeitem]; | |
6586 [treeitem autorelease]; | |
6587 DW_FUNCTION_RETURN_THIS(treeitem); | |
6107 } | 6588 } |
6108 | 6589 |
6109 /* | 6590 /* |
6110 * Inserts an item into a tree window (widget). | 6591 * Inserts an item into a tree window (widget). |
6111 * Parameters: | 6592 * Parameters: |
6117 * Returns: | 6598 * Returns: |
6118 * A handle to a tree item or NULL on failure. | 6599 * A handle to a tree item or NULL on failure. |
6119 */ | 6600 */ |
6120 HTREEITEM API dw_tree_insert(HWND handle, const char *title, HICN icon, HTREEITEM parent, void *itemdata) | 6601 HTREEITEM API dw_tree_insert(HWND handle, const char *title, HICN icon, HTREEITEM parent, void *itemdata) |
6121 { | 6602 { |
6122 /* TODO: Implement tree for iOS if possible */ | 6603 return dw_tree_insert_after(handle, NULL, title, icon, parent, itemdata); |
6123 return 0; | |
6124 } | 6604 } |
6125 | 6605 |
6126 /* | 6606 /* |
6127 * Gets the text an item in a tree window (widget). | 6607 * Gets the text an item in a tree window (widget). |
6128 * Parameters: | 6608 * Parameters: |
6129 * handle: Handle to the tree containing the item. | 6609 * handle: Handle to the tree containing the item. |
6130 * item: Handle of the item to be modified. | 6610 * item: Handle of the item to be modified. |
6131 * Returns: | 6611 * Returns: |
6132 * A malloc()ed buffer of item text to be dw_free()ed or NULL on error. | 6612 * A malloc()ed buffer of item text to be dw_free()ed or NULL on error. |
6133 */ | 6613 */ |
6134 char * API dw_tree_get_title(HWND handle, HTREEITEM item) | 6614 DW_FUNCTION_DEFINITION(dw_tree_get_title, char *, HWND handle, HTREEITEM item) |
6135 { | 6615 DW_FUNCTION_ADD_PARAM2(handle, item) |
6136 /* TODO: Implement tree for iOS if possible */ | 6616 DW_FUNCTION_RETURN(dw_tree_get_title, char *) |
6137 return NULL; | 6617 DW_FUNCTION_RESTORE_PARAM2(DW_UNUSED(handle), HWND, item, HTREEITEM) |
6618 { | |
6619 DW_FUNCTION_INIT; | |
6620 char *title = NULL; | |
6621 DWTreeItem *treeitem = item; | |
6622 if(treeitem) | |
6623 title = strdup([treeitem.title UTF8String]); | |
6624 DW_FUNCTION_RETURN_THIS(title); | |
6138 } | 6625 } |
6139 | 6626 |
6140 /* | 6627 /* |
6141 * Gets the text an item in a tree window (widget). | 6628 * Gets the text an item in a tree window (widget). |
6142 * Parameters: | 6629 * Parameters: |
6143 * handle: Handle to the tree containing the item. | 6630 * handle: Handle to the tree containing the item. |
6144 * item: Handle of the item to be modified. | 6631 * item: Handle of the item to be modified. |
6145 * Returns: | 6632 * Returns: |
6146 * A handle to a tree item or NULL on failure. | 6633 * A handle to a tree item or NULL on failure. |
6147 */ | 6634 */ |
6148 HTREEITEM API dw_tree_get_parent(HWND handle, HTREEITEM item) | 6635 DW_FUNCTION_DEFINITION(dw_tree_get_parent, HTREEITEM, HWND handle, HTREEITEM item) |
6149 { | 6636 DW_FUNCTION_ADD_PARAM2(handle, item) |
6150 /* TODO: Implement tree for iOS if possible */ | 6637 DW_FUNCTION_RETURN(dw_tree_get_parent, HTREEITEM) |
6151 return 0; | 6638 DW_FUNCTION_RESTORE_PARAM2(DW_UNUSED(handle), HWND, item, HTREEITEM) |
6639 { | |
6640 DW_FUNCTION_INIT; | |
6641 DWTreeItem *treeparent = nil; | |
6642 DWTreeItem *treeitem = item; | |
6643 if(treeitem) | |
6644 treeparent = treeitem.parent; | |
6645 DW_FUNCTION_RETURN_THIS(treeparent); | |
6152 } | 6646 } |
6153 | 6647 |
6154 /* | 6648 /* |
6155 * Sets the text and icon of an item in a tree window (widget). | 6649 * Sets the text and icon of an item in a tree window (widget). |
6156 * Parameters: | 6650 * Parameters: |