package com.itmill.toolkit.terminal.gwt.client.ui;\r
\r
-import java.util.HashSet;\r
-\r
import com.google.gwt.user.client.DOM;\r
import com.google.gwt.user.client.Element;\r
import com.google.gwt.user.client.Event;\r
import com.google.gwt.user.client.Timer;\r
-import com.google.gwt.user.client.ui.MouseListener;\r
-import com.google.gwt.user.client.ui.SourcesMouseEvents;\r
import com.google.gwt.user.client.ui.Widget;\r
import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;\r
import com.itmill.toolkit.terminal.gwt.client.Paintable;\r
private boolean readonly;\r
\r
private int handleSize;\r
- private float min;\r
- private float max;\r
+ private double min;\r
+ private double max;\r
private int resolution;\r
- private Object value;\r
- private HashSet values;\r
+ private Double value;\r
private boolean vertical;\r
private int size = -1;\r
+ private boolean arrows;\r
\r
/* DOM element for slider's base */\r
private Element base;\r
/* DOM element for slider's handle */\r
private Element handle;\r
\r
- private boolean dragging;\r
+ /* DOM element for decrement arrow */\r
+ private Element smaller;\r
+ \r
+ /* DOM element for increment arrow */\r
+ private Element bigger;\r
+ \r
+ /* Temporary dragging/animation variables */\r
+ private boolean dragging = false;\r
+ private Timer anim;\r
\r
public ISlider() {\r
super();\r
- setElement(DOM.createElement("div"));\r
- base = DOM.createElement("div");\r
- DOM.appendChild(getElement(), base);\r
- handle = DOM.createElement("div");\r
- DOM.appendChild(base, handle);\r
+ \r
+ setElement(DOM.createDiv());\r
+ base = DOM.createDiv();\r
+ handle = DOM.createDiv();\r
+ smaller = DOM.createDiv();\r
+ bigger = DOM.createDiv();\r
+ \r
setStyleName(CLASSNAME);\r
DOM.setAttribute(base, "className", CLASSNAME+"-base");\r
DOM.setAttribute(handle, "className", CLASSNAME+"-handle");\r
+ DOM.setAttribute(smaller, "className", CLASSNAME+"-smaller");\r
+ DOM.setAttribute(bigger, "className", CLASSNAME+"-bigger");\r
+ \r
+ DOM.appendChild(getElement(), bigger);\r
+ DOM.appendChild(getElement(), smaller);\r
+ DOM.appendChild(getElement(), base);\r
+ DOM.appendChild(base, handle);\r
+ \r
+ // Hide initially\r
+ DOM.setStyleAttribute(smaller, "display", "none");\r
+ DOM.setStyleAttribute(bigger, "display", "none");\r
\r
- DOM.sinkEvents(base, Event.MOUSEEVENTS);\r
+ DOM.sinkEvents(base, Event.ONMOUSEDOWN);\r
DOM.sinkEvents(handle, Event.MOUSEEVENTS);\r
+ DOM.sinkEvents(smaller, Event.ONMOUSEDOWN);\r
+ DOM.sinkEvents(bigger, Event.ONMOUSEDOWN);\r
}\r
\r
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
readonly = uidl.getBooleanAttribute("readonly");\r
\r
vertical = uidl.hasAttribute("vertical");\r
+ arrows = uidl.hasAttribute("arrows");\r
+ \r
+ if(arrows) {\r
+ DOM.setStyleAttribute(smaller, "display", "block");\r
+ DOM.setStyleAttribute(bigger, "display", "block");\r
+ if(vertical) {\r
+ int arrowSize = Integer.parseInt(DOM.getAttribute(smaller, "offsetWidth"));\r
+ DOM.setStyleAttribute(bigger, "marginLeft", arrowSize+"px");\r
+ DOM.setStyleAttribute(bigger, "marginRight", arrowSize+"px");\r
+ }\r
+ }\r
\r
if(vertical)\r
addStyleName(CLASSNAME+"-vertical");\r
else\r
removeStyleName(CLASSNAME+"-vertical");\r
\r
- if(uidl.hasAttribute("values")) {\r
- values = uidl.getStringArrayAttributeAsSet("values");\r
- value = uidl.getStringVariable("value");\r
- } else {\r
- min = uidl.getLongAttribute("min");\r
- max = uidl.getLongAttribute("max");\r
- resolution = uidl.getIntAttribute("resolution");\r
- value = new Float(uidl.getFloatVariable("value"));\r
- values = null;\r
- }\r
+ min = uidl.getDoubleAttribute("min");\r
+ max = uidl.getDoubleAttribute("max");\r
+ resolution = uidl.getIntAttribute("resolution");\r
+ value = new Double(uidl.getDoubleVariable("value"));\r
\r
handleSize = uidl.getIntAttribute("hsize");\r
\r
Timer delay = new Timer() {\r
public void run() {\r
buildHandle();\r
- setHandlePosition(value);\r
+ setValue(value, true);\r
}\r
};\r
delay.schedule(100);\r
} else {\r
buildHandle();\r
- setHandlePosition(value);\r
+ setValue(value, true);\r
}\r
}\r
\r
} else {\r
if(size > -1)\r
DOM.setStyleAttribute(base, "width", size + "px");\r
- else DOM.setStyleAttribute(base, "width", "100%");\r
+ else {\r
+ Element p = DOM.getParent(getElement());\r
+ if(Integer.parseInt(DOM.getAttribute(p, "offsetWidth")) > 50)\r
+ DOM.setStyleAttribute(base, "width", "auto");\r
+ else {\r
+ // Set minimum of 50px width and adjust after all \r
+ // components have (supposedly) been drawn completely.\r
+ DOM.setStyleAttribute(base, "width", "50px");\r
+ Timer adjust = new Timer() {\r
+ public void run() {\r
+ Element p = DOM.getParent(getElement());\r
+ if(Integer.parseInt(DOM.getAttribute(p, "offsetWidth")) > 50)\r
+ DOM.setStyleAttribute(base, "width", "auto");\r
+ }\r
+ };\r
+ adjust.schedule(100);\r
+ }\r
+ }\r
}\r
// Allow absolute positioning of handle\r
DOM.setStyleAttribute(base, "position", "relative");\r
int t = Integer.parseInt(DOM.getAttribute(base, "offsetHeight")) - Integer.parseInt(DOM.getAttribute(handle, "offsetHeight"));\r
DOM.setStyleAttribute(handle, "top", (t/2)+"px");\r
DOM.setStyleAttribute(handle, "left", "0px");\r
- int w = (int) (Float.parseFloat(DOM.getAttribute(base, "offsetWidth")) / 100 * handleSize);\r
+ int w = (int) (Double.parseDouble(DOM.getAttribute(base, "offsetWidth")) / 100 * handleSize);\r
DOM.setStyleAttribute(handle, "width", w+"px");\r
}\r
\r
}\r
\r
- private void setHandlePosition(Object value) {\r
+ private void setValue(Double value, boolean animate) {\r
if(vertical) {\r
// TODO\r
} else {\r
- if(values == null) {\r
- int handleWidth = Integer.parseInt(DOM.getAttribute(handle, "offsetWidth"));\r
- int baseWidth = Integer.parseInt(DOM.getAttribute(base, "offsetWidth"));\r
- int range = baseWidth - handleWidth;\r
- float v = ((Float)value).floatValue();\r
- float valueRange = max - min;\r
- float pos = range * ((v - min) / valueRange);\r
- DOM.setStyleAttribute(handle, "left", pos+"px");\r
- DOM.setAttribute(handle, "title", ""+v);\r
- }\r
+ int handleWidth = Integer.parseInt(DOM.getAttribute(handle, "offsetWidth"));\r
+ int baseWidth = Integer.parseInt(DOM.getAttribute(base, "offsetWidth"));\r
+ int range = baseWidth - handleWidth;\r
+ double v = value.doubleValue();\r
+ double valueRange = max - min;\r
+ final double pos = range * ((v - min) / valueRange);\r
+ \r
+ String styleLeft = DOM.getStyleAttribute(handle, "left");\r
+ int left = Integer.parseInt(styleLeft.substring(0, styleLeft.length()-2));\r
+\r
+ if((int)pos != left && animate) {\r
+ if(anim != null)\r
+ anim.cancel();\r
+ anim = new Timer() {\r
+ private int left;\r
+ private int goal = (int)pos;\r
+ private int dir = 0;\r
+ public void run() {\r
+ String styleLeft = DOM.getStyleAttribute(handle, "left");\r
+ left = Integer.parseInt(styleLeft.substring(0, styleLeft.length()-2));\r
+ \r
+ // Determine direction\r
+ if(dir == 0)\r
+ dir = (goal-left)/Math.abs(goal-left);\r
+ \r
+ if((dir > 0 && left >= goal) || (dir < 0 && left <= goal)) {\r
+ this.cancel();\r
+ return;\r
+ }\r
+ int increment = (goal - left) / 2;\r
+ DOM.setStyleAttribute(handle, "left", (left+increment)+"px");\r
+ }\r
+ };\r
+ anim.scheduleRepeating(50);\r
+ } else DOM.setStyleAttribute(handle, "left", pos+"px");\r
+ DOM.setAttribute(handle, "title", ""+v);\r
}\r
+ \r
this.value = value;\r
}\r
\r
public void onBrowserEvent(Event event) {\r
- if(dragging || DOM.compare(DOM.eventGetTarget(event), handle))\r
+ Element targ = DOM.eventGetTarget(event);\r
+ if(dragging || DOM.compare(targ, handle)) {\r
processHandleEvent(event);\r
- else\r
+ } else if(DOM.compare(targ, smaller)) {\r
+ if(DOM.eventGetType(event) == Event.ONMOUSEDOWN)\r
+ decrease();\r
+ } else if(DOM.compare(targ, bigger)) {\r
+ if(DOM.eventGetType(event) == Event.ONMOUSEDOWN)\r
+ increase();\r
+ } else {\r
processBaseEvent(event);\r
+ }\r
}\r
\r
private void processHandleEvent(Event event) {\r
switch (DOM.eventGetType(event)) {\r
case Event.ONMOUSEDOWN:\r
- client.console.log("Slider handle: mousedown");\r
if(!disabled && !readonly) {\r
+ anim.cancel();\r
dragging = true;\r
DOM.setCapture(handle);\r
DOM.eventPreventDefault(event); // prevent selecting text\r
+ DOM.eventCancelBubble(event, true);\r
}\r
break;\r
case Event.ONMOUSEMOVE:\r
if (dragging) {\r
- int x = DOM.eventGetClientX(event);\r
- int y = DOM.eventGetClientY(event);\r
- if(vertical) {\r
- // TODO\r
- } else {\r
- if(values == null) {\r
- client.console.log("Slider handle: dragging..." + x);\r
- float handleW = Integer.parseInt(DOM.getAttribute(handle, "offsetWidth"));\r
- float baseX = DOM.getAbsoluteLeft(base);\r
- float baseW = Integer.parseInt(DOM.getAttribute(base, "offsetWidth"));\r
- float v = ((x-baseX)/(baseW-baseX)) * (max-min) + min;\r
- if(resolution > 0) {\r
- setHandlePosition(new Float(v));\r
- } else\r
- setHandlePosition(new Float((int)v));\r
- } else {\r
- // TODO\r
- }\r
- }\r
+ setValueByEvent(event, false);\r
}\r
break;\r
case Event.ONMOUSEUP:\r
}\r
\r
private void processBaseEvent(Event event) {\r
- // TODO\r
- super.onBrowserEvent(event);\r
+ if(DOM.eventGetType(event) == Event.ONMOUSEDOWN) {\r
+ if(!disabled && !readonly && !dragging) {\r
+ setValueByEvent(event, true);\r
+ DOM.eventCancelBubble(event, true);\r
+ }\r
+ }\r
+ }\r
+ \r
+ private void setValueByEvent(Event event, boolean animate) {\r
+ int x = DOM.eventGetClientX(event);\r
+ int y = DOM.eventGetClientY(event);\r
+ double v = min; // Fallback to min\r
+ if(vertical) {\r
+ // TODO\r
+ } else {\r
+ double handleW = Integer.parseInt(DOM.getAttribute(handle, "offsetWidth"));\r
+ double baseX = DOM.getAbsoluteLeft(base) + handleW/2;\r
+ double baseW = Integer.parseInt(DOM.getAttribute(base, "offsetWidth"));\r
+ v = ((x-baseX)/(baseW-handleW)) * (max-min) + min;\r
+ }\r
+ \r
+ if(v < min)\r
+ v = min;\r
+ else if(v > max)\r
+ v = max;\r
+ \r
+ if(resolution > 0) {\r
+ v = (int)(v * (double)Math.pow(10, resolution));\r
+ v = v / (double)Math.pow(10, resolution);\r
+ setValue(new Double(v), animate);\r
+ } else\r
+ setValue(new Double((int)v), animate);\r
+ \r
+ }\r
+ \r
+ private void decrease() {\r
+ double diff = (max-min)/max*10 + (max-min)/10;\r
+ double v = value.doubleValue()-diff;\r
+ if(resolution > 0) {\r
+ v = (int)(v * (double)Math.pow(10, resolution));\r
+ v = v / (double)Math.pow(10, resolution);\r
+ } else v = (int)v;\r
+ if(v < min)\r
+ v = min;\r
+ setValue(new Double(v), true);\r
+ }\r
+ \r
+ private void increase() {\r
+ double diff = (max-min)/max*10 + (max-min)/10;\r
+ double v = value.doubleValue()+diff;\r
+ if(resolution > 0) {\r
+ v = (int)(v * (double)Math.pow(10, resolution));\r
+ v = v / (double)Math.pow(10, resolution);\r
+ } else v = (int)v;\r
+ if(v > max)\r
+ v = max;\r
+ setValue(new Double(v), true);\r
}\r
\r
}\r
package com.itmill.toolkit.ui;\r
\r
import java.util.Map;\r
-import java.util.Set;\r
\r
import com.itmill.toolkit.terminal.PaintException;\r
import com.itmill.toolkit.terminal.PaintTarget;\r
public static final int ORIENTATION_VERTICAL = 1;\r
\r
/** Minimum value of slider */\r
- private float min = 0;\r
+ private double min = 0;\r
/** Maximum value of slider */\r
- private float max = 100;\r
+ private double max = 100;\r
\r
/**\r
* Resolution, how many digits are considered relevant after desimal point.\r
*/\r
private int resolution = 0;\r
\r
- /** \r
- * Object values for slider in stead of numeric (usually strings).\r
- * If this is set, min, max and resolution values are ignored.\r
- */\r
- private Set values;\r
- \r
/**\r
* Slider orientation (horizontal==default/vertical).\r
*/\r
* Handle size in percents related to base size.\r
* Must be a value between 1-100.\r
*/\r
- private int handleSize = 20;\r
+ private int handleSize = -1;\r
\r
+ /**\r
+ * Show arrows that can be pressed to slide the \r
+ * handle in some increments (client-side \r
+ * implementation decides the increment).\r
+ */\r
+ private boolean arrows = true;\r
\r
public Slider() {\r
super();\r
- super.setValue(new Float(min));\r
+ super.setValue(new Double(min));\r
+ }\r
+ \r
+ public Slider(String caption) {\r
+ this();\r
+ setCaption(caption);\r
+ }\r
+ \r
+ public Slider(double min, double max, int resolution) {\r
+ this();\r
+ setMin(min);\r
+ setMax(max);\r
+ setResolution(resolution);\r
+ }\r
+ \r
+ public Slider(int min, int max) {\r
+ this();\r
+ setMin(min);\r
+ setMax(max);\r
+ setResolution(0);\r
+ }\r
+ \r
+ public Slider(String caption, int min, int max) {\r
+ this(min, max);\r
+ setCaption(caption);\r
}\r
\r
- public float getMax() {\r
+ public double getMax() {\r
return max;\r
}\r
\r
* Set the maximum value of the Slider. As a side-effect nullifies the "values" Set.\r
* @param max\r
*/\r
- public void setMax(float max) {\r
+ public void setMax(double max) {\r
this.max = max;\r
- this.values = null;\r
try {\r
if((new Float(getValue().toString())).floatValue() > max)\r
super.setValue(new Float(min));\r
} catch(ClassCastException e) {\r
super.setValue(new Float(max));\r
}\r
+ if(handleSize == -1)\r
+ handleSize = (int) ((max-min)/max*10 + (max-min)/10);\r
requestRepaint();\r
}\r
\r
- public float getMin() {\r
+ public double getMin() {\r
return min;\r
}\r
\r
* Set the minimum value of the Slider. As a side-effect nullifies the "values" Set.\r
* @param max\r
*/\r
- public void setMin(float min) {\r
+ public void setMin(double min) {\r
this.min = min;\r
- this.values = null;\r
try {\r
- if((new Float(getValue().toString())).floatValue() < min)\r
- super.setValue(new Float(min));\r
+ if((new Double(getValue().toString())).doubleValue() < min)\r
+ super.setValue(new Double(min));\r
} catch(ClassCastException e) {\r
- super.setValue(new Float(min));\r
+ super.setValue(new Double(min));\r
}\r
+ if(handleSize == -1)\r
+ handleSize = (int) ((max-min)/max*10 + (max-min)/10);\r
requestRepaint();\r
}\r
\r
requestRepaint();\r
}\r
\r
- public Set getValues() {\r
- return values;\r
- }\r
-\r
- public void setValues(Set values) {\r
- this.values = values;\r
- requestRepaint();\r
- }\r
-\r
- public void setValue(Float value, boolean repaintIsNotNeeded) throws ValueOutOfBoundsException {\r
- float v = new Float(value.toString()).floatValue();\r
- Object newValue;\r
+ public void setValue(Double value, boolean repaintIsNotNeeded) throws ValueOutOfBoundsException {\r
+ double v = new Double(value.toString()).doubleValue();\r
+ double newValue;\r
if(resolution>0) {\r
// Round up to resolution\r
- newValue = new Float(v * (resolution*10) / (resolution*10));\r
- if(min > ((Float)newValue).floatValue() || max < ((Float)newValue).floatValue())\r
+ newValue = (int) (v * (double) Math.pow(10, resolution));\r
+ newValue = newValue / (double) Math.pow(10, resolution);\r
+ if(min > newValue || max < newValue)\r
throw new ValueOutOfBoundsException(value);\r
} else {\r
- newValue = new Float((int) v);\r
- if(min > ((Float)newValue).intValue() || max < ((Float)newValue).intValue())\r
+ newValue = (int) v;\r
+ if(min > newValue || max < newValue)\r
throw new ValueOutOfBoundsException(value);\r
}\r
- super.setValue(newValue, repaintIsNotNeeded);\r
+ super.setValue(new Double(newValue), repaintIsNotNeeded);\r
}\r
\r
- public void setValue(Float value)throws ValueOutOfBoundsException {\r
- setValue(value, false);\r
- }\r
- \r
- public void setValue(String value, boolean repaintIsNotNeeded) throws ValueOutOfBoundsException {\r
- if(this.values != null) {\r
- String v = new String(value.toString());\r
- if(this.values.contains(v))\r
- super.setValue(v, repaintIsNotNeeded);\r
- else throw new ValueOutOfBoundsException(value);\r
- } else {\r
- // TODO\r
- }\r
- }\r
- \r
- public void setValue(String value) throws ValueOutOfBoundsException {\r
+ public void setValue(Double value) throws ValueOutOfBoundsException {\r
setValue(value, false);\r
}\r
\r
this.handleSize = handleSize;\r
requestRepaint();\r
}\r
+ \r
+ public void setArrows(boolean visible) {\r
+ arrows = visible;\r
+ requestRepaint();\r
+ }\r
+ \r
+ public boolean arrowsVisible() {\r
+ return arrows;\r
+ }\r
\r
public String getTag() {\r
return "slider";\r
\r
public void paintContent(PaintTarget target) throws PaintException {\r
super.paintContent(target);\r
-\r
- if(values == null) {\r
- \r
- target.addAttribute("min", (long) min);\r
- target.addAttribute("max", (long) max);\r
- target.addAttribute("resolution", resolution);\r
- \r
- if(resolution > 0)\r
- target.addVariable(this, "value", ((Float)getValue()).floatValue());\r
- else\r
- target.addVariable(this, "value", ((Float)getValue()).intValue());\r
\r
- } else {\r
- target.addVariable(this, "value", getValue().toString());\r
- target.addAttribute("values", values.toArray(new String[values.size()]));\r
- }\r
+ target.addAttribute("min", min);\r
+ target.addAttribute("max", max);\r
+ target.addAttribute("resolution", resolution);\r
\r
+ if(resolution > 0)\r
+ target.addVariable(this, "value", ((Double)getValue()).doubleValue());\r
+ else\r
+ target.addVariable(this, "value", ((Double)getValue()).intValue());\r
+ \r
if(orientation == ORIENTATION_VERTICAL)\r
target.addAttribute("vertical", true);\r
\r
+ if(arrows)\r
+ target.addAttribute("arrows", true);\r
+ \r
if(size > -1)\r
target.addAttribute("size", size);\r
\r
public void changeVariables(Object source, Map variables) {\r
if (variables.containsKey("value")) {\r
Object newValue = variables.get("value");\r
- if(values == null) {\r
- if(resolution >0)\r
- newValue = new Long(newValue.toString());\r
- else \r
- newValue = new Integer(newValue.toString());\r
- if(newValue != null && newValue != getValue() && !newValue.equals(getValue())) {\r
- setValue(newValue);\r
- }\r
- } else {\r
- // TODO\r
+ if(resolution > 0)\r
+ newValue = new Double(newValue.toString());\r
+ else \r
+ newValue = new Integer(newValue.toString());\r
+ if(newValue != null && newValue != getValue() && !newValue.equals(getValue())) {\r
+ setValue(newValue, true);\r
}\r
}\r
}\r
*/\r
private static final long serialVersionUID = -6451298598644446340L;\r
\r
- private Object value;\r
+ private Double value;\r
\r
/**\r
* Constructs an <code>ValueOutOfBoundsException</code> with the specified\r
* \r
* @param valueOutOfBounds\r
*/\r
- public ValueOutOfBoundsException(Object valueOutOfBounds) {\r
+ public ValueOutOfBoundsException(Double valueOutOfBounds) {\r
this.value = valueOutOfBounds;\r
}\r
\r
- public Object getValue() {\r
+ public Double getValue() {\r
return this.value;\r
}\r
\r
}\r
\r
public Class getType() {\r
- if(values == null)\r
- return Float.class;\r
- return String.class;\r
+ return Double.class;\r
}\r
\r
}\r