initial checkin
[org.ibex.widgets.git] / src / ibex / lib / selectable.t
1 <!-- Copyleft 2004 - see COPYING for details [LGPL] -->
2
3 <ibex>
4     <meta:doc>
5         Author: Charles Goodwin
6
7         See ibex.theme.selectable for documentation
8
9         TODO:
10             1..n selection model with rolling selection
11     </meta:doc>
12
13     // static content
14
15     var groups = {};    // the groups of selectables
16
17     static.toGroup = function(v, oldg, g) {
18
19         // no group given, create group
20         if (3 > arguments.length) {
21             g = { members : (ibex..ibex.util.vector..newVector(v)),
22                   selected : null, selection : [] };
23             //groups[g] = g;
24             groups[g] = g;
25         }
26         // validate group
27         else if (g and groups[g] != g) {
28             ibex.log.warn("Invalid group passed to toGroup: " + g + " " + groups[g]);
29             return oldg;
30         }
31
32         // remove v from oldg
33         if (oldg and g != oldg) {
34             oldg.members.remove(v);
35
36             // clean up group info
37             if (oldg.selection[v]) v.selected = false;
38
39             // clean up groups list
40             if (!oldg.members.length) groups[oldg] = null;
41         }
42
43         // add to group
44         if (g) {
45             if (g != oldg) g.members.push(v);
46             return g;
47         }
48         else return null;
49     }
50
51     // end of static content
52
53     <ui:box>
54
55         thisbox.mixed;      // mixed status
56         thisbox.nextselect; // next group member to select
57         thisbox.prevselect; // previous group member to select
58         thisbox.selected;   // selection status
59
60         var groupref;       // internal reference to group
61
62         // group read trap
63         thisbox.group ++= function() {
64             // if no group, get one
65             if (!groupref) groupref = static.toGroup(thisbox);
66             return groupref;
67         }
68
69         // group write trap
70         thisbox.group ++= function(v) {
71             // add us to group v
72             groupref = static.toGroup(thisbox, groupref, v);
73         }
74
75         // selected read trap
76         thisbox.selected ++= function() {
77             if (mixed) return true;
78             else return cascade;
79         }
80
81         // selected write trap
82         thisbox.selected ++= function(v) {
83             if (groupref) {
84                 if (v) {
85                     if (groupref.selected != thisbox) {
86                         if (groupref.selected) groupref.selected.selected = false;
87                         groupref.selected = thisbox;
88                     }
89                 }
90                 else if (groupref.selected == thisbox) groupref.selected = null;
91             }
92         }
93
94         // find the next selectable member
95         thisbox.nextselect ++= function() {
96             var ns = thisbox;
97             do {
98                 ns = groupref.members.after(ns);
99                 if (!ns) ns = groupref.members.first;
100             } while (!ns.enabled and ns != thisbox);
101             
102             return ns.enabled ? ns : null;
103         }
104
105         // find the previous selectable member
106         thisbox.prevselect ++= function() {
107             var ps = thisbox;
108             do {
109                 ps = groupref.members.before(ps);
110                 if (!ps) ps = groupref.members.last;
111             } while (!ps.enabled and ps != thisbox);
112
113             return ps.enabled ? ps : null;
114         }
115
116         // integration with clickable
117         action ++= function(v) { selected = true; }
118
119         // integration with clickable and focusable
120         focusable ++= function() { return cascade and (primed or selected); }
121
122         // integration with focusable
123         nextfocus ++= function() {
124             var nf = cascade;
125             while (nf.group == groupref and nf != thisbox) nf = cascade;
126             return nf;
127         }
128
129         // integration with focusable
130         prevfocus ++= function() {
131             var pf = cascade;
132             while (pf.group == groupref and pf != thisbox) pf = cascade;
133             return pf;
134         }
135
136     </ui:box>
137 </ibex>