OSDN Git Service

open
[eliscolors/main.git] / ElisController.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 //  ElisController.m
24 //  Elis Colors
25 //
26 //  Created by 柳 on 09/09/12.
27 //  Copyright 2009 __MyCompanyName__. All rights reserved.
28 //
29
30 #import "ElisController.h"
31
32
33 static float convertQTTimeToSecond(QTTime t)
34 {
35     return (float)t.timeValue/t.timeScale;
36 }
37
38 @implementation ElisController
39
40 - (void)awakeFromNib
41 {
42     layers = [[NSMutableArray alloc] init];
43     _animationLayerFactory = [[ElisAnimationLayerFactory alloc] init];
44     playing = NO;
45     recording = NO;
46     hipTime = 0.0;
47     savePath = nil;
48     
49     ProjectMovieSize = CGRectMake(0, 0, 640, 480);
50     
51     // カスタムフィルタを初期化。
52     [ElisCustomFilter class];
53     
54     NSLog(@"Building effects ...");
55     // エフェクトメニューを構築。
56     [self buildEffectMenu];
57     
58     // テキストフィールドでリッチテキスト編集を許可する。
59 //    [_textLayerField setAllowsEditingTextAttributes:YES];
60     
61     timeLineXShift = 0;
62     usingStampMode = NO;
63     
64 #ifdef __SNOW_LEOPARD_GCD__
65     diq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
66 #endif
67 }
68
69 - (CALayer*)createNewLayer:(NSString*)path
70 {
71     ElisLayer* layer;
72     CALayer* alayer;
73     ElisMedia* m;
74     layer = [[ElisLayer alloc] init];
75     
76     NSWorkspace* sharedWorkspace = [NSWorkspace sharedWorkspace];
77     
78     // 読めるメディアかチェック
79     if([sharedWorkspace type:[sharedWorkspace typeOfFile:path error:nil] 
80               conformsToType:@"public.image"])
81     {
82         m = [[ElisMedia alloc] initWithImageFile:path];
83         alayer = [_animationLayerFactory createNewAnimationLayer:convertQTTimeToSecond([m duration]) 
84                                                             name:[path lastPathComponent] type:@"image"];
85     }
86     else if([sharedWorkspace type:[sharedWorkspace typeOfFile:path error:nil]
87               conformsToType:@"public.audio"])
88     {
89            m = [[ElisMedia alloc] initWithSoundFile:path];
90            alayer = [_animationLayerFactory createNewAnimationLayer:convertQTTimeToSecond([m duration]) 
91                                                                name:[path lastPathComponent] type:@"sound"];
92     }
93     else if([sharedWorkspace type:[sharedWorkspace typeOfFile:path error:nil] 
94                    conformsToType:@"public.movie"] ||
95             [sharedWorkspace type:[sharedWorkspace typeOfFile:path error:nil] 
96                    conformsToType:@"com.apple.quartz-composer-composition"])
97     {
98         m = [[ElisMedia alloc] initWithMovieFile:path];
99         alayer = [_animationLayerFactory createNewAnimationLayer:convertQTTimeToSecond([m duration])
100                                                             name:[path lastPathComponent] type:@"movie"];
101     }
102     else {
103         NSLog(@"error: cannot open %@", path);
104         return nil;
105     }
106
107     layer.media = m;
108 //    [alayer setValue:layer forKey:@"ElisLayer"];
109
110     [layer setAlayer:alayer];
111     [layers addObject:layer];
112     
113     return alayer;
114 }
115
116 - (CALayer*)createNewTextLayer:(NSString*)t
117 {
118 //    [_textLayerField selectAll:nil];
119 //    NSAttributedString* as = [[NSAttributedString alloc]
120 //                              initWithRTF:[_textLayerField RTFFromRange:[_textLayerField selectedRange]] documentAttributes:nil];
121     NSAttributedString* as = [_textLayerField attributedString];
122     ElisLayer* layer = [[ElisLayer alloc] init];
123     ElisMedia* m = [[ElisMedia alloc] initWithText:as];
124     CALayer* cal = [_animationLayerFactory createNewAnimationLayer:convertQTTimeToSecond([m duration])
125                                                               name:@"text" type:@"text"];
126     
127     layer.media = m;
128     [layer setAlayer:cal];
129     [layers addObject:layer];
130     
131     return cal;
132 }
133
134 // 絶対時間qttimeと関係があるレイヤーをまとめて返す。
135 - (void)getFrameForTime:(QTTime)qttime result:(NSMutableArray*)layerSet
136 {
137     int size = [layers count];
138     
139     // 再生時間オーバー。停止。
140     if(convertQTTimeToSecond(qttime) >= hipTime){
141         [_mainView stopDisplayLink];
142         [self stop:qttime];
143         [_playstopButton setState:NSOffState];
144         return;
145     }
146     
147     globalCurrentTime = qttime;
148     [self moveSliderTo:qttime];
149     [_tableController reload];
150     
151     // GCD使ってみたら画面がちらつく。どういうことなの...?
152 #ifdef __SNOW_LEOPARD_GCD__
153     dispatch_apply(size, diq, ^(size_t i) {
154         ElisLayer* l = [layers objectAtIndex:i];
155         if([l isInclude:qttime]){
156             if(playing) [l play];
157             [layerSet addObject:l];
158         }else{
159             if(playing) [l stop];
160         }
161     });
162 #else
163     // GCDなりOpenMPなりで並列化すること。
164     int i;
165     ElisLayer* l;
166     for(i = 0; i < size; i++){
167         l = [layers objectAtIndex:i];
168         if([l isInclude:qttime]){
169             if(playing) [l play];
170             [layerSet addObject:l];
171         }else{
172             if(playing) [l stop];
173         }
174     }
175 #endif
176 }
177
178 - (void)play:(QTTime)time
179 {
180     NSMutableArray* interestLayers = [[NSMutableArray alloc] init];
181     int i, size = [layers count];
182     
183     hipTime = [self getHipTime];
184     
185     for(i = 0; i < size; i++)
186         if([[layers objectAtIndex:i] isInclude:time])
187             [interestLayers addObject:[layers objectAtIndex:i]];
188     
189     size = [interestLayers count];
190
191     for(i = 0; i < size; i++)
192         [(ElisLayer*)[interestLayers objectAtIndex:i] play];
193     
194     playing = YES;
195 }
196
197 - (void)stop:(QTTime)time
198 {
199 //    NSMutableArray* interestLayers = [[NSMutableArray alloc] init];
200     int i, size = [layers count];
201     
202 //    hipTime = [self getHipTime];
203 //    
204 //    for(i = 0; i < size; i++)
205 ////        if([[layers objectAtIndex:i] isInclude:time])
206 //        [interestLayers addObject:[layers objectAtIndex:i]];
207 //    
208 //    size = [interestLayers count];
209 //    
210 //    for(i = 0; i < size; i++)
211 //        [(ElisLayer*)[interestLayers objectAtIndex:i] stop];
212     
213     for(i = 0; i < size; i++)
214         [(ElisLayer*)[layers objectAtIndex:i] stop];
215     
216     playing = NO;
217     globalCurrentTime = time;
218     _currentTime = time;
219 }
220
221 - (IBAction)startPlay:(id)sender
222 {
223     hipTime = [self getHipTime];
224     QTTime currentTime = QTMakeTime([timeSlider floatValue] * hipTime * DEFAULT_FPS, DEFAULT_FPS);
225     [self seek:currentTime];
226     [self play:currentTime];
227     [_mainView startDisplayLink];
228 }
229
230 - (IBAction)stopPlay:(id)sender
231 {
232     hipTime = [self getHipTime];
233     QTTime currentTime = QTMakeTime([timeSlider floatValue] * hipTime * DEFAULT_FPS, DEFAULT_FPS);
234     [self stop:currentTime];
235     [_mainView stopDisplayLink];
236 }
237     
238 - (float)getHipTime
239 {
240     int i, size = [layers count];
241     float hipTimeSecond = 0.0f, candidate;
242     
243     for(i = 0; i < size; i++){
244         candidate = convertQTTimeToSecond([[layers objectAtIndex:i] mapping].time)
245                     + convertQTTimeToSecond([[layers objectAtIndex:i] mapping].duration);
246         if(candidate > hipTimeSecond)
247             hipTimeSecond = candidate;
248     }
249
250     return hipTimeSecond;
251 }
252
253 - (void)moveSliderTo:(QTTime)time
254 {
255     float now = convertQTTimeToSecond(time);
256     [timeSlider setFloatValue:now/hipTime];
257     [timeCodeField setStringValue:QTStringFromTime(QTMakeTime(now * DEFAULT_FPS, DEFAULT_FPS))];
258     [_timeLineController movePlaybackBar:now*timeLineScale];
259 }
260
261 - (IBAction)timeSliderChanged:(id)sender
262 {
263     float seconds = [sender floatValue];
264     QTTime currentTime = QTMakeTime(seconds * hipTime * DEFAULT_FPS, DEFAULT_FPS);
265     [timeCodeField setStringValue:QTStringFromTime(currentTime)];
266     _currentTime = currentTime;
267     globalCurrentTime = currentTime;
268     [self refresh];
269 }
270
271 - (void)seek:(QTTime)time
272 {
273     int i, size = [layers count];
274     [_mainView seek:time];
275
276     for(i = 0; i < size; i++)
277         [[layers objectAtIndex:i] seek:time];
278 }
279
280 - (void)refresh
281 {
282     if(playing) return;
283     hipTime = [self getHipTime];
284     [_mainView getFrameForQTTime:_currentTime];
285 }
286
287 - (void)getSoundTrack:(NSMutableArray*)soundTrack
288 {
289     int i, size = [layers count];
290     for(i = 0; i < size; i++)
291         [[layers objectAtIndex:i] getSoundTrack:soundTrack];
292 }
293
294 - (IBAction)deleteSelectLayer:(id)sender
295 {
296     CALayer* selected = [_timeLineController getSelectLayer];
297     ElisLayer* layer = [selected valueForKey:@"ElisLayer"];
298     
299     [layers removeObject:layer];
300     [selected removeFromSuperlayer];
301     [_timeLineController removeSelectLayer];
302     [_tableController createPropertyTable:nil];
303     [_tableController reload];
304     [self refresh];
305 }
306
307 - (IBAction)recordingStateChanged:(id)sender
308 {
309     recording = !recording;
310 }
311
312 - (IBAction)removeAllKeyFrame:(id)sender
313 {
314     [_tableController removeAllKeyframe];
315     [self refresh];
316 }
317
318 - (IBAction)removeEffect:(id)sender
319 {
320     [_tableController removeEffect];
321     [self refresh];
322 }
323
324 - (IBAction)writeToFile:(id)sender
325 {
326     NSSavePanel* sp = [NSSavePanel savePanel];
327     
328     [sp setRequiredFileType:@"mov"];
329     [sp beginSheetForDirectory:nil
330                           file:nil 
331                 modalForWindow:_mainWindow
332                  modalDelegate:self
333                 didEndSelector:@selector(writeMovie:returnCode:contextInfo:)
334                    contextInfo:NULL];
335 }
336
337 - (void)writeMovie:(NSSavePanel*)sheet returnCode:(int)code contextInfo:(void*)info
338 {
339     NSString* path = [sheet filename];
340     
341     if(code == NSCancelButton) return;
342     [sheet close];
343     
344     ElisWriterLegacy* writer;
345     writer = [[ElisWriterLegacy alloc] init];
346     [writer setMainWindow:_mainWindow];
347     [writer setMainController:self];
348     [writer setMainView:_mainView];
349     
350 //    [_writer write:sheet];
351     [NSThread detachNewThreadSelector:@selector(write:) toTarget:writer withObject:sheet];
352 }
353
354 // エフェクトのメニュー項目を構築
355 - (void)buildEffectMenu
356 {
357     NSArray* filterNames;
358     CIFilter* filter;
359     NSDictionary* attrs;
360     filterNames = [CIFilter filterNamesInCategories:[NSArray arrayWithObjects:
361                                                      kCICategoryDistortionEffect,
362                                                      kCICategoryGeometryAdjustment,
363                                                      kCICategoryCompositeOperation,
364                                                      kCICategoryHalftoneEffect,
365                                                      kCICategoryColorAdjustment,
366                                                      kCICategoryColorEffect,
367                                                      kCICategoryTransition,
368                                                      kCICategoryTileEffect,
369                                                      kCICategoryGenerator,
370                                                      kCICategoryGradient,
371                                                      kCICategoryStylize,
372                                                      kCICategorySharpen,
373                                                      kCICategoryBlur,
374                                                      nil]];
375     
376     NSString* name;
377     NSArray* inputKeys;
378     id elm;
379     NSMenuItem* item = [[NSMenuItem alloc] init], *child;
380     NSMenu* menu = [[NSMenu alloc] init];
381     int c = 0;
382     
383     [item setTitle:@"Effect"];
384     [menu setTitle:@"Effect"];
385     
386     filterNames = [CIFilter filterNamesInCategory:kCICategoryBuiltIn];
387     
388     for(name in filterNames){
389         filter = [CIFilter filterWithName:name];
390         attrs = [filter attributes];
391         inputKeys = [filter inputKeys];
392         if([inputKeys count] == 1) goto jimp;
393         for(elm in inputKeys){
394             if([elm isEqualToString:@"inputImage"]) continue;
395             if([[[attrs valueForKey:elm] valueForKey:kCIAttributeClass] isEqualToString:@"CIVector"]){
396                 if([[[attrs valueForKey:elm] valueForKey:kCIAttributeDefault] count] == 2) goto ok;
397             }
398             if(!([[[attrs valueForKey:elm] valueForKey:kCIAttributeClass] isEqualToString:@"NSNumber"] || 
399                  [[[attrs valueForKey:elm] valueForKey:kCIAttributeClass] isEqualToString:@"CIColor"])){
400                 goto jimp;
401             }
402         }
403     ok:
404         child = [[[NSMenuItem alloc] init] autorelease];
405         [child setTitle:name];
406         [child setAction:@selector(effectMenuPushed:)];
407         [child setTarget:self];
408         c++;
409         
410         [menu addItem:child];
411         
412     jimp:
413         ; // ラベルの後ろには必ずstatementがないといけないらしい。なんで?
414     }
415     NSLog(@"%d effetcs usable.", c);
416     [item setSubmenu:menu];
417     [menu setAutoenablesItems:NO];
418     [item setEnabled:YES];
419     [menu release];
420     [[NSApp mainMenu] insertItem:item atIndex:5];
421     [item setTarget:self];
422 }
423
424 - (void)effectMenuPushed:(id)sender
425 {
426     CALayer* l;
427     l = [_timeLineController getSelectLayer];
428     [[l valueForKey:@"ElisLayer"] addEffect:[sender title]];
429     [self refresh];
430     [_tableController createPropertyTable:[l valueForKey:@"ElisLayer"]];
431     [_undoManager pushOperation:[l valueForKey:@"ElisLayer"]];
432     [_tableController reload];
433 }
434
435 - (void)saveProjectToFile:(NSSavePanel*)sheet returnCode:(int)code contextInfo:(void*)info
436 {
437     NSString* path = [sheet filename];
438     NSMutableData* data = [NSMutableData data];
439     NSKeyedArchiver* encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
440     
441     [encoder encodeObject:layers forKey:@"layers"];
442     [encoder encodeFloat:ProjectMovieSize.size.width forKey:@"movieWidth"];
443     [encoder encodeFloat:ProjectMovieSize.size.height forKey:@"movieHeight"];
444     [encoder encodeObject:ELIS_VERSION forKey:@"version"];
445     [encoder finishEncoding];
446     
447     savePath = path;
448     
449     [data writeToFile:path atomically:YES];
450 }
451
452 - (void)loadProjectFromFile:(NSString*)path
453 {
454     NSMutableData* data = [NSMutableData dataWithContentsOfFile:path];
455     NSKeyedUnarchiver* decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
456     float w, h;
457     
458     [_timeLineController awakeFromNib]; // これはひどい。
459     layers = [decoder decodeObjectForKey:@"layers"];
460     w = [decoder decodeFloatForKey:@"movieWidth"];
461     h = [decoder decodeFloatForKey:@"movieHeight"];
462     [decoder finishDecoding];
463     
464     ProjectMovieSize.size.width = w;
465     ProjectMovieSize.size.height = h;
466     
467     int i, size = [layers count];
468     ElisLayer* l;
469     CALayer* al;
470     
471     for(i = 0; i < size; i++){
472         l = [layers objectAtIndex:i];
473         al = [_animationLayerFactory createNewAnimationLayer:[l duration] name:[l printName] type:[l getType]];
474         [l setLayer:al];
475         [_timeLineController addLayer:al];
476     }
477     
478     savePath = path;
479     
480     [self refresh];
481 }
482
483 - (IBAction)openProjectSaveDialog:(id)sender
484 {
485     NSSavePanel* sp = [NSSavePanel savePanel];
486     
487     [sp setRequiredFileType:@"elis"];
488     [sp beginSheetForDirectory:nil
489                           file:nil 
490                 modalForWindow:_mainWindow
491                  modalDelegate:self
492                 didEndSelector:@selector(saveProjectToFile:returnCode:contextInfo:)
493                    contextInfo:NULL];
494 }
495
496 - (IBAction)openProjectLoadDialog:(id)sender
497 {
498     NSOpenPanel* op = [NSOpenPanel openPanel];
499     
500     int st;
501     st = [op runModalForTypes:[NSArray arrayWithObject:@"elis"]];
502     
503     if(st == NSOKButton)
504         [self loadProjectFromFile:[op filename]];
505 }
506
507 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
508 {
509     if([menuItem action] == @selector(rewriteProject:))
510         return savePath != nil;
511     
512 //    if([menuItem action] == @selector(removeAllKeyFrame:))
513 //        return [_tableController canRemoveAllKeyframe];
514     
515     if([menuItem action] == @selector(removeEffect:))
516         return [_tableController canRemoveEffect];
517     
518     if([menuItem action] == @selector(deleteSelectLayer:))
519         return [_timeLineController canDeleteLayer];
520     
521     if([menuItem action] == @selector(undo:))
522         return [_undoManager canUndo];
523     
524     if([menuItem action] == @selector(redo:))
525         return [_undoManager canRedo];
526     
527     if([menuItem action] == @selector(changeMovieSpeed:))
528         return [self canChangeMovieSpeed];
529     
530     if([menuItem action] == @selector(cutLayerAtCurrentTime:))
531         return [_timeLineController canDeleteLayer];
532     
533     return YES;
534 }
535
536 - (IBAction)rewriteProject:(id)sender
537 {
538     NSMutableData* data = [NSMutableData data];
539     NSKeyedArchiver* encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
540     
541     [encoder encodeObject:layers forKey:@"layers"];
542     [encoder encodeFloat:ProjectMovieSize.size.width forKey:@"movieWidth"];
543     [encoder encodeFloat:ProjectMovieSize.size.height forKey:@"movieHeight"];
544     [encoder finishEncoding];
545     
546     [data writeToFile:savePath atomically:YES];
547 }
548
549 - (IBAction)changeToSmallWindiw:(id)sender
550 {
551     [_mainWindow close];
552     [NSBundle loadNibNamed:@"MainMenuForSmallDisplay" owner:self];
553 }
554
555 - (IBAction)undo:(id)sender
556 {
557     ElisLayer* l = [_undoManager popOperation];
558     [self refresh];
559     [_timeLineController updateKeyframeLayer];
560     [_tableController createPropertyTable:l];
561     [_tableController reload];
562 }
563
564 - (IBAction)redo:(id)sender
565 {
566     [_undoManager redoOperation];
567     [self refresh];
568     [_timeLineController updateKeyframeLayer];
569     [_tableController reload];
570 }
571
572 - (IBAction)changeMovieSize:(id)sender
573 {
574     ElisMovieSizeWindowController* c;
575     c = [[ElisMovieSizeWindowController alloc] init];
576     
577     [c setMainWindow:_mainWindow];
578     [c setMainView:_mainView];
579     [c run];
580 }
581
582 - (IBAction)preference:(id)sender
583 {
584     ElisPreferenceController*c;
585     c = [[ElisPreferenceController alloc] init];
586     
587     [c setMainWindow:_mainWindow];
588     [c run];
589 }
590
591 - (void)textDidChange:(NSNotification*)n
592 {
593     CALayer* l = [_timeLineController getSelectLayer];
594     ElisLayer* layer;
595     if(l == nil) return;
596     
597     layer = [l valueForKey:@"ElisLayer"];
598     if([[[layer  media] type] isEqualToString:@"text"]){
599         NSAttributedString* s = [_textLayerField attributedString];
600         [[layer media] setText:s];
601         [self refresh];
602     }
603     
604 }
605
606 - (IBAction)changeMovieSpeed:(id)sender
607 {
608     ElisMovieSpeedController* c;
609     c = [[ElisMovieSpeedController alloc] init];
610     
611     [_undoManager pushOperation:[[_timeLineController getSelectLayer] valueForKey:@"ElisLayer"]];
612     
613     [c setMainWindow:_mainWindow];
614     [c setLayer:[[_timeLineController getSelectLayer] valueForKey:@"ElisLayer"]];
615     [c run];
616     
617     [self refresh];
618 }
619
620 - (BOOL)canChangeMovieSpeed
621 {
622     CALayer* l;
623     l = [_timeLineController getSelectLayer];
624     if(l == nil) return NO;
625     if([[[[l valueForKey:@"ElisLayer"] media] type] isEqualToString:@"movie"]) return YES;
626     return NO;
627 }
628
629 - (IBAction)gotoNextKeyTime:(id)sender
630 {
631     float currentTime = [self getHipTime] * [timeSlider floatValue];
632     NSMutableArray* array = [[NSMutableArray alloc] init];
633     ElisLayer* l;
634     QTTime nextTime;
635     int i, size = [layers count];
636     
637     for(i = 0; i < size; i++){
638         [array addObject:[NSNumber numberWithFloat:0.0]];
639         [array addObject:[NSNumber numberWithFloat:convertQTTimeToSecond([[layers objectAtIndex:i] mapping].time)]];
640         [array addObject:[NSNumber numberWithFloat:convertQTTimeToSecond([[layers objectAtIndex:i] mapping].time) + 
641                           convertQTTimeToSecond([[layers objectAtIndex:i] mapping].duration)]];
642     }
643     
644     [array sortUsingSelector:@selector(compare:)];
645     size = [array count];
646     
647     for(i = 0; i < size; i++)
648         if([[array objectAtIndex:i] floatValue] > currentTime){
649             nextTime = QTMakeTime(([[array objectAtIndex:i] floatValue] +1.0/60.0)* DEFAULT_FPS, DEFAULT_FPS);
650             globalCurrentTime = nextTime;
651             _currentTime = nextTime;
652             [self moveSliderTo:nextTime];
653             [self refresh];
654             return;
655         }
656 }
657
658 - (IBAction)gotoPrevKeyTime:(id)sender
659 {
660     float currentTime = [self getHipTime] * [timeSlider floatValue];
661     NSMutableArray* array = [[NSMutableArray alloc] init];
662     ElisLayer* l;
663     QTTime nextTime;
664     int i, size = [layers count];
665     
666     for(i = 0; i < size; i++){
667         [array addObject:[NSNumber numberWithFloat:0.0]];
668         [array addObject:[NSNumber numberWithFloat:convertQTTimeToSecond([[layers objectAtIndex:i] mapping].time)]];
669         [array addObject:[NSNumber numberWithFloat:convertQTTimeToSecond([[layers objectAtIndex:i] mapping].time) + 
670                           convertQTTimeToSecond([[layers objectAtIndex:i] mapping].duration)]];
671     }
672     
673     [array sortUsingSelector:@selector(compare:)];
674     size = [array count];
675     
676     for(i = size-1; i >= 0; i--)
677         if([[array objectAtIndex:i] floatValue] < currentTime){
678 //            if(i % 2 != 0)
679 //                nextTime = QTMakeTime(([[array objectAtIndex:i] floatValue] -1.0/60)* DEFAULT_FPS, DEFAULT_FPS);
680 //            else
681 //                nextTime = QTMakeTime(([[array objectAtIndex:i] floatValue] +1.0/60)* DEFAULT_FPS, DEFAULT_FPS);
682             nextTime = QTMakeTime(([[array objectAtIndex:i] floatValue] +0.0/60)* DEFAULT_FPS, DEFAULT_FPS);
683             globalCurrentTime = nextTime;
684             _currentTime = nextTime;
685             [self moveSliderTo:nextTime];
686             [self refresh];
687             return;
688         }
689 }
690
691 - (IBAction)cutLayerAtCurrentTime:(id)sender
692 {
693     ElisLayer* layer = [[_timeLineController getSelectLayer] valueForKey:@"ElisLayer"];
694     ElisLayer* new;
695
696     new = [layer cutAtTime:globalCurrentTime];
697     [layers addObject:new];
698     
699     [_timeLineController addLayer:[new alayer]];
700 }
701
702 - (IBAction)playStop:(id)sender
703 {
704     if(playing) [self stopPlay:nil];
705     else [self startPlay:nil];
706 }
707
708 @end