forked from samsouder/reggy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
RBSplitView.h
222 lines (175 loc) · 12.2 KB
/
RBSplitView.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//
// RBSplitView.h version 1.1.3
// RBSplitView
//
// Created by Rainer Brockerhoff on 24/09/2004.
// Copyright 2004,2005 Rainer Brockerhoff.
// Some Rights Reserved under the Creative Commons Attribution License, version 2.0, and/or the MIT License.
//
#import "RBSplitSubview.h"
// These values are used to handle the various cursor types.
typedef enum {
RBSVHorizontalCursor=0, // appears over horizontal dividers
RBSVVerticalCursor, // appears over vertical dividers
RBSV2WayCursor, // appears over two-way thumbs
RBSVDragCursor, // appears while dragging
RBSVCursorTypeCount
} RBSVCursorType;
@interface RBSplitView : RBSplitSubview {
// Subclasses normally should use setter methods instead of changing instance variables by assignment.
// Most getter methods simply return the corresponding instance variable, so with some care, subclasses
// could reference them directly.
IBOutlet id delegate; // The delegate (may be nil).
NSString* autosaveName; // This name is used for storing subview proportions in user defaults.
NSColor* background; // The color used to paint the view's background (may be nil).
NSImage* divider; // The image used for the divider "dimple".
NSRect* dividers; // A C array of NSRects, one for each divider.
float dividerThickness; // Actual divider width; should be an integer and at least 1.0.
BOOL mustAdjust; // Set internally if the subviews need to be adjusted.
BOOL mustClearFractions; // Set internally if fractions should be cleared before adjusting.
BOOL isHorizontal; // The divider's orientation; default is vertical.
BOOL canSaveState; // Set internally to allow saving subview state.
BOOL isCoupled; // If YES, take some parameters from the containing RBSplitView, if any.
BOOL isAdjusting; // Set internally while the subviews are being adjusted.
BOOL isDragging; // Set internally while in a drag loop.
}
// These class methods get and set the cursor used for each type.
// Pass in nil to reset to the default cursor for that type.
+ (NSCursor*)cursor:(RBSVCursorType)type;
+ (void)setCursor:(RBSVCursorType)type toCursor:(NSCursor*)cursor;
// This class method clears the saved state for a given autosave name from the defaults.
+ (void)removeStateUsingName:(NSString*)name;
// This class method returns the actual key used to store autosave data in the defaults.
+ (NSString*)defaultsKeyForName:(NSString*)name isHorizontal:(BOOL)orientation;
// Sets and gets the autosaveName; this will be the key used to store the subviews' proportions
// in the user defaults. Default is @"", which doesn't save anything. Set flag to YES to set
// unique names for nested subviews. You are responsible for avoiding duplicates.
- (void)setAutosaveName:(NSString*)aString recursively:(BOOL)flag;
- (NSString*)autosaveName;
// Saves the current state of the subviews if there's a valid autosave name set. If the argument
// is YES, it's then also called recursively for nested RBSplitViews. Returns YES if successful.
- (BOOL)saveState:(BOOL)recurse;
// Restores the saved state of the subviews if there's a valid autosave name set. If the argument
// is YES, it's first called recursively for nested RBSplitViews. Returns YES if successful.
// You need to call adjustSubviews after calling this.
- (BOOL)restoreState:(BOOL)recurse;
// Returns a string encoding the current state of all direct subviews. Does not check for nesting.
- (NSString*)stringWithSavedState;
// Readjusts all direct subviews according to the encoded string parameter. The number of subviews
// must match. Returns YES if successful. Does not check for nesting.
- (BOOL)setStateFromString:(NSString*)aString;
// Returns an array with complete state information for the receiver and all subviews, taking
// nesting into account. Don't store this array in a file, as its format might change in the
// future; this is for taking a state snapshot and later restoring it with setStatesFromArray.
- (NSArray*)arrayWithStates;
// Restores the state of the receiver and all subviews. The array must have been produced by a
// previous call to arrayWithStates. Returns YES if successful. This will fail if you have
// added or removed subviews in the meantime!
// You need to call adjustSubviews after calling this.
- (BOOL)setStatesFromArray:(NSArray*)array;
// This is the designated initializer for creating RBSplitViews programmatically.
- (id)initWithFrame:(NSRect)frame;
// This convenience initializer adds any number of subviews and adjusts them proportionally.
- (id)initWithFrame:(NSRect)frame andSubviews:(unsigned)count;
// Sets and gets the delegate. (Delegates aren't retained.) See further down for delegate methods.
- (void)setDelegate:(id)anObject;
- (id)delegate;
// Returns a subview which has a certain identifier string, or nil if there's none
- (RBSplitSubview*)subviewWithIdentifier:(NSString*)anIdentifier;
// Returns the subview at a certain position. Returns nil if the position is invalid.
- (RBSplitSubview*)subviewAtPosition:(unsigned)position;
// Adds a subview at a certain position.
- (void)addSubview:(NSView*)aView atPosition:(unsigned)position;
// Sets and gets the divider thickness, which should be a positive integer or zero.
// Setting the divider image also resets this automatically, so you would call this
// only if you want the divider to be larger or smaller than the image. Zero means that
// the image dimensions will be used.
- (void)setDividerThickness:(float)thickness;
- (float)dividerThickness;
// Sets and gets the divider image. The default image can also be set in Interface Builder, so usually
// there's no need to call this. Passing in nil means that the default divider thickness will be zero,
// and no mouse events will be processed, so that the dividers can be moved only programmatically.
- (void)setDivider:(NSImage*)image;
- (NSImage*)divider;
// Sets and gets the view background. The default is nil, meaning no background is
// drawn and the view and its subviews are considered transparent.
- (void)setBackground:(NSColor*)color;
- (NSColor*)background;
// Sets and gets the orientation. This uses the same convention as NSSplitView: vertical means the
// dividers are vertical, but the subviews are in a horizontal row. Sort of counter-intuitive, yes.
- (void)setVertical:(BOOL)flag;
- (BOOL)isVertical;
- (BOOL)isHorizontal;
// Call this to force adjusting the subviews before display. Called automatically if anything
// relevant is changed.
- (void)setMustAdjust;
// Returns YES if there's a pending adjustment.
- (BOOL)mustAdjust;
// Returns YES if we're in a dragging loop.
- (BOOL)isDragging;
// Call this to recalculate all subview dimensions. Normally this is done automatically whenever
// something relevant is changed, so you rarely will need to call this explicitly.
- (void)adjustSubviews;
// This method should be called only from within the splitView:wasResizedFrom:to: delegate method
// to keep some specific subview the same size.
- (void)adjustSubviewsExcepting:(RBSplitSubview*)excepting;
// This method draws dividers. You should never call it directly but you can override it when
// subclassing, if you need custom dividers.
- (void)drawDivider:(NSImage*)anImage inRect:(NSRect)rect betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing;
@end
// The following methods are optionally implemented by the delegate.
@interface NSObject(RBSplitViewDelegate)
// The delegate can override a subview's ability to collapse by implementing this method.
// Return YES to allow collapsing. If this is implemented, the subviews' built-in
// 'collapsed' flags are ignored.
- (BOOL)splitView:(RBSplitView*)sender canCollapse:(RBSplitSubview*)subview;
// The delegate can alter the divider's appearance by implementing this method.
// Before calling this, the divider is filled with the background, and afterwards
// the divider image is drawn into the returned rect. If imageRect is empty, no
// divider image will be drawn, because there are nested RBSplitViews. Return
// NSZeroRect to suppress the divider image. Return imageRect to use the default
// location for the image, or change its origin to place the image elsewhere.
// You could also draw the divider yourself at this point and return NSZeroRect.
- (NSRect)splitView:(RBSplitView*)sender willDrawDividerInRect:(NSRect)dividerRect betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing withProposedRect:(NSRect)imageRect;
// These methods are called after a subview is completely collapsed or expanded. adjustSubviews may or not
// have been called, however.
- (void)splitView:(RBSplitView*)sender didCollapse:(RBSplitSubview*)subview;
- (void)splitView:(RBSplitView*)sender didExpand:(RBSplitSubview*)subview;
// These methods are called just before and after adjusting subviews.
- (void)willAdjustSubviews:(RBSplitView*)sender;
- (void)didAdjustSubviews:(RBSplitView*)sender;
// This method will be called after a RBSplitView is resized with setFrameSize: but before
// adjustSubviews is called on it.
- (void)splitView:(RBSplitView*)sender wasResizedFrom:(float)oldDimension to:(float)newDimension;
// This method will be called when a divider is double-clicked and both leading and trailing
// subviews can be collapsed. Return either of the parameters to collapse that subview, or nil
// to collapse neither. If not implemented, the smaller subview will be collapsed.
- (RBSplitSubview*)splitView:(RBSplitView*)sender collapseLeading:(RBSplitSubview*)leading orTrailing:(RBSplitSubview*)trailing;
// This method will be called when a cursor rect is being set (inside resetCursorRects). The
// proposed rect is passed in. Return the actual rect, or NSZeroRect to suppress cursor setting
// for this divider. This won't be called for two-axis thumbs, however. The rects are in
// sender's local coordinates.
- (NSRect)splitView:(RBSplitView*)sender cursorRect:(NSRect)rect forDivider:(unsigned int)divider;
// This method will be called whenever a mouse-down event is received in a divider. Return YES to have
// the event handled by the split view, NO if you wish to ignore it or handle it in the delegate.
- (BOOL)splitView:(RBSplitView*)sender shouldHandleEvent:(NSEvent*)theEvent inDivider:(unsigned int)divider betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing;
// This method will be called just before a subview will be collapsed or expanded with animation.
// Return the approximate time the animation should take, or 0.0 to disallow animation.
// If not implemented, it will use the default of 0.2 seconds per 150 pixels.
- (NSTimeInterval)splitView:(RBSplitView*)sender willAnimateSubview:(RBSplitSubview*)subview withDimension:(float)dimension;
// This method will be called whenever a subview's frame is changed, usually from inside adjustSubviews' final loop.
// You'd normally use this to move some auxiliary view to keep it aligned with the subview.
- (void)splitView:(RBSplitView*)sender changedFrameOfSubview:(RBSplitSubview*)subview from:(NSRect)fromRect to:(NSRect)toRect;
// This method is called whenever the event handlers want to check if some point within the RBSplitSubview
// should act as an alternate drag view. Usually, the delegate will check the point (which is in sender's
// local coordinates) against the frame of one or several auxiliary views, and return a valid divider number.
// Returning NSNotFound means the point is not valid, returning -1 or -2 means that the window will
// be resized along with the subview. Return -1 to grow the subview to the right, -2 to shrink it from the left.
- (unsigned int)splitView:(RBSplitView*)sender dividerForPoint:(NSPoint)point inSubview:(RBSplitSubview*)subview;
// This method is called continuously while a divider is dragged, just before the leading subview is resized.
// Return NO to resize the trailing view by the same amount, YES to resize the containing window by the same amount.
- (BOOL)splitView:(RBSplitView*)sender shouldResizeWindowForDivider:(unsigned int)divider betweenView:(RBSplitSubview*)leading andView:(RBSplitSubview*)trailing willGrow:(BOOL)grow;
// This method is called by each subview's drawRect: method, just after filling it with the background color but
// before the contained subviews are drawn. Usually you would use this to draw a frame inside the subview.
- (void)splitView:(RBSplitView*)sender willDrawSubview:(RBSplitSubview*)subview inRect:(NSRect)rect;
@end