1 /*
   2  * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing.plaf.basic;
  26 
  27 import javax.swing.*;
  28 import java.awt.Component;
  29 import java.awt.Color;
  30 import java.awt.Dimension;
  31 import java.awt.Font;
  32 import java.awt.FontMetrics;
  33 import java.awt.Graphics;
  34 import java.awt.Insets;
  35 import java.awt.Rectangle;
  36 import java.awt.event.KeyEvent;
  37 import sun.swing.SwingUtilities2;
  38 
  39 
  40 /*
  41  * @author Hans Muller
  42  */
  43 
  44 public class BasicGraphicsUtils
  45 {
  46 
  47     private static final Insets GROOVE_INSETS = new Insets(2, 2, 2, 2);
  48     private static final Insets ETCHED_INSETS = new Insets(2, 2, 2, 2);
  49 
  50     public static void drawEtchedRect(Graphics g, int x, int y, int w, int h,
  51                                       Color shadow, Color darkShadow,
  52                                       Color highlight, Color lightHighlight)
  53     {
  54         Color oldColor = g.getColor();  // Make no net change to g
  55         g.translate(x, y);
  56 
  57         g.setColor(shadow);
  58         g.drawLine(0, 0, w-1, 0);      // outer border, top
  59         g.drawLine(0, 1, 0, h-2);      // outer border, left
  60 
  61         g.setColor(darkShadow);
  62         g.drawLine(1, 1, w-3, 1);      // inner border, top
  63         g.drawLine(1, 2, 1, h-3);      // inner border, left
  64 
  65         g.setColor(lightHighlight);
  66         g.drawLine(w-1, 0, w-1, h-1);  // outer border, bottom
  67         g.drawLine(0, h-1, w-1, h-1);  // outer border, right
  68 
  69         g.setColor(highlight);
  70         g.drawLine(w-2, 1, w-2, h-3);  // inner border, right
  71         g.drawLine(1, h-2, w-2, h-2);  // inner border, bottom
  72 
  73         g.translate(-x, -y);
  74         g.setColor(oldColor);
  75     }
  76 
  77 
  78     /**
  79      * Returns the amount of space taken up by a border drawn by
  80      * <code>drawEtchedRect()</code>
  81      *
  82      * @return  the inset of an etched rect
  83      */
  84     public static Insets getEtchedInsets() {
  85         return ETCHED_INSETS;
  86     }
  87 
  88 
  89     public static void drawGroove(Graphics g, int x, int y, int w, int h,
  90                                   Color shadow, Color highlight)
  91     {
  92         Color oldColor = g.getColor();  // Make no net change to g
  93         g.translate(x, y);
  94 
  95         g.setColor(shadow);
  96         g.drawRect(0, 0, w-2, h-2);
  97 
  98         g.setColor(highlight);
  99         g.drawLine(1, h-3, 1, 1);
 100         g.drawLine(1, 1, w-3, 1);
 101 
 102         g.drawLine(0, h-1, w-1, h-1);
 103         g.drawLine(w-1, h-1, w-1, 0);
 104 
 105         g.translate(-x, -y);
 106         g.setColor(oldColor);
 107     }
 108 
 109     /**
 110      * Returns the amount of space taken up by a border drawn by
 111      * <code>drawGroove()</code>
 112      *
 113      * @return  the inset of a groove border
 114      */
 115     public static Insets getGrooveInsets() {
 116         return GROOVE_INSETS;
 117     }
 118 
 119 
 120     public static void drawBezel(Graphics g, int x, int y, int w, int h,
 121                                  boolean isPressed, boolean isDefault,
 122                                  Color shadow, Color darkShadow,
 123                                  Color highlight, Color lightHighlight)
 124     {
 125         Color oldColor = g.getColor();  // Make no net change to g
 126         g.translate(x, y);
 127 
 128         if (isPressed && isDefault) {
 129             g.setColor(darkShadow);
 130             g.drawRect(0, 0, w - 1, h - 1);
 131             g.setColor(shadow);
 132             g.drawRect(1, 1, w - 3, h - 3);
 133         } else if (isPressed) {
 134             drawLoweredBezel(g, x, y, w, h,
 135                              shadow, darkShadow, highlight, lightHighlight);
 136         } else if (isDefault) {
 137             g.setColor(darkShadow);
 138             g.drawRect(0, 0, w-1, h-1);
 139 
 140             g.setColor(lightHighlight);
 141             g.drawLine(1, 1, 1, h-3);
 142             g.drawLine(2, 1, w-3, 1);
 143 
 144             g.setColor(highlight);
 145             g.drawLine(2, 2, 2, h-4);
 146             g.drawLine(3, 2, w-4, 2);
 147 
 148             g.setColor(shadow);
 149             g.drawLine(2, h-3, w-3, h-3);
 150             g.drawLine(w-3, 2, w-3, h-4);
 151 
 152             g.setColor(darkShadow);
 153             g.drawLine(1, h-2, w-2, h-2);
 154             g.drawLine(w-2, h-2, w-2, 1);
 155         } else {
 156             g.setColor(lightHighlight);
 157             g.drawLine(0, 0, 0, h-1);
 158             g.drawLine(1, 0, w-2, 0);
 159 
 160             g.setColor(highlight);
 161             g.drawLine(1, 1, 1, h-3);
 162             g.drawLine(2, 1, w-3, 1);
 163 
 164             g.setColor(shadow);
 165             g.drawLine(1, h-2, w-2, h-2);
 166             g.drawLine(w-2, 1, w-2, h-3);
 167 
 168             g.setColor(darkShadow);
 169             g.drawLine(0, h-1, w-1, h-1);
 170             g.drawLine(w-1, h-1, w-1, 0);
 171         }
 172         g.translate(-x, -y);
 173         g.setColor(oldColor);
 174     }
 175 
 176     public static void drawLoweredBezel(Graphics g, int x, int y, int w, int h,
 177                                         Color shadow, Color darkShadow,
 178                                         Color highlight, Color lightHighlight)  {
 179         g.setColor(darkShadow);
 180         g.drawLine(0, 0, 0, h-1);
 181         g.drawLine(1, 0, w-2, 0);
 182 
 183         g.setColor(shadow);
 184         g.drawLine(1, 1, 1, h-2);
 185         g.drawLine(1, 1, w-3, 1);
 186 
 187         g.setColor(lightHighlight);
 188         g.drawLine(0, h-1, w-1, h-1);
 189         g.drawLine(w-1, h-1, w-1, 0);
 190 
 191         g.setColor(highlight);
 192         g.drawLine(1, h-2, w-2, h-2);
 193         g.drawLine(w-2, h-2, w-2, 1);
 194      }
 195 
 196 
 197     /** Draw a string with the graphics <code>g</code> at location (x,y)
 198      *  just like <code>g.drawString</code> would.
 199      *  The first occurrence of <code>underlineChar</code>
 200      *  in text will be underlined. The matching algorithm is
 201      *  not case sensitive.
 202      */
 203     public static void drawString(Graphics g,String text,int underlinedChar,int x,int y) {
 204         int index=-1;
 205 
 206         if (underlinedChar != '\0') {
 207             char uc = Character.toUpperCase((char)underlinedChar);
 208             char lc = Character.toLowerCase((char)underlinedChar);
 209             int uci = text.indexOf(uc);
 210             int lci = text.indexOf(lc);
 211 
 212             if(uci == -1) {
 213                 index = lci;
 214             }
 215             else if(lci == -1) {
 216                 index = uci;
 217             }
 218             else {
 219                 index = (lci < uci) ? lci : uci;
 220             }
 221         }
 222         drawStringUnderlineCharAt(g, text, index, x, y);
 223     }
 224 
 225     /**
 226      * Draw a string with the graphics <code>g</code> at location
 227      * (<code>x</code>, <code>y</code>)
 228      * just like <code>g.drawString</code> would.
 229      * The character at index <code>underlinedIndex</code>
 230      * in text will be underlined. If <code>index</code> is beyond the
 231      * bounds of <code>text</code> (including < 0), nothing will be
 232      * underlined.
 233      *
 234      * @param g Graphics to draw with
 235      * @param text String to draw
 236      * @param underlinedIndex Index of character in text to underline
 237      * @param x x coordinate to draw at
 238      * @param y y coordinate to draw at
 239      * @since 1.4
 240      */
 241     public static void drawStringUnderlineCharAt(Graphics g, String text,
 242                            int underlinedIndex, int x,int y) {
 243         SwingUtilities2.drawStringUnderlineCharAt(null, g, text,
 244                                                   underlinedIndex, x, y);
 245     }
 246 
 247     public static void drawDashedRect(Graphics g,int x,int y,int width,int height) {
 248         int vx,vy;
 249 
 250         // draw upper and lower horizontal dashes
 251         for (vx = x; vx < (x + width); vx+=2) {
 252             g.fillRect(vx, y, 1, 1);
 253             g.fillRect(vx, y + height-1, 1, 1);
 254         }
 255 
 256         // draw left and right vertical dashes
 257         for (vy = y; vy < (y + height); vy+=2) {
 258             g.fillRect(x, vy, 1, 1);
 259             g.fillRect(x+width-1, vy, 1, 1);
 260         }
 261     }
 262 
 263     public static Dimension getPreferredButtonSize(AbstractButton b, int textIconGap)
 264     {
 265         if(b.getComponentCount() > 0) {
 266             return null;
 267         }
 268 
 269         Icon icon = (Icon) b.getIcon();
 270         String text = b.getText();
 271 
 272         Font font = b.getFont();
 273         FontMetrics fm = b.getFontMetrics(font);
 274 
 275         Rectangle iconR = new Rectangle();
 276         Rectangle textR = new Rectangle();
 277         Rectangle viewR = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
 278 
 279         SwingUtilities.layoutCompoundLabel(
 280             (JComponent) b, fm, text, icon,
 281             b.getVerticalAlignment(), b.getHorizontalAlignment(),
 282             b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
 283             viewR, iconR, textR, (text == null ? 0 : textIconGap)
 284         );
 285 
 286         /* The preferred size of the button is the size of
 287          * the text and icon rectangles plus the buttons insets.
 288          */
 289 
 290         Rectangle r = iconR.union(textR);
 291 
 292         Insets insets = b.getInsets();
 293         r.width += insets.left + insets.right;
 294         r.height += insets.top + insets.bottom;
 295 
 296         return r.getSize();
 297     }
 298 
 299     /*
 300      * Convenience function for determining ComponentOrientation.  Helps us
 301      * avoid having Munge directives throughout the code.
 302      */
 303     static boolean isLeftToRight( Component c ) {
 304         return c.getComponentOrientation().isLeftToRight();
 305     }
 306 }