cleaned all trailing white space from source files.
[sdk] / extras / gui / controls / CheckListBox.ec
1 #ifdef ECERE_STATIC
2 import static "ecere"
3 #else
4 import "ecere"
5 #endif
6
7 class CheckListBoxButton : Button
8 {
9    isCheckbox = true, inactive = true, size = { 12, 12 };
10
11    bool CheckListBox::NotifyPushed(Button button, int x, int y, Modifiers mods)
12    {
13       currentRow = (DataRow)button.id;
14       ToggleCheck(currentRow);
15       return false;
16    }
17
18    bool CheckListBox::NotifyReleased(Button button, int x, int y, Modifiers mods)
19    {
20       return false;
21    }
22
23    bool OnMouseOver(int x, int y, Modifiers mods)
24    {
25
26       return true;
27    }
28
29    bool OnMouseLeave(Modifiers mods)
30    {
31
32       return true;
33    }
34 }
35
36 class CheckListBox : ListBox
37 {
38    Map<uintptr, CheckListBoxButton> buttonMaps { };
39    AVLTree<DataRow> rowChecks { };
40    AVLTree<DataRow> rowDisabled { };
41    int checkIndent;
42
43    checkIndent = 20;
44
45    fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true,
46    noDragging = true;
47    // rowHeight = 18;
48
49    void OnDestroy()
50    {
51       buttonMaps.RemoveAll();
52    }
53
54    bool NotifyCollapse(CheckListBox listBox, DataRow row, bool collapsed)
55    {
56       DataRow r;
57       for(r = row.firstRow; r && r != row; )
58       {
59          if(collapsed)
60          {
61             MapIterator<uintptr, Button> it { map = listBox.buttonMaps };
62             if(it.Index((uintptr)r, false))
63             {
64                Button checkBox = it.data;
65                if(checkBox)
66                {
67                   checkBox.Destroy(0);
68                   it.Remove();
69                }
70             }
71          }
72          else
73          {
74             listBox.SetupButtons(r, false);
75          }
76          if(r.firstRow && !r.collapsed)
77             r = r.firstRow;
78          else
79             for(; r != row; r = r.parent)
80                if(r.next) { r = r.next; break; }
81       }
82       for(r = row.GetNextRow(); r; r = r.GetNextRow())
83       {
84          Button checkBox = listBox.buttonMaps[(uintptr)r];
85          if(checkBox)
86             checkBox.position.y = 1 + (r.index + listBox.hasHeader) * listBox.rowHeight;
87       }
88       return true;
89    }
90
91    bool CheckPartialChecks(DataRow row)
92    {
93       DataRow r;
94       for(r = row.firstRow; r; r = r.next)
95       {
96          if(rowChecks.Find(r) || CheckPartialChecks(r))
97             return true;
98       }
99       return false;
100    }
101
102    void SetupButtons(DataRow row, bool recurse)
103    {
104       DataRow parent;
105       CheckListBoxButton button;
106       int indent = checkIndent;
107
108       for(parent = row.parent; parent; parent = parent.parent) indent += 20;
109       button = buttonMaps[(uintptr)row];
110       if(!button) button = CheckListBoxButton { this };
111       button.position = { 2 + indent, 1+(row.index + hasHeader) * rowHeight };
112       button.id = (uintptr)row;
113
114       for(parent = row; parent; parent = parent.parent) if(rowChecks.Find(parent)) break;
115       if(parent)
116       {
117          button.checked = true;
118          button.buttonState = up;
119       }
120       else
121       {
122          button.checked = CheckPartialChecks(row);
123          button.buttonState = button.checked ? down : up;
124       }
125       if(rowDisabled.Find(row))
126          button.disabled = true;
127       button.Create();
128       buttonMaps[(uintptr)row] = button;
129       if(recurse && !row.collapsed)
130       {
131          DataRow r;
132          for(r = row.firstRow; r; r = r.next)
133             SetupButtons(r, recurse);
134       }
135    }
136
137    void UpdateButtons()
138    {
139       DataRow row;
140       for(row = firstRow; row; row = row.next)
141          SetupButtons(row, true);
142    }
143
144    bool OnCreate()
145    {
146       if(ListBox::OnCreate())
147       {
148          DataRow row;
149
150          buttonMaps.RemoveAll();
151
152          for(row = firstRow; row; row = row.next)
153             SetupButtons(row, true);
154          return true;
155       }
156       return false;
157    }
158
159    void ToggleCheck(DataRow row)
160    {
161       CheckListBoxButton checkBox = buttonMaps[(uintptr)row];
162       if(checkBox && !checkBox.disabled)
163       {
164          bool checked = false;
165          DataRow r;
166          for(r = row; r; r = r.parent)
167             if(rowChecks.Find(r))
168             {
169                checked = true;
170                break;
171             }
172          SetCheck(row, !checked);
173       }
174    }
175
176    void UncheckBoxes(DataRow row)
177    {
178       if(!row.parent || !row.parent.collapsed)
179       {
180          CheckListBoxButton button = buttonMaps[(uintptr)row];
181          if(button)
182          {
183             bool wasChecked = button.checked;
184             button.checked = false;
185             button.buttonState = up;
186          }
187       }
188       // if(!row.collapsed)
189       {
190          DataRow r;
191          for(r = row.firstRow; r; r = r.next)
192             UncheckBoxes(r);
193       }
194       NotifyChecked(master, this, row);
195    }
196
197    void UnsetChildren(DataRow row)
198    {
199       DataRow r;
200       CheckListBoxButton button = buttonMaps[(uintptr)row];
201       if(button)
202       {
203          button.checked = true;
204          button.buttonState = up;
205       }
206
207       for(r = row.firstRow; r; r = r.next)
208       {
209          Iterator<DataRow> it { rowChecks };
210
211          if(it.Find(r))
212             it.Remove();
213          UnsetChildren(r);
214          NotifyChecked(master, this, r);
215       }
216    }
217
218    void SetCheck(DataRow row, bool checked)
219    {
220       DataRow parent;
221       bool wasChecked = false;
222
223       for(parent = row; parent; parent = parent.parent)
224       {
225          if(rowChecks.Find(parent)) { wasChecked = true; break; }
226       }
227       if(checked != wasChecked)
228       {
229          modifiedDocument = true;
230          // NotifyChecked(master, this, row);
231          if(checked)
232          {
233             DataRow rr = row;
234             // Check if all siblings are checked, if so go up until we reach a row not fully checked
235             while(rr)
236             {
237                DataRow r;
238                for(r = rr.parent.firstRow; r; r = r.next)
239                {
240                   if(r != rr && !rowChecks.Find(r))
241                      break;
242                }
243                if(r || !rr.parent) break;
244                rr = rr.parent;
245             }
246
247             rowChecks.Add(rr);
248
249             // Take out all children from rowChecks, checking them all
250             UnsetChildren(rr);
251
252             NotifyChecked(master, this, rr);
253
254             for(parent = rr.parent; parent; parent = parent.parent)
255             {
256                CheckListBoxButton button = buttonMaps[(uintptr)parent];
257                if(button)
258                {
259                   button.checked = true;
260                   button.buttonState = down;
261
262                   NotifyChecked(master, this, parent);
263                }
264             }
265          }
266          else
267          {
268             DataRow rr = row;
269
270             parent = rr.parent;
271             while(rr)
272             {
273                Iterator<DataRow> it { rowChecks };
274                if(it.Find(rr))
275                {
276                   it.Remove();
277                   break;
278                }
279                else
280                {
281                   DataRow r;
282                   for(r = rr.parent.firstRow; r; r = r.next)
283                   {
284                      if(r != rr)
285                         rowChecks.Add(r);
286                   }
287                   rr = rr.parent;
288                }
289             }
290
291             UncheckBoxes(row);
292
293             for(; parent; parent = parent.parent)
294             {
295                CheckListBoxButton button = buttonMaps[(uintptr)parent];
296                if(button)
297                {
298                   if(CheckPartialChecks(parent))
299                   {
300                      button.checked = true;
301                      button.buttonState = down;
302                   }
303                   else
304                   {
305                      button.checked = false;
306                      button.buttonState = up;
307                   }
308
309                   NotifyChecked(master, this, parent);
310                }
311             }
312          }
313       }
314    }
315
316    bool NotifyKeyDown(CheckListBox listBox, DataRow row, Key key, unichar ch)
317    {
318       if(key == space)
319       {
320          listBox.ToggleCheck(row);
321          return false;
322       }
323       return true;
324    }
325
326    bool OnKeyHit(Key key, unichar ch)
327    {
328       if(key == space)
329          return false;
330       return ListBox::OnKeyHit(key, ch);
331    }
332
333    bool NotifyDoubleClick(CheckListBox listBox, int x, int y, Modifiers mods)
334    {
335       listBox.OnLeftButtonDown(x, y, mods);
336       return false;
337    }
338
339    bool NotifyReclick(CheckListBox listBox, DataRow row, Modifiers mods)
340    {
341       if(row == listBox.currentRow)
342          listBox.ToggleCheck(row);
343       return true;
344    }
345
346 public:
347    bool IsChecked(DataRow row)
348    {
349       CheckListBoxButton button = buttonMaps[(uintptr)row];
350       DataRow parent;
351       for(parent = row; parent; parent = parent.parent) if(rowChecks.Find(parent)) return true;
352       // For partially checked because of children:
353       if(button && button.checked)
354          return true;
355       return false;
356    }
357
358    virtual void Window::NotifyChecked(CheckListBox listBox, DataRow row);
359
360    void SetDisabled(DataRow row, bool disabled)
361    {
362       CheckListBoxButton checkBox = buttonMaps[(uintptr)row];
363       if(checkBox)
364          checkBox.disabled = disabled;
365
366       if(rowDisabled.Find(row))
367       {
368          if(!disabled)
369             rowDisabled.TakeOut(row);
370       }
371       else
372       {
373          if(disabled)
374             rowDisabled.Add(row);
375       }
376    }
377 };