00001
00002
00003
00004
00005
00006
00007 package org.swtchart.internal;
00008
00009 import java.util.HashMap;
00010 import java.util.Map;
00011
00012 import org.eclipse.swt.SWT;
00013 import org.eclipse.swt.graphics.Point;
00014 import org.eclipse.swt.graphics.Rectangle;
00015 import org.eclipse.swt.widgets.Composite;
00016 import org.eclipse.swt.widgets.Control;
00017 import org.eclipse.swt.widgets.Layout;
00018 import org.swtchart.Chart;
00019 import org.swtchart.IAxis;
00020 import org.swtchart.IAxis.Position;
00021 import org.swtchart.IAxisSet;
00022 import org.swtchart.internal.axis.Axis;
00023 import org.swtchart.internal.axis.AxisTickLabels;
00024 import org.swtchart.internal.axis.AxisTickMarks;
00025 import org.swtchart.internal.axis.AxisTitle;
00026
00030 public class ChartLayout extends Layout {
00031
00033 private int titleHeight;
00034
00036 private int titleWidth;
00037
00039 private int legendWidth;
00040
00042 private int legendHeight;
00043
00045 private int bottomAxisHeight;
00046
00048 private int topAxisHeight;
00049
00051 private int leftAxisWidth;
00052
00054 private int rightAxisWidth;
00055
00057 private int plotAreaWidth;
00058
00060 private int plotAreaHeight;
00061
00063 private ChartTitle title;
00064
00066 private Legend legend;
00067
00069 private PlotArea plot;
00070
00072 private Axis[] axes;
00073
00075 private Axis[] horizontalAxes;
00076
00078 private Axis[] verticalAxes;
00079
00081 private Map<Axis, AxisLayoutData> axisLayoutDataMap;
00082
00084 private int bottomAxisOffset = 0;
00085
00087 private int topAxisOffset = 0;
00088
00090 private int leftAxisOffset = 0;
00091
00093 private int rightAxisOffset = 0;
00094
00096 public static final int MARGIN = 5;
00097
00099 public static final int PADDING = 5;
00100
00104 public ChartLayout() {
00105 initWidgetSizeVariables();
00106 axisLayoutDataMap = new HashMap<Axis, AxisLayoutData>();
00107 }
00108
00112 private void initWidgetSizeVariables() {
00113 titleHeight = 0;
00114 titleWidth = 0;
00115 bottomAxisHeight = 0;
00116 topAxisHeight = 0;
00117 leftAxisWidth = 0;
00118 rightAxisWidth = 0;
00119 legendWidth = 0;
00120 legendHeight = 0;
00121 plotAreaWidth = 0;
00122 plotAreaHeight = 0;
00123 }
00124
00125
00126
00127
00128 @Override
00129 protected Point computeSize(Composite composite, int wHint, int hHint,
00130 boolean flushCache) {
00131 return new Point(wHint, hHint);
00132 }
00133
00134
00135
00136
00137 @Override
00138 protected void layout(Composite composite, boolean flushCache) {
00139 if (!parseControls(composite)) {
00140 return;
00141 }
00142
00143 Rectangle r = composite.getClientArea();
00144
00145 initWidgetSizeVariables();
00146 initTitleAndLegendSize();
00147 initAxisSize();
00148
00149 computePlotAreaSize(r);
00150 computeAxisSize(r);
00151 adjustForRotatedTickLabels(r);
00152 adjustForMostLeftRightTickLabel(r);
00153
00154 layoutTitle(r);
00155 layoutLegend(r);
00156 layoutPlot(r);
00157 layoutAxes(r);
00158 }
00159
00167 private boolean parseControls(Composite composite) {
00168 for (Control child : composite.getChildren()) {
00169 if (child instanceof Legend) {
00170 legend = (Legend) child;
00171 } else if (child instanceof PlotArea) {
00172 plot = (PlotArea) child;
00173 }
00174 }
00175
00176 if (composite instanceof Chart) {
00177 IAxisSet axisSet = ((Chart) composite).getAxisSet();
00178 if (axisSet != null) {
00179 axes = (Axis[]) axisSet.getAxes();
00180
00181 if (((Chart) composite).getOrientation() == SWT.HORIZONTAL) {
00182 horizontalAxes = (Axis[]) axisSet.getXAxes();
00183 verticalAxes = (Axis[]) axisSet.getYAxes();
00184 } else {
00185 verticalAxes = (Axis[]) axisSet.getXAxes();
00186 horizontalAxes = (Axis[]) axisSet.getYAxes();
00187 }
00188 }
00189 title = (ChartTitle) ((Chart) composite).getTitle();
00190 }
00191
00192 if (title == null || legend == null || plot == null || axes == null) {
00193
00194 return false;
00195 }
00196 return true;
00197 }
00198
00202 private void initTitleAndLegendSize() {
00203 titleWidth = ((ChartLayoutData) title.getLayoutData()).widthHint;
00204 titleHeight = ((ChartLayoutData) title.getLayoutData()).heightHint;
00205 legendWidth = ((ChartLayoutData) legend.getLayoutData()).widthHint;
00206 legendHeight = ((ChartLayoutData) legend.getLayoutData()).heightHint;
00207 }
00208
00212 private void initAxisSize() {
00213 axisLayoutDataMap.clear();
00214
00215 for (Axis axis : axes) {
00216 AxisLayoutData layoutData = new AxisLayoutData(axis);
00217 if (layoutData.titleLayoutdata == null
00218 || layoutData.tickLabelsLayoutdata == null
00219 || layoutData.tickMarksLayoutdata == null) {
00220 continue;
00221 }
00222 axisLayoutDataMap.put(axis, layoutData);
00223
00224 Position position = axis.getPosition();
00225 if (position == Position.Primary && axis.isHorizontalAxis()) {
00226 bottomAxisHeight += layoutData.titleLayoutdata.heightHint
00227 + layoutData.tickLabelsLayoutdata.heightHint
00228 + layoutData.tickMarksLayoutdata.heightHint;
00229 } else if (position == Position.Secondary
00230 && axis.isHorizontalAxis()) {
00231 topAxisHeight += layoutData.titleLayoutdata.heightHint
00232 + layoutData.tickLabelsLayoutdata.heightHint
00233 + layoutData.tickMarksLayoutdata.heightHint;
00234 } else if (position == Position.Primary && !axis.isHorizontalAxis()) {
00235 leftAxisWidth += layoutData.titleLayoutdata.widthHint
00236 + layoutData.tickLabelsLayoutdata.widthHint
00237 + layoutData.tickMarksLayoutdata.widthHint;
00238 } else if (position == Position.Secondary
00239 && !axis.isHorizontalAxis()) {
00240 rightAxisWidth += layoutData.titleLayoutdata.widthHint
00241 + layoutData.tickLabelsLayoutdata.widthHint
00242 + layoutData.tickMarksLayoutdata.widthHint;
00243 }
00244 }
00245 }
00246
00253 private void computePlotAreaSize(Rectangle r) {
00254 int legendPosition = legend.getPosition();
00255
00256 plotAreaWidth = r.width
00257 - leftAxisWidth
00258 - rightAxisWidth
00259 - (legendPosition == SWT.LEFT || legendPosition == SWT.RIGHT ? legendWidth
00260 + (legendWidth == 0 ? 0 : PADDING)
00261 : 0) - MARGIN * 2;
00262
00263 plotAreaHeight = r.height
00264 - bottomAxisHeight
00265 - topAxisHeight
00266 - titleHeight
00267 - MARGIN
00268 * 2
00269 - (titleHeight == 0 ? 0 : PADDING)
00270 - (legendPosition == SWT.TOP || legendPosition == SWT.BOTTOM ? legendHeight
00271 + (legendHeight == 0 ? 0 : PADDING)
00272 : 0);
00273 }
00274
00281 private void computeAxisSize(Rectangle r) {
00282
00283
00284 updateVerticalAxisTick();
00285
00286
00287 for (IAxis axis : verticalAxes) {
00288 int tickLabelMaxLength = ((Axis) axis).getTick()
00289 .getAxisTickLabels().getTickLabelMaxLength();
00290
00291 AxisLayoutData axisLayout = axisLayoutDataMap.get(axis);
00292 axisLayout.tickLabelsLayoutdata.widthHint += tickLabelMaxLength;
00293 if (axis.getPosition() == Position.Primary) {
00294 leftAxisWidth += tickLabelMaxLength;
00295 } else {
00296 rightAxisWidth += tickLabelMaxLength;
00297 }
00298 }
00299
00300
00301 computePlotAreaSize(r);
00302
00303
00304 updateHorizontalAxisTick();
00305 }
00306
00313 private void adjustForRotatedTickLabels(Rectangle r) {
00314 for (IAxis axis : horizontalAxes) {
00315 double angle = axis.getTick().getTickLabelAngle();
00316 if (angle == 0) {
00317 continue;
00318 }
00319
00320
00321 int tickLabelMaxLength = ((Axis) axis).getTick()
00322 .getAxisTickLabels().getTickLabelMaxLength();
00323 AxisLayoutData layoutData = axisLayoutDataMap.get(axis);
00324 int height = Axis.MARGIN
00325 + (int) (tickLabelMaxLength
00326 * Math.sin(Math.toRadians(angle)) + Util
00327 .getExtentInGC(layoutData.axisTickLabels.getFont(),
00328 "dummy").y
00329 * Math.cos(Math.toRadians(angle)));
00330 int delta = height - layoutData.tickLabelsLayoutdata.heightHint;
00331 layoutData.tickLabelsLayoutdata.heightHint = height;
00332
00333
00334 if (axis.getPosition() == Position.Primary) {
00335 bottomAxisHeight += delta;
00336 } else {
00337 topAxisHeight += delta;
00338 }
00339
00340
00341 computePlotAreaSize(r);
00342
00343 updateVerticalAxisTick();
00344 }
00345 }
00346
00353 private void adjustForMostLeftRightTickLabel(Rectangle r) {
00354
00355
00356 int rightAxisMarginHint = 0;
00357 int leftAxisMarginHint = 0;
00358 for (IAxis axis : horizontalAxes) {
00359 rightAxisMarginHint = Math.max(rightAxisMarginHint,
00360 ((Axis) axis).getTick().getAxisTickLabels()
00361 .getRightMarginHint(plotAreaWidth));
00362 leftAxisMarginHint = Math.max(leftAxisMarginHint,
00363 ((Axis) axis).getTick().getAxisTickLabels()
00364 .getLeftMarginHint(plotAreaWidth));
00365 }
00366
00367
00368 if ((legendWidth == 0 || legend.getPosition() != SWT.RIGHT)
00369 && rightAxisWidth < rightAxisMarginHint) {
00370 rightAxisWidth = rightAxisMarginHint;
00371 computePlotAreaSize(r);
00372 updateHorizontalAxisTick();
00373 }
00374
00375
00376 if ((legendWidth == 0 || legend.getPosition() != SWT.LEFT)
00377 && leftAxisWidth < leftAxisMarginHint) {
00378 leftAxisWidth = leftAxisMarginHint;
00379 computePlotAreaSize(r);
00380 updateHorizontalAxisTick();
00381 }
00382 }
00383
00387 private void updateHorizontalAxisTick() {
00388 for (IAxis axis : horizontalAxes) {
00389 ((Axis) axis).getTick().updateTick(plotAreaWidth);
00390 }
00391 }
00392
00396 private void updateVerticalAxisTick(){
00397 for (IAxis axis : verticalAxes) {
00398 ((Axis) axis).getTick().updateTick(plotAreaHeight);
00399 }
00400 }
00401
00408 private void layoutTitle(Rectangle r) {
00409 int x = (int) ((r.width - titleWidth) / 2d);
00410 int y = MARGIN;
00411 int width = titleWidth;
00412 int height = titleHeight;
00413
00414 title.setBounds(x, y, width, height);
00415 }
00416
00423 private void layoutLegend(Rectangle r) {
00424 int legendPosition = legend.getPosition();
00425
00426 int tHeight = titleHeight + ((titleHeight == 0) ? 0 : PADDING);
00427 int x;
00428 int y;
00429 if (legendPosition == SWT.RIGHT) {
00430 x = r.width - legendWidth - MARGIN;
00431 y = (tHeight + r.height - legendHeight) / 2;
00432 } else if (legendPosition == SWT.LEFT) {
00433 x = MARGIN;
00434 y = (tHeight + r.height - legendHeight) / 2;
00435 } else if (legendPosition == SWT.TOP) {
00436 x = (r.width - legendWidth) / 2;
00437 y = tHeight + MARGIN;
00438 } else if (legendPosition == SWT.BOTTOM) {
00439 x = (r.width - legendWidth) / 2;
00440 y = r.height - legendHeight - MARGIN;
00441 } else {
00442 throw new IllegalStateException();
00443 }
00444 int width = legendWidth;
00445 int height = legendHeight;
00446
00447 if (y < tHeight) {
00448 y = tHeight;
00449 }
00450
00451 legend.setBounds(x, y, width, height);
00452 }
00453
00460 private void layoutPlot(Rectangle r) {
00461 int legendPosition = legend.getPosition();
00462
00463 int x = leftAxisWidth
00464 + MARGIN
00465 + (legendPosition == SWT.LEFT ? legendWidth
00466 + (legendWidth == 0 ? 0 : PADDING) : 0);
00467 int y = titleHeight
00468 + topAxisHeight
00469 + MARGIN
00470 + (titleHeight == 0 ? 0 : PADDING)
00471 + (legendPosition == SWT.TOP ? legendHeight
00472 + (legendHeight == 0 ? 0 : PADDING) : 0);
00473
00474 plot.setBounds(x, y, plotAreaWidth, plotAreaHeight);
00475 }
00476
00483 private void layoutAxes(Rectangle r) {
00484 bottomAxisOffset = 0;
00485 topAxisOffset = 0;
00486 leftAxisOffset = 0;
00487 rightAxisOffset = 0;
00488
00489 for (Axis axis : axes) {
00490 AxisLayoutData layoutData = axisLayoutDataMap.get(axis);
00491 Position position = axis.getPosition();
00492
00493 if (position == Position.Primary && axis.isHorizontalAxis()) {
00494 layoutBottomAxis(r, layoutData);
00495 } else if (position == Position.Secondary
00496 && axis.isHorizontalAxis()) {
00497 layoutTopAxis(r, layoutData);
00498 } else if (position == Position.Primary && !axis.isHorizontalAxis()) {
00499 layoutLeftAxis(r, layoutData);
00500 } else if (position == Position.Secondary
00501 && !axis.isHorizontalAxis()) {
00502 layoutRightAxis(r, layoutData);
00503 }
00504 }
00505 }
00506
00515 private void layoutBottomAxis(Rectangle r, AxisLayoutData layoutData) {
00516 int legendPosition = legend.getPosition();
00517
00518 int height = layoutData.titleLayoutdata.heightHint;
00519 int x = leftAxisWidth
00520 + MARGIN
00521 + (legendPosition == SWT.LEFT ? legendWidth
00522 + (legendWidth == 0 ? 0 : PADDING) : 0);
00523 int y = r.height
00524 - height
00525 - bottomAxisOffset
00526 - MARGIN
00527 - (legendPosition == SWT.BOTTOM ? legendHeight
00528 + (legendHeight == 0 ? 0 : PADDING) : 0);
00529
00530 bottomAxisOffset += height;
00531 if (y - layoutData.tickLabelsLayoutdata.heightHint
00532 - layoutData.tickMarksLayoutdata.heightHint < titleHeight
00533 + (titleHeight == 0 ? 0 : PADDING)) {
00534 y = titleHeight + (titleHeight == 0 ? 0 : PADDING)
00535 + layoutData.tickLabelsLayoutdata.heightHint
00536 + layoutData.tickMarksLayoutdata.heightHint;
00537 }
00538 int width = layoutData.titleLayoutdata.widthHint;
00539 int titleX = x + (plotAreaWidth - width) / 2;
00540 layoutData.axisTitle.setBounds(titleX, y, width, height);
00541
00542 height = layoutData.tickLabelsLayoutdata.heightHint;
00543 y -= height;
00544 bottomAxisOffset += height;
00545 layoutData.axisTickLabels.setBounds(0, y, r.width, height);
00546
00547 height = layoutData.tickMarksLayoutdata.heightHint;
00548 y -= height;
00549 bottomAxisOffset += height;
00550 layoutData.axisTickMarks.setBounds(x, y, plotAreaWidth, height);
00551 }
00552
00561 private void layoutTopAxis(Rectangle r, AxisLayoutData layoutData) {
00562 int legendPosition = legend.getPosition();
00563
00564 int height = layoutData.titleLayoutdata.heightHint;
00565 int x = leftAxisWidth
00566 + MARGIN
00567 + (legendPosition == SWT.LEFT ? legendWidth
00568 + (legendWidth == 0 ? 0 : PADDING) : 0);
00569 int y = titleHeight + topAxisOffset + MARGIN
00570 + ((titleHeight == 0) ? 0 : PADDING);
00571
00572 topAxisOffset += height;
00573 int width = layoutData.titleLayoutdata.widthHint;
00574 int titleX = x + (plotAreaWidth - width) / 2;
00575 layoutData.axisTitle.setBounds(titleX, y, width, height);
00576
00577 y += height;
00578 height = layoutData.tickLabelsLayoutdata.heightHint;
00579 topAxisOffset += height;
00580 layoutData.axisTickLabels.setBounds(0, y, r.width, height);
00581
00582 y += height;
00583 height = layoutData.tickMarksLayoutdata.heightHint;
00584 topAxisOffset += height;
00585 layoutData.axisTickMarks.setBounds(x, y, plotAreaWidth, height);
00586 }
00587
00596 private void layoutLeftAxis(Rectangle r, AxisLayoutData layoutData) {
00597 int legendPosition = legend.getPosition();
00598
00599 int yAxisMargin = Axis.MARGIN + AxisTickMarks.TICK_LENGTH;
00600
00601 int width = layoutData.titleLayoutdata.widthHint;
00602 int x = MARGIN
00603 + leftAxisOffset
00604 + (legendPosition == SWT.LEFT ? legendWidth
00605 + (legendWidth == 0 ? 0 : PADDING) : 0);
00606 int y = titleHeight
00607 + topAxisHeight
00608 + MARGIN
00609 + ((titleHeight == 0) ? 0 : PADDING)
00610 + (legendPosition == SWT.TOP ? legendHeight
00611 + (legendHeight == 0 ? 0 : PADDING) : 0);
00612
00613 leftAxisOffset += width;
00614 int height = layoutData.titleLayoutdata.heightHint;
00615 int titleY = y + (plotAreaHeight - height) / 2;
00616 layoutData.axisTitle.setBounds(x, titleY, width, height);
00617
00618 x += width;
00619 width = layoutData.tickLabelsLayoutdata.widthHint;
00620 leftAxisOffset += width;
00621 layoutData.axisTickLabels.setBounds(x, y - yAxisMargin, width,
00622 plotAreaHeight + yAxisMargin * 2);
00623
00624 x += width;
00625 width = layoutData.tickMarksLayoutdata.widthHint;
00626 leftAxisOffset += width;
00627 layoutData.axisTickMarks.setBounds(x, y, width, plotAreaHeight);
00628 }
00629
00638 private void layoutRightAxis(Rectangle r, AxisLayoutData layoutData) {
00639 int legendPosition = legend.getPosition();
00640
00641 int yAxisMargin = Axis.MARGIN + AxisTickMarks.TICK_LENGTH;
00642
00643 int width = layoutData.titleLayoutdata.widthHint;
00644 int x = r.width
00645 - width
00646 - rightAxisOffset
00647 - MARGIN
00648 - (legendPosition == SWT.RIGHT ? legendWidth
00649 + (legendWidth == 0 ? 0 : PADDING) : 0);
00650 int y = titleHeight
00651 + topAxisHeight
00652 + MARGIN
00653 + ((titleHeight == 0) ? 0 : PADDING)
00654 + (legendPosition == SWT.TOP ? legendHeight
00655 + (legendHeight == 0 ? 0 : PADDING) : 0);
00656
00657 rightAxisOffset += width;
00658 int height = layoutData.titleLayoutdata.heightHint;
00659 int titleY = y + (plotAreaHeight - height) / 2;
00660 layoutData.axisTitle.setBounds(x, titleY, width, height);
00661
00662 width = layoutData.tickLabelsLayoutdata.widthHint;
00663 x -= width;
00664 rightAxisOffset += width;
00665 layoutData.axisTickLabels.setBounds(x, y - yAxisMargin, width, plotAreaHeight
00666 + yAxisMargin * 2);
00667
00668 width = layoutData.tickMarksLayoutdata.widthHint;
00669 x -= width;
00670 rightAxisOffset += width;
00671 layoutData.axisTickMarks.setBounds(x, y, width, plotAreaHeight);
00672 }
00673
00677 private static class AxisLayoutData {
00678
00680 public AxisTickMarks axisTickMarks;
00681
00683 public AxisTickLabels axisTickLabels;
00684
00686 public AxisTitle axisTitle;
00687
00689 public ChartLayoutData titleLayoutdata;
00690
00692 public ChartLayoutData tickLabelsLayoutdata;
00693
00695 public ChartLayoutData tickMarksLayoutdata;
00696
00703 public AxisLayoutData(Axis axis) {
00704 axisTickMarks = axis.getTick().getAxisTickMarks();
00705 axisTickLabels = axis.getTick().getAxisTickLabels();
00706 axisTitle = (AxisTitle) axis.getTitle();
00707
00708 titleLayoutdata = (ChartLayoutData) axisTitle.getLayoutData();
00709 tickLabelsLayoutdata = axisTickLabels.getLayoutData();
00710 tickMarksLayoutdata = axisTickMarks.getLayoutData();
00711 }
00712 }
00713 }