]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.trend/src/org/simantics/trend/impl/VertRuler.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.trend / src / org / simantics / trend / impl / VertRuler.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.trend.impl;\r
13 \r
14 import java.awt.Color;\r
15 import java.awt.Font;\r
16 import java.awt.FontMetrics;\r
17 import java.awt.Graphics2D;\r
18 import java.awt.geom.AffineTransform;\r
19 import java.awt.geom.Path2D;\r
20 import java.text.Format;\r
21 \r
22 import org.simantics.g2d.utils.GridSpacing;\r
23 import org.simantics.g2d.utils.GridUtil;\r
24 import org.simantics.trend.configuration.ItemPlacement;\r
25 import org.simantics.trend.configuration.TrendItem.Renderer;\r
26 import org.simantics.utils.format.ValueFormat;\r
27 \r
28 public class VertRuler extends TrendGraphicalNode {\r
29 \r
30         private static final long serialVersionUID = 3773787909384380074L;\r
31 \r
32         GridSpacing spacing = GridSpacing.SOME_SPACING;\r
33         double min = -1, max = 1;\r
34         double iMin = Double.MAX_VALUE, iMax = -Double.MAX_VALUE;\r
35         String label = "";\r
36         Color color = Color.GRAY;\r
37         boolean autoscroll = true;  // Autoscroll on/off\r
38         boolean manualscale = false; // Autoscale / manual scale\r
39         double labelWidth = 7;\r
40 \r
41         static final double TRIANGLE_SIZE = 7;\r
42     static final Path2D TRIANGLE;\r
43                         \r
44         public void layout()\r
45         {\r
46                 TrendNode trend = getTrend();\r
47                 ValueFormat vf = trend.valueFormat;\r
48                 spacing = GridSpacing.makeGridSpacing(max-min, getHeight(), 15);\r
49                 labelWidth = Math.max(7, GridUtil.calcLabelWidth(min, max, vf.format, spacing));\r
50                 double w = 30 + labelWidth;\r
51                 // Snap w -> next 20 pixels\r
52                 double quantization = 10; \r
53                 int x = (int) Math.ceil( w / quantization );\r
54                 if (x<4) x = 4;\r
55                 w = x * quantization;\r
56                 w += 5;\r
57                 bounds.setFrame(0, 0, w, getHeight());          \r
58                 trend.shapedirty = true;\r
59         }\r
60 \r
61         public void setHeight(double height) {\r
62                 if (height==bounds.getHeight()) return;\r
63                 bounds.setFrame(0, 0, bounds.getWidth(), height);               \r
64                 getTrend().shapedirty = true;\r
65         }\r
66         \r
67         public boolean setMinMax(double min, double max) {\r
68                 if (min==this.min && max==this.max) return false;\r
69                 spacing = GridSpacing.makeGridSpacing(max-min, getHeight(), 15);\r
70                 this.min = min;\r
71                 this.max = max;\r
72                 getTrend().shapedirty = true;\r
73                 return true;\r
74         }       \r
75         \r
76         @Override\r
77         protected void doRender(Graphics2D g) {\r
78                 TrendNode trend = (TrendNode) getParent();\r
79                 \r
80                 // Draw little "Frozen"\r
81                 if ( !trend.printing )\r
82                 {\r
83                         g.setColor( Color.LIGHT_GRAY );\r
84                         g.setFont( RULER_FONT );\r
85                         String txt = !autoscroll ? (manualscale ? "*" : "Auto off") : (manualscale ? "" : "Auto on");\r
86                         // Draw at bottom\r
87                         //g.drawString(txt, 2.f, (float)getHeight() + 14.f );\r
88                         // Draw at top\r
89                         g.drawString(txt, 5.f, -9.f );\r
90                 }\r
91                 \r
92                 g.setPaint( color );\r
93                 g.setStroke( GridUtil.RULER_LINE_STROKE );              \r
94                                 \r
95                 ValueFormat vf = trend.valueFormat;\r
96                 VertRuler master = trend.vertRuler;\r
97                 VertRuler slave = this;\r
98                 if ( master != slave )\r
99                 {       \r
100                         // Paint "slave" ruler - a ruler with ticks from master and labels from this\r
101                         int tickCount = GridUtil.getTickCount(master.spacing, master.min, master.getHeight());\r
102                         int noOfDecimals = calcNoOfDecimals(tickCount, slave.max-slave.min);\r
103                         Format format = vf.toFormat(noOfDecimals);\r
104                         \r
105                         GridUtil.paintVerticalSlaveRuler(\r
106                                         master.spacing,\r
107                                         spacing, \r
108                                         g,\r
109                                         master.min,\r
110                                         slave.min,\r
111                                         getHeight(),\r
112                                         format);\r
113                 } else {\r
114                         Format format = vf.format;\r
115                         \r
116                         // Paint normal ruler\r
117                         GridUtil.paintVerticalRuler(\r
118                                 spacing, \r
119                                 g,\r
120                                 min,\r
121                                 getHeight(),\r
122                                 format);\r
123                 }\r
124                 \r
125                 // Draw label\r
126                 {\r
127 //                      Shape oldClip = g2d.getClip();\r
128 //                      Rectangle2D.Double newClip = new Rectangle2D.Double(0,-20, getWidth(), 30);\r
129 //                      g2d.setClip(newClip);\r
130                         boolean selected = trend.singleAxis ? false : trend.vertRuler==this;\r
131                         selected &= !trend.printing;\r
132                         \r
133                         Font font = selected ? RULER_FONT_BOLD : RULER_FONT;\r
134                         FontMetrics fm = g.getFontMetrics( font );\r
135                         //LineMetrics lm = fm.getLineMetrics(label, g);\r
136                         double wid = fm.stringWidth(label);\r
137                         \r
138                         AffineTransform at = g.getTransform();\r
139                         g.translate( getWidth()-15, (getHeight()-wid)/2);\r
140 //                      g2d.translate( 18+labelWidth, (getHeight()-wid)/2);\r
141                         g.transform( AffineTransform.getQuadrantRotateInstance(1) );\r
142                         g.setColor( color );\r
143                         g.setFont( font );\r
144                         g.drawString( label, (float) 0, (float) 0);\r
145                         g.setTransform( at );                   \r
146 //                      g2d.setClip(oldClip);\r
147                         \r
148                         // Triangle\r
149                         if (selected) {\r
150                                 at = g.getTransform();\r
151                                 g.translate( getWidth() - TRIANGLE_SIZE - 5, 0 );\r
152                                 g.setColor( color );\r
153                                 g.fill( TRIANGLE );                             \r
154                                 g.setTransform( at );                   \r
155                         }\r
156                 }\r
157         }\r
158 \r
159         public void setKnownMinMax() {\r
160                 TrendNode trend = (TrendNode) getParent();\r
161                 iMax = -Double.MAX_VALUE;\r
162                 iMin = Double.MAX_VALUE;\r
163                 for (ItemNode item : trend.analogItems) {\r
164                         if (item.item.renderer != Renderer.Analog || item.ruler!=this) continue;\r
165                         if ( !Double.isNaN(item.min ) ) iMin  = Math.min(iMin, item.min ); \r
166                         if ( !Double.isNaN(item.max ) ) iMax  = Math.max(iMax, item.max );\r
167                 }\r
168                 \r
169                 if (iMin == Double.MAX_VALUE && iMax == -Double.MAX_VALUE) {\r
170                         iMin = 0.;\r
171                         iMax = 1.;\r
172                 }\r
173         }\r
174         \r
175         public boolean autoscale() {\r
176                 if (!autoscroll) return false;\r
177                 setKnownMinMax();\r
178                 double nMin = iMin;\r
179                 double nMax = iMax;\r
180                 double diff = nMax - nMin;\r
181                 if (diff==0.0) {\r
182                         nMin -= 0.5;\r
183                         nMax += 0.5;\r
184                         diff = nMax - nMin;\r
185                 }\r
186                 double margin = diff*0.02;\r
187                 \r
188                 TrendNode trend = getTrend();\r
189                 if (trend.itemPlacement == ItemPlacement.Stacked) {\r
190                         int c = trend.vertRulers.size();\r
191                         int i = c-trend.vertRulers.indexOf(this)-1;\r
192                         nMin = nMin - (diff)*i - margin;\r
193                         nMax = nMax + (diff)*(c-i-1) + margin;\r
194                         \r
195                 } else {\r
196                         nMin = iMin - margin;\r
197                         nMax = iMax + margin;\r
198                 }               \r
199 \r
200                 return setMinMax(nMin, nMax);\r
201         }\r
202         \r
203         public void translate(double dy) {\r
204                 min += dy;\r
205                 max += dy;\r
206                 autoscroll = false;\r
207         }\r
208         \r
209         public void zoomIn(double y, double height) {\r
210                 autoscroll = false;\r
211                 \r
212                 double diff = max-min;\r
213                 double sy = diff / getHeight();\r
214                 if ( Math.abs(diff)<GridSpacing.GRID_MIN_USER_SIZE && height<getHeight()) {\r
215 //                      System.out.println(y/getHeight()*4+", "+getHeight());\r
216 //                      diff = GridSpacing.GRID_MIN_USER_SIZE;\r
217 //                      sy = diff / getHeight();\r
218 //                      double ry = y/getHeight()*4;\r
219 //                      double vy = (max+min)/2-y*sy; \r
220 //                      setMinMax(vy-GridSpacing.GRID_MIN_USER_SIZE/2, vy+GridSpacing.GRID_MIN_USER_SIZE/2);\r
221                         return;\r
222                 } else {\r
223                         double newMin  = min + (getHeight() - y-height)*sy;\r
224                         double newMax  = max - (y)*sy;\r
225                         setMinMax(newMin, newMax);\r
226                 }\r
227         }\r
228         \r
229         public void zoomOut() {\r
230                 autoscroll = true;\r
231                 autoscale();\r
232         }       \r
233         \r
234         public void zoomTo(double min, double max) {\r
235                 setMinMax(min, max);\r
236                 autoscroll = false;\r
237         }\r
238         \r
239         public double unitsPerPixel() {\r
240                 return (max-min) / getHeight();\r
241         }\r
242         \r
243         static int calcNoOfDecimals(int tickCount, double diff)\r
244         {\r
245                 int interestingNumbers;\r
246                 if ( tickCount<=2 ) interestingNumbers = 1; else\r
247                 if ( tickCount>=3 && tickCount<=9 ) interestingNumbers = 2; else\r
248                 if ( tickCount>=10 && tickCount<=99 ) interestingNumbers = 3; else\r
249                 if ( tickCount>=100 && tickCount<=999 ) interestingNumbers = 4; else\r
250                         interestingNumbers = 5;\r
251                 \r
252                 int decimals = interestingNumbers - ((int)Math.ceil( Math.log10(diff) ));\r
253                 if (decimals<0) decimals = 0;\r
254                 \r
255                 return decimals;\r
256         }\r
257         \r
258         public static void main(String[] args) {\r
259                 double diff = 12.4567890;\r
260                 for ( int tickCount=0; tickCount<15; tickCount++) {\r
261                         int noOfDecimals = calcNoOfDecimals(tickCount, diff);\r
262                         Format format = ValueFormat.Currency.toFormat(noOfDecimals);\r
263                         System.out.println("diff="+diff+", tickcount="+tickCount+", #ofDecimals="+noOfDecimals+", formatted diff="+format.format(diff));\r
264                 }\r
265         }\r
266         static {\r
267                 \r
268                 TRIANGLE = new Path2D.Double();\r
269                 TRIANGLE.moveTo(-TRIANGLE_SIZE/2, 0);\r
270                 TRIANGLE.lineTo(TRIANGLE_SIZE/2, 0);\r
271                 TRIANGLE.lineTo(0, TRIANGLE_SIZE);\r
272 \r
273         }\r
274 \r
275 }\r