/* * 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 java.util.*; import javax.swing.*; import javax.swing.event.*; import org.sikuli.script.Finder; import org.sikuli.script.Match; import org.sikuli.script.Pattern; import org.sikuli.script.Region; import org.sikuli.script.ScreenImage; import org.sikuli.script.ScreenUnion; import org.sikuli.ide.util.LoadingSpinner; import org.sikuli.script.natives.Vision; import org.sikuli.script.Debug; class PatternPaneScreenshot extends JPanel implements ChangeListener, ComponentListener { final static int DEFAULT_H = 500; static int MAX_NUM_MATCHING = 100; Region _match_region; int _width, _height; double _scale, _ratio; boolean _runFind = false; float _similarity; int _numMatches; Set<Match> _fullMatches = null; final Boolean _fullMatchesSynch = true; ArrayList<Match> _showMatches = null; final Boolean _showMatchesSynch = true; protected ScreenImage _simg; protected BufferedImage _screen = null; protected Rectangle _uBound; private JLabel btnSimilar, _lblMatchCount; private JSlider sldSimilar; private JSpinner txtNumMatches; private LoadingSpinner _loading; static String _I(String key, Object... args) { return SikuliIDEI18N._I(key, args); } public PatternPaneScreenshot(ScreenImage simg) { init(simg); } private void init(ScreenImage simg) { _match_region = new ScreenUnion(); int w = _match_region.w, h = _match_region.h; _ratio = (double) w / h; _height = DEFAULT_H; _scale = (double) _height / h; _width = (int) (w * _scale); setPreferredSize(new Dimension(_width, _height)); addComponentListener(this); _simg = simg; _screen = simg.getImage(); MAX_NUM_MATCHING = (int) Vision.getParameter("FindAllMaxReturn"); autoResize(); _loading = new LoadingSpinner(); } public JComponent createControls() { JPanel pane = new JPanel(new GridBagLayout()); btnSimilar = new JLabel(_I("lblSimilarity")); sldSimilar = createSlider(); JLabel lblPreNumMatches = new JLabel(_I("lblNumberOfMatches")); _lblMatchCount = new JLabel("0"); Dimension size = _lblMatchCount.getPreferredSize(); size.width *= 2; _lblMatchCount.setPreferredSize(size); SpinnerNumberModel model = new SpinnerNumberModel(10, 0, PatternPaneScreenshot.MAX_NUM_MATCHING, 1); txtNumMatches = new JSpinner(model); lblPreNumMatches.setLabelFor(txtNumMatches); GridBagConstraints c = new GridBagConstraints(); c.fill = 1; c.gridy = 0; pane.add(btnSimilar, c); c.gridwidth = 3; pane.add(sldSimilar, c); c.fill = 0; c.gridy = 1; c.gridwidth = 1; pane.add(lblPreNumMatches, c); c.insets = new Insets(0, 10, 0, 0); pane.add(_lblMatchCount, c); c.insets = new Insets(0, 0, 0, 0); pane.add(new JLabel("/"), c); c.insets = new Insets(0, 0, 0, 100); pane.add(txtNumMatches, c); txtNumMatches.addChangeListener(this); return pane; } private JSlider createSlider() { sldSimilar = new PatternSimilaritySlider(0, 100, 70, btnSimilar); sldSimilar.setMajorTickSpacing(10); sldSimilar.setPaintTicks(true); Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>(); labelTable.put(new Integer(0), new JLabel("0.0")); labelTable.put(new Integer(50), new JLabel("0.5")); labelTable.put(new Integer(100), new JLabel("0.99")); sldSimilar.setLabelTable(labelTable); sldSimilar.setPaintLabels(true); sldSimilar.addChangeListener(this); return sldSimilar; } public void setParameters(final String patFilename, final boolean exact, final float similarity, final int numMatches) throws IOException, AWTException { if (!_runFind) { _runFind = true; Thread thread = new Thread(new Runnable() { @Override public void run() { try { Finder f = new Finder(_simg, _match_region); f.findAll(new Pattern(patFilename).similar(0.00001f)); _fullMatches = new TreeSet<Match>(new Comparator() { @Override public int compare(Object o1, Object o2) { return -1 * ((Comparable) o1).compareTo(o2); } @Override public boolean equals(Object o) { return false; } @Override public int hashCode() { int hash = 3; return hash; } }); int count = 0; while (f.hasNext()) { if (++count > MAX_NUM_MATCHING) { break; } Match m = f.next(); synchronized (_fullMatchesSynch) { _fullMatches.add(m); } setParameters(exact, similarity, numMatches); } } catch (Exception e) { e.printStackTrace(); } } }); thread.start(); } else { setParameters(exact, similarity, numMatches); } } public void setParameters(boolean exact, float similarity, int numMatches) { if (!exact) { _similarity = similarity; } else { _similarity = 0.99f; } _numMatches = numMatches; filterMatches(_similarity, _numMatches); sldSimilar.setValue((int) (similarity * 100)); repaint(); } @Override public void componentHidden(ComponentEvent e) { } @Override public void componentMoved(ComponentEvent e) { } @Override public void componentShown(ComponentEvent e) { } @Override public void componentResized(ComponentEvent e) { autoResize(); } private void autoResize() { _width = getWidth(); if (_width == 0) { _width = (int) getPreferredSize().getWidth(); } _height = (int) ((double) _width / _ratio); _scale = (double) _height / _match_region.h; setPreferredSize(new Dimension(_width, _height)); repaint(); } public boolean isExact() { return _similarity >= 0.99f; } public float getSimilarity() { return _similarity; } public int getNumMatches() { return _numMatches; } public void setSimilarity(float similarity) { _similarity = similarity > 0.99f ? 0.99f : similarity; filterMatches(_similarity, _numMatches); repaint(); } public void setNumMatches(int numMatches) { _numMatches = numMatches; filterMatches(_similarity, _numMatches); repaint(); } void filterMatches(float similarity, int numMatches) { int count = 0; if (_fullMatches != null && numMatches >= 0) { Debug.log(7, "filterMatches(%.2f,%d): %d", similarity, numMatches, count); if (_showMatches == null) { _showMatches = new ArrayList<Match>(); } synchronized (_showMatchesSynch) { _showMatches.clear(); if (numMatches == 0) { return; } synchronized (_fullMatchesSynch) { for (Match m : _fullMatches) { if (m.getScore() >= similarity) { _showMatches.add(m); if (++count >= numMatches) { break; } } } } } _lblMatchCount.setText(Integer.toString(count)); } } @Override public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; if (_screen != null) { g2d.drawImage(_screen, 0, 0, _width, _height, null); if (_showMatches != null) { paintMatches(g2d); } else { paintOverlay(g2d); } } } void paintOverlay(Graphics2D g2d) { g2d.setColor(new Color(0, 0, 0, 150)); g2d.fillRect(0, 0, _width, _height); BufferedImage spinner = _loading.getFrame(); g2d.drawImage(spinner, null, _width / 2 - spinner.getWidth() / 2, _height / 2 - spinner.getHeight() / 2); repaint(); } void paintMatches(Graphics2D g2d) { synchronized (_showMatchesSynch) { for (Match m : _showMatches) { int x = (int) ((m.x - _match_region.x) * _scale); int y = (int) ((m.y - _match_region.y) * _scale); int w = (int) (m.w * _scale); int h = (int) (m.h * _scale); Color c = PatternSimilaritySlider.getScoreColor(m.getScore()); g2d.setColor(c); g2d.fillRect(x, y, w, h); g2d.drawRect(x, y, w - 1, h - 1); } } } @Override public void stateChanged(javax.swing.event.ChangeEvent e) { Object src = e.getSource(); if (src instanceof JSlider) { JSlider source = (JSlider) e.getSource(); int val = (int) source.getValue(); setSimilarity((float) val / 100); } else if (src instanceof JSpinner) { JSpinner source = (JSpinner) e.getSource(); int val = (Integer) source.getValue(); setNumMatches(val); } } }