⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmenu.java

📁 lumaQQ的源文件
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 luma <stubma@163.com>
*
* 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
*/
package edu.tsinghua.lumaqq.widgets.menu;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;

import edu.tsinghua.lumaqq.ui.helper.UITool;

/**
 * 自定义菜单组件 
 *
 * @author luma
 */
public class CMenu {	
	private List<CMenuItem> items;
	private CMenuItem activeItem;
	private CMenu parent;
	private CMenu activeChild;
	
	private Point location;
	private Point size;
	private boolean visible;
	private boolean sizeDirty;
	
	private Shell menuShell;
	private Listener listener;
	
	private int fontHeight;
	
	static final int ITEM_TOP_MARGIN = 1;
	static final int ITEM_BOTTOM_MARGIN = 1;
	static final int ITEM_LEFT_MARGIN = 5;
	static final int ITEM_RIGHT_MARGIN = 5;
	static final int IMAGE_TEXT_SPACING = 5;
	static final int ARROW = 4;
	static final int TEXT_ARROW_SPACING = 10;
	static final int VERTICAL_SPACING = 1;
	static final int TOP_MARGIN = 3;
	static final int BOTTOM_MARGIN = 3;
	static final int LEFT_MARGIN = 1;
	static final int RIGHT_MARGIN = 1;
	static final int SEPARATOR_HEIGHT = 7;
	static final int BORDER = 1;
	
	private int imageSize;
	
	private Color background;
	private Color textColor;
	private Color textHoverColor;
	private Color activeBackground;
	private Color borderColor;
	private Color disabledTextColor;
	
	private static final Color DEFAULT_BACKGROUND = new Color(Display.getCurrent(), 0xE0, 0xEE, 0xFC);
	private static final Color DEFAULT_TEXT_COLOR = new Color(Display.getCurrent(), 0x07, 0x1E, 0x81);
	private static final Color DEFAULT_TEXT_HOVER_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
	private static final Color DEFAULT_ACTIVE_BACKGROUND = new Color(Display.getCurrent(), 0x2E, 0x91, 0xEC);
	private static final Color DEFAULT_BORDER_COLOR = new Color(Display.getCurrent(), 0x87, 0xA4, 0xC5);
	private static final Color DEFAULT_DISABLED_TEXT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
	private static final Color DARK_SEPARATOR = new Color(Display.getCurrent(), 0xAB, 0xC2, 0xDB);
	private static final Color LIGHT_SEPARATOR = new Color(Display.getCurrent(), 0xDF, 0xED, 0xFB);
	
	private Map<String, Object> datas;
	private static final String DEFAULT_DATA = "default_data";
	
	private List<IMenuListener> listeners;
	
	// 是否做双缓冲
	private static final boolean DOUBLE_BUFFERED;
	static {
	    // 如果不是Mac,底层也不是gtk,则做双缓冲
		String platform = SWT.getPlatform();
		DOUBLE_BUFFERED = !"carbon".equals(platform);
	}
	
	public CMenu(CMenuItem item) {
		item.setChild(this);
		items = new ArrayList<CMenuItem>();
		imageSize = 16;
		fontHeight = UITool.calculateDefaultFontHeight(new GC(Display.getDefault()));
		initColors();
	}

	public CMenu() {
		items = new ArrayList<CMenuItem>();
		imageSize = 16;
		fontHeight = UITool.calculateDefaultFontHeight(new GC(Display.getDefault()));
		initColors();
	}
	
	private void initColors() {
		 background = DEFAULT_BACKGROUND;
		 textColor = DEFAULT_TEXT_COLOR;
		 textHoverColor = DEFAULT_TEXT_HOVER_COLOR;
		 activeBackground = DEFAULT_ACTIVE_BACKGROUND;
		 borderColor = DEFAULT_BORDER_COLOR;
		 disabledTextColor = DEFAULT_DISABLED_TEXT_COLOR;
	}
	
	public void addMenuListener(IMenuListener ml) {
		if(listeners == null)
			listeners = new ArrayList<IMenuListener>();
		listeners.add(ml);
	}
	
	void fireMenuShownEvent() {
		if(listeners == null)
			return;
		
		MenuEvent e = new MenuEvent(this);
		for(IMenuListener ml : listeners)
			ml.menuShown(e);
	}
	
	public void setData(Object data) {
		if(datas == null)
			datas = new HashMap<String, Object>();
		datas.put(DEFAULT_DATA, data);
	}
	
	public void setData(String key, Object data) {
		if(datas == null)
			datas = new HashMap<String, Object>();
		datas.put(key, data);
	}
	
	public Object getData() {
		if(datas == null)
			return null;
		else
			return datas.get(DEFAULT_DATA);
	}
	
	public Object getData(String key) {
		if(datas == null)
			return null;
		else
			return datas.get(key);
	}
	
	void addItem(CMenuItem item) {
		items.add(item);
	}
	
	void addItem(CMenuItem item, int index) {
		items.add(index, item);
	}
	
	/**
	 * 显示菜单
	 */
	void show() {
		fireMenuShownEvent();
		if(menuShell != null && !menuShell.isDisposed()) {	
			// 检查菜单大小是否需要重新计算
			if(sizeDirty)
				computeSize();

			// 调整菜单位置,显示
			adjustShellLocation();
			if(!menuShell.getVisible())
				menuShell.setVisible(true);
		} else {
			menuShell = new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.ON_TOP | SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
			listener = new Listener() {
				public void handleEvent(Event e) {
					switch(e.type) {
						case SWT.Paint:
							handlePaint(e);
							break;
						case SWT.MouseMove:
							handleMouseMove(e);
							break;
						case SWT.MouseUp:
							handleMouseUp(e);
							break;
						case SWT.Dispose:
							handleDispose(e);
							break;
					}
				}
			};
			menuShell.addListener(SWT.Paint, listener);
			menuShell.addListener(SWT.MouseMove, listener);
			menuShell.addListener(SWT.Dispose, listener);
			menuShell.addListener(SWT.MouseUp, listener);
			computeSize();
			if(location == null)
				location = new Point(0, 0);
			adjustShellLocation();
			menuShell.setSize(size);
			menuShell.setVisible(true);
			menuShell.redraw();
		}
	}
	
	/**
	 * 调整菜单位置
	 */
	private void adjustShellLocation() {
		Rectangle displayBound = menuShell.getDisplay().getBounds();
		int shellX, shellY;
		int rightExceed = location.x + size.x - displayBound.width;
		int leftExceed = - (location.x - size.x);
		int topExceed = - (location.y - size.y);
		int bottomExceed = location.y + size.y - displayBound.height;
		if(rightExceed <= 0 || rightExceed <= leftExceed)
			shellX = location.x;
		else
			shellX = -leftExceed;
		if(bottomExceed <= 0 || bottomExceed <= topExceed)
			shellY = location.y;
		else
			shellY = -topExceed;
		menuShell.setLocation(shellX, shellY);
	}

	/**
	 * 隐藏菜单
	 */
	void hide() {
		hide(true);
	}
	
	/**
	 * 隐藏菜单,可选是否也隐藏上一级菜单
	 * 
	 * @param hideParent
	 */
	void hide(boolean hideParent) {
		hideSelf();
		if(parent != null && hideParent)
			parent.hide(hideParent);
		if(activeChild != null)
			activeChild.hideSelf();
	}
	
	void hideSelf() {
		visible = false;
		if(menuShell != null && !menuShell.isDisposed()) {
			menuShell.setVisible(false);
			menuShell.dispose();
			menuShell = null;
		}
	}

	/**
	 * @return
	 * 		菜单大小
	 */
	public Point getSize() {
		if(size == null)
			computeSize();
		return size;
	}
	
	public int getItemCount() {
		return items.size();
	}
	
	public CMenuItem[] getItems() {
		return items.toArray(new CMenuItem[getItemCount()]);
	}
	
	public CMenuItem getItem(int index) {
		return items.get(index);
	}
	
	void removeItem(CMenuItem item) {
		items.remove(item);
	}
	
	/**
	 * 菜单的大小
	 */
	protected void computeSize() {
		if(size == null)
			size = new Point(0, 0);
		
		GC gc = new GC(Display.getCurrent());
		
		int maxTextWidth = 0;
		int itemHeight = getItemHeight();
		size.x = LEFT_MARGIN + RIGHT_MARGIN + imageSize + IMAGE_TEXT_SPACING + ITEM_LEFT_MARGIN + ITEM_RIGHT_MARGIN + BORDER + BORDER + ARROW + TEXT_ARROW_SPACING;
		size.y = TOP_MARGIN + BOTTOM_MARGIN + BORDER + BORDER;
		for(CMenuItem item : items) {
			if(!item.isVisible())
				continue;
			if(item.getStyle() == SWT.SEPARATOR)
				size.y += SEPARATOR_HEIGHT + VERTICAL_SPACING;
			else {
				size.y += itemHeight + VERTICAL_SPACING;
				maxTextWidth = Math.max(maxTextWidth, gc.textExtent(item.getText()).x);				
			}
		}
		size.x += maxTextWidth;
		size.y -= VERTICAL_SPACING;
		
		gc.dispose();
		sizeDirty = false;
	}

	protected void handleDispose(Event e) {
		menuShell.removeListener(SWT.Dispose, listener);
	}

	protected void handleMouseUp(Event e) {
		if(activeItem != null) {
			if(activeItem.isEnabled()) {
				switch(activeItem.getStyle()) {
					case SWT.PUSH:
						setVisible(false);
						activeItem.fireSelectionEvent();
						break;
					case SWT.CHECK:
						setVisible(false);
						activeItem.setSelected(!activeItem.isSelected());
						activeItem.fireSelectionEvent();
						break;
					case SWT.RADIO:
						setVisible(false);
						activeItem.setSelected(!activeItem.isSelected());
						unselect(activeItem);
						activeItem.fireSelectionEvent();
						break;
				}				
			}
		} else
			setVisible(false);
	}

	/**
	 * 取消其他radio菜单的选择状态
	 * 
	 * @param except
	 * 		除了这个之外
	 */
	private void unselect(CMenuItem except) {
		int index = items.indexOf(except);
		if(index == -1)
			return;
		int size = getItemCount();
		for(int i = index + 1; i < size; i++) {
			CMenuItem item = getItem(i);
			if(item.getStyle() == SWT.RADIO)
				item.setSelected(false);
			else if(item.getStyle() == SWT.SEPARATOR)
				break;
		}
		
		for(int i = index - 1; i >= 0; i--) {
			CMenuItem item = getItem(i);
			if(item.getStyle() == SWT.RADIO)
				item.setSelected(false);
			else if(item.getStyle() == SWT.SEPARATOR)
				break;
		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -