/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.swt.macosx.cocoa;
import java.util.List;
import org.eclipse.core.runtime.IProduct;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.TabItem;
import com.windowtester.runtime.swt.internal.display.DisplayExec;
import com.windowtester.swt.platform.ext.macosx.MacExtensions;
/**
* All methods must be executed on the UI thread.
* @author messick
*/
@SuppressWarnings("restriction")
public abstract class MacCocoa implements MacExtensions {
static final int kCFAllocatorDefault = 0;
static final String kAXChildrenAttribute = "AXChildren";
static final String kAXPositionAttribute = "AXPosition";
static final String kAXSizeAttribute = "AXSize";
private static final String MENU_BAR_FONT_NAME = "Lucinda Grande";
/**
* This value will be over-written at initialization time to accommodate different font sizes
* associated with different monitor resolutions.
*
* @see {@link #fixMenuBarFontSize()}.
*/
public static int MENU_BAR_FONT_SIZE = 12;
private static final int MENU_BAR_ITEM_HORIZ_PADDING = 21;
private static final int MENU_BAR_ITEM_VERT_PADDING = 3;
private static final int APPLE_MENU_OFFSET_X = 45;
private static final String APP_NAME_PROPERTY = "appName";
private static final String DEFAULT_APP_NAME = "Eclipse";
/**
* Initialize the menu bar font size based on the primary monitor's screen resolution.
*
*/
static void fixMenuBarFontSize() {
DisplayExec.sync(new Runnable(){
public void run() {
Monitor monitor = Display.getDefault().getPrimaryMonitor();
Rectangle bounds = monitor.getBounds();
if (bounds.width >= 1440) {
MENU_BAR_FONT_SIZE = 12;
} else {
/*
* TODO: fill out other possible values for different monitor resolutions
*/
MENU_BAR_FONT_SIZE = 14;
}
}
});
}
/**
* Given a MenuItem, return its bounding box.
*
* @param item the menu item
* @return Rectangle of item (in global coordinates), or null if something didn't work
*/
public abstract Rectangle getMenuItemBounds(MenuItem menuItem);
/**
* Given a TabItem, return its bounding box.
* <p>
* Not used in Cocoa.
*
* @param item the tab item
* @return Rectangle of item (in global coordinates), or null if something didn't work
*/
public Rectangle getTabItemBounds(TabItem item) {
throw new UnsupportedOperationException();
}
/**
* Return true if the accessibility API is enabled.
* <p>
* To enable it: open System Preferences, select Universal Access, then
* select "Enable access for assistive devices".
* <p>
* NB: Accessibility is not needed in Cocoa.
*
* @return true if the accessibility API is enabled
*/
public abstract boolean isAXAPIEnabled();
/**
* @return <code>true</code> if the given menu item appears in the menu bar.
*/
static boolean isMenuBarItem(MenuItem item) {
return isMenuBar(item.getParent());
}
/**
* Fills the {@link List} of {@link Rectangle} with
* items bounds of menu bar in <code>bounds</code> parameter.
*
* @param menu the {@link Menu} with style {@link SWT#BAR}.
* @param bounds the {@link List} of {@link Rectangle} to fill with items bounds values.
*/
void getMenuBarVisualData(Menu menu, List bounds) {
Point ext = getApplicationMenuLabelExtent();
int height = ext.y;
int menuWidth = ext.x + APPLE_MENU_OFFSET_X;
for (int i = 0; i < menu.getItemCount(); ++i) {
MenuItem item = menu.getItem(i);
String text = item.getText();
int itemWidth = 5;
if (text != null) {
Point textDimensions = getMenuBarLabelExtent(text);
itemWidth = textDimensions.x;
}
bounds.add(new Rectangle(menuWidth, 0, itemWidth, height));
menuWidth += itemWidth;
}
}
/**
* Return the menu bar height.
*/
abstract int getMenuBarHeight();
private String getApplicationName() {
IProduct product = Platform.getProduct();
String appName = product == null ? DEFAULT_APP_NAME : product.getProperty(APP_NAME_PROPERTY);
return appName.length() == 0 ? DEFAULT_APP_NAME : appName;
}
private Point getApplicationMenuLabelExtent() {
Point ext = getMenuLabelExtent(getApplicationName(), SWT.BOLD);
return new Point(ext.x + MENU_BAR_ITEM_HORIZ_PADDING, ext.y + MENU_BAR_ITEM_VERT_PADDING);
}
private Point getMenuBarLabelExtent(String label) {
Point ext = getMenuLabelExtent(label, SWT.NORMAL);
return new Point(ext.x + MENU_BAR_ITEM_HORIZ_PADDING, ext.y + MENU_BAR_ITEM_VERT_PADDING);
}
private Point getMenuLabelExtent(String label, int style) {
Display d = Display.getCurrent();
Font f = new Font(d, MENU_BAR_FONT_NAME, MENU_BAR_FONT_SIZE, style);
GC gc = new GC(d);
gc.setFont(f);
Point pt = gc.stringExtent(label);
gc.dispose();
return pt;
}
/**
* @return <code>true</code> if the given menu is the menu bar.
*/
private static boolean isMenuBar(Menu menu) {
return (menu.getStyle() & SWT.BAR) != 0;
}
}