package org.geogebra.desktop.gui.inputfield;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.ImageIcon;
import javax.swing.border.AbstractBorder;
/**
* Extended Border class that adds simulated buttons to the right border of a
* JTextField. See MyTextField and AutoCompleteTextField for usage.
*
* @author G. Sturr
*
*/
public class BorderButtonD extends AbstractBorder
implements MouseListener, MouseMotionListener {
private static final long serialVersionUID = 1L;
private Component borderOwner;
public static final String cmdSuffix = "BorderButtonAction";
private ImageIcon[] icon;
private static final int hGap = 7;
private boolean[] isVisibleIcon;
private boolean[] isMouseOverIcon;
private Rectangle[] iconRect;
private ActionListener[] al;
private Cursor otherCursor = Cursor.getDefaultCursor();
private boolean isMouseOverIconRegion = false;
private int maxIconCount = 4;
/**************************************
* Constructs a BorderButton
*
* @param borderOwner
*/
public BorderButtonD(Component borderOwner) {
this.borderOwner = borderOwner;
// register our mouseListener, making sure it is the first one added
MouseListener[] ml = borderOwner.getMouseListeners();
for (int i = 0; i < ml.length; i++) {
borderOwner.removeMouseListener(ml[i]);
}
borderOwner.addMouseListener(this);
for (int i = 0; i < ml.length; i++) {
borderOwner.addMouseListener(ml[i]);
}
// register mouseMotionListener
borderOwner.addMouseMotionListener(this);
icon = new ImageIcon[maxIconCount];
isVisibleIcon = new boolean[maxIconCount];
isMouseOverIcon = new boolean[maxIconCount];
iconRect = new Rectangle[maxIconCount];
al = new ActionListener[maxIconCount];
for (int i = 0; i < maxIconCount; i++) {
icon[i] = new ImageIcon();
iconRect[i] = new Rectangle();
isMouseOverIcon[i] = false;
// need default visibility = false so that focus lost/gained
// visibility works
isVisibleIcon[i] = false;
}
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int w,
int h) {
int offset = hGap;
int xStart = x + w - getTotalInsetWidth();
int yMid = y + h / 2;
for (int i = 0; i < icon.length; i++) {
if (icon[i] != null && isVisibleIcon[i]) {
g.drawImage(icon[i].getImage(), xStart + offset,
yMid - icon[i].getIconHeight() / 2, null);
iconRect[i].x = xStart + offset;
iconRect[i].y = yMid - icon[i].getIconHeight() / 2;
iconRect[i].width = icon[i].getIconWidth();
iconRect[i].height = icon[i].getIconHeight();
offset += icon[i].getIconWidth() + hGap;
}
}
}
public void setBorderButton(int index, ImageIcon icon,
ActionListener listener) {
if (index < 0 || index > maxIconCount) {
return;
}
this.icon[index] = icon;
al[index] = listener;
}
public void setIconVisible(int index, boolean isVisible) {
if (index < 0 || index > maxIconCount) {
return;
}
isVisibleIcon[index] = isVisible;
this.borderOwner.validate();
}
public boolean isIconVisible(int index) {
return isVisibleIcon[index];
}
private int getTotalInsetWidth() {
int insetWidth = 0;
for (int i = 0; i < icon.length; i++) {
if (isVisibleIcon[i]) {
insetWidth += icon[i].getIconWidth() + hGap;
}
}
return insetWidth;
}
@Override
public Insets getBorderInsets(Component c) {
return new Insets(0, 0, 0, getTotalInsetWidth());
}
@Override
public boolean isBorderOpaque() {
return false;
}
private void swapCursor() {
Cursor tmp = borderOwner.getCursor();
borderOwner.setCursor(otherCursor);
otherCursor = tmp;
}
// =============================================
// Mouse Listeners
// =============================================
@Override
public void mouseDragged(MouseEvent e) {
// only care about mouse move and press
}
@Override
public void mouseMoved(MouseEvent e) {
boolean isOver = e.getPoint().x > iconRect[0].x;
if (isMouseOverIconRegion != isOver) {
isMouseOverIconRegion = isOver;
swapCursor();
}
for (int i = 0; i < iconRect.length; i++) {
isOver = iconRect[i].contains(e.getPoint());
if (isMouseOverIcon[i] != isOver) {
isMouseOverIcon[i] = isOver;
borderOwner.repaint();
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
// only care about mouse move and press
}
@Override
public void mouseEntered(MouseEvent e) {
// only care about mouse move and press
}
@Override
public void mouseExited(MouseEvent e) {
// only care about mouse move and press
}
@Override
public void mousePressed(MouseEvent e) {
for (int i = 0; i < iconRect.length; i++) {
if (isMouseOverIcon[i]) {
e.consume();
ActionEvent ae = new ActionEvent(this,
ActionEvent.ACTION_PERFORMED, i + cmdSuffix);
al[i].actionPerformed(ae);
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
for (int i = 0; i < iconRect.length; i++) {
if (isMouseOverIcon[i]) {
e.consume();
}
}
}
/**************************************************************
* TODO Main --- for testing, remove later
**************************************************************/
/*
* private static void createAndShowGUI() { //Create and set up the window.
* JFrame frame = new JFrame("Test");
* frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
* frame.setPreferredSize(new Dimension(150, 150));
*
*
* JTextField tf = new JTextField("Some text here"); tf.setColumns(3);
*
*
*
* ActionListener al = new ActionListener(){
*
* public void actionPerformed(ActionEvent e) { String cmd =
* e.getActionCommand(); if(cmd.endsWith(cmdSuffix)){ int i =
* Integer.parseInt(cmd.substring(0, 1)); } } };
*
* BorderButton btnBorder = new BorderButton(tf);
* btnBorder.setBorderButton(0, GeoGebraIcon.createTreeIcon(), al);
* btnBorder.setBorderButton(1, GeoGebraIcon.createTreeIcon(), al);
*
* Border tfBorder = tf.getBorder();
* tf.setBorder(BorderFactory.createCompoundBorder(tfBorder, btnBorder));
*
* //tf.setBorder(BorderFactory.createEtchedBorder());
*
*
* JPanel p = new JPanel(new BorderLayout()); p.add(tf, BorderLayout.NORTH);
*
* frame.getContentPane().add(p, BorderLayout.CENTER); frame.pack();
* frame.setVisible(true); }
*
* public static void main(String[] args) {
* javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run()
* { createAndShowGUI(); } }); }
*/
}