001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.swt.widgets;
011:
012: import org.eclipse.swt.*;
013: import org.eclipse.swt.graphics.*;
014: import org.eclipse.swt.internal.carbon.*;
015: import org.eclipse.swt.internal.Callback;
016: import org.eclipse.swt.internal.carbon.RGBColor;
017:
018: /**
019: * Instances of this class allow the user to select a font
020: * from all available fonts in the system.
021: * <dl>
022: * <dt><b>Styles:</b></dt>
023: * <dd>(none)</dd>
024: * <dt><b>Events:</b></dt>
025: * <dd>(none)</dd>
026: * </dl>
027: * <p>
028: * IMPORTANT: This class is intended to be subclassed <em>only</em>
029: * within the SWT implementation.
030: * </p>
031: */
032: public class FontDialog extends Dialog {
033: FontData fontData;
034: RGB rgb;
035: boolean open;
036: int fontID, fontSize;
037:
038: /**
039: * Constructs a new instance of this class given only its parent.
040: *
041: * @param parent a shell which will be the parent of the new instance
042: *
043: * @exception IllegalArgumentException <ul>
044: * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
045: * </ul>
046: * @exception SWTException <ul>
047: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
048: * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
049: * </ul>
050: */
051: public FontDialog(Shell parent) {
052: this (parent, SWT.APPLICATION_MODAL);
053: }
054:
055: /**
056: * Constructs a new instance of this class given its parent
057: * and a style value describing its behavior and appearance.
058: * <p>
059: * The style value is either one of the style constants defined in
060: * class <code>SWT</code> which is applicable to instances of this
061: * class, or must be built by <em>bitwise OR</em>'ing together
062: * (that is, using the <code>int</code> "|" operator) two or more
063: * of those <code>SWT</code> style constants. The class description
064: * lists the style constants that are applicable to the class.
065: * Style bits are also inherited from superclasses.
066: * </p>
067: *
068: * @param parent a shell which will be the parent of the new instance
069: * @param style the style of dialog to construct
070: *
071: * @exception IllegalArgumentException <ul>
072: * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
073: * </ul>
074: * @exception SWTException <ul>
075: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
076: * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
077: * </ul>
078: */
079: public FontDialog(Shell parent, int style) {
080: super (parent, style);
081: checkSubclass();
082: }
083:
084: /**
085: * Returns a FontData object describing the font that was
086: * selected in the dialog, or null if none is available.
087: *
088: * @return the FontData for the selected font, or null
089: * @deprecated use #getFontList ()
090: */
091: public FontData getFontData() {
092: return fontData;
093: }
094:
095: /**
096: * Returns a FontData set describing the font that was
097: * selected in the dialog, or null if none is available.
098: *
099: * @return the FontData for the selected font, or null
100: * @since 2.1.1
101: */
102: public FontData[] getFontList() {
103: if (fontData == null)
104: return null;
105: FontData[] result = new FontData[1];
106: result[0] = fontData;
107: return result;
108: }
109:
110: /**
111: * Returns an RGB describing the color that was selected
112: * in the dialog, or null if none is available.
113: *
114: * @return the RGB value for the selected color, or null
115: *
116: * @see PaletteData#getRGBs
117: *
118: * @since 2.1
119: */
120: public RGB getRGB() {
121: return rgb;
122: }
123:
124: int fontProc(int nextHandler, int theEvent, int userData) {
125: int kind = OS.GetEventKind(theEvent);
126: switch (kind) {
127: case OS.kEventFontPanelClosed:
128: open = false;
129: break;
130: case OS.kEventFontSelection:
131: int[] fontID = new int[1];
132: if (OS.GetEventParameter(theEvent,
133: OS.kEventParamATSUFontID, OS.typeUInt32, null, 4,
134: null, fontID) == OS.noErr) {
135: this .fontID = fontID[0];
136: }
137: int[] fontSize = new int[1];
138: if (OS.GetEventParameter(theEvent,
139: OS.kEventParamATSUFontSize, OS.typeFixed, null, 4,
140: null, fontSize) == OS.noErr) {
141: this .fontSize = fontSize[0];
142: }
143: RGBColor color = new RGBColor();
144: int[] actualSize = new int[1];
145: if (OS.GetEventParameter(theEvent, OS.kEventParamFontColor,
146: OS.typeRGBColor, null, RGBColor.sizeof, actualSize,
147: color) == OS.noErr) {
148: int red = (color.red >> 8) & 0xFF;
149: int green = (color.green >> 8) & 0xFF;
150: int blue = (color.blue >> 8) & 0xFF;
151: rgb = new RGB(red, green, blue);
152: } else {
153: int[] dict = new int[1];
154: if (OS.GetEventParameter(theEvent,
155: OS.kEventParamDictionary,
156: OS.typeCFDictionaryRef, null, 4, actualSize,
157: dict) == OS.noErr) {
158: int[] attrib = new int[1];
159: if (OS.CFDictionaryGetValueIfPresent(dict[0], OS
160: .kFontPanelAttributesKey(), attrib)) {
161: int[] tags = new int[1];
162: int[] sizes = new int[1];
163: int[] values = new int[1];
164: if (OS.CFDictionaryGetValueIfPresent(attrib[0],
165: OS.kFontPanelAttributeTagsKey(), tags)
166: && OS
167: .CFDictionaryGetValueIfPresent(
168: attrib[0],
169: OS
170: .kFontPanelAttributeSizesKey(),
171: sizes)
172: && OS
173: .CFDictionaryGetValueIfPresent(
174: attrib[0],
175: OS
176: .kFontPanelAttributeValuesKey(),
177: values)) {
178: int count = OS.CFDataGetLength(tags[0]) / 4;
179: int tagPtr = OS.CFDataGetBytePtr(tags[0]);
180: int sizePtr = OS.CFDataGetBytePtr(sizes[0]);
181: int[] tag = new int[1];
182: int[] size = new int[1];
183: int valueOffset = 0;
184: for (int i = 0; i < count; i++) {
185: OS.memmove(tag, tagPtr + (i * 4), 4);
186: OS.memmove(size, sizePtr + (i * 4), 4);
187: if (tag[0] == OS.kATSUColorTag
188: && size[0] == RGBColor.sizeof) {
189: int valuePtr = OS
190: .CFDataGetBytePtr(values[0]);
191: OS.memmove(color, valuePtr
192: + valueOffset,
193: RGBColor.sizeof);
194: int red = (color.red >> 8) & 0xFF;
195: int green = (color.green >> 8) & 0xFF;
196: int blue = (color.blue >> 8) & 0xFF;
197: rgb = new RGB(red, green, blue);
198: break;
199: }
200: valueOffset = size[0];
201: }
202: }
203: }
204: }
205: }
206: break;
207: }
208: return OS.noErr;
209: }
210:
211: /**
212: * Makes the dialog visible and brings it to the front
213: * of the display.
214: *
215: * @return a FontData object describing the font that was selected,
216: * or null if the dialog was cancelled or an error occurred
217: *
218: * @exception SWTException <ul>
219: * <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
220: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
221: * </ul>
222: */
223: public FontData open() {
224: Display display = parent != null ? parent.display : Display
225: .getCurrent();
226: if (fontData != null) {
227: Font font = new Font(display, fontData);
228: int ptr = OS.NewPtr(4);
229: OS.memmove(ptr, new int[] { font.atsuiStyle }, 4);
230: //TODO - not sure how to set initial color in font panel
231: // if (rgb != null) {
232: // RGBColor color = new RGBColor ();
233: // rgb.red = (short) (rgb.red * 0xffff);
234: // rgb.green = (short) (rgb.green * 0xffff);
235: // rgb.blue = (short) (rgb.blue * 0xffff);
236: // int ptr1 = OS.NewPtr (RGBColor.sizeof);
237: // OS.memcpy(ptr, color, RGBColor.sizeof);
238: // int [] tags = new int []{OS.kATSUColorTag};
239: // int [] sizes = new int []{RGBColor.sizeof};
240: // int [] values = new int []{ptr1};
241: // OS.ATSUSetAttributes (font.atsuiStyle, tags.length, tags, sizes, values);
242: // OS.DisposePtr(ptr1);
243: // }
244: OS.SetFontInfoForSelection(OS.kFontSelectionATSUIType, 1,
245: ptr, 0);
246: OS.DisposePtr(ptr);
247: font.dispose();
248: }
249: int[] mask = new int[] { OS.kEventClassFont,
250: OS.kEventFontSelection, OS.kEventClassFont,
251: OS.kEventFontPanelClosed, };
252: Callback fontPanelCallback = new Callback(this , "fontProc", 3);
253: int fontPanelCallbackAddress = fontPanelCallback.getAddress();
254: if (fontPanelCallbackAddress == 0)
255: SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
256: int appTarget = OS.GetApplicationEventTarget();
257: int[] outRef = new int[1];
258: OS.InstallEventHandler(appTarget, fontPanelCallbackAddress,
259: mask.length / 2, mask, 0, outRef);
260: fontSize = fontID = 0;
261: fontData = null;
262: rgb = null;
263: open = true;
264: /*
265: * Feature in the Macintosh. The Fonts window is not modal and it cannot
266: * be accessed through direct API. The fix is to figure out the Fonts
267: * window by checking all available windows and set its modality
268: * explicitily.
269: */
270: int count = 0;
271: int window = OS.GetPreviousWindow(0);
272: while (window != 0) {
273: count++;
274: window = OS.GetPreviousWindow(window);
275: }
276: int[] windows = new int[count];
277: boolean[] visible = new boolean[count];
278: count = 0;
279: window = OS.GetPreviousWindow(0);
280: while (window != 0) {
281: windows[count] = window;
282: visible[count] = OS.IsWindowVisible(window);
283: count++;
284: window = OS.GetPreviousWindow(window);
285: }
286: OS.FPShowHideFontPanel();
287: int fontsWindow = 0;
288: window = OS.GetPreviousWindow(0);
289: while (window != 0 && fontsWindow == 0) {
290: if (OS.IsWindowVisible(window)) {
291: boolean found = false;
292: for (int i = 0; i < windows.length; i++) {
293: if (windows[i] == window) {
294: found = true;
295: if (!visible[i]) {
296: fontsWindow = window;
297: break;
298: }
299: }
300: }
301: if (!found) {
302: fontsWindow = window;
303: break;
304: }
305: }
306: window = OS.GetPreviousWindow(window);
307: }
308: if (fontsWindow != 0) {
309: int inModalKind = OS.kWindowModalityNone;
310: if ((style & SWT.PRIMARY_MODAL) != 0)
311: inModalKind = OS.kWindowModalityWindowModal;
312: if ((style & SWT.APPLICATION_MODAL) != 0)
313: inModalKind = OS.kWindowModalityAppModal;
314: if ((style & SWT.SYSTEM_MODAL) != 0)
315: inModalKind = OS.kWindowModalitySystemModal;
316: if (inModalKind != OS.kWindowModalityNone) {
317: int inUnavailableWindow = 0;
318: if (parent != null)
319: inUnavailableWindow = OS
320: .GetControlOwner(parent.handle);
321: OS.SetWindowModality(fontsWindow, inModalKind,
322: inUnavailableWindow);
323: OS.SelectWindow(fontsWindow);
324: }
325: }
326: while (!parent.isDisposed() && open) {
327: if (!display.readAndDispatch())
328: display.sleep();
329: }
330: OS.RemoveEventHandler(outRef[0]);
331: fontPanelCallback.dispose();
332: if (fontID != 0 && fontSize != 0) {
333: int atsFont = OS.FMGetATSFontRefFromFont(fontID);
334: Font font = Font.carbon_new(display, atsFont, (short) 0,
335: (float) OS.Fix2X(fontSize));
336: fontData = font.getFontData()[0];
337: font.dispose();
338: }
339: return fontData;
340: }
341:
342: /**
343: * Sets a FontData object describing the font to be
344: * selected by default in the dialog, or null to let
345: * the platform choose one.
346: *
347: * @param fontData the FontData to use initially, or null
348: * @deprecated use #setFontList (FontData [])
349: */
350: public void setFontData(FontData fontData) {
351: this .fontData = fontData;
352: }
353:
354: /**
355: * Sets the set of FontData objects describing the font to
356: * be selected by default in the dialog, or null to let
357: * the platform choose one.
358: *
359: * @param fontData the set of FontData objects to use initially, or null
360: * to let the platform select a default when open() is called
361: *
362: * @see Font#getFontData
363: *
364: * @since 2.1.1
365: */
366: public void setFontList(FontData[] fontData) {
367: if (fontData != null && fontData.length > 0) {
368: this .fontData = fontData[0];
369: } else {
370: this .fontData = null;
371: }
372: }
373:
374: /**
375: * Sets the RGB describing the color to be selected by default
376: * in the dialog, or null to let the platform choose one.
377: *
378: * @param rgb the RGB value to use initially, or null to let
379: * the platform select a default when open() is called
380: *
381: * @see PaletteData#getRGBs
382: *
383: * @since 2.1
384: */
385: public void setRGB(RGB rgb) {
386: this.rgb = rgb;
387: }
388:
389: }
|