/*
* AnimationHelper.java
*
* Copyright (C) 2009-12 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.core.client.layout;
import com.google.gwt.layout.client.Layout;
import com.google.gwt.user.client.ui.Widget;
import org.rstudio.core.client.theme.WindowFrame;
import static org.rstudio.core.client.layout.WindowState.*;
class AnimationHelper
{
public static AnimationHelper create(BinarySplitLayoutPanel panel,
LogicalWindow top,
LogicalWindow bottom,
int normal,
int splitterHeight,
boolean animate,
boolean skipFocusChange)
{
boolean focusGoesOnTop = animate && focusGoesOnTop(top, bottom);
int splitterPos;
boolean splitterPosFromTop;
if (bottom.getState() == WindowState.NORMAL)
{
splitterPos = normal;
splitterPosFromTop = false;
}
else if (top.getState() == WindowState.HIDE)
{
splitterPos = -splitterHeight;
splitterPosFromTop = true;
}
else if (bottom.getState() == WindowState.HIDE)
{
splitterPos = -splitterHeight;
splitterPosFromTop = false;
}
else if (top.getState() == WindowState.MINIMIZE)
{
splitterPos = top.getMinimized().getDesiredHeight();
splitterPosFromTop = true;
}
else if (bottom.getState() == WindowState.MINIMIZE)
{
splitterPos = bottom.getMinimized().getDesiredHeight();
splitterPosFromTop = false;
}
else
{
throw new RuntimeException("Unexpected condition");
}
return new AnimationHelper(panel,
getVisible(top),
getVisible(bottom),
top.getNormal(),
bottom.getNormal(),
top.getActiveWidget(),
bottom.getActiveWidget(),
splitterPos,
splitterPosFromTop,
bottom.getState() == WindowState.NORMAL,
animate,
focusGoesOnTop,
skipFocusChange);
}
private static Widget getVisible(LogicalWindow window)
{
return window.getNormal().isVisible() ? window.getNormal() :
window.getMinimized().isVisible() ? window.getMinimized() :
null;
}
public AnimationHelper(BinarySplitLayoutPanel panel,
Widget startWidgetTop,
Widget startWidgetBottom,
Widget animWidgetTop,
Widget animWidgetBottom,
Widget endWidgetTop,
Widget endWidgetBottom,
int endSplitterPos,
boolean splitterPosFromTop,
boolean splitterVisible,
boolean animate,
boolean focusGoesOnTop,
boolean skipFocusChange)
{
panel_ = panel;
startWidgetTop_ = startWidgetTop;
startWidgetBottom_ = startWidgetBottom;
animWidgetTop_ = animWidgetTop;
animWidgetBottom_ = animWidgetBottom;
endWidgetTop_ = endWidgetTop;
endWidgetBottom_ = endWidgetBottom;
endSplitterPos_ = endSplitterPos;
splitterPosFromTop_ = splitterPosFromTop;
splitterVisible_ = splitterVisible;
animate_ = animate;
focusGoesOnTop_ = focusGoesOnTop;
skipFocusChange_ = skipFocusChange;
}
public void animate()
{
panel_.setSplitterVisible(false);
if (startWidgetTop_ != animWidgetTop_)
panel_.setTopWidget(animWidgetTop_, true);
if (startWidgetBottom_ != animWidgetBottom_)
panel_.setBottomWidget(animWidgetBottom_, true);
panel_.forceLayout();
panel_.setSplitterPos(endSplitterPos_,
splitterPosFromTop_);
if (animate_)
{
panel_.animate(250, new Layout.AnimationCallback()
{
public void onAnimationComplete()
{
finish();
if (skipFocusChange_)
return;
((WindowFrame)(focusGoesOnTop_
? endWidgetTop_
: endWidgetBottom_)).focus();
}
public void onLayout(Layout.Layer layer, double progress)
{
}
});
}
else
{
finish();
}
}
private void finish()
{
panel_.setSplitterVisible(splitterVisible_);
if (animWidgetTop_ != endWidgetTop_)
panel_.setTopWidget(endWidgetTop_, true);
if (animWidgetBottom_ != endWidgetBottom_)
panel_.setBottomWidget(endWidgetBottom_, true);
if (endWidgetTop_ != startWidgetTop_)
setParentZindex(startWidgetTop_, -10);
setParentZindex(endWidgetTop_, 0);
if (endWidgetBottom_ != startWidgetBottom_)
setParentZindex(startWidgetBottom_, -10);
setParentZindex(endWidgetBottom_, 0);
panel_.onResize();
}
private static boolean focusGoesOnTop(LogicalWindow top, LogicalWindow bottom)
{
// If one window is maximized and the other is minimized, focus the
// maximized one.
WindowState topState = top.getState();
WindowState bottomState = bottom.getState();
if (topState == WindowState.MAXIMIZE && bottomState == WindowState.MINIMIZE)
return true;
else if (topState == WindowState.MINIMIZE && bottomState == WindowState.MAXIMIZE)
return false;
// If both windows are "normal", focus the one that was previously
// minimized.
if (top.getState() == MAXIMIZE || bottom.getState() == MAXIMIZE ||
top.getState() == EXCLUSIVE || bottom.getState() == EXCLUSIVE)
{
assert top.getState() == MINIMIZE || bottom.getState() == MINIMIZE
|| top.getState() == HIDE || bottom.getState() == HIDE;
// If one of the windows is minimized, focus the other one.
return top.getState() == MAXIMIZE || top.getState() == EXCLUSIVE;
}
assert top.getState() == NORMAL && bottom.getState() == NORMAL;
assert top.getNormal().isVisible() || bottom.getNormal().isVisible();
return !top.getNormal().isVisible();
}
public static void setParentZindex(Widget widget, int zIndex)
{
if (widget != null)
widget.getElement().getParentElement().getStyle().setZIndex(zIndex);
}
BinarySplitLayoutPanel panel_;
Widget startWidgetTop_;
Widget startWidgetBottom_;
Widget animWidgetTop_;
Widget animWidgetBottom_;
Widget endWidgetTop_;
Widget endWidgetBottom_;
int endSplitterPos_;
boolean splitterPosFromTop_;
boolean splitterVisible_;
private final boolean animate_;
private final boolean focusGoesOnTop_;
private final boolean skipFocusChange_;
}