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