OSDN Git Service

add undo/redo system
[eliscolors/main.git] / ElisTimeLineController.m
1 //  Copyright (c) 2009 Yanagi Asakura
2 //
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.
6 //
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:
10 //
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.
15 //
16 //  2. Altered source versions must be plainly marked as such, and must not be
17 //  misrepresented as being the original software.
18 //
19 //  3. This notice may not be removed or altered from any source
20 //  distribution.
21
22 //
23 //  ElisTimeLineController.m
24 //  Elis Colors
25 //
26 //  Created by 柳 on 09/09/12.
27 //  Copyright 2009 __MyCompanyName__. All rights reserved.
28 //
29
30 #import "ElisTimeLineController.h"
31
32
33 @implementation ElisTimeLineController
34
35 - (void)awakeFromNib
36 {
37     NSLog(@"Building TimeLine ...");
38     
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];
43
44     timeLineScale = 10.0; // 10倍表示
45     
46     rootLayer = [CALayer layer];
47     timeLine = [CALayer layer];
48     playbackBar = [CALayer layer];
49     
50     rootLayer.backgroundColor = CGColorCreateGenericGray(0, 0.4f);
51     playbackBar.contents = (id)bar;
52     playbackBar.frame = CGRectMake(0, 0, 1, 51*TRACK_MAX);
53     
54     int i;
55     CALayer* track;
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;
60         track.opacity = 0.35;
61         track.autoresizingMask = kCALayerWidthSizable;
62         [timeLine addSublayer:track];
63     }
64     timeLine.autoresizingMask = kCALayerWidthSizable;
65     
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;
70     
71     [rootLayer addSublayer:timeLine];
72     [rootLayer addSublayer:playbackBar];
73     [_timeLineView setLayer:rootLayer];
74     [_timeLineView setWantsLayer:YES];
75
76     draggingLayer = nil;
77     clickedPosition.x = -1;
78     dragging = NO;
79     _layerFactory = [[ElisAnimationLayerFactory alloc] init];
80 }
81
82 - (void)movePlaybackBar:(float)p
83 {
84     // 自動スクロールはうまくできないので無効にしてある。
85     // 再生中にフリーズするよ! よ!
86 //    NSRect r = [_timeLineView visibleRect];
87 //    if(p > r.origin.x){
88 //        r.origin.x += 2;
89 //        [_timeLineView scrollPoint:r.origin];
90 //    }
91     [CATransaction begin];
92     [CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration];
93     CGPoint po = playbackBar.position;
94     po.x = p;
95     playbackBar.position = po;
96     [CATransaction commit];
97 }
98
99 - (void)addMedia:(NSString*)path
100 {
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"]];
107 }
108
109 - (void)readyInDrag:(NSPoint)p
110 {
111     clickedPosition = p;
112     clickedLayerPosition = *(CGPoint*)&p;
113 }
114
115 - (void)dragging:(NSPoint)point
116 {
117     if(draggingLayer == nil) return;
118     
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];
125         }
126         return;
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];
135         }
136         return;
137     }
138     
139     if(dragging == NO) dragging = YES;
140     if(clickedPosition.x == -1 && NO){
141         NSLog(@"called? %f", point.x);
142 //        point.x -= 600;
143 //        point.y -= 25;
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);
149     } /*else*/ {
150         float dx = clickedPosition.x - point.x;
151         float dy = clickedPosition.y - point.y;
152         point = NSMakePoint(clickedLayerPosition.x - dx, clickedLayerPosition.y - dy);
153     }
154     [self changeLayerPosition:draggingLayer position:point];
155 }
156
157 - (void)draggingDone
158 {
159     if(draggingLayer == nil) return;
160     if(dragging){
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"]];
166         draggingLayer = nil;
167         clickedPosition.x = -1;
168         dragging = NO;
169 //        [_timeLineView setCursorRect:NSZeroRect]; // これなに?
170     }
171     if(stretch != 0) [_undoManager pushOperation:[draggingLayer valueForKey:@"ElisLayer"]];
172     [_timeLineView setCursorRect:draggingLayer.frame];
173     stretch = 0;
174 }
175
176 - (void)changeLayerPosition:(CALayer*)layer position:(NSPoint)point
177 {
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の構造が変わったので再描画を要請。ループしないよう注意。
186 }
187
188 - (void)changeLayerFrame:(CALayer*)layer rect:(CGRect)rect
189 {
190     [CATransaction begin];
191     [CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration];
192     layer.frame = rect;
193     [CATransaction commit];
194     [_mainController refresh];
195 }
196
197 - (IBAction)add:(id)sender
198 {
199     [self addMedia:@"/Users/yanagi/Desktop/59926_2_m1_1.mp4"];
200     NSValue* v = [draggingLayer valueForKey:@"frame"];
201     NSRect r = [v rectValue];
202     r.origin.x = 0;
203 //    [draggingLayer willChangeValueForKey:@"frame"];
204     [draggingLayer setValue:[NSValue valueWithRect:r] forKey:@"frame"];
205 //    [draggingLayer didChangeValueForKey:@"frame"];
206 }
207
208 - (void)clicked:(NSPoint)point
209 {
210     if(draggingLayer){
211         draggingLayer.opacity = 0.75;
212         draggingLayer = nil;
213         [_tableController createPropertyTable:nil];
214         [_tableController reload];
215     }
216     
217     NSArray* layers;
218     int i, size;
219
220     layers = [timeLine sublayers];
221     size = [layers count];
222     dragging = NO;
223     
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"]];
235             return;
236         }
237     }
238     if(draggingLayer){ // これなに?
239         draggingLayer.opacity = 0.75;
240         draggingLayer = nil;
241     }
242     clickedPosition.x = -1; // "レイヤーは選択されていない" という意味。
243     stretch = 0;
244 }
245
246 - (void)doubleClicked
247 {
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で回収されるようにする
253         return;
254     }
255     
256     CALayer* keyframeLayer;
257     keyframeLayer = [_layerFactory createKeyframeLayerWithLayer:draggingLayer];
258     
259     float size = draggingLayer.frame.size.width;
260     float x;
261     CGRect r;
262     CALayer *miniLayer;
263     
264     [draggingLayer addSublayer:keyframeLayer];
265     [draggingLayer setValue:[NSNumber numberWithBool:YES] forKey:@"have keyframeLayer"];
266     
267     if([_tableController isSelected] == NO)
268         [_tableController selectDefault];
269     
270     for(x = 0.0; x < size-1; x += MINI_LAYER_WIDTH){
271         miniLayer = [_layerFactory createKeyframeLevelLayer];
272         r = miniLayer.frame;
273         r.size.height = 100 * [_tableController getSelectedValueForTime:x];
274         r.origin.x = x;
275         miniLayer.frame = r;
276         [keyframeLayer addSublayer:miniLayer];
277     }
278         
279 }
280
281 - (void)updateKeyframeLayer
282 {
283     if(draggingLayer == nil) return;
284     if([[draggingLayer valueForKey:@"have keyframeLayer"] boolValue] == NO) return;
285     
286     NSArray* minis;
287     minis = [[[draggingLayer sublayers] lastObject] sublayers];
288     CALayer* mini;
289     CGRect r;
290     
291     int i, size = [minis count];
292     for(i = 0; i < size; i++){
293         mini = [minis objectAtIndex:i];
294         r = mini.frame;
295         r.size.height = 100 * [_tableController getSelectedValueForTime:i * MINI_LAYER_WIDTH];
296         mini.frame = r;
297     }
298 }
299     
300 // 左側のマッピングを調整する。(レイヤー内オフセットをいじる)
301 - (void)stretchLeft
302 {
303     stretch = STRETCH_LEFT;
304 }
305
306 // 右側のマッピングを調整する。(マッピングの範囲を変えるだけ)
307 - (void)stretchRight
308 {
309     stretch = STRETCH_RIGHT;
310 }
311
312 - (BOOL)isInclude:(CALayer*)layer point:(NSPoint)point
313 {
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;
317 }
318
319 - (CALayer*)getSelectLayer
320 {
321     return draggingLayer;
322 }
323
324 - (void)removeSelectLayer
325 {
326     [draggingLayer setValue:nil forKey:@"ElisLayer"];
327     draggingLayer = nil;
328 }
329
330 - (void)addLayer:(CALayer*)l
331 {
332     [timeLine addSublayer:l];
333 }
334
335 - (BOOL)canDeleteLayer
336 {
337     return draggingLayer != nil;
338 }
339
340 @end