package es.upm.fi.dia.oeg.map4rdf.client.widget; import java.util.HashMap; import java.util.Map; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style.Cursor; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.Style.Visibility; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.dom.client.MouseMoveEvent; import com.google.gwt.event.dom.client.MouseMoveHandler; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseUpEvent; import com.google.gwt.event.dom.client.MouseUpHandler; import com.google.gwt.event.logical.shared.HasValueChangeHandlers; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ProvidesResize; import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; public class SliderBar extends SimplePanel implements HasValueChangeHandlers<Double>,RequiresResize,ProvidesResize{ private FocusPanel mainPanel; private FlowPanel flowPanel; private Image knob; private FlowPanel line; private boolean mouseDown; private int min; private int max; private double stepSize; private int numTicks; private int numLabels; private int horizontalSpacing = 12; private LabelFormatter labelFormatter; private Map<Integer,Double> positionsMap; private boolean isLoad; private int actualPosition; private int lastPosition; private int lastWidth; public interface LabelFormatter { String formatLabel(SliderBar slider, double value); } public SliderBar(int min, int max, LabelFormatter labelFormatter) { this.min = min; this.max = max; stepSize = 1.0; numTicks = (int) ((max - min) / stepSize); numLabels = (int) ((max - min) / stepSize); this.labelFormatter = labelFormatter; positionsMap=new HashMap<Integer, Double>(); actualPosition=horizontalSpacing; lastPosition=horizontalSpacing; isLoad=false; mouseDown=false; lastWidth=0; this.setWidget(createUI()); //initWidget(createUI()); } private Widget createUI() { mainPanel = new FocusPanel(); addMainStyle(mainPanel); mainPanel.setHeight("34pt"); flowPanel = new FlowPanel(); line = new FlowPanel(); addLineStyle(line); flowPanel.setHeight("34pt"); knob = new Image(GWT.getModuleBaseURL() + "slider.png"); addKnobStyle(knob); mainPanel.addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) { mouseDown=true; int x =(int) (event.getRelativeX(mainPanel.getElement())-knob.getOffsetWidth()/2); int nearX=searchNearPosition(x); if(actualPosition!=nearX){ actualPosition=nearX; refreshPosition(nearX); } } } }); mainPanel.addMouseUpHandler(new MouseUpHandler() { @Override public void onMouseUp(MouseUpEvent event) { if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) { mouseDown = false; if(lastPosition!=actualPosition){ fireEvents(); } } } }); mainPanel.addMouseMoveHandler(new MouseMoveHandler() { @Override public void onMouseMove(MouseMoveEvent event) { if (mouseDown && event.getNativeButton() == NativeEvent.BUTTON_LEFT) { int x =(int) (event.getRelativeX(mainPanel.getElement())-knob.getOffsetWidth()/2); int nearX=searchNearPosition(x); if(actualPosition!=nearX){ actualPosition=nearX; refreshPosition(nearX); } } } }); mainPanel.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent event) { mouseDown=false; refreshPosition(lastPosition); actualPosition=lastPosition; } }); mainPanel.add(flowPanel); return mainPanel; } public void setCurrentValue(double value, boolean fireEvent) { double distance=max-min; for(int i:positionsMap.keySet()){ double temp=Math.abs(value-positionsMap.get(i)); if(temp<=distance){ actualPosition=i; distance=temp; } } move(knob,actualPosition); if(fireEvent){ fireEvents(); } } public double getCurrentValue(){ return positionsMap.get(actualPosition); } public void setStepSize(double stepSize) { this.stepSize = stepSize; if(isLoad){ initComponents(); } } public double getStepSize() { return stepSize; } public void setNumTicks(int numTicks) { this.numTicks = numTicks; if(isLoad){ initComponents(); } } public int getNumTicks() { return numTicks; } public void setNumLabels(int numLabels) { this.numLabels = numLabels; if(isLoad){ initComponents(); } } public int getNumLabels() { return numLabels; } public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Double> valueChangeHandler) { return this.addHandler(valueChangeHandler, ValueChangeEvent.getType()); } @Override public void onLoad() { super.onLoad(); isLoad=true; initComponents(); } @Override public void onResize(){ if(lastWidth!=mainPanel.getOffsetWidth()){ initComponents(); Widget child = getWidget(); if ((child != null) && (child instanceof RequiresResize)) { ((RequiresResize) child).onResize(); } } } @Override public void setWidth(String width){ super.setWidth(width); onResize(); } @Override public void setSize(String width,String height){ super.setSize(width, height); onResize(); } @Override public void setPixelSize(int width,int height){ super.setPixelSize(width, height); onResize(); } private void fireEvents() { lastPosition=actualPosition; ValueChangeEvent.fire(this,positionsMap.get(actualPosition)); } private int searchNearPosition(int x){ int minDistance=mainPanel.getOffsetWidth()-horizontalSpacing/2; int toReturn=min; for(int px:positionsMap.keySet()){ if(Math.abs(x-px)<minDistance){ minDistance=Math.abs(x-px); toReturn=px; } } return toReturn; } private void addMainStyle(Widget widget) { widget.getElement().getStyle().setBackgroundColor("white"); widget.getElement().getStyle().setCursor(Cursor.AUTO); } private void addLabelStyle(Widget widget) { widget.getElement().getStyle().setPosition(Position.ABSOLUTE); widget.getElement().getStyle().setVisibility(Visibility.VISIBLE); widget.getElement().getStyle().setTop(2, Unit.PT); widget.getElement().getStyle().setFontSize(8, Unit.PT); widget.getElement().getStyle().setCursor(Cursor.DEFAULT); widget.getElement().setAttribute("draggable", "false"); } private void addLineStyle(Widget widget) { widget.getElement().getStyle().setProperty("border", "1px solid black"); widget.getElement().getStyle().setBackgroundColor("white"); widget.getElement().getStyle().setHeight(4, Unit.PX); widget.getElement().getStyle().setTop(22, Unit.PT); widget.getElement().getStyle().setOverflow(Overflow.HIDDEN); widget.getElement().getStyle().setPosition(Position.ABSOLUTE); widget.getElement().getStyle().setLeft(horizontalSpacing, Unit.PX); widget.getElement().getStyle().setVisibility(Visibility.VISIBLE); widget.getElement().getStyle().setOpacity(1.0); widget.getElement().setAttribute("draggable", "false"); } private void addKnobStyle(Widget widget) { widget.getElement().getStyle().setPosition(Position.ABSOLUTE); widget.getElement().getStyle().setTop(14, Unit.PT); widget.getElement().setAttribute("border", "0"); widget.getElement().getStyle().setLeft(horizontalSpacing-5, Unit.PX); widget.getElement().getStyle().setCursor(Cursor.POINTER); widget.getElement().getStyle().setVisibility(Visibility.VISIBLE); widget.getElement().getStyle().setOpacity(1.0); widget.getElement().setAttribute("draggable", "false"); } private void addTickStyle(Widget widget) { widget.getElement().getStyle().setPosition(Position.ABSOLUTE); widget.getElement().getStyle().setTop(16, Unit.PT); widget.getElement().getStyle().setWidth(1, Unit.PX); widget.getElement().getStyle().setHeight(6, Unit.PT); widget.getElement().getStyle().setProperty("background", "none repeat scroll 0% 0% black"); widget.getElement().getStyle().setOverflow(Overflow.HIDDEN); widget.getElement().getStyle().setVisibility(Visibility.VISIBLE); widget.getElement().getStyle().setOpacity(1.0); widget.getElement().setAttribute("draggable", "false"); } private void move(Widget widget, int pixelMove) { widget.getElement().getStyle().setLeft(pixelMove, Unit.PX); } private void refreshPosition(int x) { if (x > (mainPanel.getOffsetWidth() - horizontalSpacing - knob .getOffsetWidth() / 2)) { x = mainPanel.getOffsetWidth() - horizontalSpacing - knob.getOffsetWidth() / 2; } if (x < horizontalSpacing - knob.getOffsetWidth() / 2) { x = horizontalSpacing - knob.getOffsetWidth() / 2; } move(knob, x); } private void initComponents() { lastWidth=mainPanel.getOffsetWidth(); flowPanel.clear(); // Init line line.setWidth((mainPanel.getOffsetWidth() - (horizontalSpacing * 2) - 2) + "px"); flowPanel.add(line); // Init ticks double separationTicks = mainPanel.getOffsetWidth() - horizontalSpacing * 2; separationTicks = separationTicks / (numTicks - 1); double x = horizontalSpacing; for (int i = 0; i < numTicks; i++) { FlowPanel tick = new FlowPanel(); addTickStyle(tick); flowPanel.add(tick); int move; if (i == numTicks - 1) { move=mainPanel.getOffsetWidth() - horizontalSpacing - 1; } else { move=(int) Math.round(x); } move(tick,move); x += separationTicks; } // Init labels double separationLabels = mainPanel.getOffsetWidth() - horizontalSpacing * 2; separationLabels = separationLabels / (numLabels - 1); double xLabel = horizontalSpacing; for (int i = 0; i < numLabels; i++) { Label label = new Label(labelFormatter.formatLabel(this, (((double)(max-min)/(double)(numLabels-1))*i)+min)); addLabelStyle(label); flowPanel.add(label); int move; if (i == numTicks - 1) { move= mainPanel.getOffsetWidth() - horizontalSpacing - label.getOffsetWidth()+3; } else if (i == 0) { move= (int) Math.round(xLabel)-4; } else { move=(int) Math.round(xLabel - label.getOffsetWidth() / 2); } move(label,move); xLabel += separationLabels; } // Init knob flowPanel.add(knob); move(knob, actualPosition); // Init steps positionsMap.clear(); double numStepsDouble=(max-min)/stepSize; int numStepsInt=(int)Math.round(numStepsDouble); double separationSteps=mainPanel.getOffsetWidth() - horizontalSpacing* 2; separationSteps = separationSteps/ numStepsInt; if(numStepsInt!=numStepsDouble){ positionsMap.put(mainPanel.getOffsetWidth() - horizontalSpacing - 1 - knob.getOffsetWidth()/2,(double)max); } int stepPX=horizontalSpacing-knob.getOffsetWidth()/2; for(double i=min;i<=max;i=i+stepSize){ positionsMap.put(stepPX,i); stepPX=(int)Math.round((double)(stepPX)+separationSteps); } } }