/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.color; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.ToolBarManager; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.ColorDialog; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; public class PaletteViewer extends Viewer implements IPaletteViewer { protected final class PaletteItemAction extends ColorAction { private static final int DEFAULT_WIDTH = 16; private static final int DEFAULT_HEIGHT = 16; private int type; public PaletteItemAction(int type, String text) { super(null, AS_CHECK_BOX); this.type = type; setText(text); } public PaletteItemAction(PaletteItem item) { super(item.color, AS_CHECK_BOX); this.type = IColorSelection.CUSTOM; setToolTipText(item.description); } public int getType() { return type; } public void setColor(RGB color) { super.setColor(color); if (getText() == PaletteMessages.PaletteViewer_MoreColors) setImageDescriptor(new ImageDescriptor() { public ImageData getImageData() { Display display = Display.getCurrent(); Image image = new Image(display, DEFAULT_WIDTH, DEFAULT_HEIGHT); GC gc = new GC(image); gc.setLineWidth(1); gc.setLineStyle(SWT.LINE_SOLID); gc.setAntialias(SWT.ON); int standardRadius = DEFAULT_WIDTH / 2; float brightness = 1.0f; for (int index = standardRadius; index > 1; index = index - 1) { drawCycle(gc, index, brightness); } gc.dispose(); ImageData imageData = image.getImageData(); image.dispose(); return imageData; } }); } private void drawCycle(GC graphics, int radius, float brightness) { int standardRadius = DEFAULT_WIDTH / 2; int delta = standardRadius - radius; float saturation = 1.0f - delta * 1.0f / standardRadius; Color color = null; for (int index = 0; index < 360; index++) { color = new Color(null, new RGB(index, saturation, brightness)); graphics.setBackground(color); graphics.fillArc(delta, delta, radius * 2, radius * 2, index, 1); color.dispose(); } } public void run() { super.run(); actionSelected(this); } } private static final int ITEM_SIZE = 70; private Composite control = null; private PaletteContents contents = null; private PaletteItemAction autoAction = null; private PaletteItemAction noneAction = null; private PaletteItemAction customAction = null; private boolean showAuto = false; private boolean showNone = false; private boolean showCustom = false; private boolean showStandardLabel = true; private boolean hasVerticalIndent = true; private RGB autoColor = null; private ToolBarManager autoToolBar = null; private Control sep1 = null; private List<ToolBarManager> paletteToolBarManagers = null; private Control sep2 = null; private Label standard = null; private Control sep3 = null; private ToolBarManager noneToolBar = null; private ToolBarManager customToolBar = null; private List<PaletteItemAction> paletteActions = null; private PaletteItemAction selection = null; private List<IOpenListener> openListeners = null; public PaletteViewer() { } public Control createControl(Composite parent) { if (!controlExists() && parent != null) { control = new Composite(parent, SWT.NO_FOCUS); GridLayout layout = new GridLayout(); layout.verticalSpacing = 0; layout.marginWidth = 0; layout.marginHeight = 0; control.setLayout(layout); control.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { handleDispose(e); } }); } return control; } protected void handleDispose(DisposeEvent e) { if (autoToolBar != null) autoToolBar.dispose(); if (noneToolBar != null) noneToolBar.dispose(); if (customToolBar != null) customToolBar.dispose(); if (paletteToolBarManagers != null) { for (ToolBarManager toolBarManager : paletteToolBarManagers) { toolBarManager.dispose(); } paletteToolBarManagers.clear(); paletteToolBarManagers = null; } // if (paletteToolBar != null) // paletteToolBar.dispose(); if (sep1 != null) { sep1.dispose(); sep1 = null; } if (sep2 != null) { sep2.dispose(); sep2 = null; } if (sep3 != null) { sep3.dispose(); sep3 = null; } } private boolean controlExists() { return control != null && !control.isDisposed(); } public Control getControl() { return control; } public void setPaletteItems(PaletteItem[] items) { setContents(items == null ? null : new PaletteContents(items)); } public PaletteItem[] getPaletteItems() { return contents == null ? null : contents.toArray(); } public void setContents(PaletteContents contents) { PaletteContents oldContents = this.contents; this.contents = contents; inputChanged(contents, oldContents); } public PaletteContents getContents() { return contents; } public boolean getShowAutoItem() { return showAuto; } public boolean getShowCustomItem() { return showCustom; } public boolean getShowNoneItem() { return showNone; } public void setShowAutoItem(boolean show) { if (show == getShowAutoItem()) return; this.showAuto = show; if (show) { if (autoToolBar == null) autoToolBar = createItemBar(); if (autoAction == null) autoAction = createItemAction(IColorSelection.AUTO, PaletteMessages.PaletteViewer_Automatic, getAutoColor(), autoToolBar); } else { autoAction = null; if (autoToolBar != null) { autoToolBar.dispose(); autoToolBar = null; } if (sep1 != null) { sep1.dispose(); sep1 = null; } } refresh(); } public boolean isShowStandardLabel() { return showStandardLabel; } public boolean hasVerticalIndent() { return hasVerticalIndent; } public void setShowNoneItem(boolean show) { if (show == getShowNoneItem()) return; this.showNone = show; if (show) { if (noneToolBar == null) noneToolBar = createItemBar(); if (noneAction == null) noneAction = createItemAction(IColorSelection.NONE, null, null, noneToolBar); } else { noneAction = null; if (noneToolBar != null) { noneToolBar.dispose(); noneToolBar = null; } } refresh(); } public void setShowCustomItem(boolean show) { if (show == getShowCustomItem()) return; this.showCustom = show; if (show) { if (customToolBar == null) customToolBar = createItemBar(); if (customAction == null) customAction = createItemAction(IColorSelection.CUSTOM, PaletteMessages.PaletteViewer_MoreColors, null, customToolBar); } else { customAction = null; if (customToolBar != null) { customToolBar.dispose(); customToolBar = null; } if (sep2 != null) { sep2.dispose(); sep2 = null; } if (standard != null) { standard.dispose(); standard = null; } if (sep3 != null) { sep3.dispose(); sep3 = null; } } refresh(); } public void setShowStandardLabel(boolean showStandardLabel) { this.showStandardLabel = showStandardLabel; } public void setHasVerticalIndent(boolean hasVerticalIndent) { this.hasVerticalIndent = hasVerticalIndent; } public RGB getAutoColor() { return autoColor; } public void setAutoColor(RGB color) { if (color == this.autoColor || (color != null && color.equals(this.autoColor))) return; this.autoColor = color; if (autoAction != null) { autoAction.setColor(color); } } public ISelection getSelection() { return selection == null ? ColorSelection.EMPTY : new ColorSelection(selection.getType(), selection.getColor()); } public void refresh() { setContents(getContents()); } protected void inputChanged(Object input, Object oldInput) { super.inputChanged(input, oldInput); if (control != null && !control.isDisposed()) { update(control, input, oldInput); } } private void update(Composite parent, Object input, Object oldInput) { boolean showAutoItem = getShowAutoItem(); boolean showNoneItem = getShowNoneItem(); boolean showCustomItem = getShowCustomItem(); PaletteItem[] oldItems = oldInput == null ? null : ((PaletteContents) oldInput).toArray(); PaletteItem[] newItems = input == null ? null : ((PaletteContents) input).toArray(); boolean paletteChanged = !equals(oldItems, newItems); boolean showPaletteItems = newItems != null && newItems.length > 0; int selType = selection == null ? -1 : selection.getType(); RGB selColor = selection == null ? null : selection.getColor(); Control last = null; if (showAutoItem) { last = showItemBar(autoToolBar, parent, last); if (showPaletteItems || showNoneItem || showCustomItem) { if (sep1 == null || sep1.isDisposed()) { sep1 = createSeparator(parent); } last = moveControl(sep1, last); } } if (paletteActions != null) { paletteActions.clear(); paletteActions = null; } if (paletteToolBarManagers != null) { if (!paletteToolBarManagers.isEmpty()) for (ToolBarManager toolBarManager : paletteToolBarManagers) { toolBarManager.removeAll(); toolBarManager.dispose(); } paletteToolBarManagers.clear(); paletteToolBarManagers = null; } if (showPaletteItems) { if (isShowStandardLabel()) { int cols = ((PaletteContents) input).getPreferredColumns(); List<PaletteItem> items = Arrays.asList(newItems); List<PaletteItem> genItems = items.subList(0, items.size() - cols); last = showPalette(input, genItems.toArray(new PaletteItem[genItems.size()]), paletteChanged, parent, last); if (sep2 == null || sep2.isDisposed()) { sep2 = createSeparator(parent); } last = moveControl(sep2, last); if (standard == null || standard.isDisposed()) { standard = new Label(parent, SWT.NONE); standard.setText( PaletteMessages.PaletteItem_Standard_label); GridData labelLayout = new GridData( GridData.FILL_HORIZONTAL); labelLayout.horizontalIndent = 7; labelLayout.verticalIndent = 5; standard.setLayoutData(labelLayout); } last = moveControl(standard, last); List<PaletteItem> staItems = items.subList(items.size() - cols, items.size()); last = showPalette(input, staItems.toArray(new PaletteItem[staItems.size()]), paletteChanged, parent, last); } else { List<PaletteItem> items = Arrays.asList(newItems); last = showPalette(input, items.toArray(new PaletteItem[items.size()]), paletteChanged, parent, last); } } if (showCustomItem) { if (showAutoItem || showPaletteItems || showNoneItem) { if (sep3 == null || sep3.isDisposed()) { sep3 = createSeparator(parent); } last = moveControl(sep3, last); } if (showNoneItem) { Composite moreAndNone = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); layout.numColumns = 2; layout.marginLeft = 0; layout.horizontalSpacing = 2; moreAndNone.setLayout(layout); last = showItemBar(noneToolBar, moreAndNone, last); last = showItemBar(customToolBar, moreAndNone, last); } else { last = showItemBar(customToolBar, parent, last); } } selection = findActionToSelect(selType, selColor); parent.layout(); } private Control showPalette(Object newInput, PaletteItem[] newItems, boolean paletteChanged, final Composite parent, Control currentControl) { Composite paletteContainer = new Composite(parent, SWT.NONE); GridLayout containerLayout = new GridLayout(); containerLayout.numColumns = ((PaletteContents) newInput) .getPreferredColumns(); containerLayout.verticalSpacing = 0; containerLayout.horizontalSpacing = 0; containerLayout.marginHeight = 0; containerLayout.marginWidth = 5; // if (newItems.length == ITEM_SIZE - containerLayout.numColumns // || newItems.length == containerLayout.numColumns) { // containerLayout.verticalSpacing = 0; // containerLayout.horizontalSpacing = 4; // } paletteContainer.setLayout(containerLayout); if (paletteToolBarManagers == null) { paletteToolBarManagers = new ArrayList<ToolBarManager>(); paletteChanged = true; } if (paletteActions == null) { paletteActions = new ArrayList<PaletteItemAction>(); paletteChanged = true; } if (paletteChanged) { // for (ToolBarManager toolBarManager : paletteToolBarManagers) { // if (toolBarManager != null) { // toolBarManager.removeAll(); // toolBarManager.dispose(); // } // } // paletteToolBarManagers.clear(); // paletteActions.clear(); for (int i = 0; i < newItems.length; i++) { PaletteItemAction action = new PaletteItemAction(newItems[i]); final ToolBar tb = new ToolBar(paletteContainer, SWT.FLAT | SWT.RIGHT); GridData layoutData = new GridData(GridData.FILL_HORIZONTAL); if (newItems.length == ITEM_SIZE - containerLayout.numColumns) if (hasVerticalIndent() && i >= containerLayout.numColumns && i < containerLayout.numColumns * 2) { layoutData.verticalIndent = 10; } tb.setLayoutData(layoutData); ToolBarManager toolBar = new ToolBarManager(tb); toolBar.add(action); tb.addMouseTrackListener(new MouseTrackListener() { public void mouseHover(MouseEvent e) { } public void mouseExit(MouseEvent e) { tb.setBackground(parent.getBackground()); } public void mouseEnter(MouseEvent e) { tb.setBackground(parent.getDisplay() .getSystemColor(SWT.COLOR_RED)); } }); tb.addMouseMoveListener(new MouseMoveListener() { public void mouseMove(MouseEvent e) { } }); paletteToolBarManagers.add(toolBar); paletteActions.add(action); } } for (int i = 0; i < paletteToolBarManagers.size(); i++) { ToolBarManager toolBar = paletteToolBarManagers.get(i); if (toolBar != null) { ToolBar tb = toolBar.getControl(); if (tb == null) { tb = toolBar.createControl(paletteContainer); GridData layoutData = new GridData( GridData.FILL_HORIZONTAL); if (newItems.length == ITEM_SIZE - containerLayout.numColumns) if (hasVerticalIndent() && i >= containerLayout.numColumns && i < containerLayout.numColumns * 2) { layoutData.verticalIndent = 10; } tb.setLayoutData(layoutData); } else { // toolBar.update(false); updatePaletteToolBar(toolBar); } } } moveControl(paletteContainer, currentControl); return paletteContainer; } private void updatePaletteToolBar(ToolBarManager toolBarManager) { ToolBar toolBar = toolBarManager.getControl(); // clean contains all active items without double separators IContributionItem item = toolBarManager.getItems()[0]; // determine obsolete items (removed or non active) ToolItem[] mi = toolBar.getItems(); if (mi.length > 0 && mi[0].getData() == item) { } else { for (int i = 0; i < mi.length; i++) { mi[i].dispose(); } item.fill(toolBar, 0); } } private Control showItemBar(ToolBarManager tbm, Composite parent, Control last) { if (tbm != null) { ToolBar tb = tbm.getControl(); if (tb == null || tb.isDisposed()) { tb = tbm.createControl(parent); tb.setLayoutData(new GridData(GridData.BEGINNING, GridData.FILL, true, false)); moveControl(tb, last); } else { tbm.update(true); } return tb; } return last; } protected Control createSeparator(Composite parent) { Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); return label; } private ToolBarManager createItemBar() { return new ToolBarManager(SWT.RIGHT | SWT.FLAT); } private PaletteItemAction createItemAction(int type, String text, RGB initColor, ToolBarManager parent) { PaletteItemAction action = new PaletteItemAction(type, text); action.setColor(initColor); ActionContributionItem ci = new ActionContributionItem(action); ci.setMode(ActionContributionItem.MODE_FORCE_TEXT); parent.add(ci); return action; } private Control moveControl(Control c, Control last) { if (c != null) { if (last != null) { c.moveBelow(last); } else { c.moveAbove(null); } return c; } return last; } protected PaletteItemAction findActionToSelect(int type, RGB color) { if (autoAction != null && type == autoAction.getType()) return autoAction; if (noneAction != null && type == noneAction.getType()) return noneAction; if (type == IColorSelection.CUSTOM) { if (paletteActions != null) { for (PaletteItemAction a : paletteActions) { if (equals(color, a.getColor())) return a; } } if (customAction != null && equals(color, customAction.getColor())) return customAction; } return null; } protected static boolean equals(Object o1, Object o2) { return o1 == o2 || (o1 != null && o1.equals(o2)); } public void setSelection(ISelection selection, boolean reveal) { PaletteItemAction oldSelection = this.selection; if (selection == null || selection.isEmpty() || !(selection instanceof IColorSelection)) { selectAction(null); if (oldSelection != null) fireColorSelectionChanged(); return; } IColorSelection colorSelection = (IColorSelection) selection; setSelection(colorSelection.getType(), colorSelection.getColor()); } protected void setSelection(int type, RGB color) { PaletteItemAction oldSelection = this.selection; PaletteItemAction newSelection = findActionToSelect(type, color); if (newSelection == null) { if (type == IColorSelection.CUSTOM && customAction != null) { RGB oldCustomColor = customAction.getColor(); if (!equals(color, oldCustomColor)) { customAction.setColor(color); selectAction(customAction); fireColorSelectionChanged(); return; } } } selectAction(newSelection); if (newSelection != oldSelection) fireColorSelectionChanged(); } protected void fireColorSelectionChanged() { fireSelectionChanged(new SelectionChangedEvent(this, getSelection())); } protected void selectAction(PaletteItemAction action) { if (action != null) action.setChecked(true); if (action == selection) return; this.selection = action; if (autoAction != null && autoAction != action) autoAction.setChecked(false); if (noneAction != null && noneAction != action) noneAction.setChecked(false); if (customAction != null && customAction != action) customAction.setChecked(false); if (paletteActions != null) { for (PaletteItemAction a : paletteActions) { if (a != action) a.setChecked(false); } } } public Object getInput() { return getContents(); } public void setInput(Object input) { if (!(input instanceof PaletteContents)) input = null; setContents((PaletteContents) input); } public void addOpenListener(IOpenListener listener) { if (openListeners == null) openListeners = new ArrayList<IOpenListener>(); openListeners.add(listener); } public void removeOpenListener(IOpenListener listener) { if (openListeners == null) return; openListeners.remove(listener); } protected void fireOpenEvent(final OpenEvent event) { if (openListeners == null) return; for (final Object l : openListeners.toArray()) { SafeRunner.run(new SafeRunnable() { public void run() throws Exception { ((IOpenListener) l).open(event); } }); } } protected void actionSelected(PaletteItemAction action) { if (action == customAction) { RGB oldColor = action.getColor(); Shell shell = getControl().getShell(); if (shell != null && !shell.isDisposed()) { RGB newColor = openNativeColorDialog(shell, oldColor); if (newColor != null) { setSelection(action.getType(), newColor); action.setColor(newColor); } } } else { setSelection(action.getType(), action.getColor()); } fireOpenEvent(new OpenEvent(this, getSelection())); } protected RGB openNativeColorDialog(Shell shell, RGB oldColor) { ColorDialog dialog = new ColorDialog(shell, SWT.NONE); dialog.setRGB(oldColor); return dialog.open(); } }