3 class CheckListBoxButton : Button
5 isCheckbox = true, inactive = true, size = { 12, 12 };
7 bool CheckListBox::NotifyPushed(Button button, int x, int y, Modifiers mods)
9 currentRow = (DataRow)button.id;
10 ToggleCheck(currentRow);
14 bool CheckListBox::NotifyReleased(Button button, int x, int y, Modifiers mods)
19 bool OnMouseOver(int x, int y, Modifiers mods)
25 bool OnMouseLeave(Modifiers mods)
32 class CheckListBox : ListBox
34 Map<uintptr, CheckListBoxButton> buttonMaps { };
35 AVLTree<DataRow> rowChecks { };
36 AVLTree<DataRow> rowDisabled { };
41 fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true,
47 buttonMaps.RemoveAll();
50 bool NotifyCollapse(CheckListBox listBox, DataRow row, bool collapsed)
53 for(r = row.firstRow; r && r != row; )
57 MapIterator<uintptr, Button> it { map = listBox.buttonMaps };
58 if(it.Index((uintptr)r, false))
60 Button checkBox = it.data;
70 listBox.SetupButtons(r, false);
72 if(r.firstRow && !r.collapsed)
75 for(; r != row; r = r.parent)
76 if(r.next) { r = r.next; break; }
78 for(r = row.GetNextRow(); r; r = r.GetNextRow())
80 Button checkBox = listBox.buttonMaps[(uintptr)r];
82 checkBox.position.y = 1 + (r.index + listBox.hasHeader) * listBox.rowHeight;
87 bool CheckPartialChecks(DataRow row)
90 for(r = row.firstRow; r; r = r.next)
92 if(rowChecks.Find(r) || CheckPartialChecks(r))
98 void SetupButtons(DataRow row, bool recurse)
101 CheckListBoxButton button;
102 int indent = checkIndent;
104 for(parent = row.parent; parent; parent = parent.parent) indent += 20;
105 button = buttonMaps[(uintptr)row];
106 if(!button) button = CheckListBoxButton { this };
107 button.position = { 2 + indent, 1+(row.index + hasHeader) * rowHeight };
108 button.id = (uintptr)row;
110 for(parent = row; parent; parent = parent.parent) if(rowChecks.Find(parent)) break;
113 button.checked = true;
114 button.buttonState = up;
118 button.checked = CheckPartialChecks(row);
119 button.buttonState = button.checked ? down : up;
121 if(rowDisabled.Find(row))
122 button.disabled = true;
124 buttonMaps[(uintptr)row] = button;
125 if(recurse && !row.collapsed)
128 for(r = row.firstRow; r; r = r.next)
129 SetupButtons(r, recurse);
136 for(row = firstRow; row; row = row.next)
137 SetupButtons(row, true);
142 if(ListBox::OnCreate())
146 buttonMaps.RemoveAll();
148 for(row = firstRow; row; row = row.next)
149 SetupButtons(row, true);
155 void ToggleCheck(DataRow row)
157 CheckListBoxButton checkBox = buttonMaps[(uintptr)row];
158 if(checkBox && !checkBox.disabled)
160 bool checked = false;
162 for(r = row; r; r = r.parent)
163 if(rowChecks.Find(r))
168 SetCheck(row, !checked);
172 void UncheckBoxes(DataRow row)
174 if(!row.parent || !row.parent.collapsed)
176 CheckListBoxButton button = buttonMaps[(uintptr)row];
179 bool wasChecked = button.checked;
180 button.checked = false;
181 button.buttonState = up;
184 // if(!row.collapsed)
187 for(r = row.firstRow; r; r = r.next)
190 NotifyChecked(master, this, row);
193 void UnsetChildren(DataRow row)
196 CheckListBoxButton button = buttonMaps[(uintptr)row];
199 button.checked = true;
200 button.buttonState = up;
203 for(r = row.firstRow; r; r = r.next)
205 Iterator<DataRow> it { rowChecks };
210 NotifyChecked(master, this, r);
214 void SetCheck(DataRow row, bool checked)
217 bool wasChecked = false;
219 for(parent = row; parent; parent = parent.parent)
221 if(rowChecks.Find(parent)) { wasChecked = true; break; }
223 if(checked != wasChecked)
225 modifiedDocument = true;
226 // NotifyChecked(master, this, row);
230 // Check if all siblings are checked, if so go up until we reach a row not fully checked
234 for(r = rr.parent.firstRow; r; r = r.next)
236 if(r != rr && !rowChecks.Find(r))
239 if(r || !rr.parent) break;
245 // Take out all children from rowChecks, checking them all
248 NotifyChecked(master, this, row);
250 for(parent = rr.parent; parent; parent = parent.parent)
252 CheckListBoxButton button = buttonMaps[(uintptr)parent];
255 button.checked = true;
256 button.buttonState = down;
258 NotifyChecked(master, this, parent);
269 Iterator<DataRow> it { rowChecks };
278 for(r = rr.parent.firstRow; r; r = r.next)
289 for(; parent; parent = parent.parent)
291 CheckListBoxButton button = buttonMaps[(uintptr)parent];
294 if(CheckPartialChecks(parent))
296 button.checked = true;
297 button.buttonState = down;
301 button.checked = false;
302 button.buttonState = up;
305 NotifyChecked(master, this, parent);
312 bool NotifyKeyDown(CheckListBox listBox, DataRow row, Key key, unichar ch)
316 listBox.ToggleCheck(row);
322 bool OnKeyHit(Key key, unichar ch)
326 return ListBox::OnKeyHit(key, ch);
329 bool NotifyDoubleClick(CheckListBox listBox, int x, int y, Modifiers mods)
331 listBox.OnLeftButtonDown(x, y, mods);
335 bool NotifyReclick(CheckListBox listBox, DataRow row, Modifiers mods)
337 if(row == listBox.currentRow)
338 listBox.ToggleCheck(row);
343 bool IsChecked(DataRow row)
345 CheckListBoxButton button = buttonMaps[(uintptr)row];
347 for(parent = row; parent; parent = parent.parent) if(rowChecks.Find(parent)) return true;
348 // For partially checked because of children:
349 if(button && button.checked)
354 virtual void Window::NotifyChecked(CheckListBox listBox, DataRow row);
356 void SetDisabled(DataRow row, bool disabled)
358 CheckListBoxButton checkBox = buttonMaps[(uintptr)row];
360 checkBox.disabled = disabled;
362 if(rowDisabled.Find(row))
365 rowDisabled.TakeOut(row);
370 rowDisabled.Add(row);