X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.trend%2Fsrc%2Forg%2Fsimantics%2Ftrend%2Fimpl%2FHorizRuler.java;fp=bundles%2Forg.simantics.trend%2Fsrc%2Forg%2Fsimantics%2Ftrend%2Fimpl%2FHorizRuler.java;h=0c0daee8aad4c2dfebb592080e70a4c7b8df2fb0;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.trend/src/org/simantics/trend/impl/HorizRuler.java b/bundles/org.simantics.trend/src/org/simantics/trend/impl/HorizRuler.java new file mode 100644 index 000000000..0c0daee8a --- /dev/null +++ b/bundles/org.simantics.trend/src/org/simantics/trend/impl/HorizRuler.java @@ -0,0 +1,299 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 Association for Decentralized Information Management in + * Industry THTH ry. + * 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: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.trend.impl; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.text.Format; +import java.text.NumberFormat; + +import org.simantics.g2d.utils.GridSpacing; +import org.simantics.g2d.utils.GridUtil; +import org.simantics.trend.configuration.TimeWindow; +import org.simantics.trend.configuration.TrendSpec; +import org.simantics.utils.format.TimeFormat; + +public class HorizRuler extends TrendGraphicalNode { + + private static final long serialVersionUID = 7155812928124259094L; + + GridSpacing spacing = GridSpacing.SOME_SPACING; + public double from = 0; + public double end = 100; + public boolean autoscroll = true; // Determines if auto-scroll is on/off + boolean manualscale = false; // Locked in trend spec + TimeFormat timeFormat = new TimeFormat(0, 0); + private Format f = timeFormat; + double iFrom = Double.MAX_VALUE; + double iEnd = -Double.MAX_VALUE; + public double basetime = 0; + public TimeWindowListener listener; + public static final Color AUTOSCROLL_ON = new Color(0, 225, 34); + public static final Color AUTOSCROLL_OFF = new Color(255, 115, 115); + + + public boolean setWidth(double width) { + if (getWidth()==width) return false; + this.setSize(width, 20); + return true; + } + + public boolean setFromEnd(double from, double end) { + if (this.from!=from || this.end!=end) { + this.from = from; + this.end = end; + getTrend().shapedirty = true; + return true; + } + return false; + } + + public boolean setFromScale(double from, double scaleX) { + double end = getWidth() * scaleX + from; + return setFromEnd(from, end); + } + + + public void fireListener() { + if (listener != null) { + double wid = getWidth(); + if ( wid == 0.0 ) wid = 0.1; + double sx = (end-from) / wid; + listener.onNewWindow(from, end, sx); + } + } + + /** + * Set grid spacing and text formatter; + */ + public void layout() { + TrendNode trend = getTrend(); + if (trend.timeFormat == org.simantics.trend.configuration.TimeFormat.Time) { + // Figure out how many decimals are needed + timeFormat.setMaxValue(end); + timeFormat.setDecimals(1); + + double labelWidth = 0; + double maxLabelWidth = 0; + for (int i=0; i<2; i++) { + labelWidth = GridUtil.calcLabelWidth(from - basetime, end - basetime, timeFormat, spacing); + maxLabelWidth = Math.max(labelWidth, maxLabelWidth); + spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), labelWidth+10); + timeFormat.setDecimals((int) -spacing.segmentExp); + } + + if (maxLabelWidth>labelWidth) { + spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), maxLabelWidth+10); + timeFormat.setDecimals((int) -spacing.segmentExp); + } + + f = timeFormat; + + } else { + f = NumberFormat.getInstance(); + double labelWidth = GridUtil.calcLabelWidth(from - basetime, end, f, spacing); + this.spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), labelWidth+10); + } + } + + @Override + protected void doRender(Graphics2D g2d) { + TrendNode trend = getTrend(); + + // Draw little "Frozen" + if ( !trend.printing ) + { +// g2d.setColor( Color.LIGHT_GRAY ); + g2d.setColor( autoscroll ? AUTOSCROLL_ON : AUTOSCROLL_OFF ); + g2d.setFont( GridUtil.RULER_FONT ); + String txt = !autoscroll ? (manualscale ? "*" : "Auto-scroll off") : (manualscale ? "" : "Auto-scroll on"); + // Draw at bottom +// g2d.drawString(txt, 0.f, (float)getHeight() + 12.f ); + // Draw to right + g2d.drawString(txt, (float) getWidth()+20, 20.f ); + } + + g2d.setPaint(Color.GRAY); + g2d.setStroke( GridUtil.RULER_LINE_STROKE ); + GridUtil.paintHorizontalRuler( + spacing, + g2d, + from - basetime, + getWidth(), + f); + } + + /** + * This method sets iFrom and iEnd values. + * Read reads values from ItemNodes. + * So it is good idea to call {@link ItemNode#readMinMaxFromEnd()} first. + */ + public void setKnownFromEnd() { + TrendNode trendNode = (TrendNode) getParent(); + + iFrom = Double.MAX_VALUE; + iEnd = -Double.MAX_VALUE; + for (ItemNode item : trendNode.allItems) { + if ( !Double.isNaN(item.from) ) iFrom = Math.min(iFrom, item.from); + if ( !Double.isNaN(item.end ) ) iEnd = Math.max(iEnd , item.end ); + } + // Scale to 0..10 if there is no data + if (iFrom == Double.MAX_VALUE && iEnd == -Double.MAX_VALUE) { + iFrom = 0.; + iEnd = 10.; + } + } + + /** + * If zoomed, do nothing. + * If not zoomed, set from and end according to TrendSpec's time window settings. + */ + public boolean autoscale() { + if (!autoscroll) return false; + + setKnownFromEnd(); + TrendNode trendNode = (TrendNode) getParent(); + TrendSpec spec = trendNode.spec; + + double nFrom = from; + double nEnd = end; + + TimeWindow timeWindow = spec.viewProfile.timeWindow; + double len = timeWindow.timeWindowLength != null ? timeWindow.timeWindowLength : iEnd-iFrom; + + if (timeWindow.timeWindowStart != null) { + + if (timeWindow.timeWindowIncrement != null && timeWindow.timeWindowLength==null) { + nFrom = timeWindow.timeWindowStart + basetime; + if (nFrom>iEnd) { + nEnd = nFrom + 1.0; + } else { + len = Math.max(0, iEnd-nFrom); + double f = (100-timeWindow.timeWindowIncrement) / 100; + double b = 1/f; + double x = Math.log( len ) / Math.log( b ); + x = Math.ceil( x ); + x = Math.pow(b, x); + nEnd = nFrom + x; + } + } else { + nFrom = timeWindow.timeWindowStart + basetime; + nEnd = nFrom + len; + } + } else + { + if (timeWindow.timeWindowIncrement == null) { + nFrom = iEnd - len; + nEnd = iEnd; + // Marginal + nEnd += len * 0.02; + } + else + { + if (timeWindow.timeWindowLength != null) { + double f = timeWindow.timeWindowIncrement / 100; + double fraction = len * f; + + nEnd = Math.floor( (iEnd +fraction)/ fraction ) * fraction; + nFrom = nEnd - len; + if (nFromnEnd) nFrom = nEnd; + } + + return setFromEnd(nFrom, nEnd); + } + + public void translate(double dx) { + from += dx; + end += dx; + autoscroll = false; + fireListener(); + } + + /** + * Convert x position in rulers coordinate space to time value. + * This function does not apply basetime. To apply basetime deduct it from + * the result. + * + * @param x + * @return time + */ + public double toTime( double x ) { + double sx = (end-from) / getWidth(); + return from + x*sx; + } + + public double toX( double time ) { + double sx = (end-from) / getWidth(); + return (time-from) / sx; + } + + public void zoomIn(double x, double width) { + autoscroll = false; + + double sx = (end-from) / getWidth(); + double newFrom = from + x*sx; + double newEnd = from + (x+width)*sx; + + from = newFrom; + end = newEnd; + fireListener(); + } + + public void zoomOut() { + autoscroll = true; + autoscale(); + layout(); + fireListener(); + } + + public double unitsPerPixel() { + return (end-from) / getWidth(); + } + + /** + * @return the current ending sample time calculated from all visible chart + * items. + */ + public double getItemEndTime() { + return iEnd; + } + + public interface TimeWindowListener { + void onNewWindow(double from, double end, double sx); + } + +}