processing.app.syntax.im.CompositionTextPainter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pde Show documentation
Show all versions of pde Show documentation
Processing is a programming language, development environment, and online community.
This PDE package contains the Processing IDE.
package processing.app.syntax.im;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.font.TextHitInfo;
import java.awt.font.TextLayout;
import processing.app.Base;
import processing.app.Messages;
import processing.app.syntax.JEditTextArea;
/**
* Paint texts from input method. Text via input method are transmitted by
* AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter
* to handle AttributedCaharacterIterator.
*
* For practical purposes, paint to textarea is done by TextLayout class.
* Because TextLayout class is easy to draw composing texts. (For example,
* draw underline composing texts, focus when select from candidates text.)
*
* @author Takashi Maekawa ([email protected])
*/
public class CompositionTextPainter {
private TextLayout composedTextLayout;
private int composedBeginCaretPosition = 0;
private JEditTextArea textArea;
private boolean caretColorFlag;
private TextHitInfo caret;
/**
* Constructor for painter.
* @param textArea textarea used by PDE.
*/
public CompositionTextPainter(JEditTextArea textArea) {
this.textArea = textArea;
composedTextLayout = null;
}
/**
* Check the painter has TextLayout.
* If a user input via InputMethod, this result will return true.
*/
public boolean hasComposedTextLayout() {
return (composedTextLayout != null);
}
/**
* Set TextLayout to the painter.
* TextLayout will be created and set by CompositionTextManager.
*
* @see CompositionTextManager
*/
public void setComposedTextLayout(TextLayout composedTextLayout, int composedStartCaretPosition) {
this.composedTextLayout = composedTextLayout;
this.composedBeginCaretPosition = composedStartCaretPosition;
}
/**
* Invalidate this TextLayout to set null.
* If a user end input via InputMethod, this method will called from CompositionTextManager.endCompositionText
*/
public void invalidateComposedTextLayout(int composedEndCaretPosition) {
this.composedTextLayout = null;
this.composedBeginCaretPosition = composedEndCaretPosition;
//this.composedBeginCaretPosition = textArea.getCaretPosition();
}
/**
* Draw text via input method with composed text information.
* This method can draw texts with some underlines to illustrate converting characters.
*
* This method is workaround for TextAreaPainter.
* Because, TextAreaPainter can't treat AttributedCharacterIterator directly.
* AttributedCharacterIterator has very important information when composing text.
* It has a map where are converted characters and committed characters.
* Ideally, changing TextAreaPainter method can treat AttributedCharacterIterator is better. But it's very tough!!
* So I choose to write some code as a workaround.
*
* This draw method is proceeded with the following steps.
* 1. Original TextAreaPainter draws characters.
* 2. CompositionTextPainter.draw method paints composed text. It was actually drawn by TextLayout.
*
* @param gfx set TextAreaPainter's Graphics object.
* @param fillBackGroundColor set textarea's background.
*/
// public void draw(Graphics gfx, Color fillBackGroundColor) {
// assert(composedTextLayout != null);
// Point composedLoc = getCaretLocation();
// //refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y);
// composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y);
// }
public void draw(Graphics gfx, Color fillBackGroundColor) {
//assert(composedTextLayout != null);
if (composedTextLayout != null) {
Point composedLoc = getCaretLocation();
//refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y);
composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y);
// draw caret.
if (this.caret != null) {
int caretLocation = Math.round(composedTextLayout.getCaretInfo(caret)[0]);
Rectangle rect = new Rectangle(composedLoc.x + caretLocation,
composedLoc.y - (int)composedTextLayout.getAscent(),
1,
(int)composedTextLayout.getAscent() + (int)composedTextLayout.getDescent());
// blink caret.
if (Base.DEBUG) {
Messages.log(rect.toString());
}
Color c = gfx.getColor(); // save
if (caretColorFlag) {
caretColorFlag = false;
gfx.setColor(Color.WHITE);
} else {
caretColorFlag = true;
gfx.setColor(Color.BLACK);
}
gfx.fillRect(rect.x, rect.y, rect.width, rect.height);
gfx.setColor(c); // restore
}
}
}
// /**
// * Fill color to erase characters drawn by original TextAreaPainter.
// *
// * @param fillColor fill color to erase characters drawn by original TextAreaPainter method.
// * @param x x-coordinate where to fill.
// * @param y y-coordinate where to fill.
// */
// private void refillComposedArea(Color fillColor, int x, int y) {
// Graphics gfx = textArea.getPainter().getGraphics();
// gfx.setColor(fillColor);
// FontMetrics fm = textArea.getPainter().getFontMetrics();
// int newY = y - (fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT);
// int paintHeight = fm.getHeight();
// int paintWidth = (int) composedTextLayout.getBounds().getWidth();
// gfx.fillRect(x, newY, paintWidth, paintHeight);
// }
private Point getCaretLocation() {
int line = textArea.getCaretLine();
int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(line);
// '+1' mean textArea.lineToY(line) + textArea.getPainter().getFontMetrics().getHeight().
// TextLayout#draw method need at least one height of font.
return new Point(textArea.offsetToX(line, offsetX), textArea.lineToY(line + 1));
}
public void setCaret(TextHitInfo caret) {
this.caret = caret;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy