From 72e3937ec6becc2c11cf83e43cc6d8bb240a690b Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Thu, 6 Jun 2013 22:46:37 +0200 Subject: [PATCH] Basic window decorator with title bar and close button. Extend the canvas.Window class to create a simple window decoration if a type for it (currently every type maps to the same style) is given. It supports moving the window by dragging inside the title bar and setting a window title. --- Nasal/canvas/api.nas | 16 +-- Nasal/canvas/gui.nas | 98 +++++++++++++++--- gui/images/shadow.png | Bin 0 -> 595 bytes .../AmbianceClassic/close_focused_normal.png | Bin 0 -> 833 bytes .../close_focused_prelight.png | Bin 0 -> 858 bytes .../AmbianceClassic/close_focused_pressed.png | Bin 0 -> 589 bytes 6 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 gui/images/shadow.png create mode 100644 gui/styles/AmbianceClassic/close_focused_normal.png create mode 100644 gui/styles/AmbianceClassic/close_focused_prelight.png create mode 100644 gui/styles/AmbianceClassic/close_focused_pressed.png diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas index b63dcc5d9..6e575d5d3 100644 --- a/Nasal/canvas/api.nas +++ b/Nasal/canvas/api.nas @@ -833,10 +833,12 @@ var Canvas = { # @param id Optional id/name for the group createGroup: func(id = nil) { - var ghost = me._createGroup(); - return { - parents: [ Group.new(ghost) ] - }; + return Group.new(me._createGroup(id)); + }, + # Get the group with the given name + getGroup: func(id) + { + return Group.new(me._getGroup(id)); }, # Set the background color # @@ -859,10 +861,12 @@ var Canvas = { var wrapCanvas = func(canvas_ghost) { - return { - parents: [Canvas, canvas_ghost], + var m = { + parents: [PropertyElement, Canvas, canvas_ghost], texture: props.wrapNode(canvas_ghost._node_ghost) }; + m._node = m.texture; + return m; } # Create a new canvas. Pass parameters as hash, eg: diff --git a/Nasal/canvas/gui.nas b/Nasal/canvas/gui.nas index 8cf66dc0e..6c66ac0ab 100644 --- a/Nasal/canvas/gui.nas +++ b/Nasal/canvas/gui.nas @@ -2,23 +2,31 @@ var Window = { # Constructor # # @param size ([width, height]) - new: func(size, id = nil) + new: func(size, type = nil, id = nil) { + var ghost = _newWindowGhost(id); var m = { - parents: [Window, PropertyElement.new(["/sim/gui/canvas", "window"], id)] + parents: [Window, PropertyElement, ghost], + _node: props.wrapNode(ghost._node_ghost) }; + m.setInt("size[0]", size[0]); m.setInt("size[1]", size[1]); + # TODO better default position + m.move(0,0); + # arg = [child, listener_node, mode, is_child_event] setlistener(m._node, func m._propCallback(arg[0], arg[2]), 0, 2); + if( type ) + m.set("type", type); return m; }, # Destructor del: func { - me.parents[1].del(); + me._node.remove(); if( me["_canvas"] != nil ) me._canvas.del(); }, @@ -58,15 +66,19 @@ var Window = { { return me['_canvas']; }, + getCanvasDecoration: func() + { + return wrapCanvas(me._getCanvasDecoration()); + }, setPosition: func(x, y) { - me.setInt("x", x); - me.setInt("y", y); + me.setInt("tf/t[0]", x); + me.setInt("tf/t[1]", y); }, move: func(x, y) { - me.setInt("x", me.get("x", 0) + x); - me.setInt("y", me.get("y", 0) + y); + me.setInt("tf/t[0]", me.get("tf/t[0]", 10) + x); + me.setInt("tf/t[1]", me.get("tf/t[1]", 30) + y); }, # Raise to top of window stack raise: func() @@ -76,11 +88,22 @@ var Window = { # private: _propCallback: func(child, mode) { + if( !me._node.equals(child.getParent()) ) + return; + var name = child.getName(); + # support for CSS like position: absolute; with right and/or bottom margin - if( child.getName() == "right" ) - me._handlePositionAbsolute(child, mode, child.getName(), 0); - else if( child.getName() == "bottom" ) - me._handlePositionAbsolute(child, mode, child.getName(), 1); + if( name == "right" ) + me._handlePositionAbsolute(child, mode, name, 0); + else if( name == "bottom" ) + me._handlePositionAbsolute(child, mode, name, 1); + + # update decoration on type change + else if( name == "type" ) + { + if( mode == 0 ) + settimer(func me._updateDecoration(), 0); + } }, _handlePositionAbsolute: func(child, mode, name, index) { @@ -112,10 +135,61 @@ var Window = { { me.setInt ( - index == 0 ? "x" : "y", + "tf/t[" ~ index ~ "]", getprop("/sim/gui/canvas/size[" ~ index ~ "]") - me.get(name) - me.get("size[" ~ index ~ "]") ); + }, + _updateDecoration: func() + { + var border_radius = 9; + me.set("decoration-border", "25 1 1"); + me.set("shadow-inset", int((1 - math.cos(45 * D2R)) * border_radius + 0.5)); + me.set("shadow-radius", 5); + + var canvas_deco = me.getCanvasDecoration(); + canvas_deco.addEventListener("mousedown", func me.raise()); + canvas_deco.set("blend-source-rgb", "src-alpha"); + canvas_deco.set("blend-destination-rgb", "one-minus-src-alpha"); + canvas_deco.set("blend-source-alpha", "one"); + canvas_deco.set("blend-destination-alpha", "one"); + + var group_deco = canvas_deco.getGroup("decoration"); + var title_bar = group_deco.createChild("group", "title_bar"); + title_bar.addEventListener("drag", func(e) { me.move(e.deltaX, e.deltaY); }); + title_bar + .rect( 0, 0, + me.get("size[0]"), + me.get("size[1]"), #25, + {"border-top-radius": border_radius} ) + .setColorFill(0.25,0.24,0.22) + .setStrokeLineWidth(0); + + var style_dir = "gui/styles/AmbianceClassic/"; + + # close icon + var x = 10; + var y = 3; + var w = 19; + var h = 19; + var ico = title_bar.createChild("image", "icon-close") + .set("file", style_dir ~ "close_focused_normal.png") + .setTranslation(x,y); + ico.addEventListener("click", func me.del()); + ico.addEventListener("mouseover", func ico.set("file", style_dir ~ "close_focused_prelight.png")); + ico.addEventListener("mousedown", func ico.set("file", style_dir ~ "close_focused_pressed.png")); + ico.addEventListener("mouseout", func ico.set("file", style_dir ~ "close_focused_normal.png")); + + # title + me._title = title_bar.createChild("text", "title") + .set("alignment", "left-center") + .set("character-size", 14) + .set("font", "LiberationFonts/LiberationSans-Bold.ttf") + .setTranslation(x + 1.5 * w, y + 0.5 * h); + + var title = me.get("title", "Canvas Dialog"); + me._node.getNode("title", 1).alias(me._title._node.getPath() ~ "/text"); + me.set("title", title); } }; diff --git a/gui/images/shadow.png b/gui/images/shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..597d7a7c66f75003a81d60354c2631e849aea4b8 GIT binary patch literal 595 zcmV-Z0<8UsP)~F1Nk9!OfTeV;{c9lJ`3V?-0XRyJz{#Smfd;q(*3ylD z41@sUoew|{bU-T&kPToVr(57bdIPKkUWF_y`bm) zzEm;#qoRJ3pX^FDS_Vs(!47zl-nuO204(|s*%c~RC#m8YY*eBh@T~QnBC7(x)s?LR`Ki&2J$pyh29#5X# zX`J%YIF+aI%1_hupT(;_OHh55r130S^Ldfui!{9#`BpFTZC_>>yv#CwS>W)h(BV~) z18k74Cs6^M(#WAGf zR_cV8=1hqq?Z&*W$=Mku9Ew7bO0M5jqo-|3S>m>MWA7U0W^+#6U(5IA8`nJeS@gd0 zobC5{zk{d#ab(pr%bI)dLe_=XSN8K=4&cjwqW!4!f|O5L#8Tae6VEs8tWnHZeXMKU z8vUt1r<`0;b$a4q>9YIx>wetGJhD)^?Gi(dJ|n}mZ44g#LKi0PTcUC{>e{H zYfCR&JkA+d6Zf*D?EIdNq(>cX=e|^NS4!kcSGIh8ce3Rf-#S*uhz)$v%M$k9bT0ln z&*J>~Qr~;}ipsZdrRYRwu9EPOAN`=v#Z_lKsy`PP4U6O-^=``5Smq zxI^xg3-jBkpZB9SYs(~kn;CE;b=|=!FmU*IE&we5N=nY9h2_=pR=FQ YW{bDko0aCez%XX;boFyt=akR{00FUH8~^|S literal 0 HcmV?d00001 diff --git a/gui/styles/AmbianceClassic/close_focused_prelight.png b/gui/styles/AmbianceClassic/close_focused_prelight.png new file mode 100644 index 0000000000000000000000000000000000000000..5768c54c18365c9b3f1a89130177ab335f9a40a5 GIT binary patch literal 858 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{Rd`VB8$w6XN=7PVIj%u(3ABM0U28 zXoB{3R&Wsqdut%u9<0XB#sb8K8RDQI43zb@Gxbpu^HG=d1tJXzKXq|GdsBZ634cw= zFb9(;FQ*u9r+6RdQfKXYe~Xp?%brC4-bDZY^oY5Mo(qzFmZteH3%A@HpuELLdV7@N zf#R@(g+YfR^$w*w9nSYZT%UF%-t1^e=&@-1V-=Cd+6s>s2A)VXKhd0dGT-NPNyynE zzq2)Q=i&{|C7WGHGPzI|c0G{)W{m3Hx|sW&xeps-A9m$Eno#y6nC(f0@6%AOr(rzL z!ug&>2tSJwdsgZ9Y-Z#0SlJixiZ7GZU#9E7%rJPBZSpF|>{V<0>olF$t?_S)Y~SXX zzRfj%TkPz<^7tR_iJhA@2N$XYn)3FliKGf_Qs0!K>D{s>@|2KP)+V5sx6cf< zkj1_~C)X~woV(M0&-ZiB_k6y$bNectP8TLeffY{!6M}XI-CY@WYN^uXOrNs<+wbQc zN)cUVu;cU5OYtjbluN&22{V>Cn^N3*-$`$FC!eBC^X&c|DOzX$7Q76ZWS!B-=zQEh z@>_xNM2|ObH@~?q!8PNQVET-!_juF1_a87QbXQKek=wKE{`Kl*U%TZ^WOpBAxV+Dn zaj#FQ&%UOAe^xyGeok4$buF(?$!&-JIUlNhuNipieLrirrsVA8lpCk+2lupbB$dCL zwP`FiN4$y!CU)fmLz}_V)z4*}Q$iB}1_y>x literal 0 HcmV?d00001 diff --git a/gui/styles/AmbianceClassic/close_focused_pressed.png b/gui/styles/AmbianceClassic/close_focused_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..590a7c3120950698658e916996cdc24236fedaec GIT binary patch literal 589 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5t-vWF>T<_k!`>w$H|Ns9s*5>3P zI~$NjWD>}AP!RS}6ZLVh^ivb_bF>I_G!J$(4|BFG_pz+>v#Rv7uJX683$UK$sWHb( zV}Xz6B44egkyhK1?6)O3>`JuVoou%|#bIxx!Tu=2gVBbEV~mc+8J$S6K9y>HD$V9> zmc#i(lZ#0vmy=Der<&c(vAdgVe>czRevZxkT)X>u_V){%U*%iBDs*^T?D)3C8R)@x z1vc*rfynkK`ajBLvmsIFF=G|-7 z-MMfl)bya*`(q0X^5;x92>srX#+P8gdQJ4qiv#=QWub?{MP<(hfQ5)Uy`hDh2HJ24iP01d-d*5ulm?ox8LBAPlul`>+XsljBP*XPiyI1 z{d}qX#Z714J8Unjt}i)h`|kEP-!J-|zuoeyZ+w%wxW6DsGVP+t6p_ZctiRbMT20RA TUr0*<`kKMh)z4*}Q$iB}#d`HB literal 0 HcmV?d00001