X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Felementclass%2Fslider%2FSliderHandle.java;fp=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Felementclass%2Fslider%2FSliderHandle.java;h=7b0d36775836a7389d8e06c97bfdf2a0483961ec;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/elementclass/slider/SliderHandle.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/elementclass/slider/SliderHandle.java new file mode 100644 index 000000000..7b0d36775 --- /dev/null +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/elementclass/slider/SliderHandle.java @@ -0,0 +1,361 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * 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: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.g2d.elementclass.slider; + +import java.awt.Graphics2D; +import java.awt.geom.Line2D; +import java.awt.geom.Path2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.diagram.participant.DiagramParticipant; +import org.simantics.g2d.element.ElementHints; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.SceneGraphNodeKey; +import org.simantics.g2d.element.handler.SceneGraph; +import org.simantics.g2d.element.handler.Stateful; +import org.simantics.g2d.element.handler.impl.AbstractGrabbable; +import org.simantics.scenegraph.Node; +import org.simantics.scenegraph.g2d.G2DNode; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.scenegraph.g2d.events.MouseEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; + +/** + * + * TODO set Track Rectangle + * @author Toni Kalajainen + */ +public class SliderHandle extends AbstractGrabbable implements SceneGraph { + + private static final long serialVersionUID = 3632511991491704966L; + public static final Key KEY_SLIDER_COLOR_PROFILE = new KeyOf(SliderColorProfile.class); + /** Grab position of handle in terms of element coordinates */ + public static final Key KEY_SLIDER_POSITION = ElementHints.KEY_VALUE; + public static final Key KEY_SLIDER_MIN_VALUE = ElementHints.KEY_MIN_VALUE; + public static final Key KEY_SLIDER_MAX_VALUE = ElementHints.KEY_MAX_VALUE; + public static final SliderHandle INSTANCE = new SliderHandle(); + + public Key positionKey = KEY_SLIDER_POSITION; + + public static final Key SG_NODE = new SceneGraphNodeKey(Node.class, "SUB_SG_NODE"); + + public SliderHandle() { + super(1000.0); + } + private final static Key KEY_HANDLE_GRAB_POS = new KeyOf(Double.class); + + @Override + public void cleanup(IElement e) { + Node node = e.removeHint(SG_NODE); + if (node != null) + node.remove(); + } + + @Override + public void init(IElement e, G2DParentNode parent) { + CustomSliderNode node = (CustomSliderNode) e.getHint(SG_NODE); + if (node == null) { + node = parent.addNode(CustomSliderNode.class); + e.setHint(SG_NODE, node); + } + + SliderColorProfile colors = e.getHint(KEY_SLIDER_COLOR_PROFILE); + Rectangle2D rect = getBounds(e); + boolean enabled = isEnabled(e); + + double handleWidth = getHandleWidth(e); + double handleOffset = getHandleOffset(e); + + // FIXME: handleOffset is probably never updated.. + node.init(rect, enabled, colors, handleWidth, handleOffset); + } + + public static class CustomSliderNode extends G2DNode { + /** + * + */ + private static final long serialVersionUID = 1423400213815428725L; + Rectangle2D rect = null; + boolean enabled = false; + SliderColorProfile colors = null; + double handleWidth = 0; + double handleOffset = 0; + + @Override + public Rectangle2D getBoundsInLocal() { + return rect; + } + + public void init(Rectangle2D rect, boolean enabled, SliderColorProfile colors, double handleWidth, double handleOffset) { + this.rect = rect; + this.enabled = enabled; + this.colors = colors; + this.handleWidth = handleWidth; + this.handleOffset = handleOffset; + } + + @Override + public void render(Graphics2D g) { + double height = rect.getHeight(); + Rectangle2D r = new Rectangle2D.Double(); + Line2D l = new Line2D.Double(); + + height = height + 1; + + g.translate(rect.getMinX(), rect.getMinY()); + g.translate(handleOffset, 0); + + g.setColor((enabled?colors.HANDLE4:colors.DISABLED_HANDLE4)); + r.setFrame(1, 1, handleWidth-3, height-3); + g.fill(r); + + g.setColor((enabled?colors.HANDLE3:colors.DISABLED_HANDLE3)); + l.setLine(2, 1, handleWidth-3, 1); + g.draw(l); + l.setLine(1, 2, 1, height-3); + g.draw(l); + + g.setColor((enabled?colors.HANDLE5:colors.DISABLED_HANDLE5)); + l.setLine(2, height-2, handleWidth-3, height-2); + g.draw(l); + l.setLine(handleWidth-2, 2, handleWidth-2, height-3); + g.draw(l); + + g.setColor((enabled?colors.HANDLE2:colors.DISABLED_HANDLE2)); + Path2D p = new Path2D.Double(); + p.moveTo(0, 2); + p.lineTo(2, 0); + p.lineTo(handleWidth-3, 0); + p.lineTo(handleWidth-1, 2); + p.lineTo(handleWidth-1, height-3); + p.lineTo(handleWidth-3, height-1); + p.lineTo(2, height-1); + p.lineTo(0, height-3); + p.lineTo(0, 2); + p.closePath(); + g.draw(p); + + // Paint scratches (lines) on the handle + if (handleWidth>height) + { + g.translate((handleWidth-height)/2, 0); + + g.setColor((enabled?colors.HANDLE8:colors.DISABLED_HANDLE8)); + g.drawLine((int) ((height)*0.2), (int) ((height)*0.55)+1, (int) ((height)*0.4), (int) ((height)*0.35)+1); + g.setColor((enabled?colors.HANDLE7:colors.DISABLED_HANDLE7)); + g.drawLine((int) ((height)*0.2), (int) ((height)*0.55), (int) ((height)*0.4), (int) ((height)*0.35)); + + g.setColor((enabled?colors.HANDLE8:colors.DISABLED_HANDLE8)); + g.drawLine((int) ((height)*0.40), (int) ((height)*0.60)+1, (int) ((height)*0.65), (int) ((height)*0.30)+1); + g.setColor((enabled?colors.HANDLE7:colors.DISABLED_HANDLE7)); + g.drawLine((int) ((height)*0.40), (int) ((height)*0.60), (int) ((height)*0.65), (int) ((height)*0.30)); + + g.setColor((enabled?colors.HANDLE8:colors.DISABLED_HANDLE8)); + g.drawLine((int) ((height)*0.62), (int) ((height)*0.60)+1, (int) ((height)*0.8), (int) ((height)*0.40)+1); + g.setColor((enabled?colors.HANDLE7:colors.DISABLED_HANDLE7)); + g.drawLine((int) ((height)*0.62), (int) ((height)*0.60), (int) ((height)*0.8), (int) ((height)*0.40)); + } + } + } + + @Override + protected boolean onGrabCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos) { + // 1. Must be enabled + if (!isEnabled(e)) return false; + + // 2. Grab must hit the handle + Point2D mouseElementPos = ElementUtils.controlToElementCoordinate(e, ctx, pickPos, null); + Rectangle2D bounds = getBounds(e); + if (!bounds.contains(mouseElementPos)) return false; + + double x = mouseElementPos.getX() - bounds.getMinX(); + double y = mouseElementPos.getY() - bounds.getMinY(); + + double handleOffset = getHandleOffset(e); + double handleWidth = getHandleWidth(e); + boolean pointerOnHandle = (x>=handleOffset && x<=handleOffset+handleWidth); + //boolean pointerInBeginning = x < handleOffset; + if (!pointerOnHandle) return false; + + // 3. Only one pointer may grab + if (getGrabCount(e, ctx)>1) return false; + + // Everything checks --> OK + return true; + } + + @Override + protected void onDrag(GrabInfo gi, ICanvasContext ctx) { + IElement e = gi.e; + DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class); + Rectangle2D bounds = getBounds(e); + double grabPosOnHandle = dp.getElementHint(gi.e, KEY_HANDLE_GRAB_POS); + + // Get track length + double trackWidth = getTrackWidth(e); + // Get handle legnth + double handleWidth = getHandleWidth(e); + // Free space on the track == track - handle + double varaa = trackWidth - handleWidth+1; + // Where are we suggesting where the handle offset should be? (widget coordinates) + double suggestedHandlePos = gi.dragPosElement.getX()-grabPosOnHandle; + // widget coordinates -> offset 0..1 + double suggestedOffset = (suggestedHandlePos) /varaa; + // 0..1 -> min..max + double min = e.getHint(KEY_SLIDER_MIN_VALUE); + double max = e.getHint(KEY_SLIDER_MAX_VALUE); + double suggestedPosition = (suggestedOffset * (max-min))+min; + setPosition(e, suggestedPosition); + } + + /** + * Handle click on track + */ + @Override + public boolean handleMouseEvent(IElement e, ICanvasContext ctx, MouseEvent me) { + boolean superResult = super.handleMouseEvent(e, ctx, me); + if (superResult) return superResult; + if (!(me instanceof MouseClickEvent)) return false; + MouseClickEvent mpe = (MouseClickEvent) me; + if (mpe.button != MouseEvent.LEFT_BUTTON) return false; + + // 1. Grab must hit the handle + Point2D mouseElementPos = ElementUtils.controlToElementCoordinate(e, ctx, me.controlPosition, null); + Rectangle2D rect = getBounds(e); + double mx = mouseElementPos.getX(); + double my = mouseElementPos.getY(); + boolean onTrackRect = rect.contains(mx, my); + if (!onTrackRect) return false; + mx -= rect.getMinX(); + my -= rect.getMinY(); + + double trackWidth = getTrackWidth(e); + double handleOffset = getHandleOffset(e); + double handleWidth = getHandleWidth(e); + boolean pointerOnHandle = (mx>=handleOffset && mx<=handleOffset+handleWidth); + boolean pointerInBeginning = mx < handleOffset; + if (pointerOnHandle) return false; + + double min = e.getHint(KEY_SLIDER_MIN_VALUE); + double max = e.getHint(KEY_SLIDER_MAX_VALUE); + double pageIncrement = (max-min) / (trackWidth/handleWidth); + if (!pointerInBeginning) pageIncrement *= -1; + modifyPosition(e, -pageIncrement); + + return true; + } + + @Override + protected void onGrab(GrabInfo gi, ICanvasContext ctx) { + double handlePos = getHandleOffset(gi.e); + double grabPosOnHandle = gi.grabPosElement.getX() - handlePos; + DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class); + dp.setElementHint(gi.e, KEY_HANDLE_GRAB_POS, grabPosOnHandle); + } + + @Override + protected void onGrabCancel(GrabInfo gi, ICanvasContext ctx) { + DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class); + dp.removeElementHint(gi.e, KEY_HANDLE_GRAB_POS); + } + + @Override + protected void onRelease(GrabInfo gi, ICanvasContext ctx) { + DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class); + dp.removeElementHint(gi.e, KEY_HANDLE_GRAB_POS); + } + + public synchronized void modifyPosition(IElement e, double modification) { + Double position = e.getHint(positionKey); + if (position==null) position = 0.0; + double newPosition = position + modification; + setPosition(e, newPosition); + } + + public synchronized void setPosition(IElement e, double position) { + double min = e.getHint(KEY_SLIDER_MIN_VALUE); + double max = e.getHint(KEY_SLIDER_MAX_VALUE); + if (positionmax) position = max; + e.setHint(positionKey, position); + } + + public double getPosition(IElement e) + { + Double d = e.getHint(positionKey); + if (d==null) return 0.0; + return d; + } + + private double getHandleOffset(IElement e) + { + double position = getPosition(e); + + double min = e.getHint(KEY_SLIDER_MIN_VALUE); + double max = e.getHint(KEY_SLIDER_MAX_VALUE); + double width = getTrackWidth(e); + double handleWidth = _calcHandleLength(width, min, max); + + return _calcHandleOffset(width, handleWidth, position, min, max); + } + + protected double getHandleWidth(IElement e) + { + double min = e.getHint(KEY_SLIDER_MIN_VALUE); + double max = e.getHint(KEY_SLIDER_MAX_VALUE); + double width = getTrackWidth(e); + return _calcHandleLength(width, min, max); + } + + private double getTrackWidth(IElement e) + { + return getBounds(e).getWidth(); + } + + /** + * Calculates the offset of the handle in element coordinates + * @return offset of the handle in element coordinates + */ + private static double _calcHandleOffset(double trackLength, double handleLength, double position, double min, double max) + { + double varaa = trackLength - handleLength+1; + double relativePos = ((position-min))/(max-min); + return varaa * relativePos; + } + + /** + * Calculate the length of the handle + */ + private static double _calcHandleLength(double width, double min, double max) + { + double len = width / ((max-min)+1); + if (len<28) len = 28; + return len; + } + + public boolean isEnabled(IElement e) { + Stateful enabled = e.getElementClass().getAtMostOneItemOfClass(Stateful.class); + if (enabled==null) return true; + return enabled.isEnabled(e); + } + + protected Rectangle2D getBounds(IElement e) + { + return ElementUtils.getElementBounds(e); + } + +}