Index: editor/tools/plugins/com.xored.glance.ui/src/com/xored/glance/ui/controls/items/ItemDecorator.java |
=================================================================== |
--- editor/tools/plugins/com.xored.glance.ui/src/com/xored/glance/ui/controls/items/ItemDecorator.java (revision 0) |
+++ editor/tools/plugins/com.xored.glance.ui/src/com/xored/glance/ui/controls/items/ItemDecorator.java (revision 0) |
@@ -0,0 +1,277 @@ |
+/******************************************************************************* |
+ * Copyright (c) 2008 xored software, 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: |
+ * xored software, Inc. - initial API and Implementation (Yuri Strot) |
+ *******************************************************************************/ |
+package com.xored.glance.ui.controls.items; |
+ |
+import java.util.HashMap; |
+import java.util.HashSet; |
+import java.util.List; |
+import java.util.Map; |
+ |
+import org.eclipse.core.runtime.ListenerList; |
+import org.eclipse.jface.text.Region; |
+import org.eclipse.jface.text.TextPresentation; |
+import org.eclipse.swt.SWT; |
+import org.eclipse.swt.custom.StyleRange; |
+import org.eclipse.swt.graphics.Color; |
+import org.eclipse.swt.graphics.GC; |
+import org.eclipse.swt.graphics.Image; |
+import org.eclipse.swt.graphics.Rectangle; |
+import org.eclipse.swt.graphics.TextLayout; |
+import org.eclipse.swt.widgets.Composite; |
+import org.eclipse.swt.widgets.Event; |
+import org.eclipse.swt.widgets.Item; |
+import org.eclipse.swt.widgets.Listener; |
+ |
+import com.xored.glance.ui.sources.ColorManager; |
+import com.xored.glance.ui.sources.ITextSourceListener; |
+import com.xored.glance.ui.utils.TextUtils; |
+ |
+/** |
+ * @author Yuri Strot |
+ */ |
+public class ItemDecorator implements Listener { |
+ |
+ public static final int DEFAULT_STYLE = SWT.BACKGROUND | SWT.FOREGROUND | SWT.SELECTED | SWT.HOT; |
+ |
+ protected Composite composite; |
+ protected ItemProvider provider; |
+ protected int style; |
+ |
+ protected TextLayout textLayout; |
+ protected Map<ItemCell, StyleRange[]> itemToMatches; |
+ protected Map<ItemCell, StyleRange[]> cacheStyles; |
+ protected List<ItemCell> cells; |
+ protected HashSet<ItemCell> cellSet; |
+ |
+ private ListenerList listeners = new ListenerList(); |
+ |
+ public ItemDecorator(Composite composite, ItemProvider provider) { |
+ this(composite, provider, DEFAULT_STYLE); |
+ } |
+ |
+ public ItemDecorator(Composite composite, ItemProvider provider, int style) { |
+ this.composite = composite; |
+ this.provider = provider; |
+ this.style = style; |
+ clearStyles(); |
+ init(); |
+ } |
+ |
+ public void addTextSourceListener(ITextSourceListener listener) { |
+ listeners.add(listener); |
+ } |
+ |
+ public void removeTextSourceListener(ITextSourceListener listener) { |
+ listeners.remove(listener); |
+ } |
+ |
+ public ITextSourceListener[] getListeners() { |
+ Object[] objects = listeners.getListeners(); |
+ ITextSourceListener[] listeners = new ITextSourceListener[objects.length]; |
+ System.arraycopy(objects, 0, listeners, 0, objects.length); |
+ return listeners; |
+ } |
+ |
+ public void blocksChanged(ItemCell[] removed, ItemCell[] added) { |
+ for (ItemCell cell : removed) { |
+ cells.remove(cell); |
+ cellSet.remove(cell); |
+ } |
+ for (ItemCell cell : added) { |
+ cells.add(cell); |
+ cellSet.add(cell); |
+ cell.getItem().addListener(SWT.Dispose, this); |
+ } |
+ for (ITextSourceListener listener : getListeners()) { |
+ listener.blocksChanged(removed, added); |
+ } |
+ } |
+ |
+ public void clearStyles() { |
+ itemToMatches = new HashMap<ItemCell, StyleRange[]>(); |
+ cacheStyles = new HashMap<ItemCell, StyleRange[]>(); |
+ } |
+ |
+ public List<ItemCell> getCells() { |
+ return cells; |
+ } |
+ |
+ public void setCells(List<ItemCell> cells) { |
+ this.cells = cells; |
+ for (ItemCell cell : cells) { |
+ cell.getItem().addListener(SWT.Dispose, this); |
+ } |
+ cellSet = new HashSet<ItemCell>(cells); |
+ } |
+ |
+ public void setStyles(ItemCell cell, StyleRange[] styles) { |
+ if (styles == null) |
+ itemToMatches.remove(cell); |
+ else |
+ itemToMatches.put(cell, styles); |
+ cacheStyles.put(cell, calculateStyles(cell)); |
+ } |
+ |
+ public void redraw() { |
+ Rectangle rect = composite.getClientArea(); |
+ composite.redraw(rect.x, rect.y, rect.width, rect.height, true); |
+ } |
+ |
+ public void redraw(ItemCell cell) { |
+ Rectangle rect = provider.getBounds(cell.getItem(), cell.getIndex()); |
+ composite.redraw(rect.x, rect.y, rect.width, rect.height, true); |
+ } |
+ |
+ protected TextLayout getTextLayout() { |
+ if (textLayout == null) { |
+ int orientation = composite.getStyle() & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); |
+ textLayout = new TextLayout(composite.getDisplay()); |
+ textLayout.setOrientation(orientation); |
+ } else { |
+ textLayout.setText(""); |
+ } |
+ return textLayout; |
+ } |
+ |
+ protected StyleRange[] getRanges(ItemCell cell) { |
+ StyleRange[] ranges = cacheStyles.get(cell); |
+ if (ranges == null) { |
+ ranges = calculateStyles(cell); |
+ cacheStyles.put(cell, ranges); |
+ } |
+ return ranges; |
+ } |
+ |
+ protected StyleRange[] calculateStyles(ItemCell cell) { |
+ StyleRange[] cellStyles = cell.getStyles(); |
+ StyleRange[] matchStyles = itemToMatches.get(cell); |
+ if (matchStyles == null || matchStyles.length == 0) |
+ return cellStyles; |
+ if (cellStyles.length == 0) |
+ return matchStyles; |
+ Region region = new Region(0, cell.getLength()); |
+ int size = cellStyles.length + matchStyles.length; |
+ TextPresentation presentation = new TextPresentation(region, size); |
+ presentation.replaceStyleRanges(cellStyles); |
+ presentation.mergeStyleRanges(matchStyles); |
+ return TextUtils.getStyles(presentation); |
+ } |
+ |
+ public void handleEvent(Event event) { |
+ switch (event.type) { |
+ case SWT.PaintItem: |
+ paint(event); |
+ break; |
+ case SWT.EraseItem: |
+ erase(event); |
+ break; |
+ case SWT.Dispose: |
+ if (event.widget instanceof Item) { |
+ ItemCell cell = new ItemCell((Item) event.widget, event.index, provider); |
+ blocksChanged(new ItemCell[] {cell}, new ItemCell[0]); |
+ } |
+ break; |
+ } |
+ } |
+ |
+ protected void paint(Event event) { |
+ Item item = (Item) event.item; |
+ GC gc = event.gc; |
+ // remember colors to restore the GC later |
+ Color oldForeground = gc.getForeground(); |
+ Color oldBackground = gc.getBackground(); |
+ |
+ Color foreground = provider.getForeground(item, event.index); |
+ if (foreground != null) { |
+ gc.setForeground(foreground); |
+ } |
+ |
+ Color background = provider.getBackground(item, event.index); |
+ if (background != null) { |
+ gc.setBackground(background); |
+ } |
+ |
+ if (!ColorManager.getInstance().isUseNative() && (event.detail & SWT.SELECTED) != 0) { |
+ gc.setBackground(ColorManager.getInstance().getTreeSelectionBg()); |
+ gc.setForeground(ColorManager.getInstance().getTreeSelectionFg()); |
+ gc.fillRectangle(provider.getBounds(item, event.index)); |
+ } |
+ |
+ Image image = provider.getImage(item, event.index); |
+ if (image != null) { |
+ Rectangle imageBounds = provider.getImageBounds(item, event.index); |
+ if (imageBounds != null) { |
+ Rectangle bounds = image.getBounds(); |
+ |
+ // center the image in the given space |
+ int x = imageBounds.x + Math.max(0, (imageBounds.width - bounds.width) / 2); |
+ int y = imageBounds.y + Math.max(0, (imageBounds.height - bounds.height) / 2); |
+ gc.drawImage(image, x, y); |
+ } |
+ } |
+ |
+ Rectangle textBounds = provider.getTextBounds(item, event.index); |
+ if (textBounds != null) { |
+ TextLayout layout = getTextLayout(); |
+ layout.setText(provider.getText(item, event.index)); |
+ layout.setFont(provider.getFont(item, event.index)); |
+ |
+ ItemCell cell = new ItemCell(item, event.index, provider); |
+ if (!cellSet.contains(cell)) { |
+ blocksChanged(new ItemCell[0], new ItemCell[] {cell}); |
+ } |
+ StyleRange[] ranges = getRanges(cell); |
+ for (StyleRange range : ranges) { |
+ layout.setStyle(range, range.start, range.start + range.length - 1); |
+ } |
+ |
+ Rectangle layoutBounds = layout.getBounds(); |
+ |
+ int x = textBounds.x; |
+ int avg = (textBounds.height - layoutBounds.height) / 2; |
+ int y = textBounds.y + Math.max(0, avg); |
+ |
+ layout.draw(gc, x, y); |
+ } |
+ |
+ gc.setForeground(oldForeground); |
+ gc.setBackground(oldBackground); |
+ } |
+ |
+ public void erase(Event event) { |
+ int style = SWT.BACKGROUND | SWT.FOREGROUND; |
+ if (!ColorManager.getInstance().isUseNative()) { |
+ style |= SWT.SELECTED | SWT.HOT; |
+ } |
+ |
+ event.detail &= ~style; |
+ } |
+ |
+ protected void init() { |
+ // FIXME |
+ composite.addListener(SWT.EraseItem, this); |
+ composite.addListener(SWT.PaintItem, this); |
+ redraw(); |
+ } |
+ |
+ public void dispose() { |
+ if (!disposed) { |
+ clearStyles(); |
+ composite.removeListener(SWT.PaintItem, this); |
+ composite.removeListener(SWT.EraseItem, this); |
+ disposed = true; |
+ redraw(); |
+ } |
+ } |
+ |
+ public boolean isDisposed() { |
+ return disposed; |
+ } |
+ |
+ private boolean disposed; |
+ |
+} |