1
0
Fork 0

canvas.gui: Checkable buttons, layout for ScrollArea and images for Lables.

This commit is contained in:
Thomas Geymayer 2014-06-10 18:46:52 +02:00
parent 7e2c93825f
commit 48f33fe78f
6 changed files with 112 additions and 73 deletions

View file

@ -35,7 +35,7 @@ var WindowButton = {
var window_focus = me._windowFocus(); var window_focus = me._windowFocus();
file ~= window_focus ? "_focused" : "_unfocused"; file ~= window_focus ? "_focused" : "_unfocused";
if( me._active ) if( me._down )
file ~= "_pressed"; file ~= "_pressed";
else if( me._hover ) else if( me._hover )
file ~= "_prelight"; file ~= "_prelight";
@ -405,7 +405,7 @@ var Window = {
var button_close = WindowButton.new(title_bar, "close") var button_close = WindowButton.new(title_bar, "close")
.move(x, y); .move(x, y);
button_close.onClick = func me.del(); button_close.listen("clicked", func me.del());
# title # title
me._title = title_bar.createChild("text", "title") me._title = title_bar.createChild("text", "title")
@ -452,32 +452,6 @@ var Dialog = {
} }
}; };
var createLayoutTest = func
{
var dlg = canvas.Window.new([350,250], "dialog")
.set("resize", 1);
dlg.getCanvas(1)
.set("background", style.getColor("bg_color"));
var root = dlg.getCanvas().createGroup();
var vbox = VBoxLayout.new();
dlg.setLayout(vbox);
var b = gui.widgets.Button.new(root, style, {}).setText("Stretch");
b.setMaximumSize([9999, 9999]);
vbox.addItem(b, 1);
var button_box = HBoxLayout.new();
vbox.addItem(button_box);
var b1 = gui.widgets.Button.new(root, style, {}).setText("Ok");
button_box.addItem(b1);
b1.setFocus();
var b2 = gui.widgets.Button.new(root, style, {}).setText("Abort");
button_box.addItem(b2);
}
# Canvas GUI demo # Canvas GUI demo
# #
# Shows an icon in the top-right corner which upon click opens a simple window # Shows an icon in the top-right corner which upon click opens a simple window
@ -498,9 +472,6 @@ var initDemo = func
}); });
my_canvas.addEventListener("click", func(e) my_canvas.addEventListener("click", func(e)
{ {
if( e.button == 1 )
return createLayoutTest();
var dlg = canvas.Window.new([400,300], "dialog") var dlg = canvas.Window.new([400,300], "dialog")
.set("resize", 1); .set("resize", 1);
var my_canvas = dlg.createCanvas() var my_canvas = dlg.createCanvas()
@ -511,9 +482,8 @@ var initDemo = func
my_canvas.addEventListener("drag", func(e) { printf("drag: screen(%.1f|%.1f) client(%.1f|%.1f) local(%.1f|%.1f) delta(%.1f|%.1f)", e.screenX, e.screenY, e.clientX, e.clientY, e.localX, e.localY, e.deltaX, e.deltaY); }); my_canvas.addEventListener("drag", func(e) { printf("drag: screen(%.1f|%.1f) client(%.1f|%.1f) local(%.1f|%.1f) delta(%.1f|%.1f)", e.screenX, e.screenY, e.clientX, e.clientY, e.localX, e.localY, e.deltaX, e.deltaY); });
my_canvas.addEventListener("wheel", func(e) { printf("wheel: screen(%.1f|%.1f) client(%.1f|%.1f) %.1f", e.screenX, e.screenY, e.clientX, e.clientY, e.deltaY); }); my_canvas.addEventListener("wheel", func(e) { printf("wheel: screen(%.1f|%.1f) client(%.1f|%.1f) %.1f", e.screenX, e.screenY, e.clientX, e.clientY, e.deltaY); });
var root = my_canvas.createGroup(); var root = my_canvas.createGroup();
root.addEventListener("test", func(e) { printf("test: %s", e.detail.test); }); root.createChild("image")
root.createChild("image") .set("src", "http://wiki.flightgear.org/skins/common/images/icons-fg-135.png");
.set("src", "http://wiki.flightgear.org/skins/common/images/icons-fg-135.png");
var text = var text =
root.createChild("text") root.createChild("text")
.setText("This could be used for building an 'Aircraft Help' dialog.\nYou can also #use it to play around with the new Canvas system :). β") .setText("This could be used for building an 'Aircraft Help' dialog.\nYou can also #use it to play around with the new Canvas system :). β")
@ -533,7 +503,6 @@ root.createChild("image")
.set("fill", "#ff0000") .set("fill", "#ff0000")
.hide(); .hide();
var visible_count = 0; var visible_count = 0;
text.addEventListener("click", func root.dispatchEvent(canvas.CustomEvent.new("test", {detail: {"test": "some important data.."}})));
text.addEventListener("mouseover", func text_move.show()); text.addEventListener("mouseover", func text_move.show());
text.addEventListener("mouseout", func text_move.hide()); text.addEventListener("mouseout", func text_move.hide());
text.addEventListener("mousemove", func(e) { printf("move: screen(%.1f|%.1f) client(%.1f|%.1f) local(%.1f|%.1f) delta(%.1f|%.1f)", e.screenX, e.screenY, e.clientX, e.clientY, e.localX, e.localY, e.deltaX, e.deltaY); }); text.addEventListener("mousemove", func(e) { printf("move: screen(%.1f|%.1f) client(%.1f|%.1f) local(%.1f|%.1f) delta(%.1f|%.1f)", e.screenX, e.screenY, e.clientX, e.clientY, e.localX, e.localY, e.deltaX, e.deltaY); });

View file

@ -22,10 +22,16 @@ gui.Widget = {
m.setSizeHint([32, 32]); m.setSizeHint([32, 32]);
m.setMaximumSize([m._MAX_SIZE, m._MAX_SIZE]); m.setMaximumSize([m._MAX_SIZE, m._MAX_SIZE]);
m.setSetGeometryFunc(m.setGeometry); m.setSetGeometryFunc(m._impl.setGeometry);
return m; return m;
}, },
setFixedSize: func(x, y)
{
me.setMinimumSize([x, y]);
me.setSizeHint([x, y]);
me.setMaximumSize([x, y]);
},
# Move the widget to the given position (relative to its parent) # Move the widget to the given position (relative to its parent)
move: func(x, y) move: func(x, y)
{ {
@ -48,11 +54,11 @@ gui.Widget = {
}, },
# Set geometry of widget (usually used by layouting system) # Set geometry of widget (usually used by layouting system)
# #
# @param geom [<min-x>, <min-y>, <max-x>, <max-y>] # @param geom [<x>, <y>, <width>, <height>]
setGeometry: func(geom) setGeometry: func(geom)
{ {
me.move(geom[0], geom[1]); me.move(geom[0], geom[1]);
me.setSize(geom[2] - geom[0], geom[3] - geom[1]); me.setSize(geom[2], geom[3]);
me._onStateChange(); me._onStateChange();
return me; return me;
}, },
@ -69,7 +75,7 @@ gui.Widget = {
me._focused = 1; me._focused = 1;
canvas._focused_widget = me; canvas._focused_widget = me;
me.onFocusIn(); me._trigger("focus-in");
me._onStateChange(); me._onStateChange();
return me; return me;
@ -83,15 +89,16 @@ gui.Widget = {
me._focused = 0; me._focused = 0;
me.getCanvas()._focused_widget = nil; me.getCanvas()._focused_widget = nil;
me.onFocusOut(); me._trigger("focus-out");
me._onStateChange(); me._onStateChange();
return me; return me;
}, },
onFocusIn: func {}, listen: func(type, cb)
onFocusOut: func {}, {
onMouseEnter: func {}, me._view._root.addEventListener("cb." ~ type, cb);
onMouseLeave: func {}, return me;
},
# protected: # protected:
_MAX_SIZE: 32768, # size for "no size-limit" _MAX_SIZE: 32768, # size for "no size-limit"
_onStateChange: func {}, _onStateChange: func {},
@ -112,7 +119,7 @@ gui.Widget = {
root.addEventListener("mouseenter", func { root.addEventListener("mouseenter", func {
me._hover = 1; me._hover = 1;
me.onMouseEnter(); me._trigger("mouse-enter");
me._onStateChange(); me._onStateChange();
}); });
root.addEventListener("mousedown", func { root.addEventListener("mousedown", func {
@ -121,10 +128,17 @@ gui.Widget = {
}); });
root.addEventListener("mouseleave", func { root.addEventListener("mouseleave", func {
me._hover = 0; me._hover = 0;
me.onMouseLeave(); me._trigger("mouse-leave");
me._onStateChange(); me._onStateChange();
}); });
}, },
_trigger: func(type, data = nil)
{
me._view._root.dispatchEvent(
canvas.CustomEvent.new("cb." ~ type, {detail: data})
);
return me;
},
_windowFocus: func _windowFocus: func
{ {
var canvas = me.getCanvas(); var canvas = me.getCanvas();

View file

@ -70,7 +70,7 @@ DefaultStyle.widgets.button = {
me._label.set("fill", me._style.getColor("fg_color")); me._label.set("fill", me._style.getColor("fg_color"));
file ~= "button"; file ~= "button";
if( model._active ) if( model._down )
{ {
file ~= "-active"; file ~= "-active";
me._label.setTranslation(w / 2 + 1, h / 2 + 6); me._label.setTranslation(w / 2 + 1, h / 2 + 6);
@ -82,7 +82,7 @@ DefaultStyle.widgets.button = {
if( model._focused and !backdrop ) if( model._focused and !backdrop )
file ~= "-focused"; file ~= "-focused";
if( model._hover and !model._active ) if( model._hover and !model._down )
{ {
file ~= "-hover"; file ~= "-hover";
me._bg.set("fill", me._style.getColor("button_bg_color_hover")); me._bg.set("fill", me._style.getColor("button_bg_color_hover"));
@ -104,6 +104,9 @@ DefaultStyle.widgets.label = {
{ {
if( me['_bg'] != nil ) if( me['_bg'] != nil )
me._bg.reset().rect(0, 0, w, h); me._bg.reset().rect(0, 0, w, h);
if( me['_img'] != nil )
me._img.set("size[0]", w)
.set("size[1]", h);
if( me['_text'] != nil ) if( me['_text'] != nil )
# TODO different alignment # TODO different alignment
me._text.setTranslation(2, h / 2); me._text.setTranslation(2, h / 2);
@ -115,11 +118,23 @@ DefaultStyle.widgets.label = {
return me._deleteElement('text'); return me._deleteElement('text');
me._createElement("text", "text") me._createElement("text", "text")
.set("text", text); .set("text", text)
.set("fill", "black");
# TODO get real font metrics # TODO get real font metrics
model.setMinimumSize([size(text) * 5 + 4, 14]); model.setMinimumSize([size(text) * 5 + 4, 14]);
model.setSizeHint([size(text) * 8 + 8, 24]); model.setSizeHint([size(text) * 5 + 14, 24]);
return me;
},
setImage: func(model, img)
{
if( img == nil or size(img) == 0 )
return me._deleteElement('img');
me._createElement("img", "image")
.set("src", img)
.set("preserveAspectRatio", "xMidYMid slice");
return me; return me;
}, },

View file

@ -4,7 +4,8 @@ gui.widgets.Button = {
var cfg = Config.new(cfg); var cfg = Config.new(cfg);
var m = gui.Widget.new(gui.widgets.Button); var m = gui.Widget.new(gui.widgets.Button);
m._focus_policy = m.StrongFocus; m._focus_policy = m.StrongFocus;
m._active = 0; m._down = 0;
m._checkable = 0;
m._flat = cfg.get("flat", 0); m._flat = cfg.get("flat", 0);
if( style != nil and !m._flat ) if( style != nil and !m._flat )
@ -17,25 +18,41 @@ gui.widgets.Button = {
me._view.setText(me, text); me._view.setText(me, text);
return me; return me;
}, },
setActive: func setCheckable: func(checkable)
{ {
if( me._active ) me._checkable = checkable;
return me;
},
setChecked: func(checked = 1)
{
if( !me._checkable or me._down == checked )
return me; return me;
me._active = 1; me._trigger("clicked", {checked: checked});
me._trigger("toggled", {checked: checked});
me._down = checked;
me._onStateChange(); me._onStateChange();
return me; return me;
}, },
clearActive: func setDown: func(down = 1)
{ {
if( !me._active ) if( me._checkable or me._down == down )
return me; return me;
me._active = 0; me._down = down;
me._onStateChange(); me._onStateChange();
return me; return me;
}, },
onClick: func {}, toggle: func
{
if( !me._checkable )
me._trigger("clicked", {checked: 0});
else
me.setChecked(!me._down);
return me;
},
# protected: # protected:
_onStateChange: func _onStateChange: func
{ {
@ -45,14 +62,11 @@ gui.widgets.Button = {
_setView: func(view) _setView: func(view)
{ {
var el = view._root; var el = view._root;
el.addEventListener("mousedown", func me.setActive()); el.addEventListener("mousedown", func me.setDown(1));
el.addEventListener("mouseup", func me.clearActive()); el.addEventListener("mouseup", func me.setDown(0));
el.addEventListener("click", func me.toggle());
# Use 'call' to ensure 'me' is not set and can be used in the closure of el.addEventListener("mouseleave",func me.setDown(0));
# custom callbacks. TODO pass 'me' as argument?
el.addEventListener("click", func call(me.onClick));
el.addEventListener("mouseleave",func me.clearActive());
el.addEventListener("drag", func(e) e.stopPropagation()); el.addEventListener("drag", func(e) e.stopPropagation());
call(gui.Widget._setView, [view], me); call(gui.Widget._setView, [view], me);

View file

@ -13,6 +13,11 @@ gui.widgets.Label = {
me._view.setText(me, text); me._view.setText(me, text);
return me; return me;
}, },
setImage: func(img)
{
me._view.setImage(me, img);
return me;
},
setBackground: func(bg) setBackground: func(bg)
{ {
me._view.setBackground(me, bg); me._view.setBackground(me, bg);

View file

@ -7,6 +7,7 @@ gui.widgets.ScrollArea = {
m._scroll_pos = [0,0]; m._scroll_pos = [0,0];
m._max_scroll = [0, 0]; m._max_scroll = [0, 0];
m._content_size = [0, 0]; m._content_size = [0, 0];
m._layout = nil;
if( style != nil ) if( style != nil )
m._setView( style.createWidget(parent, "scroll-area", cfg) ); m._setView( style.createWidget(parent, "scroll-area", cfg) );
@ -15,6 +16,12 @@ gui.widgets.ScrollArea = {
return m; return m;
}, },
setLayout: func(l)
{
me._layout = l;
l.setParent(me);
return me.update();
},
getContent: func() getContent: func()
{ {
return me._view.content; return me._view.content;
@ -143,12 +150,30 @@ gui.widgets.ScrollArea = {
_updateBB: func() _updateBB: func()
{ {
# TODO only update on content resize # TODO only update on content resize
var bb = me.getContent().getTightBoundingBox(); if( me._layout == nil )
{
var bb = me.getContent().getTightBoundingBox();
if( bb[2] < bb[0] or bb[3] < bb[1] ) if( bb[2] < bb[0] or bb[3] < bb[1] )
return nil; return nil;
var w = bb[2] - bb[0]; var w = bb[2] - bb[0];
var h = bb[3] - bb[1]; var h = bb[3] - bb[1];
var cur_offset = me.getContent().getTranslation();
me._content_offset = [cur_offset[0] - bb[0], cur_offset[1] - bb[1]];
}
else
{
var min_size = me._layout.minimumSize();
var max_size = me._layout.maximumSize();
var size_hint = me._layout.sizeHint();
var w = math.min(max_size[0], math.max(math.max(min_size[0], size_hint[0]), me._size[0]));
var h = math.min(max_size[1], math.max(math.max(min_size[1], size_hint[1]), me._size[1]));
me._layout.setGeometry([0, 0, w, h]);
# Layout always has the origin at (0, 0)
me._content_offset = [0, 0];
}
if( w > me._size[0] ) if( w > me._size[0] )
{ {
@ -168,8 +193,5 @@ gui.widgets.ScrollArea = {
me._content_size[0] = w; me._content_size[0] = w;
me._content_size[1] = h; me._content_size[1] = h;
var cur_offset = me.getContent().getTranslation();
me._content_offset = [cur_offset[0] - bb[0], cur_offset[1] - bb[1]];
} }
}; };