comparison dwtx/draw2d/ScaledGraphics.d @ 98:95307ad235d9

Added Draw2d code, still work in progress
author Frank Benoit <benoit@tionex.de>
date Sun, 03 Aug 2008 00:52:14 +0200
parents
children 2d6540440fe6
comparison
equal deleted inserted replaced
96:b492ba44e44d 98:95307ad235d9
1 /*******************************************************************************
2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module dwtx.draw2d.ScaledGraphics;
14
15 import dwt.dwthelper.utils;
16 import dwtx.dwtxhelper.Collection;
17
18 import dwt.DWT;
19 import dwt.graphics.Color;
20 import dwt.graphics.Font;
21 import dwt.graphics.FontData;
22 import dwt.graphics.FontMetrics;
23 import dwt.graphics.Image;
24 import dwt.graphics.Path;
25 import dwt.graphics.PathData;
26 import dwt.graphics.TextLayout;
27 import dwt.graphics.TextStyle;
28 import dwt.widgets.Display;
29 static import dwt.graphics.Rectangle;
30 import dwtx.draw2d.geometry.Point;
31 import dwtx.draw2d.geometry.PointList;
32 import dwtx.draw2d.geometry.Rectangle;
33 import dwtx.draw2d.Graphics;
34 import dwtx.draw2d.FigureUtilities;
35
36 /**
37 * A Graphics object able to scale all operations based on the current scale factor.
38 */
39 public class ScaledGraphics
40 : Graphics
41 {
42 alias Graphics.translate translate;
43 alias Graphics.fillRectangle fillRectangle;
44
45 private static class FontHeightCache {
46 Font font;
47 int height;
48 }
49
50 static class FontKey {
51 Font font;
52 int height;
53 protected this() { }
54 protected this(Font font, int height) {
55 this.font = font;
56 this.height = height;
57 }
58
59 public override int opEquals(Object obj) {
60 return ((cast(FontKey)obj).font.opEquals(font)
61 && (cast(FontKey)obj).height is height);
62 }
63
64 public override hash_t toHash() {
65 return font.toHash() ^ height;
66 }
67
68 protected void setValues(Font font, int height) {
69 this.font = font;
70 this.height = height;
71 }
72 }
73
74 /**
75 * The internal state of the scaled graphics.
76 */
77 protected static class State {
78 private double appliedX;
79 private double appliedY;
80 private Font font;
81 private int lineWidth;
82 private double zoom;
83
84 /**
85 * Constructs a new, uninitialized State object.
86 */
87 protected this() { }
88
89 /**
90 * Constructs a new State object and initializes the properties based on the given
91 * values.
92 *
93 * @param zoom the zoom factor
94 * @param x the x offset
95 * @param y the y offset
96 * @param font the font
97 * @param lineWidth the line width
98 */
99 protected this(double zoom, double x, double y, Font font, int lineWidth) {
100 this.zoom = zoom;
101 this.appliedX = x;
102 this.appliedY = y;
103 this.font = font;
104 this.lineWidth = lineWidth;
105 }
106
107 /**
108 * Sets all the properties of the state object.
109 * @param zoom the zoom factor
110 * @param x the x offset
111 * @param y the y offset
112 * @param font the font
113 * @param lineWidth the line width
114 */
115 protected void setValues(double zoom, double x, double y,
116 Font font, int lineWidth) {
117 this.zoom = zoom;
118 this.appliedX = x;
119 this.appliedY = y;
120 this.font = font;
121 this.lineWidth = lineWidth;
122 }
123 }
124
125 private static int[][] intArrayCache;
126 private final Rectangle tempRECT;
127
128 static this(){
129 intArrayCache = new int[][](8);
130 for (int i = 0; i < intArrayCache.length; i++)
131 intArrayCache[i] = new int[i + 1];
132 }
133 private void instanceInit(){
134 tempRECT = new Rectangle();
135 localCache = new FontHeightCache();
136 targetCache = new FontHeightCache();
137 stack = new ArrayList();
138 fontKey = new FontKey();
139 fontDataCache = new HashMap();
140 fontCache = new HashMap();
141 }
142 private bool allowText = true;
143 //private static final Point PT = new Point();
144 private Map fontCache;
145 private Map fontDataCache;
146 private FontKey fontKey;
147 private double fractionalX;
148 private double fractionalY;
149 private Graphics graphics;
150 private FontHeightCache localCache;
151 private Font localFont;
152 private int localLineWidth;
153 private List stack;
154 private int stackPointer = 0;
155 private FontHeightCache targetCache;
156
157 double zoom = 1.0;
158
159 /**
160 * Constructs a new ScaledGraphics based on the given Graphics object.
161 * @param g the base graphics object
162 */
163 public this(Graphics g) {
164 instanceInit();
165 graphics = g;
166 localFont = g.getFont();
167 localLineWidth = g.getLineWidth();
168 }
169
170 /** @see Graphics#clipRect(Rectangle) */
171 public void clipRect(Rectangle r) {
172 graphics.clipRect(zoomClipRect(r));
173 }
174
175 Font createFont(FontData data) {
176 return new Font(Display.getCurrent(), data);
177 }
178
179 private Path createScaledPath(Path path) {
180 PathData p = path.getPathData();
181 for (int i = 0; i < p.points.length; i += 2) {
182 p.points[i] = cast(float) (p.points[i] * zoom + fractionalX);
183 p.points[i + 1] = cast(float) (p.points[i + 1] * zoom + fractionalY);
184 }
185 Path scaledPath = new Path(path.getDevice());
186 int index = 0;
187 for (int i = 0; i < p.types.length; i++) {
188 byte type = p.types[i];
189 switch (type) {
190 case DWT.PATH_MOVE_TO:
191 scaledPath.moveTo(p.points[index], p.points[index + 1]);
192 index += 2;
193 break;
194 case DWT.PATH_LINE_TO:
195 scaledPath.lineTo(p.points[index], p.points[index + 1]);
196 index += 2;
197 break;
198 case DWT.PATH_CUBIC_TO:
199 scaledPath.cubicTo(p.points[index], p.points[index + 1],
200 p.points[index + 2], p.points[index + 3], p.points[index + 4],
201 p.points[index + 5]);
202 index += 6;
203 break;
204 case DWT.PATH_QUAD_TO:
205 scaledPath.quadTo(p.points[index], p.points[index + 1],
206 p.points[index + 2], p.points[index + 3]);
207 index += 4;
208 break;
209 case DWT.PATH_CLOSE:
210 scaledPath.close();
211 break;
212 }
213 }
214 return scaledPath;
215 }
216
217 /** @see Graphics#dispose() */
218 public void dispose() {
219 //Remove all states from the stack
220 while (stackPointer > 0) {
221 popState();
222 }
223
224 //Dispose fonts
225 Iterator iter = fontCache.values().iterator();
226 while (iter.hasNext()) {
227 Font font = (cast(Font)iter.next());
228 font.dispose();
229 }
230
231 }
232
233 /** @see Graphics#drawArc(int, int, int, int, int, int) */
234 public void drawArc(int x, int y, int w, int h, int offset, int sweep) {
235 Rectangle z = zoomRect(x, y, w, h);
236 if (z.isEmpty() || sweep is 0)
237 return;
238 graphics.drawArc(z, offset, sweep);
239 }
240
241 /** @see Graphics#drawFocus(int, int, int, int) */
242 public void drawFocus(int x, int y, int w, int h) {
243 graphics.drawFocus(zoomRect(x, y, w, h));
244 }
245
246 /** @see Graphics#drawImage(Image, int, int) */
247 public void drawImage(Image srcImage, int x, int y) {
248 dwt.graphics.Rectangle.Rectangle size = srcImage.getBounds();
249 graphics.drawImage(srcImage, 0, 0, size.width, size.height,
250 cast(int)(Math.floor((x * zoom + fractionalX))),
251 cast(int)(Math.floor((y * zoom + fractionalY))),
252 cast(int)(Math.floor((size.width * zoom + fractionalX))),
253 cast(int)(Math.floor((size.height * zoom + fractionalY))));
254 }
255
256 /** @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int) */
257 public void drawImage(Image srcImage, int sx, int sy, int sw, int sh,
258 int tx, int ty, int tw, int th) {
259 //"t" is target rectangle, "s" = source
260
261 Rectangle t = zoomRect(tx, ty, tw, th);
262 if (!t.isEmpty())
263 graphics.drawImage(srcImage, sx, sy, sw, sh, t.x, t.y, t.width, t.height);
264 }
265
266 /** @see Graphics#drawLine(int, int, int, int) */
267 public void drawLine(int x1, int y1, int x2, int y2) {
268 graphics.drawLine(
269 cast(int)(Math.floor((x1 * zoom + fractionalX))),
270 cast(int)(Math.floor((y1 * zoom + fractionalY))),
271 cast(int)(Math.floor((x2 * zoom + fractionalX))),
272 cast(int)(Math.floor((y2 * zoom + fractionalY))));
273 }
274
275 /** @see Graphics#drawOval(int, int, int, int) */
276 public void drawOval(int x, int y, int w, int h) {
277 graphics.drawOval(zoomRect(x, y, w, h));
278 }
279
280 /** @see Graphics#drawPath(Path) */
281 public void drawPath(Path path) {
282 Path scaledPath = createScaledPath(path);
283 try {
284 graphics.drawPath(scaledPath);
285 } finally {
286 scaledPath.dispose();
287 }
288 }
289
290 /** @see Graphics#drawPoint(int, int) */
291 public void drawPoint(int x, int y) {
292 graphics.drawPoint(cast(int)Math.floor(x * zoom + fractionalX),
293 cast(int)Math.floor(y * zoom + fractionalY));
294 }
295
296 /**
297 * @see Graphics#drawPolygon(int[])
298 */
299 public void drawPolygon(int[] points) {
300 graphics.drawPolygon(zoomPointList(points));
301 }
302
303 /** @see Graphics#drawPolygon(PointList) */
304 public void drawPolygon(PointList points) {
305 graphics.drawPolygon(zoomPointList(points.toIntArray()));
306 }
307
308 /**
309 * @see Graphics#drawPolyline(int[])
310 */
311 public void drawPolyline(int[] points) {
312 graphics.drawPolyline(zoomPointList(points));
313 }
314
315 /** @see Graphics#drawPolyline(PointList) */
316 public void drawPolyline(PointList points) {
317 graphics.drawPolyline(zoomPointList(points.toIntArray()));
318 }
319
320 /** @see Graphics#drawRectangle(int, int, int, int) */
321 public void drawRectangle(int x, int y, int w, int h) {
322 graphics.drawRectangle(zoomRect(x, y, w, h));
323 }
324
325 /** @see Graphics#drawRoundRectangle(Rectangle, int, int) */
326 public void drawRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
327 graphics.drawRoundRectangle(zoomRect(r.x, r.y, r.width, r.height),
328 cast(int)(arcWidth * zoom),
329 cast(int)(arcHeight * zoom));
330 }
331
332 /** @see Graphics#drawString(String, int, int) */
333 public void drawString(String s, int x, int y) {
334 if (allowText)
335 graphics.drawString(s, zoomTextPoint(x, y));
336 }
337
338 /** @see Graphics#drawText(String, int, int) */
339 public void drawText(String s, int x, int y) {
340 if (allowText)
341 graphics.drawText(s, zoomTextPoint(x, y));
342 }
343
344 /**
345 * @see Graphics#drawText(String, int, int, int)
346 */
347 public void drawText(String s, int x, int y, int style) {
348 if (allowText)
349 graphics.drawText(s, zoomTextPoint(x, y), style);
350 }
351
352 /**
353 * @see Graphics#drawTextLayout(TextLayout, int, int, int, int, Color, Color)
354 */
355 public void drawTextLayout(TextLayout layout, int x, int y, int selectionStart,
356 int selectionEnd, Color selectionForeground, Color selectionBackground) {
357 TextLayout scaled = zoomTextLayout(layout);
358 graphics.drawTextLayout(scaled,
359 cast(int)Math.floor(x * zoom + fractionalX),
360 cast(int)Math.floor(y * zoom + fractionalY),
361 selectionStart, selectionEnd, selectionBackground, selectionForeground);
362 scaled.dispose();
363 }
364
365 /** @see Graphics#fillArc(int, int, int, int, int, int) */
366 public void fillArc(int x, int y, int w, int h, int offset, int sweep) {
367 Rectangle z = zoomFillRect(x, y, w, h);
368 if (z.isEmpty() || sweep is 0)
369 return;
370 graphics.fillArc(z, offset, sweep);
371 }
372
373 /** @see Graphics#fillGradient(int, int, int, int, bool) */
374 public void fillGradient(int x, int y, int w, int h, bool vertical) {
375 graphics.fillGradient(zoomFillRect(x, y, w, h), vertical);
376 }
377
378 /** @see Graphics#fillOval(int, int, int, int) */
379 public void fillOval(int x, int y, int w, int h) {
380 graphics.fillOval(zoomFillRect(x, y, w, h));
381 }
382
383 /** @see Graphics#fillPath(Path) */
384 public void fillPath(Path path) {
385 Path scaledPath = createScaledPath(path);
386 try {
387 graphics.fillPath(scaledPath);
388 } finally {
389 scaledPath.dispose();
390 }
391 }
392
393 /**
394 * @see Graphics#fillPolygon(int[])
395 */
396 public void fillPolygon(int[] points) {
397 graphics.fillPolygon(zoomPointList(points));
398 }
399
400 /** @see Graphics#fillPolygon(PointList) */
401 public void fillPolygon(PointList points) {
402 graphics.fillPolygon(zoomPointList(points.toIntArray()));
403 }
404
405 /** @see Graphics#fillRectangle(int, int, int, int) */
406 public void fillRectangle(int x, int y, int w, int h) {
407 graphics.fillRectangle(zoomFillRect(x, y, w, h));
408 }
409
410 /** @see Graphics#fillRoundRectangle(Rectangle, int, int) */
411 public void fillRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
412 graphics.fillRoundRectangle(zoomFillRect(r.x, r.y, r.width, r.height),
413 cast(int)(arcWidth * zoom),
414 cast(int)(arcHeight * zoom));
415 }
416
417 /** @see Graphics#fillString(String, int, int) */
418 public void fillString(String s, int x, int y) {
419 if (allowText)
420 graphics.fillString(s, zoomTextPoint(x, y));
421 }
422
423 /** @see Graphics#fillText(String, int, int) */
424 public void fillText(String s, int x, int y) {
425 if (allowText)
426 graphics.fillText(s, zoomTextPoint(x, y));
427 }
428
429 /**
430 * @see Graphics#getAbsoluteScale()
431 */
432 public double getAbsoluteScale() {
433 return zoom * graphics.getAbsoluteScale();
434 }
435
436 /**
437 * @see Graphics#getAlpha()
438 */
439 public int getAlpha() {
440 return graphics.getAlpha();
441 }
442
443 /**
444 * @see Graphics#getAntialias()
445 */
446 public int getAntialias() {
447 return graphics.getAntialias();
448 }
449
450 /** @see Graphics#getBackgroundColor() */
451 public Color getBackgroundColor() {
452 return graphics.getBackgroundColor();
453 }
454
455 Font getCachedFont(FontKey key) {
456 Font font = cast(Font)fontCache.get(key);
457 if (font !is null)
458 return font;
459 key = new FontKey(key.font, key.height);
460 FontData data = key.font.getFontData()[0];
461 data.setHeight(key.height);
462 Font zoomedFont = createFont(data);
463 fontCache.put(key, zoomedFont);
464 return zoomedFont;
465 }
466
467 FontData getCachedFontData(Font f) {
468 FontData data = cast(FontData)fontDataCache.get(f);
469 if (data !is null)
470 return data;
471 data = getLocalFont().getFontData()[0];
472 fontDataCache.put(f, data);
473 return data;
474 }
475
476 /** @see Graphics#getClip(Rectangle) */
477 public Rectangle getClip(Rectangle rect) {
478 graphics.getClip(rect);
479 int x = cast(int)(rect.x / zoom);
480 int y = cast(int)(rect.y / zoom);
481 /*
482 * If the clip rectangle is queried, perform an inverse zoom, and take the ceiling of
483 * the resulting double. This is necessary because forward scaling essentially performs
484 * a floor() function. Without this, figures will think that they don't need to paint
485 * when actually they do.
486 */
487 rect.width = cast(int)Math.ceil(rect.right() / zoom) - x;
488 rect.height = cast(int)Math.ceil(rect.bottom() / zoom) - y;
489 rect.x = x;
490 rect.y = y;
491 return rect;
492 }
493
494 /**
495 * @see Graphics#getFillRule()
496 */
497 public int getFillRule() {
498 return graphics.getFillRule();
499 }
500
501 /** @see Graphics#getFont() */
502 public Font getFont() {
503 return getLocalFont();
504 }
505
506 /** @see Graphics#getFontMetrics() */
507 public FontMetrics getFontMetrics() {
508 return FigureUtilities.getFontMetrics(localFont);
509 }
510
511 /** @see Graphics#getForegroundColor() */
512 public Color getForegroundColor() {
513 return graphics.getForegroundColor();
514 }
515
516 /**
517 * @see Graphics#getInterpolation()
518 */
519 public int getInterpolation() {
520 return graphics.getInterpolation();
521 }
522
523 /**
524 * @see Graphics#getLineCap()
525 */
526 public int getLineCap() {
527 return graphics.getLineCap();
528 }
529
530 /**
531 * @see Graphics#getLineJoin()
532 */
533 public int getLineJoin() {
534 return graphics.getLineJoin();
535 }
536
537 /** @see Graphics#getLineStyle() */
538 public int getLineStyle() {
539 return graphics.getLineStyle();
540 }
541
542 /** @see Graphics#getLineWidth() */
543 public int getLineWidth() {
544 return getLocalLineWidth();
545 }
546
547 private Font getLocalFont() {
548 return localFont;
549 }
550
551 private int getLocalLineWidth() {
552 return localLineWidth;
553 }
554
555 /**
556 * @see Graphics#getTextAntialias()
557 */
558 public int getTextAntialias() {
559 return graphics.getTextAntialias();
560 }
561
562 /** @see Graphics#getXORMode() */
563 public bool getXORMode() {
564 return graphics.getXORMode();
565 }
566
567 /** @see Graphics#popState() */
568 public void popState() {
569 graphics.popState();
570 stackPointer--;
571 restoreLocalState(cast(State)stack.get(stackPointer));
572 }
573
574 /** @see Graphics#pushState() */
575 public void pushState() {
576 State s;
577 if (stack.size() > stackPointer) {
578 s = cast(State)stack.get(stackPointer);
579 s.setValues(zoom, fractionalX, fractionalY, getLocalFont(), localLineWidth);
580 } else {
581 stack.add(new State(zoom, fractionalX, fractionalY, getLocalFont(),
582 localLineWidth));
583 }
584 stackPointer++;
585
586 graphics.pushState();
587 }
588
589 private void restoreLocalState(State state) {
590 this.fractionalX = state.appliedX;
591 this.fractionalY = state.appliedY;
592 setScale(state.zoom);
593 setLocalFont(state.font);
594 setLocalLineWidth(state.lineWidth);
595 }
596
597 /** @see Graphics#restoreState() */
598 public void restoreState() {
599 graphics.restoreState();
600 restoreLocalState(cast(State)stack.get(stackPointer - 1));
601 }
602
603 /** @see Graphics#scale(double) */
604 public void scale(double amount) {
605 setScale(zoom * amount);
606 }
607
608 /**
609 * @see Graphics#setAlphacast(int)
610 */
611 public void setAlpha(int alpha) {
612 graphics.setAlpha(alpha);
613 }
614
615 /**
616 * @see Graphics#setAntialiascast(int)
617 */
618 public void setAntialias(int value) {
619 graphics.setAntialias(value);
620 }
621
622 /** @see Graphics#setBackgroundColor(Color) */
623 public void setBackgroundColor(Color rgb) {
624 graphics.setBackgroundColor(rgb);
625 }
626
627 /** @see Graphics#setClip(Path) */
628 public void setClip(Path path) {
629 Path scaledPath = createScaledPath(path);
630 try {
631 graphics.setClip(scaledPath);
632 } finally {
633 scaledPath.dispose();
634 }
635 }
636
637 /** @see Graphics#setClip(Rectangle) */
638 public void setClip(Rectangle r) {
639 graphics.setClip(zoomClipRect(r));
640 }
641
642 /**
643 * @see Graphics#setFillRulecast(int)
644 */
645 public void setFillRule(int rule) {
646 graphics.setFillRule(rule);
647 }
648
649 /** @see Graphics#setFontcast(Font) */
650 public void setFont(Font f) {
651 setLocalFont(f);
652 }
653
654 /** @see Graphics#setForegroundColor(Color) */
655 public void setForegroundColor(Color rgb) {
656 graphics.setForegroundColor(rgb);
657 }
658
659 /**
660 * @see dwtx.draw2d.Graphics#setInterpolationcast(int)
661 */
662 public void setInterpolation(int interpolation) {
663 graphics.setInterpolation(interpolation);
664 }
665
666 /**
667 * @see Graphics#setLineCapcast(int)
668 */
669 public void setLineCap(int cap) {
670 graphics.setLineCap(cap);
671 }
672
673 /**
674 * @see Graphics#setLineDash(int[])
675 */
676 public void setLineDash(int[] dash) {
677 graphics.setLineDash(dash);
678 }
679
680 /**
681 * @see Graphics#setLineJoincast(int)
682 */
683 public void setLineJoin(int join) {
684 graphics.setLineJoin(join);
685 }
686
687 /** @see Graphics#setLineStylecast(int) */
688 public void setLineStyle(int style) {
689 graphics.setLineStyle(style);
690 }
691
692 /** @see Graphics#setLineWidthcast(int) */
693 public void setLineWidth(int width) {
694 setLocalLineWidth(width);
695 }
696
697 private void setLocalFont(Font f) {
698 localFont = f;
699 graphics.setFont(zoomFont(f));
700 }
701
702 private void setLocalLineWidth(int width) {
703 localLineWidth = width;
704 graphics.setLineWidth(zoomLineWidth(width));
705 }
706
707 void setScale(double value) {
708 if (zoom is value)
709 return;
710 this.zoom = value;
711 graphics.setFont(zoomFont(getLocalFont()));
712 graphics.setLineWidth(zoomLineWidth(localLineWidth));
713 }
714
715 /**
716 * @see Graphics#setTextAntialiascast(int)
717 */
718 public void setTextAntialias(int value) {
719 graphics.setTextAntialias(value);
720 }
721
722 /** @see Graphics#setXORMode(bool) */
723 public void setXORMode(bool b) {
724 graphics.setXORMode(b);
725 }
726
727 /** @see Graphics#translate(int, int) */
728 public void translate(int dx, int dy) {
729 // fractionalX/Y is the fractional part left over from previous
730 // translates that gets lost in the integer approximation.
731 double dxFloat = dx * zoom + fractionalX;
732 double dyFloat = dy * zoom + fractionalY;
733 fractionalX = dxFloat - Math.floor(dxFloat);
734 fractionalY = dyFloat - Math.floor(dyFloat);
735 graphics.translate(cast(int)Math.floor(dxFloat), cast(int)Math.floor(dyFloat));
736 }
737
738 /** @see Graphics#translate(float, float) */
739 public void translate(float dx, float dy) {
740 double dxFloat = dx * zoom + fractionalX;
741 double dyFloat = dy * zoom + fractionalY;
742 fractionalX = dxFloat - Math.floor(dxFloat);
743 fractionalY = dyFloat - Math.floor(dyFloat);
744 graphics.translate(cast(int)Math.floor(dxFloat), cast(int)Math.floor(dyFloat));
745 }
746
747 private Rectangle zoomClipRect(Rectangle r) {
748 tempRECT.x = cast(int)(Math.floor(r.x * zoom + fractionalX));
749 tempRECT.y = cast(int)(Math.floor(r.y * zoom + fractionalY));
750 tempRECT.width = cast(int)(Math.ceil(((r.x + r.width) * zoom + fractionalX))) - tempRECT.x;
751 tempRECT.height = cast(int)(Math.ceil(((r.y + r.height) * zoom + fractionalY))) - tempRECT.y;
752 return tempRECT;
753 }
754
755 private Rectangle zoomFillRect(int x, int y, int w, int h) {
756 tempRECT.x = cast(int)(Math.floor((x * zoom + fractionalX)));
757 tempRECT.y = cast(int)(Math.floor((y * zoom + fractionalY)));
758 tempRECT.width = cast(int)(Math.floor(((x + w - 1) * zoom + fractionalX))) - tempRECT.x + 1;
759 tempRECT.height = cast(int)(Math.floor(((y + h - 1) * zoom + fractionalY))) - tempRECT.y + 1;
760 return tempRECT;
761 }
762
763 Font zoomFont(Font f) {
764 if (f is null)
765 f = Display.getCurrent().getSystemFont();
766 FontData data = getCachedFontData(f);
767 int zoomedFontHeight = zoomFontHeight(data.getHeight());
768 allowText = zoomedFontHeight > 0;
769 fontKey.setValues(f, zoomedFontHeight);
770 return getCachedFont(fontKey);
771 }
772
773 int zoomFontHeight(int height) {
774 return cast(int)(zoom * height);
775 }
776
777 int zoomLineWidth(int w) {
778 return w;
779 }
780
781 private int[] zoomPointList(int[] points) {
782 int[] scaled = null;
783
784 // Look in cache for a integer array with the same length as 'points'
785 for (int i = 0; i < intArrayCache.length; i++) {
786 if (intArrayCache[i].length is points.length) {
787 scaled = intArrayCache[i];
788
789 // Move this integer array up one notch in the array
790 if (i !is 0) {
791 int[] temp = intArrayCache[i - 1];
792 intArrayCache[i - 1] = scaled;
793 intArrayCache[i] = temp;
794 }
795 }
796 }
797
798 // If no match is found, take the one that is last and resize it.
799 if (scaled is null) {
800 intArrayCache[intArrayCache.length - 1] = new int[points.length];
801 scaled = intArrayCache[intArrayCache.length - 1];
802 }
803
804 // Scale the points
805 for (int i = 0; (i + 1) < points.length; i += 2) {
806 scaled[i] = cast(int)(Math.floor((points[i] * zoom + fractionalX)));
807 scaled[i + 1] = cast(int)(Math.floor((points[i + 1] * zoom + fractionalY)));
808 }
809 return scaled;
810 }
811
812 private Rectangle zoomRect(int x, int y, int w, int h) {
813 tempRECT.x = cast(int)(Math.floor(x * zoom + fractionalX));
814 tempRECT.y = cast(int)(Math.floor(y * zoom + fractionalY));
815 tempRECT.width = cast(int)(Math.floor(((x + w) * zoom + fractionalX))) - tempRECT.x;
816 tempRECT.height = cast(int)(Math.floor(((y + h) * zoom + fractionalY))) - tempRECT.y;
817 return tempRECT;
818 }
819
820 private TextLayout zoomTextLayout(TextLayout layout) {
821 TextLayout zoomed = new TextLayout(Display.getCurrent());
822 zoomed.setText(layout.getText());
823
824 int zoomWidth = -1;
825
826 if (layout.getWidth() !is -1)
827 zoomWidth = (cast(int)(layout.getWidth() * zoom));
828
829 if (zoomWidth < -1 || zoomWidth is 0)
830 return null;
831
832 zoomed.setFont(zoomFont(layout.getFont()));
833 zoomed.setAlignment(layout.getAlignment());
834 zoomed.setAscent(layout.getAscent());
835 zoomed.setDescent(layout.getDescent());
836 zoomed.setOrientation(layout.getOrientation());
837 zoomed.setSegments(layout.getSegments());
838 zoomed.setSpacing(layout.getSpacing());
839 zoomed.setTabs(layout.getTabs());
840
841 zoomed.setWidth(zoomWidth);
842 int length = layout.getText().length;
843 if (length > 0) {
844 int start = 0, offset = 1;
845 TextStyle style = null, lastStyle = layout.getStyle(0);
846 for (; offset <= length; offset++) {
847 if (offset !is length
848 && (style = layout.getStyle(offset)) is lastStyle)
849 continue;
850 int end = offset - 1;
851
852 if (lastStyle !is null) {
853 TextStyle zoomedStyle = new TextStyle(zoomFont(lastStyle.font),
854 lastStyle.foreground, lastStyle.background);
855 zoomedStyle.metrics = lastStyle.metrics;
856 zoomedStyle.rise = lastStyle.rise;
857 zoomedStyle.strikeout = lastStyle.strikeout;
858 zoomedStyle.underline = lastStyle.underline;
859 zoomed.setStyle(zoomedStyle, start, end);
860 }
861 lastStyle = style;
862 start = offset;
863 }
864 }
865 return zoomed;
866 }
867
868 private Point zoomTextPoint(int x, int y) {
869 if (localCache.font !is localFont) {
870 //Font is different, re-calculate its height
871 FontMetrics metric = FigureUtilities.getFontMetrics(localFont);
872 localCache.height = metric.getHeight() - metric.getDescent();
873 localCache.font = localFont;
874 }
875 if (targetCache.font !is graphics.getFont()) {
876 FontMetrics metric = graphics.getFontMetrics();
877 targetCache.font = graphics.getFont();
878 targetCache.height = metric.getHeight() - metric.getDescent();
879 }
880 return new Point((cast(int)(Math.floor((x * zoom) + fractionalX))),
881 cast(int)(Math.floor((y + localCache.height - 1) * zoom
882 - targetCache.height + 1 + fractionalY)));
883 }
884
885 }