1
0
Fork 0

canvas.gui: Basic ScrollArea widget.

This commit is contained in:
Thomas Geymayer 2014-03-19 23:20:09 +01:00
parent 313175b943
commit d7ddeb7183
6 changed files with 187 additions and 49 deletions

View file

@ -8,10 +8,12 @@ var gui_dir = getprop("/sim/fg-root") ~ "/Nasal/canvas/gui/";
var loadGUIFile = func(file) io.load_nasal(gui_dir ~ file, "canvas");
var loadWidget = func(name) loadGUIFile("widgets/" ~ name ~ ".nas");
loadGUIFile("Config.nas");
loadGUIFile("Style.nas");
loadGUIFile("Widget.nas");
loadGUIFile("styles/DefaultStyle.nas");
loadWidget("Button");
loadWidget("ScrollArea");
var style = DefaultStyle.new("AmbianceClassic");
var WindowButton = {

View file

@ -0,0 +1,21 @@
var Config = {
new: func(cfg)
{
var m = {
parents: [Config],
_cfg: cfg
};
if( typeof(m._cfg) != "hash" )
m._cfg = {};
return m;
},
get: func(key, default = nil)
{
var val = me._cfg[key];
if( val != nil )
return val;
return default;
}
};

View file

@ -13,7 +13,8 @@ gui.Widget = {
_focused: 0,
_focus_policy: gui.Widget.NoFocus,
_hover: 0,
_root: nil
_root: nil,
_size: [64, 64]
};
},
# Move the widget to the given position (relative to its parent)
@ -23,6 +24,12 @@ gui.Widget = {
return me;
},
#
setSize: func(w, h)
{
me._size[0] = w;
me._size[1] = h;
},
#
setFocus: func
{
if( me._focused )

View file

@ -12,7 +12,12 @@ var DefaultStyle = {
return nil;
}
return factory.new(parent, me, cfg);
var w = {
parents: [factory],
_style: me
};
call(factory.new, [parent, cfg], w);
return w;
},
widgets: {}
};
@ -20,31 +25,26 @@ var DefaultStyle = {
# A button
DefaultStyle.widgets.button = {
padding: [6, 8, 6, 8],
new: func(parent, style, cfg)
new: func(parent, cfg)
{
var button = {
parents: [DefaultStyle.widgets.button],
element: parent.createChild("group", "button"),
size: cfg.get("size", [26, 26]),
_style: style
};
me.element = parent.createChild("group", "button");
me.size = cfg.get("size", [26, 26]);
button._bg =
button.element.rect( 3,
3,
button.size[0] - 6,
button.size[1] - 6,
{"border-radius": 5} );
button._border =
button.element.createChild("image", "button")
.set("slice", "10 12") #"7")
.setSize(button.size);
button._label =
button.element.createChild("text")
.setFont("LiberationFonts/LiberationSans-Regular.ttf")
.set("character-size", 14)
.set("alignment", "center-baseline");
return button;
me._bg =
me.element.rect( 3,
3,
me.size[0] - 6,
me.size[1] - 6,
{"border-radius": 5} );
me._border =
me.element.createChild("image", "button")
.set("slice", "10 12") #"7")
.setSize(me.size);
me._label =
me.element.createChild("text")
.setFont("LiberationFonts/LiberationSans-Regular.ttf")
.set("character-size", 14)
.set("alignment", "center-baseline");
},
setText: func(text)
{
@ -85,3 +85,46 @@ DefaultStyle.widgets.button = {
me._border.set("file", file ~ ".png");
}
};
# ScrollArea
DefaultStyle.widgets["scroll-area"] = {
new: func(parent, cfg)
{
me.element = parent.createChild("group", "scroll-area");
me._bg = me.element.createChild("path", "background")
.set("fill", "#e0e0e0");
me.content = me.element.createChild("group", "scroll-content")
.set("clip-frame", Element.PARENT);
me.vert = me._newScroll(me.element, "vert");
me.horiz = me._newScroll(me.element, "horiz");
},
update: func(widget)
{
me.horiz.reset();
if( widget._max_scroll[0] > 1 )
# only show scroll bar if horizontally scrollable
me.horiz.moveTo(widget._pos[0], widget._size[1] - 2)
.horiz(widget._size[0] - widget._max_scroll[0]);
me.vert.reset();
if( widget._max_scroll[1] > 1 )
# only show scroll bar if vertically scrollable
me.vert.moveTo(widget._size[0] - 2, widget._pos[1])
.vert(widget._size[1] - widget._max_scroll[1]);
me._bg.reset()
.rect(0, 0, widget._size[0], widget._size[1]);
me.content.set(
"clip",
"rect(0, " ~ widget._size[0] ~ ", " ~ widget._size[1] ~ ", 0)"
);
},
# private:
_newScroll: func(el, orient)
{
return el.createChild("path", "scroll-" ~ orient)
.set("stroke", "#f07845")
.set("stroke-width", 4);
}
};

View file

@ -1,25 +1,3 @@
var Config = {
new: func(cfg)
{
var m = {
parents: [Config],
_cfg: cfg
};
if( typeof(m._cfg) != "hash" )
m._cfg = {};
return m;
},
get: func(key, default = nil)
{
var val = me._cfg[key];
if( val != nil )
return val;
return default;
}
};
gui.widgets.Button = {
new: func(parent, style, cfg)
{
@ -82,5 +60,3 @@ gui.widgets.Button = {
call(gui.Widget._setRoot, [el], me);
}
};
return;

View file

@ -0,0 +1,89 @@
gui.widgets.ScrollArea = {
new: func(parent, style, cfg)
{
var cfg = Config.new(cfg);
var m = gui.Widget.new(gui.widgets.ScrollArea);
m._focus_policy = m.StrongFocus;
m._active = 0;
m._pos = [0,0];
m._size = cfg.get("size", m._size);
if( style != nil )
{
m._scroll = style.createWidget(parent, "scroll-area", cfg);
m._setRoot(m._scroll.element);
m._scroll.vert.addEventListener("mousedown", func(e) m._dragStart(e));
m._scroll.horiz.addEventListener("mousedown", func(e) m._dragStart(e));
m._scroll.vert.addEventListener
(
"drag",
func(e) m.moveTo(m._pos[0], m._drag_offsetY + e.clientY)
);
m._scroll.horiz.addEventListener
(
"drag",
func(e) m.moveTo(m._drag_offsetX + e.clientX, m._pos[1])
);
}
return m;
},
getContent: func()
{
return me._scroll.content;
},
moveTo: func(x, y)
{
me._pos[0] = math.max(0, math.min(x, me._max_scroll[0]));
me._pos[1] = math.max(0, math.min(y, me._max_scroll[1]));
me.update();
},
update: func()
{
# TODO only update on content resize
var bb = me.getContent().getTransformedBounds();
var w = bb[2] - bb[0];
var h = bb[3] - bb[1];
me._max_scroll = [0, 0];
if( w > me._size[0] )
me._max_scroll[0] = me._size[0] * (1 - me._size[0] / w);
if( h > me._size[1] )
me._max_scroll[1] = me._size[1] * (1 - me._size[1] / h);
me._content_size = [w, h];
var cur_offset = me.getContent().getTranslation();
me._content_offset = [cur_offset[0] - bb[0], cur_offset[1] - bb[1]];
var offset = [ me._content_offset[0],
me._content_offset[1] ];
if( me._max_scroll[0] > 1 )
offset[0] -= (me._pos[0] / me._max_scroll[0])
* (me._content_size[0] - me._size[0]);
if( me._max_scroll[1] > 1 )
offset[1] -= (me._pos[1] / me._max_scroll[1])
* (me._content_size[1] - me._size[1]);
me.getContent().setTranslation(offset);
me._scroll.update(me);
me.getContent().update();
},
# protected:
_setRoot: func(el)
{
el.addEventListener("wheel", func(e) me.moveTo(me._pos[0], me._pos[1] - e.deltaY));
call(gui.Widget._setRoot, [el], me);
},
_dragStart: func(e)
{
me._drag_offsetX = me._pos[0] - e.clientX;
me._drag_offsetY = me._pos[1] - e.clientY;
}
};