/******************************************************************************* * Copyright (c) 2012 Rushan R. Gilmullin and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Rushan R. Gilmullin - initial API and implementation *******************************************************************************/ package org.semanticsoft.vaadinaddons.boundsinfo.client.ui; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; /** * @author rushan * */ public class BoundsUpdateManager { private static class Bounds { int x, y, width, height; public Bounds(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } public int getSquare() { return width*height; } @Override public boolean equals(Object obj) { if (obj instanceof Bounds) { Bounds b = (Bounds) obj; return this.x == b.x && this.y == b.y && this.width == b.width && this.height == b.height; } else return false; } /** * adopted from java.awt.Rectangle * @param r * @return */ public Bounds intersection(Bounds r) { int tx1 = this.x; int ty1 = this.y; int rx1 = r.x; int ry1 = r.y; long tx2 = tx1; tx2 += this.width; long ty2 = ty1; ty2 += this.height; long rx2 = rx1; rx2 += r.width; long ry2 = ry1; ry2 += r.height; if (tx1 < rx1) tx1 = rx1; if (ty1 < ry1) ty1 = ry1; if (tx2 > rx2) tx2 = rx2; if (ty2 > ry2) ty2 = ry2; tx2 -= tx1; ty2 -= ty1; // tx2,ty2 will never overflow (they will never be // larger than the smallest of the two source w,h) // they might underflow, though... if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE; if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE; return new Bounds(tx1, ty1, (int) tx2, (int) ty2); } } private Widget widget; private String paintableId; private ApplicationConnection client; private Bounds prevBounds; private long prevTime; private static double OVERLAP = 0.1; private static double PERIOD = 1000; public BoundsUpdateManager(Widget widget, String paintableId, ApplicationConnection client) { this.widget = widget; this.client = client; this.paintableId = paintableId; } public void update() { if (!widget.isAttached() || widget.getParent() == null || !widget.isVisible()) return; Bounds bounds = new Bounds(widget.getAbsoluteLeft(), widget.getAbsoluteTop(), widget.getOffsetWidth(), widget.getOffsetHeight()); if (bounds.width == 0 && bounds.height == 0) return; if (prevBounds == null) { doUpdate(bounds); } else if (!bounds.equals(prevBounds)) //the necessary condition of update - bounds must change since last update { Bounds overlap = prevBounds.intersection(bounds); float prevS = prevBounds.getSquare(); float s = bounds.getSquare(); float overlapS = overlap.getSquare(); if ( (s - overlapS) /s < OVERLAP && (prevS - overlapS)/prevS < OVERLAP ) {//the bounds changes are small //so we look on ellapsed time and do update only if ellapsed time is more the PERIOD long time = System.currentTimeMillis(); if (time - prevTime > PERIOD) doUpdate(bounds); } else //if changes are large, then update doUpdate(bounds); } } private void doUpdate(Bounds bounds) { final String boundsStr = BoundsParser.toString(bounds.x, bounds.y, bounds.width, bounds.height); client.updateVariable(paintableId, "bounds", boundsStr, true); prevBounds = bounds; prevTime = System.currentTimeMillis(); } }