/** * This implementation calls <code>super.hitTest</code> and returns the result if non-null (this * should be a HitInfo.Point), then returns a HitInfo.Interior if the mouse-click occured inside * the text bound (as defined by text layout) * * @return a HitInfo corresponding to the given mouse-event */ public HitInfo hitTest(PEMouseEvent e) { // from Bitmap: if (image != null) { if (getBounds().contains(e.getPicPoint())) { return new HitInfo.Interior((PicText) element, e); } return null; } // from TextLayout: if (!getBounds().contains(e.getPicPoint())) return null; PicText te = (PicText) element; // recompute textlayout b-box, but store it in a temporary field ! Rectangle2D tb = textLayout.getBounds(); Shape text_bounds = text2ModelTr.createTransformedShape(tb); if (text_bounds.contains(e.getPicPoint())) { // [SR:pending] for the hitInfo to be reliable, getPicPoint() should first be transformed by // inverse text2ModelTr ! (especially when rotationAngle != 0) TextHitInfo thi = textLayout.hitTestChar( (float) (e.getPicPoint().x - strx), (float) (e.getPicPoint().y - stry)); // guaranteed to return a non-null thi return new HitInfo.Text((PicText) element, thi, e); } // test hit on textlayout's bounding rectangle : // else if (bounds.contains(e.getPicPoint())) return new HitInfo.Interior(element,e); return null; }
/** * update strx stry = location of TextLayout's bottom-Left corner with respect to PicText's * anchor-point */ protected void syncStringLocation() { PicText te = (PicText) element; PicPoint anchor = te.getCtrlPt(TextEditable.P_ANCHOR, ptBuf); if (image == null) { if (!areDimensionsComputed) { te.setDimensions( textLayout.getBounds().getWidth(), textLayout.getAscent(), textLayout.getDescent()); } strx = te.getLeftX() - anchor.x; stry = te.getBaseLineY() - anchor.y; } else { // image not null strx = te.getLeftX() - anchor.x; stry = te.getBottomY() - anchor.y; } }
/** * Synchronize the textLayout and the shape (=frame box, by calling syncFrame) with the model When * <code>TextLayout</code> is used, this delegates to <code>getRotation()</code> where computing * rotation angle is concerned, and updates the AffineTransform returned by <code> * getTextToModelTransform()</code>. */ protected void syncShape() { PicText te = (PicText) element; // textLayout = new TextLayout(te.getText().length()==0 ? " " : te.getText(), // textFont, // new FontRenderContext(null,false,false)); text2ModelTr.setToIdentity(); // reset PicPoint anchor = te.getCtrlPt(TextEditable.P_ANCHOR, ptBuf); text2ModelTr.rotate(getRotation(), anchor.x, anchor.y); // rotate along P_ANCHOR ! // the reference point of an image is the top-left one, but the refpoint of a text layout is on // the baseline if (image != null) { text2ModelTr.translate(te.getLeftX(), te.getTopY()); if (te.getWidth() != 0 && image.getWidth() != 0 && (te.getDepth() + te.getHeight()) != 0 && image.getHeight() != 0) text2ModelTr.scale( te.getWidth() / image.getWidth(), -(te.getHeight() + te.getDepth()) / image.getHeight()); } else { // Hack ? Just cheating a little bit ? Ou juste ruse ? // we want here to use the dimensions of the textLayout instead of latex dimensions if // areDimensionsComputed // sinon on va aligner le textlayout en fonction des parametres latex, et l'Utilisateur (qui // est bien bete) ne va rien comprendre. double latexH = 0; double latexD = 0; double latexW = 0; if (areDimensionsComputed) { // store latex dimensions, and setDimensions to textLayout ones latexH = te.getHeight(); latexD = te.getDepth(); latexW = te.getWidth(); te.setDimensions( textLayout.getBounds().getWidth(), textLayout.getAscent(), textLayout.getDescent()); } text2ModelTr.translate(te.getLeftX(), te.getBaseLineY()); if (areDimensionsComputed) { // restore latex dimensions te.setDimensions(latexW, latexH, latexD); } // Autre possibilite= comprimer le texte pour qu'il rentre dans la boite (evite le hack // ci-dessus): // text2ModelTr.scale(te.getWidth()/textLayout.getWidth(),-(te.getHeight()+te.getDepth())/textLayout.getHeight()); text2ModelTr.scale(1.0, -1.0); } syncFrame(); }
/** * Render the View to the given graphic context. This implementation render the interior first, * then the outline. */ public void paint(Graphics2D g, Rectangle2D a) { if (!a.intersects(getBounds())) return; if (image != null) { // paint bitmap g.drawImage(image, text2ModelTr, null); // debug: g.setPaint(Color.red); g.draw(this.bounds); super.paint(g, a); // possibly paint framebox if non-null } else { // paint textlayout super.paint(g, a); // possibly paint framebox if non-null AffineTransform oldAT = g.getTransform(); // paint text in black g.setPaint(Color.black); // from now on, we work in Y-direct (<0) coordinates to avoid inextricable problems with font // being mirrored... g.transform(text2ModelTr); // also include rotation textLayout.draw(g, 0.0f, 0.0f); // [pending] ajouter un cadre si areDimensionsComputed (wysiwyg du pauvre) // get back to previous transform g.setTransform(oldAT); if (DEBUG) { g.setPaint(Color.red); g.draw(bounds); } } }
/** * Give notification from the model that a change occured to the text this view is responsible for * rendering. * * <p> */ public void changedUpdate(DrawingEvent.EventType eventType) { PicText text = (PicText) element; if (textLayout == null) { // new *************************** begin (by ss & bp) textLayout = new TextLayout( text.getText(text.getTextMode()).length() == 0 ? " " : text.getText(text.getTextMode()), // new *************************** end (by ss & bp) DefaultViewFactory.textFont, // static field new FontRenderContext(null, false, false)); } if (eventType == DrawingEvent.EventType.TEXT_CHANGE) { // new *************************** begin (by ss & bp) textLayout = new TextLayout( text.getText(text.getTextMode()).length() == 0 ? " " : text.getText(text.getTextMode()), // new *************************** end (by ss & bp) DefaultViewFactory.textFont, new FontRenderContext(null, false, false)); // first try to create a bitmap image = null; // aka "reset" image => we might temporarily resort to TextLayout until the image is // ready areDimensionsComputed = false; // reset dimensions to the textlayout dimensions text.setDimensions( textLayout.getBounds().getWidth(), textLayout.getAscent(), textLayout.getDescent()); // new *************************** begin (by ss & bp) if (wantToComputeLatexDimensions && text.getText(text.getTextMode()).length() > 0) { // new *************************** end (by ss & bp) // don't produce a bitmap for an empty string (LaTeX might not like it) // [pending] this should be made dependent on a preference's option new Thread(this).start(); } if (image == null) super.changedUpdate(null); // ie resort to TextLayout (update all) } else { text.updateFrame(); super.changedUpdate(eventType); } }
/** Synchronizes bounding box with the model ; */ protected void syncBounds() { PicText te = (PicText) element; // [pending] Il faut tenir compte de la rotation ! Rectangle2D latexBB = null; // BB relative to latex dimensions (including rotation) (without frame) Rectangle2D textLayoutBB = null; // BB relative to textLayout dimensions (including rotation) (without frame) Rectangle2D textBB = null; // BB of the text (including rotation), without frame if (areDimensionsComputed) { // compute latexBB Rectangle2D nonRotated = new Rectangle2D.Double( te.getLeftX(), te.getBottomY(), te.getWidth(), te.getHeight() + te.getDepth()); AffineTransform tr = new AffineTransform(); // maps Image coordinates to Model coordinates (see paint) tr.setToIdentity(); // reset PicPoint anchor = te.getCtrlPt(TextEditable.P_ANCHOR, ptBuf); tr.rotate(getRotation(), anchor.x, anchor.y); // rotate along P_ANCHOR ! latexBB = tr.createTransformedShape(nonRotated).getBounds2D(); } if (image == null) { // compute textLayoutBB Rectangle2D nonRotated = textLayout.getBounds(); textLayoutBB = text2ModelTr.createTransformedShape(nonRotated).getBounds2D(); } // use textLayoutBB or latexBB or their union if (image != null) textBB = latexBB; else { if (!areDimensionsComputed) textBB = textLayoutBB; else { textBB = latexBB.createUnion(textLayoutBB); } } // union with frame BB if (te.isFramed()) { super.syncBounds(); // update bounds of the frame if necessary Rectangle2D.union(super.bounds, textBB, this.bounds); } else this.bounds = textBB; }