/* * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.ide.ui.laf.intellij; import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; import com.intellij.ide.ui.laf.darcula.ui.TextFieldWithPopupHandlerUI; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.Gray; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.MacUIUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.plaf.ComponentUI; import javax.swing.text.JTextComponent; import java.awt.*; import java.awt.geom.Area; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; /** * @author Konstantin Bulenkov */ public class MacIntelliJTextFieldUI extends TextFieldWithPopupHandlerUI { public MacIntelliJTextFieldUI(JTextField textField) { super(textField); } @SuppressWarnings("MethodOverridesStaticMethodOfSuperclass") public static ComponentUI createUI(final JComponent c) { return new MacIntelliJTextFieldUI((JTextField)c); } public void showSearchPopup() { final Object value = myTextField.getClientProperty("JTextField.Search.FindPopup"); final JTextComponent editor = getComponent(); if (editor != null && value instanceof JPopupMenu) { final JPopupMenu popup = (JPopupMenu)value; popup.show(editor, getSearchIconCoord().x, editor.getHeight()); } } @Override public String getToolTipText(JTextComponent t, Point pt) { if (getActionUnder(pt) == SearchAction.NEWLINE) { AbstractAction action = getNewLineAction(t); if (action != null) return (String)action.getValue(Action.SHORT_DESCRIPTION); } return super.getToolTipText(t, pt); } public SearchAction getActionUnder(@NotNull Point p) { int off = JBUI.scale(8); Point point = new Point(p.x - off, p.y - off); if (point.distance(getSearchIconCoord()) <= off) { return SearchAction.POPUP; } if (hasText() && point.distance(getClearIconCoord()) <= off) { return SearchAction.CLEAR; } if (getNewLineAction(myTextField) != null && point.distance(getAddNewLineIconCoord()) <= off) { return SearchAction.NEWLINE; } return null; } protected Rectangle getDrawingRect() { return new Rectangle(0, (myTextField.getHeight() - 28) / 2, myTextField.getWidth(), myTextField.getHeight()); } private static Icon getSearchIcon(Component c) { return MacIntelliJIconCache.getIcon(isSearchFieldWithHistoryPopup(c) ? "searchFieldWithHistory" : "search"); } protected Point getSearchIconCoord() { final Rectangle r = getDrawingRect(); Icon icon = getSearchIcon(myTextField); return new Point(r.x + (hasText() || myTextField.hasFocus() || isSearchFieldWithHistoryPopup(myTextField) ? JBUI.scale(8) : (r.width - icon.getIconWidth()) / 2), r.y + (r.height - icon.getIconHeight()) / 2); } protected Point getClearIconCoord() { Rectangle r = getDrawingRect(); Icon icon = MacIntelliJIconCache.getIcon("searchFieldClear"); return new Point(r.x + r.width - icon.getIconWidth() - JBUI.scale(6), r.y + (r.height - icon.getIconHeight()) / 2); } protected Point getAddNewLineIconCoord() { Point point = getClearIconCoord(); if (!StringUtil.isEmpty(myTextField.getText())) point.x -= JBUI.scale(16) + JBUI.scale(8); return point; } @Override protected void paintBackground(Graphics graphics) { Graphics2D g = (Graphics2D)graphics; final JTextComponent c = getComponent(); final Container parent = c.getParent(); final Rectangle r = getDrawingRect(); if (c.isOpaque() && parent != null) { g.setColor(parent.getBackground()); g.fillRect(0, 0, c.getWidth(), c.getHeight()); } if (isSearchField(c)) { paintSearchField(g, c, r); } else { if (c.getBorder() instanceof MacIntelliJTextBorder) { g.setColor(c.getBackground()); g.fillRect(JBUI.scale(3), JBUI.scale(3), c.getWidth() - JBUI.scale(6), c.getHeight() - JBUI.scale(6)); } else { super.paintBackground(g); } } } @NotNull @Override public Dimension getPreferredSize(JComponent c) { Dimension size = super.getPreferredSize(c); return new Dimension(size.width + getIconsWidth(c), Math.max(28, size.height)); } @Override public Dimension getMinimumSize(JComponent c) { Dimension minimumSize = super.getMinimumSize(c); return new Dimension(minimumSize.width + getIconsWidth(c), minimumSize.height); } private int getIconsWidth(JComponent c) { int width = 0; if (isSearchField(c)) { Icon label = getSearchIcon(c); width += label.getIconWidth(); if (hasText()) { Icon clearIcon = MacIntelliJIconCache.getIcon("searchFieldClear"); width += clearIcon.getIconWidth() + 3; } } return width; } protected void paintSearchField(Graphics2D g, JTextComponent c, Rectangle r) { Graphics2D g2 = (Graphics2D)g.create(); try { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE); g2.translate(r.x, r.y); int arc = JBUI.scale(6); double lw = UIUtil.isRetina(g2) ? 0.5 : 1.0; Shape outerShape = new RoundRectangle2D.Double(JBUI.scale(3), JBUI.scale(3), r.width - JBUI.scale(6), r.height - JBUI.scale(6), arc, arc); g2.setColor(c.getBackground()); g2.fill(outerShape); Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD); path.append(outerShape, false); path.append(new RoundRectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw, r.width - JBUI.scale(6) - lw*2, r.height - JBUI.scale(6) - lw*2, arc-lw, arc-lw), false); g2.setColor(Gray.xBC); g2.fill(path); if (c.hasFocus() && c.getClientProperty("JTextField.Search.noBorderRing") != Boolean.TRUE) { DarculaUIUtil.paintFocusBorder(g2, r.width, r.height, arc, true); } g2.translate(-r.x, -r.y); boolean withHistoryPopup = isSearchFieldWithHistoryPopup(c); Icon label = getSearchIcon(c); boolean isEmpty = !hasText(); Point point = getSearchIconCoord(); if (isEmpty && !c.hasFocus() && !withHistoryPopup) { label.paintIcon(c, g2, point.x, point.y); } else { Graphics ig = g2.create(0, 0, c.getWidth(), c.getHeight()); Area area = new Area(new Rectangle2D.Double(point.x, point.y, isEmpty ? label.getIconWidth() : 16, label.getIconHeight())); area.intersect(new Area(ig.getClip())); ig.setClip(area); label.paintIcon(c, ig, point.x, point.y); ig.dispose(); } if (!isEmpty) { Point ic = getClearIconCoord(); MacIntelliJIconCache.getIcon("searchFieldClear").paintIcon(c, g2, ic.x, ic.y); } AbstractAction newLineAction = getNewLineAction(c); if (newLineAction != null) { Icon newLineIcon = (Icon)newLineAction.getValue(Action.SMALL_ICON); if (newLineIcon != null) { newLineIcon.paintIcon(c, g2, getAddNewLineIconCoord().x, r.y); } } } finally { g2.dispose(); } } @Override protected Rectangle getVisibleEditorRect() { Rectangle rect = super.getVisibleEditorRect(); if (rect != null) { if (isSearchField(myTextField)) { int extraOffset = isSearchFieldWithHistoryPopup(myTextField) ? 3 : 0; rect.width -= 36 + extraOffset; if (getNewLineAction(myTextField) != null) rect.width -= 24; rect.x += 19 + extraOffset; if (rect.height % 2 == 1) { rect.y += 1; } } else { rect.x += 2; rect.width -= 4; } } return rect; } @Override protected void paintSafely(Graphics g) { paintBackground(g); super.paintSafely(g); } public static void paintAquaSearchFocusRing(Graphics2D g, Rectangle r, Component c) { Graphics2D g2 = (Graphics2D)g.create(); try { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE); g2.translate(r.x, r.y); int arc = JBUI.scale(6); double lw = UIUtil.isRetina(g2) ? 0.5 : 1.0; Shape outerShape = new RoundRectangle2D.Double(JBUI.scale(3), JBUI.scale(3), r.width - JBUI.scale(6), r.height - JBUI.scale(6), arc, arc); g2.setColor(c.getBackground()); g2.fill(outerShape); Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD); path.append(outerShape, false); path.append(new RoundRectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw, r.width - JBUI.scale(6) - lw*2, r.height - JBUI.scale(6) - lw*2, arc-lw, arc-lw), false); g2.setColor(Gray.xBC); g2.fill(path); if (c.hasFocus()) { DarculaUIUtil.paintFocusBorder(g2, r.width, r.height, arc, true); } } finally { g2.dispose(); } } }