-
Notifications
You must be signed in to change notification settings - Fork 4
/
SCRATCHPAD
486 lines (391 loc) · 17.1 KB
/
SCRATCHPAD
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
/** WARNING: Personal notes that are vague and may change, move or become part
of another framework.
Rendering tree is an extension of renderer support, this extension is
useful essentially in imaging applications either vector or bitmap based.
Rendering is the step which precedes display and encompass both layout and
real time graphics computation.
A renderer tree would be roughly identical to GEGL model.
Layout item tree and renderer tree form two parallel trees which are
bridged together and ruled by layout items.
At each layout item node, a renderer branch is connected.
Both trees are visited together from top to bottom at rendering time.
At rendering time, a visitor object which encapsulates the rendering state
is passed through layout items:
- it enters a layout item
- it visits the item renderer branch and computes it if needed
- it memorizes the first renderer directly connected to the layout item
- it quits the layout item
- it enters a second layout item
- it checks whether the first renderer of the layout item has a second
input if we put aside renderer branch which plays the first input role; if
no second input is present, it uses the last memorized renderer in this
role
- it removes the last memorized renderer of the second input if necessary
- it memorizes the renderer connected to the second layout
- it quits the layout item
*/
== Random API ideas ==
@interface NSObject (ETInspector) <ETObjectInspection>
- (id <ETInspector>) inspector;
@end
/** Returns the custom inspector associated with the receiver. By default,
returns nil.
-[NSObject(EtoileUI) inspect:] will show this inspector, unless nil is returned. */
- (id <ETInspector>) inspector;
/** Sets the custom inspector associated with the receiver. */
- (void) setInspector: (id <ETInspector>)inspector;
/* ETLayoutItem/Group Live Development */
/* Live Development */
/** This feature is not yet implemented. */
- (void) beginEditingUI
{
id view = [self supervisorView];
/* Notify to view */
if (view != nil && [view respondsToSelector: @selector(beginEditingUI)])
[view beginEditingUI];
/* Notify decorator item chain */
[[self decoratorItem] beginEditingUI];
}
- (void) beginEditingUI
{
/* Notify view and decorator item chain */
[super beginEditingUI];
/* Notify children */
[[self items] makeObjectsPerformSelector: @selector(beginEditingUI)];
}
/*- (BOOL) isEditingUI;
- (void) commitEditingUI;*/
// TODO: For each document set the editor tool. Eventually offer a
// delegate method either through ETTool or ETDocumentManager to give
// more control over this...
+ (void) setEditorTool: (id)anTool
{
//[documentLayout setAttachedTool: anTool];
}
// TODO: Think about...
+ (void) setEditorTargetItems: (NSArray *)items
{
}
// TODO: Implement
//- (void) didBecomeActive: (ETTool *)prevTool;
// or
/*- (void) willBecomeActive
{
ETTool *activeTool = [ETTool activeTool];
BOOL isToolReplacement = ([activeTool isSelectTool] && [[activeTool layoutOwner] isEqual: [self layoutOwner]]);
if (isToolReplacement)
[self setAllowedDragUTIs: [activeTool allowedDragUTIs]];
}*/
// or rather take the values from the controller when attaching the tool for the first time. or cache a select tool prototype in the controller? Well need a general mechanism to store tool prototypes anyway…
// -[ETController setPrototype: forToolClass:]?
// TODO: Inspection and ETSelectTool
/* Returns inspector based on selection unlike ETLayoutItem.
If a custom inspector hasn't been set by calling -setInspector:, the inspector
set on the base item is retrieved. If the option/alt modifier key is pressed,
a copy of the inspector is returned rather reusing the existing instance as
usual. This facility allows to easily inspect two items with two distinct
inspectors, even if these layout items belong to the same base item. At UI level,
the user can press the option/alt key when choosing Inspect in a menu. */
/** ETlayoutItem has no delegate but rather used the delegate of the closest
container ancestor.
Implements this method if you set values in aggregate views or cells. For
example, when you have a mixed icon text cell, you would write:
if ([property isEqual: kPropertyName])
{
[[item cell] setText: value];
[[item cell] setImage: [item valueForProperty: @"icon"];
}
Be careful with property because it can be a key path so you may better
to always retrieve the last component.
Binding can be used instead of this method if you prefer.
An other alternative is to subclass ETLayoutItem and overrides method
-setValue:forProperty:. But the purpose of this delegate is precisely to
avoid subclassing burden. */
@interface ETLayoutItem (ETLayoutItemDelegate)
- (void) layoutItem: (ETLayoutItem *)item setValue: (id)value forProperty: (NSString *)property;
@end
- (void) setDraggingAllowedForTypes: (NSArray *)types;
- (NSArray *) allowedDraggingTypes;
- (void) setDroppingAllowedForTypes: (NSArray *)types;
- (NSArray *) allowedDroppingTypes;
- (void) setDropTargetTypes: (NSArray *)types;
- (NSArray *)dropTargetTypes;
- (ETLayoutAlignment) layoutAlignment;
- (void) setLayoutAlignment: (ETLayoutAlignment)alignment;
- (ETLayoutOverflowStyle) overflowStyle;
- (void) setOverflowStyle: (ETLayoutOverflowStyle);
- (id) scaleItemsToRect: (NSRect)rect;
- (id) scaleItemsToFit: (id)sender;
// This method is equivalent to calling -setItemScaleFactor with 1.0 value
- (id) scaleItemsToActualSize: (id)sender;
- (float) itemRotationAngle;
- (void) setItemRotationAngle: (float)factor;
@interface NSObject (ETContainerSource)
/* Coordinates retrieval useful with containers oriented towards graphics and
spreadsheet */
- (ETVector *) container: (ETContainer *)container
locationForItem: (ETLayoutItem *)item;
- (void) container: (ETContainer *)container setLocation: (ETVector *)vectorLoc
forItem: (ETLayoutItem *)item;
/* Extra infos */
- (NSArray *) editableItemPropertiesInContainer: (ETContainer *)container;
- (NSView *) container: (ETContainer *)container
editorObjectForProperty: (NSString *)property ;
- (int) firstVisibleItemInContainer: (ETContainer *)container;
- (int) lastVisibleItemInContainer: (ETContainer *)container;
/* Pick and drop support and Bindings support by index */
/* When operation is a pick and drop one (either copy/paste or drag/drop),
- 'container:addItems:operation:' is called when no selection is set
- 'container:insertItems:atIndexes:operation:' is called when a selection
exists */
/* These methods make also possible to use your data source with bindings if
you use the specifically designed controller ETSourceController */
- (BOOL) container: (ETContainer *)container addItems: (NSArray *)items
operation: (ETEvent *)op;
- (BOOL) container: (ETContainer *)container insertItems: (NSArray *)items
atIndexes: (NSIndexSet *)indexes operation: (ETEvent *)op;
- (BOOL) container: (ETContainer *)container removeItems: (NSArray *)items
atIndexes: (NSIndexSet *)indexes operation: (ETEvent *)op;
/* Pick and drop support and Bindings support by index path */
- (BOOL) container: (ETContainer *)container addItems: (NSArray *)items
atPath: (NSIndexPath *)path operation: (ETEvent *)op;
- (BOOL) container: (ETContainer *)container insertItems: (NSArray *)items
atPaths: (NSArray *)paths operation: (ETEvent *)op;
- (BOOL) container: (ETContainer *)container
removeItemsAtPaths: (NSArray *)paths operation: (ETEvent *)op;
/* Advanced pick and drop support
Only needed if you want to override pick and drop support. Useful to get more
control over drag an drop. */
- (BOOL) container: (ETContainer *)container handlePick: (ETEvent *)event
forItems: (NSArray *)items pickboard: (ETPickboard *)pboard;
- (BOOL) container: (ETContainer *)container handleAcceptDrop: (id)dragInfo
forItems: (NSArray *)items on: (id)item pickboard: (ETPickboard *)pboard;
- (BOOL) container: (ETContainer *)container handleDrop: (id)dragInfo
forItems: (NSArray *)items on: (id)item pickboard: (ETPickboard *)pboard;
// TODO: Extend the informal protocol to propogate group/ungroup actions in
// they can be properly reflected on model side.
@end
@interface ETContainer (ETContainerDelegate)
- (void) containerShouldStackItem: (NSNotification *)notif;
- (void) containerDidStackItem: (NSNotification *)notif;
- (void) containerShouldGroupItem: (NSNotification *)notif;
- (void) containerDidGroupItem: (NSNotification *)notif;
// NOTE: We use a double action instead of the delegate to handle double-click
//- (void) containerDoubleClickedItem: (NSNotification *)notif;
@end
== Special Group Access Ideas in ETLayoutItemFactory ==
/** Returns the absolute root group usually located in the UI server.
This root group representing the whole environment is the only layout item
with truly no parent.
WARNING: Not yet implemented. */
- (id) rootGroup
{
return nil;
}
//static ETLayoutItemGroup *localRootGroup = nil;
/** Returns the local root group which represents the current work context or
application.
WARNING: You should avoid to use this method. For now, it returns -windowGroup
as the local root group, but this probably won't be the case in the future.
This method might also removed. -windowGroup is the method you are encouraged
to use.
When the UI server is running, the local root group is inserted as a child in a
parent located in the UI server process. When no UI server is available, the
local root group will have no parent.
ETApplication returns the same item when you call -layoutItem method
(unless the method has been overriden). This might not hold in the future either. */
- (id) localRootGroup
{
// TODO: Should add -windowGroup... but how the top part of the layout
// item tree is organized needs to be worked out in details.
#if 0
if (localRootGroup == nil)
{
localRootGroup = [[ETLayoutItemGroup alloc] init];
[localRootGroup setName: _(@"Application")];
[localRootGroup addItem: [self windowGroup]];
}
return localRootGroup;
#endif
return [self windowGroup];
}
/** Returns the item representing the main screen.
TODO: Implement or rethink... */
- (id) screen
{
return nil;
}
/** Returns the item group representing all screens available (usually the
screens connected to the computer).
TODO: Implement or rethink... */
- (id) screenGroup
{
return nil;
}
/** Returns the item group representing the active project.
TODO: Implement or rethink... */
- (id) project
{
return nil;
}
/** Returns the item group representing all projects.
TODO: Implement or rethink... */
- (id) projectGroup
{
return nil;
}
== Initial Stacking Support in ETLayoutItemGroup ==
/* Stacking */
+ (NSSize) stackSize
{
return NSMakeSize(200, 200);
}
- (ETLayout *) stackedItemLayout
{
return _stackedLayout;
}
- (void) setStackedItemLayout: (ETLayout *)layout
{
ASSIGN(_stackedLayout, layout);
}
- (ETLayout *) unstackedItemLayout
{
return _unstackedLayout;
}
- (void) setUnstackedItemLayout: (ETLayout *)layout
{
ASSIGN(_unstackedLayout, layout);
}
- (void) setIsStack: (BOOL)flag
{
if (_isStack == NO)
{
[self setItemScaleFactor: 0.7];
[self setSize: [ETLayoutItemGroup stackSize]];
}
_isStack = flag;
}
- (BOOL) isStack
{
return _isStack;
}
/** Returns YES when the receiver is a collapsed stack, otherwise returns NO. */
- (BOOL) isStacked
{
return [self isStack] && [[self layout] isEqual: [self stackedItemLayout]];
}
- (void) stack
{
/* Turn item group into stack if necessary */
[self setIsStack: YES];
[self reloadIfNeeded];
[self setLayout: [self stackedItemLayout]];
}
- (void) unstack
{
/* Turn item group into stack if necessary */
[self setIsStack: YES];
[self reloadIfNeeded];
[self setLayout: [self unstackedItemLayout]];
}
== ETView/ETContainer Archiving Code ==
- (id) archiver: (NSKeyedArchiver *)archiver willEncodeObject: (id)object
{
ETDebugLog(@"---- Will encode %@", object);
/* Don't encode layout view and item views */
if ([object isEqual: [self subviews]])
{
id archivableSubviews = [object mutableCopy];
id itemViews = [[self items] valueForKey: @"displayView"];
ETDebugLog(@"> Won't be encoded");
if ([self layoutView] != nil)
[archivableSubviews removeObject: [self layoutView]];
[itemViews removeObjectsInArray: archivableSubviews];
return archivableSubviews;
}
return object;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
if ([coder allowsKeyedCoding] == NO)
{
[NSException raise: NSInvalidArgumentException format: @"ETView only "
@"supports keyed archiving"];
}
/* We must disable the encoding of item subviews by catching it on
-[ETView encodeWithCoder:] with call back -archiver:willEncodeObject: */
[(NSKeyedArchiver *)coder setDelegate: self];
[super encodeWithCoder: coder];
// TODO: We might want to use -encodeLateBoundObject:forKey: to serialize
// an id rather the object itself
[coder encodeObject: [self titleBarView] forKey: @"ETTitleBarView"];
[coder encodeObject: [self wrappedView] forKey: @"ETWrappedView"];
[coder encodeObject: [self temporaryView] forKey: @"ETTemporaryView"];
[coder encodeBool: [self isDisclosable] forKey: @"ETDisclosable"];
[coder encodeBool: [self usesCustomTitleBar] forKey: @"ETUsesCustomTitleBar"];
[coder encodeBool: [self isFlipped] forKey: @"ETFlipped"];
[(NSKeyedArchiver *)coder setDelegate: nil];
}
- (id) initWithCoder: (NSCoder *)coder
{
self = [super initWithCoder: coder];
if ([coder allowsKeyedCoding] == NO)
{
[NSException raise: NSInvalidArgumentException format: @"ETView only "
@"supports keyed unarchiving"];
return nil;
}
// NOTE: Don't use accessors, they involve a lot of set up logic and they
// would change the subviews in relation with their call order.
_usesCustomTitleBar = [coder decodeBoolForKey: @"ETUsesCustomTitleBar"];
_disclosable = [coder decodeBoolForKey: @"ETDisclosable"];
ASSIGN(_titleBarView, [coder decodeObjectForKey: @"ETTitleBarView"]);
ASSIGN(_wrappedView, [coder decodeObjectForKey: @"ETWrappedView"]);
ASSIGN(_temporaryView, [coder decodeObjectForKey: @"ETTemporaryView"]);
[self setFlipped: [coder decodeBoolForKey: @"ETFlipped"]];
return self;
}
== Free Layout Ideas ==
// TODO: If we want to allow the source to handle the item locations manually,
// the following methods have to be added back to ETFreeLayout. Take note
// that vectorLoc could be an NSPoint initially. The benefit of using a vector
// would be simplify the support of a 2.5D behavior (simulating 3D with 2D
// transforms).
// I'm not yet sure that's the best way to let the developer implement
// positional constraint. May be this could be implemented in a 'positional
// constraint layer/handler' that the developer sets on its ETFreeLayout
// instance, this might be better if the contraint logic tends to be large. By
// doing so, we could eventually provide more ready-to-use logic that simplifies
// the developer task.
// For 2.5D or 3D, we could add more properties to ETLayoutItem in CoreAnimation
// spirit. For example, a zPosition property and a orientationVector property.
// Think more about that...
// -itemGroup:locationForItem: should be called in -itemAtLocation:. If no
// source exists, -itemAtLocation must run exactly as it is now and requests the
// item location to super.
// -itemGroup:setLocation:forItem: should be called in
// -handleDrop:forItem:layout: or similar.
// -itemGroup:acceptLocation:forItem: may be needed in
// -handleDrag:forItem:layout: to give feedback about positional constraints to
// the user.
#if 0
/* Overriden method to delegate it to the layout item group data source. */
- (ETVector *) itemGroup: (ETLayoutItemGroup *)itemGroup locationForItem: (ETLayoutItem *)item
{
return [[itemGroup source] itemGroup: itemGroup locationForItem: item];
}
/* Overriden method to delegate it to the layout item group data source. */
- (void) itemGroup: (ETLayoutItemGroup *)itemGroup setLocation: (ETVector *)vectorLoc forItem: (ETLayoutItem *)item
{
[[itemGroup source] itemGroup: itemGroup setLocation: vectorLoc forItem: item];
}
#endif
Old Ideas
---------
## Layout
For ETFlow/Line/ColumnLayout, my idea was to introduce layout strategie as a ETLayoutAlgorithm class tree:
- ETHorizontalFlowAlgorithm
- ETVerticalFlowAlgorithm
For these two subclasses, you can specify how the overflow should be handled. In ETFlowLayout, the right Flow algorithm is selected depending on the value returned by -isVerticallyOriented. In a very-long term vision, these classes could be eventually be subclassed for implementing text layout algorithms (see Universal Polygons in STEPS first year report).
So ETLineLayout results of using ETHorizontalFlowAlgorithm limited to a single line and the overflow hidden. Similarly ETColumnLayout results of using ETVerticalFlowAlgorithm limited to a single column and the overflow hidden.
* Fix stack and unstack operations, they are currently broken. Documentation is probably missing in this area. Stack/Unstack operations are unrelated to the stack layout (we got a naming issue here), they allow to set a temporary layout on an item group, so that the child item becomes visible instead of the drawing or the view of the item group itself. For example, you set a table layout on a folder item, then the content of the folder appears 'exploded' as a table view rather than just an opaque folder icon. This feature gives a very generic implementation of Aperture-like stacks.