package com.drawbridge.text;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
public class DBCaret
{
private final DBDocument mTextComponent;
private boolean mVisible;
private Rectangle mBounds;
// Dot is the last drop position
private Point mDotPixelPosition;
public Point mDotCharPosition;
// Mark is the initial click position
public Point mMarkPixelPosition;
public Point mMarkCharPosition;
private Blinker mBlinker;
private Thread mBlinkerThread;
private int mBlinkDelay = 500; // default is 600
private final int mCaretThickness = 2;
public DBCaret(DBDocument textComponent, Rectangle bounds) {
mTextComponent = textComponent;
mBounds = bounds;
mVisible = false;
}
public void setDotPositionFromClick(int panelX, int panelY)
{
panelX = panelX - mTextComponent.getInsets().left;
// get nearest valid line
int closestYLine = mTextComponent.getLinePosition(panelY);
Point closestCharPos = mTextComponent.getDocumentModel().getCharPosFromMouseClick(panelX, closestYLine);
Point closestPixelPos = mTextComponent.charPosToPixelPos(closestCharPos.x, closestCharPos.y);
setDotPosition(closestPixelPos, closestCharPos);
restartDotAnimation();
}
public void setMarkPositionFromClick(int panelX, int panelY)
{
panelX = panelX - mTextComponent.getInsets().left;
// get nearest valid line
int closestYLine = mTextComponent.getLinePosition(panelY);
Point closestCharPos = mTextComponent.getDocumentModel().getCharPosFromMouseClick(panelX, closestYLine);
Point closestPixelPos = mTextComponent.charPosToPixelPos(closestCharPos.x, closestCharPos.y);
setMarkPosition(closestPixelPos, closestCharPos);
restartDotAnimation();
}
public Blinker getBlinker()
{
return mBlinker;
}
public void Paint(Graphics g)
{
if (mBlinker == null || mBlinkerThread == null) {
mVisible = false;
mBlinker = new Blinker();
mBlinkerThread = new Thread(mBlinker);
restartDotAnimation();
DBCaret.this.setDotPosition(new Point(0, 0), new Point(0, 0));
}
// Draw Caret
if (mVisible && mBounds != null && mDotPixelPosition != null)
{
int xPos = mBounds.x + mDotPixelPosition.x;
int yPosTop = mBounds.y + mDotPixelPosition.y;
int yPosBottom = yPosTop + mTextComponent.getLineHeight() + mTextComponent.getLineSpacing();
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.black);
g2.setStroke(new BasicStroke(mCaretThickness));
g2.drawLine(xPos, yPosTop, xPos, yPosBottom);
}
}
/**
* Controls the caret animation
*/
class Blinker implements Runnable
{
boolean cancelled = false;
@Override
public void run()
{
DBCaret.this.mVisible = false;
do
{
try
{
DBCaret.this.mVisible = !DBCaret.this.mVisible;
mTextComponent.repaint();
Thread.sleep(DBCaret.this.mBlinkDelay);
} catch (InterruptedException e)
{
e.printStackTrace();
}
} while (!cancelled && mTextComponent.hasFocus());
}
}
public void restartDotAnimation()
{
if (mBlinkerThread != null && mBlinker != null && mBlinkerThread.isAlive())
{
mBlinker.cancelled = true;
}
mVisible = true;
mBlinker = new Blinker();
mBlinkerThread = new Thread(mBlinker);
mBlinkerThread.start();
}
public void setBlinkRate(int blinkRateMilliseconds)
{
mBlinkDelay = blinkRateMilliseconds;
}
public void setVisible(boolean b)
{
mVisible = b;
}
public Point getDotPixelPosition()
{
return mDotPixelPosition;
}
public Point getDotCharPosition()
{
return mDotCharPosition;
}
public void setDotPosition(Point newPixelPosition, Point newCharPosition)
{
this.mDotPixelPosition = newPixelPosition;
this.mDotCharPosition = newCharPosition;
}
public void setMarkPosition(Point newPixelPosition, Point newCharPosition)
{
this.mMarkPixelPosition = newPixelPosition;
this.mMarkCharPosition = newCharPosition;
}
@Override
public String toString()
{
return "DBCaret Position: (" + mDotPixelPosition.x + ", " + mDotPixelPosition.y + ")";
}
public void setDotCharPosition(Point charPos)
{
mDotCharPosition = charPos;
mDotPixelPosition = mTextComponent.charPosToPixelPos(charPos.x, charPos.y);
this.restartDotAnimation();
}
public void setMarkCharPosition(Point charPos)
{
mMarkCharPosition = charPos;
mMarkPixelPosition = mTextComponent.charPosToPixelPos(charPos.x, charPos.y);
this.restartDotAnimation();
}
public Point getMarkCharPosition()
{
return mMarkCharPosition;
}
public Point getMarkPixelPosition()
{
return mMarkPixelPosition;
}
public String toStringMarkChar()
{
return "(" + this.mMarkCharPosition.x + ", " + this.mMarkCharPosition.y + ")";
}
public String toStringDotChar()
{
return "(" + this.mDotCharPosition.x + ", " + this.mDotCharPosition.y + ")";
}
}