Browse Source

Slider component finished, fixes #1030

svn changeset:2600/svn branch:trunk
tags/6.7.0.beta1
Jouni Koivuviita 16 years ago
parent
commit
f1d379b8de

+ 213
- 167
src/com/itmill/toolkit/terminal/gwt/client/ui/ISlider.java View File

@@ -8,13 +8,22 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;
import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener;
import com.itmill.toolkit.terminal.gwt.client.Paintable;
import com.itmill.toolkit.terminal.gwt.client.UIDL;
import com.itmill.toolkit.terminal.gwt.client.Util;
public class ISlider extends Widget implements Paintable {
public class ISlider extends Widget implements Paintable,
ContainerResizedListener {
public static final String CLASSNAME = "i-slider";
/**
* Minimum size (width or height, depending on orientation) of the slider
* base.
*/
private static final int MIN_SIZE = 50;
ApplicationConnection client;
String id;
@@ -22,6 +31,7 @@ public class ISlider extends Widget implements Paintable {
private boolean immediate;
private boolean disabled;
private boolean readonly;
private boolean scrollbarStyle;
private int handleSize;
private double min;
@@ -73,10 +83,13 @@ public class ISlider extends Widget implements Paintable {
DOM.setStyleAttribute(bigger, "display", "none");
DOM.setStyleAttribute(handle, "visibility", "hidden");
DOM.sinkEvents(base, Event.ONMOUSEDOWN);
DOM.sinkEvents(getElement(), Event.MOUSEEVENTS);
DOM.sinkEvents(base, Event.ONCLICK);
DOM.sinkEvents(handle, Event.MOUSEEVENTS);
DOM.sinkEvents(smaller, Event.ONMOUSEDOWN | Event.ONMOUSEUP);
DOM.sinkEvents(bigger, Event.ONMOUSEDOWN | Event.ONMOUSEUP);
DOM.sinkEvents(smaller, Event.ONMOUSEDOWN | Event.ONMOUSEUP
| Event.ONMOUSEOUT);
DOM.sinkEvents(bigger, Event.ONMOUSEDOWN | Event.ONMOUSEUP
| Event.ONMOUSEOUT);
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
@@ -95,15 +108,15 @@ public class ISlider extends Widget implements Paintable {
vertical = uidl.hasAttribute("vertical");
arrows = uidl.hasAttribute("arrows");
String style = "";
if (uidl.hasAttribute("style"))
style = uidl.getStringAttribute("style");
scrollbarStyle = style.indexOf("scrollbar") > -1;
if (arrows) {
DOM.setStyleAttribute(smaller, "display", "block");
DOM.setStyleAttribute(bigger, "display", "block");
if (vertical) {
int arrowSize = Integer.parseInt(DOM.getElementProperty(
smaller, "offsetWidth"));
DOM.setStyleAttribute(bigger, "marginLeft", arrowSize + "px");
DOM.setStyleAttribute(bigger, "marginRight", arrowSize + "px");
}
}
if (vertical)
@@ -125,14 +138,12 @@ public class ISlider extends Widget implements Paintable {
if (!vertical) {
// Draw handle with a delay to allow base to gain maximum width
// TODO implement with onLoad or DeferredCommand ??
Timer delay = new Timer() {
public void run() {
DeferredCommand.addCommand(new Command() {
public void execute() {
buildHandle();
setValue(value, false, false);
}
};
delay.schedule(100);
});
} else {
buildHandle();
setValue(value, false, false);
@@ -140,122 +151,116 @@ public class ISlider extends Widget implements Paintable {
}
private void buildBase() {
if (vertical) {
// TODO
} else {
if (size > -1)
DOM.setStyleAttribute(getElement(), "width", size + "px");
else {
Element p = DOM.getParent(getElement());
if (Integer.parseInt(DOM.getElementProperty(p, "offsetWidth")) > 50)
DOM.setStyleAttribute(getElement(), "width", "auto");
else {
// Set minimum of 50px width and adjust after all
// components have (supposedly) been drawn completely.
DOM.setStyleAttribute(getElement(), "width", "50px");
DeferredCommand.addCommand(new Command() {
public void execute() {
Element p = DOM.getParent(getElement());
if (Integer.parseInt(DOM.getElementProperty(p,
"offsetWidth")) > 50)
DOM.setStyleAttribute(getElement(), "width",
"auto");
}
});
}
final String styleAttribute = vertical ? "height" : "width";
final String domProperty = vertical ? "offsetHeight" : "offsetWidth";
if (size == -1) {
Element p = DOM.getParent(getElement());
if (DOM.getElementPropertyInt(p, domProperty) > 50) {
if (vertical)
setHeight();
else
DOM.setStyleAttribute(base, styleAttribute, "");
} else {
// Set minimum size and adjust after all components have
// (supposedly) been drawn completely.
DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px");
DeferredCommand.addCommand(new Command() {
public void execute() {
Element p = DOM.getParent(getElement());
if (DOM.getElementPropertyInt(p, domProperty) > 50)
if (vertical) {
setHeight();
} else
DOM.setStyleAttribute(base, styleAttribute, "");
}
});
}
}
// Allow absolute positioning of handle
DOM.setStyleAttribute(base, "position", "relative");
} else
DOM.setStyleAttribute(base, styleAttribute, size + "px");
// TODO attach listeners for focusing and arrow keys
// TODO attach listeners for focusing and arrow keys + scroll wheel
}
private void buildHandle() {
// Allow absolute positioning
DOM.setStyleAttribute(handle, "position", "absolute");
String styleAttribute = vertical ? "height" : "width";
String handleAttribute = vertical ? "marginTop" : "marginLeft";
String domProperty = vertical ? "offsetHeight" : "offsetWidth";
if (vertical) {
// TODO
} else {
int t = Integer.parseInt(DOM.getElementProperty(base,
"offsetHeight"))
- Integer.parseInt(DOM.getElementProperty(handle,
"offsetHeight"));
DOM.setStyleAttribute(handle, "top", (t / 2) + "px");
DOM.setStyleAttribute(handle, "left", "0px");
int w = (int) (Double.parseDouble(DOM.getElementProperty(base,
"offsetWidth")) / 100 * handleSize);
DOM.setStyleAttribute(handle, handleAttribute, "0");
if (scrollbarStyle) {
// Only stretch the handle if scrollbar style is set.
int s = (int) (Double.parseDouble(DOM.getElementProperty(base,
domProperty)) / 100 * handleSize);
if (handleSize == -1) {
int baseW = Integer.parseInt(DOM.getElementProperty(base,
"offsetWidth"));
int baseS = Integer.parseInt(DOM.getElementProperty(base,
domProperty));
double range = (max - min) * (resolution + 1) * 3;
w = (int) (baseW - range);
s = (int) (baseS - range);
}
if (w < 3)
w = 3;
DOM.setStyleAttribute(handle, "width", w + "px");
}
if (s < 3)
s = 3;
DOM.setStyleAttribute(handle, styleAttribute, s + "px");
} else
DOM.setStyleAttribute(handle, styleAttribute, "");
// Restore visibility
DOM.setStyleAttribute(handle, "visibility", "visible");
}
private void setValue(Double value, boolean animate, boolean updateToServer) {
if (vertical) {
// TODO
} else {
int handleWidth = Integer.parseInt(DOM.getElementProperty(handle,
"offsetWidth"));
int baseWidth = Integer.parseInt(DOM.getElementProperty(base,
"offsetWidth"));
int range = baseWidth - handleWidth;
double v = value.doubleValue();
double valueRange = max - min;
double p = 0;
if (valueRange != 0)
p = range * ((v - min) / valueRange);
if (p < 0)
p = 0;
final double pos = p;
String styleLeft = DOM.getStyleAttribute(handle, "left");
int left = Integer.parseInt(styleLeft.substring(0, styleLeft
.length() - 2));
if ((int) (Math.round(pos)) != left && animate) {
if (anim != null)
anim.cancel();
anim = new Timer() {
private int left;
private int goal = (int) Math.round(pos);
private int dir = 0;
public void run() {
String styleLeft = DOM
.getStyleAttribute(handle, "left");
left = Integer.parseInt(styleLeft.substring(0,
styleLeft.length() - 2));
// Determine direction
if (dir == 0)
dir = (goal - left) / Math.abs(goal - left);
if ((dir > 0 && left >= goal)
|| (dir < 0 && left <= goal)) {
this.cancel();
return;
}
int increment = (goal - left) / 2;
DOM.setStyleAttribute(handle, "left",
(left + increment) + "px");
final String styleAttribute = vertical ? "marginTop" : "marginLeft";
String domProperty = vertical ? "offsetHeight" : "offsetWidth";
int handleSize = Integer.parseInt(DOM.getElementProperty(handle,
domProperty));
int baseSize = Integer.parseInt(DOM.getElementProperty(base,
domProperty));
int range = baseSize - handleSize;
double v = value.doubleValue();
double valueRange = max - min;
double p = 0;
if (valueRange > 0)
p = range * ((v - min) / valueRange);
if (p < 0)
p = 0;
if (vertical)
p = range - p - (Util.isIE6() ? 1 : 0);
final double pos = p;
int current = DOM.getIntStyleAttribute(handle, styleAttribute);
if ((int) (Math.round(pos)) != current && animate) {
if (anim != null)
anim.cancel();
anim = new Timer() {
private int current;
private int goal = (int) Math.round(pos);
private int dir = 0;
public void run() {
current = DOM.getIntStyleAttribute(handle, styleAttribute);
// Determine direction
if (dir == 0)
dir = (goal - current) / Math.abs(goal - current);
if ((dir > 0 && current >= goal)
|| (dir < 0 && current <= goal)) {
this.cancel();
return;
}
};
anim.scheduleRepeating(50);
} else
DOM.setStyleAttribute(handle, "left", ((int) pos) + "px");
// DOM.setAttribute(handle, "title", ""+v);
}
int increment = (goal - current) / 2;
DOM.setStyleAttribute(handle, styleAttribute,
(current + increment) + "px");
}
};
anim.scheduleRepeating(50);
} else
DOM.setStyleAttribute(handle, styleAttribute, ((int) pos) + "px");
DOM.setElementAttribute(handle, "title", "" + v);
if (value.doubleValue() < min)
value = new Double(min);
@@ -274,47 +279,10 @@ public class ISlider extends Widget implements Paintable {
Element targ = DOM.eventGetTarget(event);
if (dragging || DOM.compare(targ, handle)) {
processHandleEvent(event);
} else if (DOM.compare(targ, smaller)) {
// Decrease value by resolution
if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
setValue(new Double(value.doubleValue()
- Math.pow(10, -resolution)), false, true);
if (anim != null)
anim.cancel();
anim = new Timer() {
public void run() {
if (value.doubleValue() - Math.pow(10, -resolution) > min)
setValue(new Double(value.doubleValue()
- Math.pow(10, -resolution)), false, true);
}
};
anim.scheduleRepeating(100);
DOM.eventCancelBubble(event, true);
} else if (DOM.eventGetType(event) == Event.ONMOUSEUP) {
anim.cancel();
}
decreaseValue(event);
} else if (DOM.compare(targ, bigger)) {
// Increase value by resolution
if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
setValue(new Double(value.doubleValue()
+ Math.pow(10, -resolution)), false, true);
if (anim != null)
anim.cancel();
anim = new Timer() {
public void run() {
if (value.doubleValue() - Math.pow(10, -resolution) < max)
setValue(new Double(value.doubleValue()
+ Math.pow(10, -resolution)), false, true);
}
};
anim.scheduleRepeating(100);
DOM.eventCancelBubble(event, true);
} else if (DOM.eventGetType(event) == Event.ONMOUSEUP) {
anim.cancel();
}
increaseValue(event);
} else
processBaseEvent(event);
}
@@ -333,7 +301,7 @@ public class ISlider extends Widget implements Paintable {
break;
case Event.ONMOUSEMOVE:
if (dragging) {
DOM.setCapture(getElement());
// DOM.setCapture(getElement());
setValueByEvent(event, false, false);
}
break;
@@ -353,23 +321,73 @@ public class ISlider extends Widget implements Paintable {
setValueByEvent(event, true, true);
DOM.eventCancelBubble(event, true);
}
} else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && dragging) {
dragging = false;
DOM.releaseCapture(getElement());
setValueByEvent(event, true, true);
}
}
private void decreaseValue(Event event) {
if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
setValue(
new Double(value.doubleValue() - Math.pow(10, -resolution)),
false, true);
if (anim != null)
anim.cancel();
anim = new Timer() {
public void run() {
if (value.doubleValue() - Math.pow(10, -resolution) > min)
setValue(new Double(value.doubleValue()
- Math.pow(10, -resolution)), false, true);
}
};
anim.scheduleRepeating(100);
DOM.eventCancelBubble(event, true);
} else
anim.cancel();
}
private void increaseValue(Event event) {
if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
setValue(
new Double(value.doubleValue() + Math.pow(10, -resolution)),
false, true);
if (anim != null)
anim.cancel();
anim = new Timer() {
public void run() {
if (value.doubleValue() - Math.pow(10, -resolution) < max)
setValue(new Double(value.doubleValue()
+ Math.pow(10, -resolution)), false, true);
}
};
anim.scheduleRepeating(100);
DOM.eventCancelBubble(event, true);
} else
anim.cancel();
}
private void setValueByEvent(Event event, boolean animate, boolean roundup) {
int x = DOM.eventGetClientX(event);
// int y = DOM.eventGetClientY(event);
double v = min; // Fallback to min
if (vertical) {
// TODO
} else {
double handleW = Integer.parseInt(DOM.getElementProperty(handle,
"offsetWidth"));
double baseX = DOM.getAbsoluteLeft(base) + handleW / 2;
double baseW = Integer.parseInt(DOM.getElementProperty(base,
"offsetWidth"));
v = ((x - baseX) / (baseW - handleW)) * (max - min) + min;
}
int coord = vertical ? DOM.eventGetClientY(event) : DOM
.eventGetClientX(event);
String domProperty = vertical ? "offsetHeight" : "offsetWidth";
double handleSize = Integer.parseInt(DOM.getElementProperty(handle,
domProperty));
double baseSize = Integer.parseInt(DOM.getElementProperty(base,
domProperty));
double baseOffset = vertical ? DOM.getAbsoluteTop(base) - handleSize
/ 2 : DOM.getAbsoluteLeft(base) + handleSize / 2;
if (vertical)
v = ((baseSize - (coord - baseOffset)) / (baseSize - handleSize))
* (max - min) + min;
else
v = ((coord - baseOffset) / (baseSize - handleSize)) * (max - min)
+ min;
if (v < min)
v = min;
@@ -387,4 +405,32 @@ public class ISlider extends Widget implements Paintable {
setValue(new Double(v), animate, roundup);
}
public void iLayout() {
if (vertical) {
setHeight();
}
// Update handle position
setValue(value, false, false);
}
private void setHeight() {
if (size == -1) {
// Calculate decoration size
DOM.setStyleAttribute(base, "height", "0");
DOM.setStyleAttribute(base, "overflow", "hidden");
int decoHeight = DOM.getElementPropertyInt(getElement(),
"offsetHeight");
// Get available space size
int availableHeight = DOM.getElementPropertyInt(DOM
.getParent(getElement()), "offsetHeight");
int h = availableHeight - decoHeight;
if (h < MIN_SIZE)
h = MIN_SIZE;
DOM.setStyleAttribute(base, "height", h + "px");
} else {
DOM.setStyleAttribute(base, "height", size + "px");
}
DOM.setStyleAttribute(base, "overflow", "");
}
}

BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/arrow-left-over.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/arrow-left.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/arrow-right-over.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/arrow-right.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/bg.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/handle-bg.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/handle-horizontal.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/handle-left.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/handle-right.png View File


BIN
src/com/itmill/toolkit/terminal/gwt/public/default/slider/img/handle-vertical.png View File


+ 79
- 98
src/com/itmill/toolkit/terminal/gwt/public/default/slider/slider.css View File

@@ -1,99 +1,80 @@
.i-slider {
background: #c3d0dd url(../img/bg.png) repeat-x;
border: 1px solid #29528a;
border-left: none;
border-right: none;
height: 14px;
}
.i-slider:before {
display: block;
width: 1px;
height: 14px;
background-color: #29528a;
border-top: 1px solid #b9c8dc;
border-bottom: 1px solid #b9c8dc;
margin: -1px 0 -15px -1px;
content: "";
}
.i-slider:after {
display: block;
width: 1px;
height: 14px;
background-color: #29528a;
border-top: 1px solid #b9c8dc;
border-bottom: 1px solid #b9c8dc;
margin: -15px 0 0 100%;
content: "";
}
.i-slider-base {
background: #c3d0dd url(../img/bg.png) repeat-x;
height: 14px;
overflow: hidden;
}
.i-slider-handle {
background: #fff url(../img/handle-bg.png) repeat-x;
border: 1px solid #29528a;
height: 10px;
font-size: 1px;
}
.i-slider-handle:before {
display: block;
height: 12px;
background: transparent url(../img/handle-right.png) no-repeat right top;
margin: -1px -1px 0 -1px;
content: url(../img/handle-left.png);
}
.i-slider-bigger {
background: #dde4ef url(../img/arrow-right.png);
float: right;
width: 14px;
height: 14px;
overflow: hidden;
margin: 0 0 0 1px;
}
.i-slider-bigger:hover {
background-image: url(../img/arrow-right-over.png);
}
.i-slider-smaller {
background: #dde4ef url(../img/arrow-left.png);
float: left;
width: 14px;
height: 14px;
overflow: hidden;
margin: 0 1px 0 0;
}
.i-slider-smaller:hover {
background-image: url(../img/arrow-left-over.png);
}
/*-----------------
Vertical styles
-----------------*/
.i-slider-vertical {
}
.i-slider-vertical .i-slider-base {
}
.i-slider-vertical .i-slider-handle {
}
.i-slider-vertical .i-slider-bigger {
}
/*--------------------
IE specific styles
-------------------*/
* html .i-slider {
border: 1px solid #29528a;
}
*+html .i-slider {
border: 1px solid #29528a;
/*--------------------------
Default (horizontal) styles
--------------------------*/

.i-slider {
border: 1px solid #d8dbdc;
height: 2px;
margin: 5px 0;
}

.i-slider-base {
height: 1px;
border-top: 1px solid #e5e8e8;
background: #fff;
}
.i-slider-handle {
background: #babfc0 url(img/handle-horizontal.png);
width: 7px;
height: 15px;
margin-top: -5px;
font-size: 0;
cursor: pointer;
}
/* TODO
.i-slider-bigger {
background: #dde4ef url(img/arrow-right.png);
float: right;
width: 14px;
height: 14px;
overflow: hidden;
margin: 0 0 0 1px;
}

.i-slider-bigger:hover {
background-image: url(img/arrow-right-over.png);
}

.i-slider-smaller {
background: #dde4ef url(img/arrow-left.png);
float: left;
width: 14px;
height: 14px;
overflow: hidden;
margin: 0 1px 0 0;
}

.i-slider-smaller:hover {
background-image: url(img/arrow-left-over.png);
}
*/


/*-----------------
Vertical styles
-----------------*/

.i-slider-vertical {
width: 2px;
height: auto;
margin: 0 5px;
}
.i-slider-vertical .i-slider-base {
width: 1px;
border-left: 1px solid #e5e8e8;
background: #fff;
}
.i-slider-vertical .i-slider-handle {
background: #babfc0 url(img/handle-vertical.png);
width: 14px;
height: 7px;
font-size: 0;
cursor: pointer;
margin-left: -7px;
}
.i-slider-vertical .i-slider-bigger {

}
.i-slider-vertical .i-slider-smaller {

}

+ 13
- 2
src/com/itmill/toolkit/ui/Slider.java View File

@@ -45,6 +45,14 @@ public class Slider extends AbstractField {
public static final int ORIENTATION_VERTICAL = 1;
/**
* Style constant representing a scrollbar styled slider. Use this with
* {@link #addStyleName(String)}. Default styling usually represents a
* common slider found e.g. in Adobe Photoshop. The client side
* implementation dictates how different styles will look.
*/
public static final String STYLE_SCROLLBAR = "scrollbar";
/** Minimum value of slider */
private double min = 0;
@@ -82,7 +90,7 @@ public class Slider extends AbstractField {
* (client-side implementation decides the increment, usually somewhere
* between 5-10% of slide range).
*/
private boolean arrows = true;
private boolean arrows = false;
/**
* Default Slider constructor. Sets all values to defaults and the slide
@@ -295,7 +303,7 @@ public class Slider extends AbstractField {
/**
* Get the current Slider size.
*
* @return size in pixels or -1.
* @return size in pixels or -1 for auto sizing.
*/
public int getSize() {
return size;
@@ -391,6 +399,9 @@ public class Slider extends AbstractField {
target.addAttribute("hsize", handleSize);
else
target.addAttribute("hsize", 100);
if(!getStyleName().equals(""))
target.addAttribute("style", getStyleName());
}

Loading…
Cancel
Save