teichmann@5835: package org.dive4elements.river.client.client.ui.chart; ingo@540: ingo@540: import java.util.ArrayList; ingo@540: import java.util.List; ingo@540: ingo@543: import com.google.gwt.core.client.GWT; ingo@543: ingo@540: import com.smartgwt.client.types.Positioning; ingo@540: import com.smartgwt.client.types.SelectionType; ingo@543: import com.smartgwt.client.widgets.ImgButton; ingo@540: import com.smartgwt.client.widgets.Canvas; ingo@540: import com.smartgwt.client.widgets.events.MouseDownEvent; ingo@540: import com.smartgwt.client.widgets.events.MouseDownHandler; ingo@540: import com.smartgwt.client.widgets.events.MouseMoveEvent; ingo@540: import com.smartgwt.client.widgets.events.MouseMoveHandler; ingo@546: import com.smartgwt.client.widgets.events.MouseOutEvent; ingo@546: import com.smartgwt.client.widgets.events.MouseOutHandler; ingo@540: import com.smartgwt.client.widgets.events.MouseUpEvent; ingo@540: import com.smartgwt.client.widgets.events.MouseUpHandler; ingo@540: teichmann@5835: import org.dive4elements.river.client.client.event.HasZoomHandlers; teichmann@5835: import org.dive4elements.river.client.client.event.ZoomEvent; teichmann@5835: import org.dive4elements.river.client.client.event.ZoomHandler; ingo@540: ingo@540: ingo@540: /** ingo@540: * This control observes that panel retrieved by ChartOutputTab.getChartPanel(). ingo@540: * If activated, a zoombox is drawn. One of the two edges is the position of the ingo@540: * mouse down event on the observed panel. The other edge is specified by the ingo@540: * current mouse position. If the mouse up event occurs, start and end point ingo@540: * relative to the left and upper border of the observed panel is determined and ingo@540: * a ZoomEvent is fired. ingo@540: * ingo@540: * @author Ingo Weinzierl ingo@540: */ ingo@540: public class ZoomboxControl ingo@543: extends ImgButton ingo@546: implements MouseDownHandler, MouseUpHandler, MouseMoveHandler, HasZoomHandlers, ingo@546: MouseOutHandler ingo@540: { ingo@540: protected List handlers; ingo@540: ingo@540: protected ChartOutputTab chartTab; ingo@540: ingo@540: protected Canvas zoombox; ingo@540: ingo@540: protected int[] start; ingo@540: protected int[] end; ingo@540: ingo@540: ingo@543: public ZoomboxControl(ChartOutputTab chartTab, String imageUrl) { ingo@543: super(); ingo@540: ingo@540: this.handlers = new ArrayList(); ingo@540: this.chartTab = chartTab; ingo@779: this.start = new int[] { -1, -1 }; ingo@540: this.end = new int[2]; ingo@540: this.zoombox = new Canvas(); ingo@540: ingo@540: initZoombox(); ingo@540: ingo@543: String baseUrl = GWT.getHostPageBaseURL(); ingo@543: setSrc(baseUrl + imageUrl); ingo@540: setActionType(SelectionType.CHECKBOX); ingo@543: setSize(20); ingo@543: setShowRollOver(false); ingo@540: setSelected(false); ingo@540: ingo@779: Canvas chart = chartTab.getChartPanel(); ingo@779: chart.addMouseDownHandler(this); ingo@779: chart.addMouseOutHandler(this); ingo@779: chart.addMouseMoveHandler(this); ingo@779: chart.addMouseUpHandler(this); ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * Initializes the zoombox that is displayed over the observed area. The ingo@540: * zoombox has an opaque background. Its height/width and x/y values are ingo@540: * determined by the start point (mouse down) and the current mouse ingo@540: * position. ingo@540: */ ingo@540: protected void initZoombox() { ingo@779: Canvas chart = chartTab.getChartPanel(); ingo@779: chart.addChild(zoombox); ingo@779: ingo@540: zoombox.setPosition(Positioning.ABSOLUTE); ingo@541: zoombox.setBorder("2px solid black"); ingo@540: zoombox.setOpacity(50); ingo@779: zoombox.setWidth(1); ingo@779: zoombox.setHeight(1); ingo@779: zoombox.setLeft(-10000); ingo@779: zoombox.setTop(-10000); ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * Registers a new ZoomHandler that wants to listen to ZoomEvents. ingo@540: * ingo@540: * @param handler A new ZoomHandler. ingo@540: */ ingo@540: public void addZoomHandler(ZoomHandler handler) { ingo@540: if (handler != null) { ingo@540: handlers.add(handler); ingo@540: } ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * A mouse down event on the specified area will set the start point for the ingo@540: * zoombox. ingo@540: * ingo@540: * @param event The mouse down event which contains the xy coordinates of ingo@540: * the observed area. ingo@540: */ ingo@540: public void onMouseDown(MouseDownEvent event) { ingo@540: if (!isSelected()) { ingo@540: return; ingo@540: } ingo@540: ingo@779: start[0] = getRelativeX(event.getX()) - 1; ingo@779: start[1] = getRelativeY(event.getY()) + 1; ingo@540: ingo@540: end[0] = start[0]; ingo@540: end[1] = start[1]; ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * A mouse move event on the specified area will set the end point for the ingo@540: * zoombox. If the end point differs from the start point, an opaque box is ingo@540: * displayed. ingo@540: * ingo@540: * @param event The mouse move event which contains the xy coordinates of ingo@540: * the observed area. ingo@540: */ ingo@540: public void onMouseMove(MouseMoveEvent event) { ingo@779: if (!isSelected() || !isZooming()) { ingo@540: return; ingo@540: } ingo@540: ingo@779: int x = getRelativeX(event.getX()); ingo@779: int y = getRelativeY(event.getY()); ingo@779: ingo@779: end[0] = x > start[0] ? x-1 : x+1; ingo@779: end[1] = y > start[1] ? y-1 : y+1; ingo@540: ingo@540: positionZoombox(); ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * The mouse up event finalizes the zoom operation. It sets the end point ingo@540: * for this operation, clears the zoombox and fires a ZoomEvent. ingo@540: * ingo@540: * @param event The mouse up event which contains the xy coordinates of the ingo@540: * observed area. ingo@540: */ ingo@540: public void onMouseUp(MouseUpEvent event) { ingo@540: if (!isSelected()) { ingo@540: return; ingo@540: } ingo@540: ingo@540: end[0] = getRelativeX(event.getX()); ingo@540: end[1] = getRelativeY(event.getY()); ingo@540: ingo@541: fireZoomEvent(); ingo@541: ingo@779: reset(); ingo@546: } ingo@540: ingo@546: ingo@546: /** ingo@546: * The mouse out event is used to cancel an active zoom operation. ingo@546: * ingo@546: * @param event The mouse out event. ingo@546: */ ingo@546: public void onMouseOut(MouseOutEvent event) { ingo@546: if (!isSelected() || !isMouseOut(event.getX(), event.getY())) { ingo@546: return; ingo@546: } ingo@546: ingo@779: reset(); ingo@546: } ingo@546: ingo@546: ingo@546: /** ingo@546: * Returns the chart panel. ingo@546: * ingo@546: * @return the chart panel. ingo@546: */ ingo@546: protected Canvas getChartPanel() { ingo@546: return chartTab.getChartPanel(); ingo@546: } ingo@546: ingo@546: ingo@546: /** ingo@546: * This method is required to check manually if the mouse pointer really ingo@546: * moves out the chart area. The MouseOutEvent is also fired if the mouse ingo@546: * goes down which doesn't seem to be correct. So, we gonna check this ingo@546: * manually. ingo@546: * ingo@546: * @param x The x coordinate. ingo@546: * @param y The y coordinate. ingo@546: * ingo@546: * @return true, if the mouse is really out of the chart area, otherwise ingo@546: * false. ingo@546: */ ingo@546: protected boolean isMouseOut(int x, int y) { ingo@546: Canvas chart = getChartPanel(); ingo@546: ingo@546: int left = chart.getPageLeft(); ingo@546: int right = chart.getPageRight(); ingo@546: int top = chart.getPageTop(); ingo@546: int bottom = chart.getPageBottom(); ingo@546: ingo@546: if (x <= left || x >= right || y <= top || y >= bottom) { ingo@546: return true; ingo@546: } ingo@546: ingo@546: return false; ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@779: * Returns true, if a zoom action is in process. ingo@779: * ingo@779: * @return true, if a zoom action is in process. ingo@779: */ ingo@779: public boolean isZooming() { ingo@779: return start[0] > 0 && start[1] > 0; ingo@779: } ingo@779: ingo@779: ingo@779: /** ingo@540: * Returns the X coordinate relative to the left border. ingo@540: * ingo@540: * @param x The X coordinate relative to the window. ingo@540: * ingo@540: * @return the X coordinate relative to the left border. ingo@540: */ ingo@540: protected int getRelativeX(int x) { ingo@540: return x - chartTab.getChartPanel().getPageLeft(); ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * Returns the Y coordinate relative to the top border. ingo@540: * ingo@540: * @param y The Y coordinate relative to the window. ingo@540: * ingo@540: * @return the Y coordinate relative to the top border. ingo@540: */ ingo@540: protected int getRelativeY(int y) { ingo@540: return y - chartTab.getChartPanel().getPageTop(); ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * Returns min and max x/y values based on the stored values in start ingo@540: * and end. ingo@540: * ingo@540: * @return an int[] as follows: [xmin, ymin, xmax, ymax]. ingo@540: */ ingo@540: protected int[] orderPositions() { ingo@540: int xmin = start[0] < end[0] ? start[0] : end[0]; ingo@540: int ymin = start[1] < end[1] ? start[1] : end[1]; ingo@540: ingo@540: int xmax = start[0] >= end[0] ? start[0] : end[0]; ingo@540: int ymax = start[1] >= end[1] ? start[1] : end[1]; ingo@540: ingo@540: return new int[] { xmin, ymin, xmax, ymax }; ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * Sets the width, height, x and y values of the zoombox. ingo@540: */ ingo@540: protected void positionZoombox() { ingo@540: int[] values = orderPositions(); ingo@540: ingo@540: zoombox.setLeft(values[0]); ingo@540: zoombox.setTop(values[1]); ingo@540: zoombox.setWidth(values[2] - values[0]); ingo@540: zoombox.setHeight(values[3] - values[1]); ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * Clears the zoombox (set position and size to null). ingo@540: */ ingo@540: protected void clearZoombox() { ingo@779: zoombox.setLeft(-10000); ingo@779: zoombox.setTop(-10000); ingo@779: zoombox.setWidth(1); ingo@779: zoombox.setHeight(1); ingo@779: } ingo@546: ingo@779: ingo@779: /** ingo@779: * Resets the zoom control (start point and zoombox). ingo@779: */ ingo@779: protected void reset() { ingo@779: start[0] = -1; ingo@779: start[1] = -1; ingo@779: ingo@779: clearZoombox(); ingo@540: } ingo@540: ingo@540: ingo@540: /** ingo@540: * Fires a ZoomEvent to all registered listeners. ingo@540: */ ingo@540: protected void fireZoomEvent() { ingo@540: int[] pos = orderPositions(); ingo@540: ingo@540: ZoomEvent event = new ZoomEvent(pos[0], pos[1], pos[2], pos[3]); ingo@540: ingo@540: for (ZoomHandler handler: handlers) { ingo@540: handler.onZoom(event); ingo@540: } ingo@540: } ingo@540: } ingo@540: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :