1 // Copyright (c) 2009 Yanagi Asakura
3 // This software is provided 'as-is', without any express or implied
4 // warranty. In no event will the authors be held liable for any damages
5 // arising from the use of this software.
7 // Permission is granted to anyone to use this software for any purpose,
8 // including commercial applications, and to alter it and redistribute it
9 // freely, subject to the following restrictions:
11 // 1. The origin of this software must not be misrepresented; you must not
12 // claim that you wrote the original software. If you use this software
13 // in a product, an acknowledgment in the product documentation would be
14 // appreciated but is not required.
16 // 2. Altered source versions must be plainly marked as such, and must not be
17 // misrepresented as being the original software.
19 // 3. This notice may not be removed or altered from any source
23 // ElisTimeLineController.m
26 // Created by 柳 on 09/09/12.
27 // Copyright 2009 __MyCompanyName__. All rights reserved.
30 #import "ElisTimeLineController.h"
33 @implementation ElisTimeLineController
37 NSLog(@"Building TimeLine ...");
39 CGImageRef bar, trblack;
40 NSBundle *bundle = [NSBundle mainBundle];
41 bar = [[NSBitmapImageRep imageRepWithContentsOfFile:[bundle pathForResource:@"white" ofType:@"jpg"]] CGImage];
42 trblack = [[NSBitmapImageRep imageRepWithContentsOfFile:[bundle pathForResource:@"trackgray" ofType:@"jpg"]] CGImage];
44 timeLineScale = 10.0; // 10倍表示
46 rootLayer = [CALayer layer];
47 timeLine = [CALayer layer];
48 playbackBar = [CALayer layer];
50 rootLayer.backgroundColor = CGColorCreateGenericGray(0, 0.4f);
51 playbackBar.contents = (id)bar;
52 playbackBar.frame = CGRectMake(0, 0, 1, 51*TRACK_MAX);
56 for(i = 0; i < TRACK_MAX; i++){
57 track = [CALayer layer];
58 track.frame = CGRectMake(0, 51*i+1, [_timeLineView frame].size.width, 50);
59 track.contents = (id)trblack;
61 track.autoresizingMask = kCALayerWidthSizable;
62 [timeLine addSublayer:track];
64 timeLine.autoresizingMask = kCALayerWidthSizable;
66 NSRect r = [_timeLineView frame];
67 [_timeLineView setFrame:NSMakeRect(0, 0, 10*60*timeLineScale, 51*TRACK_MAX)];
68 rootLayer.frame = *(CGRect*)&r;
69 rootLayer.masksToBounds = YES;
71 [rootLayer addSublayer:timeLine];
72 [rootLayer addSublayer:playbackBar];
73 [_timeLineView setLayer:rootLayer];
74 [_timeLineView setWantsLayer:YES];
77 clickedPosition.x = -1;
79 _layerFactory = [[ElisAnimationLayerFactory alloc] init];
82 - (void)movePlaybackBar:(float)p
84 // 自動スクロールはうまくできないので無効にしてある。
86 // NSRect r = [_timeLineView visibleRect];
87 // if(p > r.origin.x){
89 // [_timeLineView scrollPoint:r.origin];
91 [CATransaction begin];
92 [CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration];
93 CGPoint po = playbackBar.position;
95 playbackBar.position = po;
96 [CATransaction commit];
99 - (void)addMedia:(NSString*)path
101 CALayer* newLayer = [_mainController createNewLayer:path];
102 if(draggingLayer) draggingLayer.opacity = 0.75;
103 draggingLayer = newLayer;
104 [timeLine addSublayer:newLayer];
105 clickedPosition.x = -1;
106 // [_undoManager pushOperation:[draggingLayer valueForKey:@"ElisLayer"]];
109 - (void)readyInDrag:(NSPoint)p
112 clickedLayerPosition = *(CGPoint*)&p;
115 - (void)dragging:(NSPoint)point
117 if(draggingLayer == nil) return;
119 if(stretch == STRETCH_RIGHT){
120 CGRect rect = draggingLayer.frame;
121 float dx = point.x - rect.origin.x - rect.size.width;
122 rect.size.width += dx;
123 if([[draggingLayer valueForKey:@"ElisLayer"] canChangeMapping:rect]){
124 [self changeLayerFrame:draggingLayer rect:rect];
127 } else if (stretch == STRETCH_LEFT){
128 CGRect rect = draggingLayer.frame;
129 float dx = point.x - rect.origin.x;
130 if([[draggingLayer valueForKey:@"ElisLayer"] canChangeOffset:dx]){
131 [[draggingLayer valueForKey:@"ElisLayer"] changeOffset:dx];
132 rect.size.width -= dx;
133 [self changeLayerFrame:draggingLayer rect:rect];
134 [_mainController refresh];
139 if(dragging == NO) dragging = YES;
140 if(clickedPosition.x == -1 && NO){
141 NSLog(@"called? %f", point.x);
144 clickedPosition = point;
145 clickedLayerPosition = *(CGPoint*)&point;
146 [self changeLayerPosition:draggingLayer position:point];
147 // [_undoManager pushOperation:[draggingLayer valueForKey:@"ElisLayer"]];
148 NSLog(@"%f", draggingLayer.frame.origin.x);
150 float dx = clickedPosition.x - point.x;
151 float dy = clickedPosition.y - point.y;
152 point = NSMakePoint(clickedLayerPosition.x - dx, clickedLayerPosition.y - dy);
154 [self changeLayerPosition:draggingLayer position:point];
159 if(draggingLayer == nil) return;
161 CGPoint point = draggingLayer.position;
162 point.y = floor(point.y/51.0) * 51 + 1 + 25; // +25ってどこから出てきた?
163 draggingLayer.position = point;
164 draggingLayer.opacity = 0.75;
165 [_undoManager pushOperation:[draggingLayer valueForKey:@"ElisLayer"]];
167 clickedPosition.x = -1;
169 // [_timeLineView setCursorRect:NSZeroRect]; // これなに?
171 if(stretch != 0) [_undoManager pushOperation:[draggingLayer valueForKey:@"ElisLayer"]];
172 [_timeLineView setCursorRect:draggingLayer.frame];
176 - (void)changeLayerPosition:(CALayer*)layer position:(NSPoint)point
178 [CATransaction begin];
179 [CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration];
180 CGRect r = layer.frame;
181 r.origin.x = point.x;
182 r.origin.y = point.y;
183 layer.frame = r; // KVOでCALayerに対応してElisLayerも変化
184 [CATransaction commit];
185 [_mainController refresh]; // ElisLayerの構造が変わったので再描画を要請。ループしないよう注意。
188 - (void)changeLayerFrame:(CALayer*)layer rect:(CGRect)rect
190 [CATransaction begin];
191 [CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration];
193 [CATransaction commit];
194 [_mainController refresh];
197 - (IBAction)add:(id)sender
199 [self addMedia:@"/Users/yanagi/Desktop/59926_2_m1_1.mp4"];
200 NSValue* v = [draggingLayer valueForKey:@"frame"];
201 NSRect r = [v rectValue];
203 // [draggingLayer willChangeValueForKey:@"frame"];
204 [draggingLayer setValue:[NSValue valueWithRect:r] forKey:@"frame"];
205 // [draggingLayer didChangeValueForKey:@"frame"];
208 - (void)clicked:(NSPoint)point
211 draggingLayer.opacity = 0.75;
213 [_tableController createPropertyTable:nil];
214 [_tableController reload];
220 layers = [timeLine sublayers];
221 size = [layers count];
224 for(i = TRACK_MAX; i < size; i++){
225 if([self isInclude:[layers objectAtIndex:i] point:point]){
226 draggingLayer = [layers objectAtIndex:i];
227 draggingLayer.opacity = 1.0;
228 clickedPosition = point;
229 clickedLayerPosition = draggingLayer.frame.origin;
230 [_timeLineView setCursorRect:draggingLayer.frame];
231 [_tableController createPropertyTable:[draggingLayer valueForKey:@"ElisLayer"]];
232 [_tableController reload];
233 [_mainController refresh];
234 [_undoManager pushOperation:[draggingLayer valueForKey:@"ElisLayer"]];
238 if(draggingLayer){ // これなに?
239 draggingLayer.opacity = 0.75;
242 clickedPosition.x = -1; // "レイヤーは選択されていない" という意味。
246 - (void)doubleClicked
248 if(draggingLayer == nil) return;
249 if([[draggingLayer valueForKey:@"have keyframeLayer"] boolValue]){
250 [[[draggingLayer sublayers] lastObject] removeFromSuperlayer];
251 [draggingLayer setValue:[NSNumber numberWithBool:NO] forKey:@"have keyframeLayer"];
252 [_layerFactory removeParentLayer]; // 参照を切る = GCで回収されるようにする
256 CALayer* keyframeLayer;
257 keyframeLayer = [_layerFactory createKeyframeLayerWithLayer:draggingLayer];
259 float size = draggingLayer.frame.size.width;
264 [draggingLayer addSublayer:keyframeLayer];
265 [draggingLayer setValue:[NSNumber numberWithBool:YES] forKey:@"have keyframeLayer"];
267 if([_tableController isSelected] == NO)
268 [_tableController selectDefault];
270 for(x = 0.0; x < size-1; x += MINI_LAYER_WIDTH){
271 miniLayer = [_layerFactory createKeyframeLevelLayer];
273 r.size.height = 100 * [_tableController getSelectedValueForTime:x];
276 [keyframeLayer addSublayer:miniLayer];
281 - (void)updateKeyframeLayer
283 if(draggingLayer == nil) return;
284 if([[draggingLayer valueForKey:@"have keyframeLayer"] boolValue] == NO) return;
287 minis = [[[draggingLayer sublayers] lastObject] sublayers];
291 int i, size = [minis count];
292 for(i = 0; i < size; i++){
293 mini = [minis objectAtIndex:i];
295 r.size.height = 100 * [_tableController getSelectedValueForTime:i * MINI_LAYER_WIDTH];
300 // 左側のマッピングを調整する。(レイヤー内オフセットをいじる)
303 stretch = STRETCH_LEFT;
306 // 右側のマッピングを調整する。(マッピングの範囲を変えるだけ)
309 stretch = STRETCH_RIGHT;
312 - (BOOL)isInclude:(CALayer*)layer point:(NSPoint)point
314 CGRect r = layer.frame;
315 return r.origin.x <= point.x && point.x <= r.origin.x + r.size.width
316 && r.origin.y <= point.y && point.y <= r.origin.y + r.size.height;
319 - (CALayer*)getSelectLayer
321 return draggingLayer;
324 - (void)removeSelectLayer
326 [draggingLayer setValue:nil forKey:@"ElisLayer"];
330 - (void)addLayer:(CALayer*)l
332 [timeLine addSublayer:l];
335 - (BOOL)canDeleteLayer
337 return draggingLayer != nil;