/*
* Created on Mar 7, 2010 11:10:45 AM
* Copyright (C) 2010 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*/
package com.aelitis.azureus.ui.swt.utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.ui.swt.Utils;
/**
* @author TuxPaper
* @created Mar 7, 2010
*
*/
public class FontUtils
{
private static Method mFontData_SetHeight;
private static Method mFontData_GetHeightF;
static {
try {
mFontData_SetHeight = FontData.class.getDeclaredMethod("setHeight",
new Class[] {
float.class
});
mFontData_SetHeight.setAccessible(true);
} catch (Throwable e) {
mFontData_SetHeight = null;
}
try {
mFontData_GetHeightF = FontData.class.getDeclaredMethod("getHeightF",
new Class[] {
});
mFontData_GetHeightF.setAccessible(true);
} catch (Throwable e) {
mFontData_GetHeightF = null;
}
}
/**
*
* @param baseFont
* @param gc Can be null
* @param heightInPixels
* @return
*
* @since 3.0.0.7
*/
public static float getFontHeightFromPX(Font baseFont, GC gc,
int heightInPixels) {
Font font = null;
Device device = baseFont.getDevice();
// hack..
heightInPixels++;
// This isn't accurate, but gets us close
float[] size = {
Utils.pixelsToPoint(heightInPixels, device.getDPI().y) + 1
};
if (size[0] <= 0) {
return 0;
}
boolean bOurGC = gc == null || gc.isDisposed();
try {
if (bOurGC) {
gc = new GC(device);
}
FontData[] fontData = baseFont.getFontData();
font = findFont(gc, font, fontData, size, heightInPixels, SWT.DEFAULT);
} finally {
if (bOurGC) {
gc.dispose();
}
if (font != null && !font.isDisposed()) {
font.dispose();
}
}
return size[0];
}
public static float getFontHeightFromPX(Device device, FontData[] fontData,
GC gc, int heightInPixels) {
Font font = null;
// hack..
heightInPixels++;
// This isn't accurate, but gets us close
float[] size = {
Utils.pixelsToPoint(heightInPixels, device.getDPI().y) + 1
};
if (size[0] <= 0) {
return 0;
}
boolean bOurGC = gc == null || gc.isDisposed();
try {
if (bOurGC) {
gc = new GC(device);
}
font = findFont(gc, font, fontData, size, heightInPixels, SWT.DEFAULT);
} finally {
if (bOurGC) {
gc.dispose();
}
if (font != null && !font.isDisposed()) {
font.dispose();
}
}
return size[0];
}
public static Font getFontWithHeight(Font baseFont, GC gc, int heightInPixels) {
return getFontWithHeight(baseFont, gc, heightInPixels, SWT.DEFAULT);
}
public static Font getFontWithHeight(Font baseFont, GC gc,
int heightInPixels, int style) {
Font font = null;
Device device = baseFont.getDevice();
// hack..
heightInPixels++;
// This isn't accurate, but gets us close
float[] size = {
Utils.pixelsToPoint(heightInPixels, device.getDPI().y) + 1
};
if (size[0] <= 0) {
size[0] = 2;
}
boolean bOurGC = gc == null || gc.isDisposed();
try {
if (bOurGC) {
gc = new GC(device);
}
FontData[] fontData = baseFont.getFontData();
font = findFont(gc, font, fontData, size, heightInPixels, style);
} finally {
if (bOurGC) {
gc.dispose();
}
}
return font;
}
public static void setFontDataHeight(FontData[] fd, float fontSize) {
if (mFontData_SetHeight != null) {
try {
mFontData_SetHeight.invoke(fd[0], fontSize);
return;
} catch (Throwable e) {
}
}
fd[0].setHeight((int) fontSize);
}
private static Font findFont(GC gc, Font font, FontData[] fontData,
float[] size, int heightInPixels, int style) {
if (mFontData_SetHeight != null) {
return findFontByFloat(gc, font, fontData, size, heightInPixels, style);
}
return findFontByInt(gc, font, fontData, size, heightInPixels, style);
}
public static Font findFontByInt(GC gc, Font font, FontData[] fontData,
float[] returnSize, int heightInPixels, int style) {
int size = (int) returnSize[0];
do {
if (font != null) {
size--;
font.dispose();
}
fontData[0].setHeight(size);
if (style != SWT.DEFAULT) {
fontData[0].setStyle(style);
}
font = new Font(gc.getDevice(), fontData);
gc.setFont(font);
} while (font != null
&& gc.textExtent(Utils.GOOD_STRING).y > heightInPixels && size > 1);
returnSize[0] = size;
return font;
}
public static Font findFontByFloat(GC gc, Font font, FontData[] fontData,
float[] returnSize, int heightInPixels, int style) {
float size = returnSize[0];
float delta = 2.0f;
boolean fits;
int numLoops = 0;
do {
numLoops++;
if (font != null) {
size -= delta;
font.dispose();
}
try {
mFontData_SetHeight.invoke(fontData[0], size);
} catch (Throwable e) {
Debug.out(e);
}
if (style != SWT.DEFAULT) {
fontData[0].setStyle(style);
}
font = new Font(gc.getDevice(), fontData);
gc.setFont(font);
//System.out.println("yay " + size + " = "
// + gc.textExtent(Utils.GOOD_STRING).y + " (want " + heightInPixels
// + ")");
fits = gc.textExtent(Utils.GOOD_STRING).y <= heightInPixels;
if (fits && delta > .1) {
size += delta;
delta /= 2;
fits = false;
}
} while (!fits && size > 1);
returnSize[0] = size;
return font;
}
public static int getFontHeightInPX(FontData[] fd) {
Font font = new Font(Display.getDefault(), fd);
try {
return getFontHeightInPX(font);
} finally {
font.dispose();
}
}
public static int getFontHeightInPX(Font font) {
GC gc = new GC(font.getDevice());
try {
gc.setFont(font);
return gc.textExtent(Utils.GOOD_STRING).y;
} finally {
gc.dispose();
}
}
/**
* Change the height of the installed <code>Font</code> and takes care of disposing
* the new font when the control is disposed
* @param control
* @param height
* @param style one or both of SWT.BOLD, SWT.ITALIC, or SWT.NORMAL
*/
public static void setFontHeight(Control control, int height, int style) {
FontData[] fDatas = control.getFont().getFontData();
for (int i = 0; i < fDatas.length; i++) {
fDatas[i].height = height;
fDatas[i].setStyle(style);
}
final Font newFont = new Font(control.getDisplay(), fDatas);
control.setFont(newFont);
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (null != newFont && false == newFont.isDisposed()) {
newFont.dispose();
}
}
});
}
public static float getHeight(FontData[] fd) {
if (mFontData_GetHeightF != null) {
try {
return ((Number) mFontData_GetHeightF.invoke(fd[0], new Object[] {})).floatValue();
} catch (Throwable e) {
}
}
return fd[0].getHeight();
}
public static Font getFontPercentOf(Font baseFont, float pct) {
FontData[] fontData = baseFont.getFontData();
float height = getHeight(fontData) * pct;
setFontDataHeight(fontData, height);
return new Font(baseFont.getDevice(), fontData);
}
}