1 /*
   2  * Copyright (c) 2005, 2006, 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.nimbus;
  26 
  27 import javax.swing.Painter;
  28 import sun.swing.plaf.synth.SynthIcon;
  29 
  30 import javax.swing.plaf.synth.SynthContext;
  31 import javax.swing.*;
  32 import java.awt.*;
  33 import java.awt.image.BufferedImage;
  34 import javax.swing.plaf.UIResource;
  35 
  36 /**
  37  * An icon that delegates to a painter.
  38  * @author rbair
  39  */
  40 class NimbusIcon extends SynthIcon {
  41     private int width;
  42     private int height;
  43     private String prefix;
  44     private String key;
  45 
  46     NimbusIcon(String prefix, String key, int w, int h) {
  47         this.width = w;
  48         this.height = h;
  49         this.prefix = prefix;
  50         this.key = key;
  51     }
  52 
  53     @SuppressWarnings("unchecked")
  54     private static Painter<JComponent> paintFilter(@SuppressWarnings("rawtypes") Painter painter) {
  55         return (Painter<JComponent>) painter;
  56     }
  57 
  58     @Override
  59     public void paintIcon(SynthContext context, Graphics g, int x, int y,
  60                           int w, int h) {
  61         Painter<JComponent> painter = null;
  62         if (context != null) {
  63             painter = paintFilter((Painter)context.getStyle().get(context, key));
  64         }
  65         if (painter == null){
  66             painter = paintFilter((Painter)UIManager.get(prefix + "[Enabled]." + key));
  67         }
  68 
  69         if (painter != null && context != null) {
  70             JComponent c = context.getComponent();
  71             boolean rotate = false;
  72             boolean flip = false;
  73             //translatex and translatey are additional translations that
  74             //must occur on the graphics context when rendering a toolbar
  75             //icon
  76             int translatex = 0;
  77             int translatey = 0;
  78             if (c instanceof JToolBar) {
  79                 JToolBar toolbar = (JToolBar)c;
  80                 rotate = toolbar.getOrientation() == JToolBar.VERTICAL;
  81                 flip = !toolbar.getComponentOrientation().isLeftToRight();
  82                 Object o = NimbusLookAndFeel.resolveToolbarConstraint(toolbar);
  83                 //we only do the +1 hack for UIResource borders, assuming
  84                 //that the border is probably going to be our border
  85                 if (toolbar.getBorder() instanceof UIResource) {
  86                     if (o == BorderLayout.SOUTH) {
  87                         translatey = 1;
  88                     } else if (o == BorderLayout.EAST) {
  89                         translatex = 1;
  90                     }
  91                 }
  92             } else if (c instanceof JMenu) {
  93                 flip = ! c.getComponentOrientation().isLeftToRight();
  94             }
  95             if (g instanceof Graphics2D){
  96                 Graphics2D gfx = (Graphics2D)g;
  97                 gfx.translate(x, y);
  98                 gfx.translate(translatex, translatey);
  99                 if (rotate) {
 100                     gfx.rotate(Math.toRadians(90));
 101                     gfx.translate(0, -w);
 102                     painter.paint(gfx, context.getComponent(), h, w);
 103                     gfx.translate(0, w);
 104                     gfx.rotate(Math.toRadians(-90));
 105                 } else if (flip){
 106                     gfx.scale(-1, 1);
 107                     gfx.translate(-w,0);
 108                     painter.paint(gfx, context.getComponent(), w, h);
 109                     gfx.translate(w,0);
 110                     gfx.scale(-1, 1);
 111                 } else {
 112                     painter.paint(gfx, context.getComponent(), w, h);
 113                 }
 114                 gfx.translate(-translatex, -translatey);
 115                 gfx.translate(-x, -y);
 116             } else {
 117                 // use image if we are printing to a Java 1.1 PrintGraphics as
 118                 // it is not a instance of Graphics2D
 119                 BufferedImage img = new BufferedImage(w,h,
 120                         BufferedImage.TYPE_INT_ARGB);
 121                 Graphics2D gfx = img.createGraphics();
 122                 if (rotate) {
 123                     gfx.rotate(Math.toRadians(90));
 124                     gfx.translate(0, -w);
 125                     painter.paint(gfx, context.getComponent(), h, w);
 126                 } else if (flip){
 127                     gfx.scale(-1, 1);
 128                     gfx.translate(-w,0);
 129                     painter.paint(gfx, context.getComponent(), w, h);
 130                 } else {
 131                     painter.paint(gfx, context.getComponent(), w, h);
 132                 }
 133                 gfx.dispose();
 134                 g.drawImage(img,x,y,null);
 135                 img = null;
 136             }
 137         }
 138     }
 139 
 140     /**
 141      * Implements the standard Icon interface's paintIcon method as the standard
 142      * synth stub passes null for the context and this will cause us to not
 143      * paint any thing, so we override here so that we can paint the enabled
 144      * state if no synth context is available
 145      */
 146     @Override
 147     public void paintIcon(Component c, Graphics g, int x, int y) {
 148         Painter<JComponent> painter =
 149             paintFilter((Painter)UIManager.get(prefix + "[Enabled]." + key));
 150         if (painter != null){
 151             JComponent jc = (c instanceof JComponent) ? (JComponent)c : null;
 152             Graphics2D gfx = (Graphics2D)g;
 153             gfx.translate(x, y);
 154             painter.paint(gfx, jc , width, height);
 155             gfx.translate(-x, -y);
 156         }
 157     }
 158 
 159     @Override
 160     public int getIconWidth(SynthContext context) {
 161         if (context == null) {
 162             return width;
 163         }
 164         JComponent c = context.getComponent();
 165         if (c instanceof JToolBar && ((JToolBar)c).getOrientation() == JToolBar.VERTICAL) {
 166             //we only do the -1 hack for UIResource borders, assuming
 167             //that the border is probably going to be our border
 168             if (c.getBorder() instanceof UIResource) {
 169                 return c.getWidth() - 1;
 170             } else {
 171                 return c.getWidth();
 172             }
 173         } else {
 174             return scale(context, width);
 175         }
 176     }
 177 
 178     @Override
 179     public int getIconHeight(SynthContext context) {
 180         if (context == null) {
 181             return height;
 182         }
 183         JComponent c = context.getComponent();
 184         if (c instanceof JToolBar){
 185             JToolBar toolbar = (JToolBar)c;
 186             if (toolbar.getOrientation() == JToolBar.HORIZONTAL) {
 187                 //we only do the -1 hack for UIResource borders, assuming
 188                 //that the border is probably going to be our border
 189                 if (toolbar.getBorder() instanceof UIResource) {
 190                     return c.getHeight() - 1;
 191                 } else {
 192                     return c.getHeight();
 193                 }
 194             } else {
 195                 return scale(context, width);
 196             }
 197         } else {
 198             return scale(context, height);
 199         }
 200     }
 201 
 202     /**
 203      * Scale a size based on the "JComponent.sizeVariant" client property of the
 204      * component that is using this icon
 205      *
 206      * @param context The synthContext to get the component from
 207      * @param size The size to scale
 208      * @return The scaled size or original if "JComponent.sizeVariant" is not
 209      *          set
 210      */
 211     private int scale(SynthContext context, int size) {
 212         if (context == null || context.getComponent() == null){
 213             return size;
 214         }
 215         // The key "JComponent.sizeVariant" is used to match Apple's LAF
 216         String scaleKey = (String) context.getComponent().getClientProperty(
 217                 "JComponent.sizeVariant");
 218         if (scaleKey != null) {
 219             if (NimbusStyle.LARGE_KEY.equals(scaleKey)) {
 220                 size *= NimbusStyle.LARGE_SCALE;
 221             } else if (NimbusStyle.SMALL_KEY.equals(scaleKey)) {
 222                 size *= NimbusStyle.SMALL_SCALE;
 223             } else if (NimbusStyle.MINI_KEY.equals(scaleKey)) {
 224                 // mini is not quite as small for icons as full mini is
 225                 // just too tiny
 226                 size *= NimbusStyle.MINI_SCALE + 0.07;
 227             }
 228         }
 229         return size;
 230     }
 231 }