1
0
Fork 0

canvas.gui: restructuring, fixing and new Label widget.

This commit is contained in:
Thomas Geymayer 2014-06-09 00:37:14 +02:00
parent 7b46de3e27
commit 7e2c93825f
6 changed files with 249 additions and 139 deletions

View file

@ -13,6 +13,7 @@ loadGUIFile("Style.nas");
loadGUIFile("Widget.nas");
loadGUIFile("styles/DefaultStyle.nas");
loadWidget("Button");
loadWidget("Label");
loadWidget("ScrollArea");
var style = DefaultStyle.new("AmbianceClassic");
@ -24,7 +25,7 @@ var WindowButton = {
_name: name
};
m._focus_policy = m.NoFocus;
m._setRoot( parent.createChild("image", "WindowButton-" ~ name) );
m._setView({_root: parent.createChild("image", "WindowButton-" ~ name)});
return m;
},
# protected:
@ -41,7 +42,7 @@ var WindowButton = {
else if( window_focus )
file ~= "_normal";
me._root.set("src", file ~ ".png");
me._view._root.set("src", file ~ ".png");
}
};
@ -110,7 +111,7 @@ var Window = {
];
me._canvas = new({
size: [2 * size[0], 2 * size[1]],
size: [size[0], size[1]],
view: size,
placement: {
type: "window",
@ -538,18 +539,22 @@ root.createChild("image")
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.set("fill", style.getColor("text_color"));
gui.widgets.Button.new(root, style, {size: [64, 26]})
gui.widgets.Button.new(root, style, {})
.setText("Ok")
.move(20, 250);
gui.widgets.Button.new(root, style, {size: [64, 26]})
.move(20, 250)
.setSize(64, 26);
gui.widgets.Button.new(root, style, {})
.setText("Apply")
.move(100, 250);
gui.widgets.Button.new(root, style, {size: [64, 64]})
.move(100, 250)
.setSize(64, 26);
gui.widgets.Button.new(root, style, {})
.setText("Cancel")
.move(180, 200);
.move(180, 200)
.setSize(64, 64);
var scroll = gui.widgets.ScrollArea.new(root, style, {size: [96, 128]})
.move(20, 100);
var scroll = gui.widgets.ScrollArea.new(root, style, {})
.move(20, 100)
.setSize(96, 128);
var txt = scroll.getContent().createChild("text")
.set("text", "01hallo\n02asdasd\n03\n04\n05asdasd06\n07ß\n08\n09asdasd\n10\n11");
scroll.update();

View file

@ -8,19 +8,32 @@ gui.Widget = {
#
new: func(derived)
{
return canvas.Widget.new({
var m = canvas.Widget.new({
parents: [derived, gui.Widget],
_focused: 0,
_focus_policy: gui.Widget.NoFocus,
_hover: 0,
_root: nil,
_size: [64, 64]
_view: nil,
_pos: [0, 0],
_size: [32, 32]
});
m.setMinimumSize([16, 16]);
m.setSizeHint([32, 32]);
m.setMaximumSize([m._MAX_SIZE, m._MAX_SIZE]);
m.setSetGeometryFunc(m.setGeometry);
return m;
},
# Move the widget to the given position (relative to its parent)
move: func(x, y)
{
me._root.setTranslation(x, y);
me._pos[0] = x;
me._pos[1] = y;
if( me._view != nil )
me._view._root.setTranslation(x, y);
return me;
},
#
@ -28,6 +41,20 @@ gui.Widget = {
{
me._size[0] = w;
me._size[1] = h;
if( me._view != nil )
me._view.setSize(w, h);
return me;
},
# Set geometry of widget (usually used by layouting system)
#
# @param geom [<min-x>, <min-y>, <max-x>, <max-y>]
setGeometry: func(geom)
{
me.move(geom[0], geom[1]);
me.setSize(geom[2] - geom[0], geom[3] - geom[1]);
me._onStateChange();
return me;
},
#
setFocus: func
@ -68,11 +95,12 @@ gui.Widget = {
# protected:
_MAX_SIZE: 32768, # size for "no size-limit"
_onStateChange: func {},
_setRoot: func(el)
_setView: func(view)
{
me._root = el;
me._view = view;
var canvas = el.getCanvas();
var root = view._root;
var canvas = root.getCanvas();
me.setCanvas(canvas);
canvas.addEventListener("wm.focus-in", func {
@ -82,16 +110,16 @@ gui.Widget = {
me._onStateChange();
});
el.addEventListener("mouseenter", func {
root.addEventListener("mouseenter", func {
me._hover = 1;
me.onMouseEnter();
me._onStateChange();
});
el.addEventListener("mousedown", func {
root.addEventListener("mousedown", func {
if( bits.test(me._focus_policy, me.ClickFocus / 2) )
me.setFocus();
});
el.addEventListener("mouseleave", func {
root.addEventListener("mouseleave", func {
me._hover = 0;
me.onMouseLeave();
me._onStateChange();

View file

@ -27,38 +27,40 @@ DefaultStyle.widgets.button = {
padding: [6, 8, 6, 8],
new: func(parent, cfg)
{
me.element = parent.createChild("group", "button");
me._root = parent.createChild("group", "button");
me._bg =
me.element.createChild("path");
me._root.createChild("path");
me._border =
me.element.createChild("image", "button")
.set("slice", "10 12"); #"7")
me._root.createChild("image", "button")
.set("slice", "10 12"); #"7")
me._label =
me.element.createChild("text")
.setFont("LiberationFonts/LiberationSans-Regular.ttf")
.set("character-size", 14)
.set("alignment", "center-baseline");
me.setSize( cfg.get("size", [26, 26]) );
me._root.createChild("text")
.set("font", "LiberationFonts/LiberationSans-Regular.ttf")
.set("character-size", 14)
.set("alignment", "center-baseline");
},
setSize: func(size)
setSize: func(w, h)
{
me._bg.reset()
.rect( 3,
3,
size[0] - 6,
size[1] - 6,
{"border-radius": 5} );
me._border.setSize(size);
me.size = size;
.rect(3, 3, w - 6, h - 6, {"border-radius": 5});
me._border.setSize(w, h);
},
setText: func(text)
setText: func(model, text)
{
me._label.set("text", text);
# TODO get real font metrics
model.setMinimumSize([size(text) * 5 + 6, 16]);
model.setSizeHint([size(text) * 8 + 16, 32]);
return me;
},
update: func(active, focused, hover, backdrop)
update: func(model)
{
var backdrop = !model._windowFocus();
var (w, h) = model._size;
var file = me._style._dir_widgets ~ "/";
if( backdrop )
{
file ~= "backdrop-";
@ -68,19 +70,19 @@ DefaultStyle.widgets.button = {
me._label.set("fill", me._style.getColor("fg_color"));
file ~= "button";
if( active )
if( model._active )
{
file ~= "-active";
me._label.setTranslation(me.size[0] / 2 + 1, me.size[1] / 2 + 6);
me._label.setTranslation(w / 2 + 1, h / 2 + 6);
}
else
me._label.setTranslation(me.size[0] / 2, me.size[1] / 2 + 5);
me._label.setTranslation(w / 2, h / 2 + 5);
if( focused and !backdrop )
if( model._focused and !backdrop )
file ~= "-focused";
if( hover and !active )
if( model._hover and !model._active )
{
file ~= "-hover";
me._bg.set("fill", me._style.getColor("button_bg_color_hover"));
@ -92,18 +94,88 @@ DefaultStyle.widgets.button = {
}
};
# A label
DefaultStyle.widgets.label = {
new: func(parent, cfg)
{
me._root = parent.createChild("group", "label");
},
setSize: func(w, h)
{
if( me['_bg'] != nil )
me._bg.reset().rect(0, 0, w, h);
if( me['_text'] != nil )
# TODO different alignment
me._text.setTranslation(2, h / 2);
return me;
},
setText: func(model, text)
{
if( text == nil or size(text) == 0 )
return me._deleteElement('text');
me._createElement("text", "text")
.set("text", text);
# TODO get real font metrics
model.setMinimumSize([size(text) * 5 + 4, 14]);
model.setSizeHint([size(text) * 8 + 8, 24]);
return me;
},
# @param bg CSS color or 'none'
setBackground: func(model, bg)
{
if( bg == nil or bg == "none" )
return me._deleteElement("bg");
me._createElement("bg", "path")
.set("fill", bg);
me.setSize(model._size[0], model._size[1]);
return me;
},
# protected:
_createElement: func(name, type)
{
var mem = '_' ~ name;
if( me[ mem ] == nil )
{
me[ mem ] = me._root.createChild(type, "label-" ~ name);
if( type == "text" )
{
me[ mem ].set("font", "LiberationFonts/LiberationSans-Regular.ttf")
.set("character-size", 14)
.set("alignment", "left-center");
}
}
return me[ mem ];
},
_deleteElement: func(name)
{
name = '_' ~ name;
if( me[ name ] != nil )
{
me[ name ].del();
me[ name ] = nil;
}
return me;
}
};
# ScrollArea
DefaultStyle.widgets["scroll-area"] = {
new: func(parent, cfg)
{
me.element = parent.createChild("group", "scroll-area");
me._root = 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");
me._bg = me._root.createChild("path", "background")
.set("fill", "#e0e0e0");
me.content = me._root.createChild("group", "scroll-content")
.set("clip-frame", Element.PARENT);
me.vert = me._newScroll(me._root, "vert");
me.horiz = me._newScroll(me._root, "horiz");
},
setColorBackground: func
{
@ -111,25 +183,25 @@ DefaultStyle.widgets["scroll-area"] = {
var arg = arg[0];
me._bg.setColorFill(arg);
},
update: func(widget)
update: func(model)
{
me.horiz.reset();
if( widget._max_scroll[0] > 1 )
if( model._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.horiz.moveTo(model._scroll_pos[0], model._size[1] - 2)
.horiz(model._size[0] - model._max_scroll[0]);
me.vert.reset();
if( widget._max_scroll[1] > 1 )
if( model._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.vert.moveTo(model._size[0] - 2, model._scroll_pos[1])
.vert(model._size[1] - model._max_scroll[1]);
me._bg.reset()
.rect(0, 0, widget._size[0], widget._size[1]);
.rect(0, 0, model._size[0], model._size[1]);
me.content.set(
"clip",
"rect(0, " ~ widget._size[0] ~ ", " ~ widget._size[1] ~ ", 0)"
"rect(0, " ~ model._size[0] ~ ", " ~ model._size[1] ~ ", 0)"
);
},
# private:

View file

@ -8,22 +8,13 @@ gui.widgets.Button = {
m._flat = cfg.get("flat", 0);
if( style != nil and !m._flat )
{
m._button = style.createWidget(parent, "button", cfg);
m._setRoot(m._button.element);
}
m.setMinimumSize([16, 16]);
m.setSizeHint([32, 32]);
m.setMaximumSize([m._MAX_SIZE, m._MAX_SIZE]);
m.setSetGeometryFunc(m.setGeometry);
m._setView( style.createWidget(parent, "button", cfg) );
return m;
},
setText: func(text)
{
me._button.setText(text);
me._view.setText(me, text);
return me;
},
setActive: func
@ -45,21 +36,15 @@ gui.widgets.Button = {
return me;
},
onClick: func {},
setGeometry: func(geom)
{
me.move(geom[0], geom[1]);
me._button.setSize([geom[2] - geom[0], geom[3] - geom[1]]);
me._onStateChange();
return me;
},
# protected:
_onStateChange: func
{
if( me._button != nil )
me._button.update(me._active, me._focused, me._hover, !me._windowFocus());
if( me._view != nil )
me._view.update(me);
},
_setRoot: func(el)
_setView: func(view)
{
var el = view._root;
el.addEventListener("mousedown", func me.setActive());
el.addEventListener("mouseup", func me.clearActive());
@ -70,6 +55,6 @@ gui.widgets.Button = {
el.addEventListener("mouseleave",func me.clearActive());
el.addEventListener("drag", func(e) e.stopPropagation());
call(gui.Widget._setRoot, [el], me);
call(gui.Widget._setView, [view], me);
}
};

View file

@ -0,0 +1,21 @@
gui.widgets.Label = {
new: func(parent, style, cfg)
{
var cfg = Config.new(cfg);
var m = gui.Widget.new(gui.widgets.Label);
m._focus_policy = m.NoFocus;
m._setView( style.createWidget(parent, "label", cfg) );
return m;
},
setText: func(text)
{
me._view.setText(me, text);
return me;
},
setBackground: func(bg)
{
me._view.setBackground(me, bg);
return me;
}
};

View file

@ -3,44 +3,21 @@ gui.widgets.ScrollArea = {
{
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);
m._focus_policy = m.NoFocus;
m._scroll_pos = [0,0];
m._max_scroll = [0, 0];
m._content_size = [0, 0];
m.setMinimumSize([16, 16]);
m.setSizeHint([128, 128]);
m.setMaximumSize([m._MAX_SIZE, m._MAX_SIZE]);
m.setSetGeometryFunc(m.setGeometry);
if( style != nil )
{
m._scroll = style.createWidget(parent, "scroll-area", cfg);
m._setRoot(m._scroll.element);
m._setView( style.createWidget(parent, "scroll-area", cfg) );
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])
);
}
m.setMinimumSize([32, 32]);
return m;
},
getContent: func()
{
return me._scroll.content;
return me._view.content;
},
# Set the background color for the content area.
#
@ -49,7 +26,7 @@ gui.widgets.ScrollArea = {
{
if( size(arg) == 1 )
var arg = arg[0];
me._scroll.setColorBackground(arg);
me._view.setColorBackground(arg);
},
# Reset the size of the content area, e.g. on window resize.
#
@ -71,15 +48,15 @@ gui.widgets.ScrollArea = {
{
var bb = me._updateBB();
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._scroll_pos[0] = math.max(0, math.min(x, me._max_scroll[0]));
me._scroll_pos[1] = math.max(0, math.min(y, me._max_scroll[1]));
me.update(bb);
},
# Move the scrollable area to the top-most position and update.
moveToTop: func()
{
me._pos[1] = 0;
me._scroll_pos[1] = 0;
me.update();
},
@ -88,14 +65,14 @@ gui.widgets.ScrollArea = {
{
var bb = me._updateBB();
me._pos[1] = me._max_scroll[1];
me._scroll_pos[1] = me._max_scroll[1];
me.update(bb);
},
# Move the scrollable area to the left-most position and update.
moveToLeft: func()
{
me._pos[0] = 0;
me._scroll_pos[0] = 0;
me.update();
},
@ -104,16 +81,10 @@ gui.widgets.ScrollArea = {
{
var bb = me._updateBB();
me._pos[0] = me._max_scroll[0];
me._scroll_pos[0] = me._max_scroll[0];
me.update(bb);
},
setGeometry: func(geom)
{
me.move(geom[0], geom[1]);
me.setSize([geom[2] - geom[0], geom[3] - geom[1]]);
return me;
},
# Update scroll bar and content area.
#
# Needs to be called when the size of the content changes.
@ -126,32 +97,51 @@ gui.widgets.ScrollArea = {
me._content_offset[1] ];
if( me._max_scroll[0] > 1 )
offset[0] -= (me._pos[0] / me._max_scroll[0])
offset[0] -= (me._scroll_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])
offset[1] -= (me._scroll_pos[1] / me._max_scroll[1])
* (me._content_size[1] - me._size[1]);
me.getContent().setTranslation(offset);
me._scroll.update(me);
me._view.update(me);
me.getContent().update();
return me;
},
# protected:
_setRoot: func(el)
_setView: func(view)
{
el.addEventListener("wheel", func(e) me.moveTo(me._pos[0], me._pos[1] - e.deltaY));
view.vert.addEventListener("mousedown", func(e) me._dragStart(e));
view.horiz.addEventListener("mousedown", func(e) me._dragStart(e));
call(gui.Widget._setRoot, [el], me);
view.vert.addEventListener
(
"drag",
func(e) me.moveTo(me._scroll_pos[0], me._drag_offsetY + e.clientY)
);
view.horiz.addEventListener
(
"drag",
func(e) me.moveTo(me._drag_offsetX + e.clientX, me._scroll_pos[1])
);
view._root.addEventListener
(
"wheel",
func(e) me.moveTo(me._scroll_pos[0], me._scroll_pos[1] - e.deltaY)
);
call(gui.Widget._setView, [view], me);
},
_dragStart: func(e)
{
me._drag_offsetX = me._pos[0] - e.clientX;
me._drag_offsetY = me._pos[1] - e.clientY;
me._drag_offsetX = me._scroll_pos[0] - e.clientX;
me._drag_offsetY = me._scroll_pos[1] - e.clientY;
},
_updateBB: func() {
_updateBB: func()
{
# TODO only update on content resize
var bb = me.getContent().getTightBoundingBox();
@ -161,16 +151,25 @@ gui.widgets.ScrollArea = {
var h = bb[3] - bb[1];
if( w > me._size[0] )
me._max_scroll[0] = me._size[0] * (1 - me._size[0] / w);
else me._max_scroll[0] = 0;
{
var scroller_size = math.max(12, me._size[0] * (me._size[0] / w));
me._max_scroll[0] = me._size[0] - scroller_size;
}
else
me._max_scroll[0] = 0;
if( h > me._size[1] )
me._max_scroll[1] = me._size[1] * (1 - me._size[1] / h);
else me._max_scroll[1] = 0;
{
var scroller_size = math.max(12, me._size[1] * (me._size[1] / h));
me._max_scroll[1] = me._size[1] - scroller_size;
}
else
me._max_scroll[1] = 0;
me._content_size[0] = w;
me._content_size[1] = h;
var cur_offset = me.getContent().getTranslation();
me._content_offset = [cur_offset[0] - bb[0], cur_offset[1] - bb[1]];
},
}
};