Package com.peterhi.ui.bar2

Source Code of com.peterhi.ui.bar2.StripBar5

package com.peterhi.ui.bar2;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.EventObject;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

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.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
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 org.jdesktop.core.animation.timing.Animator;
import org.jdesktop.core.animation.timing.TimingTarget;
import org.jdesktop.core.animation.timing.TimingTargetAdapter;

import com.peterhi.runtime.RT;
import com.peterhi.ui.UI;
import com.peterhi.ui.UIImageResource;

public final class StripBar5 extends Canvas {
 
  public static interface StripItemListener extends EventListener {
    void hovered(StripItemEvent e);
  }
 
  public static abstract class StripItemAdapter implements StripItemListener {
    @Override
    public void hovered(StripItemEvent e) {
    }
  }
 
  public static final class StripItemEvent extends EventObject {
    private static final long serialVersionUID = -2990774029657941119L;
   
    private final StripItem item;
    private final StripItem lastItem;
   
    public StripItemEvent(StripBar5 bar, StripItem item, StripItem lastItem) {
      super(bar);
      this.item = item;
      this.lastItem = lastItem;
    }
   
    public StripBar5 getStripBar() {
      return (StripBar5 )getSource();
    }
   
    public StripItem getItem() {
      return item;
    }
   
    public StripItem getLastItem() {
      return lastItem;
    }
  }

  public static final class StripItem {
    public static final RGB[] DEFAULT = new RGB[] {
      Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND).getRGB(),
      Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGB()
    };

    public static final RGB[] HOVERED = new RGB[] {
      Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND).getRGB(),
      new RGB(72, 118, 255)
    };
   
    public static final RGB[] PRESSED = new RGB[] {
      Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND).getRGB(),
      new RGB(65, 105, 225)
    };
   
    public static final RGB[] SELECTED = new RGB[] {
      Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB(),
      new RGB(67, 110, 238)
    };
   
    private final String id;
    private String text;
    private Image image;

    StripBar5 parent;
    Animator animator;
    RGB foreground;
    RGB background;
   
    public StripItem(String id) {
      this.id = id;
    }
   
    public StripBar5 getParent() {
      return parent;
    }
   
    void setParent(StripBar5 parent) {
      this.parent = parent;
    }
   
    public String getId() {
      return id;
    }
   
    public String getText() {
      return text;
    }
   
    public void setText(String value) {
      text = value;
    }
   
    public Image getImage() {
      return image;
    }
   
    public void setImage(Image value) {
      image = value;
    }
   
    public Rectangle getBounds() {
      checkParent();
      return parent.getBounds(this);
    }
   
    public Rectangle getImageBounds() {
      checkParent();
      return parent.getImageBounds(this);
    }
   
    public Rectangle getTextBounds() {
      checkParent();
      return parent.getTextBounds(this);
    }
   
    public Rectangle getCloseButtonBounds() {
      checkParent();
      return parent.getCloseButtonBounds(this);
    }
   
    public int getIndex() {
      checkParent();
      return parent.indexOf(this);
    }
   
    public StripItem getPreviousItem() {
      checkParent();
      return parent.getItem(getIndex() - 1);
    }
   
    public StripItem getNextItem() {
      checkParent();
      return parent.getItem(getIndex() + 1);
    }
   
    public void dispose() {
      checkParent();
      parent.removeItem(this);
    }
   
    public boolean isHovered() {
      checkParent();
      return equals(parent.getHoveredItem());
    }
   
    public boolean isPressed() {
      checkParent();
      return equals(parent.getPressedItem());
    }
   
    public boolean isSelected() {
      checkParent();
      return parent.isSelected(this);
    }
   
    public void setSelected(boolean value) {
      checkParent();
      parent.setSelected(this, value);
    }
   
    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((id == null) ? 0 : id.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (getClass() != obj.getClass())
        return false;
      StripItem other = (StripItem) obj;
      if (id == null) {
        if (other.id != null)
          return false;
      } else if (!id.equals(other.id))
        return false;
      return true;
    }
   
    @Override
    public String toString() {
      return MessageFormat.format("{0} \"{1}\"", id, text);
    }
   
    private void checkParent() {
      if (parent == null) {
        throw new IllegalStateException();
      }
    }
  }
 
  public static final int SPACING = 6;
  private final List<StripItem> items = new ArrayList<StripItem>();
  private final List<StripItemListener> listeners = new ArrayList<StripItemListener>();
  private final Set<StripItem> selected = new HashSet<StripItem>();
  private StripItem hovered;
  private StripItem pressed;
 
  public StripBar5(Composite parent, int style) {
    super(parent, style);
   
    addListener(SWT.Paint, new Listener() {
      @Override
      public void handleEvent(Event event) {
        onPaint(event);
      }
    });
   
    Listener hoverListener = new Listener() {
      @Override
      public void handleEvent(Event event) {
        onHover(event);
      }
    };
   
    addListener(SWT.MouseEnter, hoverListener);
    addListener(SWT.MouseExit, hoverListener);
    addListener(SWT.MouseMove, hoverListener);

    addListener(SWT.MouseDown, new Listener() {
      @Override
      public void handleEvent(Event event) {
        onPress(event);
      }
    });
   
    addListener(SWT.MouseUp, new Listener() {
      @Override
      public void handleEvent(Event event) {
        onSelect(event);
      }
    });
  }
 
  @Override
  public Point computeSize(int wHint, int hHint, boolean changed) {
    Point size = new Point(0, 0);
   
    for (StripItem item : items) {
      Rectangle bounds = item.getBounds();
      size.x += bounds.width;
      size.y = Math.max(size.y, bounds.height);
    }
   
    size.x += SPACING * (items.size() - 1);
    size.y += SPACING * 2;
   
    Rectangle boundsWithTrim = computeTrim(0, 0, size.x, size.y);
    size.x = boundsWithTrim.width;
    size.y = boundsWithTrim.height;
   
    return size;
  }
 
  public void addStripItemListener(StripItemListener listener) {
    if (listener == null) {
      throw new NullPointerException();
    }
   
    listeners.add(listener);
  }
 
  public void removeStripItemListener(StripItemListener listener) {
    if (listener == null) {
      throw new NullPointerException();
    }
   
    listeners.remove(listener);
  }
 
  public void removeAllStripItemListeners() {
    listeners.clear();
  }

  public boolean addItem(StripItem item) {
    return insertItem(item, getItemCount());
  }
 
  public boolean insertItem(StripItem item, int index) {
    if (item == null) {
      throw new NullPointerException();
    }

    if (items.contains(item)) {
      return false;
    }
   
    items.add(index, item);
    item.setParent(this);
    return true;
  }
 
  public boolean removeItem(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!items.contains(item)) {
      return false;
    }

    boolean result = items.remove(item);
   
    if (result) {
      if (item.equals(hovered)) {
        hovered = null;
      }
     
      item.setParent(null);
    }
   
    return result;
  }
 
  public int getItemCount() {
    return items.size();
  }
 
  public StripItem getItem(int index) {
    return items.get(index);
  }
 
  public StripItem getItem(int x, int y) {
    for (StripItem item : items) {
      Rectangle bounds = item.getBounds();
     
      if (bounds.contains(x, y)) {
        return item;
      }
    }
   
    return null;
  }
 
  public int indexOf(StripItem item) {
    return items.indexOf(item);
  }
 
  public StripItem[] getItems() {
    return items.toArray(new StripItem[items.size()]);
  }
 
  public StripItem getHoveredItem() {
    return hovered;
  }
 
  public StripItem getPressedItem() {
    return pressed;
  }
 
  public boolean isSelected(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!items.contains(item)) {
      throw new IllegalArgumentException();
    }
   
    return selected.contains(item);
  }
 
  public void setSelected(StripItem item, boolean value) {
    setSelected(item, value, false, true);
  }
 
  public void setSelected(StripItem item, boolean value, boolean fromPressedState, boolean checkOthers) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!items.contains(item)) {
      throw new IllegalArgumentException();
    }
   
    boolean needsAnimation = false;
   
    if (value) {
      if (selected.add(item)) {
        needsAnimation = true;
      }
    } else {
      if (selected.remove(item)) {
        needsAnimation = true;
      }
    }
   
    if (needsAnimation) {
      Point location = getDisplay().getCursorLocation();
      location = toControl(location);
      StripItem over = getItem(location.x, location.y);
     
      RGB from = item.background;
      RGB to = null;
     
      if (selected.contains(item)) {
        if (from == null) {
          if (fromPressedState) {
            from = StripItem.PRESSED[1];
          } else if (item.equals(over)) {
            from = StripItem.HOVERED[1];
          } else {
            from = StripItem.DEFAULT[1];
          }
        }
       
        item.foreground = StripItem.SELECTED[0];
        to = StripItem.SELECTED[1];
      } else {
        if (from == null) {
          from = StripItem.SELECTED[1];
        }
       
        if (item.equals(over)) {
          item.foreground = StripItem.HOVERED[0];
          to = StripItem.HOVERED[1];
        } else {
          item.foreground = StripItem.DEFAULT[0];
          to = StripItem.DEFAULT[1];
        }
      }
     
      if (from != null && to != null) {
        animBackColorChange(item, from, to);
      }
    }
   
    if (checkOthers && !isMultiSelection()) {
      for (StripItem otherItem : items) {
        if (otherItem.equals(item)) {
          continue;
        }
       
        if (otherItem.isSelected()) {
          setSelected(otherItem, false, fromPressedState, false);
        }
      }
    }
  }
 
  public StripItem[] getSelectedItems() {
    return selected.toArray(new StripItem[selected.size()]);
  }
 
  public Rectangle getBounds(StripItem destItem) {
    if (destItem == null) {
      throw new NullPointerException();
    }
   
    if (!items.contains(destItem)) {
      throw new IllegalArgumentException();
    }
   
    GC gc = new GC(this);
    Rectangle bounds = new Rectangle(SPACING, SPACING, 0, 0);
    Image closeButtonImage = UIImageResource.T.closeNormal10();
    Rectangle closeButtonImageBounds = closeButtonImage.getBounds();

    for (StripItem srcItem : items) {
      if (srcItem.getImage() != null) {
        Rectangle imageBounds = srcItem.getImage().getBounds();
        bounds.height = Math.max(bounds.height, imageBounds.height);
      }
     
      if (srcItem.getText() != null && !srcItem.getText().isEmpty()) {
        Point textSize = gc.stringExtent(srcItem.getText());
        bounds.height = Math.max(bounds.height, textSize.y);
      }
     
      bounds.height = Math.max(bounds.height, closeButtonImageBounds.height);
    }
   
    bounds.height += SPACING * 2;
   
    for (StripItem srcItem : items) {
      int extent = SPACING;
     
      if (srcItem.getImage() != null) {
        Rectangle imageBounds = srcItem.getImage().getBounds();
        extent += imageBounds.width;
        extent += SPACING;
      }
     
      if (srcItem.getText() != null && !srcItem.getText().isEmpty()) {
        Point textSize = gc.stringExtent(srcItem.getText());
        extent += textSize.x;
        extent += SPACING;
      }
     
      extent += closeButtonImageBounds.width;
      extent += SPACING;
     
      if (srcItem.equals(destItem)) {
        bounds.width = extent;
        break;
      } else {
        bounds.x += extent;
        bounds.x += SPACING;
      }
    }
   
    gc.dispose();
    return bounds;
  }
 
  public Rectangle getImageBounds(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!items.contains(item)) {
      throw new IllegalArgumentException();
    }
   
    Rectangle bounds = getBounds(item);
    bounds.y += bounds.height / 2;
    bounds.width = 0;
    bounds.height = 0;

    if (item.getImage() != null) {
      Rectangle imageBounds = item.getImage().getBounds();
      bounds.x += SPACING;
      bounds.y -= imageBounds.height / 2;
      bounds.width = imageBounds.width;
      bounds.height = imageBounds.height;
    }

    return bounds;
  }
 
  public Rectangle getTextBounds(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!items.contains(item)) {
      throw new IllegalArgumentException();
    }
   
    Rectangle bounds = getImageBounds(item);
    bounds.x += bounds.width;
    bounds.y += bounds.height / 2;
    bounds.width = 0;
    bounds.height = 0;

    if (item.getText() != null && !item.getText().isEmpty()) {
      GC gc = new GC(this);
      Point textSize = gc.stringExtent(item.getText());
      bounds.x += SPACING;
      bounds.y -= textSize.y / 2;
      bounds.width = textSize.x;
      bounds.height = textSize.y;
      gc.dispose();
    }
   
    return bounds;
  }
 
  public Rectangle getCloseButtonBounds(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!items.contains(item)) {
      throw new IllegalArgumentException();
    }
   
    Rectangle bounds = getTextBounds(item);
    bounds.x += bounds.width;
    bounds.y += bounds.height / 2;
    bounds.width = 0;
    bounds.height = 0;
   
    Image closeButtonImage = UIImageResource.T.closeNormal10();
    Rectangle closeButtonImageBounds = closeButtonImage.getBounds();
    bounds.x += SPACING;
    bounds.y -= closeButtonImageBounds.height / 2;
    bounds.width = closeButtonImageBounds.width;
    bounds.height = closeButtonImageBounds.height;
    return bounds;
  }
 
  public boolean isMultiSelection() {
    int style = getStyle();
    boolean multi = (style & SWT.MULTI) == SWT.MULTI;
    return multi;
  }
 
  private void fireHoveredEvent(StripItemEvent e) {
    for (StripItemListener listener : listeners) {
      listener.hovered(e);
    }
  }
 
  private void onPaint(Event event) {
    for (StripItem item : items) {
      paintStripItem(event.gc, item);
    }
  }
 
  private void paintStripItem(GC gc, StripItem item) {
    paintStripItemBackground(gc, item);
    paintStripItemImage(gc, item);
    paintStripItemText(gc, item);
    paintStripItemCloseButton(gc, item);
    paintStripItemFrame(gc, item);
  }
 
  private void paintStripItemBackground(GC gc, StripItem item) {
    Rectangle bounds = item.getBounds();
    Color old = gc.getBackground();
    Color neo;
   
    if (item.background == null) {
      neo = new Color(getDisplay(), StripItem.DEFAULT[1]);
    } else {
      neo = new Color(getDisplay(), item.background);
    }
   
    gc.setBackground(neo);
    gc.fillRectangle(bounds);
    gc.setBackground(old);
    neo.dispose();
  }
 
  private void paintStripItemImage(GC gc, StripItem item) {
    if (item.getImage() == null) {
      return;
    }
   
    Rectangle bounds = item.getImageBounds();
    gc.drawImage(item.getImage(), bounds.x, bounds.y);
  }
 
  private void paintStripItemText(GC gc, StripItem item) {
    if (item.getText() == null || item.getText().isEmpty()) {
      return;
    }
   
    Rectangle bounds = item.getTextBounds();
    Color old = gc.getForeground();
    Color neo;
   
    if (item.foreground == null) {
      neo = new Color(getDisplay(), StripItem.DEFAULT[0]);
    } else {
      neo = new Color(getDisplay(), item.foreground);
    }
   
    gc.setForeground(neo);
    gc.drawText(item.getText(), bounds.x, bounds.y, true);
    gc.setForeground(old);
    neo.dispose();
  }
 
  private void paintStripItemCloseButton(GC gc, StripItem item) {
    Image closeButtonImage = UIImageResource.T.closeNormal10();
    Rectangle bounds = item.getCloseButtonBounds();
    gc.drawImage(closeButtonImage, bounds.x, bounds.y);
  }
 
  private void paintStripItemFrame(GC gc, StripItem item) {
    Color old = gc.getForeground();
    Color neo = getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
    gc.setForeground(neo);
    Rectangle bounds = item.getBounds();
    gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
    gc.setForeground(old);
  }
 
  private void onHover(Event event) {
    StripItem old = hovered;
    StripItem neo = getItem(event.x, event.y);
   
    if (RT.equals(old, neo)) {
      return;
    }
   
    if (old != null && !old.isPressed() && !old.isSelected()) {
      RGB from = old.background;
     
      if (from == null) {
        from = StripItem.HOVERED[1];
      }
     
      RGB to = StripItem.DEFAULT[1];
      animBackColorChange(old, from, to);
    }
   
    if (neo != null && !neo.isPressed() && !neo.isSelected()) {
      RGB from = neo.background;
     
      if (from == null) {
        from = StripItem.DEFAULT[1];
      }
     
      RGB to = StripItem.HOVERED[1];
      animBackColorChange(neo, from, to);
    }
   
    hovered = neo;
    fireHoveredEvent(new StripItemEvent(this, neo, old));
  }
 
  private void onPress(Event event) {
    StripItem item = getItem(event.x, event.y);
   
    if (item != null) {
      if (isMultiSelection() || !item.isSelected()) {
        Rectangle bounds = item.getBounds();
        item.foreground = StripItem.PRESSED[0];
        item.background = StripItem.PRESSED[1];
        redraw(bounds.x, bounds.y, bounds.width, bounds.height, true);
        pressed = item;
      }
    }
  }
 
  private void onSelect(Event event) {
    if (pressed != null) {
      boolean wasSelected = pressed.isSelected();
      setSelected(pressed, !wasSelected, true, true);
      pressed = null;
    }
  }
 
  private void animBackColorChange(final StripItem item, final RGB from, final RGB to) {
    if (item.animator != null) {
      item.animator.cancel();
      item.animator = null;
    }
   
    TimingTarget tt = new TimingTargetAdapter() {
      @Override
      public void timingEvent(Animator source, double fraction) {
        Rectangle bounds = item.getBounds();
        int r = (int )Math.round((to.red - from.red) * fraction);
        int g = (int )Math.round((to.green - from.green) * fraction);
        int b = (int )Math.round((to.blue - from.blue) * fraction);
        item.background = new RGB(from.red + r, from.green + g, from.blue + b);
        redraw(bounds.x, bounds.y, bounds.width, bounds.height, true);
      }

      @Override
      public void end(Animator source) {
        Rectangle bounds = item.getBounds();
        item.background = to;
        redraw(bounds.x, bounds.y, bounds.width, bounds.height, true);
      }
    };
   
    item.animator = new Animator.Builder().addTarget(tt).setDuration(100, TimeUnit.MILLISECONDS).build();
    item.animator.start();
  }

  public static void main(String[] args) {
    UI.initialize();
    Display display = Display.getDefault();
    Shell shell = new Shell(display);
    StripBar5 bar = new StripBar5(shell, SWT.DOUBLE_BUFFERED | SWT.MULTI);
   
    GridLayout layout = new GridLayout();
    layout.horizontalSpacing = 0;
    layout.verticalSpacing = 0;
    layout.marginWidth = 0;
    layout.marginHeight = 0;
    shell.setLayout(layout);
   
    GridData data = new GridData();
    data.horizontalAlignment = SWT.FILL;
    data.verticalAlignment = SWT.FILL;
    data.grabExcessHorizontalSpace = true;
    bar.setLayoutData(data);
   
    StripItem item0 = new StripItem("item0");
    item0.setText("Item 0");
    item0.setImage(UIImageResource.T.about16());
   
    StripItem item1 = new StripItem("item1");
    item1.setText("Item 1");
   
    StripItem item2 = new StripItem("item2");
    item2.setImage(UIImageResource.T.addContact16());
   
    StripItem item3 = new StripItem("item3");
   
    bar.addItem(item0);
    bar.addItem(item1);
    bar.addItem(item2);
    bar.addItem(item3);
   
    shell.open();
   
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
   
    UI.destroy();
  }

}
TOP

Related Classes of com.peterhi.ui.bar2.StripBar5

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.