Summary
See this thread in the mailing lists.
Here is a pretty box widget. Adjust the color attribute of a SweetBox when you add it for different results.
Code
To work in JavaFXPad, add the following:
Canvas {
content: SweetBox {
color: red
roundness: 1
x: 10
y: 10
w: 200
h: 40
}
}
CustomNode
//new API
import javafx.application.Frame;
import javafx.application.Stage;
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.Group;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.RadialGradient;
import javafx.scene.geometry.Rectangle;
import javafx.scene.paint.Stop;
import javafx.scene.paint.Color;
import javafx.scene.effect.GaussianBlur;
function lighter(c: Color, k: Number)
{
Color
{
red: bind (1 - (1 - c.red) * k)
green: bind (1 - (1 - c.green) * k)
blue: bind (1 - (1 - c.blue) * k)
opacity: bind c.opacity
};
}
function darker(c: Color, k: Number)
{
Color
{
red: bind c.red * k
green: bind c.green * k
blue: bind c.blue * k
opacity: bind c.opacity
};
}
public class SweetBox extends CustomNode
{
attribute color: Color;
attribute roundness: Number;
attribute inset: Number = 1;
attribute x: Number;
attribute y: Number;
attribute w: Number;
attribute h: Number;
function frame(x:Number, y: Number, w:Number, h:Number)
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public function create(): Node
{
Group
{
effect:GaussianBlur {radius: 2}
content:
[
Rectangle
{
x: bind x
y: bind y
width: bind w
height: bind h
arcHeight: bind roundness * h
arcWidth: bind roundness * h
fill: bind LinearGradient
{
startX: x,
startY: y,
endX: x,
endY: y + h
proportional: false;
stops:
[
Stop {offset: 0.0 color: darker(color, 0.5)},
Stop {offset: 1.0 color: color}
]
//spreadMethod: SpreadMethod.PAD
}
},
Rectangle
{
x: bind x+inset
y: bind y+inset
width: bind w-2*inset
height: bind h-2*inset
arcHeight: bind roundness * h
arcWidth: bind roundness * h
opacity: 0.8
fill: bind LinearGradient
{
//startX: 0, startY: 0, endX: 0, endY: 0.5
startX:x
startY:y
endX:x
endY:y + h
proportional: false;
stops:
[
Stop {offset: 0.0 color: Color.WHITE},
Stop {offset: 1.0 color: lighter(color, 0.8)}
]
//spreadMethod: SpreadMethod.PAD
}
clip: Rectangle
{
x: bind x+inset
y: bind y+inset
width: bind w-2*inset
height: bind (h-2*inset) /2
arcHeight: bind roundness * h /3
arcWidth: bind roundness * h /3
}
}
]
};
}
}
public class Model
{
public attribute boxColor:Color;
}
var model1 = Model{};
model1.boxColor = Color.LIME;
Frame {
visible: true
stage:
Stage
{
content:[SweetBox {
color: bind model1.boxColor
roundness: 1
x: 10
y: 10
w: 200
h: 40
}
]
}
}
Rewritted with New syntax and binding.
package javafxapplication1;
import javafx.ui.*;
import javafx.ui.canvas.*;
import javafx.ui.filter.*;
//updated by devantor
function lighter(c: Color, k: Number)
{
Color
{
red: bind (1 - (1 - c.red) * k)
green: bind (1 - (1 - c.green) * k)
blue: bind (1 - (1 - c.blue) * k)
opacity: bind c.opacity
};
}
function darker(c: Color, k: Number)
{
Color
{
red: bind c.red * k
green: bind c.green * k
blue: bind c.blue * k
opacity: bind c.opacity
};
}
public class SweetBox extends CompositeNode
{
attribute color: Color;
attribute roundness: Number;
attribute inset: Number = 1;
attribute x: Number;
attribute y: Number;
attribute w: Number;
attribute h: Number;
function frame(x:Number, y: Number, w:Number, h:Number)
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
function composeNode()
{
Group
{
filter: GaussianBlur {radius: 2}
content:
[
Rect
{
x: bind x
y: bind y
width: bind w
height: bind h
arcHeight: bind roundness * h
arcWidth: bind roundness * h
fill: bind LinearGradient
{
startX: x,
startY: y,
endX: x,
endY: y + h
stops:
[
Stop {offset: 0.0 color: darker(color, 0.5)},
Stop {offset: 1.0 color: color}
]
spreadMethod: SpreadMethod.PAD
}
},
Clip
{
shape: Rect
{
x: bind x+inset
y: bind y+inset
width: bind w-2*inset
height: bind (h-2*inset) /2
arcHeight: bind roundness * h /3
arcWidth: bind roundness * h /3
}
content: Rect
{
x: bind x+inset
y: bind y+inset
width: bind w-2*inset
height: bind h-2*inset
arcHeight: bind roundness * h
arcWidth: bind roundness * h
opacity: 0.8
fill: bind LinearGradient
{
//startX: 0, startY: 0, endX: 0, endY: 0.5
startX:x
startY:y
endX:x
endY:y + h
stops:
[
Stop {offset: 0.0 color: Color.WHITE},
Stop {offset: 1.0 color: lighter(color, 0.8)}
]
spreadMethod: SpreadMethod.PAD
}
}
}
]
};
}
}
public class Model
{
public attribute boxColor:Color;
}
var model1 = Model{};
Canvas {
content: [SweetBox {
color: bind model1.boxColor
roundness: 1
x: 10
y: 10
w: 200
h: 40
},
View{ content: Button {
text: "Press Me"
action: function() {
model1.boxColor = Color.LIME;
}
}
},
]
}
Old version
import javafx.ui.*;
import javafx.ui.canvas.*;
import javafx.ui.filter.*;
function lighter(c: Color, k: Number) =
Color
{
red: (1 - (1 - c.red) * k)
green: (1 - (1 - c.green) * k)
blue: (1 - (1 - c.blue) * k)
opacity: c.opacity
};
function darker(c: Color, k: Number) =
Color
{
red: c.red * k
green: c.green * k
blue: c.blue * k
opacity: c.opacity
};
class SweetBox extends CompositeNode
{
attribute color: Color;
attribute roundness: Number;
attribute inset: Number;
attribute x: Number;
attribute y: Number;
attribute w: Number;
attribute h: Number;
operation frame(x:Number, y: Number, w:Number, h:Number);
}
attribute SweetBox.inset = 1;
operation SweetBox.frame(x:Number, y: Number, w:Number, h:Number)
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
function SweetBox.composeNode() =
Group
{
filter: [GaussianBlur {radius: 2}]
content:
[
Rect
{
x: bind x
y: bind y
width: bind w
height: bind h
arcHeight: bind roundness * h
arcWidth: bind roundness * h
fill: bind LinearGradient
{
x1: 0, y1: 0, x2: 0, y2: 1
stops:
[
Stop {offset: 0.0 color: darker(color, 0.5)},
Stop {offset: 1.0 color: color}
]
spreadMethod: PAD
}
},
Clip
{
shape: Rect
{
x: bind x+inset
y: bind y+inset
width: bind w-2*inset
height: bind (h-2*inset) /2
arcHeight: bind roundness * h /3
arcWidth: bind roundness * h /3
}
content: Rect
{
x: bind x+inset
y: bind y+inset
width: bind w-2*inset
height: bind h-2*inset
arcHeight: bind roundness * h
arcWidth: bind roundness * h
opacity: 0.8
fill: bind LinearGradient
{
x1: 0, y1: 0, x2: 0, y2: 0.5
stops:
[
Stop {offset: 0.0 color: white},
Stop {offset: 1.0 color: lighter(color, 0.8)}
]
spreadMethod: PAD
}
}
}
]
};