]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.trend/src/org/simantics/trend/impl/HorizRuler.java
a70949d5e1e2995fd9176e7e2c19d11ae030e4a7
[simantics/platform.git] / bundles / org.simantics.trend / src / org / simantics / trend / impl / HorizRuler.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.trend.impl;
13
14 import java.awt.Color;
15 import java.awt.Graphics2D;
16 import java.text.Format;
17 import java.text.NumberFormat;
18
19 import org.simantics.g2d.utils.GridSpacing;
20 import org.simantics.g2d.utils.GridUtil;
21 import org.simantics.trend.configuration.TimeWindow;
22 import org.simantics.trend.configuration.TrendSpec;
23 import org.simantics.utils.format.TimeFormat;
24
25 public class HorizRuler extends TrendGraphicalNode {
26
27         private static final long serialVersionUID = 7155812928124259094L;
28
29         GridSpacing spacing = GridSpacing.SOME_SPACING;
30         public double from = 0;
31         public double end = 100;
32         public boolean autoscroll = true; // Determines if auto-scroll is on/off
33         boolean manualscale = false; // Locked in trend spec
34         TimeFormat timeFormat = new TimeFormat(0, 0);
35         private Format f = timeFormat;
36         double iFrom = Double.MAX_VALUE;
37         double iEnd  = -Double.MAX_VALUE;
38         public double basetime = 0;
39         public TimeWindowListener listener;
40         public static final Color AUTOSCROLL_ON = new Color(0, 225, 34);
41         public static final Color AUTOSCROLL_OFF = new Color(255, 115, 115);
42         
43                 
44         public boolean setWidth(double width) {
45                 if (getWidth()==width) return false;
46                 this.setSize(width, 20);
47                 return true;
48         }
49         
50         public boolean setFromEnd(double from, double end) {
51                 if (this.from!=from || this.end!=end) {
52                         this.from = from;
53                         this.end = end;
54                         getTrend().shapedirty = true;
55                         return true;
56                 }
57                 return false;
58         }
59
60         public boolean setFromScale(double from, double scaleX) {
61                 double end = getWidth() * scaleX + from;
62                 return setFromEnd(from, end);
63         }
64         
65         
66         public void fireListener() {
67                 if (listener != null) {
68                         double wid = getWidth();
69                         if ( wid == 0.0 ) wid = 0.1;
70                         double sx = (end-from) / wid;
71                         listener.onNewWindow(from, end, sx);
72                 }
73         }
74
75         /**
76          * Set grid spacing and text formatter;
77          */
78         public void layout() {
79                 TrendNode trend = getTrend();
80                 if (trend.timeFormat == org.simantics.trend.configuration.TimeFormat.Time) {                    
81                         // Figure out how many decimals are needed
82                         timeFormat.setMaxValue(end);
83                         timeFormat.setDecimals(1);
84                         
85                         double labelWidth = 0;
86                         double maxLabelWidth = 0;                       
87                         for (int i=0; i<2; i++) {
88                                 labelWidth = GridUtil.calcLabelWidth(from - basetime, end - basetime, timeFormat, spacing);
89                                 maxLabelWidth = Math.max(labelWidth, maxLabelWidth);
90                                 spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), labelWidth+10);
91                                 timeFormat.setDecimals((int) -spacing.segmentExp);
92                         }
93
94                         if (maxLabelWidth>labelWidth) {
95                                 spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), maxLabelWidth+10);
96                                 timeFormat.setDecimals((int) -spacing.segmentExp);
97                         }
98                         
99                         f = timeFormat;
100                         
101                 } else {
102                         f = NumberFormat.getInstance();
103                         double labelWidth = GridUtil.calcLabelWidth(from - basetime, end, f, spacing);
104                         this.spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), labelWidth+10);
105                 }
106         }
107         
108         @Override
109         protected void doRender(Graphics2D g2d) {
110                 TrendNode trend = getTrend();           
111                 
112                 // Draw little "Frozen"
113                 if ( !trend.printing )
114                 {
115 //                      g2d.setColor( Color.LIGHT_GRAY );
116                         g2d.setColor( autoscroll ? AUTOSCROLL_ON : AUTOSCROLL_OFF );
117                         g2d.setFont( GridUtil.RULER_FONT );
118                         String txt = !autoscroll ? (manualscale ? "*" : "Auto-scroll off") : (manualscale ? "" : "Auto-scroll on");
119                         // Draw at bottom
120 //                      g2d.drawString(txt, 0.f, (float)getHeight() + 12.f      );
121                         // Draw to right
122                         g2d.drawString(txt, (float) getWidth()+20, 20.f         );
123                 }
124                 
125                 g2d.setPaint(Color.GRAY);
126                 g2d.setStroke( GridUtil.RULER_LINE_STROKE );            
127                 GridUtil.paintHorizontalRuler(
128                         spacing, 
129                         g2d,
130                         from - basetime,
131                         getWidth(),
132                         f);
133         }
134         
135         /**
136          * This method sets iFrom and iEnd values. 
137          * Read reads values from ItemNodes.
138          * So it is good idea to call {@link ItemNode#readMinMaxFromEnd()} first. 
139          */
140         public void setKnownFromEnd() {
141                 TrendNode trendNode = (TrendNode) getParent();
142                 
143                 iFrom = Double.MAX_VALUE;
144                 iEnd  = -Double.MAX_VALUE;
145                 for (ItemNode item : trendNode.allItems) {
146                         if ( !Double.isNaN(item.from) ) iFrom = Math.min(iFrom, item.from); 
147                         if ( !Double.isNaN(item.end ) ) iEnd  = Math.max(iEnd , item.end ); 
148                 }
149                 // Scale to 0..10 if there is no data
150                 if (iFrom == Double.MAX_VALUE && iEnd == -Double.MAX_VALUE) {
151                         iFrom = 0.; 
152                         iEnd = 10.;
153                 }
154         }       
155         
156         /**
157          * If zoomed, do nothing.
158          * If not zoomed, set from and end according to TrendSpec's time window settings. 
159          */
160         public boolean autoscale() {
161                 if (!autoscroll) return false;
162
163                 setKnownFromEnd();
164                 TrendNode trendNode = (TrendNode) getParent();
165                 TrendSpec spec = trendNode.spec;
166                 
167                 double nFrom = from;
168                 double nEnd = end;
169                                 
170                 TimeWindow timeWindow = spec.viewProfile.timeWindow;
171                 double len = timeWindow.timeWindowLength != null ? timeWindow.timeWindowLength : iEnd-iFrom;
172                                                 
173                 if (timeWindow.timeWindowStart != null) {
174                         
175                         if (timeWindow.timeWindowIncrement != null && timeWindow.timeWindowLength==null) {
176                                 nFrom = timeWindow.timeWindowStart + basetime;
177                                 if (nFrom>iEnd) {
178                                         nEnd = nFrom + 1.0; 
179                                 } else {
180                                         len = Math.max(0, iEnd-nFrom);
181                                         double f = (100-timeWindow.timeWindowIncrement) / 100;
182                                         double b = 1/f;
183                                         double x = Math.log( len ) / Math.log( b );
184                                         x = Math.ceil( x );
185                                         x = Math.pow(b, x);
186                                         nEnd = nFrom + x;
187                                 }
188                         } else {
189                                 nFrom = timeWindow.timeWindowStart + basetime;
190                                 nEnd = nFrom + len;
191                         }
192                 } else 
193                 {
194                         if (timeWindow.timeWindowIncrement == null) {
195                                 nFrom = iEnd - len;
196                                 nEnd = iEnd;                                    
197                                 // Marginal
198                                 nEnd += len * 0.02; 
199                         }
200                         else
201                         {                                       
202                                 if (timeWindow.timeWindowLength != null) {
203                                         double f = timeWindow.timeWindowIncrement / 100;
204                                         double fraction = len * f;
205                                                 
206                                         nEnd = Math.floor( (iEnd +fraction)/ fraction ) * fraction;
207                                         nFrom = nEnd - len;
208                                         if (nFrom<iFrom) {
209                                                 double diff = iFrom-nFrom;
210                                                 nFrom += diff;
211                                                 nEnd += diff;
212                                         }
213
214                                         if (Double.isInfinite(nEnd)) {
215                                                 nFrom = 0;
216                                                 nEnd = len; 
217                                         } else {
218                                                 // Marginal
219                                                 nEnd += len * 0.02;
220                                         }
221                                 } else {
222                                         double f = (100-timeWindow.timeWindowIncrement) / 100;
223                                         double b = 1/f;
224                                         double x = Math.log( len ) / Math.log( b );
225                                         x = Math.ceil( x );
226                                         x = Math.pow(b, x);
227                                                 
228                                         nEnd = iFrom + x;
229                                         nFrom = iFrom;
230                                 }
231                         }
232                 
233                         if (nFrom>nEnd) nFrom = nEnd;
234                 }               
235                 
236                 return setFromEnd(nFrom, nEnd);
237         }
238         
239         public void translate(double dx) {
240                 from += dx;
241                 end += dx;
242                 autoscroll = false;
243                 fireListener();
244         }
245         
246         /**
247          * Convert x position in rulers coordinate space to time value.
248          * This function does not apply basetime. To apply basetime deduct it from
249          * the result.
250          * 
251          * @param x
252          * @return time
253          */
254         public double toTime( double x ) {
255                 double sx = (end-from) / getWidth();
256                 return from + x*sx;
257         }
258         
259         public double toX( double time ) {
260                 double sx = (end-from) / getWidth();
261                 return (time-from) / sx;
262         }
263         
264         public void zoomIn(double x, double width) {
265                 autoscroll = false;
266                 
267                 double sx = (end-from) / getWidth();
268                 double newFrom = from + x*sx;
269                 double newEnd  = from + (x+width)*sx;
270                 
271                 from = newFrom;
272                 end = newEnd;           
273                 fireListener();
274         }
275         
276         public void zoomOut() {
277                 autoscroll = true;
278                 autoscale();
279                 layout();
280                 fireListener();
281         }       
282         
283         public double unitsPerPixel() {
284                 return (end-from) / getWidth();
285         }
286
287         /**
288          * @return the current ending sample time calculated from all visible chart
289          *         items.
290          */
291         public double getItemEndTime() {
292                 return iEnd;
293         }
294
295         public interface TimeWindowListener {
296                 void onNewWindow(double from, double end, double sx);
297         }
298
299 }