Package com.peterhi.ui.stripbar2

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

package com.peterhi.ui.stripbar2;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
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 StripBar extends Canvas implements Listener, PropertyChangeListener {

  public static final int SPACE = 5;
  private final List<StripItemController> controllers = new ArrayList<StripItemController>();
  private StripItemController hovered;
  private StripItemController pressed;
  private final Set<StripItemController> selected = new HashSet<StripItemController>();
 
  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);
      } else if (event.type == SWT.MouseEnter) {
        onMouseEnter(event);
      } else if (event.type == SWT.MouseExit) {
        onMouseExit(event);
      } else if (event.type == SWT.MouseDown) {
        onMouseDown(event);
      } else if (event.type == SWT.MouseMove) {
        onMouseMove(event);
      } else if (event.type == SWT.MouseUp) {
        onMouseUp(event);
      }
    }
  }

  @Override
  public void propertyChange(PropertyChangeEvent event) {
    if (event.getSource() instanceof StripItem) {
      if (event.getPropertyName().equals(StripItem.PROPID_TEXT)) {
        onItemTextChange(event);
      } else if (event.getPropertyName().equals(StripItem.PROPID_IMAGE)) {
        onItemImageChange(event);
      }
    }
  }

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

  public boolean add(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }

    StripItemController controller = new StripItemController(item);
   
    if (controllers.contains(controller)) {
      return false;
    }
   
    if (controllers.add(controller)) {
      onAdd(controller);
      return true;
    }

    return false;
  }
 
  public boolean add(StripItem item, int index) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    StripItemController controller = new StripItemController(item);
   
    if (controllers.contains(controller)) {
      return false;
    }
   
    controllers.add(index, controller);
    onAdd(controller);
    return true;
  }
 
  public boolean remove(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    StripItemController controller = new StripItemController(item);
   
    if (controllers.remove(controller)) {
      onRemove(controller);
      return true;
    }

    return false;
  }
 
  public StripItem remove(int index) {
    StripItemController controller = controllers.remove(index);
    onRemove(controller);
    return controller.getItem();
  }
 
  public int size() {
    return controllers.size();
  }
 
  public StripItem get(int index) {
    return controllers.get(index).getItem();
  }
 
  public StripItem get(int x, int y) {
    StripItemController controller = getControllerAt(x, y);
   
    if (controller == null) {
      return null;
    }
   
    return controller.getItem();
  }
 
  public int indexOf(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }

    for (int i = 0; i < controllers.size(); i++) {
      StripItemController controller = controllers.get(i);
     
      if (controller.getItem().equals(item)) {
        return i;
      }
    }

    return -1;
  }
 
  public boolean contains(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    for (StripItemController controller : controllers) {
      if (controller.getItem().equals(item)) {
        return true;
      }
    }

    return false;
  }
 
  public StripItem[] toArray() {
    List<StripItem> items = new ArrayList<StripItem>();
   
    for (StripItemController controller : controllers) {
      items.add(controller.getItem());
    }
   
    return items.toArray(new StripItem[items.size()]);
  }
 
  public Rectangle getBounds(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!contains(item)) {
      throw new IllegalArgumentException();
    }
   
    Rectangle bounds = new Rectangle(SPACE, SPACE, 0, 0);

    for (StripItemController aController : controllers) {
      if (hasImage(aController.getItem())) {
        bounds.height = Math.max(bounds.height, getImageSize(aController.getItem()).y);
      }
     
      if (hasText(aController.getItem())) {
        bounds.height = Math.max(bounds.height, getTextSize(aController.getItem()).y);
      }
     
      bounds.height = Math.max(bounds.height, getCloseButtonSize().y);
    }
   
    bounds.height += SPACE * 2;
   
    for (StripItemController aController : controllers) {
      int extent = SPACE;
     
      if (hasImage(aController.getItem())) {
        extent += getImageSize(aController.getItem()).x;
        extent += SPACE;
      }
     
      if (hasText(aController.getItem())) {
        extent += getTextSize(aController.getItem()).x;
        extent += SPACE;
      }
     
      extent += getCloseButtonSize().x;
      extent += SPACE;
     
      if (aController.getItem().equals(item)) {
        bounds.width = extent;
        break;
      } else {
        bounds.x += extent;
        bounds.x += SPACE;
      }
    }
   
    return bounds;
  }
 
  public boolean hasImage(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }

    return item.getImage() != null;
  }
 
  public Point getImageSize(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (!hasImage(item)) {
      return new Point(0, 0);
    }
   
    Rectangle imageBounds = item.getImage().getBounds();
    Point imageSize = new Point(imageBounds.width, imageBounds.height);
    return imageSize;
  }
 
  public Rectangle getImageBounds(StripItem item) {
    Rectangle bounds = getBounds(item);
    bounds.y += bounds.height / 2;
    bounds.width = 0;
    bounds.height = 0;
   
    if (hasImage(item)) {
      Point imageSize = getImageSize(item);
      bounds.x += SPACE;
      bounds.y -= imageSize.y / 2;
      bounds.width = imageSize.x;
      bounds.height = imageSize.y;
    }
   
    return bounds;
  }
 
  public boolean hasText(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (item.getText() == null) {
      return false;
    }
   
    if (item.getText().isEmpty()) {
      return false;
    }
   
    return true;
  }
 
  public Point getTextSize(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }

    if (!hasText(item)) {
      return new Point(0, 0);
    }
   
    GC gc = new GC(this);
    Point textSize = gc.stringExtent(item.getText());
    gc.dispose();
    return textSize;
  }
 
  public Rectangle getTextBounds(StripItem item) {
    Rectangle bounds = getImageBounds(item);
    bounds.x += bounds.width;
    bounds.y += bounds.height / 2;
    bounds.width = 0;
    bounds.height = 0;
   
    if (hasText(item)) {
      Point textSize = getTextSize(item);
      bounds.x += SPACE;
      bounds.y -= textSize.y / 2;
      bounds.width = textSize.x;
      bounds.height = textSize.y;
    }
   
    return bounds;
  }
 
  public Image getCloseButtonImage() {
    return UIImageResource.T.closeNormal10();
  }
 
  public Point getCloseButtonSize() {
    Image closeButtonImage = getCloseButtonImage();
    Rectangle closeButtonBounds = closeButtonImage.getBounds();
    Point closeButtonSize = new Point(closeButtonBounds.width, closeButtonBounds.height);
    return closeButtonSize;
  }
 
  public Rectangle getCloseButtonBounds(StripItem item) {
    Point closeButtonSize = getCloseButtonSize();
    Rectangle bounds = getTextBounds(item);
    bounds.x += bounds.width + SPACE;
    bounds.y += bounds.height / 2 - closeButtonSize.y / 2;
    bounds.width = closeButtonSize.x;
    bounds.height = closeButtonSize.y;
    return bounds;
  }
 
  public boolean isHovered() {
    return getHoveredItem() != null;
  }
 
  public boolean isHovered(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (hovered == null) {
      return false;
    }
   
    return hovered.getItem().equals(item);
  }
 
  public StripItem getHoveredItem() {
    if (hovered == null) {
      return null;
    }
   
    return hovered.getItem();
  }
 
  public boolean isPressed() {
    return getPressedItem() != null;
  }
 
  public boolean isPressed(StripItem item) {
    if (item == null) {
      throw new NullPointerException();
    }
   
    if (pressed == null) {
      return false;
    }
   
    return pressed.getItem().equals(item);
  }
 
  public StripItem getPressedItem() {
    if (pressed == null) {
      return null;
    }

    return pressed.getItem();
  }
 
  public boolean isSelected(StripItem item) {
    for (StripItemController controller : selected) {
      if (controller.getItem().equals(item)) {
        return true;
      }
    }
   
    return false;
  }
 
  public StripItem[] getSelectedItems() {
    List<StripItem> items = new ArrayList<StripItem>();
   
    for (StripItemController controller : selected) {
      items.add(controller.getItem());
    }
   
    return items.toArray(new StripItem[items.size()]);
  }
 
  public boolean isMulti() {
    int style = getStyle();
    boolean multi = (style & SWT.MULTI) == SWT.MULTI;
    return multi;
  }
 
  protected StripItemController getControllerAt(int x, int y) {
    for (StripItemController controller : controllers) {
      if (getBounds(controller.getItem()).contains(x, y)) {
        return controller;
      }
    }
   
    return null;
  }
 
  protected void onAdd(StripItemController controller) {
    if (controller == null) {
      throw new NullPointerException();
    }
   
    controller.getItem().addPropertyChangeListener(this);
  }
 
  protected void onRemove(StripItemController controller) {
    if (controller == null) {
      throw new NullPointerException();
    }
   
    controller.getItem().removePropertyChangeListener(this);
   
    if (controller.equals(hovered)) {
      hovered = null;
    }
   
    if (controller.equals(pressed)) {
      pressed = null;
    }

    selected.remove(controller);
  }
 
  protected void onPaint(Event event) {
    for (StripItemController controller : controllers) {
      paint(event.gc, controller);
    }
  }
 
  protected void onMouseEnter(Event event) {
    performHover(event.x, event.y);
  }

  protected void onMouseExit(Event event) {
    performHover(event.x, event.y);
  }

  protected void onMouseDown(Event event) {
    performPress(event.x, event.y);
  }

  protected void onMouseMove(Event event) {
    performHover(event.x, event.y);
  }

  protected void onMouseUp(Event event) {
    performSelect(event.x, event.y);
  }
 
  protected void onItemTextChange(PropertyChangeEvent event) {
    redraw();
  }
 
  protected void onItemImageChange(PropertyChangeEvent event) {
    redraw();
  }
 
  private void performHover(int x, int y) {
    StripItemController old = hovered;
    StripItemController neo = getControllerAt(x, y);
   
    if (RT.equals(old, neo)) {
      return;
    }
   
    if (old != null && !isPressed() && !isSelected(old.getItem())) {
      if (!old.hasBackground()) {
        old.setForeground(StripItemState.HOVERED.getForeground());
        old.setBackground(StripItemState.HOVERED.getBackground());
      }
     
      animBackgroundChange(old, old.getBackground(), StripItemState.NONE.getBackground());
    }
   
    if (neo != null && !isPressed() && !isSelected(neo.getItem())) {
      if (!neo.hasBackground()) {
        neo.setForeground(StripItemState.NONE.getForeground());
        neo.setBackground(StripItemState.NONE.getBackground());
      }
     
      animBackgroundChange(neo, neo.getBackground(), StripItemState.HOVERED.getBackground());
    }
   
    if (!isPressed()) {
      hovered = neo;
    }
  }
 
  private void performPress(int x, int y) {
    StripItemController old = pressed;
    StripItemController neo = getControllerAt(x, y);
   
    if (RT.equals(old, neo)) {
      return;
    }
   
    if (selected.contains(neo)) {
      return;
    }
   
    if (old != null) {
      old.setForeground(StripItemState.NONE.getForeground());
      old.setBackground(StripItemState.NONE.getBackground());
      repaint(old);
    }
   
    if (neo != null) {
      neo.setForeground(StripItemState.PRESSED.getForeground());
      neo.setBackground(StripItemState.PRESSED.getBackground());
      repaint(neo);
    }

    pressed = neo;
  }
 
  private void performSelect(int x, int y) {
    if (pressed == null) {
      return;
    }
   
    if (!isMulti()) {
      for (StripItemController controller : selected) {
        controller.setForeground(StripItemState.NONE.getForeground());
       
        if (!controller.hasBackground()) {
          controller.setBackground(StripItemState.SELECTED.getBackground());
        }
       
        animBackgroundChange(controller, controller.getBackground(), StripItemState.NONE.getBackground());
      }
     
      selected.clear();
    }

    if (isSelected(pressed.getItem())) {
      if (selected.remove(pressed)) {
        pressed.setForeground(StripItemState.HOVERED.getForeground());
        pressed.setBackground(StripItemState.HOVERED.getBackground());
      } else {
        pressed.setForeground(StripItemState.SELECTED.getForeground());
        pressed.setBackground(StripItemState.SELECTED.getBackground());
      }
    } else {
      if (selected.add(pressed)) {
        pressed.setForeground(StripItemState.SELECTED.getForeground());
        pressed.setBackground(StripItemState.SELECTED.getBackground());
      } else {
        pressed.setForeground(StripItemState.HOVERED.getForeground());
        pressed.setBackground(StripItemState.HOVERED.getBackground());
      }
    }
   
    repaint(pressed);
    pressed = null;
  }
 
  private void animBackgroundChange(final StripItemController controller, final RGB from, final RGB to) {
    if (controller.hasAnimator()) {
      controller.getAnimator().cancel();
      controller.setAnimator(null);
    }
   
    TimingTarget tt = new TimingTargetAdapter() {
      @Override
      public void timingEvent(Animator source, double fraction) {
        double r = to.red - from.red;
        double g = to.green - from.green;
        double b = to.blue - from.blue;
       
        r *= fraction;
        g *= fraction;
        b *= fraction;
       
        r += from.red;
        g += from.green;
        b += from.blue;
       
        controller.setBackground(new RGB((int )r, (int )g, (int )b));
        repaint(controller);
      }

      @Override
      public void end(Animator source) {
        controller.setBackground(to);
        repaint(controller);
      }
    };
   
    Animator animator = new Animator.Builder().addTarget(tt).setDuration(100, TimeUnit.MILLISECONDS).build();
    controller.setAnimator(animator);
    animator.start();
  }
 
  private void repaint(StripItemController controller) {
    if (controller == null) {
      throw new NullPointerException();
    }
   
    Rectangle bounds = getBounds(controller.getItem());
    redraw(bounds.x, bounds.y, bounds.width, bounds.height, true);
  }
 
  private void paint(GC gc, StripItemController controller) {
    paintBackground(gc, controller);
    paintImage(gc, controller);
    paintText(gc, controller);
    paintCloseButton(gc, controller);
    paintFrame(gc, controller);
  }
 
  private void paintBackground(GC gc, StripItemController controller) {
    if (!controller.hasBackground()) {
      return;
    }
   
    Color old = gc.getBackground();
    Color neo = null;
   
    if (controller.getBackground() != null) {
      neo = newColor(controller.getBackground());
      gc.setBackground(neo);
    }
   
    Rectangle bounds = getBounds(controller.getItem());
    gc.fillRectangle(bounds);
   
    gc.setBackground(old);
   
    if (neo != null) {
      neo.dispose();
    }
  }

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

  private void paintText(GC gc, StripItemController controller) {
    if (!hasText(controller.getItem())) {
      return;
    }
   
    Color old = gc.getForeground();
    Color neo = null;
   
    if (controller.getForeground() != null) {
      neo = newColor(controller.getForeground());
      gc.setForeground(neo);
    }
   
    Rectangle textBounds = getTextBounds(controller.getItem());
    gc.drawText(controller.getItem().getText(), textBounds.x, textBounds.y, true);

    gc.setForeground(old);
   
    if (neo != null) {
      neo.dispose();
    }
  }

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

  private void paintFrame(GC gc, StripItemController controller) {
    Rectangle bounds = getBounds(controller.getItem());
    Color old = gc.getForeground();
    Color neo = getColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
    gc.setForeground(neo);
    gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
    gc.setForeground(old);
  }
 
  private Color getColor(int id) {
    Display display = getDisplay();
    return display.getSystemColor(id);
  }
 
  private Color newColor(RGB rgb) {
    if (rgb == null) {
      throw new NullPointerException();
    }
   
    Display display = getDisplay();
    return new Color(display, 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 = SWT.FILL;
    data.verticalAlignment = SWT.FILL;
    data.grabExcessHorizontalSpace = true;
    bar.setLayoutData(data);
   
    StripItem item0 = new StripItem("item0");
    StripItem item1 = new StripItem("item1");
    StripItem item2 = new StripItem("item2");
    StripItem item3 = new StripItem("item3");
   
    item0.setText("Item 0");
    item1.setText("Item 1");
    item0.setImage(UIImageResource.T.about16());
    item2.setImage(UIImageResource.T.addContact16());
   
    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.stripbar2.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.