/*
* Copyright 2010-2013, Sikuli.org
* Released under the MIT License.
*
* modified RaiMan 2013
*/
package org.sikuli.ide;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
import org.sikuli.script.Location;
import org.sikuli.script.Debug;
import org.sikuli.script.FileManager;
class EditorPatternButton extends JButton implements ActionListener, Serializable, MouseListener {
static final int DEFAULT_NUM_MATCHES = 10;
static final float DEFAULT_SIMILARITY = 0.7f;
private String _imgFilename, _thumbFname, _imgFilenameSaved;
private JLabel patternImageIcon = null;
private EditorPane _pane;
private float _similarity, _similaritySaved;
private int _numMatches = DEFAULT_NUM_MATCHES;
private boolean _exact, _exactSaved;
private Location _offset = new Location(0, 0), _offsetSaved;
private int _imgW, _imgH;
private float _scale = 1f;
private static PatternWindow pwin = null;
private static Font textFont = new Font("arial", Font.BOLD, 12);
private Color oldC;
private String buttonFname = "";
private String buttonSimilar = "";
private String buttonOffset = "";
private EditorPatternLabel _lbl;
protected EditorPatternButton(EditorPane pane) {
init(pane, null);
}
public EditorPatternButton(EditorPane pane, String imgFilename) {
init(pane, imgFilename);
}
protected EditorPatternButton(EditorPatternLabel lbl) {
super();
_lbl = lbl;
_imgFilename = _lbl.getFile();
_exact = false;
_similarity = _lbl.getSimilarity();
_offset = _lbl.getTargetOffset();
_numMatches = DEFAULT_NUM_MATCHES;
_pane = _lbl.getPane();
}
private void init(EditorPane pane, String imgFilename) {
//TODO thumbMax = PreferencesUser.getInstance().getDefaultThumbHeight() == 0 ? false : true;
_pane = pane;
_exact = false;
_similarity = DEFAULT_SIMILARITY;
_numMatches = DEFAULT_NUM_MATCHES;
if (imgFilename != null) {
setFilename(imgFilename);
}
setMargin(new Insets(0, 0, 0, 0));
setBorderPainted(true);
setCursor(new Cursor(Cursor.HAND_CURSOR));
addActionListener(this);
setButtonText();
}
public BufferedImage createThumbnailImage(int maxHeight) {
return createThumbnailImage(_imgFilename, maxHeight);
}
public static EditorPatternButton createFromString(EditorPane parentPane, String str, EditorPatternLabel lbl) {
if (!str.startsWith("Pattern")) {
if (str.charAt(0) == '\"' && str.charAt(str.length() - 1) == '\"') {
String filename = str.substring(1, str.length() - 1);
File f = parentPane.getFileInBundle(filename);
if (f != null) {
return new EditorPatternButton(parentPane, f.getAbsolutePath());
}
}
return null;
}
EditorPatternButton btn = new EditorPatternButton(parentPane);
String[] tokens = str.split("\\)\\s*\\.?");
for (String tok : tokens) {
//System.out.println("token: " + tok);
if (tok.startsWith("exact")) {
btn.setExact(true);
btn.setSimilarity(0.99f);
} else if (tok.startsWith("Pattern")) {
String filename = tok.substring(
tok.indexOf("\"") + 1, tok.lastIndexOf("\""));
File f = parentPane.getFileInBundle(filename);
if (f != null && f.exists()) {
btn.setFilename(f.getAbsolutePath());
} else {
return null;
}
} else if (tok.startsWith("similar")) {
String strArg = tok.substring(tok.lastIndexOf("(") + 1);
try {
btn.setSimilarity(Float.valueOf(strArg));
} catch (NumberFormatException e) {
return null;
}
} else if (tok.startsWith("firstN")) { // FIXME: replace with limit/max
String strArg = tok.substring(tok.lastIndexOf("(") + 1);
btn._numMatches = Integer.valueOf(strArg);
} else if (tok.startsWith("targetOffset")) {
String strArg = tok.substring(tok.lastIndexOf("(") + 1);
String[] args = strArg.split(",");
try {
Location offset = new Location(0, 0);
offset.x = Integer.valueOf(args[0]);
offset.y = Integer.valueOf(args[1]);
btn.setTargetOffset(offset);
} catch (NumberFormatException e) {
return null;
}
}
}
btn.setButtonText();
return btn;
}
@Override
public void actionPerformed(ActionEvent e) {
Debug.log(2, "open Pattern Settings");
if (pwin == null) {
_offsetSaved = new Location(_offset);
_similaritySaved = _similarity;
_exactSaved = _similarity >= 0.99f;
_imgFilenameSaved = _imgFilename.substring(0);
pwin = new PatternWindow(this, _exactSaved, _similarity, _numMatches);
pwin.setTargetOffset(_offset);
} else {
pwin.requestFocus();
}
Rectangle sb = pwin.getGraphicsConfiguration().getDevice().getDefaultConfiguration().getBounds();
sb.height -= 100;
Rectangle wb = pwin.getBounds();
if (! sb.contains(wb)) {
if (wb.height > sb.height - 100) {
wb.setSize(wb.width, sb.height - 200);
}
if (!sb.contains(wb.getLocation())) {
wb.setLocation(sb.x+100, wb.y);
}
Point tr = wb.getLocation();
tr.translate(wb.width, 0);
if (!sb.contains(tr)) {
int off = tr.x - sb.x - sb.width;
wb.setLocation(wb.x-off, wb.y);
}
Point bl = wb.getLocation();
bl.translate(0, wb.height);
if (!sb.contains(bl)) {
int off = bl.y - sb.y - sb.height;
wb.setLocation(wb.x, wb.y-off);
}
pwin.setBounds(wb);
}
}
@Override
public Point getLocationOnScreen() {
if (_lbl == null) {
return super.getLocationOnScreen();
}
else {
return _lbl.getLocationOnScreen();
}
}
@Override
public void mouseEntered(MouseEvent me) {
}
@Override
public void mouseExited(MouseEvent me) {
}
public PatternWindow getWindow() {
return pwin;
}
public void resetWindow() {
pwin = null;
}
public String getFilename() {
File img = new File(_imgFilename);
String oldBundle = img.getParent();
String newBundle = _pane.getSrcBundle();
Debug.log(2, "ImageButton.getFilename: " + oldBundle + " " + newBundle);
if (oldBundle == newBundle) {
return _imgFilename;
}
setFilename(newBundle + File.separatorChar + img.getName());
return _imgFilename;
}
public void setFilename(String newFilename) {
_imgFilename = newFilename;
_thumbFname = createThumbnail(_imgFilename);
setIcon(new ImageIcon(_thumbFname));
setButtonText();
}
private String createThumbnail(String imgFname) {
return createThumbnail(imgFname, PreferencesUser.getInstance().getDefaultThumbHeight());
}
private String createThumbnail(String imgFname, int maxHeight) {
BufferedImage thumb = createThumbnailImage(imgFname, maxHeight);
return FileManager.saveTmpImage(thumb);
}
private BufferedImage createThumbnailImage(String imgFname, int maxHeight) {
try {
BufferedImage img = ImageIO.read(new File(imgFname));
int w = img.getWidth(null), h = img.getHeight(null);
_imgW = w;
_imgH = h;
if (maxHeight == 0 || maxHeight >= h) {
return img;
}
_scale = (float) maxHeight / h;
w *= _scale;
h *= _scale;
h = (int) h ;
BufferedImage thumb = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = thumb.createGraphics();
g2d.drawImage(img, 0, 0, w, h, null);
g2d.dispose();
return thumb;
} catch (IOException e) {
Debug.error("Can't read file: " + e.getMessage());
return null;
}
}
public boolean setParameters(boolean exact, float similarity, int numMatches) {
boolean dirty = false;
Debug.log(2, "setParameters: " + exact + "," + similarity + "," + numMatches);
dirty |= setExact(exact);
dirty |= setSimilarity(similarity);
setButtonText();
return dirty;
}
public void resetParameters() {
setFilename(_imgFilenameSaved);
setParameters(_exactSaved, _similaritySaved, DEFAULT_NUM_MATCHES);
setTargetOffset(_offsetSaved);
}
public boolean setExact(boolean exact) {
if (_exact != exact) {
_exact = exact;
return true;
}
return false;
}
public boolean setSimilarity(float val) {
float sim;
if (val < 0) {
sim = 0;
} else if (val >= 1) {
sim = 0.99f;
} else {
sim = val;
}
if (sim != _similarity) {
_similarity = sim;
return true;
}
return false;
}
public float getSimilarity() {
return _similarity;
}
public boolean setTargetOffset(Location offset) {
Debug.log(2, "setTargetOffset: " + offset);
if (!_offset.equals(offset)) {
_offset = offset;
setButtonText();
return true;
}
return false;
}
public Location getTargetOffset() {
return _offset;
}
public String getFileName() {
return _imgFilename;
}
//<editor-fold defaultstate="collapsed" desc="paint button">
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
drawText(g2d);
if( useThumbnail() ){
g2d.setColor( new Color(0, 128, 128, 128) );
g2d.drawRoundRect(3, 3, getWidth()-7, getHeight()-7, 5, 5);
}
}
private void drawText(Graphics2D g2d) {
String strSim = null, strOffset = null;
if (_similarity != DEFAULT_SIMILARITY) {
if (_exact) {
strSim = "99";
} else {
strSim = String.format("%d", (int) (_similarity * 100));
}
}
if (_offset != null && (_offset.x != 0 || _offset.y != 0)) {
strOffset = _offset.toString();
}
if (strOffset == null && strSim == null) {
return;
}
final int fontH = g2d.getFontMetrics().getMaxAscent();
final int x = getWidth(), y = 0;
drawText(g2d, strSim, x, y);
if (_offset != null) {
drawCross(g2d);
}
}
private void drawText(Graphics2D g2d, String str, int x, int y) {
if (str == null) {
return;
}
final int w = g2d.getFontMetrics().stringWidth(str);
final int fontH = g2d.getFontMetrics().getMaxAscent();
final int borderW = 3;
g2d.setFont(textFont);
g2d.setColor(new Color(0, 128, 0, 128));
g2d.fillRoundRect(x - borderW * 2 - w - 1, y, w + borderW * 2 + 1, fontH + borderW * 2 + 1, 3, 3);
g2d.setColor(Color.white);
g2d.drawString(str, x - w - 3, y + fontH + 3);
}
private void drawCross(Graphics2D g2d) {
int x, y;
final String cross = "+";
final int w = g2d.getFontMetrics().stringWidth(cross);
final int h = g2d.getFontMetrics().getMaxAscent();
if (_offset.x > _imgW / 2) {
x = getWidth() - w;
} else if (_offset.x < -_imgW / 2) {
x = 0;
} else {
x = (int) (getWidth() / 2 + _offset.x * _scale - w / 2);
}
if (_offset.y > _imgH / 2) {
y = getHeight() + h / 2 - 3;
} else if (_offset.y < -_imgH / 2) {
y = h / 2 + 2;
} else {
y = (int) (getHeight() / 2 + _offset.y * _scale + h / 2);
}
g2d.setFont(textFont);
g2d.setColor(new Color(0, 0, 0, 180));
g2d.drawString(cross, x + 1, y + 1);
g2d.setColor(new Color(255, 0, 0, 180));
g2d.drawString(cross, x, y);
}
private boolean useThumbnail() {
return !_imgFilename.equals(_thumbFname);
}
//</editor-fold>
@Override
public String toString() {
return _pane.getPatternString(_imgFilename, _similarity, _offset);
}
private void setButtonText() {
if (_lbl == null) {
setToolTipText(toString());
} else {
_lbl.resetLabel(_imgFilename, _similarity, _offset);
}
}
//<editor-fold defaultstate="collapsed" desc="mouse events not used">
@Override
public void mouseClicked(MouseEvent me) {}
@Override
public void mousePressed(MouseEvent me) {}
@Override
public void mouseReleased(MouseEvent me) {}
//</editor-fold>
}