blob: c8f991166dafdeac87d2cd7a289afe83e5df6052 [file] [log] [blame]
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.client.diff;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Widget;
import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.CodeMirror.RegisteredHandler;
import net.codemirror.lib.Pos;
/** Displayed on the vertical scrollbar to place a chunk or comment. */
class ScrollbarAnnotation extends Widget implements ClickHandler {
private final CodeMirror cm;
private CodeMirror cmB;
private RegisteredHandler refresh;
private Pos from;
private Pos to;
private double scale;
ScrollbarAnnotation(CodeMirror cm) {
setElement((Element) DOM.createDiv());
getElement().setAttribute("not-content", "true");
addDomHandler(this, ClickEvent.getType());
this.cm = cm;
this.cmB = cm;
}
void remove() {
removeFromParent();
}
void at(int line) {
at(Pos.create(line), Pos.create(line + 1));
}
void at(Pos from, Pos to) {
this.from = from;
this.to = to;
}
void renderOn(CodeMirror cm) {
this.cmB = cm;
}
@Override
protected void onLoad() {
cmB.getWrapperElement().appendChild(getElement());
refresh = cmB.on("refresh", new Runnable() {
@Override
public void run() {
if (updateScale()) {
updatePosition();
}
}
});
updateScale();
updatePosition();
}
@Override
protected void onUnload() {
cmB.off("refresh", refresh);
}
private boolean updateScale() {
double old = scale;
double docHeight = cmB.getWrapperElement().getClientHeight();
double lineHeight = cmB.heightAtLine(cmB.lastLine() + 1, "local");
scale = (docHeight - cmB.barHeight()) / lineHeight;
return old != scale;
}
private void updatePosition() {
double top = cm.charCoords(from, "local").top() * scale;
double bottom = cm.charCoords(to, "local").bottom() * scale;
Element e = getElement();
e.getStyle().setTop(top, Unit.PX);
e.getStyle().setWidth(Math.max(2, cm.barWidth() - 1), Unit.PX);
e.getStyle().setHeight(Math.max(3, bottom - top), Unit.PX);
}
@Override
public void onClick(ClickEvent event) {
event.stopPropagation();
int line = from.line();
int h = to.line() - line;
if (h > 5) {
// Map click inside of the annotation to the relative position
// within the region covered by the annotation.
double s = ((double) event.getY()) / getElement().getOffsetHeight();
line += (int) (s * h);
}
double y = cm.heightAtLine(line, "local");
double viewport = cm.getScrollInfo().clientHeight();
cm.setCursor(from);
cm.scrollTo(0, y - 0.5 * viewport);
cm.focus();
}
}