/*
* NotebookProgressWidget.java
*
* Copyright (C) 2009-16 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.studio.client.workbench.views.source.editors.text.status;
import java.util.ArrayList;
import org.rstudio.core.client.ColorUtil;
import com.google.gwt.animation.client.AnimationScheduler;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style.Cursor;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
public class NotebookProgressWidget extends Composite
implements HasClickHandlers
{
private static NotebookProgressWidgetUiBinder uiBinder = GWT
.create(NotebookProgressWidgetUiBinder.class);
interface NotebookProgressWidgetUiBinder
extends UiBinder<Widget, NotebookProgressWidget>
{
}
@Override
public void setVisible(boolean visible)
{
super.setVisible(visible);
if (visible)
{
AnimationScheduler.get().requestAnimationFrame(
new AnimationScheduler.AnimationCallback()
{
@Override
public void execute(double pos)
{
if (start_ == 0)
{
// initialization
start_ = pos;
}
else if (pos - start_ > STEP_MS)
{
highlight_ += Math.round(pos - start_) / STEP_MS;
start_ = pos;
updateProgressBar(false);
}
// request another frame if we're still showing
if (isVisible())
{
final AnimationScheduler.AnimationCallback callback = this;
new Timer()
{
@Override
public void run()
{
AnimationScheduler.get().requestAnimationFrame(
callback);
}
}.schedule(STEP_MS);
}
}
private double start_ = 0;
private final int STEP_MS = 15;
});
}
}
public void setPercent(int percent)
{
percent_ = percent;
updateProgressBar(true);
}
public void setLabel(String label)
{
progressLabel_.setText(label + ": ");
}
public HandlerRegistration addClickHandler(ClickHandler handler)
{
return manager_.addHandler(ClickEvent.getType(), handler);
}
public HandlerRegistration addCancelHandler(final Command onCanceled)
{
cancelCommands_.add(onCanceled);
return new HandlerRegistration()
{
@Override
public void removeHandler()
{
cancelCommands_.remove(onCanceled);
}
};
}
public NotebookProgressWidget()
{
manager_ = new HandlerManager(this);
cancelCommands_ = new ArrayList<Command>();
initWidget(uiBinder.createAndBindUi(this));
// ensure elements look clickable
progressBar_.getElement().getStyle().setCursor(Cursor.POINTER);
interruptButton_.getElement().getStyle().setCursor(Cursor.POINTER);
MouseDownHandler handler = new MouseDownHandler()
{
public void onMouseDown(MouseDownEvent event)
{
event.preventDefault();
event.stopPropagation();
ClickEvent.fireNativeEvent(
Document.get().createClickEvent(0, 0, 0, 0, 0, false, false,
false, false),
manager_);
}
};
// connect native click handler
progressBar_.addDomHandler(handler, MouseDownEvent.getType());
interruptButton_.addDomHandler(new MouseDownHandler()
{
@Override
public void onMouseDown(MouseDownEvent event)
{
for (Command cancelCommand: cancelCommands_)
cancelCommand.execute();
}
}, MouseDownEvent.getType());
}
private void updateProgressBar(boolean resetHighlight)
{
ColorUtil.RGBColor barColor = ColorUtil.RGBColor.fromCss(
"rgba(24, 163, 82, 1.0)");
ColorUtil.RGBColor highColor = ColorUtil.RGBColor.fromCss(
"rgba(208, 233, 201, 1.0)");
ColorUtil.RGBColor emptyColor = ColorUtil.RGBColor.fromCss(
"rgba(24, 163, 82, 0.3)");
int end = Math.round((float)progressBar_.getOffsetWidth() *
((float) percent_ / (float) 100));
final int HEAD_WIDTH = 10;
final int TAIL_WIDTH = 35;
int high = highlight_ % (progressBar_.getOffsetWidth() + TAIL_WIDTH);
int highStart = Math.max(high - TAIL_WIDTH, 0);
int highEnd = Math.min(high + HEAD_WIDTH, end);
highlight_ = high; // avoid overflow
if (high > end && highStart <= end)
{
highColor = highColor.mixedWith(barColor,
(float)(end - highStart) / (float) TAIL_WIDTH, 1);
high = end;
}
else if (highStart > end)
{
// don't draw highlight bar if it's fully out past the edge
if (resetHighlight)
highlight_ = 0;
high = 0;
highStart = 0;
highEnd = 0;
}
progressBar_.getElement().getStyle().setBackgroundImage(
"linear-gradient(to right, " +
barColor.asRgb() + " 0, " +
barColor.asRgb() + " " + highStart + "px, " +
highColor.asRgb() + " " + high + "px, " +
barColor.asRgb() + " " + highEnd + "px, " +
barColor.asRgb() + " " + end + "px, " +
emptyColor.asRgb() + " " + end + "px, " +
emptyColor.asRgb() + " 100%)");
}
@UiField HTMLPanel progressBar_;
@UiField HorizontalPanel root_;
@UiField Label progressLabel_;
@UiField Image interruptButton_;
private int percent_ = 0;
private int highlight_ = 0;
private final HandlerManager manager_;
private final ArrayList<Command> cancelCommands_;
}