/* * Copyright 2000-2013 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.darcula; import com.intellij.ide.IdeEventQueue; import com.intellij.ide.ui.laf.intellij.IntelliJLaf; import com.intellij.ui.ColorUtil; import com.intellij.ui.JBColor; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.MacUIUtil; import com.intellij.util.ui.UIUtil; import javax.swing.*; import javax.swing.text.JTextComponent; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.geom.Path2D; /** * @author Konstantin Bulenkov */ public class DarculaUIUtil implements SwingConstants { public static final Color GLOW_COLOR = new JBColor(new Color(96, 132, 212), new Color(96, 175, 255)); @SuppressWarnings("UseJBColor") private static final Color MAC_ACTIVE_ERROR_COLOR = new Color(0x80f53b3b, true); private static final JBColor DEFAULT_ACTIVE_ERROR_COLOR = new JBColor(0xe53e4d, 0x8b3c3c); @SuppressWarnings("UseJBColor") private static final Color MAC_INACTIVE_ERROR_COLOR = new Color(0x80f7bcbc, true); private static final JBColor DEFAULT_INACTIVE_ERROR_COLOR = new JBColor(0xebbcbc, 0x725252); @SuppressWarnings("UseJBColor") private static final Color MAC_REGULAR_COLOR = new Color(0x80479cfc, true); @SuppressWarnings("UseJBColor") private static final Color MAC_GRAPHITE_COLOR = new Color(0x8099979d, true); private static final Color ACTIVE_ERROR_COLOR = new JBColor(() -> UIUtil.isUnderDefaultMacTheme() ? MAC_ACTIVE_ERROR_COLOR : DEFAULT_ACTIVE_ERROR_COLOR); private static final Color INACTIVE_ERROR_COLOR = new JBColor(() -> UIUtil.isUnderDefaultMacTheme() ? MAC_INACTIVE_ERROR_COLOR : DEFAULT_INACTIVE_ERROR_COLOR); public static void paintFocusRing(Graphics g, int x, int y, int width, int height) { MacUIUtil.paintFocusRing((Graphics2D)g, getGlow(), new Rectangle(x, y, width, height)); } public static void paintFocusOval(Graphics g, int x, int y, int width, int height) { MacUIUtil.paintFocusRing((Graphics2D)g, getGlow(), new Rectangle(x, y, width, height), true); } private static Color getGlow() { return new JBColor(new Color(35, 121, 212), new Color(96, 175, 255)); } public static void paintSearchFocusRing(Graphics2D g, Rectangle bounds, Component component) { paintSearchFocusRing(g, bounds, component, -1); } public static void paintSearchFocusRing(Graphics2D g, Rectangle bounds, Component component, int maxArcSize) { int correction = UIUtil.isUnderAquaLookAndFeel() ? 30 : UIUtil.isUnderDarcula() ? 50 : 0; final Color[] colors = new Color[]{ ColorUtil.toAlpha(GLOW_COLOR, 180 - correction), ColorUtil.toAlpha(GLOW_COLOR, 120 - correction), ColorUtil.toAlpha(GLOW_COLOR, 70 - correction), ColorUtil.toAlpha(GLOW_COLOR, 100 - correction), ColorUtil.toAlpha(GLOW_COLOR, 50 - correction) }; final Object oldAntialiasingValue = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING); final Object oldStrokeControlValue = g.getRenderingHint(RenderingHints.KEY_STROKE_CONTROL); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE); final Rectangle r = new Rectangle(bounds.x - 3, bounds.y - 3, bounds.width + 6, bounds.height + 6); int arcSize = r.height - 1; if (maxArcSize>0) arcSize = Math.min(maxArcSize, arcSize); if (arcSize %2 == 1) arcSize--; g.setColor(component.getBackground()); g.fillRoundRect(r.x + 2, r.y + 2, r.width - 5, r.height - 5, arcSize - 4, arcSize - 4); g.setColor(colors[0]); g.drawRoundRect(r.x + 2, r.y + 2, r.width - 5, r.height - 5, arcSize-4, arcSize-4); g.setColor(colors[1]); g.drawRoundRect(r.x + 1, r.y + 1, r.width - 3, r.height - 3, arcSize-2, arcSize-2); g.setColor(colors[2]); g.drawRoundRect(r.x, r.y, r.width - 1, r.height - 1, arcSize, arcSize); g.setColor(colors[3]); g.drawRoundRect(r.x+3, r.y+3, r.width - 7, r.height - 7, arcSize-6, arcSize-6); g.setColor(colors[4]); g.drawRoundRect(r.x+4, r.y+4, r.width - 9, r.height - 9, arcSize-8, arcSize-8); // restore rendering hints g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAntialiasingValue); g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, oldStrokeControlValue); } public static void paintErrorBorder(Graphics2D g, int width, int height, int arc, boolean symmetric, boolean hasFocus) { g.setPaint(hasFocus ? ACTIVE_ERROR_COLOR : INACTIVE_ERROR_COLOR); doPaint(g, width, height, arc, symmetric); } public static void paintFocusBorder(Graphics2D g, int width, int height, int arc, boolean symmetric) { g.setPaint(IntelliJLaf.isGraphite() ? MAC_GRAPHITE_COLOR : MAC_REGULAR_COLOR); doPaint(g, width, height, arc, symmetric); } @SuppressWarnings("SuspiciousNameCombination") private static void doPaint(Graphics2D g, int width, int height, int arc, boolean symmetric) { double bw = UIUtil.isRetina(g) ? 0.5 : 1.0; double lw = JBUI.scale(UIUtil.isUnderDefaultMacTheme() ? 3 : 2); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, MacUIUtil.USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE); double outerArc = arc > 0 ? arc + lw - JBUI.scale(2) : lw; double rightOuterArc = symmetric ? outerArc : JBUI.scale(6); Path2D outerRect = new Path2D.Double(Path2D.WIND_EVEN_ODD); outerRect.moveTo(width - rightOuterArc, 0); outerRect.quadTo(width, 0, width, rightOuterArc); outerRect.lineTo(width, height - rightOuterArc); outerRect.quadTo(width, height, width - rightOuterArc, height); outerRect.lineTo(outerArc, height); outerRect.quadTo(0, height, 0, height - outerArc); outerRect.lineTo(0, outerArc); outerRect.quadTo(0, 0, outerArc, 0); outerRect.closePath(); lw += bw; double rightInnerArc = symmetric ? outerArc : JBUI.scale(7); Path2D innerRect = new Path2D.Double(Path2D.WIND_EVEN_ODD); innerRect.moveTo(width - rightInnerArc, lw); innerRect.quadTo(width - lw, lw, width - lw, rightInnerArc); innerRect.lineTo(width - lw, height - rightInnerArc); innerRect.quadTo(width - lw, height - lw, width - rightInnerArc, height - lw); innerRect.lineTo(outerArc, height - lw); innerRect.quadTo(lw, height - lw, lw, height - outerArc); innerRect.lineTo(lw, outerArc); innerRect.quadTo(lw, lw, outerArc, lw); innerRect.closePath(); Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD); path.append(outerRect, false); path.append(innerRect, false); g.fill(path); } public static boolean isCurrentEventShiftDownEvent() { AWTEvent event = IdeEventQueue.getInstance().getTrueCurrentEvent(); return (event instanceof KeyEvent && ((KeyEvent)event).isShiftDown()); } /** * @return -1 if visual position shouldn't be patched, otherwise selection start or selection end * @see javax.swing.plaf.basic.BasicTextUI#getNextVisualPositionFrom(JTextComponent, int, Position.Bias, int, Position.Bias[]) */ public static int getPatchedNextVisualPositionFrom(JTextComponent t, int pos, int direction) { if (!isCurrentEventShiftDownEvent()) { if (direction == WEST && t.getSelectionStart() < t.getSelectionEnd() && t.getSelectionEnd() == pos) { return t.getSelectionStart(); } if (direction == EAST && t.getSelectionStart() < t.getSelectionEnd() && t.getSelectionStart() == pos) { return t.getSelectionEnd(); } } return -1; } }