Package com.peterhi.ui.bar2

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

package com.peterhi.ui.bar2;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
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.TimingTargetAdapter;

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

public final class StripBar extends Canvas implements Listener {

  public static enum State {
    DEFAULT,
    HOVERED,
    PRESSED,
    SELECTED;
   
    private static final Map<State, RGB> foregrounds = new HashMap<State, RGB>();
    private static final Map<State, RGB> backgrounds = new HashMap<State, RGB>();
   
    static {
      Display display = Display.getDefault();
     
      Color color = display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND);
      RGB rgb = color.getRGB();
      foregrounds.put(DEFAULT, rgb);
      foregrounds.put(HOVERED, rgb);

      color = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
      rgb = color.getRGB();
      foregrounds.put(PRESSED, rgb);
      foregrounds.put(SELECTED, rgb);
     
      color = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
      rgb = color.getRGB();
      backgrounds.put(DEFAULT, rgb);
     
      rgb = new RGB(72, 118, 255);
      backgrounds.put(HOVERED, rgb);
     
      rgb = new RGB(65, 105, 225);
      backgrounds.put(PRESSED, rgb);
     
      rgb = new RGB(67, 110, 238);
      backgrounds.put(SELECTED, rgb);
    }
   
    public static RGB getForeground(State state) {
      return foregrounds.get(state);
    }
   
    public static RGB getBackground(State state) {
      return backgrounds.get(state);
    }
   
    public RGB getForeground() {
      return getForeground(this);
    }
   
    public RGB getBackground() {
      return getBackground(this);
    }
  }
 
  public static final class Item {
    private final String id;
    private String text;
    private Image image;
    private State state;
   
    StripBar parent;
    Animator animator;
    RGB foreground;
    RGB background;
   
    public Item(String id) {
      this.id = id;
      this.state = State.DEFAULT;
    }
   
    public StripBar getParent() {
      return parent;
    }
   
    void setParent(StripBar value) {
      parent = value;
    }
   
    public String getId() {
      return id;
    }
   
    public String getText() {
      return text;
    }
   
    public void setText(String value) {
      text = value;
    }
   
    public boolean hasText() {
      if (text == null) {
        return false;
      }
     
      if (text.isEmpty()) {
        return false;
      }
     
      return true;
    }
   
    public Point getTextSize() {
      if (!hasText()) {
        return null;
      }
     
      Display display = Display.getDefault();
      GC gc = new GC(display);
      Point textSize = gc.stringExtent(text);
      gc.dispose();
      return textSize;
    }
   
    public Rectangle getTextBounds() {
      checkParent();
      return parent.getTextBounds(this);
    }
   
    public Image getImage() {
      return image;
    }
   
    public void setImage(Image value) {
      image = value;
    }
   
    public boolean hasImage() {
      return image != null;
    }
   
    public Point getImageSize() {
      if (!hasImage()) {
        return null;
      }
     
      Rectangle imageBounds = image.getBounds();
      return new Point(imageBounds.width, imageBounds.height);
    }
   
    public Rectangle getImageBounds() {
      checkParent();
      return parent.getImageBounds(this);
    }
   
    public Rectangle getCloseButtonBounds() {
      checkParent();
      return parent.getCloseButtonBounds(this);
    }
   
    public Rectangle getBounds() {
      checkParent();
      return parent.getBounds(this);
    }
   
    public State getState() {
      return state;
    }
   
    public void setState(State value) {
      if (value == null) {
        throw new NullPointerException();
      }
     
      checkParent();
     
      if (state == value) {
        return;
      }

      if (animator != null) {
        animator.cancel();
        animator = null;
      }
     
      if ((state == State.DEFAULT && value == State.HOVERED) || (state == State.HOVERED && value == State.DEFAULT)) {
        RGB from = background;
       
        if (from == null) {
          from = state.getBackground();
        }
       
        Fade fade = new Fade(this, from, value.getBackground());
        animator = new Animator.Builder().addTarget(fade).setDuration(100, TimeUnit.MILLISECONDS).build();
        animator.start();
      } else {
        foreground = value.getForeground();
        background = value.getBackground();
        redraw();
      }
     
      state = value;
    }
   
    public boolean isDefault() {
      return state == State.DEFAULT;
    }
   
    public boolean isHovered() {
      return state == State.HOVERED;
    }
   
    public boolean isPressed() {
      return state == State.PRESSED;
    }
   
    public boolean isSelected() {
      return state == State.SELECTED;
    }
   
    public int getIndex() {
      checkParent();
      return parent.indexOf(this);
    }
   
    public Item getLast() {
      checkParent();
      return parent.get(getIndex() - 1);
    }
   
    public Item getNext() {
      checkParent();
      return parent.get(getIndex() + 1);
    }

    public void dispose() {
      checkParent();
      parent.remove(this);
    }
   
    public void redraw() {
      checkParent();
      Rectangle bounds = getBounds();
      parent.redraw(bounds.x, bounds.y, bounds.width, bounds.height, true);
    }
   
    @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;
      Item other = (Item) 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();
      }
    }
  }
 
  static final class Fade extends TimingTargetAdapter {
   
    private final Item item;
    private final RGB from;
    private final RGB to;
   
    public Fade(Item item, RGB from, RGB to) {
      this.item = item;
      this.from = from;
      this.to = to;
    }
   
    @Override
    public void timingEvent(Animator source, double fraction) {
      double r = (to.red - from.red) * fraction;
      double g = (to.green - from.green) * fraction;
      double b = (to.blue - from.blue) * fraction;
      item.background = new RGB(0, 0, 0);
      item.background.red += from.red;
      item.background.green += from.green;
      item.background.blue += from.blue;
      item.background.red += (int )Math.round(r);
      item.background.green += (int )Math.round(g);
      item.background.blue += (int )Math.round(b);
      item.redraw();
    }
   
    @Override
    public void end(Animator source) {
      item.background = to;
      item.redraw();
    }
  }
 
  public static final int SPACE = 6;
  private final List<Item> items = new ArrayList<Item>();
  private Item hovered;
  private Item pressed;
  private final Set<Item> selected = new HashSet<Item>();
 
  public StripBar(Composite parent, int style) {
    super(parent, style);
    addListener(SWT.Paint, this);
    addListener(SWT.MouseEnter, this);
    addListener(SWT.MouseExit, this);
    addListener(SWT.MouseDown, this);
    addListener(SWT.MouseMove, this);
    addListener(SWT.MouseUp, this);
  }
 
  @Override
  public void handleEvent(Event event) {
    if (equals(event.widget)) {
      if (event.type == SWT.Paint) {
        onPaint(event);
      }
     
      if (event.type == SWT.MouseEnter || event.type == SWT.MouseExit || event.type == SWT.MouseMove) {
        onHover(event);
      }
     
      if (event.type == SWT.MouseDown) {
        onPress(event);
      }
     
      if (event.type == SWT.MouseUp) {
        onSelect(event);
      }
    }
  }
 
  private void onPaint(Event event) {
    for (Item item : items) {
      paint(event.gc, item);
    }
  }
 
  private void onHover(Event event) {
    Item old = hovered;
    Item neo = get(event.x, event.y);

    if (RT.equals(neo, old)) {
      return;
    }
   
    if (neo != null) {
      neo.setState(State.HOVERED);
    }
   
    if (old != null && !old.isSelected()) {
      old.setState(State.DEFAULT);
    }

    hovered = neo;
  }
 
  private void onPress(Event event) {
    Item neo = get(event.x, event.y);
   
    if (neo != null) {
      neo.setState(State.PRESSED);
    }
   
    pressed = neo;
  }
 
  private void onSelect(Event event) {
    if (pressed != null) {
      pressed.setState(State.SELECTED);
    }
   
    selected.add(pressed);
    pressed = null;
  }

  @Override
  public Point computeSize(int wHint, int hHint, boolean changed) {
    Point size = new Point(0, 0);
   
    for (Item item : items) {
      Rectangle bounds = item.getBounds();
      size.x += bounds.width;
      size.y = Math.max(size.y, bounds.height);
    }
   
    size.x += SPACE * (items.size() - 1);
    size.y += SPACE * 2;
   
    Rectangle boundsWithTrim = computeTrim(0, 0, size.x, size.y);
    size.x = boundsWithTrim.width;
    size.y = boundsWithTrim.height;
    return size;
  }

  public boolean add(Item item) {
    return insert(item, size());
  }
 
  public boolean insert(Item item, int index) {
    if (item == null) {
      throw new NullPointerException();
    }

    if (contains(item)) {
      return false;
    }

    items.add(index, item);
    item.setParent(this);
    return true;
  }
 
  public boolean remove(Item item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!contains(item)) {
      return false;
    }
   
    items.remove(item);
    item.setParent(null);
    return true;
  }
 
  public void remove(int index) {
    Item item = items.remove(index);
    item.setParent(null);
  }
 
  public int size() {
    return items.size();
  }
 
  public boolean contains(Item item) {
    return items.contains(item);
  }
 
  public int indexOf(Item item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    return items.indexOf(item);
  }
 
  public Item get(int index) {
    return items.get(index);
  }
 
  public Item get(int x, int y) {
    for (Item item : items) {
      Rectangle bounds = item.getBounds();
     
      if (bounds.contains(x, y)) {
        return item;
      }
    }
   
    return null;
  }
 
  public Item[] getAll() {
    return items.toArray(new Item[items.size()]);
  }
 
  public Rectangle getBounds(Item item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!contains(item)) {
      return null;
    }
   
    Rectangle bounds = new Rectangle(SPACE, SPACE, 0, 0);
   
    for (Item anItem : items) {
      if (anItem.hasImage()) {
        bounds.height = Math.max(bounds.height, anItem.getImageSize().y);
      }
     
      if (anItem.hasText()) {
        bounds.height = Math.max(bounds.height, anItem.getTextSize().y);
      }
     
      bounds.height = Math.max(bounds.height, getCloseButtonSize().y);
    }
   
    bounds.height += SPACE * 2;
   
    for (Item anItem : items) {
      int extent = SPACE;
     
      if (anItem.hasImage()) {
        extent += anItem.getImageSize().x;
        extent += SPACE;
      }
     
      if (anItem.hasText()) {
        extent += anItem.getTextSize().x;
        extent += SPACE;
      }
     
      extent += getCloseButtonSize().x;
      extent += SPACE;
     
      if (anItem.equals(item)) {
        bounds.width = extent;
        break;
      } else {
        bounds.x += extent;
        bounds.x += SPACE;
      }
    }
   
    return bounds;
  }
 
  public Rectangle getImageBounds(Item item) {
    Rectangle bounds = getBounds(item);
   
    if (bounds == null) {
      return null;
    }
   
    bounds.y += bounds.height / 2;
    bounds.width = 0;
    bounds.height = 0;
   
    if (item.hasImage()) {
      Point imageSize = item.getImageSize();
      bounds.x += SPACE;
      bounds.y -= imageSize.y / 2;
      bounds.width = imageSize.x;
      bounds.height = imageSize.y;
    }
   
    return bounds;
  }
 
  public Rectangle getTextBounds(Item item) {
    Rectangle bounds = getImageBounds(item);
   
    if (bounds == null) {
      return null;
    }
   
    bounds.x += bounds.width;
    bounds.y += bounds.height / 2;
    bounds.width = 0;
    bounds.height = 0;
   
    if (item.hasText()) {
      Point textSize = item.getTextSize();
      bounds.x += SPACE;
      bounds.y -= textSize.y / 2;
      bounds.width = textSize.x;
      bounds.height = textSize.y;
    }
   
    return bounds;
  }
 
  public Rectangle getCloseButtonBounds(Item item) {
    Rectangle bounds = getTextBounds(item);
   
    if (bounds == null) {
      return null;
    }
   
    Point closeButtonSize = getCloseButtonSize();
    bounds.x += bounds.width + SPACE;
    bounds.y += bounds.height / 2 - closeButtonSize.y / 2;
    bounds.width = closeButtonSize.x;
    bounds.height = closeButtonSize.y;
    return bounds;
  }
 
  private void paint(GC gc, Item item) {
    paintBackground(gc, item);
    paintImage(gc, item);
    paintText(gc, item);
    paintCloseButton(gc, item);
    paintFrame(gc, item);
  }

  private void paintBackground(GC gc, Item item) {
    Color old = gc.getBackground();
    Color neo = null;
   
    if (item.background != null) {
      neo = getColor(item.background);
      gc.setBackground(neo);
    }
   
    Rectangle bounds = item.getBounds();
    gc.fillRectangle(bounds);
   
    gc.setBackground(old);
   
    if (neo != null) {
      neo.dispose();
    }
  }

  private void paintImage(GC gc, Item item) {
    if (!item.hasImage()) {
      return;
    }
   
    Rectangle imageBounds = item.getImageBounds();
    gc.drawImage(item.getImage(), imageBounds.x, imageBounds.y);
  }

  private void paintText(GC gc, Item item) {
    if (!item.hasText()) {
      return;
    }

    Color old = gc.getForeground();
    Color neo = null;
   
    if (item.foreground != null) {
      neo = getColor(item.foreground);
      gc.setForeground(neo);
    }
   
    Rectangle textBounds = item.getTextBounds();
    gc.drawText(item.getText(), textBounds.x, textBounds.y, true);
   
    gc.setForeground(old);
   
    if (neo != null) {
      neo.dispose();
    }
  }

  private void paintCloseButton(GC gc, Item item) {
    Rectangle closeButtonBounds = item.getCloseButtonBounds();
    gc.drawImage(getCloseButtonImage(), closeButtonBounds.x, closeButtonBounds.y);
  }

  private void paintFrame(GC gc, Item item) {
    Rectangle bounds = item.getBounds();
    Color oldForeground = gc.getForeground();
    Color newForeground = getColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
    gc.setForeground(newForeground);
    gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
    gc.setForeground(oldForeground);
  }

  private Image getCloseButtonImage() {
    return UIImageResource.T.closeNormal10();
  }
 
  private Point getCloseButtonSize() {
    Rectangle closeButtonImageBounds = getCloseButtonImage().getBounds();
    return new Point(closeButtonImageBounds.width, closeButtonImageBounds.height);
  }

  private Color getColor(int id) {
    return getDisplay().getSystemColor(id);
  }
 
  private Color getColor(RGB rgb) {
    return new Color(getDisplay(), rgb);
  }
 
  public static void main(String[] args) {
    UI.initialize();
    Display display = Display.getDefault();
    Shell shell = new Shell(display);
    StripBar bar = new StripBar(shell, SWT.DOUBLE_BUFFERED);

    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 = GridData.FILL;
    data.verticalAlignment = GridData.FILL;
    data.grabExcessHorizontalSpace = true;
    bar.setLayoutData(data);
   
    Item item0 = new Item("item0");
    item0.setText("Item 0");
    item0.setImage(UIImageResource.T.about16());
   
    Item item1 = new Item("item1");
    item1.setText("Item 1");
   
    Item item2 = new Item("item2");
    item2.setImage(UIImageResource.T.addContact16());
   
    Item item3 = new Item("item3");
   
    bar.add(item0);
    bar.add(item1);
    bar.add(item2);
    bar.add(item3);
   
    shell.open();
   
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
   
    UI.destroy();
  }

}
TOP

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

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.