1
2 package net.phbwt.jtans.guimain;
3
4 import net.phbwt.jtans.guicommon;
5 import net.phbwt.jtans.calc;
6
7 import java.awt;
8 import java.awt.geom;
9 import java.awt.image;
10 import javax.swing;
11 import javax.swing.border;
12 import javax.swing.text;
13 import java.awt.event;
14 import java.util;
15
16
17 /**
18 * Emet des PropertyChangeEvent :
19 * PROPERTY_FOUND lorsque la solution est trouv?e/resett?e.
20 * PROPERTY_SELECTION lorsque une pi?ce (de)selectionn?e.
21 *
22 * G?re tous les autre events (bon d'accord, c'est pas bien).
23 */
24
25 public final class EditableFigureComponent extends JPanel implements Observer {
26
27 public static final String PROPERTY_SELECTION = "jt.selection";
28 public static final String PROPERTY_FOUND = "jt.found";
29
30 private static final boolean DEBUG = false;
31
32 public static final int MODE_NONE = 1;
33 public static final int MODE_MOVE = 2;
34 public static final int MODE_ROTATION = 3;
35
36 // la config n?cessitant des acc?s graphiques
37 private boolean gfxIsConfigured = false;
38
39 // le fond et les pieces (unsel et sel)
40 private Surface bgSurface;
41 private Paint bgPaint;
42 private Surface unselectedFiguresSurface;
43 private Paint unselectedFiguresPaint;
44 private Surface selectedFigureSurface;
45 private Paint selectedFigurePaint;
46 private Composite selectedFigureComposite;
47
48 // le trait
49 private Paint traitPaint;
50 private Stroke traitStroke;
51 private int traitGrow; // augmentation de la zone ? rafraichir pour tenir compte de la largeur du stroke
52
53 // bordure des shapes
54 private Paint borderPaint;
55 private Stroke borderStroke;
56 private int borderGrow; // augmentation de la zone ? rafraichir pour tenir compte de la largeur du stroke
57
58 // outline
59 private Paint outlinePaint;
60 private Stroke outlineStroke;
61
62 // la marque "trouv?"
63 private Shape foundMarkShapeScaled; // rescal?e ? chaque changement de taille
64 private Stroke foundMarkStroke;
65 private Composite foundMarkComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f);
66
67 // rendering hints
68 private RenderingHints hints;
69
70 public EditableFigure fig; // la figure dont les pi?ces sont affich?es
71 public DisplayFigure outlineFig; // la figure outlin?e
72
73 private double refScale;
74
75 // variables li?es au buffer offscreen
76 protected BufferedImage offImg;
77 protected Graphics2D offImgGr;
78 protected int offImgW, offImgH;
79
80 // taille des bordures haut et gauche (pour placement de l'image)
81 int compBorderTop, compBorderLeft;
82
83 // zone ? rafraichir pour effacer la pi?ce selectionn?e
84 Rectangle selectedPieceLastBounds;
85 // juste pour ?viter de cr?er un objet local pour le grow()
86 Rectangle selectedPieceActualBounds = new Rectangle();
87
88 // zone ? rafraichir pour effacer le trait de rotation
89 Rectangle traitLastBounds;
90 // juste pour ?viter de cr?er un objet local pour le grow()
91 Rectangle traitActualBounds = new Rectangle();
92
93 // trait de rotation
94 Line2D.Double traitShape = new Line2D.Double();
95
96 // derni?re position de la souris (pour MOVE et trait de ROTATION)
97 // r?el ou dans les limites
98 int lastX, lastY;
99
100 // il y a une pi?ce selectionn?e
101 boolean isSelected = false;
102
103 // l'outline est affich?e
104 boolean withOutline = false;
105
106 // trouv? maintenant ( != figure d?j? trouv?e)
107 boolean isFound = false;
108 int compareAccuracy;
109
110 // d?placement/rotation
111 int actualMode = MODE_NONE;
112
113 // gestion de la rotation
114 int rotOriginX, rotOriginY;
115 double rotOriginAngle;
116 double rotRefAngle;
117
118 // i18n
119 private static ResourceBundle i18n = null;
120
121
122 /**
123 *
124 * @param ef La figure affich?e.
125 * @param of La figure outlin?e.
126 * @param li l'Observer notifi? lorsque la solution est trouv?e
127 */
128
129 EditableFigureComponent(EditableFigure ef, DisplayFigure of, Config cf) {
130 setOpaque(true);
131 setDoubleBuffered(true);
132
133 fig = ef;
134 outlineFig = of;
135
136 config(cf);
137 cf.addObserver(this);
138
139 if ( i18n == null ) {
140 i18n = ResourceBundle.getBundle("net.phbwt.jtans.i18n.main");
141 }
142
143 // changement de taille
144 this.addComponentListener(new ComponentAdapter() {
145 public void componentResized(ComponentEvent e) {
146
147 if ( DEBUG ) {
148 System.out.println("taille");
149 }
150
151 setScale(refScale);
152
153 offImg = null;
154
155 // marque
156 foundMarkShapeScaled = null; // ? recr?er
157 foundMarkStroke = new BasicStroke(((float) getWidth()) / 150f,
158 BasicStroke.CAP_ROUND,
159 BasicStroke.JOIN_ROUND);
160
161 repaint(); // sinon pb. ? la diparition de la statusbar
162 }
163 });
164
165
166 // click
167 this.addMouseListener(new MouseAdapter() {
168 public void mouseReleased(MouseEvent e) {
169 traitShape.setLine(rotOriginX, rotOriginY, rotOriginX, rotOriginY);
170 refreshSelectedPiece();
171 actualMode = MODE_NONE;
172
173 if (!isFound && fig.getCalcFigure().compare(outlineFig.getCalcFigure(),
174 compareAccuracy)) {
175 isFound = true;
176 unselect();
177 repaint(); // dessine la marque
178
179 firePropertyChange(PROPERTY_FOUND, false, true);
180 }
181 }
182
183 public void mousePressed(MouseEvent e) {
184
185 // d?j? trouv?
186 if (isFound) return;
187
188 int x = e.getX();
189 int y = e.getY();
190 int sel = fig.selectAt( x, y);
191
192 if ( sel == EditableFigure.SEL_NONE &&
193 isSelected &&
194 (e.getModifiers() & InputEvent.BUTTON1_MASK) != 0 ) {
195 // passage en mode rotation
196 // System.out.println("mode rot");
197 actualMode = MODE_ROTATION;
198 rotOriginX = fig.getSelectedPiece().getPosX();
199 rotOriginY = fig.getSelectedPiece().getPosY();
200 rotOriginAngle = fig.getSelectedPiece().getRotation();
201 rotRefAngle = Math.atan2(x - rotOriginX, y - rotOriginY);
202 // System.out.println("mode rot:orig=" + rotOriginAngle + ":ref=" + rotRefAngle);
203
204 traitShape.setLine(rotOriginX, rotOriginY, x, y);
205 refreshSelectedPiece();
206 }
207
208 if ( sel != EditableFigure.SEL_NONE ) {
209 // click dans une piece
210 // System.out.println("mode move");
211 actualMode = MODE_MOVE;
212 if ( sel == EditableFigure.SEL_NEW || !isSelected ) {
213 // selection d'une nouvelle piece (ou de l'ancienne si non selectionn?e)
214 boolean oldSel = isSelected;
215 isSelected = true;
216 // refreshAll();
217 redrawOffscreenImage(true);
218 repaint();
219
220 firePropertyChange(PROPERTY_SELECTION, oldSel, true);
221 }
222 }
223
224 if ( ( e.getClickCount() == 2 ||
225 (e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 )
226 && isSelected ) {
227 fig.flipSelectedPiece();
228 refreshSelectedPiece();
229 }
230
231 lastX = x;
232 lastY = y;
233 }
234 });
235
236
237 // drag
238 this.addMouseMotionListener(new MouseMotionAdapter() {
239 public void mouseDragged(MouseEvent e) {
240
241 switch ( actualMode) {
242
243 case MODE_MOVE:
244 Point p = fig.translateSelectedPiece(e.getX() - lastX, e.getY() - lastY);
245
246 lastX += p.x;
247 lastY += p.y;
248 refreshSelectedPiece();
249
250 break;
251
252 case MODE_ROTATION:
253 double angle = rotOriginAngle -
254 rotRefAngle +
255 Math.atan2(e.getX() - rotOriginX, e.getY() - rotOriginY);
256 // System.out.println("angle=" + angle);
257
258 fig.setRotationForSelectedPiece(angle);
259
260 lastX = e.getX();
261 lastY = e.getY();
262
263 traitShape.setLine(rotOriginX, rotOriginY, lastX, lastY);
264
265 refreshSelectedPiece();
266
267 break;
268 }
269 }
270 });
271 }
272
273
274 /**
275 * Prend en compte les modifs de la config.
276 * N'est pas appell? ? l'init.
277 */
278
279 public void update(Observable obs, Object obj) {
280
281 if ( DEBUG ) {
282 System.out.println("editfig update");
283 }
284
285 config((Config) obs);
286 refreshAll();
287 }
288
289
290 /**
291 * R?cup?re les param?tres dans la config.
292 * Pas d'acc?s graphiques.
293 */
294
295 private void config(Config cf) {
296
297 if ( DEBUG ) {
298 System.out.println("editfig config");
299 }
300
301 Trait t;
302
303 bgSurface = cf.getSurface("main.background");
304
305 unselectedFiguresSurface = cf.getSurface("main.piece.normal");
306
307 selectedFigureSurface = cf.getSurface("main.piece.selected");
308
309 selectedFigureComposite = cf.getComposite("main.piece.selected.alpha");
310
311 t = cf.getTrait("main.rotation");
312 traitPaint = t.getColor();
313 traitStroke = t.getStroke();
314 traitGrow = t.getGrow();
315
316 t = cf.getTrait("main.piece.border");
317 borderPaint = t.getColor();
318 borderStroke = t.getStroke();
319 borderGrow = t.getGrow();
320
321 t = cf.getTrait("main.outline");
322 outlinePaint = t.getColor();
323 outlineStroke = t.getStroke();
324
325 // taille relative
326 setScale(cf.getDouble("main.scale", 0.1d));
327
328 // type de rotation
329 switch ( cf.getInt("main.rotationStep", Config.ROTATION_STEP_32)) {
330 case Config.ROTATION_CONTINUOUS:
331 fig.setSteppedRotation(-1d, 0d);
332 break;
333
334 case Config.ROTATION_STEP_32:
335 fig.setSteppedRotation(Math.PI / 16, 0d);
336 break;
337
338 case Config.ROTATION_STEP_AUTO:
339 fig.setSteppedRotation(Math.PI / 16, 0d);
340 break;
341 }
342
343 // pr?cision de comparaison
344 compareAccuracy = cf.getInt("main.compareAccuracy", CalcFigure.COMPARE_ACCURACY_MEDIUM);
345 // System.out.println("accuracy" + compareAccuracy);
346
347 // rendering
348 hints = cf.getRenderingHints();
349
350 // provoque une re-init graphique
351 offImg = null; // pour dessiner avec les bons hints
352 gfxIsConfigured = false;
353 }
354
355
356 /**
357 * post config (n?cessitant un contexte graphique).
358 */
359
360 private void configGfx() {
361
362 if ( DEBUG ) {
363 System.out.println("editfig config gfx");
364 }
365
366 bgPaint = bgSurface.getPaintNoError(this);
367 unselectedFiguresPaint = unselectedFiguresSurface.getPaintNoError(this);
368 selectedFigurePaint = selectedFigureSurface.getPaintNoError(this);
369
370
371 // if ( bgSurface != null) {
372 // bgPaint = bgSurface.getPaint(this);
373 // } else {
374 // bgPaint = new Color(190, 190, 200);
375 // }
376
377 // if ( unselectedFiguresSurface != null) {
378 // unselectedFiguresPaint = unselectedFiguresSurface.getPaint(this);
379 // } else {
380 // unselectedFiguresPaint = Color.black;
381 // }
382
383 // if ( selectedFigureSurface != null) {
384 // selectedFigurePaint = selectedFigureSurface.getPaint(this);
385 // } else {
386 // selectedFigurePaint = new Color(100, 100, 100);
387 // }
388
389 gfxIsConfigured = true;
390 }
391
392
393 public final void paintComponent(Graphics g){
394
395 // partie graphique de la configuration (si n?cessaire)
396 if ( !gfxIsConfigured ) {
397 configGfx();
398 }
399
400 Graphics2D g2 = (Graphics2D)g;
401 Stroke oldStroke = g2.getStroke();
402 Composite oldComposite = null; // utilis? si le composite est modifi?
403
404 // cr?e et dessine le buffer
405 if ( offImg == null ) {
406 redrawOffscreenImage(false);
407 }
408
409 // le fond et les shapes non selectionn?es
410 g2.drawImage(offImg, compBorderLeft, compBorderTop, this);
411
412 // le trait de rotation
413 if ( actualMode == MODE_ROTATION ) {
414 // dessin du trait
415 g2.setPaint(traitPaint);
416 g2.setStroke(traitStroke);
417 g2.draw(traitShape);
418 if ( traitLastBounds == null ) {
419 traitLastBounds = new Rectangle();
420 }
421 // recopie le contenu (pas la r?f?rence)
422 traitLastBounds.setBounds(traitShape.getBounds());
423 traitLastBounds.grow(traitGrow, traitGrow); // en gros moiti? de la largeur du trait
424 }
425
426 // dessin de la shape selectionn?e
427 if ( isSelected ) {
428
429 g2.setPaint(selectedFigurePaint);
430
431 if ( selectedFigureComposite != null ) {
432 oldComposite = g2.getComposite();
433 g2.setComposite(selectedFigureComposite);
434 }
435 } else {
436 g2.setPaint(unselectedFiguresPaint);
437 }
438
439 g2.fill(fig.getSelectedPiece());
440 g2.setPaint(borderPaint);
441 g2.setStroke(borderStroke);
442 g2.draw(fig.getSelectedPiece());
443
444 // pour effacement de l'ancienne pi?ce
445 if ( selectedPieceLastBounds == null ) {
446 selectedPieceLastBounds = new Rectangle();
447 }
448
449 // recopie le contenu (pas la r?f?rence)
450 selectedPieceLastBounds.setBounds(fig.getSelectedPiece().getBounds());
451 selectedPieceLastBounds.grow(borderGrow, borderGrow); // moiti? de la largeur du trait
452
453 // marque
454 if ( isFound ) {
455
456 long time = System.currentTimeMillis();
457
458 // (re)cr?e la forme
459 if (foundMarkShapeScaled == null) {
460 foundMarkShapeScaled = createFoundMarkShape(g2);
461 }
462
463 if (oldComposite == null) {
464 oldComposite = g2.getComposite();
465 }
466
467 g2.setComposite(foundMarkComposite);
468 g2.setPaint(Color.white);
469 g2.fill(foundMarkShapeScaled);
470 g2.setStroke(foundMarkStroke);
471 g2.setPaint(Color.black);
472 g2.draw(foundMarkShapeScaled);
473
474 if (DEBUG) {
475 time = System.currentTimeMillis() - time; // *debug*
476 System.out.println("redraw foundMark :" + time);
477 }
478 }
479
480 // restaure l'?tat de d?part
481 g2.setStroke(oldStroke);
482 if (oldComposite != null) {
483 g2.setComposite(oldComposite);
484 }
485 }
486
487
488 /**
489 * Red?ssine le buffer apr?s l'avoir cr?? si n?cessaire.
490 * Dessine le fond, l'outline, les pi?ces no selectionn?es.
491 */
492
493 protected void redrawOffscreenImage(boolean fast){
494
495 if ( DEBUG ) {
496 System.out.println("offscreenImage redessine");
497 }
498
499 if ( offImg == null ) {
500
501 if ( DEBUG ) {
502 System.out.println("offscreenImage recree");
503 }
504
505 Insets in = getInsets();
506 compBorderLeft = in.left;
507 compBorderTop = in.top;
508 int w = getWidth() - in.left - in.right;
509 int h = getHeight() - in.top - in.bottom;
510
511 offImg = (BufferedImage)createImage(w, h);
512 offImgGr = (Graphics2D)offImg.createGraphics();
513
514 offImgGr.translate(-compBorderLeft, -compBorderTop);
515 // fig.setRefX(-compBorderLeft, -compBorderTop);
516
517 // offImgGr.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
518 // offImgGr.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
519 // RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
520
521 // valeur par d?faut ?cras?es
522 offImgGr.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
523 RenderingHints.VALUE_ANTIALIAS_OFF);
524 offImgGr.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
525 RenderingHints.VALUE_COLOR_RENDER_SPEED);
526 offImgGr.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
527 RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
528 offImgGr.setRenderingHint(RenderingHints.KEY_DITHERING,
529 RenderingHints.VALUE_DITHER_DISABLE);
530 offImgGr.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
531 RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
532 offImgGr.setRenderingHint(RenderingHints.KEY_RENDERING,
533 RenderingHints.VALUE_RENDER_SPEED);
534
535 offImgGr.addRenderingHints(hints);
536
537 offImgW = w;
538 offImgH = h;
539
540 fast = false;
541 }
542
543 long time = System.currentTimeMillis(); // *debug*
544
545 if ( fast && fig.getPreviousSelectedPiece() != null ) {
546 Rectangle rect = fig.getPreviousSelectedPiece().getBounds()
547 .union(fig.getSelectedPiece().getBounds());
548 rect.grow(traitGrow, traitGrow);
549 offImgGr.setClip(rect);
550 } else {
551 offImgGr.setClip(null);
552 }
553
554 // le fond
555 offImgGr.setPaint(bgPaint);
556 offImgGr.fill(new Rectangle(compBorderLeft, compBorderTop, offImgW, offImgH));
557
558 // l'outline
559 if ( withOutline ) {
560 offImgGr.setPaint(outlinePaint);
561 offImgGr.setStroke(outlineStroke);
562 for ( Iterator i = outlineFig.outlineIterator(); i.hasNext(); ) {
563 offImgGr.draw((PixelOutlinePolygon) i.next());
564 }
565 }
566
567 // les shapes non s?lectionn?es
568 for ( Iterator i = fig.pieceIteratorBottomUp(); i.hasNext();) {
569 Shape s = (Shape)i.next();
570 offImgGr.setPaint(unselectedFiguresPaint);
571 offImgGr.fill(s);
572 offImgGr.setPaint(borderPaint);
573 offImgGr.setStroke(borderStroke);
574 offImgGr.draw(s);
575 }
576
577 // // les tiny triangles
578 // offImgGr.setPaint(Color.red);
579 // TinyTab tt = fig.calcFig.getFigureTinyTab();
580 // for ( int i = 0; i < tt.ntriangles; i++ ) {
581 // int x = (int)(tt.xtriangles[i] * fig.scale) + fig.refX;
582 // int y = (int)(tt.ytriangles[i] * fig.scale) + fig.refY;
583 // offImgGr.drawLine(x, y, x + 1, y + 1);
584 // }
585
586 // // la shape selectionn?e
587 // offImgGr.setPaint(selectedFigurePaint);
588 // offImgGr.fill(fig.shapes[CalcFigure.PIECE_SELECTED]);
589
590 if ( DEBUG ) {
591 time = System.currentTimeMillis() - time; // *debug*
592 System.out.println("duree redraw=" + time + ":clipping=" + offImgGr.getClip());
593 }
594 }
595
596
597 public void refreshSelectedPiece() {
598
599 if ( actualMode == MODE_ROTATION ) {
600
601 // red?ssine le fond sous le trait de rotation
602 if ( traitLastBounds != null ) {
603 this.repaint(traitLastBounds);
604 }
605
606 // red?ssine le trait
607 traitActualBounds.setBounds(traitShape.getBounds());
608 traitActualBounds.grow(traitGrow, traitGrow); // moiti? de la largeur du stroke
609 this.repaint(traitActualBounds);
610 }
611
612 // red?ssine le fond sous l'ancienne position
613 if ( selectedPieceLastBounds != null ) {
614 this.repaint(selectedPieceLastBounds);
615 }
616
617 // d?ssine ? la position actuelle
618 selectedPieceActualBounds.setBounds(fig.getSelectedPiece().getBounds());
619 selectedPieceActualBounds.grow(borderGrow, borderGrow); // moiti? de la largeur du trait
620 this.repaint(selectedPieceActualBounds);
621 }
622
623
624 public void refreshAll() {
625
626 if ( !gfxIsConfigured ) {
627 configGfx();
628 }
629
630 redrawOffscreenImage(false);
631 this.repaint();
632 }
633
634
635 /**
636 * (D?) s?lectionne l'affichage de l'outline.
637 * Appelle refreshAll().
638 */
639
640 public void toggleOutline() {
641 withOutline = ! withOutline;
642 refreshAll();
643 }
644
645
646 /**
647 * Change de figure outline.
648 * Passe en mode outline non affich?e.
649 * Peut appeller refreshAll().
650 */
651
652 public void setOutlineFigure(DisplayFigure df) {
653 outlineFig = df;
654
655 if (isFound) {
656 isFound = false;
657 firePropertyChange(PROPERTY_FOUND, true, false);
658 repaint(); // efface la marque
659 }
660
661 setScale(refScale);
662 if ( withOutline ) {
663 toggleOutline();
664 }
665 }
666
667
668 /**
669 * D?s?lectionne la piece.
670 * Appelle refreshAll().
671 */
672
673 public void unselect() {
674 if (isSelected) {
675 isSelected = false;
676 // refreshAll();
677 refreshSelectedPiece();
678
679 firePropertyChange(PROPERTY_SELECTION, true, false);
680 }
681 }
682
683
684 /**
685 * Flippe la piece.
686 * Appelle refreshSelectedPiece().
687 */
688
689 public void flip() {
690 if (! isFound) {
691 fig.flipSelectedPiece();
692 refreshSelectedPiece();
693 }
694 }
695
696
697 /**
698 * Modifie la taille relative des pi?ce.
699 * Recalcule le scale interne (qui d?pends aussi de la taille du composant).
700 * L'outline est recentr?e.
701 * ne redessine pas : peut ?tre suivie par refreshAll();
702 */
703
704 public void setScale(double newScale) {
705
706 refScale = newScale;
707
708 Insets in = getInsets();
709 double scale = refScale * (getWidth() - in.left - in.right);
710 fig.setScale(scale);
711 fig.setLimits( in.left,
712 in.top,
713 getWidth() - in.right,
714 getHeight() - in.bottom );
715 outlineFig.setScale(scale);
716 outlineFig.center( in.left,
717 in.top,
718 getWidth() - in.right,
719 getHeight() - in.bottom );
720 }
721
722
723 protected final Graphics getComponentGraphics(Graphics g) {
724 ((Graphics2D) g).addRenderingHints(hints);
725 // ((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
726 // ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
727 // RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
728 return g;
729 }
730
731
732 /**
733 * Cr?e la forme.
734 */
735
736 private Shape createFoundMarkShape(Graphics2D g2) {
737
738 if (DEBUG) {
739 System.out.println("createFoundMarkShape");
740 }
741
742 Shape ret;
743
744 // arrangement (1 : toute la largeur/hauteur)
745 double scaleX, scaleY;
746
747 // creation de la marque/texte
748 Font f = new Font("SansSerif", Font.PLAIN, 10);
749 java.awt.font.GlyphVector gv;
750 String symbol = i18n.getString("foundMarkSymbol");
751 if (f.canDisplayUpTo(symbol) < 0) {
752 gv = f.createGlyphVector(g2.getFontRenderContext(), symbol);
753 scaleX = scaleY = .75;
754 } else {
755 // manque des glyph : fallback sur le 2?me texte
756 gv = f.createGlyphVector(g2.getFontRenderContext(), i18n.getString("foundMarkText"));
757 scaleX = 1;
758 scaleY = .5;
759 }
760 Shape s = gv.getOutline();
761
762 AffineTransform at = new AffineTransform();
763
764 // [0..1] -> taille et pos. du component
765 Insets in = getInsets();
766 at.translate(in.left, in.top);
767 at.scale(getWidth() - in.left - in.right, getHeight() - in.top - in.bottom);
768
769 // arrangement
770 at.translate((1 - scaleX) / 2, (1 - scaleY) / 2);
771 at.scale(scaleX, scaleY);
772
773 // texte -> [0..1]
774 Rectangle r = s.getBounds();
775 at.scale(1d / (r.getMaxX() - r.getMinX()), 1d / (r.getMaxY() - r.getMinY()));
776 at.translate(-r.getMinX(), -r.getMinY());
777
778 // transformation
779 ret = at.createTransformedShape(s);
780
781 return ret;
782 }
783 }
784