package org.korsakow.ide.ui.laf; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Paint; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import javax.swing.Icon; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JScrollBar; import javax.swing.ListCellRenderer; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.plaf.basic.ComboPopup; import org.korsakow.ide.util.UIResourceManager; import com.sun.java.swing.plaf.motif.MotifComboBoxUI; public class KorsakowComboBoxUI extends MotifComboBoxUI { private static Icon arrowIcon; public static ComponentUI createUI(JComponent c) { return new KorsakowComboBoxUI(); } @Override protected ComboPopup createPopup() { return new MyBasicComboPopup(comboBox); } @Override public void installUI(JComponent c) { super.installUI(c); if (arrowIcon == null) { arrowIcon = UIResourceManager.getIcon("laf/combobox_arrow.png"); } c.setOpaque(false); c.setBackground(UIManager.getColor("ComboBox.background")); c.putClientProperty("ui.background2", UIManager.getColor("ComboBox.background2")); } @Override public Insets getInsets() { int arcWidth = UIManager.getInt("ComboBox.roundedCornerSize"); //KorsakowLookAndFeel.ROUNDED_CORNER_SIZE; Insets insets = super.getInsets(); insets.left += arcWidth/2; insets.top += 1; return insets; } @Override public Dimension getMinimumSize(JComponent c) { float strokeSize = UIManager.getInt("ComboBox.borderSize"); Dimension d = super.getMinimumSize(c); d.height = 16; d.height += strokeSize*2; return d; } @Override public void paint(Graphics g, JComponent c) { JComboBox comp = (JComboBox)c; Color background2 = (Color)c.getClientProperty("ui.background2"); int arcWidth = UIManager.getInt("ComboBox.roundedCornerSize"); //KorsakowLookAndFeel.ROUNDED_CORNER_SIZE; int arcHeight = UIManager.getInt("ComboBox.roundedCornerSize"); //KorsakowLookAndFeel.ROUNDED_CORNER_SIZE; float strokeSize = UIManager.getInt("ComboBox.borderSize"); //KorsakowLookAndFeel.BORDER_STROKE_SIZE; int width = c.getWidth(); width -= 1; // rounded rect gets clipped slightly int height = c.getHeight(); Rectangle bounds = c.getBounds(); Graphics2D g2 = (Graphics2D)g; RoundRectangle2D.Float borderRect = new RoundRectangle2D.Float(strokeSize, strokeSize/2, width-strokeSize, height-strokeSize, arcWidth, arcHeight); final int separatorX = width-15; final int arrowLeft = width-15 + (15 - arrowIcon.getIconWidth())/2; final int buttonWidth = width-separatorX; RoundRectangle2D.Float buttonRect1 = new RoundRectangle2D.Float(arrowLeft, strokeSize/2, buttonWidth, height-strokeSize, arcWidth, arcHeight); Rectangle2D.Float buttonRect2 = new Rectangle2D.Float(separatorX+strokeSize, strokeSize/2, buttonWidth-arcWidth, height-strokeSize); // draw background // if (!comp.isEditable()) { Paint paint = null; // paint = KorsakowLafUtil.createDefaultBackgroundGradient(height); //// paint = UIManager.getColor("ComboBox.background"); // g2.setPaint(paint); // g2.fill(borderRect); // } else { // Paint paint = null; //// paint = KorsakowLafUtil.createDefaultBackgroundGradient(height); // paint = UIManager.getColor("TextField.background"); // g2.setPaint(paint); // g2.fill(borderRect); //// paintCurrentValue(g2, bounds, hasFocus); // } // background paint = null; if (background2 == null) paint = c.getBackground(); else paint = new GradientPaint(0, 0, c.getBackground(), 0, height, background2, false); g2.setPaint(paint); g2.fill(borderRect); // button background g2.setPaint(new GradientPaint(0, 0, UIManager.getColor("ComboBox.background"), 0, height, UIManager.getColor("ComboBox.background2"), false)); //UIManager.getColor("ComboBox.background")); g2.fill(buttonRect1); g2.fill(buttonRect2); g2.setPaint(paint); // draw separator g2.setStroke(new BasicStroke(strokeSize)); g2.setColor(UIManager.getColor("ComboBox.borderColor")); g2.fillRect(separatorX, 1, 2, height-1); // draw arrow arrowIcon.paintIcon(c, g, arrowLeft, (15 - arrowIcon.getIconHeight())/2); // draw border g2.setStroke(new BasicStroke(strokeSize)); g2.setColor(UIManager.getColor("ComboBox.borderColor")); borderRect.height-=1; g2.draw(borderRect); if ( !comboBox.isEditable() ) { Rectangle r = rectangleForCurrentValue(); paintCurrentValue(g,r,hasFocus); } comp.getEditor().getEditorComponent().setBackground(c.getBackground()); comp.getEditor().getEditorComponent().setForeground(c.getForeground()); ((JComponent)comp.getEditor().getEditorComponent()).putClientProperty("ui.background2", background2); comp.getEditor().getEditorComponent().repaint(); } @Override public void paintCurrentValue(Graphics g,Rectangle bounds,boolean hasFocus) { ListCellRenderer renderer = comboBox.getRenderer(); JComponent c; Dimension d; c = (JComponent)renderer.getListCellRendererComponent(listBox, comboBox.getSelectedItem(), -1, false, false); c.setFont(comboBox.getFont()); if ( comboBox.isEnabled() ) { c.setForeground(comboBox.getForeground()); c.setBackground(comboBox.getBackground()); c.setOpaque(false); } else { c.setOpaque(false); c.setForeground(UIManager.getColor("ComboBox.disabledForeground")); c.setBackground(UIManager.getColor("ComboBox.disabledBackground")); } d = c.getPreferredSize(); currentValuePane.paintComponent(g,c,comboBox,bounds.x,(bounds.y), bounds.width,(d.height)); } private static class MyBasicComboPopup extends BasicComboPopup { private static int scrollbarWidth = new JScrollBar().getPreferredSize().width;; public MyBasicComboPopup(JComboBox combo) { super(combo); } @Override protected void configureList() { super.configureList(); setForeground(Color.black); } @Override protected Rectangle computePopupBounds(int px,int py,int pw,int ph) { // we assume a reasonable metric is at least as big as the combobox itself // and no bigger than twice its size int w = Math.min(pw*2, getList().getPreferredSize().width); // TODO: actually determine whether the list will scroll and only add the extra width if necessary w += scrollbarWidth; pw = Math.max(w, pw); return super.computePopupBounds(px, py, pw, ph); } } }