Revision: 4793
          http://sourceforge.net/p/vexi/code/4793
Author:   clrg
Date:     2015-05-09 09:40:24 +0000 (Sat, 09 May 2015)
Log Message:
-----------
Widgets for integrated layout
- Button, CheckBox, RadioButton
- move to vexi.gui namespace

Modified Paths:
--------------
    branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_poke/testfeature.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/default.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/lib/button.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_poke/poke/widgets/basic.t

Added Paths:
-----------
    
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/BasicWidgets.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/Icon.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/Button.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/CheckBox.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/Defaults.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/RadioButton.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/Icon.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Clickable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Container.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/ContextMenuAgent.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Draggable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/FocusManager.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Focusable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Polarized.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/PopupManager.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Popupable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Repeater.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectContainer.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectGrouper.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectList.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Selectable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Subsurface.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Surface.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/TooltipAgent.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/TooltipManager.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/theme/
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/Bevel.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/Button.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/CheckBox.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/RadioButton.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/Settings.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/Surface.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/Tooltip.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/lib/FocusBorder.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/conf/Settings.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/conf/Theme.t
    branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/gui/
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/gui/Bevel.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/gui/Button.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/gui/ButtonGroup.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/gui/CheckBox.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/gui/RadioButton.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/gui/Surface.t
    branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_poke/poke/gui/
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_poke/poke/gui/RadioButton.t

Removed Paths:
-------------
    
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/widgets_basic.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/icon.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/icon.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/clickable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/contextable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/draggable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/focusable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/focusmanager.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/polarizable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/popupable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/popupmanager.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/repeatable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/selectable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/selectcontainer.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/selectgroup.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/selectlist.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/subsurface.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/surface.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/tooltipable.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/tooltipmanager.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/button.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/check.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/radio.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/bevel.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/button.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/check.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/lib/focusborder.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/radio.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/settings.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/surface.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/tooltip.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/conf/settings.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/conf/theme.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/widget/bevel.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/widget/button.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/widget/check.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/widget/radio.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/widget/selectgroup.t
    
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/vexi/widget/surface.t

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/BasicWidgets.t
 (from rev 4791, 
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/widgets_basic.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/BasicWidgets.t
                           (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/BasicWidgets.t
   2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,101 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui"
+      xmlns="vexi.gui">
+    
+    static.name = "Widgets (Basic)";
+    static.category = "Widgets";
+    
+    <ui:Box orient="vertical" padding="10">
+        <ui:Box vshrink="true">
+            <ui:Box />
+            <ButtonGroup id="radios" align="left" orient="vertical" 
shrink="true">
+                <RadioButton id="r1" margin="10 5 0 5" text="white bg" />
+                <RadioButton id="r2" margin="10 5 0 5" text="red bg" />
+                <RadioButton id="r3" margin="10 5 0 5" text="green bg" />
+                <RadioButton id="r4" margin="10 5 0 5" text="blue bg" />
+            </ButtonGroup>
+            <ui:Box id="checks" align="left" orient="vertical" shrink="true">
+                <CheckBox id="c1" margin="10 5 0 5" text="disable white 
button" />
+                <CheckBox id="c2" margin="10 5 0 5" text="disable red button" 
/>
+                <CheckBox id="c3" margin="10 5 0 5" text="disable green 
button" />
+                <CheckBox id="c4" margin="10 5 0 5" text="disable blue button" 
/>
+            </ui:Box>
+            <ui:Box />
+        </ui:Box>
+        <ui:Box id="buttons" vshrink="true">
+            <ui:Box />
+            <Button id="b1" margin="10 5 0 5" text="cycle" shrink="false" />
+            <Button id="b2" margin="10 5 0 5" text="random" shrink="false" />
+            <Button id="b3" margin="10 5 0 5" text="reset" shrink="false" />
+            <ui:Box />
+        </ui:Box>
+        <Bevel id="bg" form="down" margin="10" />
+
+        // alternative to selectgroup
+        //$r2.group = $r1.group;
+        //$r3.group = $r1.group;
+        //$r4.group = $r1.group;
+        
+        var noValidColors = false;
+
+        $bg.fill ++= function(v) {
+            cascade = v;
+            if (v == null) {
+                if ($r1.group.selected)
+                    $r1.group.selected.selected = false;
+                $bg.text = noValidColors ? "No enabled colors to choose from!" 
: "";
+                return;
+            }
+            $bg.text = "";
+            noValidColors = false;
+            if (v == "white") $r1.selected = true;
+            else if (v == "red") $r2.selected = true;
+            else if (v == "green") $r3.selected = true;
+            else if (v == "blue") $r4.selected = true;
+        }
+
+        $b1.action ++= function(v) {
+            cascade = v;
+            if ($radios.selected and $radios.selected.nextselect) {
+                $radios.selected.nextselect.selected = true;
+            } else {
+                $radios.selectFirst();
+            }
+            if ($radios.selected == null) {
+                noValidColors = true;
+                $bg.fill = null;
+            }
+        }
+        
+        $b2.action ++= function(v) {
+            cascade = v;
+            var targets = [];
+            for (var i=0; 4 > i; i++) {
+                if ($radios[i].enabled)
+                    targets[targets.length] = $radios[i];
+            }
+
+            if (targets.length > 0) {
+                var n = vexi.math.floor(targets.length * vexi.math.random());
+                targets[n].selected = true;
+            } else {
+                noValidColors = true;
+                $bg.fill = null;
+            }
+        }
+
+        $b3.action ++= function(v) { noValidColors = false; $bg.fill = null; 
cascade = v; }
+
+        $c1.selected ++= function(v) { $r1.enabled = !v; cascade = v; }
+        $c2.selected ++= function(v) { $r2.enabled = !v; cascade = v; }
+        $c3.selected ++= function(v) { $r3.enabled = !v; cascade = v; }
+        $c4.selected ++= function(v) { $r4.enabled = !v; cascade = v; }
+
+        $r1.selected ++= function(v) { cascade = v; if (v and $bg.fill != 
"#ffffff") $bg.fill = "white"; }
+        $r2.selected ++= function(v) { cascade = v; if (v and $bg.fill != 
"#ff0000") $bg.fill = "red"; }
+        $r3.selected ++= function(v) { cascade = v; if (v and $bg.fill != 
"#008000") $bg.fill = "green"; }
+        $r4.selected ++= function(v) { cascade = v; if (v and $bg.fill != 
"#0000ff") $bg.fill = "blue"; }
+        
+    </ui:Box>
+</vexi>

Deleted: 
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/widgets_basic.t
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/widgets_basic.t
  2015-05-09 09:29:30 UTC (rev 4792)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/widgets_basic.t
  2015-05-09 09:40:24 UTC (rev 4793)
@@ -1,100 +0,0 @@
-<!-- Copyright 2007 - see COPYING for details [LGPL] -->
-
-<vexi xmlns:ui="vexi://ui" xmlns:lay="vexi.layout" xmlns="vexi.widget">
-    
-    static.name = "Widgets (Basic)";
-    static.category = "Widgets";
-    
-    <lay:pad orient="vertical" padding="10">
-        <ui:box vshrink="true">
-            <ui:box />
-            <selectgroup id="radios" align="left" orient="vertical" 
shrink="true">
-                <radio id="r1" margin="10 5 0 5" text="white bg" />
-                <radio id="r2" margin="10 5 0 5" text="red bg" />
-                <radio id="r3" margin="10 5 0 5" text="green bg" />
-                <radio id="r4" margin="10 5 0 5" text="blue bg" />
-            </selectgroup>
-            <ui:box id="checks" align="left" orient="vertical" shrink="true">
-                <check id="c1" margin="10 5 0 5" text="disable white button" />
-                <check id="c2" margin="10 5 0 5" text="disable red button" />
-                <check id="c3" margin="10 5 0 5" text="disable green button" />
-                <check id="c4" margin="10 5 0 5" text="disable blue button" />
-            </ui:box>
-            <ui:box />
-        </ui:box>
-        <ui:box id="buttons" vshrink="true">
-            <ui:box />
-            <button id="b1" margin="10 5 0 5" text="cycle" shrink="false" />
-            <button id="b2" margin="10 5 0 5" text="random" shrink="false" />
-            <button id="b3" margin="10 5 0 5" text="reset" shrink="false" />
-            <ui:box />
-        </ui:box>
-        <bevel id="bg" form="down" margin="10" />
-
-        // alternative to selectgroup
-        //$r2.group = $r1.group;
-        //$r3.group = $r1.group;
-        //$r4.group = $r1.group;
-        
-        var noValidColors = false;
-
-        $bg.fill ++= function(v) {
-            cascade = v;
-            if (v == null) {
-                if ($r1.group.selected)
-                    $r1.group.selected.selected = false;
-                $bg.text = noValidColors ? "No enabled colors to choose from!" 
: "";
-                return;
-            }
-            $bg.text = "";
-            noValidColors = false;
-            if (v == "white") $r1.selected = true;
-            else if (v == "red") $r2.selected = true;
-            else if (v == "green") $r3.selected = true;
-            else if (v == "blue") $r4.selected = true;
-        }
-
-        $b1.action ++= function(v) {
-            cascade = v;
-            if ($radios.selected and $radios.selected.nextselect) {
-                $radios.selected.nextselect.selected = true;
-            } else {
-                $radios.selectFirst();
-            }
-            if ($radios.selected == null) {
-                noValidColors = true;
-                $bg.fill = null;
-            }
-        }
-        
-        $b2.action ++= function(v) {
-            cascade = v;
-            var targets = [];
-            for (var i=0; 4 > i; i++) {
-                if ($radios[i].enabled)
-                    targets[targets.length] = $radios[i];
-            }
-
-            if (targets.length > 0) {
-                var n = vexi.math.floor(targets.length * vexi.math.random());
-                targets[n].selected = true;
-            } else {
-                noValidColors = true;
-                $bg.fill = null;
-            }
-        }
-
-        $b3.action ++= function(v) { noValidColors = false; $bg.fill = null; 
cascade = v; }
-
-        $c1.selected ++= function(v) { $r1.enabled = !v; cascade = v; }
-        $c2.selected ++= function(v) { $r2.enabled = !v; cascade = v; }
-        $c3.selected ++= function(v) { $r3.enabled = !v; cascade = v; }
-        $c4.selected ++= function(v) { $r4.enabled = !v; cascade = v; }
-
-        $r1.selected ++= function(v) { cascade = v; if (v and $bg.fill != 
"#ffffff") $bg.fill = "white"; }
-        $r2.selected ++= function(v) { cascade = v; if (v and $bg.fill != 
"#ff0000") $bg.fill = "red"; }
-        $r3.selected ++= function(v) { cascade = v; if (v and $bg.fill != 
"#008000") $bg.fill = "green"; }
-        $r4.selected ++= function(v) { cascade = v; if (v and $bg.fill != 
"#0000ff") $bg.fill = "blue"; }
-        
-    </lay:pad>
-</vexi>

Modified: 
branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_poke/testfeature.t
===================================================================
--- branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_poke/testfeature.t  
2015-05-09 09:29:30 UTC (rev 4792)
+++ branches/vexi3_integrated_layout/org.vexi-vexi.demo/src_poke/testfeature.t  
2015-05-09 09:40:24 UTC (rev 4793)
@@ -1,12 +1,12 @@
 <!-- public domain -->
 
-<vexi xmlns:ui="vexi://ui" xmlns="vexi.widget" xmlns:f="org.vexi.demo.feature">
-    <surface />
+<vexi xmlns:ui="vexi://ui" xmlns="vexi.gui" xmlns:f="org.vexi.demo.feature">
+    <Surface />
     <ui:box>
         
         // very simple template to open a feature in a frame
         var feature = vexi.params["feature"];
-        if (feature==null) feature = "grid";
+        if (feature==null) feature = "BasicWidgets";
         thisbox[0] = f[feature](vexi.box);
         
         // or comment out the above and uncomment this

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/Icon.t 
(from rev 4791, 
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/icon.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/Icon.t  
                            (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/Icon.t  
    2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,5 @@
+<!-- provides the location to look for icons -->
+<vexi xmlns:ui="vexi://ui">
+    <ui:box />
+    static.iconpath = [vexi..org.vexi.crystal];
+</vexi>
\ No newline at end of file

Deleted: 
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/icon.t
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/icon.t  
    2015-05-09 09:29:30 UTC (rev 4792)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.icons/src_main/vexi/conf/icon.t  
    2015-05-09 09:40:24 UTC (rev 4793)
@@ -1,5 +0,0 @@
-<!-- provides the location to look for icons -->
-<vexi xmlns:ui="vexi://ui">
-    <ui:box />
-    static.iconpath = [vexi..org.vexi.crystal];
-</vexi>
\ No newline at end of file

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/Button.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/button.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/Button.t
                           (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/Button.t
   2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,7 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns="org.vexi.lib.role">
+    <Clickable />
+    <Focusable />
+    <TooltipAgent />
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/CheckBox.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/check.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/CheckBox.t
                         (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/CheckBox.t
 2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,29 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="org.vexi.lib.role">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <note>
+           At some point this should be using selectable (which
+           should also implement the necessary action/value traps)
+        </note>
+    </meta:doc>
+
+    <Clickable />
+    <Focusable />
+    <TooltipAgent />
+    <ui:Box>
+        
+        thisbox.selected = false;
+        
+        thisbox.action ++= static.actionWrite;
+        thisbox.value  ++= static.valueWrite;
+        thisbox.value  ++= static.valueRead;
+        
+    </ui:Box>
+    
+    static.actionWrite = function(v) { trapee.selected = !trapee.selected; 
cascade = v; }
+    static.valueWrite = function(v) { trapee.selected = v == true; return; }
+    static.valueRead = function() { return trapee.selected == true; }
+    
+</vexi>

Added: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/Defaults.t
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/Defaults.t
                         (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/Defaults.t
 2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,15 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns="vexi://ui">
+    <Box>
+        {
+            const s = thisbox.v_defaultSettings;
+               if (s!=null) {
+                   // initialize properties
+                   for (var p,v in s) {
+                       thisbox[p] = v;
+                   }
+               }
+        }
+    </Box>
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/RadioButton.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/radio.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/RadioButton.t
                              (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/gui/RadioButton.t
      2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,8 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns="org.vexi.lib.role">
+    <Clickable />
+    <Selectable />
+    <Focusable />
+    <TooltipAgent />
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/Icon.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/icon.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/Icon.t
                          (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/Icon.t
  2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,110 @@
+<!-- Copyright 2014 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui"
+    xmlns:icon="vexi.icon">
+    
+    
+    <ui:box shrink="true">
+        <ui:box id="size" align="bottomright" layout="layer">
+            <ui:box id="image" shrink="true" />
+            <ui:box id="emblem" shrink="true" />
+        </ui:box>
+        
+        thisbox.emblem ++= static.emblemWrite;
+        thisbox.image ++= static.imageWrite;
+        thisbox.icon ++= static.iconWrite;
+        thisbox.size ++= static.sizeWrite;
+        
+    </ui:box>
+    
+    /** set the emblem, a 1/4 size image in the bottom right corner */
+    static.emblemWrite = function(v) {
+        cascade = v;
+        if (!trapee.size) {
+            return;
+        }
+        trapee[0][1].fill = v ? static.getIcon("icon"+(trapee.size/2), v) : 
null;
+    }
+    
+    /** sets the icon's image to the specified resource */
+    static.imageWrite = function(v) {
+        cascade = v;
+        trapee[0][0].fill = v;
+    }
+    
+    /** sets the icon's image to an existing icon */
+    static.iconWrite = function(v) {
+        cascade = v;
+        if (!trapee.size) {
+            return;
+        }
+        trapee[0][0].fill = v ? static.getIcon("icon"+trapee.size, v) : null;  
        
+    }
+    
+    /** sets the size, in pixels, of this icon */
+    static.sizeWrite = function(v) {
+        cascade = v;
+        var i = trapee[0];
+        i.width = v;
+        i.height = v;
+        if (trapee.icon) {
+            trapee.icon = trapee.icon;
+        }
+        if (trapee.image) {
+            trapee.image = trapee.image;
+        }
+    }
+    
+    const icons = {};
+    
+    static.iconpath ++= function(v){
+        cascade = v;
+        // done like this because we cannot test easily if an icon exists or 
not (no method for this, and threading issues
+           // which don't exist for listing)
+           for(var i,subkey in ["icon8", "icon16", "icon32"]){
+               const submap = icons[subkey] = {};
+               for(var j,l in static.iconpath){
+                   const lsub = l[subkey];
+                   for(var k in lsub){
+                       var d = k.indexOf('.');
+                       if (d==0) {
+                           // skips hidden dirs e.g. .svn
+                           continue;
+                       }
+                       if (d>=1) {
+                           // image files should have an extension e.g. 
image.png
+                           k = k.substring(0, d);
+                       }
+                       submap[k] = lsub[k];
+                   }
+               }
+           }
+    };
+    
+ 
+    
+    const list = function(subdir){
+        var r = (keysof icons[subdir]).toArray();
+        r.sort();
+        return r;
+    };    
+    
+    const listed = {};
+    
+    static.getIcon = function(subdir, name){
+        const key = subdir+"."+name;
+        var r = icons[subdir][name];
+        if(!r){
+            
+            var msg = "[WARNING] icon not found: "+subdir+"/"+name;
+            vexi.log.warn(new vexi.js.Exception(msg));                         
       
+            if(!listed[subdir]){
+                listed[subdir] = true;
+                vexi.log.warn(list(subdir).join("\n    "));
+            }
+            r = icon[subdir]["blank"];                       
+        }
+        return r;
+    }; 
+     
+</vexi>

Deleted: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/icon.t
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/icon.t
  2015-05-09 09:29:30 UTC (rev 4792)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/icon.t
  2015-05-09 09:40:24 UTC (rev 4793)
@@ -1,110 +0,0 @@
-<!-- Copyright 2014 - see COPYING for details [LGPL] -->
-
-<vexi xmlns:ui="vexi://ui"
-    xmlns:icon="vexi.icon">
-    
-    
-    <ui:box shrink="true">
-        <ui:box id="size" align="bottomright" layout="layer">
-            <ui:box id="image" shrink="true" />
-            <ui:box id="emblem" shrink="true" />
-        </ui:box>
-        
-        thisbox.emblem ++= static.emblemWrite;
-        thisbox.image ++= static.imageWrite;
-        thisbox.icon ++= static.iconWrite;
-        thisbox.size ++= static.sizeWrite;
-        
-    </ui:box>
-    
-    /** set the emblem, a 1/4 size image in the bottom right corner */
-    static.emblemWrite = function(v) {
-        cascade = v;
-        if (!trapee.size) {
-            return;
-        }
-        trapee[0][1].fill = v ? static.getIcon("icon"+(trapee.size/2), v) : 
null;
-    }
-    
-    /** sets the icon's image to the specified resource */
-    static.imageWrite = function(v) {
-        cascade = v;
-        trapee[0][0].fill = v;
-    }
-    
-    /** sets the icon's image to an existing icon */
-    static.iconWrite = function(v) {
-        cascade = v;
-        if (!trapee.size) {
-            return;
-        }
-        trapee[0][0].fill = v ? static.getIcon("icon"+trapee.size, v) : null;  
        
-    }
-    
-    /** sets the size, in pixels, of this icon */
-    static.sizeWrite = function(v) {
-        cascade = v;
-        var i = trapee[0];
-        i.width = v;
-        i.height = v;
-        if (trapee.icon) {
-            trapee.icon = trapee.icon;
-        }
-        if (trapee.image) {
-            trapee.image = trapee.image;
-        }
-    }
-    
-    const icons = {};
-    
-    static.iconpath ++= function(v){
-        cascade = v;
-        // done like this because we cannot test easily if an icon exists or 
not (no method for this, and threading issues
-           // which don't exist for listing)
-           for(var i,subkey in ["icon8", "icon16", "icon32"]){
-               const submap = icons[subkey] = {};
-               for(var j,l in static.iconpath){
-                   const lsub = l[subkey];
-                   for(var k in lsub){
-                       var d = k.indexOf('.');
-                       if (d==0) {
-                           // skips hidden dirs e.g. .svn
-                           continue;
-                       }
-                       if (d>=1) {
-                           // image files should have an extension e.g. 
image.png
-                           k = k.substring(0, d);
-                       }
-                       submap[k] = lsub[k];
-                   }
-               }
-           }
-    };
-    
- 
-    
-    const list = function(subdir){
-        var r = (keysof icons[subdir]).toArray();
-        r.sort();
-        return r;
-    };    
-    
-    const listed = {};
-    
-    static.getIcon = function(subdir, name){
-        const key = subdir+"."+name;
-        var r = icons[subdir][name];
-        if(!r){
-            
-            var msg = "[WARNING] icon not found: "+subdir+"/"+name;
-            vexi.log.warn(new vexi.js.Exception(msg));                         
       
-            if(!listed[subdir]){
-                listed[subdir] = true;
-                vexi.log.warn(list(subdir).join("\n    "));
-            }
-            r = icon[subdir]["blank"];                       
-        }
-        return r;
-    }; 
-     
-</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Clickable.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/clickable.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Clickable.t
                               (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Clickable.t
       2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,246 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:meta="vexi://meta"
+      xmlns="org.vexi.lib.role">
+
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <desc>
+            Implements standard clickable widget behaviour by providing
+            an interface to the state to make implementation of visual
+            feedback easy as well as behaving as the user expects.
+        </desc>
+        <notes>
+            We trap only on Press1 instead of _Press1 because it is not
+            unlikely that we may need to prevent press events reaching
+            a clickable widget e.g. it is overlaid by another widget.
+            
+            We trap on surface._Release1 because we always want to
+            reset a clickable widget on release.
+        </notes>
+        <usage>
+            By preapplying clickable, a widget gains access to several
+            state properties that are used as triggers i.e. can be
+            trapped to know when the clickable widget changes state:
+            
+            * hover  - When a mouse is over a widget without the left
+                       mouse button having been depressed first
+            
+            * normal - When a widget has no interaction with the mouse
+                       or keyboard
+            
+            * active - When the left mouse button is depressed or the
+                       widget is focused and spacebar depressed
+            
+            * action - This is put to when a clickable widget is
+                       successfully clicked upon
+            
+            As the only value put to these state properties is 'true',
+            their actual value is meaningless; they are just triggers.
+            
+            Clickable widgets recognise the following state property:
+            
+            * enabled - Put 'true' (default) to enable the widget and
+                        allow user interaction, 'false' to disable it
+        </usage>
+    </meta:doc>
+    
+    <Repeater>
+        
+        // template properties
+        thisbox.action;          // action trigger
+        thisbox.enabled;         // self explanatory
+        thisbox.focused;         // focusable integration
+        thisbox.active;          // active state (mouse.inside and primed)
+        thisbox.hover;           // hover state (mouse.inside and !primed)
+        thisbox.normal;          // normal state (!mouse.inside)
+        thisbox.primed;          // track activation irrespective of 
mouse.inside
+        thisbox.repeats = false; // if a repeating action is desired
+        
+        // initialize enabled state (from preapply)
+        if (enabled === null)
+            enabled = true;
+        if (enabled) {
+            Enter ++= static.enterEvent;
+            Leave ++= static.leaveEvent;
+        }
+        
+        // assign trap functions
+        enabled     ++= static.enabledWrite;
+        focused     ++= static.focusedWrite;
+        interval    ++= static.intervalWrite;
+        primed      ++= static.primedWrite;
+        KeyPressed  ++= static.keypressEvent;
+        KeyReleased ++= static.keyreleaseEvent;
+        Press1      ++= static.pressEvent;
+        surface     ++= static.initNormal;
+        
+    </Repeater>
+    
+    static.defaultinterval = 100;
+    static.initialinterval = 500;
+    
+    /** initialise as normal state */
+    static.initNormal = function(v) {
+        cascade = v;
+        trapee.normal = true;
+        trapee.surface --= callee;
+    }
+    
+    /** enabled write trap */
+    static.enabledWrite = function(v) {
+        var e = trapee.enabled;
+        cascade = v;
+        if (e != trapee.enabled) {
+            if (trapee.enabled) {
+                trapee.Enter ++= static.enterEvent;
+                trapee.Leave ++= static.leaveEvent;
+            } else {
+                trapee.Enter --= static.enterEvent;
+                trapee.Leave --= static.leaveEvent;
+                // deprime us when disabled
+                trapee.primed = false;
+            }
+            // sets visible state
+            trapee.normal = true;
+        }
+    }
+    
+    /** focused write trap */
+    static.focusedWrite = function(v) {
+        var f = trapee.focused;
+        cascade = v;
+        if (f and !trapee.focused and trapee.primed) {
+            // unprime if defocused
+            trapee.primed = false;
+        }
+    }
+    
+    /** returns the appropriate interval for repeating clickable to use */
+    static.intervalWrite = function() {
+        return (trapee.counter==0)
+            ? (trapee.initialinterval
+                ? trapee.initialinterval
+                : static.initialinterval)
+            : (cascade
+                ? cascade
+                : trapee.defaultinterval);
+    }
+    
+    /** primed write trap */
+    static.primedWrite = function(v) {
+        // behaviour if widget is enabled
+        if (trapee.enabled) {
+            // determine physical state and activate trigger
+            if (v) trapee.active = true;
+            else {
+                var m = trapee.mouse;
+                if (m and m.inside) {
+                    trapee.hover = true;
+                } else {
+                    trapee.normal = true;
+                }
+            }
+            // set repeat state if necessary
+            if (trapee.repeats) {
+                trapee.repeat = v;
+            }
+            cascade = v;
+        }
+        // do nothing when not enabled
+        else cascade = false;
+    }
+    
+    /** KeyPressed write trap */
+    static.keypressEvent = function(v) {
+        switch (v) {
+        case "enter": case " ":
+            trapee.primed = true;
+            break;
+        case "escape":
+            trapee.primed = false;
+            break;
+        default:
+            cascade = v;
+        }
+    }
+    
+    /** KeyReleased write trap */
+    static.keyreleaseEvent = function(v) {
+        if ((v == "enter" or v == " ") and trapee.primed and trapee.enabled) {
+            trapee.action = true;
+            trapee.primed = false;
+        }
+        else cascade = v;
+    }
+    
+    /** Enter write trap */
+    static.enterEvent = function(v) {
+        if (trapee.enabled) {
+            if (trapee.primed) {
+                trapee.active = true;
+                if (trapee.repeats) {
+                    trapee.repeat = true;
+                }
+            } else {
+                trapee.hover = true;
+            }
+        }
+        cascade = v;
+    }
+    
+    /** Leave write trap */
+    static.leaveEvent = function(v) {
+        if (trapee.enabled) {
+            trapee.normal = true;
+            if (trapee.repeats and trapee.primed) {
+                trapee.repeat = false;
+            }
+        }
+        cascade = v;
+    }
+    
+    /** Press1 write trap */
+    static.pressEvent = function(v) {
+        if (trapee.enabled) {
+            // set primed state; ready to fire action on release
+            trapee.primed = true;
+            // apply release trap to surface otherwise a release outside
+            // of this clickable would leave it in an active state
+            var s = trapee.surface;
+            var targ = s and s.event ? s.event : trapee;
+            var tbox = trapee;
+            targ._Release1 ++= function(v) {
+                try {
+                    // important; allows focusmanager to process focused
+                    // before firing an action on the clickable
+                    cascade = v;
+                    // check clickable conditions for
+                    // firing either repeat or action 
+                    if (tbox.enabled) {
+                        // primed e.g. button down
+                        if (tbox.primed) {
+                            // fire action or stop repeat
+                            if (tbox.mouse?.inside) {
+                                if (tbox.repeats) {
+                                    // note repeat fires action
+                                    tbox.repeat = false;
+                                } else {
+                                    tbox.action = true;
+                                }
+                            }
+                        }
+                    }
+                } finally {
+                    // clean up trap
+                    targ._Release1 --= callee;
+                    // deprime widget - this handleds repeat
+                    // and other button deactivation tasks
+                    tbox.primed = false;
+                }
+            }
+        }
+        cascade = v;
+    }
+    
+</vexi>

Added: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Container.t
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Container.t
                               (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Container.t
       2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,21 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns:util="vexi.util">
+    <meta:doc>
+        <name>Container</name>
+        <desc>Signals container's readiness</desc>
+        <usage>
+            Post-apply container to your full constructed widget
+        </usage>
+    </meta:doc>
+    
+    <ui:box>
+        
+        if (v_content == null) v_content = thisbox;
+        
+        // signal readiness - allows widgets to finalize
+        // container targets before assigning redirects
+        thisbox.v_container = true;
+        
+    </ui:box>
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/ContextMenuAgent.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/contextable.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/ContextMenuAgent.t
                                (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/ContextMenuAgent.t
        2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,36 @@
+<!-- Copyright 2012 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui"
+      xmlns="vexi.widget">
+    
+    <ui:box>
+        
+        thisbox.Press2 ++= static.popupContext;
+        
+    </ui:box>
+    
+    static.popupContext = function(p) {
+        cascade = p;
+        var actions = trapee.contextActions;
+        if (actions != null and actions.length>1) {
+            var model = trapee.surface.popup;
+            var popup = new .menu();
+            var close = function(v) { cascade = v; model.pop(popup, false); }
+            popup.popdownOnExternalEvent = true;
+            for (var i,item in actions) {
+                item.action ++= close;
+                popup.add(item);
+            }
+            popup.v_popbox.visible ++= function(v) {
+                cascade = v;
+                if (!v) model.delPopBox(popup);
+            }
+            var m = trapee.surface.frame.mouse;
+            popup.v_popbox.surface_x = m.x;
+            popup.v_popbox.surface_y = m.y;
+            model.addPopBox(popup);
+            model.pop(popup, true);
+        }
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Draggable.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/draggable.t)
===================================================================
(Binary files differ)

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/FocusManager.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/focusmanager.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/FocusManager.t
                            (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/FocusManager.t
    2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,250 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="vexi">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <author>David Crawshaw</author>
+        <desc>Manages the focusable widgets on a surface</desc>
+        <usage>
+            Directly apply to a surface widget (done automatically by
+            using FIXME: vexi.widget.frame) and when directly applying
+            vexi.theme.focusable (usually preapplied by widgets) to a
+            template, it should then be automatically registered as
+            focusable with the surface.
+        </usage>
+        <notes>For further documentation, see vexi.theme.surface</notes>
+    </meta:doc>
+    
+    <ui:box>
+        
+        // the current focus for this surface
+        var focus = null;
+        var model = {};
+        var surfaceFocused = false;
+        
+        // the focus list for this surface
+        const fvector = new .util.vector();
+        
+        // access to the model and current focus
+        model.focus ++= .util.common..readOnly;
+        model.current ++= function() { return focus; }
+        surface.focus ++= function() { return model; }
+        surface.focus ++= .util.common..readOnly;
+        
+        /** defocus when frame/window is closed */
+        surface.frame.Close ++= function(v) {
+            cascade = v;
+            // REMARK: this seems necessary as frame.Focused
+            // is not put to when a frame or window is closed
+            if (focus!=null) {
+                focus.focused = false;
+            }
+        }
+        
+        /** return current frame Focused state */
+        surface.frame.Focused ++= function() { return surfaceFocused; }
+        
+        /** (un)focus the focused widget according to root.Focused */
+        surface.frame.Focused ++= function(v) {
+            cascade = v;
+            surfaceFocused = v;
+            if (focus) {
+                if (v) {
+                    focus.focused = true;
+                } else {
+                    focus.focused = false;
+                }
+            }
+        }
+        
+        var defocus;
+        
+        /** set or unset a focused widget */
+        model.setFocus = function(v, f) {
+            if (f and fvector.contains(v)) {
+                // valid request to focus
+                if (focus != v) {
+                    defocus = focus;
+                    if (defocus) {
+                        try { defocus.focused = false; }
+                        finally { defocus = null; }
+                    }
+                    // focus
+                    focus = v;
+                    model.current = v;
+                }
+                return true;
+            } else if (!f and focus == v) {
+                // request to unfocus
+                if (defocus == v) {
+                    // already in setFocus; defocus as
+                    // part of focusing another widget
+                    return false;
+                }
+                if (surfaceFocused) {
+                    // defocus
+                    focus = null;
+                    model.current = null;
+                    return false;
+                }
+            } else {
+                // nothing to do
+                return false;
+            }
+        }
+        
+        /** add a focus to the focus vector, optionally after w */
+        model.addFocus = function(v, w) {
+            // make sure we're not already in the focus list
+            model.dropFocus(v);
+            
+            if (w and fvector.contains(w)) {
+                return fvector.insert(v, w);
+            }
+            return fvector.push(v);
+        }
+        
+        /** drop a focus from the focus vector for this surface */
+        model.dropFocus = function(v) {
+            if (fvector.contains(v)) {
+                // remove v from surface's focus model
+                if (focus == v) {
+                    var nf = model.nextFocus(v);
+                    if (nf != null and nf != v) {
+                        nf.focused = true;
+                    } else {
+                        v.focused = false;
+                        focus = null;
+                    }
+                }
+                return fvector.remove(v);
+            } else {
+                // not a member of this surface's focus model
+                return false;
+            }
+        }
+
+        /** return the next-in-line for focus after v */
+        model.nextFocus = function(v) {
+            var nf = fvector.after(v);
+            if (!nf) {
+                // wrap around
+                nf = fvector.first;
+            }
+            while (nf != v) {
+                if (nf.focusable) {                
+                    return nf;
+                }
+                nf = fvector.after(nf);
+                if (!nf) {
+                    // wrap around
+                    nf = fvector.first;
+                }
+            }
+            return v.focusable ? v : null;
+        }
+        
+        /** return the previous-in-line for focus after v */
+        model.prevFocus = function(v) {
+            var pf = fvector.before(v);
+            if (!pf) {
+                // wrap around
+                pf = fvector.last;
+            }
+            while (pf != v) {
+                if (pf.focusable) {
+                    return pf;
+                }
+                pf = fvector.before(pf);
+                if (!pf) {
+                    // wrap around
+                    pf = fvector.last;
+                }
+            }
+            return v.focusable ? v : null;
+        }
+        
+        
+        model.lastFocus ++= function() { return fvector.last; };
+        
+        
+        /** give the requested widget the focus */
+        surface.event._Press1 ++= function(v) {
+            // clear focusrequest as it gets set by manual focused puts
+            model.focusrequest = null;
+            // pass event to rest of ui
+            cascade = v;
+        }
+        
+        /** give the requested widget the focus */
+        surface.event._Release1 ++= function(v) {
+            // if a request for focus has been made, honor it
+            if (model.focusrequest) {
+                // focus but avoid repeat focusing
+                if (!model.focusrequest.focused) {
+                    model.focusrequest.focused = true;
+                }
+                model.focusrequest = null;
+            }
+            // et fini
+            cascade = v;
+        }
+        
+        //////// Key Event Handling ///////////////////////////////////
+        
+        /** pass key-press events to focused child */
+        var surfaceKeyPress = function(v) {
+            model.focusModelKeyPressed(v);
+            return;
+        }
+        
+        surface.event._KeyPressed ++= surfaceKeyPress;
+        
+        /** pass key-release events to focused child */
+        var surfaceKeyRelease = function(v) {
+            model.focusModelKeyReleased(v);
+            return;
+        }
+        
+        surface.event._KeyReleased ++= surfaceKeyRelease;
+        
+        /** focus model keypress event */
+        model.focusModelKeyPressed = function(v) {
+            if (focus and focus.grabKeyList and focus.grabKeyList[v]) {
+                // the focused widget wishes to intercept special keys
+                focus.KeyPressed = v;
+                
+            } else if (v.charCodeAt(0) == 65535) {
+                // ignore capslock
+                //break;
+                
+            } else if (v=="tab") {
+                // on tab, move forwards through focus list
+                var f = focus ? focus.nextfocus : 
model.nextFocus(fvector.last);
+                if (f) {
+                    f.focused = true;
+                }
+                
+            } else if (v=="TAB") {
+                // on shift-tab, move backwards through focus list
+                var f = focus ? focus.prevfocus : 
model.prevFocus(fvector.first);
+                if (f) {
+                    f.focused = true;
+                }
+                
+            } else if (focus) {
+                // pass keypress onto focused widget
+                focus.KeyPressed = v;
+            }
+        }
+
+        /** focus model keyrelease event */
+        model.focusModelKeyReleased = function(v) {
+            if (focus and ((focus.grabKeyList and focus.grabKeyList[v])
+                    or v!="tab" or v!="TAB" or v.charCodeAt(0)!=65535)) {
+                focus.KeyReleased = v;
+            }
+        }
+
+    </ui:box>
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Focusable.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/focusable.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Focusable.t
                               (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Focusable.t
       2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,138 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <desc>
+            Handles widget focusing, automating keyboard navigation, when
+            combined with a focusmanager-enabled surface
+        </desc>
+        <details>
+            The following state properties are meaningful:
+            
+            * enabled   - Whether this widget is 'on'; only an enabled
+              (true)      widget may be focused
+            
+            * focusable - If 'true' widget desires focus, otherwise it
+              (true)      rejects focus
+            
+            * focused   - Set 'true' when the widget is focused and
+              (false)     conversely set to 'false' when defocused
+            
+            * nextfocus - The next available focusable widget
+              (null)
+            
+            * prevfocus - The previous available focuslable widget
+              (null)
+            
+            All of these properties may be manually put to in order to
+            arbitrarily update their focused (sic) state.
+        </details>
+    </meta:doc>
+    
+    <ui:Box>
+        
+        if (thisbox.enabled==null) {
+            enabled = true;
+        }
+        
+        thisbox.focusable = true; // whether a focusable may be focused
+        thisbox.focused;          // whether a focusable is focused
+        thisbox.nextfocus;        // read for the focus after thisbox on the 
surface
+        thisbox.prevfocus;        // read for the focus before thisbox on the 
surface
+        thisbox.v_focusmodel;
+        
+        // assign checkFocus traps
+        display   ++= static.checkFocus; // defocus when hidden
+        enabled   ++= static.checkFocus; // defocus when disabled
+        focusable ++= static.checkFocus; // defocus if made unfocusable
+        visible   ++= static.checkFocus; // defocus if no longer visible
+        
+        // assign trap functions
+        focusable ++= static.focusableRead;
+        focused   ++= static.focusedWrite;
+        nextfocus ++= static.nextfocusRead;
+        prevfocus ++= static.prevfocusRead;
+        surface   ++= static.surfaceWrite;
+        Press1    ++= static.pressWrite;
+        
+    </ui:Box>
+    
+    /** private function to assign to traps */
+    static.checkFocus = function(v) {
+        if (!v and trapee.focused) {
+            trapee.focused = false;
+        }
+        cascade = v;
+    }
+    
+    /** read trap to return focusable state */
+    static.focusableRead = function() {
+        return trapee.visible and trapee.enabled and cascade;
+    }
+    
+    /** write trap to set focused state */
+    static.focusedWrite = function(v) {
+        // REMARK: the following sequence could be more compact
+        // but it is easier to follow in the more explicit form
+        const model = trapee.surface?.focus;
+        if (model==null) {
+            cascade = false;
+        } else if (v) {
+            if (trapee.focusable) {
+                model.focusrequest = trapee;
+                cascade = model.setFocus(trapee, true);
+            }
+        } else {
+            if (model.current == trapee) {
+                cascade = model.setFocus(trapee, false);
+            } else {
+                cascade = false;
+            }
+        }
+    }
+    
+    /** read trap to return the focus after trapee on the surface */
+    static.nextfocusRead = function() {
+        var s = trapee.surface;
+        if (s and s.focus) {
+            return s.focus.nextFocus(trapee);
+        }
+        return null;
+    }
+    
+    /** read trap to return the focus before trapee on the surface */
+    static.prevfocusRead = function() {
+        var s = trapee.surface;
+        if (s and s.focus) {
+            return s.focus.prevFocus(trapee);
+        }
+        return null;
+    }
+    
+    /** write trap to handle surface change */
+    static.surfaceWrite = function(v) {
+        var s = trapee.surface;
+        if (s and s.focus) {
+            // drop from current surface
+            s.focus.dropFocus(trapee);
+        }
+        if (v and v.focus) {
+            // add to new surface
+            v.focus.addFocus(trapee);
+        }
+        cascade = v;
+    }
+    
+    /** write trap to focus on Press1 */
+    static.pressWrite = function(v) {
+        cascade = v;
+        if (trapee.focusable) {
+            var s = trapee.surface;
+            if (s and s.focus and !s.focus.focusrequest) {
+                s.focus.focusrequest = trapee;
+            }
+        }
+    }
+
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Polarized.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/polarizable.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Polarized.t
                               (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Polarized.t
       2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,77 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+    </meta:doc>
+    
+    <ui:box>
+        
+        thisbox.contentdim = "contentwidth";
+        thisbox.dim = "width";
+        thisbox.mindim = "minwidth";
+        thisbox.maxdim = "maxwidth";
+        thisbox.orient = "horizontal";
+        thisbox.mousewheel = "HScroll";
+        thisbox.pos = "x";
+        thisbox.shr = "hshrink";
+        thisbox.flip = static.flip;
+        thisbox.horizontal = true;
+        thisbox.orient ++= static.orientWrite;
+        
+    </ui:box>
+    
+    static.flip = function(f) {
+        switch (f) {
+        case "width": return "height";
+        case "height": return "width";
+        case "x": return "y";
+        case "y": return "x";
+        case "contentwidth": return "contentheight";
+        case "contentheight": return "contentwidth";
+        case "maxwidth": return "maxheight";
+        case "maxheight": return "maxwidth";
+        case "minwidth": return "minheight";
+        case "minheight": return "minwidth";
+        case "horizontal": return "vertical";
+        case "vertical": return "horizontal";
+        case "hshrink": return "vshrink";
+        case "vshrink": return "hshrink";
+        case "HScroll": return "VScroll";
+        case "VScroll": return "HScroll";
+        default: return null;
+        }
+    }
+    
+    static.orientWrite = function(v) {
+        var t = trapee;
+        var c = trapee.v_container ? null : trapee.v_content;
+        if (c) {
+            if (v==c.orient) return;
+            c.orient = v;
+        } else {
+            if (v==trapee.orient) return;
+            cascade = v;
+        }
+        if (v == "horizontal") {
+            t.contentdim = "contentwidth";
+            t.dim        = "width";
+            t.maxdim     = "maxwidth";
+            t.mindim     = "minwidth";
+            t.pos        = "x";
+            t.shr        = "hshrink";
+            t.mousewheel = "HScroll";
+            t.horizontal = true;
+        } else {
+            t.contentdim = "contentheight";
+            t.dim        = "height";
+            t.maxdim     = "maxheight";
+            t.mindim     = "minheight";
+            t.pos        = "y";
+            t.shr        = "vshrink";
+            t.mousewheel = "VScroll";
+            t.horizontal = false;
+        }
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/PopupManager.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/popupmanager.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/PopupManager.t
                            (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/PopupManager.t
    2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,318 @@
+<!-- Copyright 2012 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui"
+      xmlns:meta="vexi://meta"
+      xmlns="vexi">
+    
+    <ui:box redirect=":$content" layout="layer">
+        <ui:box id="content" />
+        <ui:box id="container" align="topleft" display="false" layout="place" 
/>
+        
+        .util.redirect..addRedirect(thisbox, $content, "align", "layout", 
"orient");
+        
+        var model = {};
+        surface.popup ++= function() { return model; }
+        surface.popup ++= .util.common..readOnly;
+        
+        var interval = 50;    // sleep interval for pop thread
+        var popcount = 0;     // number of active popups
+        var popforegs = {};   // popgroup foregrounds
+        var popbygroup = {};  // track current popup by group
+        var poptip;           // pop thread in progress marker
+        var requests = {};    // pop request array
+        var reqtimes = {};    // pop request times
+        
+        /** implement event blocking when a popup is displayed to
+         *  stop mouse events being passed to widgets underneath */       
+        var eventBlock = function(v) { return; }
+        
+        var pressWrite = function(v) {
+            cascade = v;
+            for (var k,p in popbygroup) {
+                // keys may be invalidated by popdowns occuring
+                // as a consequence of other group popdowns
+                if (p==null) {
+                    continue;
+                }
+                // take into account whether interacting with the
+                // original popupable as often they are designed
+                // to toggle popped state; this would interfere
+                var m = p.v_popmaster;
+                if (m?.popdownOnExternalEvent and !(m?.mouse?.inside)) {
+                    m.popdown = true;
+                    // popmaster may be off-screen
+                    if (!m.surface) model.pop(m, false);
+                }
+            }
+        }
+        
+        var setupHoldingBox = function(b) {
+            // block Enter/Leave underneath popup
+            b.Move ++= eventBlock;
+               b.Press1 ++= eventBlock;
+               b.Press2 ++= eventBlock;
+               b.Press3 ++= eventBlock;
+               b.Click1 ++= eventBlock;
+               b.Click2 ++= eventBlock;
+               b.Click3 ++= eventBlock;
+               b.DoubleClick1 ++= eventBlock;
+               b.DoubleClick2 ++= eventBlock;
+               b.DoubleClick3 ++= eventBlock;
+        }
+        
+        $container.Press1 ++= pressWrite;
+        $container.Press2 ++= pressWrite;
+        $container.Press3 ++= pressWrite;
+        
+        /** used to track surface_x/y changes */
+        var syncXPos = function(v) { cascade = v; 
popforegs[trapee.popgroup?:"default"].x = v; }
+        var syncYPos = function(v) { cascade = v; 
popforegs[trapee.popgroup?:"default"].y = v; }
+        var updateXPos = function(v) {
+            cascade = v;
+            var m = trapee.v_popmaster;
+            var s = surface;
+            var sW = m.surfaceWidth;
+            if (s and sW) {
+                var d = s.frame.distanceto(m);
+                sW(d.x, s.frame.width);
+            }
+        }
+        var updateYPos = function(v) {
+            cascade = v;
+            var m = trapee.v_popmaster;
+            var s = surface;
+            var sH = m.surfaceHeight;
+            if (s and sH) {
+                var d = s.frame.distanceto(m);
+                sH(d.y, s.frame.height);
+            }
+        }
+        
+        /** private function to pop down popupable 'v' */
+        var popDown = function(v) {
+            var p = v.v_popbox;
+            // ignore non-visible requests
+            if (p.visible) {
+                p.display = false;
+            }
+        }
+        
+        var popboxDisplay = function(v) {
+            cascade = v;
+            if (v) {
+                return;
+            }
+            var p = trapee;
+            // drop active popup traps
+            p.surface_x --= syncXPos;
+            p.surface_y --= syncYPos;
+            p.width --= updateXPos;
+            p.height --= updateYPos;
+            p.visible --= callee;
+            // handle container display
+            popcount--;
+            $container.display = popcount>0;
+            // use default group if none is specified
+            var g = p.popgroup ? p.popgroup : "default";
+            if (popforegs[g]) {
+                popforegs[g].display = false;
+            }
+            if (popbygroup[g]) {
+                (keysof(popbygroup)).remove(g);
+            }
+        }
+        
+        /** private function to pop up box 'v' */
+        var popUp = function(v) {
+            var p = v.v_popbox;
+            // p.v_popmaster == v;
+            // use default group if none is specified
+            var g = p.popgroup ? p.popgroup : "default";
+            // establish popup group
+            var fg = popforegs[g];
+            // establish 'v' as active popup for group
+            if (popbygroup[g]) {
+                // undisplay previous popup in group
+                popbygroup[g].display = false;
+            }
+            popbygroup[g] = p;
+            // call surface update functions
+            var s = surface;
+            var sW = v.surfaceWidth;
+            var sH = v.surfaceHeight;
+            if (s and (sW or sH)) {
+                var d = s.frame.distanceto(v);
+                if (sW) {
+                    sW(d.x, s.frame.width);
+                }
+                if (sH) {
+                    sH(d.y, s.frame.height);
+                }
+            }
+            // display and position popup
+            fg.display = true;
+            fg.x = p.surface_x;
+            fg.y = p.surface_y;
+            p.display = true;
+            // assign active popup traps
+            p.surface_x ++= syncXPos;
+            p.surface_y ++= syncYPos;
+            p.width ++= updateXPos;
+            p.height ++= updateYPos;
+            p.visible ++= popboxDisplay;
+            // handle container display
+            popcount++;
+            $container.display = true;
+        }
+        
+        /** private function to handle timed pop requests */
+        var popRequest = function(v, up, time) {
+            if (time==0 or 2>=arguments.length) {
+                // no delay stated, perform immediate popup/popdown
+                if (requests[v]) {
+                    // drop existing request
+                    (keysof(reqtimes)).remove(v);
+                    (keysof(requests)).remove(v);
+                }
+                up ? popUp(v) : popDown(v);
+                return;
+            }
+            
+            if (requests[v]) {
+                // in request queue
+                if (up == requests[v].display) {
+                    // delete request if display state is same as request
+                    (keysof(reqtimes)).remove(v);
+                    (keysof(requests)).remove(v);
+                } else {
+                    // update time
+                    reqtimes[v] = time;
+                }
+            } else if (up != v.v_popbox.display) {
+                // add to request queue
+                requests[v] = v;
+                reqtimes[v] = time;
+            } else {
+                return;
+            }
+            
+            // check if pop request thread is running and necessary
+            if (!poptip and requests[v]) {
+                // signal thread is active
+                poptip = true;
+                // initiate a background thread to hande timed pop requests
+                vexi.thread = function() {
+                    var activerequests;
+                    do {
+                        // reset active marker
+                        activerequests = false;
+                        // loop through pop requests
+                        for (var key in requests) {
+                            // update request time and act if necessary
+                            if (0 >= (reqtimes[key] -= interval)) {
+                                requests[key].display ? popDown(v) : popUp(v);
+                                continue;
+                            }
+                            // mark to keep loop active
+                            activerequests = true;
+                        }
+                        // sleep
+                        vexi.thread.sleep( interval );
+                    // loop if marked
+                    } while (activerequests);
+                    // signal thread has ended
+                    poptip = false;
+                }
+            }
+        }
+        
+        /** add a popupable box to the surface */
+        model.addPopBox = function(v) {
+            var p = v.v_popbox;
+            
+            // detach popbox
+            p.thisbox = null;
+            
+            // use default group if none is specified
+            var g = p.popgroup ? p.popgroup : "default";
+            
+            if (popforegs[g]) {
+                // if group exists slot into it
+                popforegs[g].add(p);
+            
+            } else {
+                // initialize new group, especially its foreground box
+                var z = p.popindex;
+                if (z==null) {
+                    z = 0;
+                }
+                var fg = vexi.box;
+                fg.cursor = "default";
+                fg.display = false;
+                fg.shrink = true;
+                fg.zindex = z;
+                fg.add(p);
+                setupHoldingBox(fg);
+                popforegs[g] = fg;
+                var n = $container.numchildren;
+                for (var i=1; n>i; i++) {
+                    if ($container[i].zindex>z) {
+                        $container[i] = fg;
+                        return;
+                    }
+                }
+                $container[n] = fg;
+            }
+        }
+
+        /** remove a popupable box from the surface */
+        model.delPopBox = function(v) {
+            var p = v.v_popbox;
+            // use default group if none is specified
+            var g = p.popgroup ? p.popgroup : "default";
+            if (p.visible) {
+                // clean up popbox
+                popDown(v);
+            }
+            var fg = popforegs[g];
+            // FIXME: needed to avoid error; open/close 'packed layout' tab in 
demo
+            if (fg==null) {
+                return;
+            }
+            fg[fg.indexof(p)] = null;
+            
+            if (fg.numchildren == 0) {
+                // clean up unused foreground box
+                popforegs[g] = null;
+                fg.thisbox = null;
+            }
+        }
+        
+        /** pop box 'v', direction 'up', optionally after 'time' */
+        model.pop = function(v, up, time) {
+            if (time) {
+                popRequest(v, up, time);
+            } else {
+                if (up) {
+                    popUp(v);
+                } else {
+                    popDown(v);
+                }
+            }
+        }
+        
+        /** popdown when surface loses focus unless told to otherwise */
+        surface.frame.Focused ++= function(v) {
+            cascade = v;
+            if (!v) {
+                for (var k,p in popbygroup) {
+                    var m = p.v_popmaster;
+                    if (!m.ignoreFocusLoss) {
+                        m.popdown = true;
+                    }
+                }
+            }
+        }
+        
+    </ui:box>
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Popupable.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/popupable.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Popupable.t
                               (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Popupable.t
       2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,157 @@
+<!-- Copyright 2011 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <usage>
+            Point v_popbox to the box that should be popped up.
+            This should not be the same as the box applying popupable,
+            but instead should be a child box of the template.
+
+            The popbox is positioned according to its surface_x and
+            surface_y properties so set the appropriate traps to
+            adjust these as necessary (v_popbox.surface_x = ...).
+
+            For examples see option and combo in org.vexi.theme.classic
+        </usage>
+    </meta:doc>
+    
+    <ui:box>
+        
+        // public properties
+        thisbox.focused;
+        thisbox.popupable;
+        thisbox.popup;
+        thisbox.popdown;
+        thisbox.popupdelay = 0;
+        thisbox.popdowndelay = 0;
+        thisbox.popped = false;
+        
+        // implementation properties
+        // TODO: thisbox.blockEvents = true;
+        thisbox.popdownOnExternalEvent = true;
+        thisbox.v_popbox = null;
+        
+        // assign static trap functions
+        focused    ++= static.focusWrite;
+        popdown    ++= static.popdownWrite;
+        popped     ++= static.poppedRead;
+        popup      ++= static.popupWrite;
+        popupable  ++= static.popupableRead;
+        surface    ++= static.surfaceWrite;
+        v_popbox   ++= static.popboxWrite;
+        KeyPressed ++= static.keypressWrite;
+        
+    </ui:box>
+    
+    // for code readabiliy
+    static.UP = true;
+    static.DOWN = false;
+    
+    /** popdown if popbox undisplays itself */
+    static.displayWrite = function(v) {
+        cascade = v;
+        var m = trapee.v_popmaster;
+        if (m.popped and !v) {
+            m.popdown = true;
+        }
+        if (!m.popped and v) {
+            m.popup = true;
+        }
+    }
+    
+    /** integration with focusable */
+    static.focusWrite = function(v) {
+        if (!v and trapee.v_popbox and trapee.v_popbox.visible) {
+            trapee.popdown = true;
+        }
+        cascade = v;
+    }
+    
+    /** write trap on KeyPressed event */
+    static.keypressWrite = function(v) {
+        cascade = v;
+        if (v == "escape") {
+            trapee.popdown = true;
+        }
+    }
+    
+    /** write trap to popdown v_popbox */
+    static.popdownWrite = function(v) {
+        cascade = v;
+        var s = trapee.surface;
+        // need a surface to function
+        if (!s or !trapee.popped) {
+            return;
+        }
+        // pop down
+        s.popup.pop(trapee, static.DOWN, trapee.popdowndelay);
+        trapee.v_popbox.display --= static.displayWrite;
+    }
+    
+    /** indicate state of the popbox */
+    static.poppedRead = function() { return trapee.v_popbox.display; }
+    
+    /** write trap to popup v_popbox */
+    static.popupWrite = function(v) {
+        cascade = v;
+        var s = trapee.surface;
+        // need a surface to function
+        if (!s or trapee.popped) {
+            return;
+        }
+        // pop up
+        s.popup.pop(trapee, static.UP, trapee.popupdelay);
+        trapee.v_popbox.display ++= static.displayWrite;
+    }
+    
+    /** read trap to detect popupable state */
+    static.popupableRead = function() { return trapee.enabled; }
+    
+    /** initialize popbox */
+    static.popboxWrite = function(v) {
+        var s = trapee.surface;
+        var p = trapee.v_popbox;
+        if (p) {
+            p.Move --= static.blockEvent;
+            p.v_popmaster = null;
+            if (s) {
+                s.popup.delPopBox(p);
+            }
+        }
+        cascade = v;
+        if (v) {
+            v.Move ++= static.blockEvent;
+            v.display = false;
+            v.v_popmaster = trapee;
+            if (s) {
+                s.popup.addPopBox(trapee);
+            }
+        }
+    }
+    
+    /** block press events hitting underneath the popbox */
+    static.blockEvent = function(v) { return true; }
+    
+    /** register popbox once surface is available */
+    static.surfaceWrite = function(v) {
+        // clean up old surface
+        var s = trapee.surface;
+        if (s and trapee.v_popbox) { // FIXME: why is the 2nd check required?
+            if (trapee.popped) {
+                s.popup.pop(trapee, static.DOWN, 0);
+            }
+            s.popup.delPopBox(trapee);
+            trapee.v_popbox.display --= static.displayWrite;
+        }
+        // register with new surface
+        if (v and trapee.v_popbox) {
+            v.popup.addPopBox(trapee);
+            // must do this because v_popbox is removed
+            // and its surface trap won't fire otherwise
+            trapee.v_popbox.surface = v;
+        }
+        cascade = v;
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Repeater.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/repeatable.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Repeater.t
                                (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Repeater.t
        2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,88 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <desc>Apply to make a widget have a repeating action</desc>
+        <usage>
+            The repeating behaviour depends on the following:
+            
+            * repeat - put to true or false to start/stop repeating
+            
+            * interval - the interval between repeats in ms
+            
+            * repeatCall - the property to put to when repeating
+            
+            Repeater widgets recognise the following state property:
+            
+            * enabled - Repeating behaviour only works if 'true'
+                        and putting 'false' to enabled will end any
+                        ongoing repeating
+        </usage>
+    </meta:doc>
+    
+    <ui:Box>
+        
+        thisbox.counter = 0;        // consecutive repetition counter
+        thisbox.enabled;
+        thisbox.interval = 100;     // repetition interval (ms)
+        thisbox.repeat = false;     // repeating state
+        thisbox.repeatCall = "action"; // the property to repeat to
+        
+        if (enabled==null) {
+            enabled = true;
+        } 
+        
+        enabled ++= static.enableWrite;
+        repeat ++= static.repeatWrite;
+        
+    </ui:Box>
+    
+    /** initiate (true) or stop (false) repeating action */
+    static.enableWrite = function(v) {
+        cascade = v;
+        if (!trapee.enabled and trapee.repeat) {
+            trapee.repeat = false;
+        }
+    }
+    
+    /** initiate (true) or stop (false) repeating action */
+    static.repeatWrite = function(v) {
+        if (v) {
+            if (!trapee.repeat) {
+                // perform first action immediately
+                trapee.v_repeatCallTime = vexi.date().getTime();
+                trapee.action = true;
+                // only start if previously false and thread is inactive
+                if (!trapee.v_repeat_thread) {
+                    // marks the thread as active
+                    trapee.v_repeat_thread = true;
+                    // begin background thread
+                    vexi.thread = function() {
+                        do {
+                            // pause before first repeating action
+                            var t = vexi.date().getTime();
+                            var d = t - trapee.v_repeatCallTime;
+                            while (trapee.repeat and (trapee.interval > d)) {
+                                vexi.thread.sleep(trapee.interval - d);
+                                t = vexi.date().getTime();
+                                d = t - trapee.v_repeatCallTime;
+                            }
+                            if (trapee.repeat) {
+                                trapee.v_repeatCallTime = t;
+                                trapee[trapee.repeatCall] = true;
+                                trapee.counter ++;
+                            }
+                        } while (trapee.repeat);
+                        // mark thread inactive
+                        trapee.v_repeat_thread = false;
+                    }
+                }
+            }
+        } else {
+            trapee.counter = 0;
+        }
+        cascade = v;
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectContainer.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/selectcontainer.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectContainer.t
                         (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectContainer.t
 2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,123 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="org.vexi.lib.role" 
xmlns:rdt="vexi.util.redirect" >
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <desc>
+            Implements a container for selectable children.
+        </desc>
+        <notes>
+            If using this template, you must either post-apply
+            org.vexi.lib.layout.container or alternatively put
+            'true' to the 'v_container' property manually.
+        </notes>
+    </meta:doc>
+    
+    <ui:box>
+        
+        thisbox.v_content = thisbox;
+        thisbox.v_listgroup;
+        
+        thisbox.group ++= static.groupRead;
+        thisbox.v_listgroup ++= static.listgroupWrite;
+        
+        /** select the first available item in the list */
+        thisbox.selectFirst = function() {
+            var group = v_listgroup;
+            if (group==null) {
+                return;
+            }
+            var vec = group.members;
+            var item = vec.first;
+            while (item!=null) {
+                if (item.display and item.enabled) {
+                    item.selected = true;
+                    break;
+                }
+                item = vec.after(item);
+            }
+        }
+        
+        /** select the lastmost available item in the list */
+        thisbox.selectLast = function() {
+            var group = v_listgroup;
+            if (group==null) {
+                return;
+            }
+            var vec = group.members;
+            var item = vec.last;
+            while (item!=null) {
+                if (item.display and item.enabled) {
+                    item.selected = true;
+                    break;
+                }
+                item = vec.before(item);
+            }
+        }
+        
+        thisbox.v_container ++= static.containerWrite;
+        
+    </ui:box>
+    
+    /** access to the group */
+    static.groupRead = function() {
+        return trapee.v_listgroup;
+    }
+    
+    /** allow trapping/putting to selected */
+    static.listgroupWrite = function(v) {
+        cascade = v;
+        rdt..addRedirect(trapee, trapee.v_listgroup, "selected");
+    }
+    
+    /** assign group and traps to children */
+    static.childrenAdded = function(c) {
+        cascade = c;
+        var t = trapee;
+        var g = t.v_listgroup;
+        if (c) {
+            if (g) {
+                // insert into existing group
+                // NB write trap on selectable.group handles assignment
+                c.group = g;
+            } else {
+                // no group yet, create one
+                // NB read trap on selectable.group handles group creation
+                g = c.group;
+                if (g==null) {
+                    // not a selectable
+                    return;
+                }
+                t.v_listgroup = g;
+                
+                if (trapee.syncView) {
+                    // keep selected in view if a scrolling widget
+                    g.selected ++= trapee.syncView;
+                }
+                if (c.selected) {
+                    // respect selected state of c
+                    t.v_listgroup.selected = c;
+                }
+            }
+        }
+    }
+    
+    /** assign group and traps to children */
+    static.childrenRemoved = function(c) {
+        if (c==null) {
+            var _c = trapee[trapname];
+            if (_c and _c.v_group) {
+                _c.group = null;
+            }
+        }
+        cascade = c;
+    }
+    
+    /** complete widget is set up */
+    static.containerWrite = function(v) {
+        cascade = v;
+        trapee.Children ++= static.childrenAdded;
+        trapee.v_content.Children ++= static.childrenRemoved;
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectGrouper.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/selectgroup.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectGrouper.t
                           (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectGrouper.t
   2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,34 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:meta="vexi://meta"
+      xmlns="org.vexi.lib.role">
+
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <desc>
+            Groups visible selectable children e.g. RadioButtons
+        </desc>
+        <notes>
+            If using this template, you must either post-apply
+            org.vexi.lib.role.Container or alternatively put
+            'true' to the 'v_container' property manually.
+        </notes>
+    </meta:doc>
+    
+    <SelectContainer>
+        
+        // allow group enable/disable
+        thisbox.enabled ++= static.enableWrite;
+        
+    </SelectContainer>
+    
+    static.enableWrite = function(v) {
+        cascade = v;
+        var content = trapee.v_content;
+        var n = content.numchildren;
+        for (var i=n-1; i>=0; i--) {
+            content[i].enabled = v;
+        }
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectList.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/selectlist.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectList.t
                              (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/SelectList.t
      2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,97 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:meta="vexi://meta" xmlns="org.vexi.lib.role">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <desc>
+            Implements a container for selectable children.
+        </desc>
+        <notes>
+            If using this template, you must either post-apply
+            org.vexi.lib.layout.container or alternatively put
+            'true' to the 'v_container' property manually.
+        </notes>
+    </meta:doc>
+    
+    <SelectContainer>
+        
+        thisbox.selection;
+        
+        // reusable distanceto objects
+        var dtscroll = null;
+        var dtcontent = null;
+        
+        /** keeps the selected item within view */
+        thisbox.syncView = function(v) {
+            cascade = v;
+            if (!v or !popped) {
+                return;
+            }
+            if (dtscroll==null) {
+                dtscroll = th_scroll.distanceto(v);
+                dtcontent = v_content.distanceto(v);
+            } else {
+                dtscroll.to = v;
+                dtcontent.to = v;
+            }
+            if (dtscroll.y+v.height > th_scroll.height) {
+                th_scroll.viewy = dtcontent.y+v.height-th_scroll.height;
+            } else if (0 > dtscroll.y) {
+                th_scroll.viewy = dtcontent.y;
+            }
+        }
+        
+        thisbox.selection ++= static.selectionRead;
+        thisbox.v_container ++= static.containerWrite;
+        
+    </SelectContainer>
+    
+    /** applied to list items */
+    static.enterEvent = function(v) {
+        if (trapee.enabled) {
+            trapee.selected = true;
+        }
+        cascade = v;
+    }
+    
+    /** applied to list items */
+    static.leaveEvent = function(v) {
+        if (trapee.selected) {
+            trapee.selected = false;
+        }
+        cascade = v;
+    }
+    
+    /** assign group and traps to children */
+    static.childrenWrite = function(c) {
+        if (c) {
+            c.Enter ++= static.enterEvent;
+            c.Leave ++= static.leaveEvent;
+        } else {
+            var _c = trapee[trapname];
+            if (_c) {
+                _c.Enter ++= static.enterEvent;
+                _c.Leave --= static.leaveEvent;
+            }
+        }
+        cascade = c;
+    }
+    
+    /** complete widget is set up */
+    static.containerWrite = function(v) {
+        cascade = v;
+        trapee.v_content.Children ++= static.childrenWrite;
+    }
+    
+    /** return selected elements as an array */
+    static.selectionRead = function() {
+        var s = [];
+        for (var i,child in trapee.v_content) {
+            if (child.selected) {
+                s.push(child);
+            }
+        }
+        return s;
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Selectable.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/selectable.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Selectable.t
                              (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Selectable.t
      2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,264 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="vexi.util">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <desc>
+        </desc>
+        <todo>
+            1..n selection model with rolling selection
+            Split group manager code into 'lib.role.selectmanager'
+        </todo>
+        <details>
+            Items which wish to be part of a group of selectable widgets
+            are grouped together using the following properties:
+            
+            * group - When read this returns the group of a selectable
+                      widget.  If it has no group, one is created and then
+                      returned, so reading this property inserts a widget
+                      into a group of its own.  Putting a different group
+                      to this property will add the widget to that group.
+            
+            * selected - Whether this is the (or one of the) selected
+                         members of its group.
+            
+            It integrates with clickable and focusable.
+        </details>
+    </meta:doc>
+    
+    <ui:box>
+        
+        thisbox.action;           // clickable integration
+        thisbox.focusable;        // focusable integration
+        thisbox.group;            // external access to group
+        thisbox.v_group;          // internal reference to group
+        thisbox.mixed = false;    // mixed status
+        thisbox.nextselect;       // next group member to select
+        thisbox.prevselect;       // previous group member to select
+        thisbox.selected = false; // selection status
+        
+        action     ++= static.actionWrite;
+        focusable  ++= static.focusableRead;
+        group      ++= static.groupRead;
+        group      ++= static.groupWrite;
+        nextselect ++= static.nextselectRead;
+        prevselect ++= static.prevselectRead;
+        selected   ++= static.selectedRead;
+        selected   ++= static.selectedWrite;
+        KeyPressed ++= static.keypressWrite;
+        
+    </ui:box>
+    
+    /** clickable integration */
+    static.actionWrite = function(v) {
+        cascade = v;
+        trapee.selected = trapee.v_group ? true : !trapee.selected;
+    }
+    
+    /** integration with clickable and focusable */
+    static.focusableRead = function() {
+        var t = trapee;
+        var g = trapee.v_group;
+        // focusable property must be true
+        return cascade and (!g or
+            // selectable clickable widget being clicked on
+            (t.primed or t.selected) or
+            // navigated group with keys
+            (g.keygroup) or
+            // no other group member is selected
+            (!g.selected and (t == g.firstMember)));
+    }
+    
+    /** group read trap */
+    static.groupRead = function() {
+        // if no group, get one
+        if (!trapee.v_group) {
+            trapee.v_group = static.toGroup(trapee);
+        }
+        return trapee.v_group;
+    }
+    
+    /** group write trap */
+    static.groupWrite = function(v) {
+        // add us to group v
+        trapee.v_group = static.toGroup(trapee, trapee.v_group, v);
+        cascade = v;
+    }
+    
+    /** find the next selectable member */
+    static.nextselectRead = function() {
+        var ns = trapee;
+        var g = ns.v_group;
+        do {
+            ns = g.members.after(ns);
+            if (!ns) {
+                ns = g.members.first;
+            }
+            if (!ns.visible or !ns.enabled) {
+                continue;
+            }
+            return ns;
+        } while (ns != trapee);
+        return ns;
+    }
+    
+    /** find the previous selectable member */
+    static.prevselectRead = function() {
+        var ps = trapee;
+        var g = ps.v_group;
+        do {
+            ps = g.members.before(ps);
+            if (!ps) {
+                ps = g.members.last;
+            }
+            if (!ps.visible or !ps.enabled) {
+                continue;
+            }
+            return ps;
+        } while (ps != trapee);
+        return ps;
+    }
+    
+    /** selected read trap - use 'cascade == true' to guarrantee booleans */
+    static.selectedRead = function() { return trapee.mixed or (cascade == 
true); }
+    
+    /** selected write trap */
+    static.selectedWrite = function(v) {
+        var t = trapee;
+        var g = t.v_group;
+        if (g) {
+            if (v) {
+                if (g.selected != t) {
+                    if (g.selected) {
+                        g.selected.selected = false;
+                    }
+                    g.selected = t;
+                    g.focused = true;
+                }
+            } else if (g.selected == t) {
+                g.selected = null;
+            }
+        }
+        // to avoid selected == null
+        cascade = v == true;
+    }
+    
+    /** selection by keyboard navigation for selectable groups */
+    static.keypressWrite = function(v) {
+        var t = trapee;
+        var g = t.v_group;
+        if (!g) {
+            // can't do anything with no group
+            cascade = v;
+            return;
+        }
+        
+        // deal with key event
+        g.keygroup = true;
+        if (v == "down" or v == "right") {
+            // forwards
+            var ns = t.nextselect;
+            if (ns) {
+                ns.selected = true;
+            }
+        } else if (v == "up" or v == "left") {
+            // backwards
+            var ps = t.prevselect;
+            if (ps) {
+                ps.selected = true;
+            }
+        } else {
+            // pass to other widget code
+            cascade = v;
+        }
+        // finished - move on
+        g.keygroup = false;
+        
+        // focus the next selected
+        if (g.selected and g.selected != trapee) {
+            g.selected.focused = true;
+        }
+    }
+    
+    // static content
+    
+    // create a new group containing, optionally, v
+    var newGroup = function(v) {
+        // initialize new group
+        var g = {
+            keygroup : false,
+            members : new .vector(v),
+            selected : null,
+            selection : []
+        };
+        
+        // merge another select group with this one
+        g.merge = function(group, after) {
+            if (group.selected) {
+                group.selected = false;
+            }
+            var mem = group.members;
+            var obj = mem.first;
+            // reassign group references - must happen before merge
+            while (obj) {
+                obj.v_group = g;
+                obj = mem.after(obj);
+            }
+            // merge vectors
+            g.members.merge(mem, after);
+        }
+        
+        // select the first in the group
+        g.firstMember ++= function() {
+            var f = g.members.first;
+            while (f and !f.enabled or !f.visible) {
+                f = g.members.after(f);
+            }
+            return f;
+        }
+        
+        // return next member in the group after 'n'
+        g.memberAfter = function(n) { return n.nextselect; }
+        
+        // select previous group member before 'p'
+        g.memberBefore = function(p) { return p.prevselect; }
+        
+        return g;
+    }
+    
+    /** change the group of v from oldg to newg, dealing with null args */
+    static.toGroup = function(v, oldg, newg, after) {
+        if (3 > arguments.length) {
+            // no group given, create group
+            newg = newGroup(v);
+        } else {
+            if (oldg) {
+                // remove v from oldg
+                oldg.members.remove(v);
+                if (oldg.selected == v) {
+                    oldg.selected = null;
+                }
+            }
+            if (newg) {
+                // add to group
+                if (after) {
+                    newg.members.insert(v, after);
+                } else {
+                    newg.members.push(v);
+                }
+            } else {
+                return null;
+            }
+        }
+        if (v.selected) {
+            // initialize as selected
+            if (newg.selected) {
+                newg.selected.selected = false;
+            }
+            newg.selected = v;
+        }
+        // return the new group for reference
+        return newg;
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Subsurface.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/subsurface.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Subsurface.t
                              (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Subsurface.t
      2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,46 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta"
+    xmlns:role="org.vexi.lib.role" xmlns:rdrt="vexi.util.redirect">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <name>Subsurface</name>
+        <desc>For advanced management of surface objects</desc>
+        <usage>
+            Using a subsurface allows a widget to modify a surface
+            by using read traps on a clone that will not affect the
+            original surface.
+            
+            Preapply and the surface argument will always be the
+            clone.  Postapply if your template requires access to
+            the original surface object as well as the clone.
+        </usage>
+    </meta:doc>
+    
+    <ui:box>
+    
+        var old_clone;     // clone of old surface
+        var old_surface;   // original old surface
+        var surface_clone; // clone of surface object
+        
+        /** return the cloned surface object representing the current surface 
*/
+        thisbox.surface ++= function() {
+            // the check against the old surface is required to
+            // keep descendent surface trap behaviour consistent
+            // - if we just return the clone then surface reads
+            // appear the same to descendents pre/post cascade
+            return cascade==old_surface ? old_clone : surface_clone;
+        }
+        
+        /** set up clone of the surface object */
+        thisbox.surface ++= function(v) {
+            surface_clone = v==null ? null : vexi.clone(v);
+            cascade = surface_clone;
+            // all descendent surface traps are now complete
+            // so subsuquent actions here do not affect them
+            old_clone = surface_clone;
+            old_surface = v;
+        }
+        
+    </ui:box>
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Surface.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/surface.t)
===================================================================
--- 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Surface.t
                         (rev 0)
+++ 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/Surface.t
 2015-05-09 09:40:24 UTC (rev 4793)
@@ -0,0 +1,193 @@
+<!-- Copyright 2015 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="vexi">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <desc>Apply to the root of a surface (frame/window)</desc>
+    </meta:doc>
+    
+    <ui:Box>
+    
+        const readOnly = .util.common..readOnly;
+        const addRedirect = .util.redirect..addRedirect;
+        
+        // the surface object and key components
+        var s = {};
+        
+        /** proxy to the surface object */
+        thisbox.surface ++= function() { return s; };
+        
+        var event = {};
+        s.event ++= function() { return event; }
+        s.event ++= readOnly;
+        
+        var frame = {};
+        s.frame ++= function() { return frame; }
+        s.frame ++= readOnly;
+        
+        // for locking trap forwarding on CLose/s.Close
+        var closeLock = false;
+        
+        /** notify surface.Close when closing surface
+         *  REMARK - done this way [instead of using a redirect] to prevent
+         *  application code from blocking the user closing a frame
+         */
+        thisbox.Close ++= function(v) {
+            if (!closeLock) {
+                closeLock = true;
+                frame.Close = true;
+                closeLock = false;
+            }
+            cascade = v;
+        }
+        
+        /** manually redirect s.frame.Close */
+        frame.Close ++= function(v) {
+            if (closeLock) {
+                return;
+            }
+            closeLock = true;
+            Close = true;
+            closeLock = false;
+            cascade = v;
+        }
+        
+        /** used to add traps on surface.Move as redirecting Move impacts 
performance */
+        event.addMoveTrap = function(v) { thisbox._Move ++= v; };
+        
+        /** used to remove traps from surface.Move */
+        event.delMoveTrap = function(v) { thisbox._Move --= v; };
+            
+        /** redirect input events for access */
+        addRedirect(event, thisbox,
+            "Click1", "Click2", "Click3", "HScroll", "VScroll",
+            "DoubleClick1", "DoubleClick2", "DoubleClick3",
+            "Press1", "Press2", "Press3",
+            "Release1", "Release2", "Release3",
+            "_Click1", "_Click2", "_Click3", "_HScroll", "_VScroll",
+            "_DoubleClick1", "_DoubleClick2", "_DoubleClick3",
+            "_Press1", "_Press2", "_Press3",
+            "_Release1", "_Release2", "_Release3" );
+        
+        /** special case key events for focusable integration */
+        addRedirect(thisbox, event, "_KeyPressed", "_KeyReleased" );
+        
+        /** redirect frame properties for access */
+        addRedirect(frame, thisbox,
+            "framewidth", "frameheight", "frameicon", "frametitle",
+            "mouse", "distanceto", "width", "height", "x", "y",
+            "ToFront", "ToBack", "RequestFocus", "Maximized", "Minimized");
+        
+        // special case Focused, forward only
+        thisbox.Focused ++= function(v) { cascade = v; frame.Focused = v; }
+        
+    </ui:Box>
+    <theme.Surface />
+    
+    /** access to the theme parameter setting */
+    const getThemeRes = function(themestr) {
+        var themeres = null;
+        if (themestr != null) {
+            var sub = themestr.split('.');
+            var res = vexi[""];
+            for (var i=0; sub.length>i; i++) {
+                res = res[sub[i]];
+            }
+            themeres = res;
+        }
+        // string doesn't resolve
+        if (themeres == null) {
+            vexi.log.debug("Could not resolve '"+themestr+"', looking in 
.conf.Theme");
+            if (.conf.Theme[""]!=null) {
+                themeres = .conf.Theme..location;
+            }
+        }
+        if (themeres == null) {
+            vexi.log.debug("No theme found, defaulting to classic");
+            themeres = vexi..org.vexi.theme.classic;
+        }
+        var str = (""+ret);
+        str = str.substring(0, str.indexOf('$'));
+        var themename;
+        try { themename = ret.Settings..themename; } catch(e) { }
+        vexi.log.debug("Using theme "+(themename?"  ("+str+")":str));
+        return themeres;
+    }
+
+
+    /** access to the icon parameter setting */
+    const getIconResource = function() {
+        var iconstr = vexi.params["vexi.icon"];
+        var iconres = null;
+        if (iconstr != null) {
+            var sub = iconstr.split('.');
+            var res = vexi[""];
+            for (var i=0; sub.length>i; i++) {
+                res = res[sub[i]];
+            }
+            iconres = res;
+        }
+        if (iconres == null) {
+            if (.conf.Icon[""]!=null) {
+                iconres = .conf.Icon..iconpath?[0];
+            }
+        }
+        if (iconres == null) {
+            try { iconres = .theme.Settings..iconlocation; } catch(e) { }
+        } 
+        var str = (""+ret);
+        str = str.substring(0, str.indexOf('$'));
+        vexi.log.debug("Using icon set: "+str);
+        return iconres;
+    }
+    
+    static.getIcons = function(){
+        var r = .conf.Icon[""]?.iconpath;
+        if(r==null) return [];
+        return r;
+    };
+    
+    /*
+     * THEME HANDLING
+     */
+    
+    static.theme ++= function(newtheme) {
+        if (typeof newtheme == "string") {
+            static.theme = getThemeRes(newtheme);
+            return;
+        }
+        if (static.theme) {
+            .theme --= static.theme;
+        }
+        try {
+            .theme ++= newtheme;
+            cascade = newtheme;
+        } catch(e) {
+            vexi.trace("Unable to apply theme");
+            vexi.trace(e);
+        }
+    }    
+    
+    
+    try {
+        const theme = getThemeRes(vexi.params["vexi.theme"]);
+        // theme specified
+        static.theme = theme;
+    } catch(e) {
+        vexi.trace("Unable to establish theme, most widgets will not work");
+        vexi.trace(e);
+    }
+    
+    try {
+       var icons = getIconResource();
+        // icons specified
+        if (icons) {
+            .icon ++= icons;
+        }
+        vexi..org.vexi.lib.layout.Icon..iconpath = getIcons();
+    } catch(e) {
+        vexi.trace("Unable to establish icons");
+        vexi.trace(e);
+    }
+    
+</vexi>

Copied: 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/TooltipAgent.t
 (from rev 4785, 
branches/vexi3_integrated_layout/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/tooltipable.t)

@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
One dashboard for servers and applications across Physical-Virtual-Cloud 
Widest out-of-the-box monitoring support with 50+ applications
Performance metrics, stats and reports that give you Actionable Insights
Deep dive visibility with transaction tracing using APM Insight.
http://ad.doubleclick.net/ddm/clk/290420510;117567292;y
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to