ecere:ListBox: null check for allowing setting currentRow to null
[sdk] / ecere / src / gui / controls / ListBox.ec
1 namespace gui::controls;
2
3 import "Window"
4
5 static define branchesColor = Color { 85, 85, 85 };
6 static define headerCollapseForeground = Color { 135, 135, 135 };
7 static define dataBoxBackground = Color { 67, 134, 198 };
8 static define dataBoxForeground = lightYellow;
9
10 #define SNAPDOWN(x, d) \
11       if(Abs(x) % (d)) \
12       { \
13          if(x < 0) x -= ((d) - Abs(x) % (d)); else x -= x % (d); \
14       }
15
16 #include <stdarg.h>
17
18 static class ListBoxCell : struct
19 {
20    ListBoxCell prev, next;
21    bool isSet;
22    // data follows
23    void * data[1];
24 };
25
26 #define RESIZE_BORDER   5
27 #define PLUSY  4
28 #define EXTRA_SPACE 8
29
30 class ListBoxBits
31 {
32    bool header:1, freeSelect:1 /*Exclusive to ELS_MULTISELECT*/, fullRowSelect:1, multiSelect:1, autoScroll:1, alwaysHL : 1, moveRows:1, resizable:1;
33    bool moveFields:1, clearHeader:1, alwaysEdit:1, collapse:1, treeBranch:1, rootCollapse:1, heightSet:1;
34    bool sortable:1, noDragging:1, fillLastField:1, expandOnAdd:1;
35 };
36
37 public class DataDisplayFlags
38 {
39    public bool selected:1, fullRow:1, current:1, active:1, dropBox:1, header:1, firstField:1;
40 };
41
42 enum SelectedFlag { unselected, selected, tempSelected, tempUnselected };
43
44 default:
45 extern int __ecereVMethodID_class_OnEdit;
46 extern int __ecereVMethodID_class_OnDisplay;
47 extern int __ecereVMethodID_class_OnGetString;
48 extern int __ecereVMethodID_class_OnFree;
49 extern int __ecereVMethodID_class_OnCompare;
50 extern int __ecereVMethodID_class_OnCopy;
51 extern int __ecereVMethodID_class_OnSaveEdit;
52
53 private:
54
55 public class DataField 
56 {
57 public:
58    property Class dataType
59    {
60       set { dataType = value; if(value) alignment = value.defaultAlignment; }
61       get { return dataType; }
62    }
63    property bool editable { set { editable = value; } };
64    property Alignment alignment
65    {
66       set
67       {
68          alignment = value;
69          if(headButton) headButton.alignment = value;
70          if(listBox) listBox.Update(null);
71       }
72    };
73    property int width
74    {
75       set
76       {
77          width = Max(value, -EXTRA_SPACE);
78          if(listBox)
79             listBox.AdaptToFieldWidth(this, false);
80       }
81       get { return width; }
82    };
83    property int index { get { return this ? index : 0; } };
84    property int position
85    {
86       set
87       {
88          if(listBox)
89          {
90             int index = 0;
91             DataField field;
92             for(field = listBox.fields.first; field; field = field.next)
93             {
94                if(index == value - 2)
95                   break;
96                index++;
97             }
98             Move(field);
99          }
100       }
101       get
102       {
103          if(listBox)
104          {
105             int index = 0;
106             DataField field;
107             for(field = listBox.fields.first; field; field = field.next)
108             {
109                if(this == field)
110                {
111                   return index + 1;
112                }
113                index++;
114             }
115          }
116          return -1;
117       }
118    };
119    property int sortOrder { get { return this ? sortOrder : 0; } };
120    property char * header
121    {
122       set
123       {
124          header = value;
125          if(headButton)
126             headButton.text = header;
127       }
128    };
129    property void * userData
130    {
131       set
132       {
133          userData = value;
134       } 
135       get
136       {
137          return this ? userData : null;
138       }
139    };
140    property bool freeData
141    {
142       set { freeData = value; } get { return freeData; }      
143    };
144    property DataField prev { get { return prev; } };
145    property DataField next { get { return next; } };
146
147    void Move(DataField after)
148    {
149       if(prev != after)
150       {
151          int position = 0;
152          DataField field;
153
154          listBox.fields.Move(this, after);
155
156          // Fix up positions
157          listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
158          listBox.Update(null);
159       }
160    }
161
162 private:
163    DataField()
164    {
165       // property::dataType = "String";
166       property::dataType = "char *";
167       // width = 80;
168       freeData = true;
169    }
170
171    ~DataField()
172    {
173       Free();
174    }
175
176    void Free()
177    {
178       headButton.Destroy(0);
179       delete headButton;
180       if(listBox)
181       {
182          DataField field;
183          listBox.fields.Remove(this);
184          for(field = listBox.fields.first; field; field = field.next)
185          {
186             if(field.index >= index) 
187                field.index--;
188          }
189          if(listBox.currentField == this)
190             listBox.currentField = null;            
191          listBox.numFields--;
192          listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
193          listBox = null;
194       }
195    }
196
197    DataField prev, next;
198    char * header;
199    Class dataType;
200    int width;
201    uint index;
202    int x;
203    Button headButton;
204    int sortOrder;
205    int alignment;
206    bool editable;
207    ListBox listBox;
208    bool defaultField;
209    void * userData;
210    bool freeData;
211 };
212
213 public class DataRow
214 {
215    class_no_expansion
216 public:
217    property int tag { set { tag = value; } get { return tag; } };
218    property DataRow previous { get { return prev; } };
219    property DataRow next { get { return next; } };
220    property int index { get { return (this && (!parent || parent.IsExpanded())) ? index : -1; } };
221    property char * string
222    {
223       set { SetData(listBox.fields.first, value); }
224       get { return GetData(listBox.fields.first); }
225    };
226    property bool isHeader { set { header = value; } get { return this ? header : false; } };
227    property BitmapResource icon { set { icon = value; } get { return icon; } };
228    property bool collapsed
229    {
230       set
231       {
232          if(collapsed != value)
233          {
234             collapsed = value;
235             if(parent.IsExpanded())
236             {
237                DataRow search;
238                int index;
239
240                if(value)
241                {
242                   for(search = subRows.first; search; search = search.next)
243                      search.selectedFlag = 0;
244
245                   if(listBox.clickedRow && !listBox.clickedRow.parent.IsExpanded())
246                   {
247                      listBox.clickedRow = GetNextRow();
248                      if(!listBox.clickedRow)
249                         listBox.clickedRow = this;
250                   }
251                   if(listBox.currentRow && !listBox.currentRow.parent.IsExpanded()) 
252                   {
253                      listBox.SetCurrentRow(this, true);
254                   }
255                   if(listBox.firstRowShown && !listBox.firstRowShown.parent.IsExpanded()) 
256                   {
257                      listBox.firstRowShown = GetPrevRow();
258                      if(!listBox.firstRowShown)
259                         listBox.firstRowShown = this;
260                   }
261                }
262
263                // TODO: FIX row indices
264                index = this.index+1;
265                for(search = GetNextRow(); search; search = search.GetNextRow())
266                   search.index = index++;
267                listBox.rowCount = index;
268
269                listBox.HideEditBox(false, false, true);
270
271                listBox.SetScrollArea(
272                   listBox.width,
273                   (listBox.rowCount * listBox.rowHeight) + 
274                   ((listBox.style.header) ? listBox.rowHeight : 0) -
275                   ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
276                listBox.Update(null);
277                listBox.NotifyCollapse(listBox.master, listBox, this, value);
278             }
279          }
280       }
281       get { return this ? collapsed : false; }
282    };
283    property bool selected
284    {
285       set
286       {
287          if(this)
288          {
289             selectedFlag = value ? selected : unselected;
290             listBox.Update(null);
291          }
292       }
293       get { return selectedFlag == selected || selectedFlag == tempSelected; }
294    };
295    property DataRow parent
296    {
297       set
298       {
299          if(this && (value != this))
300          {
301             DataRow search;
302             DataRow after = value ? value.subRows.last : listBox.rows.last;
303             if(parent.IsExpanded())
304             {
305                for(search = GetNextRow(); search; search = search.GetNextRow())
306                   search.index--;         
307                listBox.rowCount--;
308             }
309
310             listBox.HideEditBox(false, false, true);
311
312             /*
313             if(this == listBox.clickedRow) 
314             {
315                listBox.clickedRow = GetNextRow();
316                if(!listBox.clickedRow)
317                   listBox.clickedRow = GetPrevRow();
318             }
319
320             if(this == listBox.currentRow) 
321             {
322                DataRow newCurrentRow = GetNextRow();
323                if(!listBox.newCurrentRow)
324                   listBox.newCurrentRow = GetPrevRow();
325                listBox.SetCurrentRow(newCurrentRow, true);
326             }
327
328             if(this == listBox.firstRowShown) 
329             {
330                listBox.firstRowShown = GetPrevRow();
331                if(!listBox.firstRowShown)
332                   listBox.firstRowShown = GetNextRow();
333             }
334             */
335
336             (parent ? parent.subRows : listBox.rows).Remove(this);
337
338             if(value)
339                value.subRows.Insert(after, this);
340             else
341                listBox.rows.Insert(after, this);
342
343             parent = value;
344
345             if(value && listBox.style.expandOnAdd)
346                value.collapsed = false;
347
348             if(value.IsExpanded(this))
349             {
350                DataRow search;
351
352                if(after && after.subRows.first && !after.collapsed)
353                {
354                   for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
355                      search = search.subRows.last;
356                   index = search.index + 1;
357                }
358                else
359                   index = after ? (after.index + 1) : (index + 1);
360
361                listBox.rowCount++;
362
363                for(search = GetNextRow(); search; search = search.GetNextRow())
364                   search.index++;            
365
366                listBox.SetScrollArea(
367                   listBox.width,
368                   (listBox.rowCount * listBox.rowHeight) + 
369                   ((listBox.style.header) ? listBox.rowHeight : 0) -
370                   ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
371                if(listBox.style.autoScroll)
372                   listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
373             }
374             // TESTING THIS HERE...
375             if(listBox.created)
376                listBox.Sort(listBox.sortField, listBox.sortField.sortOrder);
377
378             {
379                int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
380                int height = listBox.clientSize.h + 1 - headerSize;
381                if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
382                   listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
383                else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
384                {
385                   int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
386                   listBox.SetScrollPosition(listBox.scroll.x, line);
387                }
388                else
389                   listBox.OnVScroll(0, listBox.scroll.y, 0);
390             }
391             listBox.Update(null);
392          }
393       }
394       get
395       {
396          return parent;
397       }
398    };
399    property DataRow lastRow { get { return this ? subRows.last : null; } };
400    property DataRow firstRow { get { return this ? subRows.first : null; } };
401
402    void Edit(DataField field)
403    {
404       if(this)
405       {
406          if(listBox)
407          {
408             if(!field || !field.editable)
409             {
410                for(field = listBox.fields.first; field; field = field.next)
411                   if(field.editable) break;
412             }
413             if(field && field.editable)
414             {
415                listBox.SetCurrentRow(this, true);
416                listBox.PopupEditBox(field, false);
417             }
418          }
419       }
420    }
421
422    void Move(DataRow after)
423    {
424       if(this)
425       {
426          incref this;
427          if(listBox && prev != after)
428          {
429             DataRow search;
430             int afterIndex = -1;
431             int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
432             int height = listBox.clientSize.h + 1 - headerSize;
433
434             if(!after || after.index < index)
435             {
436                if(after == listBox.firstRowShown.prev) 
437                   listBox.firstRowShown = this;
438
439                // All rows between AFTER (exclusive) and ROW (exclusive) are incremented by one
440                // ROW is equal to AFTER's index + 1
441
442                // TODO: Fix indices
443                for(search = after ? after.next : listBox.rows.first; search && search != this; search = search.GetNextRow())
444                   search.index++;
445
446                if(after && after.subRows.first && !after.collapsed)
447                {
448                   for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
449                      search = search.subRows.last;
450                   index = search.index + 1;
451                }
452                else
453                   index = after ? (after.index + 1) : 0;
454             }
455             else
456             {
457                if(this == listBox.firstRowShown)
458                {
459                   listBox.firstRowShown = GetNextRow();
460                }
461
462                // All rows between ROW (exclusive) and AFTER (inclusive) are decremented by one
463                // ROW is equal to AFTER's index
464
465                // TODO: Fix indices
466                for(search = GetNextRow(); search; search = search.GetNextRow())
467                {
468                   search.index--;
469                   if(search == after) break;
470                }
471                index = after ? (after.index + 1) : 0;
472             }
473             listBox.rows.Move(this, after);
474
475             listBox.HideEditBox(true, false, true);
476             if(listBox)
477             {
478                if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
479                   listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
480                else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
481                {
482                   int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
483                   //SNAPUP(line, listBox.rowHeight);
484                   listBox.SetScrollPosition(listBox.scroll.x, line);
485                }
486                else
487                   listBox.OnVScroll(0, listBox.scroll.y, 0);
488
489                listBox.modifiedDocument = true;
490
491                listBox.Update(null);
492             }
493          }
494          delete this;
495       }
496    }
497
498    any_object GetData(DataField field)
499    {
500       if(this)
501       {
502          ListBoxCell cell = listBox.GetCell(&this, &field);
503          if(cell && cell.isSet && cell.data)
504          {
505             if((field.dataType.type == normalClass || field.dataType.type == noHeadClass))
506                return cell.data[0];
507             else
508                return (void *)cell.data;   // Cast for MemoryGuard
509          }
510       }
511       return null;
512    }
513
514    void * SetData(DataField field, any_object newData)
515    {
516       if(this)
517       {
518          ListBoxCell cell = listBox.GetCell(&this, &field);
519          if(cell)
520          {
521             Class dataType = field.dataType;
522
523             if(dataType)
524             {
525                if(dataType.type == normalClass || dataType.type == noHeadClass)
526                {
527                   if(cell.data[0] && field.freeData)
528                      dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data[0]);
529
530                   if(eClass_IsDerived(dataType, class(char *)) && field.freeData)
531                      dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, cell.data, newData);
532                   else
533                      cell.data[0] = (void *)newData;
534                }
535                else
536                {
537                   // Free old data first
538                   dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data);
539                   dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, cell.data, newData);
540                }
541             }
542             cell.isSet = true;
543             listBox.modifiedDocument = true;
544             listBox.Update(null);
545             if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
546                return (void *)cell.data;     // Cast for MemoryGuard
547             else
548                return &cell.data;
549          }
550       }
551       return null;
552    }
553
554    void UnsetData(DataField field)
555    {
556       if(this)
557       {
558          ListBoxCell cell = listBox.GetCell(&this, &field);
559          if(cell)
560          {
561             Class dataType = field.dataType;
562
563             if(dataType)
564             {
565                if(dataType.type == normalClass || dataType.type == noHeadClass)
566                {
567                   if(cell.data[0] && field.freeData)
568                      dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data[0]);
569                   cell.data[0] = null;
570                }
571                else
572                {
573                   // Free old data first
574                   dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data);
575                }
576             }
577             cell.isSet = false;
578             listBox.Update(null);
579          }
580       }
581    }
582
583    DataRow FindRow(int tag)
584    {
585       DataRow row = null;
586       for(row = subRows.first; row; row = row.next)
587       {
588          if(!row.noneRow && row.tag == tag)
589             break;
590       }
591       return row;
592    }
593
594    DataRow FindSubRow(int tag)
595    {
596       DataRow row = null;
597       for(row = subRows.first; row; row = row.next)
598       {
599          if(!row.noneRow && row.tag == tag)
600             break;
601          if(row.subRows.first)
602          {
603             DataRow subRow = row.FindSubRow(tag);
604             if(subRow)
605                return subRow;
606          }
607       }
608       return row;
609    }
610
611    DataRow AddRowAfter(DataRow after)
612    {
613       if(this)
614       {
615          DataRow row { };
616          incref row;
617          if(row)
618          {
619             DataField field;
620             int c;
621             subRows.Insert(after, row);
622             row.listBox = listBox;
623             *&row.parent = this;
624
625             row.cells.Clear();
626             for(c = 0; c<listBox.fields.count; c++)
627             {
628                for(field = listBox.fields.first; field; field = field.next)
629                   if((int)field.index == c)
630                      break;
631                if(field)
632                {
633                   int size = (field.dataType && field.dataType.typeSize) ? 
634                      (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
635                   ListBoxCell cell = (ListBoxCell)new0 byte[size];
636                   row.cells.Add(cell);
637                   FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
638                   cell.isSet = false;
639                }
640             }
641
642             if(IsExpanded(this))
643             {
644                DataRow search;
645
646                if(after && after.subRows.first && !after.collapsed)
647                {
648                   for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
649                      search = search.subRows.last;
650                   row.index = search.index + 1;
651                }
652                else
653                   row.index = after ? (after.index + 1) : (index + 1);
654
655                listBox.rowCount++;
656
657                // TODO: Fix indices
658                for(search = row.GetNextRow(); search; search = search.GetNextRow())
659                   search.index++;            
660
661                listBox.SetScrollArea(
662                   listBox.width,
663                   (listBox.rowCount * listBox.rowHeight) + 
664                   ((listBox.style.header) ? listBox.rowHeight : 0) -
665                   ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
666                if(listBox.style.autoScroll)
667                   listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
668             }
669
670             listBox.modifiedDocument = true;
671          }
672          return row;
673       }
674       return null;
675    }
676
677    DataRow AddRow()
678    {
679       if(this)
680          return AddRowAfter(subRows.last);
681       return null;
682    }
683
684    DataRow AddStringf(char * format, ...)
685    {
686       if(this)
687       {
688          DataRow row;
689          char string[MAX_F_STRING];
690          va_list args;
691
692          va_start(args, format);
693          vsprintf(string, format, args);
694          va_end(args);
695
696          row = AddRow();
697          row.SetData(null, string);
698          return row;
699       }
700       return null;
701    }
702
703    DataRow AddString(char * string)
704    {
705       if(this)
706       {
707          DataRow row;
708          row = AddRow();
709          row.SetData(listBox.fields.first, string);
710          return row;
711       }
712       return null;
713    }
714
715
716 private:
717    DataRow()
718    {
719       subRows.offset = (uint)&((DataRow)0).prev;
720    }
721
722    ~DataRow()
723    {
724       ListBoxCell cell, next;
725       uint cellIndex = 0;
726       DataRow subRow;
727
728       // Delete SubRows
729       while((subRow = subRows.first))
730       {
731          subRows.Remove(subRow);
732          delete subRow;
733       }
734
735       for(cell = cells.first; cell; cell = next, cellIndex++)
736       {
737          if(listBox)
738          {
739             DataField field;
740             for(field = listBox.fields.first; field && field.index != cellIndex; field = field.next);
741             if(field.dataType)
742             {
743                // TOCHECK: Is this check good? Will need incref/decref sometime?
744                if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
745                {
746                   if(cell.data[0] && field.freeData)
747                      field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data[0]);
748                }
749                else
750                   field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data);
751             }
752          }
753          next = cell.next;
754          delete cell;
755       }
756    }
757
758    bool IsExpanded()
759    {
760       return !this || (!collapsed && (!parent || parent.IsExpanded()));
761    }
762
763    int Compare(DataRow b, DataField sortField)
764    {
765       int result = 0;
766       ListBoxCell cell1, cell2;
767       uint index;
768       for(index = 0, cell1 = cells.first, cell2 = b.cells.first; 
769           index != sortField.index; 
770           index++, cell1 = cell1.next, cell2 = cell2.next);
771    /*
772       if(!cell1.isSet && !cell2.isSet)
773          result = 0;
774       else if(!cell1.isSet)
775          result = -1;
776       else if(!cell2.isSet)
777          result = 1;
778       else */
779       if(noneRow && !b.noneRow) return -1;
780       else if(!noneRow && b.noneRow) return 1;
781       else if(noneRow && b.noneRow) return 0;
782
783       if(sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])
784       {
785          if(sortField.dataType.type == normalClass || sortField.dataType.type == noHeadClass)
786          {
787             result = sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare](sortField.dataType, 
788                (cell1.isSet && cell1.data) ? cell1.data[0] : null, 
789                (cell2.isSet && cell2.data) ? cell2.data[0] : null);
790          }
791          else
792          {
793             result = sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare](sortField.dataType, 
794                cell1.isSet ? cell1.data : null, 
795                cell2.isSet ? cell2.data : null);
796          }
797       }
798       return sortField.sortOrder * result;
799    }
800
801    void _SortSubRows(DataField field, int order)
802    {
803       DataRow search;
804       for(search = subRows.first; search; search = search.next)
805          search._SortSubRows(field, order);
806       subRows.Sort(Compare, field);
807    }
808
809    public void SortSubRows(bool scrollToCurrent)
810    {
811       if(this && listBox && listBox.sortField)
812       {
813          _SortSubRows(listBox.sortField, listBox.sortField.sortOrder);
814
815          // TODO: Recompute row indices
816          {
817             DataRow search;
818             int index = this.index;
819             for(search = this; search; search = search.GetNextRow())
820                search.index = index++;
821          }
822          if(scrollToCurrent)
823          {
824             int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
825             int height = listBox.clientSize.h + 1 - headerSize;
826             if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
827                listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
828             else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
829                listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0);
830             listBox.OnVScroll(0, listBox.scroll.y, 0);
831          }
832       }
833    }
834
835    public DataRow GetPrevRow()
836    {
837       DataRow row;
838       // Find Previous row
839       if(prev)
840       {
841          for(row = prev; row && !row.collapsed && row.subRows.last; row = row.subRows.last);
842       }
843       else
844          row = parent;
845       return row;
846    }
847
848    public DataRow GetNextRow()
849    {
850       DataRow row;
851       // Find Next row
852       if(subRows.first && !collapsed) 
853          row = subRows.first;
854       else 
855       {
856          for(row = this; row; row = row.parent)
857          {
858             if(row.next) { row = row.next; break; }
859          }
860       }
861       return row;
862    }
863
864    DataRow prev, next;
865    OldList cells;
866    int tag;
867    SelectedFlag selectedFlag;
868    ListBox listBox;
869    bool header;
870    OldList subRows;
871    DataRow parent;
872    bool collapsed;
873    BitmapResource icon;
874    int index;
875    bool noneRow;
876 };
877
878 public class ListBox : CommonControl
879 {
880    hasVertScroll = true;
881    // background = white;
882    borderStyle = deep;
883    snapVertScroll = true;
884
885    class_property(icon) = "<:ecere>controls/listBox.png";
886
887 public:
888    // Properties
889    property bool freeSelect { property_category "Behavior" set { style.freeSelect = value; } get { return style.freeSelect; } };
890    property DataRow currentRow { property_category "Private" /*"Behavior"*/ set { SetCurrentRow(value, false); } get { return currentRow; } };
891    property DataField currentField
892    {
893       get { return currentField; }
894       // TODO: Needs definition of what this is, testing
895       set
896       {
897          currentField = value;
898          HideEditBox(true, true, false);
899          if(value && value.editable)
900             PopupEditBox(currentField, false);
901       }
902    };
903
904    property int rowHeight
905    {
906       property_category "Appearance" 
907       isset { return style.heightSet; }
908       set
909       {
910          if(value)
911          {
912             style.heightSet = true;
913             rowHeight = value;
914             SetScrollLineStep(8, value);
915          }
916          else
917          {
918             style.heightSet = false;
919             OnLoadGraphics();
920             OnApplyGraphics();
921          }
922       }
923       get { return rowHeight; }
924    };
925    property Seconds typingTimeout
926    {
927       property_category "Behavior" 
928       set
929       {
930          typedString[0] = '\0';
931          typingTimer.delay = value;
932          typingTimeOut = value;
933       }
934       get { return typingTimeOut; }
935    };
936    property bool moveRows { property_category "Behavior" set { style.moveRows = value; } get { return style.moveRows; } };
937    property bool moveFields { property_category "Behavior" set { style.moveFields = value; } get { return style.moveFields; } };
938    property bool resizable { property_category "Behavior" set { style.resizable = value; } get { return style.resizable; } };
939    property bool autoScroll { property_category "Behavior" set { style.autoScroll = value; } get { return style.autoScroll; } };
940    property bool alwaysHighLight { property_category "Appearance" set { style.alwaysHL = value; } get { return style.alwaysHL; } };
941    property bool hasClearHeader { property_category "Appearance" set { style.clearHeader = value; if(value) property::hasHeader = true; } get { return style.clearHeader; } };
942    property bool hasHeader
943    {
944       property_category "Appearance" 
945       set
946       {
947          if(value && !style.header)
948          {
949             endBevel = Button
950             {
951                this;
952                stayOnTop = true;
953                bevel = !guiApp.textMode && !style.clearHeader;
954                dontScrollVert = true;
955                inactive = true;
956                size.h = rowHeight;
957                NotifyPushed = HeaderPushed;
958                NotifyClicked = HeaderClicked;
959                NotifyReleased = HeaderReleased;
960                NotifyMouseMove = HeaderMouseMove;
961             };
962             incref endBevel;
963             endBevel.Create();
964             endBevel.visible = false;
965          }
966          style.header = value;
967       }
968       get { return style.header; }
969    };   
970    property bool multiSelect { property_category "Behavior" set { style.multiSelect = value; } get { return style.multiSelect; } };
971    property bool alwaysEdit { property_category "Behavior" set { style.alwaysEdit = value; } get { return style.alwaysEdit; } };
972    property bool fullRowSelect { property_category "Appearance" set { style.fullRowSelect = value; } get { return style.fullRowSelect; } };
973    property bool collapseControl { property_category "Appearance" set { style.collapse = value; } get { return style.collapse; } };
974    property bool treeBranches { property_category "Appearance" set { style.treeBranch = value; } get { return style.treeBranch; } };
975    property bool rootCollapseButton { property_category "Appearance" set { style.rootCollapse = value; } get { return style.rootCollapse; } };
976    property bool sortable { property_category "Behavior" set { style.sortable = value; } get { return style.sortable; } };
977    property bool noDragging { property_category "Behavior" set { style.noDragging = value; } get { return style.noDragging; } };
978    property bool fillLastField
979    {
980       property_category "Behavior" 
981       set
982       {
983          style.fillLastField = value;
984       }
985       get { return style.fillLastField; }
986    };
987    property int numSelections
988    {
989       get
990       {
991          int numSelections = 0;
992          if(this && style.multiSelect)
993          {
994             DataRow row;
995             for(row = rows.first; row; row = row.GetNextRow())
996                if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
997                   numSelections++;
998          }
999          return numSelections;
1000       }
1001    };
1002    property int currentIndex
1003    {
1004       get { return currentRow ? currentRow.index : -1; }
1005    };
1006    property DataRow lastRow { get { return this ? rows.last : null; } };
1007    property DataRow firstRow { get { return this ? rows.first : null; } };
1008    property int rowCount { get { return rowCount; } };
1009    property DataField firstField { get { return this ? fields.first : null; } };
1010    property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
1011    property Color selectionText  { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
1012    property Color stippleColor { set { stippleColor = value; } get { return stippleColor; } };
1013    property bool expandOnAdd { set { style.expandOnAdd = value; } get { return style.expandOnAdd; } };
1014
1015    // Notifications
1016    virtual bool Window::NotifySelect(ListBox listBox, DataRow row, Modifiers mods);
1017    virtual bool Window::NotifyHighlight(ListBox listBox, DataRow row, Modifiers mods);
1018    virtual bool Window::NotifyReclick(ListBox listBox, DataRow row, Modifiers mods);
1019    virtual bool Window::NotifySort(ListBox listBox, DataField field, Modifiers mods);
1020    virtual bool Window::NotifyChanged(ListBox listBox, DataRow row);
1021    virtual bool Window::NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch);
1022    virtual bool Window::NotifyEdited(ListBox listBox, DataRow row);
1023    virtual bool Window::NotifyEditDone(ListBox listBox, DataRow row);
1024    virtual bool Window::NotifyMovedField(ListBox listBox, DataField field, Modifiers mods);
1025    virtual bool Window::NotifyMove(ListBox listBox, DataRow row, Modifiers mods);
1026    virtual bool Window::NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods);
1027    virtual bool Window::NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods);
1028    virtual bool Window::NotifyResized(ListBox listBox, DataField field, Modifiers mods);
1029    virtual bool Window::NotifyCollapse(ListBox listBox, DataRow row, bool collapsed);
1030    virtual bool Window::NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch);
1031    virtual bool Window::NotifyModified(ListBox listBox, DataRow row);   
1032    virtual bool Window::NotifyEditing(ListBox listBox, DataRow row);
1033
1034    // Methods
1035    void AddField(DataField addedField)
1036    {
1037       if(this)
1038       {
1039          DataField field;
1040          if(fields.first && ((DataField)fields.first).defaultField)
1041          {
1042             DataField defaultField = fields.first;
1043             // TODO:
1044             defaultField.Free();
1045             delete defaultField;
1046          }
1047          if(!addedField)
1048          {
1049             addedField = DataField { };
1050          }
1051
1052          incref addedField;
1053          addedField.listBox = this;
1054          fields.Add(addedField);
1055       
1056          addedField.sortOrder = 1;
1057          addedField.index = numFields;
1058          numFields++;
1059          if(style.header)
1060          {
1061             addedField.headButton.Destroy(0);
1062             delete addedField.headButton;
1063             addedField.headButton = Button
1064             {
1065                this;
1066                stayOnTop = true;
1067                inactive = true;
1068                dontScrollVert = true;
1069                id = (uint)addedField;
1070                text = addedField.header;
1071                bevel = (!guiApp.textMode && !style.clearHeader);
1072                ellipsis = true;
1073                alignment = addedField.alignment;
1074                NotifyPushed = HeaderPushed;
1075                NotifyClicked = HeaderClicked;
1076                NotifyReleased = HeaderReleased;
1077                NotifyMouseMove = HeaderMouseMove;
1078             };
1079             incref addedField.headButton;
1080             addedField.headButton.Create();
1081
1082             if(guiApp.textMode)
1083                addedField.headButton.background = Color { 0, 170, 0 };
1084          }
1085          if(rows.first)
1086          {
1087             DataRow row;
1088             field = addedField;
1089             for(row = rows.first; row; )
1090             {
1091                int size = (field.dataType && field.dataType.typeSize) ? 
1092                   (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1093                ListBoxCell cell = (ListBoxCell)new0 byte[size];
1094                row.cells.Add(cell);
1095                FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1096                cell.isSet = false;
1097
1098                if(row.subRows.first) 
1099                   row = row.subRows.first;
1100                else 
1101                {
1102                   for(; row; row = row.parent)
1103                   {
1104                      if(row.next) { row = row.next; break; }
1105                   }
1106                }
1107             }
1108          }
1109          OnResize(clientSize.w, clientSize.h);
1110       }
1111    }
1112
1113    void ClearFields()
1114    {
1115       if(this)
1116       {
1117          DataField field;
1118          while((field = fields.first))
1119          {
1120             //delete field;
1121             field.Free();
1122             delete field;
1123          }
1124          endBevel.visible = false;
1125          sortField = null;
1126       }
1127    }
1128
1129    void RemoveField(DataField field)
1130    {
1131       if(this)
1132       {
1133          if(field)
1134          {
1135             int index = field.index;
1136             DataRow row;
1137
1138             for(row = rows.first; row; )
1139             {
1140                int c;
1141                ListBoxCell cell;
1142
1143                for(cell = row.cells.first, c = 0; c < index && cell; c++, cell = cell.next);
1144                if(cell && index == c)
1145                {
1146                   if(field.dataType)
1147                   {
1148                      // TOCHECK: Is this check good? Will need incref/decref sometime?
1149                      if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
1150                      {
1151                         if(cell.data[0] && field.freeData)
1152                            field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data[0]);
1153                      }
1154                      else
1155                         field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data);
1156                   }
1157
1158                   row.cells.Remove(cell);
1159                   delete cell;
1160                }
1161
1162                if(row.subRows.first) 
1163                   row = row.subRows.first;
1164                else 
1165                {
1166                   for(; row; row = row.parent)
1167                   {
1168                      if(row.next) { row = row.next; break; }
1169                   }
1170                }
1171             }
1172
1173             field.Free();
1174             delete field;
1175          }
1176          if(!fields.count)
1177             endBevel.visible = false;
1178       }
1179    }
1180
1181    DataRow AddRowNone()
1182    {
1183       DataRow row { noneRow = true };
1184       incref row;
1185       if(row)
1186       {
1187          DataRow search;
1188          DataField field;
1189          int c;
1190
1191          row.index = 0;
1192          rows.Insert(null, row);
1193          row.listBox = this;
1194
1195          for(search = row.GetNextRow(); search; search = search.GetNextRow())
1196             search.index++;         
1197
1198          this.rowCount++;
1199          row.cells.Clear();
1200          
1201          firstRowShown = row;
1202
1203          SetScrollArea(
1204             width,
1205             (rowCount * rowHeight) + 
1206             ((style.header) ? rowHeight : 0) -
1207             ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1208          if(style.autoScroll)
1209             SetScrollPosition(0, MAXINT - rowHeight);
1210          modifiedDocument = true;
1211          return row;
1212       }
1213       return null;
1214    }
1215
1216    DataRow AddRow()
1217    {
1218       if(this)
1219       {
1220          if(fields.first)
1221          {
1222             DataRow row { };
1223             incref row;
1224             if(row)
1225             {
1226                DataField field;
1227                int c;
1228
1229                // Find very last row
1230                {
1231                   DataRow lastRow;
1232                   for(lastRow = rows.last; lastRow && !lastRow.collapsed && lastRow.subRows.last; lastRow)
1233                      lastRow = lastRow.subRows.last;
1234                   row.index = lastRow ? (lastRow.index + 1) : 0;
1235                }
1236
1237                rows.Add(row);
1238                row.listBox = this;
1239                rowCount++;
1240
1241                row.cells.Clear();
1242                for(c = 0; c<fields.count; c++)
1243                {
1244                   for(field = fields.first; field; field = field.next)
1245                      if((int)field.index == c)
1246                         break;
1247                   if(field)
1248                   {
1249                      int size = (field.dataType && field.dataType.typeSize) ? 
1250                         (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1251                      ListBoxCell cell = (ListBoxCell) new0 byte[size];
1252                      row.cells.Add(cell);
1253                      FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1254                      cell.isSet = false;
1255                   }
1256                }
1257
1258                if(!firstRowShown)
1259                {
1260                   firstRowShown = row;
1261                }
1262
1263                if(rowHeight)
1264                   SetScrollArea(
1265                      width,
1266                      (rowCount * rowHeight) + 
1267                      ((style.header) ? rowHeight : 0) -
1268                      ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1269                if(style.autoScroll)
1270                   SetScrollPosition(0, MAXINT - rowHeight);
1271                modifiedDocument = true;
1272             }
1273             return row;
1274          }
1275       }
1276       return null;
1277    }
1278
1279    DataRow AddRowAfter(DataRow after)
1280    {
1281       if(fields.first)
1282       {
1283          DataRow row { };
1284          incref row;
1285          if(row)
1286          {
1287             DataRow search;
1288             DataField field;
1289             int c;
1290
1291             if(after && after.subRows.first && !after.collapsed)
1292             {
1293                for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
1294                   search = search.subRows.last;
1295                row.index = search.index + 1;
1296             }
1297             else
1298                row.index = after ? (after.index + 1) : 0;
1299             rows.Insert(after, row);
1300             row.listBox = this;
1301
1302             // TODO: FIX row indices
1303             for(search = row.GetNextRow(); search; search = search.GetNextRow())
1304                search.index++;         
1305
1306             this.rowCount++;
1307             row.cells.Clear();
1308             for(c = 0; c<fields.count; c++)
1309             {
1310                for(field = fields.first; field; field = field.next)
1311                   if((int)field.index == c)
1312                      break;
1313                if(field)
1314                {
1315                   int size = (field.dataType && field.dataType.typeSize) ? 
1316                      (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1317                   ListBoxCell cell = (ListBoxCell) new0 byte[size];
1318                   row.cells.Add(cell);
1319                   FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1320                   cell.isSet = false;
1321                }
1322             }
1323             if(!firstRowShown || !after)
1324             {
1325                firstRowShown = row;
1326             }
1327
1328             SetScrollArea(
1329                width,
1330                (rowCount * rowHeight) + 
1331                ((style.header) ? rowHeight : 0) -
1332                ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1333             if(style.autoScroll)
1334                SetScrollPosition(0, MAXINT - rowHeight);
1335             modifiedDocument = true;
1336             return row;
1337          }
1338       }
1339       return null;
1340    }
1341
1342    DataRow AddStringf(char * format, ...)
1343    {
1344       if(this)
1345       {
1346          DataRow row;
1347
1348          char string[MAX_F_STRING];
1349          va_list args;
1350
1351          va_start(args, format);
1352          vsprintf(string, format ? format : "", args);
1353          va_end(args);
1354
1355          row = AddRow();
1356          row.SetData(fields.first, string);
1357          return row;
1358       }
1359       return null;
1360    }
1361
1362    DataRow AddString(char * string)
1363    {
1364       if(this)
1365       {
1366          DataRow row;
1367          row = AddRow();
1368          row.SetData(fields.first, string);
1369          return row;
1370       }
1371       return null;
1372    }
1373
1374    void SelectRow(DataRow row)
1375    {
1376       SetCurrentRow(row, true);
1377    }
1378
1379    void DeleteRow(DataRow row)
1380    {
1381       if(!row) row = currentRow;
1382       if(row)
1383       {
1384          DataRow search;
1385          // Trying to move this here (Messed up deleting watches)
1386          //HideEditBox(false, false, true);
1387          if(row.parent.IsExpanded())
1388          {
1389             // TODO: FIX row indices
1390             for(search = row.GetNextRow(); search; search = search.GetNextRow())
1391                search.index--;         
1392             this.rowCount--;
1393          }
1394
1395          HideEditBox(false, false, true);
1396
1397          if(row == clickedRow) 
1398          {
1399             clickedRow = row.GetNextRow();
1400             if(!clickedRow)
1401                clickedRow = row.GetPrevRow();
1402          }
1403
1404          if(row == currentRow) 
1405          {
1406             DataRow newCurrentRow = row.GetNextRow();
1407             if(!newCurrentRow)
1408                newCurrentRow = row.GetPrevRow();
1409             SetCurrentRow(newCurrentRow, true);
1410          }
1411
1412          if(row == firstRowShown) 
1413          {
1414             firstRowShown = row.GetPrevRow();
1415             if(!firstRowShown)
1416                firstRowShown = row.GetNextRow();
1417          }
1418
1419          (row.parent ? row.parent.subRows: rows).Remove(row);
1420          delete row;
1421
1422          //HideEditBox(false, false, true);
1423
1424          SetScrollArea(
1425             this.width,
1426             (this.rowCount * rowHeight) + 
1427             ((style.header) ? rowHeight : 0) -
1428             ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1429
1430          modifiedDocument = true;
1431
1432          Update(null);
1433       }
1434    }
1435
1436    DataRow FindRow(int tag)
1437    {
1438       if(this)
1439       {
1440          DataRow row = null;
1441          for(row = rows.first; row; row = row.next)
1442          {
1443             if(!row.noneRow && row.tag == tag)
1444                break;
1445          }
1446          return row;
1447       }
1448       return null;
1449    }
1450
1451    DataRow FindString(char * searchedString)
1452    {
1453       DataField field;
1454       bool checkNextField = true;
1455       int len = searchedString ? strlen(searchedString) : 0;
1456
1457       for(field = fields.first; field; field = field.next)
1458       {
1459          if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1460          {
1461             DataRow row;
1462             for(row = rows.first; row; row = row.GetNextRow())
1463             {
1464                if(!row.noneRow)
1465                {
1466                   void * data = row.GetData(field);
1467                   char tempString[1024] = "";
1468                   bool needClass = false;
1469                   char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1470
1471                   if(string && string[0])
1472                      checkNextField = false;
1473                   if(string && string[0] && !strcmp(string, searchedString))
1474                      return row;
1475                }
1476             }
1477          }
1478          if(!checkNextField) break;
1479       }
1480       return null;
1481    }
1482
1483    DataRow FindSubString(char * subString)
1484    {
1485       DataField field;
1486       bool checkNextField = true;
1487       int len = subString ? strlen(subString) : 0;
1488
1489       if(len)
1490       {
1491          for(field = fields.first; field; field = field.next)
1492          {
1493             if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1494             {
1495                DataRow row;
1496                for(row = rows.first; row; row = row.GetNextRow())
1497                {
1498                   if(!row.noneRow)
1499                   {
1500                      void * data = row.GetData(field);
1501                      char tempString[1024] = "";
1502                      bool needClass = false;
1503                      char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1504
1505                      if(string && string[0])
1506                         checkNextField = false;
1507                      if(string && string[0] && !strncmp(string, subString, len))
1508                         return row;
1509                   }
1510                }
1511             }
1512             if(!checkNextField) break;
1513          }
1514       }
1515       return null;
1516    }
1517
1518    DataRow FindSubStringi(char * subString)
1519    {
1520       DataField field;
1521       bool checkNextField = true;
1522       int len = subString ? strlen(subString) : 0;
1523       DataRow result = null;
1524       char * bestResult = null;
1525       int bestLen = 0;
1526
1527       if(len)
1528       {
1529          for(field = fields.first; field; field = field.next)
1530          {
1531             if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1532             {
1533                DataRow row;
1534                for(row = rows.first; row; row = row.GetNextRow())
1535                {
1536                   if(!row.noneRow)
1537                   {
1538                      void * data = row.GetData(field);
1539                      char tempString[1024] = "";
1540                      bool needClass = false;
1541                      char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1542
1543                      if(string && string[0])
1544                         checkNextField = false;
1545                      if(string && string[0])
1546                      {
1547                         int stringLen = strlen(string);
1548
1549                         if(!strnicmp(string, subString, Min(len, stringLen)))
1550                         {
1551                            if(bestLen < Min(len, stringLen))
1552                               bestResult = 0;
1553                            if(!bestResult || strcmpi(string, bestResult) < 0)
1554                            {
1555                               bestLen = Min(len, stringLen);
1556                               bestResult = string;
1557                               result = row;
1558                            }
1559                         }
1560                      }
1561                   }
1562                }
1563             }
1564             if(!checkNextField) break;
1565          }
1566       }
1567       return result;
1568    }
1569
1570    DataRow FindSubStringAfter(DataRow after, char * subString)
1571    {
1572       DataField field;
1573       bool checkNextField = true;
1574       int len = subString ? strlen(subString) : 0;
1575
1576       if(len)
1577       {
1578          for(field = fields.first; field; field = field.next)
1579          {
1580             if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1581             {
1582                DataRow row;
1583                for(row = after.GetNextRow(); row && row != after; row = row.GetNextRow(), (!row) ? (row = rows.first) : null)
1584                {
1585                   if(!row.noneRow)
1586                   {
1587                      void * data = row.GetData(field);
1588                      char tempString[1024] = "";
1589                      bool needClass = false;
1590                      char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1591
1592                      if(string && string[0])
1593                         checkNextField = false;
1594                      if(string && string[0] && !strncmp(string, subString, len))
1595                         return row;
1596                   }
1597                }
1598             }
1599             if(!checkNextField) break;
1600          }
1601       }
1602       return null;
1603    }
1604
1605    DataRow FindSubRow(int tag)
1606    {
1607       if(this)
1608       {
1609          DataRow row = null;
1610       
1611          for(row = rows.first; row; row = row.next)
1612          {
1613             if(!row.noneRow && row.tag == tag)
1614                break;
1615             if(!row.noneRow && row.subRows.first)
1616             {
1617                DataRow subRow = row.FindSubRow(tag);
1618                if(subRow)
1619                   return subRow;
1620             }
1621          }
1622          return row;
1623       }
1624       return null;
1625    }
1626
1627    void Clear()
1628    {
1629       if(this)
1630       {
1631          Window master = this.master;
1632
1633          HideEditBox(false, true, false);
1634          editData.Destroy(0);
1635                
1636          firstRowShown = currentRow = null;
1637          ClearEx();
1638      
1639          if(master)
1640          {
1641             if(style.freeSelect)
1642                NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1643             else
1644                NotifySelect(master, this, currentRow ? currentRow : null, 0);
1645          }
1646
1647          if(style.alwaysEdit && currentRow)
1648             currentRow.Edit(currentField);
1649
1650       
1651          this.rowCount = 0;
1652       
1653          SetScrollArea(
1654                this.width,
1655                (this.rowCount * rowHeight) + 
1656                ((style.header) ? rowHeight : 0) -
1657                ((rowHeight && !((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1658          Update(null);
1659       }
1660    }
1661
1662    void Sort(DataField field, int order)
1663    {
1664       if(this)
1665       {
1666          DataRow search;
1667          int headerSize = ((style.header) ? rowHeight : 0);
1668          int height = clientSize.h + 1 - headerSize;
1669
1670          if(!field) field = fields.first;
1671          sortField = field;
1672          field.sortOrder = order ? order : 1;
1673          rows.Sort(DataRow::Compare, field);
1674
1675          for(search = rows.first; search; search = search.next)
1676             search._SortSubRows(field, order);
1677
1678          // TODO: Recompute row indices
1679          {
1680             int index = 0;
1681             for(search = rows.first; search; search = search.GetNextRow())
1682                search.index = index++;
1683          }
1684
1685          if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1686             SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
1687          else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1688             SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
1689
1690          OnVScroll(0, scroll.y, 0);
1691
1692          // SetScrollPosition(0, scroll.y);
1693          // Update(null);
1694       }
1695    }
1696
1697    void StopEditing(bool save)
1698    {
1699       HideEditBox(save, false, true);
1700    }
1701
1702    void GetMultiSelection(OldList list)
1703    {
1704       list.Clear();
1705       if(this && style.multiSelect)
1706       {
1707          DataRow row;
1708
1709          for(row = rows.first; row; row = row.GetNextRow())
1710          {
1711             if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1712             {
1713                list.Add(OldLink { data = row });
1714             }
1715          }
1716       }
1717    }
1718
1719    // Convenience Current Row Methods
1720    void * SetData(DataField field, any_object data)
1721    {
1722       return currentRow.SetData(field, data);
1723    }
1724
1725    any_object GetData(DataField field)
1726    {
1727       return (void *)currentRow.GetData(field);
1728    }
1729
1730    int GetTag()
1731    {
1732       return currentRow.tag;
1733    }
1734
1735 private:
1736    ListBox()
1737    {
1738       DataField defaultField { };
1739       rows.offset = (uint)&((DataRow)0).prev;
1740       fields.offset = (uint)&((DataField)0).prev;
1741       style.fullRowSelect = true;
1742       style.fillLastField = true;
1743       style.expandOnAdd = true;
1744       typingTimeOut = 0.5;
1745       rowHeight = 16;   // Stuff depending on creation and default property checking
1746       maxShown = 10;
1747
1748       defaultField.defaultField = true;
1749
1750       AddField(defaultField);
1751
1752       typedString = new char[1];
1753       typedString[0] = '\0';
1754       dropIndex = -1;
1755       return true;
1756    }
1757
1758    ~ListBox()
1759    {
1760       DataField field;
1761
1762       delete editData;
1763       delete typedString;
1764       delete endBevel;
1765
1766       ClearEx();
1767
1768       while((field = fields.first))
1769       {
1770          // fields.Remove(field);
1771          field.Free();
1772          delete field;
1773       }
1774    }
1775
1776    void ClearEx()
1777    {
1778       DataRow row;
1779       clickedRow = null;
1780       while((row = rows.first))
1781       {
1782          rows.Remove(row);
1783          delete row;
1784       }
1785    }
1786
1787    ListBoxCell GetCell(DataRow * row, DataField * field)
1788    {
1789       ListBoxCell cell = null;
1790       if(!*row) *row = currentRow;
1791       if(*row)
1792       {
1793          if(!*field) *field = this ? currentField : null;
1794          if(!*field && this) 
1795          {
1796             for(*field = fields.first; (*field).index != 0; *field = (*field).next);
1797          }
1798          if(*field)
1799          {
1800             uint index;
1801             if(field->listBox == this)
1802             {
1803                for(index = 0, cell = (*row).cells.first; cell && index != (*field).index; index++, cell = cell.next);
1804             }
1805          }
1806       }
1807       return cell;
1808    }
1809
1810    void HideEditBox(bool save, bool alwaysStopEdit, bool repositionOnly)
1811    {
1812       if(editData && editData.visible)
1813       {
1814          Class dataType = currentField.dataType;
1815          if(save) 
1816             editData.SaveData();
1817          
1818          editData.visible = false;
1819          NotifyEditDone(master, this, currentRow);
1820
1821          // ENSURE DATA BOX IS NOT VISIBLE
1822          editData.visible = false;
1823
1824          if(style.alwaysEdit && !alwaysStopEdit)
1825          {
1826             /*
1827             int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1828             int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1829             int x = currentField.x;
1830             int width = (!currentField.next && style.fillLastField && (!hasHorzScroll || clientSize.w - currentField.x > currentField.width + EXTRA_SPACE)) ? 
1831                   clientSize.w - currentField.x : (currentField.width + EXTRA_SPACE);
1832
1833             if(!style.alwaysEdit)
1834             {
1835                editData.position = { x, y };
1836                editData.size = { width, height };
1837             }
1838             else
1839             {
1840                editData.position = { x, y - editData.clientStart.y };
1841                editData.size = { width, height + editData.clientStart.y * 2 };
1842             }
1843             editData.visible = true;
1844             if(style.alwaysEdit)
1845                editData.Deactivate();
1846             */
1847             PopupEditBox(currentField, repositionOnly);
1848          }
1849          else
1850             printf("");
1851             
1852          /*else
1853             currentField = null;*/
1854       }
1855    }
1856
1857    void SetCurrentRow(DataRow row, bool notify)
1858    {
1859       if(currentRow != row || (currentRow && currentRow.selectedFlag == unselected))
1860       {
1861          int headerSize = ((style.header) ? rowHeight : 0);
1862          int height = clientSize.h + 1 - headerSize;
1863
1864          // true: destroy edit box
1865          HideEditBox(true, true, false);
1866
1867          if(!(style.multiSelect) && currentRow)
1868             currentRow.selectedFlag = unselected;
1869
1870          currentRow = row;
1871
1872          if(style.multiSelect)
1873          {
1874             DataRow selRow;
1875
1876             for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
1877                selRow.selectedFlag = unselected;
1878             if(currentRow)
1879                currentRow.selectedFlag = selected;
1880
1881             clickedRow = row;
1882          }
1883          else if(currentRow)
1884             currentRow.selectedFlag = selected;
1885
1886          if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1887             SetScrollPosition(scroll.x,
1888                currentRow.index * rowHeight - height + rowHeight);
1889          else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1890          {
1891             int line = currentRow ? currentRow.index * rowHeight : 0;
1892             //SNAPUP(line, rowHeight);
1893             SetScrollPosition(scroll.x, line);
1894          }
1895
1896          if(notify)
1897          {
1898             Window master = this.master;
1899             if(master)
1900             {
1901                if(style.freeSelect && visible)
1902                   NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1903                else
1904                   NotifySelect(master, this, currentRow ? currentRow : null, 0);
1905                if(style.alwaysEdit && currentRow)
1906                   currentRow.Edit(currentField);
1907             }
1908          }
1909
1910          Update(null);
1911       }
1912    }
1913
1914    void PopupEditBox(DataField whichField, bool repositionOnly)
1915    {
1916       if((!editData || !editData.visible || currentField != whichField) && currentRow)
1917       {
1918          // true: destroy edit box
1919          HideEditBox(true, true, false);
1920          if(whichField)
1921          {
1922             int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1923             int x = 0;
1924             int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1925             int width;
1926             //void * data = currentRow.GetData(whichField);
1927             DataField field;
1928             DataRow row = null;
1929             ListBoxCell cell;
1930
1931             if(style.collapse && !(style.treeBranch))
1932                x += 15;
1933
1934             for(field = fields.first; field; field = field.next)
1935             {
1936                width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
1937                   clientSize.w - field.x : (field.width + EXTRA_SPACE);
1938                if(field == whichField) break;
1939                x += width;
1940             }
1941
1942             currentField = whichField;
1943             cell = GetCell(&row, &currentField);
1944
1945             if(!editData)
1946             {
1947                editData = DataBox
1948                {
1949                   this;
1950                   background = dataBoxBackground;
1951                   foreground = dataBoxForeground;
1952
1953                   bool NotifyChanged(bool closingDropDown)
1954                   {
1955                      DataRow row = null;
1956                      DataField field = null;
1957                      ListBoxCell cell = GetCell(&row, &field);
1958                      if(cell)
1959                      {
1960                         cell.isSet = true;
1961                         modifiedDocument = true;
1962                         Update(null);
1963                         NotifyChanged(master, this, currentRow);
1964                      }
1965                      return true;
1966                   }
1967
1968                   bool NotifyModified()
1969                   {
1970                      //DataRow row = null;
1971                      //DataField field = null;
1972                      //ListBoxCell cell = GetCell(&row, &field);
1973                      //cell.isSet = true;
1974                      modifiedDocument = true;
1975                      //Update(null);
1976                      NotifyModified(master, this, currentRow);
1977                      return true;
1978                   }
1979
1980                   bool OnKeyDown(Key key, unichar ch)
1981                   {
1982                      bool result = DataBox::OnKeyDown(key, ch);
1983                      if(visible && active)   // Added this check here, because we will not use enter/escape otherwise, and lose DataBox's result
1984                      {
1985                         if((SmartKey)key == enter || (SmartKey)key == escape) 
1986                            return true;
1987                      }
1988                      return result;
1989                   }
1990                };
1991                incref editData;
1992             }
1993             else
1994                editData.Destroy(0);
1995             editData.type = whichField.dataType;
1996             editData.fieldData = whichField.userData;
1997             editData.borderStyle = style.alwaysEdit ? 0 : deep;
1998             editData.data = cell ? cell.data : null;
1999
2000             if(!repositionOnly)
2001                // Might not really need this anymore...
2002                NotifyEditing(master, this, currentRow);
2003
2004             editData.Create();
2005             if(!style.alwaysEdit)
2006             {
2007                editData.position = { x, y - editData.clientStart.y };
2008                editData.size = { width, height + editData.clientStart.y * 2 };
2009             }
2010             else
2011             {
2012                editData.position = { x, y };
2013                editData.size = { width, height };
2014             }
2015             if(!repositionOnly)
2016                editData.Refresh();
2017             editData.visible = true;
2018
2019             if(style.alwaysEdit)
2020                editData.Deactivate();
2021
2022             //   MOVED THIS HIGHER FOR DATALIST EDITOR
2023             if(!repositionOnly)
2024                // Might not really need this anymore...
2025                NotifyEdited(master, this, currentRow);
2026          }
2027       }
2028    }
2029
2030    void OnRedraw(Surface surface)
2031    {
2032       DataRow row;
2033       int y = (style.header) ? rowHeight : 0;
2034       bool isActive = active;
2035       Font font = fontObject;
2036       Font boldFont = this.boldFont.font;
2037
2038       // Draw gray grid
2039       if(style.alwaysEdit && style.fullRowSelect)
2040       {
2041          // Horizontal lines
2042          int y = (style.header) ? rowHeight : 0;
2043          int x = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
2044          int w = clientSize.w;
2045          int h = clientSize.h;
2046          DataRow row;
2047          DataField field;
2048
2049          // Fill out indent column
2050          if(style.collapse && !(style.treeBranch) && rows.first)
2051          {
2052             x += 15;
2053             surface.SetBackground(activeBorder);
2054             surface.Area(-scroll.x, 0, x, clientSize.h);
2055          }
2056
2057          surface.SetForeground(activeBorder);
2058          for(row = firstRowShown; row; row = row.GetNextRow())
2059          {
2060             y += rowHeight;
2061             surface.HLine(x + 1, w-1, y-1);
2062             if(y >= h)
2063                break;
2064          }
2065
2066          // Vertical lines
2067          for(field = fields.first; field; field = field.next)
2068          {
2069             int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2070                clientSize.w - field.x : (field.width + EXTRA_SPACE);
2071             if(field.prev && y > 0)
2072                surface.VLine(0, y-1, x);
2073             x += width;
2074          }
2075       }
2076
2077       surface.foreground = this.foreground;
2078       surface.TextOpacity(false);
2079
2080       // Draw the tree branches
2081       if(style.treeBranch)
2082       {
2083          int y = -scroll.y + ((style.header) ? rowHeight : 0);
2084          surface.LineStipple(0x5555);
2085          surface.SetForeground(branchesColor);
2086          for(row = rows.first; row; row = row.GetNextRow() )
2087          {
2088             int x = -scroll.x + EXTRA_SPACE / 2-1;
2089             int rowStart = -scroll.x;
2090             int indent = 0;
2091             DataRow parent;
2092             int plusIndent;
2093
2094             for(parent = row.parent; parent; parent = parent.parent)
2095                if(!parent.header) indent += 20;
2096             if(style.rootCollapse) indent += 20;
2097
2098             plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2099
2100             x += indent;
2101
2102             // Vertical line
2103             if(row.subRows.first)
2104             {
2105                int numRows = 0;
2106                int y1 = y + PLUSY + 4;
2107                int y2;
2108                DataRow child;
2109             
2110                for(child = row.collapsed ? null : row.subRows.first; child && child != row; )
2111                {
2112                   numRows++;
2113                   if(child.subRows.first && !child.collapsed && child != row.subRows.last)
2114                      child = child.subRows.first;
2115                   else if(child.next)
2116                      child = child.next;
2117                   else
2118                   {
2119                      for(; child && child != row; child = child.parent)
2120                      {
2121                         if(child.next)
2122                         {
2123                            child = child.next;
2124                            break;
2125                         }
2126                      }
2127                   }
2128                }
2129                y2 = y + numRows * rowHeight + PLUSY + 4;
2130                surface.VLine(y1, y2, rowStart + plusIndent + 7 + 20);
2131             }
2132             surface.HLine(rowStart + plusIndent + 7, rowStart + indent, y + PLUSY + 4);
2133
2134             y += rowHeight;
2135             if(y >= clientSize.h)
2136                break;
2137          }
2138          // Root Vertical Lines
2139          if(style.rootCollapse && rows.first)
2140          {
2141             int numRows = 0;
2142             int y1, y2;
2143             DataRow child;
2144             y = -scroll.y + ((style.header) ? rowHeight : 0);
2145             y1 = y + PLUSY + 4;
2146             for(child = rows.first; child && child != rows.last; )
2147             {
2148                numRows++;
2149                if(child.subRows.first && !child.collapsed && child != rows.last)
2150                   child = child.subRows.first;
2151                else if(child.next)
2152                   child = child.next;
2153                else
2154                {
2155                   for(; child; child = child.parent)
2156                   {
2157                      if(child.next)
2158                      {
2159                         child = child.next;
2160                         break;
2161                      }
2162                   }
2163                }
2164             }
2165             y2 = y + numRows * rowHeight + PLUSY + 4;
2166             surface.VLine(y1, y2, -scroll.x + 11);
2167          }
2168          surface.LineStipple(0);
2169       }
2170
2171       for(row = firstRowShown; row; row = row.GetNextRow() )
2172       {
2173          int x = -scroll.x + EXTRA_SPACE / 2-1;
2174          DataField field;
2175          ListBoxCell cell;
2176          Color foreground = this.foreground /*black*/, background = this.background /*white*/;
2177          DataDisplayFlags dataDisplayFlags = 0;
2178          int rowStart = -scroll.x;
2179          int indent = 0;
2180          DataRow parent;
2181          Bitmap icon = row.icon ? row.icon.bitmap : null;
2182          int collapseRowStart;
2183
2184          for(parent = row.parent; parent; parent = parent.parent)
2185          {
2186             if(!parent.header)
2187             {
2188                if(style.treeBranch)
2189                   indent += 20;
2190                else
2191                   indent += 15;
2192             }
2193          }
2194          if(style.rootCollapse) indent += 20;
2195          x += indent;
2196
2197          dataDisplayFlags.fullRow = style.fullRowSelect;
2198          dataDisplayFlags.active = isActive;
2199          dataDisplayFlags.header = row.header;
2200
2201          surface.Clip(null);
2202          if(style.collapse)
2203          {
2204             collapseRowStart = rowStart;
2205
2206             if(!(style.treeBranch))
2207             {
2208                x += 15;
2209                rowStart += 15;
2210             }
2211          }
2212
2213          if(style.multiSelect)
2214          {
2215             dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2216             dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2217          }
2218          else
2219          {
2220             dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2221             dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2222             /*
2223             if(row == currentRow)
2224             {
2225                dataDisplayFlags.current = true;
2226                dataDisplayFlags.selectedFlag = true;
2227             }
2228             else if(!currentRow && row == firstRowShown)
2229             {
2230                dataDisplayFlags.current = true;
2231             }*/
2232          }
2233
2234          surface.TextOpacity(true);
2235
2236          background = this.background;
2237          foreground = this.foreground;
2238
2239          // Draw the current row background
2240          if(row.header)
2241          {
2242             background = activeBorder;
2243             surface.SetBackground(activeBorder);
2244             surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - 1);
2245             foreground = branchesColor;
2246          }
2247          else if(dataDisplayFlags.selected)
2248          {
2249             if(dataDisplayFlags.selected && (isActive || style.alwaysHL || (style.alwaysEdit && style.fullRowSelect)))
2250             {
2251                if(!isActive && style.alwaysEdit)
2252                   background = activeBorder;
2253                else
2254                   background = selectionColor ? selectionColor : SELECTION_COLOR;
2255                if(style.fullRowSelect)
2256                {
2257                   int offset = (style.alwaysEdit) ? 2 : 1;
2258                   surface.SetBackground(background);
2259                   surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - offset);
2260                }
2261                if(isActive || !(style.alwaysEdit))
2262                   foreground = selectionText ? selectionText : SELECTION_TEXT;
2263                else
2264                   foreground = branchesColor;
2265             }
2266          }
2267
2268          if(icon)
2269          {
2270             surface.Blit(icon, x + (20 - icon.width) /2,y + 2,0,0, icon.width, icon.height);
2271             x += 20;
2272          }
2273
2274          if(row.noneRow)
2275          {
2276             int width = clientSize.w;
2277             Box clip;
2278             dataDisplayFlags.firstField = true;
2279             clip.left = x - EXTRA_SPACE / 2+1;
2280             clip.top = y;
2281             clip.right = x + width - EXTRA_SPACE/2 - 0;
2282             clip.bottom = y + rowHeight - 1;
2283             surface.Clip(&clip);
2284
2285             surface.TextFont(font);
2286
2287             surface.SetForeground(foreground);
2288             surface.SetBackground(background);
2289
2290             class(String)._vTbl[__ecereVMethodID_class_OnDisplay](class(String), "(none)", surface, x, y - 1 + (rowHeight - fontH)/2, width - EXTRA_SPACE/2, null, Alignment::left, dataDisplayFlags);
2291          }
2292          else
2293          {
2294             // Draw the rows
2295             for(field = fields.first; field; field = field.next)
2296             {
2297                uint index;
2298                int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2299                   clientSize.w - field.x : (field.width + EXTRA_SPACE);
2300
2301                // Box clip = { x, y+1, x + field.width - EXTRA_SPACE - 1, y + rowHeight - 2 };
2302                Box clip;
2303
2304                //width -= EXTRA_SPACE;
2305
2306                if(!field.prev) width -= indent;
2307
2308
2309                dataDisplayFlags.firstField = field.prev ? false : true;
2310
2311                if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2312                {
2313                   background = this.background;
2314                   foreground = this.foreground;
2315                }
2316
2317                if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2318                {
2319                   surface.Clip(null);
2320                   surface.SetBackground(background);
2321                   surface.Area(x-3, y, x+width-1, y + rowHeight-2);
2322                }
2323
2324                clip.left = x - EXTRA_SPACE / 2+1;
2325                clip.top = y;
2326                clip.right = x + width - EXTRA_SPACE/2 - 0;
2327                clip.bottom = y + rowHeight - 1;
2328                surface.Clip(&clip);
2329
2330                for(index = 0, cell = row.cells.first; cell && index != field.index; index++, cell = cell.next);
2331                // Should always be as many cells in the row as fields in the listbox
2332                if(cell && cell.isSet && field.dataType)
2333                {
2334                   if(row.header)
2335                      surface.TextFont(boldFont);
2336                   else
2337                      surface.TextFont(font);
2338
2339                   surface.SetForeground(foreground);
2340                   surface.SetBackground(background);
2341
2342                   if(field.dataType.type == noHeadClass || field.dataType.type == normalClass)
2343                      field.dataType._vTbl[__ecereVMethodID_class_OnDisplay](field.dataType, cell.data[0], surface, x, y - 1 + (rowHeight - fontH)/2, width - EXTRA_SPACE/2, field.userData, field.alignment, dataDisplayFlags);
2344                   else
2345                      field.dataType._vTbl[__ecereVMethodID_class_OnDisplay](field.dataType, cell.data, surface, x, y - 1 + (rowHeight - fontH)/2, width - EXTRA_SPACE/2, field.userData, field.alignment, dataDisplayFlags);
2346                }
2347
2348                if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2349                   background = activeBorder;
2350
2351                if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2352                {
2353                   background = activeBorder;
2354                   foreground = this.background;
2355                }
2356
2357                x += width;// + EXTRA_SPACE;
2358
2359                if(row.header) break;
2360             }
2361          }
2362
2363          if(style.collapse)
2364          {
2365             int plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2366             surface.Clip(null);
2367             if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)))
2368             {
2369                surface.SetForeground(row.header ? headerCollapseForeground : this.foreground);
2370                surface.Rectangle(collapseRowStart + 3 + plusIndent, y + PLUSY, collapseRowStart + 11 + plusIndent, y + PLUSY + 8);
2371
2372                surface.SetBackground(row.header ? (activeBorder) : (this.background)); //white
2373                surface.Area(collapseRowStart + 4 + plusIndent, y + PLUSY + 1, collapseRowStart + 10 + plusIndent, y + PLUSY + 7);
2374
2375                surface.HLine(collapseRowStart + 5 + plusIndent, collapseRowStart + 9 + plusIndent, y+PLUSY+4);
2376                if(row.collapsed)
2377                   surface.VLine(y + PLUSY + 2, y + PLUSY + 6, collapseRowStart + 7 + plusIndent);
2378             }
2379
2380          }
2381
2382          // Draw the current row stipple
2383          if(style.fullRowSelect && !(style.alwaysEdit) && (dataDisplayFlags.current) && isActive)
2384          {
2385             surface.Clip(null);
2386             if(isActive)
2387             {
2388                surface.LineStipple(0x5555);
2389                if(dataDisplayFlags.selected)
2390                   surface.SetForeground(stippleColor);
2391                else
2392                   surface.SetForeground(this.foreground);
2393             }
2394             else
2395                surface.SetForeground(selectionColor ? selectionColor : SELECTION_COLOR);
2396             surface.Rectangle(0, y, clientSize.w-1, (y + rowHeight) - 1);
2397             surface.LineStipple(0);
2398          }
2399
2400          y += rowHeight;
2401          if(y >= clientSize.h)
2402             break;
2403       }
2404       if(firstRowShown) surface.Clip(null);
2405       if(this.dragRow && this.dropIndex != -1)
2406       {
2407          int dropIndex = this.dropIndex;
2408          int y;
2409
2410          if(!style.multiSelect && currentRow.index < this.dropIndex)
2411             dropIndex++;
2412          surface.DrawingChar(223);
2413
2414          y = style.header ? rowHeight : 0;
2415          y += dropIndex * rowHeight - scroll.y;
2416
2417          surface.SetForeground(Color { 85, 85, 255 });
2418          surface.HLine(0, clientSize.w-1, y);
2419          surface.HLine(0, clientSize.w-1, y + 1);
2420       }
2421    }
2422
2423    void OnDrawOverChildren(Surface surface)
2424    {
2425       if(draggingField && this.dropField)
2426       {
2427          int position = this.dropField.x;
2428          if(draggingField.x < position)
2429             position += this.dropField.width + EXTRA_SPACE;
2430
2431          surface.SetForeground(Color { 85, 85, 255 });
2432          surface.VLine(0, rowHeight - 1, position - scroll.x - 2);
2433          surface.VLine(0, rowHeight - 1, position - scroll.x);
2434       }
2435       if(sortField && !style.clearHeader && style.header)
2436       {
2437          DataField field = sortField;
2438          int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2439             clientSize.w - field.x : (field.width + EXTRA_SPACE);
2440          int tw = 0, th = 0;
2441          if(field.header)
2442             surface.TextExtent(field.header, strlen(field.header), &tw, &th);
2443          if(tw < width - EXTRA_SPACE)
2444          {
2445             bool up = field.sortOrder == 1;
2446             int x = 4, y = 4;
2447             Box clip = 
2448             { 
2449                field.x + 2 - scroll.x, 0, 
2450                field.x + width + EXTRA_SPACE - 1 - scroll.x, rowHeight
2451             };
2452             surface.Clip(&clip);
2453             if(field.alignment == left || field.alignment == center)
2454             {
2455                if(field.alignment == center)
2456                   x = field.x + (width + EXTRA_SPACE - tw) / 2 + tw + EXTRA_SPACE + 4;
2457                else
2458                   x = field.x + tw + EXTRA_SPACE + 4;
2459              
2460                x = Min(x, field.x + width - 4);
2461             }
2462             else if(field.alignment == right)
2463             {
2464                x = field.x + width - tw - EXTRA_SPACE - 4;
2465                x = Max(x, field.x + 2);
2466             }
2467             x -= scroll.x;
2468
2469             if(guiApp.textMode)
2470             {
2471                // surface.SetForeground((wmenu.selectedFlag == item) ? white : black);
2472                // surface.WriteText(clientSize.w-8, y+(wmenu.rh - 8)/2, "\020", 1);
2473             }
2474             else
2475             {
2476                if(up)
2477                {
2478                   surface.SetForeground(Color { 128,128,128 } );
2479                   surface.DrawLine(x + 3, y, x, y + 5);
2480                   surface.PutPixel(x + 1, y + 5);
2481                   surface.PutPixel(x + 1, y + 3);
2482                   surface.PutPixel(x + 2, y + 1);
2483             
2484                   surface.SetForeground(white);
2485                   surface.DrawLine(x + 4, y, x + 7, y + 5);
2486                   surface.PutPixel(x + 6, y + 5);
2487                   surface.PutPixel(x + 6, y + 3);
2488                   surface.PutPixel(x + 5, y + 1);
2489
2490                   surface.DrawLine(x, y + 6, x + 7, y + 6);
2491                }
2492                else
2493                {
2494                   surface.SetForeground(Color { 128,128,128 });
2495                   surface.DrawLine(x + 3, y+6, x, y+1);
2496                   surface.PutPixel(x + 1, y+1);
2497                   surface.PutPixel(x + 1, y+3);
2498                   surface.PutPixel(x + 2, y+5);
2499             
2500                   surface.SetForeground(white);
2501                   surface.DrawLine(x + 4, y+6, x + 7, y+1);
2502                   surface.PutPixel(x + 6, y+1);
2503                   surface.PutPixel(x + 6, y+3);
2504                   surface.PutPixel(x + 5, y+5);
2505
2506                   surface.DrawLine(x, y, x + 7, y);
2507                }
2508             }
2509             surface.Clip(null);
2510          }
2511       }
2512
2513    }
2514
2515    void OnResize(int w, int h)
2516    {
2517       DataField field;
2518       bool showEndBevel = false;
2519       int x = 0;
2520       if(style.collapse && !style.treeBranch)
2521          x += 15;
2522       for(field = fields.first; field; field = field.next)
2523       {
2524          int width = field.width + EXTRA_SPACE;
2525          field.x = x;
2526          x += width;
2527       }
2528       width = x;
2529
2530       SetScrollArea(
2531          width,
2532          (rowCount * rowHeight) + 
2533          ((style.header) ? rowHeight : 0) -
2534          ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
2535
2536       for(field = fields.first; field; field = field.next)
2537       {
2538          int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2539             clientSize.w - field.x : (field.width + EXTRA_SPACE);
2540          if(style.header && field.headButton)
2541          {
2542             showEndBevel = true;
2543             if(width > 0)
2544             {
2545                field.headButton.position = { field.x, 0 };
2546                field.headButton.size = { width, rowHeight };
2547                field.headButton.visible = true;
2548             }
2549             else
2550                field.headButton.visible = false;
2551          }
2552       }
2553
2554       if(!style.fillLastField && showEndBevel && endBevel)
2555       {
2556          endBevel.position = { x, 0 };
2557          endBevel.size = { clientSize.w + 2 - x, rowHeight };
2558          endBevel.visible = true;
2559       }
2560       else if(endBevel)
2561          endBevel.visible = false;
2562
2563       if(style.alwaysEdit && editData && editData.visible)
2564       {
2565          HideEditBox(true, false, true);
2566       }
2567    }
2568
2569    void AdaptToFieldWidth(DataField field, bool doScroll)
2570    {
2571       OnResize(clientSize.w, clientSize.h);
2572
2573       // Scroll appropriately
2574       if(doScroll)
2575       {
2576          if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2577                  field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2578          {
2579             SetScrollPosition(field.x + field.width + EXTRA_SPACE - clientSize.w, scroll.y);
2580          }
2581          else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2582                  field.x < scroll.x)
2583             SetScrollPosition(field.x, scroll.y);
2584       }
2585       Update(null);
2586    }
2587
2588    bool HeaderPushed(Button control, int x, int y, Modifiers mods)
2589    {
2590       DataField field = (DataField)control.id;
2591       // false: dont destroy edit box
2592       HideEditBox(true, false, true);
2593       if(style.resizable && ((!field && x < RESIZE_BORDER && fields.last) ||
2594          (field && x < RESIZE_BORDER && field.prev) || 
2595          (field && x >= control.clientSize.w - RESIZE_BORDER)))
2596       {
2597          if(!field)
2598             field = fields.last;
2599          else if(x < RESIZE_BORDER && field.prev)
2600             field = field.prev;
2601
2602          resizingField = field;
2603          this.resizeX = x + control.position.x;
2604          this.startWidth = field.width;
2605          this.oldX = x - scroll.x;
2606          return false;
2607       }
2608       else if(field)
2609       {
2610          draggingField = field;
2611          if(style.moveFields)
2612             field.headButton.stayDown = true;
2613          else if(!style.sortable)
2614             return false;
2615       }
2616       else
2617          return false;
2618       return true;
2619    }
2620
2621    bool HeaderMouseMove(Button control, int x, int y, Modifiers mods)
2622    {
2623       if(resizingField)
2624       {
2625          // Resize left
2626          DataField field = resizingField;
2627
2628          x += control.position.x;
2629
2630          // Tweak to prevent shrinking field if we're actually moving right
2631          if(x - scroll.x > this.oldX && 
2632             this.startWidth + x - this.resizeX < field.width)
2633          {
2634             this.oldX = x - scroll.x;
2635             return true;
2636          }
2637          this.oldX = x - scroll.x;
2638
2639          field.width = this.startWidth + x - this.resizeX;
2640          field.width = Max(field.width, - EXTRA_SPACE);
2641
2642          AdaptToFieldWidth(field, true);
2643       }
2644       else if(draggingField)
2645       {
2646          x += control.position.x;
2647          if(style.moveFields)
2648          {
2649             DataField field = fields.last;
2650             int fieldX = 0;
2651             for(field = fields.first; field; field = field.next)
2652             {
2653                fieldX += ((field.width || style.resizable) ? 
2654                   field.width : clientSize.w) + EXTRA_SPACE;
2655                if(fieldX > x) 
2656                   break;
2657             }
2658             if(draggingField == field)
2659             {
2660                // Reset scroll position
2661                if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2662                        field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2663                {
2664                   SetScrollPosition(
2665                      field.x + field.width + EXTRA_SPACE - clientSize.w, 
2666                      scroll.y);
2667                }
2668                else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2669                        field.x < scroll.x)
2670                   SetScrollPosition(field.x, scroll.y);
2671                field = null;
2672             }
2673             if(this.dropField != field)
2674             {
2675                this.dropField = field;
2676                if(field)
2677                {
2678                   int position = field.x;
2679                   // Moving right
2680                   if(draggingField.x < position)
2681                   {
2682                      position += field.width + EXTRA_SPACE - clientSize.w;
2683                      if(position > scroll.x)
2684                         SetScrollPosition(position, scroll.y);
2685                   }
2686                   // Moving Left
2687                   else
2688                   {
2689                      if(position < scroll.x)
2690                         SetScrollPosition(position, scroll.y);
2691                   }
2692
2693                   this.movingFields = true;
2694                }
2695                Update(null);
2696             }
2697          }
2698       }
2699       else if(style.resizable)
2700       {
2701          DataField field = (DataField)control.id;
2702          if(field)
2703          {
2704             if(x < RESIZE_BORDER && field.prev)
2705                control.cursor = guiApp.GetCursor(sizeWE);
2706             else if(x >= control.clientSize.w - RESIZE_BORDER)
2707                control.cursor = guiApp.GetCursor(sizeWE);
2708             else
2709                control.cursor = null;
2710          }
2711          else
2712          {
2713             if(x < RESIZE_BORDER && fields.last)
2714                control.cursor = guiApp.GetCursor(sizeWE);
2715             else
2716                control.cursor = null;
2717          }
2718       }
2719       return true;
2720    }
2721
2722    bool HeaderReleased(Button control, int x, int y, Modifiers mods)
2723    {
2724       if(resizingField)
2725       {
2726          NotifyResized(master, this, resizingField, mods);
2727          resizingField = null;
2728       }
2729
2730       if(draggingField)
2731       {
2732          bool result = true;
2733          
2734          if(style.moveFields)
2735          {
2736             if(dropField)
2737             {
2738                // Find which field
2739                DataField switchField = fields.last;
2740                DataField field;
2741                int fieldX = 0;
2742
2743                x += draggingField.x;
2744                for(field = fields.first; field; field = field.next)
2745                {
2746                   fieldX += ((field.width || style.resizable) ? 
2747                      field.width : clientSize.w) + EXTRA_SPACE;
2748                   if(fieldX > x) 
2749                   {
2750                      switchField = field;
2751                      break;
2752                   }
2753                }
2754                if(switchField && draggingField != switchField && this.dropField)
2755                {
2756                   for(field = fields.first; field; field = field.next)
2757                   {
2758                      if(field == switchField || field == draggingField)
2759                         break;
2760                   }
2761
2762                   // Switch field first: move before
2763                   if(field == switchField)
2764                      draggingField.Move(switchField.prev);
2765                   // Dragged field first: move after
2766                   else
2767                      draggingField.Move(switchField);
2768
2769                   NotifyMovedField(master, this, draggingField, mods);
2770                }
2771                draggingField.headButton.stayDown = false;
2772             }
2773             if(movingFields)
2774                result = false;
2775             dropField = null;
2776             movingFields = false;
2777          }
2778          draggingField = null;
2779          return result;
2780       }
2781       return true;
2782    }
2783
2784    bool HeaderClicked(Button control, int x, int y, Modifiers mods)
2785    {
2786       if(style.header && !this.dropField && style.sortable)
2787       {
2788          DataField field = (DataField)control.id;
2789          if(sortField == field)
2790             field.sortOrder *= -1;
2791          else
2792             sortField = field;
2793          if(field)
2794          {
2795             Sort(sortField, field.sortOrder);
2796             NotifySort(master, this, field, mods);
2797          }
2798       }
2799       return true;
2800    }
2801
2802    watch(visible)
2803    {
2804       if(style.freeSelect)
2805       {
2806          if(!visible)
2807          {
2808             ReleaseCapture();
2809             this.rolledOver = this.dragging = false;
2810          }
2811          /*else
2812             Capture();*/
2813       }
2814    };
2815
2816    bool OnLoadGraphics()
2817    {
2818       display.FontExtent(fontObject, "W", 1, null, &fontH); 
2819       if(!style.heightSet)
2820       {
2821          rowHeight = Max(fontH + 2, 16) + (style.alwaysEdit ? 1 : 0);
2822          SetScrollLineStep(8, rowHeight);
2823       }
2824       return true;
2825    }
2826
2827    void OnApplyGraphics()
2828    {
2829       SetScrollLineStep(8, rowHeight);
2830       if(style.header)
2831       {
2832          DataField field;
2833          for(field = fields.first; field; field = field.next)
2834          {
2835             if(field.headButton)
2836             {
2837                field.headButton.bevel = (!guiApp.textMode && !style.clearHeader);
2838                if(guiApp.textMode)
2839                   field.headButton.background = Color { 0, 170, 0 };
2840             }
2841          }
2842       }
2843       OnResize(clientSize.w, clientSize.h);
2844    }
2845
2846    bool OnResizing(int *w, int *h)
2847    {
2848       if(rows.first)
2849       {
2850          if(!initSize.w && (!anchor.left.type || !anchor.right.type) /**w*/)
2851          {
2852             // Use widest item
2853             DataRow row;
2854             int maxWidth = 0;
2855             Font font = fontObject;
2856             Font boldFont = this.boldFont.font;
2857             Display display = this.display;
2858             
2859             for(row = rows.first; row; row = row.GetNextRow())
2860             {
2861                Bitmap icon = row.icon ? row.icon.bitmap : null;
2862                int x = -scroll.x + EXTRA_SPACE / 2-1;
2863                DataField field;
2864                int indent = 0;
2865                DataRow parent;
2866                for(parent = row.parent; parent; parent = parent.parent)
2867                {
2868                   if(!parent.header)
2869                   {
2870                      if(style.treeBranch)
2871                         indent += 20;
2872                      else
2873                         indent += 15;
2874                   }
2875                }
2876                if(style.rootCollapse) indent += 20;
2877                x += indent;
2878                if(style.collapse && !(style.treeBranch)) x += 15;
2879                if(icon)
2880                   x += 20;
2881
2882                // Compute the rows size
2883                for(field = fields.first; field; field = field.next)
2884                {
2885                   if(((style.resizable && (!(style.alwaysEdit) || field.next)) || field.width) && !row.header)
2886                      x += field.width - (field.prev ? 0 : indent);
2887                   else
2888                   {
2889                      ListBoxCell cell;
2890                      uint index;
2891                      for(index = 0, cell = row.cells.first; index != field.index; index++, cell = cell.next);
2892
2893                      // Should always be as many cells in the row as fields in the listbox
2894                      if(cell && cell.isSet && field.dataType)
2895                      {
2896                         Bitmap icon = null;
2897                         char tempString[1024];
2898                         char * string;
2899                         int tw, th;
2900                         if(field.dataType.type == 0 normalClass || field.dataType.type == noHeadClass)
2901                            string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data[0], tempString, field.userData, null);
2902                         else
2903                            string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data, tempString, field.userData, null);
2904                         /* GCC-4.4 Bug!
2905                         if(!string) string = "";
2906                         display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
2907                         */
2908                         if(string)
2909                            display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
2910                         else
2911                            display.FontExtent(row.header ? boldFont : font, "", 0, &tw, &th);
2912                         x += tw;
2913                      }
2914                      if(row.header) break;
2915                   }
2916                   x += EXTRA_SPACE;
2917                }
2918                maxWidth = Max(maxWidth, x);
2919             }
2920             *w = maxWidth;
2921          }
2922          if(!*h)
2923          {
2924             *h = Min(this.maxShown, this.rowCount) * rowHeight;
2925          }
2926       }
2927       else
2928       {
2929          if(!*w) *w = rowHeight * 5;
2930          if(!*h) *h = rowHeight * 5;
2931       }
2932       return true;
2933    }
2934
2935    watch(font)
2936    {
2937       FontResource font = this.font;
2938       FontResource boldFont
2939       {
2940          faceName = font.faceName, size = font.size, bold = true
2941       };
2942       AddResource(boldFont);
2943       RemoveResource(this.boldFont);
2944       this.boldFont = boldFont;
2945
2946       OnLoadGraphics();
2947
2948       SetInitSize(initSize);
2949    };
2950
2951    bool OnMouseMove(int x, int y, Modifiers mods)
2952    {
2953       bool isTimer = false;
2954       int realX = x, realY = y;
2955
2956       if(insideNotifySelect) return true;
2957
2958       if(style.alwaysEdit && style.resizable &&
2959          resizingField && !(mods.isSideEffect))
2960       {
2961         // Resize left
2962          DataField field = resizingField;
2963          field.width = this.startWidth + x - this.resizeX;
2964          field.width = Max(field.width, - EXTRA_SPACE);
2965
2966          AdaptToFieldWidth(field, true);
2967       }
2968
2969       cursor = null;
2970       if(style.alwaysEdit && style.resizable)
2971       {
2972          int vx = -scroll.x - 1;
2973          DataField field;
2974
2975          if(style.collapse && !(style.treeBranch))
2976             vx += 15;
2977
2978          for(field = fields.first; field; field = field.next)
2979          {
2980             int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2981                clientSize.w - field.x : (field.width + EXTRA_SPACE);
2982
2983             if(field.prev)
2984             {
2985                if(Abs(x - vx) < 2)
2986                {
2987                   cursor = guiApp.GetCursor(sizeWE);
2988                   break;
2989                }
2990             }
2991             vx += width + EXTRA_SPACE;
2992          }
2993       }
2994
2995       if((editData && editData.visible) || (style.alwaysEdit))
2996          return true;
2997       
2998       if(x == MAXINT && y == MAXINT)
2999       {
3000          x = this.mouseX;
3001          y = this.mouseY;
3002          isTimer = true;
3003       }
3004
3005       // ADDED THIS CHECK FOR FieldDropBox LEAKS
3006       if(/*!mods.isSideEffect && */(this.rolledOver || !this.dragging))
3007       {
3008          int rowY = (style.header) ? rowHeight : 0;
3009          DataRow row = null;
3010          int rowIndex;
3011
3012          mouseX = x;
3013          mouseY = y;
3014
3015          if(this.dragging &&
3016             ((vertScroll && vertScroll.visible && 
3017              (y < 0 || y >= clientSize.h)) ||
3018              (horzScroll && horzScroll.visible && 
3019              (x < 0 || x >= clientSize.w))))
3020          {
3021             timer.Start();
3022             if(isTimer)
3023             {
3024                if(vertScroll && vertScroll.visible && 
3025                   (y < 0 || y >= clientSize.h))
3026                   vertScroll.Action((y<0)?up:down, 0, 0);
3027                if(horzScroll && horzScroll.visible && 
3028                   (x < 0 || x >= clientSize.w))
3029                   horzScroll.Action((x<0)?up:down, 0, 0);
3030             }
3031          }
3032          else
3033             timer.Stop();
3034
3035          // This must be done after the scrolling took place
3036          rowIndex = firstRowShown ? firstRowShown.index : -1;
3037          y = Max(y, 0);
3038          y = Min(y, clientSize.h-1);
3039          for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3040          {
3041             rowY += rowHeight;
3042             if(rowY > y)
3043             {
3044                break;
3045             }
3046          }
3047
3048          if(row && currentRow != row)
3049          {
3050             if(this.dragRow && style.moveRows)
3051             {
3052                if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3053                   rowIndex = -1;
3054                else if(style.multiSelect)
3055                {
3056                   DataRow thisRow;
3057                   for(thisRow = rows.first; thisRow; thisRow = thisRow.GetNextRow())
3058                      if((thisRow.selectedFlag == selected || thisRow.selectedFlag == tempSelected) || 
3059                         thisRow == row)
3060                         break;
3061                   if(thisRow != row)
3062                      rowIndex++;
3063                }
3064                if(this.dropIndex != rowIndex)
3065                {
3066                   this.dropIndex = rowIndex;
3067                   this.editRow = null;
3068                   Update(null);
3069                   this.movedRow = true;
3070                }
3071             }
3072             else if((style.freeSelect  || this.dragging) && ((realX>= 0 && realY >= 0 && realX< clientSize.w && realY < clientSize.h) || this.rolledOver))
3073             {
3074                if(!(style.multiSelect))
3075                {
3076                   if(currentRow)currentRow.selectedFlag = unselected;
3077                   if(row)row.selectedFlag = selected;
3078                }
3079                currentRow = row;
3080
3081                if(style.multiSelect)
3082                {
3083                   DataRow selRow;
3084
3085                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3086                   {
3087                      if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3088                      else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3089                   }
3090
3091                   if(rowIndex >= clickedRow.index)
3092                   {
3093                      for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3094                      {
3095                         selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3096                         if(selRow == row)
3097                            break;
3098                      }
3099                   }
3100                   else
3101                   {
3102                      for(selRow = row; selRow; selRow = selRow.GetNextRow())
3103                      {
3104                         selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3105                         if(selRow == clickedRow)
3106                            break;
3107                      }
3108                   }
3109                }
3110                Update(null);
3111                if(style.freeSelect)
3112                   NotifyHighlight(master, this, currentRow, mods);
3113                else
3114                {
3115                   insideNotifySelect = true;
3116                   NotifySelect(master, this, currentRow, mods);
3117                   insideNotifySelect = false;
3118                }
3119
3120                if(style.alwaysEdit && currentRow)
3121                   currentRow.Edit(currentField);
3122             }
3123          }
3124       }
3125       return true;
3126    }
3127
3128    bool OnMouseOver(int x, int y, Modifiers mods)
3129    {
3130       if(this.dragging)
3131          this.rolledOver = true;
3132       return true;
3133    }
3134
3135    bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
3136    {
3137       // TOCHECK: WAS THIS MISSING ? CHECK FOR SLOWDOWN
3138       if(!active) Update(null);
3139
3140       if(!active && (!swap || !swap.isModal))
3141       {
3142          // true: destroy edit box
3143          HideEditBox(true, true, false);
3144       }
3145       else if(!swap || !swap.isModal)
3146       {
3147          // Bring back edit box
3148          if(currentRow && style.alwaysEdit)
3149          {
3150             currentRow.Edit(currentField ? currentField : null);
3151          }
3152          Update(null);
3153       }
3154       return true; //NotifyActivate(master, this, active, swap, 0);
3155    }
3156
3157
3158    bool OnButtonDown(int x, int y, Modifiers mods, bool right)
3159    {
3160       bool result = true;
3161       // Check to see if we're dragging the vertical divider
3162       if(style.alwaysEdit && style.resizable && !right)
3163       {
3164          int vx = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
3165          DataField field;
3166
3167          if(style.collapse && !(style.treeBranch))
3168             vx += 15;
3169
3170          for(field = fields.first; field; field = field.next)
3171          {
3172             int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3173                clientSize.w - field.x : (field.width + EXTRA_SPACE);
3174
3175             if(field.prev)
3176             {
3177                if(Abs(x - vx) < 2)
3178                {
3179                   resizingField = field.prev;
3180                   this.resizeX = x;
3181                   this.startWidth = resizingField.width;
3182                   Capture();
3183                   SetMouseRangeToClient();
3184                   break;
3185                }
3186             }
3187             vx += width + EXTRA_SPACE;
3188          }
3189       }
3190
3191       if(!(style.freeSelect))
3192       {
3193          int rowY = (style.header) ? rowHeight : 0;
3194          DataRow row = null;
3195          int rowIndex = firstRowShown ? firstRowShown.index : -1;
3196          DataRow previousRow = currentRow;
3197          DataRow newCurrentRow = null;
3198          DataField newCurrentField = null;
3199          bool moveMultiple = false;
3200          int numSelected = 0;
3201          int rowStart = -scroll.x;
3202
3203          if(style.multiSelect)
3204          {
3205             if(!right)
3206             {
3207                DataRow row;
3208                if(!(mods.shift))
3209                {
3210                   for(row = rows.first; row; row = row.GetNextRow())
3211                   {
3212                      if(row.selectedFlag == tempSelected)
3213                         row.selectedFlag = selected;
3214                      else if(row.selectedFlag == tempUnselected)
3215                         row.selectedFlag = unselected;
3216                      if(row.selectedFlag == selected)
3217                         numSelected++;
3218                   }
3219                }
3220             }
3221          }
3222
3223          for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3224          {
3225             rowY += rowHeight;
3226             if(rowY > y || (style.multiSelect && !row.GetNextRow())) 
3227             {
3228                int plusIndent = 0;
3229                if(style.treeBranch)
3230                {
3231                   DataRow parent;
3232                   for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3233                      if(!parent.header)
3234                         plusIndent += 20;
3235                   plusIndent += 4;
3236                }
3237
3238                /*    THIS WAS TOO STRICT:
3239                if(style.collapse && row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) &&
3240                   (x >= rowStart + 3 + plusIndent && y >= rowY - rowHeight + PLUSY && x <= rowStart + 11 + plusIndent && y <= rowY - rowHeight + PLUSY + 8))
3241                */
3242                if(style.collapse && 
3243                   (x >= rowStart && y >= rowY - rowHeight && x <= rowStart + 18 + plusIndent && y <= rowY + rowHeight-1))
3244                {
3245                   if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) && x >= plusIndent)
3246                      row.collapsed = !row.collapsed;
3247                   return false;
3248                }
3249                else
3250                {
3251                   if(rowY > y)
3252                   {
3253                      newCurrentRow = row;
3254                   }
3255                   if(style.multiSelect)
3256                   {
3257                      // Deselect everything if user didn't clicked on a row
3258                      if(y >= rowY)
3259                      {
3260                         DataRow selRow;
3261                         for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3262                            selRow.selectedFlag = unselected;
3263                         clickedRow = row;
3264                         //this.clickedRowIndex = rowIndex;
3265                      }
3266                      else if(style.moveRows && !(mods.shift) && 
3267                         (row.selectedFlag == selected || row.selectedFlag == tempSelected) &&
3268                         !right && !(mods.isActivate))
3269                         moveMultiple = true;
3270                      else
3271                      {
3272                         DataRow selRow;
3273                         if(right)
3274                         {
3275                            if(row.selectedFlag == tempUnselected || row.selectedFlag == unselected)
3276                            {
3277                               for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3278                                  selRow.selectedFlag = unselected;
3279                               row.selectedFlag = selected;
3280                            }
3281                            clickedRow = row;
3282                            //this.clickedRowIndex = rowIndex;
3283                         }
3284                         else
3285                         {
3286                            if(!(mods.ctrl))
3287                            {
3288                               for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3289                                  selRow.selectedFlag = unselected;
3290                            }
3291                            else
3292                            {
3293                               for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3294                               {
3295                                  if(selRow != clickedRow)
3296                                  {
3297                                     if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3298                                     else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3299                                  }
3300                               }
3301                            }
3302
3303                            if(mods.shift)
3304                            {
3305                               if(rowIndex >= clickedRow.index)
3306                               {
3307                                  for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3308                                  {
3309                                     if(mods.ctrl)
3310                                     {
3311                                        if(selRow != clickedRow)
3312                                        {
3313                                           if(selRow.selectedFlag) 
3314                                              selRow.selectedFlag = tempUnselected;
3315                                           else
3316                                              selRow.selectedFlag = tempSelected;
3317                                        }
3318                                     }
3319                                     else
3320                                        selRow.selectedFlag = selected;
3321                                     if(selRow == row)
3322                                        break;
3323                                  }
3324                               }
3325                               else
3326                               {
3327                                  for(selRow = row; selRow; selRow = selRow.GetNextRow())
3328                                  {
3329                                     if(mods.ctrl)
3330                                     {
3331                                        if(selRow != clickedRow)
3332                                        {
3333                                           if(selRow.selectedFlag)
3334                                              selRow.selectedFlag = tempUnselected;
3335                                           else
3336                                              selRow.selectedFlag = tempSelected;
3337                                        }
3338                                     }
3339                                     else
3340                                        selRow.selectedFlag = selected;
3341                                     if(selRow == clickedRow)
3342                                        break;
3343                                  }
3344                               }
3345                            }
3346                            else
3347                            {
3348                               if(mods.ctrl)
3349                               {
3350                                  if(row.selectedFlag)
3351                                     row.selectedFlag = tempUnselected;
3352                                  else row.selectedFlag = tempSelected;
3353                               }
3354                               else
3355                                  row.selectedFlag = tempSelected;
3356                               clickedRow = row;
3357                               //this.clickedRowIndex = rowIndex;
3358                            }
3359                         }
3360                      }
3361                   }
3362                }
3363                break;
3364             }
3365          }
3366
3367          // true: destroy edit box
3368          if(newCurrentRow)
3369          {
3370             incref newCurrentRow;
3371          }
3372
3373          if(currentRow != newCurrentRow)
3374             HideEditBox(true, true, false);
3375
3376          if(newCurrentRow)
3377          {
3378             if(newCurrentRow._refCount <= 1)
3379                delete newCurrentRow;
3380             else
3381                newCurrentRow._refCount--;
3382          }
3383
3384          if(newCurrentRow)
3385          {
3386             if(!(style.multiSelect))
3387             {
3388                if(currentRow) currentRow.selectedFlag = unselected;
3389                if(newCurrentRow) newCurrentRow.selectedFlag = selected;
3390             }
3391          }
3392
3393          if(currentRow != newCurrentRow)
3394          {
3395             /*
3396             // true: destroy edit box
3397             if(newCurrentRow)
3398             {
3399                //incref newCurrentRow;
3400                incref newCurrentRow;
3401             }
3402
3403             HideEditBox(true, true, false);
3404             */
3405
3406             if(newCurrentRow)
3407             {
3408                int headerSize = ((style.header) ? rowHeight : 0);
3409                int height = clientSize.h + 1 - headerSize;
3410
3411                /*if(newCurrentRow._refCount <= 1)
3412                   delete newCurrentRow;
3413                else
3414                {
3415                   newCurrentRow._refCount--;
3416                   //newCurrentRow._refCount--;
3417                }
3418                */
3419                currentRow = newCurrentRow;
3420
3421                if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
3422                   SetScrollPosition(scroll.x,
3423                      currentRow.index * rowHeight - height + rowHeight);
3424                else if(!currentRow || currentRow.index * rowHeight < scroll.y)
3425                {
3426                   int line = currentRow ? currentRow.index * rowHeight : 0;
3427                   //SNAPUP(line, rowHeight);
3428                   SetScrollPosition(scroll.x, line);
3429                }
3430
3431                // GO THROUGH SetCurrentRow eventually?
3432                // SetCurrentRow(newCurrentRow, true);
3433             }
3434          }
3435
3436          if(style.freeSelect)
3437             NotifyHighlight(master, this, currentRow, mods);
3438          else if((moveMultiple || (!(style.multiSelect) && previousRow == currentRow)) && 
3439             newCurrentRow && !(mods.shift))
3440          {
3441             if(!right)
3442             {
3443                if(!(mods.isActivate))
3444                {
3445                   if(style.moveRows)
3446                   {
3447                      this.dragRow = currentRow;
3448                      this.dropIndex = -1;
3449                      this.movedRow = false;
3450                   }
3451                   if(editData && editData.visible && style.alwaysEdit)
3452                   {
3453                      DataField field;
3454                      int sx = -scroll.x;
3455                      int indent = 0;
3456                      DataRow parent;
3457
3458                      if(style.collapse && !style.treeBranch)
3459                         sx += 15;
3460
3461                      for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3462                         if(!parent.header)
3463                            indent += (style.treeBranch) ? 20 : 15;
3464                      sx += indent;
3465
3466                      for(field = fields.first; field; field = field.next)
3467                      {
3468                         int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3469                            clientSize.w - field.x : (field.width + EXTRA_SPACE);
3470
3471                         if(!field.prev) width -= indent;
3472                         if(x >= sx && x < sx + width)
3473                            break;                     
3474                         sx += width;
3475                      }
3476                      if(field == currentField)
3477                         editData.Deactivate();
3478                      else
3479                      {
3480                         currentRow.Edit(field);                     
3481                         editData.Activate();
3482                      }
3483                   }
3484                   else if(!(mods.ctrl) && numSelected <= 1)
3485                      this.editRow = currentRow;
3486
3487                   if(style.noDragging && newCurrentRow)
3488                     NotifyReclick(master, this, newCurrentRow, mods);
3489                }
3490                else
3491                {
3492                   // If the user clicked exactly on the edited field,
3493                   // activate it
3494                   if(editData && editData.visible && newCurrentRow)
3495                   {
3496                      DataField field, whichField;
3497                      int sx = -scroll.x;
3498                      int indent = 0;
3499
3500                      if(style.collapse && !(style.treeBranch))
3501                         sx += 15;
3502                   
3503                      whichField = currentField;
3504
3505                      {
3506                         DataRow parent;
3507                         for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3508                            if(!parent.header)
3509                               indent += (style.treeBranch) ? 20 : 15;
3510                         sx += indent;
3511                      }
3512
3513                      for(field = fields.first; field; field = field.next)
3514                      {
3515                         int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3516                            clientSize.w - field.x : (field.width + EXTRA_SPACE);
3517                         if(!field.prev) width -= indent;
3518                         if(x >= sx && x < sx + width && newCurrentRow)
3519                            break;
3520                         sx += width;
3521                      }
3522
3523                      if(field) //x >= sx && x < sx + width && newCurrentRow)
3524                      {
3525                         if(field == currentField)
3526                            editData.Activate();
3527                         /*else
3528                            newCurrentRow.Edit(currentField);*/
3529                      }
3530                      else if(style.noDragging && newCurrentRow)
3531                        NotifyReclick(master, this, newCurrentRow, mods);
3532                   }
3533                   else if(style.noDragging && newCurrentRow)
3534                     NotifyReclick(master, this, newCurrentRow, mods);
3535                }
3536             }
3537          }
3538          else
3539          {
3540             result = NotifySelect(master, this, 
3541                currentRow ? currentRow : null, mods);
3542             if(result && style.alwaysEdit && currentRow)
3543             {
3544                if(newCurrentRow)
3545                {
3546                   DataField field = null;
3547                   int sx = -scroll.x;
3548                   int indent = 0;
3549                   DataRow parent;
3550
3551                   if(style.collapse && !style.treeBranch)
3552                      sx += 15;
3553
3554                   for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3555                      if(!parent.header)
3556                         indent += (style.treeBranch) ? 20 : 15;
3557                   sx += indent;
3558
3559                   for(field = fields.first; field; field = field.next)
3560                   {
3561                      int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3562                         clientSize.w - field.x : (field.width + EXTRA_SPACE);
3563
3564                      if(!field.prev) width -= indent;
3565                      if(x >= sx && x < sx + width)
3566                      {
3567                         currentField = field;
3568                         break;
3569                      }
3570                      sx += width;
3571                   }
3572                }
3573                currentRow.Edit(currentField);
3574
3575                // If the user clicked exactly on the edited field,
3576                // activate it
3577                if(editData && editData.visible && newCurrentRow)
3578                {
3579                   if(currentField)
3580                   {
3581                      editData.Activate();
3582                   }
3583                   else if(style.noDragging && newCurrentRow)
3584                      NotifyReclick(master, this, newCurrentRow, mods);
3585                }
3586             }
3587             else if(style.noDragging && newCurrentRow)
3588               NotifyReclick(master, this, newCurrentRow, mods);
3589          }
3590       }
3591       /*
3592          For drop box to capture...
3593       else
3594       {
3595          if(x < 0 || y < 0 || x >= clientSize.w || y >= clientSize.h)
3596          {
3597             bool goOn = true;
3598             master.parent.Activate();
3599             Update(null);
3600             ReleaseCapture();
3601             return true;
3602          }
3603       }
3604       */
3605       if(result)
3606       {
3607          if(!style.noDragging)
3608          {
3609             this.dragging = true;
3610             Capture();
3611          }
3612          if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h)
3613             this.rolledOver = true;
3614          Update(null);
3615       }
3616       else
3617       {
3618          this.dragging = false;
3619          OnLeftButtonUp(x, y, mods);
3620       }
3621       return result;
3622    }
3623
3624    bool OnLeftButtonDown(int x, int y, Modifiers mods)
3625    {
3626       return OnButtonDown(x,y, mods, false);
3627    }
3628
3629    bool OnLeftButtonUp(int x, int y, Modifiers mods)
3630    {
3631       if(resizingField && style.alwaysEdit)
3632       {
3633          Window::FreeMouseRange();
3634          ReleaseCapture();
3635          resizingField = null;
3636       }
3637
3638       if(dragRow || editRow)
3639       {
3640          DataRow row, switchRow = rows.last;
3641          int rowY = (style.header) ? rowHeight : 0;
3642          for(row = firstRowShown; row; row = row.GetNextRow())
3643          {
3644             rowY += rowHeight;
3645             if(rowY > y) 
3646             {
3647                switchRow = row;
3648                break;
3649             }
3650          }
3651          if(this.editRow == switchRow && y >= 0)
3652          {
3653             // Find which field
3654             DataField field;
3655             int fieldX = 0;
3656             for(field = fields.first; field; field = field.next)
3657             {
3658                int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3659                   clientSize.w - field.x : (field.width + EXTRA_SPACE);
3660                fieldX += width;
3661
3662                if(fieldX > x + scroll.x) 
3663                   break;
3664             }
3665             
3666             if(field && field.editable)
3667             {
3668                // true: destroy edit box
3669                HideEditBox(true, true, false);
3670                PopupEditBox(field, false);
3671             }
3672             else if(!style.noDragging)
3673                NotifyReclick(master, this, currentRow, mods);
3674          }
3675          else if(style.moveRows && switchRow)
3676          {
3677             if(this.dragRow == switchRow && this.movedRow == false)
3678             {
3679                DataRow row = this.dragRow;
3680                DataRow selRow;
3681                if(!(mods.ctrl))
3682                {
3683                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3684                      selRow.selectedFlag = unselected;
3685                }
3686                else
3687                {
3688                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3689                   {
3690                      if(selRow != clickedRow)
3691                      {
3692                         if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3693                         else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3694                      }
3695                   }
3696                }
3697                if(mods.ctrl)
3698                {
3699                   if(row.selectedFlag)
3700                      row.selectedFlag = tempUnselected;
3701                   else row.selectedFlag = tempSelected;
3702                }
3703                else
3704                   row.selectedFlag = tempSelected;
3705                clickedRow = row;
3706             }
3707             else
3708             { 
3709                if(style.multiSelect)
3710                {
3711                   if(!switchRow.selectedFlag)
3712                   {
3713                      bool foundSwitch = false;
3714                      bool after = false;
3715                      DataRow next;
3716                      DataRow afterRow = switchRow.prev;
3717                      for(row = rows.first; row; row = next)
3718                      {
3719                         next = row.GetNextRow();
3720                         if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3721                         {
3722                            if(!foundSwitch && !after)
3723                            {
3724                               after = true;
3725                               afterRow = switchRow;
3726                            }
3727                            if(!after || !(row.selectedFlag == selected || row.selectedFlag == tempSelected) ||
3728                               !foundSwitch)
3729                            {
3730                               row.Move(afterRow);
3731                               afterRow = row;
3732                            }
3733                         }
3734                         else if(row == switchRow)
3735                            foundSwitch = true;
3736                      }
3737                   }
3738                }
3739                else
3740                {
3741                   for(row = rows.first; row; row = row.GetNextRow())
3742                   {
3743                      if(row == switchRow || row == this.dragRow)
3744                         break;
3745                   }
3746
3747                   // Switch row first: move before
3748                   if(row == switchRow)
3749                   {
3750                      if(NotifyMove(master, this, switchRow.prev, mods))
3751                         dragRow.Move(switchRow.prev);
3752                   }
3753                   // Dragged row first: move after
3754                   else
3755                   {
3756                      if(NotifyMove(master, this, switchRow, mods))
3757                         dragRow.Move(switchRow);
3758                   }
3759                }
3760             }
3761          }
3762          dragRow = null;
3763          editRow = null;
3764          movedRow = false;
3765          dropIndex = -1;
3766          Update(null);
3767       }
3768
3769       timer.Stop();
3770       if(this.dragging || style.freeSelect)
3771       {
3772          if(this.dragging)
3773          {
3774             this.rolledOver = this.dragging = false;
3775          }
3776          if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h && currentRow && style.freeSelect)
3777          {
3778             bool result;
3779             ReleaseCapture();
3780             result = NotifySelect(master, this, currentRow, mods);
3781             if(style.alwaysEdit)
3782                currentRow.Edit(currentField);
3783             return result;
3784
3785          }
3786          // if(!(style.freeSelect))
3787          ReleaseCapture();
3788       }
3789       return true;
3790    }
3791
3792    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
3793    {
3794       int rowStart = -scroll.x;
3795       DataRow row;
3796       int rowY = (style.header) ? rowHeight : 0;
3797       int plusIndent = 0;
3798
3799       OnLeftButtonUp(x,y,mods);
3800       if(style.alwaysEdit)
3801       {
3802          if(!(style.collapse) || x > 15)
3803             if(editData && editData.visible)
3804             {
3805                editData.Activate();
3806                NotifyDoubleClick(master, this, x, y, mods);
3807                return false;
3808             }
3809       }
3810       for(row = firstRowShown; row; row = row.GetNextRow())
3811       {
3812          rowY += rowHeight;
3813          if(rowY > y || (style.multiSelect && !row.GetNextRow())) 
3814          {
3815             if(style.treeBranch)
3816             {
3817                DataRow parent;
3818                for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3819                   if(!parent.header)
3820                      plusIndent += 20;
3821                plusIndent += 4;
3822             }
3823             break;
3824          }
3825       }
3826
3827       if((row && style.collapse && (x >= rowStart && x <= rowStart + 18 + plusIndent)) ||
3828          NotifyDoubleClick(master, this, x, y, mods))
3829       {
3830          if(style.collapse)
3831          {
3832             if(row && row.subRows.first)
3833             {
3834                row.collapsed = !row.collapsed;
3835                return false;
3836             }
3837          }
3838          // We need to return true here so that OnLeftButtonDown can popup the DataBox Editors
3839          return true;
3840       }
3841       return false;
3842    }
3843
3844    bool OnRightButtonDown(int x, int y, Modifiers mods)
3845    {
3846       return OnButtonDown(x,y, mods, true);
3847    }
3848
3849    bool OnRightButtonUp(int x, int y, Modifiers mods)
3850    {
3851       OnLeftButtonUp(x,y,mods);
3852       return NotifyRightClick(master, this, x, y, mods);
3853    }
3854
3855    bool GoToLetter(unichar ch, bool keyHit)
3856    {
3857       bool result = false;
3858       DataField field;
3859       bool checkNextField = true;
3860       int len = keyHit ? 0 : strlen(typedString);
3861
3862       typedString = renew typedString char[len + 2];
3863       typedString[len++] = (char)tolower(ch);         // TODO: FIX UNICODE
3864       typedString[len] = '\0';
3865
3866       for(field = fields.first; field; field = field.next)
3867       {
3868          DataRow startRow = currentRow ? currentRow : rows.first;
3869
3870          if(startRow && field.dataType && field.dataType._vTbl[__ecereVMethodID_class_OnGetString] && ch)
3871          {
3872             DataRow row, next;
3873             bool looped = false;
3874             if(len == 1 && currentRow)
3875                startRow = (next = startRow.GetNextRow(), (next ? next : rows.first));
3876         
3877             for(row = startRow; row != startRow || !looped; next = row.GetNextRow(), row = next ? next : rows.first)
3878             {
3879                void * data = row.GetData(field);
3880                char tempString[1024] = "";
3881                bool needClass = false;
3882                char * string = data ? (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass) : null;
3883
3884                if(string && string[0])
3885                   checkNextField = false;
3886                if(string && string[0] && !strnicmp(string, typedString, len))
3887                {
3888                   if(style.multiSelect)
3889                   {
3890                      DataRow selRow;
3891                      bool foundRow = false;
3892
3893                      //this.clickedRowIndex = 0;
3894                      clickedRow = row;
3895                      for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3896                      {
3897                         if(selRow == row) foundRow = true;
3898                         selRow.selectedFlag = unselected;
3899                         //if(!foundRow) this.clickedRowIndex++;
3900                      }
3901                      row.selectedFlag = selected;
3902                   }
3903                   SetCurrentRow(row, true);
3904                   result = true;
3905                   break;
3906                }
3907                looped = true;
3908             }
3909             typingTimer.Stop();
3910             if(this.typingTimeOut && !keyHit)
3911                typingTimer.Start();
3912             if(!result || !this.typingTimeOut || keyHit)
3913                typedString[len-1] = '\0';
3914          }
3915          if(!checkNextField || result) break;
3916       }
3917       return result;
3918    }
3919
3920    bool OnKeyDown(Key key, unichar ch)
3921    {
3922       DataField field;
3923
3924       if(key == enter || key == keyPadEnter)
3925       {
3926          if(editData && editData.visible && editData.active)
3927          {
3928             HideEditBox(true, false, false);
3929             return false;
3930          }
3931       }
3932       else if(key == escape)
3933       {
3934          if(resizingField || this.movingFields || (editData && editData.visible) || this.dragRow)
3935          {
3936             if(editData && editData.visible && style.alwaysEdit && !editData.active)
3937                return true;
3938             // false: dont destroy edit box
3939             HideEditBox(false, false, false);
3940             if(resizingField)
3941             {
3942                resizingField.width = this.startWidth;
3943                AdaptToFieldWidth(resizingField, true);
3944                resizingField = null;
3945                ReleaseCapture();
3946             }
3947             this.dragRow = null;
3948             if(this.dragging)
3949             {
3950                this.dragging = false;
3951                ReleaseCapture();
3952             }
3953
3954             this.movingFields = false;
3955             draggingField = null;
3956             Update(null);
3957             return false;
3958          }      
3959       }
3960
3961       if(!currentField || !currentField.editable)            
3962          for(field = fields.first; field; field = field.next)
3963          {
3964             if(field.editable)
3965             {
3966                currentField = field;
3967                break;
3968             }
3969          }
3970       if(key == f2 && currentField && currentField.editable)
3971       {
3972          PopupEditBox(currentField, false);
3973          if(editData && editData.visible)
3974          {
3975             if(style.alwaysEdit)
3976                editData.Activate();
3977             return false;
3978          }
3979       }
3980  
3981       if(!NotifyKeyDown(master, this, currentRow, key, ch))
3982          return false;
3983
3984       // Editable fields...
3985       if(currentField)
3986       {
3987          if(style.alwaysEdit && editData && editData.visible)
3988             return editData.OnKeyDown(key, ch);
3989          return true;   // We want to pick up the OnKeyHit to replace contents, but skip GoToLetter
3990       }
3991       
3992       if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, false))
3993       {
3994          /*if(inactive && window.state != Hidden)
3995             NotifyHighlight(master, this, currentRow, 0);
3996          else
3997          {
3998             NotifySelect(master, this, currentRow, 0);
3999          }*/
4000          return false;
4001       }
4002       return true;
4003    }
4004
4005    bool OnKeyHit(Key key, unichar ch)
4006    {
4007       if(!ch && !key.alt && !key.ctrl)
4008       {
4009          key.code = (SmartKey)key.code;
4010       }
4011       if(ch >= 32 && !key.alt && !key.ctrl && ch != 128)
4012       {
4013          DataField field;
4014          if(!currentField || !currentField.editable)
4015             for(field = fields.first; field; field = field.next)
4016             {
4017                if(field.editable)
4018                {
4019                   currentField = field;
4020                   break;
4021                }
4022             }
4023          if(currentField && currentField.editable)
4024          {
4025             if((!editData || !editData.visible) || !editData.active)
4026             {
4027                PopupEditBox(currentField, false);
4028                if(editData && editData.visible)
4029                {
4030                   editData.Activate();
4031                   editData.OnKeyHit(key, ch);
4032                }
4033             }
4034             return false;
4035          }
4036       }
4037
4038       if(!(style.multiSelect) && (key.ctrl))
4039          return true;
4040
4041       if(editData && editData.visible && ch && !key.alt && !key.ctrl && editData.active)
4042          return false;
4043
4044       switch(key.code)
4045       {
4046          case left:
4047             if(style.alwaysEdit)
4048             {
4049                if(currentField)
4050                {
4051                   DataField field;
4052                   for(field = currentField.prev; field; field = field.prev)
4053                   {
4054                      if(field.editable)
4055                      {
4056                         currentField = field;
4057                         HideEditBox(true, true, false);
4058                         PopupEditBox(currentField, false);
4059                         return false;
4060                      }                     
4061                   }
4062                }
4063             }
4064             if(style.collapse && currentRow /*&& !currentField*/)  // THIS PREVENTED COLLAPSING THE PROPERTY SHEET
4065             {
4066                if(currentRow.subRows.first && !currentRow.collapsed)
4067                {
4068                   currentRow.collapsed = true;
4069                }
4070                else if(currentRow.parent)
4071                   SetCurrentRow(currentRow.parent, true);
4072                return false;
4073             }
4074             break;
4075          case right:
4076             if(style.collapse && currentRow && currentRow.subRows.first)
4077             {
4078                if(currentRow.collapsed)
4079                   currentRow.collapsed = false;
4080                else
4081                   SetCurrentRow(currentRow.subRows.first, true);
4082                return false;
4083             }
4084             else if(style.alwaysEdit)
4085             {
4086                if(currentField)
4087                {
4088                   DataField field;
4089                   for(field = currentField.next; field; field = field.next)
4090                   {
4091                      if(field.editable)
4092                      {
4093                         currentField = field;
4094                         HideEditBox(true, true, false);
4095                         PopupEditBox(currentField, false);
4096                         break;
4097                      }                     
4098                   }
4099                }
4100             }
4101             break;
4102          case down: case up:
4103          case pageDown: case pageUp:
4104          case end: case home:
4105          {
4106             int headerSize = ((style.header) ? rowHeight : 0);
4107             int height = clientSize.h + 1 - headerSize;
4108             DataRow oldRow;
4109
4110             // true: destroy edit box
4111             // !!! TESTING true HERE !!!
4112             HideEditBox(true, true, false);
4113             // HideEditBox(false, true, false);
4114             
4115             oldRow = currentRow;
4116
4117             SNAPDOWN(height, rowHeight);
4118             if((!currentRow || key.code == home) && key.code != end)
4119             {
4120                currentRow = rows.first;
4121             }
4122             else
4123             {
4124                DataRow next;
4125                switch(key.code)
4126                {
4127                   case down:
4128                      if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4129                         next = currentRow;
4130                      else
4131                         next = currentRow.GetNextRow();
4132                      if(next)
4133                      {
4134                         currentRow = next;
4135                      }
4136                      break;
4137                   case up:
4138                      if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4139                         next = currentRow;
4140                      else
4141                         next = currentRow.GetPrevRow();
4142
4143                      if(next)
4144                      {
4145                         currentRow = next;
4146                      }
4147                      break;
4148                   case end:
4149                      // TODO: Find very last row
4150                      for(currentRow = rows.last; currentRow && !currentRow.collapsed && currentRow.subRows.last;)
4151                         currentRow = currentRow.subRows.last;
4152                      break;
4153                   case pageUp:
4154                   {
4155                      int c;
4156                      for(c = 0;
4157                      currentRow && (next = currentRow.GetPrevRow()) && c < height / rowHeight;
4158                          c++, currentRow = next);
4159                      break;
4160                   }
4161                   case pageDown:
4162                   {
4163                      int c;
4164                      for(c = 0;
4165                          currentRow && (next = currentRow.GetNextRow()) && c < height / rowHeight;
4166                          c++, currentRow = next);
4167                      break;
4168                   }
4169                }
4170             }
4171             if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
4172                SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
4173             else if(!currentRow || currentRow.index * rowHeight < scroll.y)
4174                SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
4175
4176             if(style.multiSelect)
4177             {
4178                DataRow selRow;
4179
4180                if(!(key.shift) && (key.ctrl))
4181                {
4182                   DataRow row;
4183                   for(row = rows.first; row; row = row.GetNextRow())
4184                   {
4185                      if(row.selectedFlag == tempSelected)
4186                         row.selectedFlag = selected;
4187                      else if(row.selectedFlag == tempUnselected)
4188                         row.selectedFlag = unselected;
4189                   }
4190                }
4191
4192                if(!(key.ctrl))
4193                {
4194                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4195                      selRow.selectedFlag = unselected;
4196                }
4197                else
4198                {
4199                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4200                   {
4201                      if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
4202                      else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
4203                   }
4204                }
4205
4206                if(key.shift)
4207                {
4208                   if(currentRow.index >= clickedRow.index)
4209                   {
4210                      for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
4211                      {
4212                         if(key.ctrl)
4213                         {
4214                            if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4215                         }
4216                         else
4217                            selRow.selectedFlag = selected;
4218                         if(selRow == currentRow)
4219                            break;
4220                      }
4221                   }
4222                   else
4223                   {
4224                      for(selRow = currentRow; selRow; selRow = selRow.GetNextRow())
4225                      {
4226                         if(key.ctrl)
4227                         {
4228                            if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4229                         }
4230                         else
4231                            selRow.selectedFlag = selected;
4232                         if(selRow == clickedRow)
4233                            break;
4234                      }
4235                   }
4236                }
4237                else
4238                {
4239                   if(!(key.ctrl) && currentRow)
4240                   {
4241                      currentRow.selectedFlag = selected;
4242                   }
4243
4244                   clickedRow = currentRow;
4245                }
4246             }
4247             else
4248             {
4249                if(oldRow) oldRow.selectedFlag = unselected;
4250                if(currentRow) currentRow.selectedFlag = selected;
4251             }
4252
4253             if(currentRow)
4254             {
4255                if(style.freeSelect)
4256                   NotifyHighlight(master, this, currentRow, 0);
4257                else
4258                   NotifySelect(master, this, currentRow, 0);
4259
4260                if(style.alwaysEdit && currentRow)
4261                   currentRow.Edit(currentField /*null*/);
4262             }
4263             Update(null);
4264             return false;
4265          }
4266          case space:
4267          {
4268             if(style.multiSelect && currentRow)
4269             {
4270                if(currentRow.selectedFlag)
4271                {
4272                   if(key.ctrl)
4273                      currentRow.selectedFlag = unselected;
4274                }
4275                else
4276                   currentRow.selectedFlag = selected;
4277                Update(null);
4278
4279                if(style.freeSelect)
4280                   NotifyHighlight(master, this, currentRow, 0);
4281                else
4282                   NotifySelect(master, this, currentRow, 0);
4283             }
4284             break;
4285          }
4286       }
4287  
4288       if(!NotifyKeyHit(master, this, currentRow, key, ch))
4289          return false;
4290
4291       if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, true))
4292       {
4293          /*if(inactive && window.state != Hidden)
4294             return NotifyHighlight(master, this, currentRow, 0);
4295          else
4296          {
4297             return NotifySelect(master, this, currentRow, 0);
4298          }*/
4299          return false;
4300       }
4301       return true;
4302    }
4303
4304
4305    void OnHScroll(ScrollBarAction action, int position, Key key)
4306    {
4307       Update(null);
4308    }
4309
4310    void OnVScroll(ScrollBarAction action, int position, Key key)
4311    {
4312       int y = 0;
4313       DataRow next;
4314
4315       for(firstRowShown = rows.first; firstRowShown; firstRowShown = next)
4316       {
4317          next = firstRowShown.GetNextRow();
4318          if(y >= position || !next) break;
4319
4320          y += rowHeight;
4321       }
4322       Update(null);
4323    }
4324
4325    OldList fields;
4326    OldList rows;
4327    int numFields;
4328    DataRow firstRowShown;
4329    DataRow clickedRow;
4330    DataRow currentRow;
4331    int width;
4332    DataField sortField;
4333    int rowCount;
4334    int rowHeight;
4335    int fontH;
4336    double typingTimeOut;
4337    char * typedString;
4338
4339    int mouseX, mouseY;
4340
4341    Timer timer
4342    {
4343       delay = 0.1;
4344       userData = this;
4345
4346       bool DelayExpired()
4347       {
4348          Modifiers mods { };
4349          if(guiApp.GetKeyState(shift)) mods.shift = true;
4350          if(guiApp.GetKeyState(alt)) mods.alt = true;
4351          if(guiApp.GetKeyState(control)) mods.ctrl = true;
4352          OnMouseMove(MAXINT, MAXINT, mods);
4353
4354          return true;
4355       }
4356    };
4357
4358    Timer typingTimer
4359    {
4360       delay = 0.5; // typingTimeOut
4361       userData = this;
4362       
4363       bool DelayExpired()
4364       {
4365          typedString[0] = '\0';
4366
4367          // The next line was commented... Why? When commented typing words stops working ( only first character jumps )
4368          typingTimer.Stop();
4369          return true;
4370       }
4371    };
4372
4373    bool dragging, rolledOver;
4374    int numSelections;
4375    Button endBevel;
4376
4377    // For moving rows
4378    DataRow dragRow;
4379    int dropIndex;
4380    bool movedRow;
4381
4382    // For editing fields
4383    DataBox editData;
4384    DataField currentField;
4385    DataRow editRow;
4386
4387    // For moving fields
4388    DataField draggingField, dropField;
4389    bool movingFields;
4390
4391    // For resizing fields
4392    DataField resizingField;
4393    int resizeX, oldX, startWidth;
4394
4395    ListBoxBits style;
4396    FontResource boldFont;
4397    int maxShown;
4398
4399    // Only used for OnMouseMove so far, for avoiding problems with consequential mouse moves
4400    bool insideNotifySelect;
4401    Color selectionColor, selectionText, stippleColor;
4402    stippleColor = 0xFFFFFF80;
4403 };