1 /*
2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
320 animation.getTotalDuration() : animation.getTotalDuration().divide(absRate);
321 final Duration childDuration = totalDuration.add(animation.getDelay());
322 if (childDuration.isIndefinite()) {
323 return Duration.INDEFINITE;
324 } else {
325 if (childDuration.greaterThan(maxTime)) {
326 maxTime = childDuration;
327 }
328 }
329 }
330 return maxTime;
331 }
332
333 private double calculateFraction(long currentTicks, long cycleTicks) {
334 final double frac = (double) currentTicks / cycleTicks;
335 return (frac <= 0.0) ? 0 : (frac >= 1.0) ? 1.0 : frac;
336 }
337
338 private boolean startChild(Animation child, int index) {
339 final boolean forceSync = forceChildSync[index];
340 if (child.impl_startable(forceSync)) {
341 child.clipEnvelope.setRate(rates[index] * Math.signum(getCurrentRate()));
342 child.impl_start(forceSync);
343 forceChildSync[index] = false;
344 return true;
345 }
346 return false;
347 }
348
349 @Override
350 void impl_sync(boolean forceSync) {
351 super.impl_sync(forceSync);
352 if ((forceSync && childrenChanged) || (durations == null)) {
353 cachedChildren = getChildren().toArray(EMPTY_ANIMATION_ARRAY);
354 final int n = cachedChildren.length;
355 durations = new long[n];
356 delays = new long[n];
357 rates = new double[n];
358 offsetTicks = new long[n];
359 forceChildSync = new boolean[n];
360 cycleTime = 0;
361 int i = 0;
362 for (final Animation animation : cachedChildren) {
363 rates[i] = Math.abs(animation.getRate());
364 if (rates[i] < EPSILON) {
365 rates[i] = 1;
366 }
367 durations[i] = fromDuration(animation.getTotalDuration(), rates[i]);
368 delays[i] = fromDuration(animation.getDelay());
369 cycleTime = Math.max(cycleTime, add(durations[i], delays[i]));
370 forceChildSync[i] = true;
371 i++;
372 }
373 childrenChanged = false;
374 } else if (forceSync) {
375 final int n = forceChildSync.length;
376 for (int i=0; i<n; i++) {
377 forceChildSync[i] = true;
378 }
379 }
380 }
381
382 @Override
383 void impl_pause() {
384 super.impl_pause();
385 for (final Animation animation : cachedChildren) {
386 if (animation.getStatus() == Status.RUNNING) {
387 animation.impl_pause();
388 }
389 }
390 }
391
392 @Override
393 void impl_resume() {
394 super.impl_resume();
395 int i = 0;
396 for (final Animation animation : cachedChildren) {
397 if (animation.getStatus() == Status.PAUSED) {
398 animation.impl_resume();
399 animation.clipEnvelope.setRate(rates[i] * Math.signum(getCurrentRate()));
400 }
401 i++;
402 }
403 }
404
405 @Override
406 void impl_start(boolean forceSync) {
407 super.impl_start(forceSync);
408 toggledRate = false;
409 rateProperty().addListener(rateListener);
410 double curRate = getCurrentRate();
411 final long currentTicks = TickCalculation.fromDuration(getCurrentTime());
412 if (curRate < 0) {
413 jumpToEnd();
414 if (currentTicks < cycleTime) {
415 impl_jumpTo(currentTicks, cycleTime, false);
416 }
417 } else {
418 jumpToStart();
419 if (currentTicks > 0) {
420 impl_jumpTo(currentTicks, cycleTime, false);
421 }
422 }
423 }
424
425 @Override
426 void impl_stop() {
427 super.impl_stop();
428 for (final Animation animation : cachedChildren) {
429 if (animation.getStatus() != Status.STOPPED) {
430 animation.impl_stop();
431 }
432 }
433 if (childrenChanged) {
434 setCycleDuration(computeCycleDuration());
435 }
436 rateProperty().removeListener(rateListener);
437 }
438
439
440 /**
441 * @treatAsPrivate implementation detail
442 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
443 */
444 @Deprecated
445 @Override public void impl_playTo(long currentTicks, long cycleTicks) {
446 impl_setCurrentTicks(currentTicks);
447 final double frac = calculateFraction(currentTicks, cycleTicks);
448 final long newTicks = Math.max(0, Math.min(getCachedInterpolator().interpolate(0, cycleTicks, frac), cycleTicks));
449 if (toggledRate) {
450 for (int i = 0; i < cachedChildren.length; ++i) {
451 if (cachedChildren[i].getStatus() == Status.RUNNING) {
452 offsetTicks[i] -= Math.signum(getCurrentRate()) * (durations[i] - 2 * (oldTicks - delays[i]));
453 }
454 }
455 toggledRate = false;
456 }
457 if (getCurrentRate() > 0) {
458 int i = 0;
459 for (final Animation animation : cachedChildren) {
460 if ((newTicks >= delays[i]) && ((oldTicks <= delays[i]) ||
461 ((newTicks < add(delays[i], durations[i])) && (animation.getStatus() == Status.STOPPED)))) {
462 final boolean enteringCycle = oldTicks <= delays[i];
463 if (startChild(animation, i)) {
464 animation.clipEnvelope.jumpTo(0);
465 } else {
466 if (enteringCycle) {
467 final EventHandler<ActionEvent> handler = animation.getOnFinished();
468 if (handler != null) {
469 handler.handle(new ActionEvent(this, null));
470 }
471 }
472 continue;
473 }
474 }
475 if (newTicks >= add(durations[i], delays[i])) {
476 if (animation.getStatus() == Status.RUNNING) {
477 animation.impl_timePulse(sub(durations[i], offsetTicks[i]));
478 offsetTicks[i] = 0;
479 }
480 } else if (newTicks > delays[i]) {
481 animation.impl_timePulse(sub(newTicks - delays[i], offsetTicks[i]));
482 }
483 i++;
484 }
485 } else {
486 int i = 0;
487 for (final Animation animation : cachedChildren) {
488 if (newTicks < add(durations[i], delays[i])) {
489 if ((oldTicks >= add(durations[i], delays[i])) || ((newTicks >= delays[i]) && (animation.getStatus() == Status.STOPPED))){
490 final boolean enteringCycle = oldTicks >= add(durations[i], delays[i]);
491 if (startChild(animation, i)) {
492 animation.clipEnvelope.jumpTo(Math.round(durations[i] * rates[i]));
493 } else {
494 if (enteringCycle) {
495 final EventHandler<ActionEvent> handler = animation.getOnFinished();
496 if (handler != null) {
497 handler.handle(new ActionEvent(this, null));
498 }
499 }
500 continue;
501 }
502 }
503 if (newTicks <= delays[i]) {
504 if (animation.getStatus() == Status.RUNNING) {
505 animation.impl_timePulse(sub(durations[i], offsetTicks[i]));
506 offsetTicks[i] = 0;
507 }
508 } else {
509 animation.impl_timePulse(sub( add(durations[i], delays[i]) - newTicks, offsetTicks[i]));
510 }
511 }
512 i++;
513 }
514 }
515 oldTicks = newTicks;
516 }
517
518 /**
519 * @treatAsPrivate implementation detail
520 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
521 */
522 @Deprecated
523 @Override public void impl_jumpTo(long currentTicks, long cycleTicks, boolean forceJump) {
524 impl_setCurrentTicks(currentTicks);
525 if (getStatus() == Status.STOPPED && !forceJump) {
526 return;
527 }
528 impl_sync(false);
529 final double frac = calculateFraction(currentTicks, cycleTicks);
530 final long newTicks = Math.max(0, Math.min(getCachedInterpolator().interpolate(0, cycleTicks, frac), cycleTicks));
531 int i = 0;
532 for (final Animation animation : cachedChildren) {
533 final Status status = animation.getStatus();
534 if (newTicks <= delays[i]) {
535 offsetTicks[i] = 0;
536 if (status != Status.STOPPED) {
537 animation.clipEnvelope.jumpTo(0);
538 animation.impl_stop();
539 } else if(TickCalculation.fromDuration(animation.getCurrentTime()) != 0) {
540 animation.impl_jumpTo(0, durations[i], true);
541 }
542 } else if (newTicks >= add(durations[i], delays[i])) {
543 offsetTicks[i] = 0;
544 if (status != Status.STOPPED) {
545 animation.clipEnvelope.jumpTo(Math.round(durations[i] * rates[i]));
546 animation.impl_stop();
547 } else if (TickCalculation.fromDuration(animation.getCurrentTime()) != durations[i]) {
548 animation.impl_jumpTo(durations[i], durations[i], true);
549 }
550 } else {
551 if (status == Status.STOPPED) {
552 startChild(animation, i);
553 if (getStatus() == Status.PAUSED) {
554 animation.impl_pause();
555 }
556
557 offsetTicks[i] = (getCurrentRate() > 0)? newTicks - delays[i] : add(durations[i], delays[i]) - newTicks;
558 } else if (status == Status.PAUSED) {
559 offsetTicks[i] += (newTicks - oldTicks) * Math.signum(this.clipEnvelope.getCurrentRate());
560 } else {
561 offsetTicks[i] += (getCurrentRate() > 0) ? newTicks - oldTicks : oldTicks - newTicks;
562 }
563 animation.clipEnvelope.jumpTo(Math.round(sub(newTicks, delays[i]) * rates[i]));
564 }
565 i++;
566 }
567 oldTicks = newTicks;
568 }
569
570 /**
571 * {@inheritDoc}
572 */
573 @Override
574 protected void interpolate(double frac) {
575 // no-op
576 }
577
578 private void jumpToEnd() {
579 for (int i = 0 ; i < cachedChildren.length; ++i) {
580 if (forceChildSync[i]) {
581 // See explanation in SequentialTransition#jumpToEnd
582 cachedChildren[i].impl_sync(true);
583 }
584 cachedChildren[i].impl_jumpTo(durations[i], durations[i], true);
585 }
586 }
587
588 private void jumpToStart() {
589 for (int i = cachedChildren.length - 1 ; i >= 0; --i) {
590 if (forceChildSync[i]) {
591 cachedChildren[i].impl_sync(true);
592 }
593 cachedChildren[i].impl_jumpTo(0, durations[i], true);
594 }
595 }
596
597 }
|
1 /*
2 * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
320 animation.getTotalDuration() : animation.getTotalDuration().divide(absRate);
321 final Duration childDuration = totalDuration.add(animation.getDelay());
322 if (childDuration.isIndefinite()) {
323 return Duration.INDEFINITE;
324 } else {
325 if (childDuration.greaterThan(maxTime)) {
326 maxTime = childDuration;
327 }
328 }
329 }
330 return maxTime;
331 }
332
333 private double calculateFraction(long currentTicks, long cycleTicks) {
334 final double frac = (double) currentTicks / cycleTicks;
335 return (frac <= 0.0) ? 0 : (frac >= 1.0) ? 1.0 : frac;
336 }
337
338 private boolean startChild(Animation child, int index) {
339 final boolean forceSync = forceChildSync[index];
340 if (child.startable(forceSync)) {
341 child.clipEnvelope.setRate(rates[index] * Math.signum(getCurrentRate()));
342 child.doStart(forceSync);
343 forceChildSync[index] = false;
344 return true;
345 }
346 return false;
347 }
348
349 @Override
350 void sync(boolean forceSync) {
351 super.sync(forceSync);
352 if ((forceSync && childrenChanged) || (durations == null)) {
353 cachedChildren = getChildren().toArray(EMPTY_ANIMATION_ARRAY);
354 final int n = cachedChildren.length;
355 durations = new long[n];
356 delays = new long[n];
357 rates = new double[n];
358 offsetTicks = new long[n];
359 forceChildSync = new boolean[n];
360 cycleTime = 0;
361 int i = 0;
362 for (final Animation animation : cachedChildren) {
363 rates[i] = Math.abs(animation.getRate());
364 if (rates[i] < EPSILON) {
365 rates[i] = 1;
366 }
367 durations[i] = fromDuration(animation.getTotalDuration(), rates[i]);
368 delays[i] = fromDuration(animation.getDelay());
369 cycleTime = Math.max(cycleTime, add(durations[i], delays[i]));
370 forceChildSync[i] = true;
371 i++;
372 }
373 childrenChanged = false;
374 } else if (forceSync) {
375 final int n = forceChildSync.length;
376 for (int i=0; i<n; i++) {
377 forceChildSync[i] = true;
378 }
379 }
380 }
381
382 @Override
383 void doPause() {
384 super.doPause();
385 for (final Animation animation : cachedChildren) {
386 if (animation.getStatus() == Status.RUNNING) {
387 animation.doPause();
388 }
389 }
390 }
391
392 @Override
393 void doResume() {
394 super.doResume();
395 int i = 0;
396 for (final Animation animation : cachedChildren) {
397 if (animation.getStatus() == Status.PAUSED) {
398 animation.doResume();
399 animation.clipEnvelope.setRate(rates[i] * Math.signum(getCurrentRate()));
400 }
401 i++;
402 }
403 }
404
405 @Override
406 void doStart(boolean forceSync) {
407 super.doStart(forceSync);
408 toggledRate = false;
409 rateProperty().addListener(rateListener);
410 double curRate = getCurrentRate();
411 final long currentTicks = TickCalculation.fromDuration(getCurrentTime());
412 if (curRate < 0) {
413 jumpToEnd();
414 if (currentTicks < cycleTime) {
415 doJumpTo(currentTicks, cycleTime, false);
416 }
417 } else {
418 jumpToStart();
419 if (currentTicks > 0) {
420 doJumpTo(currentTicks, cycleTime, false);
421 }
422 }
423 }
424
425 @Override
426 void doStop() {
427 super.doStop();
428 for (final Animation animation : cachedChildren) {
429 if (animation.getStatus() != Status.STOPPED) {
430 animation.doStop();
431 }
432 }
433 if (childrenChanged) {
434 setCycleDuration(computeCycleDuration());
435 }
436 rateProperty().removeListener(rateListener);
437 }
438
439 @Override
440 void doPlayTo(long currentTicks, long cycleTicks) {
441 setCurrentTicks(currentTicks);
442 final double frac = calculateFraction(currentTicks, cycleTicks);
443 final long newTicks = Math.max(0, Math.min(getCachedInterpolator().interpolate(0, cycleTicks, frac), cycleTicks));
444 if (toggledRate) {
445 for (int i = 0; i < cachedChildren.length; ++i) {
446 if (cachedChildren[i].getStatus() == Status.RUNNING) {
447 offsetTicks[i] -= Math.signum(getCurrentRate()) * (durations[i] - 2 * (oldTicks - delays[i]));
448 }
449 }
450 toggledRate = false;
451 }
452 if (getCurrentRate() > 0) {
453 int i = 0;
454 for (final Animation animation : cachedChildren) {
455 if ((newTicks >= delays[i]) && ((oldTicks <= delays[i]) ||
456 ((newTicks < add(delays[i], durations[i])) && (animation.getStatus() == Status.STOPPED)))) {
457 final boolean enteringCycle = oldTicks <= delays[i];
458 if (startChild(animation, i)) {
459 animation.clipEnvelope.jumpTo(0);
460 } else {
461 if (enteringCycle) {
462 final EventHandler<ActionEvent> handler = animation.getOnFinished();
463 if (handler != null) {
464 handler.handle(new ActionEvent(this, null));
465 }
466 }
467 continue;
468 }
469 }
470 if (newTicks >= add(durations[i], delays[i])) {
471 if (animation.getStatus() == Status.RUNNING) {
472 animation.doTimePulse(sub(durations[i], offsetTicks[i]));
473 offsetTicks[i] = 0;
474 }
475 } else if (newTicks > delays[i]) {
476 animation.doTimePulse(sub(newTicks - delays[i], offsetTicks[i]));
477 }
478 i++;
479 }
480 } else {
481 int i = 0;
482 for (final Animation animation : cachedChildren) {
483 if (newTicks < add(durations[i], delays[i])) {
484 if ((oldTicks >= add(durations[i], delays[i])) || ((newTicks >= delays[i]) && (animation.getStatus() == Status.STOPPED))){
485 final boolean enteringCycle = oldTicks >= add(durations[i], delays[i]);
486 if (startChild(animation, i)) {
487 animation.clipEnvelope.jumpTo(Math.round(durations[i] * rates[i]));
488 } else {
489 if (enteringCycle) {
490 final EventHandler<ActionEvent> handler = animation.getOnFinished();
491 if (handler != null) {
492 handler.handle(new ActionEvent(this, null));
493 }
494 }
495 continue;
496 }
497 }
498 if (newTicks <= delays[i]) {
499 if (animation.getStatus() == Status.RUNNING) {
500 animation.doTimePulse(sub(durations[i], offsetTicks[i]));
501 offsetTicks[i] = 0;
502 }
503 } else {
504 animation.doTimePulse(sub( add(durations[i], delays[i]) - newTicks, offsetTicks[i]));
505 }
506 }
507 i++;
508 }
509 }
510 oldTicks = newTicks;
511 }
512
513 @Override
514 void doJumpTo(long currentTicks, long cycleTicks, boolean forceJump) {
515 setCurrentTicks(currentTicks);
516 if (getStatus() == Status.STOPPED && !forceJump) {
517 return;
518 }
519 sync(false);
520 final double frac = calculateFraction(currentTicks, cycleTicks);
521 final long newTicks = Math.max(0, Math.min(getCachedInterpolator().interpolate(0, cycleTicks, frac), cycleTicks));
522 int i = 0;
523 for (final Animation animation : cachedChildren) {
524 final Status status = animation.getStatus();
525 if (newTicks <= delays[i]) {
526 offsetTicks[i] = 0;
527 if (status != Status.STOPPED) {
528 animation.clipEnvelope.jumpTo(0);
529 animation.doStop();
530 } else if(TickCalculation.fromDuration(animation.getCurrentTime()) != 0) {
531 animation.doJumpTo(0, durations[i], true);
532 }
533 } else if (newTicks >= add(durations[i], delays[i])) {
534 offsetTicks[i] = 0;
535 if (status != Status.STOPPED) {
536 animation.clipEnvelope.jumpTo(Math.round(durations[i] * rates[i]));
537 animation.doStop();
538 } else if (TickCalculation.fromDuration(animation.getCurrentTime()) != durations[i]) {
539 animation.doJumpTo(durations[i], durations[i], true);
540 }
541 } else {
542 if (status == Status.STOPPED) {
543 startChild(animation, i);
544 if (getStatus() == Status.PAUSED) {
545 animation.doPause();
546 }
547
548 offsetTicks[i] = (getCurrentRate() > 0)? newTicks - delays[i] : add(durations[i], delays[i]) - newTicks;
549 } else if (status == Status.PAUSED) {
550 offsetTicks[i] += (newTicks - oldTicks) * Math.signum(this.clipEnvelope.getCurrentRate());
551 } else {
552 offsetTicks[i] += (getCurrentRate() > 0) ? newTicks - oldTicks : oldTicks - newTicks;
553 }
554 animation.clipEnvelope.jumpTo(Math.round(sub(newTicks, delays[i]) * rates[i]));
555 }
556 i++;
557 }
558 oldTicks = newTicks;
559 }
560
561 /**
562 * {@inheritDoc}
563 */
564 @Override
565 protected void interpolate(double frac) {
566 // no-op
567 }
568
569 private void jumpToEnd() {
570 for (int i = 0 ; i < cachedChildren.length; ++i) {
571 if (forceChildSync[i]) {
572 // See explanation in SequentialTransition#jumpToEnd
573 cachedChildren[i].sync(true);
574 }
575 cachedChildren[i].doJumpTo(durations[i], durations[i], true);
576 }
577 }
578
579 private void jumpToStart() {
580 for (int i = cachedChildren.length - 1 ; i >= 0; --i) {
581 if (forceChildSync[i]) {
582 cachedChildren[i].sync(true);
583 }
584 cachedChildren[i].doJumpTo(0, durations[i], true);
585 }
586 }
587
588 }
|