001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.imagej; 020 021import icy.gui.util.LookAndFeelUtil; 022import icy.gui.util.LookAndFeelUtil.WeakSkinChangeListener; 023import icy.system.IcyExceptionHandler; 024import icy.system.SystemUtil; 025import icy.util.ColorUtil; 026import icy.util.ReflectionUtil; 027 028import java.awt.Color; 029import java.awt.Container; 030import java.awt.Graphics; 031import java.awt.MenuComponent; 032import java.awt.PopupMenu; 033import java.lang.reflect.Field; 034import java.util.Vector; 035 036import javax.swing.BorderFactory; 037import javax.swing.JToolBar; 038import javax.swing.SwingConstants; 039 040import org.pushingpixels.substance.api.skin.SkinChangeListener; 041 042import ij.IJ; 043import ij.gui.Toolbar; 044import ij.plugin.MacroInstaller; 045 046/** 047 * ImageJ ToolBar Wrapper class. 048 * 049 * @author Stephane 050 */ 051public class ToolbarWrapper extends Toolbar 052{ 053 private class CustomToolBar extends JToolBar 054 { 055 /** 056 * 057 */ 058 private static final long serialVersionUID = -3278693015639517146L; 059 060 /** 061 * @param orientation 062 */ 063 public CustomToolBar(int orientation) 064 { 065 super(orientation); 066 067 setBorder(BorderFactory.createEmptyBorder()); 068 setFloatable(false); 069 } 070 071 @Override 072 protected void paintComponent(Graphics g) 073 { 074 ToolbarWrapper.this.paint(g); 075 076 // try 077 // { 078 // if (drawButtonsMethod != null) 079 // drawButtonsMethod.invoke(ToolbarWrapper.this, g); 080 // } 081 // catch (Exception e) 082 // { 083 // IcyExceptionHandler.showErrorMessage(e, false); 084 // System.err.println("Cannot redraw toolbar buttons from ImageJ."); 085 // } 086 } 087 088 @Override 089 public void removeNotify() 090 { 091 try 092 { 093 // TODO: remove this temporary hack when the "window dispose" bug will be fixed 094 // on the OpenJDK / Sun JVM 095 if (SystemUtil.isUnix()) 096 { 097 @SuppressWarnings("rawtypes") 098 Vector pp = (Vector) ReflectionUtil.getFieldObject(this, "popups", true); 099 pp.clear(); 100 } 101 } 102 catch (Exception e) 103 { 104 IcyExceptionHandler.showErrorMessage(e, false); 105 System.err.println("Cannot remove toolbar buttons from ImageJ."); 106 } 107 108 super.removeNotify(); 109 } 110 } 111 112 /** 113 * 114 */ 115 private static final long serialVersionUID = 6546185720732862969L; 116 117 final CustomToolBar swingComponent; 118 119 private final SkinChangeListener skinChangeListener; 120 121 /** 122 * leaked methods and fields 123 */ 124 // Method drawButtonsMethod; 125 Field grayField; 126 Field brighterField; 127 Field darkerField; 128 Field evenDarkerField; 129 Field toolColorField; 130 131 // private Color gray = ImageJ.backgroundColor; 132 // private Color brighter = gray.brighter(); 133 // private Color darker = new Color(175, 175, 175); 134 // private Color evenDarker = new Color(110, 110, 110); 135 136 public ToolbarWrapper(ImageJWrapper ijw) 137 { 138 super(); 139 140 swingComponent = new CustomToolBar(SwingConstants.HORIZONTAL); 141 142 swingComponent.setMinimumSize(getMinimumSize()); 143 swingComponent.setPreferredSize(getPreferredSize()); 144 swingComponent.addKeyListener(ijw); 145 swingComponent.addMouseListener(this); 146 swingComponent.addMouseMotionListener(this); 147 148 try 149 { 150 @SuppressWarnings("rawtypes") 151 final Vector popups = (Vector) ((Vector) ReflectionUtil.getFieldObject(this, "popups", true)).clone(); 152 153 // transfer all popup from original toolbar to the swing toolbar 154 for (Object obj : popups) 155 { 156 final PopupMenu popup = (PopupMenu) obj; 157 158 super.remove(popup); 159 swingComponent.add(popup); 160 } 161 162 // get access to private methods 163 // drawButtonsMethod = ReflectionUtil.getMethod(this.getClass(), "drawButtons", true, 164 // Graphics.class); 165 166 // get access to private fields 167 grayField = ReflectionUtil.getField(this.getClass(), "gray", true); 168 brighterField = ReflectionUtil.getField(this.getClass(), "brighter", true); 169 darkerField = ReflectionUtil.getField(this.getClass(), "darker", true); 170 evenDarkerField = ReflectionUtil.getField(this.getClass(), "evenDarker", true); 171 toolColorField = ReflectionUtil.getField(this.getClass(), "toolColor", true); 172 } 173 catch (Exception e) 174 { 175 IcyExceptionHandler.showErrorMessage(e, false); 176 System.err.println("Cannot restore toolbar buttons from ImageJ."); 177 } 178 179 skinChangeListener = new SkinChangeListener() 180 { 181 @Override 182 public void skinChanged() 183 { 184 Color bgCol = LookAndFeelUtil.getBackground(swingComponent); 185 Color brighterCol; 186 Color darkerCol; 187 Color evenDarkerCol; 188 189 if (ColorUtil.getLuminance(bgCol) < 64) 190 bgCol = ColorUtil.mix(bgCol, Color.gray); 191 192 brighterCol = ColorUtil.mix(bgCol, Color.white); 193 darkerCol = ColorUtil.mix(bgCol, Color.black); 194 evenDarkerCol = ColorUtil.mix(darkerCol, Color.black); 195 196 if (ColorUtil.getLuminance(bgCol) < 128) 197 brighterCol = ColorUtil.mix(bgCol, brighterCol); 198 else 199 { 200 darkerCol = ColorUtil.mix(bgCol, darkerCol); 201 evenDarkerCol = ColorUtil.mix(darkerCol, evenDarkerCol); 202 } 203 204 try 205 { 206 if (grayField != null) 207 grayField.set(ToolbarWrapper.this, bgCol); 208 if (brighterField != null) 209 brighterField.set(ToolbarWrapper.this, brighterCol); 210 if (darkerField != null) 211 darkerField.set(ToolbarWrapper.this, darkerCol); 212 if (evenDarkerField != null) 213 evenDarkerField.set(ToolbarWrapper.this, evenDarkerCol); 214 if (toolColorField != null) 215 toolColorField.set(ToolbarWrapper.this, LookAndFeelUtil.getForeground(swingComponent)); 216 217 swingComponent.repaint(); 218 } 219 catch (Exception e) 220 { 221 IcyExceptionHandler.showErrorMessage(e, false); 222 System.err.println("Cannot hack background color of ImageJ toolbar."); 223 } 224 } 225 }; 226 227 // install default tools and macros 228 new MacroInstaller().run(IJ.getDirectory("macros") + "StartupMacros.txt"); 229 230 LookAndFeelUtil.addSkinChangeListener(new WeakSkinChangeListener(skinChangeListener)); 231 } 232 233 @Override 234 public Container getParent() 235 { 236 return swingComponent.getParent(); 237 } 238 239 /** 240 * @return the swingComponent 241 */ 242 public JToolBar getSwingComponent() 243 { 244 return swingComponent; 245 } 246 247 @Override 248 public synchronized void add(PopupMenu popup) 249 { 250 if (swingComponent == null) 251 super.add(popup); 252 else 253 { 254 swingComponent.add(popup); 255 swingComponent.repaint(); 256 } 257 } 258 259 @Override 260 public synchronized void remove(MenuComponent popup) 261 { 262 if (swingComponent == null) 263 super.remove(popup); 264 else 265 { 266 swingComponent.remove(popup); 267 swingComponent.repaint(); 268 } 269 } 270 271 // @Override 272 // public void itemStateChanged(ItemEvent e) 273 // { 274 // super.itemStateChanged(e); 275 // 276 // swingComponent.repaint(); 277 // } 278 // 279 // @Override 280 // public void paint(Graphics g) 281 // { 282 // swingComponent.repaint(); 283 // } 284 285 @Override 286 public Graphics getGraphics() 287 { 288 return swingComponent.getGraphics(); 289 } 290 291 // /** 292 // * Rebuild swing toolbar component 293 // */ 294 // protected void rebuild() 295 // { 296 // swingComponent.removeAll(); 297 // swingComponent.validate(); 298 // } 299}